xref: /trunk/main/oox/source/dump/dumperbase.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "oox/dump/dumperbase.hxx"
29 
30 #include <algorithm>
31 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
32 #include <com/sun/star/io/XActiveDataSource.hpp>
33 #include <com/sun/star/io/XTextOutputStream.hpp>
34 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
35 #include <comphelper/docpasswordhelper.hxx>
36 #include <osl/file.hxx>
37 #include <rtl/math.hxx>
38 #include <rtl/tencinfo.h>
39 #include "oox/core/filterbase.hxx"
40 #include "oox/helper/binaryoutputstream.hxx"
41 #include "oox/helper/textinputstream.hxx"
42 #include "oox/xls/biffhelper.hxx"
43 
44 #if OOX_INCLUDE_DUMPER
45 
46 namespace oox {
47 namespace dump {
48 
49 // ============================================================================
50 
51 using namespace ::com::sun::star::beans;
52 using namespace ::com::sun::star::io;
53 using namespace ::com::sun::star::lang;
54 using namespace ::com::sun::star::ucb;
55 using namespace ::com::sun::star::uno;
56 using namespace ::com::sun::star::util;
57 
58 using ::comphelper::MediaDescriptor;
59 using ::oox::core::FilterBase;
60 using ::rtl::OString;
61 using ::rtl::OStringBuffer;
62 using ::rtl::OStringToOUString;
63 using ::rtl::OUString;
64 using ::rtl::OUStringBuffer;
65 using ::rtl::OUStringToOString;
66 
67 // ============================================================================
68 
69 namespace {
70 
71 const sal_Unicode OOX_DUMP_BOM          = 0xFEFF;
72 const sal_Int32 OOX_DUMP_MAXSTRLEN      = 80;
73 const sal_Int32 OOX_DUMP_INDENT         = 2;
74 const sal_Unicode OOX_DUMP_BINDOT       = '.';
75 const sal_Unicode OOX_DUMP_CFG_LISTSEP  = ',';
76 const sal_Unicode OOX_DUMP_CFG_QUOTE    = '\'';
77 const sal_Unicode OOX_DUMP_LF           = '\n';
78 const sal_Unicode OOX_DUMP_ITEMSEP      = '=';
79 const sal_Int32 OOX_DUMP_BYTESPERLINE   = 16;
80 const sal_Int64 OOX_DUMP_MAXARRAY       = 16;
81 
82 } // namespace
83 
84 // ============================================================================
85 // ============================================================================
86 
87 // file names -----------------------------------------------------------------
88 
89 OUString InputOutputHelper::convertFileNameToUrl( const OUString& rFileName )
90 {
91     OUString aFileUrl;
92     if( ::osl::FileBase::getFileURLFromSystemPath( rFileName, aFileUrl ) == ::osl::FileBase::E_None )
93         return aFileUrl;
94     return OUString();
95 }
96 
97 sal_Int32 InputOutputHelper::getFileNamePos( const OUString& rFileUrl )
98 {
99     sal_Int32 nSepPos = rFileUrl.lastIndexOf( '/' );
100     return (nSepPos < 0) ? 0 : (nSepPos + 1);
101 }
102 
103 OUString InputOutputHelper::getFileNameExtension( const OUString& rFileUrl )
104 {
105     sal_Int32 nNamePos = getFileNamePos( rFileUrl );
106     sal_Int32 nExtPos = rFileUrl.lastIndexOf( '.' );
107     if( nExtPos >= nNamePos )
108         return rFileUrl.copy( nExtPos + 1 );
109     return OUString();
110 }
111 
112 // input streams --------------------------------------------------------------
113 
114 Reference< XInputStream > InputOutputHelper::openInputStream(
115         const Reference< XComponentContext >& rxContext, const OUString& rFileName )
116 {
117     Reference< XInputStream > xInStrm;
118     if( rxContext.is() ) try
119     {
120         Reference< XMultiServiceFactory > xFactory( rxContext->getServiceManager(), UNO_QUERY_THROW );
121         Reference< XSimpleFileAccess > xFileAccess( xFactory->createInstance( CREATE_OUSTRING( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY_THROW );
122         xInStrm = xFileAccess->openFileRead( rFileName );
123     }
124     catch( Exception& )
125     {
126     }
127     return xInStrm;
128 }
129 
130 // output streams -------------------------------------------------------------
131 
132 Reference< XOutputStream > InputOutputHelper::openOutputStream(
133         const Reference< XComponentContext >& rxContext, const OUString& rFileName )
134 {
135     Reference< XOutputStream > xOutStrm;
136     if( rxContext.is() ) try
137     {
138         Reference< XMultiServiceFactory > xFactory( rxContext->getServiceManager(), UNO_QUERY_THROW );
139         Reference< XSimpleFileAccess > xFileAccess( xFactory->createInstance( CREATE_OUSTRING( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY_THROW );
140         xOutStrm = xFileAccess->openFileWrite( rFileName );
141     }
142     catch( Exception& )
143     {
144     }
145     return xOutStrm;
146 }
147 
148 Reference< XTextOutputStream > InputOutputHelper::openTextOutputStream(
149         const Reference< XComponentContext >& rxContext, const Reference< XOutputStream >& rxOutStrm, rtl_TextEncoding eTextEnc )
150 {
151     Reference< XTextOutputStream > xTextOutStrm;
152     const char* pcCharset = rtl_getMimeCharsetFromTextEncoding( eTextEnc );
153     if( rxContext.is() && rxOutStrm.is() && pcCharset ) try
154     {
155         Reference< XMultiServiceFactory > xFactory( rxContext->getServiceManager(), UNO_QUERY_THROW );
156         Reference< XActiveDataSource > xDataSource( xFactory->createInstance( CREATE_OUSTRING( "com.sun.star.io.TextOutputStream" ) ), UNO_QUERY_THROW );
157         xDataSource->setOutputStream( rxOutStrm );
158         xTextOutStrm.set( xDataSource, UNO_QUERY_THROW );
159         xTextOutStrm->setEncoding( OUString::createFromAscii( pcCharset ) );
160     }
161     catch( Exception& )
162     {
163     }
164     return xTextOutStrm;
165 }
166 
167 Reference< XTextOutputStream > InputOutputHelper::openTextOutputStream(
168         const Reference< XComponentContext >& rxContext, const OUString& rFileName, rtl_TextEncoding eTextEnc )
169 {
170     return openTextOutputStream( rxContext, openOutputStream( rxContext, rFileName ), eTextEnc );
171 }
172 
173 // ============================================================================
174 // ============================================================================
175 
176 ItemFormat::ItemFormat() :
177     meDataType( DATATYPE_VOID ),
178     meFmtType( FORMATTYPE_NONE )
179 {
180 }
181 
182 void ItemFormat::set( DataType eDataType, FormatType eFmtType, const OUString& rItemName )
183 {
184     meDataType = eDataType;
185     meFmtType = eFmtType;
186     maItemName = rItemName;
187     maListName = OUString();
188 }
189 
190 void ItemFormat::set( DataType eDataType, FormatType eFmtType, const OUString& rItemName, const OUString& rListName )
191 {
192     set( eDataType, eFmtType, rItemName );
193     maListName = rListName;
194 }
195 
196 OUStringVector::const_iterator ItemFormat::parse( const OUStringVector& rFormatVec )
197 {
198     set( DATATYPE_VOID, FORMATTYPE_NONE, OUString() );
199 
200     OUStringVector::const_iterator aIt = rFormatVec.begin(), aEnd = rFormatVec.end();
201     OUString aDataType, aFmtType;
202     if( aIt != aEnd ) aDataType = *aIt++;
203     if( aIt != aEnd ) aFmtType = *aIt++;
204     if( aIt != aEnd ) maItemName = *aIt++;
205     if( aIt != aEnd ) maListName = *aIt++;
206 
207     meDataType = StringHelper::convertToDataType( aDataType );
208     meFmtType = StringHelper::convertToFormatType( aFmtType );
209 
210     if( meFmtType == FORMATTYPE_NONE )
211     {
212         if( aFmtType.equalsAscii( "unused" ) )
213             set( meDataType, FORMATTYPE_HEX, CREATE_OUSTRING( OOX_DUMP_UNUSED ) );
214         else if( aFmtType.equalsAscii( "unknown" ) )
215             set( meDataType, FORMATTYPE_HEX, CREATE_OUSTRING( OOX_DUMP_UNKNOWN ) );
216     }
217 
218     return aIt;
219 }
220 
221 OUStringVector ItemFormat::parse( const OUString& rFormatStr )
222 {
223     OUStringVector aFormatVec;
224     StringHelper::convertStringToStringList( aFormatVec, rFormatStr, false );
225     OUStringVector::const_iterator aIt = parse( aFormatVec );
226     return OUStringVector( aIt, const_cast< const OUStringVector& >( aFormatVec ).end() );
227 }
228 
229 // ============================================================================
230 // ============================================================================
231 
232 // append string to string ----------------------------------------------------
233 
234 void StringHelper::appendChar( OUStringBuffer& rStr, sal_Unicode cChar, sal_Int32 nCount )
235 {
236     for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
237         rStr.append( cChar );
238 }
239 
240 void StringHelper::appendString( OUStringBuffer& rStr, const OUString& rData, sal_Int32 nWidth, sal_Unicode cFill )
241 {
242     appendChar( rStr, cFill, nWidth - rData.getLength() );
243     rStr.append( rData );
244 }
245 
246 // append decimal -------------------------------------------------------------
247 
248 void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt8 nData, sal_Int32 nWidth, sal_Unicode cFill )
249 {
250     appendString( rStr, OUString::valueOf( static_cast< sal_Int32 >( nData ) ), nWidth, cFill );
251 }
252 
253 void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int8 nData, sal_Int32 nWidth, sal_Unicode cFill )
254 {
255     appendString( rStr, OUString::valueOf( static_cast< sal_Int32 >( nData ) ), nWidth, cFill );
256 }
257 
258 void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt16 nData, sal_Int32 nWidth, sal_Unicode cFill )
259 {
260     appendString( rStr, OUString::valueOf( static_cast< sal_Int32 >( nData ) ), nWidth, cFill );
261 }
262 
263 void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int16 nData, sal_Int32 nWidth, sal_Unicode cFill )
264 {
265     appendString( rStr, OUString::valueOf( static_cast< sal_Int32 >( nData ) ), nWidth, cFill );
266 }
267 
268 void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt32 nData, sal_Int32 nWidth, sal_Unicode cFill )
269 {
270     appendString( rStr, OUString::valueOf( static_cast< sal_Int64 >( nData ) ), nWidth, cFill );
271 }
272 
273 void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int32 nData, sal_Int32 nWidth, sal_Unicode cFill )
274 {
275     appendString( rStr, OUString::valueOf( nData ), nWidth, cFill );
276 }
277 
278 void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt64 nData, sal_Int32 nWidth, sal_Unicode cFill )
279 {
280     /*  Values greater than biggest signed 64bit integer will change to
281         negative when converting to sal_Int64. Therefore, the trailing digit
282         will be written separately. */
283     OUStringBuffer aBuffer;
284     if( nData > 9 )
285         aBuffer.append( OUString::valueOf( static_cast< sal_Int64 >( nData / 10 ) ) );
286     aBuffer.append( static_cast< sal_Unicode >( '0' + (nData % 10) ) );
287     appendString( rStr, aBuffer.makeStringAndClear(), nWidth, cFill );
288 }
289 
290 void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int64 nData, sal_Int32 nWidth, sal_Unicode cFill )
291 {
292     appendString( rStr, OUString::valueOf( nData ), nWidth, cFill );
293 }
294 
295 void StringHelper::appendDec( OUStringBuffer& rStr, double fData, sal_Int32 nWidth, sal_Unicode cFill )
296 {
297     appendString( rStr, ::rtl::math::doubleToUString( fData, rtl_math_StringFormat_G, 15, '.', true ), nWidth, cFill );
298 }
299 
300 // append hexadecimal ---------------------------------------------------------
301 
302 void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt8 nData, bool bPrefix )
303 {
304     static const sal_Unicode spcHexDigits[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
305     if( bPrefix )
306         rStr.appendAscii( "0x" );
307     rStr.append( spcHexDigits[ (nData >> 4) & 0x0F ] ).append( spcHexDigits[ nData & 0x0F ] );
308 }
309 
310 void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int8 nData, bool bPrefix )
311 {
312     appendHex( rStr, static_cast< sal_uInt8 >( nData ), bPrefix );
313 }
314 
315 void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt16 nData, bool bPrefix )
316 {
317     appendHex( rStr, static_cast< sal_uInt8 >( nData >> 8 ), bPrefix );
318     appendHex( rStr, static_cast< sal_uInt8 >( nData ), false );
319 }
320 
321 void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int16 nData, bool bPrefix )
322 {
323     appendHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix );
324 }
325 
326 void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt32 nData, bool bPrefix )
327 {
328     appendHex( rStr, static_cast< sal_uInt16 >( nData >> 16 ), bPrefix );
329     appendHex( rStr, static_cast< sal_uInt16 >( nData ), false );
330 }
331 
332 void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int32 nData, bool bPrefix )
333 {
334     appendHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix );
335 }
336 
337 void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt64 nData, bool bPrefix )
338 {
339     appendHex( rStr, static_cast< sal_uInt32 >( nData >> 32 ), bPrefix );
340     appendHex( rStr, static_cast< sal_uInt32 >( nData ), false );
341 }
342 
343 void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int64 nData, bool bPrefix )
344 {
345     appendHex( rStr, static_cast< sal_uInt64 >( nData ), bPrefix );
346 }
347 
348 void StringHelper::appendHex( OUStringBuffer& rStr, double fData, bool bPrefix )
349 {
350     appendHex( rStr, *reinterpret_cast< const sal_uInt64* >( &fData ), bPrefix );
351 }
352 
353 // append shortened hexadecimal -----------------------------------------------
354 
355 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt8 nData, bool bPrefix )
356 {
357     appendHex( rStr, nData, bPrefix );
358 }
359 
360 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int8 nData, bool bPrefix )
361 {
362     appendHex( rStr, nData, bPrefix );
363 }
364 
365 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt16 nData, bool bPrefix )
366 {
367     if( nData > SAL_MAX_UINT8 )
368         appendHex( rStr, nData, bPrefix );
369     else
370         appendHex( rStr, static_cast< sal_uInt8 >( nData ), bPrefix );
371 }
372 
373 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int16 nData, bool bPrefix )
374 {
375     appendShortHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix );
376 }
377 
378 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt32 nData, bool bPrefix )
379 {
380     if( nData > SAL_MAX_UINT16 )
381         appendHex( rStr, nData, bPrefix );
382     else
383         appendShortHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix );
384 }
385 
386 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int32 nData, bool bPrefix )
387 {
388     appendShortHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix );
389 }
390 
391 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt64 nData, bool bPrefix )
392 {
393     if( nData > SAL_MAX_UINT32 )
394         appendHex( rStr, nData, bPrefix );
395     else
396         appendShortHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix );
397 }
398 
399 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int64 nData, bool bPrefix )
400 {
401     appendShortHex( rStr, static_cast< sal_uInt64 >( nData ), bPrefix );
402 }
403 
404 void StringHelper::appendShortHex( OUStringBuffer& rStr, double fData, bool bPrefix )
405 {
406     appendHex( rStr, fData, bPrefix );
407 }
408 
409 // append binary --------------------------------------------------------------
410 
411 void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt8 nData, bool bDots )
412 {
413     for( sal_uInt8 nMask = 0x80; nMask != 0; (nMask >>= 1) &= 0x7F )
414     {
415         rStr.append( static_cast< sal_Unicode >( (nData & nMask) ? '1' : '0' ) );
416         if( bDots && (nMask == 0x10) )
417             rStr.append( OOX_DUMP_BINDOT );
418     }
419 }
420 
421 void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int8 nData, bool bDots )
422 {
423     appendBin( rStr, static_cast< sal_uInt8 >( nData ), bDots );
424 }
425 
426 void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt16 nData, bool bDots )
427 {
428     appendBin( rStr, static_cast< sal_uInt8 >( nData >> 8 ), bDots );
429     if( bDots )
430         rStr.append( OOX_DUMP_BINDOT );
431     appendBin( rStr, static_cast< sal_uInt8 >( nData ), bDots );
432 }
433 
434 void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int16 nData, bool bDots )
435 {
436     appendBin( rStr, static_cast< sal_uInt16 >( nData ), bDots );
437 }
438 
439 void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt32 nData, bool bDots )
440 {
441     appendBin( rStr, static_cast< sal_uInt16 >( nData >> 16 ), bDots );
442     if( bDots )
443         rStr.append( OOX_DUMP_BINDOT );
444     appendBin( rStr, static_cast< sal_uInt16 >( nData ), bDots );
445 }
446 
447 void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int32 nData, bool bDots )
448 {
449     appendBin( rStr, static_cast< sal_uInt32 >( nData ), bDots );
450 }
451 
452 void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt64 nData, bool bDots )
453 {
454     appendBin( rStr, static_cast< sal_uInt32 >( nData >> 32 ), bDots );
455     if( bDots )
456         rStr.append( OOX_DUMP_BINDOT );
457     appendBin( rStr, static_cast< sal_uInt32 >( nData ), bDots );
458 }
459 
460 void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int64 nData, bool bDots )
461 {
462     appendBin( rStr, static_cast< sal_uInt64 >( nData ), bDots );
463 }
464 
465 void StringHelper::appendBin( OUStringBuffer& rStr, double fData, bool bDots )
466 {
467     appendBin( rStr, *reinterpret_cast< const sal_uInt64* >( &fData ), bDots );
468 }
469 
470 // append formatted value -----------------------------------------------------
471 
472 void StringHelper::appendBool( OUStringBuffer& rStr, bool bData )
473 {
474     rStr.appendAscii( bData ? "true" : "false" );
475 }
476 
477 // append columns, rows, addresses --------------------------------------------
478 
479 void StringHelper::appendAddrCol( OUStringBuffer& rStr, sal_Int32 nCol, bool bRel )
480 {
481     if( !bRel ) rStr.append( OOX_DUMP_ADDRABS );
482     sal_Int32 nPos = rStr.getLength();
483     for( sal_Int32 nTemp = nCol; nTemp >= 0; (nTemp /= 26) -= 1 )
484         rStr.insert( nPos, static_cast< sal_Unicode >( 'A' + (nTemp % 26) ) );
485 }
486 
487 void StringHelper::appendAddrRow( OUStringBuffer& rStr, sal_Int32 nRow, bool bRel )
488 {
489     if( !bRel ) rStr.append( OOX_DUMP_ADDRABS );
490     appendDec( rStr, nRow + 1 );
491 }
492 
493 void StringHelper::appendAddrName( OUStringBuffer& rStr, sal_Unicode cPrefix, sal_Int32 nColRow, bool bRel )
494 {
495     rStr.append( cPrefix );
496     if( bRel && (nColRow != 0) )
497     {
498         rStr.append( OOX_DUMP_R1C1OPEN );
499         appendDec( rStr, nColRow );
500         rStr.append( OOX_DUMP_R1C1CLOSE );
501     }
502     else if( !bRel )
503         appendDec( rStr, nColRow + 1 );
504 }
505 
506 void StringHelper::appendAddress( OUStringBuffer& rStr, const Address& rPos )
507 {
508     appendAddrCol( rStr, rPos.mnCol, true );
509     appendAddrRow( rStr, rPos.mnRow, true );
510 }
511 
512 void StringHelper::appendRange( OUStringBuffer& rStr, const Range& rRange )
513 {
514     appendAddress( rStr, rRange.maFirst );
515     rStr.append( OOX_DUMP_RANGESEP );
516     appendAddress( rStr, rRange.maLast );
517 }
518 
519 void StringHelper::appendRangeList( OUStringBuffer& rStr, const RangeList& rRanges )
520 {
521     OUStringBuffer aData;
522     for( RangeList::const_iterator aIt = rRanges.begin(), aEnd = rRanges.end(); aIt != aEnd; ++aIt )
523     {
524         OUStringBuffer aRange;
525         appendRange( aRange, *aIt );
526         appendToken( aData, aRange.makeStringAndClear(), OOX_DUMP_LISTSEP );
527     }
528     rStr.append( aData.makeStringAndClear() );
529 }
530 
531 void StringHelper::appendAddress( OUStringBuffer& rStr, const TokenAddress& rPos, bool bR1C1 )
532 {
533     if( bR1C1 && (rPos.mbRelCol || rPos.mbRelRow) )
534     {
535         appendAddrName( rStr, OOX_DUMP_R1C1ROW, rPos.mnRow, rPos.mbRelRow );
536         appendAddrName( rStr, OOX_DUMP_R1C1COL, rPos.mnCol, rPos.mbRelCol );
537     }
538     else
539     {
540         appendAddrCol( rStr, rPos.mnCol, rPos.mbRelCol );
541         appendAddrRow( rStr, rPos.mnRow, rPos.mbRelRow );
542     }
543 }
544 
545 void StringHelper::appendRange( OUStringBuffer& rStr, const TokenRange& rRange, bool bR1C1 )
546 {
547     appendAddress( rStr, rRange.maFirst, bR1C1 );
548     rStr.append( OOX_DUMP_RANGESEP );
549     appendAddress( rStr, rRange.maLast, bR1C1 );
550 }
551 
552 // encoded text output --------------------------------------------------------
553 
554 void StringHelper::appendCChar( OUStringBuffer& rStr, sal_Unicode cChar, bool bPrefix )
555 {
556     if( cChar > 0x00FF )
557     {
558         if( bPrefix )
559             rStr.appendAscii( "\\u" );
560         appendHex( rStr, static_cast< sal_uInt16 >( cChar ), false );
561     }
562     else
563     {
564         if( bPrefix )
565             rStr.appendAscii( "\\x" );
566         appendHex( rStr, static_cast< sal_uInt8 >( cChar ), false );
567     }
568 }
569 
570 void StringHelper::appendEncChar( OUStringBuffer& rStr, sal_Unicode cChar, sal_Int32 nCount, bool bPrefix )
571 {
572     if( cChar < 0x0020 )
573     {
574         // C-style hex code
575         OUStringBuffer aCode;
576         appendCChar( aCode, cChar, bPrefix );
577         for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
578             rStr.append( aCode );
579     }
580     else
581     {
582         appendChar( rStr, cChar, nCount );
583     }
584 }
585 
586 void StringHelper::appendEncString( OUStringBuffer& rStr, const OUString& rData, bool bPrefix )
587 {
588     sal_Int32 nBeg = 0;
589     sal_Int32 nIdx = 0;
590     sal_Int32 nEnd = rData.getLength();
591     while( nIdx < nEnd )
592     {
593         // find next character that needs encoding
594         while( (nIdx < nEnd) && (rData[ nIdx ] >= 0x20) ) ++nIdx;
595         // append portion
596         if( nBeg < nIdx )
597         {
598             if( (nBeg == 0) && (nIdx == nEnd) )
599                 rStr.append( rData );
600             else
601                 rStr.append( rData.copy( nBeg, nIdx - nBeg ) );
602         }
603         // append characters to be encoded
604         while( (nIdx < nEnd) && (rData[ nIdx ] < 0x20) )
605         {
606             appendCChar( rStr, rData[ nIdx ], bPrefix );
607             ++nIdx;
608         }
609         // adjust limits
610         nBeg = nIdx;
611     }
612 }
613 
614 // token list -----------------------------------------------------------------
615 
616 void StringHelper::appendToken( OUStringBuffer& rStr, const OUString& rToken, sal_Unicode cSep )
617 {
618     if( (rStr.getLength() > 0) && (rToken.getLength() > 0) )
619         rStr.append( cSep );
620     rStr.append( rToken );
621 }
622 
623 void StringHelper::appendToken( OUStringBuffer& rStr, sal_Int64 nToken, sal_Unicode cSep )
624 {
625     OUStringBuffer aToken;
626     appendDec( aToken, nToken );
627     appendToken( rStr, aToken.makeStringAndClear(), cSep );
628 }
629 
630 void StringHelper::prependToken( OUStringBuffer& rStr, const OUString& rToken, sal_Unicode cSep )
631 {
632     if( (rStr.getLength() > 0) && (rToken.getLength() > 0) )
633         rStr.insert( 0, cSep );
634     rStr.insert( 0, rToken );
635 }
636 
637 void StringHelper::prependToken( OUStringBuffer& rStr, sal_Int64 nToken, sal_Unicode cSep )
638 {
639     OUStringBuffer aToken;
640     appendDec( aToken, nToken );
641     prependToken( rStr, aToken.makeStringAndClear(), cSep );
642 }
643 
644 void StringHelper::appendIndex( OUStringBuffer& rStr, const OUString& rIdx )
645 {
646     rStr.append( sal_Unicode( '[' ) ).append( rIdx ).append( sal_Unicode( ']' ) );
647 }
648 
649 void StringHelper::appendIndex( OUStringBuffer& rStr, sal_Int64 nIdx )
650 {
651     OUStringBuffer aToken;
652     appendDec( aToken, nIdx );
653     appendIndex( rStr, aToken.makeStringAndClear() );
654 }
655 
656 void StringHelper::appendIndexedText( OUStringBuffer& rStr, const OUString& rData, const OUString& rIdx )
657 {
658     rStr.append( rData );
659     appendIndex( rStr, rIdx );
660 }
661 
662 void StringHelper::appendIndexedText( OUStringBuffer& rStr, const OUString& rData, sal_Int64 nIdx )
663 {
664     rStr.append( rData );
665     appendIndex( rStr, nIdx );
666 }
667 
668 OUString StringHelper::getToken( const OUString& rData, sal_Int32& rnPos, sal_Unicode cSep )
669 {
670     return trimSpaces( rData.getToken( 0, cSep, rnPos ) );
671 }
672 
673 void StringHelper::enclose( OUStringBuffer& rStr, sal_Unicode cOpen, sal_Unicode cClose )
674 {
675     rStr.insert( 0, cOpen ).append( cClose ? cClose : cOpen );
676 }
677 
678 // string conversion ----------------------------------------------------------
679 
680 namespace {
681 
682 sal_Int32 lclIndexOf( const OUString& rStr, sal_Unicode cChar, sal_Int32 nStartPos )
683 {
684     sal_Int32 nIndex = rStr.indexOf( cChar, nStartPos );
685     return (nIndex < 0) ? rStr.getLength() : nIndex;
686 }
687 
688 OUString lclTrimQuotedStringList( const OUString& rStr )
689 {
690     OUStringBuffer aBuffer;
691     sal_Int32 nPos = 0;
692     sal_Int32 nLen = rStr.getLength();
693     while( nPos < nLen )
694     {
695         if( rStr[ nPos ] == OOX_DUMP_CFG_QUOTE )
696         {
697             // quoted string, skip leading quote character
698             ++nPos;
699             // process quoted text and ambedded literal quote characters
700             OUStringBuffer aToken;
701             do
702             {
703                 // seek to next quote character and add text portion to token buffer
704                 sal_Int32 nEnd = lclIndexOf( rStr, OOX_DUMP_CFG_QUOTE, nPos );
705                 aToken.append( rStr.copy( nPos, nEnd - nPos ) );
706                 // process literal quotes
707                 while( (nEnd + 1 < nLen) && (rStr[ nEnd ] == OOX_DUMP_CFG_QUOTE) && (rStr[ nEnd + 1 ] == OOX_DUMP_CFG_QUOTE) )
708                 {
709                     aToken.append( OOX_DUMP_CFG_QUOTE );
710                     nEnd += 2;
711                 }
712                 // nEnd is start of possible next text portion
713                 nPos = nEnd;
714             }
715             while( (nPos < nLen) && (rStr[ nPos ] != OOX_DUMP_CFG_QUOTE) );
716             // add token, seek to list separator, ignore text following closing quote
717             aBuffer.append( aToken.makeStringAndClear() );
718             nPos = lclIndexOf( rStr, OOX_DUMP_CFG_LISTSEP, nPos );
719             if( nPos < nLen )
720                 aBuffer.append( OOX_DUMP_LF );
721             // set current position behind list separator
722             ++nPos;
723         }
724         else
725         {
726             // find list separator, add token text to buffer
727             sal_Int32 nEnd = lclIndexOf( rStr, OOX_DUMP_CFG_LISTSEP, nPos );
728             aBuffer.append( rStr.copy( nPos, nEnd - nPos ) );
729             if( nEnd < nLen )
730                 aBuffer.append( OOX_DUMP_LF );
731             // set current position behind list separator
732             nPos = nEnd + 1;
733         }
734     }
735 
736     return aBuffer.makeStringAndClear();
737 }
738 
739 } // namespace
740 
741 OUString StringHelper::trimSpaces( const OUString& rStr )
742 {
743     sal_Int32 nBeg = 0;
744     while( (nBeg < rStr.getLength()) && ((rStr[ nBeg ] == ' ') || (rStr[ nBeg ] == '\t')) )
745         ++nBeg;
746     sal_Int32 nEnd = rStr.getLength();
747     while( (nEnd > nBeg) && ((rStr[ nEnd - 1 ] == ' ') || (rStr[ nEnd - 1 ] == '\t')) )
748         --nEnd;
749     return rStr.copy( nBeg, nEnd - nBeg );
750 }
751 
752 OUString StringHelper::trimTrailingNul( const OUString& rStr )
753 {
754     sal_Int32 nLastPos = rStr.getLength() - 1;
755     if( (nLastPos >= 0) && (rStr[ nLastPos ] == 0) )
756         return rStr.copy( 0, nLastPos );
757     return rStr;
758 }
759 
760 OString StringHelper::convertToUtf8( const OUString& rStr )
761 {
762     return OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 );
763 }
764 
765 DataType StringHelper::convertToDataType( const OUString& rStr )
766 {
767     DataType eType = DATATYPE_VOID;
768     if( rStr.equalsAscii( "int8" ) )
769         eType = DATATYPE_INT8;
770     else if( rStr.equalsAscii( "uint8" ) )
771         eType = DATATYPE_UINT8;
772     else if( rStr.equalsAscii( "int16" ) )
773         eType = DATATYPE_INT16;
774     else if( rStr.equalsAscii( "uint16" ) )
775         eType = DATATYPE_UINT16;
776     else if( rStr.equalsAscii( "int32" ) )
777         eType = DATATYPE_INT32;
778     else if( rStr.equalsAscii( "uint32" ) )
779         eType = DATATYPE_UINT32;
780     else if( rStr.equalsAscii( "int64" ) )
781         eType = DATATYPE_INT64;
782     else if( rStr.equalsAscii( "uint64" ) )
783         eType = DATATYPE_UINT64;
784     else if( rStr.equalsAscii( "float" ) )
785         eType = DATATYPE_FLOAT;
786     else if( rStr.equalsAscii( "double" ) )
787         eType = DATATYPE_DOUBLE;
788     return eType;
789 }
790 
791 FormatType StringHelper::convertToFormatType( const OUString& rStr )
792 {
793     FormatType eType = FORMATTYPE_NONE;
794     if( rStr.equalsAscii( "dec" ) )
795         eType = FORMATTYPE_DEC;
796     else if( rStr.equalsAscii( "hex" ) )
797         eType = FORMATTYPE_HEX;
798     else if( rStr.equalsAscii( "shorthex" ) )
799         eType = FORMATTYPE_SHORTHEX;
800     else if( rStr.equalsAscii( "bin" ) )
801         eType = FORMATTYPE_BIN;
802     else if( rStr.equalsAscii( "fix" ) )
803         eType = FORMATTYPE_FIX;
804     else if( rStr.equalsAscii( "bool" ) )
805         eType = FORMATTYPE_BOOL;
806     return eType;
807 }
808 
809 bool StringHelper::convertFromDec( sal_Int64& ornData, const OUString& rData )
810 {
811     sal_Int32 nPos = 0;
812     sal_Int32 nLen = rData.getLength();
813     bool bNeg = false;
814     if( (nLen > 0) && (rData[ 0 ] == '-') )
815     {
816         bNeg = true;
817         ++nPos;
818     }
819     ornData = 0;
820     for( ; nPos < nLen; ++nPos )
821     {
822         sal_Unicode cChar = rData[ nPos ];
823         if( (cChar < '0') || (cChar > '9') )
824             return false;
825         (ornData *= 10) += (cChar - '0');
826     }
827     if( bNeg )
828         ornData *= -1;
829     return true;
830 }
831 
832 bool StringHelper::convertFromHex( sal_Int64& ornData, const OUString& rData )
833 {
834     ornData = 0;
835     for( sal_Int32 nPos = 0, nLen = rData.getLength(); nPos < nLen; ++nPos )
836     {
837         sal_Unicode cChar = rData[ nPos ];
838         if( ('0' <= cChar) && (cChar <= '9') )
839             cChar -= '0';
840         else if( ('A' <= cChar) && (cChar <= 'F') )
841             cChar -= ('A' - 10);
842         else if( ('a' <= cChar) && (cChar <= 'f') )
843             cChar -= ('a' - 10);
844         else
845             return false;
846         (ornData <<= 4) += cChar;
847     }
848     return true;
849 }
850 
851 bool StringHelper::convertStringToInt( sal_Int64& ornData, const OUString& rData )
852 {
853     if( (rData.getLength() > 2) && (rData[ 0 ] == '0') && ((rData[ 1 ] == 'X') || (rData[ 1 ] == 'x')) )
854         return convertFromHex( ornData, rData.copy( 2 ) );
855     return convertFromDec( ornData, rData );
856 }
857 
858 bool StringHelper::convertStringToDouble( double& orfData, const OUString& rData )
859 {
860     rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
861     sal_Int32 nSize = 0;
862     orfData = rtl::math::stringToDouble( rData, '.', '\0', &eStatus, &nSize );
863     return (eStatus == rtl_math_ConversionStatus_Ok) && (nSize == rData.getLength());
864 }
865 
866 bool StringHelper::convertStringToBool( const OUString& rData )
867 {
868     if( rData.equalsAscii( "true" ) )
869         return true;
870     if( rData.equalsAscii( "false" ) )
871         return false;
872     sal_Int64 nData;
873     return convertStringToInt( nData, rData ) && (nData != 0);
874 }
875 
876 OUStringPair StringHelper::convertStringToPair( const OUString& rString, sal_Unicode cSep )
877 {
878     OUStringPair aPair;
879     if( rString.getLength() > 0 )
880     {
881         sal_Int32 nEqPos = rString.indexOf( cSep );
882         if( nEqPos < 0 )
883         {
884             aPair.first = rString;
885         }
886         else
887         {
888             aPair.first = StringHelper::trimSpaces( rString.copy( 0, nEqPos ) );
889             aPair.second = StringHelper::trimSpaces( rString.copy( nEqPos + 1 ) );
890         }
891     }
892     return aPair;
893 }
894 
895 void StringHelper::convertStringToStringList( OUStringVector& orVec, const OUString& rData, bool bIgnoreEmpty )
896 {
897     orVec.clear();
898     OUString aUnquotedData = lclTrimQuotedStringList( rData );
899     sal_Int32 nPos = 0;
900     sal_Int32 nLen = aUnquotedData.getLength();
901     while( (0 <= nPos) && (nPos < nLen) )
902     {
903         OUString aToken = getToken( aUnquotedData, nPos, OOX_DUMP_LF );
904         if( !bIgnoreEmpty || (aToken.getLength() > 0) )
905             orVec.push_back( aToken );
906     }
907 }
908 
909 void StringHelper::convertStringToIntList( Int64Vector& orVec, const OUString& rData, bool bIgnoreEmpty )
910 {
911     orVec.clear();
912     OUString aUnquotedData = lclTrimQuotedStringList( rData );
913     sal_Int32 nPos = 0;
914     sal_Int32 nLen = aUnquotedData.getLength();
915     sal_Int64 nData;
916     while( (0 <= nPos) && (nPos < nLen) )
917     {
918         bool bOk = convertStringToInt( nData, getToken( aUnquotedData, nPos, OOX_DUMP_LF ) );
919         if( !bIgnoreEmpty || bOk )
920             orVec.push_back( bOk ? nData : 0 );
921     }
922 }
923 
924 // ============================================================================
925 // ============================================================================
926 
927 FormulaStack::FormulaStack() :
928     mbError( false )
929 {
930 }
931 
932 void FormulaStack::pushOperand( const String& rOp, const OUString& rTokClass )
933 {
934     maFmlaStack.push( rOp );
935     maClassStack.push( rTokClass );
936 }
937 
938 void FormulaStack::pushOperand( const String& rOp )
939 {
940     pushOperand( rOp, OUString( OOX_DUMP_BASECLASS ) );
941 }
942 
943 void FormulaStack::pushUnaryOp( const String& rLOp, const String& rROp )
944 {
945     pushUnaryOp( maFmlaStack, rLOp, rROp );
946     pushUnaryOp( maClassStack, rLOp, rROp );
947 }
948 
949 void FormulaStack::pushBinaryOp( const String& rOp )
950 {
951     pushBinaryOp( maFmlaStack, rOp );
952     pushBinaryOp( maClassStack, rOp );
953 }
954 
955 void FormulaStack::pushFuncOp( const String& rFunc, const OUString& rTokClass, sal_uInt8 nParamCount )
956 {
957     pushFuncOp( maFmlaStack, rFunc, nParamCount );
958     pushFuncOp( maClassStack, rTokClass, nParamCount );
959 }
960 
961 void FormulaStack::replaceOnTop( const OUString& rOld, const OUString& rNew )
962 {
963     if( !maFmlaStack.empty() )
964     {
965         sal_Int32 nPos = maFmlaStack.top().indexOf( rOld );
966         if( nPos >= 0 )
967             maFmlaStack.top() = maFmlaStack.top().copy( 0, nPos ) + rNew + maFmlaStack.top().copy( nPos + rOld.getLength() );
968     }
969 }
970 
971 const OUString& FormulaStack::getString( const StringStack& rStack ) const
972 {
973     static const OUString saStackError = OOX_DUMP_ERRSTRING( "stack" );
974     return (mbError || rStack.empty()) ? saStackError : rStack.top();
975 }
976 
977 void FormulaStack::pushUnaryOp( StringStack& rStack, const OUString& rLOp, const OUString& rROp )
978 {
979     if( check( !rStack.empty() ) )
980         rStack.top() = rLOp + rStack.top() + rROp;
981 }
982 
983 void FormulaStack::pushBinaryOp( StringStack& rStack, const OUString& rOp )
984 {
985     OUString aSecond;
986     if( check( !rStack.empty() ) )
987     {
988         aSecond = rStack.top();
989         rStack.pop();
990     }
991     if( check( !rStack.empty() ) )
992         rStack.top() = rStack.top() + rOp + aSecond;
993 }
994 
995 void FormulaStack::pushFuncOp( StringStack& rStack, const OUString& rOp, sal_uInt8 nParamCount )
996 {
997     OUStringBuffer aFunc;
998     for( sal_uInt8 nParam = 0; (nParam < nParamCount) && check( !rStack.empty() ); ++nParam )
999     {
1000         StringHelper::prependToken( aFunc, rStack.top(), OOX_DUMP_FUNCSEP );
1001         rStack.pop();
1002     }
1003     StringHelper::enclose( aFunc, '(', ')' );
1004     aFunc.insert( 0, rOp );
1005     rStack.push( aFunc.makeStringAndClear() );
1006 }
1007 
1008 // ============================================================================
1009 // ============================================================================
1010 
1011 Base::~Base()
1012 {
1013 }
1014 
1015 // ============================================================================
1016 // ============================================================================
1017 
1018 ConfigItemBase::~ConfigItemBase()
1019 {
1020 }
1021 
1022 void ConfigItemBase::readConfigBlock( TextInputStream& rStrm )
1023 {
1024     readConfigBlockContents( rStrm );
1025 }
1026 
1027 void ConfigItemBase::implProcessConfigItemStr(
1028         TextInputStream& /*rStrm*/, const OUString& /*rKey*/, const OUString& /*rData*/ )
1029 {
1030 }
1031 
1032 void ConfigItemBase::implProcessConfigItemInt(
1033         TextInputStream& /*rStrm*/, sal_Int64 /*nKey*/, const OUString& /*rData*/ )
1034 {
1035 }
1036 
1037 void ConfigItemBase::readConfigBlockContents( TextInputStream& rStrm )
1038 {
1039     bool bLoop = true;
1040     while( bLoop && !rStrm.isEof() )
1041     {
1042         OUString aKey, aData;
1043         switch( readConfigLine( rStrm, aKey, aData ) )
1044         {
1045             case LINETYPE_DATA:
1046                 processConfigItem( rStrm, aKey, aData );
1047             break;
1048             case LINETYPE_END:
1049                 bLoop = false;
1050             break;
1051         }
1052     }
1053 }
1054 
1055 ConfigItemBase::LineType ConfigItemBase::readConfigLine(
1056         TextInputStream& rStrm, OUString& orKey, OUString& orData ) const
1057 {
1058     OUString aLine;
1059     while( !rStrm.isEof() && (aLine.getLength() == 0) )
1060     {
1061         aLine = rStrm.readLine();
1062         if( (aLine.getLength() > 0) && (aLine[ 0 ] == OOX_DUMP_BOM) )
1063             aLine = aLine.copy( 1 );
1064         aLine = StringHelper::trimSpaces( aLine );
1065         if( aLine.getLength() > 0 )
1066         {
1067             // ignore comments (starting with hash or semicolon)
1068             sal_Unicode cChar = aLine[ 0 ];
1069             if( (cChar == '#') || (cChar == ';') )
1070                 aLine = OUString();
1071         }
1072     }
1073 
1074     OUStringPair aPair = StringHelper::convertStringToPair( aLine );
1075     orKey = aPair.first;
1076     orData = aPair.second;
1077     return ((orKey.getLength() > 0) && ((orData.getLength() > 0) || !orKey.equalsAscii( "end" ))) ?
1078         LINETYPE_DATA : LINETYPE_END;
1079 }
1080 
1081 ConfigItemBase::LineType ConfigItemBase::readConfigLine( TextInputStream& rStrm ) const
1082 {
1083     OUString aKey, aData;
1084     return readConfigLine( rStrm, aKey, aData );
1085 }
1086 
1087 void ConfigItemBase::processConfigItem(
1088         TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
1089 {
1090     sal_Int64 nKey;
1091     if( StringHelper::convertStringToInt( nKey, rKey ) )
1092         implProcessConfigItemInt( rStrm, nKey, rData );
1093     else
1094         implProcessConfigItemStr( rStrm, rKey, rData );
1095 }
1096 
1097 // ============================================================================
1098 
1099 NameListBase::~NameListBase()
1100 {
1101 }
1102 
1103 void NameListBase::setName( sal_Int64 nKey, const String& rName )
1104 {
1105     implSetName( nKey, rName );
1106 }
1107 
1108 void NameListBase::includeList( const NameListRef& rxList )
1109 {
1110     if( rxList.get() )
1111     {
1112         for( const_iterator aIt = rxList->begin(), aEnd = rxList->end(); aIt != aEnd; ++aIt )
1113             maMap[ aIt->first ] = aIt->second;
1114         implIncludeList( *rxList );
1115     }
1116 }
1117 
1118 bool NameListBase::implIsValid() const
1119 {
1120     return true;
1121 }
1122 
1123 void NameListBase::implProcessConfigItemStr(
1124         TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
1125 {
1126     if( rKey.equalsAscii( "include" ) )
1127         include( rData );
1128     else if( rKey.equalsAscii( "exclude" ) )
1129         exclude( rData );
1130     else
1131         ConfigItemBase::implProcessConfigItemStr( rStrm, rKey, rData );
1132 }
1133 
1134 void NameListBase::implProcessConfigItemInt(
1135         TextInputStream& /*rStrm*/, sal_Int64 nKey, const OUString& rData )
1136 {
1137     implSetName( nKey, rData );
1138 }
1139 
1140 void NameListBase::insertRawName( sal_Int64 nKey, const OUString& rName )
1141 {
1142     maMap[ nKey ] = rName;
1143 }
1144 
1145 const OUString* NameListBase::findRawName( sal_Int64 nKey ) const
1146 {
1147     const_iterator aIt = maMap.find( nKey );
1148     return (aIt == end()) ? 0 : &aIt->second;
1149 }
1150 
1151 void NameListBase::include( const OUString& rListKeys )
1152 {
1153     OUStringVector aVec;
1154     StringHelper::convertStringToStringList( aVec, rListKeys, true );
1155     for( OUStringVector::const_iterator aIt = aVec.begin(), aEnd = aVec.end(); aIt != aEnd; ++aIt )
1156         includeList( mrCfgData.getNameList( *aIt ) );
1157 }
1158 
1159 void NameListBase::exclude( const OUString& rKeys )
1160 {
1161     Int64Vector aVec;
1162     StringHelper::convertStringToIntList( aVec, rKeys, true );
1163     for( Int64Vector::const_iterator aIt = aVec.begin(), aEnd = aVec.end(); aIt != aEnd; ++aIt )
1164         maMap.erase( *aIt );
1165 }
1166 
1167 // ============================================================================
1168 
1169 void ItemFormatMap::insertFormats( const NameListRef& rxNameList )
1170 {
1171     if( Base::isValid( rxNameList ) )
1172         for( NameListBase::const_iterator aIt = rxNameList->begin(), aEnd = rxNameList->end(); aIt != aEnd; ++aIt )
1173             (*this)[ aIt->first ].parse( aIt->second );
1174 }
1175 
1176 // ============================================================================
1177 
1178 ConstList::ConstList( const SharedConfigData& rCfgData ) :
1179     NameListBase( rCfgData ),
1180     maDefName( OOX_DUMP_ERR_NONAME ),
1181     mbQuoteNames( false )
1182 {
1183 }
1184 
1185 void ConstList::implProcessConfigItemStr(
1186         TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
1187 {
1188     if( rKey.equalsAscii( "default" ) )
1189         setDefaultName( rData );
1190     else if( rKey.equalsAscii( "quote-names" ) )
1191         setQuoteNames( StringHelper::convertStringToBool( rData ) );
1192     else
1193         NameListBase::implProcessConfigItemStr( rStrm, rKey, rData );
1194 }
1195 
1196 void ConstList::implSetName( sal_Int64 nKey, const OUString& rName )
1197 {
1198     insertRawName( nKey, rName );
1199 }
1200 
1201 OUString ConstList::implGetName( const Config& /*rCfg*/, sal_Int64 nKey ) const
1202 {
1203     const OUString* pName = findRawName( nKey );
1204     OUString aName = pName ? *pName : maDefName;
1205     if( mbQuoteNames )
1206     {
1207         OUStringBuffer aBuffer( aName );
1208         StringHelper::enclose( aBuffer, OOX_DUMP_STRQUOTE );
1209         aName = aBuffer.makeStringAndClear();
1210     }
1211     return aName;
1212 }
1213 
1214 OUString ConstList::implGetNameDbl( const Config& /*rCfg*/, double /*fValue*/ ) const
1215 {
1216     return OUString();
1217 }
1218 
1219 void ConstList::implIncludeList( const NameListBase& rList )
1220 {
1221     if( const ConstList* pConstList = dynamic_cast< const ConstList* >( &rList ) )
1222     {
1223         maDefName = pConstList->maDefName;
1224         mbQuoteNames = pConstList->mbQuoteNames;
1225     }
1226 }
1227 
1228 // ============================================================================
1229 
1230 MultiList::MultiList( const SharedConfigData& rCfgData ) :
1231     ConstList( rCfgData ),
1232     mbIgnoreEmpty( true )
1233 {
1234 }
1235 
1236 void MultiList::setNamesFromVec( sal_Int64 nStartKey, const OUStringVector& rNames )
1237 {
1238     sal_Int64 nKey = nStartKey;
1239     for( OUStringVector::const_iterator aIt = rNames.begin(), aEnd = rNames.end(); aIt != aEnd; ++aIt, ++nKey )
1240         if( !mbIgnoreEmpty || (aIt->getLength() > 0) )
1241             insertRawName( nKey, *aIt );
1242 }
1243 
1244 void MultiList::implProcessConfigItemStr(
1245         TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
1246 {
1247     if( rKey.equalsAscii( "ignore-empty" ) )
1248         mbIgnoreEmpty = StringHelper::convertStringToBool( rData );
1249     else
1250         ConstList::implProcessConfigItemStr( rStrm, rKey, rData );
1251 }
1252 
1253 void MultiList::implSetName( sal_Int64 nKey, const OUString& rName )
1254 {
1255     OUStringVector aNames;
1256     StringHelper::convertStringToStringList( aNames, rName, false );
1257     setNamesFromVec( nKey, aNames );
1258 }
1259 
1260 // ============================================================================
1261 
1262 FlagsList::FlagsList( const SharedConfigData& rCfgData ) :
1263     NameListBase( rCfgData ),
1264     mnIgnore( 0 )
1265 {
1266 }
1267 
1268 void FlagsList::implProcessConfigItemStr(
1269         TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
1270 {
1271     if( rKey.equalsAscii( "ignore" ) )
1272     {
1273         sal_Int64 nIgnore;
1274         if( StringHelper::convertStringToInt( nIgnore, rData ) )
1275             setIgnoreFlags( nIgnore );
1276     }
1277     else
1278     {
1279         NameListBase::implProcessConfigItemStr( rStrm, rKey, rData );
1280     }
1281 }
1282 
1283 void FlagsList::implSetName( sal_Int64 nKey, const OUString& rName )
1284 {
1285     if( (nKey != 0) && ((nKey & (nKey - 1)) == 0) )  // only a single bit set?
1286         insertRawName( nKey, rName );
1287 }
1288 
1289 OUString FlagsList::implGetName( const Config& /*rCfg*/, sal_Int64 nKey ) const
1290 {
1291     sal_Int64 nFound = mnIgnore;
1292     OUStringBuffer aName;
1293     // add known flags
1294     for( const_iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt )
1295     {
1296         sal_Int64 nMask = aIt->first;
1297         setFlag( nFound, nMask );
1298         if( !getFlag( mnIgnore, nMask ) )
1299         {
1300             const OUString& rFlagName = aIt->second;
1301             bool bOnOff = (rFlagName.getLength() > 0) && (rFlagName[ 0 ] == ':');
1302             bool bFlag = getFlag( nKey, nMask );
1303             if( bOnOff )
1304             {
1305                 StringHelper::appendToken( aName, rFlagName.copy( 1 ) );
1306                 aName.appendAscii( bFlag ? ":on" : ":off" );
1307             }
1308             else
1309             {
1310                 bool bNegated = (rFlagName.getLength() > 0) && (rFlagName[ 0 ] == '!');
1311                 sal_Int32 nBothSep = bNegated ? rFlagName.indexOf( '!', 1 ) : -1;
1312                 if( bFlag )
1313                 {
1314                     if( !bNegated )
1315                         StringHelper::appendToken( aName, rFlagName );
1316                     else if( nBothSep > 0 )
1317                         StringHelper::appendToken( aName, rFlagName.copy( nBothSep + 1 ) );
1318                 }
1319                 else if( bNegated )
1320                 {
1321                     if( nBothSep > 0 )
1322                         StringHelper::appendToken( aName, rFlagName.copy( 1, nBothSep - 1 ) );
1323                     else
1324                         StringHelper::appendToken( aName, rFlagName.copy( 1 ) );
1325                 }
1326             }
1327         }
1328     }
1329     // add unknown flags
1330     setFlag( nKey, nFound, false );
1331     if( nKey != 0 )
1332     {
1333         OUStringBuffer aUnknown( CREATE_OUSTRING( OOX_DUMP_UNKNOWN ) );
1334         aUnknown.append( OOX_DUMP_ITEMSEP );
1335         StringHelper::appendShortHex( aUnknown, nKey, true );
1336         StringHelper::enclose( aUnknown, '(', ')' );
1337         StringHelper::appendToken( aName, aUnknown.makeStringAndClear() );
1338     }
1339     return aName.makeStringAndClear();
1340 }
1341 
1342 OUString FlagsList::implGetNameDbl( const Config& /*rCfg*/, double /*fValue*/ ) const
1343 {
1344     return OUString();
1345 }
1346 
1347 void FlagsList::implIncludeList( const NameListBase& rList )
1348 {
1349     if( const FlagsList* pFlagsList = dynamic_cast< const FlagsList* >( &rList ) )
1350         mnIgnore = pFlagsList->mnIgnore;
1351 }
1352 
1353 // ============================================================================
1354 
1355 bool CombiList::ExtItemFormatKey::operator<( const ExtItemFormatKey& rRight ) const
1356 {
1357     return (mnKey < rRight.mnKey) || ((mnKey == rRight.mnKey) && (maFilter < rRight.maFilter));
1358 }
1359 
1360 CombiList::CombiList( const SharedConfigData& rCfgData ) :
1361     FlagsList( rCfgData )
1362 {
1363 }
1364 
1365 void CombiList::implSetName( sal_Int64 nKey, const OUString& rName )
1366 {
1367     if( (nKey & (nKey - 1)) != 0 )  // more than a single bit set?
1368     {
1369         typedef ::std::set< ExtItemFormatKey > ExtItemFormatKeySet;
1370         ::std::set< ExtItemFormatKey > aItemKeys;
1371         ExtItemFormat aItemFmt;
1372         OUStringVector aRemain = aItemFmt.parse( rName );
1373         for( OUStringVector::iterator aIt = aRemain.begin(), aEnd = aRemain.end(); aIt != aEnd; ++aIt )
1374         {
1375             OUStringPair aPair = StringHelper::convertStringToPair( *aIt );
1376             if( aPair.first.equalsAscii( "noshift" ) )
1377             {
1378                 aItemFmt.mbShiftValue = StringHelper::convertStringToBool( aPair.second );
1379             }
1380             else if( aPair.first.equalsAscii( "filter" ) )
1381             {
1382                 OUStringPair aFilter = StringHelper::convertStringToPair( aPair.second, '~' );
1383                 ExtItemFormatKey aKey( nKey );
1384                 if( (aFilter.first.getLength() > 0) && StringHelper::convertStringToInt( aKey.maFilter.first, aFilter.first ) &&
1385                     (aFilter.second.getLength() > 0) && StringHelper::convertStringToInt( aKey.maFilter.second, aFilter.second ) )
1386                 {
1387                     if( aKey.maFilter.first == 0 )
1388                         aKey.maFilter.second = 0;
1389                     aItemKeys.insert( aKey );
1390                 }
1391             }
1392         }
1393         if( aItemKeys.empty() )
1394             aItemKeys.insert( ExtItemFormatKey( nKey ) );
1395         for( ExtItemFormatKeySet::iterator aIt = aItemKeys.begin(), aEnd = aItemKeys.end(); aIt != aEnd; ++aIt )
1396             maFmtMap[ *aIt ] = aItemFmt;
1397     }
1398     else
1399     {
1400         FlagsList::implSetName( nKey, rName );
1401     }
1402 }
1403 
1404 OUString CombiList::implGetName( const Config& rCfg, sal_Int64 nKey ) const
1405 {
1406     sal_Int64 nFound = 0;
1407     OUStringBuffer aName;
1408     // add known flag fields
1409     for( ExtItemFormatMap::const_iterator aIt = maFmtMap.begin(), aEnd = maFmtMap.end(); aIt != aEnd; ++aIt )
1410     {
1411         const ExtItemFormatKey& rMapKey = aIt->first;
1412         sal_Int64 nMask = rMapKey.mnKey;
1413         if( (nMask != 0) && ((nKey & rMapKey.maFilter.first) == rMapKey.maFilter.second) )
1414         {
1415             const ExtItemFormat& rItemFmt = aIt->second;
1416 
1417             sal_uInt64 nUFlags = static_cast< sal_uInt64 >( nKey );
1418             sal_uInt64 nUMask = static_cast< sal_uInt64 >( nMask );
1419             if( rItemFmt.mbShiftValue )
1420                 while( (nUMask & 1) == 0 ) { nUFlags >>= 1; nUMask >>= 1; }
1421 
1422             sal_uInt64 nUValue = nUFlags & nUMask;
1423             sal_Int64 nSValue = static_cast< sal_Int64 >( nUValue );
1424             if( getFlag< sal_uInt64 >( nUValue, (nUMask + 1) >> 1 ) )
1425                 setFlag( nSValue, static_cast< sal_Int64 >( ~nUMask ) );
1426 
1427             OUStringBuffer aItem( rItemFmt.maItemName );
1428             OUStringBuffer aValue;
1429             switch( rItemFmt.meDataType )
1430             {
1431                 case DATATYPE_INT8:     StringHelper::appendValue( aValue, static_cast< sal_Int8 >( nSValue ), rItemFmt.meFmtType );    break;
1432                 case DATATYPE_UINT8:    StringHelper::appendValue( aValue, static_cast< sal_uInt8 >( nUValue ), rItemFmt.meFmtType );   break;
1433                 case DATATYPE_INT16:    StringHelper::appendValue( aValue, static_cast< sal_Int16 >( nSValue ), rItemFmt.meFmtType );   break;
1434                 case DATATYPE_UINT16:   StringHelper::appendValue( aValue, static_cast< sal_uInt16 >( nUValue ), rItemFmt.meFmtType );  break;
1435                 case DATATYPE_INT32:    StringHelper::appendValue( aValue, static_cast< sal_Int32 >( nSValue ), rItemFmt.meFmtType );   break;
1436                 case DATATYPE_UINT32:   StringHelper::appendValue( aValue, static_cast< sal_uInt32 >( nUValue ), rItemFmt.meFmtType );  break;
1437                 case DATATYPE_INT64:    StringHelper::appendValue( aValue, nSValue, rItemFmt.meFmtType );                               break;
1438                 case DATATYPE_UINT64:   StringHelper::appendValue( aValue, nUValue, rItemFmt.meFmtType );                               break;
1439                 case DATATYPE_FLOAT:    StringHelper::appendValue( aValue, static_cast< float >( nSValue ), rItemFmt.meFmtType );       break;
1440                 case DATATYPE_DOUBLE:   StringHelper::appendValue( aValue, static_cast< double >( nSValue ), rItemFmt.meFmtType );      break;
1441                 default:;
1442             }
1443             StringHelper::appendToken( aItem, aValue.makeStringAndClear(), OOX_DUMP_ITEMSEP );
1444             if( rItemFmt.maListName.getLength() > 0 )
1445             {
1446                 OUString aValueName = rCfg.getName( rItemFmt.maListName, static_cast< sal_Int64 >( nUValue ) );
1447                 StringHelper::appendToken( aItem, aValueName, OOX_DUMP_ITEMSEP );
1448             }
1449             StringHelper::enclose( aItem, '(', ')' );
1450             StringHelper::appendToken( aName, aItem.makeStringAndClear() );
1451             setFlag( nFound, nMask );
1452         }
1453     }
1454     setFlag( nKey, nFound, false );
1455     StringHelper::appendToken( aName, FlagsList::implGetName( rCfg, nKey ) );
1456     return aName.makeStringAndClear();
1457 }
1458 
1459 void CombiList::implIncludeList( const NameListBase& rList )
1460 {
1461     if( const CombiList* pCombiList = dynamic_cast< const CombiList* >( &rList ) )
1462         maFmtMap = pCombiList->maFmtMap;
1463     FlagsList::implIncludeList( rList );
1464 }
1465 
1466 // ============================================================================
1467 
1468 UnitConverter::UnitConverter( const SharedConfigData& rCfgData ) :
1469     NameListBase( rCfgData ),
1470     mfFactor( 1.0 )
1471 {
1472 }
1473 
1474 void UnitConverter::implSetName( sal_Int64 /*nKey*/, const OUString& /*rName*/ )
1475 {
1476     // nothing to do
1477 }
1478 
1479 OUString UnitConverter::implGetName( const Config& rCfg, sal_Int64 nKey ) const
1480 {
1481     return implGetNameDbl( rCfg, static_cast< double >( nKey ) );
1482 }
1483 
1484 OUString UnitConverter::implGetNameDbl( const Config& /*rCfg*/, double fValue ) const
1485 {
1486     OUStringBuffer aValue;
1487     StringHelper::appendDec( aValue, mfFactor * fValue );
1488     aValue.append( maUnitName );
1489     return aValue.makeStringAndClear();
1490 }
1491 
1492 void UnitConverter::implIncludeList( const NameListBase& /*rList*/ )
1493 {
1494 }
1495 
1496 // ============================================================================
1497 
1498 NameListRef NameListWrapper::getNameList( const Config& rCfg ) const
1499 {
1500     return mxList.get() ? mxList : (mxList = rCfg.getNameList( maName ));
1501 }
1502 
1503 // ============================================================================
1504 // ============================================================================
1505 
1506 SharedConfigData::SharedConfigData( const OUString& rFileName,
1507         const Reference< XComponentContext >& rxContext, const StorageRef& rxRootStrg,
1508         const OUString& rSysFileName, MediaDescriptor& rMediaDesc ) :
1509     mxContext( rxContext ),
1510     mxRootStrg( rxRootStrg ),
1511     maSysFileName( rSysFileName ),
1512     mrMediaDesc( rMediaDesc ),
1513     mbLoaded( false ),
1514     mbPwCancelled( false )
1515 {
1516     OUString aFileUrl = InputOutputHelper::convertFileNameToUrl( rFileName );
1517     if( aFileUrl.getLength() > 0 )
1518     {
1519         sal_Int32 nNamePos = InputOutputHelper::getFileNamePos( aFileUrl );
1520         maConfigPath = aFileUrl.copy( 0, nNamePos );
1521         mbLoaded = readConfigFile( aFileUrl );
1522     }
1523 }
1524 
1525 SharedConfigData::~SharedConfigData()
1526 {
1527 }
1528 
1529 void SharedConfigData::setOption( const OUString& rKey, const OUString& rData )
1530 {
1531     maConfigData[ rKey ] = rData;
1532 }
1533 
1534 const OUString* SharedConfigData::getOption( const OUString& rKey ) const
1535 {
1536     ConfigDataMap::const_iterator aIt = maConfigData.find( rKey );
1537     return (aIt == maConfigData.end()) ? 0 : &aIt->second;
1538 }
1539 
1540 void SharedConfigData::setNameList( const OUString& rListName, const NameListRef& rxList )
1541 {
1542     if( rListName.getLength() > 0 )
1543         maNameLists[ rListName ] = rxList;
1544 }
1545 
1546 void SharedConfigData::eraseNameList( const OUString& rListName )
1547 {
1548     maNameLists.erase( rListName );
1549 }
1550 
1551 NameListRef SharedConfigData::getNameList( const OUString& rListName ) const
1552 {
1553     NameListRef xList;
1554     NameListMap::const_iterator aIt = maNameLists.find( rListName );
1555     if( aIt != maNameLists.end() )
1556         xList = aIt->second;
1557     return xList;
1558 }
1559 
1560 Sequence< NamedValue > SharedConfigData::requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier )
1561 {
1562     Sequence< NamedValue > aEncryptionData;
1563     if( !mbPwCancelled )
1564     {
1565         ::std::vector< OUString > aDefaultPasswords;
1566         aDefaultPasswords.push_back( CREATE_OUSTRING( "VelvetSweatshop" ) );
1567         aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
1568             rVerifier, mrMediaDesc, ::comphelper::DocPasswordRequestType_MS, &aDefaultPasswords );
1569         mbPwCancelled = !aEncryptionData.hasElements();
1570     }
1571     return aEncryptionData;
1572 }
1573 
1574 bool SharedConfigData::implIsValid() const
1575 {
1576     return mbLoaded && mxContext.is() && mxRootStrg.get() && (maSysFileName.getLength() > 0);
1577 }
1578 
1579 void SharedConfigData::implProcessConfigItemStr(
1580         TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
1581 {
1582     if( rKey.equalsAscii( "include-config-file" ) )
1583         readConfigFile( maConfigPath + rData );
1584     else if( rKey.equalsAscii( "constlist" ) )
1585         readNameList< ConstList >( rStrm, rData );
1586     else if( rKey.equalsAscii( "multilist" ) )
1587         readNameList< MultiList >( rStrm, rData );
1588     else if( rKey.equalsAscii( "flagslist" ) )
1589         readNameList< FlagsList >( rStrm, rData );
1590     else if( rKey.equalsAscii( "combilist" ) )
1591         readNameList< CombiList >( rStrm, rData );
1592     else if( rKey.equalsAscii( "shortlist" ) )
1593         createShortList( rData );
1594     else if( rKey.equalsAscii( "unitconverter" ) )
1595         createUnitConverter( rData );
1596     else
1597         setOption( rKey, rData );
1598 }
1599 
1600 bool SharedConfigData::readConfigFile( const OUString& rFileUrl )
1601 {
1602     bool bLoaded = maConfigFiles.count( rFileUrl ) > 0;
1603     if( !bLoaded )
1604     {
1605         Reference< XInputStream > xInStrm = InputOutputHelper::openInputStream( mxContext, rFileUrl );
1606         TextInputStream aTxtStrm( mxContext, xInStrm, RTL_TEXTENCODING_UTF8 );
1607         if( !aTxtStrm.isEof() )
1608         {
1609             maConfigFiles.insert( rFileUrl );
1610             readConfigBlockContents( aTxtStrm );
1611             bLoaded = true;
1612         }
1613     }
1614     return bLoaded;
1615 }
1616 
1617 void SharedConfigData::createShortList( const OUString& rData )
1618 {
1619     OUStringVector aDataVec;
1620     StringHelper::convertStringToStringList( aDataVec, rData, false );
1621     if( aDataVec.size() >= 3 )
1622     {
1623         sal_Int64 nStartKey;
1624         if( StringHelper::convertStringToInt( nStartKey, aDataVec[ 1 ] ) )
1625         {
1626             ::boost::shared_ptr< MultiList > xList = createNameList< MultiList >( aDataVec[ 0 ] );
1627             if( xList.get() )
1628             {
1629                 aDataVec.erase( aDataVec.begin(), aDataVec.begin() + 2 );
1630                 xList->setNamesFromVec( nStartKey, aDataVec );
1631             }
1632         }
1633     }
1634 }
1635 
1636 void SharedConfigData::createUnitConverter( const OUString& rData )
1637 {
1638     OUStringVector aDataVec;
1639     StringHelper::convertStringToStringList( aDataVec, rData, false );
1640     if( aDataVec.size() >= 2 )
1641     {
1642         OUString aFactor = aDataVec[ 1 ];
1643         bool bRecip = (aFactor.getLength() > 0) && (aFactor[ 0 ] == '/');
1644         if( bRecip )
1645             aFactor = aFactor.copy( 1 );
1646         double fFactor;
1647         if( StringHelper::convertStringToDouble( fFactor, aFactor ) && (fFactor != 0.0) )
1648         {
1649             ::boost::shared_ptr< UnitConverter > xList = createNameList< UnitConverter >( aDataVec[ 0 ] );
1650             if( xList.get() )
1651             {
1652                 xList->setFactor( bRecip ? (1.0 / fFactor) : fFactor );
1653                 if( aDataVec.size() >= 3 )
1654                     xList->setUnitName( aDataVec[ 2 ] );
1655             }
1656         }
1657     }
1658 }
1659 
1660 // ============================================================================
1661 
1662 Config::Config( const Config& rParent ) :
1663     Base()  // c'tor needs to be called explicitly to avoid compiler warning
1664 {
1665     construct( rParent );
1666 }
1667 
1668 Config::Config( const sal_Char* pcEnvVar, const FilterBase& rFilter )
1669 {
1670     construct( pcEnvVar, rFilter );
1671 }
1672 
1673 Config::Config( const sal_Char* pcEnvVar, const Reference< XComponentContext >& rxContext, const StorageRef& rxRootStrg, const OUString& rSysFileName, MediaDescriptor& rMediaDesc )
1674 {
1675     construct( pcEnvVar, rxContext, rxRootStrg, rSysFileName, rMediaDesc );
1676 }
1677 
1678 Config::~Config()
1679 {
1680 }
1681 
1682 void Config::construct( const Config& rParent )
1683 {
1684     *this = rParent;
1685 }
1686 
1687 void Config::construct( const sal_Char* pcEnvVar, const FilterBase& rFilter )
1688 {
1689     if( rFilter.getFileUrl().getLength() > 0 )
1690         construct( pcEnvVar, rFilter.getComponentContext(), rFilter.getStorage(), rFilter.getFileUrl(), rFilter.getMediaDescriptor() );
1691 }
1692 
1693 void Config::construct( const sal_Char* pcEnvVar, const Reference< XComponentContext >& rxContext, const StorageRef& rxRootStrg, const OUString& rSysFileName, MediaDescriptor& rMediaDesc )
1694 {
1695     if( pcEnvVar && rxRootStrg.get() && (rSysFileName.getLength() > 0) )
1696         if( const sal_Char* pcFileName = ::getenv( pcEnvVar ) )
1697             mxCfgData.reset( new SharedConfigData( OUString::createFromAscii( pcFileName ), rxContext, rxRootStrg, rSysFileName, rMediaDesc ) );
1698 }
1699 
1700 void Config::setStringOption( const String& rKey, const String& rData )
1701 {
1702     mxCfgData->setOption( rKey, rData );
1703 }
1704 
1705 const OUString& Config::getStringOption( const String& rKey, const OUString& rDefault ) const
1706 {
1707     const OUString* pData = implGetOption( rKey );
1708     return pData ? *pData : rDefault;
1709 }
1710 
1711 bool Config::getBoolOption( const String& rKey, bool bDefault ) const
1712 {
1713     const OUString* pData = implGetOption( rKey );
1714     return pData ? StringHelper::convertStringToBool( *pData ) : bDefault;
1715 }
1716 
1717 bool Config::isDumperEnabled() const
1718 {
1719     return getBoolOption( "enable-dumper", false );
1720 }
1721 
1722 bool Config::isImportEnabled() const
1723 {
1724     return getBoolOption( "enable-import", true );
1725 }
1726 
1727 void Config::setNameList( const String& rListName, const NameListRef& rxList )
1728 {
1729     mxCfgData->setNameList( rListName, rxList );
1730 }
1731 
1732 void Config::eraseNameList( const String& rListName )
1733 {
1734     mxCfgData->eraseNameList( rListName );
1735 }
1736 
1737 NameListRef Config::getNameList( const String& rListName ) const
1738 {
1739     return implGetNameList( rListName );
1740 }
1741 
1742 Sequence< NamedValue > Config::requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier )
1743 {
1744     return mxCfgData->requestEncryptionData( rVerifier );
1745 }
1746 
1747 bool Config::isPasswordCancelled() const
1748 {
1749     return mxCfgData->isPasswordCancelled();
1750 }
1751 
1752 bool Config::implIsValid() const
1753 {
1754     return isValid( mxCfgData );
1755 }
1756 
1757 const OUString* Config::implGetOption( const OUString& rKey ) const
1758 {
1759     return mxCfgData->getOption( rKey );
1760 }
1761 
1762 NameListRef Config::implGetNameList( const OUString& rListName ) const
1763 {
1764     return mxCfgData->getNameList( rListName );
1765 }
1766 
1767 // ============================================================================
1768 // ============================================================================
1769 
1770 Output::Output( const Reference< XComponentContext >& rxContext, const OUString& rFileName ) :
1771     mxStrm( InputOutputHelper::openTextOutputStream( rxContext, rFileName, RTL_TEXTENCODING_UTF8 ) ),
1772     mnCol( 0 ),
1773     mnItemLevel( 0 ),
1774     mnMultiLevel( 0 ),
1775     mnItemIdx( 0 ),
1776     mnLastItem( 0 )
1777 {
1778     if( mxStrm.is() )
1779         mxStrm->writeString( OUString( OOX_DUMP_BOM ) );
1780 }
1781 
1782 // ----------------------------------------------------------------------------
1783 
1784 void Output::newLine()
1785 {
1786     if( maLine.getLength() > 0 )
1787     {
1788         mxStrm->writeString( maIndent );
1789         maLine.append( sal_Unicode( '\n' ) );
1790         mxStrm->writeString( maLine.makeStringAndClear() );
1791         mnCol = 0;
1792         mnLastItem = 0;
1793     }
1794 }
1795 
1796 void Output::emptyLine( size_t nCount )
1797 {
1798     for( size_t nIdx = 0; nIdx < nCount; ++nIdx )
1799         mxStrm->writeString( OUString( sal_Unicode( '\n' ) ) );
1800 }
1801 
1802 void Output::incIndent()
1803 {
1804     OUStringBuffer aBuffer( maIndent );
1805     StringHelper::appendChar( aBuffer, ' ', OOX_DUMP_INDENT );
1806     maIndent = aBuffer.makeStringAndClear();
1807 }
1808 
1809 void Output::decIndent()
1810 {
1811     if( maIndent.getLength() >= OOX_DUMP_INDENT )
1812         maIndent = maIndent.copy( OOX_DUMP_INDENT );
1813 }
1814 
1815 void Output::resetIndent()
1816 {
1817     maIndent = OUString();
1818 }
1819 
1820 void Output::startTable( sal_Int32 nW1 )
1821 {
1822     startTable( 1, &nW1 );
1823 }
1824 
1825 void Output::startTable( sal_Int32 nW1, sal_Int32 nW2 )
1826 {
1827     sal_Int32 pnColWidths[ 2 ];
1828     pnColWidths[ 0 ] = nW1;
1829     pnColWidths[ 1 ] = nW2;
1830     startTable( 2, pnColWidths );
1831 }
1832 
1833 void Output::startTable( sal_Int32 nW1, sal_Int32 nW2, sal_Int32 nW3 )
1834 {
1835     sal_Int32 pnColWidths[ 3 ];
1836     pnColWidths[ 0 ] = nW1;
1837     pnColWidths[ 1 ] = nW2;
1838     pnColWidths[ 2 ] = nW3;
1839     startTable( 3, pnColWidths );
1840 }
1841 
1842 void Output::startTable( sal_Int32 nW1, sal_Int32 nW2, sal_Int32 nW3, sal_Int32 nW4 )
1843 {
1844     sal_Int32 pnColWidths[ 4 ];
1845     pnColWidths[ 0 ] = nW1;
1846     pnColWidths[ 1 ] = nW2;
1847     pnColWidths[ 2 ] = nW3;
1848     pnColWidths[ 3 ] = nW4;
1849     startTable( 4, pnColWidths );
1850 }
1851 
1852 void Output::startTable( size_t nColCount, const sal_Int32* pnColWidths )
1853 {
1854     maColPos.clear();
1855     maColPos.push_back( 0 );
1856     sal_Int32 nColPos = 0;
1857     for( size_t nCol = 0; nCol < nColCount; ++nCol )
1858     {
1859         nColPos = nColPos + pnColWidths[ nCol ];
1860         maColPos.push_back( nColPos );
1861     }
1862 }
1863 
1864 void Output::tab()
1865 {
1866     tab( mnCol + 1 );
1867 }
1868 
1869 void Output::tab( size_t nCol )
1870 {
1871     mnCol = nCol;
1872     if( mnCol < maColPos.size() )
1873     {
1874         sal_Int32 nColPos = maColPos[ mnCol ];
1875         if( maLine.getLength() >= nColPos )
1876             maLine.setLength( ::std::max< sal_Int32 >( nColPos - 1, 0 ) );
1877         StringHelper::appendChar( maLine, ' ', nColPos - maLine.getLength() );
1878     }
1879     else
1880     {
1881         StringHelper::appendChar( maLine, ' ', 2 );
1882     }
1883 }
1884 
1885 void Output::endTable()
1886 {
1887     maColPos.clear();
1888 }
1889 
1890 void Output::resetItemIndex( sal_Int64 nIdx )
1891 {
1892     mnItemIdx = nIdx;
1893 }
1894 
1895 void Output::startItem( const String& rItemName )
1896 {
1897     if( mnItemLevel == 0 )
1898     {
1899         if( (mnMultiLevel > 0) && (maLine.getLength() > 0) )
1900             tab();
1901         if( rItemName.has() )
1902         {
1903             writeItemName( rItemName );
1904             writeChar( OOX_DUMP_ITEMSEP );
1905         }
1906     }
1907     ++mnItemLevel;
1908     mnLastItem = maLine.getLength();
1909 }
1910 
1911 void Output::contItem()
1912 {
1913     if( mnItemLevel > 0 )
1914     {
1915         if( (maLine.getLength() == 0) || (maLine[ maLine.getLength() - 1 ] != OOX_DUMP_ITEMSEP) )
1916             writeChar( OOX_DUMP_ITEMSEP );
1917         mnLastItem = maLine.getLength();
1918     }
1919 }
1920 
1921 void Output::endItem()
1922 {
1923     if( mnItemLevel > 0 )
1924     {
1925         maLastItem = OUString( maLine.getStr() + mnLastItem );
1926         if( (maLastItem.getLength() == 0) && (mnLastItem > 0) && (maLine[ mnLastItem - 1 ] == OOX_DUMP_ITEMSEP) )
1927             maLine.setLength( mnLastItem - 1 );
1928         --mnItemLevel;
1929     }
1930     if( mnItemLevel == 0 )
1931     {
1932         if( mnMultiLevel == 0 )
1933             newLine();
1934     }
1935     else
1936         contItem();
1937 }
1938 
1939 void Output::startMultiItems()
1940 {
1941     ++mnMultiLevel;
1942 }
1943 
1944 void Output::endMultiItems()
1945 {
1946     if( mnMultiLevel > 0 )
1947         --mnMultiLevel;
1948     if( mnMultiLevel == 0 )
1949         newLine();
1950 }
1951 
1952 // ----------------------------------------------------------------------------
1953 
1954 void Output::writeChar( sal_Unicode cChar, sal_Int32 nCount )
1955 {
1956     StringHelper::appendEncChar( maLine, cChar, nCount );
1957 }
1958 
1959 void Output::writeAscii( const sal_Char* pcStr )
1960 {
1961     if( pcStr )
1962         maLine.appendAscii( pcStr );
1963 }
1964 
1965 void Output::writeString( const OUString& rStr )
1966 {
1967     StringHelper::appendEncString( maLine, rStr );
1968 }
1969 
1970 void Output::writeArray( const sal_uInt8* pnData, sal_Size nSize, sal_Unicode cSep )
1971 {
1972     const sal_uInt8* pnEnd = pnData ? (pnData + nSize) : 0;
1973     for( const sal_uInt8* pnByte = pnData; pnByte < pnEnd; ++pnByte )
1974     {
1975         if( pnByte > pnData )
1976             writeChar( cSep );
1977         writeHex( *pnByte, false );
1978     }
1979 }
1980 
1981 void Output::writeBool( bool bData )
1982 {
1983     StringHelper::appendBool( maLine, bData );
1984 }
1985 
1986 void Output::writeColorABGR( sal_Int32 nColor )
1987 {
1988     writeChar( 'a' );
1989     writeDec( static_cast< sal_uInt8 >( nColor >> 24 ) );
1990     writeAscii( ",r" );
1991     writeDec( static_cast< sal_uInt8 >( nColor ) );
1992     writeAscii( ",g" );
1993     writeDec( static_cast< sal_uInt8 >( nColor >> 8 ) );
1994     writeAscii( ",b" );
1995     writeDec( static_cast< sal_uInt8 >( nColor >> 16 ) );
1996 }
1997 
1998 void Output::writeDateTime( const DateTime& rDateTime )
1999 {
2000     writeDec( rDateTime.Year, 4, '0' );
2001     writeChar( '-' );
2002     writeDec( rDateTime.Month, 2, '0' );
2003     writeChar( '-' );
2004     writeDec( rDateTime.Day, 2, '0' );
2005     writeChar( 'T' );
2006     writeDec( rDateTime.Hours, 2, '0' );
2007     writeChar( ':' );
2008     writeDec( rDateTime.Minutes, 2, '0' );
2009     writeChar( ':' );
2010     writeDec( rDateTime.Seconds, 2, '0' );
2011 }
2012 
2013 void Output::writeColIndex( sal_Int32 nCol )
2014 {
2015     StringHelper::appendAddrCol( maLine, nCol, true );
2016 }
2017 
2018 void Output::writeRowIndex( sal_Int32 nRow )
2019 {
2020     StringHelper::appendAddrRow( maLine, nRow, true );
2021 }
2022 
2023 void Output::writeColRowRange( sal_Int32 nColRow1, sal_Int32 nColRow2 )
2024 {
2025     writeDec( nColRow1 );
2026     writeChar( OOX_DUMP_RANGESEP );
2027     writeDec( nColRow2 );
2028 }
2029 
2030 void Output::writeColRange( sal_Int32 nCol1, sal_Int32 nCol2 )
2031 {
2032     writeColIndex( nCol1 );
2033     writeChar( OOX_DUMP_RANGESEP );
2034     writeColIndex( nCol2 );
2035 }
2036 
2037 void Output::writeRowRange( sal_Int32 nRow1, sal_Int32 nRow2 )
2038 {
2039     writeRowIndex( nRow1 );
2040     writeChar( OOX_DUMP_RANGESEP );
2041     writeRowIndex( nRow2 );
2042 }
2043 
2044 void Output::writeAddress( const Address& rPos )
2045 {
2046     StringHelper::appendAddress( maLine, rPos );
2047 }
2048 
2049 void Output::writeRange( const Range& rRange )
2050 {
2051     StringHelper::appendRange( maLine, rRange );
2052 }
2053 
2054 void Output::writeRangeList( const RangeList& rRanges )
2055 {
2056     StringHelper::appendRangeList( maLine, rRanges );
2057 }
2058 
2059 // ----------------------------------------------------------------------------
2060 
2061 bool Output::implIsValid() const
2062 {
2063     return mxStrm.is();
2064 }
2065 
2066 void Output::writeItemName( const String& rItemName )
2067 {
2068     if( rItemName.has() && (rItemName[ 0 ] == '#') )
2069     {
2070         writeString( rItemName.copy( 1 ) );
2071         StringHelper::appendIndex( maLine, mnItemIdx++ );
2072     }
2073     else
2074         writeString( rItemName );
2075 }
2076 
2077 // ============================================================================
2078 
2079 StorageIterator::StorageIterator( const StorageRef& rxStrg ) :
2080     mxStrg( rxStrg )
2081 {
2082     if( mxStrg.get() )
2083         mxStrg->getElementNames( maNames );
2084     maIt = maNames.begin();
2085 }
2086 
2087 StorageIterator::~StorageIterator()
2088 {
2089 }
2090 
2091 size_t StorageIterator::getElementCount() const
2092 {
2093     return maNames.size();
2094 }
2095 
2096 StorageIterator& StorageIterator::operator++()
2097 {
2098     if( maIt != maNames.end() )
2099         ++maIt;
2100     return *this;
2101 }
2102 
2103 OUString StorageIterator::getName() const
2104 {
2105     OUString aName;
2106     if( maIt != maNames.end() )
2107         aName = *maIt;
2108     return aName;
2109 }
2110 
2111 bool StorageIterator::isStream() const
2112 {
2113     return isValid() && mxStrg->openInputStream( *maIt ).is();
2114 }
2115 
2116 bool StorageIterator::isStorage() const
2117 {
2118     if( !isValid() )
2119         return false;
2120     StorageRef xStrg = mxStrg->openSubStorage( *maIt, false );
2121     return xStrg.get() && xStrg->isStorage();
2122 }
2123 
2124 bool StorageIterator::implIsValid() const
2125 {
2126     return mxStrg.get() && mxStrg->isStorage() && (maIt != maNames.end());
2127 }
2128 
2129 // ============================================================================
2130 // ============================================================================
2131 
2132 ObjectBase::~ObjectBase()
2133 {
2134 }
2135 
2136 void ObjectBase::construct( const ConfigRef& rxConfig )
2137 {
2138     mxConfig = rxConfig;
2139 }
2140 
2141 void ObjectBase::construct( const ObjectBase& rParent )
2142 {
2143     *this = rParent;
2144 }
2145 
2146 void ObjectBase::dump()
2147 {
2148     if( isValid() )
2149         implDump();
2150 }
2151 
2152 bool ObjectBase::implIsValid() const
2153 {
2154     return isValid( mxConfig );
2155 }
2156 
2157 void ObjectBase::implDump()
2158 {
2159 }
2160 
2161 void ObjectBase::reconstructConfig( const ConfigRef& rxConfig )
2162 {
2163     if( isValid( rxConfig ) )
2164         mxConfig = rxConfig;
2165 }
2166 
2167 // ============================================================================
2168 // ============================================================================
2169 
2170 void StorageObjectBase::construct( const ObjectBase& rParent, const StorageRef& rxStrg, const OUString& rSysPath )
2171 {
2172     ObjectBase::construct( rParent );
2173     mxStrg = rxStrg;
2174     maSysPath = rSysPath;
2175 }
2176 
2177 void StorageObjectBase::construct( const ObjectBase& rParent )
2178 {
2179     ObjectBase::construct( rParent );
2180     if( ObjectBase::implIsValid() )
2181     {
2182         mxStrg = cfg().getRootStorage();
2183         maSysPath = cfg().getSysFileName();
2184     }
2185 }
2186 
2187 bool StorageObjectBase::implIsValid() const
2188 {
2189     return mxStrg.get() && (maSysPath.getLength() > 0) && ObjectBase::implIsValid();
2190 }
2191 
2192 void StorageObjectBase::implDump()
2193 {
2194     bool bIsStrg = mxStrg->isStorage();
2195     bool bIsRoot = mxStrg->isRootStorage();
2196     Reference< XInputStream > xBaseStrm;
2197     if( !bIsStrg )
2198         xBaseStrm = mxStrg->openInputStream( OUString() );
2199 
2200     OUString aSysOutPath = maSysPath;
2201     if( bIsRoot ) try
2202     {
2203         aSysOutPath += OOX_DUMP_DUMPEXT;
2204         Reference< XMultiServiceFactory > xFactory( getContext()->getServiceManager(), UNO_QUERY_THROW );
2205         Reference< XSimpleFileAccess > xFileAccess( xFactory->createInstance( CREATE_OUSTRING( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY_THROW );
2206         xFileAccess->kill( aSysOutPath );
2207     }
2208     catch( Exception& )
2209     {
2210     }
2211 
2212     if( bIsStrg )
2213     {
2214         extractStorage( mxStrg, OUString(), aSysOutPath );
2215     }
2216     else if( xBaseStrm.is() )
2217     {
2218         BinaryInputStreamRef xInStrm( new BinaryXInputStream( xBaseStrm, false ) );
2219         xInStrm->seekToStart();
2220         implDumpBaseStream( xInStrm, aSysOutPath );
2221     }
2222 }
2223 
2224 void StorageObjectBase::implDumpStream( const Reference< XInputStream >&, const OUString&, const OUString&, const OUString& )
2225 {
2226 }
2227 
2228 void StorageObjectBase::implDumpStorage( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rSysPath )
2229 {
2230     extractStorage( rxStrg, rStrgPath, rSysPath );
2231 }
2232 
2233 void StorageObjectBase::implDumpBaseStream( const BinaryInputStreamRef&, const OUString& )
2234 {
2235 }
2236 
2237 void StorageObjectBase::addPreferredStream( const String& rStrmName )
2238 {
2239     if( rStrmName.has() )
2240         maPreferred.push_back( PreferredItem( rStrmName, false ) );
2241 }
2242 
2243 void StorageObjectBase::addPreferredStorage( const String& rStrgPath )
2244 {
2245     if( rStrgPath.has() )
2246         maPreferred.push_back( PreferredItem( rStrgPath, true ) );
2247 }
2248 
2249 OUString StorageObjectBase::getSysFileName( const OUString& rStrmName, const OUString& rSysOutPath )
2250 {
2251     // encode all characters < 0x20
2252     OUStringBuffer aBuffer;
2253     StringHelper::appendEncString( aBuffer, rStrmName, false );
2254 
2255     // replace all characters reserved in file system
2256     OUString aFileName = aBuffer.makeStringAndClear();
2257     static const sal_Unicode spcReserved[] = { '/', '\\', ':', '*', '?', '<', '>', '|' };
2258     for( const sal_Unicode* pcChar = spcReserved; pcChar < STATIC_ARRAY_END( spcReserved ); ++pcChar )
2259         aFileName = aFileName.replace( *pcChar, '_' );
2260 
2261     // build full path
2262     return rSysOutPath + OUString( sal_Unicode( '/' ) ) + aFileName;
2263 }
2264 
2265 void StorageObjectBase::extractStream( StorageBase& rStrg, const OUString& rStrgPath, const OUString& rStrmName, const OUString& rSysFileName )
2266 {
2267     BinaryXInputStream aInStrm( rStrg.openInputStream( rStrmName ), true );
2268     if( !aInStrm.isEof() )
2269     {
2270         BinaryXOutputStream aOutStrm( InputOutputHelper::openOutputStream( getContext(), rSysFileName ), true );
2271         if( !aOutStrm.isEof() )
2272             aInStrm.copyToStream( aOutStrm );
2273     }
2274     Reference< XInputStream > xDumpStrm = InputOutputHelper::openInputStream( getContext(), rSysFileName );
2275     if( xDumpStrm.is() )
2276         implDumpStream( xDumpStrm, rStrgPath, rStrmName, rSysFileName );
2277 }
2278 
2279 void StorageObjectBase::extractStorage( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rSysPath )
2280 {
2281     // create directory in file system
2282     ::osl::FileBase::RC eRes = ::osl::Directory::create( rSysPath );
2283     if( (eRes != ::osl::FileBase::E_None) && (eRes != ::osl::FileBase::E_EXIST) )
2284         return;
2285 
2286     // process preferred storages and streams in root storage first
2287     if( rStrgPath.getLength() == 0 )
2288         for( PreferredItemVector::iterator aIt = maPreferred.begin(), aEnd = maPreferred.end(); aIt != aEnd; ++aIt )
2289             extractItem( rxStrg, rStrgPath, aIt->maName, rSysPath, aIt->mbStorage, !aIt->mbStorage );
2290 
2291     // process children of the storage
2292     for( StorageIterator aIt( rxStrg ); aIt.isValid(); ++aIt )
2293     {
2294         // skip processed preferred items
2295         OUString aItemName = aIt.getName();
2296         bool bFound = false;
2297         if( rStrgPath.getLength() == 0 )
2298             for( PreferredItemVector::iterator aIIt = maPreferred.begin(), aIEnd = maPreferred.end(); !bFound && (aIIt != aIEnd); ++aIIt )
2299                 bFound = aIIt->maName == aItemName;
2300         if( !bFound )
2301             extractItem( rxStrg, rStrgPath, aItemName, rSysPath, aIt.isStorage(), aIt.isStream() );
2302     }
2303 }
2304 
2305 void StorageObjectBase::extractItem( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rItemName, const OUString& rSysPath, bool bIsStrg, bool bIsStrm )
2306 {
2307     OUString aSysFileName = getSysFileName( rItemName, rSysPath );
2308     if( bIsStrg )
2309     {
2310         OUStringBuffer aStrgPath( rStrgPath );
2311         StringHelper::appendToken( aStrgPath, rItemName, '/' );
2312         implDumpStorage( rxStrg->openSubStorage( rItemName, false ), aStrgPath.makeStringAndClear(), aSysFileName );
2313     }
2314     else if( bIsStrm )
2315     {
2316         extractStream( *rxStrg, rStrgPath, rItemName, aSysFileName );
2317     }
2318 }
2319 
2320 // ============================================================================
2321 // ============================================================================
2322 
2323 OutputObjectBase::~OutputObjectBase()
2324 {
2325 }
2326 
2327 void OutputObjectBase::construct( const ObjectBase& rParent, const OUString& rSysFileName )
2328 {
2329     ObjectBase::construct( rParent );
2330     if( ObjectBase::implIsValid() )
2331     {
2332         maSysFileName = rSysFileName;
2333         mxOut.reset( new Output( getContext(), rSysFileName + OOX_DUMP_DUMPEXT ) );
2334     }
2335 }
2336 
2337 void OutputObjectBase::construct( const OutputObjectBase& rParent )
2338 {
2339     *this = rParent;
2340 }
2341 
2342 bool OutputObjectBase::implIsValid() const
2343 {
2344     return isValid( mxOut ) && ObjectBase::implIsValid();
2345 }
2346 
2347 void OutputObjectBase::writeEmptyItem( const String& rName )
2348 {
2349     ItemGuard aItem( mxOut, rName );
2350 }
2351 
2352 void OutputObjectBase::writeInfoItem( const String& rName, const String& rData )
2353 {
2354     ItemGuard aItem( mxOut, rName );
2355     mxOut->writeString( rData );
2356 }
2357 
2358 void OutputObjectBase::writeCharItem( const String& rName, sal_Unicode cData )
2359 {
2360     ItemGuard aItem( mxOut, rName );
2361     mxOut->writeChar( OOX_DUMP_STRQUOTE );
2362     mxOut->writeChar( cData );
2363     mxOut->writeChar( OOX_DUMP_STRQUOTE );
2364 }
2365 
2366 void OutputObjectBase::writeStringItem( const String& rName, const OUString& rData )
2367 {
2368     ItemGuard aItem( mxOut, rName );
2369     mxOut->writeAscii( "(len=" );
2370     mxOut->writeDec( rData.getLength() );
2371     mxOut->writeAscii( ")," );
2372     OUStringBuffer aValue( rData.copy( 0, ::std::min( rData.getLength(), OOX_DUMP_MAXSTRLEN ) ) );
2373     StringHelper::enclose( aValue, OOX_DUMP_STRQUOTE );
2374     mxOut->writeString( aValue.makeStringAndClear() );
2375     if( rData.getLength() > OOX_DUMP_MAXSTRLEN )
2376         mxOut->writeAscii( ",cut" );
2377 }
2378 
2379 void OutputObjectBase::writeArrayItem( const String& rName, const sal_uInt8* pnData, sal_Size nSize, sal_Unicode cSep )
2380 {
2381     ItemGuard aItem( mxOut, rName );
2382     mxOut->writeArray( pnData, nSize, cSep );
2383 }
2384 
2385 void OutputObjectBase::writeBoolItem( const String& rName, bool bData )
2386 {
2387     ItemGuard aItem( mxOut, rName );
2388     mxOut->writeBool( bData );
2389 }
2390 
2391 double OutputObjectBase::writeRkItem( const String& rName, sal_Int32 nRk )
2392 {
2393     MultiItemsGuard aMultiGuard( mxOut );
2394     writeHexItem( rName, static_cast< sal_uInt32 >( nRk ), "RK-FLAGS" );
2395     double fValue = ::oox::xls::BiffHelper::calcDoubleFromRk( nRk );
2396     writeDecItem( "decoded", fValue );
2397     return fValue;
2398 }
2399 
2400 void OutputObjectBase::writeColorABGRItem( const String& rName, sal_Int32 nColor )
2401 {
2402     ItemGuard aItem( mxOut, rName );
2403     writeHexItem( rName, nColor );
2404     mxOut->writeColorABGR( nColor );
2405 }
2406 
2407 void OutputObjectBase::writeDateTimeItem( const String& rName, const DateTime& rDateTime )
2408 {
2409     ItemGuard aItem( mxOut, rName );
2410     mxOut->writeDateTime( rDateTime );
2411 }
2412 
2413 void OutputObjectBase::writeGuidItem( const String& rName, const OUString& rGuid )
2414 {
2415     ItemGuard aItem( mxOut, rName );
2416     mxOut->writeString( rGuid );
2417     aItem.cont();
2418     mxOut->writeString( cfg().getStringOption( rGuid, OUString() ) );
2419 }
2420 
2421 void OutputObjectBase::writeColIndexItem( const String& rName, sal_Int32 nCol )
2422 {
2423     ItemGuard aItem( mxOut, rName );
2424     mxOut->writeDec( nCol );
2425     aItem.cont();
2426     mxOut->writeColIndex( nCol );
2427 }
2428 
2429 void OutputObjectBase::writeRowIndexItem( const String& rName, sal_Int32 nRow )
2430 {
2431     ItemGuard aItem( mxOut, rName );
2432     mxOut->writeDec( nRow );
2433     aItem.cont();
2434     mxOut->writeRowIndex( nRow );
2435 }
2436 
2437 void OutputObjectBase::writeColRangeItem( const String& rName, sal_Int32 nCol1, sal_Int32 nCol2 )
2438 {
2439     ItemGuard aItem( mxOut, rName );
2440     mxOut->writeColRowRange( nCol1, nCol2 );
2441     aItem.cont();
2442     mxOut->writeColRange( nCol1, nCol2 );
2443 }
2444 
2445 void OutputObjectBase::writeRowRangeItem( const String& rName, sal_Int32 nRow1, sal_Int32 nRow2 )
2446 {
2447     ItemGuard aItem( mxOut, rName );
2448     mxOut->writeColRowRange( nRow1, nRow2 );
2449     aItem.cont();
2450     mxOut->writeRowRange( nRow1, nRow2 );
2451 }
2452 
2453 void OutputObjectBase::writeAddressItem( const String& rName, const Address& rPos )
2454 {
2455     ItemGuard aItem( mxOut, rName );
2456     StringHelper::appendAddress( mxOut->getLine(), rPos );
2457 }
2458 
2459 void OutputObjectBase::writeRangeItem( const String& rName, const Range& rRange )
2460 {
2461     ItemGuard aItem( mxOut, rName );
2462     StringHelper::appendRange( mxOut->getLine(), rRange );
2463 }
2464 
2465 void OutputObjectBase::writeRangeListItem( const String& rName, const RangeList& rRanges )
2466 {
2467     MultiItemsGuard aMultiGuard( mxOut );
2468     writeEmptyItem( rName );
2469     writeDecItem( "count", static_cast< sal_uInt16 >( rRanges.size() ) );
2470     ItemGuard aItem( mxOut, "ranges" );
2471     StringHelper::appendRangeList( mxOut->getLine(), rRanges );
2472 }
2473 
2474 void OutputObjectBase::writeTokenAddressItem( const String& rName, const TokenAddress& rPos, bool bNameMode )
2475 {
2476     ItemGuard aItem( mxOut, rName );
2477     StringHelper::appendAddress( mxOut->getLine(), rPos, bNameMode );
2478 }
2479 
2480 void OutputObjectBase::writeTokenAddress3dItem( const String& rName, const OUString& rRef, const TokenAddress& rPos, bool bNameMode )
2481 {
2482     ItemGuard aItem( mxOut, rName );
2483     mxOut->writeString( rRef );
2484     StringHelper::appendAddress( mxOut->getLine(), rPos, bNameMode );
2485 }
2486 
2487 void OutputObjectBase::writeTokenRangeItem( const String& rName, const TokenRange& rRange, bool bNameMode )
2488 {
2489     ItemGuard aItem( mxOut, rName );
2490     StringHelper::appendRange( mxOut->getLine(), rRange, bNameMode );
2491 }
2492 
2493 void OutputObjectBase::writeTokenRange3dItem( const String& rName, const OUString& rRef, const TokenRange& rRange, bool bNameMode )
2494 {
2495     ItemGuard aItem( mxOut, rName );
2496     mxOut->writeString( rRef );
2497     StringHelper::appendRange( mxOut->getLine(), rRange, bNameMode );
2498 }
2499 
2500 // ============================================================================
2501 // ============================================================================
2502 
2503 InputObjectBase::~InputObjectBase()
2504 {
2505 }
2506 
2507 void InputObjectBase::construct( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName )
2508 {
2509     OutputObjectBase::construct( rParent, rSysFileName );
2510     mxStrm = rxStrm;
2511 }
2512 
2513 void InputObjectBase::construct( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxStrm )
2514 {
2515     OutputObjectBase::construct( rParent );
2516     mxStrm = rxStrm;
2517 }
2518 
2519 void InputObjectBase::construct( const InputObjectBase& rParent )
2520 {
2521     *this = rParent;
2522 }
2523 
2524 bool InputObjectBase::implIsValid() const
2525 {
2526     return mxStrm.get() && OutputObjectBase::implIsValid();
2527 }
2528 
2529 void InputObjectBase::skipBlock( sal_Int64 nBytes, bool bShowSize )
2530 {
2531     sal_Int64 nEndPos = ::std::min< sal_Int64 >( mxStrm->tell() + nBytes, mxStrm->size() );
2532     if( mxStrm->tell() < nEndPos )
2533     {
2534         if( bShowSize )
2535             writeDecItem( "skipped-data-size", static_cast< sal_uInt64 >( nEndPos - mxStrm->tell() ) );
2536         mxStrm->seek( nEndPos );
2537     }
2538 }
2539 
2540 void InputObjectBase::dumpRawBinary( sal_Int64 nBytes, bool bShowOffset, bool bStream )
2541 {
2542     TableGuard aTabGuard( mxOut,
2543         bShowOffset ? 12 : 0,
2544         3 * OOX_DUMP_BYTESPERLINE / 2 + 1,
2545         3 * OOX_DUMP_BYTESPERLINE / 2 + 1,
2546         OOX_DUMP_BYTESPERLINE / 2 + 1 );
2547 
2548     sal_Int64 nMaxShowSize = cfg().getIntOption< sal_Int64 >(
2549         bStream ? "max-binary-stream-size" : "max-binary-data-size", SAL_MAX_INT64 );
2550 
2551     bool bSeekable = mxStrm->size() >= 0;
2552     sal_Int64 nEndPos = bSeekable ? ::std::min< sal_Int64 >( mxStrm->tell() + nBytes, mxStrm->size() ) : 0;
2553     sal_Int64 nDumpEnd = bSeekable ? ::std::min< sal_Int64 >( mxStrm->tell() + nMaxShowSize, nEndPos ) : nMaxShowSize;
2554     sal_Int64 nPos = bSeekable ? mxStrm->tell() : 0;
2555     bool bLoop = true;
2556 
2557     while( bLoop && (nPos < nDumpEnd) )
2558     {
2559         mxOut->writeHex( static_cast< sal_uInt32 >( nPos ) );
2560         mxOut->tab();
2561 
2562         sal_uInt8 pnLineData[ OOX_DUMP_BYTESPERLINE ];
2563         sal_Int32 nLineSize = bSeekable ? ::std::min( static_cast< sal_Int32 >( nDumpEnd - mxStrm->tell() ), OOX_DUMP_BYTESPERLINE ) : OOX_DUMP_BYTESPERLINE;
2564         sal_Int32 nReadSize = mxStrm->readMemory( pnLineData, nLineSize );
2565         bLoop = nReadSize == nLineSize;
2566         nPos += nReadSize;
2567 
2568         if( nReadSize > 0 )
2569         {
2570             const sal_uInt8* pnByte = 0;
2571             const sal_uInt8* pnEnd = 0;
2572             for( pnByte = pnLineData, pnEnd = pnLineData + nReadSize; pnByte != pnEnd; ++pnByte )
2573             {
2574                 if( (pnByte - pnLineData) == (OOX_DUMP_BYTESPERLINE / 2) ) mxOut->tab();
2575                 mxOut->writeHex( *pnByte, false );
2576                 mxOut->writeChar( ' ' );
2577             }
2578 
2579             aTabGuard.tab( 3 );
2580             for( pnByte = pnLineData, pnEnd = pnLineData + nReadSize; pnByte != pnEnd; ++pnByte )
2581             {
2582                 if( (pnByte - pnLineData) == (OOX_DUMP_BYTESPERLINE / 2) ) mxOut->tab();
2583                 mxOut->writeChar( static_cast< sal_Unicode >( (*pnByte < 0x20) ? '.' : *pnByte ) );
2584             }
2585             mxOut->newLine();
2586         }
2587     }
2588 
2589     // skip undumped data
2590     if( bSeekable )
2591         skipBlock( nEndPos - mxStrm->tell() );
2592 }
2593 
2594 void InputObjectBase::dumpBinary( const String& rName, sal_Int64 nBytes, bool bShowOffset )
2595 {
2596     {
2597         MultiItemsGuard aMultiGuard( mxOut );
2598         writeEmptyItem( rName );
2599         writeDecItem( "size", nBytes );
2600     }
2601     IndentGuard aIndGuard( mxOut );
2602     dumpRawBinary( nBytes, bShowOffset );
2603 }
2604 
2605 void InputObjectBase::dumpRemaining( sal_Int64 nBytes )
2606 {
2607     if( nBytes > 0 )
2608     {
2609         if( cfg().getBoolOption( "show-trailing-unknown", true ) )
2610             dumpBinary( "remaining-data", nBytes, false );
2611         else
2612             skipBlock( nBytes );
2613     }
2614 }
2615 
2616 void InputObjectBase::dumpRemainingTo( sal_Int64 nPos )
2617 {
2618     if( mxStrm->isEof() || (mxStrm->tell() > nPos) )
2619         writeInfoItem( "stream-state", OOX_DUMP_ERR_STREAM );
2620     else
2621         dumpRemaining( nPos - mxStrm->tell() );
2622     mxStrm->seek( nPos );
2623 }
2624 
2625 void InputObjectBase::dumpRemainingStream()
2626 {
2627     dumpRemainingTo( mxStrm->size() );
2628 }
2629 
2630 void InputObjectBase::dumpArray( const String& rName, sal_Int32 nBytes, sal_Unicode cSep )
2631 {
2632     sal_Int32 nDumpSize = getLimitedValue< sal_Int32, sal_Int64 >( mxStrm->size() - mxStrm->tell(), 0, nBytes );
2633     if( nDumpSize > OOX_DUMP_MAXARRAY )
2634     {
2635         dumpBinary( rName, nBytes, false );
2636     }
2637     else if( nDumpSize > 1 )
2638     {
2639         sal_uInt8 pnData[ OOX_DUMP_MAXARRAY ];
2640         mxStrm->readMemory( pnData, nDumpSize );
2641         writeArrayItem( rName, pnData, nDumpSize, cSep );
2642     }
2643     else if( nDumpSize == 1 )
2644         dumpHex< sal_uInt8 >( rName );
2645 }
2646 
2647 sal_Unicode InputObjectBase::dumpChar( const String& rName, rtl_TextEncoding eTextEnc )
2648 {
2649     sal_uInt8 nChar;
2650     *mxStrm >> nChar;
2651     OUString aChar = OStringToOUString( OString( static_cast< sal_Char >( nChar ) ), eTextEnc );
2652     sal_Unicode cChar = (aChar.getLength() > 0) ? aChar[ 0 ] : 0;
2653     writeCharItem( rName( "char" ), cChar );
2654     return cChar;
2655 }
2656 
2657 sal_Unicode InputObjectBase::dumpUnicode( const String& rName )
2658 {
2659     sal_uInt16 nChar;
2660     *mxStrm >> nChar;
2661     sal_Unicode cChar = static_cast< sal_Unicode >( nChar );
2662     writeCharItem( rName( "char" ), cChar );
2663     return cChar;
2664 }
2665 
2666 OUString InputObjectBase::dumpCharArray( const String& rName, sal_Int32 nLen, rtl_TextEncoding eTextEnc, bool bHideTrailingNul )
2667 {
2668     sal_Int32 nDumpSize = getLimitedValue< sal_Int32, sal_Int64 >( mxStrm->size() - mxStrm->tell(), 0, nLen );
2669     OUString aString;
2670     if( nDumpSize > 0 )
2671     {
2672         ::std::vector< sal_Char > aBuffer( static_cast< sal_Size >( nLen ) + 1 );
2673         sal_Int32 nCharsRead = mxStrm->readMemory( &aBuffer.front(), nLen );
2674         aBuffer[ nCharsRead ] = 0;
2675         aString = OStringToOUString( OString( &aBuffer.front() ), eTextEnc );
2676     }
2677     if( bHideTrailingNul )
2678         aString = StringHelper::trimTrailingNul( aString );
2679     writeStringItem( rName( "text" ), aString );
2680     return aString;
2681 }
2682 
2683 OUString InputObjectBase::dumpUnicodeArray( const String& rName, sal_Int32 nLen, bool bHideTrailingNul )
2684 {
2685     OUStringBuffer aBuffer;
2686     for( sal_Int32 nIndex = 0; !mxStrm->isEof() && (nIndex < nLen); ++nIndex )
2687         aBuffer.append( static_cast< sal_Unicode >( mxStrm->readuInt16() ) );
2688     OUString aString = aBuffer.makeStringAndClear();
2689     if( bHideTrailingNul )
2690         aString = StringHelper::trimTrailingNul( aString );
2691     writeStringItem( rName( "text" ), aString );
2692     return aString;
2693 }
2694 
2695 OUString InputObjectBase::dumpNullCharArray( const String& rName, rtl_TextEncoding eTextEnc )
2696 {
2697     OStringBuffer aBuffer;
2698     sal_uInt8 nChar;
2699     for( *mxStrm >> nChar; !mxStrm->isEof() && (nChar > 0); *mxStrm >> nChar )
2700         aBuffer.append( static_cast< sal_Char >( nChar ) );
2701     OUString aString = OStringToOUString( aBuffer.makeStringAndClear(), eTextEnc );
2702     writeStringItem( rName( "text" ), aString );
2703     return aString;
2704 }
2705 
2706 OUString InputObjectBase::dumpNullUnicodeArray( const String& rName )
2707 {
2708     OUStringBuffer aBuffer;
2709     sal_uInt16 nChar;
2710     for( *mxStrm >> nChar; !mxStrm->isEof() && (nChar > 0); *mxStrm >> nChar )
2711         aBuffer.append( static_cast< sal_Unicode >( nChar ) );
2712     OUString aString = aBuffer.makeStringAndClear();
2713     writeStringItem( rName( "text" ), aString );
2714     return aString;
2715 }
2716 
2717 double InputObjectBase::dumpRk( const String& rName )
2718 {
2719     sal_Int32 nRk;
2720     *mxStrm >> nRk;
2721     return writeRkItem( rName( "rk-value" ), nRk );
2722 }
2723 
2724 sal_Int32 InputObjectBase::dumpColorABGR( const String& rName )
2725 {
2726     sal_Int32 nColor;
2727     *mxStrm >> nColor;
2728     writeColorABGRItem( rName( "color" ), nColor );
2729     return nColor;
2730 }
2731 
2732 DateTime InputObjectBase::dumpFileTime( const String& rName )
2733 {
2734     DateTime aDateTime;
2735 
2736     ItemGuard aItem( mxOut, rName( "file-time" ) );
2737     sal_Int64 nFileTime = dumpDec< sal_Int64 >( EMPTY_STRING );
2738     // file time is in 10^-7 seconds (100 nanoseconds), convert to 1/100 seconds
2739     nFileTime /= 100000;
2740     // entire days
2741     sal_Int64 nDays = nFileTime / sal_Int64( 360000 * 24 );
2742     // number of entire years
2743     sal_Int64 nYears = (nDays - (nDays / (4 * 365)) + (nDays / (100 * 365)) - (nDays / (400 * 365))) / 365;
2744     // remaining days in the year
2745     sal_Int64 nDaysInYear = nDays - (nYears * 365 + nYears / 4 - nYears / 100 + nYears / 400);
2746     // the year (file dates start from 1601-01-01)
2747     aDateTime.Year = static_cast< sal_uInt16 >( 1601 + nYears );
2748     // leap year?
2749     bool bLeap = ((aDateTime.Year % 4 == 0) && (aDateTime.Year % 100 != 0)) || (aDateTime.Year % 400 == 0);
2750     // static arrays with number of days in month
2751     static const sal_Int64 spnDaysInMonth[]  = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
2752     static const sal_Int64 spnDaysInMonthL[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
2753     const sal_Int64* pnDaysInMonth = bLeap ? spnDaysInMonthL : spnDaysInMonth;
2754     // the month
2755     aDateTime.Month = 1;
2756     while( nDaysInYear >= *pnDaysInMonth )
2757     {
2758         nDaysInYear -= *pnDaysInMonth++;
2759         ++aDateTime.Month;
2760     }
2761     // the day
2762     aDateTime.Day = static_cast< sal_uInt16 >( nDaysInYear + 1 );
2763     // number of 1/100 seconds in the day
2764     sal_Int64 nTimeInDay = nFileTime % sal_Int64( 360000 * 24 );
2765     // 1/100 seconds
2766     aDateTime.HundredthSeconds = static_cast< sal_uInt16 >( nTimeInDay % 100 );
2767     nTimeInDay /= 100;
2768     // seconds
2769     aDateTime.Seconds = static_cast< sal_uInt16 >( nTimeInDay % 60 );
2770     nTimeInDay /= 60;
2771     // minutes
2772     aDateTime.Minutes = static_cast< sal_uInt16 >( nTimeInDay % 60 );
2773     nTimeInDay /= 60;
2774     // hours
2775     aDateTime.Hours = static_cast< sal_uInt16 >( nTimeInDay );
2776 
2777     writeDateTimeItem( EMPTY_STRING, aDateTime );
2778     return aDateTime;
2779 }
2780 
2781 OUString InputObjectBase::dumpGuid( const String& rName )
2782 {
2783     OUStringBuffer aBuffer;
2784     sal_uInt32 nData32;
2785     sal_uInt16 nData16;
2786     sal_uInt8 nData8;
2787 
2788     *mxStrm >> nData32;
2789     StringHelper::appendHex( aBuffer, nData32, false );
2790     aBuffer.append( sal_Unicode( '-' ) );
2791     *mxStrm >> nData16;
2792     StringHelper::appendHex( aBuffer, nData16, false );
2793     aBuffer.append( sal_Unicode( '-' ) );
2794     *mxStrm >> nData16;
2795     StringHelper::appendHex( aBuffer, nData16, false );
2796     aBuffer.append( sal_Unicode( '-' ) );
2797     *mxStrm >> nData8;
2798     StringHelper::appendHex( aBuffer, nData8, false );
2799     *mxStrm >> nData8;
2800     StringHelper::appendHex( aBuffer, nData8, false );
2801     aBuffer.append( sal_Unicode( '-' ) );
2802     for( int nIndex = 0; nIndex < 6; ++nIndex )
2803     {
2804         *mxStrm >> nData8;
2805         StringHelper::appendHex( aBuffer, nData8, false );
2806     }
2807     StringHelper::enclose( aBuffer, '{', '}' );
2808     OUString aGuid = aBuffer.makeStringAndClear();
2809     writeGuidItem( rName( "guid" ), aGuid );
2810     return aGuid;
2811 }
2812 
2813 void InputObjectBase::dumpItem( const ItemFormat& rItemFmt )
2814 {
2815     switch( rItemFmt.meDataType )
2816     {
2817         case DATATYPE_VOID:                                         break;
2818         case DATATYPE_INT8:    dumpValue< sal_Int8 >( rItemFmt );   break;
2819         case DATATYPE_UINT8:   dumpValue< sal_uInt8 >( rItemFmt );  break;
2820         case DATATYPE_INT16:   dumpValue< sal_Int16 >( rItemFmt );  break;
2821         case DATATYPE_UINT16:  dumpValue< sal_uInt16 >( rItemFmt ); break;
2822         case DATATYPE_INT32:   dumpValue< sal_Int32 >( rItemFmt );  break;
2823         case DATATYPE_UINT32:  dumpValue< sal_uInt32 >( rItemFmt ); break;
2824         case DATATYPE_INT64:   dumpValue< sal_Int64 >( rItemFmt );  break;
2825         case DATATYPE_UINT64:  dumpValue< sal_uInt64 >( rItemFmt ); break;
2826         case DATATYPE_FLOAT:   dumpValue< float >( rItemFmt );      break;
2827         case DATATYPE_DOUBLE:  dumpValue< double >( rItemFmt );     break;
2828         default:;
2829     }
2830 }
2831 
2832 // ============================================================================
2833 // ============================================================================
2834 
2835 BinaryStreamObject::BinaryStreamObject( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName )
2836 {
2837     InputObjectBase::construct( rParent, rxStrm, rSysFileName );
2838 }
2839 
2840 BinaryStreamObject::BinaryStreamObject( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxStrm )
2841 {
2842     InputObjectBase::construct( rParent, rxStrm );
2843 }
2844 
2845 void BinaryStreamObject::dumpBinaryStream( bool bShowOffset )
2846 {
2847     mxStrm->seekToStart();
2848     dumpRawBinary( mxStrm->size(), bShowOffset, true );
2849     mxOut->emptyLine();
2850 }
2851 
2852 void BinaryStreamObject::implDump()
2853 {
2854     dumpBinaryStream();
2855 }
2856 
2857 // ============================================================================
2858 // ============================================================================
2859 
2860 void TextStreamObjectBase::construct( const ObjectBase& rParent,
2861         const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc, const OUString& rSysFileName )
2862 {
2863     InputObjectBase::construct( rParent, rxStrm, rSysFileName );
2864     constructTextStrmObj( eTextEnc );
2865 }
2866 
2867 void TextStreamObjectBase::construct( const OutputObjectBase& rParent,
2868         const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc )
2869 {
2870     InputObjectBase::construct( rParent, rxStrm );
2871     constructTextStrmObj( eTextEnc );
2872 }
2873 
2874 void TextStreamObjectBase::construct( const InputObjectBase& rParent, rtl_TextEncoding eTextEnc )
2875 {
2876     InputObjectBase::construct( rParent );
2877     constructTextStrmObj( eTextEnc );
2878 }
2879 
2880 bool TextStreamObjectBase::implIsValid() const
2881 {
2882     return InputObjectBase::implIsValid() && mxTextStrm.get();
2883 }
2884 
2885 void TextStreamObjectBase::implDump()
2886 {
2887     implDumpText( *mxTextStrm );
2888 }
2889 
2890 void TextStreamObjectBase::constructTextStrmObj( rtl_TextEncoding eTextEnc )
2891 {
2892     if( mxStrm.get() )
2893         mxTextStrm.reset( new TextInputStream( getContext(), *mxStrm, eTextEnc ) );
2894 }
2895 
2896 // ============================================================================
2897 
2898 TextLineStreamObject::TextLineStreamObject( const ObjectBase& rParent,
2899         const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc, const OUString& rSysFileName )
2900 {
2901     TextStreamObjectBase::construct( rParent, rxStrm, eTextEnc, rSysFileName );
2902 }
2903 
2904 TextLineStreamObject::TextLineStreamObject( const OutputObjectBase& rParent,
2905         const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc )
2906 {
2907     TextStreamObjectBase::construct( rParent, rxStrm, eTextEnc );
2908 }
2909 
2910 void TextLineStreamObject::implDumpText( TextInputStream& rTextStrm )
2911 {
2912     sal_uInt32 nLine = 0;
2913     while( !rTextStrm.isEof() )
2914     {
2915         OUString aLine = rTextStrm.readLine();
2916         if( !rTextStrm.isEof() || (aLine.getLength() > 0) )
2917             implDumpLine( aLine, ++nLine );
2918     }
2919 }
2920 
2921 void TextLineStreamObject::implDumpLine( const OUString& rLine, sal_uInt32 nLine )
2922 {
2923     TableGuard aTabGuard( mxOut, 8 );
2924     mxOut->writeDec( nLine, 6 );
2925     mxOut->tab();
2926     mxOut->writeString( rLine );
2927     mxOut->newLine();
2928 }
2929 
2930 // ============================================================================
2931 
2932 XmlStreamObject::XmlStreamObject( const ObjectBase& rParent,
2933         const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName )
2934 {
2935     TextStreamObjectBase::construct( rParent, rxStrm, RTL_TEXTENCODING_UTF8, rSysFileName );
2936 }
2937 
2938 XmlStreamObject::XmlStreamObject( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxStrm )
2939 {
2940     TextStreamObjectBase::construct( rParent, rxStrm, RTL_TEXTENCODING_UTF8 );
2941 }
2942 
2943 void XmlStreamObject::implDumpText( TextInputStream& rTextStrm )
2944 {
2945     /*  Buffers a start element and the following element text. Needed to dump
2946         matching start/end elements and the element text on the same line. */
2947     OUStringBuffer aOldStartElem;
2948     // special handling for VML
2949     bool bIsVml = InputOutputHelper::getFileNameExtension( maSysFileName ).equalsIgnoreAsciiCaseAscii( "vml" );
2950 
2951     while( !rTextStrm.isEof() )
2952     {
2953         // get the next element and the following element text from text stream
2954         OUString aElem = rTextStrm.readToChar( '>', true ).trim();
2955         OUString aText = rTextStrm.readToChar( '<', false );
2956 
2957         // remove multiple whitespace from element
2958         sal_Int32 nPos = 0;
2959         while( nPos < aElem.getLength() )
2960         {
2961             while( (nPos < aElem.getLength()) && (aElem[ nPos ] >= 32) ) ++nPos;
2962             if( nPos < aElem.getLength() )
2963                 aElem = OUStringBuffer( aElem.copy( 0, nPos ) ).append( sal_Unicode( ' ' ) ).append( aElem.copy( nPos ).trim() ).makeStringAndClear();
2964             ++nPos;
2965         }
2966 
2967         sal_Int32 nElemLen = aElem.getLength();
2968         if( (nElemLen >= 2) && (aElem[ 0 ] == '<') && (aElem[ nElemLen - 1 ] == '>') )
2969         {
2970             // determine type of the element
2971             bool bSimpleElem = (aElem[ 1 ] == '!') || (aElem[ 1 ] == '?') || (aElem[ nElemLen - 2 ] == '/') ||
2972                 (bIsVml && (nElemLen == 4) && (aElem[ 1 ] == 'b') && (aElem[ 2 ] == 'r'));
2973             bool bStartElem = !bSimpleElem && (aElem[ 1 ] != '/');
2974             bool bEndElem = !bSimpleElem && !bStartElem;
2975 
2976             /*  Start element or simple element: flush old start element and
2977                 its text from previous iteration, and start a new indentation
2978                 level for the new element. Trim whitespace and line breaks from
2979                 the text of the old start element. */
2980             if( (bSimpleElem || bStartElem) && (aOldStartElem.getLength() > 0) )
2981             {
2982                 mxOut->writeString( aOldStartElem.makeStringAndClear().trim() );
2983                 mxOut->newLine();
2984                 mxOut->incIndent();
2985             }
2986 
2987             /*  Start element: remember it and its text, to be able to print the
2988                 matching end element on the same line in the next iteration. */
2989             if( bStartElem )
2990             {
2991                 aOldStartElem.append( aElem ).append( aText );
2992             }
2993             else
2994             {
2995                 /*  End element: if a start element has been remembered in the
2996                     previous iteration, write it out here untrimmed, to show
2997                     all whitespace in the element text, and without trailing
2998                     line break. Code below will add the end element right after
2999                     it. Otherwise, return to previous indentation level. */
3000                 if( bEndElem )
3001                 {
3002                     if( aOldStartElem.getLength() == 0 )
3003                         mxOut->decIndent();
3004                     else
3005                         mxOut->writeString( aOldStartElem.makeStringAndClear() );
3006                 }
3007 
3008                 /*  Write the element. Write following element text in a new
3009                     line, but only, if it does not contain of white space
3010                     entirely. */
3011                 mxOut->writeString( aElem );
3012                 mxOut->newLine();
3013                 if( aText.trim().getLength() > 0 )
3014                 {
3015                     mxOut->writeString( aText );
3016                     mxOut->newLine();
3017                 }
3018             }
3019         }
3020     }
3021 }
3022 
3023 // ============================================================================
3024 // ============================================================================
3025 
3026 void RecordObjectBase::construct( const ObjectBase& rParent,
3027         const BinaryInputStreamRef& rxBaseStrm, const OUString& rSysFileName,
3028         const BinaryInputStreamRef& rxRecStrm, const String& rRecNames, const String& rSimpleRecs )
3029 {
3030     InputObjectBase::construct( rParent, rxRecStrm, rSysFileName );
3031     constructRecObjBase( rxBaseStrm, rRecNames, rSimpleRecs );
3032 }
3033 
3034 void RecordObjectBase::construct( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxBaseStrm,
3035         const BinaryInputStreamRef& rxRecStrm, const String& rRecNames, const String& rSimpleRecs )
3036 {
3037     InputObjectBase::construct( rParent, rxRecStrm );
3038     constructRecObjBase( rxBaseStrm, rRecNames, rSimpleRecs );
3039 }
3040 
3041 bool RecordObjectBase::implIsValid() const
3042 {
3043     return mxBaseStrm.get() && InputObjectBase::implIsValid();
3044 }
3045 
3046 void RecordObjectBase::implDump()
3047 {
3048     NameListRef xRecNames = getRecNames();
3049     ItemFormatMap aSimpleRecs( maSimpleRecs.getNameList( cfg() ) );
3050 
3051     while( implStartRecord( *mxBaseStrm, mnRecPos, mnRecId, mnRecSize ) )
3052     {
3053         // record header
3054         mxOut->emptyLine();
3055         writeHeader();
3056         implWriteExtHeader();
3057         IndentGuard aIndGuard( mxOut );
3058         sal_Int64 nRecPos = mxStrm->tell();
3059 
3060         // record body
3061         if( !mbBinaryOnly && cfg().hasName( xRecNames, mnRecId ) )
3062         {
3063             ItemFormatMap::const_iterator aIt = aSimpleRecs.find( mnRecId );
3064             if( aIt != aSimpleRecs.end() )
3065                 dumpItem( aIt->second );
3066             else
3067                 implDumpRecordBody();
3068         }
3069 
3070         // remaining undumped data
3071         if( !mxStrm->isEof() && (mxStrm->tell() == nRecPos) )
3072             dumpRawBinary( mnRecSize, false );
3073         else
3074             dumpRemainingTo( nRecPos + mnRecSize );
3075     }
3076 }
3077 
3078 void RecordObjectBase::implWriteExtHeader()
3079 {
3080 }
3081 
3082 void RecordObjectBase::implDumpRecordBody()
3083 {
3084 }
3085 
3086 void RecordObjectBase::constructRecObjBase( const BinaryInputStreamRef& rxBaseStrm, const String& rRecNames, const String& rSimpleRecs )
3087 {
3088     mxBaseStrm = rxBaseStrm;
3089     maRecNames = rRecNames;
3090     maSimpleRecs = rSimpleRecs;
3091     mnRecPos = mnRecId = mnRecSize = 0;
3092     mbBinaryOnly = false;
3093     if( InputObjectBase::implIsValid() )
3094         mbShowRecPos = cfg().getBoolOption( "show-record-position", true );
3095 }
3096 
3097 void RecordObjectBase::writeHeader()
3098 {
3099     MultiItemsGuard aMultiGuard( mxOut );
3100     writeEmptyItem( "REC" );
3101     if( mbShowRecPos && mxBaseStrm->isSeekable() )
3102         writeShortHexItem( "pos", mnRecPos, "CONV-DEC" );
3103     writeShortHexItem( "size", mnRecSize, "CONV-DEC" );
3104     ItemGuard aItem( mxOut, "id" );
3105     mxOut->writeShortHex( mnRecId );
3106     addNameToItem( mnRecId, "CONV-DEC" );
3107     addNameToItem( mnRecId, maRecNames );
3108 }
3109 
3110 // ============================================================================
3111 
3112 void SequenceRecordObjectBase::construct( const ObjectBase& rParent,
3113         const BinaryInputStreamRef& rxBaseStrm, const ::rtl::OUString& rSysFileName,
3114         const String& rRecNames, const String& rSimpleRecs )
3115 {
3116     BinaryInputStreamRef xRecStrm( new SequenceInputStream( *mxRecData ) );
3117     RecordObjectBase::construct( rParent, rxBaseStrm, rSysFileName, xRecStrm, rRecNames, rSimpleRecs );
3118 }
3119 
3120 void SequenceRecordObjectBase::construct( const OutputObjectBase& rParent,
3121         const BinaryInputStreamRef& rxBaseStrm, const String& rRecNames, const String& rSimpleRecs )
3122 {
3123     BinaryInputStreamRef xRecStrm( new SequenceInputStream( *mxRecData ) );
3124     RecordObjectBase::construct( rParent, rxBaseStrm, xRecStrm, rRecNames, rSimpleRecs );
3125 }
3126 
3127 bool SequenceRecordObjectBase::implStartRecord( BinaryInputStream& rBaseStrm, sal_Int64& ornRecPos, sal_Int64& ornRecId, sal_Int64& ornRecSize )
3128 {
3129     bool bValid = true;
3130     if( rBaseStrm.isSeekable() )
3131     {
3132         ornRecPos = rBaseStrm.tell();
3133         // do not try to overread seekable streams, may cause assertions
3134         bValid = ornRecPos < rBaseStrm.size();
3135     }
3136 
3137     // read the record header
3138     if( bValid )
3139         bValid = implReadRecordHeader( rBaseStrm, ornRecId, ornRecSize ) && !rBaseStrm.isEof() && (0 <= ornRecSize) && (ornRecSize <= 0x00100000);
3140 
3141     // read record contents into data sequence
3142     if( bValid )
3143     {
3144         sal_Int32 nRecSize = static_cast< sal_Int32 >( ornRecSize );
3145         mxRecData->realloc( nRecSize );
3146         bValid = (nRecSize == 0) || (rBaseStrm.readData( *mxRecData, nRecSize ) == nRecSize);
3147         mxStrm->seekToStart();
3148     }
3149     return bValid;
3150 }
3151 
3152 // ============================================================================
3153 // ============================================================================
3154 
3155 DumperBase::~DumperBase()
3156 {
3157 }
3158 
3159 bool DumperBase::isImportEnabled() const
3160 {
3161     return !isValid() || cfg().isImportEnabled();
3162 }
3163 
3164 bool DumperBase::isImportCancelled() const
3165 {
3166     return isValid() && cfg().isPasswordCancelled();
3167 }
3168 
3169 void DumperBase::construct( const ConfigRef& rxConfig )
3170 {
3171     if( isValid( rxConfig ) && rxConfig->isDumperEnabled() )
3172         ObjectBase::construct( rxConfig );
3173 }
3174 
3175 // ============================================================================
3176 // ============================================================================
3177 
3178 } // namespace dump
3179 } // namespace oox
3180 
3181 #endif
3182