/**************************************************************
 * 
 * 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/biffdumper.hxx"

#include <osl/thread.h>
#include <rtl/tencinfo.h>
#include "oox/core/filterbase.hxx"
#include "oox/dump/oledumper.hxx"
#include "oox/ole/olestorage.hxx"
#include "oox/xls/biffdetector.hxx"
#include "oox/xls/biffinputstream.hxx"
#include "oox/xls/formulabase.hxx"

#if OOX_INCLUDE_DUMPER

namespace oox {
namespace dump {
namespace biff {

// ============================================================================

using namespace ::com::sun::star::io;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::util;
using namespace ::oox::xls;

using ::comphelper::MediaDescriptor;
using ::oox::core::FilterBase;
using ::rtl::OString;
using ::rtl::OStringBuffer;
using ::rtl::OStringToOUString;
using ::rtl::OUString;
using ::rtl::OUStringBuffer;

// ============================================================================

namespace  {

// constants ------------------------------------------------------------------

const sal_uInt16 BIFF_FONTFLAG_BOLD         = 0x0001;
const sal_uInt16 BIFF_FONTFLAG_ITALIC       = 0x0002;

const sal_uInt16 BIFF_OBJTYPE_GROUP         = 0;
const sal_uInt16 BIFF_OBJTYPE_LINE          = 1;
const sal_uInt16 BIFF_OBJTYPE_RECTANGLE     = 2;
const sal_uInt16 BIFF_OBJTYPE_OVAL          = 3;
const sal_uInt16 BIFF_OBJTYPE_ARC           = 4;
const sal_uInt16 BIFF_OBJTYPE_CHART         = 5;
const sal_uInt16 BIFF_OBJTYPE_TEXT          = 6;
const sal_uInt16 BIFF_OBJTYPE_BUTTON        = 7;
const sal_uInt16 BIFF_OBJTYPE_PICTURE       = 8;
const sal_uInt16 BIFF_OBJTYPE_POLYGON       = 9;
const sal_uInt16 BIFF_OBJTYPE_CHECKBOX      = 11;
const sal_uInt16 BIFF_OBJTYPE_OPTIONBUTTON  = 12;
const sal_uInt16 BIFF_OBJTYPE_EDIT          = 13;
const sal_uInt16 BIFF_OBJTYPE_LABEL         = 14;
const sal_uInt16 BIFF_OBJTYPE_DIALOG        = 15;
const sal_uInt16 BIFF_OBJTYPE_SPIN          = 16;
const sal_uInt16 BIFF_OBJTYPE_SCROLLBAR     = 17;
const sal_uInt16 BIFF_OBJTYPE_LISTBOX       = 18;
const sal_uInt16 BIFF_OBJTYPE_GROUPBOX      = 19;
const sal_uInt16 BIFF_OBJTYPE_DROPDOWN      = 20;
const sal_uInt16 BIFF_OBJTYPE_NOTE          = 25;
const sal_uInt16 BIFF_OBJTYPE_DRAWING       = 30;

const sal_uInt16 BIFF_OBJFLAGS_CONTROL      = 0x0010;   /// Form control.
const sal_uInt16 BIFF_OBJFLAGS_CTLSSTREAM   = 0x0020;   /// Data in Ctls stream.

const sal_uInt16 BIFF_STYLE_BUILTIN         = 0x8000;

const sal_uInt16 BIFF_PT_NOSTRING           = 0xFFFF;

// ----------------------------------------------------------------------------

void lclDumpDffClientPos( const OutputRef& rxOut, const BinaryInputStreamRef& rxStrm, const String& rName, sal_uInt16 nSubScale )
{
    MultiItemsGuard aMultiGuard( rxOut );
    TableGuard aTabGuard( rxOut, 17 );
    {
        sal_uInt16 nPos = rxStrm->readuInt16();
        ItemGuard aItem( rxOut, rName );
        rxOut->writeDec( nPos );
    }
    {
        sal_uInt16 nSubUnits = rxStrm->readuInt16();
        ItemGuard aItem( rxOut, "sub-units" );
        rxOut->writeDec( nSubUnits );
        rxOut->writeChar( '/' );
        rxOut->writeDec( nSubScale );
    }
}

void lclDumpDffClientRect( const OutputRef& rxOut, const BinaryInputStreamRef& rxStrm )
{
    lclDumpDffClientPos( rxOut, rxStrm, "start-col", 1024 );
    lclDumpDffClientPos( rxOut, rxStrm, "start-row", 256 );
    lclDumpDffClientPos( rxOut, rxStrm, "end-col", 1024 );
    lclDumpDffClientPos( rxOut, rxStrm, "end-row", 256 );
}

} // namespace

// ============================================================================
// ============================================================================

BiffDffStreamObject::BiffDffStreamObject( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxStrm )
{
    DffStreamObject::construct( rParent, rxStrm );
}

void BiffDffStreamObject::implDumpClientAnchor()
{
    dumpHex< sal_uInt16 >( "flags", "DFF-CLIENTANCHOR-FLAGS" );
    lclDumpDffClientRect( mxOut, mxStrm );
}

// ============================================================================

BiffCtlsStreamObject::BiffCtlsStreamObject( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxStrm )
{
    InputObjectBase::construct( rParent, rxStrm );
    mnStartPos = mnLength = 0;
}

void BiffCtlsStreamObject::dumpControl( sal_uInt32 nStartPos, sal_uInt32 nLength )
{
    mnStartPos = nStartPos;
    mnLength = nLength;
    dump();
    mnStartPos = mnLength = 0;
}

void BiffCtlsStreamObject::implDump()
{
    if( mnLength > 0 )
    {
        mxOut->emptyLine();
        writeEmptyItem( "CTLS-START" );
        {
            IndentGuard aIndGuard( mxOut );
            mxStrm->seek( mnStartPos );
            BinaryInputStreamRef xRelStrm( new RelativeInputStream( *mxStrm, mnLength ) );
            FormControlStreamObject( *this, xRelStrm ).dump();
        }
        writeEmptyItem( "CTLS-END" );
        mxOut->emptyLine();
    }
}

// ============================================================================
// ============================================================================

BiffConfig::BiffConfig( const Config& rParent, BiffType eBiff ) :
    meBiff( eBiff )
{
    Config::construct( rParent );
}

bool BiffConfig::implIsValid() const
{
    return (meBiff != BIFF_UNKNOWN) && Config::implIsValid();
}

NameListRef BiffConfig::implGetNameList( const OUString& rKey ) const
{
    NameListRef xList = Config::implGetNameList( rKey );
    if( !xList )
    {
        OUString aBaseKey = rKey + CREATE_OUSTRING( "-BIFF" );
        switch( meBiff )
        {
            // fall-through intended!
            case BIFF8: if( !xList ) xList = Config::implGetNameList( aBaseKey + OUString( sal_Unicode( '8' ) ) );
            case BIFF5: if( !xList ) xList = Config::implGetNameList( aBaseKey + OUString( sal_Unicode( '5' ) ) );
            case BIFF4: if( !xList ) xList = Config::implGetNameList( aBaseKey + OUString( sal_Unicode( '4' ) ) );
            case BIFF3: if( !xList ) xList = Config::implGetNameList( aBaseKey + OUString( sal_Unicode( '3' ) ) );
            case BIFF2: if( !xList ) xList = Config::implGetNameList( aBaseKey + OUString( sal_Unicode( '2' ) ) );
            case BIFF_UNKNOWN: break;
        }
    }
    return xList;
}

// ============================================================================

BiffSharedData::BiffSharedData( BiffType eBiff ) :
    meBiff( eBiff ),
    meTextEnc( osl_getThreadTextEncoding() )
{
}

void BiffSharedData::initializePerSheet()
{
    maFontEncs.clear();
    maXfFontIds.clear();
    meTextEnc = osl_getThreadTextEncoding();
}

void BiffSharedData::setTextEncoding( rtl_TextEncoding eTextEnc )
{
    if( eTextEnc != RTL_TEXTENCODING_DONTKNOW )
        meTextEnc = eTextEnc;
}

sal_uInt16 BiffSharedData::getFontCount() const
{
    return static_cast< sal_uInt16 >( maFontEncs.size() );
}

rtl_TextEncoding BiffSharedData::getFontEncoding( sal_uInt16 nFontId ) const
{
    return (nFontId < getFontCount()) ? maFontEncs[ nFontId ] : meTextEnc;
}

void BiffSharedData::appendFontEncoding( rtl_TextEncoding eFontEnc )
{
    maFontEncs.push_back( (eFontEnc == RTL_TEXTENCODING_DONTKNOW) ? meTextEnc : eFontEnc );
    if( maFontEncs.size() == 4 )
        maFontEncs.push_back( meTextEnc );
}

sal_uInt16 BiffSharedData::getXfCount() const
{
    return static_cast< sal_uInt16 >( maXfFontIds.size() );
}

rtl_TextEncoding BiffSharedData::getXfEncoding( sal_uInt16 nXfId ) const
{
    sal_uInt16 nFontId = (nXfId < getXfCount()) ? maXfFontIds[ nXfId ] : 0;
    return getFontEncoding( nFontId );
}

void BiffSharedData::appendXfFontId( sal_uInt16 nFontId )
{
    maXfFontIds.push_back( nFontId );
}

bool BiffSharedData::implIsValid() const
{
    return meBiff != BIFF_UNKNOWN;
}

// ============================================================================

BiffObjectBase::~BiffObjectBase()
{
}

void BiffObjectBase::construct( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, BiffType eBiff, const OUString& rSysFileName )
{
    if( rParent.isValid() && rxStrm.get() && (eBiff != BIFF_UNKNOWN) )
    {
        mxBiffData.reset( new BiffSharedData( eBiff ) );
        mxBiffStrm.reset( new BiffInputStream( *rxStrm ) );
        RecordObjectBase::construct( rParent, rxStrm, rSysFileName, mxBiffStrm, "RECORD-NAMES", "SIMPLE-RECORDS" );
        if( RecordObjectBase::implIsValid() )
        {
            reconstructConfig( ConfigRef( new BiffConfig( cfg(), eBiff ) ) );
            mxDffObj.reset( new BiffDffStreamObject( *this, mxBiffStrm ) );
            if( StorageBase* pRootStrg = cfg().getRootStorage().get() )
            {
                BinaryInputStreamRef xCtlsStrm( new BinaryXInputStream( pRootStrg->openInputStream( CREATE_OUSTRING( "Ctls" ) ), true ) );
                mxCtlsObj.reset( new BiffCtlsStreamObject( *this, xCtlsStrm ) );
            }
            const Config& rCfg = cfg();
            mxErrCodes = rCfg.getNameList( "ERRORCODES" );
            mxConstType = rCfg.getNameList( "CONSTVALUE-TYPE" );
            mxResultType = rCfg.getNameList( "FORMULA-RESULTTYPE" );
            mnLastRecId = BIFF_ID_UNKNOWN;
            mbMergeContRec = rCfg.getBoolOption( "merge-continue-record", true );
        }
    }
}

void BiffObjectBase::construct( const BiffObjectBase& rParent )
{
    *this = rParent;
}

bool BiffObjectBase::implIsValid() const
{
    return isValid( mxBiffData ) && mxBiffStrm.get() && isValid( mxDffObj ) && InputObjectBase::implIsValid();
}

bool BiffObjectBase::implStartRecord( BinaryInputStream&, sal_Int64& ornRecPos, sal_Int64& ornRecId, sal_Int64& ornRecSize )
{
    // previous record
    mnLastRecId = mxBiffStrm->getRecId();
    switch( mnLastRecId )
    {
        case BIFF_ID_CHBEGIN:
            mxOut->incIndent();
        break;
    }

    // start next record
    bool bValid = mxBiffStrm->startNextRecord();
    ornRecPos = mxBiffStrm->tellBase() - 4;
    ornRecId = mxBiffStrm->getRecId();

    // special CONTINUE handling
    mxBiffStrm->resetRecord( mbMergeContRec );
    if( mbMergeContRec ) switch( mxBiffStrm->getRecId() )
    {
        case BIFF_ID_OBJ:
        case BIFF_ID_TXO:
        case BIFF_ID_EOF:
        case BIFF_ID_CONT:
            mxBiffStrm->resetRecord( false );
        break;
        case BIFF_ID_MSODRAWINGGROUP:
        case BIFF_ID_CHESCHERFORMAT:
            mxBiffStrm->resetRecord( true, mxBiffStrm->getRecId() );
        break;
    }

    // record specific settings
    switch( mxBiffStrm->getRecId() )
    {
        case BIFF2_ID_BOF:
        case BIFF3_ID_BOF:
        case BIFF4_ID_BOF:
        case BIFF5_ID_BOF:
        case BIFF_ID_INTERFACEHDR:
            mxBiffStrm->enableDecoder( false );
        break;
        case BIFF_ID_CHEND:
            mxOut->decIndent();
        break;
    }

    ornRecSize = mxBiffStrm->size();
    return bValid;
}

OUString BiffObjectBase::getErrorName( sal_uInt8 nErrCode ) const
{
    return cfg().getName( mxErrCodes, nErrCode );
}

// ----------------------------------------------------------------------------

sal_Int32 BiffObjectBase::readCol( bool bCol16Bit )
{
    return bCol16Bit ? mxBiffStrm->readuInt16() : mxBiffStrm->readuInt8();
}

sal_Int32 BiffObjectBase::readRow( bool bRow32Bit )
{
    return bRow32Bit ? mxBiffStrm->readInt32() : mxBiffStrm->readuInt16();
}

void BiffObjectBase::readAddress( Address& orAddress, bool bCol16Bit, bool bRow32Bit )
{
    orAddress.mnRow = readRow( bRow32Bit );
    orAddress.mnCol = readCol( bCol16Bit );
}

void BiffObjectBase::readRange( Range& orRange, bool bCol16Bit, bool bRow32Bit )
{
    orRange.maFirst.mnRow = readRow( bRow32Bit );
    orRange.maLast.mnRow = readRow( bRow32Bit );
    orRange.maFirst.mnCol = readCol( bCol16Bit );
    orRange.maLast.mnCol = readCol( bCol16Bit );
}

void BiffObjectBase::readRangeList( RangeList& orRanges, bool bCol16Bit, bool bRow32Bit )
{
    sal_uInt16 nCount;
    *mxBiffStrm >> nCount;
    orRanges.resize( nCount );
    for( RangeList::iterator aIt = orRanges.begin(), aEnd = orRanges.end(); !mxBiffStrm->isEof() && (aIt != aEnd); ++aIt )
        readRange( *aIt, bCol16Bit, bRow32Bit );
}

// ----------------------------------------------------------------------------

void BiffObjectBase::writeBooleanItem( const String& rName, sal_uInt8 nBool )
{
    writeDecItem( rName, nBool, "BOOLEAN" );
}

void BiffObjectBase::writeErrorCodeItem( const String& rName, sal_uInt8 nErrCode )
{
    writeHexItem( rName, nErrCode, mxErrCodes );
}

void BiffObjectBase::writeFontPortions( const FontPortionModelList& rPortions )
{
    if( !rPortions.empty() )
    {
        writeDecItem( "font-count", static_cast< sal_uInt32 >( rPortions.size() ) );
        TableGuard aTabGuard( mxOut, 14 );
        for( FontPortionModelList::const_iterator aIt = rPortions.begin(), aEnd = rPortions.end(); aIt != aEnd; ++aIt )
        {
            MultiItemsGuard aMultiGuard( mxOut );
            writeDecItem( "char-pos", aIt->mnPos );
            writeDecItem( "font-idx", aIt->mnFontId, "FONTNAMES" );
        }
    }
}

// ----------------------------------------------------------------------------

OUString BiffObjectBase::dumpByteString( const String& rName, BiffStringFlags nFlags, rtl_TextEncoding eDefaultTextEnc )
{
    OSL_ENSURE( !getFlag( nFlags, static_cast< BiffStringFlags >( ~(BIFF_STR_8BITLENGTH | BIFF_STR_EXTRAFONTS) ) ), "BiffObjectBase::dumpByteString - unknown flag" );
    bool b8BitLength = getFlag( nFlags, BIFF_STR_8BITLENGTH );

    OString aString = mxBiffStrm->readByteString( !b8BitLength, true );
    FontPortionModelList aPortions;
    if( getFlag( nFlags, BIFF_STR_EXTRAFONTS ) )
        aPortions.importPortions( *mxBiffStrm, false );

    // create string portions
    OUStringBuffer aBuffer;
    sal_Int32 nStrLen = aString.getLength();
    if( nStrLen > 0 )
    {
        // add leading and trailing string position to ease the following loop
        if( aPortions.empty() || (aPortions.front().mnPos > 0) )
            aPortions.insert( aPortions.begin(), FontPortionModel( 0, -1 ) );
        if( aPortions.back().mnPos < nStrLen )
            aPortions.push_back( FontPortionModel( nStrLen, -1 ) );

        // use global text encoding, if nothing special is specified
        if( eDefaultTextEnc == RTL_TEXTENCODING_DONTKNOW )
            eDefaultTextEnc = getBiffData().getTextEncoding();

        // create all string portions according to the font id vector
        for( FontPortionModelList::const_iterator aIt = aPortions.begin(); aIt->mnPos < nStrLen; ++aIt )
        {
            sal_Int32 nPortionLen = (aIt + 1)->mnPos - aIt->mnPos;
            if( nPortionLen > 0 )
            {
                // convert byte string to unicode string, using current font encoding
                rtl_TextEncoding eTextEnc = mxBiffData->getFontEncoding( static_cast< sal_uInt16 >( aIt->mnFontId ) );
                if( eTextEnc == RTL_TEXTENCODING_DONTKNOW )
                    eTextEnc = eDefaultTextEnc;
                aBuffer.append( OStringToOUString( aString.copy( aIt->mnPos, nPortionLen ), eTextEnc ) );
            }
        }
    }

    OUString aUniStr = aBuffer.makeStringAndClear();
    writeStringItem( rName( "text" ), aUniStr );
    return aUniStr;
}

OUString BiffObjectBase::dumpUniString( const String& rName, BiffStringFlags nFlags )
{
    OSL_ENSURE( !getFlag( nFlags, static_cast< BiffStringFlags >( ~(BIFF_STR_8BITLENGTH | BIFF_STR_SMARTFLAGS) ) ), "BiffObjectBase::dumpUniString - unknown flag" );
    bool b8BitLength = getFlag( nFlags, BIFF_STR_8BITLENGTH );

    // --- string header ---
    sal_uInt16 nChars = b8BitLength ? mxBiffStrm->readuInt8() : mxBiffStrm->readuInt16();
    sal_uInt8 nFlagField = 0;
    if( (nChars > 0) || !getFlag( nFlags, BIFF_STR_SMARTFLAGS ) )
        *mxBiffStrm >> nFlagField;
    bool b16Bit    = getFlag( nFlagField, BIFF_STRF_16BIT );
    bool bFonts    = getFlag( nFlagField, BIFF_STRF_RICH );
    bool bPhonetic = getFlag( nFlagField, BIFF_STRF_PHONETIC );
    sal_uInt16 nFontCount = bFonts ? mxBiffStrm->readuInt16() : 0;
    sal_uInt32 nPhoneticSize = bPhonetic ? mxBiffStrm->readuInt32() : 0;

    // --- character array ---
    OUString aString = mxBiffStrm->readUniStringChars( nChars, b16Bit, true );
    writeStringItem( rName( "text" ), aString );

    // --- formatting ---
    // #122185# bRich flag may be set, but format runs may be missing
    if( nFontCount > 0 )
    {
        IndentGuard aIndGuard( mxOut );
        FontPortionModelList aPortions;
        aPortions.importPortions( *mxBiffStrm, nFontCount, BIFF_FONTPORTION_16BIT );
        writeFontPortions( aPortions );
    }

    // --- phonetic information ---
    // #122185# bPhonetic flag may be set, but phonetic data may be missing
    if( nPhoneticSize > 0 )
    {
        sal_Int64 nStrmPos = mxBiffStrm->tell();
        IndentGuard aIndGuard( mxOut );
        writeEmptyItem( "phonetic-data" );
        dumpUnused( 2 );
        dumpDec< sal_uInt16 >( "size" );
        dumpDec< sal_uInt16 >( "font-idx", "FONTNAMES" );
        dumpHex< sal_uInt16 >( "flags", "PHONETICPR-FLAGS" );
        sal_uInt16 nCount = dumpDec< sal_uInt16 >( "portion-count" );
        sal_uInt16 nLen = dumpDec< sal_uInt16 >( "text-len" );
        dumpUnicodeArray( "text", mxBiffStrm->readuInt16() );
        if( nLen == 0 ) dumpUnused( 2 );
        for( sal_uInt16 nPortion = 0; !mxBiffStrm->isEof() && (nPortion < nCount); ++nPortion )
        {
            MultiItemsGuard aMultiGuard( mxOut );
            dumpDec< sal_uInt16 >( "first-portion-char" );
            dumpDec< sal_uInt16 >( "first-main-char" );
            dumpDec< sal_uInt16 >( "main-char-count" );
        }
        dumpRemainingTo( nStrmPos + nPhoneticSize );
    }

    return aString;
}

OUString BiffObjectBase::dumpString( const String& rName, BiffStringFlags nByteFlags, BiffStringFlags nUniFlags, rtl_TextEncoding eDefaultTextEnc )
{
    return (getBiff() == BIFF8) ? dumpUniString( rName, nUniFlags ) : dumpByteString( rName, nByteFlags, eDefaultTextEnc );
}

OUString BiffObjectBase::dumpSegmentedUniString( const String& rName )
{
    sal_Int32 nLength = mxBiffStrm->readInt32();
    OUStringBuffer aBuffer;
    while( !mxBiffStrm->isEof() && (aBuffer.getLength() < nLength) )
        aBuffer.append( mxBiffStrm->readUniString() );
    OUString aString = aBuffer.makeStringAndClear();
    writeStringItem( rName, aString );
    return aString;
}

void BiffObjectBase::dumpSegmentedUniStringArray( const String& rName )
{
    writeEmptyItem( rName );
    IndentGuard aIndGuard( mxOut );
    mxOut->resetItemIndex();
    for( sal_uInt16 nIndex = 0, nCount = dumpDec< sal_uInt16 >( "count" ); !mxBiffStrm->isEof() && (nIndex < nCount); ++nIndex )
        dumpSegmentedUniString( "#entry" );
}

sal_uInt8 BiffObjectBase::dumpBoolean( const String& rName )
{
    sal_uInt8 nBool;
    *mxBiffStrm >> nBool;
    writeBooleanItem( rName( "boolean" ), nBool );
    return nBool;
}

sal_uInt8 BiffObjectBase::dumpErrorCode( const String& rName )
{
    sal_uInt8 nErrCode;
    *mxBiffStrm >> nErrCode;
    writeErrorCodeItem( rName( "error-code" ), nErrCode );
    return nErrCode;
}

rtl_TextEncoding BiffObjectBase::dumpCodePage( const String& rName )
{
    sal_uInt16 nCodePage = dumpDec< sal_uInt16 >( rName( "codepage" ), "CODEPAGES" );
    return BiffHelper::calcTextEncodingFromCodePage( nCodePage );
}

void BiffObjectBase::dumpFormulaResult( const String& rName )
{
    MultiItemsGuard aMultiGuard( mxOut );
    sal_uInt8 pnResult[ 8 ];
    mxBiffStrm->readMemory( pnResult, 8 );
    writeArrayItem( rName( "result" ), pnResult, 8 );
    if( (pnResult[ 6 ] == 0xFF) && (pnResult[ 7 ] == 0xFF) )
    {
        sal_uInt8 nType = pnResult[ 0 ];
        sal_uInt8 nData = pnResult[ 2 ];
        writeHexItem( "type", nType, mxResultType );
        switch( nType )
        {
            case 1: writeBooleanItem( "value", nData );     break;
            case 2: writeErrorCodeItem( "value", nData );   break;
        }
    }
    else
    {
        double* pfValue = reinterpret_cast< double* >( pnResult );
        ByteOrderConverter::convertLittleEndian( *pfValue );
        writeDecItem( "value", *pfValue );
    }
}

sal_Int32 BiffObjectBase::dumpColIndex( const String& rName, bool bCol16Bit )
{
    sal_Int32 nCol = readCol( bCol16Bit );
    writeColIndexItem( rName( "col-idx" ), nCol );
    return nCol;
}

sal_Int32 BiffObjectBase::dumpRowIndex( const String& rName, bool bRow32Bit )
{
    sal_Int32 nRow = readRow( bRow32Bit );
    writeRowIndexItem( rName( "row-idx" ), nRow );
    return nRow;
}

sal_Int32 BiffObjectBase::dumpColRange( const String& rName, bool bCol16Bit )
{
    sal_Int32 nCol1 = readCol( bCol16Bit );
    sal_Int32 nCol2 = readCol( bCol16Bit );
    writeColRangeItem( rName( "col-range" ), nCol1, nCol2 );
    return nCol2 - nCol1 + 1;
}

sal_Int32 BiffObjectBase::dumpRowRange( const String& rName, bool bRow32Bit )
{
    sal_Int32 nRow1 = readRow( bRow32Bit );
    sal_Int32 nRow2 = readRow( bRow32Bit );
    writeRowRangeItem( rName( "row-range" ), nRow1, nRow2 );
    return nRow2 - nRow1 + 1;
}

Address BiffObjectBase::dumpAddress( const String& rName, bool bCol16Bit, bool bRow32Bit )
{
    Address aPos;
    readAddress( aPos, bCol16Bit, bRow32Bit );
    writeAddressItem( rName( "addr" ), aPos );
    return aPos;
}

Range BiffObjectBase::dumpRange( const String& rName, bool bCol16Bit, bool bRow32Bit )
{
    Range aRange;
    readRange( aRange, bCol16Bit, bRow32Bit );
    writeRangeItem( rName( "range" ), aRange );
    return aRange;
}

void BiffObjectBase::dumpRangeList( const String& rName, bool bCol16Bit, bool bRow32Bit )
{
    RangeList aRanges;
    readRangeList( aRanges, bCol16Bit, bRow32Bit );
    writeRangeListItem( rName( "range-list" ), aRanges );
}

void BiffObjectBase::dumpConstArrayHeader( sal_uInt32& rnCols, sal_uInt32& rnRows )
{
    MultiItemsGuard aMultiGuard( mxOut );
    rnCols = dumpDec< sal_uInt8 >( "width" );
    rnRows = dumpDec< sal_uInt16 >( "height" );
    switch( getBiff() )
    {
        case BIFF2:
        case BIFF3:
        case BIFF4:
        case BIFF5: if( rnCols == 0 ) rnCols = 256; break;
        case BIFF8: ++rnCols; ++rnRows;             break;
        case BIFF_UNKNOWN:                          break;
    }
    ItemGuard aItem( mxOut, "size" );
    mxOut->writeDec( rnCols );
    mxOut->writeChar( 'x' );
    mxOut->writeDec( rnRows );
    aItem.cont();
    mxOut->writeDec( rnCols * rnRows );
}

OUString BiffObjectBase::dumpConstValue( sal_Unicode cStrQuote )
{
    MultiItemsGuard aMultiGuard( mxOut );
    OUStringBuffer aValue;
    switch( dumpDec< sal_uInt8 >( "type", mxConstType ) )
    {
        case BIFF_DATATYPE_EMPTY:
            dumpUnused( 8 );
            aValue.append( OOX_DUMP_EMPTYVALUE );
        break;
        case BIFF_DATATYPE_DOUBLE:
            dumpDec< double >( "value" );
            aValue.append( mxOut->getLastItemValue() );
        break;
        case BIFF_DATATYPE_STRING:
            aValue.append( dumpString( "value", BIFF_STR_8BITLENGTH ) );
            StringHelper::enclose( aValue, cStrQuote );
        break;
        case BIFF_DATATYPE_BOOL:
            dumpBoolean( "value" );
            aValue.append( mxOut->getLastItemValue() );
            dumpUnused( 7 );
        break;
        case BIFF_DATATYPE_ERROR:
            dumpErrorCode( "value" );
            aValue.append( mxOut->getLastItemValue() );
            dumpUnused( 7 );
        break;
    }
    return aValue.makeStringAndClear();
}

sal_uInt16 BiffObjectBase::dumpRepeatedRecId()
{
    return dumpHex< sal_uInt16 >( "repeated-rec-id", getRecNames() );
}

void BiffObjectBase::dumpFrHeader( bool bWithFlags, bool bWithRange )
{
    dumpHex< sal_uInt16 >( "fr-rec-id", getRecNames() );
    sal_Int16 nFlags = bWithFlags ? dumpHex< sal_uInt16 >( "fr-flags", "FR-FLAGS" ) : 0x0001;
    if( bWithRange )
    {
        if( getFlag< sal_uInt16 >( nFlags, 0x0001 ) )
            dumpRange( "fr-range" );
        else
            dumpUnused( 8 );
    }
}

void BiffObjectBase::dumpDffClientRect()
{
    lclDumpDffClientRect( mxOut, mxStrm );
}

void BiffObjectBase::dumpEmbeddedDff()
{
    mxOut->decIndent();
    writeEmptyItem( "EMBEDDED-DFF-START" );
    mxOut->incIndent();
    mxDffObj->dump();
    mxOut->emptyLine();
    mxOut->decIndent();
    writeEmptyItem( "EMBEDDED-DFF-END" );
    mxOut->incIndent();
}

void BiffObjectBase::dumpControl()
{
    sal_uInt32 nStartPos = dumpHex< sal_uInt32 >( "ctls-stream-pos", "CONV-DEC" );
    sal_uInt32 nLength = dumpHex< sal_uInt32 >( "ctls-stream-length", "CONV-DEC" );
    if( isValid( mxCtlsObj ) )
        mxCtlsObj->dumpControl( nStartPos, nLength );
}

// ============================================================================
// ============================================================================

FormulaObject::FormulaObject( const BiffObjectBase& rParent ) :
    mnSize( 0 )
{
    BiffObjectBase::construct( rParent );
    constructFmlaObj();
}

FormulaObject::~FormulaObject()
{
}

sal_uInt16 FormulaObject::readFormulaSize()
{
    return (getBiff() == BIFF2) ? getBiffStream().readuInt8() : getBiffStream().readuInt16();
}

sal_uInt16 FormulaObject::dumpFormulaSize( const String& rName )
{
    sal_uInt16 nSize = readFormulaSize();
    writeDecItem( rName( "formula-size" ), nSize );
    return nSize;
}

void FormulaObject::dumpCellFormula( const String& rName, sal_uInt16 nSize )
{
    dumpFormula( rName, nSize, false );
}

void FormulaObject::dumpCellFormula( const String& rName )
{
    dumpFormula( rName, false );
}

void FormulaObject::dumpNameFormula( const String& rName, sal_uInt16 nSize )
{
    dumpFormula( rName, nSize, true );
}

void FormulaObject::dumpNameFormula( const String& rName )
{
    dumpFormula( rName, true );
}

void FormulaObject::implDump()
{
    {
        MultiItemsGuard aMultiGuard( mxOut );
        writeEmptyItem( maName );
        writeDecItem( "formula-size", mnSize );
    }
    if( mnSize == 0 ) return;

    sal_Int64 nStartPos = mxStrm->tell();
    sal_Int64 nEndPos = ::std::min< sal_Int64 >( nStartPos + mnSize, mxStrm->size() );

    bool bValid = mxTokens.get();
    mxStack.reset( new FormulaStack );
    maAddData.clear();
    IndentGuard aIndGuard( mxOut );
    {
        TableGuard aTabGuard( mxOut, 8, 18 );
        while( bValid && !mxStrm->isEof() && (mxStrm->tell() < nEndPos) )
        {
            MultiItemsGuard aMultiGuard( mxOut );
            writeHexItem( EMPTY_STRING, static_cast< sal_uInt16 >( mxStrm->tell() - nStartPos ) );
            sal_uInt8 nTokenId = dumpHex< sal_uInt8 >( EMPTY_STRING, mxTokens );
            bValid = mxTokens->hasName( nTokenId );
            if( bValid )
            {
                sal_uInt8 nTokClass = nTokenId & BIFF_TOKCLASS_MASK;
                sal_uInt8 nBaseId = nTokenId & BIFF_TOKID_MASK;
                if( nTokClass == BIFF_TOKCLASS_NONE )
                {
                    switch( nBaseId )
                    {
                        case BIFF_TOKID_EXP:        dumpExpToken( "EXP" );          break;
                        case BIFF_TOKID_TBL:        dumpExpToken( "TBL" );          break;
                        case BIFF_TOKID_ADD:        dumpBinaryOpToken( "+" );       break;
                        case BIFF_TOKID_SUB:        dumpBinaryOpToken( "-" );       break;
                        case BIFF_TOKID_MUL:        dumpBinaryOpToken( "*" );       break;
                        case BIFF_TOKID_DIV:        dumpBinaryOpToken( "/" );       break;
                        case BIFF_TOKID_POWER:      dumpBinaryOpToken( "^" );       break;
                        case BIFF_TOKID_CONCAT:     dumpBinaryOpToken( "&" );       break;
                        case BIFF_TOKID_LT:         dumpBinaryOpToken( "<" );       break;
                        case BIFF_TOKID_LE:         dumpBinaryOpToken( "<=" );      break;
                        case BIFF_TOKID_EQ:         dumpBinaryOpToken( "=" );       break;
                        case BIFF_TOKID_GE:         dumpBinaryOpToken( ">=" );      break;
                        case BIFF_TOKID_GT:         dumpBinaryOpToken( "<" );       break;
                        case BIFF_TOKID_NE:         dumpBinaryOpToken( "<>" );      break;
                        case BIFF_TOKID_ISECT:      dumpBinaryOpToken( " " );       break;
                        case BIFF_TOKID_LIST:       dumpBinaryOpToken( "," );       break;
                        case BIFF_TOKID_RANGE:      dumpBinaryOpToken( ":" );       break;
                        case BIFF_TOKID_UPLUS:      dumpUnaryOpToken( "+", "" );    break;
                        case BIFF_TOKID_UMINUS:     dumpUnaryOpToken( "-", "" );    break;
                        case BIFF_TOKID_PERCENT:    dumpUnaryOpToken( "", "%" );    break;
                        case BIFF_TOKID_PAREN:      dumpUnaryOpToken( "(", ")" );   break;
                        case BIFF_TOKID_MISSARG:    dumpMissArgToken();             break;
                        case BIFF_TOKID_STR:        dumpStringToken();              break;
                        case BIFF_TOKID_NLR:        bValid = dumpNlrToken();        break;
                        case BIFF_TOKID_ATTR:       bValid = dumpAttrToken();       break;
                        case BIFF_TOKID_SHEET:      dumpSheetToken();               break;
                        case BIFF_TOKID_ENDSHEET:   dumpEndSheetToken();            break;
                        case BIFF_TOKID_ERR:        dumpErrorToken();               break;
                        case BIFF_TOKID_BOOL:       dumpBoolToken();                break;
                        case BIFF_TOKID_INT:        dumpIntToken();                 break;
                        case BIFF_TOKID_NUM:        dumpDoubleToken();              break;
                        default:                    bValid = false;
                    }
                }
                else
                {
                    OUString aTokClass = cfg().getName( mxClasses, nTokClass );
                    switch( nBaseId )
                    {
                        case BIFF_TOKID_ARRAY:      dumpArrayToken( aTokClass );                break;
                        case BIFF_TOKID_FUNC:       dumpFuncToken( aTokClass );                 break;
                        case BIFF_TOKID_FUNCVAR:    dumpFuncVarToken( aTokClass );              break;
                        case BIFF_TOKID_NAME:       dumpNameToken( aTokClass );                 break;
                        case BIFF_TOKID_REF:        dumpRefToken( aTokClass, false );           break;
                        case BIFF_TOKID_AREA:       dumpAreaToken( aTokClass, false );          break;
                        case BIFF_TOKID_MEMAREA:    dumpMemAreaToken( aTokClass, true );        break;
                        case BIFF_TOKID_MEMERR:     dumpMemAreaToken( aTokClass, false );       break;
                        case BIFF_TOKID_MEMNOMEM:   dumpMemAreaToken( aTokClass, false );       break;
                        case BIFF_TOKID_MEMFUNC:    dumpMemFuncToken( aTokClass );              break;
                        case BIFF_TOKID_REFERR:     dumpRefErrToken( aTokClass, false );        break;
                        case BIFF_TOKID_AREAERR:    dumpRefErrToken( aTokClass, true );         break;
                        case BIFF_TOKID_REFN:       dumpRefToken( aTokClass, true );            break;
                        case BIFF_TOKID_AREAN:      dumpAreaToken( aTokClass, true );           break;
                        case BIFF_TOKID_MEMAREAN:   dumpMemFuncToken( aTokClass );              break;
                        case BIFF_TOKID_MEMNOMEMN:  dumpMemFuncToken( aTokClass );              break;
                        case BIFF_TOKID_FUNCCE:     dumpCmdToken( aTokClass );                  break;
                        case BIFF_TOKID_NAMEX:      dumpNameXToken( aTokClass );                break;
                        case BIFF_TOKID_REF3D:      dumpRef3dToken( aTokClass, mbNameMode );    break;
                        case BIFF_TOKID_AREA3D:     dumpArea3dToken( aTokClass, mbNameMode );   break;
                        case BIFF_TOKID_REFERR3D:   dumpRefErr3dToken( aTokClass, false );      break;
                        case BIFF_TOKID_AREAERR3D:  dumpRefErr3dToken( aTokClass, true );       break;
                        default:                    bValid = false;
                    }
                }
            }
        }
    }
    bValid = nEndPos == mxStrm->tell();
    if( bValid )
    {
        dumpAddTokenData();
        writeInfoItem( "formula", mxStack->getFormulaString() );
        writeInfoItem( "classes", mxStack->getClassesString() );
    }
    else
        dumpBinary( OOX_DUMP_ERRASCII( "formula-error" ), nEndPos - mxStrm->tell(), false );

    mnSize = 0;
}

void FormulaObject::dumpFormula( const String& rName, sal_uInt16 nSize, bool bNameMode )
{
    maName = rName( "formula" );
    mnSize = nSize;
    mbNameMode = bNameMode;
    dump();
    mnSize = 0;
}

void FormulaObject::dumpFormula( const String& rName, bool bNameMode )
{
    dumpFormula( rName, readFormulaSize(), bNameMode );
}

// private --------------------------------------------------------------------

void FormulaObject::constructFmlaObj()
{
    if( BiffObjectBase::implIsValid() )
    {
        mxFuncProv.reset( new FunctionProvider( FILTER_BIFF, getBiff(), true ) );

        Config& rCfg = cfg();
        mxClasses   = rCfg.getNameList( "TOKENCLASSES" );
        mxRelFlags  = rCfg.getNameList( "REFRELFLAGS" );
        mxNlrTypes  = rCfg.getNameList( "NLRTYPES" );
        mxAttrTypes = rCfg.getNameList( "ATTRTYPES" );
        mxSpTypes   = rCfg.getNameList( "ATTRSPACETYPES" );

        // create classified token names
        mxTokens = rCfg.createNameList< ConstList >( "TOKENS" );
        mxTokens->includeList( rCfg.getNameList( "BASETOKENS" ) );

        NameListRef xClassTokens = rCfg.getNameList( "CLASSTOKENS" );
        if( mxClasses.get() && xClassTokens.get() )
            for( NameListBase::const_iterator aCIt = mxClasses->begin(), aCEnd = mxClasses->end(); aCIt != aCEnd; ++aCIt )
                for( NameListBase::const_iterator aTIt = xClassTokens->begin(), aTEnd = xClassTokens->end(); aTIt != aTEnd; ++aTIt )
                    mxTokens->setName( aCIt->first | aTIt->first, aTIt->second + aCIt->second );

        mnColCount = 256;
        mnRowCount = (getBiff() == BIFF8) ? 65536 : 16384;
    }
}

// ----------------------------------------------------------------------------

namespace {

OUString lclCreateName( const OUString& rRef, sal_uInt16 nNameIdx )
{
    OUStringBuffer aName( rRef );
    StringHelper::appendIndexedText( aName, CREATE_OUSTRING( "NAME" ), nNameIdx );
    return aName.makeStringAndClear();
}

OUString lclCreateNlr( const OUString& rData, bool bRel = true )
{
    OUStringBuffer aNlr;
    if( !bRel ) aNlr.append( OOX_DUMP_ADDRABS );
    StringHelper::appendIndexedText( aNlr, CREATE_OUSTRING( "NLR" ), rData );
    return aNlr.makeStringAndClear();
}

OUString lclCreateNlr( const TokenAddress& rPos )
{
    OUStringBuffer aAddr;
    StringHelper::appendAddrCol( aAddr, rPos.mnCol, true );
    StringHelper::appendAddrRow( aAddr, rPos.mnRow, true );
    return lclCreateNlr( aAddr.makeStringAndClear(), rPos.mbRelRow );
}

} // namespace

// ----------------------------------------------------------------------------

TokenAddress FormulaObject::createTokenAddress( sal_uInt16 nCol, sal_uInt16 nRow, bool bRelC, bool bRelR, bool bNameMode ) const
{
    TokenAddress aPos;
    aPos.mnCol = nCol;
    if( bRelC && bNameMode && (nCol >= mnColCount / 2) ) aPos.mnCol -= mnColCount;
    aPos.mbRelCol = bRelC;
    aPos.mnRow = nRow;
    if( bRelR && bNameMode && (nRow >= mnRowCount / 2) ) aPos.mnRow -= mnRowCount;
    aPos.mbRelRow = bRelR;
    return aPos;
}

OUString FormulaObject::createRef( const OUString& rData ) const
{
    return maRefPrefix + rData;
}

OUString FormulaObject::createName( sal_uInt16 nNameIdx ) const
{
    return lclCreateName( maRefPrefix, nNameIdx );
}

OUString FormulaObject::createPlaceHolder( size_t nIdx ) const
{
    OUStringBuffer aStr;
    StringHelper::appendDec( aStr, static_cast< sal_uInt32 >( nIdx ) );
    StringHelper::enclose( aStr, OOX_DUMP_PLACEHOLDER );
    return aStr.makeStringAndClear();
}

OUString FormulaObject::createPlaceHolder() const
{
    return createPlaceHolder( maAddData.size() );
}

sal_uInt16 FormulaObject::readFuncId()
{
    return (getBiff() >= BIFF4) ? mxStrm->readuInt16() : mxStrm->readuInt8();
}

OUString FormulaObject::writeFuncIdItem( sal_uInt16 nFuncId, const FunctionInfo** oppFuncInfo )
{
    ItemGuard aItemGuard( mxOut, "func-id" );
    writeHexItem( EMPTY_STRING, nFuncId, "FUNCID" );
    OUStringBuffer aBuffer;
    const FunctionInfo* pFuncInfo = mxFuncProv->getFuncInfoFromBiffFuncId( nFuncId );
    if( pFuncInfo )
        aBuffer.append( pFuncInfo->maOoxFuncName );
    else
    {
        bool bCmd = getFlag( nFuncId, BIFF_TOK_FUNCVAR_CMD );
        aBuffer.appendAscii( bCmd ? "CMD" : "FUNC" );
        StringHelper::appendIndex( aBuffer, nFuncId & BIFF_TOK_FUNCVAR_FUNCIDMASK );
    }
    OUString aFuncName = aBuffer.makeStringAndClear();
    aItemGuard.cont();
    mxOut->writeChar( OOX_DUMP_STRQUOTE );
    mxOut->writeString( aFuncName );
    mxOut->writeChar( OOX_DUMP_STRQUOTE );
    if( oppFuncInfo ) *oppFuncInfo = pFuncInfo;
    return aFuncName;
}

sal_uInt16 FormulaObject::dumpTokenCol( const String& rName, bool& rbRelC, bool& rbRelR )
{
    sal_uInt16 nCol = 0;
    if( getBiff() == BIFF8 )
    {
        nCol = dumpHex< sal_uInt16 >( rName, mxRelFlags );
        rbRelC = getFlag( nCol, BIFF_TOK_REF_COLREL );
        rbRelR = getFlag( nCol, BIFF_TOK_REF_ROWREL );
        nCol &= BIFF_TOK_REF_COLMASK;
    }
    else
        nCol = dumpDec< sal_uInt8 >( rName );
    return nCol;
}

sal_uInt16 FormulaObject::dumpTokenRow( const String& rName, bool& rbRelC, bool& rbRelR )
{
    sal_uInt16 nRow = 0;
    if( getBiff() == BIFF8 )
        nRow = dumpDec< sal_uInt16 >( rName );
    else
    {
        nRow = dumpHex< sal_uInt16 >( rName, mxRelFlags );
        rbRelC = getFlag( nRow, BIFF_TOK_REF_COLREL );
        rbRelR = getFlag( nRow, BIFF_TOK_REF_ROWREL );
        nRow &= BIFF_TOK_REF_ROWMASK;
    }
    return nRow;
}

TokenAddress FormulaObject::dumpTokenAddress( bool bNameMode )
{
    bool bRelC = false;
    bool bRelR = false;
    sal_uInt16 nRow = dumpTokenRow( "row", bRelC, bRelR );
    sal_uInt16 nCol = dumpTokenCol( "col", bRelC, bRelR );
    return createTokenAddress( nCol, nRow, bRelC, bRelR, bNameMode );
}

TokenRange FormulaObject::dumpTokenRange( bool bNameMode )
{
    bool bRelC1 = false;
    bool bRelR1 = false;
    bool bRelC2 = false;
    bool bRelR2 = false;
    sal_uInt16 nRow1 = dumpTokenRow( "row1", bRelC1, bRelR1 );
    sal_uInt16 nRow2 = dumpTokenRow( "row2", bRelC2, bRelR2 );
    sal_uInt16 nCol1 = dumpTokenCol( "col1", bRelC1, bRelR1 );
    sal_uInt16 nCol2 = dumpTokenCol( "col2", bRelC2, bRelR2 );
    TokenRange aRange;
    aRange.maFirst = createTokenAddress( nCol1, nRow1, bRelC1, bRelR1, bNameMode );
    aRange.maLast  = createTokenAddress( nCol2, nRow2, bRelC2, bRelR2, bNameMode );
    return aRange;
}

sal_Int16 FormulaObject::readTokenRefIdx()
{
    sal_Int16 nRefIdx = dumpDec< sal_Int16 >( "ref-idx" );
    switch( getBiff() )
    {
        case BIFF2: dumpUnused( 1 );    break;
        case BIFF3: dumpUnused( 2 );    break;
        case BIFF4: dumpUnused( 2 );    break;
        case BIFF5: dumpUnused( 8 );    break;
        case BIFF8:                     break;
        case BIFF_UNKNOWN:              break;
    }
    return nRefIdx;
}

OUString FormulaObject::dumpTokenRefIdx()
{
    OUStringBuffer aRef( CREATE_OUSTRING( "REF" ) );
    StringHelper::appendIndex( aRef, readTokenRefIdx() );
    aRef.append( OOX_DUMP_TABSEP );
    return aRef.makeStringAndClear();
}

OUString FormulaObject::dumpTokenRefTabIdxs()
{
    sal_Int16 nRefIdx = readTokenRefIdx();
    OUStringBuffer aRef( CREATE_OUSTRING( "REF" ) );
    StringHelper::appendIndex( aRef, nRefIdx );
    if( getBiff() == BIFF5 )
    {
        dumpDec< sal_Int16 >( "tab1" );
        sal_Int16 nTab2 = dumpDec< sal_Int16 >( "tab2" );
        if( (nRefIdx > 0) && (nTab2 > 0) && (nRefIdx != nTab2) )
        {
            aRef.append( OOX_DUMP_RANGESEP );
            aRef.appendAscii( "REF" );
            StringHelper::appendIndex( aRef, nTab2 );
        }
    }
    aRef.append( OOX_DUMP_TABSEP );
    return aRef.makeStringAndClear();
}

void FormulaObject::dumpIntToken()
{
    dumpDec< sal_uInt16 >( "value" );
    mxStack->pushOperand( mxOut->getLastItemValue() );
}

void FormulaObject::dumpDoubleToken()
{
    dumpDec< double >( "value" );
    mxStack->pushOperand( mxOut->getLastItemValue() );
}

void FormulaObject::dumpStringToken()
{
    OUStringBuffer aValue;
    aValue.append( dumpString( "value", BIFF_STR_8BITLENGTH, BIFF_STR_8BITLENGTH ) );
    StringHelper::enclose( aValue, OOX_DUMP_FMLASTRQUOTE );
    mxStack->pushOperand( aValue.makeStringAndClear() );
}

void FormulaObject::dumpBoolToken()
{
    dumpBoolean( "value" );
    mxStack->pushOperand( mxOut->getLastItemValue() );
}

void FormulaObject::dumpErrorToken()
{
    dumpErrorCode( "value" );
    mxStack->pushOperand( mxOut->getLastItemValue() );
}

void FormulaObject::dumpMissArgToken()
{
    mxStack->pushOperand( OUString( OOX_DUMP_EMPTYVALUE ) );
}

void FormulaObject::dumpArrayToken( const OUString& rTokClass )
{
    dumpUnused( (getBiff() == BIFF2) ? 6 : 7 );
    mxStack->pushOperand( createPlaceHolder(), rTokClass );
    maAddData.push_back( ADDDATA_ARRAY );
}

void FormulaObject::dumpNameToken( const OUString& rTokClass )
{
    sal_uInt16 nNameIdx = dumpDec< sal_uInt16 >( "name-idx" );
    switch( getBiff() )
    {
        case BIFF2: dumpUnused( 5 );    break;
        case BIFF3:
        case BIFF4: dumpUnused( 8 );    break;
        case BIFF5: dumpUnused( 12 );   break;
        case BIFF8: dumpUnused( 2 );    break;
        case BIFF_UNKNOWN:              break;
    }
    mxStack->pushOperand( createName( nNameIdx ), rTokClass );
}

void FormulaObject::dumpNameXToken( const OUString& rTokClass )
{
    OUString aRef = dumpTokenRefIdx();
    sal_uInt16 nNameIdx = dumpDec< sal_uInt16 >( "name-idx" );
    dumpUnused( (getBiff() == BIFF8) ? 2 : 12 );
    mxStack->pushOperand( lclCreateName( aRef, nNameIdx ), rTokClass );
}

void FormulaObject::dumpRefToken( const OUString& rTokClass, bool bNameMode )
{
    TokenAddress aPos = dumpTokenAddress( bNameMode );
    writeTokenAddressItem( "addr", aPos, bNameMode );
    mxStack->pushOperand( createRef( mxOut->getLastItemValue() ), rTokClass );
}

void FormulaObject::dumpAreaToken( const OUString& rTokClass, bool bNameMode )
{
    TokenRange aRange = dumpTokenRange( bNameMode );
    writeTokenRangeItem( "range", aRange, bNameMode );
    mxStack->pushOperand( createRef( mxOut->getLastItemValue() ), rTokClass );
}

void FormulaObject::dumpRefErrToken( const OUString& rTokClass, bool bArea )
{
    dumpUnused( ((getBiff() == BIFF8) ? 4 : 3) * (bArea ? 2 : 1) );
    mxStack->pushOperand( createRef( getErrorName( BIFF_ERR_REF ) ), rTokClass );
}

void FormulaObject::dumpRef3dToken( const OUString& rTokClass, bool bNameMode )
{
    OUString aRef = dumpTokenRefTabIdxs();
    TokenAddress aPos = dumpTokenAddress( bNameMode );
    writeTokenAddress3dItem( "addr", aRef, aPos, bNameMode );
    mxStack->pushOperand( mxOut->getLastItemValue(), rTokClass );
}

void FormulaObject::dumpArea3dToken( const OUString& rTokClass, bool bNameMode )
{
    OUString aRef = dumpTokenRefTabIdxs();
    TokenRange aRange = dumpTokenRange( bNameMode );
    writeTokenRange3dItem( "range", aRef, aRange, bNameMode );
    mxStack->pushOperand( mxOut->getLastItemValue(), rTokClass );
}

void FormulaObject::dumpRefErr3dToken( const OUString& rTokClass, bool bArea )
{
    OUString aRef = dumpTokenRefTabIdxs();
    dumpUnused( ((getBiff() == BIFF8) ? 4 : 3) * (bArea ? 2 : 1) );
    mxStack->pushOperand( aRef + getErrorName( BIFF_ERR_REF ), rTokClass );
}

void FormulaObject::dumpMemFuncToken( const OUString& /*rTokClass*/ )
{
    dumpDec< sal_uInt16, sal_uInt8 >( getBiff() != BIFF2, "size" );
}

void FormulaObject::dumpMemAreaToken( const OUString& rTokClass, bool bAddData )
{
    dumpUnused( (getBiff() == BIFF2) ? 3 : 4 );
    dumpMemFuncToken( rTokClass );
    if( bAddData )
        maAddData.push_back( ADDDATA_MEMAREA );
}

void FormulaObject::dumpExpToken( const String& rName )
{
    Address aPos;
    aPos.mnRow = dumpDec< sal_uInt16 >( "row" );
    aPos.mnCol = dumpDec< sal_uInt16, sal_uInt8 >( getBiff() != BIFF2, "col" );
    writeAddressItem( "base-addr", aPos );
    OUStringBuffer aOp( rName );
    StringHelper::appendIndex( aOp, mxOut->getLastItemValue() );
    mxStack->pushOperand( aOp.makeStringAndClear() );
}

void FormulaObject::dumpUnaryOpToken( const String& rLOp, const String& rROp )
{
    mxStack->pushUnaryOp( rLOp, rROp );
}

void FormulaObject::dumpBinaryOpToken( const String& rOp )
{
    mxStack->pushBinaryOp( rOp );
}

void FormulaObject::dumpFuncToken( const OUString& rTokClass )
{
    sal_uInt16 nFuncId = readFuncId();
    const FunctionInfo* pFuncInfo = 0;
    OUString aFuncName = writeFuncIdItem( nFuncId, &pFuncInfo );
    if( pFuncInfo && (pFuncInfo->mnMinParamCount == pFuncInfo->mnMaxParamCount) )
        mxStack->pushFuncOp( aFuncName, rTokClass, pFuncInfo->mnMinParamCount );
    else
        mxStack->setError();
}

void FormulaObject::dumpFuncVarToken( const OUString& rTokClass )
{
    sal_uInt8 nParamCount;
    *mxStrm >> nParamCount;
    sal_uInt16 nFuncId = readFuncId();
    bool bCmd = getFlag( nFuncId, BIFF_TOK_FUNCVAR_CMD );
    if( bCmd )
        writeHexItem( "param-count", nParamCount, "PARAMCOUNT-CMD" );
    else
        writeDecItem( "param-count", nParamCount );
    OUString aFuncName = writeFuncIdItem( nFuncId );
    if( bCmd && getFlag( nParamCount, BIFF_TOK_FUNCVAR_CMDPROMPT ) )
    {
        aFuncName += OUString( OOX_DUMP_CMDPROMPT );
        nParamCount &= BIFF_TOK_FUNCVAR_COUNTMASK;
    }
    mxStack->pushFuncOp( aFuncName, rTokClass, nParamCount );
}

void FormulaObject::dumpCmdToken( const OUString& rTokClass )
{
    sal_uInt8 nParamCount = dumpDec< sal_uInt8 >( "param-count", "PARAMCOUNT-CMD" );
    sal_uInt16 nCmdId = readFuncId() | BIFF_TOK_FUNCVAR_CMD;
    OUString aFuncName = writeFuncIdItem( nCmdId );
    if( getFlag( nParamCount, BIFF_TOK_FUNCVAR_CMDPROMPT ) )
    {
        aFuncName += OUString( OOX_DUMP_CMDPROMPT );
        nParamCount &= BIFF_TOK_FUNCVAR_COUNTMASK;
    }
    mxStack->pushFuncOp( aFuncName, rTokClass, nParamCount );
}

void FormulaObject::dumpSheetToken()
{
    dumpUnused( (getBiff() == BIFF2) ? 4 : 6 );
    maRefPrefix = dumpTokenRefIdx();
}

void FormulaObject::dumpEndSheetToken()
{
    dumpUnused( (getBiff() == BIFF2) ? 3 : 4 );
    maRefPrefix = OUString();
}

bool FormulaObject::dumpAttrToken()
{
    bool bValid = true;
    bool bBiff2 = getBiff() == BIFF2;
    sal_uInt8 nType = dumpHex< sal_uInt8 >( "type", mxAttrTypes );
    switch( nType )
    {
        case BIFF_TOK_ATTR_VOLATILE:
            dumpUnused( bBiff2 ? 1 : 2 );
        break;
        case BIFF_TOK_ATTR_IF:
            dumpDec< sal_uInt16, sal_uInt8 >( !bBiff2, "skip" );
        break;
        case BIFF_TOK_ATTR_CHOOSE:
        {
            sal_uInt16 nCount = dumpDec< sal_uInt16, sal_uInt8 >( !bBiff2, "choices" );
            mxOut->resetItemIndex();
            for( sal_uInt16 nIdx = 0; nIdx < nCount; ++nIdx )
                dumpDec< sal_uInt16, sal_uInt8 >( !bBiff2, "#skip" );
            dumpDec< sal_uInt16, sal_uInt8 >( !bBiff2, "skip-err" );
        }
        break;
        case 0:     // in array formulas and defined names, the skip-bit may be 0
        case BIFF_TOK_ATTR_SKIP:
            dumpDec< sal_uInt16, sal_uInt8 >( !bBiff2, "skip" );
        break;
        case BIFF_TOK_ATTR_SUM:
            dumpUnused( bBiff2 ? 1 : 2 );
            mxStack->pushFuncOp( CREATE_OUSTRING( "SUM" ), OUString( OOX_DUMP_BASECLASS ), 1 );
        break;
        case BIFF_TOK_ATTR_ASSIGN:
            dumpUnused( bBiff2 ? 1 : 2 );
        break;
        case BIFF_TOK_ATTR_SPACE:
        case BIFF_TOK_ATTR_SPACE | BIFF_TOK_ATTR_VOLATILE:
            switch( getBiff() )
            {
                case BIFF2:
                    bValid = false;
                break;
                case BIFF3:
                    dumpDec< sal_uInt16 >( "leading-spaces" );
                break;
                case BIFF4:
                case BIFF5:
                case BIFF8:
                    dumpDec< sal_uInt8 >( "char-type", mxSpTypes );
                    dumpDec< sal_uInt8 >( "char-count" );
                break;
                case BIFF_UNKNOWN: break;
            }
        break;
        default:
            bValid = false;
    }
    return bValid;
}

bool FormulaObject::dumpNlrToken()
{
    const OUString aRefClass = cfg().getName( mxClasses, BIFF_TOKCLASS_REF );
    const OUString aValClass = cfg().getName( mxClasses, BIFF_TOKCLASS_VAL );

    bool bValid = true;
    sal_uInt8 nType = dumpHex< sal_uInt8 >( "type", mxNlrTypes );
    switch( nType )
    {
        case BIFF_TOK_NLR_ERR:      dumpNlrErrToken();                      break;
        case BIFF_TOK_NLR_ROWR:     dumpNlrColRowToken( aRefClass, false ); break;
        case BIFF_TOK_NLR_COLR:     dumpNlrColRowToken( aRefClass, false ); break;
        case BIFF_TOK_NLR_ROWV:     dumpNlrColRowToken( aValClass, false ); break;
        case BIFF_TOK_NLR_COLV:     dumpNlrColRowToken( aValClass, false ); break;
        case BIFF_TOK_NLR_RANGE:    dumpNlrRangeToken( aRefClass, false );  break;
        case BIFF_TOK_NLR_SRANGE:   dumpNlrRangeToken( aRefClass, true );   break;
        case BIFF_TOK_NLR_SROWR:    dumpNlrColRowToken( aRefClass, true );  break;
        case BIFF_TOK_NLR_SCOLR:    dumpNlrColRowToken( aRefClass, true );  break;
        case BIFF_TOK_NLR_SROWV:    dumpNlrColRowToken( aValClass, true );  break;
        case BIFF_TOK_NLR_SCOLV:    dumpNlrColRowToken( aValClass, true );  break;
        case BIFF_TOK_NLR_RANGEERR: dumpNlrRangeErrToken();                 break;
        default:                    bValid = false;
    }
    return bValid;
}

void FormulaObject::dumpNlrErrToken()
{
    dumpDec< sal_uInt32 >( "delname-idx" );
    mxStack->pushOperand( lclCreateNlr( getErrorName( BIFF_ERR_NAME ) ) );
}

void FormulaObject::dumpNlrColRowToken( const OUString& rTokClass, bool bAddData )
{
    if( bAddData )
    {
        dumpUnused( 4 );
        mxStack->pushOperand( createPlaceHolder(), rTokClass );
        maAddData.push_back( ADDDATA_NLR );
    }
    else
    {
        TokenAddress aPos = dumpTokenAddress( false );
        writeInfoItem( "addr", lclCreateNlr( aPos ) );
        mxStack->pushOperand( mxOut->getLastItemValue(), rTokClass );
    }
}

void FormulaObject::dumpNlrRangeToken( const OUString& rTokClass, bool bAddData )
{
    if( bAddData )
    {
        dumpUnused( 4 );
        mxStack->pushOperand( createPlaceHolder(), rTokClass );
        maAddData.push_back( ADDDATA_NLR );
    }
    else
    {
        TokenAddress aPos = dumpTokenAddress( false );
        writeInfoItem( "addr", lclCreateNlr( aPos ) );
        mxStack->pushOperand( mxOut->getLastItemValue(), rTokClass );
    }
    dumpUnknown( 1 );
    dumpRange( "target-range" );
}

void FormulaObject::dumpNlrRangeErrToken()
{
    dumpDec< sal_uInt32 >( "delname-idx" );
    dumpUnused( 9 );
    mxStack->pushOperand( lclCreateNlr( getErrorName( BIFF_ERR_NAME ) ) );
}

void FormulaObject::dumpAddTokenData()
{
    mxOut->resetItemIndex();
    for( AddDataTypeVec::const_iterator aIt = maAddData.begin(), aEnd = maAddData.end(); aIt != aEnd; ++aIt )
    {
        AddDataType eType = *aIt;

        {
            ItemGuard aItem( mxOut, "#add-data" );
            switch( eType )
            {
                case ADDDATA_NLR:       mxOut->writeAscii( "tNlr" );      break;
                case ADDDATA_ARRAY:     mxOut->writeAscii( "tArray" );    break;
                case ADDDATA_MEMAREA:   mxOut->writeAscii( "tMemArea" );  break;
            }
        }

        size_t nIdx = aIt - maAddData.begin();
        IndentGuard aIndGuard( mxOut );
        switch( eType )
        {
            case ADDDATA_NLR:       dumpAddDataNlr( nIdx );     break;
            case ADDDATA_ARRAY:     dumpAddDataArray( nIdx );   break;
            case ADDDATA_MEMAREA:   dumpAddDataMemArea( nIdx ); break;
        }
    }
}

void FormulaObject::dumpAddDataNlr( size_t nIdx )
{
    sal_uInt32 nFlags = dumpHex< sal_uInt32 >( "flags", "NLRADDFLAGS" );
    sal_uInt32 nCount = nFlags & BIFF_TOK_NLR_ADDMASK;
    OUStringBuffer aBuffer;
    for( sal_uInt32 nPos = 0; nPos < nCount; ++nPos )
    {
        Address aPos;
        readAddress( aPos );
        OUStringBuffer aAddr;
        StringHelper::appendAddress( aAddr, aPos );
        StringHelper::appendToken( aBuffer, aAddr.makeStringAndClear(), OOX_DUMP_LISTSEP );
    }
    OUString aAddrList = aBuffer.makeStringAndClear();
    writeInfoItem( "stacked-positions", aAddrList );
    mxStack->replaceOnTop( createPlaceHolder( nIdx ), lclCreateNlr( aAddrList ) );
}

void FormulaObject::dumpAddDataArray( size_t nIdx )
{
    sal_uInt32 nCols, nRows;
    dumpConstArrayHeader( nCols, nRows );

    OUStringBuffer aOp;
    TableGuard aTabGuard( mxOut, 17 );
    for( sal_uInt32 nRow = 0; nRow < nRows; ++nRow )
    {
        OUStringBuffer aArrayLine;
        for( sal_uInt32 nCol = 0; nCol < nCols; ++nCol )
            StringHelper::appendToken( aArrayLine, dumpConstValue( OOX_DUMP_FMLASTRQUOTE ), OOX_DUMP_LISTSEP );
        StringHelper::appendToken( aOp, aArrayLine.makeStringAndClear(), OOX_DUMP_ARRAYSEP );
    }
    StringHelper::enclose( aOp, '{', '}' );
    mxStack->replaceOnTop( createPlaceHolder( nIdx ), aOp.makeStringAndClear() );
}

void FormulaObject::dumpAddDataMemArea( size_t /*nIdx*/ )
{
    dumpRangeList( EMPTY_STRING, getBiff() == BIFF8 );
}

// ============================================================================
// ============================================================================

RecordStreamObject::~RecordStreamObject()
{
}

void RecordStreamObject::construct( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, BiffType eBiff, const OUString& rSysFileName )
{
    BiffObjectBase::construct( rParent, rxStrm, eBiff, rSysFileName );
    if( BiffObjectBase::implIsValid() )
        mxFmlaObj.reset( new FormulaObject( *this ) );
}

bool RecordStreamObject::implIsValid() const
{
    return isValid( mxFmlaObj ) && BiffObjectBase::implIsValid();
}

// ============================================================================

WorkbookStreamObject::WorkbookStreamObject( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName )
{
    if( rxStrm.get() )
    {
        BiffType eBiff = BiffDetector::detectStreamBiffVersion( *rxStrm );
        RecordStreamObject::construct( rParent, rxStrm, eBiff, rSysFileName );
        if( RecordStreamObject::implIsValid() )
        {
            Config& rCfg = cfg();
            mxColors = rCfg.getNameList( "COLORS" );
            mxBorderStyles = rCfg.getNameList( "BORDERSTYLES" );
            mxFillPatterns = rCfg.getNameList( "FILLPATTERNS" );
            mnPTRowFields = 0;
            mnPTColFields = 0;
            mnPTRowColItemsIdx = 0;
            mbHasDff = false;
            initializePerSheet();
        }
    }
}

WorkbookStreamObject::~WorkbookStreamObject()
{
    if( WorkbookStreamObject::implIsValid() )
    {
        Config& rCfg = cfg();
        rCfg.eraseNameList( "FONTNAMES" );
        rCfg.eraseNameList( "FORMATS" );
    }
}

void WorkbookStreamObject::implDumpRecordBody()
{
    BiffInputStream& rStrm = getBiffStream();
    sal_uInt16 nRecId = rStrm.getRecId();
    sal_Int64 nRecSize = rStrm.size();
    BiffType eBiff = getBiff();

    switch( nRecId )
    {
        case BIFF2_ID_ARRAY:
        case BIFF3_ID_ARRAY:
            dumpRange( "array-range", false );
            dumpHex< sal_uInt16, sal_uInt8 >( eBiff != BIFF2, "flags", "ARRAY-FLAGS" );
            if( eBiff >= BIFF5 ) dumpUnused( 4 );
            getFormulaDumper().dumpCellFormula();
        break;

        case BIFF2_ID_BLANK:
        case BIFF3_ID_BLANK:
            dumpCellHeader( nRecId == BIFF2_ID_BLANK );
        break;

        case BIFF2_ID_BOF:
        case BIFF3_ID_BOF:
        case BIFF4_ID_BOF:
        case BIFF5_ID_BOF:
            dumpHex< sal_uInt16 >( "bof-type", "BOF-BIFFTYPE" );
            dumpHex< sal_uInt16 >( "sheet-type", "BOF-SHEETTYPE" );
            if( nRecSize >= 6 )  dumpDec< sal_uInt16 >( "build-id" );
            if( nRecSize >= 8 )  dumpDec< sal_uInt16 >( "build-year" );
            if( nRecSize >= 12 ) dumpHex< sal_uInt32 >( "history-flags", "BOF-HISTORY-FLAGS" );
            if( nRecSize >= 16 ) dumpHex< sal_uInt32 >( "lowest-version", "BOF-LOWESTVERSION-FLAGS" );
            if( (eBiff == BIFF4) && (getLastRecId() != BIFF_ID_OBJ) )
                initializePerSheet();
        break;

        case BIFF_ID_BOOKEXT:
            dumpFrHeader( true, true );
            dumpDec< sal_uInt32 >( "rec-size" );
            dumpHex< sal_uInt32 >( "flags-1", "BOOKEXT-FLAGS1" );
            if( rStrm.getRemaining() > 0 ) dumpHex< sal_uInt8 >( "flags-2", "BOOKEXT-FLAGS2" );
            if( rStrm.getRemaining() > 0 ) dumpHex< sal_uInt8 >( "flags-3", "BOOKEXT-FLAGS3" );
        break;

        case BIFF2_ID_BOOLERR:
        case BIFF3_ID_BOOLERR:
            dumpCellHeader( nRecId == BIFF2_ID_BOOLERR );
            dumpBoolErr();
        break;

        case BIFF_ID_CFHEADER:
            dumpDec< sal_uInt16 >( "rule-count" );
            dumpHex< sal_uInt16 >( "flags", "CFHEADER-FLAGS" );
            dumpRange( "bounding-range" );
            dumpRangeList();
        break;

        case BIFF_ID_CFRULE:
        {
            dumpDec< sal_uInt8 >( "type", "CFRULE-TYPE" );
            dumpDec< sal_uInt8 >( "operator", "CFRULE-OPERATOR" );
            sal_uInt16 nFmla1Size = dumpDec< sal_uInt16 >( "formula1-size" );
            sal_uInt16 nFmla2Size = dumpDec< sal_uInt16 >( "formula2-size" );
            dumpCfRuleProp();
            if( nFmla1Size > 0 ) getFormulaDumper().dumpNameFormula( "formula1", nFmla1Size );
            if( nFmla2Size > 0 ) getFormulaDumper().dumpNameFormula( "formula2", nFmla2Size );
        }
        break;

        case BIFF_ID_CFRULE12:
        {
            dumpFrHeader( true, true );
            dumpDec< sal_uInt8 >( "type", "CFRULE12-TYPE" );
            dumpDec< sal_uInt8 >( "operator", "CFRULE-OPERATOR" );
            sal_uInt16 nFmla1Size = dumpDec< sal_uInt16 >( "formula1-size" );
            sal_uInt16 nFmla2Size = dumpDec< sal_uInt16 >( "formula2-size" );
            dumpDxf12Prop();
            if( nFmla1Size > 0 ) getFormulaDumper().dumpNameFormula( "formula1", nFmla1Size );
            if( nFmla2Size > 0 ) getFormulaDumper().dumpNameFormula( "formula2", nFmla2Size );
            getFormulaDumper().dumpNameFormula( "active-formula" );
            dumpHex< sal_uInt8 >( "flags", "CFRULE12-FLAGS" );
            dumpDec< sal_uInt16 >( "priority" );
            dumpCfRule12Param( dumpDec< sal_uInt16 >( "sub-type", "CFRULE12-SUBTYPE" ) );
        }
        break;

        case BIFF_ID_CFRULEEXT:
            dumpFrHeader( true, true );
            dumpBool< sal_uInt32 >( "cfrule12-follows" );
            dumpDec< sal_uInt16 >( "cfheader-id" );
            if( rStrm.getRemaining() >= 25 )
            {
                dumpDec< sal_uInt16 >( "cfrule-idx" );
                dumpDec< sal_uInt8 >( "operator", "CFRULE-OPERATOR" );
                sal_uInt8 nSubType = dumpDec< sal_uInt8 >( "sub-type", "CFRULE12-SUBTYPE" );
                dumpDec< sal_uInt16 >( "priority" );
                dumpHex< sal_uInt8 >( "flags", "CFRULEEXT-FLAGS" );
                if( dumpBoolean( "has-dxf-data" ) ) dumpDxf12Prop();
                dumpCfRule12Param( nSubType );
            }
        break;

        case BIFF_ID_CH3DDATAFORMAT:
            dumpDec< sal_uInt8 >( "base", "CH3DDATAFORMAT-BASE" );
            dumpDec< sal_uInt8 >( "top", "CH3DDATAFORMAT-TOP" );
        break;

        case BIFF_ID_CHAREAFORMAT:
            dumpColorABGR( "fg-color" );
            dumpColorABGR( "bg-color" );
            dumpPatternIdx();
            dumpHex< sal_uInt16 >( "flags", "CHAREAFORMAT-FLAGS" );
            if( eBiff == BIFF8 ) dumpColorIdx( "fg-color-idx" );
            if( eBiff == BIFF8 ) dumpColorIdx( "bg-color-idx" );
        break;

        case BIFF_ID_CHAXESSET:
            dumpDec< sal_uInt16 >( "axesset-id", "CHAXESSET-ID" );
            dumpRect< sal_Int32 >( "inner-plotarea-pos", (eBiff <= BIFF4) ? "CONV-TWIP-TO-CM" : "" );
        break;

        case BIFF_ID_CHAXIS:
            dumpDec< sal_uInt16 >( "axis-type", "CHAXIS-TYPE" );
            if( eBiff <= BIFF4 )
                dumpRect< sal_Int32 >( "position", "CONV-TWIP-TO-CM" );
            else
                dumpUnused( 16 );
        break;

        case BIFF_ID_CHBAR:
            dumpDec< sal_Int16 >( "overlap", "CONV-PERCENT-NEG" );
            dumpDec< sal_Int16 >( "gap", "CONV-PERCENT" );
            dumpHex< sal_uInt16 >( "flags", "CHBAR-FLAGS" );
        break;

        case BIFF_ID_CHCHART:
            dumpRect< sal_Int32 >( "chart-frame", "CONV-PT1616-TO-CM", FORMATTYPE_FIX );
        break;

        case BIFF_ID_CHCHART3D:
            dumpDec< sal_uInt16 >( "rotation-angle", "CONV-DEG" );
            dumpDec< sal_Int16 >( "elevation-angle", "CONV-DEG" );
            dumpDec< sal_uInt16 >( "eye-distance" );
            dumpDec< sal_uInt16 >( "relative-height", "CONV-PERCENT" );
            dumpDec< sal_uInt16 >( "relative-depth", "CONV-PERCENT" );
            dumpDec< sal_uInt16 >( "depth-gap", "CONV-PERCENT" );
            dumpHex< sal_uInt16 >( "flags", "CHCHART3D-FLAGS" );
        break;

        case BIFF_ID_CHDATAFORMAT:
            dumpDec< sal_Int16 >( "point-idx", "CHDATAFORMAT-POINTIDX" );
            dumpDec< sal_Int16 >( "series-idx" );
            if( eBiff >= BIFF5 ) dumpDec< sal_Int16 >( "format-idx", "CHDATAFORMAT-FORMATIDX" );
            if( eBiff >= BIFF5 ) dumpHex< sal_uInt16 >( "flags", "CHDATAFORMAT-FLAGS" );
        break;

        case BIFF_ID_CHDATERANGE:
            dumpDec< sal_uInt16 >( "minimum-date" );
            dumpDec< sal_uInt16 >( "maximum-date" );
            dumpDec< sal_uInt16 >( "major-unit-value" );
            dumpDec< sal_uInt16 >( "major-unit", "CHDATERANGE-UNIT" );
            dumpDec< sal_uInt16 >( "minor-unit-value" );
            dumpDec< sal_uInt16 >( "minor-unit", "CHDATERANGE-UNIT" );
            dumpDec< sal_uInt16 >( "base-unit", "CHDATERANGE-UNIT" );
            dumpDec< sal_uInt16 >( "axis-crossing-date" );
            dumpHex< sal_uInt16 >( "flags", "CHDATERANGE-FLAGS" );
        break;

        case BIFF_ID_CHECKCOMPAT:
            dumpFrHeader( true, true );
            dumpBool< sal_uInt32 >( "check-compatibility" );
        break;

        case BIFF_ID_CHESCHERFORMAT:
            dumpEmbeddedDff();
        break;

        case BIFF_ID_CHFRAME:
            dumpDec< sal_uInt16 >( "format", "CHFRAME-FORMAT" );
            dumpHex< sal_uInt16 >( "flags", "CHFRAME-FLAGS" );
        break;

        case BIFF_ID_CHFRAMEPOS:
            dumpDec< sal_uInt16 >( "tl-mode", "CHFRAMEPOS-POSMODE" );
            dumpDec< sal_uInt16 >( "br-mode", "CHFRAMEPOS-POSMODE" );
            dumpRectWithGaps< sal_Int16 >( "position", 2 );
        break;

        case BIFF_ID_CHFRBLOCKBEGIN:
            dumpFrHeader( true, false );
            dumpDec< sal_uInt16 >( "type", "CHFRBLOCK-TYPE" );
            dumpDec< sal_uInt16 >( "context" );
            dumpDec< sal_uInt16 >( "value-1" );
            dumpDec< sal_uInt16 >( "value-2" );
        break;

        case BIFF_ID_CHFRBLOCKEND:
            dumpFrHeader( true, false );
            dumpDec< sal_uInt16 >( "type", "CHFRBLOCK-TYPE" );
            if( rStrm.getRemaining() >= 6 )
                dumpUnused( 6 );
        break;

        case BIFF_ID_CHFRCATEGORYPROPS:
            dumpFrHeader( true, false );
            dumpDec< sal_uInt16 >( "label-offset", "CONV-PERCENT" );
            dumpDec< sal_uInt16 >( "alignment", "CHFRCATEGORYPROPS-ALIGN" );
            dumpHex< sal_uInt16 >( "flags", "CHFRCATEGORYPROPS-FLAGS" );
        break;

        case BIFF_ID_CHFREXTPROPS:
        {
            dumpFrHeader( true, true );
            dumpDec< sal_uInt32 >( "data-size" );
            dumpDec< sal_uInt8 >( "version" );
            dumpUnused( 1 );
            dumpDec< sal_uInt16 >( "parent", "CHFREXTPROPS-PARENT" );
            dumpChFrExtProps();
            dumpUnused( 4 );
        }
        break;

        case BIFF_ID_CHFRINFO:
        {
            dumpFrHeader( true, false );
            dumpDec< sal_uInt8 >( "creator", "CHFRINFO-APPVERSION" );
            dumpDec< sal_uInt8 >( "writer", "CHFRINFO-APPVERSION" );
            sal_uInt16 nCount = dumpDec< sal_uInt16 >( "rec-range-count" );
            mxOut->resetItemIndex();
            for( sal_uInt16 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
                dumpHexPair< sal_uInt16 >( "#rec-range", '-' );
        }
        break;

        case BIFF_ID_CHFRLABELPROPS:
            dumpFrHeader( true, true );
            dumpHex< sal_uInt16 >( "flags", "CHFRLABELPROPS-FLAGS" );
            dumpUniString( "separator", BIFF_STR_SMARTFLAGS );
        break;

        case BIFF_ID_CHFRLAYOUT:
            dumpFrHeader( true, true );
            dumpHex< sal_uInt32 >( "checksum" );
            dumpHex< sal_uInt16 >( "flags", "CHFRLAYOUT-FLAGS" );
            dumpDec< sal_uInt16 >( "mode-x", "CHFRLAYOUT-MODE" );
            dumpDec< sal_uInt16 >( "mode-y", "CHFRLAYOUT-MODE" );
            dumpDec< sal_uInt16 >( "mode-w", "CHFRLAYOUT-MODE" );
            dumpDec< sal_uInt16 >( "mode-h", "CHFRLAYOUT-MODE" );
            dumpRect< double >( "position" );
            dumpUnused( 2 );
        break;

        case BIFF_ID_CHFRPLOTAREALAYOUT:
            dumpFrHeader( true, true );
            dumpHex< sal_uInt32 >( "checksum" );
            dumpHex< sal_uInt16 >( "flags", "CHFRPLOTAREALAYOUT-FLAGS" );
            dumpRect< sal_Int16 >( "position" );
            dumpDec< sal_uInt16 >( "mode-x", "CHFRLAYOUT-MODE" );
            dumpDec< sal_uInt16 >( "mode-y", "CHFRLAYOUT-MODE" );
            dumpDec< sal_uInt16 >( "mode-w", "CHFRLAYOUT-MODE" );
            dumpDec< sal_uInt16 >( "mode-h", "CHFRLAYOUT-MODE" );
            dumpRect< double >( "position" );
            dumpUnused( 2 );
        break;

        case BIFF_ID_CHFRSHAPEPROPS:
            dumpFrHeader( true, true );
            dumpDec< sal_uInt16 >( "context" );
            dumpUnused( 2 );
            dumpHex< sal_uInt32 >( "checksum" );
            dumpDec< sal_uInt32 >( "xml-size" );
        break;

        case BIFF_ID_CHFRTEXTPROPS:
            dumpFrHeader( true, true );
            dumpHex< sal_uInt32 >( "checksum" );
            dumpDec< sal_uInt32 >( "xml-size" );
        break;

        case BIFF_ID_CHFRUNITPROPS:
            dumpFrHeader( true, false );
            dumpDec< sal_Int16 >( "preset", "CHFRUNITPROPS-PRESET" );
            dumpDec< double >( "unit" );
            dumpHex< sal_uInt16 >( "flags", "CHFRUNITPROPS-FLAGS" );
        break;

        case BIFF_ID_CHFRWRAPPER:
            dumpFrHeader( true, false );
        break;

        case BIFF_ID_CHLABELRANGE:
            dumpDec< sal_uInt16 >( "axis-crossing" );
            dumpDec< sal_uInt16 >( "label-frequency" );
            dumpDec< sal_uInt16 >( "tick-frequency" );
            dumpHex< sal_uInt16 >( "flags", "CHLABELRANGE-FLAGS" );
        break;

        case BIFF_ID_CHLEGEND:
            dumpRect< sal_Int32 >( "position", (eBiff <= BIFF4) ? "CONV-TWIP-TO-CM" : "" );
            dumpDec< sal_uInt8 >( "docked-pos", "CHLEGEND-DOCKPOS" );
            dumpDec< sal_uInt8 >( "spacing", "CHLEGEND-SPACING" );
            dumpHex< sal_uInt16 >( "flags", "CHLEGEND-FLAGS" );
        break;

        case BIFF_ID_CHLINEFORMAT:
            dumpColorABGR();
            dumpDec< sal_uInt16 >( "line-type", "CHLINEFORMAT-LINETYPE" );
            dumpDec< sal_Int16 >( "line-weight", "CHLINEFORMAT-LINEWEIGHT" );
            dumpHex< sal_uInt16 >( "flags", "CHLINEFORMAT-FLAGS" );
            if( eBiff == BIFF8 ) dumpColorIdx();
        break;

        case BIFF_ID_CHMARKERFORMAT:
            dumpColorABGR( "border-color" );
            dumpColorABGR( "fill-color" );
            dumpDec< sal_uInt16 >( "marker-type", "CHMARKERFORMAT-TYPE" );
            dumpHex< sal_uInt16 >( "flags", "CHMARKERFORMAT-FLAGS" );
            if( eBiff == BIFF8 ) dumpColorIdx( "border-color-idx" );
            if( eBiff == BIFF8 ) dumpColorIdx( "fill-color-idx" );
            if( eBiff == BIFF8 ) dumpDec< sal_Int32 >( "marker-size", "CONV-TWIP-TO-PT" );
        break;

        case BIFF_ID_CHOBJECTLINK:
            dumpDec< sal_uInt16 >( "link-target", "CHOBJECTLINK-TARGET" );
            dumpDec< sal_Int16 >( "series-idx" );
            dumpDec< sal_Int16 >( "point-idx", "CHOBJECTLINK-POINT" );
        break;

        case BIFF_ID_CHPICFORMAT:
            dumpDec< sal_uInt16 >( "bitmap-mode", "CHPICFORMAT-BITMAP-MODE" );
            dumpUnused( 2 );
            dumpHex< sal_uInt16 >( "flags", "CHPICFORMAT-FLAGS" );
            dumpDec< double >( "scaling-factor" );
        break;

        case BIFF_ID_CHPIE:
            dumpDec< sal_uInt16 >( "angle", "CONV-DEG" );
            if( eBiff >= BIFF5 ) dumpDec< sal_uInt16 >( "hole-size" );
            if( eBiff >= BIFF8 ) dumpHex< sal_uInt16 >( "flags", "CHPIE-FLAGS" );
        break;

        case BIFF_ID_CHPIVOTFLAGS:
            dumpRepeatedRecId();
            dumpUnused( 2 );
            dumpHex< sal_uInt16 >( "flags", "CHPIVOTFLAGS-FLAGS" );
        break;

        case BIFF8_ID_CHPIVOTREF:
            dumpRepeatedRecId();
            dumpUnused( 4 );
            dumpUniString( "ref", BIFF_STR_8BITLENGTH );
        break;

        case BIFF_ID_CHPLOTGROWTH:
            dumpFix< sal_Int32 >( "horizontal-growth" );
            dumpFix< sal_Int32 >( "vertical-growth" );
        break;

        case BIFF_ID_CHPROPERTIES:
            dumpHex< sal_uInt16 >( "flags", "CHPROPERTIES-FLAGS" );
            dumpDec< sal_uInt8 >( "empty-cells", "CHPROPERTIES-EMPTYCELLS" );
        break;

        case BIFF_ID_CHSCATTER:
            if( eBiff == BIFF8 ) dumpDec< sal_uInt16 >( "bubble-size", "CONV-PERCENT" );
            if( eBiff == BIFF8 ) dumpDec< sal_uInt16 >( "size-type", "CHSCATTER-SIZETYPE" );
            if( eBiff == BIFF8 ) dumpHex< sal_uInt16 >( "flags", "CHSCATTER-FLAGS" );
        break;

        case BIFF_ID_CHSERERRORBAR:
            dumpDec< sal_uInt8 >( "type", "CHSERERRORBAR-TYPE" );
            dumpDec< sal_uInt8 >( "source", "CHSERERRORBAR-SOURCE" );
            dumpBool< sal_uInt8 >( "draw-t-shape" );
            dumpBool< sal_uInt8 >( "draw-line" );
            dumpDec< double >( "value" );
            dumpDec< sal_uInt16 >( "custom-count" );
        break;

        case BIFF_ID_CHSERIES:
            dumpDec< sal_uInt16 >( "categories-type", "CHSERIES-TYPE" );
            dumpDec< sal_uInt16 >( "values-type", "CHSERIES-TYPE" );
            dumpDec< sal_uInt16 >( "categories-count" );
            dumpDec< sal_uInt16 >( "values-count" );
            if( eBiff == BIFF8 ) dumpDec< sal_uInt16 >( "bubbles-type", "CHSERIES-TYPE" );
            if( eBiff == BIFF8 ) dumpDec< sal_uInt16 >( "bubbles-count" );
        break;

        case BIFF_ID_CHSERTRENDLINE:
            switch( dumpDec< sal_uInt8 >( "type", "CHSERTRENDLINE-TYPE" ) )
            {
                case 0:     dumpDec< sal_uInt8 >( "order" );            break;
                case 4:     dumpDec< sal_uInt8 >( "average-period" );   break;
                default:    dumpUnused( 1 );
            }
            dumpDec< double >( "intercept" );
            dumpBool< sal_uInt8 >( "show-equation" );
            dumpBool< sal_uInt8 >( "show-r-sqrare" );
            dumpDec< double >( "forecast-forward" );
            dumpDec< double >( "forecast-backward" );
        break;

        case BIFF_ID_CHSOURCELINK:
            dumpDec< sal_uInt8 >( "link-target", "CHSOURCELINK-TARGET" );
            dumpDec< sal_uInt8 >( "link-type", "CHSOURCELINK-TYPE" );
            dumpHex< sal_uInt16 >( "flags", "CHSOURCELINK-FLAGS" );
            dumpFormatIdx();
            getFormulaDumper().dumpNameFormula();
        break;

        case BIFF_ID_CHSTRING:
            dumpDec< sal_uInt16 >( "text-type", "CHSTRING-TYPE" );
            dumpString( "text", BIFF_STR_8BITLENGTH, BIFF_STR_8BITLENGTH );
        break;

        case BIFF_ID_CHTEXT:
            dumpDec< sal_uInt8 >( "horizontal-align", "CHTEXT-HORALIGN" );
            dumpDec< sal_uInt8 >( "vertical-align", "CHTEXT-VERALIGN" );
            dumpDec< sal_uInt16 >( "fill-mode", "CHTEXT-FILLMODE" );
            dumpColorABGR();
            dumpRect< sal_Int32 >( "position", (eBiff <= BIFF4) ? "CONV-TWIP-TO-CM" : "" );
            dumpHex< sal_uInt16 >( "flags-1", "CHTEXT-FLAGS1" );
            if( eBiff == BIFF8 ) dumpColorIdx();
            if( eBiff == BIFF8 ) dumpHex< sal_uInt16 >( "flags-2", "CHTEXT-FLAGS2" );
            if( eBiff == BIFF8 ) dumpDec< sal_uInt16 >( "rotation", "TEXTROTATION" );
        break;

        case BIFF_ID_CHTICK:
            dumpDec< sal_uInt8 >( "major-ticks", "CHTICK-TYPE" );
            dumpDec< sal_uInt8 >( "minor-ticks", "CHTICK-TYPE" );
            dumpDec< sal_uInt8 >( "label-position", "CHTICK-LABELPOS" );
            dumpDec< sal_uInt8 >( "fill-mode", "CHTEXT-FILLMODE" );
            dumpColorABGR( "label-color" );
            dumpUnused( 16 );
            dumpHex< sal_uInt16 >( "flags", "CHTICK-FLAGS" );
            if( eBiff == BIFF8 ) dumpColorIdx( "label-color-idx" );
            if( eBiff == BIFF8 ) dumpDec< sal_uInt16 >( "label-rotation", "TEXTROTATION" );
        break;

        case BIFF_ID_CHTYPEGROUP:
            dumpUnused( 16 );
            dumpHex< sal_uInt16 >( "flags", "CHTYPEGROUP-FLAGS" );
            if( eBiff >= BIFF5 ) dumpDec< sal_uInt16 >( "group-idx" );
        break;

        case BIFF_ID_CHVALUERANGE:
            dumpDec< double >( "minimum" );
            dumpDec< double >( "maximum" );
            dumpDec< double >( "major-inc" );
            dumpDec< double >( "minor-inc" );
            dumpDec< double >( "axis-crossing" );
            dumpHex< sal_uInt16 >( "flags", "CHVALUERANGE-FLAGS" );
        break;

        case BIFF_ID_CODENAME:
            dumpUniString( "codename" );
        break;

        case BIFF_ID_CODEPAGE:
            getBiffData().setTextEncoding( dumpCodePage() );
            mbHasCodePage = true;
        break;

        case BIFF_ID_COLINFO:
            dumpColRange();
            dumpDec< sal_uInt16 >( "col-width", "CONV-COLWIDTH" );
            dumpXfIdx( "xf-idx" );
            dumpHex< sal_uInt16 >( "flags", "COLINFO-FLAGS" );
            dumpUnused( 2 );
        break;

        case BIFF_ID_COLUMNDEFAULT:
            mxOut->resetItemIndex();
            for( sal_Int32 nCol = 0, nCount = dumpColRange(); nCol < nCount; ++nCol )
                dumpXfIdx( "#xf-idx", true );
            dumpUnused( 2 );
        break;

        case BIFF_ID_COLWIDTH:
            dumpColRange( EMPTY_STRING, false );
            dumpDec< sal_uInt16 >( "col-width", "CONV-COLWIDTH" );
        break;

        case BIFF_ID_COMPRESSPICS:
            dumpFrHeader( true, true );
            dumpBool< sal_uInt32 >( "recommend-compress-pics" );
        break;

        case BIFF_ID_CONNECTION:
        {
            dumpFrHeader( true, false );
            sal_uInt16 nType = dumpDec< sal_uInt16 >( "data-source-type", "CONNECTION-SOURCETYPE" );
            sal_uInt16 nFlags1 = dumpHex< sal_uInt16 >( "flags", "CONNECTION-FLAGS" );
            dumpDec< sal_uInt16 >( "param-count" );
            dumpUnused( 2 );
            dumpHex< sal_uInt16 >( "querytable-flags", "QUERYTABLESETTINGS-FLAGS" );
            switch( nType )
            {
                case 4:     dumpHex< sal_uInt16 >( "html-flags", "QUERYTABLESETTINGS-HTML-FLAGS" );     break;
                case 5:     dumpHex< sal_uInt16 >( "oledb-flags", "QUERYTABLESETTINGS-OLEDB-FLAGS" );   break;
                case 7:     dumpHex< sal_uInt16 >( "ado-flags", "QUERYTABLESETTINGS-ADO-FLAGS" );       break;
                default:    dumpUnused( 2 );
            }
            dumpDec< sal_uInt8 >( "edited-version" );
            dumpDec< sal_uInt8 >( "refreshed-version" );
            dumpDec< sal_uInt8 >( "min-refresh-version" );
            dumpDec< sal_uInt16 >( "refresh-interval", "QUERYTABLESETTINGS-INTERVAL" );
            dumpDec< sal_uInt16 >( "html-format", "QUERYTABLESETTINGS-HTMLFORMAT" );
            dumpDec< sal_Int32 >( "reconnect-type", "CONNECTION-RECONNECTTYPE" );
            dumpDec< sal_uInt8 >( "credentials", "CONNECTION-CREDENTIALS" );
            dumpUnused( 1 );
            dumpSegmentedUniString( "source-file" );
            dumpSegmentedUniString( "source-conn-file" );
            dumpSegmentedUniString( "name" );
            dumpSegmentedUniString( "description" );
            dumpSegmentedUniString( "sso-id" );
            if( nFlags1 & 0x0004 ) dumpSegmentedUniString( "table-names" );
            if( nFlags1 & 0x0010 )
            {
                break;   // TODO: parameter array structure
            }
            bool bEscape = false;
            switch( nType )
            {
                case 1:
                    dumpSegmentedUniString( "connection-string" );
                break;
                case 4:
                    dumpSegmentedUniStringArray( "urls" );
                    dumpSegmentedUniStringArray( "post-method" );
                break;
                case 5:
                    bEscape = true;
                break;
                case 6:
                    bEscape = true;
                break;
            }
            if( bEscape )
                break;
            dumpSegmentedUniStringArray( "sql-command" );
            dumpSegmentedUniStringArray( "orig-sql-command" );
            dumpSegmentedUniStringArray( "webquery-dialog-url" );
            switch( dumpDec< sal_uInt8 >( "linked-object-type", "CONNECTION-LINKEDOBJECTTYPE" ) )
            {
                case 1: dumpSegmentedUniString( "defined-name" );   break;
                case 2: dumpHex< sal_uInt16 >( "cache-id" );        break;
            }
        }
        break;
        
        case BIFF_ID_CONT:
            if( (eBiff == BIFF8) && (getLastRecId() == BIFF_ID_OBJ) )
                dumpEmbeddedDff();
        break;

        case BIFF_ID_COORDLIST:
        {
            mxOut->resetItemIndex();
            TableGuard aTabGuard( mxOut, 12, 10 );
            while( rStrm.getRemaining() >= 4 )
            {
                MultiItemsGuard aMultiGuard( mxOut );
                writeEmptyItem( "#point" );
                dumpDec< sal_uInt16 >( "x" );
                dumpDec< sal_uInt16 >( "y" );
            }
        }
        break;

        case BIFF_ID_COUNTRY:
            dumpDec< sal_uInt16 >( "ui-country", "COUNTRY" );
            dumpDec< sal_uInt16 >( "sys-country", "COUNTRY" );
        break;

        case BIFF_ID_CRN:
        {
            sal_Int32 nCol2 = dumpColIndex( "last-col-idx", false );
            sal_Int32 nCol1 = dumpColIndex( "first-col-idx", false );
            sal_Int32 nRow = dumpRowIndex( "row-idx" );
            TableGuard aTabGuard( mxOut, 14, 17 );
            for( Address aPos( nCol1, nRow ); !rStrm.isEof() && (aPos.mnCol <= nCol2); ++aPos.mnCol )
            {
                MultiItemsGuard aMultiGuard( mxOut );
                writeAddressItem( "pos", aPos );
                dumpConstValue();
            }
        }
        break;

        case BIFF_ID_DCONBINAME:
            dumpDec< sal_uInt8 >( "builtin-id", "DEFINEDNAME-BUILTINID" );
            dumpUnused( 3 );
            dumpString( "source-link", BIFF_STR_8BITLENGTH, BIFF_STR_SMARTFLAGS );
        break;

        case BIFF_ID_DCONNAME:
            dumpString( "source-name", BIFF_STR_8BITLENGTH );
            dumpString( "source-link", BIFF_STR_8BITLENGTH, BIFF_STR_SMARTFLAGS );
        break;

        case BIFF_ID_DCONREF:
            dumpRange( "source-range", false );
            dumpString( "source-link", BIFF_STR_8BITLENGTH, BIFF_STR_SMARTFLAGS );
        break;

        case BIFF2_ID_DATATABLE:
            dumpRange( "table-range", false );
            dumpBoolean( "recalc-always" );
            dumpBoolean( "row-table" );
            dumpAddress( "ref1" );
        break;

        case BIFF3_ID_DATATABLE:
            dumpRange( "table-range", false );
            dumpHex< sal_uInt16 >( "flags", "DATATABLE-FLAGS" );
            dumpAddress( "ref1" );
            dumpAddress( "ref2" );
        break;

        case BIFF2_ID_DATATABLE2:
            dumpRange( "table-range", false );
            dumpBoolean( "recalc-always" );
            dumpUnused( 1 );
            dumpAddress( "ref1" );
            dumpAddress( "ref2" );
        break;

        case BIFF_ID_DATAVALIDATION:
        {
            dumpHex< sal_uInt32 >( "flags", "DATAVALIDATION-FLAGS" );
            dumpUniString( "input-title" );
            dumpUniString( "error-title" );
            dumpUniString( "input-message" );
            dumpUniString( "error-message" );
            sal_uInt16 nFmla1Size = getFormulaDumper().dumpFormulaSize( "formula1-size" );
            dumpUnused( 2 );
            if( nFmla1Size > 0 )
                getFormulaDumper().dumpNameFormula( "formula1", nFmla1Size );
            sal_uInt16 nFmla2Size = getFormulaDumper().dumpFormulaSize( "formula2-size" );
            dumpUnused( 2 );
            if( nFmla2Size > 0 )
                getFormulaDumper().dumpNameFormula( "formula2", nFmla2Size );
            dumpRangeList();
        }
        break;

        case BIFF_ID_DATAVALIDATIONS:
            dumpHex< sal_uInt16 >( "flags", "DATAVALIDATIONS-FLAGS" );
            dumpDec< sal_Int32 >( "input-box-pos-x" );
            dumpDec< sal_Int32 >( "input-box-pos-y" );
            dumpDec< sal_Int32 >( "dropdown-object-id" );
            dumpDec< sal_Int32 >( "dval-entry-count" );
        break;

        case BIFF_ID_DBCELL:
            dumpDec< sal_uInt32 >( "reverse-offset-to-row" );
            mxOut->resetItemIndex();
            while( rStrm.getRemaining() >= 2 )
                dumpDec< sal_uInt16 >( "#cell-offset" );
        break;

        case BIFF_ID_DBQUERY:
            if( eBiff == BIFF8 )
            {
                if( (getLastRecId() != BIFF_ID_PCITEM_STRING) && (getLastRecId() != BIFF_ID_DBQUERY) )
                {
                    dumpHex< sal_uInt16 >( "flags", "DBQUERY-FLAGS" );
                    dumpDec< sal_uInt16 >( "sql-param-count" );
                    dumpDec< sal_uInt16 >( "command-count" );
                    dumpDec< sal_uInt16 >( "post-method-count" );
                    dumpDec< sal_uInt16 >( "server-sql-count" );
                    dumpDec< sal_uInt16 >( "odbc-connection-count" );
                }
            }
        break;

        case BIFF2_ID_DEFINEDNAME:
        case BIFF3_ID_DEFINEDNAME:
        {
            rtl_TextEncoding eTextEnc = getBiffData().getTextEncoding();
            dumpHex< sal_uInt16, sal_uInt8 >( eBiff != BIFF2, "flags", "DEFINEDNAME-FLAGS" );
            if( eBiff == BIFF2 ) dumpDec< sal_uInt8 >( "macro-type", "DEFINEDNAME-MACROTYPE-BIFF2" );
            dumpChar( "accelerator", eTextEnc );
            sal_uInt8 nNameLen = dumpDec< sal_uInt8 >( "name-len" );
            sal_uInt16 nFmlaSize = getFormulaDumper().dumpFormulaSize();
            if( eBiff >= BIFF5 )
            {
                bool bBiff8 = eBiff == BIFF8;
                if( bBiff8 ) dumpUnused( 2 ); else dumpDec< sal_uInt16 >( "externsheet-idx", "DEFINEDNAME-SHEETIDX" );
                dumpDec< sal_uInt16 >( "sheet-idx", "DEFINEDNAME-SHEETIDX" );
                sal_uInt8 nMenuLen = dumpDec< sal_uInt8 >( "menu-text-len" );
                sal_uInt8 nDescrLen = dumpDec< sal_uInt8 >( "description-text-len" );
                sal_uInt8 nHelpLen = dumpDec< sal_uInt8 >( "help-text-len" );
                sal_uInt8 nStatusLen = dumpDec< sal_uInt8 >( "statusbar-text-len" );
                writeStringItem( "name", bBiff8 ? rStrm.readUniStringBody( nNameLen, true ) : rStrm.readCharArrayUC( nNameLen, eTextEnc, true ) );
                getFormulaDumper().dumpNameFormula( EMPTY_STRING, nFmlaSize );
                if( nMenuLen > 0 ) writeStringItem( "menu-text", bBiff8 ? rStrm.readUniStringBody( nMenuLen, true ) : rStrm.readCharArrayUC( nMenuLen, eTextEnc, true ) );
                if( nDescrLen > 0 ) writeStringItem( "description-text", bBiff8 ? rStrm.readUniStringBody( nDescrLen, true ) : rStrm.readCharArrayUC( nDescrLen, eTextEnc, true ) );
                if( nHelpLen > 0 ) writeStringItem( "help-text", bBiff8 ? rStrm.readUniStringBody( nHelpLen, true ) : rStrm.readCharArrayUC( nHelpLen, eTextEnc, true ) );
                if( nStatusLen > 0 ) writeStringItem( "statusbar-text", bBiff8 ? rStrm.readUniStringBody( nStatusLen, true ) : rStrm.readCharArrayUC( nStatusLen, eTextEnc, true ) );
            }
            else
            {
                writeStringItem( "name", rStrm.readCharArrayUC( nNameLen, eTextEnc, true ) );
                getFormulaDumper().dumpNameFormula( EMPTY_STRING, nFmlaSize );
                if( eBiff == BIFF2 ) getFormulaDumper().dumpFormulaSize();
            }
        }
        break;

        case BIFF3_ID_DEFROWHEIGHT:
            dumpHex< sal_uInt16 >( "flags", "DEFROWHEIGHT-FLAGS" );
            dumpDec< sal_uInt16 >( "row-height", "CONV-TWIP-TO-PT" );
        break;

        case BIFF2_ID_DIMENSION:
        case BIFF3_ID_DIMENSION:
            dumpRange( "used-area", true, (nRecId == BIFF3_ID_DIMENSION) && (eBiff == BIFF8) );
            if( nRecId == BIFF3_ID_DIMENSION ) dumpUnused( 2 );
        break;

        case BIFF_ID_DXF:
            dumpFrHeader( true, true );
            dumpHex< sal_uInt16 >( "flags", "DXF-FLAGS" );
            dumpDxfProp();
        break;

        case BIFF_ID_EXTERNALBOOK:
        {
            sal_uInt16 nCount = dumpDec< sal_uInt16 >( "sheet-count" );
            if( rStrm.getRemaining() == 2 )
                dumpHex< sal_uInt16 >( "special-key", "EXTERNALBOOK-KEY" );
            else
            {
                dumpString( "workbook-url" );
                mxOut->resetItemIndex();
                for( sal_uInt16 nSheet = 0; !rStrm.isEof() && (nSheet < nCount); ++nSheet )
                    dumpString( "#sheet-name" );
            }
        }
        break;

        case BIFF2_ID_EXTERNALNAME:
        case BIFF3_ID_EXTERNALNAME:
        {
            sal_uInt16 nFlags = (eBiff >= BIFF3) ? dumpHex< sal_uInt16 >( "flags", "EXTERNALNAME-FLAGS" ) : 0;
            if( eBiff >= BIFF5 )
            {
                if( getFlag< sal_uInt16 >( nFlags, 0x0010 ) )
                {
                    dumpHex< sal_uInt32 >( "storage-id" );
                }
                else
                {
                    dumpDec< sal_uInt16 >( "externsheet-idx" );
                    dumpUnused( 2 );
                }
            }
            OUString aName = dumpString( "name", BIFF_STR_8BITLENGTH, BIFF_STR_8BITLENGTH );
            if( (aName.getLength() > 0) && (aName[ 0 ] == 1) && (rStrm.getRemaining() >= 2) )
                getFormulaDumper().dumpNameFormula();
        }
        break;

        case BIFF_ID_EXTERNSHEET:
            if( eBiff == BIFF8 )
            {
                sal_uInt16 nCount = dumpDec< sal_uInt16 >( "ref-count" );
                TableGuard aTabGuard( mxOut, 10, 17, 24 );
                mxOut->resetItemIndex();
                for( sal_uInt16 nRefId = 0; !rStrm.isEof() && (nRefId < nCount); ++nRefId )
                {
                    MultiItemsGuard aMultiGuard( mxOut );
                    writeEmptyItem( "#ref" );
                    dumpDec< sal_uInt16 >( "extbook-idx" );
                    dumpDec< sal_Int16 >( "first-sheet", "EXTERNSHEET-IDX" );
                    dumpDec< sal_Int16 >( "last-sheet", "EXTERNSHEET-IDX" );
                }
            }
            else
            {
                OStringBuffer aUrl( rStrm.readByteString( false, true ) );
                if( (aUrl.getLength() > 0) && (aUrl[ 0 ] == '\x03') )
                    aUrl.append( static_cast< sal_Char >( rStrm.readuInt8() ) );
                writeStringItem( "encoded-url", OStringToOUString( aUrl.makeStringAndClear(), getBiffData().getTextEncoding() ) );
            }
        break;

        case BIFF_ID_FILEPASS:
        {
            rStrm.enableDecoder( false );
            if( eBiff == BIFF8 )
            {
                switch( dumpDec< sal_uInt16 >( "type", "FILEPASS-TYPE" ) )
                {
                    case 0:
                        dumpHex< sal_uInt16 >( "key" );
                        dumpHex< sal_uInt16 >( "verifier" );
                    break;
                    case 1:
                    {
                        sal_uInt16 nMajor = dumpDec< sal_uInt16 >( "major-version", "FILEPASS-MAJOR" );
                        dumpDec< sal_uInt16 >( "minor-version" );
                        switch( nMajor )
                        {
                            case 1:
                                dumpArray( "salt", 16 );
                                dumpArray( "verifier", 16 );
                                dumpArray( "verifier-hash", 16 );
                            break;
                        }
                    }
                    break;
                }
            }
            else
            {
                dumpHex< sal_uInt16 >( "key" );
                dumpHex< sal_uInt16 >( "verifier" );
            }
            rStrm.seekToStart();
            BiffDecoderRef xDecoder = BiffCodecHelper::implReadFilePass( rStrm, eBiff );
            if( xDecoder.get() )
                cfg().requestEncryptionData( *xDecoder );
            setBinaryOnlyMode( !xDecoder || !xDecoder->isValid() );
        }
        break;

        case BIFF_ID_FILESHARING:
            dumpBool< sal_uInt16 >( "recommend-read-only" );
            dumpHex< sal_uInt16 >( "password-hash" );
            dumpString( "password-creator", BIFF_STR_8BITLENGTH, BIFF_STR_SMARTFLAGS );
        break;

        case BIFF_ID_FILTERCOLUMN:
        {
            dumpDec< sal_uInt16 >( "column-index" );
            dumpHex< sal_uInt16 >( "flags", "FILTERCOLUMN-FLAGS" );
            sal_uInt8 nStrLen1 = dumpFilterColumnOperator( "operator-1" );
            sal_uInt8 nStrLen2 = dumpFilterColumnOperator( "operator-2" );
            bool bBiff8 = eBiff == BIFF8;
            rtl_TextEncoding eTextEnc = getBiffData().getTextEncoding();
            if( nStrLen1 > 0 ) writeStringItem( "string-1", bBiff8 ? rStrm.readUniStringBody( nStrLen1, true ) : rStrm.readCharArrayUC( nStrLen1, eTextEnc, true ) );
            if( nStrLen2 > 0 ) writeStringItem( "string-2", bBiff8 ? rStrm.readUniStringBody( nStrLen2, true ) : rStrm.readCharArrayUC( nStrLen2, eTextEnc, true ) );
        }
        break;
        
        case BIFF2_ID_FONT:
        case BIFF3_ID_FONT:
            dumpFontRec();
        break;

        case BIFF_ID_FORCEFULLCALC:
            dumpFrHeader( true, true );
            dumpBool< sal_Int32 >( "recalc-all-formulas" );
        break;

        case BIFF2_ID_FORMAT:
        case BIFF4_ID_FORMAT:
            dumpFormatRec();
        break;

        case BIFF2_ID_FORMULA:
        case BIFF3_ID_FORMULA:
        case BIFF4_ID_FORMULA:
            dumpCellHeader( eBiff == BIFF2 );
            dumpFormulaResult();
            dumpHex< sal_uInt16, sal_uInt8 >( eBiff != BIFF2, "flags", "FORMULA-FLAGS" );
            if( eBiff >= BIFF5 ) dumpUnused( 4 );
            getFormulaDumper().dumpCellFormula();
        break;

        case BIFF_ID_FOOTER:
            if( rStrm.getRemaining() > 0 )
                dumpString( "footer", BIFF_STR_8BITLENGTH );
        break;

        case BIFF_ID_GUTS:
            dumpDec< sal_uInt16 >( "row-outlines-width" );
            dumpDec< sal_uInt16 >( "column-outlines-height" );
            dumpDec< sal_uInt16 >( "row-levels", "GUTS-LEVELS" );
            dumpDec< sal_uInt16 >( "column-levels", "GUTS-LEVELS" );
        break;

        case BIFF_ID_HEADER:
            if( rStrm.getRemaining() > 0 )
                dumpString( "header", BIFF_STR_8BITLENGTH );
        break;

        case BIFF_ID_HEADERFOOTER:
        {
            dumpFrHeader( true, true );
            dumpGuid( "view-guid" );
            dumpHex< sal_uInt16 >( "flags", "HEADERFOOTER-FLAGS" );
            sal_uInt16 nEvenHLen = dumpDec< sal_uInt16 >( "even-h-len" );
            sal_uInt16 nEvenFLen = dumpDec< sal_uInt16 >( "even-f-len" );
            sal_uInt16 nFirstHLen = dumpDec< sal_uInt16 >( "first-h-len" );
            sal_uInt16 nFirstFLen = dumpDec< sal_uInt16 >( "first-f-len" );
            if( nEvenHLen > 0 ) dumpUniString( "even-h" );
            if( nEvenFLen > 0 ) dumpUniString( "even-f" );
            if( nFirstHLen > 0 ) dumpUniString( "first-h" );
            if( nFirstFLen > 0 ) dumpUniString( "first-f" );
        }
        break;

        case BIFF_ID_HYPERLINK:
            dumpRange();
            if( cfg().getStringOption( dumpGuid( "guid" ), OUString() ).equalsAscii( "StdHlink" ) )
                StdHlinkObject( *this ).dump();
        break;

        case BIFF3_ID_IMGDATA:
        case BIFF8_ID_IMGDATA:
        {
            sal_uInt16 nFormat = dumpDec< sal_uInt16 >( "image-format", "IMGDATA-FORMAT" );
            dumpDec< sal_uInt16 >( "environment", "IMGDATA-ENV" );
            dumpDec< sal_uInt32 >( "data-size" );
            if( nFormat == 9 )
            {
                writeEmptyItem( "bitmap-header" );
                IndentGuard aIndGuard( mxOut );
                if( dumpDec< sal_uInt32 >( "header-size" ) == 12 )
                {
                    dumpDec< sal_Int16 >( "width" );
                    dumpDec< sal_Int16 >( "height" );
                    dumpDec< sal_Int16 >( "planes" );
                    dumpDec< sal_Int16 >( "bit-count" );
                }
            }
        }
        break;

        case BIFF2_ID_INDEX:
        case BIFF3_ID_INDEX:
            if( eBiff <= BIFF4 )
                dumpHex< sal_uInt32 >( "first-defname-pos", "CONV-DEC" );
            else
                dumpUnused( 4 );
            dumpRowIndex( "first-row-with-cell", eBiff == BIFF8 );
            dumpRowIndex( "first-free-row", eBiff == BIFF8 );
            if( nRecId == BIFF3_ID_INDEX ) dumpHex< sal_uInt32 >( (eBiff <= BIFF4) ? "first-xf-pos" : "defcolwidth-pos", "CONV-DEC" );
            mxOut->resetItemIndex();
            while( rStrm.getRemaining() >= 4 )
                dumpHex< sal_uInt32 >( "#first-row-pos-of-block", "CONV-DEC" );
        break;

        case BIFF2_ID_INTEGER:
            dumpCellHeader( true );
            dumpDec< sal_uInt16 >( "value" );
        break;

        case BIFF2_ID_LABEL:
        case BIFF3_ID_LABEL:
        {
            bool bBiff2 = nRecId == BIFF2_ID_LABEL;
            sal_uInt16 nXfIdx = dumpCellHeader( bBiff2 );
            rtl_TextEncoding eOldTextEnc = getBiffData().getTextEncoding();
            getBiffData().setTextEncoding( getBiffData().getXfEncoding( nXfIdx ) );
            dumpString( "value", bBiff2 ? BIFF_STR_8BITLENGTH : BIFF_STR_DEFAULT );
            getBiffData().setTextEncoding( eOldTextEnc );
        }
        break;

        case BIFF_ID_LABELRANGES:
            dumpRangeList( "row-ranges" );
            dumpRangeList( "col-ranges" );
        break;

        case BIFF_ID_LABELSST:
            dumpCellHeader();
            dumpDec< sal_Int32 >( "sst-idx" );
        break;

        case BIFF_ID_MERGEDCELLS:
            mxOut->resetItemIndex();
            for( sal_uInt16 nIdx = 0, nCount = dumpDec< sal_uInt16 >( "count" ); !rStrm.isEof() && (nIdx < nCount); ++nIdx )
                dumpRange( "#range" );
        break;
        
        case BIFF_ID_MSODRAWING:
        case BIFF_ID_MSODRAWINGGROUP:
        case BIFF_ID_MSODRAWINGSEL:
            dumpEmbeddedDff();
            mbHasDff = true;
        break;

        case BIFF_ID_MTHREADSETTINGS:
            dumpFrHeader( true, true );
            dumpBool< sal_Int32 >( "multi-thread-enabled" );
            dumpBool< sal_Int32 >( "manual-thread-count" );
            dumpDec< sal_Int32 >( "thread-count" );
        break;

        case BIFF_ID_MULTBLANK:
        {
            Address aPos = dumpAddress();
            {
                TableGuard aTabGuard( mxOut, 12 );
                for( ; rStrm.getRemaining() >= 4; ++aPos.mnCol )
                {
                    MultiItemsGuard aMultiGuard( mxOut );
                    writeAddressItem( "pos", aPos );
                    dumpXfIdx();
                }
            }
            dumpColIndex( "last-col-idx" );
        }
        break;

        case BIFF_ID_MULTRK:
        {
            Address aPos = dumpAddress();
            {
                TableGuard aTabGuard( mxOut, 12, 12 );
                for( ; rStrm.getRemaining() >= 8; ++aPos.mnCol )
                {
                    MultiItemsGuard aMultiGuard( mxOut );
                    writeAddressItem( "pos", aPos );
                    dumpXfIdx();
                    dumpRk( "value" );
                }
            }
            dumpColIndex( "last-col-idx" );
        }
        break;

        case BIFF_ID_NOTE:
            dumpAddress( "anchor-cell" );
            if( eBiff == BIFF8 )
            {
                dumpHex< sal_uInt16 >( "flags", "NOTE-FLAGS" );
                dumpDec< sal_uInt16 >( "obj-id" );
                dumpUniString( "author" );
                dumpUnused( 1 );
            }
            else
            {
                sal_uInt16 nTextLen = dumpDec< sal_uInt16 >( "text-len" );
                nTextLen = ::std::min( nTextLen, static_cast< sal_uInt16 >( rStrm.getRemaining() ) );
                writeStringItem( "note-text", rStrm.readCharArrayUC( nTextLen, getBiffData().getTextEncoding(), true ) );
            }
        break;

        case BIFF_ID_NOTESOUND:
            dumpHex< sal_uInt32 >( "identifier" );
            dumpDec< sal_uInt32 >( "total-data-size" );
            dumpDec< sal_uInt32 >( "wave-data-size" );
            if( dumpDec< sal_uInt32 >( "fmt-size" ) >= 16 )
            {
                dumpDec< sal_uInt16 >( "format", "NOTESOUND-FORMAT" );
                dumpDec< sal_uInt16 >( "channels" );
                dumpDec< sal_uInt32 >( "sampling-rate" );
                dumpDec< sal_uInt32 >( "data-rate" );
                dumpDec< sal_uInt16 >( "data-block-size" );
                dumpDec< sal_uInt16 >( "bits-per-sample" );
            }
        break;
        
        case BIFF2_ID_NUMBER:
        case BIFF3_ID_NUMBER:
            dumpCellHeader( nRecId == BIFF2_ID_NUMBER );
            dumpDec< double >( "value" );
        break;

        case BIFF_ID_OBJ:
            dumpObjRec();
        break;

        case BIFF_ID_OLESIZE:
            dumpUnused( 2 );
            dumpRange( "visible-range", false );
        break;
        
        case BIFF_ID_PAGELAYOUTVIEW:
            dumpFrHeader( true, true );
            dumpDec< sal_uInt16 >( "scaling", "CONV-PERCENT" );
            dumpHex< sal_uInt16 >( "flags", "PAGELAYOUTVIEW-FLAGS" );
        break;

        case BIFF_ID_PAGESETUP:
            dumpDec< sal_uInt16 >( "paper-size", "PAGESETUP-PAPERSIZE" );
            dumpDec< sal_uInt16 >( "scaling", "CONV-PERCENT" );
            dumpDec< sal_uInt16 >( "first-page" );
            dumpDec< sal_uInt16 >( "scale-to-width", "PAGESETUP-SCALETOPAGES" );
            dumpDec< sal_uInt16 >( "scale-to-height", "PAGESETUP-SCALETOPAGES" );
            dumpHex< sal_uInt16 >( "flags", "PAGESETUP-FLAGS" );
            if( eBiff >= BIFF5 )
            {
                dumpDec< sal_uInt16 >( "horizontal-res", "PAGESETUP-DPI" );
                dumpDec< sal_uInt16 >( "vertical-res", "PAGESETUP-DPI" );
                dumpDec< double >( "header-margin", "CONV-INCH-TO-CM" );
                dumpDec< double >( "footer-margin", "CONV-INCH-TO-CM" );
                dumpDec< sal_uInt16 >( "copies" );
            }
        break;

        case BIFF_ID_PALETTE:
            mxOut->resetItemIndex( 8 );
            for( sal_uInt16 nIdx = 0, nCount = dumpDec< sal_uInt16 >( "count" ); !rStrm.isEof() && (nIdx < nCount); ++nIdx )
            {
                OUStringBuffer aColorName;
                StringHelper::appendHex( aColorName, dumpColorABGR( "#color" ) );
                mxColors->setName( nIdx + 8, aColorName.makeStringAndClear() );
            }
        break;

        case BIFF_ID_PANE:
            dumpDec< sal_uInt16 >( "x-pos", "CONV-TWIP-TO-CM" );
            dumpDec< sal_uInt16 >( "y-pos", "CONV-TWIP-TO-CM" );
            dumpAddress( "first-visible-cell" );
            dumpDec< sal_uInt8 >( "active-pane", "PANE-ID" );
        break;

        case BIFF_ID_PCITEM_STRING:
            dumpString( "value" );
        break;

        case BIFF_ID_PHONETICPR:
            dumpDec< sal_uInt16 >( "font-id", "FONTNAMES" );
            dumpHex< sal_uInt16 >( "flags", "PHONETICPR-FLAGS" );
            dumpRangeList( "show-phonetic" );
        break;

        case BIFF_ID_PROJEXTSHEET:
            dumpDec< sal_uInt8 >( "sheet-type", "PROJEXTSHEET-TYPE" );
            dumpUnused( 1 );
            dumpByteString( "sheet-link", BIFF_STR_8BITLENGTH );
        break;

        case BIFF_ID_PTDATAFIELD:
            dumpDec< sal_Int16 >( "field" );
            dumpDec< sal_uInt16 >( "subtotal", "PTDATAFIELD-SUBTOTAL" );
            dumpDec< sal_uInt16 >( "show-data-as", "PTDATAFIELD-SHOWDATAAS" );
            dumpDec< sal_Int16 >( "base-field" );
            dumpDec< sal_Int16 >( "base-item", "PTDATAFIELD-BASEITEM" );
            dumpFormatIdx();
            dumpPivotString( "name" );
        break;

        case BIFF_ID_PTDEFINITION:
        {
            dumpRange( "output-range" );
            dumpRowIndex( "first-header-row-idx" );
            dumpAddress( "first-data-pos" );
            dumpDec< sal_uInt16 >( "cache-idx" );
            dumpUnused( 2 );
            dumpDec< sal_uInt16 >( "default-data-axis", "PTFIELD-AXISTYPE" );
            dumpDec< sal_Int16 >( "default-data-pos", "PTDEFINITION-DATAFIELD-POS" );
            dumpDec< sal_uInt16 >( "field-count" );
            mnPTRowFields = dumpDec< sal_uInt16 >( "row-field-count" );
            mnPTColFields = dumpDec< sal_uInt16 >( "column-field-count" );
            dumpDec< sal_uInt16 >( "page-field-count" );
            dumpDec< sal_uInt16 >( "data-field-count" );
            dumpDec< sal_uInt16 >( "data-row-count" );
            dumpDec< sal_uInt16 >( "data-column-count" );
            dumpHex< sal_uInt16 >( "flags", "PTDEFINITION-FLAGS" );
            dumpDec< sal_uInt16 >( "auto-format-idx" );
            sal_uInt16 nTabNameLen = dumpDec< sal_uInt16 >( "table-name-len" );
            sal_uInt16 nDataNameLen = dumpDec< sal_uInt16 >( "data-name-len" );
            dumpPivotString( "table-name", nTabNameLen );
            dumpPivotString( "data-name", nDataNameLen );
            mnPTRowColItemsIdx = 0;
        }
        break;

        case BIFF_ID_PTDEFINITION2:
        {
            dumpDec< sal_uInt16 >( "format-rec-count" );
            sal_uInt16 nErrCaptLen = dumpDec< sal_uInt16 >( "error-caption-len" );
            sal_uInt16 nMissCaptLen = dumpDec< sal_uInt16 >( "missing-caption-len" );
            sal_uInt16 nTagLen = dumpDec< sal_uInt16 >( "tag-len" );
            dumpDec< sal_uInt16 >( "select-rec-count" );
            dumpDec< sal_uInt16 >( "page-rows" );
            dumpDec< sal_uInt16 >( "page-cols" );
            dumpHex< sal_uInt32 >( "flags", "PTDEFINITION2-FLAGS" );
            sal_uInt16 nPageStyleLen = dumpDec< sal_uInt16 >( "page-field-style-len" );
            sal_uInt16 nTabStyleLen = dumpDec< sal_uInt16 >( "pivot-table-style-len" );
            sal_uInt16 nVacStyleLen = dumpDec< sal_uInt16 >( "vacated-style-len" );
            dumpPivotString( "error-caption", nErrCaptLen );
            dumpPivotString( "missing-caption", nMissCaptLen );
            dumpPivotString( "tag", nTagLen );
            dumpPivotString( "page-field-style", nPageStyleLen );
            dumpPivotString( "pivot-table-style", nTabStyleLen );
            dumpPivotString( "vacated-style", nVacStyleLen );
        }
        break;

        case BIFF_ID_PTFIELD:
            dumpDec< sal_uInt16 >( "axis-type", "PTFIELD-AXISTYPE" );
            dumpDec< sal_uInt16 >( "subtotal-count" );
            dumpHex< sal_uInt16 >( "subtotals", "PTFIELD-SUBTOTALS" );
            dumpDec< sal_uInt16 >( "item-count" );
            dumpPivotString( "field-name" );
        break;

        case BIFF_ID_PTFIELD2:
            dumpHex< sal_uInt32 >( "flags", "PTFIELD2-FLAGS" );
            dumpDec< sal_Int16 >( "autosort-basefield-idx" );
            dumpDec< sal_Int16 >( "autoshow-basefield-idx" );
            dumpFormatIdx();
            if( rStrm.getRemaining() >= 2 )
            {
                sal_uInt16 nFuncNameLen = dumpDec< sal_uInt16 >( "subtotal-func-name-len" );
                dumpUnused( 8 );
                dumpPivotString( "subtotal-func-name", nFuncNameLen );
            }
        break;

        case BIFF_ID_PTFITEM:
            dumpDec< sal_uInt16 >( "item-type", "PTFITEM-ITEMTYPE" );
            dumpHex< sal_uInt16 >( "flags", "PTFITEM-FLAGS" );
            dumpDec< sal_Int16 >( "cache-idx", "PTFITEM-CACHEIDX" );
            dumpPivotString( "item-name" );
        break;

        case BIFF_ID_PTPAGEFIELDS:
        {
            mxOut->resetItemIndex();
            TableGuard aTabGuard( mxOut, 17, 17, 17 );
            while( rStrm.getRemaining() >= 6 )
            {
                writeEmptyItem( "#page-field" );
                MultiItemsGuard aMultiGuard( mxOut );
                IndentGuard aIndGuard( mxOut );
                dumpDec< sal_Int16 >( "base-field" );
                dumpDec< sal_Int16 >( "item", "PTPAGEFIELDS-ITEM" );
                dumpDec< sal_uInt16 >( "dropdown-obj-id" );
            }
        }
        break;

        case BIFF_ID_PTROWCOLFIELDS:
            mxOut->resetItemIndex();
            for( sal_Int64 nIdx = 0, nCount = rStrm.getRemaining() / 2; nIdx < nCount; ++nIdx )
                dumpDec< sal_Int16 >( "#field-idx" );
        break;

        case BIFF_ID_PTROWCOLITEMS:
            if( mnPTRowColItemsIdx < 2 )
            {
                sal_uInt16 nCount = (mnPTRowColItemsIdx == 0) ? mnPTRowFields : mnPTColFields;
                sal_Int64 nLineSize = 8 + 2 * nCount;
                mxOut->resetItemIndex();
                while( rStrm.getRemaining() >= nLineSize )
                {
                    writeEmptyItem( "#line-data" );
                    IndentGuard aIndGuard( mxOut );
                    MultiItemsGuard aMultiGuard( mxOut );
                    dumpDec< sal_uInt16 >( "ident-count" );
                    dumpDec< sal_uInt16 >( "item-type", "PTROWCOLITEMS-ITEMTYPE" );
                    dumpDec< sal_uInt16 >( "used-count" );
                    dumpHex< sal_uInt16 >( "flags", "PTROWCOLITEMS-FLAGS" );
                    OUStringBuffer aItemList;
                    for( sal_uInt16 nIdx = 0; nIdx < nCount; ++nIdx )
                        StringHelper::appendToken( aItemList, mxStrm->readInt16() );
                    writeInfoItem( "item-idxs", aItemList.makeStringAndClear() );
                }
                ++mnPTRowColItemsIdx;
            }
        break;

        case BIFF_ID_QUERYTABLE:
            dumpHex< sal_uInt16 >( "flags", "QUERYTABLE-FLAGS" );
            dumpDec< sal_uInt16 >( "autoformat-id" );
            dumpHex< sal_uInt16 >( "autoformat-flags", "QUERYTABLE-AUTOFORMAT-FLAGS" );
            dumpUnused( 4 );
            dumpUniString( "defined-name" );
            dumpUnused( 2 );
        break;
        
        case BIFF_ID_QUERYTABLEREFRESH:
        {
            dumpFrHeader( true, false );
            bool bPivot = dumpBool< sal_uInt16 >( "pivot-table" );
            dumpHex< sal_uInt16 >( "flags", "QUERYTABLEREFRESH-FLAGS" );
            dumpHex< sal_uInt32 >( bPivot ? "pivottable-flags" : "querytable-flags", bPivot ? "QUERYTABLEREFRESH-PTFLAGS" : "QUERYTABLEREFRESH-QTFLAGS" );
            dumpDec< sal_uInt8 >( "refreshed-version" );
            dumpDec< sal_uInt8 >( "min-refresh-version" );
            dumpUnused( 2 );
            dumpUniString( "table-name" );
            dumpUnused( 2 );
        }
        break;

        case BIFF_ID_QUERYTABLESETTINGS:
        {
            dumpFrHeader( true, false );
            sal_uInt16 nType = dumpDec< sal_uInt16 >( "data-source-type", "CONNECTION-SOURCETYPE" );
            dumpHex< sal_uInt16 >( "flags-1", "QUERYTABLESETTINGS-FLAGS" );
            switch( nType )
            {
                case 4:     dumpHex< sal_uInt16 >( "html-flags", "QUERYTABLESETTINGS-HTML-FLAGS" );     break;
                case 5:     dumpHex< sal_uInt16 >( "oledb-flags", "QUERYTABLESETTINGS-OLEDB-FLAGS" );   break;
                case 7:     dumpHex< sal_uInt16 >( "ado-flags", "QUERYTABLESETTINGS-ADO-FLAGS" );       break;
                default:    dumpUnused( 2 );
            }
            dumpHex< sal_uInt16 >( "ext-flags", "QUERYTABLESETTINGS-EXT-FLAGS" );
            dumpDec< sal_uInt8 >( "edited-version" );
            dumpDec< sal_uInt8 >( "refreshed-version" );
            dumpDec< sal_uInt8 >( "min-refresh-version" );
            dumpUnused( 3 );
            dumpDec< sal_uInt16 >( "oledb-count" );
            dumpDec< sal_uInt16 >( "future-data-size" );
            dumpDec< sal_uInt16 >( "refresh-interval", "QUERYTABLESETTINGS-INTERVAL" );
            dumpDec< sal_uInt16 >( "html-format", "QUERYTABLESETTINGS-HTMLFORMAT" );
        }
        break;

        case BIFF_ID_QUERYTABLESTRING:
            dumpFrHeader( true, false );
            dumpUniString( "connection-string" );
        break;

        case BIFF_ID_RECALCID:
            dumpFrHeader( true, false );
            dumpDec< sal_uInt32 >( "recalc-engine-id" );
        break;

        case BIFF_ID_RK:
            dumpCellHeader();
            dumpRk( "value" );
        break;

        case BIFF2_ID_ROW:
        {
            dumpRowIndex();
            dumpColIndex( "first-used-col-idx" );
            dumpColIndex( "first-free-col-idx" );
            dumpHex< sal_uInt16 >( "height", "ROW-HEIGHT" );
            dumpUnused( 2 );
            bool bHasDefXf = dumpBool< sal_uInt8 >( "custom-format" );
            dumpDec< sal_uInt16 >( "cell-offset" );
            if( bHasDefXf ) dumpXfIdx( "custom-format", true );
            if( bHasDefXf ) dumpXfIdx( "custom-xf-idx", false );
        }
        break;

        case BIFF3_ID_ROW:
            dumpRowIndex();
            dumpColIndex( "first-used-col-idx" );
            dumpColIndex( "first-free-col-idx" );
            dumpHex< sal_uInt16 >( "height", "ROW-HEIGHT" );
            dumpUnused( (eBiff <= BIFF4) ? 2 : 4 );
            if( eBiff <= BIFF4 ) dumpDec< sal_uInt16 >( "cell-offset" );
            dumpHex< sal_uInt32 >( "flags", "ROW-FLAGS" );
        break;

        case BIFF_ID_RSTRING:
        {
            sal_uInt16 nXfIdx = dumpCellHeader();
            rtl_TextEncoding eOldTextEnc = getBiffData().getTextEncoding();
            getBiffData().setTextEncoding( getBiffData().getXfEncoding( nXfIdx ) );
            dumpString( "value" );
            getBiffData().setTextEncoding( eOldTextEnc );
            FontPortionModelList aPortions;
            aPortions.importPortions( rStrm, eBiff == BIFF8 );
            writeFontPortions( aPortions );
        }
        break;

        case BIFF_ID_SCENARIO:
        {
            sal_uInt16 nCellCount = dumpDec< sal_uInt16 >( "cell-count" );
            // two bytes instead of flag field
            dumpBoolean( "locked" );
            dumpBoolean( "hidden" );
            sal_uInt16 nNameLen = dumpDec< sal_uInt8 >( "name-len" );
            sal_uInt16 nCommentLen = dumpDec< sal_uInt8 >( "comment-len" );
            sal_uInt16 nUserLen = dumpDec< sal_uInt8 >( "user-len" );
            writeStringItem( "name", rStrm.readUniStringBody( nNameLen, true ) );
            if( nUserLen > 0 ) dumpUniString( "user" );         // repeated string length
            if( nCommentLen > 0 ) dumpUniString( "comment" );   // repeated string length
            mxOut->resetItemIndex();
            for( sal_uInt16 nCell = 0; !rStrm.isEof() && (nCell < nCellCount); ++nCell )
                dumpAddress( "#pos" );
            mxOut->resetItemIndex();
            for( sal_uInt16 nCell = 0; !rStrm.isEof() && (nCell < nCellCount); ++nCell )
                dumpString( "#value" );
            dumpUnused( 2 * nCellCount );
        }
        break;

        case BIFF_ID_SCENARIOS:
            dumpDec< sal_uInt16 >( "count" );
            dumpDec< sal_uInt16 >( "selected" );
            dumpDec< sal_uInt16 >( "shown" );
            dumpRangeList( "result-cells" );
        break;

        case BIFF_ID_SCL:
        {
            sal_uInt16 nNum = dumpDec< sal_uInt16 >( "numerator" );
            sal_uInt16 nDen = dumpDec< sal_uInt16 >( "denominator" );
            if( nDen > 0 ) writeDecItem( "current-zoom", static_cast< sal_uInt16 >( nNum * 100 / nDen ), "CONV-PERCENT" );
        }
        break;

        case BIFF_ID_SCREENTIP:
            dumpFrHeader( false, true );
            dumpNullUnicodeArray( "tooltip" );
        break;

        case BIFF_ID_SELECTION:
            dumpDec< sal_uInt8 >( "pane", "PANE-ID" );
            dumpAddress( "active-cell" );
            dumpDec< sal_uInt16 >( "list-idx" );
            dumpRangeList( "selection", false );
        break;

        case BIFF_ID_SHAREDFEATHEAD:
        {
            dumpFrHeader( true, true );
            sal_uInt16 nType = dumpDec< sal_uInt16 >( "feature-type", "SHAREDFEATHEAD-TYPE" );
            dumpUnused( 1 );
            if( dumpBool< sal_Int32 >( "has-data" ) ) switch( nType )
            {
                case 2:
                    dumpHex< sal_uInt32 >( "allowed-flags", "SHAREDFEATHEAD-PROT-FLAGS" );
                break;
            }
        }
        break;

        case BIFF_ID_SHAREDFMLA:
            dumpRange( "formula-range", false );
            dumpUnused( 1 );
            dumpDec< sal_uInt8 >( "cell-count" );
            getFormulaDumper().dumpCellFormula();
        break;

        case BIFF_ID_SHEET:
            if( eBiff >= BIFF5 )
            {
                rStrm.enableDecoder( false );
                dumpHex< sal_uInt32 >( "sheet-stream-pos", "CONV-DEC" );
                rStrm.enableDecoder( true );
                dumpDec< sal_uInt8 >( "sheet-state", "SHEET-STATE" );
                dumpDec< sal_uInt8 >( "sheet-type", "SHEET-TYPE" );
            }
            dumpString( "sheet-name", BIFF_STR_8BITLENGTH, BIFF_STR_8BITLENGTH );
        break;

        case BIFF_ID_SHEETEXT:
            dumpFrHeader( true, true );
            dumpDec< sal_uInt32 >( "rec-size" );
            dumpDec< sal_uInt32 >( "flags-1", "SHEETEXT-FLAGS1" );
            if( rStrm.getRemaining() >= 20 )
            {
                dumpDec< sal_uInt32 >( "flags-2", "SHEETEXT-FLAGS2" );
                dumpExtCfColor( "tab-color" );
            }
        break;

        case BIFF_ID_SHEETHEADER:
            dumpHex< sal_uInt32 >( "substream-size", "CONV-DEC" );
            dumpByteString( "sheet-name", BIFF_STR_8BITLENGTH );
        break;

        case BIFF_ID_SST:
            dumpDec< sal_uInt32 >( "string-cell-count" );
            dumpDec< sal_uInt32 >( "sst-size" );
            mxOut->resetItemIndex();
            while( !rStrm.isEof() && (rStrm.getRemaining() >= 3) )
                dumpUniString( "#entry" );
        break;

        case BIFF2_ID_STRING:
        case BIFF3_ID_STRING:
            dumpString( "result", ((nRecId == BIFF2_ID_STRING) && (eBiff <= BIFF4)) ? BIFF_STR_8BITLENGTH : BIFF_STR_DEFAULT );
        break;

        case BIFF_ID_STYLE:
        {
            sal_uInt16 nFlags = dumpHex< sal_uInt16 >( "flags", "STYLE-FLAGS" );
            if( getFlag( nFlags, BIFF_STYLE_BUILTIN ) )
            {
                dumpDec< sal_Int8 >( "builtin-idx", "STYLE-BUILTIN" );
                dumpDec< sal_Int8 >( "outline-level" );
            }
            else
                dumpString( "style-name", BIFF_STR_8BITLENGTH );
        }
        break;

        case BIFF_ID_STYLEEXT:
            dumpFrHeader( true, true );
            dumpHex< sal_uInt8 >( "flags", "STYLEEXT-FLAGS" );
            dumpDec< sal_uInt8 >( "category", "STYLEEXT-CATEGORY" );
            dumpDec< sal_Int8 >( "builtin-idx", "STYLEEXT-BUILTIN" );
            dumpDec< sal_Int8 >( "outline-level" );
            dumpUnicodeArray( "style-name", rStrm.readuInt16() );
            dumpDxfProp();
        break;

        case BIFF_ID_TABLESTYLES:
        {
            dumpFrHeader( true, true );
            dumpDec< sal_uInt32 >( "table-style-count" );
            sal_uInt16 nDefTableLen, nDefPivotLen;
            rStrm >> nDefTableLen >> nDefPivotLen;
            dumpUnicodeArray( "def-table-style", nDefTableLen );
            dumpUnicodeArray( "def-pivot-style", nDefPivotLen );
        }
        break;

        case BIFF_ID_THEME:
            dumpFrHeader( true, true );
            dumpDec< sal_uInt32 >( "theme-version", "THEME-VERSION" );
        break;

        case BIFF_ID_TXO:
            dumpHex< sal_uInt16 >( "flags", "TXO-FLAGS" );
            dumpDec< sal_uInt16 >( "orientation", "TEXTORIENTATION" );
            dumpHex< sal_uInt16 >( "button-flags", "OBJ-BUTTON-FLAGS" );
            dumpUnicode( "accelerator" );
            dumpUnicode( "fareast-accelerator" );
            dumpDec< sal_uInt16 >( "text-len" );
            dumpDec< sal_uInt16 >( "format-run-size" );
            dumpUnused( 4 );
        break;

        case BIFF_ID_WINDOW1:
            dumpDec< sal_uInt16 >( "window-x", "CONV-TWIP-TO-CM" );
            dumpDec< sal_uInt16 >( "window-y", "CONV-TWIP-TO-CM" );
            dumpDec< sal_uInt16 >( "window-width", "CONV-TWIP-TO-CM" );
            dumpDec< sal_uInt16 >( "window-height", "CONV-TWIP-TO-CM" );
            if( eBiff <= BIFF4 )
            {
                dumpBool< sal_uInt8 >( "hidden" );
            }
            else
            {
                dumpHex< sal_uInt16 >( "flags", "WINDOW1-FLAGS" );
                dumpDec< sal_uInt16 >( "active-tab" );
                dumpDec< sal_uInt16 >( "first-visible-tab" );
                dumpDec< sal_uInt16 >( "selected-tabs" );
                dumpDec< sal_uInt16 >( "tabbar-ratio", "WINDOW1-TABBARRATIO" );
            }
        break;

        case BIFF2_ID_WINDOW2:
            dumpBool< sal_uInt8 >( "show-formulas" );
            dumpBool< sal_uInt8 >( "show-gridlines" );
            dumpBool< sal_uInt8 >( "show-headings" );
            dumpBool< sal_uInt8 >( "frozen-panes" );
            dumpBool< sal_uInt8 >( "show-zeros" );
            dumpAddress( "first-visible-cell" );
            dumpBool< sal_uInt8 >( "auto-grid-color" );
            dumpColorABGR( "grid-color" );
        break;

        case BIFF3_ID_WINDOW2:
            dumpHex< sal_uInt16 >( "flags", "WINDOW2-FLAGS" );
            dumpAddress( "first-visible-cell" );
            if( eBiff == BIFF8 )
            {
                dumpColorIdx( "grid-color-idx" );
                dumpUnused( 2 );
                if( rStrm.getRemaining() >= 8 )
                {
                    dumpDec< sal_uInt16 >( "pagebreak-zoom", "CONV-PERCENT" );
                    dumpDec< sal_uInt16 >( "normal-zoom", "CONV-PERCENT" );
                    dumpUnused( 4 );
                }
            }
            else
                dumpColorABGR( "grid-color" );
        break;

        case BIFF_ID_WRITEACCESS:
            dumpString( "user-name", BIFF_STR_8BITLENGTH );
        break;

        case BIFF_ID_XCT:
            dumpDec< sal_uInt16 >( "crn-count" );
            if( eBiff == BIFF8 ) dumpDec< sal_Int16 >( "sheet-idx" );
        break;

        case BIFF2_ID_XF:
        case BIFF3_ID_XF:
        case BIFF4_ID_XF:
        case BIFF5_ID_XF:
            dumpXfRec();
        break;

        case BIFF_ID_XFCRC:
            dumpFrHeader( true, true );
            dumpUnused( 2 );
            dumpDec< sal_uInt16 >( "xf-count" );
            dumpHex< sal_uInt32 >( "xf-checksum" );
        break;

        case BIFF_ID_XFEXT:
            dumpFrHeader( true, true );
            dumpUnused( 2 );
            dumpXfIdx( "xf-idx" );
            dumpUnused( 2 );
            dumpXfExtProp();
        break;
    }
}

void WorkbookStreamObject::initializePerSheet()
{
    getBiffData().initializePerSheet();
    mxFontNames = cfg().createNameList< ConstList >( "FONTNAMES" );
    mxFontNames->setName( 0, createFontName( CREATE_OUSTRING( "Arial" ), 200, false, false ) );
    mxFormats = cfg().createNameList< ConstList >( "FORMATS" );
    mxFormats->includeList( cfg().getNameList( "BUILTIN-FORMATS" ) );
    mnFormatIdx = 0;
    mbHasCodePage = false;
}

OUString WorkbookStreamObject::createFontName( const OUString& rName, sal_uInt16 nHeight, bool bBold, bool bItalic ) const
{
    OUStringBuffer aName( rName );
    StringHelper::enclose( aName, OOX_DUMP_STRQUOTE );
    StringHelper::appendToken( aName, cfg().getName( "CONV-TWIP-TO-PT", nHeight ), ',' );
    if( bBold )
        StringHelper::appendToken( aName, CREATE_OUSTRING( "bold" ), ',' );
    if( bItalic )
        StringHelper::appendToken( aName, CREATE_OUSTRING( "italic" ), ',' );
    return aName.makeStringAndClear();
}

sal_uInt16 WorkbookStreamObject::dumpPatternIdx( const String& rName, bool b16Bit )
{
    return dumpDec< sal_uInt16, sal_uInt8 >( b16Bit, rName( "fill-pattern" ), mxFillPatterns );
}

sal_uInt16 WorkbookStreamObject::dumpColorIdx( const String& rName, bool b16Bit )
{
    return dumpDec< sal_uInt16, sal_uInt8 >( b16Bit, rName( "color-idx" ), mxColors );
}

sal_uInt16 WorkbookStreamObject::dumpFontIdx( const String& rName, bool b16Bit )
{
    return dumpDec< sal_uInt16, sal_uInt8 >( b16Bit, rName( "font-idx" ), mxFontNames );
}

sal_uInt16 WorkbookStreamObject::dumpFormatIdx( const String& rName )
{
    return dumpDec< sal_uInt16, sal_uInt8 >( getBiff() >= BIFF5, rName( "fmt-idx" ), mxFormats );
}

sal_uInt16 WorkbookStreamObject::dumpXfIdx( const String& rName, bool bBiff2Style )
{
    String aName = rName( "xf-idx" );
    sal_uInt16 nXfIdx = 0;
    if( bBiff2Style )
    {
        dumpHex< sal_uInt8 >( aName, "CELL-XFINDEX" );
        dumpHex< sal_uInt8 >( "fmt-font-idx", "CELL-XFFORMAT" );
        dumpHex< sal_uInt8 >( "style", "CELL-XFSTYLE" );
    }
    else
        nXfIdx = dumpDec< sal_uInt16 >( aName );
    return nXfIdx;
}

void WorkbookStreamObject::dumpExtColorValue( sal_uInt32 nColorType )
{
    switch( nColorType )
    {
        case 0:     dumpUnused( 4 );                                break;
        case 1:     dumpDec< sal_uInt32 >( "color-idx", mxColors ); break;
        case 2:     dumpColorABGR();                                break;
        case 3:     dumpDec< sal_uInt32 >( "theme-id" );            break;
        case 4:     dumpUnused( 4 );                                break;
        default:    dumpUnknown( 4 );
    }
}

void WorkbookStreamObject::dumpExtColor( const String& rName )
{
    MultiItemsGuard aMultiGuard( mxOut );
    writeEmptyItem( rName( "color" ) );
    switch( extractValue< sal_uInt8 >( dumpDec< sal_uInt8 >( "flags", "EXTCOLOR-FLAGS" ), 1, 7 ) )
    {
        case 0:     dumpUnused( 1 );                    break;
        case 1:     dumpColorIdx( "color-idx", false ); break;
        case 2:     dumpUnused( 1 );                    break;
        case 3:     dumpDec< sal_uInt8 >( "theme-id" ); break;
        case 4:     dumpUnused( 1 );                    break;
        default:    dumpUnknown( 1 );
    }
    dumpDec< sal_Int16 >( "tint", "CONV-TINT" );
    dumpColorABGR();
}

void WorkbookStreamObject::dumpExtCfColor( const String& rName )
{
    MultiItemsGuard aMultiGuard( mxOut );
    writeEmptyItem( rName( "color" ) );
    dumpExtColorValue( dumpExtColorType< sal_uInt32 >() );
    dumpDec< double >( "tint", "CONV-FLOAT-TO-PERC" );
}

void WorkbookStreamObject::dumpExtGradientHead()
{
    dumpDec< sal_Int32 >( "gradient-type", "EXTGRADIENT-TYPE" );
    dumpDec< double >( "linear-angle" );
    dumpDec< double >( "pos-left" );
    dumpDec< double >( "pos-right" );
    dumpDec< double >( "pos-top" );
    dumpDec< double >( "pos-bottom" );
}

sal_uInt8 WorkbookStreamObject::dumpFilterColumnOperator( const String& rName )
{
    sal_uInt8 nStrLen = 0;
    writeEmptyItem( rName );
    IndentGuard aIndGuard( mxOut );
    sal_uInt8 nType = dumpDec< sal_uInt8 >( "data-type", "FILTERCOLUMN-DATATYPE" );
    dumpDec< sal_uInt8 >( "operator", "FILTERCOLUMN-OPERATOR" );
    switch( nType )
    {
        case 2:
            dumpRk( "value" );
            dumpUnused( 4 );
        break;
        case 4:
            dumpDec< double >( "value" );
        break;
        case 6:
            dumpUnused( 4 );
            nStrLen = dumpDec< sal_uInt8 >( "length" );
            dumpBoolean( "simple" );
            dumpUnused( 2 );
        break;
        case 8:
            dumpBoolErr();
            dumpUnused( 6 );
        break;
        default:
            dumpUnused( 8 );
    }
    return nStrLen;
}

OUString WorkbookStreamObject::dumpPivotString( const String& rName, sal_uInt16 nStrLen )
{
    OUString aString;
    if( nStrLen != BIFF_PT_NOSTRING )
    {
        aString = (getBiff() == BIFF8) ?
            getBiffStream().readUniStringBody( nStrLen ) :
            getBiffStream().readCharArrayUC( nStrLen, getBiffData().getTextEncoding() );
        writeStringItem( rName, aString );
    }
    return aString;
}

OUString WorkbookStreamObject::dumpPivotString( const String& rName )
{
    sal_uInt16 nStrLen = dumpDec< sal_uInt16 >( "string-len", "PIVOT-NAMELEN" );
    return dumpPivotString( rName, nStrLen );
}

sal_uInt16 WorkbookStreamObject::dumpCellHeader( bool bBiff2Style )
{
    dumpAddress();
    return dumpXfIdx( EMPTY_STRING, bBiff2Style );
}

void WorkbookStreamObject::dumpBoolErr()
{
    MultiItemsGuard aMultiGuard( mxOut );
    sal_uInt8 nValue = dumpHex< sal_uInt8 >( "value" );
    bool bErrCode = dumpBool< sal_uInt8 >( "is-error-code" );
    if( bErrCode )
        writeErrorCodeItem( "error-code", nValue );
    else
        writeBooleanItem( "boolean", nValue );
}

void WorkbookStreamObject::dumpCfRuleProp()
{
    BiffInputStream& rStrm = getBiffStream();
    sal_uInt32 nFlags1 = dumpHex< sal_uInt32 >( "flags-1", "CFRULE-FLAGS1" );
    sal_uInt16 nFlags2 = dumpHex< sal_uInt16 >( "flags-2", "CFRULE-FLAGS2" );
    if( getFlag< sal_uInt32 >( nFlags1, 0x02000000 ) )
    {
        writeEmptyItem( "numfmt-block" );
        IndentGuard aIndGuard( mxOut );
        if( getFlag< sal_uInt16 >( nFlags2, 0x0001 ) )
        {
            dumpDec< sal_uInt16 >( "size" );
            dumpUniString( "numfmt" );
        }
        else
        {
            dumpUnused( 1 );
            dumpDec< sal_uInt8 >( "fmt-idx", mxFormats );
        }
    }
    if( getFlag< sal_uInt32 >( nFlags1, 0x04000000 ) )
    {
        writeEmptyItem( "font-block" );
        IndentGuard aIndGuard( mxOut );
        sal_Int64 nRecPos = rStrm.tell();
        dumpUniString( "name", BIFF_STR_8BITLENGTH );
        dumpUnused( static_cast< sal_Int32 >( nRecPos + 64 - rStrm.tell() ) );
        dumpDec< sal_Int32 >( "height", "CONV-TWIP-TO-PT" );
        dumpHex< sal_uInt32 >( "flags", "CFRULE-FONTFLAGS" );
        dumpDec< sal_Int16 >( "weight", "CFRULE-FONTWEIGHT" );
        dumpDec< sal_Int16 >( "escapement", "CFRULE-FONTESCAPEMENT" );
        dumpDec< sal_Int8 >( "underline", "CFRULE-FONTUNDERLINE" );
        dumpDec< sal_uInt8 >( "family", "FONT-FAMILY" );
        dumpDec< sal_uInt8 >( "charset", "CHARSET" );
        dumpUnused( 1 );
        dumpDec< sal_Int32 >( "color", "CFRULE-FONTCOLOR" );
        dumpUnused( 4 );
        dumpHex< sal_uInt32 >( "used-flags", "CFRULE-FONTUSEDFLAGS" );
        dumpDec< sal_uInt32 >( "escapement-used", "CFRULE-FONTUSED" );
        dumpDec< sal_uInt32 >( "underline-used", "CFRULE-FONTUSED" );
        dumpDec< sal_uInt32 >( "weight-used", "CFRULE-FONTUSED" );
        dumpUnused( 4 );
        dumpDec< sal_Int32 >( "first-char" );
        dumpDec< sal_Int32 >( "char-count" );
        dumpDec< sal_uInt16 >( "font-idx" );
    }
    if( getFlag< sal_uInt32 >( nFlags1, 0x08000000 ) )
    {
        writeEmptyItem( "alignment-block" );
        IndentGuard aIndGuard( mxOut );
        dumpHex< sal_uInt8 >( "alignent", "CFRULE-ALIGNMENT" );
        dumpHex< sal_uInt8 >( "rotation", "TEXTROTATION" );
        dumpHex< sal_uInt16 >( "indent", "CFRULE-INDENT" );
        dumpDec< sal_Int32 >( "relative-indent" );
    }
    if( getFlag< sal_uInt32 >( nFlags1, 0x10000000 ) )
    {
        writeEmptyItem( "border-block" );
        IndentGuard aIndGuard( mxOut );
        dumpHex< sal_uInt16 >( "border-style", "XF-BORDERSTYLE" );
        dumpHex< sal_uInt16 >( "border-color1", "XF-BORDERCOLOR1" );
        dumpHex< sal_uInt32 >( "border-color2", "CFRULE-BORDERCOLOR2" );
    }
    if( getFlag< sal_uInt32 >( nFlags1, 0x20000000 ) )
    {
        writeEmptyItem( "pattern-block" );
        IndentGuard aIndGuard( mxOut );
        dumpHex< sal_uInt32 >( "pattern", "CFRULE-FILLBLOCK" );
    }
    if( getFlag< sal_uInt32 >( nFlags1, 0x40000000 ) )
    {
        writeEmptyItem( "protection-block" );
        IndentGuard aIndGuard( mxOut );
        dumpHex< sal_uInt16 >( "flags", "CFRULE-PROTECTION-FLAGS" );
    }
}

void WorkbookStreamObject::dumpXfExtProp()
{
    BiffInputStream& rStrm = getBiffStream();
    for( sal_uInt16 nIndex = 0, nCount = dumpDec< sal_uInt16 >( "subrec-count" ); !rStrm.isEof() && (nIndex < nCount); ++nIndex )
    {
        mxOut->startMultiItems();
        sal_Int64 nStartPos = rStrm.tell();
        writeEmptyItem( "SUBREC" );
        sal_uInt16 nSubRecId = dumpDec< sal_uInt16 >( "id", "XFEXT-SUBREC" );
        sal_uInt16 nSubRecSize = dumpDec< sal_uInt16 >( "size" );
        sal_Int64 nEndPos = nStartPos + nSubRecSize;
        mxOut->endMultiItems();
        IndentGuard aIndGuard( mxOut );
        switch( nSubRecId )
        {
            case 4: case 5: case 7: case 8: case 9: case 10: case 11: case 13:
            {
                sal_uInt16 nColorType = dumpExtColorType< sal_uInt16 >();
                dumpDec< sal_Int16 >( "tint", "CONV-TINT" );
                dumpExtColorValue( nColorType );
                dumpUnused( 8 );
            }
            break;
            case 6:
                dumpExtGradientHead();
                mxOut->resetItemIndex();
                for( sal_Int32 nStop = 0, nStopCount = dumpDec< sal_Int32 >( "stop-count" ); (nStop < nStopCount) && !mxStrm->isEof(); ++nStop )
                {
                    writeEmptyItem( "#stop" );
                    IndentGuard aIndGuard2( mxOut );
                    sal_uInt16 nColorType = dumpExtColorType< sal_uInt16 >();
                    dumpExtColorValue( nColorType );
                    dumpDec< double >( "stop-pos" );
                    dumpDec< double >( "tint", "CONV-FLOAT-TO-PERC" );
                }
            break;
            case 14:
                dumpDec< sal_Int8 >( "font-scheme", "EXTFONT-SCHEME" );
            break;
            case 15:
                dumpDec< sal_uInt16 >( "indent" );
            break;
        }
        dumpRemainingTo( nEndPos );
    }
}

void WorkbookStreamObject::dumpDxfProp()
{
    BiffInputStream& rStrm = getBiffStream();
    dumpUnused( 2 );
    for( sal_uInt16 nIndex = 0, nCount = dumpDec< sal_uInt16 >( "subrec-count" ); !rStrm.isEof() && (nIndex < nCount); ++nIndex )
    {
        mxOut->startMultiItems();
        sal_Int64 nStartPos = rStrm.tell();
        writeEmptyItem( "SUBREC" );
        sal_uInt16 nSubRecId = dumpDec< sal_uInt16 >( "id", "DXF-SUBREC" );
        sal_uInt16 nSubRecSize = dumpDec< sal_uInt16 >( "size" );
        sal_Int64 nEndPos = nStartPos + nSubRecSize;
        mxOut->endMultiItems();
        IndentGuard aIndGuard( mxOut );
        switch( nSubRecId )
        {
            case 0:
                dumpDec< sal_uInt8 >( "pattern", mxFillPatterns );
            break;
            case 1: case 2: case 5:
                dumpExtColor();
            break;
            case 3:
                dumpExtGradientHead();
            break;
            case 4:
                dumpDec< sal_uInt16 >( "index" );
                dumpDec< double >( "stop-position" );
                dumpExtColor( "stop-color" );
            break;
            case 6: case 7: case 8: case 9: case 10: case 11: case 12:
                dumpExtColor( "color" );
                dumpDec< sal_uInt16 >( "style", mxBorderStyles );
            break;
            case 13: case 14:
                dumpBoolean( "value" );
            break;
            case 15:
                dumpDec< sal_uInt8 >( "alignment", "XF-HORALIGN" );
            break;
            case 16:
                dumpDec< sal_uInt8 >( "alignment", "XF-VERALIGN" );
            break;
            case 17:
                dumpDec< sal_uInt8 >( "rotation", "TEXTROTATION" );
            break;
            case 18:
                dumpDec< sal_uInt16 >( "indent" );
            break;
            case 19:
                dumpDec< sal_uInt8 >( "text-dir", "XF-TEXTDIRECTION" );
            break;
            case 20: case 21: case 22: case 23:
                dumpBoolean( "value" );
            break;
            case 24:
                dumpUnicodeArray( "name", rStrm.readuInt16() );
            break;
            case 25:
                dumpDec< sal_uInt16 >( "weight", "FONT-WEIGHT" );
            break;
            case 26:
                dumpDec< sal_uInt16 >( "underline", "FONT-UNDERLINE" );
            break;
            case 27:
                dumpDec< sal_uInt16 >( "escapement", "FONT-ESCAPEMENT" );
            break;
            case 28: case 29: case 30: case 31: case 32: case 33:
                dumpBoolean( "value" );
            break;
            case 34:
                dumpDec< sal_uInt8 >( "charset", "CHARSET" );
            break;
            case 35:
                dumpDec< sal_uInt8 >( "family", "FONT-FAMILY" );
            break;
            case 36:
                dumpDec< sal_Int32 >( "height", "CONV-TWIP-TO-PT" );
            break;
            case 37:
                dumpDec< sal_uInt8 >( "scheme", "EXTFONT-SCHEME" );
            break;
            case 38:
                dumpUnicodeArray( "numfmt", rStrm.readuInt16() );
            break;
            case 41:
                dumpDec< sal_uInt16 >( "fmt-idx", mxFormats );
            break;
            case 42:
                dumpDec< sal_Int16 >( "relative-indent" );
            break;
            case 43: case 44:
                dumpBoolean( "value" );
            break;
        }
        dumpRemainingTo( nEndPos );
    }
}

void WorkbookStreamObject::dumpDxf12Prop()
{
    BiffInputStream& rStrm = getBiffStream();
    writeEmptyItem( "dxf-data" );
    IndentGuard aIndGuard( mxOut );
    sal_uInt32 nSize = dumpDec< sal_uInt32 >( "dxf-size" );
    if( nSize == 0 )
    {
        dumpUnused( 2 );
    }
    else
    {
        sal_Int64 nEndPos = rStrm.tell() + nSize;
        dumpCfRuleProp();
        if( rStrm.tell() + 8 <= nEndPos )
        {
            dumpUnused( 6 );
            dumpXfExtProp();
        }
        dumpRemainingTo( nEndPos );
    }
}

void WorkbookStreamObject::dumpCfRule12Param( sal_uInt16 nSubType )
{
    sal_uInt8 nSize = dumpDec< sal_uInt8 >( "params-size" );
    sal_Int64 nEndPos = getBiffStream().tell() + nSize;
    {
        writeEmptyItem( "params" );
        IndentGuard aIndGuard( mxOut );
        switch( nSubType )
        {
            case 5:
                dumpHex< sal_uInt8 >( "flags", "CFRULE12-TOP10-FLAGS" );
                dumpDec< sal_uInt16 >( "rank" );
                dumpUnused( 13 );
            break;
            case 8:
                dumpDec< sal_uInt16 >( "operator", "CFRULE12-TEXT-OPERATOR" );
                dumpUnused( 14 );
            break;
            case 15: case 16: case 17: case 18: case 19: case 20: case 21: case 22: case 23: case 24:
                dumpDec< sal_uInt16 >( "operator", "CFRULE12-DATE-OPERATOR" );
                dumpUnused( 14 );
            break;
            case 25: case 26: case 29: case 30:
                dumpDec< sal_uInt16 >( "std-dev" );
                dumpUnused( 14 );
            break;
            default:
                dumpUnused( 16 );
        }
    }
    dumpRemainingTo( nEndPos );
}

void WorkbookStreamObject::dumpFontRec()
{
    sal_uInt16 nFontId = getBiffData().getFontCount();
    mxOut->resetItemIndex( nFontId );
    writeEmptyItem( "#font" );
    sal_uInt16 nHeight = dumpDec< sal_uInt16 >( "height", "CONV-TWIP-TO-PT" );
    sal_uInt16 nFlags = dumpHex< sal_uInt16 >( "flags", "FONT-FLAGS" );
    bool bBold = getFlag( nFlags, BIFF_FONTFLAG_BOLD );
    bool bItalic = getFlag( nFlags, BIFF_FONTFLAG_ITALIC );
    rtl_TextEncoding eFontEnc = RTL_TEXTENCODING_DONTKNOW;
    if( getBiff() >= BIFF3 )
        dumpColorIdx();
    if( getBiff() >= BIFF5 )
    {
        bBold = dumpDec< sal_uInt16 >( "weight", "FONT-WEIGHT" ) > 450;
        dumpDec< sal_uInt16 >( "escapement", "FONT-ESCAPEMENT" );
        dumpDec< sal_uInt8 >( "underline", "FONT-UNDERLINE" );
        dumpDec< sal_uInt8 >( "family", "FONT-FAMILY" );
        sal_uInt8 nCharSet = dumpDec< sal_uInt8 >( "charset", "CHARSET" );
        eFontEnc = rtl_getTextEncodingFromWindowsCharset( nCharSet );
        dumpUnused( 1 );
    }
    OUString aName = dumpString( "name", BIFF_STR_8BITLENGTH, BIFF_STR_8BITLENGTH );

    // append font data to vector
    mxFontNames->setName( nFontId, createFontName( aName, nHeight, bBold, bItalic ) );

    // store font encoding
    getBiffData().appendFontEncoding( eFontEnc );

    // set font encoding as default text encoding in case of missing CODEPAGE record
    if( !mbHasCodePage && (nFontId == 0) )
        getBiffData().setTextEncoding( eFontEnc );
}

void WorkbookStreamObject::dumpFormatRec()
{
    sal_uInt16 nFormatIdx = 0;
    switch( getBiff() )
    {
        case BIFF2:
        case BIFF3:
            nFormatIdx = mnFormatIdx++;
            mxOut->resetItemIndex( nFormatIdx );
            writeEmptyItem( "#fmt" );
        break;
        case BIFF4:
            nFormatIdx = mnFormatIdx++;
            mxOut->resetItemIndex( nFormatIdx );
            writeEmptyItem( "#fmt" );
            dumpUnused( 2 );
        break;
        case BIFF5:
        case BIFF8:
            getBiffStream() >> nFormatIdx;
            mxOut->resetItemIndex( nFormatIdx );
            writeEmptyItem( "#fmt" );
            writeDecItem( "fmt-idx", nFormatIdx );
        break;
        case BIFF_UNKNOWN: break;
    }
    OUString aFormat = dumpString( "format", BIFF_STR_8BITLENGTH );
    mxFormats->setName( nFormatIdx, aFormat );
}

void WorkbookStreamObject::dumpXfRec()
{
    sal_uInt16 nXfId = getBiffData().getXfCount();
    mxOut->resetItemIndex( nXfId );
    writeEmptyItem( "#xf" );
    sal_uInt16 nFontId = dumpFontIdx( EMPTY_STRING, getBiff() >= BIFF5 );
    switch( getBiff() )
    {
        case BIFF2:
            dumpUnused( 1 );
            dumpHex< sal_uInt8 >( "type-flags", "XF-TYPEFLAGS" );
            dumpHex< sal_uInt8 >( "style-flags", "XF-STYLEFLAGS" );
        break;
        case BIFF3:
            dumpFormatIdx();
            dumpHex< sal_uInt8 >( "type-flags", "XF-TYPEFLAGS" );
            dumpHex< sal_uInt8 >( "used-attributes", "XF-USEDATTRIBS-FLAGS" );
            dumpHex< sal_uInt16 >( "alignment", "XF-ALIGNMENT" );
            dumpHex< sal_uInt16 >( "fill-style", "XF-FILL" );
            dumpHex< sal_uInt32 >( "border-style", "XF-BORDER" );
        break;
        case BIFF4:
            dumpFormatIdx();
            dumpHex< sal_uInt16 >( "type-flags", "XF-TYPEFLAGS" );
            dumpHex< sal_uInt8 >( "alignment", "XF-ALIGNMENT" );
            dumpHex< sal_uInt8 >( "used-attributes", "XF-USEDATTRIBS-FLAGS" );
            dumpHex< sal_uInt16 >( "fill-style", "XF-FILL" );
            dumpHex< sal_uInt32 >( "border-style", "XF-BORDER" );
        break;
        case BIFF5:
            dumpFormatIdx();
            dumpHex< sal_uInt16 >( "type-flags", "XF-TYPEFLAGS" );
            dumpHex< sal_uInt8 >( "alignment", "XF-ALIGNMENT" );
            dumpHex< sal_uInt8 >( "orientation", "XF-ORIENTATTRIBS" );
            dumpHex< sal_uInt32 >( "fill-style", "XF-FILL" );
            dumpHex< sal_uInt32 >( "border-style", "XF-BORDER" );
        break;
        case BIFF8:
            dumpFormatIdx();
            dumpHex< sal_uInt16 >( "type-flags", "XF-TYPEFLAGS" );
            dumpHex< sal_uInt8 >( "alignment", "XF-ALIGNMENT" );
            dumpDec< sal_uInt8 >( "rotation", "TEXTROTATION" );
            dumpHex< sal_uInt8 >( "text-flags", "XF-TEXTFLAGS" );
            dumpHex< sal_uInt8 >( "used-attributes", "XF-USEDATTRIBS-FLAGS" );
            dumpHex< sal_uInt16 >( "border-style", "XF-BORDERSTYLE" );
            dumpHex< sal_uInt16 >( "border-color1", "XF-BORDERCOLOR1" );
            dumpHex< sal_uInt32 >( "border-color2", "XF-BORDERCOLOR2" );
            dumpHex< sal_uInt16 >( "fill-color", "XF-FILLCOLOR" );
        break;
        case BIFF_UNKNOWN: break;
    }
    getBiffData().appendXfFontId( nFontId );
}

void WorkbookStreamObject::dumpObjRec()
{
    switch( getBiff() )
    {
        case BIFF3:
            dumpObjRecBiff3();
        break;
        case BIFF4:
            dumpObjRecBiff4();
        break;
        case BIFF5:
            dumpObjRecBiff5();
        break;
        case BIFF8:
            // #i61786# OBJ records without DFF stream are in BIFF5 format
            if( mbHasDff ) dumpObjRecBiff8(); else dumpObjRecBiff5();
        break;
        default:;
    }
}

void WorkbookStreamObject::dumpObjRecBiff3()
{
    dumpDec< sal_uInt32 >( "obj-count" );
    sal_uInt16 nObjType = dumpDec< sal_uInt16 >( "obj-type", "OBJ-TYPE" );
    dumpDec< sal_uInt16 >( "obj-id" );
    dumpHex< sal_uInt16 >( "flags", "OBJ-FLAGS" );
    dumpDffClientRect();
    sal_uInt16 nMacroSize = dumpDec< sal_uInt16 >( "macro-size" );
    dumpUnused( 2 );
    sal_uInt16 nTextLen = 0, nFormatSize = 0, nLinkSize = 0;
    switch( nObjType )
    {
        case BIFF_OBJTYPE_GROUP:
            dumpUnused( 4 );
            dumpDec< sal_uInt16 >( "next-ungrouped-id" );
            dumpUnused( 16 );
            dumpObjRecString( "macro", nMacroSize, true );
        break;
        case BIFF_OBJTYPE_LINE:
            dumpObjRecLineData();
            dumpHex< sal_uInt16 >( "line-end", "OBJ-LINEENDS" );
            dumpDec< sal_uInt8 >( "line-direction", "OBJ-LINEDIR" );
            dumpUnused( 1 );
            dumpObjRecString( "macro", nMacroSize, true );
        break;
        case BIFF_OBJTYPE_RECTANGLE:
        case BIFF_OBJTYPE_OVAL:
            dumpObjRecRectData();
            dumpObjRecString( "macro", nMacroSize, true );
        break;
        case BIFF_OBJTYPE_ARC:
            dumpObjRecFillData();
            dumpObjRecLineData();
            dumpDec< sal_uInt8 >( "quadrant", "OBJ-ARC-QUADRANT" );
            dumpUnused( 1 );
            dumpObjRecString( "macro", nMacroSize, true );
        break;
        case BIFF_OBJTYPE_CHART:
            dumpObjRecRectData();
            dumpUnused( 18 );
            dumpObjRecString( "macro", nMacroSize, true );
        break;
        case BIFF_OBJTYPE_TEXT:
        case BIFF_OBJTYPE_BUTTON:
            dumpObjRecRectData();
            dumpObjRecTextDataBiff3( nTextLen, nFormatSize );
            dumpObjRecString( "macro", nMacroSize, true );
            dumpObjRecString( "text", nTextLen, false );
            dumpObjRecTextFmt( nFormatSize );
        break;
        case BIFF_OBJTYPE_PICTURE:
            dumpObjRecRectData();
            dumpDec< sal_Int16 >( "image-format", "IMGDATA-FORMAT" );
            dumpUnused( 4 );
            nLinkSize = dumpDec< sal_uInt16 >( "pic-link-size" );
            dumpUnused( 2 );
            dumpHex< sal_uInt16 >( "flags", "OBJ-PICTURE-FLAGS" );
            dumpObjRecString( "macro", nMacroSize, true );
            dumpObjRecPictFmla( nLinkSize );
        break;
    }
}

void WorkbookStreamObject::dumpObjRecBiff4()
{
    dumpDec< sal_uInt32 >( "obj-count" );
    sal_uInt16 nObjType = dumpDec< sal_uInt16 >( "obj-type", "OBJ-TYPE" );
    dumpDec< sal_uInt16 >( "obj-id" );
    dumpHex< sal_uInt16 >( "flags", "OBJ-FLAGS" );
    dumpDffClientRect();
    sal_uInt16 nMacroSize = dumpDec< sal_uInt16 >( "macro-size" );
    dumpUnused( 2 );
    sal_uInt16 nTextLen = 0, nFormatSize = 0, nLinkSize = 0;
    switch( nObjType )
    {
        case BIFF_OBJTYPE_GROUP:
            dumpUnused( 4 );
            dumpDec< sal_uInt16 >( "next-ungrouped-id" );
            dumpUnused( 16 );
            dumpObjRecFmla( "macro", nMacroSize );
        break;
        case BIFF_OBJTYPE_LINE:
            dumpObjRecLineData();
            dumpHex< sal_uInt16 >( "line-end", "OBJ-LINEENDS" );
            dumpDec< sal_uInt8 >( "line-direction", "OBJ-LINEDIR" );
            dumpUnused( 1 );
            dumpObjRecFmla( "macro", nMacroSize );
        break;
        case BIFF_OBJTYPE_RECTANGLE:
        case BIFF_OBJTYPE_OVAL:
            dumpObjRecRectData();
            dumpObjRecFmla( "macro", nMacroSize );
        break;
        case BIFF_OBJTYPE_ARC:
            dumpObjRecFillData();
            dumpObjRecLineData();
            dumpDec< sal_uInt8 >( "quadrant", "OBJ-ARC-QUADRANT" );
            dumpUnused( 1 );
            dumpObjRecFmla( "macro", nMacroSize );
        break;
        case BIFF_OBJTYPE_CHART:
            dumpObjRecRectData();
            dumpUnused( 18 );
            dumpObjRecFmla( "macro", nMacroSize );
        break;
        case BIFF_OBJTYPE_TEXT:
        case BIFF_OBJTYPE_BUTTON:
            dumpObjRecRectData();
            dumpObjRecTextDataBiff3( nTextLen, nFormatSize );
            dumpObjRecFmla( "macro", nMacroSize );
            dumpObjRecString( "text", nTextLen, false );
            dumpObjRecTextFmt( nFormatSize );
        break;
        case BIFF_OBJTYPE_PICTURE:
            dumpObjRecRectData();
            dumpDec< sal_Int16 >( "image-format", "IMGDATA-FORMAT" );
            dumpUnused( 4 );
            nLinkSize = dumpDec< sal_uInt16 >( "pic-link-size" );
            dumpUnused( 2 );
            dumpHex< sal_uInt16 >( "flags", "OBJ-PICTURE-FLAGS" );
            dumpObjRecFmla( "macro", nMacroSize );
            dumpObjRecPictFmla( nLinkSize );
        break;
        case BIFF_OBJTYPE_POLYGON:
            dumpObjRecRectData();
            dumpHex< sal_uInt16 >( "flags", "OBJ-POLYGON-FLAGS" );
            dumpUnused( 10 );
            dumpDec< sal_uInt16 >( "point-count" );
            dumpUnused( 8 );
            dumpObjRecFmla( "macro", nMacroSize );
        break;
    }
}

void WorkbookStreamObject::dumpObjRecBiff5()
{
    BiffInputStream& rStrm = getBiffStream();
    dumpDec< sal_uInt32 >( "obj-count" );
    sal_uInt16 nObjType = dumpDec< sal_uInt16 >( "obj-type", "OBJ-TYPE" );
    dumpDec< sal_uInt16 >( "obj-id" );
    dumpHex< sal_uInt16 >( "flags", "OBJ-FLAGS" );
    dumpDffClientRect();
    sal_uInt16 nMacroSize = dumpDec< sal_uInt16 >( "macro-size" );
    dumpUnused( 2 );
    sal_uInt16 nNameLen = dumpDec< sal_uInt16 >( "name-len" );
    dumpUnused( 2 );
    sal_uInt16 nTextLen = 0, nFormatSize = 0, nLinkSize = 0;
    switch( nObjType )
    {
        case BIFF_OBJTYPE_GROUP:
            dumpUnused( 4 );
            dumpDec< sal_uInt16 >( "next-ungrouped-id" );
            dumpUnused( 16 );
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", nMacroSize );
        break;
        case BIFF_OBJTYPE_LINE:
            dumpObjRecLineData();
            dumpHex< sal_uInt16 >( "line-end", "OBJ-LINEENDS" );
            dumpDec< sal_uInt8 >( "line-direction", "OBJ-LINEDIR" );
            dumpUnused( 1 );
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", nMacroSize );
        break;
        case BIFF_OBJTYPE_RECTANGLE:
        case BIFF_OBJTYPE_OVAL:
            dumpObjRecRectData();
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", nMacroSize );
        break;
        case BIFF_OBJTYPE_ARC:
            dumpObjRecFillData();
            dumpObjRecLineData();
            dumpDec< sal_uInt8 >( "quadrant", "OBJ-ARC-QUADRANT" );
            dumpUnused( 1 );
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", nMacroSize );
        break;
        case BIFF_OBJTYPE_CHART:
            dumpObjRecRectData();
            dumpHex< sal_uInt16 >( "chart-flags", "OBJ-CHART-FLAGS" );
            dumpUnused( 16 );
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", nMacroSize );
        break;
        case BIFF_OBJTYPE_TEXT:
        case BIFF_OBJTYPE_BUTTON:
        case BIFF_OBJTYPE_LABEL:
        case BIFF_OBJTYPE_DIALOG:
            dumpObjRecRectData();
            dumpObjRecTextDataBiff5( nTextLen, nFormatSize, nLinkSize );
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", nMacroSize );
            dumpObjRecString( "text", nTextLen, false );
            dumpObjRecFmla( "text-link", nLinkSize );
            dumpObjRecTextFmt( nFormatSize );
        break;
        case BIFF_OBJTYPE_PICTURE:
            dumpObjRecRectData();
            dumpDec< sal_Int16 >( "image-format", "IMGDATA-FORMAT" );
            dumpUnused( 4 );
            nLinkSize = dumpDec< sal_uInt16 >( "pic-link-size" );
            dumpUnused( 2 );
            dumpHex< sal_uInt16 >( "flags", "OBJ-PICTURE-FLAGS" );
            dumpUnused( 4 );
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", nMacroSize );
            dumpObjRecPictFmla( nLinkSize );
            if( rStrm.getRemaining() >= 4 )
                dumpHex< sal_uInt32 >( "ole-storage-id" );
        break;
        case BIFF_OBJTYPE_POLYGON:
            dumpObjRecRectData();
            dumpHex< sal_uInt16 >( "flags", "OBJ-POLYGON-FLAGS" );
            dumpUnused( 10 );
            dumpDec< sal_uInt16 >( "point-count" );
            dumpUnused( 8 );
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", nMacroSize );
        break;
        case BIFF_OBJTYPE_CHECKBOX:
            dumpObjRecRectData();
            dumpUnused( 10 );
            dumpHex< sal_uInt16 >( "flags", "OBJ-TEXT-FLAGS" );
            dumpUnused( 20 );
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", dumpDec< sal_uInt16 >( "macro-size" ) );
            dumpObjRecFmla( "cell-link", dumpDec< sal_uInt16 >( "cell-link-size" ) );
            dumpObjRecString( "text", dumpDec< sal_uInt16 >( "text-len" ), false );
            dumpObjRecCblsData();
        break;
        case BIFF_OBJTYPE_OPTIONBUTTON:
            dumpObjRecRectData();
            dumpUnused( 10 );
            dumpHex< sal_uInt16 >( "flags", "OBJ-TEXT-FLAGS" );
            dumpUnused( 32 );
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", dumpDec< sal_uInt16 >( "macro-size" ) );
            dumpObjRecFmla( "cell-link", dumpDec< sal_uInt16 >( "cell-link-size" ) );
            dumpObjRecString( "text", dumpDec< sal_uInt16 >( "text-len" ), false );
            dumpObjRecCblsData();
            dumpObjRecRboData();
        break;
        case BIFF_OBJTYPE_EDIT:
            dumpObjRecRectData();
            dumpUnused( 10 );
            dumpHex< sal_uInt16 >( "flags", "OBJ-TEXT-FLAGS" );
            dumpUnused( 14 );
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", dumpDec< sal_uInt16 >( "macro-size" ) );
            dumpObjRecString( "text", dumpDec< sal_uInt16 >( "text-len" ), false );
            dumpObjRecEdoData();
        break;
        case BIFF_OBJTYPE_SPIN:
        case BIFF_OBJTYPE_SCROLLBAR:
            dumpObjRecRectData();
            dumpObjRecSbsData();
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", dumpDec< sal_uInt16 >( "macro-size" ) );
            dumpObjRecFmla( "cell-link", dumpDec< sal_uInt16 >( "cell-link-size" ) );
        break;
        case BIFF_OBJTYPE_LISTBOX:
            dumpObjRecRectData();
            dumpObjRecSbsData();
            dumpUnused( 18 );
            dumpFontIdx( "font-idx" );
            dumpUnused( 4 );
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", dumpDec< sal_uInt16 >( "macro-size" ) );
            dumpObjRecFmla( "cell-link", dumpDec< sal_uInt16 >( "cell-link-size" ) );
            dumpObjRecLbsData();
        break;
        case BIFF_OBJTYPE_GROUPBOX:
            dumpObjRecRectData();
            dumpUnused( 10 );
            dumpHex< sal_uInt16 >( "flags", "OBJ-TEXT-FLAGS" );
            dumpUnused( 26 );
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", dumpDec< sal_uInt16 >( "macro-size" ) );
            dumpObjRecString( "text", dumpDec< sal_uInt16 >( "text-len" ), false );
            dumpObjRecGboData();
        break;
        case BIFF_OBJTYPE_DROPDOWN:
            dumpObjRecRectData();
            dumpObjRecSbsData();
            dumpUnused( 18 );
            dumpFontIdx( "font-idx" );
            dumpUnused( 14 );
            dumpDec< sal_uInt16 >( "bounding-left" );
            dumpDec< sal_uInt16 >( "bounding-top" );
            dumpDec< sal_uInt16 >( "bounding-right" );
            dumpDec< sal_uInt16 >( "bounding-bottom" );
            dumpUnused( 4 );
            dumpObjRecString( "obj-name", nNameLen, true );
            dumpObjRecFmla( "macro", dumpDec< sal_uInt16 >( "macro-size" ) );
            dumpObjRecFmla( "cell-link", dumpDec< sal_uInt16 >( "cell-link-size" ) );
            dumpObjRecLbsData();
            dumpDec< sal_uInt16 >( "type", "OBJ-DROPDOWN-TYPE" );
            dumpDec< sal_uInt16 >( "line-count" );
            dumpDec< sal_uInt16 >( "min-list-width" );
            dumpObjRecString( "text", dumpDec< sal_uInt16 >( "text-len" ), false );
        break;
    }
}

void WorkbookStreamObject::dumpObjRecBiff8()
{
    BiffInputStream& rStrm = getBiffStream();
    NameListRef xRecNames = cfg().getNameList( "OBJ-RECNAMES" );
    sal_uInt16 nObjType = 0xFFFF;
    bool bControl = false;
    bool bCtlsStrm = false;
    bool bLoop = true;
    while( bLoop && (rStrm.getRemaining() >= 4) )
    {
        mxOut->emptyLine();
        sal_uInt16 nSubRecId, nSubRecSize;
        {
            MultiItemsGuard aMultiGuard( mxOut );
            writeEmptyItem( "OBJREC" );
            writeHexItem( "pos", static_cast< sal_uInt32 >( rStrm.tell() ) );
            rStrm >> nSubRecId >> nSubRecSize;
            writeHexItem( "size", nSubRecSize );
            writeHexItem( "id", nSubRecId, xRecNames );
        }

        sal_Int64 nSubRecStart = rStrm.tell();
        // sometimes the last subrecord has an invalid length
        sal_Int64 nRealRecSize = ::std::min< sal_Int64 >( nSubRecSize, rStrm.getRemaining() );
        sal_Int64 nSubRecEnd = nSubRecStart + nRealRecSize;

        IndentGuard aIndGuard( mxOut );
        switch( nSubRecId )
        {
            case BIFF_ID_OBJMACRO:
                dumpObjRecFmlaRaw();
            break;
            case BIFF_ID_OBJCF:
                dumpDec< sal_Int16 >( "clipboard-format", "IMGDATA-FORMAT" );
            break;
            case BIFF_ID_OBJFLAGS:
            {
                sal_uInt16 nFlags = dumpHex< sal_uInt16 >( "flags", "OBJFLAGS-FLAGS" );
                bControl = getFlag( nFlags, BIFF_OBJFLAGS_CONTROL );
                bCtlsStrm = getFlag( nFlags, BIFF_OBJFLAGS_CTLSSTREAM );
            }
            break;
            case BIFF_ID_OBJPICTFMLA:
            {
                dumpObjRecPictFmla( dumpDec< sal_uInt16 >( "pic-link-size" ) );
                if( rStrm.tell() + 4 <= nSubRecEnd )
                {
                    if( bControl && bCtlsStrm )
                        dumpControl();
                    else
                        dumpHex< sal_uInt32 >( "ole-storage-id" );
                }
                if( bControl && (rStrm.tell() + 8 <= nSubRecEnd) )
                {
                    sal_uInt32 nKeySize = dumpDec< sal_uInt32 >( "licence-key-size" );
                    if( nKeySize > 0 )
                    {
                        IndentGuard aIndGuard2( mxOut );
                        sal_Int64 nKeyEnd = rStrm.tell() + nKeySize;
                        dumpArray( "licence-key", static_cast< sal_Int32 >( nKeySize ) );
                        rStrm.seek( nKeyEnd );
                    }
                    dumpObjRecFmla( "cell-link", dumpDec< sal_uInt16 >( "cell-link-size" ) );
                    dumpObjRecFmla( "source-range", dumpDec< sal_uInt16 >( "source-range-size" ) );
                }
            }
            break;
            case BIFF_ID_OBJCBLS:
                dumpDec< sal_uInt16 >( "state", "OBJ-CHECKBOX-STATE" );
                dumpUnused( 4 );
                dumpUnicode( "accelerator" );
                dumpUnicode( "fareast-accelerator" );
                dumpHex< sal_uInt16 >( "checkbox-flags", "OBJ-CHECKBOX-FLAGS" );
            break;
            case BIFF_ID_OBJRBO:
                dumpUnused( 4 );
                dumpBool< sal_uInt16 >( "first-in-group" );
            break;
            case BIFF_ID_OBJSBS:
                dumpObjRecSbsData();
            break;
            case BIFF_ID_OBJGBODATA:
                dumpObjRecGboData();
            break;
            case BIFF_ID_OBJEDODATA:
                dumpObjRecEdoData();
            break;
            case BIFF_ID_OBJRBODATA:
                dumpObjRecRboData();
            break;
            case BIFF_ID_OBJCBLSDATA:
                dumpObjRecCblsData();
            break;
            case BIFF_ID_OBJLBSDATA:
                dumpObjRecLbsData();
                if( nObjType == BIFF_OBJTYPE_DROPDOWN )
                {
                    dumpHex< sal_uInt16 >( "dropdown-flags", "OBJ-DROPDOWN-FLAGS" );
                    dumpDec< sal_uInt16 >( "line-count" );
                    dumpDec< sal_uInt16 >( "min-list-width" );
                    dumpObjRecString( "text", dumpDec< sal_uInt16 >( "text-len" ), false );
                }
            break;
            case BIFF_ID_OBJCBLSFMLA:
            case BIFF_ID_OBJSBSFMLA:
                dumpObjRecFmlaRaw();
            break;
            case BIFF_ID_OBJCMO:
                nObjType = dumpDec< sal_uInt16 >( "type", "OBJ-TYPE" );
                dumpDec< sal_uInt16 >( "id" );
                dumpHex< sal_uInt16 >( "flags", "OBJCMO-FLAGS" );
                dumpUnused( 12 );
            break;
        }
        // remaining undumped data
        if( !rStrm.isEof() && (rStrm.tell() == nSubRecStart) )
            dumpRawBinary( nRealRecSize, false );
        else
            dumpRemainingTo( nSubRecEnd );
    }
}

void WorkbookStreamObject::dumpObjRecLineData()
{
    dumpColorIdx( "line-color-idx", false );
    dumpDec< sal_uInt8 >( "line-type", "OBJ-LINETYPE" );
    dumpDec< sal_uInt8 >( "line-weight", "OBJ-LINEWEIGHT" );
    dumpHex< sal_uInt8 >( "line-flags", "OBJ-AUTO-FLAGS" );
}

void WorkbookStreamObject::dumpObjRecFillData()
{
    dumpColorIdx( "back-color-idx", false );
    dumpColorIdx( "patt-color-idx", false );
    dumpPatternIdx( EMPTY_STRING, false );
    dumpHex< sal_uInt8 >( "area-flags", "OBJ-AUTO-FLAGS" );
}

void WorkbookStreamObject::dumpObjRecRectData()
{
    dumpObjRecFillData();
    dumpObjRecLineData();
    dumpHex< sal_uInt16 >( "frame-style", "OBJ-FRAMESTYLE-FLAGS" );
}

void WorkbookStreamObject::dumpObjRecTextDataBiff3( sal_uInt16& ornTextLen, sal_uInt16& ornFormatSize )
{
    ornTextLen = dumpDec< sal_uInt16 >( "text-len" );
    dumpUnused( 2 );
    ornFormatSize = dumpDec< sal_uInt16 >( "format-run-size" );
    dumpFontIdx( "default-font-idx" );
    dumpUnused( 2 );
    dumpHex< sal_uInt16 >( "flags", "OBJ-TEXT-FLAGS" );
    dumpDec< sal_uInt16 >( "orientation", "TEXTORIENTATION" );
    dumpUnused( 8 );
}

void WorkbookStreamObject::dumpObjRecTextDataBiff5( sal_uInt16& ornTextLen, sal_uInt16& ornFormatSize, sal_uInt16& ornLinkSize )
{
    ornTextLen = dumpDec< sal_uInt16 >( "text-len" );
    dumpUnused( 2 );
    ornFormatSize = dumpDec< sal_uInt16 >( "format-run-size" );
    dumpFontIdx( "default-font-idx" );
    dumpUnused( 2 );
    dumpHex< sal_uInt16 >( "flags", "OBJ-TEXT-FLAGS" );
    dumpDec< sal_uInt16 >( "orientation", "TEXTORIENTATION" );
    dumpUnused( 2 );
    ornLinkSize = dumpDec< sal_uInt16 >( "link-size" );
    dumpUnused( 2 );
    dumpHex< sal_uInt16 >( "button-flags", "OBJ-BUTTON-FLAGS" );
    dumpUnicode( "accelerator" );
    dumpUnicode( "fareast-accelerator" );
}

void WorkbookStreamObject::dumpObjRecSbsData()
{
    dumpUnused( 4 );
    dumpDec< sal_uInt16 >( "value" );
    dumpDec< sal_uInt16 >( "min" );
    dumpDec< sal_uInt16 >( "max" );
    dumpDec< sal_uInt16 >( "step" );
    dumpDec< sal_uInt16 >( "page-step" );
    dumpBool< sal_uInt16 >( "horizontal" );
    dumpDec< sal_uInt16 >( "thumb-width" );
    dumpHex< sal_uInt16 >( "scrollbar-flags", "OBJ-SCROLLBAR-FLAGS" );
}

void WorkbookStreamObject::dumpObjRecGboData()
{
    dumpUnicode( "accelerator" );
    dumpUnicode( "fareast-accelerator" );
    dumpHex< sal_uInt16 >( "groupbox-flags", "OBJ-GROUPBOX-FLAGS" );
}

void WorkbookStreamObject::dumpObjRecEdoData()
{
    dumpDec< sal_uInt16 >( "type", "OBJ-EDIT-TYPE" );
    dumpBool< sal_uInt16 >( "multiline" );
    dumpBool< sal_uInt16 >( "scrollbar" );
    dumpDec< sal_uInt16 >( "listbox-obj-id" );
}

void WorkbookStreamObject::dumpObjRecRboData()
{
    dumpDec< sal_uInt16 >( "next-in-group" );
    dumpBool< sal_uInt16 >( "first-in-group" );
}

void WorkbookStreamObject::dumpObjRecCblsData()
{
    dumpDec< sal_uInt16 >( "state", "OBJ-CHECKBOX-STATE" );
    dumpUnicode( "accelerator" );
    dumpUnicode( "fareast-accelerator" );
    dumpHex< sal_uInt16 >( "checkbox-flags", "OBJ-CHECKBOX-FLAGS" );
}

void WorkbookStreamObject::dumpObjRecLbsData()
{
    dumpObjRecFmla( "source-range", dumpDec< sal_uInt16 >( "source-range-size" ) );
    dumpDec< sal_uInt16 >( "entry-count" );
    dumpDec< sal_uInt16 >( "selected-entry" );
    dumpHex< sal_uInt16 >( "listbox-flags", "OBJ-LISTBOX-FLAGS" );
    dumpDec< sal_uInt16 >( "edit-obj-id" );
}

void WorkbookStreamObject::dumpObjRecPadding()
{
    if( getBiffStream().tell() & 1 )
    {
        IndentGuard aIndGuard( mxOut );
        dumpHex< sal_uInt8 >( "padding" );
    }
}

void WorkbookStreamObject::dumpObjRecString( const String& rName, sal_uInt16 nTextLen, bool bRepeatLen )
{
    if( nTextLen > 0 )
    {
        if( bRepeatLen )
            dumpByteString( rName, BIFF_STR_8BITLENGTH );
        else
            writeStringItem( rName, getBiffStream().readCharArrayUC( nTextLen, getBiffData().getTextEncoding() ) );
        dumpObjRecPadding();
    }
}

void WorkbookStreamObject::dumpObjRecTextFmt( sal_uInt16 nFormatSize )
{
    FontPortionModelList aPortions;
    aPortions.importPortions( getBiffStream(), nFormatSize / 8, BIFF_FONTPORTION_OBJ );
    writeFontPortions( aPortions );
}

void WorkbookStreamObject::dumpObjRecFmlaRaw()
{
    sal_uInt16 nFmlaSize = dumpDec< sal_uInt16 >( "fmla-size" );
    dumpUnused( 4 );
    getFormulaDumper().dumpNameFormula( "fmla", nFmlaSize );
    dumpObjRecPadding();
}

void WorkbookStreamObject::dumpObjRecFmla( const String& rName, sal_uInt16 nFmlaSize )
{
    BiffInputStream& rStrm = getBiffStream();
    if( nFmlaSize > 0 )
    {
        writeEmptyItem( rName );
        IndentGuard aIndGuard( mxOut );
        sal_Int64 nStrmEnd = rStrm.tell() + nFmlaSize;
        dumpObjRecFmlaRaw();
        if( rStrm.isEof() || (rStrm.tell() != nStrmEnd) )
            writeEmptyItem( OOX_DUMP_ERRASCII( "fmla-size" ) );
        dumpRemainingTo( nStrmEnd );
    }
}

void WorkbookStreamObject::dumpObjRecPictFmla( sal_uInt16 nFmlaSize )
{
    BiffInputStream& rStrm = getBiffStream();
    if( nFmlaSize > 0 )
    {
        writeEmptyItem( "pic-link" );
        IndentGuard aIndGuard( mxOut );
        sal_Int64 nStrmEnd = rStrm.tell() + nFmlaSize;
        if( (getBiff() == BIFF3) && (nStrmEnd & 1) ) ++nStrmEnd; // BIFF3 size without padding
        dumpObjRecFmlaRaw();
        if( rStrm.tell() + 2 <= nStrmEnd )
        {
            dumpString( "class-name", BIFF_STR_DEFAULT, BIFF_STR_SMARTFLAGS );
            dumpObjRecPadding();
        }
        if( rStrm.isEof() || (rStrm.tell() != nStrmEnd) )
            writeEmptyItem( OOX_DUMP_ERRASCII( "pic-link-size" ) );
        dumpRemainingTo( nStrmEnd );
    }
}

void WorkbookStreamObject::dumpChFrExtProps()
{
    BiffInputStream& rStrm = getBiffStream();
    bool bValid = true;
    while( bValid && (rStrm.getRemaining() > 4) )
    {
        ChFrExtPropInfo aInfo = dumpChFrExtPropHeader();
        IndentGuard aIndGuard( mxOut );
        switch( aInfo.first )
        {
            case 0: // start
            case 1: // end
            break;
            case 2: // bool
                dumpBoolean( "value" );
                dumpUnused( 1 );
            break;
            case 3: // double
                dumpUnused( 4 );
                dumpDec< double >( "value", aInfo.second );
            break;
            case 4: // int32
                dumpDec< sal_Int32 >( "value", aInfo.second );
            break;
            case 5: // string
                dumpUnicodeArray( "value", rStrm.readInt32() );
            break;
            case 6: // uint16
                dumpDec< sal_uInt16 >( "value", aInfo.second );
            break;
            case 7: // blob
                dumpBinary( "value", rStrm.readuInt32() );
            break;
            default:
                bValid = false;
        }
    }
}

WorkbookStreamObject::ChFrExtPropInfo WorkbookStreamObject::dumpChFrExtPropHeader()
{
    MultiItemsGuard aMultiGuard( mxOut );
    ChFrExtPropInfo aInfo;
    aInfo.first = dumpDec< sal_uInt8 >( "datatype", "CHFREXTPROPS-TYPE" );
    dumpUnused( 1 );
    sal_uInt16 nTag = dumpDec< sal_uInt16 >( "tag", "CHFREXTPROPS-TAG" );
    aInfo.second = cfg().getName( "CHFREXTPROPS-TAG-NAMELIST", nTag );
    return aInfo;
}

// ============================================================================

PivotCacheStreamObject::PivotCacheStreamObject( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, BiffType eBiff, const ::rtl::OUString& rSysFileName )
{
    RecordStreamObject::construct( rParent, rxStrm, eBiff, rSysFileName );
}

void PivotCacheStreamObject::implDumpRecordBody()
{
    BiffInputStream& rStrm = getBiffStream();
    sal_uInt16 nRecId = rStrm.getRecId();

    switch( nRecId )
    {
        case BIFF_ID_PCDEFINITION:
            dumpDec< sal_Int32 >( "source-records" );
            dumpHex< sal_uInt16 >( "cache-id" );
            dumpHex< sal_uInt16 >( "flags", "PCDEFINITION-FLAGS" );
            dumpUnused( 2 );
            dumpDec< sal_uInt16 >( "sourcedata-field-count" );
            dumpDec< sal_uInt16 >( "cache-field-count" );
            dumpDec< sal_uInt16 >( "report-record-count" );
            dumpDec< sal_uInt16 >( "database-type", "PCDSOURCE-TYPE" );
            dumpString( "user-name" );
        break;

        case BIFF_ID_PCDEFINITION2:
            dumpDec< double >( "refreshed-date" );
            dumpDec< sal_Int32 >( "formula-count" );
        break;

        case BIFF_ID_PCDFDISCRETEPR:
            mxOut->resetItemIndex();
            while( !rStrm.isEof() && (rStrm.getRemaining() >= 2) )
                dumpDec< sal_uInt16 >( "#item-index" );
        break;

        case BIFF_ID_PCDFIELD:
            dumpHex< sal_uInt16 >( "flags", "PCDFIELD-FLAGS" );
            dumpDec< sal_uInt16 >( "group-parent-field" );
            dumpDec< sal_uInt16 >( "group-base-field" );
            dumpDec< sal_uInt16 >( "unique-items" );
            dumpDec< sal_uInt16 >( "group-items" );
            dumpDec< sal_uInt16 >( "base-items" );
            dumpDec< sal_uInt16 >( "shared-items" );
            if( rStrm.getRemaining() >= 3 )
                dumpString( "item-name" );
        break;

        case BIFF_ID_PCITEM_DATE:
        {
            DateTime aDateTime;
            aDateTime.Year = mxStrm->readuInt16();
            aDateTime.Month = mxStrm->readuInt16();
            aDateTime.Day = mxStrm->readuInt8();
            aDateTime.Hours = mxStrm->readuInt8();
            aDateTime.Minutes = mxStrm->readuInt8();
            aDateTime.Seconds = mxStrm->readuInt8();
            writeDateTimeItem( "value", aDateTime );
        }
        break;

        case BIFF_ID_PCITEM_STRING:
            dumpString( "value" );
        break;
    }
}

// ============================================================================
// ============================================================================

RootStorageObject::RootStorageObject( const DumperBase& rParent )
{
    OleStorageObject::construct( rParent );
    addPreferredStream( "Book" );
    addPreferredStream( "Workbook" );
}

void RootStorageObject::implDumpStream( const Reference< XInputStream >& rxStrm, const OUString& rStrgPath, const OUString& rStrmName, const OUString& rSysFileName )
{
    if( (rStrgPath.getLength() == 0) && (rStrmName.equalsAscii( "Book" ) || rStrmName.equalsAscii( "Workbook" )) )
        WorkbookStreamObject( *this, rxStrm, rSysFileName ).dump();
    else if( rStrgPath.equalsAscii( "_SX_DB" ) )
        PivotCacheStreamObject( *this, rxStrm, BIFF5, rSysFileName ).dump();
    else if( rStrgPath.equalsAscii( "_SX_DB_CUR" ) )
        PivotCacheStreamObject( *this, rxStrm, BIFF8, rSysFileName ).dump();
    else
        OleStorageObject::implDumpStream( rxStrm, rStrgPath, rStrmName, rSysFileName );
}

void RootStorageObject::implDumpStorage( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rSysPath )
{
    if( rStrgPath.equalsAscii( "_VBA_PROJECT_CUR" ) )
        VbaProjectStorageObject( *this, rxStrg, rSysPath ).dump();
    else if( rStrgPath.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "MBD" ) ) )
        VbaContainerStorageObject( *this, rxStrg, rSysPath ).dump();
    else
        OleStorageObject::implDumpStorage( rxStrg, rStrgPath, rSysPath );
}

void RootStorageObject::implDumpBaseStream( const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName )
{
    WorkbookStreamObject( *this, rxStrm, rSysFileName ).dump();
}

// ============================================================================
// ============================================================================

#define DUMP_BIFF_CONFIG_ENVVAR "OOO_BIFFDUMPER"

Dumper::Dumper( const FilterBase& rFilter )
{
    ConfigRef xCfg( new Config( DUMP_BIFF_CONFIG_ENVVAR, rFilter ) );
    DumperBase::construct( xCfg );
}

Dumper::Dumper( const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm, const OUString& rSysFileName )
{
    if( rxContext.is() && rxInStrm.is() )
    {
        StorageRef xStrg( new ::oox::ole::OleStorage( rxContext, rxInStrm, true ) );
        MediaDescriptor aMediaDesc;
        ConfigRef xCfg( new Config( DUMP_BIFF_CONFIG_ENVVAR, rxContext, xStrg, rSysFileName, aMediaDesc ) );
        DumperBase::construct( xCfg );
    }
}

void Dumper::implDump()
{
    RootStorageObject( *this ).dump();
}

// ============================================================================
// ============================================================================

} // namespace biff
} // namespace dump
} // namespace oox

#endif
