bump product version to 5.0.4.1
[LibreOffice.git] / oox / source / dump / dumperbase.cxx
blob9b3cc6c5859380a26fcecc64122883e326a58b33
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
22 #include <algorithm>
23 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
24 #include <com/sun/star/io/XActiveDataSource.hpp>
25 #include <com/sun/star/io/TextOutputStream.hpp>
26 #include <com/sun/star/ucb/SimpleFileAccess.hpp>
27 #include <comphelper/docpasswordhelper.hxx>
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>
36 #if OOX_INCLUDE_DUMPER
38 namespace oox {
39 namespace dump {
41 using namespace ::com::sun::star;
42 using namespace ::com::sun::star::beans;
43 using namespace ::com::sun::star::io;
44 using namespace ::com::sun::star::lang;
45 using namespace ::com::sun::star::ucb;
46 using namespace ::com::sun::star::uno;
48 using ::oox::core::FilterBase;
50 namespace {
52 const sal_Unicode OOX_DUMP_BOM = 0xFEFF;
53 const sal_Int32 OOX_DUMP_MAXSTRLEN = 80;
54 const sal_Int32 OOX_DUMP_INDENT = 2;
55 const sal_Unicode OOX_DUMP_BINDOT = '.';
56 const sal_Unicode OOX_DUMP_CFG_LISTSEP = ',';
57 const sal_Unicode OOX_DUMP_CFG_QUOTE = '\'';
58 const sal_Unicode OOX_DUMP_LF = '\n';
59 const sal_Unicode OOX_DUMP_ITEMSEP = '=';
60 const sal_Int32 OOX_DUMP_BYTESPERLINE = 16;
61 const sal_Int64 OOX_DUMP_MAXARRAY = 16;
63 } // namespace
65 // file names -----------------------------------------------------------------
67 OUString InputOutputHelper::convertFileNameToUrl( const OUString& rFileName )
69 OUString aFileUrl;
70 if( ::osl::FileBase::getFileURLFromSystemPath( rFileName, aFileUrl ) == ::osl::FileBase::E_None )
71 return aFileUrl;
72 return OUString();
75 sal_Int32 InputOutputHelper::getFileNamePos( const OUString& rFileUrl )
77 sal_Int32 nSepPos = rFileUrl.lastIndexOf( '/' );
78 return (nSepPos < 0) ? 0 : (nSepPos + 1);
81 OUString InputOutputHelper::getFileNameExtension( const OUString& rFileUrl )
83 sal_Int32 nNamePos = getFileNamePos( rFileUrl );
84 sal_Int32 nExtPos = rFileUrl.lastIndexOf( '.' );
85 if( nExtPos >= nNamePos )
86 return rFileUrl.copy( nExtPos + 1 );
87 return OUString();
90 // input streams --------------------------------------------------------------
92 Reference< XInputStream > InputOutputHelper::openInputStream(
93 const Reference< XComponentContext >& rxContext, const OUString& rFileName )
95 Reference< XInputStream > xInStrm;
96 if( rxContext.is() ) try
98 Reference<XSimpleFileAccess3> xFileAccess(SimpleFileAccess::create(rxContext));
99 xInStrm = xFileAccess->openFileRead( rFileName );
101 catch( Exception& )
104 return xInStrm;
107 // output streams -------------------------------------------------------------
109 Reference< XOutputStream > InputOutputHelper::openOutputStream(
110 const Reference< XComponentContext >& rxContext, const OUString& rFileName )
112 Reference< XOutputStream > xOutStrm;
113 if( rxContext.is() ) try
115 Reference<XSimpleFileAccess3> xFileAccess(SimpleFileAccess::create(rxContext));
116 xOutStrm = xFileAccess->openFileWrite( rFileName );
118 catch( Exception& )
121 return xOutStrm;
124 Reference< XTextOutputStream2 > InputOutputHelper::openTextOutputStream(
125 const Reference< XComponentContext >& rxContext, const Reference< XOutputStream >& rxOutStrm, rtl_TextEncoding eTextEnc )
127 Reference< XTextOutputStream2 > xTextOutStrm;
128 const char* pcCharset = rtl_getMimeCharsetFromTextEncoding( eTextEnc );
129 if( rxContext.is() && rxOutStrm.is() && pcCharset ) try
131 xTextOutStrm = TextOutputStream::create(rxContext);
132 xTextOutStrm->setOutputStream( rxOutStrm );
133 xTextOutStrm->setEncoding( OUString::createFromAscii( pcCharset ) );
135 catch( Exception& )
138 return xTextOutStrm;
141 Reference< XTextOutputStream2 > InputOutputHelper::openTextOutputStream(
142 const Reference< XComponentContext >& rxContext, const OUString& rFileName, rtl_TextEncoding eTextEnc )
144 return openTextOutputStream( rxContext, openOutputStream( rxContext, rFileName ), eTextEnc );
147 ItemFormat::ItemFormat() :
148 meDataType( DATATYPE_VOID ),
149 meFmtType( FORMATTYPE_NONE )
153 void ItemFormat::set( DataType eDataType, FormatType eFmtType, const OUString& rItemName )
155 meDataType = eDataType;
156 meFmtType = eFmtType;
157 maItemName = rItemName;
158 maListName.clear();
161 OUStringVector::const_iterator ItemFormat::parse( const OUStringVector& rFormatVec )
163 set( DATATYPE_VOID, FORMATTYPE_NONE, OUString() );
165 OUStringVector::const_iterator aIt = rFormatVec.begin(), aEnd = rFormatVec.end();
166 OUString aDataType, aFmtType;
167 if( aIt != aEnd ) aDataType = *aIt++;
168 if( aIt != aEnd ) aFmtType = *aIt++;
169 if( aIt != aEnd ) maItemName = *aIt++;
170 if( aIt != aEnd ) maListName = *aIt++;
172 meDataType = StringHelper::convertToDataType( aDataType );
173 meFmtType = StringHelper::convertToFormatType( aFmtType );
175 if( meFmtType == FORMATTYPE_NONE )
177 if ( aFmtType == "unused" )
178 set( meDataType, FORMATTYPE_HEX, OOX_DUMP_UNUSED );
179 else if ( aFmtType == "unknown" )
180 set( meDataType, FORMATTYPE_HEX, OOX_DUMP_UNKNOWN );
183 return aIt;
186 OUStringVector ItemFormat::parse( const OUString& rFormatStr )
188 OUStringVector aFormatVec;
189 StringHelper::convertStringToStringList( aFormatVec, rFormatStr, false );
190 OUStringVector::const_iterator aIt = parse( aFormatVec );
191 return OUStringVector( aIt, const_cast< const OUStringVector& >( aFormatVec ).end() );
194 // append string to string ----------------------------------------------------
196 void StringHelper::appendChar( OUStringBuffer& rStr, sal_Unicode cChar, sal_Int32 nCount )
198 for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
199 rStr.append( cChar );
202 void StringHelper::appendString( OUStringBuffer& rStr, const OUString& rData, sal_Int32 nWidth, sal_Unicode cFill )
204 appendChar( rStr, cFill, nWidth - rData.getLength() );
205 rStr.append( rData );
208 // append decimal -------------------------------------------------------------
210 void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt8 nData, sal_Int32 nWidth, sal_Unicode cFill )
212 appendString( rStr, OUString::number( nData ), nWidth, cFill );
215 void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int8 nData, sal_Int32 nWidth, sal_Unicode cFill )
217 appendString( rStr, OUString::number( nData ), nWidth, cFill );
220 void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt16 nData, sal_Int32 nWidth, sal_Unicode cFill )
222 appendString( rStr, OUString::number( nData ), nWidth, cFill );
225 void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int16 nData, sal_Int32 nWidth, sal_Unicode cFill )
227 appendString( rStr, OUString::number( nData ), nWidth, cFill );
230 void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt32 nData, sal_Int32 nWidth, sal_Unicode cFill )
232 appendString( rStr, OUString::number( nData ), nWidth, cFill );
235 void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int32 nData, sal_Int32 nWidth, sal_Unicode cFill )
237 appendString( rStr, OUString::number( nData ), nWidth, cFill );
240 void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt64 nData, sal_Int32 nWidth, sal_Unicode cFill )
242 /* Values greater than biggest signed 64bit integer will change to
243 negative when converting to sal_Int64. Therefore, the trailing digit
244 will be written separately. */
245 OUStringBuffer aBuffer;
246 if( nData > 9 )
247 aBuffer.append( OUString::number( nData / 10 ) );
248 aBuffer.append( static_cast< sal_Unicode >( '0' + (nData % 10) ) );
249 appendString( rStr, aBuffer.makeStringAndClear(), nWidth, cFill );
252 void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int64 nData, sal_Int32 nWidth, sal_Unicode cFill )
254 appendString( rStr, OUString::number( nData ), nWidth, cFill );
257 void StringHelper::appendDec( OUStringBuffer& rStr, double fData, sal_Int32 nWidth, sal_Unicode cFill )
259 appendString( rStr, ::rtl::math::doubleToUString( fData, rtl_math_StringFormat_G, 15, '.', true ), nWidth, cFill );
262 // append hexadecimal ---------------------------------------------------------
264 void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt8 nData, bool bPrefix )
266 static const sal_Unicode spcHexDigits[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
267 if( bPrefix )
268 rStr.appendAscii( "0x" );
269 rStr.append( spcHexDigits[ (nData >> 4) & 0x0F ] ).append( spcHexDigits[ nData & 0x0F ] );
272 void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int8 nData, bool bPrefix )
274 appendHex( rStr, static_cast< sal_uInt8 >( nData ), bPrefix );
277 void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt16 nData, bool bPrefix )
279 appendHex( rStr, static_cast< sal_uInt8 >( nData >> 8 ), bPrefix );
280 appendHex( rStr, static_cast< sal_uInt8 >( nData ), false );
283 void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int16 nData, bool bPrefix )
285 appendHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix );
288 void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt32 nData, bool bPrefix )
290 appendHex( rStr, static_cast< sal_uInt16 >( nData >> 16 ), bPrefix );
291 appendHex( rStr, static_cast< sal_uInt16 >( nData ), false );
294 void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int32 nData, bool bPrefix )
296 appendHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix );
299 void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt64 nData, bool bPrefix )
301 appendHex( rStr, static_cast< sal_uInt32 >( nData >> 32 ), bPrefix );
302 appendHex( rStr, static_cast< sal_uInt32 >( nData ), false );
305 void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int64 nData, bool bPrefix )
307 appendHex( rStr, static_cast< sal_uInt64 >( nData ), bPrefix );
310 static sal_uInt64
311 lcl_ConvertDouble(double const f)
313 sal_uInt64 i = sal_uInt64();
314 for (size_t j = 0; j < sizeof(double); ++j)
315 { // hopefully both endian independent and strict aliasing safe
316 reinterpret_cast<char *>(&i)[j] = reinterpret_cast<char const *>(&f)[j];
318 return i;
321 void StringHelper::appendHex( OUStringBuffer& rStr, double fData, bool bPrefix )
323 appendHex( rStr, lcl_ConvertDouble(fData), bPrefix );
326 // append shortened hexadecimal -----------------------------------------------
328 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt8 nData, bool bPrefix )
330 appendHex( rStr, nData, bPrefix );
333 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int8 nData, bool bPrefix )
335 appendHex( rStr, nData, bPrefix );
338 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt16 nData, bool bPrefix )
340 if( nData > SAL_MAX_UINT8 )
341 appendHex( rStr, nData, bPrefix );
342 else
343 appendHex( rStr, static_cast< sal_uInt8 >( nData ), bPrefix );
346 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int16 nData, bool bPrefix )
348 appendShortHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix );
351 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt32 nData, bool bPrefix )
353 if( nData > SAL_MAX_UINT16 )
354 appendHex( rStr, nData, bPrefix );
355 else
356 appendShortHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix );
359 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int32 nData, bool bPrefix )
361 appendShortHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix );
364 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt64 nData, bool bPrefix )
366 if( nData > SAL_MAX_UINT32 )
367 appendHex( rStr, nData, bPrefix );
368 else
369 appendShortHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix );
372 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int64 nData, bool bPrefix )
374 appendShortHex( rStr, static_cast< sal_uInt64 >( nData ), bPrefix );
377 void StringHelper::appendShortHex( OUStringBuffer& rStr, double fData, bool bPrefix )
379 appendHex( rStr, fData, bPrefix );
382 // append binary --------------------------------------------------------------
384 void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt8 nData, bool bDots )
386 for( sal_uInt8 nMask = 0x80; nMask != 0; (nMask >>= 1) &= 0x7F )
388 rStr.append( static_cast< sal_Unicode >( (nData & nMask) ? '1' : '0' ) );
389 if( bDots && (nMask == 0x10) )
390 rStr.append( OOX_DUMP_BINDOT );
394 void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int8 nData, bool bDots )
396 appendBin( rStr, static_cast< sal_uInt8 >( nData ), bDots );
399 void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt16 nData, bool bDots )
401 appendBin( rStr, static_cast< sal_uInt8 >( nData >> 8 ), bDots );
402 if( bDots )
403 rStr.append( OOX_DUMP_BINDOT );
404 appendBin( rStr, static_cast< sal_uInt8 >( nData ), bDots );
407 void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int16 nData, bool bDots )
409 appendBin( rStr, static_cast< sal_uInt16 >( nData ), bDots );
412 void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt32 nData, bool bDots )
414 appendBin( rStr, static_cast< sal_uInt16 >( nData >> 16 ), bDots );
415 if( bDots )
416 rStr.append( OOX_DUMP_BINDOT );
417 appendBin( rStr, static_cast< sal_uInt16 >( nData ), bDots );
420 void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int32 nData, bool bDots )
422 appendBin( rStr, static_cast< sal_uInt32 >( nData ), bDots );
425 void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt64 nData, bool bDots )
427 appendBin( rStr, static_cast< sal_uInt32 >( nData >> 32 ), bDots );
428 if( bDots )
429 rStr.append( OOX_DUMP_BINDOT );
430 appendBin( rStr, static_cast< sal_uInt32 >( nData ), bDots );
433 void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int64 nData, bool bDots )
435 appendBin( rStr, static_cast< sal_uInt64 >( nData ), bDots );
438 void StringHelper::appendBin( OUStringBuffer& rStr, double fData, bool bDots )
440 appendBin( rStr, lcl_ConvertDouble(fData), bDots );
443 // append formatted value -----------------------------------------------------
445 void StringHelper::appendBool( OUStringBuffer& rStr, bool bData )
447 rStr.appendAscii( bData ? "true" : "false" );
450 // encoded text output --------------------------------------------------------
452 void StringHelper::appendCChar( OUStringBuffer& rStr, sal_Unicode cChar, bool bPrefix )
454 if( cChar > 0x00FF )
456 if( bPrefix )
457 rStr.appendAscii( "\\u" );
458 appendHex( rStr, static_cast< sal_uInt16 >( cChar ), false );
460 else
462 if( bPrefix )
463 rStr.appendAscii( "\\x" );
464 appendHex( rStr, static_cast< sal_uInt8 >( cChar ), false );
468 void StringHelper::appendEncChar( OUStringBuffer& rStr, sal_Unicode cChar, sal_Int32 nCount, bool bPrefix )
470 if( cChar < 0x0020 )
472 // C-style hex code
473 OUStringBuffer aCode;
474 appendCChar( aCode, cChar, bPrefix );
475 OUString aCodeStr = aCode.makeStringAndClear();
476 for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
477 rStr.append( aCodeStr );
479 else
481 appendChar( rStr, cChar, nCount );
485 void StringHelper::appendEncString( OUStringBuffer& rStr, const OUString& rData, bool bPrefix )
487 sal_Int32 nBeg = 0;
488 sal_Int32 nIdx = 0;
489 sal_Int32 nEnd = rData.getLength();
490 while( nIdx < nEnd )
492 // find next character that needs encoding
493 while( (nIdx < nEnd) && (rData[ nIdx ] >= 0x20) ) ++nIdx;
494 // append portion
495 if( nBeg < nIdx )
497 if( (nBeg == 0) && (nIdx == nEnd) )
498 rStr.append( rData );
499 else
500 rStr.append( rData.copy( nBeg, nIdx - nBeg ) );
502 // append characters to be encoded
503 while( (nIdx < nEnd) && (rData[ nIdx ] < 0x20) )
505 appendCChar( rStr, rData[ nIdx ], bPrefix );
506 ++nIdx;
508 // adjust limits
509 nBeg = nIdx;
513 // token list -----------------------------------------------------------------
515 void StringHelper::appendToken( OUStringBuffer& rStr, const OUString& rToken, sal_Unicode cSep )
517 if( (rStr.getLength() > 0) && (!rToken.isEmpty()) )
518 rStr.append( cSep );
519 rStr.append( rToken );
522 void StringHelper::appendIndex( OUStringBuffer& rStr, const OUString& rIdx )
524 rStr.append( '[' ).append( rIdx ).append( ']' );
527 void StringHelper::appendIndex( OUStringBuffer& rStr, sal_Int64 nIdx )
529 OUStringBuffer aToken;
530 appendDec( aToken, nIdx );
531 appendIndex( rStr, aToken.makeStringAndClear() );
534 OUString StringHelper::getToken( const OUString& rData, sal_Int32& rnPos, sal_Unicode cSep )
536 return trimSpaces( rData.getToken( 0, cSep, rnPos ) );
539 void StringHelper::enclose( OUStringBuffer& rStr, sal_Unicode cOpen, sal_Unicode cClose )
541 rStr.insert( 0, cOpen ).append( cClose ? cClose : cOpen );
544 // string conversion ----------------------------------------------------------
546 namespace {
548 sal_Int32 lclIndexOf( const OUString& rStr, sal_Unicode cChar, sal_Int32 nStartPos )
550 sal_Int32 nIndex = rStr.indexOf( cChar, nStartPos );
551 return (nIndex < 0) ? rStr.getLength() : nIndex;
554 OUString lclTrimQuotedStringList( const OUString& rStr )
556 OUStringBuffer aBuffer;
557 sal_Int32 nPos = 0;
558 sal_Int32 nLen = rStr.getLength();
559 while( nPos < nLen )
561 if( rStr[ nPos ] == OOX_DUMP_CFG_QUOTE )
563 // quoted string, skip leading quote character
564 ++nPos;
565 // process quoted text and ambedded literal quote characters
566 OUStringBuffer aToken;
569 // seek to next quote character and add text portion to token buffer
570 sal_Int32 nEnd = lclIndexOf( rStr, OOX_DUMP_CFG_QUOTE, nPos );
571 aToken.append( rStr.copy( nPos, nEnd - nPos ) );
572 // process literal quotes
573 while( (nEnd + 1 < nLen) && (rStr[ nEnd ] == OOX_DUMP_CFG_QUOTE) && (rStr[ nEnd + 1 ] == OOX_DUMP_CFG_QUOTE) )
575 aToken.append( OOX_DUMP_CFG_QUOTE );
576 nEnd += 2;
578 // nEnd is start of possible next text portion
579 nPos = nEnd;
581 while( (nPos < nLen) && (rStr[ nPos ] != OOX_DUMP_CFG_QUOTE) );
582 // add token, seek to list separator, ignore text following closing quote
583 aBuffer.append( aToken.makeStringAndClear() );
584 nPos = lclIndexOf( rStr, OOX_DUMP_CFG_LISTSEP, nPos );
585 if( nPos < nLen )
586 aBuffer.append( OOX_DUMP_LF );
587 // set current position behind list separator
588 ++nPos;
590 else
592 // find list separator, add token text to buffer
593 sal_Int32 nEnd = lclIndexOf( rStr, OOX_DUMP_CFG_LISTSEP, nPos );
594 aBuffer.append( rStr.copy( nPos, nEnd - nPos ) );
595 if( nEnd < nLen )
596 aBuffer.append( OOX_DUMP_LF );
597 // set current position behind list separator
598 nPos = nEnd + 1;
602 return aBuffer.makeStringAndClear();
605 } // namespace
607 OUString StringHelper::trimSpaces( const OUString& rStr )
609 sal_Int32 nBeg = 0;
610 while( (nBeg < rStr.getLength()) && ((rStr[ nBeg ] == ' ') || (rStr[ nBeg ] == '\t')) )
611 ++nBeg;
612 sal_Int32 nEnd = rStr.getLength();
613 while( (nEnd > nBeg) && ((rStr[ nEnd - 1 ] == ' ') || (rStr[ nEnd - 1 ] == '\t')) )
614 --nEnd;
615 return rStr.copy( nBeg, nEnd - nBeg );
618 OUString StringHelper::trimTrailingNul( const OUString& rStr )
620 sal_Int32 nLastPos = rStr.getLength() - 1;
621 if( (nLastPos >= 0) && (rStr[ nLastPos ] == 0) )
622 return rStr.copy( 0, nLastPos );
623 return rStr;
626 OString StringHelper::convertToUtf8( const OUString& rStr )
628 return OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 );
631 DataType StringHelper::convertToDataType( const OUString& rStr )
633 DataType eType = DATATYPE_VOID;
634 if ( rStr == "int8" )
635 eType = DATATYPE_INT8;
636 else if ( rStr == "uint8" )
637 eType = DATATYPE_UINT8;
638 else if ( rStr == "int16" )
639 eType = DATATYPE_INT16;
640 else if ( rStr == "uint16" )
641 eType = DATATYPE_UINT16;
642 else if ( rStr == "int32" )
643 eType = DATATYPE_INT32;
644 else if ( rStr == "uint32" )
645 eType = DATATYPE_UINT32;
646 else if ( rStr == "int64" )
647 eType = DATATYPE_INT64;
648 else if ( rStr == "uint64" )
649 eType = DATATYPE_UINT64;
650 else if ( rStr == "float" )
651 eType = DATATYPE_FLOAT;
652 else if ( rStr == "double" )
653 eType = DATATYPE_DOUBLE;
654 return eType;
657 FormatType StringHelper::convertToFormatType( const OUString& rStr )
659 FormatType eType = FORMATTYPE_NONE;
660 if ( rStr == "dec" )
661 eType = FORMATTYPE_DEC;
662 else if ( rStr == "hex" )
663 eType = FORMATTYPE_HEX;
664 else if ( rStr == "shorthex" )
665 eType = FORMATTYPE_SHORTHEX;
666 else if ( rStr == "bin" )
667 eType = FORMATTYPE_BIN;
668 else if ( rStr == "fix" )
669 eType = FORMATTYPE_FIX;
670 else if ( rStr == "bool" )
671 eType = FORMATTYPE_BOOL;
672 return eType;
675 bool StringHelper::convertFromDec( sal_Int64& ornData, const OUString& rData )
677 sal_Int32 nPos = 0;
678 sal_Int32 nLen = rData.getLength();
679 bool bNeg = false;
680 if( (nLen > 0) && (rData[ 0 ] == '-') )
682 bNeg = true;
683 ++nPos;
685 ornData = 0;
686 for( ; nPos < nLen; ++nPos )
688 sal_Unicode cChar = rData[ nPos ];
689 if( (cChar < '0') || (cChar > '9') )
690 return false;
691 (ornData *= 10) += (cChar - '0');
693 if( bNeg )
694 ornData *= -1;
695 return true;
698 bool StringHelper::convertFromHex( sal_Int64& ornData, const OUString& rData )
700 ornData = 0;
701 for( sal_Int32 nPos = 0, nLen = rData.getLength(); nPos < nLen; ++nPos )
703 sal_Unicode cChar = rData[ nPos ];
704 if( ('0' <= cChar) && (cChar <= '9') )
705 cChar -= '0';
706 else if( ('A' <= cChar) && (cChar <= 'F') )
707 cChar -= ('A' - 10);
708 else if( ('a' <= cChar) && (cChar <= 'f') )
709 cChar -= ('a' - 10);
710 else
711 return false;
712 (ornData <<= 4) += cChar;
714 return true;
717 bool StringHelper::convertStringToInt( sal_Int64& ornData, const OUString& rData )
719 if( (rData.getLength() > 2) && (rData[ 0 ] == '0') && ((rData[ 1 ] == 'X') || (rData[ 1 ] == 'x')) )
720 return convertFromHex( ornData, rData.copy( 2 ) );
721 return convertFromDec( ornData, rData );
724 bool StringHelper::convertStringToDouble( double& orfData, const OUString& rData )
726 rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
727 sal_Int32 nSize = 0;
728 orfData = rtl::math::stringToDouble( rData, '.', '\0', &eStatus, &nSize );
729 return (eStatus == rtl_math_ConversionStatus_Ok) && (nSize == rData.getLength());
732 bool StringHelper::convertStringToBool( const OUString& rData )
734 if ( rData == "true" )
735 return true;
736 if ( rData == "false" )
737 return false;
738 sal_Int64 nData;
739 return convertStringToInt( nData, rData ) && (nData != 0);
742 OUStringPair StringHelper::convertStringToPair( const OUString& rString, sal_Unicode cSep )
744 OUStringPair aPair;
745 if( !rString.isEmpty() )
747 sal_Int32 nEqPos = rString.indexOf( cSep );
748 if( nEqPos < 0 )
750 aPair.first = rString;
752 else
754 aPair.first = StringHelper::trimSpaces( rString.copy( 0, nEqPos ) );
755 aPair.second = StringHelper::trimSpaces( rString.copy( nEqPos + 1 ) );
758 return aPair;
761 void StringHelper::convertStringToStringList( OUStringVector& orVec, const OUString& rData, bool bIgnoreEmpty )
763 orVec.clear();
764 OUString aUnquotedData = lclTrimQuotedStringList( rData );
765 sal_Int32 nPos = 0;
766 sal_Int32 nLen = aUnquotedData.getLength();
767 while( (0 <= nPos) && (nPos < nLen) )
769 OUString aToken = getToken( aUnquotedData, nPos, OOX_DUMP_LF );
770 if( !bIgnoreEmpty || !aToken.isEmpty() )
771 orVec.push_back( aToken );
775 void StringHelper::convertStringToIntList( Int64Vector& orVec, const OUString& rData, bool bIgnoreEmpty )
777 orVec.clear();
778 OUString aUnquotedData = lclTrimQuotedStringList( rData );
779 sal_Int32 nPos = 0;
780 sal_Int32 nLen = aUnquotedData.getLength();
781 sal_Int64 nData;
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 );
790 Base::~Base()
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 )
815 bool bLoop = true;
816 while( bLoop && !rStrm.isEof() )
818 OUString aKey, aData;
819 switch( readConfigLine( rStrm, aKey, aData ) )
821 case LINETYPE_DATA:
822 processConfigItem( rStrm, aKey, aData );
823 break;
824 case LINETYPE_END:
825 bLoop = false;
826 break;
831 ConfigItemBase::LineType ConfigItemBase::readConfigLine(
832 TextInputStream& rStrm, OUString& orKey, OUString& orData )
834 OUString aLine;
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 == ';') )
846 aLine.clear();
850 OUStringPair aPair = StringHelper::convertStringToPair( aLine );
851 orKey = aPair.first;
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 )
860 sal_Int64 nKey;
861 if( StringHelper::convertStringToInt( nKey, rKey ) )
862 implProcessConfigItemInt( rStrm, nKey, rData );
863 else
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 )
878 if( rxList.get() )
880 for( const_iterator aIt = rxList->begin(), aEnd = rxList->end(); aIt != aEnd; ++aIt )
881 maMap[ aIt->first ] = aIt->second;
882 implIncludeList( *rxList );
886 bool NameListBase::implIsValid() const
888 return true;
891 void NameListBase::implProcessConfigItemStr(
892 TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
894 if ( rKey == "include" )
895 include( rData );
896 else if ( rKey == "exclude" )
897 exclude( rData );
898 else
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()) ? 0 : &aIt->second;
919 void NameListBase::include( const OUString& rListKeys )
921 OUStringVector aVec;
922 StringHelper::convertStringToStringList( aVec, rListKeys, true );
923 for( OUStringVector::const_iterator aIt = aVec.begin(), aEnd = aVec.end(); aIt != aEnd; ++aIt )
924 includeList( mrCfgData.getNameList( *aIt ) );
927 void NameListBase::exclude( const OUString& rKeys )
929 Int64Vector aVec;
930 StringHelper::convertStringToIntList( aVec, rKeys, true );
931 for( Int64Vector::const_iterator aIt = aVec.begin(), aEnd = aVec.end(); aIt != aEnd; ++aIt )
932 maMap.erase( *aIt );
935 void ItemFormatMap::insertFormats( const NameListRef& rxNameList )
937 if( Base::isValid( rxNameList ) )
938 for( NameListBase::const_iterator aIt = rxNameList->begin(), aEnd = rxNameList->end(); aIt != aEnd; ++aIt )
939 maMap[ aIt->first ].parse( aIt->second );
942 ConstList::ConstList( const SharedConfigData& rCfgData ) :
943 NameListBase( rCfgData ),
944 maDefName( OOX_DUMP_ERR_NONAME ),
945 mbQuoteNames( false )
949 void ConstList::implProcessConfigItemStr(
950 TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
952 if ( rKey == "default" )
953 setDefaultName( rData );
954 else if ( rKey == "quote-names" )
955 setQuoteNames( StringHelper::convertStringToBool( rData ) );
956 else
957 NameListBase::implProcessConfigItemStr( rStrm, rKey, rData );
960 void ConstList::implSetName( sal_Int64 nKey, const OUString& rName )
962 insertRawName( nKey, rName );
965 OUString ConstList::implGetName( const Config& /*rCfg*/, sal_Int64 nKey ) const
967 const OUString* pName = findRawName( nKey );
968 OUString aName = pName ? *pName : maDefName;
969 if( mbQuoteNames )
971 OUStringBuffer aBuffer( aName );
972 StringHelper::enclose( aBuffer, OOX_DUMP_STRQUOTE );
973 aName = aBuffer.makeStringAndClear();
975 return aName;
978 OUString ConstList::implGetNameDbl( const Config& /*rCfg*/, double /*fValue*/ ) const
980 return OUString();
983 void ConstList::implIncludeList( const NameListBase& rList )
985 if( const ConstList* pConstList = dynamic_cast< const ConstList* >( &rList ) )
987 maDefName = pConstList->maDefName;
988 mbQuoteNames = pConstList->mbQuoteNames;
992 MultiList::MultiList( const SharedConfigData& rCfgData ) :
993 ConstList( rCfgData ),
994 mbIgnoreEmpty( true )
998 void MultiList::setNamesFromVec( sal_Int64 nStartKey, const OUStringVector& rNames )
1000 sal_Int64 nKey = nStartKey;
1001 for( OUStringVector::const_iterator aIt = rNames.begin(), aEnd = rNames.end(); aIt != aEnd; ++aIt, ++nKey )
1002 if( !mbIgnoreEmpty || !aIt->isEmpty() )
1003 insertRawName( nKey, *aIt );
1006 void MultiList::implProcessConfigItemStr(
1007 TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
1009 if ( rKey == "ignore-empty" )
1010 mbIgnoreEmpty = StringHelper::convertStringToBool( rData );
1011 else
1012 ConstList::implProcessConfigItemStr( rStrm, rKey, rData );
1015 void MultiList::implSetName( sal_Int64 nKey, const OUString& rName )
1017 OUStringVector aNames;
1018 StringHelper::convertStringToStringList( aNames, rName, false );
1019 setNamesFromVec( nKey, aNames );
1022 FlagsList::FlagsList( const SharedConfigData& rCfgData ) :
1023 NameListBase( rCfgData ),
1024 mnIgnore( 0 )
1028 void FlagsList::implProcessConfigItemStr(
1029 TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
1031 if ( rKey == "ignore" )
1033 sal_Int64 nIgnore;
1034 if( StringHelper::convertStringToInt( nIgnore, rData ) )
1035 setIgnoreFlags( nIgnore );
1037 else
1039 NameListBase::implProcessConfigItemStr( rStrm, rKey, rData );
1043 void FlagsList::implSetName( sal_Int64 nKey, const OUString& rName )
1045 if( (nKey != 0) && ((nKey & (nKey - 1)) == 0) ) // only a single bit set?
1046 insertRawName( nKey, rName );
1049 OUString FlagsList::implGetName( const Config& /*rCfg*/, sal_Int64 nKey ) const
1051 sal_Int64 nFound = mnIgnore;
1052 OUStringBuffer aName;
1053 // add known flags
1054 for( const_iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt )
1056 sal_Int64 nMask = aIt->first;
1057 setFlag( nFound, nMask );
1058 if( !getFlag( mnIgnore, nMask ) )
1060 const OUString& rFlagName = aIt->second;
1061 bool bOnOff = rFlagName.startsWith(":");
1062 bool bFlag = getFlag( nKey, nMask );
1063 if( bOnOff )
1065 StringHelper::appendToken( aName, rFlagName.copy( 1 ) );
1066 aName.appendAscii( bFlag ? ":on" : ":off" );
1068 else
1070 bool bNegated = rFlagName.startsWith("!");
1071 sal_Int32 nBothSep = bNegated ? rFlagName.indexOf( '!', 1 ) : -1;
1072 if( bFlag )
1074 if( !bNegated )
1075 StringHelper::appendToken( aName, rFlagName );
1076 else if( nBothSep > 0 )
1077 StringHelper::appendToken( aName, rFlagName.copy( nBothSep + 1 ) );
1079 else if( bNegated )
1081 if( nBothSep > 0 )
1082 StringHelper::appendToken( aName, rFlagName.copy( 1, nBothSep - 1 ) );
1083 else
1084 StringHelper::appendToken( aName, rFlagName.copy( 1 ) );
1089 // add unknown flags
1090 setFlag( nKey, nFound, false );
1091 if( nKey != 0 )
1093 OUStringBuffer aUnknown( OOX_DUMP_UNKNOWN );
1094 aUnknown.append( OOX_DUMP_ITEMSEP );
1095 StringHelper::appendShortHex( aUnknown, nKey, true );
1096 StringHelper::enclose( aUnknown, '(', ')' );
1097 StringHelper::appendToken( aName, aUnknown.makeStringAndClear() );
1099 return aName.makeStringAndClear();
1102 OUString FlagsList::implGetNameDbl( const Config& /*rCfg*/, double /*fValue*/ ) const
1104 return OUString();
1107 void FlagsList::implIncludeList( const NameListBase& rList )
1109 if( const FlagsList* pFlagsList = dynamic_cast< const FlagsList* >( &rList ) )
1110 mnIgnore = pFlagsList->mnIgnore;
1113 bool CombiList::ExtItemFormatKey::operator<( const ExtItemFormatKey& rRight ) const
1115 return (mnKey < rRight.mnKey) || ((mnKey == rRight.mnKey) && (maFilter < rRight.maFilter));
1118 CombiList::CombiList( const SharedConfigData& rCfgData ) :
1119 FlagsList( rCfgData )
1123 void CombiList::implSetName( sal_Int64 nKey, const OUString& rName )
1125 if( (nKey & (nKey - 1)) != 0 ) // more than a single bit set?
1127 typedef ::std::set< ExtItemFormatKey > ExtItemFormatKeySet;
1128 ::std::set< ExtItemFormatKey > aItemKeys;
1129 ExtItemFormat aItemFmt;
1130 OUStringVector aRemain = aItemFmt.parse( rName );
1131 for( OUStringVector::iterator aIt = aRemain.begin(), aEnd = aRemain.end(); aIt != aEnd; ++aIt )
1133 OUStringPair aPair = StringHelper::convertStringToPair( *aIt );
1134 if ( aPair.first == "noshift" )
1136 aItemFmt.mbShiftValue = StringHelper::convertStringToBool( aPair.second );
1138 else if ( aPair.first == "filter" )
1140 OUStringPair aFilter = StringHelper::convertStringToPair( aPair.second, '~' );
1141 ExtItemFormatKey aKey( nKey );
1142 if( !aFilter.first.isEmpty() && StringHelper::convertStringToInt( aKey.maFilter.first, aFilter.first ) &&
1143 !aFilter.second.isEmpty() && StringHelper::convertStringToInt( aKey.maFilter.second, aFilter.second ) )
1145 if( aKey.maFilter.first == 0 )
1146 aKey.maFilter.second = 0;
1147 aItemKeys.insert( aKey );
1151 if( aItemKeys.empty() )
1152 aItemKeys.insert( ExtItemFormatKey( nKey ) );
1153 for( ExtItemFormatKeySet::iterator aIt = aItemKeys.begin(), aEnd = aItemKeys.end(); aIt != aEnd; ++aIt )
1154 maFmtMap[ *aIt ] = aItemFmt;
1156 else
1158 FlagsList::implSetName( nKey, rName );
1162 OUString CombiList::implGetName( const Config& rCfg, sal_Int64 nKey ) const
1164 sal_Int64 nFound = 0;
1165 OUStringBuffer aName;
1166 // add known flag fields
1167 for( ExtItemFormatMap::const_iterator aIt = maFmtMap.begin(), aEnd = maFmtMap.end(); aIt != aEnd; ++aIt )
1169 const ExtItemFormatKey& rMapKey = aIt->first;
1170 sal_Int64 nMask = rMapKey.mnKey;
1171 if( (nMask != 0) && ((nKey & rMapKey.maFilter.first) == rMapKey.maFilter.second) )
1173 const ExtItemFormat& rItemFmt = aIt->second;
1175 sal_uInt64 nUFlags = static_cast< sal_uInt64 >( nKey );
1176 sal_uInt64 nUMask = static_cast< sal_uInt64 >( nMask );
1177 if( rItemFmt.mbShiftValue )
1178 while( (nUMask & 1) == 0 ) { nUFlags >>= 1; nUMask >>= 1; }
1180 sal_uInt64 nUValue = nUFlags & nUMask;
1181 sal_Int64 nSValue = static_cast< sal_Int64 >( nUValue );
1182 if( getFlag< sal_uInt64 >( nUValue, (nUMask + 1) >> 1 ) )
1183 setFlag( nSValue, static_cast< sal_Int64 >( ~nUMask ) );
1185 OUStringBuffer aItem( rItemFmt.maItemName );
1186 OUStringBuffer aValue;
1187 switch( rItemFmt.meDataType )
1189 case DATATYPE_INT8: StringHelper::appendValue( aValue, static_cast< sal_Int8 >( nSValue ), rItemFmt.meFmtType ); break;
1190 case DATATYPE_UINT8: StringHelper::appendValue( aValue, static_cast< sal_uInt8 >( nUValue ), rItemFmt.meFmtType ); break;
1191 case DATATYPE_INT16: StringHelper::appendValue( aValue, static_cast< sal_Int16 >( nSValue ), rItemFmt.meFmtType ); break;
1192 case DATATYPE_UINT16: StringHelper::appendValue( aValue, static_cast< sal_uInt16 >( nUValue ), rItemFmt.meFmtType ); break;
1193 case DATATYPE_INT32: StringHelper::appendValue( aValue, static_cast< sal_Int32 >( nSValue ), rItemFmt.meFmtType ); break;
1194 case DATATYPE_UINT32: StringHelper::appendValue( aValue, static_cast< sal_uInt32 >( nUValue ), rItemFmt.meFmtType ); break;
1195 case DATATYPE_INT64: StringHelper::appendValue( aValue, nSValue, rItemFmt.meFmtType ); break;
1196 case DATATYPE_UINT64: StringHelper::appendValue( aValue, nUValue, rItemFmt.meFmtType ); break;
1197 case DATATYPE_FLOAT: StringHelper::appendValue( aValue, static_cast< float >( nSValue ), rItemFmt.meFmtType ); break;
1198 case DATATYPE_DOUBLE: StringHelper::appendValue( aValue, static_cast< double >( nSValue ), rItemFmt.meFmtType ); break;
1199 default:;
1201 StringHelper::appendToken( aItem, aValue.makeStringAndClear(), OOX_DUMP_ITEMSEP );
1202 if( !rItemFmt.maListName.isEmpty() )
1204 OUString aValueName = rCfg.getName( rItemFmt.maListName, static_cast< sal_Int64 >( nUValue ) );
1205 StringHelper::appendToken( aItem, aValueName, OOX_DUMP_ITEMSEP );
1207 StringHelper::enclose( aItem, '(', ')' );
1208 StringHelper::appendToken( aName, aItem.makeStringAndClear() );
1209 setFlag( nFound, nMask );
1212 setFlag( nKey, nFound, false );
1213 StringHelper::appendToken( aName, FlagsList::implGetName( rCfg, nKey ) );
1214 return aName.makeStringAndClear();
1217 void CombiList::implIncludeList( const NameListBase& rList )
1219 if( const CombiList* pCombiList = dynamic_cast< const CombiList* >( &rList ) )
1220 maFmtMap = pCombiList->maFmtMap;
1221 FlagsList::implIncludeList( rList );
1224 UnitConverter::UnitConverter( const SharedConfigData& rCfgData ) :
1225 NameListBase( rCfgData ),
1226 mfFactor( 1.0 )
1230 void UnitConverter::implSetName( sal_Int64 /*nKey*/, const OUString& /*rName*/ )
1232 // nothing to do
1235 OUString UnitConverter::implGetName( const Config& rCfg, sal_Int64 nKey ) const
1237 return implGetNameDbl( rCfg, static_cast< double >( nKey ) );
1240 OUString UnitConverter::implGetNameDbl( const Config& /*rCfg*/, double fValue ) const
1242 OUStringBuffer aValue;
1243 StringHelper::appendDec( aValue, mfFactor * fValue );
1244 aValue.append( maUnitName );
1245 return aValue.makeStringAndClear();
1248 void UnitConverter::implIncludeList( const NameListBase& /*rList*/ )
1252 NameListRef NameListWrapper::getNameList( const Config& rCfg ) const
1254 return mxList.get() ? mxList : (mxList = rCfg.getNameList( maName ));
1257 SharedConfigData::SharedConfigData( const OUString& rFileName,
1258 const Reference< XComponentContext >& rxContext, const StorageRef& rxRootStrg,
1259 const OUString& rSysFileName ) :
1260 mxContext( rxContext ),
1261 mxRootStrg( rxRootStrg ),
1262 maSysFileName( rSysFileName ),
1263 mbLoaded( false ),
1264 mbPwCancelled( false )
1266 OUString aFileUrl = InputOutputHelper::convertFileNameToUrl( rFileName );
1267 if( !aFileUrl.isEmpty() )
1269 sal_Int32 nNamePos = InputOutputHelper::getFileNamePos( aFileUrl );
1270 maConfigPath = aFileUrl.copy( 0, nNamePos );
1271 mbLoaded = readConfigFile( aFileUrl );
1275 SharedConfigData::~SharedConfigData()
1279 void SharedConfigData::setOption( const OUString& rKey, const OUString& rData )
1281 maConfigData[ rKey ] = rData;
1284 const OUString* SharedConfigData::getOption( const OUString& rKey ) const
1286 ConfigDataMap::const_iterator aIt = maConfigData.find( rKey );
1287 return (aIt == maConfigData.end()) ? 0 : &aIt->second;
1290 void SharedConfigData::setNameList( const OUString& rListName, const NameListRef& rxList )
1292 if( !rListName.isEmpty() )
1293 maNameLists[ rListName ] = rxList;
1296 void SharedConfigData::eraseNameList( const OUString& rListName )
1298 maNameLists.erase( rListName );
1301 NameListRef SharedConfigData::getNameList( const OUString& rListName ) const
1303 NameListRef xList;
1304 NameListMap::const_iterator aIt = maNameLists.find( rListName );
1305 if( aIt != maNameLists.end() )
1306 xList = aIt->second;
1307 return xList;
1310 bool SharedConfigData::implIsValid() const
1312 return mbLoaded && mxContext.is() && mxRootStrg.get() && !maSysFileName.isEmpty();
1315 void SharedConfigData::implProcessConfigItemStr(
1316 TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
1318 if ( rKey == "include-config-file" )
1319 readConfigFile( maConfigPath + rData );
1320 else if ( rKey == "constlist" )
1321 readNameList< ConstList >( rStrm, rData );
1322 else if ( rKey == "multilist" )
1323 readNameList< MultiList >( rStrm, rData );
1324 else if ( rKey == "flagslist" )
1325 readNameList< FlagsList >( rStrm, rData );
1326 else if ( rKey == "combilist" )
1327 readNameList< CombiList >( rStrm, rData );
1328 else if ( rKey == "shortlist" )
1329 createShortList( rData );
1330 else if ( rKey == "unitconverter" )
1331 createUnitConverter( rData );
1332 else
1333 setOption( rKey, rData );
1336 bool SharedConfigData::readConfigFile( const OUString& rFileUrl )
1338 bool bLoaded = maConfigFiles.count( rFileUrl ) > 0;
1339 if( !bLoaded )
1341 Reference< XInputStream > xInStrm = InputOutputHelper::openInputStream( mxContext, rFileUrl );
1342 TextInputStream aTxtStrm( mxContext, xInStrm, RTL_TEXTENCODING_UTF8 );
1343 if( !aTxtStrm.isEof() )
1345 maConfigFiles.insert( rFileUrl );
1346 readConfigBlockContents( aTxtStrm );
1347 bLoaded = true;
1350 return bLoaded;
1353 void SharedConfigData::createShortList( const OUString& rData )
1355 OUStringVector aDataVec;
1356 StringHelper::convertStringToStringList( aDataVec, rData, false );
1357 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 ] );
1363 if( xList.get() )
1365 aDataVec.erase( aDataVec.begin(), aDataVec.begin() + 2 );
1366 xList->setNamesFromVec( nStartKey, aDataVec );
1372 void SharedConfigData::createUnitConverter( const OUString& rData )
1374 OUStringVector aDataVec;
1375 StringHelper::convertStringToStringList( aDataVec, rData, false );
1376 if( aDataVec.size() >= 2 )
1378 OUString aFactor = aDataVec[ 1 ];
1379 bool bRecip = aFactor.startsWith("/");
1380 if( bRecip )
1381 aFactor = aFactor.copy( 1 );
1382 double fFactor;
1383 if( StringHelper::convertStringToDouble( fFactor, aFactor ) && (fFactor != 0.0) )
1385 std::shared_ptr< UnitConverter > xList = createNameList< UnitConverter >( aDataVec[ 0 ] );
1386 if( xList.get() )
1388 xList->setFactor( bRecip ? (1.0 / fFactor) : fFactor );
1389 if( aDataVec.size() >= 3 )
1390 xList->setUnitName( aDataVec[ 2 ] );
1396 Config::Config( const Config& rParent ) :
1397 Base() // c'tor needs to be called explicitly to avoid compiler warning
1399 construct( rParent );
1402 Config::Config( const sal_Char* pcEnvVar, const FilterBase& rFilter )
1404 construct( pcEnvVar, rFilter );
1407 Config::Config( const sal_Char* pcEnvVar, const Reference< XComponentContext >& rxContext, const StorageRef& rxRootStrg, const OUString& rSysFileName )
1409 construct( pcEnvVar, rxContext, rxRootStrg, rSysFileName );
1412 Config::~Config()
1416 void Config::construct( const Config& rParent )
1418 *this = rParent;
1421 void Config::construct( const sal_Char* pcEnvVar, const FilterBase& rFilter )
1423 if( !rFilter.getFileUrl().isEmpty() )
1424 construct( pcEnvVar, rFilter.getComponentContext(), rFilter.getStorage(), rFilter.getFileUrl() );
1427 void Config::construct( const sal_Char* pcEnvVar, const Reference< XComponentContext >& rxContext, const StorageRef& rxRootStrg, const OUString& rSysFileName )
1429 if( pcEnvVar && rxRootStrg.get() && !rSysFileName.isEmpty() )
1430 if( const sal_Char* pcFileName = ::getenv( pcEnvVar ) )
1431 mxCfgData.reset( new SharedConfigData( OUString::createFromAscii( pcFileName ), rxContext, rxRootStrg, rSysFileName ) );
1434 const OUString& Config::getStringOption( const String& rKey, const OUString& rDefault ) const
1436 const OUString* pData = implGetOption( rKey );
1437 return pData ? *pData : rDefault;
1440 bool Config::getBoolOption( const String& rKey, bool bDefault ) const
1442 const OUString* pData = implGetOption( rKey );
1443 return pData ? StringHelper::convertStringToBool( *pData ) : bDefault;
1446 bool Config::isDumperEnabled() const
1448 return getBoolOption( "enable-dumper", false );
1451 bool Config::isImportEnabled() const
1453 return getBoolOption( "enable-import", true );
1456 void Config::eraseNameList( const String& rListName )
1458 mxCfgData->eraseNameList( rListName );
1461 NameListRef Config::getNameList( const String& rListName ) const
1463 return implGetNameList( rListName );
1466 bool Config::isPasswordCancelled() const
1468 return mxCfgData->isPasswordCancelled();
1471 bool Config::implIsValid() const
1473 return isValid( mxCfgData );
1476 const OUString* Config::implGetOption( const OUString& rKey ) const
1478 return mxCfgData->getOption( rKey );
1481 NameListRef Config::implGetNameList( const OUString& rListName ) const
1483 return mxCfgData->getNameList( rListName );
1486 Output::Output( const Reference< XComponentContext >& rxContext, const OUString& rFileName ) :
1487 mxStrm( InputOutputHelper::openTextOutputStream( rxContext, rFileName, RTL_TEXTENCODING_UTF8 ) ),
1488 mnCol( 0 ),
1489 mnItemLevel( 0 ),
1490 mnMultiLevel( 0 ),
1491 mnItemIdx( 0 ),
1492 mnLastItem( 0 )
1494 if( mxStrm.is() )
1495 mxStrm->writeString( OUString( OOX_DUMP_BOM ) );
1498 void Output::newLine()
1500 if( maLine.getLength() > 0 )
1502 mxStrm->writeString( maIndent );
1503 maLine.append( '\n' );
1504 mxStrm->writeString( maLine.makeStringAndClear() );
1505 mnCol = 0;
1506 mnLastItem = 0;
1510 void Output::emptyLine( size_t nCount )
1512 for( size_t nIdx = 0; nIdx < nCount; ++nIdx )
1513 mxStrm->writeString( OUString( '\n' ) );
1516 void Output::incIndent()
1518 OUStringBuffer aBuffer( maIndent );
1519 StringHelper::appendChar( aBuffer, ' ', OOX_DUMP_INDENT );
1520 maIndent = aBuffer.makeStringAndClear();
1523 void Output::decIndent()
1525 if( maIndent.getLength() >= OOX_DUMP_INDENT )
1526 maIndent = maIndent.copy( OOX_DUMP_INDENT );
1529 void Output::startTable( sal_Int32 nW1 )
1531 startTable( 1, &nW1 );
1534 void Output::startTable( sal_Int32 nW1, sal_Int32 nW2 )
1536 sal_Int32 pnColWidths[ 2 ];
1537 pnColWidths[ 0 ] = nW1;
1538 pnColWidths[ 1 ] = nW2;
1539 startTable( 2, pnColWidths );
1542 void Output::startTable( sal_Int32 nW1, sal_Int32 nW2, sal_Int32 nW3, sal_Int32 nW4 )
1544 sal_Int32 pnColWidths[ 4 ];
1545 pnColWidths[ 0 ] = nW1;
1546 pnColWidths[ 1 ] = nW2;
1547 pnColWidths[ 2 ] = nW3;
1548 pnColWidths[ 3 ] = nW4;
1549 startTable( 4, pnColWidths );
1552 void Output::startTable( size_t nColCount, const sal_Int32* pnColWidths )
1554 maColPos.clear();
1555 maColPos.push_back( 0 );
1556 sal_Int32 nColPos = 0;
1557 for( size_t nCol = 0; nCol < nColCount; ++nCol )
1559 nColPos = nColPos + pnColWidths[ nCol ];
1560 maColPos.push_back( nColPos );
1564 void Output::tab()
1566 tab( mnCol + 1 );
1569 void Output::tab( size_t nCol )
1571 mnCol = nCol;
1572 if( mnCol < maColPos.size() )
1574 sal_Int32 nColPos = maColPos[ mnCol ];
1575 if( maLine.getLength() >= nColPos )
1576 maLine.setLength( ::std::max< sal_Int32 >( nColPos - 1, 0 ) );
1577 StringHelper::appendChar( maLine, ' ', nColPos - maLine.getLength() );
1579 else
1581 StringHelper::appendChar( maLine, ' ', 2 );
1585 void Output::endTable()
1587 maColPos.clear();
1590 void Output::resetItemIndex( sal_Int64 nIdx )
1592 mnItemIdx = nIdx;
1595 void Output::startItem( const String& rItemName )
1597 if( mnItemLevel == 0 )
1599 if( (mnMultiLevel > 0) && (maLine.getLength() > 0) )
1600 tab();
1601 if( rItemName.has() )
1603 writeItemName( rItemName );
1604 writeChar( OOX_DUMP_ITEMSEP );
1607 ++mnItemLevel;
1608 mnLastItem = maLine.getLength();
1611 void Output::contItem()
1613 if( mnItemLevel > 0 )
1615 if( (maLine.getLength() == 0) || (maLine[ maLine.getLength() - 1 ] != OOX_DUMP_ITEMSEP) )
1616 writeChar( OOX_DUMP_ITEMSEP );
1617 mnLastItem = maLine.getLength();
1621 void Output::endItem()
1623 if( mnItemLevel > 0 )
1625 maLastItem = OUString( maLine.getStr() + mnLastItem );
1626 if( maLastItem.isEmpty() && mnLastItem > 0 && maLine[ mnLastItem - 1 ] == OOX_DUMP_ITEMSEP )
1627 maLine.setLength( mnLastItem - 1 );
1628 --mnItemLevel;
1630 if( mnItemLevel == 0 )
1632 if( mnMultiLevel == 0 )
1633 newLine();
1635 else
1636 contItem();
1639 void Output::startMultiItems()
1641 ++mnMultiLevel;
1644 void Output::endMultiItems()
1646 if( mnMultiLevel > 0 )
1647 --mnMultiLevel;
1648 if( mnMultiLevel == 0 )
1649 newLine();
1652 void Output::writeChar( sal_Unicode cChar, sal_Int32 nCount )
1654 StringHelper::appendEncChar( maLine, cChar, nCount );
1657 void Output::writeAscii( const sal_Char* pcStr )
1659 if( pcStr )
1660 maLine.appendAscii( pcStr );
1663 void Output::writeString( const OUString& rStr )
1665 StringHelper::appendEncString( maLine, rStr );
1668 void Output::writeArray( const sal_uInt8* pnData, sal_Size nSize, sal_Unicode cSep )
1670 const sal_uInt8* pnEnd = pnData ? (pnData + nSize) : 0;
1671 for( const sal_uInt8* pnByte = pnData; pnByte < pnEnd; ++pnByte )
1673 if( pnByte > pnData )
1674 writeChar( cSep );
1675 writeHex( *pnByte, false );
1679 void Output::writeBool( bool bData )
1681 StringHelper::appendBool( maLine, bData );
1684 void Output::writeDateTime( const util::DateTime& rDateTime )
1686 writeDec( rDateTime.Year, 4, '0' );
1687 writeChar( '-' );
1688 writeDec( rDateTime.Month, 2, '0' );
1689 writeChar( '-' );
1690 writeDec( rDateTime.Day, 2, '0' );
1691 writeChar( 'T' );
1692 writeDec( rDateTime.Hours, 2, '0' );
1693 writeChar( ':' );
1694 writeDec( rDateTime.Minutes, 2, '0' );
1695 writeChar( ':' );
1696 writeDec( rDateTime.Seconds, 2, '0' );
1699 bool Output::implIsValid() const
1701 return mxStrm.is();
1704 void Output::writeItemName( const String& rItemName )
1706 if( rItemName.has() && (rItemName[ 0 ] == '#') )
1708 writeString( rItemName.copy( 1 ) );
1709 StringHelper::appendIndex( maLine, mnItemIdx++ );
1711 else
1712 writeString( rItemName );
1715 StorageIterator::StorageIterator( const StorageRef& rxStrg ) :
1716 mxStrg( rxStrg )
1718 if( mxStrg.get() )
1719 mxStrg->getElementNames( maNames );
1720 maIt = maNames.begin();
1723 StorageIterator::~StorageIterator()
1727 StorageIterator& StorageIterator::operator++()
1729 if( maIt != maNames.end() )
1730 ++maIt;
1731 return *this;
1734 OUString StorageIterator::getName() const
1736 OUString aName;
1737 if( maIt != maNames.end() )
1738 aName = *maIt;
1739 return aName;
1742 bool StorageIterator::isStream() const
1744 return isValid() && mxStrg->openInputStream( *maIt ).is();
1747 bool StorageIterator::isStorage() const
1749 if( !isValid() )
1750 return false;
1751 StorageRef xStrg = mxStrg->openSubStorage( *maIt, false );
1752 return xStrg.get() && xStrg->isStorage();
1755 bool StorageIterator::implIsValid() const
1757 return mxStrg.get() && mxStrg->isStorage() && (maIt != maNames.end());
1760 ObjectBase::~ObjectBase()
1764 void ObjectBase::construct( const ConfigRef& rxConfig )
1766 mxConfig = rxConfig;
1769 void ObjectBase::construct( const ObjectBase& rParent )
1771 *this = rParent;
1774 void ObjectBase::dump()
1776 if( isValid() )
1777 implDump();
1780 bool ObjectBase::implIsValid() const
1782 return isValid( mxConfig );
1785 void ObjectBase::implDump()
1789 void StorageObjectBase::construct( const ObjectBase& rParent, const StorageRef& rxStrg, const OUString& rSysPath )
1791 ObjectBase::construct( rParent );
1792 mxStrg = rxStrg;
1793 maSysPath = rSysPath;
1796 void StorageObjectBase::construct( const ObjectBase& rParent )
1798 ObjectBase::construct( rParent );
1799 if( ObjectBase::implIsValid() )
1801 mxStrg = cfg().getRootStorage();
1802 maSysPath = cfg().getSysFileName();
1806 bool StorageObjectBase::implIsValid() const
1808 return mxStrg.get() && !maSysPath.isEmpty() && ObjectBase::implIsValid();
1811 void StorageObjectBase::implDump()
1813 bool bIsStrg = mxStrg->isStorage();
1814 bool bIsRoot = mxStrg->isRootStorage();
1815 Reference< XInputStream > xBaseStrm;
1816 if( !bIsStrg )
1817 xBaseStrm = mxStrg->openInputStream( OUString() );
1819 OUString aSysOutPath = maSysPath;
1820 if( bIsRoot ) try
1822 aSysOutPath += OOX_DUMP_DUMPEXT;
1823 Reference<XSimpleFileAccess3> xFileAccess(SimpleFileAccess::create(getContext()));
1824 xFileAccess->kill( aSysOutPath );
1826 catch( Exception& )
1830 if( bIsStrg )
1832 extractStorage( mxStrg, OUString(), aSysOutPath );
1834 else if( xBaseStrm.is() )
1836 BinaryInputStreamRef xInStrm( new BinaryXInputStream( xBaseStrm, false ) );
1837 xInStrm->seekToStart();
1838 implDumpBaseStream( xInStrm, aSysOutPath );
1842 void StorageObjectBase::implDumpStream( const Reference< XInputStream >&, const OUString&, const OUString&, const OUString& )
1846 void StorageObjectBase::implDumpStorage( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rSysPath )
1848 extractStorage( rxStrg, rStrgPath, rSysPath );
1851 void StorageObjectBase::implDumpBaseStream( const BinaryInputStreamRef&, const OUString& )
1855 void StorageObjectBase::addPreferredStream( const String& rStrmName )
1857 if( rStrmName.has() )
1858 maPreferred.push_back( PreferredItem( rStrmName, false ) );
1861 void StorageObjectBase::addPreferredStorage( const String& rStrgPath )
1863 if( rStrgPath.has() )
1864 maPreferred.push_back( PreferredItem( rStrgPath, true ) );
1867 OUString StorageObjectBase::getSysFileName( const OUString& rStrmName, const OUString& rSysOutPath )
1869 // encode all characters < 0x20
1870 OUStringBuffer aBuffer;
1871 StringHelper::appendEncString( aBuffer, rStrmName, false );
1873 // replace all characters reserved in file system
1874 OUString aFileName = aBuffer.makeStringAndClear();
1875 static const sal_Unicode spcReserved[] = { '/', '\\', ':', '*', '?', '<', '>', '|' };
1876 for( const sal_Unicode* pcChar = spcReserved; pcChar < STATIC_ARRAY_END( spcReserved ); ++pcChar )
1877 aFileName = aFileName.replace( *pcChar, '_' );
1879 // build full path
1880 return rSysOutPath + "/" + aFileName;
1883 void StorageObjectBase::extractStream( StorageBase& rStrg, const OUString& rStrgPath, const OUString& rStrmName, const OUString& rSysFileName )
1885 BinaryXInputStream aInStrm( rStrg.openInputStream( rStrmName ), true );
1886 if( !aInStrm.isEof() )
1888 BinaryXOutputStream aOutStrm( InputOutputHelper::openOutputStream( getContext(), rSysFileName ), true );
1889 if( !aOutStrm.isEof() )
1890 aInStrm.copyToStream( aOutStrm );
1892 Reference< XInputStream > xDumpStrm = InputOutputHelper::openInputStream( getContext(), rSysFileName );
1893 if( xDumpStrm.is() )
1894 implDumpStream( xDumpStrm, rStrgPath, rStrmName, rSysFileName );
1897 void StorageObjectBase::extractStorage( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rSysPath )
1899 // create directory in file system
1900 ::osl::FileBase::RC eRes = ::osl::Directory::create( rSysPath );
1901 if( (eRes != ::osl::FileBase::E_None) && (eRes != ::osl::FileBase::E_EXIST) )
1902 return;
1904 // process preferred storages and streams in root storage first
1905 if( rStrgPath.isEmpty() )
1906 for( PreferredItemVector::iterator aIt = maPreferred.begin(), aEnd = maPreferred.end(); aIt != aEnd; ++aIt )
1907 extractItem( rxStrg, rStrgPath, aIt->maName, rSysPath, aIt->mbStorage, !aIt->mbStorage );
1909 // process children of the storage
1910 for( StorageIterator aIt( rxStrg ); aIt.isValid(); ++aIt )
1912 // skip processed preferred items
1913 OUString aItemName = aIt.getName();
1914 bool bFound = false;
1915 if( rStrgPath.isEmpty() )
1916 for( PreferredItemVector::iterator aIIt = maPreferred.begin(), aIEnd = maPreferred.end(); !bFound && (aIIt != aIEnd); ++aIIt )
1917 bFound = aIIt->maName == aItemName;
1918 if( !bFound )
1919 extractItem( rxStrg, rStrgPath, aItemName, rSysPath, aIt.isStorage(), aIt.isStream() );
1923 void StorageObjectBase::extractItem( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rItemName, const OUString& rSysPath, bool bIsStrg, bool bIsStrm )
1925 OUString aSysFileName = getSysFileName( rItemName, rSysPath );
1926 if( bIsStrg )
1928 OUStringBuffer aStrgPath( rStrgPath );
1929 StringHelper::appendToken( aStrgPath, rItemName, '/' );
1930 implDumpStorage( rxStrg->openSubStorage( rItemName, false ), aStrgPath.makeStringAndClear(), aSysFileName );
1932 else if( bIsStrm )
1934 extractStream( *rxStrg, rStrgPath, rItemName, aSysFileName );
1938 OutputObjectBase::~OutputObjectBase()
1942 void OutputObjectBase::construct( const ObjectBase& rParent, const OUString& rSysFileName )
1944 ObjectBase::construct( rParent );
1945 if( ObjectBase::implIsValid() )
1947 maSysFileName = rSysFileName;
1948 mxOut.reset( new Output( getContext(), rSysFileName + OOX_DUMP_DUMPEXT ) );
1952 void OutputObjectBase::construct( const OutputObjectBase& rParent )
1954 *this = rParent;
1957 bool OutputObjectBase::implIsValid() const
1959 return isValid( mxOut ) && ObjectBase::implIsValid();
1962 void OutputObjectBase::writeEmptyItem( const String& rName )
1964 ItemGuard aItem( mxOut, rName );
1967 void OutputObjectBase::writeInfoItem( const String& rName, const String& rData )
1969 ItemGuard aItem( mxOut, rName );
1970 mxOut->writeString( rData );
1973 void OutputObjectBase::writeCharItem( const String& rName, sal_Unicode cData )
1975 ItemGuard aItem( mxOut, rName );
1976 mxOut->writeChar( OOX_DUMP_STRQUOTE );
1977 mxOut->writeChar( cData );
1978 mxOut->writeChar( OOX_DUMP_STRQUOTE );
1981 void OutputObjectBase::writeStringItem( const String& rName, const OUString& rData )
1983 ItemGuard aItem( mxOut, rName );
1984 mxOut->writeAscii( "(len=" );
1985 mxOut->writeDec( rData.getLength() );
1986 mxOut->writeAscii( ")," );
1987 OUStringBuffer aValue( rData.copy( 0, ::std::min( rData.getLength(), OOX_DUMP_MAXSTRLEN ) ) );
1988 StringHelper::enclose( aValue, OOX_DUMP_STRQUOTE );
1989 mxOut->writeString( aValue.makeStringAndClear() );
1990 if( rData.getLength() > OOX_DUMP_MAXSTRLEN )
1991 mxOut->writeAscii( ",cut" );
1994 void OutputObjectBase::writeArrayItem( const String& rName, const sal_uInt8* pnData, sal_Size nSize, sal_Unicode cSep )
1996 ItemGuard aItem( mxOut, rName );
1997 mxOut->writeArray( pnData, nSize, cSep );
2000 void OutputObjectBase::writeDateTimeItem( const String& rName, const util::DateTime& rDateTime )
2002 ItemGuard aItem( mxOut, rName );
2003 mxOut->writeDateTime( rDateTime );
2006 void OutputObjectBase::writeGuidItem( const String& rName, const OUString& rGuid )
2008 ItemGuard aItem( mxOut, rName );
2009 mxOut->writeString( rGuid );
2010 aItem.cont();
2011 mxOut->writeString( cfg().getStringOption( rGuid, OUString() ) );
2014 InputObjectBase::~InputObjectBase()
2018 void InputObjectBase::construct( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName )
2020 OutputObjectBase::construct( rParent, rSysFileName );
2021 mxStrm = rxStrm;
2024 void InputObjectBase::construct( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxStrm )
2026 OutputObjectBase::construct( rParent );
2027 mxStrm = rxStrm;
2030 void InputObjectBase::construct( const InputObjectBase& rParent )
2032 *this = rParent;
2035 bool InputObjectBase::implIsValid() const
2037 return mxStrm.get() && OutputObjectBase::implIsValid();
2040 void InputObjectBase::skipBlock( sal_Int64 nBytes, bool bShowSize )
2042 sal_Int64 nEndPos = ::std::min< sal_Int64 >( mxStrm->tell() + nBytes, mxStrm->size() );
2043 if( mxStrm->tell() < nEndPos )
2045 if( bShowSize )
2046 writeDecItem( "skipped-data-size", static_cast< sal_uInt64 >( nEndPos - mxStrm->tell() ) );
2047 mxStrm->seek( nEndPos );
2051 void InputObjectBase::dumpRawBinary( sal_Int64 nBytes, bool bShowOffset, bool bStream )
2053 TableGuard aTabGuard( mxOut,
2054 bShowOffset ? 12 : 0,
2055 3 * OOX_DUMP_BYTESPERLINE / 2 + 1,
2056 3 * OOX_DUMP_BYTESPERLINE / 2 + 1,
2057 OOX_DUMP_BYTESPERLINE / 2 + 1 );
2059 sal_Int64 nMaxShowSize = cfg().getIntOption< sal_Int64 >(
2060 bStream ? "max-binary-stream-size" : "max-binary-data-size", SAL_MAX_INT64 );
2062 bool bSeekable = mxStrm->size() >= 0;
2063 sal_Int64 nEndPos = bSeekable ? ::std::min< sal_Int64 >( mxStrm->tell() + nBytes, mxStrm->size() ) : 0;
2064 sal_Int64 nDumpEnd = bSeekable ? ::std::min< sal_Int64 >( mxStrm->tell() + nMaxShowSize, nEndPos ) : nMaxShowSize;
2065 sal_Int64 nPos = bSeekable ? mxStrm->tell() : 0;
2066 bool bLoop = true;
2068 while( bLoop && (nPos < nDumpEnd) )
2070 mxOut->writeHex( static_cast< sal_uInt32 >( nPos ) );
2071 mxOut->tab();
2073 sal_uInt8 pnLineData[ OOX_DUMP_BYTESPERLINE ];
2074 sal_Int32 nLineSize = bSeekable ? ::std::min( static_cast< sal_Int32 >( nDumpEnd - mxStrm->tell() ), OOX_DUMP_BYTESPERLINE ) : OOX_DUMP_BYTESPERLINE;
2075 sal_Int32 nReadSize = mxStrm->readMemory( pnLineData, nLineSize );
2076 bLoop = nReadSize == nLineSize;
2077 nPos += nReadSize;
2079 if( nReadSize > 0 )
2081 const sal_uInt8* pnByte = 0;
2082 const sal_uInt8* pnEnd = 0;
2083 for( pnByte = pnLineData, pnEnd = pnLineData + nReadSize; pnByte != pnEnd; ++pnByte )
2085 if( (pnByte - pnLineData) == (OOX_DUMP_BYTESPERLINE / 2) ) mxOut->tab();
2086 mxOut->writeHex( *pnByte, false );
2087 mxOut->writeChar( ' ' );
2090 aTabGuard.tab( 3 );
2091 for( pnByte = pnLineData, pnEnd = pnLineData + nReadSize; pnByte != pnEnd; ++pnByte )
2093 if( (pnByte - pnLineData) == (OOX_DUMP_BYTESPERLINE / 2) ) mxOut->tab();
2094 mxOut->writeChar( static_cast< sal_Unicode >( (*pnByte < 0x20) ? '.' : *pnByte ) );
2096 mxOut->newLine();
2100 // skip undumped data
2101 if( bSeekable )
2102 skipBlock( nEndPos - mxStrm->tell() );
2105 void InputObjectBase::dumpBinary( const String& rName, sal_Int64 nBytes, bool bShowOffset )
2108 MultiItemsGuard aMultiGuard( mxOut );
2109 writeEmptyItem( rName );
2110 writeDecItem( "size", nBytes );
2112 IndentGuard aIndGuard( mxOut );
2113 dumpRawBinary( nBytes, bShowOffset );
2116 void InputObjectBase::dumpRemaining( sal_Int64 nBytes )
2118 if( nBytes > 0 )
2120 if( cfg().getBoolOption( "show-trailing-unknown", true ) )
2121 dumpBinary( "remaining-data", nBytes, false );
2122 else
2123 skipBlock( nBytes );
2127 void InputObjectBase::dumpRemainingTo( sal_Int64 nPos )
2129 if( mxStrm->isEof() || (mxStrm->tell() > nPos) )
2130 writeInfoItem( "stream-state", OOX_DUMP_ERR_STREAM );
2131 else
2132 dumpRemaining( nPos - mxStrm->tell() );
2133 mxStrm->seek( nPos );
2136 void InputObjectBase::dumpRemainingStream()
2138 dumpRemainingTo( mxStrm->size() );
2141 void InputObjectBase::dumpArray( const String& rName, sal_Int32 nBytes, sal_Unicode cSep )
2143 sal_Int32 nDumpSize = getLimitedValue< sal_Int32, sal_Int64 >( mxStrm->size() - mxStrm->tell(), 0, nBytes );
2144 if( nDumpSize > OOX_DUMP_MAXARRAY )
2146 dumpBinary( rName, nBytes, false );
2148 else if( nDumpSize > 1 )
2150 sal_uInt8 pnData[ OOX_DUMP_MAXARRAY ];
2151 mxStrm->readMemory( pnData, nDumpSize );
2152 writeArrayItem( rName, pnData, nDumpSize, cSep );
2154 else if( nDumpSize == 1 )
2155 dumpHex< sal_uInt8 >( rName );
2158 sal_Unicode InputObjectBase::dumpUnicode( const String& rName )
2160 sal_uInt16 nChar = mxStrm->readuInt16();
2161 sal_Unicode cChar = static_cast< sal_Unicode >( nChar );
2162 writeCharItem( rName( "char" ), cChar );
2163 return cChar;
2166 OUString InputObjectBase::dumpCharArray( const String& rName, sal_Int32 nLen, rtl_TextEncoding eTextEnc, bool bHideTrailingNul )
2168 sal_Int32 nDumpSize = getLimitedValue< sal_Int32, sal_Int64 >( mxStrm->size() - mxStrm->tell(), 0, nLen );
2169 OUString aString;
2170 if( nDumpSize > 0 )
2172 ::std::vector< sal_Char > aBuffer( static_cast< sal_Size >( nLen ) + 1 );
2173 sal_Int32 nCharsRead = mxStrm->readMemory( &aBuffer.front(), nLen );
2174 aBuffer[ nCharsRead ] = 0;
2175 aString = OStringToOUString( OString( &aBuffer.front() ), eTextEnc );
2177 if( bHideTrailingNul )
2178 aString = StringHelper::trimTrailingNul( aString );
2179 writeStringItem( rName( "text" ), aString );
2180 return aString;
2183 OUString InputObjectBase::dumpUnicodeArray( const String& rName, sal_Int32 nLen, bool bHideTrailingNul )
2185 OUStringBuffer aBuffer;
2186 for( sal_Int32 nIndex = 0; !mxStrm->isEof() && (nIndex < nLen); ++nIndex )
2188 aBuffer.append( static_cast< sal_Unicode >( mxStrm->readuInt16() ) );
2190 OUString aString = aBuffer.makeStringAndClear();
2191 if( bHideTrailingNul )
2192 aString = StringHelper::trimTrailingNul( aString );
2193 writeStringItem( rName( "text" ), aString );
2194 return aString;
2197 util::DateTime InputObjectBase::dumpFileTime( const String& rName )
2199 util::DateTime aDateTime;
2201 ItemGuard aItem( mxOut, rName( "file-time" ) );
2202 sal_Int64 nFileTime = dumpDec< sal_Int64 >( EMPTY_STRING );
2203 // file time is in 10^-7 seconds (100 nanoseconds), convert to nanoseconds
2204 nFileTime *= 100;
2205 // entire days
2206 sal_Int64 nDays = nFileTime / sal_Int64( ::tools::Time::nanoSecPerDay );
2207 // number of entire years
2208 sal_Int64 nYears = (nDays - (nDays / (4 * 365)) + (nDays / (100 * 365)) - (nDays / (400 * 365))) / 365;
2209 // remaining days in the year
2210 sal_Int64 nDaysInYear = nDays - (nYears * 365 + nYears / 4 - nYears / 100 + nYears / 400);
2211 // the year (file dates start from 1601-01-01)
2212 aDateTime.Year = static_cast< sal_uInt16 >( 1601 + nYears );
2213 // leap year?
2214 bool bLeap = ((aDateTime.Year % 4 == 0) && (aDateTime.Year % 100 != 0)) || (aDateTime.Year % 400 == 0);
2215 // static arrays with number of days in month
2216 static const sal_Int64 spnDaysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
2217 static const sal_Int64 spnDaysInMonthL[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
2218 const sal_Int64* pnDaysInMonth = bLeap ? spnDaysInMonthL : spnDaysInMonth;
2219 // the month
2220 aDateTime.Month = 1;
2221 while( nDaysInYear >= *pnDaysInMonth )
2223 nDaysInYear -= *pnDaysInMonth++;
2224 ++aDateTime.Month;
2226 // the day
2227 aDateTime.Day = static_cast< sal_uInt16 >( nDaysInYear + 1 );
2228 // number of nanoseconds in the day
2229 sal_Int64 nTimeInDay = nFileTime % sal_Int64( ::tools::Time::nanoSecPerDay );
2230 // nanoseconds
2231 aDateTime.NanoSeconds = static_cast< sal_uInt32 >( nTimeInDay % ::tools::Time::nanoSecPerSec );
2232 nTimeInDay /= ::tools::Time::nanoSecPerSec;
2233 // seconds
2234 aDateTime.Seconds = static_cast< sal_uInt16 >( nTimeInDay % ::tools::Time::secondPerMinute );
2235 nTimeInDay /= ::tools::Time::secondPerMinute;
2236 // minutes
2237 aDateTime.Minutes = static_cast< sal_uInt16 >( nTimeInDay % ::tools::Time::minutePerHour );
2238 nTimeInDay /= ::tools::Time::minutePerHour;
2239 // hours
2240 aDateTime.Hours = static_cast< sal_uInt16 >( nTimeInDay );
2242 writeDateTimeItem( EMPTY_STRING, aDateTime );
2243 return aDateTime;
2246 OUString InputObjectBase::dumpGuid( const String& rName )
2248 OUStringBuffer aBuffer;
2249 sal_uInt32 nData32;
2250 sal_uInt16 nData16;
2251 sal_uInt8 nData8;
2253 nData32 = mxStrm->readuInt32();
2254 StringHelper::appendHex( aBuffer, nData32, false );
2255 aBuffer.append( '-' );
2256 nData16 = mxStrm->readuInt16();
2257 StringHelper::appendHex( aBuffer, nData16, false );
2258 aBuffer.append( '-' );
2259 nData16 = mxStrm->readuInt16();
2260 StringHelper::appendHex( aBuffer, nData16, false );
2261 aBuffer.append( '-' );
2262 nData8 = mxStrm->readuChar();
2263 StringHelper::appendHex( aBuffer, nData8, false );
2264 nData8 = mxStrm->readuChar( );
2265 StringHelper::appendHex( aBuffer, nData8, false );
2266 aBuffer.append( '-' );
2267 for( int nIndex = 0; nIndex < 6; ++nIndex )
2269 nData8 = mxStrm->readuChar( );
2270 StringHelper::appendHex( aBuffer, nData8, false );
2272 StringHelper::enclose( aBuffer, '{', '}' );
2273 OUString aGuid = aBuffer.makeStringAndClear();
2274 writeGuidItem( rName( "guid" ), aGuid );
2275 return aGuid;
2278 void InputObjectBase::dumpItem( const ItemFormat& rItemFmt )
2280 switch( rItemFmt.meDataType )
2282 case DATATYPE_VOID: break;
2283 case DATATYPE_INT8: dumpValue< sal_Int8 >( rItemFmt ); break;
2284 case DATATYPE_UINT8: dumpValue< sal_uInt8 >( rItemFmt ); break;
2285 case DATATYPE_INT16: dumpValue< sal_Int16 >( rItemFmt ); break;
2286 case DATATYPE_UINT16: dumpValue< sal_uInt16 >( rItemFmt ); break;
2287 case DATATYPE_INT32: dumpValue< sal_Int32 >( rItemFmt ); break;
2288 case DATATYPE_UINT32: dumpValue< sal_uInt32 >( rItemFmt ); break;
2289 case DATATYPE_INT64: dumpValue< sal_Int64 >( rItemFmt ); break;
2290 case DATATYPE_UINT64: dumpValue< sal_uInt64 >( rItemFmt ); break;
2291 case DATATYPE_FLOAT: dumpValue< float >( rItemFmt ); break;
2292 case DATATYPE_DOUBLE: dumpValue< double >( rItemFmt ); break;
2293 default:;
2297 BinaryStreamObject::BinaryStreamObject( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName )
2299 InputObjectBase::construct( rParent, rxStrm, rSysFileName );
2302 void BinaryStreamObject::dumpBinaryStream( bool bShowOffset )
2304 mxStrm->seekToStart();
2305 dumpRawBinary( mxStrm->size(), bShowOffset, true );
2306 mxOut->emptyLine();
2309 void BinaryStreamObject::implDump()
2311 dumpBinaryStream();
2314 void TextStreamObjectBase::construct( const ObjectBase& rParent,
2315 const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc, const OUString& rSysFileName )
2317 InputObjectBase::construct( rParent, rxStrm, rSysFileName );
2318 constructTextStrmObj( eTextEnc );
2321 void TextStreamObjectBase::construct( const OutputObjectBase& rParent,
2322 const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc )
2324 InputObjectBase::construct( rParent, rxStrm );
2325 constructTextStrmObj( eTextEnc );
2328 bool TextStreamObjectBase::implIsValid() const
2330 return InputObjectBase::implIsValid() && mxTextStrm.get();
2333 void TextStreamObjectBase::implDump()
2335 implDumpText( *mxTextStrm );
2338 void TextStreamObjectBase::constructTextStrmObj( rtl_TextEncoding eTextEnc )
2340 if( mxStrm.get() )
2341 mxTextStrm.reset( new TextInputStream( getContext(), *mxStrm, eTextEnc ) );
2344 TextLineStreamObject::TextLineStreamObject( const ObjectBase& rParent,
2345 const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc, const OUString& rSysFileName )
2347 TextStreamObjectBase::construct( rParent, rxStrm, eTextEnc, rSysFileName );
2350 TextLineStreamObject::TextLineStreamObject( const OutputObjectBase& rParent,
2351 const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc )
2353 TextStreamObjectBase::construct( rParent, rxStrm, eTextEnc );
2356 void TextLineStreamObject::implDumpText( TextInputStream& rTextStrm )
2358 sal_uInt32 nLine = 0;
2359 while( !rTextStrm.isEof() )
2361 OUString aLine = rTextStrm.readLine();
2362 if( !rTextStrm.isEof() || !aLine.isEmpty() )
2363 implDumpLine( aLine, ++nLine );
2367 void TextLineStreamObject::implDumpLine( const OUString& rLine, sal_uInt32 nLine )
2369 TableGuard aTabGuard( mxOut, 8 );
2370 mxOut->writeDec( nLine, 6 );
2371 mxOut->tab();
2372 mxOut->writeString( rLine );
2373 mxOut->newLine();
2376 XmlStreamObject::XmlStreamObject( const ObjectBase& rParent,
2377 const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName )
2379 TextStreamObjectBase::construct( rParent, rxStrm, RTL_TEXTENCODING_UTF8, rSysFileName );
2382 void XmlStreamObject::implDumpText( TextInputStream& rTextStrm )
2384 /* Buffers a start element and the following element text. Needed to dump
2385 matching start/end elements and the element text on the same line. */
2386 OUStringBuffer aOldStartElem;
2387 // special handling for VML
2388 bool bIsVml = InputOutputHelper::getFileNameExtension( maSysFileName ).equalsIgnoreAsciiCase("vml");
2390 while( !rTextStrm.isEof() )
2392 // get the next element and the following element text from text stream
2393 OUString aElem = rTextStrm.readToChar( '>', true ).trim();
2394 OUString aText = rTextStrm.readToChar( '<', false );
2396 // remove multiple whitespace from element
2397 sal_Int32 nPos = 0;
2398 while( nPos < aElem.getLength() )
2400 while( (nPos < aElem.getLength()) && (aElem[ nPos ] >= 32) ) ++nPos;
2401 if( nPos < aElem.getLength() )
2402 aElem = OUStringBuffer( aElem.copy( 0, nPos ) ).append( ' ' ).append( aElem.copy( nPos ).trim() ).makeStringAndClear();
2403 ++nPos;
2406 sal_Int32 nElemLen = aElem.getLength();
2407 if( (nElemLen >= 2) && (aElem[ 0 ] == '<') && (aElem[ nElemLen - 1 ] == '>') )
2409 // determine type of the element
2410 bool bSimpleElem = (aElem[ 1 ] == '!') || (aElem[ 1 ] == '?') || (aElem[ nElemLen - 2 ] == '/') ||
2411 (bIsVml && (nElemLen == 4) && (aElem[ 1 ] == 'b') && (aElem[ 2 ] == 'r'));
2412 bool bStartElem = !bSimpleElem && (aElem[ 1 ] != '/');
2413 bool bEndElem = !bSimpleElem && !bStartElem;
2415 /* Start element or simple element: flush old start element and
2416 its text from previous iteration, and start a new indentation
2417 level for the new element. Trim whitespace and line breaks from
2418 the text of the old start element. */
2419 if( (bSimpleElem || bStartElem) && (aOldStartElem.getLength() > 0) )
2421 mxOut->writeString( aOldStartElem.makeStringAndClear().trim() );
2422 mxOut->newLine();
2423 mxOut->incIndent();
2426 /* Start element: remember it and its text, to be able to print the
2427 matching end element on the same line in the next iteration. */
2428 if( bStartElem )
2430 aOldStartElem.append( aElem ).append( aText );
2432 else
2434 /* End element: if a start element has been remembered in the
2435 previous iteration, write it out here untrimmed, to show
2436 all whitespace in the element text, and without trailing
2437 line break. Code below will add the end element right after
2438 it. Otherwise, return to previous indentation level. */
2439 if( bEndElem )
2441 if( aOldStartElem.getLength() == 0 )
2442 mxOut->decIndent();
2443 else
2444 mxOut->writeString( aOldStartElem.makeStringAndClear() );
2447 /* Write the element. Write following element text in a new
2448 line, but only, if it does not contain of white space
2449 entirely. */
2450 mxOut->writeString( aElem );
2451 mxOut->newLine();
2452 if( !aText.trim().isEmpty() )
2454 mxOut->writeString( aText );
2455 mxOut->newLine();
2462 void RecordObjectBase::construct( const ObjectBase& rParent,
2463 const BinaryInputStreamRef& rxBaseStrm, const OUString& rSysFileName,
2464 const BinaryInputStreamRef& rxRecStrm, const String& rRecNames, const String& rSimpleRecs )
2466 InputObjectBase::construct( rParent, rxRecStrm, rSysFileName );
2467 constructRecObjBase( rxBaseStrm, rRecNames, rSimpleRecs );
2470 bool RecordObjectBase::implIsValid() const
2472 return mxBaseStrm.get() && InputObjectBase::implIsValid();
2475 void RecordObjectBase::implDump()
2477 NameListRef xRecNames = getRecNames();
2478 ItemFormatMap aSimpleRecs( maSimpleRecs.getNameList( cfg() ) );
2480 while( implStartRecord( *mxBaseStrm, mnRecPos, mnRecId, mnRecSize ) )
2482 // record header
2483 mxOut->emptyLine();
2484 writeHeader();
2485 implWriteExtHeader();
2486 IndentGuard aIndGuard( mxOut );
2487 sal_Int64 nRecPos = mxStrm->tell();
2489 // record body
2490 if( !mbBinaryOnly && cfg().hasName( xRecNames, mnRecId ) )
2492 ::std::map< sal_Int64, ItemFormat >::const_iterator aIt = aSimpleRecs.find( mnRecId );
2493 if( aIt != aSimpleRecs.end() )
2494 dumpItem( aIt->second );
2495 else
2496 implDumpRecordBody();
2499 // remaining undumped data
2500 if( !mxStrm->isEof() && (mxStrm->tell() == nRecPos) )
2501 dumpRawBinary( mnRecSize, false );
2502 else
2503 dumpRemainingTo( nRecPos + mnRecSize );
2507 void RecordObjectBase::implWriteExtHeader()
2511 void RecordObjectBase::implDumpRecordBody()
2515 void RecordObjectBase::constructRecObjBase( const BinaryInputStreamRef& rxBaseStrm, const String& rRecNames, const String& rSimpleRecs )
2517 mxBaseStrm = rxBaseStrm;
2518 maRecNames = rRecNames;
2519 maSimpleRecs = rSimpleRecs;
2520 mnRecPos = mnRecId = mnRecSize = 0;
2521 mbBinaryOnly = false;
2522 if( InputObjectBase::implIsValid() )
2523 mbShowRecPos = cfg().getBoolOption( "show-record-position", true );
2526 void RecordObjectBase::writeHeader()
2528 MultiItemsGuard aMultiGuard( mxOut );
2529 writeEmptyItem( "REC" );
2530 if( mbShowRecPos && mxBaseStrm->isSeekable() )
2531 writeShortHexItem( "pos", mnRecPos, "CONV-DEC" );
2532 writeShortHexItem( "size", mnRecSize, "CONV-DEC" );
2533 ItemGuard aItem( mxOut, "id" );
2534 mxOut->writeShortHex( mnRecId );
2535 addNameToItem( mnRecId, "CONV-DEC" );
2536 addNameToItem( mnRecId, maRecNames );
2539 void SequenceRecordObjectBase::construct( const ObjectBase& rParent,
2540 const BinaryInputStreamRef& rxBaseStrm, const OUString& rSysFileName,
2541 const String& rRecNames, const String& rSimpleRecs )
2543 BinaryInputStreamRef xRecStrm( new SequenceInputStream( *mxRecData ) );
2544 RecordObjectBase::construct( rParent, rxBaseStrm, rSysFileName, xRecStrm, rRecNames, rSimpleRecs );
2547 bool SequenceRecordObjectBase::implStartRecord( BinaryInputStream& rBaseStrm, sal_Int64& ornRecPos, sal_Int64& ornRecId, sal_Int64& ornRecSize )
2549 bool bValid = true;
2550 if( rBaseStrm.isSeekable() )
2552 ornRecPos = rBaseStrm.tell();
2553 // do not try to overread seekable streams, may cause assertions
2554 bValid = ornRecPos < rBaseStrm.size();
2557 // read the record header
2558 if( bValid )
2559 bValid = implReadRecordHeader( rBaseStrm, ornRecId, ornRecSize ) && !rBaseStrm.isEof() && (0 <= ornRecSize) && (ornRecSize <= 0x00100000);
2561 // read record contents into data sequence
2562 if( bValid )
2564 sal_Int32 nRecSize = static_cast< sal_Int32 >( ornRecSize );
2565 mxRecData->realloc( nRecSize );
2566 bValid = (nRecSize == 0) || (rBaseStrm.readData( *mxRecData, nRecSize ) == nRecSize);
2567 mxStrm->seekToStart();
2569 return bValid;
2572 DumperBase::~DumperBase()
2576 bool DumperBase::isImportEnabled() const
2578 return !isValid() || cfg().isImportEnabled();
2581 bool DumperBase::isImportCancelled() const
2583 return isValid() && cfg().isPasswordCancelled();
2586 void DumperBase::construct( const ConfigRef& rxConfig )
2588 if( isValid( rxConfig ) && rxConfig->isDumperEnabled() )
2589 ObjectBase::construct( rxConfig );
2592 } // namespace dump
2593 } // namespace oox
2595 #endif
2597 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */