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