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/TextOutputStream.hpp>
27 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
28 #include <osl/file.hxx>
29 #include <rtl/math.hxx>
30 #include <rtl/tencinfo.h>
31 #include <oox/core/filterbase.hxx>
32 #include <oox/helper/binaryoutputstream.hxx>
33 #include <oox/helper/textinputstream.hxx>
34 #include <tools/time.hxx>
35 #include <o3tl/string_view.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( std::u16string_view rFileUrl
)
78 size_t nSepPos
= rFileUrl
.find( '/' );
79 return (nSepPos
== std::u16string_view::npos
) ? 0 : (nSepPos
+ 1);
82 std::u16string_view
InputOutputHelper::getFileNameExtension( std::u16string_view rFileUrl
)
84 sal_Int32 nNamePos
= getFileNamePos( rFileUrl
);
85 size_t nExtPos
= rFileUrl
.rfind( '.' );
86 if( nExtPos
!= std::u16string_view::npos
&& static_cast<sal_Int32
>(nExtPos
) >= nNamePos
)
87 return rFileUrl
.substr( nExtPos
+ 1 );
88 return std::u16string_view();
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( std::u16string_view 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
, std::u16string_view rData
, sal_Int32 nWidth
, sal_Unicode cFill
)
205 appendChar( rStr
, cFill
, nWidth
- rData
.size() );
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( static_cast<sal_Int64
>(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( OUStringChar(spcHexDigits
[ (nData
>> 4) & 0x0F ] ) + OUStringChar( 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
, std::u16string_view rData
, bool bPrefix
)
490 size_t nEnd
= rData
.size();
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( 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
, std::u16string_view rToken
, sal_Unicode cSep
)
518 if( (rStr
.getLength() > 0) && (!rToken
.empty()) )
520 rStr
.append( rToken
);
523 void StringHelper::appendIndex( OUStringBuffer
& rStr
, sal_Int64 nIdx
)
525 OUStringBuffer aToken
;
526 appendDec( aToken
, nIdx
);
527 rStr
.append( "[" + aToken
+ "]" );
530 std::u16string_view
StringHelper::getToken( std::u16string_view rData
, sal_Int32
& rnPos
, sal_Unicode cSep
)
532 return trimSpaces( o3tl::getToken(rData
, 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( std::u16string_view rStr
, sal_Unicode cChar
, sal_Int32 nStartPos
)
546 size_t nIndex
= rStr
.find( cChar
, nStartPos
);
547 return (nIndex
== std::u16string_view::npos
) ? rStr
.size() : nIndex
;
550 OUString
lclTrimQuotedStringList( std::u16string_view rStr
)
552 OUStringBuffer aBuffer
;
554 size_t nLen
= rStr
.size();
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 size_t nEnd
= lclIndexOf( rStr
, OOX_DUMP_CFG_QUOTE
, nPos
);
567 aToken
.append( 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
);
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 size_t nEnd
= lclIndexOf( rStr
, OOX_DUMP_CFG_LISTSEP
, nPos
);
590 aBuffer
.append( rStr
.substr(nPos
, nEnd
- nPos
) );
592 aBuffer
.append( OOX_DUMP_LF
);
593 // set current position behind list separator
598 return aBuffer
.makeStringAndClear();
603 std::u16string_view
StringHelper::trimSpaces( std::u16string_view rStr
)
606 while( (nBeg
< rStr
.size()) && ((rStr
[ nBeg
] == ' ') || (rStr
[ nBeg
] == '\t')) )
608 size_t nEnd
= rStr
.size();
609 while( (nEnd
> nBeg
) && ((rStr
[ nEnd
- 1 ] == ' ') || (rStr
[ nEnd
- 1 ] == '\t')) )
611 return rStr
.substr( 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( std::u16string_view rStr
)
624 return OUStringToOString( rStr
, RTL_TEXTENCODING_UTF8
);
627 DataType
StringHelper::convertToDataType( std::u16string_view rStr
)
629 DataType eType
= DATATYPE_VOID
;
630 if ( rStr
== u
"int8" )
631 eType
= DATATYPE_INT8
;
632 else if ( rStr
== u
"uint8" )
633 eType
= DATATYPE_UINT8
;
634 else if ( rStr
== u
"int16" )
635 eType
= DATATYPE_INT16
;
636 else if ( rStr
== u
"uint16" )
637 eType
= DATATYPE_UINT16
;
638 else if ( rStr
== u
"int32" )
639 eType
= DATATYPE_INT32
;
640 else if ( rStr
== u
"uint32" )
641 eType
= DATATYPE_UINT32
;
642 else if ( rStr
== u
"int64" )
643 eType
= DATATYPE_INT64
;
644 else if ( rStr
== u
"uint64" )
645 eType
= DATATYPE_UINT64
;
646 else if ( rStr
== u
"float" )
647 eType
= DATATYPE_FLOAT
;
648 else if ( rStr
== u
"double" )
649 eType
= DATATYPE_DOUBLE
;
653 FormatType
StringHelper::convertToFormatType( std::u16string_view rStr
)
655 FormatType eType
= FORMATTYPE_NONE
;
656 if ( rStr
== u
"dec" )
657 eType
= FORMATTYPE_DEC
;
658 else if ( rStr
== u
"hex" )
659 eType
= FORMATTYPE_HEX
;
660 else if ( rStr
== u
"shorthex" )
661 eType
= FORMATTYPE_SHORTHEX
;
662 else if ( rStr
== u
"bin" )
663 eType
= FORMATTYPE_BIN
;
664 else if ( rStr
== u
"fix" )
665 eType
= FORMATTYPE_FIX
;
666 else if ( rStr
== u
"bool" )
667 eType
= FORMATTYPE_BOOL
;
671 bool StringHelper::convertFromDec( sal_Int64
& ornData
, std::u16string_view rData
)
674 size_t nLen
= rData
.size();
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
, std::u16string_view rData
)
697 for( size_t nPos
= 0, nLen
= rData
.size(); 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
, std::u16string_view rData
)
715 if( (rData
.size() > 2) && (rData
[ 0 ] == '0') && ((rData
[ 1 ] == 'X') || (rData
[ 1 ] == 'x')) )
716 return convertFromHex( ornData
, rData
.substr( 2 ) );
717 return convertFromDec( ornData
, rData
);
720 bool StringHelper::convertStringToDouble( double& orfData
, std::u16string_view rData
)
722 rtl_math_ConversionStatus eStatus
= rtl_math_ConversionStatus_Ok
;
724 sal_Unicode
const * pBegin
= rData
.data();
725 sal_Unicode
const * pEnd
;
726 orfData
= rtl_math_uStringToDouble(pBegin
,
727 pBegin
+ rData
.size(),
730 nSize
= static_cast<sal_Int32
>(pEnd
- pBegin
);
731 return (eStatus
== rtl_math_ConversionStatus_Ok
) && (nSize
== static_cast<sal_Int32
>(rData
.size()));
734 bool StringHelper::convertStringToBool( std::u16string_view rData
)
736 if ( rData
== u
"true" )
738 if ( rData
== u
"false" )
741 return convertStringToInt( nData
, rData
) && (nData
!= 0);
744 OUStringPair
StringHelper::convertStringToPair( const OUString
& rString
, sal_Unicode cSep
)
747 if( !rString
.isEmpty() )
749 sal_Int32 nEqPos
= rString
.indexOf( cSep
);
752 aPair
.first
= rString
;
756 aPair
.first
= StringHelper::trimSpaces( rString
.subView( 0, nEqPos
) );
757 aPair
.second
= StringHelper::trimSpaces( rString
.subView( nEqPos
+ 1 ) );
763 void StringHelper::convertStringToStringList( OUStringVector
& orVec
, std::u16string_view rData
, bool bIgnoreEmpty
)
766 OUString aUnquotedData
= lclTrimQuotedStringList( rData
);
768 sal_Int32 nLen
= aUnquotedData
.getLength();
769 while( (0 <= nPos
) && (nPos
< nLen
) )
771 std::u16string_view aToken
= getToken( aUnquotedData
, nPos
, OOX_DUMP_LF
);
772 if( !bIgnoreEmpty
|| !aToken
.empty() )
773 orVec
.push_back( OUString(aToken
) );
777 void StringHelper::convertStringToIntList( Int64Vector
& orVec
, std::u16string_view rData
, bool bIgnoreEmpty
)
780 OUString aUnquotedData
= lclTrimQuotedStringList( rData
);
782 sal_Int32 nLen
= aUnquotedData
.getLength();
784 while( (0 <= nPos
) && (nPos
< nLen
) )
786 bool bOk
= convertStringToInt( nData
, getToken( aUnquotedData
, nPos
, OOX_DUMP_LF
) );
787 if( !bIgnoreEmpty
|| bOk
)
788 orVec
.push_back( bOk
? nData
: 0 );
796 ConfigItemBase::~ConfigItemBase()
800 void ConfigItemBase::readConfigBlock( TextInputStream
& rStrm
)
802 readConfigBlockContents( rStrm
);
805 void ConfigItemBase::implProcessConfigItemStr(
806 TextInputStream
& /*rStrm*/, const OUString
& /*rKey*/, const OUString
& /*rData*/ )
810 void ConfigItemBase::implProcessConfigItemInt(
811 TextInputStream
& /*rStrm*/, sal_Int64
/*nKey*/, const OUString
& /*rData*/ )
815 void ConfigItemBase::readConfigBlockContents( TextInputStream
& rStrm
)
818 while( bLoop
&& !rStrm
.isEof() )
820 OUString aKey
, aData
;
821 switch( readConfigLine( rStrm
, aKey
, aData
) )
824 processConfigItem( rStrm
, aKey
, aData
);
833 ConfigItemBase::LineType
ConfigItemBase::readConfigLine(
834 TextInputStream
& rStrm
, OUString
& orKey
, OUString
& orData
)
837 while( !rStrm
.isEof() && aLine
.isEmpty() )
839 aLine
= rStrm
.readLine();
840 if( !aLine
.isEmpty() && (aLine
[ 0 ] == OOX_DUMP_BOM
) )
841 aLine
= aLine
.copy( 1 );
842 aLine
= StringHelper::trimSpaces( aLine
);
843 if( !aLine
.isEmpty() )
845 // ignore comments (starting with hash or semicolon)
846 sal_Unicode cChar
= aLine
[ 0 ];
847 if( (cChar
== '#') || (cChar
== ';') )
852 OUStringPair aPair
= StringHelper::convertStringToPair( aLine
);
854 orData
= aPair
.second
;
855 return ( !orKey
.isEmpty() && (!orData
.isEmpty() || orKey
!= "end" )) ?
856 LINETYPE_DATA
: LINETYPE_END
;
859 void ConfigItemBase::processConfigItem(
860 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
863 if( StringHelper::convertStringToInt( nKey
, rKey
) )
864 implProcessConfigItemInt( rStrm
, nKey
, rData
);
866 implProcessConfigItemStr( rStrm
, rKey
, rData
);
869 NameListBase::~NameListBase()
873 void NameListBase::setName( sal_Int64 nKey
, const String
& rName
)
875 implSetName( nKey
, rName
);
878 void NameListBase::includeList( const NameListRef
& rxList
)
882 for (auto const& elem
: *rxList
)
883 maMap
[ elem
.first
] = elem
.second
;
884 implIncludeList( *rxList
);
888 bool NameListBase::implIsValid() const
893 void NameListBase::implProcessConfigItemStr(
894 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
896 if ( rKey
== "include" )
898 else if ( rKey
== "exclude" )
901 ConfigItemBase::implProcessConfigItemStr( rStrm
, rKey
, rData
);
904 void NameListBase::implProcessConfigItemInt(
905 TextInputStream
& /*rStrm*/, sal_Int64 nKey
, const OUString
& rData
)
907 implSetName( nKey
, rData
);
910 void NameListBase::insertRawName( sal_Int64 nKey
, const OUString
& rName
)
912 maMap
[ nKey
] = rName
;
915 const OUString
* NameListBase::findRawName( sal_Int64 nKey
) const
917 const_iterator aIt
= maMap
.find( nKey
);
918 return (aIt
== end()) ? nullptr : &aIt
->second
;
921 void NameListBase::include( std::u16string_view rListKeys
)
924 StringHelper::convertStringToStringList( aVec
, rListKeys
, true );
925 for (auto const& elem
: aVec
)
926 includeList( mrCfgData
.getNameList(elem
) );
929 void NameListBase::exclude( std::u16string_view rKeys
)
932 StringHelper::convertStringToIntList( aVec
, rKeys
, true );
933 for (auto const& elem
: aVec
)
937 void ItemFormatMap::insertFormats( const NameListRef
& rxNameList
)
939 if( Base::isValid( rxNameList
) )
941 for (auto const& elemName
: *rxNameList
)
942 maMap
[ elemName
.first
].parse( elemName
.second
);
946 ConstList::ConstList( const SharedConfigData
& rCfgData
) :
947 NameListBase( rCfgData
),
948 maDefName( OOX_DUMP_ERR_NONAME
),
949 mbQuoteNames( false )
953 void ConstList::implProcessConfigItemStr(
954 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
956 if ( rKey
== "default" )
957 maDefName
= rData
; // Sets a default name for unknown keys.
958 else if ( rKey
== "quote-names" )
959 setQuoteNames( StringHelper::convertStringToBool( rData
) );
961 NameListBase::implProcessConfigItemStr( rStrm
, rKey
, rData
);
964 void ConstList::implSetName( sal_Int64 nKey
, const OUString
& rName
)
966 insertRawName( nKey
, rName
);
969 OUString
ConstList::implGetName( const Config
& /*rCfg*/, sal_Int64 nKey
) const
971 const OUString
* pName
= findRawName( nKey
);
972 OUString aName
= pName
? *pName
: maDefName
;
975 OUStringBuffer
aBuffer( aName
);
976 StringHelper::enclose( aBuffer
, OOX_DUMP_STRQUOTE
);
977 aName
= aBuffer
.makeStringAndClear();
982 OUString
ConstList::implGetNameDbl( const Config
& /*rCfg*/, double /*fValue*/ ) const
987 void ConstList::implIncludeList( const NameListBase
& rList
)
989 if( const ConstList
* pConstList
= dynamic_cast< const ConstList
* >( &rList
) )
991 maDefName
= pConstList
->maDefName
;
992 mbQuoteNames
= pConstList
->mbQuoteNames
;
996 MultiList::MultiList( const SharedConfigData
& rCfgData
) :
997 ConstList( rCfgData
),
998 mbIgnoreEmpty( true )
1002 void MultiList::setNamesFromVec( sal_Int64 nStartKey
, const OUStringVector
& rNames
)
1004 sal_Int64 nKey
= nStartKey
;
1005 for (auto const& name
: rNames
)
1007 if( !mbIgnoreEmpty
|| !name
.isEmpty() )
1008 insertRawName( nKey
, name
);
1013 void MultiList::implProcessConfigItemStr(
1014 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
1016 if ( rKey
== "ignore-empty" )
1017 mbIgnoreEmpty
= StringHelper::convertStringToBool( rData
);
1019 ConstList::implProcessConfigItemStr( rStrm
, rKey
, rData
);
1022 void MultiList::implSetName( sal_Int64 nKey
, const OUString
& rName
)
1024 OUStringVector aNames
;
1025 StringHelper::convertStringToStringList( aNames
, rName
, false );
1026 setNamesFromVec( nKey
, aNames
);
1029 FlagsList::FlagsList( const SharedConfigData
& rCfgData
) :
1030 NameListBase( rCfgData
),
1035 void FlagsList::implProcessConfigItemStr(
1036 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
1038 if ( rKey
== "ignore" )
1041 if( StringHelper::convertStringToInt( nIgnore
, rData
) )
1042 setIgnoreFlags( nIgnore
);
1046 NameListBase::implProcessConfigItemStr( rStrm
, rKey
, rData
);
1050 void FlagsList::implSetName( sal_Int64 nKey
, const OUString
& rName
)
1052 if( (nKey
!= 0) && ((nKey
& (nKey
- 1)) == 0) ) // only a single bit set?
1053 insertRawName( nKey
, rName
);
1056 OUString
FlagsList::implGetName( const Config
& /*rCfg*/, sal_Int64 nKey
) const
1058 sal_Int64 nFound
= mnIgnore
;
1059 OUStringBuffer aName
;
1061 for( const_iterator aIt
= begin(), aEnd
= end(); aIt
!= aEnd
; ++aIt
)
1063 sal_Int64 nMask
= aIt
->first
;
1064 setFlag( nFound
, nMask
);
1065 if( !getFlag( mnIgnore
, nMask
) )
1067 const OUString
& rFlagName
= aIt
->second
;
1068 bool bOnOff
= rFlagName
.startsWith(":");
1069 bool bFlag
= getFlag( nKey
, nMask
);
1072 StringHelper::appendToken( aName
, rFlagName
.subView( 1 ) );
1073 aName
.appendAscii( bFlag
? ":on" : ":off" );
1077 bool bNegated
= rFlagName
.startsWith("!");
1078 sal_Int32 nBothSep
= bNegated
? rFlagName
.indexOf( '!', 1 ) : -1;
1082 StringHelper::appendToken( aName
, rFlagName
);
1083 else if( nBothSep
> 0 )
1084 StringHelper::appendToken( aName
, rFlagName
.subView( nBothSep
+ 1 ) );
1089 StringHelper::appendToken( aName
, rFlagName
.subView( 1, nBothSep
- 1 ) );
1091 StringHelper::appendToken( aName
, rFlagName
.subView( 1 ) );
1096 // add unknown flags
1097 setFlag( nKey
, nFound
, false );
1100 OUStringBuffer
aUnknown( OUString::Concat(OOX_DUMP_UNKNOWN
) + OUStringChar(OOX_DUMP_ITEMSEP
) );
1101 StringHelper::appendShortHex( aUnknown
, nKey
);
1102 StringHelper::enclose( aUnknown
, '(', ')' );
1103 StringHelper::appendToken( aName
, aUnknown
);
1105 return aName
.makeStringAndClear();
1108 OUString
FlagsList::implGetNameDbl( const Config
& /*rCfg*/, double /*fValue*/ ) const
1113 void FlagsList::implIncludeList( const NameListBase
& rList
)
1115 if( const FlagsList
* pFlagsList
= dynamic_cast< const FlagsList
* >( &rList
) )
1116 mnIgnore
= pFlagsList
->mnIgnore
;
1119 bool CombiList::ExtItemFormatKey::operator<( const ExtItemFormatKey
& rRight
) const
1121 return (mnKey
< rRight
.mnKey
) || ((mnKey
== rRight
.mnKey
) && (maFilter
< rRight
.maFilter
));
1124 CombiList::CombiList( const SharedConfigData
& rCfgData
) :
1125 FlagsList( rCfgData
)
1129 void CombiList::implSetName( sal_Int64 nKey
, const OUString
& rName
)
1131 if( (nKey
& (nKey
- 1)) != 0 ) // more than a single bit set?
1133 ::std::set
< ExtItemFormatKey
> aItemKeys
;
1134 ExtItemFormat aItemFmt
;
1135 OUStringVector aRemain
= aItemFmt
.parse( rName
);
1136 for (auto const& elemRemain
: aRemain
)
1138 OUStringPair aPair
= StringHelper::convertStringToPair(elemRemain
);
1139 if ( aPair
.first
== "noshift" )
1141 aItemFmt
.mbShiftValue
= StringHelper::convertStringToBool( aPair
.second
);
1143 else if ( aPair
.first
== "filter" )
1145 OUStringPair aFilter
= StringHelper::convertStringToPair( aPair
.second
, '~' );
1146 ExtItemFormatKey
aKey( nKey
);
1147 if( !aFilter
.first
.isEmpty() && StringHelper::convertStringToInt( aKey
.maFilter
.first
, aFilter
.first
) &&
1148 !aFilter
.second
.isEmpty() && StringHelper::convertStringToInt( aKey
.maFilter
.second
, aFilter
.second
) )
1150 if( aKey
.maFilter
.first
== 0 )
1151 aKey
.maFilter
.second
= 0;
1152 aItemKeys
.insert( aKey
);
1156 if( aItemKeys
.empty() )
1157 aItemKeys
.insert( ExtItemFormatKey( nKey
) );
1158 for (auto const& itemKey
: aItemKeys
)
1159 maFmtMap
[itemKey
] = aItemFmt
;
1163 FlagsList::implSetName( nKey
, rName
);
1167 OUString
CombiList::implGetName( const Config
& rCfg
, sal_Int64 nKey
) const
1169 sal_Int64 nFound
= 0;
1170 OUStringBuffer aName
;
1171 // add known flag fields
1172 for (auto const& fmt
: maFmtMap
)
1174 const ExtItemFormatKey
& rMapKey
= fmt
.first
;
1175 sal_Int64 nMask
= rMapKey
.mnKey
;
1176 if( (nMask
!= 0) && ((nKey
& rMapKey
.maFilter
.first
) == rMapKey
.maFilter
.second
) )
1178 const ExtItemFormat
& rItemFmt
= fmt
.second
;
1180 sal_uInt64 nUFlags
= static_cast< sal_uInt64
>( nKey
);
1181 sal_uInt64 nUMask
= static_cast< sal_uInt64
>( nMask
);
1182 if( rItemFmt
.mbShiftValue
)
1183 while( (nUMask
& 1) == 0 ) { nUFlags
>>= 1; nUMask
>>= 1; }
1185 sal_uInt64 nUValue
= nUFlags
& nUMask
;
1186 sal_Int64 nSValue
= static_cast< sal_Int64
>( nUValue
);
1187 if( getFlag
< sal_uInt64
>( nUValue
, (nUMask
+ 1) >> 1 ) )
1188 setFlag( nSValue
, static_cast< sal_Int64
>( ~nUMask
) );
1190 OUStringBuffer
aItem( rItemFmt
.maItemName
);
1191 OUStringBuffer aValue
;
1192 switch( rItemFmt
.meDataType
)
1194 case DATATYPE_INT8
: StringHelper::appendValue( aValue
, static_cast< sal_Int8
>( nSValue
), rItemFmt
.meFmtType
); break;
1195 case DATATYPE_UINT8
: StringHelper::appendValue( aValue
, static_cast< sal_uInt8
>( nUValue
), rItemFmt
.meFmtType
); break;
1196 case DATATYPE_INT16
: StringHelper::appendValue( aValue
, static_cast< sal_Int16
>( nSValue
), rItemFmt
.meFmtType
); break;
1197 case DATATYPE_UINT16
: StringHelper::appendValue( aValue
, static_cast< sal_uInt16
>( nUValue
), rItemFmt
.meFmtType
); break;
1198 case DATATYPE_INT32
: StringHelper::appendValue( aValue
, static_cast< sal_Int32
>( nSValue
), rItemFmt
.meFmtType
); break;
1199 case DATATYPE_UINT32
: StringHelper::appendValue( aValue
, static_cast< sal_uInt32
>( nUValue
), rItemFmt
.meFmtType
); break;
1200 case DATATYPE_INT64
: StringHelper::appendValue( aValue
, nSValue
, rItemFmt
.meFmtType
); break;
1201 case DATATYPE_UINT64
: StringHelper::appendValue( aValue
, nUValue
, rItemFmt
.meFmtType
); break;
1202 case DATATYPE_FLOAT
: StringHelper::appendValue( aValue
, static_cast< float >( nSValue
), rItemFmt
.meFmtType
); break;
1203 case DATATYPE_DOUBLE
: StringHelper::appendValue( aValue
, static_cast< double >( nSValue
), rItemFmt
.meFmtType
); break;
1206 StringHelper::appendToken( aItem
, aValue
, OOX_DUMP_ITEMSEP
);
1207 if( !rItemFmt
.maListName
.isEmpty() )
1209 OUString aValueName
= rCfg
.getName( rItemFmt
.maListName
, static_cast< sal_Int64
>( nUValue
) );
1210 StringHelper::appendToken( aItem
, aValueName
, OOX_DUMP_ITEMSEP
);
1212 StringHelper::enclose( aItem
, '(', ')' );
1213 StringHelper::appendToken( aName
, aItem
);
1214 setFlag( nFound
, nMask
);
1217 setFlag( nKey
, nFound
, false );
1218 StringHelper::appendToken( aName
, FlagsList::implGetName( rCfg
, nKey
) );
1219 return aName
.makeStringAndClear();
1222 void CombiList::implIncludeList( const NameListBase
& rList
)
1224 if( const CombiList
* pCombiList
= dynamic_cast< const CombiList
* >( &rList
) )
1225 maFmtMap
= pCombiList
->maFmtMap
;
1226 FlagsList::implIncludeList( rList
);
1229 UnitConverter::UnitConverter( const SharedConfigData
& rCfgData
) :
1230 NameListBase( rCfgData
),
1235 void UnitConverter::implSetName( sal_Int64
/*nKey*/, const OUString
& /*rName*/ )
1240 OUString
UnitConverter::implGetName( const Config
& rCfg
, sal_Int64 nKey
) const
1242 return implGetNameDbl( rCfg
, static_cast< double >( nKey
) );
1245 OUString
UnitConverter::implGetNameDbl( const Config
& /*rCfg*/, double fValue
) const
1247 OUStringBuffer aValue
;
1248 StringHelper::appendDec( aValue
, mfFactor
* fValue
);
1249 aValue
.append( maUnitName
);
1250 return aValue
.makeStringAndClear();
1253 void UnitConverter::implIncludeList( const NameListBase
& /*rList*/ )
1257 const NameListRef
& NameListWrapper::getNameList( const Config
& rCfg
) const
1260 mxList
= rCfg
.getNameList( maName
);
1264 SharedConfigData::SharedConfigData( const OUString
& rFileName
,
1265 const Reference
< XComponentContext
>& rxContext
, StorageRef xRootStrg
,
1266 OUString aSysFileName
) :
1267 mxContext( rxContext
),
1268 mxRootStrg(std::move( xRootStrg
)),
1269 maSysFileName(std::move( aSysFileName
)),
1272 OUString aFileUrl
= InputOutputHelper::convertFileNameToUrl( rFileName
);
1273 if( !aFileUrl
.isEmpty() )
1275 sal_Int32 nNamePos
= InputOutputHelper::getFileNamePos( aFileUrl
);
1276 maConfigPath
= aFileUrl
.copy( 0, nNamePos
);
1277 mbLoaded
= readConfigFile( aFileUrl
);
1281 SharedConfigData::~SharedConfigData()
1285 const OUString
* SharedConfigData::getOption( const OUString
& rKey
) const
1287 ConfigDataMap::const_iterator aIt
= maConfigData
.find( rKey
);
1288 return (aIt
== maConfigData
.end()) ? nullptr : &aIt
->second
;
1291 void SharedConfigData::setNameList( const OUString
& rListName
, const NameListRef
& rxList
)
1293 if( !rListName
.isEmpty() )
1294 maNameLists
[ rListName
] = rxList
;
1297 void SharedConfigData::eraseNameList( const OUString
& rListName
)
1299 maNameLists
.erase( rListName
);
1302 NameListRef
SharedConfigData::getNameList( const OUString
& rListName
) const
1305 NameListMap::const_iterator aIt
= maNameLists
.find( rListName
);
1306 if( aIt
!= maNameLists
.end() )
1307 xList
= aIt
->second
;
1311 bool SharedConfigData::implIsValid() const
1313 return mbLoaded
&& mxContext
.is() && mxRootStrg
&& !maSysFileName
.isEmpty();
1316 void SharedConfigData::implProcessConfigItemStr(
1317 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
1319 if ( rKey
== "include-config-file" )
1320 readConfigFile( maConfigPath
+ rData
);
1321 else if ( rKey
== "constlist" )
1322 readNameList
< ConstList
>( rStrm
, rData
);
1323 else if ( rKey
== "multilist" )
1324 readNameList
< MultiList
>( rStrm
, rData
);
1325 else if ( rKey
== "flagslist" )
1326 readNameList
< FlagsList
>( rStrm
, rData
);
1327 else if ( rKey
== "combilist" )
1328 readNameList
< CombiList
>( rStrm
, rData
);
1329 else if ( rKey
== "shortlist" )
1330 createShortList( rData
);
1331 else if ( rKey
== "unitconverter" )
1332 createUnitConverter( rData
);
1334 maConfigData
[ rKey
] = rData
;
1337 bool SharedConfigData::readConfigFile( const OUString
& rFileUrl
)
1339 bool bLoaded
= maConfigFiles
.count( rFileUrl
) > 0;
1342 Reference
< XInputStream
> xInStrm
= InputOutputHelper::openInputStream( mxContext
, rFileUrl
);
1343 TextInputStream
aTxtStrm( mxContext
, xInStrm
, RTL_TEXTENCODING_UTF8
);
1344 if( !aTxtStrm
.isEof() )
1346 maConfigFiles
.insert( rFileUrl
);
1347 readConfigBlockContents( aTxtStrm
);
1354 void SharedConfigData::createShortList( std::u16string_view rData
)
1356 OUStringVector aDataVec
;
1357 StringHelper::convertStringToStringList( aDataVec
, rData
, false );
1358 if( aDataVec
.size() < 3 )
1361 sal_Int64 nStartKey
;
1362 if( StringHelper::convertStringToInt( nStartKey
, aDataVec
[ 1 ] ) )
1364 std::shared_ptr
< MultiList
> xList
= createNameList
< MultiList
>( aDataVec
[ 0 ] );
1367 aDataVec
.erase( aDataVec
.begin(), aDataVec
.begin() + 2 );
1368 xList
->setNamesFromVec( nStartKey
, aDataVec
);
1373 void SharedConfigData::createUnitConverter( std::u16string_view rData
)
1375 OUStringVector aDataVec
;
1376 StringHelper::convertStringToStringList( aDataVec
, rData
, false );
1377 if( aDataVec
.size() < 2 )
1380 OUString aFactor
= aDataVec
[ 1 ];
1381 bool bRecip
= aFactor
.startsWith("/");
1383 aFactor
= aFactor
.copy( 1 );
1385 if( StringHelper::convertStringToDouble( fFactor
, aFactor
) && (fFactor
!= 0.0) )
1387 std::shared_ptr
< UnitConverter
> xList
= createNameList
< UnitConverter
>( aDataVec
[ 0 ] );
1390 xList
->setFactor( bRecip
? (1.0 / fFactor
) : fFactor
);
1391 if( aDataVec
.size() >= 3 )
1392 xList
->setUnitName( aDataVec
[ 2 ] );
1397 Config::Config( const char* pcEnvVar
, const FilterBase
& rFilter
)
1399 construct( pcEnvVar
, rFilter
);
1402 Config::Config( const char* pcEnvVar
, const Reference
< XComponentContext
>& rxContext
, const StorageRef
& rxRootStrg
, const OUString
& rSysFileName
)
1404 construct( pcEnvVar
, rxContext
, rxRootStrg
, rSysFileName
);
1411 void Config::construct( const char* pcEnvVar
, const FilterBase
& rFilter
)
1413 if( !rFilter
.getFileUrl().isEmpty() )
1414 construct( pcEnvVar
, rFilter
.getComponentContext(), rFilter
.getStorage(), rFilter
.getFileUrl() );
1417 void Config::construct( const char* pcEnvVar
, const Reference
< XComponentContext
>& rxContext
, const StorageRef
& rxRootStrg
, const OUString
& rSysFileName
)
1419 if( pcEnvVar
&& rxRootStrg
&& !rSysFileName
.isEmpty() )
1420 if( const char* pcFileName
= ::getenv( pcEnvVar
) )
1421 mxCfgData
= std::make_shared
<SharedConfigData
>( OUString::createFromAscii( pcFileName
), rxContext
, rxRootStrg
, rSysFileName
);
1424 const OUString
& Config::getStringOption( const String
& rKey
, const OUString
& rDefault
) const
1426 const OUString
* pData
= implGetOption( rKey
);
1427 return pData
? *pData
: rDefault
;
1430 bool Config::getBoolOption( const String
& rKey
, bool bDefault
) const
1432 const OUString
* pData
= implGetOption( rKey
);
1433 return pData
? StringHelper::convertStringToBool( *pData
) : bDefault
;
1436 bool Config::isDumperEnabled() const
1438 return getBoolOption( "enable-dumper", false );
1441 bool Config::isImportEnabled() const
1443 return getBoolOption( "enable-import", true );
1446 void Config::eraseNameList( const String
& rListName
)
1448 mxCfgData
->eraseNameList( rListName
);
1451 NameListRef
Config::getNameList( const String
& rListName
) const
1453 return mxCfgData
->getNameList( rListName
);
1456 bool Config::implIsValid() const
1458 return isValid( mxCfgData
);
1461 const OUString
* Config::implGetOption( const OUString
& rKey
) const
1463 return mxCfgData
->getOption( rKey
);
1466 Output::Output( const Reference
< XComponentContext
>& rxContext
, const OUString
& rFileName
) :
1467 mxStrm( InputOutputHelper::openTextOutputStream( rxContext
, rFileName
, RTL_TEXTENCODING_UTF8
) ),
1475 mxStrm
->writeString( OUString( OOX_DUMP_BOM
) );
1478 void Output::newLine()
1480 if( maLine
.getLength() > 0 )
1482 mxStrm
->writeString( maIndent
);
1483 maLine
.append( '\n' );
1484 mxStrm
->writeString( maLine
.makeStringAndClear() );
1490 void Output::emptyLine( size_t nCount
)
1492 for( size_t nIdx
= 0; nIdx
< nCount
; ++nIdx
)
1493 mxStrm
->writeString( OUString('\n') );
1496 void Output::incIndent()
1498 OUStringBuffer
aBuffer( maIndent
);
1499 StringHelper::appendChar( aBuffer
, ' ', OOX_DUMP_INDENT
);
1500 maIndent
= aBuffer
.makeStringAndClear();
1503 void Output::decIndent()
1505 if( maIndent
.getLength() >= OOX_DUMP_INDENT
)
1506 maIndent
= maIndent
.copy( OOX_DUMP_INDENT
);
1509 void Output::startTable( sal_Int32 nW1
)
1511 startTable( 1, &nW1
);
1514 void Output::startTable( sal_Int32 nW1
, sal_Int32 nW2
)
1516 sal_Int32 pnColWidths
[ 2 ];
1517 pnColWidths
[ 0 ] = nW1
;
1518 pnColWidths
[ 1 ] = nW2
;
1519 startTable( 2, pnColWidths
);
1522 void Output::startTable( sal_Int32 nW1
, sal_Int32 nW2
, sal_Int32 nW3
, sal_Int32 nW4
)
1524 sal_Int32 pnColWidths
[ 4 ];
1525 pnColWidths
[ 0 ] = nW1
;
1526 pnColWidths
[ 1 ] = nW2
;
1527 pnColWidths
[ 2 ] = nW3
;
1528 pnColWidths
[ 3 ] = nW4
;
1529 startTable( 4, pnColWidths
);
1532 void Output::startTable( size_t nColCount
, const sal_Int32
* pnColWidths
)
1535 maColPos
.push_back( 0 );
1536 sal_Int32 nColPos
= 0;
1537 for( size_t nCol
= 0; nCol
< nColCount
; ++nCol
)
1539 nColPos
= nColPos
+ pnColWidths
[ nCol
];
1540 maColPos
.push_back( nColPos
);
1549 void Output::tab( size_t nCol
)
1552 if( mnCol
< maColPos
.size() )
1554 sal_Int32 nColPos
= maColPos
[ mnCol
];
1555 if( maLine
.getLength() >= nColPos
)
1556 maLine
.setLength( ::std::max
< sal_Int32
>( nColPos
- 1, 0 ) );
1557 StringHelper::appendChar( maLine
, ' ', nColPos
- maLine
.getLength() );
1561 StringHelper::appendChar( maLine
, ' ', 2 );
1565 void Output::endTable()
1570 void Output::resetItemIndex( sal_Int64 nIdx
)
1575 void Output::startItem( const String
& rItemName
)
1577 if( mnItemLevel
== 0 )
1579 if( (mnMultiLevel
> 0) && (maLine
.getLength() > 0) )
1581 if( rItemName
.has() )
1583 writeItemName( rItemName
);
1584 writeChar( OOX_DUMP_ITEMSEP
);
1588 mnLastItem
= maLine
.getLength();
1591 void Output::contItem()
1593 if( mnItemLevel
> 0 )
1595 if( (maLine
.getLength() == 0) || (maLine
[ maLine
.getLength() - 1 ] != OOX_DUMP_ITEMSEP
) )
1596 writeChar( OOX_DUMP_ITEMSEP
);
1597 mnLastItem
= maLine
.getLength();
1601 void Output::endItem()
1603 if( mnItemLevel
> 0 )
1605 maLastItem
= maLine
.copy( mnLastItem
).makeStringAndClear();
1606 if( maLastItem
.isEmpty() && mnLastItem
> 0 && maLine
[ mnLastItem
- 1 ] == OOX_DUMP_ITEMSEP
)
1607 maLine
.setLength( mnLastItem
- 1 );
1610 if( mnItemLevel
== 0 )
1612 if( mnMultiLevel
== 0 )
1619 void Output::startMultiItems()
1624 void Output::endMultiItems()
1626 if( mnMultiLevel
> 0 )
1628 if( mnMultiLevel
== 0 )
1632 void Output::writeChar( sal_Unicode cChar
, sal_Int32 nCount
)
1634 StringHelper::appendEncChar( maLine
, cChar
, nCount
);
1637 void Output::writeAscii( const char* pcStr
)
1640 maLine
.appendAscii( pcStr
);
1643 void Output::writeString( std::u16string_view rStr
)
1645 StringHelper::appendEncString( maLine
, rStr
);
1648 void Output::writeArray( const sal_uInt8
* pnData
, std::size_t nSize
, sal_Unicode cSep
)
1650 const sal_uInt8
* pnEnd
= pnData
? (pnData
+ nSize
) : nullptr;
1651 for( const sal_uInt8
* pnByte
= pnData
; pnByte
< pnEnd
; ++pnByte
)
1653 if( pnByte
> pnData
)
1655 writeHex( *pnByte
, false );
1659 void Output::writeBool( bool bData
)
1661 StringHelper::appendBool( maLine
, bData
);
1664 void Output::writeDateTime( const util::DateTime
& rDateTime
)
1666 writeDec( rDateTime
.Year
, 4, '0' );
1668 writeDec( rDateTime
.Month
, 2, '0' );
1670 writeDec( rDateTime
.Day
, 2, '0' );
1672 writeDec( rDateTime
.Hours
, 2, '0' );
1674 writeDec( rDateTime
.Minutes
, 2, '0' );
1676 writeDec( rDateTime
.Seconds
, 2, '0' );
1679 bool Output::implIsValid() const
1684 void Output::writeItemName( const String
& rItemName
)
1686 if( rItemName
.has() && (rItemName
[ 0 ] == '#') )
1688 writeString( rItemName
.subView( 1 ) );
1689 StringHelper::appendIndex( maLine
, mnItemIdx
++ );
1692 writeString( rItemName
);
1695 StorageIterator::StorageIterator( StorageRef xStrg
) :
1696 mxStrg(std::move( xStrg
))
1699 mxStrg
->getElementNames( maNames
);
1700 maIt
= maNames
.begin();
1703 StorageIterator::~StorageIterator()
1707 StorageIterator
& StorageIterator::operator++()
1709 if( maIt
!= maNames
.end() )
1714 OUString
StorageIterator::getName() const
1717 if( maIt
!= maNames
.end() )
1722 bool StorageIterator::isStream() const
1724 return isValid() && mxStrg
->openInputStream( *maIt
).is();
1727 bool StorageIterator::isStorage() const
1731 StorageRef xStrg
= mxStrg
->openSubStorage( *maIt
, false );
1732 return xStrg
&& xStrg
->isStorage();
1735 bool StorageIterator::implIsValid() const
1737 return mxStrg
&& mxStrg
->isStorage() && (maIt
!= maNames
.end());
1740 ObjectBase::~ObjectBase()
1744 void ObjectBase::construct( const ConfigRef
& rxConfig
)
1746 mxConfig
= rxConfig
;
1749 void ObjectBase::construct( const ObjectBase
& rParent
)
1754 void ObjectBase::dump()
1760 bool ObjectBase::implIsValid() const
1762 return isValid( mxConfig
);
1765 void ObjectBase::implDump()
1769 void StorageObjectBase::construct( const ObjectBase
& rParent
, const StorageRef
& rxStrg
, const OUString
& rSysPath
)
1771 ObjectBase::construct( rParent
);
1773 maSysPath
= rSysPath
;
1776 void StorageObjectBase::construct( const ObjectBase
& rParent
)
1778 ObjectBase::construct( rParent
);
1779 if( ObjectBase::implIsValid() )
1781 mxStrg
= cfg().getRootStorage();
1782 maSysPath
= cfg().getSysFileName();
1786 bool StorageObjectBase::implIsValid() const
1788 return mxStrg
&& !maSysPath
.isEmpty() && ObjectBase::implIsValid();
1791 void StorageObjectBase::implDump()
1793 bool bIsStrg
= mxStrg
->isStorage();
1794 bool bIsRoot
= mxStrg
->isRootStorage();
1795 Reference
< XInputStream
> xBaseStrm
;
1797 xBaseStrm
= mxStrg
->openInputStream( OUString() );
1799 OUString aSysOutPath
= maSysPath
;
1802 aSysOutPath
+= OOX_DUMP_DUMPEXT
;
1803 Reference
<XSimpleFileAccess3
> xFileAccess(SimpleFileAccess::create(getContext()));
1804 xFileAccess
->kill( aSysOutPath
);
1812 extractStorage( mxStrg
, OUString(), aSysOutPath
);
1814 else if( xBaseStrm
.is() )
1816 BinaryInputStreamRef
xInStrm( std::make_shared
<BinaryXInputStream
>( xBaseStrm
, false ) );
1817 xInStrm
->seekToStart();
1818 implDumpBaseStream( xInStrm
, aSysOutPath
);
1822 void StorageObjectBase::implDumpStream( const Reference
< XInputStream
>&, const OUString
&, const OUString
&, const OUString
& )
1826 void StorageObjectBase::implDumpStorage( const StorageRef
& rxStrg
, const OUString
& rStrgPath
, const OUString
& rSysPath
)
1828 extractStorage( rxStrg
, rStrgPath
, rSysPath
);
1831 void StorageObjectBase::implDumpBaseStream( const BinaryInputStreamRef
&, const OUString
& )
1835 void StorageObjectBase::addPreferredStream( const String
& rStrmName
)
1837 if( rStrmName
.has() )
1838 maPreferred
.emplace_back( rStrmName
, false );
1841 void StorageObjectBase::addPreferredStorage( const String
& rStrgPath
)
1843 if( rStrgPath
.has() )
1844 maPreferred
.emplace_back( rStrgPath
, true );
1847 OUString
StorageObjectBase::getSysFileName(
1848 std::u16string_view rStrmName
, std::u16string_view rSysOutPath
)
1850 // encode all characters < 0x20
1851 OUStringBuffer aBuffer
;
1852 StringHelper::appendEncString( aBuffer
, rStrmName
, false );
1854 // replace all characters reserved in file system
1855 OUString aFileName
= aBuffer
.makeStringAndClear();
1856 static const sal_Unicode spcReserved
[] = { '/', '\\', ':', '*', '?', '<', '>', '|' };
1857 for(const sal_Unicode cChar
: spcReserved
)
1858 aFileName
= aFileName
.replace(cChar
, '_');
1861 return OUString::Concat(rSysOutPath
) + "/" + aFileName
;
1864 void StorageObjectBase::extractStream( StorageBase
& rStrg
, const OUString
& rStrgPath
, const OUString
& rStrmName
, const OUString
& rSysFileName
)
1866 BinaryXInputStream
aInStrm( rStrg
.openInputStream( rStrmName
), true );
1867 if( !aInStrm
.isEof() )
1869 BinaryXOutputStream
aOutStrm( InputOutputHelper::openOutputStream( getContext(), rSysFileName
), true );
1870 if( !aOutStrm
.isEof() )
1871 aInStrm
.copyToStream( aOutStrm
);
1873 Reference
< XInputStream
> xDumpStrm
= InputOutputHelper::openInputStream( getContext(), rSysFileName
);
1874 if( xDumpStrm
.is() )
1875 implDumpStream( xDumpStrm
, rStrgPath
, rStrmName
, rSysFileName
);
1878 void StorageObjectBase::extractStorage( const StorageRef
& rxStrg
, const OUString
& rStrgPath
, const OUString
& rSysPath
)
1880 // create directory in file system
1881 ::osl::FileBase::RC eRes
= ::osl::Directory::create( rSysPath
);
1882 if( (eRes
!= ::osl::FileBase::E_None
) && (eRes
!= ::osl::FileBase::E_EXIST
) )
1885 // process preferred storages and streams in root storage first
1886 if( rStrgPath
.isEmpty() )
1888 for (auto const& elemPreferred
: maPreferred
)
1889 extractItem( rxStrg
, rStrgPath
, elemPreferred
.maName
, rSysPath
, elemPreferred
.mbStorage
, !elemPreferred
.mbStorage
);
1892 // process children of the storage
1893 for( StorageIterator
aIt( rxStrg
); aIt
.isValid(); ++aIt
)
1895 // skip processed preferred items
1896 OUString aItemName
= aIt
.getName();
1897 bool bFound
= false;
1898 if( rStrgPath
.isEmpty() )
1900 for (auto const& elemPreferred
: maPreferred
)
1902 bFound
= elemPreferred
.maName
== aItemName
;
1908 extractItem( rxStrg
, rStrgPath
, aItemName
, rSysPath
, aIt
.isStorage(), aIt
.isStream() );
1912 void StorageObjectBase::extractItem( const StorageRef
& rxStrg
, const OUString
& rStrgPath
, const OUString
& rItemName
, std::u16string_view rSysPath
, bool bIsStrg
, bool bIsStrm
)
1914 OUString aSysFileName
= getSysFileName( rItemName
, rSysPath
);
1917 OUStringBuffer
aStrgPath( rStrgPath
);
1918 StringHelper::appendToken( aStrgPath
, rItemName
, '/' );
1919 implDumpStorage( rxStrg
->openSubStorage( rItemName
, false ), aStrgPath
.makeStringAndClear(), aSysFileName
);
1923 extractStream( *rxStrg
, rStrgPath
, rItemName
, aSysFileName
);
1927 OutputObjectBase::~OutputObjectBase()
1931 void OutputObjectBase::construct( const ObjectBase
& rParent
, const OUString
& rSysFileName
)
1933 ObjectBase::construct( rParent
);
1934 if( ObjectBase::implIsValid() )
1936 maSysFileName
= rSysFileName
;
1937 mxOut
= std::make_shared
<Output
>( getContext(), rSysFileName
+ OOX_DUMP_DUMPEXT
);
1941 void OutputObjectBase::construct( const OutputObjectBase
& rParent
)
1946 bool OutputObjectBase::implIsValid() const
1948 return isValid( mxOut
) && ObjectBase::implIsValid();
1951 void OutputObjectBase::writeEmptyItem( const String
& rName
)
1953 ItemGuard
aItem( mxOut
, rName
);
1956 void OutputObjectBase::writeInfoItem( const String
& rName
, const String
& rData
)
1958 ItemGuard
aItem( mxOut
, rName
);
1959 mxOut
->writeString( rData
);
1962 void OutputObjectBase::writeCharItem( const String
& rName
, sal_Unicode cData
)
1964 ItemGuard
aItem( mxOut
, rName
);
1965 mxOut
->writeChar( OOX_DUMP_STRQUOTE
);
1966 mxOut
->writeChar( cData
);
1967 mxOut
->writeChar( OOX_DUMP_STRQUOTE
);
1970 void OutputObjectBase::writeStringItem( const String
& rName
, std::u16string_view rData
)
1972 ItemGuard
aItem( mxOut
, rName
);
1973 mxOut
->writeAscii( "(len=" );
1974 mxOut
->writeDec( sal_Int32(rData
.size()) );
1975 mxOut
->writeAscii( ")," );
1976 OUStringBuffer
aValue( rData
.substr( 0, ::std::min( sal_Int32(rData
.size()), OOX_DUMP_MAXSTRLEN
) ) );
1977 StringHelper::enclose( aValue
, OOX_DUMP_STRQUOTE
);
1978 mxOut
->writeString( aValue
.makeStringAndClear() );
1979 if( rData
.size() > OOX_DUMP_MAXSTRLEN
)
1980 mxOut
->writeAscii( ",cut" );
1983 void OutputObjectBase::writeArrayItem( const String
& rName
, const sal_uInt8
* pnData
, std::size_t nSize
, sal_Unicode cSep
)
1985 ItemGuard
aItem( mxOut
, rName
);
1986 mxOut
->writeArray( pnData
, nSize
, cSep
);
1989 void OutputObjectBase::writeDateTimeItem( const String
& rName
, const util::DateTime
& rDateTime
)
1991 ItemGuard
aItem( mxOut
, rName
);
1992 mxOut
->writeDateTime( rDateTime
);
1995 void OutputObjectBase::writeGuidItem( const String
& rName
, const OUString
& rGuid
)
1997 ItemGuard
aItem( mxOut
, rName
);
1998 mxOut
->writeString( rGuid
);
2000 mxOut
->writeString( cfg().getStringOption( rGuid
, OUString() ) );
2003 InputObjectBase::~InputObjectBase()
2007 void InputObjectBase::construct( const ObjectBase
& rParent
, const BinaryInputStreamRef
& rxStrm
, const OUString
& rSysFileName
)
2009 OutputObjectBase::construct( rParent
, rSysFileName
);
2013 void InputObjectBase::construct( const OutputObjectBase
& rParent
, const BinaryInputStreamRef
& rxStrm
)
2015 OutputObjectBase::construct( rParent
);
2019 void InputObjectBase::construct( const InputObjectBase
& rParent
)
2024 bool InputObjectBase::implIsValid() const
2026 return mxStrm
&& OutputObjectBase::implIsValid();
2029 void InputObjectBase::skipBlock( sal_Int64 nBytes
, bool bShowSize
)
2031 sal_Int64 nEndPos
= ::std::min
< sal_Int64
>( mxStrm
->tell() + nBytes
, mxStrm
->size() );
2032 if( mxStrm
->tell() < nEndPos
)
2035 writeDecItem( "skipped-data-size", static_cast< sal_uInt64
>( nEndPos
- mxStrm
->tell() ) );
2036 mxStrm
->seek( nEndPos
);
2040 void InputObjectBase::dumpRawBinary( sal_Int64 nBytes
, bool bShowOffset
, bool bStream
)
2042 TableGuard
aTabGuard( mxOut
,
2043 bShowOffset
? 12 : 0,
2044 3 * OOX_DUMP_BYTESPERLINE
/ 2 + 1,
2045 3 * OOX_DUMP_BYTESPERLINE
/ 2 + 1,
2046 OOX_DUMP_BYTESPERLINE
/ 2 + 1 );
2048 sal_Int64 nMaxShowSize
= cfg().getIntOption
< sal_Int64
>(
2049 bStream
? "max-binary-stream-size" : "max-binary-data-size", SAL_MAX_INT64
);
2051 bool bSeekable
= mxStrm
->size() >= 0;
2052 sal_Int64 nEndPos
= bSeekable
? ::std::min
< sal_Int64
>( mxStrm
->tell() + nBytes
, mxStrm
->size() ) : 0;
2053 sal_Int64 nDumpEnd
= bSeekable
? ::std::min
< sal_Int64
>( mxStrm
->tell() + nMaxShowSize
, nEndPos
) : nMaxShowSize
;
2054 sal_Int64 nPos
= bSeekable
? mxStrm
->tell() : 0;
2057 while( bLoop
&& (nPos
< nDumpEnd
) )
2059 mxOut
->writeHex( static_cast< sal_uInt32
>( nPos
) );
2062 sal_uInt8 pnLineData
[ OOX_DUMP_BYTESPERLINE
];
2063 sal_Int32 nLineSize
= bSeekable
? ::std::min( static_cast< sal_Int32
>( nDumpEnd
- mxStrm
->tell() ), OOX_DUMP_BYTESPERLINE
) : OOX_DUMP_BYTESPERLINE
;
2064 sal_Int32 nReadSize
= mxStrm
->readMemory( pnLineData
, nLineSize
);
2065 bLoop
= nReadSize
== nLineSize
;
2070 const sal_uInt8
* pnByte
= nullptr;
2071 const sal_uInt8
* pnEnd
= nullptr;
2072 for( pnByte
= pnLineData
, pnEnd
= pnLineData
+ nReadSize
; pnByte
!= pnEnd
; ++pnByte
)
2074 if( (pnByte
- pnLineData
) == (OOX_DUMP_BYTESPERLINE
/ 2) ) mxOut
->tab();
2075 mxOut
->writeHex( *pnByte
, false );
2076 mxOut
->writeChar( ' ' );
2080 for( pnByte
= pnLineData
, pnEnd
= pnLineData
+ nReadSize
; pnByte
!= pnEnd
; ++pnByte
)
2082 if( (pnByte
- pnLineData
) == (OOX_DUMP_BYTESPERLINE
/ 2) ) mxOut
->tab();
2083 mxOut
->writeChar( static_cast< sal_Unicode
>( (*pnByte
< 0x20) ? '.' : *pnByte
) );
2089 // skip undumped data
2091 skipBlock( nEndPos
- mxStrm
->tell() );
2094 void InputObjectBase::dumpBinary( const String
& rName
, sal_Int64 nBytes
, bool bShowOffset
)
2097 MultiItemsGuard
aMultiGuard( mxOut
);
2098 writeEmptyItem( rName
);
2099 writeDecItem( "size", nBytes
);
2101 IndentGuard
aIndGuard( mxOut
);
2102 dumpRawBinary( nBytes
, bShowOffset
);
2105 void InputObjectBase::dumpRemaining( sal_Int64 nBytes
)
2109 if( cfg().getBoolOption( "show-trailing-unknown", true ) )
2110 dumpBinary( "remaining-data", nBytes
, false );
2112 skipBlock( nBytes
);
2116 void InputObjectBase::dumpRemainingTo( sal_Int64 nPos
)
2118 if( mxStrm
->isEof() || (mxStrm
->tell() > nPos
) )
2119 writeInfoItem( "stream-state", OOX_DUMP_ERR_STREAM
);
2121 dumpRemaining( nPos
- mxStrm
->tell() );
2122 mxStrm
->seek( nPos
);
2125 void InputObjectBase::dumpRemainingStream()
2127 dumpRemainingTo( mxStrm
->size() );
2130 void InputObjectBase::dumpArray( const String
& rName
, sal_Int32 nBytes
, sal_Unicode cSep
)
2132 sal_Int32 nDumpSize
= getLimitedValue
< sal_Int32
, sal_Int64
>( mxStrm
->size() - mxStrm
->tell(), 0, nBytes
);
2133 if( nDumpSize
> OOX_DUMP_MAXARRAY
)
2135 dumpBinary( rName
, nBytes
, false );
2137 else if( nDumpSize
> 1 )
2139 sal_uInt8 pnData
[ OOX_DUMP_MAXARRAY
];
2140 mxStrm
->readMemory( pnData
, nDumpSize
);
2141 writeArrayItem( rName
, pnData
, nDumpSize
, cSep
);
2143 else if( nDumpSize
== 1 )
2144 dumpHex
< sal_uInt8
>( rName
);
2147 sal_Unicode
InputObjectBase::dumpUnicode( const String
& rName
)
2149 sal_uInt16 nChar
= mxStrm
->readuInt16();
2150 sal_Unicode cChar
= static_cast< sal_Unicode
>( nChar
);
2151 writeCharItem( rName( "char" ), cChar
);
2155 OUString
InputObjectBase::dumpCharArray( const String
& rName
, sal_Int32 nLen
, rtl_TextEncoding eTextEnc
, bool bHideTrailingNul
)
2157 sal_Int32 nDumpSize
= getLimitedValue
< sal_Int32
, sal_Int64
>( mxStrm
->size() - mxStrm
->tell(), 0, nLen
);
2161 ::std::vector
< char > aBuffer( static_cast< std::size_t >( nLen
) + 1 );
2162 sal_Int32 nCharsRead
= mxStrm
->readMemory(aBuffer
.data(), nLen
);
2163 aBuffer
[ nCharsRead
] = 0;
2164 aString
= OStringToOUString(std::string_view(aBuffer
.data()), eTextEnc
);
2166 if( bHideTrailingNul
)
2167 aString
= StringHelper::trimTrailingNul( aString
);
2168 writeStringItem( rName( "text" ), aString
);
2172 OUString
InputObjectBase::dumpUnicodeArray( const String
& rName
, sal_Int32 nLen
, bool bHideTrailingNul
)
2174 OUStringBuffer aBuffer
;
2175 for( sal_Int32 nIndex
= 0; !mxStrm
->isEof() && (nIndex
< nLen
); ++nIndex
)
2177 aBuffer
.append( static_cast< sal_Unicode
>( mxStrm
->readuInt16() ) );
2179 OUString aString
= aBuffer
.makeStringAndClear();
2180 if( bHideTrailingNul
)
2181 aString
= StringHelper::trimTrailingNul( aString
);
2182 writeStringItem( rName( "text" ), aString
);
2186 util::DateTime
InputObjectBase::dumpFileTime( const String
& rName
)
2188 util::DateTime aDateTime
;
2190 ItemGuard
aItem( mxOut
, rName( "file-time" ) );
2191 sal_Int64 nFileTime
= dumpDec
< sal_Int64
>( EMPTY_STRING
);
2192 // file time is in 10^-7 seconds (100 nanoseconds), convert to nanoseconds
2195 sal_Int64 nDays
= nFileTime
/ sal_Int64( ::tools::Time::nanoSecPerDay
);
2196 // number of entire years
2197 sal_Int64 nYears
= (nDays
- (nDays
/ (4 * 365)) + (nDays
/ (100 * 365)) - (nDays
/ (400 * 365))) / 365;
2198 // remaining days in the year
2199 sal_Int64 nDaysInYear
= nDays
- (nYears
* 365 + nYears
/ 4 - nYears
/ 100 + nYears
/ 400);
2200 // the year (file dates start from 1601-01-01)
2201 aDateTime
.Year
= static_cast< sal_uInt16
>( 1601 + nYears
);
2203 bool bLeap
= ((aDateTime
.Year
% 4 == 0) && (aDateTime
.Year
% 100 != 0)) || (aDateTime
.Year
% 400 == 0);
2204 // static arrays with number of days in month
2205 static const sal_Int64 spnDaysInMonth
[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
2206 static const sal_Int64 spnDaysInMonthL
[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
2207 const sal_Int64
* pnDaysInMonth
= bLeap
? spnDaysInMonthL
: spnDaysInMonth
;
2209 aDateTime
.Month
= 1;
2210 while( nDaysInYear
>= *pnDaysInMonth
)
2212 nDaysInYear
-= *pnDaysInMonth
++;
2216 aDateTime
.Day
= static_cast< sal_uInt16
>( nDaysInYear
+ 1 );
2217 // number of nanoseconds in the day
2218 sal_Int64 nTimeInDay
= nFileTime
% sal_Int64( ::tools::Time::nanoSecPerDay
);
2220 aDateTime
.NanoSeconds
= static_cast< sal_uInt32
>( nTimeInDay
% ::tools::Time::nanoSecPerSec
);
2221 nTimeInDay
/= ::tools::Time::nanoSecPerSec
;
2223 aDateTime
.Seconds
= static_cast< sal_uInt16
>( nTimeInDay
% ::tools::Time::secondPerMinute
);
2224 nTimeInDay
/= ::tools::Time::secondPerMinute
;
2226 aDateTime
.Minutes
= static_cast< sal_uInt16
>( nTimeInDay
% ::tools::Time::minutePerHour
);
2227 nTimeInDay
/= ::tools::Time::minutePerHour
;
2229 aDateTime
.Hours
= static_cast< sal_uInt16
>( nTimeInDay
);
2231 writeDateTimeItem( EMPTY_STRING
, aDateTime
);
2235 OUString
InputObjectBase::dumpGuid( const String
& rName
)
2237 OUStringBuffer aBuffer
;
2242 nData32
= mxStrm
->readuInt32();
2243 StringHelper::appendHex( aBuffer
, nData32
, false );
2244 aBuffer
.append( '-' );
2245 nData16
= mxStrm
->readuInt16();
2246 StringHelper::appendHex( aBuffer
, nData16
, false );
2247 aBuffer
.append( '-' );
2248 nData16
= mxStrm
->readuInt16();
2249 StringHelper::appendHex( aBuffer
, nData16
, false );
2250 aBuffer
.append( '-' );
2251 nData8
= mxStrm
->readuChar();
2252 StringHelper::appendHex( aBuffer
, nData8
, false );
2253 nData8
= mxStrm
->readuChar( );
2254 StringHelper::appendHex( aBuffer
, nData8
, false );
2255 aBuffer
.append( '-' );
2256 for( int nIndex
= 0; nIndex
< 6; ++nIndex
)
2258 nData8
= mxStrm
->readuChar( );
2259 StringHelper::appendHex( aBuffer
, nData8
, false );
2261 StringHelper::enclose( aBuffer
, '{', '}' );
2262 OUString aGuid
= aBuffer
.makeStringAndClear();
2263 writeGuidItem( rName( "guid" ), aGuid
);
2267 void InputObjectBase::dumpItem( const ItemFormat
& rItemFmt
)
2269 switch( rItemFmt
.meDataType
)
2271 case DATATYPE_VOID
: break;
2272 case DATATYPE_INT8
: dumpValue
< sal_Int8
>( rItemFmt
); break;
2273 case DATATYPE_UINT8
: dumpValue
< sal_uInt8
>( rItemFmt
); break;
2274 case DATATYPE_INT16
: dumpValue
< sal_Int16
>( rItemFmt
); break;
2275 case DATATYPE_UINT16
: dumpValue
< sal_uInt16
>( rItemFmt
); break;
2276 case DATATYPE_INT32
: dumpValue
< sal_Int32
>( rItemFmt
); break;
2277 case DATATYPE_UINT32
: dumpValue
< sal_uInt32
>( rItemFmt
); break;
2278 case DATATYPE_INT64
: dumpValue
< sal_Int64
>( rItemFmt
); break;
2279 case DATATYPE_UINT64
: dumpValue
< sal_uInt64
>( rItemFmt
); break;
2280 case DATATYPE_FLOAT
: dumpValue
< float >( rItemFmt
); break;
2281 case DATATYPE_DOUBLE
: dumpValue
< double >( rItemFmt
); break;
2286 BinaryStreamObject::BinaryStreamObject( const ObjectBase
& rParent
, const BinaryInputStreamRef
& rxStrm
, const OUString
& rSysFileName
)
2288 InputObjectBase::construct( rParent
, rxStrm
, rSysFileName
);
2291 void BinaryStreamObject::dumpBinaryStream( bool bShowOffset
)
2293 mxStrm
->seekToStart();
2294 dumpRawBinary( mxStrm
->size(), bShowOffset
, true );
2298 void BinaryStreamObject::implDump()
2303 void TextStreamObjectBase::construct( const ObjectBase
& rParent
,
2304 const BinaryInputStreamRef
& rxStrm
, rtl_TextEncoding eTextEnc
, const OUString
& rSysFileName
)
2306 InputObjectBase::construct( rParent
, rxStrm
, rSysFileName
);
2307 constructTextStrmObj( eTextEnc
);
2310 void TextStreamObjectBase::construct( const OutputObjectBase
& rParent
,
2311 const BinaryInputStreamRef
& rxStrm
, rtl_TextEncoding eTextEnc
)
2313 InputObjectBase::construct( rParent
, rxStrm
);
2314 constructTextStrmObj( eTextEnc
);
2317 bool TextStreamObjectBase::implIsValid() const
2319 return InputObjectBase::implIsValid() && mxTextStrm
;
2322 void TextStreamObjectBase::implDump()
2324 implDumpText( *mxTextStrm
);
2327 void TextStreamObjectBase::constructTextStrmObj( rtl_TextEncoding eTextEnc
)
2330 mxTextStrm
= std::make_shared
<TextInputStream
>( getContext(), *mxStrm
, eTextEnc
);
2333 TextLineStreamObject::TextLineStreamObject( const ObjectBase
& rParent
,
2334 const BinaryInputStreamRef
& rxStrm
, rtl_TextEncoding eTextEnc
, const OUString
& rSysFileName
)
2336 TextStreamObjectBase::construct( rParent
, rxStrm
, eTextEnc
, rSysFileName
);
2339 TextLineStreamObject::TextLineStreamObject( const OutputObjectBase
& rParent
,
2340 const BinaryInputStreamRef
& rxStrm
, rtl_TextEncoding eTextEnc
)
2342 TextStreamObjectBase::construct( rParent
, rxStrm
, eTextEnc
);
2345 void TextLineStreamObject::implDumpText( TextInputStream
& rTextStrm
)
2347 sal_uInt32 nLine
= 0;
2348 while( !rTextStrm
.isEof() )
2350 OUString aLine
= rTextStrm
.readLine();
2351 if( !rTextStrm
.isEof() || !aLine
.isEmpty() )
2352 implDumpLine( aLine
, ++nLine
);
2356 void TextLineStreamObject::implDumpLine( std::u16string_view rLine
, sal_uInt32 nLine
)
2358 TableGuard
aTabGuard( mxOut
, 8 );
2359 mxOut
->writeDec( nLine
, 6 );
2361 mxOut
->writeString( rLine
);
2365 XmlStreamObject::XmlStreamObject( const ObjectBase
& rParent
,
2366 const BinaryInputStreamRef
& rxStrm
, const OUString
& rSysFileName
)
2368 TextStreamObjectBase::construct( rParent
, rxStrm
, RTL_TEXTENCODING_UTF8
, rSysFileName
);
2371 void XmlStreamObject::implDumpText( TextInputStream
& rTextStrm
)
2373 /* Buffers a start element and the following element text. Needed to dump
2374 matching start/end elements and the element text on the same line. */
2375 OUStringBuffer aOldStartElem
;
2376 // special handling for VML
2377 bool bIsVml
= o3tl::equalsIgnoreAsciiCase(InputOutputHelper::getFileNameExtension( maSysFileName
), u
"vml");
2379 while( !rTextStrm
.isEof() )
2381 // get the next element and the following element text from text stream
2382 OUString aElem
= rTextStrm
.readToChar( '>', true ).trim();
2383 OUString aText
= rTextStrm
.readToChar( '<', false );
2385 // remove multiple whitespace from element
2387 while( nPos
< aElem
.getLength() )
2389 while( (nPos
< aElem
.getLength()) && (aElem
[ nPos
] >= 32) ) ++nPos
;
2390 if( nPos
< aElem
.getLength() )
2391 aElem
= aElem
.subView( 0, nPos
) + OUStringChar(' ') + o3tl::trim(aElem
.subView( nPos
));
2395 sal_Int32 nElemLen
= aElem
.getLength();
2396 if( (nElemLen
>= 2) && (aElem
[ 0 ] == '<') && (aElem
[ nElemLen
- 1 ] == '>') )
2398 // determine type of the element
2399 bool bSimpleElem
= (aElem
[ 1 ] == '!') || (aElem
[ 1 ] == '?') || (aElem
[ nElemLen
- 2 ] == '/') ||
2400 (bIsVml
&& (nElemLen
== 4) && (aElem
[ 1 ] == 'b') && (aElem
[ 2 ] == 'r'));
2401 bool bStartElem
= !bSimpleElem
&& (aElem
[ 1 ] != '/');
2402 bool bEndElem
= !bSimpleElem
&& !bStartElem
;
2404 /* Start element or simple element: flush old start element and
2405 its text from previous iteration, and start a new indentation
2406 level for the new element. Trim whitespace and line breaks from
2407 the text of the old start element. */
2408 if( (bSimpleElem
|| bStartElem
) && (aOldStartElem
.getLength() > 0) )
2410 mxOut
->writeString( o3tl::trim(aOldStartElem
.makeStringAndClear()) );
2415 /* Start element: remember it and its text, to be able to print the
2416 matching end element on the same line in the next iteration. */
2419 aOldStartElem
.append( aElem
+ aText
);
2423 /* End element: if a start element has been remembered in the
2424 previous iteration, write it out here untrimmed, to show
2425 all whitespace in the element text, and without trailing
2426 line break. Code below will add the end element right after
2427 it. Otherwise, return to previous indentation level. */
2430 if( aOldStartElem
.getLength() == 0 )
2433 mxOut
->writeString( aOldStartElem
.makeStringAndClear() );
2436 /* Write the element. Write following element text in a new
2437 line, but only, if it does not contain of white space
2439 mxOut
->writeString( aElem
);
2441 if( !o3tl::trim(aText
).empty() )
2443 mxOut
->writeString( aText
);
2451 void RecordObjectBase::construct( const ObjectBase
& rParent
,
2452 const BinaryInputStreamRef
& rxBaseStrm
, const OUString
& rSysFileName
,
2453 const BinaryInputStreamRef
& rxRecStrm
, const String
& rRecNames
, const String
& rSimpleRecs
)
2455 InputObjectBase::construct( rParent
, rxRecStrm
, rSysFileName
);
2456 constructRecObjBase( rxBaseStrm
, rRecNames
, rSimpleRecs
);
2459 bool RecordObjectBase::implIsValid() const
2461 return mxBaseStrm
&& InputObjectBase::implIsValid();
2464 void RecordObjectBase::implDump()
2466 NameListRef xRecNames
= maRecNames
.getNameList( cfg() );
2467 ItemFormatMap
aSimpleRecs( maSimpleRecs
.getNameList( cfg() ) );
2469 while( implStartRecord( *mxBaseStrm
, mnRecPos
, mnRecId
, mnRecSize
) )
2474 implWriteExtHeader();
2475 IndentGuard
aIndGuard( mxOut
);
2476 sal_Int64 nRecPos
= mxStrm
->tell();
2479 if( !mbBinaryOnly
&& cfg().hasName( xRecNames
, mnRecId
) )
2481 ::std::map
< sal_Int64
, ItemFormat
>::const_iterator aIt
= aSimpleRecs
.find( mnRecId
);
2482 if( aIt
!= aSimpleRecs
.end() )
2483 dumpItem( aIt
->second
);
2485 implDumpRecordBody();
2488 // remaining undumped data
2489 if( !mxStrm
->isEof() && (mxStrm
->tell() == nRecPos
) )
2490 dumpRawBinary( mnRecSize
, false );
2492 dumpRemainingTo( nRecPos
+ mnRecSize
);
2496 void RecordObjectBase::implWriteExtHeader()
2500 void RecordObjectBase::implDumpRecordBody()
2504 void RecordObjectBase::constructRecObjBase( const BinaryInputStreamRef
& rxBaseStrm
, const String
& rRecNames
, const String
& rSimpleRecs
)
2506 mxBaseStrm
= rxBaseStrm
;
2507 maRecNames
= rRecNames
;
2508 maSimpleRecs
= rSimpleRecs
;
2509 mnRecPos
= mnRecId
= mnRecSize
= 0;
2510 mbBinaryOnly
= false;
2511 if( InputObjectBase::implIsValid() )
2512 mbShowRecPos
= cfg().getBoolOption( "show-record-position", true );
2515 void RecordObjectBase::writeHeader()
2517 MultiItemsGuard
aMultiGuard( mxOut
);
2518 writeEmptyItem( "REC" );
2519 if( mbShowRecPos
&& mxBaseStrm
->isSeekable() )
2520 writeShortHexItem( "pos", mnRecPos
, "CONV-DEC" );
2521 writeShortHexItem( "size", mnRecSize
, "CONV-DEC" );
2522 ItemGuard
aItem( mxOut
, "id" );
2523 mxOut
->writeShortHex( mnRecId
);
2524 addNameToItem( mnRecId
, "CONV-DEC" );
2525 addNameToItem( mnRecId
, maRecNames
);
2528 void SequenceRecordObjectBase::construct( const ObjectBase
& rParent
,
2529 const BinaryInputStreamRef
& rxBaseStrm
, const OUString
& rSysFileName
,
2530 const String
& rRecNames
, const String
& rSimpleRecs
)
2532 BinaryInputStreamRef
xRecStrm( std::make_shared
<SequenceInputStream
>( *mxRecData
) );
2533 RecordObjectBase::construct( rParent
, rxBaseStrm
, rSysFileName
, xRecStrm
, rRecNames
, rSimpleRecs
);
2536 bool SequenceRecordObjectBase::implStartRecord( BinaryInputStream
& rBaseStrm
, sal_Int64
& ornRecPos
, sal_Int64
& ornRecId
, sal_Int64
& ornRecSize
)
2539 if( rBaseStrm
.isSeekable() )
2541 ornRecPos
= rBaseStrm
.tell();
2542 // do not try to overread seekable streams, may cause assertions
2543 bValid
= ornRecPos
< rBaseStrm
.size();
2546 // read the record header
2548 bValid
= implReadRecordHeader( rBaseStrm
, ornRecId
, ornRecSize
) && !rBaseStrm
.isEof() && (0 <= ornRecSize
) && (ornRecSize
<= 0x00100000);
2550 // read record contents into data sequence
2553 sal_Int32 nRecSize
= static_cast< sal_Int32
>( ornRecSize
);
2554 mxRecData
->realloc( nRecSize
);
2555 bValid
= (nRecSize
== 0) || (rBaseStrm
.readData( *mxRecData
, nRecSize
) == nRecSize
);
2556 mxStrm
->seekToStart();
2561 DumperBase::~DumperBase()
2565 bool DumperBase::isImportEnabled() const
2567 return !isValid() || cfg().isImportEnabled();
2570 void DumperBase::construct( const ConfigRef
& rxConfig
)
2572 if( isValid( rxConfig
) && rxConfig
->isDumperEnabled() )
2573 ObjectBase::construct( rxConfig
);
2580 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */