Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  dumperbase.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   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 .
 */


#include <oox/dump/dumperbase.hxx>

#include <algorithm>
#include <string_view>

#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/io/TextOutputStream.hpp>
#include <com/sun/star/ucb/SimpleFileAccess.hpp>
#include <osl/file.hxx>
#include <rtl/math.hxx>
#include <rtl/tencinfo.h>
#include <oox/core/filterbase.hxx>
#include <oox/helper/binaryoutputstream.hxx>
#include <oox/helper/textinputstream.hxx>
#include <tools/time.hxx>
#include <o3tl/string_view.hxx>
#include <o3tl/numeric.hxx>
#include <utility>

#ifdef DBG_UTIL

namespace oox::dump {

using namespace ::com::sun::star;
using namespace ::com::sun::star::io;
using namespace ::com::sun::star::ucb;
using namespace ::com::sun::star::uno;

using ::oox::core::FilterBase;

namespace {

const sal_Unicode OOX_DUMP_BOM          = 0xFEFF;
const sal_Int32 OOX_DUMP_MAXSTRLEN      = 80;
const sal_Int32 OOX_DUMP_INDENT         = 2;
const sal_Unicode OOX_DUMP_BINDOT       = '.';
const sal_Unicode OOX_DUMP_CFG_LISTSEP  = ',';
const sal_Unicode OOX_DUMP_CFG_QUOTE    = '\'';
const sal_Unicode OOX_DUMP_LF           = '\n';
const sal_Unicode OOX_DUMP_ITEMSEP      = '=';
const sal_Int32 OOX_DUMP_BYTESPERLINE   = 16;
const sal_Int64 OOX_DUMP_MAXARRAY       = 16;

// namespace

// file names -----------------------------------------------------------------

OUString InputOutputHelper::convertFileNameToUrl( const OUString& rFileName )
{
    OUString aFileUrl;
    if( ::osl::FileBase::getFileURLFromSystemPath( rFileName, aFileUrl ) == ::osl::FileBase::E_None )
        return aFileUrl;
    return OUString();
}

sal_Int32 InputOutputHelper::getFileNamePos( std::u16string_view rFileUrl )
{
    size_t nSepPos = rFileUrl.find( '/' );
    return (nSepPos == std::u16string_view::npos) ? 0 : (nSepPos + 1);
}

std::u16string_view InputOutputHelper::getFileNameExtension( std::u16string_view rFileUrl )
{
    sal_Int32 nNamePos = getFileNamePos( rFileUrl );
    size_t nExtPos = rFileUrl.rfind( '.' );
    if( nExtPos != std::u16string_view::npos && static_cast<sal_Int32>(nExtPos) >= nNamePos )
        return rFileUrl.substr( nExtPos + 1 );
    return std::u16string_view();
}

// input streams --------------------------------------------------------------

Reference< XInputStream > InputOutputHelper::openInputStream(
        const Reference< XComponentContext >& rxContext, const OUString& rFileName )
{
    Reference< XInputStream > xInStrm;
    if( rxContext.is() ) try
    {
        Reference<XSimpleFileAccess3> xFileAccess(SimpleFileAccess::create(rxContext));
        xInStrm = xFileAccess->openFileRead( rFileName );
    }
    catch( Exception& )
    {
    }
    return xInStrm;
}

// output streams -------------------------------------------------------------

Reference< XOutputStream > InputOutputHelper::openOutputStream(
        const Reference< XComponentContext >& rxContext, const OUString& rFileName )
{
    Reference< XOutputStream > xOutStrm;
    if( rxContext.is() ) try
    {
        Reference<XSimpleFileAccess3> xFileAccess(SimpleFileAccess::create(rxContext));
        xOutStrm = xFileAccess->openFileWrite( rFileName );
    }
    catch( Exception& )
    {
    }
    return xOutStrm;
}

Reference< XTextOutputStream2 > InputOutputHelper::openTextOutputStream(
        const Reference< XComponentContext >& rxContext, const Reference< XOutputStream >& rxOutStrm, rtl_TextEncoding eTextEnc )
{
    Reference< XTextOutputStream2 > xTextOutStrm;
    const char* pcCharset = rtl_getMimeCharsetFromTextEncoding( eTextEnc );
    if( rxContext.is() && rxOutStrm.is() && pcCharset ) try
    {
        xTextOutStrm = TextOutputStream::create(rxContext);
        xTextOutStrm->setOutputStream( rxOutStrm );
        xTextOutStrm->setEncoding( OUString::createFromAscii( pcCharset ) );
    }
    catch( Exception& )
    {
    }
    return xTextOutStrm;
}

Reference< XTextOutputStream2 > InputOutputHelper::openTextOutputStream(
        const Reference< XComponentContext >& rxContext, const OUString& rFileName, rtl_TextEncoding eTextEnc )
{
    return openTextOutputStream( rxContext, openOutputStream( rxContext, rFileName ), eTextEnc );
}

ItemFormat::ItemFormat() :
    meDataType( DATATYPE_VOID ),
    meFmtType( FORMATTYPE_NONE )
{
}

void ItemFormat::set( DataType eDataType, FormatType eFmtType, const OUString& rItemName )
{
    meDataType = eDataType;
    meFmtType = eFmtType;
    maItemName = rItemName;
    maListName.clear();
}

OUStringVector::const_iterator ItemFormat::parse( const OUStringVector& rFormatVec )
{
    set( DATATYPE_VOID, FORMATTYPE_NONE, OUString() );

    OUStringVector::const_iterator aIt = rFormatVec.begin(), aEnd = rFormatVec.end();
    OUString aDataType, aFmtType;
    if( aIt != aEnd ) aDataType = *aIt++;
    if( aIt != aEnd ) aFmtType = *aIt++;
    if( aIt != aEnd ) maItemName = *aIt++;
    if( aIt != aEnd ) maListName = *aIt++;

    meDataType = StringHelper::convertToDataType( aDataType );
    meFmtType = StringHelper::convertToFormatType( aFmtType );

    if( meFmtType == FORMATTYPE_NONE )
    {
        if ( aFmtType == "unused" )
            set( meDataType, FORMATTYPE_HEX, OOX_DUMP_UNUSED );
        else if ( aFmtType == "unknown" )
            set( meDataType, FORMATTYPE_HEX, OOX_DUMP_UNKNOWN );
    }

    return aIt;
}

OUStringVector ItemFormat::parse( std::u16string_view rFormatStr )
{
    OUStringVector aFormatVec;
    StringHelper::convertStringToStringList( aFormatVec, rFormatStr, false );
    OUStringVector::const_iterator aIt = parse( aFormatVec );
    return OUStringVector( aIt, const_castconst OUStringVector& >( aFormatVec ).end() );
}

// append string to string ----------------------------------------------------

void StringHelper::appendChar( OUStringBuffer& rStr, sal_Unicode cChar, sal_Int32 nCount )
{
    for( sal_Int32 nIndex = 0; nIndex < nCount; ++nIndex )
        rStr.append( cChar );
}

void StringHelper::appendString( OUStringBuffer& rStr, std::u16string_view rData, sal_Int32 nWidth, sal_Unicode cFill )
{
    appendChar( rStr, cFill, nWidth - rData.size() );
    rStr.append( rData );
}

// append decimal -------------------------------------------------------------

void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt8 nData, sal_Int32 nWidth, sal_Unicode cFill )
{
    appendString( rStr, OUString::number( nData ), nWidth, cFill );
}

void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int8 nData, sal_Int32 nWidth, sal_Unicode cFill )
{
    appendString( rStr, OUString::number( nData ), nWidth, cFill );
}

void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt16 nData, sal_Int32 nWidth, sal_Unicode cFill )
{
    appendString( rStr, OUString::number( nData ), nWidth, cFill );
}

void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int16 nData, sal_Int32 nWidth, sal_Unicode cFill )
{
    appendString( rStr, OUString::number( nData ), nWidth, cFill );
}

void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt32 nData, sal_Int32 nWidth, sal_Unicode cFill )
{
    appendString( rStr, OUString::number( nData ), nWidth, cFill );
}

void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int32 nData, sal_Int32 nWidth, sal_Unicode cFill )
{
    appendString( rStr, OUString::number( nData ), nWidth, cFill );
}

void StringHelper::appendDec( OUStringBuffer& rStr, sal_uInt64 nData, sal_Int32 nWidth, sal_Unicode cFill )
{
    /*  Values greater than biggest signed 64bit integer will change to
        negative when converting to sal_Int64. Therefore, the trailing digit
        will be written separately. */

    OUStringBuffer aBuffer;
    if( nData > 9 )
        aBuffer.append( static_cast<sal_Int64>(nData / 10 ) );
    aBuffer.append( static_cast< sal_Unicode >( '0' + (nData % 10) ) );
    appendString( rStr, aBuffer.makeStringAndClear(), nWidth, cFill );
}

void StringHelper::appendDec( OUStringBuffer& rStr, sal_Int64 nData, sal_Int32 nWidth, sal_Unicode cFill )
{
    appendString( rStr, OUString::number( nData ), nWidth, cFill );
}

void StringHelper::appendDec( OUStringBuffer& rStr, double fData, sal_Int32 nWidth, sal_Unicode cFill )
{
    appendString( rStr, ::rtl::math::doubleToUString( fData, rtl_math_StringFormat_G, 15, '.'true ), nWidth, cFill );
}

// append hexadecimal ---------------------------------------------------------

void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt8 nData, bool bPrefix )
{
    static const sal_Unicode spcHexDigits[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
    if( bPrefix )
        rStr.append( "0x" );
    rStr.append( OUStringChar(spcHexDigits[ (nData >> 4) & 0x0F ] ) + OUStringChar( spcHexDigits[ nData & 0x0F ] ) );
}

void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int8 nData, bool bPrefix )
{
    appendHex( rStr, static_cast< sal_uInt8 >( nData ), bPrefix );
}

void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt16 nData, bool bPrefix )
{
    appendHex( rStr, static_cast< sal_uInt8 >( nData >> 8 ), bPrefix );
    appendHex( rStr, static_cast< sal_uInt8 >( nData ), false );
}

void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int16 nData, bool bPrefix )
{
    appendHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix );
}

void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt32 nData, bool bPrefix )
{
    appendHex( rStr, static_cast< sal_uInt16 >( nData >> 16 ), bPrefix );
    appendHex( rStr, static_cast< sal_uInt16 >( nData ), false );
}

void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int32 nData, bool bPrefix )
{
    appendHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix );
}

void StringHelper::appendHex( OUStringBuffer& rStr, sal_uInt64 nData, bool bPrefix )
{
    appendHex( rStr, static_cast< sal_uInt32 >( nData >> 32 ), bPrefix );
    appendHex( rStr, static_cast< sal_uInt32 >( nData ), false );
}

void StringHelper::appendHex( OUStringBuffer& rStr, sal_Int64 nData, bool bPrefix )
{
    appendHex( rStr, static_cast< sal_uInt64 >( nData ), bPrefix );
}

static sal_uInt64
lcl_ConvertDouble(double const f)
{
    sal_uInt64 i = sal_uInt64();
    for (size_t j = 0; j < sizeof(double); ++j)
    {   // hopefully both endian independent and strict aliasing safe
        reinterpret_cast<char *>(&i)[j] = reinterpret_cast<char const *>(&f)[j];
    }
    return i;
}

void StringHelper::appendHex( OUStringBuffer& rStr, double fData, bool bPrefix )
{
    appendHex( rStr, lcl_ConvertDouble(fData), bPrefix );
}

// append shortened hexadecimal -----------------------------------------------

void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt8 nData, bool bPrefix )
{
    appendHex( rStr, nData, bPrefix );
}

void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int8 nData, bool bPrefix )
{
    appendHex( rStr, nData, bPrefix );
}

void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt16 nData, bool bPrefix )
{
    if( nData > SAL_MAX_UINT8 )
        appendHex( rStr, nData, bPrefix );
    else
        appendHex( rStr, static_cast< sal_uInt8 >( nData ), bPrefix );
}

void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int16 nData, bool bPrefix )
{
    appendShortHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix );
}

void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt32 nData, bool bPrefix )
{
    if( nData > SAL_MAX_UINT16 )
        appendHex( rStr, nData, bPrefix );
    else
        appendShortHex( rStr, static_cast< sal_uInt16 >( nData ), bPrefix );
}

void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int32 nData, bool bPrefix )
{
    appendShortHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix );
}

void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_uInt64 nData, bool bPrefix )
{
    if( nData > SAL_MAX_UINT32 )
        appendHex( rStr, nData, bPrefix );
    else
        appendShortHex( rStr, static_cast< sal_uInt32 >( nData ), bPrefix );
}

void StringHelper::appendShortHex( OUStringBuffer& rStr, sal_Int64 nData, bool bPrefix )
{
    appendShortHex( rStr, static_cast< sal_uInt64 >( nData ), bPrefix );
}

void StringHelper::appendShortHex( OUStringBuffer& rStr, double fData, bool bPrefix )
{
    appendHex( rStr, fData, bPrefix );
}

// append binary --------------------------------------------------------------

void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt8 nData, bool bDots )
{
    for( sal_uInt8 nMask = 0x80; nMask != 0; (nMask >>= 1) &= 0x7F )
    {
        rStr.append( static_cast< sal_Unicode >( (nData & nMask) ? '1' : '0' ) );
        if( bDots && (nMask == 0x10) )
            rStr.append( OOX_DUMP_BINDOT );
    }
}

void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int8 nData, bool bDots )
{
    appendBin( rStr, static_cast< sal_uInt8 >( nData ), bDots );
}

void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt16 nData, bool bDots )
{
    appendBin( rStr, static_cast< sal_uInt8 >( nData >> 8 ), bDots );
    if( bDots )
        rStr.append( OOX_DUMP_BINDOT );
    appendBin( rStr, static_cast< sal_uInt8 >( nData ), bDots );
}

void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int16 nData, bool bDots )
{
    appendBin( rStr, static_cast< sal_uInt16 >( nData ), bDots );
}

void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt32 nData, bool bDots )
{
    appendBin( rStr, static_cast< sal_uInt16 >( nData >> 16 ), bDots );
    if( bDots )
        rStr.append( OOX_DUMP_BINDOT );
    appendBin( rStr, static_cast< sal_uInt16 >( nData ), bDots );
}

void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int32 nData, bool bDots )
{
    appendBin( rStr, static_cast< sal_uInt32 >( nData ), bDots );
}

void StringHelper::appendBin( OUStringBuffer& rStr, sal_uInt64 nData, bool bDots )
{
    appendBin( rStr, static_cast< sal_uInt32 >( nData >> 32 ), bDots );
    if( bDots )
        rStr.append( OOX_DUMP_BINDOT );
    appendBin( rStr, static_cast< sal_uInt32 >( nData ), bDots );
}

void StringHelper::appendBin( OUStringBuffer& rStr, sal_Int64 nData, bool bDots )
{
    appendBin( rStr, static_cast< sal_uInt64 >( nData ), bDots );
}

void StringHelper::appendBin( OUStringBuffer& rStr, double fData, bool bDots )
{
    appendBin( rStr, lcl_ConvertDouble(fData), bDots );
}

// append formatted value -----------------------------------------------------

void StringHelper::appendBool( OUStringBuffer& rStr, bool bData )
{
    rStr.appendAscii( bData ? "true" : "false" );
}

// encoded text output --------------------------------------------------------

void StringHelper::appendCChar( OUStringBuffer& rStr, sal_Unicode cChar, bool bPrefix )
{
    if( cChar > 0x00FF )
    {
        if( bPrefix )
            rStr.append( "\\u" );
        appendHex( rStr, static_cast< sal_uInt16 >( cChar ), false );
    }
    else
    {
        if( bPrefix )
            rStr.append( "\\x" );
        appendHex( rStr, static_cast< sal_uInt8 >( cChar ), false );
    }
}

void StringHelper::appendEncChar( OUStringBuffer& rStr, sal_Unicode cChar, sal_Int32 nCount, bool bPrefix )
{
    if( cChar < 0x0020 )
    {
        // C-style hex code
        OUStringBuffer aCode;
        appendCChar( aCode, cChar, bPrefix );
        OUString aCodeStr = aCode.makeStringAndClear();
        for( sal_Int32 nIdx = 0; nIdx < nCount; ++nIdx )
            rStr.append( aCodeStr );
    }
    else
    {
        appendChar( rStr, cChar, nCount );
    }
}

void StringHelper::appendEncString( OUStringBuffer& rStr, std::u16string_view rData, bool bPrefix )
{
    size_t nBeg = 0;
    size_t nIdx = 0;
    size_t nEnd = rData.size();
    while( nIdx < nEnd )
    {
        // find next character that needs encoding
        while( (nIdx < nEnd) && (rData[ nIdx ] >= 0x20) ) ++nIdx;
        // append portion
        if( nBeg < nIdx )
        {
            if( (nBeg == 0) && (nIdx == nEnd) )
                rStr.append( rData );
            else
                rStr.append( rData.substr(nBeg, nIdx - nBeg) );
        }
        // append characters to be encoded
        while( (nIdx < nEnd) && (rData[ nIdx ] < 0x20) )
        {
            appendCChar( rStr, rData[ nIdx ], bPrefix );
            ++nIdx;
        }
        // adjust limits
        nBeg = nIdx;
    }
}

// token list -----------------------------------------------------------------

void StringHelper::appendToken( OUStringBuffer& rStr, std::u16string_view rToken, sal_Unicode cSep )
{
    if( (rStr.getLength() > 0) && (!rToken.empty()) )
        rStr.append( cSep );
    rStr.append( rToken );
}

void StringHelper::appendIndex( OUStringBuffer& rStr, sal_Int64 nIdx )
{
    OUStringBuffer aToken;
    appendDec( aToken, nIdx );
    rStr.append( "[" +  aToken + "]" );
}

std::u16string_view StringHelper::getToken( std::u16string_view rData, sal_Int32& ;rnPos, sal_Unicode cSep )
{
    return trimSpaces( o3tl::getToken(rData, 0, cSep, rnPos ) );
}

void StringHelper::enclose( OUStringBuffer& rStr, sal_Unicode cOpen, sal_Unicode cClose )
{
    rStr.insert( 0, cOpen ).append( cClose ? cClose : cOpen );
}

// string conversion ----------------------------------------------------------

namespace {

sal_Int32 lclIndexOf( std::u16string_view rStr, sal_Unicode cChar, sal_Int32 nStartPos )
{
    size_t nIndex = rStr.find( cChar, nStartPos );
    return (nIndex == std::u16string_view::npos) ? rStr.size() : nIndex;
}

OUString lclTrimQuotedStringList( std::u16string_view rStr )
{
    OUStringBuffer aBuffer;
    size_t nPos = 0;
    size_t nLen = rStr.size();
    while( nPos < nLen )
    {
        if( rStr[ nPos ] == OOX_DUMP_CFG_QUOTE )
        {
            // quoted string, skip leading quote character
            ++nPos;
            // process quoted text and embedded literal quote characters
            OUStringBuffer aToken;
            do
            {
                // seek to next quote character and add text portion to token buffer
                size_t nEnd = lclIndexOf( rStr, OOX_DUMP_CFG_QUOTE, nPos );
                aToken.append( rStr.substr(nPos, nEnd - nPos) );
                // process literal quotes
                while( (nEnd + 1 < nLen) && (rStr[ nEnd ] == OOX_DUMP_CFG_QUOTE) && (rStr[ nEnd + 1 ] == OOX_DUMP_CFG_QUOTE) )
                {
                    aToken.append( OOX_DUMP_CFG_QUOTE );
                    nEnd += 2;
                }
                // nEnd is start of possible next text portion
                nPos = nEnd;
            }
            while( (nPos < nLen) && (rStr[ nPos ] != OOX_DUMP_CFG_QUOTE) );
            // add token, seek to list separator, ignore text following closing quote
            aBuffer.append( aToken );
            nPos = lclIndexOf( rStr, OOX_DUMP_CFG_LISTSEP, nPos );
            if( nPos < nLen )
                aBuffer.append( OOX_DUMP_LF );
            // set current position behind list separator
            ++nPos;
        }
        else
        {
            // find list separator, add token text to buffer
            size_t nEnd = lclIndexOf( rStr, OOX_DUMP_CFG_LISTSEP, nPos );
            aBuffer.append( rStr.substr(nPos, nEnd - nPos) );
            if( nEnd < nLen )
                aBuffer.append( OOX_DUMP_LF );
            // set current position behind list separator
            nPos = nEnd + 1;
        }
    }

    return aBuffer.makeStringAndClear();
}

// namespace

std::u16string_view StringHelper::trimSpaces( std::u16string_view rStr )
{
    size_t nBeg = 0;
    while( (nBeg < rStr.size()) && ((rStr[ nBeg ] == ' ') || (rStr[ nBeg ] == '\t')) )
        ++nBeg;
    size_t nEnd = rStr.size();
    while( (nEnd > nBeg) && ((rStr[ nEnd - 1 ] == ' ') || (rStr[ nEnd - 1 ] == '\t')) )
        --nEnd;
    return rStr.substr( nBeg, nEnd - nBeg );
}

OUString StringHelper::trimTrailingNul( const OUString& rStr )
{
    sal_Int32 nLastPos = rStr.getLength() - 1;
    if( (nLastPos >= 0) && (rStr[ nLastPos ] == 0) )
        return rStr.copy( 0, nLastPos );
    return rStr;
}

OString StringHelper::convertToUtf8( std::u16string_view rStr )
{
    return OUStringToOString( rStr, RTL_TEXTENCODING_UTF8 );
}

DataType StringHelper::convertToDataType( std::u16string_view rStr )
{
    DataType eType = DATATYPE_VOID;
    if ( rStr == u"int8" )
        eType = DATATYPE_INT8;
    else if ( rStr == u"uint8" )
        eType = DATATYPE_UINT8;
    else if ( rStr == u"int16" )
        eType = DATATYPE_INT16;
    else if ( rStr == u"uint16" )
        eType = DATATYPE_UINT16;
    else if ( rStr == u"int32" )
        eType = DATATYPE_INT32;
    else if ( rStr == u"uint32" )
        eType = DATATYPE_UINT32;
    else if ( rStr == u"int64" )
        eType = DATATYPE_INT64;
    else if ( rStr == u"uint64" )
        eType = DATATYPE_UINT64;
    else if ( rStr == u"float" )
        eType = DATATYPE_FLOAT;
    else if ( rStr == u"double" )
        eType = DATATYPE_DOUBLE;
    return eType;
}

FormatType StringHelper::convertToFormatType( std::u16string_view rStr )
{
    FormatType eType = FORMATTYPE_NONE;
    if ( rStr == u"dec" )
        eType = FORMATTYPE_DEC;
    else if ( rStr == u"hex" )
        eType = FORMATTYPE_HEX;
    else if ( rStr == u"shorthex" )
        eType = FORMATTYPE_SHORTHEX;
    else if ( rStr == u"bin" )
        eType = FORMATTYPE_BIN;
    else if ( rStr == u"fix" )
        eType = FORMATTYPE_FIX;
    else if ( rStr == u"bool" )
        eType = FORMATTYPE_BOOL;
    return eType;
}

bool StringHelper::convertFromDec( sal_Int64& ornData, std::u16string_view rData )
{
    size_t nPos = 0;
    size_t nLen = rData.size();
    bool bNeg = false;
    if( (nLen > 0) && (rData[ 0 ] == '-') )
    {
        bNeg = true;
        ++nPos;
    }
    ornData = 0;
    for( ; nPos < nLen; ++nPos )
    {
        sal_Unicode cChar = rData[ nPos ];
        if( (cChar < '0') || (cChar > '9') )
            return false;
        ornData = (ornData * 10) + (cChar - '0');
    }
    if( bNeg )
        ornData *= -1;
    return true;
}

bool StringHelper::convertFromHex( sal_Int64& ornData, std::u16string_view rData )
{
    ornData = 0;
    for( size_t nPos = 0, nLen = rData.size(); nPos < nLen; ++nPos )
    {
        sal_Unicode cChar = rData[ nPos ];
        sal_Int32 nValue = o3tl::convertToHex<sal_Int32>(cChar);
        if (nValue == -1)
            return false;
        ornData = (ornData << 4) + nValue;
    }
    return true;
}

bool StringHelper::convertStringToInt( sal_Int64& ornData, std::u16string_view rData )
{
    if( (rData.size() > 2) && (rData[ 0 ] == '0') && ((rData[ 1 ] == 'X') || (rData[ 1 ] == 'x')) )
        return convertFromHex( ornData, rData.substr( 2 ) );
    return convertFromDec( ornData, rData );
}

bool StringHelper::convertStringToDouble( double& orfData, std::u16string_view rData )
{
    rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
    sal_Int32 nSize = 0;
    sal_Unicode const * pBegin = rData.data();
    sal_Unicode const * pEnd;
    orfData = rtl_math_uStringToDouble(pBegin,
                                             pBegin + rData.size(),
                                             '.''\0',
                                             &eStatus, &pEnd);
    nSize = static_cast<sal_Int32>(pEnd - pBegin);
    return (eStatus == rtl_math_ConversionStatus_Ok) && (nSize == static_cast<sal_Int32>(rData.size()));
}

bool StringHelper::convertStringToBool( std::u16string_view rData )
{
    if ( rData == u"true" )
        return true;
    if ( rData == u"false" )
        return false;
    sal_Int64 nData;
    return convertStringToInt( nData, rData ) && (nData != 0);
}

OUStringPair StringHelper::convertStringToPair( const OUString& rString, sal_Unicode cSep )
{
    OUStringPair aPair;
    if( !rString.isEmpty() )
    {
        sal_Int32 nEqPos = rString.indexOf( cSep );
        if( nEqPos < 0 )
        {
            aPair.first = rString;
        }
        else
        {
            aPair.first = StringHelper::trimSpaces( rString.subView( 0, nEqPos ) );
            aPair.second = StringHelper::trimSpaces( rString.subView( nEqPos + 1 ) );
        }
    }
    return aPair;
}

void StringHelper::convertStringToStringList( OUStringVector& orVec, std::u16string_view rData, bool bIgnoreEmpty )
{
    orVec.clear();
    OUString aUnquotedData = lclTrimQuotedStringList( rData );
    sal_Int32 nPos = 0;
    sal_Int32 nLen = aUnquotedData.getLength();
    while( (0 <= nPos) && (nPos < nLen) )
    {
        std::u16string_view aToken = getToken( aUnquotedData, nPos, OOX_DUMP_LF );
        if( !bIgnoreEmpty || !aToken.empty() )
            orVec.push_back( OUString(aToken) );
    }
}

void StringHelper::convertStringToIntList( Int64Vector& orVec, std::u16string_view rData, bool bIgnoreEmpty )
{
    orVec.clear();
    OUString aUnquotedData = lclTrimQuotedStringList( rData );
    sal_Int32 nPos = 0;
    sal_Int32 nLen = aUnquotedData.getLength();
    sal_Int64 nData;
    while( (0 <= nPos) && (nPos < nLen) )
    {
        bool bOk = convertStringToInt( nData, getToken( aUnquotedData, nPos, OOX_DUMP_LF ) );
        if( !bIgnoreEmpty || bOk )
            orVec.push_back( bOk ? nData : 0 );
    }
}

Base::~Base()
{
}

ConfigItemBase::~ConfigItemBase()
{
}

void ConfigItemBase::readConfigBlock( TextInputStream& rStrm )
{
    readConfigBlockContents( rStrm );
}

void ConfigItemBase::implProcessConfigItemStr(
        TextInputStream& /*rStrm*/, const OUString& /*rKey*/, const OUString& /*rData*/ )
{
}

void ConfigItemBase::implProcessConfigItemInt(
        TextInputStream& /*rStrm*/, sal_Int64 /*nKey*/, const OUString& /*rData*/ )
{
}

void ConfigItemBase::readConfigBlockContents( TextInputStream& rStrm )
{
    bool bLoop = true;
    while( bLoop && !rStrm.isEof() )
    {
        OUString aKey, aData;
        switch( readConfigLine( rStrm, aKey, aData ) )
        {
            case LINETYPE_DATA:
                processConfigItem( rStrm, aKey, aData );
            break;
            case LINETYPE_END:
                bLoop = false;
            break;
        }
    }
}

ConfigItemBase::LineType ConfigItemBase::readConfigLine(
        TextInputStream& rStrm, OUString& orKey, OUString& orData )
{
    OUString aLine;
    while( !rStrm.isEof() && aLine.isEmpty() )
    {
        aLine = rStrm.readLine();
        if( !aLine.isEmpty() && (aLine[ 0 ] == OOX_DUMP_BOM) )
            aLine = aLine.copy( 1 );
        aLine = StringHelper::trimSpaces( aLine );
        if( !aLine.isEmpty() )
        {
            // ignore comments (starting with hash or semicolon)
            sal_Unicode cChar = aLine[ 0 ];
            if( (cChar == '#') || (cChar == ';') )
                aLine.clear();
        }
    }

    OUStringPair aPair = StringHelper::convertStringToPair( aLine );
    orKey = aPair.first;
    orData = aPair.second;
    return ( !orKey.isEmpty() && (!orData.isEmpty() || orKey != "end" )) ?
        LINETYPE_DATA : LINETYPE_END;
}

void ConfigItemBase::processConfigItem(
        TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
{
    sal_Int64 nKey;
    if( StringHelper::convertStringToInt( nKey, rKey ) )
        implProcessConfigItemInt( rStrm, nKey, rData );
    else
        implProcessConfigItemStr( rStrm, rKey, rData );
}

NameListBase::~NameListBase()
{
}

void NameListBase::setName( sal_Int64 nKey, const String& rName )
{
    implSetName( nKey, rName );
}

void NameListBase::includeList( const NameListRef& rxList )
{
    if( rxList )
    {
        for (auto const& elem : *rxList)
            maMap[ elem.first ] = elem.second;
        implIncludeList( *rxList );
    }
}

bool NameListBase::implIsValid() const
{
    return true;
}

void NameListBase::implProcessConfigItemStr(
        TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
{
    if ( rKey == "include" )
        include( rData );
    else if ( rKey == "exclude" )
        exclude( rData );
    else
        ConfigItemBase::implProcessConfigItemStr( rStrm, rKey, rData );
}

void NameListBase::implProcessConfigItemInt(
        TextInputStream& /*rStrm*/, sal_Int64 nKey, const OUString& rData )
{
    implSetName( nKey, rData );
}

void NameListBase::insertRawName( sal_Int64 nKey, const OUString& rName )
{
    maMap[ nKey ] = rName;
}

const OUString* NameListBase::findRawName( sal_Int64 nKey ) const
{
    const_iterator aIt = maMap.find( nKey );
    return (aIt == end()) ? nullptr : &aIt->second;
}

void NameListBase::include( std::u16string_view rListKeys )
{
    OUStringVector aVec;
    StringHelper::convertStringToStringList( aVec, rListKeys, true );
    for (auto const& elem : aVec)
        includeList( mrCfgData.getNameList(elem) );
}

void NameListBase::exclude( std::u16string_view rKeys )
{
    Int64Vector aVec;
    StringHelper::convertStringToIntList( aVec, rKeys, true );
    for (auto const& elem : aVec)
        maMap.erase(elem);
}

void ItemFormatMap::insertFormats( const NameListRef& rxNameList )
{
    if( Base::isValid( rxNameList ) )
    {
        for (auto const& elemName : *rxNameList)
            maMap[ elemName.first ].parse( elemName.second );
    }
}

ConstList::ConstList( const SharedConfigData& rCfgData ) :
    NameListBase( rCfgData ),
    maDefName( OOX_DUMP_ERR_NONAME ),
    mbQuoteNames( false )
{
}

void ConstList::implProcessConfigItemStr(
        TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
{
    if ( rKey == "default" )
        maDefName = rData; // Sets a default name for unknown keys.
    else if ( rKey == "quote-names" )
        setQuoteNames( StringHelper::convertStringToBool( rData ) );
    else
        NameListBase::implProcessConfigItemStr( rStrm, rKey, rData );
}

void ConstList::implSetName( sal_Int64 nKey, const OUString& rName )
{
    insertRawName( nKey, rName );
}

OUString ConstList::implGetName( const Config& /*rCfg*/, sal_Int64 nKey ) const
{
    const OUString* pName = findRawName( nKey );
    OUString aName = pName ? *pName : maDefName;
    if( mbQuoteNames )
    {
        OUStringBuffer aBuffer( aName );
        StringHelper::enclose( aBuffer, OOX_DUMP_STRQUOTE );
        aName = aBuffer.makeStringAndClear();
    }
    return aName;
}

OUString ConstList::implGetNameDbl( const Config& /*rCfg*/, double /*fValue*/ ) const
{
    return OUString();
}

void ConstList::implIncludeList( const NameListBase& rList )
{
    ifconst ConstList* pConstList = dynamic_castconst ConstList* >( &rList ) )
    {
        maDefName = pConstList->maDefName;
        mbQuoteNames = pConstList->mbQuoteNames;
    }
}

MultiList::MultiList( const SharedConfigData& rCfgData ) :
    ConstList( rCfgData ),
    mbIgnoreEmpty( true )
{
}

void MultiList::setNamesFromVec( sal_Int64 nStartKey, const OUStringVector& rNames )
{
    sal_Int64 nKey = nStartKey;
    for (auto const& name : rNames)
    {
        if( !mbIgnoreEmpty || !name.isEmpty() )
            insertRawName( nKey, name);
        ++nKey;
    }
}

void MultiList::implProcessConfigItemStr(
        TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
{
    if ( rKey == "ignore-empty" )
        mbIgnoreEmpty = StringHelper::convertStringToBool( rData );
    else
        ConstList::implProcessConfigItemStr( rStrm, rKey, rData );
}

void MultiList::implSetName( sal_Int64 nKey, const OUString& rName )
{
    OUStringVector aNames;
    StringHelper::convertStringToStringList( aNames, rName, false );
    setNamesFromVec( nKey, aNames );
}

FlagsList::FlagsList( const SharedConfigData& rCfgData ) :
    NameListBase( rCfgData ),
    mnIgnore( 0 )
{
}

void FlagsList::implProcessConfigItemStr(
        TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
{
    if ( rKey == "ignore" )
    {
        sal_Int64 nIgnore;
        if( StringHelper::convertStringToInt( nIgnore, rData ) )
            setIgnoreFlags( nIgnore );
    }
    else
    {
        NameListBase::implProcessConfigItemStr( rStrm, rKey, rData );
    }
}

void FlagsList::implSetName( sal_Int64 nKey, const OUString& rName )
{
    if( (nKey != 0) && ((nKey & (nKey - 1)) == 0) )  // only a single bit set?
        insertRawName( nKey, rName );
}

OUString FlagsList::implGetName( const Config& /*rCfg*/, sal_Int64 nKey ) const
{
    sal_Int64 nFound = mnIgnore;
    OUStringBuffer aName;
    // add known flags
    for( const_iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt )
    {
        sal_Int64 nMask = aIt->first;
        setFlag( nFound, nMask );
        if( !getFlag( mnIgnore, nMask ) )
        {
            const OUString& rFlagName = aIt->second;
            bool bOnOff = rFlagName.startsWith(":");
            bool bFlag = getFlag( nKey, nMask );
            if( bOnOff )
            {
                StringHelper::appendToken( aName, rFlagName.subView( 1 ) );
                aName.appendAscii( bFlag ? ":on" : ":off" );
            }
            else
            {
                bool bNegated = rFlagName.startsWith("!");
                sal_Int32 nBothSep = bNegated ? rFlagName.indexOf( '!', 1 ) : -1;
                if( bFlag )
                {
                    if( !bNegated )
                        StringHelper::appendToken( aName, rFlagName );
                    else if( nBothSep > 0 )
                        StringHelper::appendToken( aName, rFlagName.subView( nBothSep + 1 ) );
                }
                else if( bNegated )
                {
                    if( nBothSep > 0 )
                        StringHelper::appendToken( aName, rFlagName.subView( 1, nBothSep - 1 ) );
                    else
                        StringHelper::appendToken( aName, rFlagName.subView( 1 ) );
                }
            }
        }
    }
    // add unknown flags
    setFlag( nKey, nFound, false );
    if( nKey != 0 )
    {
        OUStringBuffer aUnknown( OUString::Concat(OOX_DUMP_UNKNOWN) + OUStringChar(OOX_DUMP_ITEMSEP) );
        StringHelper::appendShortHex( aUnknown, nKey );
        StringHelper::enclose( aUnknown, '('')' );
        StringHelper::appendToken( aName, aUnknown );
    }
    return aName.makeStringAndClear();
}

OUString FlagsList::implGetNameDbl( const Config& /*rCfg*/, double /*fValue*/ ) const
{
    return OUString();
}

void FlagsList::implIncludeList( const NameListBase& rList )
{
    ifconst FlagsList* pFlagsList = dynamic_castconst FlagsList* >( &rList ) )
        mnIgnore = pFlagsList->mnIgnore;
}

bool CombiList::ExtItemFormatKey::operator<( const ExtItemFormatKey& rRight ) const
{
    return (mnKey < rRight.mnKey) || ((mnKey == rRight.mnKey) && (maFilter < rRight.maFilter));
}

CombiList::CombiList( const SharedConfigData& rCfgData ) :
    FlagsList( rCfgData )
{
}

void CombiList::implSetName( sal_Int64 nKey, const OUString& rName )
{
    if( (nKey & (nKey - 1)) != 0 )  // more than a single bit set?
    {
        ::std::set< ExtItemFormatKey > aItemKeys;
        ExtItemFormat aItemFmt;
        OUStringVector aRemain = aItemFmt.parse( rName );
        for (auto const& elemRemain : aRemain)
        {
            OUStringPair aPair = StringHelper::convertStringToPair(elemRemain);
            if ( aPair.first == "noshift" )
            {
                aItemFmt.mbShiftValue = StringHelper::convertStringToBool( aPair.second );
            }
            else if ( aPair.first == "filter" )
            {
                OUStringPair aFilter = StringHelper::convertStringToPair( aPair.second, '~' );
                ExtItemFormatKey aKey( nKey );
                if( !aFilter.first.isEmpty() && StringHelper::convertStringToInt( aKey.maFilter.first, aFilter.first ) &&
                    !aFilter.second.isEmpty() && StringHelper::convertStringToInt( aKey.maFilter.second, aFilter.second ) )
                {
                    if( aKey.maFilter.first == 0 )
                        aKey.maFilter.second = 0;
                    aItemKeys.insert( aKey );
                }
            }
        }
        if( aItemKeys.empty() )
            aItemKeys.insert( ExtItemFormatKey( nKey ) );
        for (auto const& itemKey : aItemKeys)
            maFmtMap[itemKey] = aItemFmt;
    }
    else
    {
        FlagsList::implSetName( nKey, rName );
    }
}

OUString CombiList::implGetName( const Config& rCfg, sal_Int64 nKey ) const
{
    sal_Int64 nFound = 0;
    OUStringBuffer aName;
    // add known flag fields
    for (auto const& fmt : maFmtMap)
    {
        const ExtItemFormatKey& rMapKey = fmt.first;
        sal_Int64 nMask = rMapKey.mnKey;
        if( (nMask != 0) && ((nKey & rMapKey.maFilter.first) == rMapKey.maFilter.second) )
        {
            const ExtItemFormat& rItemFmt = fmt.second;

            sal_uInt64 nUFlags = static_cast< sal_uInt64 >( nKey );
            sal_uInt64 nUMask = static_cast< sal_uInt64 >( nMask );
            if( rItemFmt.mbShiftValue )
                while( (nUMask & 1) == 0 ) { nUFlags >>= 1; nUMask >>= 1; }

            sal_uInt64 nUValue = nUFlags & nUMask;
            sal_Int64 nSValue = static_cast< sal_Int64 >( nUValue );
            if( getFlag< sal_uInt64 >( nUValue, (nUMask + 1) >> 1 ) )
                setFlag( nSValue, static_cast< sal_Int64 >( ~nUMask ) );

            OUStringBuffer aItem( rItemFmt.maItemName );
            OUStringBuffer aValue;
            switch( rItemFmt.meDataType )
            {
                case DATATYPE_INT8:     StringHelper::appendValue( aValue, static_cast< sal_Int8 >( nSValue ), rItemFmt.meFmtType );    break;
                case DATATYPE_UINT8:    StringHelper::appendValue( aValue, static_cast< sal_uInt8 >( nUValue ), rItemFmt.meFmtType );   break;
                case DATATYPE_INT16:    StringHelper::appendValue( aValue, static_cast< sal_Int16 >( nSValue ), rItemFmt.meFmtType );   break;
                case DATATYPE_UINT16:   StringHelper::appendValue( aValue, static_cast< sal_uInt16 >( nUValue ), rItemFmt.meFmtType );  break;
                case DATATYPE_INT32:    StringHelper::appendValue( aValue, static_cast< sal_Int32 >( nSValue ), rItemFmt.meFmtType );   break;
                case DATATYPE_UINT32:   StringHelper::appendValue( aValue, static_cast< sal_uInt32 >( nUValue ), rItemFmt.meFmtType );  break;
                case DATATYPE_INT64:    StringHelper::appendValue( aValue, nSValue, rItemFmt.meFmtType );                               break;
                case DATATYPE_UINT64:   StringHelper::appendValue( aValue, nUValue, rItemFmt.meFmtType );                               break;
                case DATATYPE_FLOAT:    StringHelper::appendValue( aValue, static_castfloat >( nSValue ), rItemFmt.meFmtType );       break;
                case DATATYPE_DOUBLE:   StringHelper::appendValue( aValue, static_castdouble >( nSValue ), rItemFmt.meFmtType );      break;
                default:;
            }
            StringHelper::appendToken( aItem, aValue, OOX_DUMP_ITEMSEP );
            if( !rItemFmt.maListName.isEmpty() )
            {
                OUString aValueName = rCfg.getName( rItemFmt.maListName, static_cast< sal_Int64 >( nUValue ) );
                StringHelper::appendToken( aItem, aValueName, OOX_DUMP_ITEMSEP );
            }
            StringHelper::enclose( aItem, '('')' );
            StringHelper::appendToken( aName, aItem );
            setFlag( nFound, nMask );
        }
    }
    setFlag( nKey, nFound, false );
    StringHelper::appendToken( aName, FlagsList::implGetName( rCfg, nKey ) );
    return aName.makeStringAndClear();
}

void CombiList::implIncludeList( const NameListBase& rList )
{
    ifconst CombiList* pCombiList = dynamic_castconst CombiList* >( &rList ) )
        maFmtMap = pCombiList->maFmtMap;
    FlagsList::implIncludeList( rList );
}

UnitConverter::UnitConverter( const SharedConfigData& rCfgData ) :
    NameListBase( rCfgData ),
    mfFactor( 1.0 )
{
}

void UnitConverter::implSetName( sal_Int64 /*nKey*/, const OUString& /*rName*/ )
{
    // nothing to do
}

OUString UnitConverter::implGetName( const Config& rCfg, sal_Int64 nKey ) const
{
    return implGetNameDbl( rCfg, static_castdouble >( nKey ) );
}

OUString UnitConverter::implGetNameDbl( const Config& /*rCfg*/, double fValue ) const
{
    OUStringBuffer aValue;
    StringHelper::appendDec( aValue, mfFactor * fValue );
    aValue.append( maUnitName );
    return aValue.makeStringAndClear();
}

void UnitConverter::implIncludeList( const NameListBase& /*rList*/ )
{
}

const NameListRef & NameListWrapper::getNameList( const Config& rCfg ) const
{
    if (!mxList)
        mxList = rCfg.getNameList( maName );
    return mxList;
}

SharedConfigData::SharedConfigData( const OUString& rFileName,
        const Reference< XComponentContext >& rxContext, StorageRef xRootStrg,
        OUString aSysFileName ) :
    mxContext( rxContext ),
    mxRootStrg(std::move( xRootStrg )),
    maSysFileName(std::move( aSysFileName )),
    mbLoaded( false )
{
    OUString aFileUrl = InputOutputHelper::convertFileNameToUrl( rFileName );
    if( !aFileUrl.isEmpty() )
    {
        sal_Int32 nNamePos = InputOutputHelper::getFileNamePos( aFileUrl );
        maConfigPath = aFileUrl.copy( 0, nNamePos );
        mbLoaded = readConfigFile( aFileUrl );
    }
}

SharedConfigData::~SharedConfigData()
{
}

const OUString* SharedConfigData::getOption( const OUString& rKey ) const
{
    ConfigDataMap::const_iterator aIt = maConfigData.find( rKey );
    return (aIt == maConfigData.end()) ? nullptr : &aIt->second;
}

void SharedConfigData::setNameList( const OUString& rListName, const NameListRef&&nbsp;rxList )
{
    if( !rListName.isEmpty() )
        maNameLists[ rListName ] = rxList;
}

void SharedConfigData::eraseNameList( const OUString& rListName )
{
    maNameLists.erase( rListName );
}

NameListRef SharedConfigData::getNameList( const OUString& rListName ) const
{
    NameListRef xList;
    NameListMap::const_iterator aIt = maNameLists.find( rListName );
    if( aIt != maNameLists.end() )
        xList = aIt->second;
    return xList;
}

bool SharedConfigData::implIsValid() const
{
    return mbLoaded && mxContext.is() && mxRootStrg && !maSysFileName.isEmpty();
}

void SharedConfigData::implProcessConfigItemStr(
        TextInputStream& rStrm, const OUString& rKey, const OUString& rData )
{
    if ( rKey == "include-config-file" )
        readConfigFile( maConfigPath + rData );
    else if ( rKey == "constlist" )
        readNameList< ConstList >( rStrm, rData );
    else if ( rKey == "multilist" )
        readNameList< MultiList >( rStrm, rData );
    else if ( rKey == "flagslist" )
        readNameList< FlagsList >( rStrm, rData );
    else if ( rKey == "combilist" )
        readNameList< CombiList >( rStrm, rData );
    else if ( rKey == "shortlist" )
        createShortList( rData );
    else if ( rKey == "unitconverter" )
        createUnitConverter( rData );
    else
        maConfigData[ rKey ] = rData;
}

bool SharedConfigData::readConfigFile( const OUString& rFileUrl )
{
    bool bLoaded = maConfigFiles.count( rFileUrl ) > 0;
    if( !bLoaded )
    {
        Reference< XInputStream > xInStrm = InputOutputHelper::openInputStream( mxContext, rFileUrl );
        TextInputStream aTxtStrm( mxContext, xInStrm, RTL_TEXTENCODING_UTF8 );
        if( !aTxtStrm.isEof() )
        {
            maConfigFiles.insert( rFileUrl );
            readConfigBlockContents( aTxtStrm );
            bLoaded = true;
        }
    }
    return bLoaded;
}

void SharedConfigData::createShortList( std::u16string_view rData )
{
    OUStringVector aDataVec;
    StringHelper::convertStringToStringList( aDataVec, rData, false );
    if( aDataVec.size() < 3 )
        return;

    sal_Int64 nStartKey;
    if( StringHelper::convertStringToInt( nStartKey, aDataVec[ 1 ] ) )
    {
        std::shared_ptr< MultiList > xList = createNameList< MultiList >( aDataVec[ 0 ] );
        if( xList )
        {
            aDataVec.erase( aDataVec.begin(), aDataVec.begin() + 2 );
            xList->setNamesFromVec( nStartKey, aDataVec );
        }
    }
}

void SharedConfigData::createUnitConverter( std::u16string_view rData )
{
    OUStringVector aDataVec;
    StringHelper::convertStringToStringList( aDataVec, rData, false );
    if( aDataVec.size() < 2 )
        return;

    OUString aFactor = aDataVec[ 1 ];
    bool bRecip = aFactor.startsWith("/");
    if( bRecip )
        aFactor = aFactor.copy( 1 );
    double fFactor;
    if( StringHelper::convertStringToDouble( fFactor, aFactor ) && (fFactor != 0.0) )
    {
        std::shared_ptr< UnitConverter > xList = createNameList< UnitConverter >( aDataVec[ 0 ] );
        if( xList )
        {
            xList->setFactor( bRecip ? (1.0 / fFactor) : fFactor );
            if( aDataVec.size() >= 3 )
                xList->setUnitName( aDataVec[ 2 ] );
        }
    }
}

Config::Config( const char* pcEnvVar, const FilterBase& rFilter )
{
    construct( pcEnvVar, rFilter );
}

Config::Config( const char* pcEnvVar, const Reference< XComponentContext >& rxContext, const StorageRef& rxRootStrg, const OUString& rSysFileName )
{
    construct( pcEnvVar, rxContext, rxRootStrg, rSysFileName );
}

Config::~Config()
{
}

void Config::construct( const char* pcEnvVar, const FilterBase& rFilter )
{
    if( !rFilter.getFileUrl().isEmpty() )
        construct( pcEnvVar, rFilter.getComponentContext(), rFilter.getStorage(), rFilter.getFileUrl() );
}

void Config::construct( const char* pcEnvVar, const Reference< XComponentContext >& rxContext, const StorageRef& rxRootStrg, const OUString& rSysFileName )
{
    if( pcEnvVar && rxRootStrg && !rSysFileName.isEmpty() )
        ifconst char* pcFileName = ::getenv( pcEnvVar ) )
            mxCfgData = std::make_shared<SharedConfigData>( OUString::createFromAscii( pcFileName ), rxContext, rxRootStrg, rSysFileName );
}

const OUString& Config::getStringOption( const String& rKey, const OUString& ;rDefault ) const
{
    const OUString* pData = implGetOption( rKey );
    return pData ? *pData : rDefault;
}

bool Config::getBoolOption( const String& rKey, bool bDefault ) const
{
    const OUString* pData = implGetOption( rKey );
    return pData ? StringHelper::convertStringToBool( *pData ) : bDefault;
}

bool Config::isDumperEnabled() const
{
    return getBoolOption( "enable-dumper"false );
}

bool Config::isImportEnabled() const
{
    return getBoolOption( "enable-import"true );
}

void Config::eraseNameList( const String& rListName )
{
    mxCfgData->eraseNameList( rListName );
}

NameListRef Config::getNameList( const String& rListName ) const
{
    return mxCfgData->getNameList( rListName );
}

bool Config::implIsValid() const
{
    return isValid( mxCfgData );
}

const OUString* Config::implGetOption( const OUString& rKey ) const
{
    return mxCfgData->getOption( rKey );
}

Output::Output( const Reference< XComponentContext >& rxContext, const OUString& rFileName ) :
    mxStrm( InputOutputHelper::openTextOutputStream( rxContext, rFileName, RTL_TEXTENCODING_UTF8 ) ),
    mnCol( 0 ),
    mnItemLevel( 0 ),
    mnMultiLevel( 0 ),
    mnItemIdx( 0 ),
    mnLastItem( 0 )
{
    if( mxStrm.is() )
        mxStrm->writeString( OUString( OOX_DUMP_BOM ) );
}

void Output::newLine()
{
    if( maLine.getLength() > 0 )
    {
        mxStrm->writeString( maIndent );
        maLine.append( '\n' );
        mxStrm->writeString( maLine.makeStringAndClear() );
        mnCol = 0;
        mnLastItem = 0;
    }
}

void Output::emptyLine( size_t nCount )
{
    for( size_t nIdx = 0; nIdx < nCount; ++nIdx )
        mxStrm->writeString( OUString('\n') );
}

void Output::incIndent()
{
    OUStringBuffer aBuffer( maIndent );
    StringHelper::appendChar( aBuffer, ' ', OOX_DUMP_INDENT );
    maIndent = aBuffer.makeStringAndClear();
}

void Output::decIndent()
{
    if( maIndent.getLength() >= OOX_DUMP_INDENT )
        maIndent = maIndent.copy( OOX_DUMP_INDENT );
}

void Output::startTable( sal_Int32 nW1 )
{
    startTable( 1, &nW1 );
}

void Output::startTable( sal_Int32 nW1, sal_Int32 nW2 )
{
    sal_Int32 pnColWidths[ 2 ];
    pnColWidths[ 0 ] = nW1;
    pnColWidths[ 1 ] = nW2;
    startTable( 2, pnColWidths );
}

void Output::startTable( sal_Int32 nW1, sal_Int32 nW2, sal_Int32 nW3, sal_Int32 nW4 )
{
    sal_Int32 pnColWidths[ 4 ];
    pnColWidths[ 0 ] = nW1;
    pnColWidths[ 1 ] = nW2;
    pnColWidths[ 2 ] = nW3;
    pnColWidths[ 3 ] = nW4;
    startTable( 4, pnColWidths );
}

void Output::startTable( size_t nColCount, const sal_Int32* pnColWidths )
{
    maColPos.clear();
    maColPos.push_back( 0 );
    sal_Int32 nColPos = 0;
    for( size_t nCol = 0; nCol < nColCount; ++nCol )
    {
        nColPos = nColPos + pnColWidths[ nCol ];
        maColPos.push_back( nColPos );
    }
}

void Output::tab()
{
    tab( mnCol + 1 );
}

void Output::tab( size_t nCol )
{
    mnCol = nCol;
    if( mnCol < maColPos.size() )
    {
        sal_Int32 nColPos = maColPos[ mnCol ];
        if( maLine.getLength() >= nColPos )
            maLine.setLength( ::std::max< sal_Int32 >( nColPos - 1, 0 ) );
        StringHelper::appendChar( maLine, ' ', nColPos - maLine.getLength() );
    }
    else
    {
        StringHelper::appendChar( maLine, ' ', 2 );
    }
}

void Output::endTable()
{
    maColPos.clear();
}

void Output::resetItemIndex( sal_Int64 nIdx )
{
    mnItemIdx = nIdx;
}

void Output::startItem( const String& rItemName )
{
    if( mnItemLevel == 0 )
    {
        if( (mnMultiLevel > 0) && (maLine.getLength() > 0) )
            tab();
        if( rItemName.has() )
        {
            writeItemName( rItemName );
            writeChar( OOX_DUMP_ITEMSEP );
        }
    }
    ++mnItemLevel;
    mnLastItem = maLine.getLength();
}

void Output::contItem()
{
    if( mnItemLevel > 0 )
    {
        if( (maLine.getLength() == 0) || (maLine[ maLine.getLength() - 1 ] != OOX_DUMP_ITEMSEP) )
            writeChar( OOX_DUMP_ITEMSEP );
        mnLastItem = maLine.getLength();
    }
}

void Output::endItem()
{
    if( mnItemLevel > 0 )
    {
        maLastItem = maLine.copy( mnLastItem ).makeStringAndClear();
        if( maLastItem.isEmpty() && mnLastItem > 0 && maLine[ mnLastItem - 1 ] == OOX_DUMP_ITEMSEP )
            maLine.setLength( mnLastItem - 1 );
        --mnItemLevel;
    }
    if( mnItemLevel == 0 )
    {
        if( mnMultiLevel == 0 )
            newLine();
    }
    else
        contItem();
}

void Output::startMultiItems()
{
    ++mnMultiLevel;
}

void Output::endMultiItems()
{
    if( mnMultiLevel > 0 )
        --mnMultiLevel;
    if( mnMultiLevel == 0 )
        newLine();
}

void Output::writeChar( sal_Unicode cChar, sal_Int32 nCount )
{
    StringHelper::appendEncChar( maLine, cChar, nCount );
}

void Output::writeAscii( const char* pcStr )
{
    if( pcStr )
        maLine.appendAscii( pcStr );
}

void Output::writeString( std::u16string_view rStr )
{
    StringHelper::appendEncString( maLine, rStr );
}

void Output::writeArray( const sal_uInt8* pnData, std::size_t nSize, sal_Unicode cSep )
{
    const sal_uInt8* pnEnd = pnData ? (pnData + nSize) : nullptr;
    forconst sal_uInt8* pnByte = pnData; pnByte < pnEnd; ++pnByte )
    {
        if( pnByte > pnData )
            writeChar( cSep );
        writeHex( *pnByte, false );
    }
}

void Output::writeBool( bool bData )
{
    StringHelper::appendBool( maLine, bData );
}

void Output::writeDateTime( const util::DateTime& rDateTime )
{
    writeDec( rDateTime.Year, 4, '0' );
    writeChar( '-' );
    writeDec( rDateTime.Month, 2, '0' );
    writeChar( '-' );
    writeDec( rDateTime.Day, 2, '0' );
    writeChar( 'T' );
    writeDec( rDateTime.Hours, 2, '0' );
    writeChar( ':' );
    writeDec( rDateTime.Minutes, 2, '0' );
    writeChar( ':' );
    writeDec( rDateTime.Seconds, 2, '0' );
}

bool Output::implIsValid() const
{
    return mxStrm.is();
}

void Output::writeItemName( const String& rItemName )
{
    if( rItemName.has() && (rItemName[ 0 ] == '#') )
    {
        writeString( rItemName.subView( 1 ) );
        StringHelper::appendIndex( maLine, mnItemIdx++ );
    }
    else
        writeString( rItemName );
}

StorageIterator::StorageIterator( StorageRef xStrg ) :
    mxStrg(std::move( xStrg ))
{
    if( mxStrg )
        mxStrg->getElementNames( maNames );
    maIt = maNames.begin();
}

StorageIterator::~StorageIterator()
{
}

StorageIterator& StorageIterator::operator++()
{
    if( maIt != maNames.end() )
        ++maIt;
    return *this;
}

OUString StorageIterator::getName() const
{
    OUString aName;
    if( maIt != maNames.end() )
        aName = *maIt;
    return aName;
}

bool StorageIterator::isStream() const
{
    return isValid() && mxStrg->openInputStream( *maIt ).is();
}

bool StorageIterator::isStorage() const
{
    if( !isValid() )
        return false;
    StorageRef xStrg = mxStrg->openSubStorage( *maIt, false );
    return xStrg && xStrg->isStorage();
}

bool StorageIterator::implIsValid() const
{
    return mxStrg && mxStrg->isStorage() && (maIt != maNames.end());
}

ObjectBase::~ObjectBase()
{
}

void ObjectBase::construct( const ConfigRef& rxConfig )
{
    mxConfig = rxConfig;
}

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

void ObjectBase::dump()
{
    if( isValid() )
        implDump();
}

bool ObjectBase::implIsValid() const
{
    return isValid( mxConfig );
}

void ObjectBase::implDump()
{
}

void StorageObjectBase::construct( const ObjectBase& rParent, const StorageRef& ;rxStrg, const OUString& rSysPath )
{
    ObjectBase::construct( rParent );
    mxStrg = rxStrg;
    maSysPath = rSysPath;
}

void StorageObjectBase::construct( const ObjectBase& rParent )
{
    ObjectBase::construct( rParent );
    if( ObjectBase::implIsValid() )
    {
        mxStrg = cfg().getRootStorage();
        maSysPath = cfg().getSysFileName();
    }
}

bool StorageObjectBase::implIsValid() const
{
    return mxStrg && !maSysPath.isEmpty() && ObjectBase::implIsValid();
}

void StorageObjectBase::implDump()
{
    bool bIsStrg = mxStrg->isStorage();
    bool bIsRoot = mxStrg->isRootStorage();
    Reference< XInputStream > xBaseStrm;
    if( !bIsStrg )
        xBaseStrm = mxStrg->openInputStream( OUString() );

    OUString aSysOutPath = maSysPath;
    if( bIsRoot ) try
    {
        aSysOutPath += OOX_DUMP_DUMPEXT;
        Reference<XSimpleFileAccess3> xFileAccess(SimpleFileAccess::create(getContext()));
        xFileAccess->kill( aSysOutPath );
    }
    catch( Exception& )
    {
    }

    if( bIsStrg )
    {
        extractStorage( mxStrg, OUString(), aSysOutPath );
    }
    else if( xBaseStrm.is() )
    {
        BinaryInputStreamRef xInStrm( std::make_shared<BinaryXInputStream>( xBaseStrm, false ) );
        xInStrm->seekToStart();
        implDumpBaseStream( xInStrm, aSysOutPath );
    }
}

void StorageObjectBase::implDumpStream( const Reference< XInputStream >&, const OUString&, const OUString&, const OUString& )
{
}

void StorageObjectBase::implDumpStorage( const StorageRef& rxStrg, const OUString&&nbsp;rStrgPath, const OUString& rSysPath )
{
    extractStorage( rxStrg, rStrgPath, rSysPath );
}

void StorageObjectBase::implDumpBaseStream( const BinaryInputStreamRef&, const OUString& )
{
}

void StorageObjectBase::addPreferredStream( const String& rStrmName )
{
    if( rStrmName.has() )
        maPreferred.emplace_back( rStrmName, false );
}

void StorageObjectBase::addPreferredStorage( const String& rStrgPath )
{
    if( rStrgPath.has() )
        maPreferred.emplace_back( rStrgPath, true );
}

OUString StorageObjectBase::getSysFileName(
    std::u16string_view rStrmName, std::u16string_view rSysOutPath )
{
    // encode all characters < 0x20
    OUStringBuffer aBuffer;
    StringHelper::appendEncString( aBuffer, rStrmName, false );

    // replace all characters reserved in file system
    OUString aFileName = aBuffer.makeStringAndClear();
    static const sal_Unicode spcReserved[] = { '/''\\'':''*''?''<''>''|' };
    for(const sal_Unicode cChar : spcReserved)
        aFileName = aFileName.replace(cChar, '_');

    // build full path
    return OUString::Concat(rSysOutPath) + "/" + aFileName;
}

void StorageObjectBase::extractStream( StorageBase& rStrg, const OUString& rStrgPath, const OUString& rStrmName, const OUString& rSysFileName )
{
    BinaryXInputStream aInStrm( rStrg.openInputStream( rStrmName ), true );
    if( !aInStrm.isEof() )
    {
        BinaryXOutputStream aOutStrm( InputOutputHelper::openOutputStream( getContext(), rSysFileName ), true );
        if( !aOutStrm.isEof() )
            aInStrm.copyToStream( aOutStrm );
    }
    Reference< XInputStream > xDumpStrm = InputOutputHelper::openInputStream( getContext(), rSysFileName );
    if( xDumpStrm.is() )
        implDumpStream( xDumpStrm, rStrgPath, rStrmName, rSysFileName );
}

void StorageObjectBase::extractStorage( const StorageRef& rxStrg, const OUString&&nbsp;rStrgPath, const OUString& rSysPath )
{
    // create directory in file system
    ::osl::FileBase::RC eRes = ::osl::Directory::create( rSysPath );
    if( (eRes != ::osl::FileBase::E_None) && (eRes != ::osl::FileBase::E_EXIST) )
        return;

    // process preferred storages and streams in root storage first
    if( rStrgPath.isEmpty() )
    {
        for (auto const& elemPreferred : maPreferred)
            extractItem( rxStrg, rStrgPath, elemPreferred.maName, rSysPath, elemPreferred.mbStorage, !elemPreferred.mbStorage );
    }

    // process children of the storage
    for( StorageIterator aIt( rxStrg ); aIt.isValid(); ++aIt )
    {
        // skip processed preferred items
        OUString aItemName = aIt.getName();
        bool bFound = false;
        if( rStrgPath.isEmpty() )
        {
            for (auto const& elemPreferred : maPreferred)
            {
                bFound = elemPreferred.maName == aItemName;
                if (bFound)
                    break;
            }
        }
        if( !bFound )
            extractItem( rxStrg, rStrgPath, aItemName, rSysPath, aIt.isStorage(), aIt.isStream() );
    }
}

void StorageObjectBase::extractItem( const StorageRef& rxStrg, const OUString& rStrgPath, const OUString& rItemName, std::u16string_view rSysPath, bool bIsStrg, bool bIsStrm )
{
    OUString aSysFileName = getSysFileName( rItemName, rSysPath );
    if( bIsStrg )
    {
        OUStringBuffer aStrgPath( rStrgPath );
        StringHelper::appendToken( aStrgPath, rItemName, '/' );
        implDumpStorage( rxStrg->openSubStorage( rItemName, false ), aStrgPath.makeStringAndClear(), aSysFileName );
    }
    else if( bIsStrm )
    {
        extractStream( *rxStrg, rStrgPath, rItemName, aSysFileName );
    }
}

OutputObjectBase::~OutputObjectBase()
{
}

void OutputObjectBase::construct( const ObjectBase& rParent, const OUString& rSysFileName )
{
    ObjectBase::construct( rParent );
    if( ObjectBase::implIsValid() )
    {
        maSysFileName = rSysFileName;
        mxOut = std::make_shared<Output>( getContext(), rSysFileName + OOX_DUMP_DUMPEXT );
    }
}

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

bool OutputObjectBase::implIsValid() const
{
    return isValid( mxOut ) && ObjectBase::implIsValid();
}

void OutputObjectBase::writeEmptyItem( const String& rName )
{
    ItemGuard aItem( mxOut, rName );
}

void OutputObjectBase::writeInfoItem( const String& rName, const String& rData )
{
    ItemGuard aItem( mxOut, rName );
    mxOut->writeString( rData );
}

void OutputObjectBase::writeCharItem( const String& rName, sal_Unicode cData )
{
    ItemGuard aItem( mxOut, rName );
    mxOut->writeChar( OOX_DUMP_STRQUOTE );
    mxOut->writeChar( cData );
    mxOut->writeChar( OOX_DUMP_STRQUOTE );
}

void OutputObjectBase::writeStringItem( const String& rName, std::u16string_view rData )
{
    ItemGuard aItem( mxOut, rName );
    mxOut->writeAscii( "(len=" );
    mxOut->writeDec( sal_Int32(rData.size()) );
    mxOut->writeAscii( ")," );
    OUStringBuffer aValue( rData.substr( 0, ::std::min( sal_Int32(rData.size()), OOX_DUMP_MAXSTRLEN ) ) );
    StringHelper::enclose( aValue, OOX_DUMP_STRQUOTE );
    mxOut->writeString( aValue.makeStringAndClear() );
    if( rData.size() > OOX_DUMP_MAXSTRLEN )
        mxOut->writeAscii( ",cut" );
}

void OutputObjectBase::writeArrayItem( const String& rName, const sal_uInt8* pnData, std::size_t nSize, sal_Unicode cSep )
{
    ItemGuard aItem( mxOut, rName );
    mxOut->writeArray( pnData, nSize, cSep );
}

void OutputObjectBase::writeDateTimeItem( const String& rName, const util::DateTime& rDateTime )
{
    ItemGuard aItem( mxOut, rName );
    mxOut->writeDateTime( rDateTime );
}

void OutputObjectBase::writeGuidItem( const String& rName, const OUString& rGuid )
{
    ItemGuard aItem( mxOut, rName );
    mxOut->writeString( rGuid );
    aItem.cont();
    mxOut->writeString( cfg().getStringOption( rGuid, OUString() ) );
}

InputObjectBase::~InputObjectBase()
{
}

void InputObjectBase::construct( const ObjectBase& rParent, const BinaryInputStreamRef& rxStrm, const OUString& rSysFileName )
{
    OutputObjectBase::construct( rParent, rSysFileName );
    mxStrm = rxStrm;
}

void InputObjectBase::construct( const OutputObjectBase& rParent, const BinaryInputStreamRef& rxStrm )
{
    OutputObjectBase::construct( rParent );
    mxStrm = rxStrm;
}

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

bool InputObjectBase::implIsValid() const
{
    return mxStrm && OutputObjectBase::implIsValid();
}

void InputObjectBase::skipBlock( sal_Int64 nBytes, bool bShowSize )
{
    sal_Int64 nEndPos = ::std::min< sal_Int64 >( mxStrm->tell() + nBytes, mxStrm->size() );
    if( mxStrm->tell() < nEndPos )
    {
        if( bShowSize )
            writeDecItem( "skipped-data-size"static_cast< sal_uInt64 >( nEndPos - mxStrm->tell() ) );
        mxStrm->seek( nEndPos );
    }
}

void InputObjectBase::dumpRawBinary( sal_Int64 nBytes, bool bShowOffset, bool bStream )
{
    TableGuard aTabGuard( mxOut,
        bShowOffset ? 12 : 0,
        3 * OOX_DUMP_BYTESPERLINE / 2 + 1,
        3 * OOX_DUMP_BYTESPERLINE / 2 + 1,
        OOX_DUMP_BYTESPERLINE / 2 + 1 );

    sal_Int64 nMaxShowSize = cfg().getIntOption< sal_Int64 >(
        bStream ? "max-binary-stream-size" : "max-binary-data-size", SAL_MAX_INT64 );

    bool bSeekable = mxStrm->size() >= 0;
    sal_Int64 nEndPos = bSeekable ? ::std::min< sal_Int64 >( mxStrm->tell() + nBytes, mxStrm->size() ) : 0;
    sal_Int64 nDumpEnd = bSeekable ? ::std::min< sal_Int64 >( mxStrm->tell() + nMaxShowSize, nEndPos ) : nMaxShowSize;
    sal_Int64 nPos = bSeekable ? mxStrm->tell() : 0;
    bool bLoop = true;

    while( bLoop && (nPos < nDumpEnd) )
    {
        mxOut->writeHex( static_cast< sal_uInt32 >( nPos ) );
        mxOut->tab();

        sal_uInt8 pnLineData[ OOX_DUMP_BYTESPERLINE ];
        sal_Int32 nLineSize = bSeekable ? ::std::min( static_cast< sal_Int32 >( nDumpEnd - mxStrm->tell() ), OOX_DUMP_BYTESPERLINE ) : OOX_DUMP_BYTESPERLINE;
        sal_Int32 nReadSize = mxStrm->readMemory( pnLineData, nLineSize );
        bLoop = nReadSize == nLineSize;
        nPos += nReadSize;

        if( nReadSize > 0 )
        {
            const sal_uInt8* pnByte = nullptr;
            const sal_uInt8* pnEnd = nullptr;
            for( pnByte = pnLineData, pnEnd = pnLineData + nReadSize; pnByte != pnEnd; ++pnByte )
            {
                if( (pnByte - pnLineData) == (OOX_DUMP_BYTESPERLINE / 2) ) mxOut->tab();
                mxOut->writeHex( *pnByte, false );
                mxOut->writeChar( ' ' );
            }

            aTabGuard.tab( 3 );
            for( pnByte = pnLineData, pnEnd = pnLineData + nReadSize; pnByte != pnEnd; ++pnByte )
            {
                if( (pnByte - pnLineData) == (OOX_DUMP_BYTESPERLINE / 2) ) mxOut->tab();
                mxOut->writeChar( static_cast< sal_Unicode >( (*pnByte < 0x20) ? '.' : *pnByte ) );
            }
            mxOut->newLine();
        }
    }

    // skip undumped data
    if( bSeekable )
        skipBlock( nEndPos - mxStrm->tell() );
}

void InputObjectBase::dumpBinary( const String& rName, sal_Int64 nBytes, bool bShowOffset )
{
    {
        MultiItemsGuard aMultiGuard( mxOut );
        writeEmptyItem( rName );
        writeDecItem( "size", nBytes );
    }
    IndentGuard aIndGuard( mxOut );
    dumpRawBinary( nBytes, bShowOffset );
}

void InputObjectBase::dumpRemaining( sal_Int64 nBytes )
{
    if( nBytes > 0 )
    {
        if( cfg().getBoolOption( "show-trailing-unknown"true ) )
            dumpBinary( "remaining-data", nBytes, false );
        else
            skipBlock( nBytes );
    }
}

void InputObjectBase::dumpRemainingTo( sal_Int64 nPos )
{
    if( mxStrm->isEof() || (mxStrm->tell() > nPos) )
        writeInfoItem( "stream-state", OOX_DUMP_ERR_STREAM );
    else
        dumpRemaining( nPos - mxStrm->tell() );
    mxStrm->seek( nPos );
}

void InputObjectBase::dumpRemainingStream()
{
    dumpRemainingTo( mxStrm->size() );
}

--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=95 H=95 G=94

¤ Dauer der Verarbeitung: 0.23 Sekunden  ¤

*© Formatika GbR, Deutschland






Entwurf

Ziele

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Ergonomie der
Schnittstellen

Diese beiden folgenden Angebotsgruppen bietet das Unternehmen

Angebot

Hier finden Sie eine Liste der Produkte des Unternehmens






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge