xref: /aoo4110/main/oox/source/dump/dumperbase.cxx (revision b1cdbd2c)
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 
convertFileNameToUrl(const OUString & rFileName)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 
getFileNamePos(const OUString & rFileUrl)93 sal_Int32 InputOutputHelper::getFileNamePos( const OUString& rFileUrl )
94 {
95     sal_Int32 nSepPos = rFileUrl.lastIndexOf( '/' );
96     return (nSepPos < 0) ? 0 : (nSepPos + 1);
97 }
98 
getFileNameExtension(const OUString & rFileUrl)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 
openInputStream(const Reference<XComponentContext> & rxContext,const OUString & rFileName)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 
openOutputStream(const Reference<XComponentContext> & rxContext,const OUString & rFileName)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 
openTextOutputStream(const Reference<XComponentContext> & rxContext,const Reference<XOutputStream> & rxOutStrm,rtl_TextEncoding eTextEnc)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 
openTextOutputStream(const Reference<XComponentContext> & rxContext,const OUString & rFileName,rtl_TextEncoding eTextEnc)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 
ItemFormat()172 ItemFormat::ItemFormat() :
173     meDataType( DATATYPE_VOID ),
174     meFmtType( FORMATTYPE_NONE )
175 {
176 }
177 
set(DataType eDataType,FormatType eFmtType,const OUString & rItemName)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 
set(DataType eDataType,FormatType eFmtType,const OUString & rItemName,const OUString & rListName)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 
parse(const OUStringVector & rFormatVec)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 
parse(const OUString & rFormatStr)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 
appendChar(OUStringBuffer & rStr,sal_Unicode cChar,sal_Int32 nCount)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 
appendString(OUStringBuffer & rStr,const OUString & rData,sal_Int32 nWidth,sal_Unicode cFill)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 
appendDec(OUStringBuffer & rStr,sal_uInt8 nData,sal_Int32 nWidth,sal_Unicode cFill)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 
appendDec(OUStringBuffer & rStr,sal_Int8 nData,sal_Int32 nWidth,sal_Unicode cFill)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 
appendDec(OUStringBuffer & rStr,sal_uInt16 nData,sal_Int32 nWidth,sal_Unicode cFill)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 
appendDec(OUStringBuffer & rStr,sal_Int16 nData,sal_Int32 nWidth,sal_Unicode cFill)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 
appendDec(OUStringBuffer & rStr,sal_uInt32 nData,sal_Int32 nWidth,sal_Unicode cFill)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 
appendDec(OUStringBuffer & rStr,sal_Int32 nData,sal_Int32 nWidth,sal_Unicode cFill)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 
appendDec(OUStringBuffer & rStr,sal_uInt64 nData,sal_Int32 nWidth,sal_Unicode cFill)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 
appendDec(OUStringBuffer & rStr,sal_Int64 nData,sal_Int32 nWidth,sal_Unicode cFill)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 
appendDec(OUStringBuffer & rStr,double fData,sal_Int32 nWidth,sal_Unicode cFill)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 
appendHex(OUStringBuffer & rStr,sal_uInt8 nData,bool bPrefix)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 
appendHex(OUStringBuffer & rStr,sal_Int8 nData,bool bPrefix)306 void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int8 nData, bool bPrefix )
307 {
308     appendHex( rStr, static_cast< sal_uInt8 >( nData ), bPrefix );
309 }
310 
appendHex(OUStringBuffer & rStr,sal_uInt16 nData,bool bPrefix)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 
appendHex(OUStringBuffer & rStr,sal_Int16 nData,bool bPrefix)317 void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int16 nData, bool bPrefix )
318 {
319     appendHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix );
320 }
321 
appendHex(OUStringBuffer & rStr,sal_uInt32 nData,bool bPrefix)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 
appendHex(OUStringBuffer & rStr,sal_Int32 nData,bool bPrefix)328 void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int32 nData, bool bPrefix )
329 {
330     appendHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix );
331 }
332 
appendHex(OUStringBuffer & rStr,sal_uInt64 nData,bool bPrefix)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 
appendHex(OUStringBuffer & rStr,sal_Int64 nData,bool bPrefix)339 void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int64 nData, bool bPrefix )
340 {
341     appendHex( rStr, static_cast< sal_uInt64 >( nData ), bPrefix );
342 }
343 
appendHex(OUStringBuffer & rStr,double fData,bool bPrefix)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 
appendShortHex(OUStringBuffer & rStr,sal_uInt8 nData,bool bPrefix)351 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt8 nData, bool bPrefix )
352 {
353     appendHex( rStr, nData, bPrefix );
354 }
355 
appendShortHex(OUStringBuffer & rStr,sal_Int8 nData,bool bPrefix)356 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int8 nData, bool bPrefix )
357 {
358     appendHex( rStr, nData, bPrefix );
359 }
360 
appendShortHex(OUStringBuffer & rStr,sal_uInt16 nData,bool bPrefix)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 
appendShortHex(OUStringBuffer & rStr,sal_Int16 nData,bool bPrefix)369 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int16 nData, bool bPrefix )
370 {
371     appendShortHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix );
372 }
373 
appendShortHex(OUStringBuffer & rStr,sal_uInt32 nData,bool bPrefix)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 
appendShortHex(OUStringBuffer & rStr,sal_Int32 nData,bool bPrefix)382 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int32 nData, bool bPrefix )
383 {
384     appendShortHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix );
385 }
386 
appendShortHex(OUStringBuffer & rStr,sal_uInt64 nData,bool bPrefix)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 
appendShortHex(OUStringBuffer & rStr,sal_Int64 nData,bool bPrefix)395 void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int64 nData, bool bPrefix )
396 {
397     appendShortHex( rStr, static_cast< sal_uInt64 >( nData ), bPrefix );
398 }
399 
appendShortHex(OUStringBuffer & rStr,double fData,bool bPrefix)400 void StringHelper::appendShortHex( OUStringBuffer& rStr, double fData, bool bPrefix )
401 {
402     appendHex( rStr, fData, bPrefix );
403 }
404 
405 // append binary --------------------------------------------------------------
406 
appendBin(OUStringBuffer & rStr,sal_uInt8 nData,bool bDots)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 
appendBin(OUStringBuffer & rStr,sal_Int8 nData,bool bDots)417 void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int8 nData, bool bDots )
418 {
419     appendBin( rStr, static_cast< sal_uInt8 >( nData ), bDots );
420 }
421 
appendBin(OUStringBuffer & rStr,sal_uInt16 nData,bool bDots)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 
appendBin(OUStringBuffer & rStr,sal_Int16 nData,bool bDots)430 void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int16 nData, bool bDots )
431 {
432     appendBin( rStr, static_cast< sal_uInt16 >( nData ), bDots );
433 }
434 
appendBin(OUStringBuffer & rStr,sal_uInt32 nData,bool bDots)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 
appendBin(OUStringBuffer & rStr,sal_Int32 nData,bool bDots)443 void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int32 nData, bool bDots )
444 {
445     appendBin( rStr, static_cast< sal_uInt32 >( nData ), bDots );
446 }
447 
appendBin(OUStringBuffer & rStr,sal_uInt64 nData,bool bDots)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 
appendBin(OUStringBuffer & rStr,sal_Int64 nData,bool bDots)456 void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int64 nData, bool bDots )
457 {
458     appendBin( rStr, static_cast< sal_uInt64 >( nData ), bDots );
459 }
460 
appendBin(OUStringBuffer & rStr,double fData,bool bDots)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 
appendBool(OUStringBuffer & rStr,bool bData)468 void StringHelper::appendBool( OUStringBuffer& rStr, bool bData )
469 {
470     rStr.appendAscii( bData ? "true" : "false" );
471 }
472 
473 // append columns, rows, addresses --------------------------------------------
474 
appendAddrCol(OUStringBuffer & rStr,sal_Int32 nCol,bool bRel)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 
appendAddrRow(OUStringBuffer & rStr,sal_Int32 nRow,bool bRel)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 
appendAddrName(OUStringBuffer & rStr,sal_Unicode cPrefix,sal_Int32 nColRow,bool bRel)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 
appendAddress(OUStringBuffer & rStr,const Address & rPos)502 void StringHelper::appendAddress( OUStringBuffer& rStr, const Address& rPos )
503 {
504     appendAddrCol( rStr, rPos.mnCol, true );
505     appendAddrRow( rStr, rPos.mnRow, true );
506 }
507 
appendRange(OUStringBuffer & rStr,const Range & rRange)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 
appendRangeList(OUStringBuffer & rStr,const RangeList & rRanges)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 
appendAddress(OUStringBuffer & rStr,const TokenAddress & rPos,bool bR1C1)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 
appendRange(OUStringBuffer & rStr,const TokenRange & rRange,bool bR1C1)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 
appendCChar(OUStringBuffer & rStr,sal_Unicode cChar,bool bPrefix)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 
appendEncChar(OUStringBuffer & rStr,sal_Unicode cChar,sal_Int32 nCount,bool bPrefix)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 
appendEncString(OUStringBuffer & rStr,const OUString & rData,bool bPrefix)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 
appendToken(OUStringBuffer & rStr,const OUString & rToken,sal_Unicode cSep)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 
appendToken(OUStringBuffer & rStr,sal_Int64 nToken,sal_Unicode cSep)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 
prependToken(OUStringBuffer & rStr,const OUString & rToken,sal_Unicode cSep)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 
prependToken(OUStringBuffer & rStr,sal_Int64 nToken,sal_Unicode cSep)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 
appendIndex(OUStringBuffer & rStr,const OUString & rIdx)640 void StringHelper::appendIndex( OUStringBuffer& rStr, const OUString& rIdx )
641 {
642     rStr.append( sal_Unicode( '[' ) ).append( rIdx ).append( sal_Unicode( ']' ) );
643 }
644 
appendIndex(OUStringBuffer & rStr,sal_Int64 nIdx)645 void StringHelper::appendIndex( OUStringBuffer& rStr, sal_Int64 nIdx )
646 {
647     OUStringBuffer aToken;
648     appendDec( aToken, nIdx );
649     appendIndex( rStr, aToken.makeStringAndClear() );
650 }
651 
appendIndexedText(OUStringBuffer & rStr,const OUString & rData,const OUString & rIdx)652 void StringHelper::appendIndexedText( OUStringBuffer& rStr, const OUString& rData, const OUString& rIdx )
653 {
654     rStr.append( rData );
655     appendIndex( rStr, rIdx );
656 }
657 
appendIndexedText(OUStringBuffer & rStr,const OUString & rData,sal_Int64 nIdx)658 void StringHelper::appendIndexedText( OUStringBuffer& rStr, const OUString& rData, sal_Int64 nIdx )
659 {
660     rStr.append( rData );
661     appendIndex( rStr, nIdx );
662 }
663 
getToken(const OUString & rData,sal_Int32 & rnPos,sal_Unicode cSep)664 OUString StringHelper::getToken( const OUString& rData, sal_Int32& rnPos, sal_Unicode cSep )
665 {
666     return trimSpaces( rData.getToken( 0, cSep, rnPos ) );
667 }
668 
enclose(OUStringBuffer & rStr,sal_Unicode cOpen,sal_Unicode cClose)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 
lclIndexOf(const OUString & rStr,sal_Unicode cChar,sal_Int32 nStartPos)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 
lclTrimQuotedStringList(const OUString & rStr)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 
trimSpaces(const OUString & rStr)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 
trimTrailingNul(const OUString & rStr)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 
convertToUtf8(const OUString & rStr)756 OString StringHelper::convertToUtf8( const OUString& rStr )
757 {
758     return OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 );
759 }
760 
convertToDataType(const OUString & rStr)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 
convertToFormatType(const OUString & rStr)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 
convertFromDec(sal_Int64 & ornData,const OUString & rData)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 
convertFromHex(sal_Int64 & ornData,const OUString & rData)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 
convertStringToInt(sal_Int64 & ornData,const OUString & rData)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 
convertStringToDouble(double & orfData,const OUString & rData)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 
convertStringToBool(const OUString & rData)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 
convertStringToPair(const OUString & rString,sal_Unicode cSep)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 
convertStringToStringList(OUStringVector & orVec,const OUString & rData,bool bIgnoreEmpty)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 
convertStringToIntList(Int64Vector & orVec,const OUString & rData,bool bIgnoreEmpty)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 
FormulaStack()923 FormulaStack::FormulaStack() :
924     mbError( false )
925 {
926 }
927 
pushOperand(const String & rOp,const OUString & rTokClass)928 void FormulaStack::pushOperand( const String& rOp, const OUString& rTokClass )
929 {
930     maFmlaStack.push( rOp );
931     maClassStack.push( rTokClass );
932 }
933 
pushOperand(const String & rOp)934 void FormulaStack::pushOperand( const String& rOp )
935 {
936     pushOperand( rOp, OUString( OOX_DUMP_BASECLASS ) );
937 }
938 
pushUnaryOp(const String & rLOp,const String & rROp)939 void FormulaStack::pushUnaryOp( const String& rLOp, const String& rROp )
940 {
941     pushUnaryOp( maFmlaStack, rLOp, rROp );
942     pushUnaryOp( maClassStack, rLOp, rROp );
943 }
944 
pushBinaryOp(const String & rOp)945 void FormulaStack::pushBinaryOp( const String& rOp )
946 {
947     pushBinaryOp( maFmlaStack, rOp );
948     pushBinaryOp( maClassStack, rOp );
949 }
950 
pushFuncOp(const String & rFunc,const OUString & rTokClass,sal_uInt8 nParamCount)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 
replaceOnTop(const OUString & rOld,const OUString & rNew)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 
getString(const StringStack & rStack) const967 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 
pushUnaryOp(StringStack & rStack,const OUString & rLOp,const OUString & rROp)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 
pushBinaryOp(StringStack & rStack,const OUString & rOp)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 
pushFuncOp(StringStack & rStack,const OUString & rOp,sal_uInt8 nParamCount)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 
~Base()1007 Base::~Base()
1008 {
1009 }
1010 
1011 // ============================================================================
1012 // ============================================================================
1013 
~ConfigItemBase()1014 ConfigItemBase::~ConfigItemBase()
1015 {
1016 }
1017 
readConfigBlock(TextInputStream & rStrm)1018 void ConfigItemBase::readConfigBlock( TextInputStream& rStrm )
1019 {
1020     readConfigBlockContents( rStrm );
1021 }
1022 
implProcessConfigItemStr(TextInputStream &,const OUString &,const OUString &)1023 void ConfigItemBase::implProcessConfigItemStr(
1024         TextInputStream& /*rStrm*/, const OUString& /*rKey*/, const OUString& /*rData*/ )
1025 {
1026 }
1027 
implProcessConfigItemInt(TextInputStream &,sal_Int64,const OUString &)1028 void ConfigItemBase::implProcessConfigItemInt(
1029         TextInputStream& /*rStrm*/, sal_Int64 /*nKey*/, const OUString& /*rData*/ )
1030 {
1031 }
1032 
readConfigBlockContents(TextInputStream & rStrm)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 
readConfigLine(TextInputStream & rStrm,OUString & orKey,OUString & orData) const1051 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 
readConfigLine(TextInputStream & rStrm) const1077 ConfigItemBase::LineType ConfigItemBase::readConfigLine( TextInputStream& rStrm ) const
1078 {
1079     OUString aKey, aData;
1080     return readConfigLine( rStrm, aKey, aData );
1081 }
1082 
processConfigItem(TextInputStream & rStrm,const OUString & rKey,const OUString & rData)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 
~NameListBase()1095 NameListBase::~NameListBase()
1096 {
1097 }
1098 
setName(sal_Int64 nKey,const String & rName)1099 void NameListBase::setName( sal_Int64 nKey, const String& rName )
1100 {
1101     implSetName( nKey, rName );
1102 }
1103 
includeList(const NameListRef & rxList)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 
implIsValid() const1114 bool NameListBase::implIsValid() const
1115 {
1116     return true;
1117 }
1118 
implProcessConfigItemStr(TextInputStream & rStrm,const OUString & rKey,const OUString & rData)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 
implProcessConfigItemInt(TextInputStream &,sal_Int64 nKey,const OUString & rData)1130 void NameListBase::implProcessConfigItemInt(
1131         TextInputStream& /*rStrm*/, sal_Int64 nKey, const OUString& rData )
1132 {
1133     implSetName( nKey, rData );
1134 }
1135 
insertRawName(sal_Int64 nKey,const OUString & rName)1136 void NameListBase::insertRawName( sal_Int64 nKey, const OUString& rName )
1137 {
1138     maMap[ nKey ] = rName;
1139 }
1140 
findRawName(sal_Int64 nKey) const1141 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 
include(const OUString & rListKeys)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 
exclude(const OUString & rKeys)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 
insertFormats(const NameListRef & rxNameList)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 
ConstList(const SharedConfigData & rCfgData)1174 ConstList::ConstList( const SharedConfigData& rCfgData ) :
1175     NameListBase( rCfgData ),
1176     maDefName( OOX_DUMP_ERR_NONAME ),
1177     mbQuoteNames( false )
1178 {
1179 }
1180 
implProcessConfigItemStr(TextInputStream & rStrm,const OUString & rKey,const OUString & rData)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 
implSetName(sal_Int64 nKey,const OUString & rName)1192 void ConstList::implSetName( sal_Int64 nKey, const OUString& rName )
1193 {
1194     insertRawName( nKey, rName );
1195 }
1196 
implGetName(const Config &,sal_Int64 nKey) const1197 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 
implGetNameDbl(const Config &,double) const1210 OUString ConstList::implGetNameDbl( const Config& /*rCfg*/, double /*fValue*/ ) const
1211 {
1212     return OUString();
1213 }
1214 
implIncludeList(const NameListBase & rList)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 
MultiList(const SharedConfigData & rCfgData)1226 MultiList::MultiList( const SharedConfigData& rCfgData ) :
1227     ConstList( rCfgData ),
1228     mbIgnoreEmpty( true )
1229 {
1230 }
1231 
setNamesFromVec(sal_Int64 nStartKey,const OUStringVector & rNames)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 
implProcessConfigItemStr(TextInputStream & rStrm,const OUString & rKey,const OUString & rData)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 
implSetName(sal_Int64 nKey,const OUString & rName)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 
FlagsList(const SharedConfigData & rCfgData)1258 FlagsList::FlagsList( const SharedConfigData& rCfgData ) :
1259     NameListBase( rCfgData ),
1260     mnIgnore( 0 )
1261 {
1262 }
1263 
implProcessConfigItemStr(TextInputStream & rStrm,const OUString & rKey,const OUString & rData)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 
implSetName(sal_Int64 nKey,const OUString & rName)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 
implGetName(const Config &,sal_Int64 nKey) const1285 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 
implGetNameDbl(const Config &,double) const1338 OUString FlagsList::implGetNameDbl( const Config& /*rCfg*/, double /*fValue*/ ) const
1339 {
1340     return OUString();
1341 }
1342 
implIncludeList(const NameListBase & rList)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 
operator <(const ExtItemFormatKey & rRight) const1351 bool CombiList::ExtItemFormatKey::operator<( const ExtItemFormatKey& rRight ) const
1352 {
1353     return (mnKey < rRight.mnKey) || ((mnKey == rRight.mnKey) && (maFilter < rRight.maFilter));
1354 }
1355 
CombiList(const SharedConfigData & rCfgData)1356 CombiList::CombiList( const SharedConfigData& rCfgData ) :
1357     FlagsList( rCfgData )
1358 {
1359 }
1360 
implSetName(sal_Int64 nKey,const OUString & rName)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 
implGetName(const Config & rCfg,sal_Int64 nKey) const1400 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 
implIncludeList(const NameListBase & rList)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 
UnitConverter(const SharedConfigData & rCfgData)1464 UnitConverter::UnitConverter( const SharedConfigData& rCfgData ) :
1465     NameListBase( rCfgData ),
1466     mfFactor( 1.0 )
1467 {
1468 }
1469 
implSetName(sal_Int64,const OUString &)1470 void UnitConverter::implSetName( sal_Int64 /*nKey*/, const OUString& /*rName*/ )
1471 {
1472     // nothing to do
1473 }
1474 
implGetName(const Config & rCfg,sal_Int64 nKey) const1475 OUString UnitConverter::implGetName( const Config& rCfg, sal_Int64 nKey ) const
1476 {
1477     return implGetNameDbl( rCfg, static_cast< double >( nKey ) );
1478 }
1479 
implGetNameDbl(const Config &,double fValue) const1480 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 
implIncludeList(const NameListBase &)1488 void UnitConverter::implIncludeList( const NameListBase& /*rList*/ )
1489 {
1490 }
1491 
1492 // ============================================================================
1493 
getNameList(const Config & rCfg) const1494 NameListRef NameListWrapper::getNameList( const Config& rCfg ) const
1495 {
1496     return mxList.get() ? mxList : (mxList = rCfg.getNameList( maName ));
1497 }
1498 
1499 // ============================================================================
1500 // ============================================================================
1501 
SharedConfigData(const OUString & rFileName,const Reference<XComponentContext> & rxContext,const StorageRef & rxRootStrg,const OUString & rSysFileName,MediaDescriptor & rMediaDesc)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 
~SharedConfigData()1521 SharedConfigData::~SharedConfigData()
1522 {
1523 }
1524 
setOption(const OUString & rKey,const OUString & rData)1525 void SharedConfigData::setOption( const OUString& rKey, const OUString& rData )
1526 {
1527     maConfigData[ rKey ] = rData;
1528 }
1529 
getOption(const OUString & rKey) const1530 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 
setNameList(const OUString & rListName,const NameListRef & rxList)1536 void SharedConfigData::setNameList( const OUString& rListName, const NameListRef& rxList )
1537 {
1538     if( rListName.getLength() > 0 )
1539         maNameLists[ rListName ] = rxList;
1540 }
1541 
eraseNameList(const OUString & rListName)1542 void SharedConfigData::eraseNameList( const OUString& rListName )
1543 {
1544     maNameLists.erase( rListName );
1545 }
1546 
getNameList(const OUString & rListName) const1547 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 
requestEncryptionData(::comphelper::IDocPasswordVerifier & rVerifier)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 
implIsValid() const1570 bool SharedConfigData::implIsValid() const
1571 {
1572     return mbLoaded && mxContext.is() && mxRootStrg.get() && (maSysFileName.getLength() > 0);
1573 }
1574 
implProcessConfigItemStr(TextInputStream & rStrm,const OUString & rKey,const OUString & rData)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 
readConfigFile(const OUString & rFileUrl)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 
createShortList(const OUString & rData)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 
createUnitConverter(const OUString & rData)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 
Config(const Config & rParent)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 
Config(const sal_Char * pcEnvVar,const FilterBase & rFilter)1664 Config::Config( const sal_Char* pcEnvVar, const FilterBase& rFilter )
1665 {
1666     construct( pcEnvVar, rFilter );
1667 }
1668 
Config(const sal_Char * pcEnvVar,const Reference<XComponentContext> & rxContext,const StorageRef & rxRootStrg,const OUString & rSysFileName,MediaDescriptor & rMediaDesc)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 
~Config()1674 Config::~Config()
1675 {
1676 }
1677 
construct(const Config & rParent)1678 void Config::construct( const Config& rParent )
1679 {
1680     *this = rParent;
1681 }
1682 
construct(const sal_Char * pcEnvVar,const FilterBase & rFilter)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 
construct(const sal_Char * pcEnvVar,const Reference<XComponentContext> & rxContext,const StorageRef & rxRootStrg,const OUString & rSysFileName,MediaDescriptor & rMediaDesc)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 
setStringOption(const String & rKey,const String & rData)1696 void Config::setStringOption( const String& rKey, const String& rData )
1697 {
1698     mxCfgData->setOption( rKey, rData );
1699 }
1700 
getStringOption(const String & rKey,const OUString & rDefault) const1701 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 
getBoolOption(const String & rKey,bool bDefault) const1707 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 
isDumperEnabled() const1713 bool Config::isDumperEnabled() const
1714 {
1715     return getBoolOption( "enable-dumper", false );
1716 }
1717 
isImportEnabled() const1718 bool Config::isImportEnabled() const
1719 {
1720     return getBoolOption( "enable-import", true );
1721 }
1722 
setNameList(const String & rListName,const NameListRef & rxList)1723 void Config::setNameList( const String& rListName, const NameListRef& rxList )
1724 {
1725     mxCfgData->setNameList( rListName, rxList );
1726 }
1727 
eraseNameList(const String & rListName)1728 void Config::eraseNameList( const String& rListName )
1729 {
1730     mxCfgData->eraseNameList( rListName );
1731 }
1732 
getNameList(const String & rListName) const1733 NameListRef Config::getNameList( const String& rListName ) const
1734 {
1735     return implGetNameList( rListName );
1736 }
1737 
requestEncryptionData(::comphelper::IDocPasswordVerifier & rVerifier)1738 Sequence< NamedValue > Config::requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier )
1739 {
1740     return mxCfgData->requestEncryptionData( rVerifier );
1741 }
1742 
isPasswordCancelled() const1743 bool Config::isPasswordCancelled() const
1744 {
1745     return mxCfgData->isPasswordCancelled();
1746 }
1747 
implIsValid() const1748 bool Config::implIsValid() const
1749 {
1750     return isValid( mxCfgData );
1751 }
1752 
implGetOption(const OUString & rKey) const1753 const OUString* Config::implGetOption( const OUString& rKey ) const
1754 {
1755     return mxCfgData->getOption( rKey );
1756 }
1757 
implGetNameList(const OUString & rListName) const1758 NameListRef Config::implGetNameList( const OUString& rListName ) const
1759 {
1760     return mxCfgData->getNameList( rListName );
1761 }
1762 
1763 // ============================================================================
1764 // ============================================================================
1765 
Output(const Reference<XComponentContext> & rxContext,const OUString & rFileName)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 
newLine()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 
emptyLine(size_t nCount)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 
incIndent()1798 void Output::incIndent()
1799 {
1800     OUStringBuffer aBuffer( maIndent );
1801     StringHelper::appendChar( aBuffer, ' ', OOX_DUMP_INDENT );
1802     maIndent = aBuffer.makeStringAndClear();
1803 }
1804 
decIndent()1805 void Output::decIndent()
1806 {
1807     if( maIndent.getLength() >= OOX_DUMP_INDENT )
1808         maIndent = maIndent.copy( OOX_DUMP_INDENT );
1809 }
1810 
resetIndent()1811 void Output::resetIndent()
1812 {
1813     maIndent = OUString();
1814 }
1815 
startTable(sal_Int32 nW1)1816 void Output::startTable( sal_Int32 nW1 )
1817 {
1818     startTable( 1, &nW1 );
1819 }
1820 
startTable(sal_Int32 nW1,sal_Int32 nW2)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 
startTable(sal_Int32 nW1,sal_Int32 nW2,sal_Int32 nW3)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 
startTable(sal_Int32 nW1,sal_Int32 nW2,sal_Int32 nW3,sal_Int32 nW4)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 
startTable(size_t nColCount,const sal_Int32 * pnColWidths)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 
tab()1860 void Output::tab()
1861 {
1862     tab( mnCol + 1 );
1863 }
1864 
tab(size_t nCol)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 
endTable()1881 void Output::endTable()
1882 {
1883     maColPos.clear();
1884 }
1885 
resetItemIndex(sal_Int64 nIdx)1886 void Output::resetItemIndex( sal_Int64 nIdx )
1887 {
1888     mnItemIdx = nIdx;
1889 }
1890 
startItem(const String & rItemName)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 
contItem()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 
endItem()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 
startMultiItems()1935 void Output::startMultiItems()
1936 {
1937     ++mnMultiLevel;
1938 }
1939 
endMultiItems()1940 void Output::endMultiItems()
1941 {
1942     if( mnMultiLevel > 0 )
1943         --mnMultiLevel;
1944     if( mnMultiLevel == 0 )
1945         newLine();
1946 }
1947 
1948 // ----------------------------------------------------------------------------
1949 
writeChar(sal_Unicode cChar,sal_Int32 nCount)1950 void Output::writeChar( sal_Unicode cChar, sal_Int32 nCount )
1951 {
1952     StringHelper::appendEncChar( maLine, cChar, nCount );
1953 }
1954 
writeAscii(const sal_Char * pcStr)1955 void Output::writeAscii( const sal_Char* pcStr )
1956 {
1957     if( pcStr )
1958         maLine.appendAscii( pcStr );
1959 }
1960 
writeString(const OUString & rStr)1961 void Output::writeString( const OUString& rStr )
1962 {
1963     StringHelper::appendEncString( maLine, rStr );
1964 }
1965 
writeArray(const sal_uInt8 * pnData,sal_Size nSize,sal_Unicode cSep)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 
writeBool(bool bData)1977 void Output::writeBool( bool bData )
1978 {
1979     StringHelper::appendBool( maLine, bData );
1980 }
1981 
writeColorABGR(sal_Int32 nColor)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 
writeDateTime(const DateTime & rDateTime)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 
writeColIndex(sal_Int32 nCol)2009 void Output::writeColIndex( sal_Int32 nCol )
2010 {
2011     StringHelper::appendAddrCol( maLine, nCol, true );
2012 }
2013 
writeRowIndex(sal_Int32 nRow)2014 void Output::writeRowIndex( sal_Int32 nRow )
2015 {
2016     StringHelper::appendAddrRow( maLine, nRow, true );
2017 }
2018 
writeColRowRange(sal_Int32 nColRow1,sal_Int32 nColRow2)2019 void Output::writeColRowRange( sal_Int32 nColRow1, sal_Int32 nColRow2 )
2020 {
2021     writeDec( nColRow1 );
2022     writeChar( OOX_DUMP_RANGESEP );
2023     writeDec( nColRow2 );
2024 }
2025 
writeColRange(sal_Int32 nCol1,sal_Int32 nCol2)2026 void Output::writeColRange( sal_Int32 nCol1, sal_Int32 nCol2 )
2027 {
2028     writeColIndex( nCol1 );
2029     writeChar( OOX_DUMP_RANGESEP );
2030     writeColIndex( nCol2 );
2031 }
2032 
writeRowRange(sal_Int32 nRow1,sal_Int32 nRow2)2033 void Output::writeRowRange( sal_Int32 nRow1, sal_Int32 nRow2 )
2034 {
2035     writeRowIndex( nRow1 );
2036     writeChar( OOX_DUMP_RANGESEP );
2037     writeRowIndex( nRow2 );
2038 }
2039 
writeAddress(const Address & rPos)2040 void Output::writeAddress( const Address& rPos )
2041 {
2042     StringHelper::appendAddress( maLine, rPos );
2043 }
2044 
writeRange(const Range & rRange)2045 void Output::writeRange( const Range& rRange )
2046 {
2047     StringHelper::appendRange( maLine, rRange );
2048 }
2049 
writeRangeList(const RangeList & rRanges)2050 void Output::writeRangeList( const RangeList& rRanges )
2051 {
2052     StringHelper::appendRangeList( maLine, rRanges );
2053 }
2054 
2055 // ----------------------------------------------------------------------------
2056 
implIsValid() const2057 bool Output::implIsValid() const
2058 {
2059     return mxStrm.is();
2060 }
2061 
writeItemName(const String & rItemName)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 
StorageIterator(const StorageRef & rxStrg)2075 StorageIterator::StorageIterator( const StorageRef& rxStrg ) :
2076     mxStrg( rxStrg )
2077 {
2078     if( mxStrg.get() )
2079         mxStrg->getElementNames( maNames );
2080     maIt = maNames.begin();
2081 }
2082 
~StorageIterator()2083 StorageIterator::~StorageIterator()
2084 {
2085 }
2086 
getElementCount() const2087 size_t StorageIterator::getElementCount() const
2088 {
2089     return maNames.size();
2090 }
2091 
operator ++()2092 StorageIterator& StorageIterator::operator++()
2093 {
2094     if( maIt != maNames.end() )
2095         ++maIt;
2096     return *this;
2097 }
2098 
getName() const2099 OUString StorageIterator::getName() const
2100 {
2101     OUString aName;
2102     if( maIt != maNames.end() )
2103         aName = *maIt;
2104     return aName;
2105 }
2106 
isStream() const2107 bool StorageIterator::isStream() const
2108 {
2109     return isValid() && mxStrg->openInputStream( *maIt ).is();
2110 }
2111 
isStorage() const2112 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 
implIsValid() const2120 bool StorageIterator::implIsValid() const
2121 {
2122     return mxStrg.get() && mxStrg->isStorage() && (maIt != maNames.end());
2123 }
2124 
2125 // ============================================================================
2126 // ============================================================================
2127 
~ObjectBase()2128 ObjectBase::~ObjectBase()
2129 {
2130 }
2131 
construct(const ConfigRef & rxConfig)2132 void ObjectBase::construct( const ConfigRef& rxConfig )
2133 {
2134     mxConfig = rxConfig;
2135 }
2136 
construct(const ObjectBase & rParent)2137 void ObjectBase::construct( const ObjectBase& rParent )
2138 {
2139     *this = rParent;
2140 }
2141 
dump()2142 void ObjectBase::dump()
2143 {
2144     if( isValid() )
2145         implDump();
2146 }
2147 
implIsValid() const2148 bool ObjectBase::implIsValid() const
2149 {
2150     return isValid( mxConfig );
2151 }
2152 
implDump()2153 void ObjectBase::implDump()
2154 {
2155 }
2156 
reconstructConfig(const ConfigRef & rxConfig)2157 void ObjectBase::reconstructConfig( const ConfigRef& rxConfig )
2158 {
2159     if( isValid( rxConfig ) )
2160         mxConfig = rxConfig;
2161 }
2162 
2163 // ============================================================================
2164 // ============================================================================
2165 
construct(const ObjectBase & rParent,const StorageRef & rxStrg,const OUString & rSysPath)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 
construct(const ObjectBase & rParent)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 
implIsValid() const2183 bool StorageObjectBase::implIsValid() const
2184 {
2185     return mxStrg.get() && (maSysPath.getLength() > 0) && ObjectBase::implIsValid();
2186 }
2187 
implDump()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 
implDumpStream(const Reference<XInputStream> &,const OUString &,const OUString &,const OUString &)2220 void StorageObjectBase::implDumpStream( const Reference< XInputStream >&, const OUString&, const OUString&, const OUString& )
2221 {
2222 }
2223 
implDumpStorage(const StorageRef & rxStrg,const OUString & rStrgPath,const OUString & rSysPath)2224 void StorageObjectBase::implDumpStorage( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rSysPath )
2225 {
2226     extractStorage( rxStrg, rStrgPath, rSysPath );
2227 }
2228 
implDumpBaseStream(const BinaryInputStreamRef &,const OUString &)2229 void StorageObjectBase::implDumpBaseStream( const BinaryInputStreamRef&, const OUString& )
2230 {
2231 }
2232 
addPreferredStream(const String & rStrmName)2233 void StorageObjectBase::addPreferredStream( const String& rStrmName )
2234 {
2235     if( rStrmName.has() )
2236         maPreferred.push_back( PreferredItem( rStrmName, false ) );
2237 }
2238 
addPreferredStorage(const String & rStrgPath)2239 void StorageObjectBase::addPreferredStorage( const String& rStrgPath )
2240 {
2241     if( rStrgPath.has() )
2242         maPreferred.push_back( PreferredItem( rStrgPath, true ) );
2243 }
2244 
getSysFileName(const OUString & rStrmName,const OUString & rSysOutPath)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 
extractStream(StorageBase & rStrg,const OUString & rStrgPath,const OUString & rStrmName,const OUString & rSysFileName)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 
extractStorage(const StorageRef & rxStrg,const OUString & rStrgPath,const OUString & rSysPath)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 
extractItem(const StorageRef & rxStrg,const OUString & rStrgPath,const OUString & rItemName,const OUString & rSysPath,bool bIsStrg,bool bIsStrm)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 
~OutputObjectBase()2319 OutputObjectBase::~OutputObjectBase()
2320 {
2321 }
2322 
construct(const ObjectBase & rParent,const OUString & rSysFileName)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 
construct(const OutputObjectBase & rParent)2333 void OutputObjectBase::construct( const OutputObjectBase& rParent )
2334 {
2335     *this = rParent;
2336 }
2337 
implIsValid() const2338 bool OutputObjectBase::implIsValid() const
2339 {
2340     return isValid( mxOut ) && ObjectBase::implIsValid();
2341 }
2342 
writeEmptyItem(const String & rName)2343 void OutputObjectBase::writeEmptyItem( const String& rName )
2344 {
2345     ItemGuard aItem( mxOut, rName );
2346 }
2347 
writeInfoItem(const String & rName,const String & rData)2348 void OutputObjectBase::writeInfoItem( const String& rName, const String& rData )
2349 {
2350     ItemGuard aItem( mxOut, rName );
2351     mxOut->writeString( rData );
2352 }
2353 
writeCharItem(const String & rName,sal_Unicode cData)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 
writeStringItem(const String & rName,const OUString & rData)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 
writeArrayItem(const String & rName,const sal_uInt8 * pnData,sal_Size nSize,sal_Unicode cSep)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 
writeBoolItem(const String & rName,bool bData)2381 void OutputObjectBase::writeBoolItem( const String& rName, bool bData )
2382 {
2383     ItemGuard aItem( mxOut, rName );
2384     mxOut->writeBool( bData );
2385 }
2386 
writeRkItem(const String & rName,sal_Int32 nRk)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 
writeColorABGRItem(const String & rName,sal_Int32 nColor)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 
writeDateTimeItem(const String & rName,const DateTime & rDateTime)2403 void OutputObjectBase::writeDateTimeItem( const String& rName, const DateTime& rDateTime )
2404 {
2405     ItemGuard aItem( mxOut, rName );
2406     mxOut->writeDateTime( rDateTime );
2407 }
2408 
writeGuidItem(const String & rName,const OUString & rGuid)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 
writeColIndexItem(const String & rName,sal_Int32 nCol)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 
writeRowIndexItem(const String & rName,sal_Int32 nRow)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 
writeColRangeItem(const String & rName,sal_Int32 nCol1,sal_Int32 nCol2)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 
writeRowRangeItem(const String & rName,sal_Int32 nRow1,sal_Int32 nRow2)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 
writeAddressItem(const String & rName,const Address & rPos)2449 void OutputObjectBase::writeAddressItem( const String& rName, const Address& rPos )
2450 {
2451     ItemGuard aItem( mxOut, rName );
2452     StringHelper::appendAddress( mxOut->getLine(), rPos );
2453 }
2454 
writeRangeItem(const String & rName,const Range & rRange)2455 void OutputObjectBase::writeRangeItem( const String& rName, const Range& rRange )
2456 {
2457     ItemGuard aItem( mxOut, rName );
2458     StringHelper::appendRange( mxOut->getLine(), rRange );
2459 }
2460 
writeRangeListItem(const String & rName,const RangeList & rRanges)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 
writeTokenAddressItem(const String & rName,const TokenAddress & rPos,bool bNameMode)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 
writeTokenAddress3dItem(const String & rName,const OUString & rRef,const TokenAddress & rPos,bool bNameMode)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 
writeTokenRangeItem(const String & rName,const TokenRange & rRange,bool bNameMode)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 
writeTokenRange3dItem(const String & rName,const OUString & rRef,const TokenRange & rRange,bool bNameMode)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 
~InputObjectBase()2499 InputObjectBase::~InputObjectBase()
2500 {
2501 }
2502 
construct(const ObjectBase & rParent,const BinaryInputStreamRef & rxStrm,const OUString & rSysFileName)2503 void InputObjectBase::construct( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName )
2504 {
2505     OutputObjectBase::construct( rParent, rSysFileName );
2506     mxStrm = rxStrm;
2507 }
2508 
construct(const OutputObjectBase & rParent,const BinaryInputStreamRef & rxStrm)2509 void InputObjectBase::construct( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxStrm )
2510 {
2511     OutputObjectBase::construct( rParent );
2512     mxStrm = rxStrm;
2513 }
2514 
construct(const InputObjectBase & rParent)2515 void InputObjectBase::construct( const InputObjectBase& rParent )
2516 {
2517     *this = rParent;
2518 }
2519 
implIsValid() const2520 bool InputObjectBase::implIsValid() const
2521 {
2522     return mxStrm.get() && OutputObjectBase::implIsValid();
2523 }
2524 
skipBlock(sal_Int64 nBytes,bool bShowSize)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 
dumpRawBinary(sal_Int64 nBytes,bool bShowOffset,bool bStream)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 
dumpBinary(const String & rName,sal_Int64 nBytes,bool bShowOffset)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 
dumpRemaining(sal_Int64 nBytes)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 
dumpRemainingTo(sal_Int64 nPos)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 
dumpRemainingStream()2621 void InputObjectBase::dumpRemainingStream()
2622 {
2623     dumpRemainingTo( mxStrm->size() );
2624 }
2625 
dumpArray(const String & rName,sal_Int32 nBytes,sal_Unicode cSep)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 
dumpChar(const String & rName,rtl_TextEncoding eTextEnc)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 
dumpUnicode(const String & rName)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 
dumpCharArray(const String & rName,sal_Int32 nLen,rtl_TextEncoding eTextEnc,bool bHideTrailingNul)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 
dumpUnicodeArray(const String & rName,sal_Int32 nLen,bool bHideTrailingNul)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 
dumpNullCharArray(const String & rName,rtl_TextEncoding eTextEnc)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 
dumpNullUnicodeArray(const String & rName)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 
dumpRk(const String & rName)2713 double InputObjectBase::dumpRk( const String& rName )
2714 {
2715     sal_Int32 nRk;
2716     *mxStrm >> nRk;
2717     return writeRkItem( rName( "rk-value" ), nRk );
2718 }
2719 
dumpColorABGR(const String & rName)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 
dumpFileTime(const String & rName)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 
dumpGuid(const String & rName)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 
dumpItem(const ItemFormat & rItemFmt)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 
BinaryStreamObject(const ObjectBase & rParent,const BinaryInputStreamRef & rxStrm,const OUString & rSysFileName)2831 BinaryStreamObject::BinaryStreamObject( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName )
2832 {
2833     InputObjectBase::construct( rParent, rxStrm, rSysFileName );
2834 }
2835 
BinaryStreamObject(const OutputObjectBase & rParent,const BinaryInputStreamRef & rxStrm)2836 BinaryStreamObject::BinaryStreamObject( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxStrm )
2837 {
2838     InputObjectBase::construct( rParent, rxStrm );
2839 }
2840 
dumpBinaryStream(bool bShowOffset)2841 void BinaryStreamObject::dumpBinaryStream( bool bShowOffset )
2842 {
2843     mxStrm->seekToStart();
2844     dumpRawBinary( mxStrm->size(), bShowOffset, true );
2845     mxOut->emptyLine();
2846 }
2847 
implDump()2848 void BinaryStreamObject::implDump()
2849 {
2850     dumpBinaryStream();
2851 }
2852 
2853 // ============================================================================
2854 // ============================================================================
2855 
construct(const ObjectBase & rParent,const BinaryInputStreamRef & rxStrm,rtl_TextEncoding eTextEnc,const OUString & rSysFileName)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 
construct(const OutputObjectBase & rParent,const BinaryInputStreamRef & rxStrm,rtl_TextEncoding eTextEnc)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 
construct(const InputObjectBase & rParent,rtl_TextEncoding eTextEnc)2870 void TextStreamObjectBase::construct( const InputObjectBase& rParent, rtl_TextEncoding eTextEnc )
2871 {
2872     InputObjectBase::construct( rParent );
2873     constructTextStrmObj( eTextEnc );
2874 }
2875 
implIsValid() const2876 bool TextStreamObjectBase::implIsValid() const
2877 {
2878     return InputObjectBase::implIsValid() && mxTextStrm.get();
2879 }
2880 
implDump()2881 void TextStreamObjectBase::implDump()
2882 {
2883     implDumpText( *mxTextStrm );
2884 }
2885 
constructTextStrmObj(rtl_TextEncoding eTextEnc)2886 void TextStreamObjectBase::constructTextStrmObj( rtl_TextEncoding eTextEnc )
2887 {
2888     if( mxStrm.get() )
2889         mxTextStrm.reset( new TextInputStream( getContext(), *mxStrm, eTextEnc ) );
2890 }
2891 
2892 // ============================================================================
2893 
TextLineStreamObject(const ObjectBase & rParent,const BinaryInputStreamRef & rxStrm,rtl_TextEncoding eTextEnc,const OUString & rSysFileName)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 
TextLineStreamObject(const OutputObjectBase & rParent,const BinaryInputStreamRef & rxStrm,rtl_TextEncoding eTextEnc)2900 TextLineStreamObject::TextLineStreamObject( const OutputObjectBase& rParent,
2901         const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc )
2902 {
2903     TextStreamObjectBase::construct( rParent, rxStrm, eTextEnc );
2904 }
2905 
implDumpText(TextInputStream & rTextStrm)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 
implDumpLine(const OUString & rLine,sal_uInt32 nLine)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 
XmlStreamObject(const ObjectBase & rParent,const BinaryInputStreamRef & rxStrm,const OUString & rSysFileName)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 
XmlStreamObject(const OutputObjectBase & rParent,const BinaryInputStreamRef & rxStrm)2934 XmlStreamObject::XmlStreamObject( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxStrm )
2935 {
2936     TextStreamObjectBase::construct( rParent, rxStrm, RTL_TEXTENCODING_UTF8 );
2937 }
2938 
implDumpText(TextInputStream & rTextStrm)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 
construct(const ObjectBase & rParent,const BinaryInputStreamRef & rxBaseStrm,const OUString & rSysFileName,const BinaryInputStreamRef & rxRecStrm,const String & rRecNames,const String & rSimpleRecs)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 
construct(const OutputObjectBase & rParent,const BinaryInputStreamRef & rxBaseStrm,const BinaryInputStreamRef & rxRecStrm,const String & rRecNames,const String & rSimpleRecs)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 
implIsValid() const3037 bool RecordObjectBase::implIsValid() const
3038 {
3039     return mxBaseStrm.get() && InputObjectBase::implIsValid();
3040 }
3041 
implDump()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 
implWriteExtHeader()3074 void RecordObjectBase::implWriteExtHeader()
3075 {
3076 }
3077 
implDumpRecordBody()3078 void RecordObjectBase::implDumpRecordBody()
3079 {
3080 }
3081 
constructRecObjBase(const BinaryInputStreamRef & rxBaseStrm,const String & rRecNames,const String & rSimpleRecs)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 
writeHeader()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 
construct(const ObjectBase & rParent,const BinaryInputStreamRef & rxBaseStrm,const::rtl::OUString & rSysFileName,const String & rRecNames,const String & rSimpleRecs)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 
construct(const OutputObjectBase & rParent,const BinaryInputStreamRef & rxBaseStrm,const String & rRecNames,const String & rSimpleRecs)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 
implStartRecord(BinaryInputStream & rBaseStrm,sal_Int64 & ornRecPos,sal_Int64 & ornRecId,sal_Int64 & ornRecSize)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 
~DumperBase()3151 DumperBase::~DumperBase()
3152 {
3153 }
3154 
isImportEnabled() const3155 bool DumperBase::isImportEnabled() const
3156 {
3157     return !isValid() || cfg().isImportEnabled();
3158 }
3159 
isImportCancelled() const3160 bool DumperBase::isImportCancelled() const
3161 {
3162     return isValid() && cfg().isPasswordCancelled();
3163 }
3164 
construct(const ConfigRef & rxConfig)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