1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <oox/dump/dumperbase.hxx>
23 #include <string_view>
25 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
26 #include <com/sun/star/io/XActiveDataSource.hpp>
27 #include <com/sun/star/io/TextOutputStream.hpp>
28 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
29 #include <osl/file.hxx>
30 #include <rtl/math.hxx>
31 #include <rtl/tencinfo.h>
32 #include <oox/core/filterbase.hxx>
33 #include <oox/helper/binaryoutputstream.hxx>
34 #include <oox/helper/textinputstream.hxx>
35 #include <tools/time.hxx>
42 using namespace ::com::sun::star
;
43 using namespace ::com::sun::star::beans
;
44 using namespace ::com::sun::star::io
;
45 using namespace ::com::sun::star::lang
;
46 using namespace ::com::sun::star::ucb
;
47 using namespace ::com::sun::star::uno
;
49 using ::oox::core::FilterBase
;
53 const sal_Unicode OOX_DUMP_BOM
= 0xFEFF;
54 const sal_Int32 OOX_DUMP_MAXSTRLEN
= 80;
55 const sal_Int32 OOX_DUMP_INDENT
= 2;
56 const sal_Unicode OOX_DUMP_BINDOT
= '.';
57 const sal_Unicode OOX_DUMP_CFG_LISTSEP
= ',';
58 const sal_Unicode OOX_DUMP_CFG_QUOTE
= '\'';
59 const sal_Unicode OOX_DUMP_LF
= '\n';
60 const sal_Unicode OOX_DUMP_ITEMSEP
= '=';
61 const sal_Int32 OOX_DUMP_BYTESPERLINE
= 16;
62 const sal_Int64 OOX_DUMP_MAXARRAY
= 16;
66 // file names -----------------------------------------------------------------
68 OUString
InputOutputHelper::convertFileNameToUrl( const OUString
& rFileName
)
71 if( ::osl::FileBase::getFileURLFromSystemPath( rFileName
, aFileUrl
) == ::osl::FileBase::E_None
)
76 sal_Int32
InputOutputHelper::getFileNamePos( const OUString
& rFileUrl
)
78 sal_Int32 nSepPos
= rFileUrl
.lastIndexOf( '/' );
79 return (nSepPos
< 0) ? 0 : (nSepPos
+ 1);
82 OUString
InputOutputHelper::getFileNameExtension( const OUString
& rFileUrl
)
84 sal_Int32 nNamePos
= getFileNamePos( rFileUrl
);
85 sal_Int32 nExtPos
= rFileUrl
.lastIndexOf( '.' );
86 if( nExtPos
>= nNamePos
)
87 return rFileUrl
.copy( nExtPos
+ 1 );
91 // input streams --------------------------------------------------------------
93 Reference
< XInputStream
> InputOutputHelper::openInputStream(
94 const Reference
< XComponentContext
>& rxContext
, const OUString
& rFileName
)
96 Reference
< XInputStream
> xInStrm
;
97 if( rxContext
.is() ) try
99 Reference
<XSimpleFileAccess3
> xFileAccess(SimpleFileAccess::create(rxContext
));
100 xInStrm
= xFileAccess
->openFileRead( rFileName
);
108 // output streams -------------------------------------------------------------
110 Reference
< XOutputStream
> InputOutputHelper::openOutputStream(
111 const Reference
< XComponentContext
>& rxContext
, const OUString
& rFileName
)
113 Reference
< XOutputStream
> xOutStrm
;
114 if( rxContext
.is() ) try
116 Reference
<XSimpleFileAccess3
> xFileAccess(SimpleFileAccess::create(rxContext
));
117 xOutStrm
= xFileAccess
->openFileWrite( rFileName
);
125 Reference
< XTextOutputStream2
> InputOutputHelper::openTextOutputStream(
126 const Reference
< XComponentContext
>& rxContext
, const Reference
< XOutputStream
>& rxOutStrm
, rtl_TextEncoding eTextEnc
)
128 Reference
< XTextOutputStream2
> xTextOutStrm
;
129 const char* pcCharset
= rtl_getMimeCharsetFromTextEncoding( eTextEnc
);
130 if( rxContext
.is() && rxOutStrm
.is() && pcCharset
) try
132 xTextOutStrm
= TextOutputStream::create(rxContext
);
133 xTextOutStrm
->setOutputStream( rxOutStrm
);
134 xTextOutStrm
->setEncoding( OUString::createFromAscii( pcCharset
) );
142 Reference
< XTextOutputStream2
> InputOutputHelper::openTextOutputStream(
143 const Reference
< XComponentContext
>& rxContext
, const OUString
& rFileName
, rtl_TextEncoding eTextEnc
)
145 return openTextOutputStream( rxContext
, openOutputStream( rxContext
, rFileName
), eTextEnc
);
148 ItemFormat::ItemFormat() :
149 meDataType( DATATYPE_VOID
),
150 meFmtType( FORMATTYPE_NONE
)
154 void ItemFormat::set( DataType eDataType
, FormatType eFmtType
, const OUString
& rItemName
)
156 meDataType
= eDataType
;
157 meFmtType
= eFmtType
;
158 maItemName
= rItemName
;
162 OUStringVector::const_iterator
ItemFormat::parse( const OUStringVector
& rFormatVec
)
164 set( DATATYPE_VOID
, FORMATTYPE_NONE
, OUString() );
166 OUStringVector::const_iterator aIt
= rFormatVec
.begin(), aEnd
= rFormatVec
.end();
167 OUString aDataType
, aFmtType
;
168 if( aIt
!= aEnd
) aDataType
= *aIt
++;
169 if( aIt
!= aEnd
) aFmtType
= *aIt
++;
170 if( aIt
!= aEnd
) maItemName
= *aIt
++;
171 if( aIt
!= aEnd
) maListName
= *aIt
++;
173 meDataType
= StringHelper::convertToDataType( aDataType
);
174 meFmtType
= StringHelper::convertToFormatType( aFmtType
);
176 if( meFmtType
== FORMATTYPE_NONE
)
178 if ( aFmtType
== "unused" )
179 set( meDataType
, FORMATTYPE_HEX
, OOX_DUMP_UNUSED
);
180 else if ( aFmtType
== "unknown" )
181 set( meDataType
, FORMATTYPE_HEX
, OOX_DUMP_UNKNOWN
);
187 OUStringVector
ItemFormat::parse( const OUString
& rFormatStr
)
189 OUStringVector aFormatVec
;
190 StringHelper::convertStringToStringList( aFormatVec
, rFormatStr
, false );
191 OUStringVector::const_iterator aIt
= parse( aFormatVec
);
192 return OUStringVector( aIt
, const_cast< const OUStringVector
& >( aFormatVec
).end() );
195 // append string to string ----------------------------------------------------
197 void StringHelper::appendChar( OUStringBuffer
& rStr
, sal_Unicode cChar
, sal_Int32 nCount
)
199 for( sal_Int32 nIndex
= 0; nIndex
< nCount
; ++nIndex
)
200 rStr
.append( cChar
);
203 void StringHelper::appendString( OUStringBuffer
& rStr
, const OUString
& rData
, sal_Int32 nWidth
, sal_Unicode cFill
)
205 appendChar( rStr
, cFill
, nWidth
- rData
.getLength() );
206 rStr
.append( rData
);
209 // append decimal -------------------------------------------------------------
211 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_uInt8 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
213 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
216 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_Int8 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
218 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
221 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_uInt16 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
223 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
226 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_Int16 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
228 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
231 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_uInt32 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
233 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
236 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_Int32 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
238 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
241 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_uInt64 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
243 /* Values greater than biggest signed 64bit integer will change to
244 negative when converting to sal_Int64. Therefore, the trailing digit
245 will be written separately. */
246 OUStringBuffer aBuffer
;
248 aBuffer
.append( OUString::number( nData
/ 10 ) );
249 aBuffer
.append( static_cast< sal_Unicode
>( '0' + (nData
% 10) ) );
250 appendString( rStr
, aBuffer
.makeStringAndClear(), nWidth
, cFill
);
253 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_Int64 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
255 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
258 void StringHelper::appendDec( OUStringBuffer
& rStr
, double fData
, sal_Int32 nWidth
, sal_Unicode cFill
)
260 appendString( rStr
, ::rtl::math::doubleToUString( fData
, rtl_math_StringFormat_G
, 15, '.', true ), nWidth
, cFill
);
263 // append hexadecimal ---------------------------------------------------------
265 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_uInt8 nData
, bool bPrefix
)
267 static const sal_Unicode spcHexDigits
[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
270 rStr
.append( spcHexDigits
[ (nData
>> 4) & 0x0F ] ).append( spcHexDigits
[ nData
& 0x0F ] );
273 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_Int8 nData
, bool bPrefix
)
275 appendHex( rStr
, static_cast< sal_uInt8
>( nData
), bPrefix
);
278 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_uInt16 nData
, bool bPrefix
)
280 appendHex( rStr
, static_cast< sal_uInt8
>( nData
>> 8 ), bPrefix
);
281 appendHex( rStr
, static_cast< sal_uInt8
>( nData
), false );
284 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_Int16 nData
, bool bPrefix
)
286 appendHex( rStr
, static_cast< sal_uInt16
>( nData
), bPrefix
);
289 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_uInt32 nData
, bool bPrefix
)
291 appendHex( rStr
, static_cast< sal_uInt16
>( nData
>> 16 ), bPrefix
);
292 appendHex( rStr
, static_cast< sal_uInt16
>( nData
), false );
295 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_Int32 nData
, bool bPrefix
)
297 appendHex( rStr
, static_cast< sal_uInt32
>( nData
), bPrefix
);
300 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_uInt64 nData
, bool bPrefix
)
302 appendHex( rStr
, static_cast< sal_uInt32
>( nData
>> 32 ), bPrefix
);
303 appendHex( rStr
, static_cast< sal_uInt32
>( nData
), false );
306 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_Int64 nData
, bool bPrefix
)
308 appendHex( rStr
, static_cast< sal_uInt64
>( nData
), bPrefix
);
312 lcl_ConvertDouble(double const f
)
314 sal_uInt64 i
= sal_uInt64();
315 for (size_t j
= 0; j
< sizeof(double); ++j
)
316 { // hopefully both endian independent and strict aliasing safe
317 reinterpret_cast<char *>(&i
)[j
] = reinterpret_cast<char const *>(&f
)[j
];
322 void StringHelper::appendHex( OUStringBuffer
& rStr
, double fData
, bool bPrefix
)
324 appendHex( rStr
, lcl_ConvertDouble(fData
), bPrefix
);
327 // append shortened hexadecimal -----------------------------------------------
329 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_uInt8 nData
, bool bPrefix
)
331 appendHex( rStr
, nData
, bPrefix
);
334 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_Int8 nData
, bool bPrefix
)
336 appendHex( rStr
, nData
, bPrefix
);
339 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_uInt16 nData
, bool bPrefix
)
341 if( nData
> SAL_MAX_UINT8
)
342 appendHex( rStr
, nData
, bPrefix
);
344 appendHex( rStr
, static_cast< sal_uInt8
>( nData
), bPrefix
);
347 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_Int16 nData
, bool bPrefix
)
349 appendShortHex( rStr
, static_cast< sal_uInt16
>( nData
), bPrefix
);
352 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_uInt32 nData
, bool bPrefix
)
354 if( nData
> SAL_MAX_UINT16
)
355 appendHex( rStr
, nData
, bPrefix
);
357 appendShortHex( rStr
, static_cast< sal_uInt16
>( nData
), bPrefix
);
360 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_Int32 nData
, bool bPrefix
)
362 appendShortHex( rStr
, static_cast< sal_uInt32
>( nData
), bPrefix
);
365 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_uInt64 nData
, bool bPrefix
)
367 if( nData
> SAL_MAX_UINT32
)
368 appendHex( rStr
, nData
, bPrefix
);
370 appendShortHex( rStr
, static_cast< sal_uInt32
>( nData
), bPrefix
);
373 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_Int64 nData
, bool bPrefix
)
375 appendShortHex( rStr
, static_cast< sal_uInt64
>( nData
), bPrefix
);
378 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, double fData
, bool bPrefix
)
380 appendHex( rStr
, fData
, bPrefix
);
383 // append binary --------------------------------------------------------------
385 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_uInt8 nData
, bool bDots
)
387 for( sal_uInt8 nMask
= 0x80; nMask
!= 0; (nMask
>>= 1) &= 0x7F )
389 rStr
.append( static_cast< sal_Unicode
>( (nData
& nMask
) ? '1' : '0' ) );
390 if( bDots
&& (nMask
== 0x10) )
391 rStr
.append( OOX_DUMP_BINDOT
);
395 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_Int8 nData
, bool bDots
)
397 appendBin( rStr
, static_cast< sal_uInt8
>( nData
), bDots
);
400 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_uInt16 nData
, bool bDots
)
402 appendBin( rStr
, static_cast< sal_uInt8
>( nData
>> 8 ), bDots
);
404 rStr
.append( OOX_DUMP_BINDOT
);
405 appendBin( rStr
, static_cast< sal_uInt8
>( nData
), bDots
);
408 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_Int16 nData
, bool bDots
)
410 appendBin( rStr
, static_cast< sal_uInt16
>( nData
), bDots
);
413 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_uInt32 nData
, bool bDots
)
415 appendBin( rStr
, static_cast< sal_uInt16
>( nData
>> 16 ), bDots
);
417 rStr
.append( OOX_DUMP_BINDOT
);
418 appendBin( rStr
, static_cast< sal_uInt16
>( nData
), bDots
);
421 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_Int32 nData
, bool bDots
)
423 appendBin( rStr
, static_cast< sal_uInt32
>( nData
), bDots
);
426 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_uInt64 nData
, bool bDots
)
428 appendBin( rStr
, static_cast< sal_uInt32
>( nData
>> 32 ), bDots
);
430 rStr
.append( OOX_DUMP_BINDOT
);
431 appendBin( rStr
, static_cast< sal_uInt32
>( nData
), bDots
);
434 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_Int64 nData
, bool bDots
)
436 appendBin( rStr
, static_cast< sal_uInt64
>( nData
), bDots
);
439 void StringHelper::appendBin( OUStringBuffer
& rStr
, double fData
, bool bDots
)
441 appendBin( rStr
, lcl_ConvertDouble(fData
), bDots
);
444 // append formatted value -----------------------------------------------------
446 void StringHelper::appendBool( OUStringBuffer
& rStr
, bool bData
)
448 rStr
.appendAscii( bData
? "true" : "false" );
451 // encoded text output --------------------------------------------------------
453 void StringHelper::appendCChar( OUStringBuffer
& rStr
, sal_Unicode cChar
, bool bPrefix
)
458 rStr
.append( "\\u" );
459 appendHex( rStr
, static_cast< sal_uInt16
>( cChar
), false );
464 rStr
.append( "\\x" );
465 appendHex( rStr
, static_cast< sal_uInt8
>( cChar
), false );
469 void StringHelper::appendEncChar( OUStringBuffer
& rStr
, sal_Unicode cChar
, sal_Int32 nCount
, bool bPrefix
)
474 OUStringBuffer aCode
;
475 appendCChar( aCode
, cChar
, bPrefix
);
476 OUString aCodeStr
= aCode
.makeStringAndClear();
477 for( sal_Int32 nIdx
= 0; nIdx
< nCount
; ++nIdx
)
478 rStr
.append( aCodeStr
);
482 appendChar( rStr
, cChar
, nCount
);
486 void StringHelper::appendEncString( OUStringBuffer
& rStr
, const OUString
& rData
, bool bPrefix
)
490 sal_Int32 nEnd
= rData
.getLength();
493 // find next character that needs encoding
494 while( (nIdx
< nEnd
) && (rData
[ nIdx
] >= 0x20) ) ++nIdx
;
498 if( (nBeg
== 0) && (nIdx
== nEnd
) )
499 rStr
.append( rData
);
501 rStr
.append( std::u16string_view(rData
).substr(nBeg
, nIdx
- nBeg
) );
503 // append characters to be encoded
504 while( (nIdx
< nEnd
) && (rData
[ nIdx
] < 0x20) )
506 appendCChar( rStr
, rData
[ nIdx
], bPrefix
);
514 // token list -----------------------------------------------------------------
516 void StringHelper::appendToken( OUStringBuffer
& rStr
, const OUString
& rToken
, sal_Unicode cSep
)
518 if( (rStr
.getLength() > 0) && (!rToken
.isEmpty()) )
520 rStr
.append( rToken
);
523 void StringHelper::appendIndex( OUStringBuffer
& rStr
, sal_Int64 nIdx
)
525 OUStringBuffer aToken
;
526 appendDec( aToken
, nIdx
);
527 rStr
.append( '[' ).append( aToken
.makeStringAndClear() ).append( ']' );
530 OUString
StringHelper::getToken( const OUString
& rData
, sal_Int32
& rnPos
, sal_Unicode cSep
)
532 return trimSpaces( rData
.getToken( 0, cSep
, rnPos
) );
535 void StringHelper::enclose( OUStringBuffer
& rStr
, sal_Unicode cOpen
, sal_Unicode cClose
)
537 rStr
.insert( 0, cOpen
).append( cClose
? cClose
: cOpen
);
540 // string conversion ----------------------------------------------------------
544 sal_Int32
lclIndexOf( const OUString
& rStr
, sal_Unicode cChar
, sal_Int32 nStartPos
)
546 sal_Int32 nIndex
= rStr
.indexOf( cChar
, nStartPos
);
547 return (nIndex
< 0) ? rStr
.getLength() : nIndex
;
550 OUString
lclTrimQuotedStringList( const OUString
& rStr
)
552 OUStringBuffer aBuffer
;
554 sal_Int32 nLen
= rStr
.getLength();
557 if( rStr
[ nPos
] == OOX_DUMP_CFG_QUOTE
)
559 // quoted string, skip leading quote character
561 // process quoted text and embedded literal quote characters
562 OUStringBuffer aToken
;
565 // seek to next quote character and add text portion to token buffer
566 sal_Int32 nEnd
= lclIndexOf( rStr
, OOX_DUMP_CFG_QUOTE
, nPos
);
567 aToken
.append( std::u16string_view(rStr
).substr(nPos
, nEnd
- nPos
) );
568 // process literal quotes
569 while( (nEnd
+ 1 < nLen
) && (rStr
[ nEnd
] == OOX_DUMP_CFG_QUOTE
) && (rStr
[ nEnd
+ 1 ] == OOX_DUMP_CFG_QUOTE
) )
571 aToken
.append( OOX_DUMP_CFG_QUOTE
);
574 // nEnd is start of possible next text portion
577 while( (nPos
< nLen
) && (rStr
[ nPos
] != OOX_DUMP_CFG_QUOTE
) );
578 // add token, seek to list separator, ignore text following closing quote
579 aBuffer
.append( aToken
.makeStringAndClear() );
580 nPos
= lclIndexOf( rStr
, OOX_DUMP_CFG_LISTSEP
, nPos
);
582 aBuffer
.append( OOX_DUMP_LF
);
583 // set current position behind list separator
588 // find list separator, add token text to buffer
589 sal_Int32 nEnd
= lclIndexOf( rStr
, OOX_DUMP_CFG_LISTSEP
, nPos
);
590 aBuffer
.append( std::u16string_view(rStr
).substr(nPos
, nEnd
- nPos
) );
592 aBuffer
.append( OOX_DUMP_LF
);
593 // set current position behind list separator
598 return aBuffer
.makeStringAndClear();
603 OUString
StringHelper::trimSpaces( const OUString
& rStr
)
606 while( (nBeg
< rStr
.getLength()) && ((rStr
[ nBeg
] == ' ') || (rStr
[ nBeg
] == '\t')) )
608 sal_Int32 nEnd
= rStr
.getLength();
609 while( (nEnd
> nBeg
) && ((rStr
[ nEnd
- 1 ] == ' ') || (rStr
[ nEnd
- 1 ] == '\t')) )
611 return rStr
.copy( nBeg
, nEnd
- nBeg
);
614 OUString
StringHelper::trimTrailingNul( const OUString
& rStr
)
616 sal_Int32 nLastPos
= rStr
.getLength() - 1;
617 if( (nLastPos
>= 0) && (rStr
[ nLastPos
] == 0) )
618 return rStr
.copy( 0, nLastPos
);
622 OString
StringHelper::convertToUtf8( const OUString
& rStr
)
624 return OUStringToOString( rStr
, RTL_TEXTENCODING_UTF8
);
627 DataType
StringHelper::convertToDataType( const OUString
& rStr
)
629 DataType eType
= DATATYPE_VOID
;
630 if ( rStr
== "int8" )
631 eType
= DATATYPE_INT8
;
632 else if ( rStr
== "uint8" )
633 eType
= DATATYPE_UINT8
;
634 else if ( rStr
== "int16" )
635 eType
= DATATYPE_INT16
;
636 else if ( rStr
== "uint16" )
637 eType
= DATATYPE_UINT16
;
638 else if ( rStr
== "int32" )
639 eType
= DATATYPE_INT32
;
640 else if ( rStr
== "uint32" )
641 eType
= DATATYPE_UINT32
;
642 else if ( rStr
== "int64" )
643 eType
= DATATYPE_INT64
;
644 else if ( rStr
== "uint64" )
645 eType
= DATATYPE_UINT64
;
646 else if ( rStr
== "float" )
647 eType
= DATATYPE_FLOAT
;
648 else if ( rStr
== "double" )
649 eType
= DATATYPE_DOUBLE
;
653 FormatType
StringHelper::convertToFormatType( const OUString
& rStr
)
655 FormatType eType
= FORMATTYPE_NONE
;
657 eType
= FORMATTYPE_DEC
;
658 else if ( rStr
== "hex" )
659 eType
= FORMATTYPE_HEX
;
660 else if ( rStr
== "shorthex" )
661 eType
= FORMATTYPE_SHORTHEX
;
662 else if ( rStr
== "bin" )
663 eType
= FORMATTYPE_BIN
;
664 else if ( rStr
== "fix" )
665 eType
= FORMATTYPE_FIX
;
666 else if ( rStr
== "bool" )
667 eType
= FORMATTYPE_BOOL
;
671 bool StringHelper::convertFromDec( sal_Int64
& ornData
, const OUString
& rData
)
674 sal_Int32 nLen
= rData
.getLength();
676 if( (nLen
> 0) && (rData
[ 0 ] == '-') )
682 for( ; nPos
< nLen
; ++nPos
)
684 sal_Unicode cChar
= rData
[ nPos
];
685 if( (cChar
< '0') || (cChar
> '9') )
687 ornData
= (ornData
* 10) + (cChar
- '0');
694 bool StringHelper::convertFromHex( sal_Int64
& ornData
, const OUString
& rData
)
697 for( sal_Int32 nPos
= 0, nLen
= rData
.getLength(); nPos
< nLen
; ++nPos
)
699 sal_Unicode cChar
= rData
[ nPos
];
700 if( ('0' <= cChar
) && (cChar
<= '9') )
702 else if( ('A' <= cChar
) && (cChar
<= 'F') )
704 else if( ('a' <= cChar
) && (cChar
<= 'f') )
708 ornData
= (ornData
<< 4) + cChar
;
713 bool StringHelper::convertStringToInt( sal_Int64
& ornData
, const OUString
& rData
)
715 if( (rData
.getLength() > 2) && (rData
[ 0 ] == '0') && ((rData
[ 1 ] == 'X') || (rData
[ 1 ] == 'x')) )
716 return convertFromHex( ornData
, rData
.copy( 2 ) );
717 return convertFromDec( ornData
, rData
);
720 bool StringHelper::convertStringToDouble( double& orfData
, const OUString
& rData
)
722 rtl_math_ConversionStatus eStatus
= rtl_math_ConversionStatus_Ok
;
724 orfData
= rtl::math::stringToDouble( rData
, '.', '\0', &eStatus
, &nSize
);
725 return (eStatus
== rtl_math_ConversionStatus_Ok
) && (nSize
== rData
.getLength());
728 bool StringHelper::convertStringToBool( const OUString
& rData
)
730 if ( rData
== "true" )
732 if ( rData
== "false" )
735 return convertStringToInt( nData
, rData
) && (nData
!= 0);
738 OUStringPair
StringHelper::convertStringToPair( const OUString
& rString
, sal_Unicode cSep
)
741 if( !rString
.isEmpty() )
743 sal_Int32 nEqPos
= rString
.indexOf( cSep
);
746 aPair
.first
= rString
;
750 aPair
.first
= StringHelper::trimSpaces( rString
.copy( 0, nEqPos
) );
751 aPair
.second
= StringHelper::trimSpaces( rString
.copy( nEqPos
+ 1 ) );
757 void StringHelper::convertStringToStringList( OUStringVector
& orVec
, const OUString
& rData
, bool bIgnoreEmpty
)
760 OUString aUnquotedData
= lclTrimQuotedStringList( rData
);
762 sal_Int32 nLen
= aUnquotedData
.getLength();
763 while( (0 <= nPos
) && (nPos
< nLen
) )
765 OUString aToken
= getToken( aUnquotedData
, nPos
, OOX_DUMP_LF
);
766 if( !bIgnoreEmpty
|| !aToken
.isEmpty() )
767 orVec
.push_back( aToken
);
771 void StringHelper::convertStringToIntList( Int64Vector
& orVec
, const OUString
& rData
, bool bIgnoreEmpty
)
774 OUString aUnquotedData
= lclTrimQuotedStringList( rData
);
776 sal_Int32 nLen
= aUnquotedData
.getLength();
778 while( (0 <= nPos
) && (nPos
< nLen
) )
780 bool bOk
= convertStringToInt( nData
, getToken( aUnquotedData
, nPos
, OOX_DUMP_LF
) );
781 if( !bIgnoreEmpty
|| bOk
)
782 orVec
.push_back( bOk
? nData
: 0 );
790 ConfigItemBase::~ConfigItemBase()
794 void ConfigItemBase::readConfigBlock( TextInputStream
& rStrm
)
796 readConfigBlockContents( rStrm
);
799 void ConfigItemBase::implProcessConfigItemStr(
800 TextInputStream
& /*rStrm*/, const OUString
& /*rKey*/, const OUString
& /*rData*/ )
804 void ConfigItemBase::implProcessConfigItemInt(
805 TextInputStream
& /*rStrm*/, sal_Int64
/*nKey*/, const OUString
& /*rData*/ )
809 void ConfigItemBase::readConfigBlockContents( TextInputStream
& rStrm
)
812 while( bLoop
&& !rStrm
.isEof() )
814 OUString aKey
, aData
;
815 switch( readConfigLine( rStrm
, aKey
, aData
) )
818 processConfigItem( rStrm
, aKey
, aData
);
827 ConfigItemBase::LineType
ConfigItemBase::readConfigLine(
828 TextInputStream
& rStrm
, OUString
& orKey
, OUString
& orData
)
831 while( !rStrm
.isEof() && aLine
.isEmpty() )
833 aLine
= rStrm
.readLine();
834 if( !aLine
.isEmpty() && (aLine
[ 0 ] == OOX_DUMP_BOM
) )
835 aLine
= aLine
.copy( 1 );
836 aLine
= StringHelper::trimSpaces( aLine
);
837 if( !aLine
.isEmpty() )
839 // ignore comments (starting with hash or semicolon)
840 sal_Unicode cChar
= aLine
[ 0 ];
841 if( (cChar
== '#') || (cChar
== ';') )
846 OUStringPair aPair
= StringHelper::convertStringToPair( aLine
);
848 orData
= aPair
.second
;
849 return ( !orKey
.isEmpty() && (!orData
.isEmpty() || orKey
!= "end" )) ?
850 LINETYPE_DATA
: LINETYPE_END
;
853 void ConfigItemBase::processConfigItem(
854 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
857 if( StringHelper::convertStringToInt( nKey
, rKey
) )
858 implProcessConfigItemInt( rStrm
, nKey
, rData
);
860 implProcessConfigItemStr( rStrm
, rKey
, rData
);
863 NameListBase::~NameListBase()
867 void NameListBase::setName( sal_Int64 nKey
, const String
& rName
)
869 implSetName( nKey
, rName
);
872 void NameListBase::includeList( const NameListRef
& rxList
)
876 for (auto const& elem
: *rxList
)
877 maMap
[ elem
.first
] = elem
.second
;
878 implIncludeList( *rxList
);
882 bool NameListBase::implIsValid() const
887 void NameListBase::implProcessConfigItemStr(
888 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
890 if ( rKey
== "include" )
892 else if ( rKey
== "exclude" )
895 ConfigItemBase::implProcessConfigItemStr( rStrm
, rKey
, rData
);
898 void NameListBase::implProcessConfigItemInt(
899 TextInputStream
& /*rStrm*/, sal_Int64 nKey
, const OUString
& rData
)
901 implSetName( nKey
, rData
);
904 void NameListBase::insertRawName( sal_Int64 nKey
, const OUString
& rName
)
906 maMap
[ nKey
] = rName
;
909 const OUString
* NameListBase::findRawName( sal_Int64 nKey
) const
911 const_iterator aIt
= maMap
.find( nKey
);
912 return (aIt
== end()) ? nullptr : &aIt
->second
;
915 void NameListBase::include( const OUString
& rListKeys
)
918 StringHelper::convertStringToStringList( aVec
, rListKeys
, true );
919 for (auto const& elem
: aVec
)
920 includeList( mrCfgData
.getNameList(elem
) );
923 void NameListBase::exclude( const OUString
& rKeys
)
926 StringHelper::convertStringToIntList( aVec
, rKeys
, true );
927 for (auto const& elem
: aVec
)
931 void ItemFormatMap::insertFormats( const NameListRef
& rxNameList
)
933 if( Base::isValid( rxNameList
) )
935 for (auto const& elemName
: *rxNameList
)
936 maMap
[ elemName
.first
].parse( elemName
.second
);
940 ConstList::ConstList( const SharedConfigData
& rCfgData
) :
941 NameListBase( rCfgData
),
942 maDefName( OOX_DUMP_ERR_NONAME
),
943 mbQuoteNames( false )
947 void ConstList::implProcessConfigItemStr(
948 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
950 if ( rKey
== "default" )
951 maDefName
= rData
; // Sets a default name for unknown keys.
952 else if ( rKey
== "quote-names" )
953 setQuoteNames( StringHelper::convertStringToBool( rData
) );
955 NameListBase::implProcessConfigItemStr( rStrm
, rKey
, rData
);
958 void ConstList::implSetName( sal_Int64 nKey
, const OUString
& rName
)
960 insertRawName( nKey
, rName
);
963 OUString
ConstList::implGetName( const Config
& /*rCfg*/, sal_Int64 nKey
) const
965 const OUString
* pName
= findRawName( nKey
);
966 OUString aName
= pName
? *pName
: maDefName
;
969 OUStringBuffer
aBuffer( aName
);
970 StringHelper::enclose( aBuffer
, OOX_DUMP_STRQUOTE
);
971 aName
= aBuffer
.makeStringAndClear();
976 OUString
ConstList::implGetNameDbl( const Config
& /*rCfg*/, double /*fValue*/ ) const
981 void ConstList::implIncludeList( const NameListBase
& rList
)
983 if( const ConstList
* pConstList
= dynamic_cast< const ConstList
* >( &rList
) )
985 maDefName
= pConstList
->maDefName
;
986 mbQuoteNames
= pConstList
->mbQuoteNames
;
990 MultiList::MultiList( const SharedConfigData
& rCfgData
) :
991 ConstList( rCfgData
),
992 mbIgnoreEmpty( true )
996 void MultiList::setNamesFromVec( sal_Int64 nStartKey
, const OUStringVector
& rNames
)
998 sal_Int64 nKey
= nStartKey
;
999 for (auto const& name
: rNames
)
1001 if( !mbIgnoreEmpty
|| !name
.isEmpty() )
1002 insertRawName( nKey
, name
);
1007 void MultiList::implProcessConfigItemStr(
1008 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
1010 if ( rKey
== "ignore-empty" )
1011 mbIgnoreEmpty
= StringHelper::convertStringToBool( rData
);
1013 ConstList::implProcessConfigItemStr( rStrm
, rKey
, rData
);
1016 void MultiList::implSetName( sal_Int64 nKey
, const OUString
& rName
)
1018 OUStringVector aNames
;
1019 StringHelper::convertStringToStringList( aNames
, rName
, false );
1020 setNamesFromVec( nKey
, aNames
);
1023 FlagsList::FlagsList( const SharedConfigData
& rCfgData
) :
1024 NameListBase( rCfgData
),
1029 void FlagsList::implProcessConfigItemStr(
1030 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
1032 if ( rKey
== "ignore" )
1035 if( StringHelper::convertStringToInt( nIgnore
, rData
) )
1036 setIgnoreFlags( nIgnore
);
1040 NameListBase::implProcessConfigItemStr( rStrm
, rKey
, rData
);
1044 void FlagsList::implSetName( sal_Int64 nKey
, const OUString
& rName
)
1046 if( (nKey
!= 0) && ((nKey
& (nKey
- 1)) == 0) ) // only a single bit set?
1047 insertRawName( nKey
, rName
);
1050 OUString
FlagsList::implGetName( const Config
& /*rCfg*/, sal_Int64 nKey
) const
1052 sal_Int64 nFound
= mnIgnore
;
1053 OUStringBuffer aName
;
1055 for( const_iterator aIt
= begin(), aEnd
= end(); aIt
!= aEnd
; ++aIt
)
1057 sal_Int64 nMask
= aIt
->first
;
1058 setFlag( nFound
, nMask
);
1059 if( !getFlag( mnIgnore
, nMask
) )
1061 const OUString
& rFlagName
= aIt
->second
;
1062 bool bOnOff
= rFlagName
.startsWith(":");
1063 bool bFlag
= getFlag( nKey
, nMask
);
1066 StringHelper::appendToken( aName
, rFlagName
.copy( 1 ) );
1067 aName
.appendAscii( bFlag
? ":on" : ":off" );
1071 bool bNegated
= rFlagName
.startsWith("!");
1072 sal_Int32 nBothSep
= bNegated
? rFlagName
.indexOf( '!', 1 ) : -1;
1076 StringHelper::appendToken( aName
, rFlagName
);
1077 else if( nBothSep
> 0 )
1078 StringHelper::appendToken( aName
, rFlagName
.copy( nBothSep
+ 1 ) );
1083 StringHelper::appendToken( aName
, rFlagName
.copy( 1, nBothSep
- 1 ) );
1085 StringHelper::appendToken( aName
, rFlagName
.copy( 1 ) );
1090 // add unknown flags
1091 setFlag( nKey
, nFound
, false );
1094 OUStringBuffer
aUnknown( OOX_DUMP_UNKNOWN
);
1095 aUnknown
.append( OOX_DUMP_ITEMSEP
);
1096 StringHelper::appendShortHex( aUnknown
, nKey
);
1097 StringHelper::enclose( aUnknown
, '(', ')' );
1098 StringHelper::appendToken( aName
, aUnknown
.makeStringAndClear() );
1100 return aName
.makeStringAndClear();
1103 OUString
FlagsList::implGetNameDbl( const Config
& /*rCfg*/, double /*fValue*/ ) const
1108 void FlagsList::implIncludeList( const NameListBase
& rList
)
1110 if( const FlagsList
* pFlagsList
= dynamic_cast< const FlagsList
* >( &rList
) )
1111 mnIgnore
= pFlagsList
->mnIgnore
;
1114 bool CombiList::ExtItemFormatKey::operator<( const ExtItemFormatKey
& rRight
) const
1116 return (mnKey
< rRight
.mnKey
) || ((mnKey
== rRight
.mnKey
) && (maFilter
< rRight
.maFilter
));
1119 CombiList::CombiList( const SharedConfigData
& rCfgData
) :
1120 FlagsList( rCfgData
)
1124 void CombiList::implSetName( sal_Int64 nKey
, const OUString
& rName
)
1126 if( (nKey
& (nKey
- 1)) != 0 ) // more than a single bit set?
1128 ::std::set
< ExtItemFormatKey
> aItemKeys
;
1129 ExtItemFormat aItemFmt
;
1130 OUStringVector aRemain
= aItemFmt
.parse( rName
);
1131 for (auto const& elemRemain
: aRemain
)
1133 OUStringPair aPair
= StringHelper::convertStringToPair(elemRemain
);
1134 if ( aPair
.first
== "noshift" )
1136 aItemFmt
.mbShiftValue
= StringHelper::convertStringToBool( aPair
.second
);
1138 else if ( aPair
.first
== "filter" )
1140 OUStringPair aFilter
= StringHelper::convertStringToPair( aPair
.second
, '~' );
1141 ExtItemFormatKey
aKey( nKey
);
1142 if( !aFilter
.first
.isEmpty() && StringHelper::convertStringToInt( aKey
.maFilter
.first
, aFilter
.first
) &&
1143 !aFilter
.second
.isEmpty() && StringHelper::convertStringToInt( aKey
.maFilter
.second
, aFilter
.second
) )
1145 if( aKey
.maFilter
.first
== 0 )
1146 aKey
.maFilter
.second
= 0;
1147 aItemKeys
.insert( aKey
);
1151 if( aItemKeys
.empty() )
1152 aItemKeys
.insert( ExtItemFormatKey( nKey
) );
1153 for (auto const& itemKey
: aItemKeys
)
1154 maFmtMap
[itemKey
] = aItemFmt
;
1158 FlagsList::implSetName( nKey
, rName
);
1162 OUString
CombiList::implGetName( const Config
& rCfg
, sal_Int64 nKey
) const
1164 sal_Int64 nFound
= 0;
1165 OUStringBuffer aName
;
1166 // add known flag fields
1167 for (auto const& fmt
: maFmtMap
)
1169 const ExtItemFormatKey
& rMapKey
= fmt
.first
;
1170 sal_Int64 nMask
= rMapKey
.mnKey
;
1171 if( (nMask
!= 0) && ((nKey
& rMapKey
.maFilter
.first
) == rMapKey
.maFilter
.second
) )
1173 const ExtItemFormat
& rItemFmt
= fmt
.second
;
1175 sal_uInt64 nUFlags
= static_cast< sal_uInt64
>( nKey
);
1176 sal_uInt64 nUMask
= static_cast< sal_uInt64
>( nMask
);
1177 if( rItemFmt
.mbShiftValue
)
1178 while( (nUMask
& 1) == 0 ) { nUFlags
>>= 1; nUMask
>>= 1; }
1180 sal_uInt64 nUValue
= nUFlags
& nUMask
;
1181 sal_Int64 nSValue
= static_cast< sal_Int64
>( nUValue
);
1182 if( getFlag
< sal_uInt64
>( nUValue
, (nUMask
+ 1) >> 1 ) )
1183 setFlag( nSValue
, static_cast< sal_Int64
>( ~nUMask
) );
1185 OUStringBuffer
aItem( rItemFmt
.maItemName
);
1186 OUStringBuffer aValue
;
1187 switch( rItemFmt
.meDataType
)
1189 case DATATYPE_INT8
: StringHelper::appendValue( aValue
, static_cast< sal_Int8
>( nSValue
), rItemFmt
.meFmtType
); break;
1190 case DATATYPE_UINT8
: StringHelper::appendValue( aValue
, static_cast< sal_uInt8
>( nUValue
), rItemFmt
.meFmtType
); break;
1191 case DATATYPE_INT16
: StringHelper::appendValue( aValue
, static_cast< sal_Int16
>( nSValue
), rItemFmt
.meFmtType
); break;
1192 case DATATYPE_UINT16
: StringHelper::appendValue( aValue
, static_cast< sal_uInt16
>( nUValue
), rItemFmt
.meFmtType
); break;
1193 case DATATYPE_INT32
: StringHelper::appendValue( aValue
, static_cast< sal_Int32
>( nSValue
), rItemFmt
.meFmtType
); break;
1194 case DATATYPE_UINT32
: StringHelper::appendValue( aValue
, static_cast< sal_uInt32
>( nUValue
), rItemFmt
.meFmtType
); break;
1195 case DATATYPE_INT64
: StringHelper::appendValue( aValue
, nSValue
, rItemFmt
.meFmtType
); break;
1196 case DATATYPE_UINT64
: StringHelper::appendValue( aValue
, nUValue
, rItemFmt
.meFmtType
); break;
1197 case DATATYPE_FLOAT
: StringHelper::appendValue( aValue
, static_cast< float >( nSValue
), rItemFmt
.meFmtType
); break;
1198 case DATATYPE_DOUBLE
: StringHelper::appendValue( aValue
, static_cast< double >( nSValue
), rItemFmt
.meFmtType
); break;
1201 StringHelper::appendToken( aItem
, aValue
.makeStringAndClear(), OOX_DUMP_ITEMSEP
);
1202 if( !rItemFmt
.maListName
.isEmpty() )
1204 OUString aValueName
= rCfg
.getName( rItemFmt
.maListName
, static_cast< sal_Int64
>( nUValue
) );
1205 StringHelper::appendToken( aItem
, aValueName
, OOX_DUMP_ITEMSEP
);
1207 StringHelper::enclose( aItem
, '(', ')' );
1208 StringHelper::appendToken( aName
, aItem
.makeStringAndClear() );
1209 setFlag( nFound
, nMask
);
1212 setFlag( nKey
, nFound
, false );
1213 StringHelper::appendToken( aName
, FlagsList::implGetName( rCfg
, nKey
) );
1214 return aName
.makeStringAndClear();
1217 void CombiList::implIncludeList( const NameListBase
& rList
)
1219 if( const CombiList
* pCombiList
= dynamic_cast< const CombiList
* >( &rList
) )
1220 maFmtMap
= pCombiList
->maFmtMap
;
1221 FlagsList::implIncludeList( rList
);
1224 UnitConverter::UnitConverter( const SharedConfigData
& rCfgData
) :
1225 NameListBase( rCfgData
),
1230 void UnitConverter::implSetName( sal_Int64
/*nKey*/, const OUString
& /*rName*/ )
1235 OUString
UnitConverter::implGetName( const Config
& rCfg
, sal_Int64 nKey
) const
1237 return implGetNameDbl( rCfg
, static_cast< double >( nKey
) );
1240 OUString
UnitConverter::implGetNameDbl( const Config
& /*rCfg*/, double fValue
) const
1242 OUStringBuffer aValue
;
1243 StringHelper::appendDec( aValue
, mfFactor
* fValue
);
1244 aValue
.append( maUnitName
);
1245 return aValue
.makeStringAndClear();
1248 void UnitConverter::implIncludeList( const NameListBase
& /*rList*/ )
1252 NameListRef
NameListWrapper::getNameList( const Config
& rCfg
) const
1254 return mxList
.get() ? mxList
: (mxList
= rCfg
.getNameList( maName
));
1257 SharedConfigData::SharedConfigData( const OUString
& rFileName
,
1258 const Reference
< XComponentContext
>& rxContext
, const StorageRef
& rxRootStrg
,
1259 const OUString
& rSysFileName
) :
1260 mxContext( rxContext
),
1261 mxRootStrg( rxRootStrg
),
1262 maSysFileName( rSysFileName
),
1265 OUString aFileUrl
= InputOutputHelper::convertFileNameToUrl( rFileName
);
1266 if( !aFileUrl
.isEmpty() )
1268 sal_Int32 nNamePos
= InputOutputHelper::getFileNamePos( aFileUrl
);
1269 maConfigPath
= aFileUrl
.copy( 0, nNamePos
);
1270 mbLoaded
= readConfigFile( aFileUrl
);
1274 SharedConfigData::~SharedConfigData()
1278 const OUString
* SharedConfigData::getOption( const OUString
& rKey
) const
1280 ConfigDataMap::const_iterator aIt
= maConfigData
.find( rKey
);
1281 return (aIt
== maConfigData
.end()) ? nullptr : &aIt
->second
;
1284 void SharedConfigData::setNameList( const OUString
& rListName
, const NameListRef
& rxList
)
1286 if( !rListName
.isEmpty() )
1287 maNameLists
[ rListName
] = rxList
;
1290 void SharedConfigData::eraseNameList( const OUString
& rListName
)
1292 maNameLists
.erase( rListName
);
1295 NameListRef
SharedConfigData::getNameList( const OUString
& rListName
) const
1298 NameListMap::const_iterator aIt
= maNameLists
.find( rListName
);
1299 if( aIt
!= maNameLists
.end() )
1300 xList
= aIt
->second
;
1304 bool SharedConfigData::implIsValid() const
1306 return mbLoaded
&& mxContext
.is() && mxRootStrg
.get() && !maSysFileName
.isEmpty();
1309 void SharedConfigData::implProcessConfigItemStr(
1310 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
1312 if ( rKey
== "include-config-file" )
1313 readConfigFile( maConfigPath
+ rData
);
1314 else if ( rKey
== "constlist" )
1315 readNameList
< ConstList
>( rStrm
, rData
);
1316 else if ( rKey
== "multilist" )
1317 readNameList
< MultiList
>( rStrm
, rData
);
1318 else if ( rKey
== "flagslist" )
1319 readNameList
< FlagsList
>( rStrm
, rData
);
1320 else if ( rKey
== "combilist" )
1321 readNameList
< CombiList
>( rStrm
, rData
);
1322 else if ( rKey
== "shortlist" )
1323 createShortList( rData
);
1324 else if ( rKey
== "unitconverter" )
1325 createUnitConverter( rData
);
1327 maConfigData
[ rKey
] = rData
;
1330 bool SharedConfigData::readConfigFile( const OUString
& rFileUrl
)
1332 bool bLoaded
= maConfigFiles
.count( rFileUrl
) > 0;
1335 Reference
< XInputStream
> xInStrm
= InputOutputHelper::openInputStream( mxContext
, rFileUrl
);
1336 TextInputStream
aTxtStrm( mxContext
, xInStrm
, RTL_TEXTENCODING_UTF8
);
1337 if( !aTxtStrm
.isEof() )
1339 maConfigFiles
.insert( rFileUrl
);
1340 readConfigBlockContents( aTxtStrm
);
1347 void SharedConfigData::createShortList( const OUString
& rData
)
1349 OUStringVector aDataVec
;
1350 StringHelper::convertStringToStringList( aDataVec
, rData
, false );
1351 if( aDataVec
.size() >= 3 )
1353 sal_Int64 nStartKey
;
1354 if( StringHelper::convertStringToInt( nStartKey
, aDataVec
[ 1 ] ) )
1356 std::shared_ptr
< MultiList
> xList
= createNameList
< MultiList
>( aDataVec
[ 0 ] );
1359 aDataVec
.erase( aDataVec
.begin(), aDataVec
.begin() + 2 );
1360 xList
->setNamesFromVec( nStartKey
, aDataVec
);
1366 void SharedConfigData::createUnitConverter( const OUString
& rData
)
1368 OUStringVector aDataVec
;
1369 StringHelper::convertStringToStringList( aDataVec
, rData
, false );
1370 if( aDataVec
.size() >= 2 )
1372 OUString aFactor
= aDataVec
[ 1 ];
1373 bool bRecip
= aFactor
.startsWith("/");
1375 aFactor
= aFactor
.copy( 1 );
1377 if( StringHelper::convertStringToDouble( fFactor
, aFactor
) && (fFactor
!= 0.0) )
1379 std::shared_ptr
< UnitConverter
> xList
= createNameList
< UnitConverter
>( aDataVec
[ 0 ] );
1382 xList
->setFactor( bRecip
? (1.0 / fFactor
) : fFactor
);
1383 if( aDataVec
.size() >= 3 )
1384 xList
->setUnitName( aDataVec
[ 2 ] );
1390 Config::Config( const sal_Char
* pcEnvVar
, const FilterBase
& rFilter
)
1392 construct( pcEnvVar
, rFilter
);
1395 Config::Config( const sal_Char
* pcEnvVar
, const Reference
< XComponentContext
>& rxContext
, const StorageRef
& rxRootStrg
, const OUString
& rSysFileName
)
1397 construct( pcEnvVar
, rxContext
, rxRootStrg
, rSysFileName
);
1404 void Config::construct( const sal_Char
* pcEnvVar
, const FilterBase
& rFilter
)
1406 if( !rFilter
.getFileUrl().isEmpty() )
1407 construct( pcEnvVar
, rFilter
.getComponentContext(), rFilter
.getStorage(), rFilter
.getFileUrl() );
1410 void Config::construct( const sal_Char
* pcEnvVar
, const Reference
< XComponentContext
>& rxContext
, const StorageRef
& rxRootStrg
, const OUString
& rSysFileName
)
1412 if( pcEnvVar
&& rxRootStrg
.get() && !rSysFileName
.isEmpty() )
1413 if( const sal_Char
* pcFileName
= ::getenv( pcEnvVar
) )
1414 mxCfgData
.reset( new SharedConfigData( OUString::createFromAscii( pcFileName
), rxContext
, rxRootStrg
, rSysFileName
) );
1417 const OUString
& Config::getStringOption( const String
& rKey
, const OUString
& rDefault
) const
1419 const OUString
* pData
= implGetOption( rKey
);
1420 return pData
? *pData
: rDefault
;
1423 bool Config::getBoolOption( const String
& rKey
, bool bDefault
) const
1425 const OUString
* pData
= implGetOption( rKey
);
1426 return pData
? StringHelper::convertStringToBool( *pData
) : bDefault
;
1429 bool Config::isDumperEnabled() const
1431 return getBoolOption( "enable-dumper", false );
1434 bool Config::isImportEnabled() const
1436 return getBoolOption( "enable-import", true );
1439 void Config::eraseNameList( const String
& rListName
)
1441 mxCfgData
->eraseNameList( rListName
);
1444 NameListRef
Config::getNameList( const String
& rListName
) const
1446 return mxCfgData
->getNameList( rListName
);
1449 bool Config::implIsValid() const
1451 return isValid( mxCfgData
);
1454 const OUString
* Config::implGetOption( const OUString
& rKey
) const
1456 return mxCfgData
->getOption( rKey
);
1459 Output::Output( const Reference
< XComponentContext
>& rxContext
, const OUString
& rFileName
) :
1460 mxStrm( InputOutputHelper::openTextOutputStream( rxContext
, rFileName
, RTL_TEXTENCODING_UTF8
) ),
1468 mxStrm
->writeString( OUString( OOX_DUMP_BOM
) );
1471 void Output::newLine()
1473 if( maLine
.getLength() > 0 )
1475 mxStrm
->writeString( maIndent
);
1476 maLine
.append( '\n' );
1477 mxStrm
->writeString( maLine
.makeStringAndClear() );
1483 void Output::emptyLine( size_t nCount
)
1485 for( size_t nIdx
= 0; nIdx
< nCount
; ++nIdx
)
1486 mxStrm
->writeString( OUString('\n') );
1489 void Output::incIndent()
1491 OUStringBuffer
aBuffer( maIndent
);
1492 StringHelper::appendChar( aBuffer
, ' ', OOX_DUMP_INDENT
);
1493 maIndent
= aBuffer
.makeStringAndClear();
1496 void Output::decIndent()
1498 if( maIndent
.getLength() >= OOX_DUMP_INDENT
)
1499 maIndent
= maIndent
.copy( OOX_DUMP_INDENT
);
1502 void Output::startTable( sal_Int32 nW1
)
1504 startTable( 1, &nW1
);
1507 void Output::startTable( sal_Int32 nW1
, sal_Int32 nW2
)
1509 sal_Int32 pnColWidths
[ 2 ];
1510 pnColWidths
[ 0 ] = nW1
;
1511 pnColWidths
[ 1 ] = nW2
;
1512 startTable( 2, pnColWidths
);
1515 void Output::startTable( sal_Int32 nW1
, sal_Int32 nW2
, sal_Int32 nW3
, sal_Int32 nW4
)
1517 sal_Int32 pnColWidths
[ 4 ];
1518 pnColWidths
[ 0 ] = nW1
;
1519 pnColWidths
[ 1 ] = nW2
;
1520 pnColWidths
[ 2 ] = nW3
;
1521 pnColWidths
[ 3 ] = nW4
;
1522 startTable( 4, pnColWidths
);
1525 void Output::startTable( size_t nColCount
, const sal_Int32
* pnColWidths
)
1528 maColPos
.push_back( 0 );
1529 sal_Int32 nColPos
= 0;
1530 for( size_t nCol
= 0; nCol
< nColCount
; ++nCol
)
1532 nColPos
= nColPos
+ pnColWidths
[ nCol
];
1533 maColPos
.push_back( nColPos
);
1542 void Output::tab( size_t nCol
)
1545 if( mnCol
< maColPos
.size() )
1547 sal_Int32 nColPos
= maColPos
[ mnCol
];
1548 if( maLine
.getLength() >= nColPos
)
1549 maLine
.setLength( ::std::max
< sal_Int32
>( nColPos
- 1, 0 ) );
1550 StringHelper::appendChar( maLine
, ' ', nColPos
- maLine
.getLength() );
1554 StringHelper::appendChar( maLine
, ' ', 2 );
1558 void Output::endTable()
1563 void Output::resetItemIndex( sal_Int64 nIdx
)
1568 void Output::startItem( const String
& rItemName
)
1570 if( mnItemLevel
== 0 )
1572 if( (mnMultiLevel
> 0) && (maLine
.getLength() > 0) )
1574 if( rItemName
.has() )
1576 writeItemName( rItemName
);
1577 writeChar( OOX_DUMP_ITEMSEP
);
1581 mnLastItem
= maLine
.getLength();
1584 void Output::contItem()
1586 if( mnItemLevel
> 0 )
1588 if( (maLine
.getLength() == 0) || (maLine
[ maLine
.getLength() - 1 ] != OOX_DUMP_ITEMSEP
) )
1589 writeChar( OOX_DUMP_ITEMSEP
);
1590 mnLastItem
= maLine
.getLength();
1594 void Output::endItem()
1596 if( mnItemLevel
> 0 )
1598 maLastItem
= OUString( maLine
.getStr() + mnLastItem
);
1599 if( maLastItem
.isEmpty() && mnLastItem
> 0 && maLine
[ mnLastItem
- 1 ] == OOX_DUMP_ITEMSEP
)
1600 maLine
.setLength( mnLastItem
- 1 );
1603 if( mnItemLevel
== 0 )
1605 if( mnMultiLevel
== 0 )
1612 void Output::startMultiItems()
1617 void Output::endMultiItems()
1619 if( mnMultiLevel
> 0 )
1621 if( mnMultiLevel
== 0 )
1625 void Output::writeChar( sal_Unicode cChar
, sal_Int32 nCount
)
1627 StringHelper::appendEncChar( maLine
, cChar
, nCount
);
1630 void Output::writeAscii( const sal_Char
* pcStr
)
1633 maLine
.appendAscii( pcStr
);
1636 void Output::writeString( const OUString
& rStr
)
1638 StringHelper::appendEncString( maLine
, rStr
);
1641 void Output::writeArray( const sal_uInt8
* pnData
, std::size_t nSize
, sal_Unicode cSep
)
1643 const sal_uInt8
* pnEnd
= pnData
? (pnData
+ nSize
) : nullptr;
1644 for( const sal_uInt8
* pnByte
= pnData
; pnByte
< pnEnd
; ++pnByte
)
1646 if( pnByte
> pnData
)
1648 writeHex( *pnByte
, false );
1652 void Output::writeBool( bool bData
)
1654 StringHelper::appendBool( maLine
, bData
);
1657 void Output::writeDateTime( const util::DateTime
& rDateTime
)
1659 writeDec( rDateTime
.Year
, 4, '0' );
1661 writeDec( rDateTime
.Month
, 2, '0' );
1663 writeDec( rDateTime
.Day
, 2, '0' );
1665 writeDec( rDateTime
.Hours
, 2, '0' );
1667 writeDec( rDateTime
.Minutes
, 2, '0' );
1669 writeDec( rDateTime
.Seconds
, 2, '0' );
1672 bool Output::implIsValid() const
1677 void Output::writeItemName( const String
& rItemName
)
1679 if( rItemName
.has() && (rItemName
[ 0 ] == '#') )
1681 writeString( rItemName
.copy( 1 ) );
1682 StringHelper::appendIndex( maLine
, mnItemIdx
++ );
1685 writeString( rItemName
);
1688 StorageIterator::StorageIterator( const StorageRef
& rxStrg
) :
1692 mxStrg
->getElementNames( maNames
);
1693 maIt
= maNames
.begin();
1696 StorageIterator::~StorageIterator()
1700 StorageIterator
& StorageIterator::operator++()
1702 if( maIt
!= maNames
.end() )
1707 OUString
StorageIterator::getName() const
1710 if( maIt
!= maNames
.end() )
1715 bool StorageIterator::isStream() const
1717 return isValid() && mxStrg
->openInputStream( *maIt
).is();
1720 bool StorageIterator::isStorage() const
1724 StorageRef xStrg
= mxStrg
->openSubStorage( *maIt
, false );
1725 return xStrg
.get() && xStrg
->isStorage();
1728 bool StorageIterator::implIsValid() const
1730 return mxStrg
.get() && mxStrg
->isStorage() && (maIt
!= maNames
.end());
1733 ObjectBase::~ObjectBase()
1737 void ObjectBase::construct( const ConfigRef
& rxConfig
)
1739 mxConfig
= rxConfig
;
1742 void ObjectBase::construct( const ObjectBase
& rParent
)
1747 void ObjectBase::dump()
1753 bool ObjectBase::implIsValid() const
1755 return isValid( mxConfig
);
1758 void ObjectBase::implDump()
1762 void StorageObjectBase::construct( const ObjectBase
& rParent
, const StorageRef
& rxStrg
, const OUString
& rSysPath
)
1764 ObjectBase::construct( rParent
);
1766 maSysPath
= rSysPath
;
1769 void StorageObjectBase::construct( const ObjectBase
& rParent
)
1771 ObjectBase::construct( rParent
);
1772 if( ObjectBase::implIsValid() )
1774 mxStrg
= cfg().getRootStorage();
1775 maSysPath
= cfg().getSysFileName();
1779 bool StorageObjectBase::implIsValid() const
1781 return mxStrg
.get() && !maSysPath
.isEmpty() && ObjectBase::implIsValid();
1784 void StorageObjectBase::implDump()
1786 bool bIsStrg
= mxStrg
->isStorage();
1787 bool bIsRoot
= mxStrg
->isRootStorage();
1788 Reference
< XInputStream
> xBaseStrm
;
1790 xBaseStrm
= mxStrg
->openInputStream( OUString() );
1792 OUString aSysOutPath
= maSysPath
;
1795 aSysOutPath
+= OOX_DUMP_DUMPEXT
;
1796 Reference
<XSimpleFileAccess3
> xFileAccess(SimpleFileAccess::create(getContext()));
1797 xFileAccess
->kill( aSysOutPath
);
1805 extractStorage( mxStrg
, OUString(), aSysOutPath
);
1807 else if( xBaseStrm
.is() )
1809 BinaryInputStreamRef
xInStrm( new BinaryXInputStream( xBaseStrm
, false ) );
1810 xInStrm
->seekToStart();
1811 implDumpBaseStream( xInStrm
, aSysOutPath
);
1815 void StorageObjectBase::implDumpStream( const Reference
< XInputStream
>&, const OUString
&, const OUString
&, const OUString
& )
1819 void StorageObjectBase::implDumpStorage( const StorageRef
& rxStrg
, const OUString
& rStrgPath
, const OUString
& rSysPath
)
1821 extractStorage( rxStrg
, rStrgPath
, rSysPath
);
1824 void StorageObjectBase::implDumpBaseStream( const BinaryInputStreamRef
&, const OUString
& )
1828 void StorageObjectBase::addPreferredStream( const String
& rStrmName
)
1830 if( rStrmName
.has() )
1831 maPreferred
.emplace_back( rStrmName
, false );
1834 void StorageObjectBase::addPreferredStorage( const String
& rStrgPath
)
1836 if( rStrgPath
.has() )
1837 maPreferred
.emplace_back( rStrgPath
, true );
1840 OUString
StorageObjectBase::getSysFileName( const OUString
& rStrmName
, const OUString
& rSysOutPath
)
1842 // encode all characters < 0x20
1843 OUStringBuffer aBuffer
;
1844 StringHelper::appendEncString( aBuffer
, rStrmName
, false );
1846 // replace all characters reserved in file system
1847 OUString aFileName
= aBuffer
.makeStringAndClear();
1848 static const sal_Unicode spcReserved
[] = { '/', '\\', ':', '*', '?', '<', '>', '|' };
1849 for(const sal_Unicode cChar
: spcReserved
)
1850 aFileName
= aFileName
.replace(cChar
, '_');
1853 return rSysOutPath
+ "/" + aFileName
;
1856 void StorageObjectBase::extractStream( StorageBase
& rStrg
, const OUString
& rStrgPath
, const OUString
& rStrmName
, const OUString
& rSysFileName
)
1858 BinaryXInputStream
aInStrm( rStrg
.openInputStream( rStrmName
), true );
1859 if( !aInStrm
.isEof() )
1861 BinaryXOutputStream
aOutStrm( InputOutputHelper::openOutputStream( getContext(), rSysFileName
), true );
1862 if( !aOutStrm
.isEof() )
1863 aInStrm
.copyToStream( aOutStrm
);
1865 Reference
< XInputStream
> xDumpStrm
= InputOutputHelper::openInputStream( getContext(), rSysFileName
);
1866 if( xDumpStrm
.is() )
1867 implDumpStream( xDumpStrm
, rStrgPath
, rStrmName
, rSysFileName
);
1870 void StorageObjectBase::extractStorage( const StorageRef
& rxStrg
, const OUString
& rStrgPath
, const OUString
& rSysPath
)
1872 // create directory in file system
1873 ::osl::FileBase::RC eRes
= ::osl::Directory::create( rSysPath
);
1874 if( (eRes
!= ::osl::FileBase::E_None
) && (eRes
!= ::osl::FileBase::E_EXIST
) )
1877 // process preferred storages and streams in root storage first
1878 if( rStrgPath
.isEmpty() )
1880 for (auto const& elemPreferred
: maPreferred
)
1881 extractItem( rxStrg
, rStrgPath
, elemPreferred
.maName
, rSysPath
, elemPreferred
.mbStorage
, !elemPreferred
.mbStorage
);
1884 // process children of the storage
1885 for( StorageIterator
aIt( rxStrg
); aIt
.isValid(); ++aIt
)
1887 // skip processed preferred items
1888 OUString aItemName
= aIt
.getName();
1889 bool bFound
= false;
1890 if( rStrgPath
.isEmpty() )
1892 for (auto const& elemPreferred
: maPreferred
)
1894 bFound
= elemPreferred
.maName
== aItemName
;
1900 extractItem( rxStrg
, rStrgPath
, aItemName
, rSysPath
, aIt
.isStorage(), aIt
.isStream() );
1904 void StorageObjectBase::extractItem( const StorageRef
& rxStrg
, const OUString
& rStrgPath
, const OUString
& rItemName
, const OUString
& rSysPath
, bool bIsStrg
, bool bIsStrm
)
1906 OUString aSysFileName
= getSysFileName( rItemName
, rSysPath
);
1909 OUStringBuffer
aStrgPath( rStrgPath
);
1910 StringHelper::appendToken( aStrgPath
, rItemName
, '/' );
1911 implDumpStorage( rxStrg
->openSubStorage( rItemName
, false ), aStrgPath
.makeStringAndClear(), aSysFileName
);
1915 extractStream( *rxStrg
, rStrgPath
, rItemName
, aSysFileName
);
1919 OutputObjectBase::~OutputObjectBase()
1923 void OutputObjectBase::construct( const ObjectBase
& rParent
, const OUString
& rSysFileName
)
1925 ObjectBase::construct( rParent
);
1926 if( ObjectBase::implIsValid() )
1928 maSysFileName
= rSysFileName
;
1929 mxOut
.reset( new Output( getContext(), rSysFileName
+ OOX_DUMP_DUMPEXT
) );
1933 void OutputObjectBase::construct( const OutputObjectBase
& rParent
)
1938 bool OutputObjectBase::implIsValid() const
1940 return isValid( mxOut
) && ObjectBase::implIsValid();
1943 void OutputObjectBase::writeEmptyItem( const String
& rName
)
1945 ItemGuard
aItem( mxOut
, rName
);
1948 void OutputObjectBase::writeInfoItem( const String
& rName
, const String
& rData
)
1950 ItemGuard
aItem( mxOut
, rName
);
1951 mxOut
->writeString( rData
);
1954 void OutputObjectBase::writeCharItem( const String
& rName
, sal_Unicode cData
)
1956 ItemGuard
aItem( mxOut
, rName
);
1957 mxOut
->writeChar( OOX_DUMP_STRQUOTE
);
1958 mxOut
->writeChar( cData
);
1959 mxOut
->writeChar( OOX_DUMP_STRQUOTE
);
1962 void OutputObjectBase::writeStringItem( const String
& rName
, const OUString
& rData
)
1964 ItemGuard
aItem( mxOut
, rName
);
1965 mxOut
->writeAscii( "(len=" );
1966 mxOut
->writeDec( rData
.getLength() );
1967 mxOut
->writeAscii( ")," );
1968 OUStringBuffer
aValue( rData
.copy( 0, ::std::min( rData
.getLength(), OOX_DUMP_MAXSTRLEN
) ) );
1969 StringHelper::enclose( aValue
, OOX_DUMP_STRQUOTE
);
1970 mxOut
->writeString( aValue
.makeStringAndClear() );
1971 if( rData
.getLength() > OOX_DUMP_MAXSTRLEN
)
1972 mxOut
->writeAscii( ",cut" );
1975 void OutputObjectBase::writeArrayItem( const String
& rName
, const sal_uInt8
* pnData
, std::size_t nSize
, sal_Unicode cSep
)
1977 ItemGuard
aItem( mxOut
, rName
);
1978 mxOut
->writeArray( pnData
, nSize
, cSep
);
1981 void OutputObjectBase::writeDateTimeItem( const String
& rName
, const util::DateTime
& rDateTime
)
1983 ItemGuard
aItem( mxOut
, rName
);
1984 mxOut
->writeDateTime( rDateTime
);
1987 void OutputObjectBase::writeGuidItem( const String
& rName
, const OUString
& rGuid
)
1989 ItemGuard
aItem( mxOut
, rName
);
1990 mxOut
->writeString( rGuid
);
1992 mxOut
->writeString( cfg().getStringOption( rGuid
, OUString() ) );
1995 InputObjectBase::~InputObjectBase()
1999 void InputObjectBase::construct( const ObjectBase
& rParent
, const BinaryInputStreamRef
& rxStrm
, const OUString
& rSysFileName
)
2001 OutputObjectBase::construct( rParent
, rSysFileName
);
2005 void InputObjectBase::construct( const OutputObjectBase
& rParent
, const BinaryInputStreamRef
& rxStrm
)
2007 OutputObjectBase::construct( rParent
);
2011 void InputObjectBase::construct( const InputObjectBase
& rParent
)
2016 bool InputObjectBase::implIsValid() const
2018 return mxStrm
.get() && OutputObjectBase::implIsValid();
2021 void InputObjectBase::skipBlock( sal_Int64 nBytes
, bool bShowSize
)
2023 sal_Int64 nEndPos
= ::std::min
< sal_Int64
>( mxStrm
->tell() + nBytes
, mxStrm
->size() );
2024 if( mxStrm
->tell() < nEndPos
)
2027 writeDecItem( "skipped-data-size", static_cast< sal_uInt64
>( nEndPos
- mxStrm
->tell() ) );
2028 mxStrm
->seek( nEndPos
);
2032 void InputObjectBase::dumpRawBinary( sal_Int64 nBytes
, bool bShowOffset
, bool bStream
)
2034 TableGuard
aTabGuard( mxOut
,
2035 bShowOffset
? 12 : 0,
2036 3 * OOX_DUMP_BYTESPERLINE
/ 2 + 1,
2037 3 * OOX_DUMP_BYTESPERLINE
/ 2 + 1,
2038 OOX_DUMP_BYTESPERLINE
/ 2 + 1 );
2040 sal_Int64 nMaxShowSize
= cfg().getIntOption
< sal_Int64
>(
2041 bStream
? "max-binary-stream-size" : "max-binary-data-size", SAL_MAX_INT64
);
2043 bool bSeekable
= mxStrm
->size() >= 0;
2044 sal_Int64 nEndPos
= bSeekable
? ::std::min
< sal_Int64
>( mxStrm
->tell() + nBytes
, mxStrm
->size() ) : 0;
2045 sal_Int64 nDumpEnd
= bSeekable
? ::std::min
< sal_Int64
>( mxStrm
->tell() + nMaxShowSize
, nEndPos
) : nMaxShowSize
;
2046 sal_Int64 nPos
= bSeekable
? mxStrm
->tell() : 0;
2049 while( bLoop
&& (nPos
< nDumpEnd
) )
2051 mxOut
->writeHex( static_cast< sal_uInt32
>( nPos
) );
2054 sal_uInt8 pnLineData
[ OOX_DUMP_BYTESPERLINE
];
2055 sal_Int32 nLineSize
= bSeekable
? ::std::min( static_cast< sal_Int32
>( nDumpEnd
- mxStrm
->tell() ), OOX_DUMP_BYTESPERLINE
) : OOX_DUMP_BYTESPERLINE
;
2056 sal_Int32 nReadSize
= mxStrm
->readMemory( pnLineData
, nLineSize
);
2057 bLoop
= nReadSize
== nLineSize
;
2062 const sal_uInt8
* pnByte
= nullptr;
2063 const sal_uInt8
* pnEnd
= nullptr;
2064 for( pnByte
= pnLineData
, pnEnd
= pnLineData
+ nReadSize
; pnByte
!= pnEnd
; ++pnByte
)
2066 if( (pnByte
- pnLineData
) == (OOX_DUMP_BYTESPERLINE
/ 2) ) mxOut
->tab();
2067 mxOut
->writeHex( *pnByte
, false );
2068 mxOut
->writeChar( ' ' );
2072 for( pnByte
= pnLineData
, pnEnd
= pnLineData
+ nReadSize
; pnByte
!= pnEnd
; ++pnByte
)
2074 if( (pnByte
- pnLineData
) == (OOX_DUMP_BYTESPERLINE
/ 2) ) mxOut
->tab();
2075 mxOut
->writeChar( static_cast< sal_Unicode
>( (*pnByte
< 0x20) ? '.' : *pnByte
) );
2081 // skip undumped data
2083 skipBlock( nEndPos
- mxStrm
->tell() );
2086 void InputObjectBase::dumpBinary( const String
& rName
, sal_Int64 nBytes
, bool bShowOffset
)
2089 MultiItemsGuard
aMultiGuard( mxOut
);
2090 writeEmptyItem( rName
);
2091 writeDecItem( "size", nBytes
);
2093 IndentGuard
aIndGuard( mxOut
);
2094 dumpRawBinary( nBytes
, bShowOffset
);
2097 void InputObjectBase::dumpRemaining( sal_Int64 nBytes
)
2101 if( cfg().getBoolOption( "show-trailing-unknown", true ) )
2102 dumpBinary( "remaining-data", nBytes
, false );
2104 skipBlock( nBytes
);
2108 void InputObjectBase::dumpRemainingTo( sal_Int64 nPos
)
2110 if( mxStrm
->isEof() || (mxStrm
->tell() > nPos
) )
2111 writeInfoItem( "stream-state", OOX_DUMP_ERR_STREAM
);
2113 dumpRemaining( nPos
- mxStrm
->tell() );
2114 mxStrm
->seek( nPos
);
2117 void InputObjectBase::dumpRemainingStream()
2119 dumpRemainingTo( mxStrm
->size() );
2122 void InputObjectBase::dumpArray( const String
& rName
, sal_Int32 nBytes
, sal_Unicode cSep
)
2124 sal_Int32 nDumpSize
= getLimitedValue
< sal_Int32
, sal_Int64
>( mxStrm
->size() - mxStrm
->tell(), 0, nBytes
);
2125 if( nDumpSize
> OOX_DUMP_MAXARRAY
)
2127 dumpBinary( rName
, nBytes
, false );
2129 else if( nDumpSize
> 1 )
2131 sal_uInt8 pnData
[ OOX_DUMP_MAXARRAY
];
2132 mxStrm
->readMemory( pnData
, nDumpSize
);
2133 writeArrayItem( rName
, pnData
, nDumpSize
, cSep
);
2135 else if( nDumpSize
== 1 )
2136 dumpHex
< sal_uInt8
>( rName
);
2139 sal_Unicode
InputObjectBase::dumpUnicode( const String
& rName
)
2141 sal_uInt16 nChar
= mxStrm
->readuInt16();
2142 sal_Unicode cChar
= static_cast< sal_Unicode
>( nChar
);
2143 writeCharItem( rName( "char" ), cChar
);
2147 OUString
InputObjectBase::dumpCharArray( const String
& rName
, sal_Int32 nLen
, rtl_TextEncoding eTextEnc
, bool bHideTrailingNul
)
2149 sal_Int32 nDumpSize
= getLimitedValue
< sal_Int32
, sal_Int64
>( mxStrm
->size() - mxStrm
->tell(), 0, nLen
);
2153 ::std::vector
< sal_Char
> aBuffer( static_cast< std::size_t >( nLen
) + 1 );
2154 sal_Int32 nCharsRead
= mxStrm
->readMemory(aBuffer
.data(), nLen
);
2155 aBuffer
[ nCharsRead
] = 0;
2156 aString
= OStringToOUString(OString(aBuffer
.data()), eTextEnc
);
2158 if( bHideTrailingNul
)
2159 aString
= StringHelper::trimTrailingNul( aString
);
2160 writeStringItem( rName( "text" ), aString
);
2164 OUString
InputObjectBase::dumpUnicodeArray( const String
& rName
, sal_Int32 nLen
, bool bHideTrailingNul
)
2166 OUStringBuffer aBuffer
;
2167 for( sal_Int32 nIndex
= 0; !mxStrm
->isEof() && (nIndex
< nLen
); ++nIndex
)
2169 aBuffer
.append( static_cast< sal_Unicode
>( mxStrm
->readuInt16() ) );
2171 OUString aString
= aBuffer
.makeStringAndClear();
2172 if( bHideTrailingNul
)
2173 aString
= StringHelper::trimTrailingNul( aString
);
2174 writeStringItem( rName( "text" ), aString
);
2178 util::DateTime
InputObjectBase::dumpFileTime( const String
& rName
)
2180 util::DateTime aDateTime
;
2182 ItemGuard
aItem( mxOut
, rName( "file-time" ) );
2183 sal_Int64 nFileTime
= dumpDec
< sal_Int64
>( EMPTY_STRING
);
2184 // file time is in 10^-7 seconds (100 nanoseconds), convert to nanoseconds
2187 sal_Int64 nDays
= nFileTime
/ sal_Int64( ::tools::Time::nanoSecPerDay
);
2188 // number of entire years
2189 sal_Int64 nYears
= (nDays
- (nDays
/ (4 * 365)) + (nDays
/ (100 * 365)) - (nDays
/ (400 * 365))) / 365;
2190 // remaining days in the year
2191 sal_Int64 nDaysInYear
= nDays
- (nYears
* 365 + nYears
/ 4 - nYears
/ 100 + nYears
/ 400);
2192 // the year (file dates start from 1601-01-01)
2193 aDateTime
.Year
= static_cast< sal_uInt16
>( 1601 + nYears
);
2195 bool bLeap
= ((aDateTime
.Year
% 4 == 0) && (aDateTime
.Year
% 100 != 0)) || (aDateTime
.Year
% 400 == 0);
2196 // static arrays with number of days in month
2197 static const sal_Int64 spnDaysInMonth
[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
2198 static const sal_Int64 spnDaysInMonthL
[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
2199 const sal_Int64
* pnDaysInMonth
= bLeap
? spnDaysInMonthL
: spnDaysInMonth
;
2201 aDateTime
.Month
= 1;
2202 while( nDaysInYear
>= *pnDaysInMonth
)
2204 nDaysInYear
-= *pnDaysInMonth
++;
2208 aDateTime
.Day
= static_cast< sal_uInt16
>( nDaysInYear
+ 1 );
2209 // number of nanoseconds in the day
2210 sal_Int64 nTimeInDay
= nFileTime
% sal_Int64( ::tools::Time::nanoSecPerDay
);
2212 aDateTime
.NanoSeconds
= static_cast< sal_uInt32
>( nTimeInDay
% ::tools::Time::nanoSecPerSec
);
2213 nTimeInDay
/= ::tools::Time::nanoSecPerSec
;
2215 aDateTime
.Seconds
= static_cast< sal_uInt16
>( nTimeInDay
% ::tools::Time::secondPerMinute
);
2216 nTimeInDay
/= ::tools::Time::secondPerMinute
;
2218 aDateTime
.Minutes
= static_cast< sal_uInt16
>( nTimeInDay
% ::tools::Time::minutePerHour
);
2219 nTimeInDay
/= ::tools::Time::minutePerHour
;
2221 aDateTime
.Hours
= static_cast< sal_uInt16
>( nTimeInDay
);
2223 writeDateTimeItem( EMPTY_STRING
, aDateTime
);
2227 OUString
InputObjectBase::dumpGuid( const String
& rName
)
2229 OUStringBuffer aBuffer
;
2234 nData32
= mxStrm
->readuInt32();
2235 StringHelper::appendHex( aBuffer
, nData32
, false );
2236 aBuffer
.append( '-' );
2237 nData16
= mxStrm
->readuInt16();
2238 StringHelper::appendHex( aBuffer
, nData16
, false );
2239 aBuffer
.append( '-' );
2240 nData16
= mxStrm
->readuInt16();
2241 StringHelper::appendHex( aBuffer
, nData16
, false );
2242 aBuffer
.append( '-' );
2243 nData8
= mxStrm
->readuChar();
2244 StringHelper::appendHex( aBuffer
, nData8
, false );
2245 nData8
= mxStrm
->readuChar( );
2246 StringHelper::appendHex( aBuffer
, nData8
, false );
2247 aBuffer
.append( '-' );
2248 for( int nIndex
= 0; nIndex
< 6; ++nIndex
)
2250 nData8
= mxStrm
->readuChar( );
2251 StringHelper::appendHex( aBuffer
, nData8
, false );
2253 StringHelper::enclose( aBuffer
, '{', '}' );
2254 OUString aGuid
= aBuffer
.makeStringAndClear();
2255 writeGuidItem( rName( "guid" ), aGuid
);
2259 void InputObjectBase::dumpItem( const ItemFormat
& rItemFmt
)
2261 switch( rItemFmt
.meDataType
)
2263 case DATATYPE_VOID
: break;
2264 case DATATYPE_INT8
: dumpValue
< sal_Int8
>( rItemFmt
); break;
2265 case DATATYPE_UINT8
: dumpValue
< sal_uInt8
>( rItemFmt
); break;
2266 case DATATYPE_INT16
: dumpValue
< sal_Int16
>( rItemFmt
); break;
2267 case DATATYPE_UINT16
: dumpValue
< sal_uInt16
>( rItemFmt
); break;
2268 case DATATYPE_INT32
: dumpValue
< sal_Int32
>( rItemFmt
); break;
2269 case DATATYPE_UINT32
: dumpValue
< sal_uInt32
>( rItemFmt
); break;
2270 case DATATYPE_INT64
: dumpValue
< sal_Int64
>( rItemFmt
); break;
2271 case DATATYPE_UINT64
: dumpValue
< sal_uInt64
>( rItemFmt
); break;
2272 case DATATYPE_FLOAT
: dumpValue
< float >( rItemFmt
); break;
2273 case DATATYPE_DOUBLE
: dumpValue
< double >( rItemFmt
); break;
2278 BinaryStreamObject::BinaryStreamObject( const ObjectBase
& rParent
, const BinaryInputStreamRef
& rxStrm
, const OUString
& rSysFileName
)
2280 InputObjectBase::construct( rParent
, rxStrm
, rSysFileName
);
2283 void BinaryStreamObject::dumpBinaryStream( bool bShowOffset
)
2285 mxStrm
->seekToStart();
2286 dumpRawBinary( mxStrm
->size(), bShowOffset
, true );
2290 void BinaryStreamObject::implDump()
2295 void TextStreamObjectBase::construct( const ObjectBase
& rParent
,
2296 const BinaryInputStreamRef
& rxStrm
, rtl_TextEncoding eTextEnc
, const OUString
& rSysFileName
)
2298 InputObjectBase::construct( rParent
, rxStrm
, rSysFileName
);
2299 constructTextStrmObj( eTextEnc
);
2302 void TextStreamObjectBase::construct( const OutputObjectBase
& rParent
,
2303 const BinaryInputStreamRef
& rxStrm
, rtl_TextEncoding eTextEnc
)
2305 InputObjectBase::construct( rParent
, rxStrm
);
2306 constructTextStrmObj( eTextEnc
);
2309 bool TextStreamObjectBase::implIsValid() const
2311 return InputObjectBase::implIsValid() && mxTextStrm
.get();
2314 void TextStreamObjectBase::implDump()
2316 implDumpText( *mxTextStrm
);
2319 void TextStreamObjectBase::constructTextStrmObj( rtl_TextEncoding eTextEnc
)
2322 mxTextStrm
.reset( new TextInputStream( getContext(), *mxStrm
, eTextEnc
) );
2325 TextLineStreamObject::TextLineStreamObject( const ObjectBase
& rParent
,
2326 const BinaryInputStreamRef
& rxStrm
, rtl_TextEncoding eTextEnc
, const OUString
& rSysFileName
)
2328 TextStreamObjectBase::construct( rParent
, rxStrm
, eTextEnc
, rSysFileName
);
2331 TextLineStreamObject::TextLineStreamObject( const OutputObjectBase
& rParent
,
2332 const BinaryInputStreamRef
& rxStrm
, rtl_TextEncoding eTextEnc
)
2334 TextStreamObjectBase::construct( rParent
, rxStrm
, eTextEnc
);
2337 void TextLineStreamObject::implDumpText( TextInputStream
& rTextStrm
)
2339 sal_uInt32 nLine
= 0;
2340 while( !rTextStrm
.isEof() )
2342 OUString aLine
= rTextStrm
.readLine();
2343 if( !rTextStrm
.isEof() || !aLine
.isEmpty() )
2344 implDumpLine( aLine
, ++nLine
);
2348 void TextLineStreamObject::implDumpLine( const OUString
& rLine
, sal_uInt32 nLine
)
2350 TableGuard
aTabGuard( mxOut
, 8 );
2351 mxOut
->writeDec( nLine
, 6 );
2353 mxOut
->writeString( rLine
);
2357 XmlStreamObject::XmlStreamObject( const ObjectBase
& rParent
,
2358 const BinaryInputStreamRef
& rxStrm
, const OUString
& rSysFileName
)
2360 TextStreamObjectBase::construct( rParent
, rxStrm
, RTL_TEXTENCODING_UTF8
, rSysFileName
);
2363 void XmlStreamObject::implDumpText( TextInputStream
& rTextStrm
)
2365 /* Buffers a start element and the following element text. Needed to dump
2366 matching start/end elements and the element text on the same line. */
2367 OUStringBuffer aOldStartElem
;
2368 // special handling for VML
2369 bool bIsVml
= InputOutputHelper::getFileNameExtension( maSysFileName
).equalsIgnoreAsciiCase("vml");
2371 while( !rTextStrm
.isEof() )
2373 // get the next element and the following element text from text stream
2374 OUString aElem
= rTextStrm
.readToChar( '>', true ).trim();
2375 OUString aText
= rTextStrm
.readToChar( '<', false );
2377 // remove multiple whitespace from element
2379 while( nPos
< aElem
.getLength() )
2381 while( (nPos
< aElem
.getLength()) && (aElem
[ nPos
] >= 32) ) ++nPos
;
2382 if( nPos
< aElem
.getLength() )
2383 aElem
= aElem
.copy( 0, nPos
) + OUStringLiteral1(' ') + aElem
.copy( nPos
).trim();
2387 sal_Int32 nElemLen
= aElem
.getLength();
2388 if( (nElemLen
>= 2) && (aElem
[ 0 ] == '<') && (aElem
[ nElemLen
- 1 ] == '>') )
2390 // determine type of the element
2391 bool bSimpleElem
= (aElem
[ 1 ] == '!') || (aElem
[ 1 ] == '?') || (aElem
[ nElemLen
- 2 ] == '/') ||
2392 (bIsVml
&& (nElemLen
== 4) && (aElem
[ 1 ] == 'b') && (aElem
[ 2 ] == 'r'));
2393 bool bStartElem
= !bSimpleElem
&& (aElem
[ 1 ] != '/');
2394 bool bEndElem
= !bSimpleElem
&& !bStartElem
;
2396 /* Start element or simple element: flush old start element and
2397 its text from previous iteration, and start a new indentation
2398 level for the new element. Trim whitespace and line breaks from
2399 the text of the old start element. */
2400 if( (bSimpleElem
|| bStartElem
) && (aOldStartElem
.getLength() > 0) )
2402 mxOut
->writeString( aOldStartElem
.makeStringAndClear().trim() );
2407 /* Start element: remember it and its text, to be able to print the
2408 matching end element on the same line in the next iteration. */
2411 aOldStartElem
.append( aElem
).append( aText
);
2415 /* End element: if a start element has been remembered in the
2416 previous iteration, write it out here untrimmed, to show
2417 all whitespace in the element text, and without trailing
2418 line break. Code below will add the end element right after
2419 it. Otherwise, return to previous indentation level. */
2422 if( aOldStartElem
.getLength() == 0 )
2425 mxOut
->writeString( aOldStartElem
.makeStringAndClear() );
2428 /* Write the element. Write following element text in a new
2429 line, but only, if it does not contain of white space
2431 mxOut
->writeString( aElem
);
2433 if( !aText
.trim().isEmpty() )
2435 mxOut
->writeString( aText
);
2443 void RecordObjectBase::construct( const ObjectBase
& rParent
,
2444 const BinaryInputStreamRef
& rxBaseStrm
, const OUString
& rSysFileName
,
2445 const BinaryInputStreamRef
& rxRecStrm
, const String
& rRecNames
, const String
& rSimpleRecs
)
2447 InputObjectBase::construct( rParent
, rxRecStrm
, rSysFileName
);
2448 constructRecObjBase( rxBaseStrm
, rRecNames
, rSimpleRecs
);
2451 bool RecordObjectBase::implIsValid() const
2453 return mxBaseStrm
.get() && InputObjectBase::implIsValid();
2456 void RecordObjectBase::implDump()
2458 NameListRef xRecNames
= maRecNames
.getNameList( cfg() );
2459 ItemFormatMap
aSimpleRecs( maSimpleRecs
.getNameList( cfg() ) );
2461 while( implStartRecord( *mxBaseStrm
, mnRecPos
, mnRecId
, mnRecSize
) )
2466 implWriteExtHeader();
2467 IndentGuard
aIndGuard( mxOut
);
2468 sal_Int64 nRecPos
= mxStrm
->tell();
2471 if( !mbBinaryOnly
&& cfg().hasName( xRecNames
, mnRecId
) )
2473 ::std::map
< sal_Int64
, ItemFormat
>::const_iterator aIt
= aSimpleRecs
.find( mnRecId
);
2474 if( aIt
!= aSimpleRecs
.end() )
2475 dumpItem( aIt
->second
);
2477 implDumpRecordBody();
2480 // remaining undumped data
2481 if( !mxStrm
->isEof() && (mxStrm
->tell() == nRecPos
) )
2482 dumpRawBinary( mnRecSize
, false );
2484 dumpRemainingTo( nRecPos
+ mnRecSize
);
2488 void RecordObjectBase::implWriteExtHeader()
2492 void RecordObjectBase::implDumpRecordBody()
2496 void RecordObjectBase::constructRecObjBase( const BinaryInputStreamRef
& rxBaseStrm
, const String
& rRecNames
, const String
& rSimpleRecs
)
2498 mxBaseStrm
= rxBaseStrm
;
2499 maRecNames
= rRecNames
;
2500 maSimpleRecs
= rSimpleRecs
;
2501 mnRecPos
= mnRecId
= mnRecSize
= 0;
2502 mbBinaryOnly
= false;
2503 if( InputObjectBase::implIsValid() )
2504 mbShowRecPos
= cfg().getBoolOption( "show-record-position", true );
2507 void RecordObjectBase::writeHeader()
2509 MultiItemsGuard
aMultiGuard( mxOut
);
2510 writeEmptyItem( "REC" );
2511 if( mbShowRecPos
&& mxBaseStrm
->isSeekable() )
2512 writeShortHexItem( "pos", mnRecPos
, "CONV-DEC" );
2513 writeShortHexItem( "size", mnRecSize
, "CONV-DEC" );
2514 ItemGuard
aItem( mxOut
, "id" );
2515 mxOut
->writeShortHex( mnRecId
);
2516 addNameToItem( mnRecId
, "CONV-DEC" );
2517 addNameToItem( mnRecId
, maRecNames
);
2520 void SequenceRecordObjectBase::construct( const ObjectBase
& rParent
,
2521 const BinaryInputStreamRef
& rxBaseStrm
, const OUString
& rSysFileName
,
2522 const String
& rRecNames
, const String
& rSimpleRecs
)
2524 BinaryInputStreamRef
xRecStrm( new SequenceInputStream( *mxRecData
) );
2525 RecordObjectBase::construct( rParent
, rxBaseStrm
, rSysFileName
, xRecStrm
, rRecNames
, rSimpleRecs
);
2528 bool SequenceRecordObjectBase::implStartRecord( BinaryInputStream
& rBaseStrm
, sal_Int64
& ornRecPos
, sal_Int64
& ornRecId
, sal_Int64
& ornRecSize
)
2531 if( rBaseStrm
.isSeekable() )
2533 ornRecPos
= rBaseStrm
.tell();
2534 // do not try to overread seekable streams, may cause assertions
2535 bValid
= ornRecPos
< rBaseStrm
.size();
2538 // read the record header
2540 bValid
= implReadRecordHeader( rBaseStrm
, ornRecId
, ornRecSize
) && !rBaseStrm
.isEof() && (0 <= ornRecSize
) && (ornRecSize
<= 0x00100000);
2542 // read record contents into data sequence
2545 sal_Int32 nRecSize
= static_cast< sal_Int32
>( ornRecSize
);
2546 mxRecData
->realloc( nRecSize
);
2547 bValid
= (nRecSize
== 0) || (rBaseStrm
.readData( *mxRecData
, nRecSize
) == nRecSize
);
2548 mxStrm
->seekToStart();
2553 DumperBase::~DumperBase()
2557 bool DumperBase::isImportEnabled() const
2559 return !isValid() || cfg().isImportEnabled();
2562 void DumperBase::construct( const ConfigRef
& rxConfig
)
2564 if( isValid( rxConfig
) && rxConfig
->isDumperEnabled() )
2565 ObjectBase::construct( rxConfig
);
2573 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */