blob: 28f84c72deb96acb5813dcda95b3dc97a898bb40 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#include "oox/dump/dumperbase.hxx"
#include <algorithm>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/io/XActiveDataSource.hpp>
#include <com/sun/star/io/XTextOutputStream.hpp>
#include <com/sun/star/ucb/XSimpleFileAccess.hpp>
#include <comphelper/docpasswordhelper.hxx>
#include <osl/file.hxx>
#include <rtl/math.hxx>
#include <rtl/tencinfo.h>
#include "oox/core/filterbase.hxx"
#include "oox/helper/binaryoutputstream.hxx"
#include "oox/helper/textinputstream.hxx"
#include "oox/xls/biffhelper.hxx"
#if OOX_INCLUDE_DUMPER
namespace oox {
namespace dump {
// ============================================================================
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::ucb;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;
using ::comphelper::MediaDescriptor;
using ::oox::core::FilterBase;
using ::rtl::OString;
using ::rtl::OStringBuffer;
using ::rtl::OStringToOUString;
using ::rtl::OUString;
using ::rtl::OUStringBuffer;
using ::rtl::OUStringToOString;
// ============================================================================
namespace {
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;
} // namespace
// ============================================================================
// ============================================================================
// 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::openInputStream(
const Reference< XComponentContext >& rxContext, const OUString& rFileName )
{
Reference< XInputStream > xInStrm;
if( rxContext.is() ) try
{
Reference< XMultiServiceFactory > xFactory( rxContext->getServiceManager(), UNO_QUERY_THROW );
Reference< XSimpleFileAccess > xFileAccess( xFactory->createInstance( CREATE_OUSTRING( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY_THROW );
xInStrm = xFileAccess->openFileRead( rFileName );
}
catch( Exception& )
{
}
return xInStrm;
}
// output streams -------------------------------------------------------------
Reference< XOutputStream > InputOutputHelper::openOutputStream(
const Reference< XComponentContext >& rxContext, const OUString& rFileName )
{
Reference< XOutputStream > xOutStrm;
if( rxContext.is() ) try
{
Reference< XMultiServiceFactory > xFactory( rxContext->getServiceManager(), UNO_QUERY_THROW );
Reference< XSimpleFileAccess > xFileAccess( xFactory->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< XComponentContext >& rxContext, const Reference< XOutputStream >& rxOutStrm, rtl_TextEncoding eTextEnc )
{
Reference< XTextOutputStream > xTextOutStrm;
const char* pcCharset = rtl_getMimeCharsetFromTextEncoding( eTextEnc );
if( rxContext.is() && rxOutStrm.is() && pcCharset ) try
{
Reference< XMultiServiceFactory > xFactory( rxContext->getServiceManager(), UNO_QUERY_THROW );
Reference< XActiveDataSource > xDataSource( xFactory->createInstance( CREATE_OUSTRING( "com.sun.star.io.TextOutputStream" ) ), UNO_QUERY_THROW );
xDataSource->setOutputStream( rxOutStrm );
xTextOutStrm.set( xDataSource, UNO_QUERY_THROW );
xTextOutStrm->setEncoding( OUString::createFromAscii( pcCharset ) );
}
catch( Exception& )
{
}
return xTextOutStrm;
}
Reference< XTextOutputStream > InputOutputHelper::openTextOutputStream(
const Reference< XComponentContext >& rxContext, const OUString& rFileName, rtl_TextEncoding eTextEnc )
{
return openTextOutputStream( rxContext, openOutputStream( rxContext, rFileName ), eTextEnc );
}
// ============================================================================
// ============================================================================
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 );
}
OUString StringHelper::trimTrailingNul( const OUString& rStr )
{
sal_Int32 nLastPos = rStr.getLength() - 1;
if( (nLastPos >= 0) && (rStr[ nLastPos ] == 0) )
return rStr.copy( 0, nLastPos );
return rStr;
}
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);
}
OUStringPair StringHelper::convertStringToPair( const OUString& rString, sal_Unicode cSep )
{
OUStringPair aPair;
if( rString.getLength() > 0 )
{
sal_Int32 nEqPos = rString.indexOf( cSep );
if( nEqPos < 0 )
{
aPair.first = rString;
}
else
{
aPair.first = StringHelper::trimSpaces( rString.copy( 0, nEqPos ) );
aPair.second = StringHelper::trimSpaces( rString.copy( nEqPos + 1 ) );
}
}
return aPair;
}
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( TextInputStream& rStrm )
{
readConfigBlockContents( rStrm );
}
void ConfigItemBase::implProcessConfigItemStr(
TextInputStream& /*rStrm*/, const OUString& /*rKey*/, const OUString& /*rData*/ )
{
}
void ConfigItemBase::implProcessConfigItemInt(
TextInputStream& /*rStrm*/, sal_Int64 /*nKey*/, const OUString& /*rData*/ )
{
}
void ConfigItemBase::readConfigBlockContents( TextInputStream& rStrm )
{
bool bLoop = true;
while( bLoop && !rStrm.isEof() )
{
OUString aKey, aData;
switch( readConfigLine( rStrm, aKey, aData ) )
{
case LINETYPE_DATA:
processConfigItem( rStrm, aKey, aData );
break;
case LINETYPE_END:
bLoop = false;
break;
}
}
}
ConfigItemBase::LineType ConfigItemBase::readConfigLine(
TextInputStream& rStrm, OUString& orKey, OUString& orData ) const
{
OUString aLine;
while( !rStrm.isEof() && (aLine.getLength() == 0) )
{
aLine = rStrm.readLine();
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();
}
}
OUStringPair aPair = StringHelper::convertStringToPair( aLine );
orKey = aPair.first;
orData = aPair.second;
return ((orKey.getLength() > 0) && ((orData.getLength() > 0) || !orKey.equalsAscii( "end" ))) ?
LINETYPE_DATA : LINETYPE_END;
}
ConfigItemBase::LineType ConfigItemBase::readConfigLine( TextInputStream& rStrm ) const
{
OUString aKey, aData;
return readConfigLine( rStrm, aKey, aData );
}
void ConfigItemBase::processConfigItem(
TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
{
sal_Int64 nKey;
if( StringHelper::convertStringToInt( nKey, rKey ) )
implProcessConfigItemInt( rStrm, nKey, rData );
else
implProcessConfigItemStr( rStrm, 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(
TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
{
if( rKey.equalsAscii( "include" ) )
include( rData );
else if( rKey.equalsAscii( "exclude" ) )
exclude( rData );
else
ConfigItemBase::implProcessConfigItemStr( rStrm, rKey, rData );
}
void NameListBase::implProcessConfigItemInt(
TextInputStream& /*rStrm*/, 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 );
}
// ============================================================================
void ItemFormatMap::insertFormats( const NameListRef& rxNameList )
{
if( Base::isValid( rxNameList ) )
for( NameListBase::const_iterator aIt = rxNameList->begin(), aEnd = rxNameList->end(); aIt != aEnd; ++aIt )
(*this)[ aIt->first ].parse( aIt->second );
}
// ============================================================================
ConstList::ConstList( const SharedConfigData& rCfgData ) :
NameListBase( rCfgData ),
maDefName( OOX_DUMP_ERR_NONAME ),
mbQuoteNames( false )
{
}
void ConstList::implProcessConfigItemStr(
TextInputStream& rStrm, 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( rStrm, 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(
TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
{
if( rKey.equalsAscii( "ignore-empty" ) )
mbIgnoreEmpty = StringHelper::convertStringToBool( rData );
else
ConstList::implProcessConfigItemStr( rStrm, 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(
TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
{
if( rKey.equalsAscii( "ignore" ) )
{
sal_Int64 nIgnore;
if( StringHelper::convertStringToInt( nIgnore, rData ) )
setIgnoreFlags( nIgnore );
}
else
{
NameListBase::implProcessConfigItemStr( rStrm, rKey, rData );
}
}
void FlagsList::implSetName( sal_Int64 nKey, const OUString& rName )
{
if( (nKey != 0) && ((nKey & (nKey - 1)) == 0) ) // only a single bit set?
insertRawName( nKey, rName );
}
OUString FlagsList::implGetName( const Config& /*rCfg*/, sal_Int64 nKey ) const
{
sal_Int64 nFound = mnIgnore;
OUStringBuffer aName;
// add known flags
for( const_iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt )
{
sal_Int64 nMask = aIt->first;
setFlag( nFound, nMask );
if( !getFlag( mnIgnore, nMask ) )
{
const OUString& rFlagName = aIt->second;
bool bOnOff = (rFlagName.getLength() > 0) && (rFlagName[ 0 ] == ':');
bool bFlag = getFlag( nKey, nMask );
if( bOnOff )
{
StringHelper::appendToken( aName, rFlagName.copy( 1 ) );
aName.appendAscii( bFlag ? ":on" : ":off" );
}
else
{
bool bNegated = (rFlagName.getLength() > 0) && (rFlagName[ 0 ] == '!');
sal_Int32 nBothSep = bNegated ? rFlagName.indexOf( '!', 1 ) : -1;
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 ) );
}
}
}
}
// add unknown flags
setFlag( nKey, nFound, false );
if( nKey != 0 )
{
OUStringBuffer aUnknown( CREATE_OUSTRING( OOX_DUMP_UNKNOWN ) );
aUnknown.append( OOX_DUMP_ITEMSEP );
StringHelper::appendShortHex( aUnknown, nKey, 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;
}
// ============================================================================
bool CombiList::ExtItemFormatKey::operator<( const ExtItemFormatKey& rRight ) const
{
return (mnKey < rRight.mnKey) || ((mnKey == rRight.mnKey) && (maFilter < rRight.maFilter));
}
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?
{
typedef ::std::set< ExtItemFormatKey > ExtItemFormatKeySet;
::std::set< ExtItemFormatKey > aItemKeys;
ExtItemFormat aItemFmt;
OUStringVector aRemain = aItemFmt.parse( rName );
for( OUStringVector::iterator aIt = aRemain.begin(), aEnd = aRemain.end(); aIt != aEnd; ++aIt )
{
OUStringPair aPair = StringHelper::convertStringToPair( *aIt );
if( aPair.first.equalsAscii( "noshift" ) )
{
aItemFmt.mbShiftValue = StringHelper::convertStringToBool( aPair.second );
}
else if( aPair.first.equalsAscii( "filter" ) )
{
OUStringPair aFilter = StringHelper::convertStringToPair( aPair.second, '~' );
ExtItemFormatKey aKey( nKey );
if( (aFilter.first.getLength() > 0) && StringHelper::convertStringToInt( aKey.maFilter.first, aFilter.first ) &&
(aFilter.second.getLength() > 0) && StringHelper::convertStringToInt( aKey.maFilter.second, aFilter.second ) )
{
if( aKey.maFilter.first == 0 )
aKey.maFilter.second = 0;
aItemKeys.insert( aKey );
}
}
}
if( aItemKeys.empty() )
aItemKeys.insert( ExtItemFormatKey( nKey ) );
for( ExtItemFormatKeySet::iterator aIt = aItemKeys.begin(), aEnd = aItemKeys.end(); aIt != aEnd; ++aIt )
maFmtMap[ *aIt ] = aItemFmt;
}
else
{
FlagsList::implSetName( nKey, rName );
}
}
OUString CombiList::implGetName( const Config& rCfg, sal_Int64 nKey ) const
{
sal_Int64 nFound = 0;
OUStringBuffer aName;
// add known flag fields
for( ExtItemFormatMap::const_iterator aIt = maFmtMap.begin(), aEnd = maFmtMap.end(); aIt != aEnd; ++aIt )
{
const ExtItemFormatKey& rMapKey = aIt->first;
sal_Int64 nMask = rMapKey.mnKey;
if( (nMask != 0) && ((nKey & rMapKey.maFilter.first) == rMapKey.maFilter.second) )
{
const ExtItemFormat& rItemFmt = aIt->second;
sal_uInt64 nUFlags = static_cast< sal_uInt64 >( nKey );
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( nKey, nFound, false );
StringHelper::appendToken( aName, FlagsList::implGetName( rCfg, nKey ) );
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< XComponentContext >& rxContext, const StorageRef& rxRootStrg,
const OUString& rSysFileName, MediaDescriptor& rMediaDesc ) :
mxContext( rxContext ),
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;
}
Sequence< NamedValue > SharedConfigData::requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier )
{
Sequence< NamedValue > aEncryptionData;
if( !mbPwCancelled )
{
::std::vector< OUString > aDefaultPasswords;
aDefaultPasswords.push_back( CREATE_OUSTRING( "VelvetSweatshop" ) );
aEncryptionData = ::comphelper::DocPasswordHelper::requestAndVerifyDocPassword(
rVerifier, mrMediaDesc, ::comphelper::DocPasswordRequestType_MS, &aDefaultPasswords );
mbPwCancelled = !aEncryptionData.hasElements();
}
return aEncryptionData;
}
bool SharedConfigData::implIsValid() const
{
return mbLoaded && mxContext.is() && mxRootStrg.get() && (maSysFileName.getLength() > 0);
}
void SharedConfigData::implProcessConfigItemStr(
TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
{
if( rKey.equalsAscii( "include-config-file" ) )
readConfigFile( maConfigPath + rData );
else if( rKey.equalsAscii( "constlist" ) )
readNameList< ConstList >( rStrm, rData );
else if( rKey.equalsAscii( "multilist" ) )
readNameList< MultiList >( rStrm, rData );
else if( rKey.equalsAscii( "flagslist" ) )
readNameList< FlagsList >( rStrm, rData );
else if( rKey.equalsAscii( "combilist" ) )
readNameList< CombiList >( rStrm, 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< XInputStream > xInStrm = InputOutputHelper::openInputStream( mxContext, rFileUrl );
TextInputStream aTxtStrm( mxContext, xInStrm, RTL_TEXTENCODING_UTF8 );
if( !aTxtStrm.isEof() )
{
maConfigFiles.insert( rFileUrl );
readConfigBlockContents( aTxtStrm );
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< XComponentContext >& rxContext, const StorageRef& rxRootStrg, const OUString& rSysFileName, MediaDescriptor& rMediaDesc )
{
construct( pcEnvVar, rxContext, 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.getComponentContext(), rFilter.getStorage(), rFilter.getFileUrl(), rFilter.getMediaDescriptor() );
}
void Config::construct( const sal_Char* pcEnvVar, const Reference< XComponentContext >& rxContext, 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 ), rxContext, 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 );
}
Sequence< NamedValue > Config::requestEncryptionData( ::comphelper::IDocPasswordVerifier& rVerifier )
{
return mxCfgData->requestEncryptionData( 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< XComponentContext >& rxContext, const OUString& rFileName ) :
mxStrm( InputOutputHelper::openTextOutputStream( rxContext, rFileName, RTL_TEXTENCODING_UTF8 ) ),
mnCol( 0 ),
mnItemLevel( 0 ),
mnMultiLevel( 0 ),
mnItemIdx( 0 ),
mnLastItem( 0 )
{
if( mxStrm.is() )
mxStrm->writeString( OUString( OOX_DUMP_BOM ) );
}
// ----------------------------------------------------------------------------
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 );
}
// ----------------------------------------------------------------------------
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() && (maSysPath.getLength() > 0) && ObjectBase::implIsValid();
}
void StorageObjectBase::implDump()
{
bool bIsStrg = mxStrg->isStorage();
bool bIsRoot = mxStrg->isRootStorage();
Reference< XInputStream > xBaseStrm;
if( !bIsStrg )
xBaseStrm = mxStrg->openInputStream( OUString() );
OUString aSysOutPath = maSysPath;
if( bIsRoot ) try
{
aSysOutPath += OOX_DUMP_DUMPEXT;
Reference< XMultiServiceFactory > xFactory( getContext()->getServiceManager(), UNO_QUERY_THROW );
Reference< XSimpleFileAccess > xFileAccess( xFactory->createInstance( CREATE_OUSTRING( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY_THROW );
xFileAccess->kill( aSysOutPath );
}
catch( Exception& )
{
}
if( bIsStrg )
{
extractStorage( mxStrg, OUString(), aSysOutPath );
}
else if( xBaseStrm.is() )
{
BinaryInputStreamRef xInStrm( new BinaryXInputStream( xBaseStrm, false ) );
xInStrm->seekToStart();
implDumpBaseStream( xInStrm, aSysOutPath );
}
}
void StorageObjectBase::implDumpStream( const Reference< XInputStream >&, const OUString&, const OUString&, const OUString& )
{
}
void StorageObjectBase::implDumpStorage( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rSysPath )
{
extractStorage( rxStrg, rStrgPath, rSysPath );
}
void StorageObjectBase::implDumpBaseStream( const BinaryInputStreamRef&, const OUString& )
{
}
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( getContext(), rSysFileName ), true );
if( !aOutStrm.isEof() )
aInStrm.copyToStream( aOutStrm );
}
Reference< XInputStream > xDumpStrm = InputOutputHelper::openInputStream( getContext(), rSysFileName );
if( xDumpStrm.is() )
implDumpStream( xDumpStrm, rStrgPath, rStrmName, rSysFileName );
}
void StorageObjectBase::extractStorage( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rSysPath )
{
// create directory in file system
::osl::FileBase::RC eRes = ::osl::Directory::create( rSysPath );
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, rSysPath, 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, rSysPath, aIt.isStorage(), aIt.isStream() );
}
}
void StorageObjectBase::extractItem( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rItemName, const OUString& rSysPath, bool bIsStrg, bool bIsStrm )
{
OUString aSysFileName = getSysFileName( rItemName, rSysPath );
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() )
{
maSysFileName = rSysFileName;
mxOut.reset( new Output( getContext(), rSysFileName + OOX_DUMP_DUMPEXT ) );
}
}
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( mxOut );
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 )
{
ItemGuard aItem( mxOut, rName );
mxOut->writeDec( nCol );
aItem.cont();
mxOut->writeColIndex( nCol );
}
void OutputObjectBase::writeRowIndexItem( const String& rName, sal_Int32 nRow )
{
ItemGuard aItem( mxOut, rName );
mxOut->writeDec( nRow );
aItem.cont();
mxOut->writeRowIndex( nRow );
}
void OutputObjectBase::writeColRangeItem( const String& rName, sal_Int32 nCol1, sal_Int32 nCol2 )
{
ItemGuard aItem( mxOut, rName );
mxOut->writeColRowRange( nCol1, nCol2 );
aItem.cont();
mxOut->writeColRange( nCol1, nCol2 );
}
void OutputObjectBase::writeRowRangeItem( const String& rName, sal_Int32 nRow1, sal_Int32 nRow2 )
{
ItemGuard aItem( mxOut, rName );
mxOut->writeColRowRange( nRow1, nRow2 );
aItem.cont();
mxOut->writeRowRange( nRow1, nRow2 );
}
void OutputObjectBase::writeAddressItem( const String& rName, const Address& rPos )
{
ItemGuard aItem( mxOut, rName );
StringHelper::appendAddress( mxOut->getLine(), rPos );
}
void OutputObjectBase::writeRangeItem( const String& rName, const Range& rRange )
{
ItemGuard aItem( mxOut, rName );
StringHelper::appendRange( mxOut->getLine(), rRange );
}
void OutputObjectBase::writeRangeListItem( const String& rName, const RangeList& rRanges )
{
MultiItemsGuard aMultiGuard( mxOut );
writeEmptyItem( rName );
writeDecItem( "count", static_cast< sal_uInt16 >( rRanges.size() ) );
ItemGuard aItem( mxOut, "ranges" );
StringHelper::appendRangeList( mxOut->getLine(), rRanges );
}
void OutputObjectBase::writeTokenAddressItem( const String& rName, const TokenAddress& rPos, bool bNameMode )
{
ItemGuard aItem( mxOut, rName );
StringHelper::appendAddress( mxOut->getLine(), rPos, bNameMode );
}
void OutputObjectBase::writeTokenAddress3dItem( const String& rName, const OUString& rRef, const TokenAddress& rPos, bool bNameMode )
{
ItemGuard aItem( mxOut, rName );
mxOut->writeString( rRef );
StringHelper::appendAddress( mxOut->getLine(), rPos, bNameMode );
}
void OutputObjectBase::writeTokenRangeItem( const String& rName, const TokenRange& rRange, bool bNameMode )
{
ItemGuard aItem( mxOut, rName );
StringHelper::appendRange( mxOut->getLine(), rRange, bNameMode );
}
void OutputObjectBase::writeTokenRange3dItem( const String& rName, const OUString& rRef, const TokenRange& rRange, bool bNameMode )
{
ItemGuard aItem( mxOut, rName );
mxOut->writeString( rRef );
StringHelper::appendRange( mxOut->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 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->size() );
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 )
{
TableGuard aTabGuard( mxOut,
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->size() >= 0;
sal_Int64 nEndPos = bSeekable ? ::std::min< sal_Int64 >( mxStrm->tell() + nBytes, mxStrm->size() ) : 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) )
{
mxOut->writeHex( static_cast< sal_uInt32 >( nPos ) );
mxOut->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) ) mxOut->tab();
mxOut->writeHex( *pnByte, false );
mxOut->writeChar( ' ' );
}
aTabGuard.tab( 3 );
for( pnByte = pnLineData, pnEnd = pnLineData + nReadSize; pnByte != pnEnd; ++pnByte )
{
if( (pnByte - pnLineData) == (OOX_DUMP_BYTESPERLINE / 2) ) mxOut->tab();
mxOut->writeChar( static_cast< sal_Unicode >( (*pnByte < 0x20) ? '.' : *pnByte ) );
}
mxOut->newLine();
}
}
// skip undumped data
if( bSeekable )
skipBlock( nEndPos - mxStrm->tell() );
}
void InputObjectBase::dumpBinary( const String& rName, sal_Int64 nBytes, bool bShowOffset )
{
{
MultiItemsGuard aMultiGuard( mxOut );
writeEmptyItem( rName );
writeDecItem( "size", nBytes );
}
IndentGuard aIndGuard( mxOut );
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() || (mxStrm->tell() > nPos) )
writeInfoItem( "stream-state", OOX_DUMP_ERR_STREAM );
else
dumpRemaining( nPos - mxStrm->tell() );
mxStrm->seek( nPos );
}
void InputObjectBase::dumpRemainingStream()
{
dumpRemainingTo( mxStrm->size() );
}
void InputObjectBase::dumpArray( const String& rName, sal_Int32 nBytes, sal_Unicode cSep )
{
sal_Int32 nDumpSize = getLimitedValue< sal_Int32, sal_Int64 >( mxStrm->size() - 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, bool bHideTrailingNul )
{
sal_Int32 nDumpSize = getLimitedValue< sal_Int32, sal_Int64 >( mxStrm->size() - 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 );
}
if( bHideTrailingNul )
aString = StringHelper::trimTrailingNul( aString );
writeStringItem( rName( "text" ), aString );
return aString;
}
OUString InputObjectBase::dumpUnicodeArray( const String& rName, sal_Int32 nLen, bool bHideTrailingNul )
{
OUStringBuffer aBuffer;
for( sal_Int32 nIndex = 0; !mxStrm->isEof() && (nIndex < nLen); ++nIndex )
aBuffer.append( static_cast< sal_Unicode >( mxStrm->readuInt16() ) );
OUString aString = aBuffer.makeStringAndClear();
if( bHideTrailingNul )
aString = StringHelper::trimTrailingNul( aString );
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( mxOut, 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 )
{
mxStrm->seekToStart();
dumpRawBinary( mxStrm->size(), bShowOffset, true );
mxOut->emptyLine();
}
void BinaryStreamObject::implDump()
{
dumpBinaryStream();
}
// ============================================================================
// ============================================================================
void TextStreamObjectBase::construct( const ObjectBase& rParent,
const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc, const OUString& rSysFileName )
{
InputObjectBase::construct( rParent, rxStrm, rSysFileName );
constructTextStrmObj( eTextEnc );
}
void TextStreamObjectBase::construct( const OutputObjectBase& rParent,
const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc )
{
InputObjectBase::construct( rParent, rxStrm );
constructTextStrmObj( eTextEnc );
}
void TextStreamObjectBase::construct( const InputObjectBase& rParent, rtl_TextEncoding eTextEnc )
{
InputObjectBase::construct( rParent );
constructTextStrmObj( eTextEnc );
}
bool TextStreamObjectBase::implIsValid() const
{
return InputObjectBase::implIsValid() && mxTextStrm.get();
}
void TextStreamObjectBase::implDump()
{
implDumpText( *mxTextStrm );
}
void TextStreamObjectBase::constructTextStrmObj( rtl_TextEncoding eTextEnc )
{
if( mxStrm.get() )
mxTextStrm.reset( new TextInputStream( getContext(), *mxStrm, eTextEnc ) );
}
// ============================================================================
TextLineStreamObject::TextLineStreamObject( const ObjectBase& rParent,
const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc, const OUString& rSysFileName )
{
TextStreamObjectBase::construct( rParent, rxStrm, eTextEnc, rSysFileName );
}
TextLineStreamObject::TextLineStreamObject( const OutputObjectBase& rParent,
const BinaryInputStreamRef& rxStrm, rtl_TextEncoding eTextEnc )
{
TextStreamObjectBase::construct( rParent, rxStrm, eTextEnc );
}
void TextLineStreamObject::implDumpText( TextInputStream& rTextStrm )
{
sal_uInt32 nLine = 0;
while( !rTextStrm.isEof() )
{
OUString aLine = rTextStrm.readLine();
if( !rTextStrm.isEof() || (aLine.getLength() > 0) )
implDumpLine( aLine, ++nLine );
}
}
void TextLineStreamObject::implDumpLine( const OUString& rLine, sal_uInt32 nLine )
{
TableGuard aTabGuard( mxOut, 8 );
mxOut->writeDec( nLine, 6 );
mxOut->tab();
mxOut->writeString( rLine );
mxOut->newLine();
}
// ============================================================================
XmlStreamObject::XmlStreamObject( const ObjectBase& rParent,
const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName )
{
TextStreamObjectBase::construct( rParent, rxStrm, RTL_TEXTENCODING_UTF8, rSysFileName );
}
XmlStreamObject::XmlStreamObject( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxStrm )
{
TextStreamObjectBase::construct( rParent, rxStrm, RTL_TEXTENCODING_UTF8 );
}
void XmlStreamObject::implDumpText( TextInputStream& rTextStrm )
{
/* Buffers a start element and the following element text. Needed to dump
matching start/end elements and the element text on the same line. */
OUStringBuffer aOldStartElem;
// special handling for VML
bool bIsVml = InputOutputHelper::getFileNameExtension( maSysFileName ).equalsIgnoreAsciiCaseAscii( "vml" );
while( !rTextStrm.isEof() )
{
// get the next element and the following element text from text stream
OUString aElem = rTextStrm.readToChar( '>', true ).trim();
OUString aText = rTextStrm.readToChar( '<', false );
// remove multiple whitespace from element
sal_Int32 nPos = 0;
while( nPos < aElem.getLength() )
{
while( (nPos < aElem.getLength()) && (aElem[ nPos ] >= 32) ) ++nPos;
if( nPos < aElem.getLength() )
aElem = OUStringBuffer( aElem.copy( 0, nPos ) ).append( sal_Unicode( ' ' ) ).append( aElem.copy( nPos ).trim() ).makeStringAndClear();
++nPos;
}
sal_Int32 nElemLen = aElem.getLength();
if( (nElemLen >= 2) && (aElem[ 0 ] == '<') && (aElem[ nElemLen - 1 ] == '>') )
{
// determine type of the element
bool bSimpleElem = (aElem[ 1 ] == '!') || (aElem[ 1 ] == '?') || (aElem[ nElemLen - 2 ] == '/') ||
(bIsVml && (nElemLen == 4) && (aElem[ 1 ] == 'b') && (aElem[ 2 ] == 'r'));
bool bStartElem = !bSimpleElem && (aElem[ 1 ] != '/');
bool bEndElem = !bSimpleElem && !bStartElem;
/* Start element or simple element: flush old start element and
its text from previous iteration, and start a new indentation
level for the new element. Trim whitespace and line breaks from
the text of the old start element. */
if( (bSimpleElem || bStartElem) && (aOldStartElem.getLength() > 0) )
{
mxOut->writeString( aOldStartElem.makeStringAndClear().trim() );
mxOut->newLine();
mxOut->incIndent();
}
/* Start element: remember it and its text, to be able to print the
matching end element on the same line in the next iteration. */
if( bStartElem )
{
aOldStartElem.append( aElem ).append( aText );
}
else
{
/* End element: if a start element has been remembered in the
previous iteration, write it out here untrimmed, to show
all whitespace in the element text, and without trailing
line break. Code below will add the end element right after
it. Otherwise, return to previous indentation level. */
if( bEndElem )
{
if( aOldStartElem.getLength() == 0 )
mxOut->decIndent();
else
mxOut->writeString( aOldStartElem.makeStringAndClear() );
}
/* Write the element. Write following element text in a new
line, but only, if it does not contain of white space
entirely. */
mxOut->writeString( aElem );
mxOut->newLine();
if( aText.trim().getLength() > 0 )
{
mxOut->writeString( aText );
mxOut->newLine();
}
}
}
}
}
// ============================================================================
// ============================================================================
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();
ItemFormatMap aSimpleRecs( maSimpleRecs.getNameList( cfg() ) );
while( implStartRecord( *mxBaseStrm, mnRecPos, mnRecId, mnRecSize ) )
{
// record header
mxOut->emptyLine();
writeHeader();
implWriteExtHeader();
IndentGuard aIndGuard( mxOut );
sal_Int64 nRecPos = mxStrm->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( !mxStrm->isEof() && (mxStrm->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( mxOut );
writeEmptyItem( "REC" );
if( mbShowRecPos && mxBaseStrm->isSeekable() )
writeShortHexItem( "pos", mnRecPos, "CONV-DEC" );
writeShortHexItem( "size", mnRecSize, "CONV-DEC" );
ItemGuard aItem( mxOut, "id" );
mxOut->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.size();
}
// 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);
mxStrm->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