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::io
;
44 using namespace ::com::sun::star::ucb
;
45 using namespace ::com::sun::star::uno
;
47 using ::oox::core::FilterBase
;
51 const sal_Unicode OOX_DUMP_BOM
= 0xFEFF;
52 const sal_Int32 OOX_DUMP_MAXSTRLEN
= 80;
53 const sal_Int32 OOX_DUMP_INDENT
= 2;
54 const sal_Unicode OOX_DUMP_BINDOT
= '.';
55 const sal_Unicode OOX_DUMP_CFG_LISTSEP
= ',';
56 const sal_Unicode OOX_DUMP_CFG_QUOTE
= '\'';
57 const sal_Unicode OOX_DUMP_LF
= '\n';
58 const sal_Unicode OOX_DUMP_ITEMSEP
= '=';
59 const sal_Int32 OOX_DUMP_BYTESPERLINE
= 16;
60 const sal_Int64 OOX_DUMP_MAXARRAY
= 16;
64 // file names -----------------------------------------------------------------
66 OUString
InputOutputHelper::convertFileNameToUrl( const OUString
& rFileName
)
69 if( ::osl::FileBase::getFileURLFromSystemPath( rFileName
, aFileUrl
) == ::osl::FileBase::E_None
)
74 sal_Int32
InputOutputHelper::getFileNamePos( std::u16string_view rFileUrl
)
76 size_t nSepPos
= rFileUrl
.find( '/' );
77 return (nSepPos
== std::u16string_view::npos
) ? 0 : (nSepPos
+ 1);
80 std::u16string_view
InputOutputHelper::getFileNameExtension( std::u16string_view rFileUrl
)
82 sal_Int32 nNamePos
= getFileNamePos( rFileUrl
);
83 size_t nExtPos
= rFileUrl
.rfind( '.' );
84 if( nExtPos
!= std::u16string_view::npos
&& static_cast<sal_Int32
>(nExtPos
) >= nNamePos
)
85 return rFileUrl
.substr( nExtPos
+ 1 );
86 return std::u16string_view();
89 // input streams --------------------------------------------------------------
91 Reference
< XInputStream
> InputOutputHelper::openInputStream(
92 const Reference
< XComponentContext
>& rxContext
, const OUString
& rFileName
)
94 Reference
< XInputStream
> xInStrm
;
95 if( rxContext
.is() ) try
97 Reference
<XSimpleFileAccess3
> xFileAccess(SimpleFileAccess::create(rxContext
));
98 xInStrm
= xFileAccess
->openFileRead( rFileName
);
106 // output streams -------------------------------------------------------------
108 Reference
< XOutputStream
> InputOutputHelper::openOutputStream(
109 const Reference
< XComponentContext
>& rxContext
, const OUString
& rFileName
)
111 Reference
< XOutputStream
> xOutStrm
;
112 if( rxContext
.is() ) try
114 Reference
<XSimpleFileAccess3
> xFileAccess(SimpleFileAccess::create(rxContext
));
115 xOutStrm
= xFileAccess
->openFileWrite( rFileName
);
123 Reference
< XTextOutputStream2
> InputOutputHelper::openTextOutputStream(
124 const Reference
< XComponentContext
>& rxContext
, const Reference
< XOutputStream
>& rxOutStrm
, rtl_TextEncoding eTextEnc
)
126 Reference
< XTextOutputStream2
> xTextOutStrm
;
127 const char* pcCharset
= rtl_getMimeCharsetFromTextEncoding( eTextEnc
);
128 if( rxContext
.is() && rxOutStrm
.is() && pcCharset
) try
130 xTextOutStrm
= TextOutputStream::create(rxContext
);
131 xTextOutStrm
->setOutputStream( rxOutStrm
);
132 xTextOutStrm
->setEncoding( OUString::createFromAscii( pcCharset
) );
140 Reference
< XTextOutputStream2
> InputOutputHelper::openTextOutputStream(
141 const Reference
< XComponentContext
>& rxContext
, const OUString
& rFileName
, rtl_TextEncoding eTextEnc
)
143 return openTextOutputStream( rxContext
, openOutputStream( rxContext
, rFileName
), eTextEnc
);
146 ItemFormat::ItemFormat() :
147 meDataType( DATATYPE_VOID
),
148 meFmtType( FORMATTYPE_NONE
)
152 void ItemFormat::set( DataType eDataType
, FormatType eFmtType
, const OUString
& rItemName
)
154 meDataType
= eDataType
;
155 meFmtType
= eFmtType
;
156 maItemName
= rItemName
;
160 OUStringVector::const_iterator
ItemFormat::parse( const OUStringVector
& rFormatVec
)
162 set( DATATYPE_VOID
, FORMATTYPE_NONE
, OUString() );
164 OUStringVector::const_iterator aIt
= rFormatVec
.begin(), aEnd
= rFormatVec
.end();
165 OUString aDataType
, aFmtType
;
166 if( aIt
!= aEnd
) aDataType
= *aIt
++;
167 if( aIt
!= aEnd
) aFmtType
= *aIt
++;
168 if( aIt
!= aEnd
) maItemName
= *aIt
++;
169 if( aIt
!= aEnd
) maListName
= *aIt
++;
171 meDataType
= StringHelper::convertToDataType( aDataType
);
172 meFmtType
= StringHelper::convertToFormatType( aFmtType
);
174 if( meFmtType
== FORMATTYPE_NONE
)
176 if ( aFmtType
== "unused" )
177 set( meDataType
, FORMATTYPE_HEX
, OOX_DUMP_UNUSED
);
178 else if ( aFmtType
== "unknown" )
179 set( meDataType
, FORMATTYPE_HEX
, OOX_DUMP_UNKNOWN
);
185 OUStringVector
ItemFormat::parse( std::u16string_view rFormatStr
)
187 OUStringVector aFormatVec
;
188 StringHelper::convertStringToStringList( aFormatVec
, rFormatStr
, false );
189 OUStringVector::const_iterator aIt
= parse( aFormatVec
);
190 return OUStringVector( aIt
, const_cast< const OUStringVector
& >( aFormatVec
).end() );
193 // append string to string ----------------------------------------------------
195 void StringHelper::appendChar( OUStringBuffer
& rStr
, sal_Unicode cChar
, sal_Int32 nCount
)
197 for( sal_Int32 nIndex
= 0; nIndex
< nCount
; ++nIndex
)
198 rStr
.append( cChar
);
201 void StringHelper::appendString( OUStringBuffer
& rStr
, std::u16string_view rData
, sal_Int32 nWidth
, sal_Unicode cFill
)
203 appendChar( rStr
, cFill
, nWidth
- rData
.size() );
204 rStr
.append( rData
);
207 // append decimal -------------------------------------------------------------
209 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_uInt8 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
211 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
214 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_Int8 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
216 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
219 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_uInt16 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
221 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
224 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_Int16 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
226 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
229 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_uInt32 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
231 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
234 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_Int32 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
236 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
239 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_uInt64 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
241 /* Values greater than biggest signed 64bit integer will change to
242 negative when converting to sal_Int64. Therefore, the trailing digit
243 will be written separately. */
244 OUStringBuffer aBuffer
;
246 aBuffer
.append( static_cast<sal_Int64
>(nData
/ 10 ) );
247 aBuffer
.append( static_cast< sal_Unicode
>( '0' + (nData
% 10) ) );
248 appendString( rStr
, aBuffer
.makeStringAndClear(), nWidth
, cFill
);
251 void StringHelper::appendDec( OUStringBuffer
& rStr
, sal_Int64 nData
, sal_Int32 nWidth
, sal_Unicode cFill
)
253 appendString( rStr
, OUString::number( nData
), nWidth
, cFill
);
256 void StringHelper::appendDec( OUStringBuffer
& rStr
, double fData
, sal_Int32 nWidth
, sal_Unicode cFill
)
258 appendString( rStr
, ::rtl::math::doubleToUString( fData
, rtl_math_StringFormat_G
, 15, '.', true ), nWidth
, cFill
);
261 // append hexadecimal ---------------------------------------------------------
263 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_uInt8 nData
, bool bPrefix
)
265 static const sal_Unicode spcHexDigits
[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
268 rStr
.append( OUStringChar(spcHexDigits
[ (nData
>> 4) & 0x0F ] ) + OUStringChar( spcHexDigits
[ nData
& 0x0F ] ) );
271 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_Int8 nData
, bool bPrefix
)
273 appendHex( rStr
, static_cast< sal_uInt8
>( nData
), bPrefix
);
276 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_uInt16 nData
, bool bPrefix
)
278 appendHex( rStr
, static_cast< sal_uInt8
>( nData
>> 8 ), bPrefix
);
279 appendHex( rStr
, static_cast< sal_uInt8
>( nData
), false );
282 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_Int16 nData
, bool bPrefix
)
284 appendHex( rStr
, static_cast< sal_uInt16
>( nData
), bPrefix
);
287 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_uInt32 nData
, bool bPrefix
)
289 appendHex( rStr
, static_cast< sal_uInt16
>( nData
>> 16 ), bPrefix
);
290 appendHex( rStr
, static_cast< sal_uInt16
>( nData
), false );
293 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_Int32 nData
, bool bPrefix
)
295 appendHex( rStr
, static_cast< sal_uInt32
>( nData
), bPrefix
);
298 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_uInt64 nData
, bool bPrefix
)
300 appendHex( rStr
, static_cast< sal_uInt32
>( nData
>> 32 ), bPrefix
);
301 appendHex( rStr
, static_cast< sal_uInt32
>( nData
), false );
304 void StringHelper::appendHex( OUStringBuffer
& rStr
, sal_Int64 nData
, bool bPrefix
)
306 appendHex( rStr
, static_cast< sal_uInt64
>( nData
), bPrefix
);
310 lcl_ConvertDouble(double const f
)
312 sal_uInt64 i
= sal_uInt64();
313 for (size_t j
= 0; j
< sizeof(double); ++j
)
314 { // hopefully both endian independent and strict aliasing safe
315 reinterpret_cast<char *>(&i
)[j
] = reinterpret_cast<char const *>(&f
)[j
];
320 void StringHelper::appendHex( OUStringBuffer
& rStr
, double fData
, bool bPrefix
)
322 appendHex( rStr
, lcl_ConvertDouble(fData
), bPrefix
);
325 // append shortened hexadecimal -----------------------------------------------
327 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_uInt8 nData
, bool bPrefix
)
329 appendHex( rStr
, nData
, bPrefix
);
332 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_Int8 nData
, bool bPrefix
)
334 appendHex( rStr
, nData
, bPrefix
);
337 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_uInt16 nData
, bool bPrefix
)
339 if( nData
> SAL_MAX_UINT8
)
340 appendHex( rStr
, nData
, bPrefix
);
342 appendHex( rStr
, static_cast< sal_uInt8
>( nData
), bPrefix
);
345 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_Int16 nData
, bool bPrefix
)
347 appendShortHex( rStr
, static_cast< sal_uInt16
>( nData
), bPrefix
);
350 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_uInt32 nData
, bool bPrefix
)
352 if( nData
> SAL_MAX_UINT16
)
353 appendHex( rStr
, nData
, bPrefix
);
355 appendShortHex( rStr
, static_cast< sal_uInt16
>( nData
), bPrefix
);
358 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_Int32 nData
, bool bPrefix
)
360 appendShortHex( rStr
, static_cast< sal_uInt32
>( nData
), bPrefix
);
363 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_uInt64 nData
, bool bPrefix
)
365 if( nData
> SAL_MAX_UINT32
)
366 appendHex( rStr
, nData
, bPrefix
);
368 appendShortHex( rStr
, static_cast< sal_uInt32
>( nData
), bPrefix
);
371 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, sal_Int64 nData
, bool bPrefix
)
373 appendShortHex( rStr
, static_cast< sal_uInt64
>( nData
), bPrefix
);
376 void StringHelper::appendShortHex( OUStringBuffer
& rStr
, double fData
, bool bPrefix
)
378 appendHex( rStr
, fData
, bPrefix
);
381 // append binary --------------------------------------------------------------
383 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_uInt8 nData
, bool bDots
)
385 for( sal_uInt8 nMask
= 0x80; nMask
!= 0; (nMask
>>= 1) &= 0x7F )
387 rStr
.append( static_cast< sal_Unicode
>( (nData
& nMask
) ? '1' : '0' ) );
388 if( bDots
&& (nMask
== 0x10) )
389 rStr
.append( OOX_DUMP_BINDOT
);
393 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_Int8 nData
, bool bDots
)
395 appendBin( rStr
, static_cast< sal_uInt8
>( nData
), bDots
);
398 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_uInt16 nData
, bool bDots
)
400 appendBin( rStr
, static_cast< sal_uInt8
>( nData
>> 8 ), bDots
);
402 rStr
.append( OOX_DUMP_BINDOT
);
403 appendBin( rStr
, static_cast< sal_uInt8
>( nData
), bDots
);
406 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_Int16 nData
, bool bDots
)
408 appendBin( rStr
, static_cast< sal_uInt16
>( nData
), bDots
);
411 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_uInt32 nData
, bool bDots
)
413 appendBin( rStr
, static_cast< sal_uInt16
>( nData
>> 16 ), bDots
);
415 rStr
.append( OOX_DUMP_BINDOT
);
416 appendBin( rStr
, static_cast< sal_uInt16
>( nData
), bDots
);
419 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_Int32 nData
, bool bDots
)
421 appendBin( rStr
, static_cast< sal_uInt32
>( nData
), bDots
);
424 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_uInt64 nData
, bool bDots
)
426 appendBin( rStr
, static_cast< sal_uInt32
>( nData
>> 32 ), bDots
);
428 rStr
.append( OOX_DUMP_BINDOT
);
429 appendBin( rStr
, static_cast< sal_uInt32
>( nData
), bDots
);
432 void StringHelper::appendBin( OUStringBuffer
& rStr
, sal_Int64 nData
, bool bDots
)
434 appendBin( rStr
, static_cast< sal_uInt64
>( nData
), bDots
);
437 void StringHelper::appendBin( OUStringBuffer
& rStr
, double fData
, bool bDots
)
439 appendBin( rStr
, lcl_ConvertDouble(fData
), bDots
);
442 // append formatted value -----------------------------------------------------
444 void StringHelper::appendBool( OUStringBuffer
& rStr
, bool bData
)
446 rStr
.appendAscii( bData
? "true" : "false" );
449 // encoded text output --------------------------------------------------------
451 void StringHelper::appendCChar( OUStringBuffer
& rStr
, sal_Unicode cChar
, bool bPrefix
)
456 rStr
.append( "\\u" );
457 appendHex( rStr
, static_cast< sal_uInt16
>( cChar
), false );
462 rStr
.append( "\\x" );
463 appendHex( rStr
, static_cast< sal_uInt8
>( cChar
), false );
467 void StringHelper::appendEncChar( OUStringBuffer
& rStr
, sal_Unicode cChar
, sal_Int32 nCount
, bool bPrefix
)
472 OUStringBuffer aCode
;
473 appendCChar( aCode
, cChar
, bPrefix
);
474 OUString aCodeStr
= aCode
.makeStringAndClear();
475 for( sal_Int32 nIdx
= 0; nIdx
< nCount
; ++nIdx
)
476 rStr
.append( aCodeStr
);
480 appendChar( rStr
, cChar
, nCount
);
484 void StringHelper::appendEncString( OUStringBuffer
& rStr
, std::u16string_view rData
, bool bPrefix
)
488 size_t nEnd
= rData
.size();
491 // find next character that needs encoding
492 while( (nIdx
< nEnd
) && (rData
[ nIdx
] >= 0x20) ) ++nIdx
;
496 if( (nBeg
== 0) && (nIdx
== nEnd
) )
497 rStr
.append( rData
);
499 rStr
.append( rData
.substr(nBeg
, nIdx
- nBeg
) );
501 // append characters to be encoded
502 while( (nIdx
< nEnd
) && (rData
[ nIdx
] < 0x20) )
504 appendCChar( rStr
, rData
[ nIdx
], bPrefix
);
512 // token list -----------------------------------------------------------------
514 void StringHelper::appendToken( OUStringBuffer
& rStr
, std::u16string_view rToken
, sal_Unicode cSep
)
516 if( (rStr
.getLength() > 0) && (!rToken
.empty()) )
518 rStr
.append( rToken
);
521 void StringHelper::appendIndex( OUStringBuffer
& rStr
, sal_Int64 nIdx
)
523 OUStringBuffer aToken
;
524 appendDec( aToken
, nIdx
);
525 rStr
.append( "[" + aToken
+ "]" );
528 std::u16string_view
StringHelper::getToken( std::u16string_view rData
, sal_Int32
& rnPos
, sal_Unicode cSep
)
530 return trimSpaces( o3tl::getToken(rData
, 0, cSep
, rnPos
) );
533 void StringHelper::enclose( OUStringBuffer
& rStr
, sal_Unicode cOpen
, sal_Unicode cClose
)
535 rStr
.insert( 0, cOpen
).append( cClose
? cClose
: cOpen
);
538 // string conversion ----------------------------------------------------------
542 sal_Int32
lclIndexOf( std::u16string_view rStr
, sal_Unicode cChar
, sal_Int32 nStartPos
)
544 size_t nIndex
= rStr
.find( cChar
, nStartPos
);
545 return (nIndex
== std::u16string_view::npos
) ? rStr
.size() : nIndex
;
548 OUString
lclTrimQuotedStringList( std::u16string_view rStr
)
550 OUStringBuffer aBuffer
;
552 size_t nLen
= rStr
.size();
555 if( rStr
[ nPos
] == OOX_DUMP_CFG_QUOTE
)
557 // quoted string, skip leading quote character
559 // process quoted text and embedded literal quote characters
560 OUStringBuffer aToken
;
563 // seek to next quote character and add text portion to token buffer
564 size_t nEnd
= lclIndexOf( rStr
, OOX_DUMP_CFG_QUOTE
, nPos
);
565 aToken
.append( rStr
.substr(nPos
, nEnd
- nPos
) );
566 // process literal quotes
567 while( (nEnd
+ 1 < nLen
) && (rStr
[ nEnd
] == OOX_DUMP_CFG_QUOTE
) && (rStr
[ nEnd
+ 1 ] == OOX_DUMP_CFG_QUOTE
) )
569 aToken
.append( OOX_DUMP_CFG_QUOTE
);
572 // nEnd is start of possible next text portion
575 while( (nPos
< nLen
) && (rStr
[ nPos
] != OOX_DUMP_CFG_QUOTE
) );
576 // add token, seek to list separator, ignore text following closing quote
577 aBuffer
.append( aToken
);
578 nPos
= lclIndexOf( rStr
, OOX_DUMP_CFG_LISTSEP
, nPos
);
580 aBuffer
.append( OOX_DUMP_LF
);
581 // set current position behind list separator
586 // find list separator, add token text to buffer
587 size_t nEnd
= lclIndexOf( rStr
, OOX_DUMP_CFG_LISTSEP
, nPos
);
588 aBuffer
.append( rStr
.substr(nPos
, nEnd
- nPos
) );
590 aBuffer
.append( OOX_DUMP_LF
);
591 // set current position behind list separator
596 return aBuffer
.makeStringAndClear();
601 std::u16string_view
StringHelper::trimSpaces( std::u16string_view rStr
)
604 while( (nBeg
< rStr
.size()) && ((rStr
[ nBeg
] == ' ') || (rStr
[ nBeg
] == '\t')) )
606 size_t nEnd
= rStr
.size();
607 while( (nEnd
> nBeg
) && ((rStr
[ nEnd
- 1 ] == ' ') || (rStr
[ nEnd
- 1 ] == '\t')) )
609 return rStr
.substr( nBeg
, nEnd
- nBeg
);
612 OUString
StringHelper::trimTrailingNul( const OUString
& rStr
)
614 sal_Int32 nLastPos
= rStr
.getLength() - 1;
615 if( (nLastPos
>= 0) && (rStr
[ nLastPos
] == 0) )
616 return rStr
.copy( 0, nLastPos
);
620 OString
StringHelper::convertToUtf8( std::u16string_view rStr
)
622 return OUStringToOString( rStr
, RTL_TEXTENCODING_UTF8
);
625 DataType
StringHelper::convertToDataType( std::u16string_view rStr
)
627 DataType eType
= DATATYPE_VOID
;
628 if ( rStr
== u
"int8" )
629 eType
= DATATYPE_INT8
;
630 else if ( rStr
== u
"uint8" )
631 eType
= DATATYPE_UINT8
;
632 else if ( rStr
== u
"int16" )
633 eType
= DATATYPE_INT16
;
634 else if ( rStr
== u
"uint16" )
635 eType
= DATATYPE_UINT16
;
636 else if ( rStr
== u
"int32" )
637 eType
= DATATYPE_INT32
;
638 else if ( rStr
== u
"uint32" )
639 eType
= DATATYPE_UINT32
;
640 else if ( rStr
== u
"int64" )
641 eType
= DATATYPE_INT64
;
642 else if ( rStr
== u
"uint64" )
643 eType
= DATATYPE_UINT64
;
644 else if ( rStr
== u
"float" )
645 eType
= DATATYPE_FLOAT
;
646 else if ( rStr
== u
"double" )
647 eType
= DATATYPE_DOUBLE
;
651 FormatType
StringHelper::convertToFormatType( std::u16string_view rStr
)
653 FormatType eType
= FORMATTYPE_NONE
;
654 if ( rStr
== u
"dec" )
655 eType
= FORMATTYPE_DEC
;
656 else if ( rStr
== u
"hex" )
657 eType
= FORMATTYPE_HEX
;
658 else if ( rStr
== u
"shorthex" )
659 eType
= FORMATTYPE_SHORTHEX
;
660 else if ( rStr
== u
"bin" )
661 eType
= FORMATTYPE_BIN
;
662 else if ( rStr
== u
"fix" )
663 eType
= FORMATTYPE_FIX
;
664 else if ( rStr
== u
"bool" )
665 eType
= FORMATTYPE_BOOL
;
669 bool StringHelper::convertFromDec( sal_Int64
& ornData
, std::u16string_view rData
)
672 size_t nLen
= rData
.size();
674 if( (nLen
> 0) && (rData
[ 0 ] == '-') )
680 for( ; nPos
< nLen
; ++nPos
)
682 sal_Unicode cChar
= rData
[ nPos
];
683 if( (cChar
< '0') || (cChar
> '9') )
685 ornData
= (ornData
* 10) + (cChar
- '0');
692 bool StringHelper::convertFromHex( sal_Int64
& ornData
, std::u16string_view rData
)
695 for( size_t nPos
= 0, nLen
= rData
.size(); nPos
< nLen
; ++nPos
)
697 sal_Unicode cChar
= rData
[ nPos
];
698 if( ('0' <= cChar
) && (cChar
<= '9') )
700 else if( ('A' <= cChar
) && (cChar
<= 'F') )
702 else if( ('a' <= cChar
) && (cChar
<= 'f') )
706 ornData
= (ornData
<< 4) + cChar
;
711 bool StringHelper::convertStringToInt( sal_Int64
& ornData
, std::u16string_view rData
)
713 if( (rData
.size() > 2) && (rData
[ 0 ] == '0') && ((rData
[ 1 ] == 'X') || (rData
[ 1 ] == 'x')) )
714 return convertFromHex( ornData
, rData
.substr( 2 ) );
715 return convertFromDec( ornData
, rData
);
718 bool StringHelper::convertStringToDouble( double& orfData
, std::u16string_view rData
)
720 rtl_math_ConversionStatus eStatus
= rtl_math_ConversionStatus_Ok
;
722 sal_Unicode
const * pBegin
= rData
.data();
723 sal_Unicode
const * pEnd
;
724 orfData
= rtl_math_uStringToDouble(pBegin
,
725 pBegin
+ rData
.size(),
728 nSize
= static_cast<sal_Int32
>(pEnd
- pBegin
);
729 return (eStatus
== rtl_math_ConversionStatus_Ok
) && (nSize
== static_cast<sal_Int32
>(rData
.size()));
732 bool StringHelper::convertStringToBool( std::u16string_view rData
)
734 if ( rData
== u
"true" )
736 if ( rData
== u
"false" )
739 return convertStringToInt( nData
, rData
) && (nData
!= 0);
742 OUStringPair
StringHelper::convertStringToPair( const OUString
& rString
, sal_Unicode cSep
)
745 if( !rString
.isEmpty() )
747 sal_Int32 nEqPos
= rString
.indexOf( cSep
);
750 aPair
.first
= rString
;
754 aPair
.first
= StringHelper::trimSpaces( rString
.subView( 0, nEqPos
) );
755 aPair
.second
= StringHelper::trimSpaces( rString
.subView( nEqPos
+ 1 ) );
761 void StringHelper::convertStringToStringList( OUStringVector
& orVec
, std::u16string_view rData
, bool bIgnoreEmpty
)
764 OUString aUnquotedData
= lclTrimQuotedStringList( rData
);
766 sal_Int32 nLen
= aUnquotedData
.getLength();
767 while( (0 <= nPos
) && (nPos
< nLen
) )
769 std::u16string_view aToken
= getToken( aUnquotedData
, nPos
, OOX_DUMP_LF
);
770 if( !bIgnoreEmpty
|| !aToken
.empty() )
771 orVec
.push_back( OUString(aToken
) );
775 void StringHelper::convertStringToIntList( Int64Vector
& orVec
, std::u16string_view rData
, bool bIgnoreEmpty
)
778 OUString aUnquotedData
= lclTrimQuotedStringList( rData
);
780 sal_Int32 nLen
= aUnquotedData
.getLength();
782 while( (0 <= nPos
) && (nPos
< nLen
) )
784 bool bOk
= convertStringToInt( nData
, getToken( aUnquotedData
, nPos
, OOX_DUMP_LF
) );
785 if( !bIgnoreEmpty
|| bOk
)
786 orVec
.push_back( bOk
? nData
: 0 );
794 ConfigItemBase::~ConfigItemBase()
798 void ConfigItemBase::readConfigBlock( TextInputStream
& rStrm
)
800 readConfigBlockContents( rStrm
);
803 void ConfigItemBase::implProcessConfigItemStr(
804 TextInputStream
& /*rStrm*/, const OUString
& /*rKey*/, const OUString
& /*rData*/ )
808 void ConfigItemBase::implProcessConfigItemInt(
809 TextInputStream
& /*rStrm*/, sal_Int64
/*nKey*/, const OUString
& /*rData*/ )
813 void ConfigItemBase::readConfigBlockContents( TextInputStream
& rStrm
)
816 while( bLoop
&& !rStrm
.isEof() )
818 OUString aKey
, aData
;
819 switch( readConfigLine( rStrm
, aKey
, aData
) )
822 processConfigItem( rStrm
, aKey
, aData
);
831 ConfigItemBase::LineType
ConfigItemBase::readConfigLine(
832 TextInputStream
& rStrm
, OUString
& orKey
, OUString
& orData
)
835 while( !rStrm
.isEof() && aLine
.isEmpty() )
837 aLine
= rStrm
.readLine();
838 if( !aLine
.isEmpty() && (aLine
[ 0 ] == OOX_DUMP_BOM
) )
839 aLine
= aLine
.copy( 1 );
840 aLine
= StringHelper::trimSpaces( aLine
);
841 if( !aLine
.isEmpty() )
843 // ignore comments (starting with hash or semicolon)
844 sal_Unicode cChar
= aLine
[ 0 ];
845 if( (cChar
== '#') || (cChar
== ';') )
850 OUStringPair aPair
= StringHelper::convertStringToPair( aLine
);
852 orData
= aPair
.second
;
853 return ( !orKey
.isEmpty() && (!orData
.isEmpty() || orKey
!= "end" )) ?
854 LINETYPE_DATA
: LINETYPE_END
;
857 void ConfigItemBase::processConfigItem(
858 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
861 if( StringHelper::convertStringToInt( nKey
, rKey
) )
862 implProcessConfigItemInt( rStrm
, nKey
, rData
);
864 implProcessConfigItemStr( rStrm
, rKey
, rData
);
867 NameListBase::~NameListBase()
871 void NameListBase::setName( sal_Int64 nKey
, const String
& rName
)
873 implSetName( nKey
, rName
);
876 void NameListBase::includeList( const NameListRef
& rxList
)
880 for (auto const& elem
: *rxList
)
881 maMap
[ elem
.first
] = elem
.second
;
882 implIncludeList( *rxList
);
886 bool NameListBase::implIsValid() const
891 void NameListBase::implProcessConfigItemStr(
892 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
894 if ( rKey
== "include" )
896 else if ( rKey
== "exclude" )
899 ConfigItemBase::implProcessConfigItemStr( rStrm
, rKey
, rData
);
902 void NameListBase::implProcessConfigItemInt(
903 TextInputStream
& /*rStrm*/, sal_Int64 nKey
, const OUString
& rData
)
905 implSetName( nKey
, rData
);
908 void NameListBase::insertRawName( sal_Int64 nKey
, const OUString
& rName
)
910 maMap
[ nKey
] = rName
;
913 const OUString
* NameListBase::findRawName( sal_Int64 nKey
) const
915 const_iterator aIt
= maMap
.find( nKey
);
916 return (aIt
== end()) ? nullptr : &aIt
->second
;
919 void NameListBase::include( std::u16string_view rListKeys
)
922 StringHelper::convertStringToStringList( aVec
, rListKeys
, true );
923 for (auto const& elem
: aVec
)
924 includeList( mrCfgData
.getNameList(elem
) );
927 void NameListBase::exclude( std::u16string_view rKeys
)
930 StringHelper::convertStringToIntList( aVec
, rKeys
, true );
931 for (auto const& elem
: aVec
)
935 void ItemFormatMap::insertFormats( const NameListRef
& rxNameList
)
937 if( Base::isValid( rxNameList
) )
939 for (auto const& elemName
: *rxNameList
)
940 maMap
[ elemName
.first
].parse( elemName
.second
);
944 ConstList::ConstList( const SharedConfigData
& rCfgData
) :
945 NameListBase( rCfgData
),
946 maDefName( OOX_DUMP_ERR_NONAME
),
947 mbQuoteNames( false )
951 void ConstList::implProcessConfigItemStr(
952 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
954 if ( rKey
== "default" )
955 maDefName
= rData
; // Sets a default name for unknown keys.
956 else if ( rKey
== "quote-names" )
957 setQuoteNames( StringHelper::convertStringToBool( rData
) );
959 NameListBase::implProcessConfigItemStr( rStrm
, rKey
, rData
);
962 void ConstList::implSetName( sal_Int64 nKey
, const OUString
& rName
)
964 insertRawName( nKey
, rName
);
967 OUString
ConstList::implGetName( const Config
& /*rCfg*/, sal_Int64 nKey
) const
969 const OUString
* pName
= findRawName( nKey
);
970 OUString aName
= pName
? *pName
: maDefName
;
973 OUStringBuffer
aBuffer( aName
);
974 StringHelper::enclose( aBuffer
, OOX_DUMP_STRQUOTE
);
975 aName
= aBuffer
.makeStringAndClear();
980 OUString
ConstList::implGetNameDbl( const Config
& /*rCfg*/, double /*fValue*/ ) const
985 void ConstList::implIncludeList( const NameListBase
& rList
)
987 if( const ConstList
* pConstList
= dynamic_cast< const ConstList
* >( &rList
) )
989 maDefName
= pConstList
->maDefName
;
990 mbQuoteNames
= pConstList
->mbQuoteNames
;
994 MultiList::MultiList( const SharedConfigData
& rCfgData
) :
995 ConstList( rCfgData
),
996 mbIgnoreEmpty( true )
1000 void MultiList::setNamesFromVec( sal_Int64 nStartKey
, const OUStringVector
& rNames
)
1002 sal_Int64 nKey
= nStartKey
;
1003 for (auto const& name
: rNames
)
1005 if( !mbIgnoreEmpty
|| !name
.isEmpty() )
1006 insertRawName( nKey
, name
);
1011 void MultiList::implProcessConfigItemStr(
1012 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
1014 if ( rKey
== "ignore-empty" )
1015 mbIgnoreEmpty
= StringHelper::convertStringToBool( rData
);
1017 ConstList::implProcessConfigItemStr( rStrm
, rKey
, rData
);
1020 void MultiList::implSetName( sal_Int64 nKey
, const OUString
& rName
)
1022 OUStringVector aNames
;
1023 StringHelper::convertStringToStringList( aNames
, rName
, false );
1024 setNamesFromVec( nKey
, aNames
);
1027 FlagsList::FlagsList( const SharedConfigData
& rCfgData
) :
1028 NameListBase( rCfgData
),
1033 void FlagsList::implProcessConfigItemStr(
1034 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
1036 if ( rKey
== "ignore" )
1039 if( StringHelper::convertStringToInt( nIgnore
, rData
) )
1040 setIgnoreFlags( nIgnore
);
1044 NameListBase::implProcessConfigItemStr( rStrm
, rKey
, rData
);
1048 void FlagsList::implSetName( sal_Int64 nKey
, const OUString
& rName
)
1050 if( (nKey
!= 0) && ((nKey
& (nKey
- 1)) == 0) ) // only a single bit set?
1051 insertRawName( nKey
, rName
);
1054 OUString
FlagsList::implGetName( const Config
& /*rCfg*/, sal_Int64 nKey
) const
1056 sal_Int64 nFound
= mnIgnore
;
1057 OUStringBuffer aName
;
1059 for( const_iterator aIt
= begin(), aEnd
= end(); aIt
!= aEnd
; ++aIt
)
1061 sal_Int64 nMask
= aIt
->first
;
1062 setFlag( nFound
, nMask
);
1063 if( !getFlag( mnIgnore
, nMask
) )
1065 const OUString
& rFlagName
= aIt
->second
;
1066 bool bOnOff
= rFlagName
.startsWith(":");
1067 bool bFlag
= getFlag( nKey
, nMask
);
1070 StringHelper::appendToken( aName
, rFlagName
.subView( 1 ) );
1071 aName
.appendAscii( bFlag
? ":on" : ":off" );
1075 bool bNegated
= rFlagName
.startsWith("!");
1076 sal_Int32 nBothSep
= bNegated
? rFlagName
.indexOf( '!', 1 ) : -1;
1080 StringHelper::appendToken( aName
, rFlagName
);
1081 else if( nBothSep
> 0 )
1082 StringHelper::appendToken( aName
, rFlagName
.subView( nBothSep
+ 1 ) );
1087 StringHelper::appendToken( aName
, rFlagName
.subView( 1, nBothSep
- 1 ) );
1089 StringHelper::appendToken( aName
, rFlagName
.subView( 1 ) );
1094 // add unknown flags
1095 setFlag( nKey
, nFound
, false );
1098 OUStringBuffer
aUnknown( OUString::Concat(OOX_DUMP_UNKNOWN
) + OUStringChar(OOX_DUMP_ITEMSEP
) );
1099 StringHelper::appendShortHex( aUnknown
, nKey
);
1100 StringHelper::enclose( aUnknown
, '(', ')' );
1101 StringHelper::appendToken( aName
, aUnknown
);
1103 return aName
.makeStringAndClear();
1106 OUString
FlagsList::implGetNameDbl( const Config
& /*rCfg*/, double /*fValue*/ ) const
1111 void FlagsList::implIncludeList( const NameListBase
& rList
)
1113 if( const FlagsList
* pFlagsList
= dynamic_cast< const FlagsList
* >( &rList
) )
1114 mnIgnore
= pFlagsList
->mnIgnore
;
1117 bool CombiList::ExtItemFormatKey::operator<( const ExtItemFormatKey
& rRight
) const
1119 return (mnKey
< rRight
.mnKey
) || ((mnKey
== rRight
.mnKey
) && (maFilter
< rRight
.maFilter
));
1122 CombiList::CombiList( const SharedConfigData
& rCfgData
) :
1123 FlagsList( rCfgData
)
1127 void CombiList::implSetName( sal_Int64 nKey
, const OUString
& rName
)
1129 if( (nKey
& (nKey
- 1)) != 0 ) // more than a single bit set?
1131 ::std::set
< ExtItemFormatKey
> aItemKeys
;
1132 ExtItemFormat aItemFmt
;
1133 OUStringVector aRemain
= aItemFmt
.parse( rName
);
1134 for (auto const& elemRemain
: aRemain
)
1136 OUStringPair aPair
= StringHelper::convertStringToPair(elemRemain
);
1137 if ( aPair
.first
== "noshift" )
1139 aItemFmt
.mbShiftValue
= StringHelper::convertStringToBool( aPair
.second
);
1141 else if ( aPair
.first
== "filter" )
1143 OUStringPair aFilter
= StringHelper::convertStringToPair( aPair
.second
, '~' );
1144 ExtItemFormatKey
aKey( nKey
);
1145 if( !aFilter
.first
.isEmpty() && StringHelper::convertStringToInt( aKey
.maFilter
.first
, aFilter
.first
) &&
1146 !aFilter
.second
.isEmpty() && StringHelper::convertStringToInt( aKey
.maFilter
.second
, aFilter
.second
) )
1148 if( aKey
.maFilter
.first
== 0 )
1149 aKey
.maFilter
.second
= 0;
1150 aItemKeys
.insert( aKey
);
1154 if( aItemKeys
.empty() )
1155 aItemKeys
.insert( ExtItemFormatKey( nKey
) );
1156 for (auto const& itemKey
: aItemKeys
)
1157 maFmtMap
[itemKey
] = aItemFmt
;
1161 FlagsList::implSetName( nKey
, rName
);
1165 OUString
CombiList::implGetName( const Config
& rCfg
, sal_Int64 nKey
) const
1167 sal_Int64 nFound
= 0;
1168 OUStringBuffer aName
;
1169 // add known flag fields
1170 for (auto const& fmt
: maFmtMap
)
1172 const ExtItemFormatKey
& rMapKey
= fmt
.first
;
1173 sal_Int64 nMask
= rMapKey
.mnKey
;
1174 if( (nMask
!= 0) && ((nKey
& rMapKey
.maFilter
.first
) == rMapKey
.maFilter
.second
) )
1176 const ExtItemFormat
& rItemFmt
= fmt
.second
;
1178 sal_uInt64 nUFlags
= static_cast< sal_uInt64
>( nKey
);
1179 sal_uInt64 nUMask
= static_cast< sal_uInt64
>( nMask
);
1180 if( rItemFmt
.mbShiftValue
)
1181 while( (nUMask
& 1) == 0 ) { nUFlags
>>= 1; nUMask
>>= 1; }
1183 sal_uInt64 nUValue
= nUFlags
& nUMask
;
1184 sal_Int64 nSValue
= static_cast< sal_Int64
>( nUValue
);
1185 if( getFlag
< sal_uInt64
>( nUValue
, (nUMask
+ 1) >> 1 ) )
1186 setFlag( nSValue
, static_cast< sal_Int64
>( ~nUMask
) );
1188 OUStringBuffer
aItem( rItemFmt
.maItemName
);
1189 OUStringBuffer aValue
;
1190 switch( rItemFmt
.meDataType
)
1192 case DATATYPE_INT8
: StringHelper::appendValue( aValue
, static_cast< sal_Int8
>( nSValue
), rItemFmt
.meFmtType
); break;
1193 case DATATYPE_UINT8
: StringHelper::appendValue( aValue
, static_cast< sal_uInt8
>( nUValue
), rItemFmt
.meFmtType
); break;
1194 case DATATYPE_INT16
: StringHelper::appendValue( aValue
, static_cast< sal_Int16
>( nSValue
), rItemFmt
.meFmtType
); break;
1195 case DATATYPE_UINT16
: StringHelper::appendValue( aValue
, static_cast< sal_uInt16
>( nUValue
), rItemFmt
.meFmtType
); break;
1196 case DATATYPE_INT32
: StringHelper::appendValue( aValue
, static_cast< sal_Int32
>( nSValue
), rItemFmt
.meFmtType
); break;
1197 case DATATYPE_UINT32
: StringHelper::appendValue( aValue
, static_cast< sal_uInt32
>( nUValue
), rItemFmt
.meFmtType
); break;
1198 case DATATYPE_INT64
: StringHelper::appendValue( aValue
, nSValue
, rItemFmt
.meFmtType
); break;
1199 case DATATYPE_UINT64
: StringHelper::appendValue( aValue
, nUValue
, rItemFmt
.meFmtType
); break;
1200 case DATATYPE_FLOAT
: StringHelper::appendValue( aValue
, static_cast< float >( nSValue
), rItemFmt
.meFmtType
); break;
1201 case DATATYPE_DOUBLE
: StringHelper::appendValue( aValue
, static_cast< double >( nSValue
), rItemFmt
.meFmtType
); break;
1204 StringHelper::appendToken( aItem
, aValue
, OOX_DUMP_ITEMSEP
);
1205 if( !rItemFmt
.maListName
.isEmpty() )
1207 OUString aValueName
= rCfg
.getName( rItemFmt
.maListName
, static_cast< sal_Int64
>( nUValue
) );
1208 StringHelper::appendToken( aItem
, aValueName
, OOX_DUMP_ITEMSEP
);
1210 StringHelper::enclose( aItem
, '(', ')' );
1211 StringHelper::appendToken( aName
, aItem
);
1212 setFlag( nFound
, nMask
);
1215 setFlag( nKey
, nFound
, false );
1216 StringHelper::appendToken( aName
, FlagsList::implGetName( rCfg
, nKey
) );
1217 return aName
.makeStringAndClear();
1220 void CombiList::implIncludeList( const NameListBase
& rList
)
1222 if( const CombiList
* pCombiList
= dynamic_cast< const CombiList
* >( &rList
) )
1223 maFmtMap
= pCombiList
->maFmtMap
;
1224 FlagsList::implIncludeList( rList
);
1227 UnitConverter::UnitConverter( const SharedConfigData
& rCfgData
) :
1228 NameListBase( rCfgData
),
1233 void UnitConverter::implSetName( sal_Int64
/*nKey*/, const OUString
& /*rName*/ )
1238 OUString
UnitConverter::implGetName( const Config
& rCfg
, sal_Int64 nKey
) const
1240 return implGetNameDbl( rCfg
, static_cast< double >( nKey
) );
1243 OUString
UnitConverter::implGetNameDbl( const Config
& /*rCfg*/, double fValue
) const
1245 OUStringBuffer aValue
;
1246 StringHelper::appendDec( aValue
, mfFactor
* fValue
);
1247 aValue
.append( maUnitName
);
1248 return aValue
.makeStringAndClear();
1251 void UnitConverter::implIncludeList( const NameListBase
& /*rList*/ )
1255 const NameListRef
& NameListWrapper::getNameList( const Config
& rCfg
) const
1258 mxList
= rCfg
.getNameList( maName
);
1262 SharedConfigData::SharedConfigData( const OUString
& rFileName
,
1263 const Reference
< XComponentContext
>& rxContext
, StorageRef xRootStrg
,
1264 OUString aSysFileName
) :
1265 mxContext( rxContext
),
1266 mxRootStrg(std::move( xRootStrg
)),
1267 maSysFileName(std::move( aSysFileName
)),
1270 OUString aFileUrl
= InputOutputHelper::convertFileNameToUrl( rFileName
);
1271 if( !aFileUrl
.isEmpty() )
1273 sal_Int32 nNamePos
= InputOutputHelper::getFileNamePos( aFileUrl
);
1274 maConfigPath
= aFileUrl
.copy( 0, nNamePos
);
1275 mbLoaded
= readConfigFile( aFileUrl
);
1279 SharedConfigData::~SharedConfigData()
1283 const OUString
* SharedConfigData::getOption( const OUString
& rKey
) const
1285 ConfigDataMap::const_iterator aIt
= maConfigData
.find( rKey
);
1286 return (aIt
== maConfigData
.end()) ? nullptr : &aIt
->second
;
1289 void SharedConfigData::setNameList( const OUString
& rListName
, const NameListRef
& rxList
)
1291 if( !rListName
.isEmpty() )
1292 maNameLists
[ rListName
] = rxList
;
1295 void SharedConfigData::eraseNameList( const OUString
& rListName
)
1297 maNameLists
.erase( rListName
);
1300 NameListRef
SharedConfigData::getNameList( const OUString
& rListName
) const
1303 NameListMap::const_iterator aIt
= maNameLists
.find( rListName
);
1304 if( aIt
!= maNameLists
.end() )
1305 xList
= aIt
->second
;
1309 bool SharedConfigData::implIsValid() const
1311 return mbLoaded
&& mxContext
.is() && mxRootStrg
&& !maSysFileName
.isEmpty();
1314 void SharedConfigData::implProcessConfigItemStr(
1315 TextInputStream
& rStrm
, const OUString
& rKey
, const OUString
& rData
)
1317 if ( rKey
== "include-config-file" )
1318 readConfigFile( maConfigPath
+ rData
);
1319 else if ( rKey
== "constlist" )
1320 readNameList
< ConstList
>( rStrm
, rData
);
1321 else if ( rKey
== "multilist" )
1322 readNameList
< MultiList
>( rStrm
, rData
);
1323 else if ( rKey
== "flagslist" )
1324 readNameList
< FlagsList
>( rStrm
, rData
);
1325 else if ( rKey
== "combilist" )
1326 readNameList
< CombiList
>( rStrm
, rData
);
1327 else if ( rKey
== "shortlist" )
1328 createShortList( rData
);
1329 else if ( rKey
== "unitconverter" )
1330 createUnitConverter( rData
);
1332 maConfigData
[ rKey
] = rData
;
1335 bool SharedConfigData::readConfigFile( const OUString
& rFileUrl
)
1337 bool bLoaded
= maConfigFiles
.count( rFileUrl
) > 0;
1340 Reference
< XInputStream
> xInStrm
= InputOutputHelper::openInputStream( mxContext
, rFileUrl
);
1341 TextInputStream
aTxtStrm( mxContext
, xInStrm
, RTL_TEXTENCODING_UTF8
);
1342 if( !aTxtStrm
.isEof() )
1344 maConfigFiles
.insert( rFileUrl
);
1345 readConfigBlockContents( aTxtStrm
);
1352 void SharedConfigData::createShortList( std::u16string_view rData
)
1354 OUStringVector aDataVec
;
1355 StringHelper::convertStringToStringList( aDataVec
, rData
, false );
1356 if( aDataVec
.size() < 3 )
1359 sal_Int64 nStartKey
;
1360 if( StringHelper::convertStringToInt( nStartKey
, aDataVec
[ 1 ] ) )
1362 std::shared_ptr
< MultiList
> xList
= createNameList
< MultiList
>( aDataVec
[ 0 ] );
1365 aDataVec
.erase( aDataVec
.begin(), aDataVec
.begin() + 2 );
1366 xList
->setNamesFromVec( nStartKey
, aDataVec
);
1371 void SharedConfigData::createUnitConverter( std::u16string_view rData
)
1373 OUStringVector aDataVec
;
1374 StringHelper::convertStringToStringList( aDataVec
, rData
, false );
1375 if( aDataVec
.size() < 2 )
1378 OUString aFactor
= aDataVec
[ 1 ];
1379 bool bRecip
= aFactor
.startsWith("/");
1381 aFactor
= aFactor
.copy( 1 );
1383 if( StringHelper::convertStringToDouble( fFactor
, aFactor
) && (fFactor
!= 0.0) )
1385 std::shared_ptr
< UnitConverter
> xList
= createNameList
< UnitConverter
>( aDataVec
[ 0 ] );
1388 xList
->setFactor( bRecip
? (1.0 / fFactor
) : fFactor
);
1389 if( aDataVec
.size() >= 3 )
1390 xList
->setUnitName( aDataVec
[ 2 ] );
1395 Config::Config( const char* pcEnvVar
, const FilterBase
& rFilter
)
1397 construct( pcEnvVar
, rFilter
);
1400 Config::Config( const char* pcEnvVar
, const Reference
< XComponentContext
>& rxContext
, const StorageRef
& rxRootStrg
, const OUString
& rSysFileName
)
1402 construct( pcEnvVar
, rxContext
, rxRootStrg
, rSysFileName
);
1409 void Config::construct( const char* pcEnvVar
, const FilterBase
& rFilter
)
1411 if( !rFilter
.getFileUrl().isEmpty() )
1412 construct( pcEnvVar
, rFilter
.getComponentContext(), rFilter
.getStorage(), rFilter
.getFileUrl() );
1415 void Config::construct( const char* pcEnvVar
, const Reference
< XComponentContext
>& rxContext
, const StorageRef
& rxRootStrg
, const OUString
& rSysFileName
)
1417 if( pcEnvVar
&& rxRootStrg
&& !rSysFileName
.isEmpty() )
1418 if( const char* pcFileName
= ::getenv( pcEnvVar
) )
1419 mxCfgData
= std::make_shared
<SharedConfigData
>( OUString::createFromAscii( pcFileName
), rxContext
, rxRootStrg
, rSysFileName
);
1422 const OUString
& Config::getStringOption( const String
& rKey
, const OUString
& rDefault
) const
1424 const OUString
* pData
= implGetOption( rKey
);
1425 return pData
? *pData
: rDefault
;
1428 bool Config::getBoolOption( const String
& rKey
, bool bDefault
) const
1430 const OUString
* pData
= implGetOption( rKey
);
1431 return pData
? StringHelper::convertStringToBool( *pData
) : bDefault
;
1434 bool Config::isDumperEnabled() const
1436 return getBoolOption( "enable-dumper", false );
1439 bool Config::isImportEnabled() const
1441 return getBoolOption( "enable-import", true );
1444 void Config::eraseNameList( const String
& rListName
)
1446 mxCfgData
->eraseNameList( rListName
);
1449 NameListRef
Config::getNameList( const String
& rListName
) const
1451 return mxCfgData
->getNameList( rListName
);
1454 bool Config::implIsValid() const
1456 return isValid( mxCfgData
);
1459 const OUString
* Config::implGetOption( const OUString
& rKey
) const
1461 return mxCfgData
->getOption( rKey
);
1464 Output::Output( const Reference
< XComponentContext
>& rxContext
, const OUString
& rFileName
) :
1465 mxStrm( InputOutputHelper::openTextOutputStream( rxContext
, rFileName
, RTL_TEXTENCODING_UTF8
) ),
1473 mxStrm
->writeString( OUString( OOX_DUMP_BOM
) );
1476 void Output::newLine()
1478 if( maLine
.getLength() > 0 )
1480 mxStrm
->writeString( maIndent
);
1481 maLine
.append( '\n' );
1482 mxStrm
->writeString( maLine
.makeStringAndClear() );
1488 void Output::emptyLine( size_t nCount
)
1490 for( size_t nIdx
= 0; nIdx
< nCount
; ++nIdx
)
1491 mxStrm
->writeString( OUString('\n') );
1494 void Output::incIndent()
1496 OUStringBuffer
aBuffer( maIndent
);
1497 StringHelper::appendChar( aBuffer
, ' ', OOX_DUMP_INDENT
);
1498 maIndent
= aBuffer
.makeStringAndClear();
1501 void Output::decIndent()
1503 if( maIndent
.getLength() >= OOX_DUMP_INDENT
)
1504 maIndent
= maIndent
.copy( OOX_DUMP_INDENT
);
1507 void Output::startTable( sal_Int32 nW1
)
1509 startTable( 1, &nW1
);
1512 void Output::startTable( sal_Int32 nW1
, sal_Int32 nW2
)
1514 sal_Int32 pnColWidths
[ 2 ];
1515 pnColWidths
[ 0 ] = nW1
;
1516 pnColWidths
[ 1 ] = nW2
;
1517 startTable( 2, pnColWidths
);
1520 void Output::startTable( sal_Int32 nW1
, sal_Int32 nW2
, sal_Int32 nW3
, sal_Int32 nW4
)
1522 sal_Int32 pnColWidths
[ 4 ];
1523 pnColWidths
[ 0 ] = nW1
;
1524 pnColWidths
[ 1 ] = nW2
;
1525 pnColWidths
[ 2 ] = nW3
;
1526 pnColWidths
[ 3 ] = nW4
;
1527 startTable( 4, pnColWidths
);
1530 void Output::startTable( size_t nColCount
, const sal_Int32
* pnColWidths
)
1533 maColPos
.push_back( 0 );
1534 sal_Int32 nColPos
= 0;
1535 for( size_t nCol
= 0; nCol
< nColCount
; ++nCol
)
1537 nColPos
= nColPos
+ pnColWidths
[ nCol
];
1538 maColPos
.push_back( nColPos
);
1547 void Output::tab( size_t nCol
)
1550 if( mnCol
< maColPos
.size() )
1552 sal_Int32 nColPos
= maColPos
[ mnCol
];
1553 if( maLine
.getLength() >= nColPos
)
1554 maLine
.setLength( ::std::max
< sal_Int32
>( nColPos
- 1, 0 ) );
1555 StringHelper::appendChar( maLine
, ' ', nColPos
- maLine
.getLength() );
1559 StringHelper::appendChar( maLine
, ' ', 2 );
1563 void Output::endTable()
1568 void Output::resetItemIndex( sal_Int64 nIdx
)
1573 void Output::startItem( const String
& rItemName
)
1575 if( mnItemLevel
== 0 )
1577 if( (mnMultiLevel
> 0) && (maLine
.getLength() > 0) )
1579 if( rItemName
.has() )
1581 writeItemName( rItemName
);
1582 writeChar( OOX_DUMP_ITEMSEP
);
1586 mnLastItem
= maLine
.getLength();
1589 void Output::contItem()
1591 if( mnItemLevel
> 0 )
1593 if( (maLine
.getLength() == 0) || (maLine
[ maLine
.getLength() - 1 ] != OOX_DUMP_ITEMSEP
) )
1594 writeChar( OOX_DUMP_ITEMSEP
);
1595 mnLastItem
= maLine
.getLength();
1599 void Output::endItem()
1601 if( mnItemLevel
> 0 )
1603 maLastItem
= maLine
.copy( mnLastItem
).makeStringAndClear();
1604 if( maLastItem
.isEmpty() && mnLastItem
> 0 && maLine
[ mnLastItem
- 1 ] == OOX_DUMP_ITEMSEP
)
1605 maLine
.setLength( mnLastItem
- 1 );
1608 if( mnItemLevel
== 0 )
1610 if( mnMultiLevel
== 0 )
1617 void Output::startMultiItems()
1622 void Output::endMultiItems()
1624 if( mnMultiLevel
> 0 )
1626 if( mnMultiLevel
== 0 )
1630 void Output::writeChar( sal_Unicode cChar
, sal_Int32 nCount
)
1632 StringHelper::appendEncChar( maLine
, cChar
, nCount
);
1635 void Output::writeAscii( const char* pcStr
)
1638 maLine
.appendAscii( pcStr
);
1641 void Output::writeString( std::u16string_view rStr
)
1643 StringHelper::appendEncString( maLine
, rStr
);
1646 void Output::writeArray( const sal_uInt8
* pnData
, std::size_t nSize
, sal_Unicode cSep
)
1648 const sal_uInt8
* pnEnd
= pnData
? (pnData
+ nSize
) : nullptr;
1649 for( const sal_uInt8
* pnByte
= pnData
; pnByte
< pnEnd
; ++pnByte
)
1651 if( pnByte
> pnData
)
1653 writeHex( *pnByte
, false );
1657 void Output::writeBool( bool bData
)
1659 StringHelper::appendBool( maLine
, bData
);
1662 void Output::writeDateTime( const util::DateTime
& rDateTime
)
1664 writeDec( rDateTime
.Year
, 4, '0' );
1666 writeDec( rDateTime
.Month
, 2, '0' );
1668 writeDec( rDateTime
.Day
, 2, '0' );
1670 writeDec( rDateTime
.Hours
, 2, '0' );
1672 writeDec( rDateTime
.Minutes
, 2, '0' );
1674 writeDec( rDateTime
.Seconds
, 2, '0' );
1677 bool Output::implIsValid() const
1682 void Output::writeItemName( const String
& rItemName
)
1684 if( rItemName
.has() && (rItemName
[ 0 ] == '#') )
1686 writeString( rItemName
.subView( 1 ) );
1687 StringHelper::appendIndex( maLine
, mnItemIdx
++ );
1690 writeString( rItemName
);
1693 StorageIterator::StorageIterator( StorageRef xStrg
) :
1694 mxStrg(std::move( xStrg
))
1697 mxStrg
->getElementNames( maNames
);
1698 maIt
= maNames
.begin();
1701 StorageIterator::~StorageIterator()
1705 StorageIterator
& StorageIterator::operator++()
1707 if( maIt
!= maNames
.end() )
1712 OUString
StorageIterator::getName() const
1715 if( maIt
!= maNames
.end() )
1720 bool StorageIterator::isStream() const
1722 return isValid() && mxStrg
->openInputStream( *maIt
).is();
1725 bool StorageIterator::isStorage() const
1729 StorageRef xStrg
= mxStrg
->openSubStorage( *maIt
, false );
1730 return xStrg
&& xStrg
->isStorage();
1733 bool StorageIterator::implIsValid() const
1735 return mxStrg
&& mxStrg
->isStorage() && (maIt
!= maNames
.end());
1738 ObjectBase::~ObjectBase()
1742 void ObjectBase::construct( const ConfigRef
& rxConfig
)
1744 mxConfig
= rxConfig
;
1747 void ObjectBase::construct( const ObjectBase
& rParent
)
1752 void ObjectBase::dump()
1758 bool ObjectBase::implIsValid() const
1760 return isValid( mxConfig
);
1763 void ObjectBase::implDump()
1767 void StorageObjectBase::construct( const ObjectBase
& rParent
, const StorageRef
& rxStrg
, const OUString
& rSysPath
)
1769 ObjectBase::construct( rParent
);
1771 maSysPath
= rSysPath
;
1774 void StorageObjectBase::construct( const ObjectBase
& rParent
)
1776 ObjectBase::construct( rParent
);
1777 if( ObjectBase::implIsValid() )
1779 mxStrg
= cfg().getRootStorage();
1780 maSysPath
= cfg().getSysFileName();
1784 bool StorageObjectBase::implIsValid() const
1786 return mxStrg
&& !maSysPath
.isEmpty() && ObjectBase::implIsValid();
1789 void StorageObjectBase::implDump()
1791 bool bIsStrg
= mxStrg
->isStorage();
1792 bool bIsRoot
= mxStrg
->isRootStorage();
1793 Reference
< XInputStream
> xBaseStrm
;
1795 xBaseStrm
= mxStrg
->openInputStream( OUString() );
1797 OUString aSysOutPath
= maSysPath
;
1800 aSysOutPath
+= OOX_DUMP_DUMPEXT
;
1801 Reference
<XSimpleFileAccess3
> xFileAccess(SimpleFileAccess::create(getContext()));
1802 xFileAccess
->kill( aSysOutPath
);
1810 extractStorage( mxStrg
, OUString(), aSysOutPath
);
1812 else if( xBaseStrm
.is() )
1814 BinaryInputStreamRef
xInStrm( std::make_shared
<BinaryXInputStream
>( xBaseStrm
, false ) );
1815 xInStrm
->seekToStart();
1816 implDumpBaseStream( xInStrm
, aSysOutPath
);
1820 void StorageObjectBase::implDumpStream( const Reference
< XInputStream
>&, const OUString
&, const OUString
&, const OUString
& )
1824 void StorageObjectBase::implDumpStorage( const StorageRef
& rxStrg
, const OUString
& rStrgPath
, const OUString
& rSysPath
)
1826 extractStorage( rxStrg
, rStrgPath
, rSysPath
);
1829 void StorageObjectBase::implDumpBaseStream( const BinaryInputStreamRef
&, const OUString
& )
1833 void StorageObjectBase::addPreferredStream( const String
& rStrmName
)
1835 if( rStrmName
.has() )
1836 maPreferred
.emplace_back( rStrmName
, false );
1839 void StorageObjectBase::addPreferredStorage( const String
& rStrgPath
)
1841 if( rStrgPath
.has() )
1842 maPreferred
.emplace_back( rStrgPath
, true );
1845 OUString
StorageObjectBase::getSysFileName(
1846 std::u16string_view rStrmName
, std::u16string_view rSysOutPath
)
1848 // encode all characters < 0x20
1849 OUStringBuffer aBuffer
;
1850 StringHelper::appendEncString( aBuffer
, rStrmName
, false );
1852 // replace all characters reserved in file system
1853 OUString aFileName
= aBuffer
.makeStringAndClear();
1854 static const sal_Unicode spcReserved
[] = { '/', '\\', ':', '*', '?', '<', '>', '|' };
1855 for(const sal_Unicode cChar
: spcReserved
)
1856 aFileName
= aFileName
.replace(cChar
, '_');
1859 return OUString::Concat(rSysOutPath
) + "/" + aFileName
;
1862 void StorageObjectBase::extractStream( StorageBase
& rStrg
, const OUString
& rStrgPath
, const OUString
& rStrmName
, const OUString
& rSysFileName
)
1864 BinaryXInputStream
aInStrm( rStrg
.openInputStream( rStrmName
), true );
1865 if( !aInStrm
.isEof() )
1867 BinaryXOutputStream
aOutStrm( InputOutputHelper::openOutputStream( getContext(), rSysFileName
), true );
1868 if( !aOutStrm
.isEof() )
1869 aInStrm
.copyToStream( aOutStrm
);
1871 Reference
< XInputStream
> xDumpStrm
= InputOutputHelper::openInputStream( getContext(), rSysFileName
);
1872 if( xDumpStrm
.is() )
1873 implDumpStream( xDumpStrm
, rStrgPath
, rStrmName
, rSysFileName
);
1876 void StorageObjectBase::extractStorage( const StorageRef
& rxStrg
, const OUString
& rStrgPath
, const OUString
& rSysPath
)
1878 // create directory in file system
1879 ::osl::FileBase::RC eRes
= ::osl::Directory::create( rSysPath
);
1880 if( (eRes
!= ::osl::FileBase::E_None
) && (eRes
!= ::osl::FileBase::E_EXIST
) )
1883 // process preferred storages and streams in root storage first
1884 if( rStrgPath
.isEmpty() )
1886 for (auto const& elemPreferred
: maPreferred
)
1887 extractItem( rxStrg
, rStrgPath
, elemPreferred
.maName
, rSysPath
, elemPreferred
.mbStorage
, !elemPreferred
.mbStorage
);
1890 // process children of the storage
1891 for( StorageIterator
aIt( rxStrg
); aIt
.isValid(); ++aIt
)
1893 // skip processed preferred items
1894 OUString aItemName
= aIt
.getName();
1895 bool bFound
= false;
1896 if( rStrgPath
.isEmpty() )
1898 for (auto const& elemPreferred
: maPreferred
)
1900 bFound
= elemPreferred
.maName
== aItemName
;
1906 extractItem( rxStrg
, rStrgPath
, aItemName
, rSysPath
, aIt
.isStorage(), aIt
.isStream() );
1910 void StorageObjectBase::extractItem( const StorageRef
& rxStrg
, const OUString
& rStrgPath
, const OUString
& rItemName
, std::u16string_view rSysPath
, bool bIsStrg
, bool bIsStrm
)
1912 OUString aSysFileName
= getSysFileName( rItemName
, rSysPath
);
1915 OUStringBuffer
aStrgPath( rStrgPath
);
1916 StringHelper::appendToken( aStrgPath
, rItemName
, '/' );
1917 implDumpStorage( rxStrg
->openSubStorage( rItemName
, false ), aStrgPath
.makeStringAndClear(), aSysFileName
);
1921 extractStream( *rxStrg
, rStrgPath
, rItemName
, aSysFileName
);
1925 OutputObjectBase::~OutputObjectBase()
1929 void OutputObjectBase::construct( const ObjectBase
& rParent
, const OUString
& rSysFileName
)
1931 ObjectBase::construct( rParent
);
1932 if( ObjectBase::implIsValid() )
1934 maSysFileName
= rSysFileName
;
1935 mxOut
= std::make_shared
<Output
>( getContext(), rSysFileName
+ OOX_DUMP_DUMPEXT
);
1939 void OutputObjectBase::construct( const OutputObjectBase
& rParent
)
1944 bool OutputObjectBase::implIsValid() const
1946 return isValid( mxOut
) && ObjectBase::implIsValid();
1949 void OutputObjectBase::writeEmptyItem( const String
& rName
)
1951 ItemGuard
aItem( mxOut
, rName
);
1954 void OutputObjectBase::writeInfoItem( const String
& rName
, const String
& rData
)
1956 ItemGuard
aItem( mxOut
, rName
);
1957 mxOut
->writeString( rData
);
1960 void OutputObjectBase::writeCharItem( const String
& rName
, sal_Unicode cData
)
1962 ItemGuard
aItem( mxOut
, rName
);
1963 mxOut
->writeChar( OOX_DUMP_STRQUOTE
);
1964 mxOut
->writeChar( cData
);
1965 mxOut
->writeChar( OOX_DUMP_STRQUOTE
);
1968 void OutputObjectBase::writeStringItem( const String
& rName
, std::u16string_view rData
)
1970 ItemGuard
aItem( mxOut
, rName
);
1971 mxOut
->writeAscii( "(len=" );
1972 mxOut
->writeDec( sal_Int32(rData
.size()) );
1973 mxOut
->writeAscii( ")," );
1974 OUStringBuffer
aValue( rData
.substr( 0, ::std::min( sal_Int32(rData
.size()), OOX_DUMP_MAXSTRLEN
) ) );
1975 StringHelper::enclose( aValue
, OOX_DUMP_STRQUOTE
);
1976 mxOut
->writeString( aValue
.makeStringAndClear() );
1977 if( rData
.size() > OOX_DUMP_MAXSTRLEN
)
1978 mxOut
->writeAscii( ",cut" );
1981 void OutputObjectBase::writeArrayItem( const String
& rName
, const sal_uInt8
* pnData
, std::size_t nSize
, sal_Unicode cSep
)
1983 ItemGuard
aItem( mxOut
, rName
);
1984 mxOut
->writeArray( pnData
, nSize
, cSep
);
1987 void OutputObjectBase::writeDateTimeItem( const String
& rName
, const util::DateTime
& rDateTime
)
1989 ItemGuard
aItem( mxOut
, rName
);
1990 mxOut
->writeDateTime( rDateTime
);
1993 void OutputObjectBase::writeGuidItem( const String
& rName
, const OUString
& rGuid
)
1995 ItemGuard
aItem( mxOut
, rName
);
1996 mxOut
->writeString( rGuid
);
1998 mxOut
->writeString( cfg().getStringOption( rGuid
, OUString() ) );
2001 InputObjectBase::~InputObjectBase()
2005 void InputObjectBase::construct( const ObjectBase
& rParent
, const BinaryInputStreamRef
& rxStrm
, const OUString
& rSysFileName
)
2007 OutputObjectBase::construct( rParent
, rSysFileName
);
2011 void InputObjectBase::construct( const OutputObjectBase
& rParent
, const BinaryInputStreamRef
& rxStrm
)
2013 OutputObjectBase::construct( rParent
);
2017 void InputObjectBase::construct( const InputObjectBase
& rParent
)
2022 bool InputObjectBase::implIsValid() const
2024 return mxStrm
&& OutputObjectBase::implIsValid();
2027 void InputObjectBase::skipBlock( sal_Int64 nBytes
, bool bShowSize
)
2029 sal_Int64 nEndPos
= ::std::min
< sal_Int64
>( mxStrm
->tell() + nBytes
, mxStrm
->size() );
2030 if( mxStrm
->tell() < nEndPos
)
2033 writeDecItem( "skipped-data-size", static_cast< sal_uInt64
>( nEndPos
- mxStrm
->tell() ) );
2034 mxStrm
->seek( nEndPos
);
2038 void InputObjectBase::dumpRawBinary( sal_Int64 nBytes
, bool bShowOffset
, bool bStream
)
2040 TableGuard
aTabGuard( mxOut
,
2041 bShowOffset
? 12 : 0,
2042 3 * OOX_DUMP_BYTESPERLINE
/ 2 + 1,
2043 3 * OOX_DUMP_BYTESPERLINE
/ 2 + 1,
2044 OOX_DUMP_BYTESPERLINE
/ 2 + 1 );
2046 sal_Int64 nMaxShowSize
= cfg().getIntOption
< sal_Int64
>(
2047 bStream
? "max-binary-stream-size" : "max-binary-data-size", SAL_MAX_INT64
);
2049 bool bSeekable
= mxStrm
->size() >= 0;
2050 sal_Int64 nEndPos
= bSeekable
? ::std::min
< sal_Int64
>( mxStrm
->tell() + nBytes
, mxStrm
->size() ) : 0;
2051 sal_Int64 nDumpEnd
= bSeekable
? ::std::min
< sal_Int64
>( mxStrm
->tell() + nMaxShowSize
, nEndPos
) : nMaxShowSize
;
2052 sal_Int64 nPos
= bSeekable
? mxStrm
->tell() : 0;
2055 while( bLoop
&& (nPos
< nDumpEnd
) )
2057 mxOut
->writeHex( static_cast< sal_uInt32
>( nPos
) );
2060 sal_uInt8 pnLineData
[ OOX_DUMP_BYTESPERLINE
];
2061 sal_Int32 nLineSize
= bSeekable
? ::std::min( static_cast< sal_Int32
>( nDumpEnd
- mxStrm
->tell() ), OOX_DUMP_BYTESPERLINE
) : OOX_DUMP_BYTESPERLINE
;
2062 sal_Int32 nReadSize
= mxStrm
->readMemory( pnLineData
, nLineSize
);
2063 bLoop
= nReadSize
== nLineSize
;
2068 const sal_uInt8
* pnByte
= nullptr;
2069 const sal_uInt8
* pnEnd
= nullptr;
2070 for( pnByte
= pnLineData
, pnEnd
= pnLineData
+ nReadSize
; pnByte
!= pnEnd
; ++pnByte
)
2072 if( (pnByte
- pnLineData
) == (OOX_DUMP_BYTESPERLINE
/ 2) ) mxOut
->tab();
2073 mxOut
->writeHex( *pnByte
, false );
2074 mxOut
->writeChar( ' ' );
2078 for( pnByte
= pnLineData
, pnEnd
= pnLineData
+ nReadSize
; pnByte
!= pnEnd
; ++pnByte
)
2080 if( (pnByte
- pnLineData
) == (OOX_DUMP_BYTESPERLINE
/ 2) ) mxOut
->tab();
2081 mxOut
->writeChar( static_cast< sal_Unicode
>( (*pnByte
< 0x20) ? '.' : *pnByte
) );
2087 // skip undumped data
2089 skipBlock( nEndPos
- mxStrm
->tell() );
2092 void InputObjectBase::dumpBinary( const String
& rName
, sal_Int64 nBytes
, bool bShowOffset
)
2095 MultiItemsGuard
aMultiGuard( mxOut
);
2096 writeEmptyItem( rName
);
2097 writeDecItem( "size", nBytes
);
2099 IndentGuard
aIndGuard( mxOut
);
2100 dumpRawBinary( nBytes
, bShowOffset
);
2103 void InputObjectBase::dumpRemaining( sal_Int64 nBytes
)
2107 if( cfg().getBoolOption( "show-trailing-unknown", true ) )
2108 dumpBinary( "remaining-data", nBytes
, false );
2110 skipBlock( nBytes
);
2114 void InputObjectBase::dumpRemainingTo( sal_Int64 nPos
)
2116 if( mxStrm
->isEof() || (mxStrm
->tell() > nPos
) )
2117 writeInfoItem( "stream-state", OOX_DUMP_ERR_STREAM
);
2119 dumpRemaining( nPos
- mxStrm
->tell() );
2120 mxStrm
->seek( nPos
);
2123 void InputObjectBase::dumpRemainingStream()
2125 dumpRemainingTo( mxStrm
->size() );
2128 void InputObjectBase::dumpArray( const String
& rName
, sal_Int32 nBytes
, sal_Unicode cSep
)
2130 sal_Int32 nDumpSize
= getLimitedValue
< sal_Int32
, sal_Int64
>( mxStrm
->size() - mxStrm
->tell(), 0, nBytes
);
2131 if( nDumpSize
> OOX_DUMP_MAXARRAY
)
2133 dumpBinary( rName
, nBytes
, false );
2135 else if( nDumpSize
> 1 )
2137 sal_uInt8 pnData
[ OOX_DUMP_MAXARRAY
];
2138 mxStrm
->readMemory( pnData
, nDumpSize
);
2139 writeArrayItem( rName
, pnData
, nDumpSize
, cSep
);
2141 else if( nDumpSize
== 1 )
2142 dumpHex
< sal_uInt8
>( rName
);
2145 sal_Unicode
InputObjectBase::dumpUnicode( const String
& rName
)
2147 sal_uInt16 nChar
= mxStrm
->readuInt16();
2148 sal_Unicode cChar
= static_cast< sal_Unicode
>( nChar
);
2149 writeCharItem( rName( "char" ), cChar
);
2153 OUString
InputObjectBase::dumpCharArray( const String
& rName
, sal_Int32 nLen
, rtl_TextEncoding eTextEnc
, bool bHideTrailingNul
)
2155 sal_Int32 nDumpSize
= getLimitedValue
< sal_Int32
, sal_Int64
>( mxStrm
->size() - mxStrm
->tell(), 0, nLen
);
2159 ::std::vector
< char > aBuffer( static_cast< std::size_t >( nLen
) + 1 );
2160 sal_Int32 nCharsRead
= mxStrm
->readMemory(aBuffer
.data(), nLen
);
2161 aBuffer
[ nCharsRead
] = 0;
2162 aString
= OStringToOUString(std::string_view(aBuffer
.data()), eTextEnc
);
2164 if( bHideTrailingNul
)
2165 aString
= StringHelper::trimTrailingNul( aString
);
2166 writeStringItem( rName( "text" ), aString
);
2170 OUString
InputObjectBase::dumpUnicodeArray( const String
& rName
, sal_Int32 nLen
, bool bHideTrailingNul
)
2172 OUStringBuffer aBuffer
;
2173 for( sal_Int32 nIndex
= 0; !mxStrm
->isEof() && (nIndex
< nLen
); ++nIndex
)
2175 aBuffer
.append( static_cast< sal_Unicode
>( mxStrm
->readuInt16() ) );
2177 OUString aString
= aBuffer
.makeStringAndClear();
2178 if( bHideTrailingNul
)
2179 aString
= StringHelper::trimTrailingNul( aString
);
2180 writeStringItem( rName( "text" ), aString
);
2184 util::DateTime
InputObjectBase::dumpFileTime( const String
& rName
)
2186 util::DateTime aDateTime
;
2188 ItemGuard
aItem( mxOut
, rName( "file-time" ) );
2189 sal_Int64 nFileTime
= dumpDec
< sal_Int64
>( EMPTY_STRING
);
2190 // file time is in 10^-7 seconds (100 nanoseconds), convert to nanoseconds
2193 sal_Int64 nDays
= nFileTime
/ sal_Int64( ::tools::Time::nanoSecPerDay
);
2194 // number of entire years
2195 sal_Int64 nYears
= (nDays
- (nDays
/ (4 * 365)) + (nDays
/ (100 * 365)) - (nDays
/ (400 * 365))) / 365;
2196 // remaining days in the year
2197 sal_Int64 nDaysInYear
= nDays
- (nYears
* 365 + nYears
/ 4 - nYears
/ 100 + nYears
/ 400);
2198 // the year (file dates start from 1601-01-01)
2199 aDateTime
.Year
= static_cast< sal_uInt16
>( 1601 + nYears
);
2201 bool bLeap
= ((aDateTime
.Year
% 4 == 0) && (aDateTime
.Year
% 100 != 0)) || (aDateTime
.Year
% 400 == 0);
2202 // static arrays with number of days in month
2203 static const sal_Int64 spnDaysInMonth
[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
2204 static const sal_Int64 spnDaysInMonthL
[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
2205 const sal_Int64
* pnDaysInMonth
= bLeap
? spnDaysInMonthL
: spnDaysInMonth
;
2207 aDateTime
.Month
= 1;
2208 while( nDaysInYear
>= *pnDaysInMonth
)
2210 nDaysInYear
-= *pnDaysInMonth
++;
2214 aDateTime
.Day
= static_cast< sal_uInt16
>( nDaysInYear
+ 1 );
2215 // number of nanoseconds in the day
2216 sal_Int64 nTimeInDay
= nFileTime
% sal_Int64( ::tools::Time::nanoSecPerDay
);
2218 aDateTime
.NanoSeconds
= static_cast< sal_uInt32
>( nTimeInDay
% ::tools::Time::nanoSecPerSec
);
2219 nTimeInDay
/= ::tools::Time::nanoSecPerSec
;
2221 aDateTime
.Seconds
= static_cast< sal_uInt16
>( nTimeInDay
% ::tools::Time::secondPerMinute
);
2222 nTimeInDay
/= ::tools::Time::secondPerMinute
;
2224 aDateTime
.Minutes
= static_cast< sal_uInt16
>( nTimeInDay
% ::tools::Time::minutePerHour
);
2225 nTimeInDay
/= ::tools::Time::minutePerHour
;
2227 aDateTime
.Hours
= static_cast< sal_uInt16
>( nTimeInDay
);
2229 writeDateTimeItem( EMPTY_STRING
, aDateTime
);
2233 OUString
InputObjectBase::dumpGuid( const String
& rName
)
2235 OUStringBuffer aBuffer
;
2240 nData32
= mxStrm
->readuInt32();
2241 StringHelper::appendHex( aBuffer
, nData32
, false );
2242 aBuffer
.append( '-' );
2243 nData16
= mxStrm
->readuInt16();
2244 StringHelper::appendHex( aBuffer
, nData16
, false );
2245 aBuffer
.append( '-' );
2246 nData16
= mxStrm
->readuInt16();
2247 StringHelper::appendHex( aBuffer
, nData16
, false );
2248 aBuffer
.append( '-' );
2249 nData8
= mxStrm
->readuChar();
2250 StringHelper::appendHex( aBuffer
, nData8
, false );
2251 nData8
= mxStrm
->readuChar( );
2252 StringHelper::appendHex( aBuffer
, nData8
, false );
2253 aBuffer
.append( '-' );
2254 for( int nIndex
= 0; nIndex
< 6; ++nIndex
)
2256 nData8
= mxStrm
->readuChar( );
2257 StringHelper::appendHex( aBuffer
, nData8
, false );
2259 StringHelper::enclose( aBuffer
, '{', '}' );
2260 OUString aGuid
= aBuffer
.makeStringAndClear();
2261 writeGuidItem( rName( "guid" ), aGuid
);
2265 void InputObjectBase::dumpItem( const ItemFormat
& rItemFmt
)
2267 switch( rItemFmt
.meDataType
)
2269 case DATATYPE_VOID
: break;
2270 case DATATYPE_INT8
: dumpValue
< sal_Int8
>( rItemFmt
); break;
2271 case DATATYPE_UINT8
: dumpValue
< sal_uInt8
>( rItemFmt
); break;
2272 case DATATYPE_INT16
: dumpValue
< sal_Int16
>( rItemFmt
); break;
2273 case DATATYPE_UINT16
: dumpValue
< sal_uInt16
>( rItemFmt
); break;
2274 case DATATYPE_INT32
: dumpValue
< sal_Int32
>( rItemFmt
); break;
2275 case DATATYPE_UINT32
: dumpValue
< sal_uInt32
>( rItemFmt
); break;
2276 case DATATYPE_INT64
: dumpValue
< sal_Int64
>( rItemFmt
); break;
2277 case DATATYPE_UINT64
: dumpValue
< sal_uInt64
>( rItemFmt
); break;
2278 case DATATYPE_FLOAT
: dumpValue
< float >( rItemFmt
); break;
2279 case DATATYPE_DOUBLE
: dumpValue
< double >( rItemFmt
); break;
2284 BinaryStreamObject::BinaryStreamObject( const ObjectBase
& rParent
, const BinaryInputStreamRef
& rxStrm
, const OUString
& rSysFileName
)
2286 InputObjectBase::construct( rParent
, rxStrm
, rSysFileName
);
2289 void BinaryStreamObject::dumpBinaryStream( bool bShowOffset
)
2291 mxStrm
->seekToStart();
2292 dumpRawBinary( mxStrm
->size(), bShowOffset
, true );
2296 void BinaryStreamObject::implDump()
2301 void TextStreamObjectBase::construct( const ObjectBase
& rParent
,
2302 const BinaryInputStreamRef
& rxStrm
, rtl_TextEncoding eTextEnc
, const OUString
& rSysFileName
)
2304 InputObjectBase::construct( rParent
, rxStrm
, rSysFileName
);
2305 constructTextStrmObj( eTextEnc
);
2308 void TextStreamObjectBase::construct( const OutputObjectBase
& rParent
,
2309 const BinaryInputStreamRef
& rxStrm
, rtl_TextEncoding eTextEnc
)
2311 InputObjectBase::construct( rParent
, rxStrm
);
2312 constructTextStrmObj( eTextEnc
);
2315 bool TextStreamObjectBase::implIsValid() const
2317 return InputObjectBase::implIsValid() && mxTextStrm
;
2320 void TextStreamObjectBase::implDump()
2322 implDumpText( *mxTextStrm
);
2325 void TextStreamObjectBase::constructTextStrmObj( rtl_TextEncoding eTextEnc
)
2328 mxTextStrm
= std::make_shared
<TextInputStream
>( getContext(), *mxStrm
, eTextEnc
);
2331 TextLineStreamObject::TextLineStreamObject( const ObjectBase
& rParent
,
2332 const BinaryInputStreamRef
& rxStrm
, rtl_TextEncoding eTextEnc
, const OUString
& rSysFileName
)
2334 TextStreamObjectBase::construct( rParent
, rxStrm
, eTextEnc
, rSysFileName
);
2337 TextLineStreamObject::TextLineStreamObject( const OutputObjectBase
& rParent
,
2338 const BinaryInputStreamRef
& rxStrm
, rtl_TextEncoding eTextEnc
)
2340 TextStreamObjectBase::construct( rParent
, rxStrm
, eTextEnc
);
2343 void TextLineStreamObject::implDumpText( TextInputStream
& rTextStrm
)
2345 sal_uInt32 nLine
= 0;
2346 while( !rTextStrm
.isEof() )
2348 OUString aLine
= rTextStrm
.readLine();
2349 if( !rTextStrm
.isEof() || !aLine
.isEmpty() )
2350 implDumpLine( aLine
, ++nLine
);
2354 void TextLineStreamObject::implDumpLine( std::u16string_view rLine
, sal_uInt32 nLine
)
2356 TableGuard
aTabGuard( mxOut
, 8 );
2357 mxOut
->writeDec( nLine
, 6 );
2359 mxOut
->writeString( rLine
);
2363 XmlStreamObject::XmlStreamObject( const ObjectBase
& rParent
,
2364 const BinaryInputStreamRef
& rxStrm
, const OUString
& rSysFileName
)
2366 TextStreamObjectBase::construct( rParent
, rxStrm
, RTL_TEXTENCODING_UTF8
, rSysFileName
);
2369 void XmlStreamObject::implDumpText( TextInputStream
& rTextStrm
)
2371 /* Buffers a start element and the following element text. Needed to dump
2372 matching start/end elements and the element text on the same line. */
2373 OUStringBuffer aOldStartElem
;
2374 // special handling for VML
2375 bool bIsVml
= o3tl::equalsIgnoreAsciiCase(InputOutputHelper::getFileNameExtension( maSysFileName
), u
"vml");
2377 while( !rTextStrm
.isEof() )
2379 // get the next element and the following element text from text stream
2380 OUString aElem
= rTextStrm
.readToChar( '>', true ).trim();
2381 OUString aText
= rTextStrm
.readToChar( '<', false );
2383 // remove multiple whitespace from element
2385 while( nPos
< aElem
.getLength() )
2387 while( (nPos
< aElem
.getLength()) && (aElem
[ nPos
] >= 32) ) ++nPos
;
2388 if( nPos
< aElem
.getLength() )
2389 aElem
= aElem
.subView( 0, nPos
) + OUStringChar(' ') + o3tl::trim(aElem
.subView( nPos
));
2393 sal_Int32 nElemLen
= aElem
.getLength();
2394 if( (nElemLen
>= 2) && (aElem
[ 0 ] == '<') && (aElem
[ nElemLen
- 1 ] == '>') )
2396 // determine type of the element
2397 bool bSimpleElem
= (aElem
[ 1 ] == '!') || (aElem
[ 1 ] == '?') || (aElem
[ nElemLen
- 2 ] == '/') ||
2398 (bIsVml
&& (nElemLen
== 4) && (aElem
[ 1 ] == 'b') && (aElem
[ 2 ] == 'r'));
2399 bool bStartElem
= !bSimpleElem
&& (aElem
[ 1 ] != '/');
2400 bool bEndElem
= !bSimpleElem
&& !bStartElem
;
2402 /* Start element or simple element: flush old start element and
2403 its text from previous iteration, and start a new indentation
2404 level for the new element. Trim whitespace and line breaks from
2405 the text of the old start element. */
2406 if( (bSimpleElem
|| bStartElem
) && (aOldStartElem
.getLength() > 0) )
2408 mxOut
->writeString( o3tl::trim(aOldStartElem
.makeStringAndClear()) );
2413 /* Start element: remember it and its text, to be able to print the
2414 matching end element on the same line in the next iteration. */
2417 aOldStartElem
.append( aElem
+ aText
);
2421 /* End element: if a start element has been remembered in the
2422 previous iteration, write it out here untrimmed, to show
2423 all whitespace in the element text, and without trailing
2424 line break. Code below will add the end element right after
2425 it. Otherwise, return to previous indentation level. */
2428 if( aOldStartElem
.getLength() == 0 )
2431 mxOut
->writeString( aOldStartElem
.makeStringAndClear() );
2434 /* Write the element. Write following element text in a new
2435 line, but only, if it does not contain of white space
2437 mxOut
->writeString( aElem
);
2439 if( !o3tl::trim(aText
).empty() )
2441 mxOut
->writeString( aText
);
2449 void RecordObjectBase::construct( const ObjectBase
& rParent
,
2450 const BinaryInputStreamRef
& rxBaseStrm
, const OUString
& rSysFileName
,
2451 const BinaryInputStreamRef
& rxRecStrm
, const String
& rRecNames
, const String
& rSimpleRecs
)
2453 InputObjectBase::construct( rParent
, rxRecStrm
, rSysFileName
);
2454 constructRecObjBase( rxBaseStrm
, rRecNames
, rSimpleRecs
);
2457 bool RecordObjectBase::implIsValid() const
2459 return mxBaseStrm
&& InputObjectBase::implIsValid();
2462 void RecordObjectBase::implDump()
2464 NameListRef xRecNames
= maRecNames
.getNameList( cfg() );
2465 ItemFormatMap
aSimpleRecs( maSimpleRecs
.getNameList( cfg() ) );
2467 while( implStartRecord( *mxBaseStrm
, mnRecPos
, mnRecId
, mnRecSize
) )
2472 implWriteExtHeader();
2473 IndentGuard
aIndGuard( mxOut
);
2474 sal_Int64 nRecPos
= mxStrm
->tell();
2477 if( !mbBinaryOnly
&& cfg().hasName( xRecNames
, mnRecId
) )
2479 ::std::map
< sal_Int64
, ItemFormat
>::const_iterator aIt
= aSimpleRecs
.find( mnRecId
);
2480 if( aIt
!= aSimpleRecs
.end() )
2481 dumpItem( aIt
->second
);
2483 implDumpRecordBody();
2486 // remaining undumped data
2487 if( !mxStrm
->isEof() && (mxStrm
->tell() == nRecPos
) )
2488 dumpRawBinary( mnRecSize
, false );
2490 dumpRemainingTo( nRecPos
+ mnRecSize
);
2494 void RecordObjectBase::implWriteExtHeader()
2498 void RecordObjectBase::implDumpRecordBody()
2502 void RecordObjectBase::constructRecObjBase( const BinaryInputStreamRef
& rxBaseStrm
, const String
& rRecNames
, const String
& rSimpleRecs
)
2504 mxBaseStrm
= rxBaseStrm
;
2505 maRecNames
= rRecNames
;
2506 maSimpleRecs
= rSimpleRecs
;
2507 mnRecPos
= mnRecId
= mnRecSize
= 0;
2508 mbBinaryOnly
= false;
2509 if( InputObjectBase::implIsValid() )
2510 mbShowRecPos
= cfg().getBoolOption( "show-record-position", true );
2513 void RecordObjectBase::writeHeader()
2515 MultiItemsGuard
aMultiGuard( mxOut
);
2516 writeEmptyItem( "REC" );
2517 if( mbShowRecPos
&& mxBaseStrm
->isSeekable() )
2518 writeShortHexItem( "pos", mnRecPos
, "CONV-DEC" );
2519 writeShortHexItem( "size", mnRecSize
, "CONV-DEC" );
2520 ItemGuard
aItem( mxOut
, "id" );
2521 mxOut
->writeShortHex( mnRecId
);
2522 addNameToItem( mnRecId
, "CONV-DEC" );
2523 addNameToItem( mnRecId
, maRecNames
);
2526 void SequenceRecordObjectBase::construct( const ObjectBase
& rParent
,
2527 const BinaryInputStreamRef
& rxBaseStrm
, const OUString
& rSysFileName
,
2528 const String
& rRecNames
, const String
& rSimpleRecs
)
2530 BinaryInputStreamRef
xRecStrm( std::make_shared
<SequenceInputStream
>( *mxRecData
) );
2531 RecordObjectBase::construct( rParent
, rxBaseStrm
, rSysFileName
, xRecStrm
, rRecNames
, rSimpleRecs
);
2534 bool SequenceRecordObjectBase::implStartRecord( BinaryInputStream
& rBaseStrm
, sal_Int64
& ornRecPos
, sal_Int64
& ornRecId
, sal_Int64
& ornRecSize
)
2537 if( rBaseStrm
.isSeekable() )
2539 ornRecPos
= rBaseStrm
.tell();
2540 // do not try to overread seekable streams, may cause assertions
2541 bValid
= ornRecPos
< rBaseStrm
.size();
2544 // read the record header
2546 bValid
= implReadRecordHeader( rBaseStrm
, ornRecId
, ornRecSize
) && !rBaseStrm
.isEof() && (0 <= ornRecSize
) && (ornRecSize
<= 0x00100000);
2548 // read record contents into data sequence
2551 sal_Int32 nRecSize
= static_cast< sal_Int32
>( ornRecSize
);
2552 mxRecData
->realloc( nRecSize
);
2553 bValid
= (nRecSize
== 0) || (rBaseStrm
.readData( *mxRecData
, nRecSize
) == nRecSize
);
2554 mxStrm
->seekToStart();
2559 DumperBase::~DumperBase()
2563 bool DumperBase::isImportEnabled() const
2565 return !isValid() || cfg().isImportEnabled();
2568 void DumperBase::construct( const ConfigRef
& rxConfig
)
2570 if( isValid( rxConfig
) && rxConfig
->isDumperEnabled() )
2571 ObjectBase::construct( rxConfig
);
2578 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */