diff options
Diffstat (limited to 'oox/source/dump/dumperbase.cxx')
-rw-r--r-- | oox/source/dump/dumperbase.cxx | 3203 |
1 files changed, 3203 insertions, 0 deletions
diff --git a/oox/source/dump/dumperbase.cxx b/oox/source/dump/dumperbase.cxx new file mode 100644 index 000000000000..af3b9b45242f --- /dev/null +++ b/oox/source/dump/dumperbase.cxx @@ -0,0 +1,3203 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2008 by Sun Microsystems, Inc. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * $RCSfile: dumperbase.cxx,v $ + * $Revision: 1.4.20.13 $ + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#include "oox/dump/dumperbase.hxx" + +#include <algorithm> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/ucb/XSimpleFileAccess.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XActiveDataSource.hpp> +#include <com/sun/star/io/XTextInputStream.hpp> +#include <com/sun/star/io/XTextOutputStream.hpp> +#include <rtl/math.hxx> +#include <osl/file.hxx> +#include <comphelper/docpasswordhelper.hxx> +#include "oox/helper/binaryoutputstream.hxx" +#include "oox/core/filterbase.hxx" +#include "oox/xls/biffhelper.hxx" + +#if OOX_INCLUDE_DUMPER + +using ::rtl::OString; +using ::rtl::OStringBuffer; +using ::rtl::OStringToOUString; +using ::rtl::OUString; +using ::rtl::OUStringBuffer; +using ::rtl::OUStringToOString; +using ::com::sun::star::uno::Exception; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::UNO_QUERY_THROW; +using ::com::sun::star::util::DateTime; +using ::com::sun::star::lang::XMultiServiceFactory; +using ::com::sun::star::ucb::XSimpleFileAccess; +using ::com::sun::star::io::XActiveDataSink; +using ::com::sun::star::io::XActiveDataSource; +using ::com::sun::star::io::XInputStream; +using ::com::sun::star::io::XOutputStream; +using ::com::sun::star::io::XTextInputStream; +using ::com::sun::star::io::XTextOutputStream; +using ::comphelper::MediaDescriptor; +using ::oox::core::FilterBase; + +namespace oox { +namespace dump { + +const sal_Unicode OOX_DUMP_BOM = 0xFEFF; +const sal_Int32 OOX_DUMP_MAXSTRLEN = 80; +const sal_Int32 OOX_DUMP_INDENT = 2; +const sal_Unicode OOX_DUMP_BINDOT = '.'; +const sal_Unicode OOX_DUMP_CFG_LISTSEP = ','; +const sal_Unicode OOX_DUMP_CFG_QUOTE = '\''; +const sal_Unicode OOX_DUMP_LF = '\n'; +const sal_Unicode OOX_DUMP_ITEMSEP = '='; +const sal_Int32 OOX_DUMP_BYTESPERLINE = 16; +const sal_Int64 OOX_DUMP_MAXARRAY = 16; + +// ============================================================================ +// ============================================================================ + +// file names ----------------------------------------------------------------- + +OUString InputOutputHelper::convertFileNameToUrl( const OUString& rFileName ) +{ + OUString aFileUrl; + if( ::osl::FileBase::getFileURLFromSystemPath( rFileName, aFileUrl ) == ::osl::FileBase::E_None ) + return aFileUrl; + return OUString(); +} + +sal_Int32 InputOutputHelper::getFileNamePos( const OUString& rFileUrl ) +{ + sal_Int32 nSepPos = rFileUrl.lastIndexOf( '/' ); + return (nSepPos < 0) ? 0 : (nSepPos + 1); +} + +OUString InputOutputHelper::getFileNameExtension( const OUString& rFileUrl ) +{ + sal_Int32 nNamePos = getFileNamePos( rFileUrl ); + sal_Int32 nExtPos = rFileUrl.lastIndexOf( '.' ); + if( nExtPos >= nNamePos ) + return rFileUrl.copy( nExtPos + 1 ); + return OUString(); +} + +// input streams -------------------------------------------------------------- + +Reference< XInputStream > InputOutputHelper::getXInputStream( BinaryInputStream& rStrm ) +{ + if( BinaryXInputStream* pXStrm = dynamic_cast< BinaryXInputStream* >( &rStrm ) ) + return pXStrm->getXInputStream(); + return 0; +} + +Reference< XInputStream > InputOutputHelper::openInputStream( + const Reference< XMultiServiceFactory >& rxFactory, const OUString& rFileName ) +{ + Reference< XInputStream > xInStrm; + if( rxFactory.is() ) try + { + Reference< XSimpleFileAccess > xFileAccess( rxFactory->createInstance( CREATE_OUSTRING( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY_THROW ); + xInStrm = xFileAccess->openFileRead( rFileName ); + } + catch( Exception& ) + { + } + return xInStrm; +} + +Reference< XTextInputStream > InputOutputHelper::openTextInputStream( + const Reference< XMultiServiceFactory >& rxFactory, const Reference< XInputStream >& rxInStrm, const OUString& rEncoding ) +{ + Reference< XTextInputStream > xTextInStrm; + if( rxFactory.is() && rxInStrm.is() ) try + { + Reference< XActiveDataSink > xDataSink( rxFactory->createInstance( CREATE_OUSTRING( "com.sun.star.io.TextInputStream" ) ), UNO_QUERY_THROW ); + xDataSink->setInputStream( rxInStrm ); + xTextInStrm.set( xDataSink, UNO_QUERY_THROW ); + xTextInStrm->setEncoding( rEncoding ); + } + catch( Exception& ) + { + } + return xTextInStrm; +} + +Reference< XTextInputStream > InputOutputHelper::openTextInputStream( + const Reference< XMultiServiceFactory >& rxFactory, const OUString& rFileName, const OUString& rEncoding ) +{ + return openTextInputStream( rxFactory, openInputStream( rxFactory, rFileName ), rEncoding ); +} + +// output streams ------------------------------------------------------------- + +Reference< XOutputStream > InputOutputHelper::openOutputStream( + const Reference< XMultiServiceFactory >& rxFactory, const OUString& rFileName ) +{ + Reference< XOutputStream > xOutStrm; + if( rxFactory.is() ) try + { + Reference< XSimpleFileAccess > xFileAccess( rxFactory->createInstance( CREATE_OUSTRING( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY_THROW ); + xOutStrm = xFileAccess->openFileWrite( rFileName ); + } + catch( Exception& ) + { + } + return xOutStrm; +} + +Reference< XTextOutputStream > InputOutputHelper::openTextOutputStream( + const Reference< XMultiServiceFactory >& rxFactory, const Reference< XOutputStream >& rxOutStrm, const OUString& rEncoding ) +{ + Reference< XTextOutputStream > xTextOutStrm; + if( rxFactory.is() && rxOutStrm.is() ) try + { + Reference< XActiveDataSource > xDataSource( rxFactory->createInstance( CREATE_OUSTRING( "com.sun.star.io.TextOutputStream" ) ), UNO_QUERY_THROW ); + xDataSource->setOutputStream( rxOutStrm ); + xTextOutStrm.set( xDataSource, UNO_QUERY_THROW ); + xTextOutStrm->setEncoding( rEncoding ); + } + catch( Exception& ) + { + } + return xTextOutStrm; +} + +Reference< XTextOutputStream > InputOutputHelper::openTextOutputStream( + const Reference< XMultiServiceFactory >& rxFactory, const OUString& rFileName, const OUString& rEncoding ) +{ + return openTextOutputStream( rxFactory, openOutputStream( rxFactory, rFileName ), rEncoding ); +} + +// ============================================================================ +// ============================================================================ + +ItemFormat::ItemFormat() : + meDataType( DATATYPE_VOID ), + meFmtType( FORMATTYPE_NONE ) +{ +} + +void ItemFormat::set( DataType eDataType, FormatType eFmtType, const OUString& rItemName ) +{ + meDataType = eDataType; + meFmtType = eFmtType; + maItemName = rItemName; + maListName = OUString(); +} + +void ItemFormat::set( DataType eDataType, FormatType eFmtType, const OUString& rItemName, const OUString& rListName ) +{ + set( eDataType, eFmtType, rItemName ); + maListName = rListName; +} + +OUStringVector::const_iterator ItemFormat::parse( const OUStringVector& rFormatVec ) +{ + set( DATATYPE_VOID, FORMATTYPE_NONE, OUString() ); + + OUStringVector::const_iterator aIt = rFormatVec.begin(), aEnd = rFormatVec.end(); + OUString aDataType, aFmtType; + if( aIt != aEnd ) aDataType = *aIt++; + if( aIt != aEnd ) aFmtType = *aIt++; + if( aIt != aEnd ) maItemName = *aIt++; + if( aIt != aEnd ) maListName = *aIt++; + + meDataType = StringHelper::convertToDataType( aDataType ); + meFmtType = StringHelper::convertToFormatType( aFmtType ); + + if( meFmtType == FORMATTYPE_NONE ) + { + if( aFmtType.equalsAscii( "unused" ) ) + set( meDataType, FORMATTYPE_HEX, CREATE_OUSTRING( OOX_DUMP_UNUSED ) ); + else if( aFmtType.equalsAscii( "unknown" ) ) + set( meDataType, FORMATTYPE_HEX, CREATE_OUSTRING( OOX_DUMP_UNKNOWN ) ); + } + + return aIt; +} + +OUStringVector ItemFormat::parse( const OUString& rFormatStr ) +{ + OUStringVector aFormatVec; + StringHelper::convertStringToStringList( aFormatVec, rFormatStr, false ); + OUStringVector::const_iterator aIt = parse( aFormatVec ); + return OUStringVector( aIt, const_cast< const OUStringVector& >( aFormatVec ).end() ); +} + +// ============================================================================ +// ============================================================================ + +// append string to string ---------------------------------------------------- + +void StringHelper::appendChar( OUStringBuffer& rStr, sal_Unicode cChar, sal_Int32 nCount ) +{ + for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex ) + rStr.append( cChar ); +} + +void StringHelper::appendString( OUStringBuffer& rStr, const OUString& rData, sal_Int32 nWidth, sal_Unicode cFill ) +{ + appendChar( rStr, cFill, nWidth - rData.getLength() ); + rStr.append( rData ); +} + +// append decimal ------------------------------------------------------------- + +void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt8 nData, sal_Int32 nWidth, sal_Unicode cFill ) +{ + appendString( rStr, OUString::valueOf( static_cast< sal_Int32 >( nData ) ), nWidth, cFill ); +} + +void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int8 nData, sal_Int32 nWidth, sal_Unicode cFill ) +{ + appendString( rStr, OUString::valueOf( static_cast< sal_Int32 >( nData ) ), nWidth, cFill ); +} + +void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt16 nData, sal_Int32 nWidth, sal_Unicode cFill ) +{ + appendString( rStr, OUString::valueOf( static_cast< sal_Int32 >( nData ) ), nWidth, cFill ); +} + +void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int16 nData, sal_Int32 nWidth, sal_Unicode cFill ) +{ + appendString( rStr, OUString::valueOf( static_cast< sal_Int32 >( nData ) ), nWidth, cFill ); +} + +void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt32 nData, sal_Int32 nWidth, sal_Unicode cFill ) +{ + appendString( rStr, OUString::valueOf( static_cast< sal_Int64 >( nData ) ), nWidth, cFill ); +} + +void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int32 nData, sal_Int32 nWidth, sal_Unicode cFill ) +{ + appendString( rStr, OUString::valueOf( nData ), nWidth, cFill ); +} + +void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt64 nData, sal_Int32 nWidth, sal_Unicode cFill ) +{ + /* Values greater than biggest signed 64bit integer will change to + negative when converting to sal_Int64. Therefore, the trailing digit + will be written separately. */ + OUStringBuffer aBuffer; + if( nData > 9 ) + aBuffer.append( OUString::valueOf( static_cast< sal_Int64 >( nData / 10 ) ) ); + aBuffer.append( static_cast< sal_Unicode >( '0' + (nData % 10) ) ); + appendString( rStr, aBuffer.makeStringAndClear(), nWidth, cFill ); +} + +void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int64 nData, sal_Int32 nWidth, sal_Unicode cFill ) +{ + appendString( rStr, OUString::valueOf( nData ), nWidth, cFill ); +} + +void StringHelper::appendDec( OUStringBuffer& rStr, double fData, sal_Int32 nWidth, sal_Unicode cFill ) +{ + appendString( rStr, ::rtl::math::doubleToUString( fData, rtl_math_StringFormat_G, 15, '.', true ), nWidth, cFill ); +} + +// append hexadecimal --------------------------------------------------------- + +void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt8 nData, bool bPrefix ) +{ + static const sal_Unicode spcHexDigits[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' }; + if( bPrefix ) + rStr.appendAscii( "0x" ); + rStr.append( spcHexDigits[ (nData >> 4) & 0x0F ] ).append( spcHexDigits[ nData & 0x0F ] ); +} + +void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int8 nData, bool bPrefix ) +{ + appendHex( rStr, static_cast< sal_uInt8 >( nData ), bPrefix ); +} + +void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt16 nData, bool bPrefix ) +{ + appendHex( rStr, static_cast< sal_uInt8 >( nData >> 8 ), bPrefix ); + appendHex( rStr, static_cast< sal_uInt8 >( nData ), false ); +} + +void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int16 nData, bool bPrefix ) +{ + appendHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix ); +} + +void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt32 nData, bool bPrefix ) +{ + appendHex( rStr, static_cast< sal_uInt16 >( nData >> 16 ), bPrefix ); + appendHex( rStr, static_cast< sal_uInt16 >( nData ), false ); +} + +void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int32 nData, bool bPrefix ) +{ + appendHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix ); +} + +void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt64 nData, bool bPrefix ) +{ + appendHex( rStr, static_cast< sal_uInt32 >( nData >> 32 ), bPrefix ); + appendHex( rStr, static_cast< sal_uInt32 >( nData ), false ); +} + +void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int64 nData, bool bPrefix ) +{ + appendHex( rStr, static_cast< sal_uInt64 >( nData ), bPrefix ); +} + +void StringHelper::appendHex( OUStringBuffer& rStr, double fData, bool bPrefix ) +{ + appendHex( rStr, *reinterpret_cast< const sal_uInt64* >( &fData ), bPrefix ); +} + +// append shortened hexadecimal ----------------------------------------------- + +void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt8 nData, bool bPrefix ) +{ + appendHex( rStr, nData, bPrefix ); +} + +void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int8 nData, bool bPrefix ) +{ + appendHex( rStr, nData, bPrefix ); +} + +void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt16 nData, bool bPrefix ) +{ + if( nData > SAL_MAX_UINT8 ) + appendHex( rStr, nData, bPrefix ); + else + appendHex( rStr, static_cast< sal_uInt8 >( nData ), bPrefix ); +} + +void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int16 nData, bool bPrefix ) +{ + appendShortHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix ); +} + +void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt32 nData, bool bPrefix ) +{ + if( nData > SAL_MAX_UINT16 ) + appendHex( rStr, nData, bPrefix ); + else + appendShortHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix ); +} + +void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int32 nData, bool bPrefix ) +{ + appendShortHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix ); +} + +void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt64 nData, bool bPrefix ) +{ + if( nData > SAL_MAX_UINT32 ) + appendHex( rStr, nData, bPrefix ); + else + appendShortHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix ); +} + +void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int64 nData, bool bPrefix ) +{ + appendShortHex( rStr, static_cast< sal_uInt64 >( nData ), bPrefix ); +} + +void StringHelper::appendShortHex( OUStringBuffer& rStr, double fData, bool bPrefix ) +{ + appendHex( rStr, fData, bPrefix ); +} + +// append binary -------------------------------------------------------------- + +void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt8 nData, bool bDots ) +{ + for( sal_uInt8 nMask = 0x80; nMask != 0; (nMask >>= 1) &= 0x7F ) + { + rStr.append( static_cast< sal_Unicode >( (nData & nMask) ? '1' : '0' ) ); + if( bDots && (nMask == 0x10) ) + rStr.append( OOX_DUMP_BINDOT ); + } +} + +void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int8 nData, bool bDots ) +{ + appendBin( rStr, static_cast< sal_uInt8 >( nData ), bDots ); +} + +void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt16 nData, bool bDots ) +{ + appendBin( rStr, static_cast< sal_uInt8 >( nData >> 8 ), bDots ); + if( bDots ) + rStr.append( OOX_DUMP_BINDOT ); + appendBin( rStr, static_cast< sal_uInt8 >( nData ), bDots ); +} + +void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int16 nData, bool bDots ) +{ + appendBin( rStr, static_cast< sal_uInt16 >( nData ), bDots ); +} + +void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt32 nData, bool bDots ) +{ + appendBin( rStr, static_cast< sal_uInt16 >( nData >> 16 ), bDots ); + if( bDots ) + rStr.append( OOX_DUMP_BINDOT ); + appendBin( rStr, static_cast< sal_uInt16 >( nData ), bDots ); +} + +void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int32 nData, bool bDots ) +{ + appendBin( rStr, static_cast< sal_uInt32 >( nData ), bDots ); +} + +void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt64 nData, bool bDots ) +{ + appendBin( rStr, static_cast< sal_uInt32 >( nData >> 32 ), bDots ); + if( bDots ) + rStr.append( OOX_DUMP_BINDOT ); + appendBin( rStr, static_cast< sal_uInt32 >( nData ), bDots ); +} + +void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int64 nData, bool bDots ) +{ + appendBin( rStr, static_cast< sal_uInt64 >( nData ), bDots ); +} + +void StringHelper::appendBin( OUStringBuffer& rStr, double fData, bool bDots ) +{ + appendBin( rStr, *reinterpret_cast< const sal_uInt64* >( &fData ), bDots ); +} + +// append formatted value ----------------------------------------------------- + +void StringHelper::appendBool( OUStringBuffer& rStr, bool bData ) +{ + rStr.appendAscii( bData ? "true" : "false" ); +} + +// append columns, rows, addresses -------------------------------------------- + +void StringHelper::appendAddrCol( OUStringBuffer& rStr, sal_Int32 nCol, bool bRel ) +{ + if( !bRel ) rStr.append( OOX_DUMP_ADDRABS ); + sal_Int32 nPos = rStr.getLength(); + for( sal_Int32 nTemp = nCol; nTemp >= 0; (nTemp /= 26) -= 1 ) + rStr.insert( nPos, static_cast< sal_Unicode >( 'A' + (nTemp % 26) ) ); +} + +void StringHelper::appendAddrRow( OUStringBuffer& rStr, sal_Int32 nRow, bool bRel ) +{ + if( !bRel ) rStr.append( OOX_DUMP_ADDRABS ); + appendDec( rStr, nRow + 1 ); +} + +void StringHelper::appendAddrName( OUStringBuffer& rStr, sal_Unicode cPrefix, sal_Int32 nColRow, bool bRel ) +{ + rStr.append( cPrefix ); + if( bRel && (nColRow != 0) ) + { + rStr.append( OOX_DUMP_R1C1OPEN ); + appendDec( rStr, nColRow ); + rStr.append( OOX_DUMP_R1C1CLOSE ); + } + else if( !bRel ) + appendDec( rStr, nColRow + 1 ); +} + +void StringHelper::appendAddress( OUStringBuffer& rStr, const Address& rPos ) +{ + appendAddrCol( rStr, rPos.mnCol, true ); + appendAddrRow( rStr, rPos.mnRow, true ); +} + +void StringHelper::appendRange( OUStringBuffer& rStr, const Range& rRange ) +{ + appendAddress( rStr, rRange.maFirst ); + rStr.append( OOX_DUMP_RANGESEP ); + appendAddress( rStr, rRange.maLast ); +} + +void StringHelper::appendRangeList( OUStringBuffer& rStr, const RangeList& rRanges ) +{ + OUStringBuffer aData; + for( RangeList::const_iterator aIt = rRanges.begin(), aEnd = rRanges.end(); aIt != aEnd; ++aIt ) + { + OUStringBuffer aRange; + appendRange( aRange, *aIt ); + appendToken( aData, aRange.makeStringAndClear(), OOX_DUMP_LISTSEP ); + } + rStr.append( aData.makeStringAndClear() ); +} + +void StringHelper::appendAddress( OUStringBuffer& rStr, const TokenAddress& rPos, bool bR1C1 ) +{ + if( bR1C1 && (rPos.mbRelCol || rPos.mbRelRow) ) + { + appendAddrName( rStr, OOX_DUMP_R1C1ROW, rPos.mnRow, rPos.mbRelRow ); + appendAddrName( rStr, OOX_DUMP_R1C1COL, rPos.mnCol, rPos.mbRelCol ); + } + else + { + appendAddrCol( rStr, rPos.mnCol, rPos.mbRelCol ); + appendAddrRow( rStr, rPos.mnRow, rPos.mbRelRow ); + } +} + +void StringHelper::appendRange( OUStringBuffer& rStr, const TokenRange& rRange, bool bR1C1 ) +{ + appendAddress( rStr, rRange.maFirst, bR1C1 ); + rStr.append( OOX_DUMP_RANGESEP ); + appendAddress( rStr, rRange.maLast, bR1C1 ); +} + +// encoded text output -------------------------------------------------------- + +void StringHelper::appendCChar( OUStringBuffer& rStr, sal_Unicode cChar, bool bPrefix ) +{ + if( cChar > 0x00FF ) + { + if( bPrefix ) + rStr.appendAscii( "\\u" ); + appendHex( rStr, static_cast< sal_uInt16 >( cChar ), false ); + } + else + { + if( bPrefix ) + rStr.appendAscii( "\\x" ); + appendHex( rStr, static_cast< sal_uInt8 >( cChar ), false ); + } +} + +void StringHelper::appendEncChar( OUStringBuffer& rStr, sal_Unicode cChar, sal_Int32 nCount, bool bPrefix ) +{ + if( cChar < 0x0020 ) + { + // C-style hex code + OUStringBuffer aCode; + appendCChar( aCode, cChar, bPrefix ); + for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx ) + rStr.append( aCode ); + } + else + { + appendChar( rStr, cChar, nCount ); + } +} + +void StringHelper::appendEncString( OUStringBuffer& rStr, const OUString& rData, bool bPrefix ) +{ + sal_Int32 nBeg = 0; + sal_Int32 nIdx = 0; + sal_Int32 nEnd = rData.getLength(); + while( nIdx < nEnd ) + { + // find next character that needs encoding + while( (nIdx < nEnd) && (rData[ nIdx ] >= 0x20) ) ++nIdx; + // append portion + if( nBeg < nIdx ) + { + if( (nBeg == 0) && (nIdx == nEnd) ) + rStr.append( rData ); + else + rStr.append( rData.copy( nBeg, nIdx - nBeg ) ); + } + // append characters to be encoded + while( (nIdx < nEnd) && (rData[ nIdx ] < 0x20) ) + { + appendCChar( rStr, rData[ nIdx ], bPrefix ); + ++nIdx; + } + // adjust limits + nBeg = nIdx; + } +} + +// token list ----------------------------------------------------------------- + +void StringHelper::appendToken( OUStringBuffer& rStr, const OUString& rToken, sal_Unicode cSep ) +{ + if( (rStr.getLength() > 0) && (rToken.getLength() > 0) ) + rStr.append( cSep ); + rStr.append( rToken ); +} + +void StringHelper::appendToken( OUStringBuffer& rStr, sal_Int64 nToken, sal_Unicode cSep ) +{ + OUStringBuffer aToken; + appendDec( aToken, nToken ); + appendToken( rStr, aToken.makeStringAndClear(), cSep ); +} + +void StringHelper::prependToken( OUStringBuffer& rStr, const OUString& rToken, sal_Unicode cSep ) +{ + if( (rStr.getLength() > 0) && (rToken.getLength() > 0) ) + rStr.insert( 0, cSep ); + rStr.insert( 0, rToken ); +} + +void StringHelper::prependToken( OUStringBuffer& rStr, sal_Int64 nToken, sal_Unicode cSep ) +{ + OUStringBuffer aToken; + appendDec( aToken, nToken ); + prependToken( rStr, aToken.makeStringAndClear(), cSep ); +} + +void StringHelper::appendIndex( OUStringBuffer& rStr, const OUString& rIdx ) +{ + rStr.append( sal_Unicode( '[' ) ).append( rIdx ).append( sal_Unicode( ']' ) ); +} + +void StringHelper::appendIndex( OUStringBuffer& rStr, sal_Int64 nIdx ) +{ + OUStringBuffer aToken; + appendDec( aToken, nIdx ); + appendIndex( rStr, aToken.makeStringAndClear() ); +} + +void StringHelper::appendIndexedText( OUStringBuffer& rStr, const OUString& rData, const OUString& rIdx ) +{ + rStr.append( rData ); + appendIndex( rStr, rIdx ); +} + +void StringHelper::appendIndexedText( OUStringBuffer& rStr, const OUString& rData, sal_Int64 nIdx ) +{ + rStr.append( rData ); + appendIndex( rStr, nIdx ); +} + +OUString StringHelper::getToken( const OUString& rData, sal_Int32& rnPos, sal_Unicode cSep ) +{ + return trimSpaces( rData.getToken( 0, cSep, rnPos ) ); +} + +void StringHelper::enclose( OUStringBuffer& rStr, sal_Unicode cOpen, sal_Unicode cClose ) +{ + rStr.insert( 0, cOpen ).append( cClose ? cClose : cOpen ); +} + +// string conversion ---------------------------------------------------------- + +namespace { + +sal_Int32 lclIndexOf( const OUString& rStr, sal_Unicode cChar, sal_Int32 nStartPos ) +{ + sal_Int32 nIndex = rStr.indexOf( cChar, nStartPos ); + return (nIndex < 0) ? rStr.getLength() : nIndex; +} + +OUString lclTrimQuotedStringList( const OUString& rStr ) +{ + OUStringBuffer aBuffer; + sal_Int32 nPos = 0; + sal_Int32 nLen = rStr.getLength(); + while( nPos < nLen ) + { + if( rStr[ nPos ] == OOX_DUMP_CFG_QUOTE ) + { + // quoted string, skip leading quote character + ++nPos; + // process quoted text and ambedded literal quote characters + OUStringBuffer aToken; + do + { + // seek to next quote character and add text portion to token buffer + sal_Int32 nEnd = lclIndexOf( rStr, OOX_DUMP_CFG_QUOTE, nPos ); + aToken.append( rStr.copy( nPos, nEnd - nPos ) ); + // process literal quotes + while( (nEnd + 1 < nLen) && (rStr[ nEnd ] == OOX_DUMP_CFG_QUOTE) && (rStr[ nEnd + 1 ] == OOX_DUMP_CFG_QUOTE) ) + { + aToken.append( OOX_DUMP_CFG_QUOTE ); + nEnd += 2; + } + // nEnd is start of possible next text portion + nPos = nEnd; + } + while( (nPos < nLen) && (rStr[ nPos ] != OOX_DUMP_CFG_QUOTE) ); + // add token, seek to list separator, ignore text following closing quote + aBuffer.append( aToken.makeStringAndClear() ); + nPos = lclIndexOf( rStr, OOX_DUMP_CFG_LISTSEP, nPos ); + if( nPos < nLen ) + aBuffer.append( OOX_DUMP_LF ); + // set current position behind list separator + ++nPos; + } + else + { + // find list separator, add token text to buffer + sal_Int32 nEnd = lclIndexOf( rStr, OOX_DUMP_CFG_LISTSEP, nPos ); + aBuffer.append( rStr.copy( nPos, nEnd - nPos ) ); + if( nEnd < nLen ) + aBuffer.append( OOX_DUMP_LF ); + // set current position behind list separator + nPos = nEnd + 1; + } + } + + return aBuffer.makeStringAndClear(); +} + +} // namespace + +OUString StringHelper::trimSpaces( const OUString& rStr ) +{ + sal_Int32 nBeg = 0; + while( (nBeg < rStr.getLength()) && ((rStr[ nBeg ] == ' ') || (rStr[ nBeg ] == '\t')) ) + ++nBeg; + sal_Int32 nEnd = rStr.getLength(); + while( (nEnd > nBeg) && ((rStr[ nEnd - 1 ] == ' ') || (rStr[ nEnd - 1 ] == '\t')) ) + --nEnd; + return rStr.copy( nBeg, nEnd - nBeg ); +} + +OString StringHelper::convertToUtf8( const OUString& rStr ) +{ + return OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 ); +} + +DataType StringHelper::convertToDataType( const OUString& rStr ) +{ + DataType eType = DATATYPE_VOID; + if( rStr.equalsAscii( "int8" ) ) + eType = DATATYPE_INT8; + else if( rStr.equalsAscii( "uint8" ) ) + eType = DATATYPE_UINT8; + else if( rStr.equalsAscii( "int16" ) ) + eType = DATATYPE_INT16; + else if( rStr.equalsAscii( "uint16" ) ) + eType = DATATYPE_UINT16; + else if( rStr.equalsAscii( "int32" ) ) + eType = DATATYPE_INT32; + else if( rStr.equalsAscii( "uint32" ) ) + eType = DATATYPE_UINT32; + else if( rStr.equalsAscii( "int64" ) ) + eType = DATATYPE_INT64; + else if( rStr.equalsAscii( "uint64" ) ) + eType = DATATYPE_UINT64; + else if( rStr.equalsAscii( "float" ) ) + eType = DATATYPE_FLOAT; + else if( rStr.equalsAscii( "double" ) ) + eType = DATATYPE_DOUBLE; + return eType; +} + +FormatType StringHelper::convertToFormatType( const OUString& rStr ) +{ + FormatType eType = FORMATTYPE_NONE; + if( rStr.equalsAscii( "dec" ) ) + eType = FORMATTYPE_DEC; + else if( rStr.equalsAscii( "hex" ) ) + eType = FORMATTYPE_HEX; + else if( rStr.equalsAscii( "shorthex" ) ) + eType = FORMATTYPE_SHORTHEX; + else if( rStr.equalsAscii( "bin" ) ) + eType = FORMATTYPE_BIN; + else if( rStr.equalsAscii( "fix" ) ) + eType = FORMATTYPE_FIX; + else if( rStr.equalsAscii( "bool" ) ) + eType = FORMATTYPE_BOOL; + return eType; +} + +bool StringHelper::convertFromDec( sal_Int64& ornData, const OUString& rData ) +{ + sal_Int32 nPos = 0; + sal_Int32 nLen = rData.getLength(); + bool bNeg = false; + if( (nLen > 0) && (rData[ 0 ] == '-') ) + { + bNeg = true; + ++nPos; + } + ornData = 0; + for( ; nPos < nLen; ++nPos ) + { + sal_Unicode cChar = rData[ nPos ]; + if( (cChar < '0') || (cChar > '9') ) + return false; + (ornData *= 10) += (cChar - '0'); + } + if( bNeg ) + ornData *= -1; + return true; +} + +bool StringHelper::convertFromHex( sal_Int64& ornData, const OUString& rData ) +{ + ornData = 0; + for( sal_Int32 nPos = 0, nLen = rData.getLength(); nPos < nLen; ++nPos ) + { + sal_Unicode cChar = rData[ nPos ]; + if( ('0' <= cChar) && (cChar <= '9') ) + cChar -= '0'; + else if( ('A' <= cChar) && (cChar <= 'F') ) + cChar -= ('A' - 10); + else if( ('a' <= cChar) && (cChar <= 'f') ) + cChar -= ('a' - 10); + else + return false; + (ornData <<= 4) += cChar; + } + return true; +} + +bool StringHelper::convertStringToInt( sal_Int64& ornData, const OUString& rData ) +{ + if( (rData.getLength() > 2) && (rData[ 0 ] == '0') && ((rData[ 1 ] == 'X') || (rData[ 1 ] == 'x')) ) + return convertFromHex( ornData, rData.copy( 2 ) ); + return convertFromDec( ornData, rData ); +} + +bool StringHelper::convertStringToDouble( double& orfData, const OUString& rData ) +{ + rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok; + sal_Int32 nSize = 0; + orfData = rtl::math::stringToDouble( rData, '.', '\0', &eStatus, &nSize ); + return (eStatus == rtl_math_ConversionStatus_Ok) && (nSize == rData.getLength()); +} + +bool StringHelper::convertStringToBool( const OUString& rData ) +{ + if( rData.equalsAscii( "true" ) ) + return true; + if( rData.equalsAscii( "false" ) ) + return false; + sal_Int64 nData; + return convertStringToInt( nData, rData ) && (nData != 0); +} + +void StringHelper::convertStringToStringList( OUStringVector& orVec, const OUString& rData, bool bIgnoreEmpty ) +{ + orVec.clear(); + OUString aUnquotedData = lclTrimQuotedStringList( rData ); + sal_Int32 nPos = 0; + sal_Int32 nLen = aUnquotedData.getLength(); + while( (0 <= nPos) && (nPos < nLen) ) + { + OUString aToken = getToken( aUnquotedData, nPos, OOX_DUMP_LF ); + if( !bIgnoreEmpty || (aToken.getLength() > 0) ) + orVec.push_back( aToken ); + } +} + +void StringHelper::convertStringToIntList( Int64Vector& orVec, const OUString& rData, bool bIgnoreEmpty ) +{ + orVec.clear(); + OUString aUnquotedData = lclTrimQuotedStringList( rData ); + sal_Int32 nPos = 0; + sal_Int32 nLen = aUnquotedData.getLength(); + sal_Int64 nData; + while( (0 <= nPos) && (nPos < nLen) ) + { + bool bOk = convertStringToInt( nData, getToken( aUnquotedData, nPos, OOX_DUMP_LF ) ); + if( !bIgnoreEmpty || bOk ) + orVec.push_back( bOk ? nData : 0 ); + } +} + +// ============================================================================ +// ============================================================================ + +FormulaStack::FormulaStack() : + mbError( false ) +{ +} + +void FormulaStack::pushOperand( const String& rOp, const OUString& rTokClass ) +{ + maFmlaStack.push( rOp ); + maClassStack.push( rTokClass ); +} + +void FormulaStack::pushOperand( const String& rOp ) +{ + pushOperand( rOp, OUString( OOX_DUMP_BASECLASS ) ); +} + +void FormulaStack::pushUnaryOp( const String& rLOp, const String& rROp ) +{ + pushUnaryOp( maFmlaStack, rLOp, rROp ); + pushUnaryOp( maClassStack, rLOp, rROp ); +} + +void FormulaStack::pushBinaryOp( const String& rOp ) +{ + pushBinaryOp( maFmlaStack, rOp ); + pushBinaryOp( maClassStack, rOp ); +} + +void FormulaStack::pushFuncOp( const String& rFunc, const OUString& rTokClass, sal_uInt8 nParamCount ) +{ + pushFuncOp( maFmlaStack, rFunc, nParamCount ); + pushFuncOp( maClassStack, rTokClass, nParamCount ); +} + +void FormulaStack::replaceOnTop( const OUString& rOld, const OUString& rNew ) +{ + if( !maFmlaStack.empty() ) + { + sal_Int32 nPos = maFmlaStack.top().indexOf( rOld ); + if( nPos >= 0 ) + maFmlaStack.top() = maFmlaStack.top().copy( 0, nPos ) + rNew + maFmlaStack.top().copy( nPos + rOld.getLength() ); + } +} + +const OUString& FormulaStack::getString( const StringStack& rStack ) const +{ + static const OUString saStackError = OOX_DUMP_ERRSTRING( "stack" ); + return (mbError || rStack.empty()) ? saStackError : rStack.top(); +} + +void FormulaStack::pushUnaryOp( StringStack& rStack, const OUString& rLOp, const OUString& rROp ) +{ + if( check( !rStack.empty() ) ) + rStack.top() = rLOp + rStack.top() + rROp; +} + +void FormulaStack::pushBinaryOp( StringStack& rStack, const OUString& rOp ) +{ + OUString aSecond; + if( check( !rStack.empty() ) ) + { + aSecond = rStack.top(); + rStack.pop(); + } + if( check( !rStack.empty() ) ) + rStack.top() = rStack.top() + rOp + aSecond; +} + +void FormulaStack::pushFuncOp( StringStack& rStack, const OUString& rOp, sal_uInt8 nParamCount ) +{ + OUStringBuffer aFunc; + for( sal_uInt8 nParam = 0; (nParam < nParamCount) && check( !rStack.empty() ); ++nParam ) + { + StringHelper::prependToken( aFunc, rStack.top(), OOX_DUMP_FUNCSEP ); + rStack.pop(); + } + StringHelper::enclose( aFunc, '(', ')' ); + aFunc.insert( 0, rOp ); + rStack.push( aFunc.makeStringAndClear() ); +} + +// ============================================================================ +// ============================================================================ + +Base::~Base() +{ +} + +// ============================================================================ +// ============================================================================ + +ConfigItemBase::~ConfigItemBase() +{ +} + +void ConfigItemBase::readConfigBlock( const ConfigInputStreamRef& rxStrm ) +{ + readConfigBlockContents( rxStrm ); +} + +void ConfigItemBase::implProcessConfigItemStr( + const ConfigInputStreamRef& /*rxStrm*/, const OUString& /*rKey*/, const OUString& /*rData*/ ) +{ +} + +void ConfigItemBase::implProcessConfigItemInt( + const ConfigInputStreamRef& /*rxStrm*/, sal_Int64 /*nKey*/, const OUString& /*rData*/ ) +{ +} + +void ConfigItemBase::readConfigBlockContents( const ConfigInputStreamRef& rxStrm ) +{ + bool bLoop = true; + while( bLoop && !rxStrm->isEOF() ) + { + OUString aKey, aData; + switch( readConfigLine( rxStrm, aKey, aData ) ) + { + case LINETYPE_DATA: + processConfigItem( rxStrm, aKey, aData ); + break; + case LINETYPE_END: + bLoop = false; + break; + } + } +} + +ConfigItemBase::LineType ConfigItemBase::readConfigLine( + const ConfigInputStreamRef& rxStrm, OUString& orKey, OUString& orData ) const +{ + OUString aLine; + while( !rxStrm->isEOF() && (aLine.getLength() == 0) ) + { + try { aLine = rxStrm->readLine(); } catch( Exception& ) { aLine = OUString(); } + if( (aLine.getLength() > 0) && (aLine[ 0 ] == OOX_DUMP_BOM) ) + aLine = aLine.copy( 1 ); + aLine = StringHelper::trimSpaces( aLine ); + if( aLine.getLength() > 0 ) + { + // ignore comments (starting with hash or semicolon) + sal_Unicode cChar = aLine[ 0 ]; + if( (cChar == '#') || (cChar == ';') ) + aLine = OUString(); + } + } + + LineType eResult = LINETYPE_END; + if( aLine.getLength() > 0 ) + { + sal_Int32 nEqPos = aLine.indexOf( '=' ); + if( nEqPos < 0 ) + { + orKey = aLine; + } + else + { + orKey = StringHelper::trimSpaces( aLine.copy( 0, nEqPos ) ); + orData = StringHelper::trimSpaces( aLine.copy( nEqPos + 1 ) ); + } + + if( (orKey.getLength() > 0) && ((orData.getLength() > 0) || !orKey.equalsAscii( "end" )) ) + eResult = LINETYPE_DATA; + } + + return eResult; +} + +ConfigItemBase::LineType ConfigItemBase::readConfigLine( const ConfigInputStreamRef& rxStrm ) const +{ + OUString aKey, aData; + return readConfigLine( rxStrm, aKey, aData ); +} + +void ConfigItemBase::processConfigItem( + const ConfigInputStreamRef& rxStrm, const OUString& rKey, const OUString& rData ) +{ + sal_Int64 nKey; + if( StringHelper::convertStringToInt( nKey, rKey ) ) + implProcessConfigItemInt( rxStrm, nKey, rData ); + else + implProcessConfigItemStr( rxStrm, rKey, rData ); +} + +// ============================================================================ + +NameListBase::~NameListBase() +{ +} + +void NameListBase::setName( sal_Int64 nKey, const String& rName ) +{ + implSetName( nKey, rName ); +} + +void NameListBase::includeList( const NameListRef& rxList ) +{ + if( rxList.get() ) + { + for( const_iterator aIt = rxList->begin(), aEnd = rxList->end(); aIt != aEnd; ++aIt ) + maMap[ aIt->first ] = aIt->second; + implIncludeList( *rxList ); + } +} + +bool NameListBase::implIsValid() const +{ + return true; +} + +void NameListBase::implProcessConfigItemStr( + const ConfigInputStreamRef& rxStrm, const OUString& rKey, const OUString& rData ) +{ + if( rKey.equalsAscii( "include" ) ) + include( rData ); + else if( rKey.equalsAscii( "exclude" ) ) + exclude( rData ); + else + ConfigItemBase::implProcessConfigItemStr( rxStrm, rKey, rData ); +} + +void NameListBase::implProcessConfigItemInt( + const ConfigInputStreamRef& /*rxStrm*/, sal_Int64 nKey, const OUString& rData ) +{ + implSetName( nKey, rData ); +} + +void NameListBase::insertRawName( sal_Int64 nKey, const OUString& rName ) +{ + maMap[ nKey ] = rName; +} + +const OUString* NameListBase::findRawName( sal_Int64 nKey ) const +{ + const_iterator aIt = maMap.find( nKey ); + return (aIt == end()) ? 0 : &aIt->second; +} + +void NameListBase::include( const OUString& rListKeys ) +{ + OUStringVector aVec; + StringHelper::convertStringToStringList( aVec, rListKeys, true ); + for( OUStringVector::const_iterator aIt = aVec.begin(), aEnd = aVec.end(); aIt != aEnd; ++aIt ) + includeList( mrCfgData.getNameList( *aIt ) ); +} + +void NameListBase::exclude( const OUString& rKeys ) +{ + Int64Vector aVec; + StringHelper::convertStringToIntList( aVec, rKeys, true ); + for( Int64Vector::const_iterator aIt = aVec.begin(), aEnd = aVec.end(); aIt != aEnd; ++aIt ) + maMap.erase( *aIt ); +} + +// ============================================================================ + +ConstList::ConstList( const SharedConfigData& rCfgData ) : + NameListBase( rCfgData ), + maDefName( OOX_DUMP_ERR_NONAME ), + mbQuoteNames( false ) +{ +} + +void ConstList::implProcessConfigItemStr( + const ConfigInputStreamRef& rxStrm, const OUString& rKey, const OUString& rData ) +{ + if( rKey.equalsAscii( "default" ) ) + setDefaultName( rData ); + else if( rKey.equalsAscii( "quote-names" ) ) + setQuoteNames( StringHelper::convertStringToBool( rData ) ); + else + NameListBase::implProcessConfigItemStr( rxStrm, rKey, rData ); +} + +void ConstList::implSetName( sal_Int64 nKey, const OUString& rName ) +{ + insertRawName( nKey, rName ); +} + +OUString ConstList::implGetName( const Config& /*rCfg*/, sal_Int64 nKey ) const +{ + const OUString* pName = findRawName( nKey ); + OUString aName = pName ? *pName : maDefName; + if( mbQuoteNames ) + { + OUStringBuffer aBuffer( aName ); + StringHelper::enclose( aBuffer, OOX_DUMP_STRQUOTE ); + aName = aBuffer.makeStringAndClear(); + } + return aName; +} + +OUString ConstList::implGetNameDbl( const Config& /*rCfg*/, double /*fValue*/ ) const +{ + return OUString(); +} + +void ConstList::implIncludeList( const NameListBase& rList ) +{ + if( const ConstList* pConstList = dynamic_cast< const ConstList* >( &rList ) ) + { + maDefName = pConstList->maDefName; + mbQuoteNames = pConstList->mbQuoteNames; + } +} + +// ============================================================================ + +MultiList::MultiList( const SharedConfigData& rCfgData ) : + ConstList( rCfgData ), + mbIgnoreEmpty( true ) +{ +} + +void MultiList::setNamesFromVec( sal_Int64 nStartKey, const OUStringVector& rNames ) +{ + sal_Int64 nKey = nStartKey; + for( OUStringVector::const_iterator aIt = rNames.begin(), aEnd = rNames.end(); aIt != aEnd; ++aIt, ++nKey ) + if( !mbIgnoreEmpty || (aIt->getLength() > 0) ) + insertRawName( nKey, *aIt ); +} + +void MultiList::implProcessConfigItemStr( + const ConfigInputStreamRef& rxStrm, const OUString& rKey, const OUString& rData ) +{ + if( rKey.equalsAscii( "ignore-empty" ) ) + mbIgnoreEmpty = StringHelper::convertStringToBool( rData ); + else + ConstList::implProcessConfigItemStr( rxStrm, rKey, rData ); +} + +void MultiList::implSetName( sal_Int64 nKey, const OUString& rName ) +{ + OUStringVector aNames; + StringHelper::convertStringToStringList( aNames, rName, false ); + setNamesFromVec( nKey, aNames ); +} + +// ============================================================================ + +FlagsList::FlagsList( const SharedConfigData& rCfgData ) : + NameListBase( rCfgData ), + mnIgnore( 0 ) +{ +} + +void FlagsList::implProcessConfigItemStr( + const ConfigInputStreamRef& rxStrm, const OUString& rKey, const OUString& rData ) +{ + if( rKey.equalsAscii( "ignore" ) ) + { + sal_Int64 nIgnore; + if( StringHelper::convertStringToInt( nIgnore, rData ) ) + setIgnoreFlags( nIgnore ); + } + else + { + NameListBase::implProcessConfigItemStr( rxStrm, rKey, rData ); + } +} + +void FlagsList::implSetName( sal_Int64 nKey, const OUString& rName ) +{ + insertRawName( nKey, rName ); +} + +OUString FlagsList::implGetName( const Config& /*rCfg*/, sal_Int64 nKey ) const +{ + sal_Int64 nFlags = nKey; + setFlag( nFlags, mnIgnore, false ); + sal_Int64 nFound = 0; + OUStringBuffer aName; + // add known flags + for( const_iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt ) + { + sal_Int64 nMask = aIt->first; + const OUString& rFlagName = aIt->second; + bool bNegated = (rFlagName.getLength() > 0) && (rFlagName[ 0 ] == '!'); + sal_Int32 nBothSep = bNegated ? rFlagName.indexOf( '!', 1 ) : -1; + bool bFlag = getFlag( nFlags, nMask ); + if( bFlag ) + { + if( !bNegated ) + StringHelper::appendToken( aName, rFlagName ); + else if( nBothSep > 0 ) + StringHelper::appendToken( aName, rFlagName.copy( nBothSep + 1 ) ); + } + else if( bNegated ) + { + if( nBothSep > 0 ) + StringHelper::appendToken( aName, rFlagName.copy( 1, nBothSep - 1 ) ); + else + StringHelper::appendToken( aName, rFlagName.copy( 1 ) ); + } + setFlag( nFound, nMask ); + } + // add unknown flags + setFlag( nFlags, nFound, false ); + if( nFlags != 0 ) + { + OUStringBuffer aUnknown( CREATE_OUSTRING( OOX_DUMP_UNKNOWN ) ); + aUnknown.append( OOX_DUMP_ITEMSEP ); + StringHelper::appendShortHex( aUnknown, nFlags, true ); + StringHelper::enclose( aUnknown, '(', ')' ); + StringHelper::appendToken( aName, aUnknown.makeStringAndClear() ); + } + return aName.makeStringAndClear(); +} + +OUString FlagsList::implGetNameDbl( const Config& /*rCfg*/, double /*fValue*/ ) const +{ + return OUString(); +} + +void FlagsList::implIncludeList( const NameListBase& rList ) +{ + if( const FlagsList* pFlagsList = dynamic_cast< const FlagsList* >( &rList ) ) + mnIgnore = pFlagsList->mnIgnore; +} + +// ============================================================================ + +CombiList::CombiList( const SharedConfigData& rCfgData ) : + FlagsList( rCfgData ) +{ +} + +void CombiList::implSetName( sal_Int64 nKey, const OUString& rName ) +{ + if( (nKey & (nKey - 1)) != 0 ) // more than a single bit set? + { + ExtItemFormat& rItemFmt = maFmtMap[ nKey ]; + OUStringVector aRemain = rItemFmt.parse( rName ); + rItemFmt.mbShiftValue = aRemain.empty() || !aRemain.front().equalsAscii( "noshift" ); + } + else + { + FlagsList::implSetName( nKey, rName ); + } +} + +OUString CombiList::implGetName( const Config& rCfg, sal_Int64 nKey ) const +{ + sal_Int64 nFlags = nKey; + sal_Int64 nFound = 0; + OUStringBuffer aName; + // add known flag fields + for( ExtItemFormatMap::const_iterator aIt = maFmtMap.begin(), aEnd = maFmtMap.end(); aIt != aEnd; ++aIt ) + { + sal_Int64 nMask = aIt->first; + if( nMask != 0 ) + { + const ExtItemFormat& rItemFmt = aIt->second; + + sal_uInt64 nUFlags = static_cast< sal_uInt64 >( nFlags ); + sal_uInt64 nUMask = static_cast< sal_uInt64 >( nMask ); + if( rItemFmt.mbShiftValue ) + while( (nUMask & 1) == 0 ) { nUFlags >>= 1; nUMask >>= 1; } + + sal_uInt64 nUValue = nUFlags & nUMask; + sal_Int64 nSValue = static_cast< sal_Int64 >( nUValue ); + if( getFlag< sal_uInt64 >( nUValue, (nUMask + 1) >> 1 ) ) + setFlag( nSValue, static_cast< sal_Int64 >( ~nUMask ) ); + + OUStringBuffer aItem( rItemFmt.maItemName ); + OUStringBuffer aValue; + switch( rItemFmt.meDataType ) + { + case DATATYPE_INT8: StringHelper::appendValue( aValue, static_cast< sal_Int8 >( nSValue ), rItemFmt.meFmtType ); break; + case DATATYPE_UINT8: StringHelper::appendValue( aValue, static_cast< sal_uInt8 >( nUValue ), rItemFmt.meFmtType ); break; + case DATATYPE_INT16: StringHelper::appendValue( aValue, static_cast< sal_Int16 >( nSValue ), rItemFmt.meFmtType ); break; + case DATATYPE_UINT16: StringHelper::appendValue( aValue, static_cast< sal_uInt16 >( nUValue ), rItemFmt.meFmtType ); break; + case DATATYPE_INT32: StringHelper::appendValue( aValue, static_cast< sal_Int32 >( nSValue ), rItemFmt.meFmtType ); break; + case DATATYPE_UINT32: StringHelper::appendValue( aValue, static_cast< sal_uInt32 >( nUValue ), rItemFmt.meFmtType ); break; + case DATATYPE_INT64: StringHelper::appendValue( aValue, nSValue, rItemFmt.meFmtType ); break; + case DATATYPE_UINT64: StringHelper::appendValue( aValue, nUValue, rItemFmt.meFmtType ); break; + case DATATYPE_FLOAT: StringHelper::appendValue( aValue, static_cast< float >( nSValue ), rItemFmt.meFmtType ); break; + case DATATYPE_DOUBLE: StringHelper::appendValue( aValue, static_cast< double >( nSValue ), rItemFmt.meFmtType ); break; + default:; + } + StringHelper::appendToken( aItem, aValue.makeStringAndClear(), OOX_DUMP_ITEMSEP ); + if( rItemFmt.maListName.getLength() > 0 ) + { + OUString aValueName = rCfg.getName( rItemFmt.maListName, static_cast< sal_Int64 >( nUValue ) ); + StringHelper::appendToken( aItem, aValueName, OOX_DUMP_ITEMSEP ); + } + StringHelper::enclose( aItem, '(', ')' ); + StringHelper::appendToken( aName, aItem.makeStringAndClear() ); + setFlag( nFound, nMask ); + } + } + setFlag( nFlags, nFound, false ); + StringHelper::appendToken( aName, FlagsList::implGetName( rCfg, nFlags ) ); + return aName.makeStringAndClear(); +} + +void CombiList::implIncludeList( const NameListBase& rList ) +{ + if( const CombiList* pCombiList = dynamic_cast< const CombiList* >( &rList ) ) + maFmtMap = pCombiList->maFmtMap; + FlagsList::implIncludeList( rList ); +} + +// ============================================================================ + +UnitConverter::UnitConverter( const SharedConfigData& rCfgData ) : + NameListBase( rCfgData ), + mfFactor( 1.0 ) +{ +} + +void UnitConverter::implSetName( sal_Int64 /*nKey*/, const OUString& /*rName*/ ) +{ + // nothing to do +} + +OUString UnitConverter::implGetName( const Config& rCfg, sal_Int64 nKey ) const +{ + return implGetNameDbl( rCfg, static_cast< double >( nKey ) ); +} + +OUString UnitConverter::implGetNameDbl( const Config& /*rCfg*/, double fValue ) const +{ + OUStringBuffer aValue; + StringHelper::appendDec( aValue, mfFactor * fValue ); + aValue.append( maUnitName ); + return aValue.makeStringAndClear(); +} + +void UnitConverter::implIncludeList( const NameListBase& /*rList*/ ) +{ +} + +// ============================================================================ + +NameListRef NameListWrapper::getNameList( const Config& rCfg ) const +{ + return mxList.get() ? mxList : (mxList = rCfg.getNameList( maName )); +} + +// ============================================================================ +// ============================================================================ + +SharedConfigData::SharedConfigData( const OUString& rFileName, + const Reference< XMultiServiceFactory >& rxFactory, const StorageRef& rxRootStrg, + const OUString& rSysFileName, MediaDescriptor& rMediaDesc ) : + mxFactory( rxFactory ), + mxRootStrg( rxRootStrg ), + maSysFileName( rSysFileName ), + mrMediaDesc( rMediaDesc ), + mbLoaded( false ), + mbPwCancelled( false ) +{ + OUString aFileUrl = InputOutputHelper::convertFileNameToUrl( rFileName ); + if( aFileUrl.getLength() > 0 ) + { + sal_Int32 nNamePos = InputOutputHelper::getFileNamePos( aFileUrl ); + maConfigPath = aFileUrl.copy( 0, nNamePos ); + mbLoaded = readConfigFile( aFileUrl ); + } +} + +SharedConfigData::~SharedConfigData() +{ +} + +void SharedConfigData::setOption( const OUString& rKey, const OUString& rData ) +{ + maConfigData[ rKey ] = rData; +} + +const OUString* SharedConfigData::getOption( const OUString& rKey ) const +{ + ConfigDataMap::const_iterator aIt = maConfigData.find( rKey ); + return (aIt == maConfigData.end()) ? 0 : &aIt->second; +} + +void SharedConfigData::setNameList( const OUString& rListName, const NameListRef& rxList ) +{ + if( rListName.getLength() > 0 ) + maNameLists[ rListName ] = rxList; +} + +void SharedConfigData::eraseNameList( const OUString& rListName ) +{ + maNameLists.erase( rListName ); +} + +NameListRef SharedConfigData::getNameList( const OUString& rListName ) const +{ + NameListRef xList; + NameListMap::const_iterator aIt = maNameLists.find( rListName ); + if( aIt != maNameLists.end() ) + xList = aIt->second; + return xList; +} + +OUString SharedConfigData::requestPassword( ::comphelper::IDocPasswordVerifier& rVerifier ) +{ + OUString aPassword; + if( !mbPwCancelled ) + { + ::std::vector< OUString > aDefaultPasswords; + aDefaultPasswords.push_back( CREATE_OUSTRING( "VelvetSweatshop" ) ); + aPassword = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword( + rVerifier, mrMediaDesc, ::comphelper::DocPasswordRequestType_MS, &aDefaultPasswords ); + mbPwCancelled = aPassword.getLength() == 0; + } + return aPassword; +} + +bool SharedConfigData::implIsValid() const +{ + return mbLoaded && mxFactory.is() && mxRootStrg.get() && (maSysFileName.getLength() > 0); +} + +void SharedConfigData::implProcessConfigItemStr( + const ConfigInputStreamRef& rxStrm, const OUString& rKey, const OUString& rData ) +{ + if( rKey.equalsAscii( "include-config-file" ) ) + readConfigFile( maConfigPath + rData ); + else if( rKey.equalsAscii( "constlist" ) ) + readNameList< ConstList >( rxStrm, rData ); + else if( rKey.equalsAscii( "multilist" ) ) + readNameList< MultiList >( rxStrm, rData ); + else if( rKey.equalsAscii( "flagslist" ) ) + readNameList< FlagsList >( rxStrm, rData ); + else if( rKey.equalsAscii( "combilist" ) ) + readNameList< CombiList >( rxStrm, rData ); + else if( rKey.equalsAscii( "shortlist" ) ) + createShortList( rData ); + else if( rKey.equalsAscii( "unitconverter" ) ) + createUnitConverter( rData ); + else + setOption( rKey, rData ); +} + +bool SharedConfigData::readConfigFile( const OUString& rFileUrl ) +{ + bool bLoaded = maConfigFiles.count( rFileUrl ) > 0; + if( !bLoaded ) + { + Reference< XTextInputStream > xTextInStrm = + InputOutputHelper::openTextInputStream( mxFactory, rFileUrl, CREATE_OUSTRING( "UTF-8" ) ); + if( xTextInStrm.is() ) + { + maConfigFiles.insert( rFileUrl ); + readConfigBlockContents( xTextInStrm ); + bLoaded = true; + } + } + return bLoaded; +} + +void SharedConfigData::createShortList( const OUString& rData ) +{ + OUStringVector aDataVec; + StringHelper::convertStringToStringList( aDataVec, rData, false ); + if( aDataVec.size() >= 3 ) + { + sal_Int64 nStartKey; + if( StringHelper::convertStringToInt( nStartKey, aDataVec[ 1 ] ) ) + { + ::boost::shared_ptr< MultiList > xList = createNameList< MultiList >( aDataVec[ 0 ] ); + if( xList.get() ) + { + aDataVec.erase( aDataVec.begin(), aDataVec.begin() + 2 ); + xList->setNamesFromVec( nStartKey, aDataVec ); + } + } + } +} + +void SharedConfigData::createUnitConverter( const OUString& rData ) +{ + OUStringVector aDataVec; + StringHelper::convertStringToStringList( aDataVec, rData, false ); + if( aDataVec.size() >= 2 ) + { + OUString aFactor = aDataVec[ 1 ]; + bool bRecip = (aFactor.getLength() > 0) && (aFactor[ 0 ] == '/'); + if( bRecip ) + aFactor = aFactor.copy( 1 ); + double fFactor; + if( StringHelper::convertStringToDouble( fFactor, aFactor ) && (fFactor != 0.0) ) + { + ::boost::shared_ptr< UnitConverter > xList = createNameList< UnitConverter >( aDataVec[ 0 ] ); + if( xList.get() ) + { + xList->setFactor( bRecip ? (1.0 / fFactor) : fFactor ); + if( aDataVec.size() >= 3 ) + xList->setUnitName( aDataVec[ 2 ] ); + } + } + } +} + +// ============================================================================ + +Config::Config( const Config& rParent ) : + Base() // c'tor needs to be called explicitly to avoid compiler warning +{ + construct( rParent ); +} + +Config::Config( const sal_Char* pcEnvVar, const FilterBase& rFilter ) +{ + construct( pcEnvVar, rFilter ); +} + +Config::Config( const sal_Char* pcEnvVar, const Reference< XMultiServiceFactory >& rxFactory, const StorageRef& rxRootStrg, const OUString& rSysFileName, MediaDescriptor& rMediaDesc ) +{ + construct( pcEnvVar, rxFactory, rxRootStrg, rSysFileName, rMediaDesc ); +} + +Config::~Config() +{ +} + +void Config::construct( const Config& rParent ) +{ + *this = rParent; +} + +void Config::construct( const sal_Char* pcEnvVar, const FilterBase& rFilter ) +{ + if( rFilter.getFileUrl().getLength() > 0 ) + construct( pcEnvVar, rFilter.getGlobalFactory(), rFilter.getStorage(), rFilter.getFileUrl(), rFilter.getMediaDescriptor() ); +} + +void Config::construct( const sal_Char* pcEnvVar, const Reference< XMultiServiceFactory >& rxFactory, const StorageRef& rxRootStrg, const OUString& rSysFileName, MediaDescriptor& rMediaDesc ) +{ + if( pcEnvVar && rxRootStrg.get() && (rSysFileName.getLength() > 0) ) + if( const sal_Char* pcFileName = ::getenv( pcEnvVar ) ) + mxCfgData.reset( new SharedConfigData( OUString::createFromAscii( pcFileName ), rxFactory, rxRootStrg, rSysFileName, rMediaDesc ) ); +} + +void Config::setStringOption( const String& rKey, const String& rData ) +{ + mxCfgData->setOption( rKey, rData ); +} + +const OUString& Config::getStringOption( const String& rKey, const OUString& rDefault ) const +{ + const OUString* pData = implGetOption( rKey ); + return pData ? *pData : rDefault; +} + +bool Config::getBoolOption( const String& rKey, bool bDefault ) const +{ + const OUString* pData = implGetOption( rKey ); + return pData ? StringHelper::convertStringToBool( *pData ) : bDefault; +} + +bool Config::isDumperEnabled() const +{ + return getBoolOption( "enable-dumper", false ); +} + +bool Config::isImportEnabled() const +{ + return getBoolOption( "enable-import", true ); +} + +void Config::setNameList( const String& rListName, const NameListRef& rxList ) +{ + mxCfgData->setNameList( rListName, rxList ); +} + +void Config::eraseNameList( const String& rListName ) +{ + mxCfgData->eraseNameList( rListName ); +} + +NameListRef Config::getNameList( const String& rListName ) const +{ + return implGetNameList( rListName ); +} + +OUString Config::requestPassword( ::comphelper::IDocPasswordVerifier& rVerifier ) +{ + return mxCfgData->requestPassword( rVerifier ); +} + +bool Config::isPasswordCancelled() const +{ + return mxCfgData->isPasswordCancelled(); +} + +bool Config::implIsValid() const +{ + return isValid( mxCfgData ); +} + +const OUString* Config::implGetOption( const OUString& rKey ) const +{ + return mxCfgData->getOption( rKey ); +} + +NameListRef Config::implGetNameList( const OUString& rListName ) const +{ + return mxCfgData->getNameList( rListName ); +} + +// ============================================================================ +// ============================================================================ + +Output::Output( const Reference< XTextOutputStream >& rxStrm ) +{ + construct( rxStrm ); +} + +Output::Output( const Reference< XMultiServiceFactory >& rxFactory, const OUString& rFileName ) +{ + construct( InputOutputHelper::openTextOutputStream( rxFactory, rFileName, CREATE_OUSTRING( "UTF-8" ) ) ); +} + +// ---------------------------------------------------------------------------- + +void Output::newLine() +{ + if( maLine.getLength() > 0 ) + { + mxStrm->writeString( maIndent ); + maLine.append( sal_Unicode( '\n' ) ); + mxStrm->writeString( maLine.makeStringAndClear() ); + mnCol = 0; + mnLastItem = 0; + } +} + +void Output::emptyLine( size_t nCount ) +{ + for( size_t nIdx = 0; nIdx < nCount; ++nIdx ) + mxStrm->writeString( OUString( sal_Unicode( '\n' ) ) ); +} + +void Output::incIndent() +{ + OUStringBuffer aBuffer( maIndent ); + StringHelper::appendChar( aBuffer, ' ', OOX_DUMP_INDENT ); + maIndent = aBuffer.makeStringAndClear(); +} + +void Output::decIndent() +{ + if( maIndent.getLength() >= OOX_DUMP_INDENT ) + maIndent = maIndent.copy( OOX_DUMP_INDENT ); +} + +void Output::resetIndent() +{ + maIndent = OUString(); +} + +void Output::startTable( sal_Int32 nW1 ) +{ + startTable( 1, &nW1 ); +} + +void Output::startTable( sal_Int32 nW1, sal_Int32 nW2 ) +{ + sal_Int32 pnColWidths[ 2 ]; + pnColWidths[ 0 ] = nW1; + pnColWidths[ 1 ] = nW2; + startTable( 2, pnColWidths ); +} + +void Output::startTable( sal_Int32 nW1, sal_Int32 nW2, sal_Int32 nW3 ) +{ + sal_Int32 pnColWidths[ 3 ]; + pnColWidths[ 0 ] = nW1; + pnColWidths[ 1 ] = nW2; + pnColWidths[ 2 ] = nW3; + startTable( 3, pnColWidths ); +} + +void Output::startTable( sal_Int32 nW1, sal_Int32 nW2, sal_Int32 nW3, sal_Int32 nW4 ) +{ + sal_Int32 pnColWidths[ 4 ]; + pnColWidths[ 0 ] = nW1; + pnColWidths[ 1 ] = nW2; + pnColWidths[ 2 ] = nW3; + pnColWidths[ 3 ] = nW4; + startTable( 4, pnColWidths ); +} + +void Output::startTable( size_t nColCount, const sal_Int32* pnColWidths ) +{ + maColPos.clear(); + maColPos.push_back( 0 ); + sal_Int32 nColPos = 0; + for( size_t nCol = 0; nCol < nColCount; ++nCol ) + { + nColPos = nColPos + pnColWidths[ nCol ]; + maColPos.push_back( nColPos ); + } +} + +void Output::tab() +{ + tab( mnCol + 1 ); +} + +void Output::tab( size_t nCol ) +{ + mnCol = nCol; + if( mnCol < maColPos.size() ) + { + sal_Int32 nColPos = maColPos[ mnCol ]; + if( maLine.getLength() >= nColPos ) + maLine.setLength( ::std::max< sal_Int32 >( nColPos - 1, 0 ) ); + StringHelper::appendChar( maLine, ' ', nColPos - maLine.getLength() ); + } + else + { + StringHelper::appendChar( maLine, ' ', 2 ); + } +} + +void Output::endTable() +{ + maColPos.clear(); +} + +void Output::resetItemIndex( sal_Int64 nIdx ) +{ + mnItemIdx = nIdx; +} + +void Output::startItem( const String& rItemName ) +{ + if( mnItemLevel == 0 ) + { + if( (mnMultiLevel > 0) && (maLine.getLength() > 0) ) + tab(); + if( rItemName.has() ) + { + writeItemName( rItemName ); + writeChar( OOX_DUMP_ITEMSEP ); + } + } + ++mnItemLevel; + mnLastItem = maLine.getLength(); +} + +void Output::contItem() +{ + if( mnItemLevel > 0 ) + { + if( (maLine.getLength() == 0) || (maLine[ maLine.getLength() - 1 ] != OOX_DUMP_ITEMSEP) ) + writeChar( OOX_DUMP_ITEMSEP ); + mnLastItem = maLine.getLength(); + } +} + +void Output::endItem() +{ + if( mnItemLevel > 0 ) + { + maLastItem = OUString( maLine.getStr() + mnLastItem ); + if( (maLastItem.getLength() == 0) && (mnLastItem > 0) && (maLine[ mnLastItem - 1 ] == OOX_DUMP_ITEMSEP) ) + maLine.setLength( mnLastItem - 1 ); + --mnItemLevel; + } + if( mnItemLevel == 0 ) + { + if( mnMultiLevel == 0 ) + newLine(); + } + else + contItem(); +} + +void Output::startMultiItems() +{ + ++mnMultiLevel; +} + +void Output::endMultiItems() +{ + if( mnMultiLevel > 0 ) + --mnMultiLevel; + if( mnMultiLevel == 0 ) + newLine(); +} + +// ---------------------------------------------------------------------------- + +void Output::writeChar( sal_Unicode cChar, sal_Int32 nCount ) +{ + StringHelper::appendEncChar( maLine, cChar, nCount ); +} + +void Output::writeAscii( const sal_Char* pcStr ) +{ + if( pcStr ) + maLine.appendAscii( pcStr ); +} + +void Output::writeString( const OUString& rStr ) +{ + StringHelper::appendEncString( maLine, rStr ); +} + +void Output::writeArray( const sal_uInt8* pnData, sal_Size nSize, sal_Unicode cSep ) +{ + const sal_uInt8* pnEnd = pnData ? (pnData + nSize) : 0; + for( const sal_uInt8* pnByte = pnData; pnByte < pnEnd; ++pnByte ) + { + if( pnByte > pnData ) + writeChar( cSep ); + writeHex( *pnByte, false ); + } +} + +void Output::writeBool( bool bData ) +{ + StringHelper::appendBool( maLine, bData ); +} + +void Output::writeColorABGR( sal_Int32 nColor ) +{ + writeChar( 'a' ); + writeDec( static_cast< sal_uInt8 >( nColor >> 24 ) ); + writeAscii( ",r" ); + writeDec( static_cast< sal_uInt8 >( nColor ) ); + writeAscii( ",g" ); + writeDec( static_cast< sal_uInt8 >( nColor >> 8 ) ); + writeAscii( ",b" ); + writeDec( static_cast< sal_uInt8 >( nColor >> 16 ) ); +} + +void Output::writeDateTime( const DateTime& rDateTime ) +{ + writeDec( rDateTime.Year, 4, '0' ); + writeChar( '-' ); + writeDec( rDateTime.Month, 2, '0' ); + writeChar( '-' ); + writeDec( rDateTime.Day, 2, '0' ); + writeChar( 'T' ); + writeDec( rDateTime.Hours, 2, '0' ); + writeChar( ':' ); + writeDec( rDateTime.Minutes, 2, '0' ); + writeChar( ':' ); + writeDec( rDateTime.Seconds, 2, '0' ); +} + +void Output::writeColIndex( sal_Int32 nCol ) +{ + StringHelper::appendAddrCol( maLine, nCol, true ); +} + +void Output::writeRowIndex( sal_Int32 nRow ) +{ + StringHelper::appendAddrRow( maLine, nRow, true ); +} + +void Output::writeColRowRange( sal_Int32 nColRow1, sal_Int32 nColRow2 ) +{ + writeDec( nColRow1 ); + writeChar( OOX_DUMP_RANGESEP ); + writeDec( nColRow2 ); +} + +void Output::writeColRange( sal_Int32 nCol1, sal_Int32 nCol2 ) +{ + writeColIndex( nCol1 ); + writeChar( OOX_DUMP_RANGESEP ); + writeColIndex( nCol2 ); +} + +void Output::writeRowRange( sal_Int32 nRow1, sal_Int32 nRow2 ) +{ + writeRowIndex( nRow1 ); + writeChar( OOX_DUMP_RANGESEP ); + writeRowIndex( nRow2 ); +} + +void Output::writeAddress( const Address& rPos ) +{ + StringHelper::appendAddress( maLine, rPos ); +} + +void Output::writeRange( const Range& rRange ) +{ + StringHelper::appendRange( maLine, rRange ); +} + +void Output::writeRangeList( const RangeList& rRanges ) +{ + StringHelper::appendRangeList( maLine, rRanges ); +} + +// ---------------------------------------------------------------------------- + +void Output::construct( const Reference< XTextOutputStream >& rxStrm ) +{ + mxStrm = rxStrm; + mnCol = mnItemLevel = mnMultiLevel = 0; + mnItemIdx = 0; + mnLastItem = 0; + if( mxStrm.is() ) + { + writeChar( OOX_DUMP_BOM ); + newLine(); + } +} + +bool Output::implIsValid() const +{ + return mxStrm.is(); +} + +void Output::writeItemName( const String& rItemName ) +{ + if( rItemName.has() && (rItemName[ 0 ] == '#') ) + { + writeString( rItemName.copy( 1 ) ); + StringHelper::appendIndex( maLine, mnItemIdx++ ); + } + else + writeString( rItemName ); +} + +// ============================================================================ + +StorageIterator::StorageIterator( const StorageRef& rxStrg ) : + mxStrg( rxStrg ) +{ + if( mxStrg.get() ) + mxStrg->getElementNames( maNames ); + maIt = maNames.begin(); +} + +StorageIterator::~StorageIterator() +{ +} + +size_t StorageIterator::getElementCount() const +{ + return maNames.size(); +} + +StorageIterator& StorageIterator::operator++() +{ + if( maIt != maNames.end() ) + ++maIt; + return *this; +} + +OUString StorageIterator::getName() const +{ + OUString aName; + if( maIt != maNames.end() ) + aName = *maIt; + return aName; +} + +bool StorageIterator::isStream() const +{ + return isValid() && mxStrg->openInputStream( *maIt ).is(); +} + +bool StorageIterator::isStorage() const +{ + if( !isValid() ) + return false; + StorageRef xStrg = mxStrg->openSubStorage( *maIt, false ); + return xStrg.get() && xStrg->isStorage(); +} + +bool StorageIterator::implIsValid() const +{ + return mxStrg.get() && mxStrg->isStorage() && (maIt != maNames.end()); +} + +// ============================================================================ +// ============================================================================ + +ObjectBase::~ObjectBase() +{ +} + +void ObjectBase::construct( const ConfigRef& rxConfig ) +{ + mxConfig = rxConfig; +} + +void ObjectBase::construct( const ObjectBase& rParent ) +{ + *this = rParent; +} + +void ObjectBase::dump() +{ + if( isValid() ) + implDump(); +} + +bool ObjectBase::implIsValid() const +{ + return isValid( mxConfig ); +} + +void ObjectBase::implDump() +{ +} + +void ObjectBase::reconstructConfig( const ConfigRef& rxConfig ) +{ + if( isValid( rxConfig ) ) + mxConfig = rxConfig; +} + +// ============================================================================ +// ============================================================================ + +void StorageObjectBase::construct( const ObjectBase& rParent, const StorageRef& rxStrg, const OUString& rSysPath ) +{ + ObjectBase::construct( rParent ); + mxStrg = rxStrg; + maSysPath = rSysPath; +} + +void StorageObjectBase::construct( const ObjectBase& rParent ) +{ + ObjectBase::construct( rParent ); + if( ObjectBase::implIsValid() ) + { + mxStrg = cfg().getRootStorage(); + maSysPath = cfg().getSysFileName(); + } +} + +bool StorageObjectBase::implIsValid() const +{ + return mxStrg.get() && mxStrg->isStorage() && (maSysPath.getLength() > 0) && ObjectBase::implIsValid(); +} + +void StorageObjectBase::implDump() +{ + try + { + Reference< XSimpleFileAccess > xFileAccess( getFactory()->createInstance( CREATE_OUSTRING( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY_THROW ); + xFileAccess->kill( maSysPath + OOX_DUMP_DUMPEXT ); + } + catch( Exception& ) + { + } + extractStorage( mxStrg, OUString(), maSysPath ); +} + +void StorageObjectBase::implDumpStream( const BinaryInputStreamRef&, const OUString&, const OUString&, const OUString& ) +{ +} + +void StorageObjectBase::implDumpStorage( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rSysPath ) +{ + extractStorage( rxStrg, rStrgPath, rSysPath ); +} + +void StorageObjectBase::addPreferredStream( const String& rStrmName ) +{ + if( rStrmName.has() ) + maPreferred.push_back( PreferredItem( rStrmName, false ) ); +} + +void StorageObjectBase::addPreferredStorage( const String& rStrgPath ) +{ + if( rStrgPath.has() ) + maPreferred.push_back( PreferredItem( rStrgPath, true ) ); +} + +OUString StorageObjectBase::getSysFileName( const OUString& rStrmName, const OUString& rSysOutPath ) +{ + // encode all characters < 0x20 + OUStringBuffer aBuffer; + StringHelper::appendEncString( aBuffer, rStrmName, false ); + + // replace all characters reserved in file system + OUString aFileName = aBuffer.makeStringAndClear(); + static const sal_Unicode spcReserved[] = { '/', '\\', ':', '*', '?', '<', '>', '|' }; + for( const sal_Unicode* pcChar = spcReserved; pcChar < STATIC_ARRAY_END( spcReserved ); ++pcChar ) + aFileName = aFileName.replace( *pcChar, '_' ); + + // build full path + return rSysOutPath + OUString( sal_Unicode( '/' ) ) + aFileName; +} + +void StorageObjectBase::extractStream( StorageBase& rStrg, const OUString& rStrgPath, const OUString& rStrmName, const OUString& rSysFileName ) +{ + BinaryXInputStream aInStrm( rStrg.openInputStream( rStrmName ), true ); + if( !aInStrm.isEof() ) + { + BinaryXOutputStream aOutStrm( InputOutputHelper::openOutputStream( getFactory(), rSysFileName ), true ); + if( !aOutStrm.isEof() ) + aOutStrm.copyStream( aInStrm ); + } + BinaryXInputStreamRef xDumpStrm( new BinaryXInputStream( InputOutputHelper::openInputStream( getFactory(), rSysFileName ), true ) ); + if( !xDumpStrm->isEof() ) + implDumpStream( xDumpStrm, rStrgPath, rStrmName, rSysFileName ); +} + +void StorageObjectBase::extractStorage( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rSysPath ) +{ + OUString aSysOutPath = rSysPath + OOX_DUMP_DUMPEXT; + + // create directory in file system + ::osl::FileBase::RC eRes = ::osl::Directory::create( aSysOutPath ); + if( (eRes != ::osl::FileBase::E_None) && (eRes != ::osl::FileBase::E_EXIST) ) + return; + + // process preferred storages and streams in root storage first + if( rStrgPath.getLength() == 0 ) + for( PreferredItemVector::iterator aIt = maPreferred.begin(), aEnd = maPreferred.end(); aIt != aEnd; ++aIt ) + extractItem( rxStrg, rStrgPath, aIt->maName, aSysOutPath, aIt->mbStorage, !aIt->mbStorage ); + + // process children of the storage + for( StorageIterator aIt( rxStrg ); aIt.isValid(); ++aIt ) + { + // skip processed preferred items + OUString aItemName = aIt.getName(); + bool bFound = false; + if( rStrgPath.getLength() == 0 ) + for( PreferredItemVector::iterator aIIt = maPreferred.begin(), aIEnd = maPreferred.end(); !bFound && (aIIt != aIEnd); ++aIIt ) + bFound = aIIt->maName == aItemName; + if( !bFound ) + extractItem( rxStrg, rStrgPath, aItemName, aSysOutPath, aIt.isStorage(), aIt.isStream() ); + } +} + +void StorageObjectBase::extractItem( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rItemName, const OUString& rSysOutPath, bool bIsStrg, bool bIsStrm ) +{ + OUString aSysFileName = getSysFileName( rItemName, rSysOutPath ); + if( bIsStrg ) + { + OUStringBuffer aStrgPath( rStrgPath ); + StringHelper::appendToken( aStrgPath, rItemName, '/' ); + implDumpStorage( rxStrg->openSubStorage( rItemName, false ), aStrgPath.makeStringAndClear(), aSysFileName ); + } + else if( bIsStrm ) + { + extractStream( *rxStrg, rStrgPath, rItemName, aSysFileName ); + } +} + +// ============================================================================ +// ============================================================================ + +OutputObjectBase::~OutputObjectBase() +{ +} + +void OutputObjectBase::construct( const ObjectBase& rParent, const OUString& rSysFileName ) +{ + ObjectBase::construct( rParent ); + if( ObjectBase::implIsValid() ) + mxOut.reset( new Output( getFactory(), rSysFileName + OOX_DUMP_DUMPEXT ) ); +} + +void OutputObjectBase::construct( const ObjectBase& rParent, const OutputRef& rxOut ) +{ + ObjectBase::construct( rParent ); + mxOut = rxOut; +} + +void OutputObjectBase::construct( const OutputObjectBase& rParent ) +{ + *this = rParent; +} + +bool OutputObjectBase::implIsValid() const +{ + return isValid( mxOut ) && ObjectBase::implIsValid(); +} + +void OutputObjectBase::writeEmptyItem( const String& rName ) +{ + ItemGuard aItem( *mxOut, rName ); +} + +void OutputObjectBase::writeInfoItem( const String& rName, const String& rData ) +{ + ItemGuard aItem( *mxOut, rName ); + mxOut->writeString( rData ); +} + +void OutputObjectBase::writeCharItem( const String& rName, sal_Unicode cData ) +{ + ItemGuard aItem( *mxOut, rName ); + mxOut->writeChar( OOX_DUMP_STRQUOTE ); + mxOut->writeChar( cData ); + mxOut->writeChar( OOX_DUMP_STRQUOTE ); +} + +void OutputObjectBase::writeStringItem( const String& rName, const OUString& rData ) +{ + ItemGuard aItem( *mxOut, rName ); + mxOut->writeAscii( "(len=" ); + mxOut->writeDec( rData.getLength() ); + mxOut->writeAscii( ")," ); + OUStringBuffer aValue( rData.copy( 0, ::std::min( rData.getLength(), OOX_DUMP_MAXSTRLEN ) ) ); + StringHelper::enclose( aValue, OOX_DUMP_STRQUOTE ); + mxOut->writeString( aValue.makeStringAndClear() ); + if( rData.getLength() > OOX_DUMP_MAXSTRLEN ) + mxOut->writeAscii( ",cut" ); +} + +void OutputObjectBase::writeArrayItem( const String& rName, const sal_uInt8* pnData, sal_Size nSize, sal_Unicode cSep ) +{ + ItemGuard aItem( *mxOut, rName ); + mxOut->writeArray( pnData, nSize, cSep ); +} + +void OutputObjectBase::writeBoolItem( const String& rName, bool bData ) +{ + ItemGuard aItem( *mxOut, rName ); + mxOut->writeBool( bData ); +} + +double OutputObjectBase::writeRkItem( const String& rName, sal_Int32 nRk ) +{ + MultiItemsGuard aMultiGuard( out() ); + writeHexItem( rName, static_cast< sal_uInt32 >( nRk ), "RK-FLAGS" ); + double fValue = ::oox::xls::BiffHelper::calcDoubleFromRk( nRk ); + writeDecItem( "decoded", fValue ); + return fValue; +} + +void OutputObjectBase::writeColorABGRItem( const String& rName, sal_Int32 nColor ) +{ + ItemGuard aItem( *mxOut, rName ); + writeHexItem( rName, nColor ); + mxOut->writeColorABGR( nColor ); +} + +void OutputObjectBase::writeDateTimeItem( const String& rName, const DateTime& rDateTime ) +{ + ItemGuard aItem( *mxOut, rName ); + mxOut->writeDateTime( rDateTime ); +} + +void OutputObjectBase::writeGuidItem( const String& rName, const OUString& rGuid ) +{ + ItemGuard aItem( *mxOut, rName ); + mxOut->writeString( rGuid ); + aItem.cont(); + mxOut->writeString( cfg().getStringOption( rGuid, OUString() ) ); +} + +void OutputObjectBase::writeColIndexItem( const String& rName, sal_Int32 nCol ) +{ + Output& rOut = out(); + ItemGuard aItem( rOut, rName ); + rOut.writeDec( nCol ); + aItem.cont(); + rOut.writeColIndex( nCol ); +} + +void OutputObjectBase::writeRowIndexItem( const String& rName, sal_Int32 nRow ) +{ + Output& rOut = out(); + ItemGuard aItem( rOut, rName ); + rOut.writeDec( nRow ); + aItem.cont(); + rOut.writeRowIndex( nRow ); +} + +void OutputObjectBase::writeColRangeItem( const String& rName, sal_Int32 nCol1, sal_Int32 nCol2 ) +{ + Output& rOut = out(); + ItemGuard aItem( rOut, rName ); + rOut.writeColRowRange( nCol1, nCol2 ); + aItem.cont(); + rOut.writeColRange( nCol1, nCol2 ); +} + +void OutputObjectBase::writeRowRangeItem( const String& rName, sal_Int32 nRow1, sal_Int32 nRow2 ) +{ + Output& rOut = out(); + ItemGuard aItem( rOut, rName ); + rOut.writeColRowRange( nRow1, nRow2 ); + aItem.cont(); + rOut.writeRowRange( nRow1, nRow2 ); +} + +void OutputObjectBase::writeAddressItem( const String& rName, const Address& rPos ) +{ + ItemGuard aItem( out(), rName ); + StringHelper::appendAddress( out().getLine(), rPos ); +} + +void OutputObjectBase::writeRangeItem( const String& rName, const Range& rRange ) +{ + ItemGuard aItem( out(), rName ); + StringHelper::appendRange( out().getLine(), rRange ); +} + +void OutputObjectBase::writeRangeListItem( const String& rName, const RangeList& rRanges ) +{ + MultiItemsGuard aMultiGuard( out() ); + writeEmptyItem( rName ); + writeDecItem( "count", static_cast< sal_uInt16 >( rRanges.size() ) ); + ItemGuard aItem( out(), "ranges" ); + StringHelper::appendRangeList( out().getLine(), rRanges ); +} + +void OutputObjectBase::writeTokenAddressItem( const String& rName, const TokenAddress& rPos, bool bNameMode ) +{ + ItemGuard aItem( out(), rName ); + StringHelper::appendAddress( out().getLine(), rPos, bNameMode ); +} + +void OutputObjectBase::writeTokenAddress3dItem( const String& rName, const OUString& rRef, const TokenAddress& rPos, bool bNameMode ) +{ + ItemGuard aItem( out(), rName ); + out().writeString( rRef ); + StringHelper::appendAddress( out().getLine(), rPos, bNameMode ); +} + +void OutputObjectBase::writeTokenRangeItem( const String& rName, const TokenRange& rRange, bool bNameMode ) +{ + ItemGuard aItem( out(), rName ); + StringHelper::appendRange( out().getLine(), rRange, bNameMode ); +} + +void OutputObjectBase::writeTokenRange3dItem( const String& rName, const OUString& rRef, const TokenRange& rRange, bool bNameMode ) +{ + ItemGuard aItem( out(), rName ); + out().writeString( rRef ); + StringHelper::appendRange( out().getLine(), rRange, bNameMode ); +} + +// ============================================================================ +// ============================================================================ + +InputObjectBase::~InputObjectBase() +{ +} + +void InputObjectBase::construct( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName ) +{ + OutputObjectBase::construct( rParent, rSysFileName ); + mxStrm = rxStrm; +} + +void InputObjectBase::construct( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, const OutputRef& rxOut ) +{ + OutputObjectBase::construct( rParent, rxOut ); + mxStrm = rxStrm; +} + +void InputObjectBase::construct( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxStrm ) +{ + OutputObjectBase::construct( rParent ); + mxStrm = rxStrm; +} + +void InputObjectBase::construct( const InputObjectBase& rParent ) +{ + *this = rParent; +} + +bool InputObjectBase::implIsValid() const +{ + return mxStrm.get() && OutputObjectBase::implIsValid(); +} + +void InputObjectBase::skipBlock( sal_Int64 nBytes, bool bShowSize ) +{ + sal_Int64 nEndPos = ::std::min< sal_Int64 >( mxStrm->tell() + nBytes, mxStrm->getLength() ); + if( mxStrm->tell() < nEndPos ) + { + if( bShowSize ) + writeDecItem( "skipped-data-size", static_cast< sal_uInt64 >( nEndPos - mxStrm->tell() ) ); + mxStrm->seek( nEndPos ); + } +} + +void InputObjectBase::dumpRawBinary( sal_Int64 nBytes, bool bShowOffset, bool bStream ) +{ + Output& rOut = out(); + TableGuard aTabGuard( rOut, + bShowOffset ? 12 : 0, + 3 * OOX_DUMP_BYTESPERLINE / 2 + 1, + 3 * OOX_DUMP_BYTESPERLINE / 2 + 1, + OOX_DUMP_BYTESPERLINE / 2 + 1 ); + + sal_Int64 nMaxShowSize = cfg().getIntOption< sal_Int64 >( + bStream ? "max-binary-stream-size" : "max-binary-data-size", SAL_MAX_INT64 ); + + bool bSeekable = mxStrm->getLength() >= 0; + sal_Int64 nEndPos = bSeekable ? ::std::min< sal_Int64 >( mxStrm->tell() + nBytes, mxStrm->getLength() ) : 0; + sal_Int64 nDumpEnd = bSeekable ? ::std::min< sal_Int64 >( mxStrm->tell() + nMaxShowSize, nEndPos ) : nMaxShowSize; + sal_Int64 nPos = bSeekable ? mxStrm->tell() : 0; + bool bLoop = true; + + while( bLoop && (nPos < nDumpEnd) ) + { + rOut.writeHex( static_cast< sal_uInt32 >( nPos ) ); + rOut.tab(); + + sal_uInt8 pnLineData[ OOX_DUMP_BYTESPERLINE ]; + sal_Int32 nLineSize = bSeekable ? ::std::min( static_cast< sal_Int32 >( nDumpEnd - mxStrm->tell() ), OOX_DUMP_BYTESPERLINE ) : OOX_DUMP_BYTESPERLINE; + sal_Int32 nReadSize = mxStrm->readMemory( pnLineData, nLineSize ); + bLoop = nReadSize == nLineSize; + nPos += nReadSize; + + if( nReadSize > 0 ) + { + const sal_uInt8* pnByte = 0; + const sal_uInt8* pnEnd = 0; + for( pnByte = pnLineData, pnEnd = pnLineData + nReadSize; pnByte != pnEnd; ++pnByte ) + { + if( (pnByte - pnLineData) == (OOX_DUMP_BYTESPERLINE / 2) ) rOut.tab(); + rOut.writeHex( *pnByte, false ); + rOut.writeChar( ' ' ); + } + + aTabGuard.tab( 3 ); + for( pnByte = pnLineData, pnEnd = pnLineData + nReadSize; pnByte != pnEnd; ++pnByte ) + { + if( (pnByte - pnLineData) == (OOX_DUMP_BYTESPERLINE / 2) ) rOut.tab(); + rOut.writeChar( static_cast< sal_Unicode >( (*pnByte < 0x20) ? '.' : *pnByte ) ); + } + rOut.newLine(); + } + } + + // skip undumped data + if( bSeekable ) + skipBlock( nEndPos - mxStrm->tell() ); +} + +void InputObjectBase::dumpBinary( const String& rName, sal_Int64 nBytes, bool bShowOffset ) +{ + { + MultiItemsGuard aMultiGuard( out() ); + writeEmptyItem( rName ); + writeDecItem( "size", nBytes ); + } + IndentGuard aIndGuard( out() ); + dumpRawBinary( nBytes, bShowOffset ); +} + +void InputObjectBase::dumpRemaining( sal_Int64 nBytes ) +{ + if( nBytes > 0 ) + { + if( cfg().getBoolOption( "show-trailing-unknown", true ) ) + dumpBinary( "remaining-data", nBytes, false ); + else + skipBlock( nBytes ); + } +} + +void InputObjectBase::dumpRemainingTo( sal_Int64 nPos ) +{ + if( mxStrm->isEof() ) + writeInfoItem( "stream-state", OOX_DUMP_ERR_STREAM ); + else + dumpRemaining( nPos - mxStrm->tell() ); + mxStrm->seek( nPos ); +} + +void InputObjectBase::dumpRemainingStream() +{ + dumpRemainingTo( mxStrm->getLength() ); +} + +void InputObjectBase::dumpArray( const String& rName, sal_Int32 nBytes, sal_Unicode cSep ) +{ + sal_Int32 nDumpSize = getLimitedValue< sal_Int32, sal_Int64 >( mxStrm->getLength() - mxStrm->tell(), 0, nBytes ); + if( nDumpSize > OOX_DUMP_MAXARRAY ) + { + dumpBinary( rName, nBytes, false ); + } + else if( nDumpSize > 1 ) + { + sal_uInt8 pnData[ OOX_DUMP_MAXARRAY ]; + mxStrm->readMemory( pnData, nDumpSize ); + writeArrayItem( rName, pnData, nDumpSize, cSep ); + } + else if( nDumpSize == 1 ) + dumpHex< sal_uInt8 >( rName ); +} + +sal_Unicode InputObjectBase::dumpChar( const String& rName, rtl_TextEncoding eTextEnc ) +{ + sal_uInt8 nChar; + *mxStrm >> nChar; + OUString aChar = OStringToOUString( OString( static_cast< sal_Char >( nChar ) ), eTextEnc ); + sal_Unicode cChar = (aChar.getLength() > 0) ? aChar[ 0 ] : 0; + writeCharItem( rName( "char" ), cChar ); + return cChar; +} + +sal_Unicode InputObjectBase::dumpUnicode( const String& rName ) +{ + sal_uInt16 nChar; + *mxStrm >> nChar; + sal_Unicode cChar = static_cast< sal_Unicode >( nChar ); + writeCharItem( rName( "char" ), cChar ); + return cChar; +} + +OUString InputObjectBase::dumpCharArray( const String& rName, sal_Int32 nLen, rtl_TextEncoding eTextEnc ) +{ + sal_Int32 nDumpSize = getLimitedValue< sal_Int32, sal_Int64 >( mxStrm->getLength() - mxStrm->tell(), 0, nLen ); + OUString aString; + if( nDumpSize > 0 ) + { + ::std::vector< sal_Char > aBuffer( static_cast< sal_Size >( nLen ) + 1 ); + sal_Int32 nCharsRead = mxStrm->readMemory( &aBuffer.front(), nLen ); + aBuffer[ nCharsRead ] = 0; + aString = OStringToOUString( OString( &aBuffer.front() ), eTextEnc ); + } + writeStringItem( rName( "text" ), aString ); + return aString; +} + +OUString InputObjectBase::dumpUnicodeArray( const String& rName, sal_Int32 nLen ) +{ + OUStringBuffer aBuffer; + for( sal_Int32 nIndex = 0; !mxStrm->isEof() && (nIndex < nLen); ++nIndex ) + aBuffer.append( static_cast< sal_Unicode >( mxStrm->readuInt16() ) ); + OUString aString = aBuffer.makeStringAndClear(); + writeStringItem( rName( "text" ), aString ); + return aString; +} + +OUString InputObjectBase::dumpNullCharArray( const String& rName, rtl_TextEncoding eTextEnc ) +{ + OStringBuffer aBuffer; + sal_uInt8 nChar; + for( *mxStrm >> nChar; !mxStrm->isEof() && (nChar > 0); *mxStrm >> nChar ) + aBuffer.append( static_cast< sal_Char >( nChar ) ); + OUString aString = OStringToOUString( aBuffer.makeStringAndClear(), eTextEnc ); + writeStringItem( rName( "text" ), aString ); + return aString; +} + +OUString InputObjectBase::dumpNullUnicodeArray( const String& rName ) +{ + OUStringBuffer aBuffer; + sal_uInt16 nChar; + for( *mxStrm >> nChar; !mxStrm->isEof() && (nChar > 0); *mxStrm >> nChar ) + aBuffer.append( static_cast< sal_Unicode >( nChar ) ); + OUString aString = aBuffer.makeStringAndClear(); + writeStringItem( rName( "text" ), aString ); + return aString; +} + +double InputObjectBase::dumpRk( const String& rName ) +{ + sal_Int32 nRk; + *mxStrm >> nRk; + return writeRkItem( rName( "rk-value" ), nRk ); +} + +sal_Int32 InputObjectBase::dumpColorABGR( const String& rName ) +{ + sal_Int32 nColor; + *mxStrm >> nColor; + writeColorABGRItem( rName( "color" ), nColor ); + return nColor; +} + +DateTime InputObjectBase::dumpFileTime( const String& rName ) +{ + DateTime aDateTime; + + ItemGuard aItem( out(), rName( "file-time" ) ); + sal_Int64 nFileTime = dumpDec< sal_Int64 >( EMPTY_STRING ); + // file time is in 10^-7 seconds (100 nanoseconds), convert to 1/100 seconds + nFileTime /= 100000; + // entire days + sal_Int64 nDays = nFileTime / sal_Int64( 360000 * 24 ); + // number of entire years + sal_Int64 nYears = (nDays - (nDays / (4 * 365)) + (nDays / (100 * 365)) - (nDays / (400 * 365))) / 365; + // remaining days in the year + sal_Int64 nDaysInYear = nDays - (nYears * 365 + nYears / 4 - nYears / 100 + nYears / 400); + // the year (file dates start from 1601-01-01) + aDateTime.Year = static_cast< sal_uInt16 >( 1601 + nYears ); + // leap year? + bool bLeap = ((aDateTime.Year % 4 == 0) && (aDateTime.Year % 100 != 0)) || (aDateTime.Year % 400 == 0); + // static arrays with number of days in month + static const sal_Int64 spnDaysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + static const sal_Int64 spnDaysInMonthL[] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + const sal_Int64* pnDaysInMonth = bLeap ? spnDaysInMonthL : spnDaysInMonth; + // the month + aDateTime.Month = 1; + while( nDaysInYear >= *pnDaysInMonth ) + { + nDaysInYear -= *pnDaysInMonth++; + ++aDateTime.Month; + } + // the day + aDateTime.Day = static_cast< sal_uInt16 >( nDaysInYear + 1 ); + // number of 1/100 seconds in the day + sal_Int64 nTimeInDay = nFileTime % sal_Int64( 360000 * 24 ); + // 1/100 seconds + aDateTime.HundredthSeconds = static_cast< sal_uInt16 >( nTimeInDay % 100 ); + nTimeInDay /= 100; + // seconds + aDateTime.Seconds = static_cast< sal_uInt16 >( nTimeInDay % 60 ); + nTimeInDay /= 60; + // minutes + aDateTime.Minutes = static_cast< sal_uInt16 >( nTimeInDay % 60 ); + nTimeInDay /= 60; + // hours + aDateTime.Hours = static_cast< sal_uInt16 >( nTimeInDay ); + + writeDateTimeItem( EMPTY_STRING, aDateTime ); + return aDateTime; +} + +OUString InputObjectBase::dumpGuid( const String& rName ) +{ + OUStringBuffer aBuffer; + sal_uInt32 nData32; + sal_uInt16 nData16; + sal_uInt8 nData8; + + *mxStrm >> nData32; + StringHelper::appendHex( aBuffer, nData32, false ); + aBuffer.append( sal_Unicode( '-' ) ); + *mxStrm >> nData16; + StringHelper::appendHex( aBuffer, nData16, false ); + aBuffer.append( sal_Unicode( '-' ) ); + *mxStrm >> nData16; + StringHelper::appendHex( aBuffer, nData16, false ); + aBuffer.append( sal_Unicode( '-' ) ); + *mxStrm >> nData8; + StringHelper::appendHex( aBuffer, nData8, false ); + *mxStrm >> nData8; + StringHelper::appendHex( aBuffer, nData8, false ); + aBuffer.append( sal_Unicode( '-' ) ); + for( int nIndex = 0; nIndex < 6; ++nIndex ) + { + *mxStrm >> nData8; + StringHelper::appendHex( aBuffer, nData8, false ); + } + StringHelper::enclose( aBuffer, '{', '}' ); + OUString aGuid = aBuffer.makeStringAndClear(); + writeGuidItem( rName( "guid" ), aGuid ); + return aGuid; +} + +void InputObjectBase::dumpItem( const ItemFormat& rItemFmt ) +{ + switch( rItemFmt.meDataType ) + { + case DATATYPE_VOID: break; + case DATATYPE_INT8: dumpValue< sal_Int8 >( rItemFmt ); break; + case DATATYPE_UINT8: dumpValue< sal_uInt8 >( rItemFmt ); break; + case DATATYPE_INT16: dumpValue< sal_Int16 >( rItemFmt ); break; + case DATATYPE_UINT16: dumpValue< sal_uInt16 >( rItemFmt ); break; + case DATATYPE_INT32: dumpValue< sal_Int32 >( rItemFmt ); break; + case DATATYPE_UINT32: dumpValue< sal_uInt32 >( rItemFmt ); break; + case DATATYPE_INT64: dumpValue< sal_Int64 >( rItemFmt ); break; + case DATATYPE_UINT64: dumpValue< sal_uInt64 >( rItemFmt ); break; + case DATATYPE_FLOAT: dumpValue< float >( rItemFmt ); break; + case DATATYPE_DOUBLE: dumpValue< double >( rItemFmt ); break; + default:; + } +} + +// ============================================================================ +// ============================================================================ + +BinaryStreamObject::BinaryStreamObject( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName ) +{ + InputObjectBase::construct( rParent, rxStrm, rSysFileName ); +} + +BinaryStreamObject::BinaryStreamObject( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxStrm ) +{ + InputObjectBase::construct( rParent, rxStrm ); +} + +void BinaryStreamObject::dumpBinaryStream( bool bShowOffset ) +{ + in().seek( 0 ); + dumpRawBinary( in().getLength(), bShowOffset, true ); + out().emptyLine(); +} + +void BinaryStreamObject::implDump() +{ + dumpBinaryStream(); +} + +// ============================================================================ + +namespace { + +bool lclIsEof( BinaryInputStream& rStrm ) +{ + return rStrm.isEof() || (rStrm.isSeekable() && (rStrm.tell() >= rStrm.getLength())); +} + +template< typename BufferType, typename CharType > +CharType lclAppendChar( BufferType& orBuffer, CharType cChar ) +{ + if( (cChar == 0x0A) || (cChar == 0x0D) ) + return cChar; + orBuffer.append( cChar ); + return 0; +} + +template< typename BufferType, typename CharType, typename StreamDataType > +bool lclReadLine( BufferType& orBuffer, sal_Unicode& orcNextLineChar, BinaryInputStream& rStrm ) +{ + CharType cLineEndChar = (orcNextLineChar == 0) ? 0 : lclAppendChar( orBuffer, static_cast< CharType >( orcNextLineChar ) ); + orcNextLineChar = 0; + + // read chars until EOF or line end character (LF or CR) + bool bIsEof = lclIsEof( rStrm ); + while( !bIsEof && (cLineEndChar == 0) ) + { + CharType cChar = static_cast< CharType >( rStrm.readValue< StreamDataType >() ); + bIsEof = rStrm.isEof(); + cLineEndChar = bIsEof ? 0 : lclAppendChar( orBuffer, cChar ); + } + + // try to skip LF following CR, or CR following LF + if( !lclIsEof( rStrm ) && (cLineEndChar != 0) ) + { + CharType cChar = static_cast< CharType >( rStrm.readValue< StreamDataType >() ); + bool bLineEnd = ((cChar == 0x0A) || (cChar == 0x0D)) && (cChar != cLineEndChar); + if( !rStrm.isEof() && !bLineEnd ) + orcNextLineChar = static_cast< sal_Unicode >( cChar ); + } + + return (cLineEndChar != 0) || (orBuffer.getLength() > 0); +} + +} // namespace + +// ---------------------------------------------------------------------------- + +TextStreamObject::TextStreamObject( const ObjectBase& rParent, + const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc, const OUString& rSysFileName ) : + meTextEnc( eTextEnc ) +{ + InputObjectBase::construct( rParent, rxStrm, rSysFileName ); +} + +TextStreamObject::TextStreamObject( const OutputObjectBase& rParent, + const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc ) : + meTextEnc( eTextEnc ) +{ + InputObjectBase::construct( rParent, rxStrm ); +} + +void TextStreamObject::implDump() +{ + OUString aLine; + sal_Unicode cNextLineChar = 0; + sal_uInt32 nLine = 0; + while( readLine( aLine, cNextLineChar ) ) + implDumpLine( aLine, ++nLine ); + out().emptyLine(); +} + +void TextStreamObject::implDumpLine( const OUString& rLine, sal_uInt32 nLine ) +{ + Output& rOut = out(); + TableGuard aTabGuard( rOut, 8 ); + rOut.writeDec( nLine, 6 ); + rOut.tab(); + rOut.writeString( rLine ); + rOut.newLine(); +} + +bool TextStreamObject::readCharLine( OUString& orLine, sal_Unicode& orcNextLineChar ) +{ + OStringBuffer aBuffer; + bool bHasData = lclReadLine< OStringBuffer, sal_Char, sal_uInt8 >( aBuffer, orcNextLineChar, in() ); + if( bHasData ) + orLine = OStringToOUString( aBuffer.makeStringAndClear(), meTextEnc ); + return bHasData; +} + +bool TextStreamObject::readUcs2Line( OUString& orLine, sal_Unicode& orcNextLineChar ) +{ + OUStringBuffer aBuffer; + bool bHasData = lclReadLine< OUStringBuffer, sal_Unicode, sal_uInt16 >( aBuffer, orcNextLineChar, in() ); + if( bHasData ) + orLine = aBuffer.makeStringAndClear(); + return bHasData; +} + +bool TextStreamObject::readLine( OUString& orLine, sal_Unicode& orcNextLineChar ) +{ + return (meTextEnc == RTL_TEXTENCODING_UCS2) ? + readUcs2Line( orLine, orcNextLineChar ) : + readCharLine( orLine, orcNextLineChar ); +} + +// ============================================================================ + +XmlStreamObject::XmlStreamObject( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName ) : + TextStreamObject( rParent, rxStrm, RTL_TEXTENCODING_UTF8, rSysFileName ) +{ +} + +void XmlStreamObject::implDump() +{ + maIncompleteLine = OUString(); + TextStreamObject::implDump(); + if( maIncompleteLine.getLength() > 0 ) + { + out().resetIndent(); + out().writeString( maIncompleteLine ); + out().emptyLine(); + writeInfoItem( "stream-state", OOX_DUMP_ERR_STREAM ); + } +} + +void XmlStreamObject::implDumpLine( const OUString& rLine, sal_uInt32 ) +{ + // build input line from cached incomplete element and new text data + OUStringBuffer aLine; + if( maIncompleteLine.getLength() > 0 ) + aLine.append( maIncompleteLine ).append( sal_Unicode( ' ' ) ); + aLine.append( rLine ); + maIncompleteLine = OUString(); + + Output& rOut = out(); + if( aLine.getLength() == 0 ) + { + rOut.newLine(); + return; + } + + const sal_Unicode* pcPos = aLine.getStr(); + const sal_Unicode* pcEnd = pcPos + aLine.getLength(); + while( pcPos < pcEnd ) + { + OUStringBuffer aOutLine; + bool bIsStartElement = false; + bool bIsComplElement = false; + bool bIsEndElement = false; + + /* check for start element at beginning of the line - pcEnd and thus (pcPos+1) + are dereferenceable, because OUStringBuffer::getStr is null-terminated. */ + if( (*pcPos == '<') && (pcPos[ 1 ] != '/') ) + { + const sal_Unicode* pcElementEnd = ::std::find( pcPos, pcEnd, '>' ); + if( pcElementEnd == pcEnd ) + { + // incomplete start element + maIncompleteLine = OUString( pcPos, static_cast< sal_Int32 >( pcEnd - pcPos ) ); + pcPos = pcEnd; + } + else + { + bIsComplElement = (pcPos[ 1 ] == '?') || (pcPos[ 1 ] == '!') || (pcElementEnd[ -1 ] == '/'); + bIsStartElement = !bIsComplElement; + ++pcElementEnd; + aOutLine.append( pcPos, static_cast< sal_Int32 >( pcElementEnd - pcPos ) ); + pcPos = pcElementEnd; + } + } + + // check for following element text + if( !bIsComplElement && (pcPos < pcEnd) ) + { + const sal_Unicode* pcElementStart = ::std::find( pcPos, pcEnd, '<' ); + // append text between elements + if( pcPos < pcElementStart ) + { + OUString aText( pcPos, static_cast< sal_Int32 >( pcElementStart - pcPos ) ); + if( aText.trim().getLength() > 0 ) + aOutLine.append( aText ); + pcPos = pcElementStart; + } + } + + // check for stand-alone or following end element + if( !bIsComplElement && (pcPos < pcEnd) && (pcPos[ 1 ] == '/') ) + { + const sal_Unicode* pcElementEnd = ::std::find( pcPos, pcEnd, '>' ); + if( pcElementEnd == pcEnd ) + { + // incomplete end element + aOutLine.append( pcPos, static_cast< sal_Int32 >( pcEnd - pcPos ) ); + maIncompleteLine = aOutLine.makeStringAndClear(); + pcPos = pcEnd; + } + else + { + bIsEndElement = true; + ++pcElementEnd; + aOutLine.append( pcPos, static_cast< sal_Int32 >( pcElementEnd - pcPos ) ); + pcPos = pcElementEnd; + } + } + + // flush output line + if( maIncompleteLine.getLength() == 0 ) + { + if( !bIsStartElement && bIsEndElement ) rOut.decIndent(); + rOut.writeString( aOutLine.makeStringAndClear() ); + rOut.newLine(); + if( bIsStartElement && !bIsEndElement ) rOut.incIndent(); + } + } +} + +// ============================================================================ +// ============================================================================ + +void RecordObjectBase::construct( const ObjectBase& rParent, + const BinaryInputStreamRef& rxBaseStrm, const OUString& rSysFileName, + const BinaryInputStreamRef& rxRecStrm, const String& rRecNames, const String& rSimpleRecs ) +{ + InputObjectBase::construct( rParent, rxRecStrm, rSysFileName ); + constructRecObjBase( rxBaseStrm, rRecNames, rSimpleRecs ); +} + +void RecordObjectBase::construct( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxBaseStrm, + const BinaryInputStreamRef& rxRecStrm, const String& rRecNames, const String& rSimpleRecs ) +{ + InputObjectBase::construct( rParent, rxRecStrm ); + constructRecObjBase( rxBaseStrm, rRecNames, rSimpleRecs ); +} + +bool RecordObjectBase::implIsValid() const +{ + return mxBaseStrm.get() && InputObjectBase::implIsValid(); +} + +void RecordObjectBase::implDump() +{ + NameListRef xRecNames = getRecNames(); + + typedef ::std::map< sal_Int64, ItemFormat > ItemFormatMap; + ItemFormatMap aSimpleRecs; + if( NameListBase* pSimpleRecs = maSimpleRecs.getNameList( cfg() ).get() ) + for( NameListBase::const_iterator aIt = pSimpleRecs->begin(), aEnd = pSimpleRecs->end(); aIt != aEnd; ++aIt ) + aSimpleRecs[ aIt->first ].parse( aIt->second ); + + while( implStartRecord( *mxBaseStrm, mnRecPos, mnRecId, mnRecSize ) ) + { + // record header + out().emptyLine(); + writeHeader(); + implWriteExtHeader(); + IndentGuard aIndGuard( out() ); + sal_Int64 nRecPos = in().tell(); + + // record body + if( !mbBinaryOnly && cfg().hasName( xRecNames, mnRecId ) ) + { + ItemFormatMap::const_iterator aIt = aSimpleRecs.find( mnRecId ); + if( aIt != aSimpleRecs.end() ) + dumpItem( aIt->second ); + else + implDumpRecordBody(); + } + + // remaining undumped data + if( !in().isEof() && (in().tell() == nRecPos) ) + dumpRawBinary( mnRecSize, false ); + else + dumpRemainingTo( nRecPos + mnRecSize ); + } +} + +void RecordObjectBase::implWriteExtHeader() +{ +} + +void RecordObjectBase::implDumpRecordBody() +{ +} + +void RecordObjectBase::constructRecObjBase( const BinaryInputStreamRef& rxBaseStrm, const String& rRecNames, const String& rSimpleRecs ) +{ + mxBaseStrm = rxBaseStrm; + maRecNames = rRecNames; + maSimpleRecs = rSimpleRecs; + mnRecPos = mnRecId = mnRecSize = 0; + mbBinaryOnly = false; + if( InputObjectBase::implIsValid() ) + mbShowRecPos = cfg().getBoolOption( "show-record-position", true ); +} + +void RecordObjectBase::writeHeader() +{ + MultiItemsGuard aMultiGuard( out() ); + writeEmptyItem( "REC" ); + if( mbShowRecPos && mxBaseStrm->isSeekable() ) + writeShortHexItem( "pos", mnRecPos, "CONV-DEC" ); + writeShortHexItem( "size", mnRecSize, "CONV-DEC" ); + ItemGuard aItem( out(), "id" ); + out().writeShortHex( mnRecId ); + addNameToItem( mnRecId, "CONV-DEC" ); + addNameToItem( mnRecId, maRecNames ); +} + +// ============================================================================ + +void SequenceRecordObjectBase::construct( const ObjectBase& rParent, + const BinaryInputStreamRef& rxBaseStrm, const ::rtl::OUString& rSysFileName, + const String& rRecNames, const String& rSimpleRecs ) +{ + BinaryInputStreamRef xRecStrm( new SequenceInputStream( *mxRecData ) ); + RecordObjectBase::construct( rParent, rxBaseStrm, rSysFileName, xRecStrm, rRecNames, rSimpleRecs ); +} + +void SequenceRecordObjectBase::construct( const OutputObjectBase& rParent, + const BinaryInputStreamRef& rxBaseStrm, const String& rRecNames, const String& rSimpleRecs ) +{ + BinaryInputStreamRef xRecStrm( new SequenceInputStream( *mxRecData ) ); + RecordObjectBase::construct( rParent, rxBaseStrm, xRecStrm, rRecNames, rSimpleRecs ); +} + +bool SequenceRecordObjectBase::implStartRecord( BinaryInputStream& rBaseStrm, sal_Int64& ornRecPos, sal_Int64& ornRecId, sal_Int64& ornRecSize ) +{ + bool bValid = true; + if( rBaseStrm.isSeekable() ) + { + ornRecPos = rBaseStrm.tell(); + // do not try to overread seekable streams, may cause assertions + bValid = ornRecPos < rBaseStrm.getLength(); + } + + // read the record header + if( bValid ) + bValid = implReadRecordHeader( rBaseStrm, ornRecId, ornRecSize ) && !rBaseStrm.isEof() && (0 <= ornRecSize) && (ornRecSize <= 0x00100000); + + // read record contents into data sequence + if( bValid ) + { + sal_Int32 nRecSize = static_cast< sal_Int32 >( ornRecSize ); + mxRecData->realloc( nRecSize ); + bValid = (nRecSize == 0) || (rBaseStrm.readData( *mxRecData, nRecSize ) == nRecSize); + in().seekToStart(); + } + return bValid; +} + +// ============================================================================ +// ============================================================================ + +DumperBase::~DumperBase() +{ +} + +bool DumperBase::isImportEnabled() const +{ + return !isValid() || cfg().isImportEnabled(); +} + +bool DumperBase::isImportCancelled() const +{ + return isValid() && cfg().isPasswordCancelled(); +} + +void DumperBase::construct( const ConfigRef& rxConfig ) +{ + if( isValid( rxConfig ) && rxConfig->isDumperEnabled() ) + ObjectBase::construct( rxConfig ); +} + +// ============================================================================ +// ============================================================================ + +} // namespace dump +} // namespace oox + +#endif + |