summaryrefslogtreecommitdiffstats
path: root/oox/source/helper
diff options
context:
space:
mode:
Diffstat (limited to 'oox/source/helper')
-rw-r--r--oox/source/helper/attributelist.cxx372
-rw-r--r--oox/source/helper/binaryinputstream.cxx322
-rw-r--r--oox/source/helper/binaryoutputstream.cxx184
-rw-r--r--oox/source/helper/binarystreambase.cxx146
-rw-r--r--oox/source/helper/containerhelper.cxx126
-rw-r--r--oox/source/helper/grabbagstack.cxx82
-rw-r--r--oox/source/helper/graphichelper.cxx327
-rw-r--r--oox/source/helper/modelobjecthelper.cxx170
-rw-r--r--oox/source/helper/ooxresid.cxx17
-rw-r--r--oox/source/helper/progressbar.cxx167
-rw-r--r--oox/source/helper/propertymap.cxx953
-rw-r--r--oox/source/helper/propertyset.cxx150
-rw-r--r--oox/source/helper/storagebase.cxx256
-rw-r--r--oox/source/helper/textinputstream.cxx208
-rw-r--r--oox/source/helper/zipstorage.cxx203
15 files changed, 3683 insertions, 0 deletions
diff --git a/oox/source/helper/attributelist.cxx b/oox/source/helper/attributelist.cxx
new file mode 100644
index 0000000000..7a973975f3
--- /dev/null
+++ b/oox/source/helper/attributelist.cxx
@@ -0,0 +1,372 @@
+/* -*- 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/helper/attributelist.hxx>
+
+#include <comphelper/string.hxx>
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <sax/fastattribs.hxx>
+#include <oox/token/tokenmap.hxx>
+#include <o3tl/string_view.hxx>
+
+namespace oox {
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::xml::sax;
+
+namespace {
+
+const sal_Int32 XSTRING_ENCCHAR_LEN = 7;
+
+bool lclAddHexDigit( sal_Unicode& orcChar, sal_Unicode cDigit, int nBitShift )
+{
+ if( ('0' <= cDigit) && (cDigit <= '9') ) { orcChar |= ((cDigit - '0') << nBitShift); return true; }
+ if( ('a' <= cDigit) && (cDigit <= 'f') ) { orcChar |= ((cDigit - 'a' + 10) << nBitShift); return true; }
+ if( ('A' <= cDigit) && (cDigit <= 'F') ) { orcChar |= ((cDigit - 'A' + 10) << nBitShift); return true; }
+ return false;
+}
+
+sal_Unicode lclGetXChar( const sal_Unicode*& rpcStr, const sal_Unicode* pcEnd )
+{
+ sal_Unicode cChar = 0;
+ if( (pcEnd - rpcStr >= XSTRING_ENCCHAR_LEN) &&
+ (rpcStr[ 0 ] == '_') &&
+ (rpcStr[ 1 ] == 'x') &&
+ (rpcStr[ 6 ] == '_') &&
+ lclAddHexDigit( cChar, rpcStr[ 2 ], 12 ) &&
+ lclAddHexDigit( cChar, rpcStr[ 3 ], 8 ) &&
+ lclAddHexDigit( cChar, rpcStr[ 4 ], 4 ) &&
+ lclAddHexDigit( cChar, rpcStr[ 5 ], 0 ) )
+ {
+ rpcStr += XSTRING_ENCCHAR_LEN;
+ return cChar;
+ }
+ return *rpcStr++;
+}
+
+} // namespace
+
+#define STRING_TO_TOKEN(color) if (sColorName == u"" #color) return XML_##color
+sal_Int32 getHighlightColorTokenFromString(std::u16string_view sColorName)
+{
+ STRING_TO_TOKEN(black);
+ STRING_TO_TOKEN(blue);
+ STRING_TO_TOKEN(cyan);
+ STRING_TO_TOKEN(darkBlue);
+ STRING_TO_TOKEN(darkCyan);
+ STRING_TO_TOKEN(darkGreen);
+ STRING_TO_TOKEN(darkMagenta);
+ STRING_TO_TOKEN(darkRed);
+ STRING_TO_TOKEN(darkYellow);
+ STRING_TO_TOKEN(darkGray);
+ STRING_TO_TOKEN(green);
+ STRING_TO_TOKEN(lightGray);
+ STRING_TO_TOKEN(magenta);
+ STRING_TO_TOKEN(red);
+ STRING_TO_TOKEN(white);
+ STRING_TO_TOKEN(yellow);
+ STRING_TO_TOKEN(none);
+
+ return XML_TOKEN_INVALID;
+}
+
+sal_Int32 AttributeConversion::decodeToken( std::u16string_view rValue )
+{
+ return TokenMap::getTokenFromUnicode( rValue );
+}
+
+OUString AttributeConversion::decodeXString( const OUString& rValue )
+{
+ // string shorter than one encoded character - no need to decode
+ if( rValue.getLength() < XSTRING_ENCCHAR_LEN )
+ return rValue;
+ if (rValue.indexOf(u"_x") == -1)
+ return rValue;
+
+ OUStringBuffer aBuffer;
+ const sal_Unicode* pcStr = rValue.getStr();
+ const sal_Unicode* pcEnd = pcStr + rValue.getLength();
+ while( pcStr < pcEnd )
+ aBuffer.append( lclGetXChar( pcStr, pcEnd ) );
+ return comphelper::string::sanitizeStringSurrogates(aBuffer.makeStringAndClear());
+}
+
+sal_Int32 AttributeConversion::decodeInteger( std::u16string_view rValue )
+{
+ return o3tl::toInt32(rValue);
+}
+
+sal_uInt32 AttributeConversion::decodeUnsigned( std::u16string_view rValue )
+{
+ return getLimitedValue< sal_uInt32, sal_Int64 >( o3tl::toInt64(rValue), 0, SAL_MAX_UINT32 );
+}
+
+sal_Int64 AttributeConversion::decodeHyper( std::u16string_view rValue )
+{
+ return o3tl::toInt64(rValue);
+}
+
+sal_Int32 AttributeConversion::decodeIntegerHex( std::u16string_view rValue )
+{
+ // It looks like all Office Open XML attributes containing hexadecimal
+ // values are based on xsd:hexBinary and so use an unsigned representation:
+ return static_cast< sal_Int32 >(o3tl::toUInt32(rValue, 16));
+ //TODO: Change this function to return sal_uInt32 and get rid of the
+ // cast, but that will have a ripple effect
+}
+
+AttributeList::AttributeList( const Reference< XFastAttributeList >& rxAttribs ) :
+ mxAttribs( rxAttribs ),
+ mpAttribList( nullptr )
+{
+ OSL_ENSURE( mxAttribs.is(), "AttributeList::AttributeList - missing attribute list interface" );
+}
+
+sax_fastparser::FastAttributeList *AttributeList::getAttribList() const
+{
+ if( mpAttribList == nullptr )
+ {
+ mpAttribList = &sax_fastparser::castToFastAttributeList( mxAttribs );
+ }
+ return mpAttribList;
+}
+
+bool AttributeList::hasAttribute( sal_Int32 nAttrToken ) const
+{
+ return mxAttribs->hasAttribute( nAttrToken );
+}
+
+oox::drawingml::Color AttributeList::getHighlightColor(sal_Int32 nAttrToken) const
+{
+ OUString sColorVal = mxAttribs->getValue(nAttrToken);
+ oox::drawingml::Color aColor;
+ aColor.setHighlight(getHighlightColorTokenFromString(sColorVal));
+ return aColor;
+}
+
+// optional return values -----------------------------------------------------
+
+std::optional< sal_Int32 > AttributeList::getToken( sal_Int32 nAttrToken ) const
+{
+ sal_Int32 nToken = mxAttribs->getOptionalValueToken( nAttrToken, XML_TOKEN_INVALID );
+ return nToken == XML_TOKEN_INVALID ? std::optional< sal_Int32 >() : std::optional< sal_Int32 >( nToken );
+}
+
+std::optional< OUString > AttributeList::getString( sal_Int32 nAttrToken ) const
+{
+ // check if the attribute exists (empty string may be different to missing attribute)
+ if( mxAttribs->hasAttribute( nAttrToken ) )
+ return std::optional< OUString >( mxAttribs->getOptionalValue( nAttrToken ) );
+ return std::optional< OUString >();
+}
+
+OUString AttributeList::getStringDefaulted( sal_Int32 nAttrToken ) const
+{
+ // check if the attribute exists (empty string may be different to missing attribute)
+ if( mxAttribs->hasAttribute( nAttrToken ) )
+ return mxAttribs->getOptionalValue( nAttrToken );
+ return OUString();
+}
+
+std::optional< OUString > AttributeList::getXString( sal_Int32 nAttrToken ) const
+{
+ // check if the attribute exists (empty string may be different to missing attribute)
+ if( mxAttribs->hasAttribute( nAttrToken ) )
+ return std::optional< OUString >( AttributeConversion::decodeXString( mxAttribs->getOptionalValue( nAttrToken ) ) );
+ return std::optional< OUString >();
+}
+
+std::optional< double > AttributeList::getDouble( sal_Int32 nAttrToken ) const
+{
+ double nValue;
+ bool bValid = getAttribList()->getAsDouble( nAttrToken, nValue );
+ return bValid ? std::optional< double >( nValue ) : std::optional< double >();
+}
+
+std::optional< sal_Int32 > AttributeList::getInteger( sal_Int32 nAttrToken ) const
+{
+ sal_Int32 nValue;
+ bool bValid = getAttribList()->getAsInteger( nAttrToken, nValue );
+ return bValid ? std::optional< sal_Int32 >( nValue ) : std::optional< sal_Int32 >();
+}
+
+std::optional< sal_uInt32 > AttributeList::getUnsigned( sal_Int32 nAttrToken ) const
+{
+ OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
+ bool bValid = !aValue.isEmpty();
+ return bValid ? std::optional< sal_uInt32 >( AttributeConversion::decodeUnsigned( aValue ) ) : std::optional< sal_uInt32 >();
+}
+
+std::optional< sal_Int64 > AttributeList::getHyper( sal_Int32 nAttrToken ) const
+{
+ std::string_view aValue = getView( nAttrToken );
+ bool bValid = !aValue.empty();
+ return bValid ? std::optional< sal_Int64 >( o3tl::toInt64( aValue ) ) : std::optional< sal_Int64 >();
+}
+
+std::optional< sal_Int32 > AttributeList::getIntegerHex( sal_Int32 nAttrToken ) const
+{
+ OUString aValue = mxAttribs->getOptionalValue( nAttrToken );
+ bool bValid = !aValue.isEmpty();
+ return bValid ? std::optional< sal_Int32 >( AttributeConversion::decodeIntegerHex( aValue ) ) : std::optional< sal_Int32 >();
+}
+
+std::optional< bool > AttributeList::getBool( sal_Int32 nAttrToken ) const
+{
+ std::string_view pAttr;
+
+ // catch the common cases as quickly as possible first
+ bool bHasAttr = getAttribList()->getAsView( nAttrToken, pAttr );
+ if( !bHasAttr )
+ return std::optional< bool >();
+ if( pAttr == "false" )
+ return std::optional< bool >( false );
+ if( pAttr == "true" )
+ return std::optional< bool >( true );
+
+ // now for all the crazy stuff
+
+ // boolean attributes may be "t", "f", "true", "false", "on", "off", "1", or "0"
+ switch( getToken( nAttrToken, XML_TOKEN_INVALID ) )
+ {
+ case XML_t: return std::optional< bool >( true ); // used in VML
+ case XML_true: return std::optional< bool >( true );
+ case XML_on: return std::optional< bool >( true );
+ case XML_f: return std::optional< bool >( false ); // used in VML
+ case XML_false: return std::optional< bool >( false );
+ case XML_off: return std::optional< bool >( false );
+ }
+ std::optional< sal_Int32 > onValue = getInteger( nAttrToken );
+ return onValue.has_value() ? std::optional< bool >( onValue.value() != 0 ) : std::optional< bool >();
+}
+
+std::optional< util::DateTime > AttributeList::getDateTime( sal_Int32 nAttrToken ) const
+{
+ std::string_view aValue = getView( nAttrToken );
+ util::DateTime aDateTime;
+ bool bValid = (aValue.size() == 19 || (aValue.size() == 20 && aValue[19] == 'Z')) &&
+ (aValue[ 4 ] == '-') && (aValue[ 7 ] == '-') && (aValue[ 10 ] == 'T') &&
+ (aValue[ 13 ] == ':') && (aValue[ 16 ] == ':');
+ if (!bValid)
+ {
+ SAL_WARN("oox", "bad date string: " << aValue);
+ return std::optional< util::DateTime >();
+ }
+ aDateTime.Year = static_cast< sal_uInt16 >( o3tl::toInt32(aValue.substr( 0, 4 )) );
+ aDateTime.Month = static_cast< sal_uInt16 >( o3tl::toInt32(aValue.substr( 5, 2 )) );
+ aDateTime.Day = static_cast< sal_uInt16 >( o3tl::toInt32(aValue.substr( 8, 2 )) );
+ aDateTime.Hours = static_cast< sal_uInt16 >( o3tl::toInt32(aValue.substr( 11, 2 )) );
+ aDateTime.Minutes = static_cast< sal_uInt16 >( o3tl::toInt32(aValue.substr( 14, 2 )) );
+ aDateTime.Seconds = static_cast< sal_uInt16 >( o3tl::toInt32(aValue.substr( 17, 2 )) );
+ return std::optional< util::DateTime >( aDateTime );
+}
+
+// defaulted return values ----------------------------------------------------
+
+sal_Int32 AttributeList::getToken( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
+{
+ return mxAttribs->getOptionalValueToken( nAttrToken, nDefault );
+}
+
+OUString AttributeList::getString( sal_Int32 nAttrToken, const OUString& rDefault ) const
+{
+ // try to avoid slow exception throw/catch if we can
+ if (rDefault.isEmpty())
+ return mxAttribs->getOptionalValue( nAttrToken );
+
+ try
+ {
+ return mxAttribs->getValue( nAttrToken );
+ }
+ catch( Exception& )
+ {
+ }
+ return rDefault;
+}
+
+OUString AttributeList::getXString( sal_Int32 nAttrToken, const OUString& rDefault ) const
+{
+ return getXString( nAttrToken ).value_or( rDefault );
+}
+
+std::string_view AttributeList::getView( sal_Int32 nAttrToken ) const
+{
+ std::string_view p;
+ getAttribList()->getAsView(nAttrToken, p);
+ return p;
+}
+
+double AttributeList::getDouble( sal_Int32 nAttrToken, double fDefault ) const
+{
+ return getDouble( nAttrToken ).value_or( fDefault );
+}
+
+sal_Int32 AttributeList::getInteger( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
+{
+ return getInteger( nAttrToken ).value_or( nDefault );
+}
+
+sal_uInt32 AttributeList::getUnsigned( sal_Int32 nAttrToken, sal_uInt32 nDefault ) const
+{
+ return getUnsigned( nAttrToken ).value_or( nDefault );
+}
+
+sal_Int64 AttributeList::getHyper( sal_Int32 nAttrToken, sal_Int64 nDefault ) const
+{
+ return getHyper( nAttrToken ).value_or( nDefault );
+}
+
+sal_Int32 AttributeList::getIntegerHex( sal_Int32 nAttrToken, sal_Int32 nDefault ) const
+{
+ return getIntegerHex( nAttrToken ).value_or( nDefault );
+}
+
+sal_uInt32 AttributeList::getUnsignedHex( sal_Int32 nAttrToken, sal_uInt32 nDefault ) const
+{
+ return getIntegerHex( nAttrToken ).value_or( nDefault );
+}
+
+bool AttributeList::getBool( sal_Int32 nAttrToken, bool bDefault ) const
+{
+ return getBool( nAttrToken ).value_or( bDefault );
+}
+
+util::DateTime AttributeList::getDateTime( sal_Int32 nAttrToken, const util::DateTime& rDefault ) const
+{
+ return getDateTime( nAttrToken ).value_or( rDefault );
+}
+
+std::vector<sal_Int32> AttributeList::getTokenList(sal_Int32 nAttrToken) const
+{
+ std::vector<sal_Int32> aValues;
+ OUString sValue = getString(nAttrToken, "");
+ sal_Int32 nIndex = 0;
+ do
+ {
+ aValues.push_back(AttributeConversion::decodeToken(o3tl::getToken(sValue, 0, ' ', nIndex)));
+ } while (nIndex >= 0);
+
+ return aValues;
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/helper/binaryinputstream.cxx b/oox/source/helper/binaryinputstream.cxx
new file mode 100644
index 0000000000..27cbc6ad6e
--- /dev/null
+++ b/oox/source/helper/binaryinputstream.cxx
@@ -0,0 +1,322 @@
+/* -*- 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/helper/binaryinputstream.hxx>
+
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <string.h>
+#include <algorithm>
+#include <vector>
+#include <rtl/ustrbuf.hxx>
+#include <osl/diagnose.h>
+#include <oox/helper/binaryoutputstream.hxx>
+
+namespace oox {
+
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+const sal_Int32 INPUTSTREAM_BUFFERSIZE = 0x8000;
+
+} // namespace
+
+OUString BinaryInputStream::readNulUnicodeArray()
+{
+ OUStringBuffer aBuffer;
+ for (;;)
+ {
+ sal_uInt16 nChar = readuInt16();
+ if ( mbEof || (nChar == 0) ) break;
+ aBuffer.append( static_cast< sal_Unicode >( nChar ) );
+ }
+ return aBuffer.makeStringAndClear();
+}
+
+OString BinaryInputStream::readCharArray( sal_Int32 nChars )
+{
+ if( nChars <= 0 )
+ return OString();
+
+ ::std::vector< sal_uInt8 > aBuffer;
+ sal_Int32 nCharsRead = readArray( aBuffer, nChars );
+ if( nCharsRead <= 0 )
+ return OString();
+
+ aBuffer.resize( static_cast< size_t >( nCharsRead ) );
+ // NUL characters are replaced by question marks.
+ ::std::replace( aBuffer.begin(), aBuffer.end(), '\0', '?' );
+
+ return OString(reinterpret_cast<char*>(aBuffer.data()), nCharsRead);
+}
+
+OUString BinaryInputStream::readCharArrayUC( sal_Int32 nChars, rtl_TextEncoding eTextEnc )
+{
+ return OStringToOUString( readCharArray( nChars ), eTextEnc );
+}
+
+OUString BinaryInputStream::readUnicodeArray( sal_Int32 nChars )
+{
+ if( nChars <= 0 )
+ return OUString();
+
+ ::std::vector< sal_uInt16 > aBuffer;
+ sal_Int32 nCharsRead = readArray( aBuffer, nChars );
+ if( nCharsRead <= 0 )
+ return OUString();
+
+ aBuffer.resize( static_cast< size_t >( nCharsRead ) );
+ // don't allow nul chars
+ ::std::replace( aBuffer.begin(), aBuffer.begin() + nCharsRead, '\0', '?' );
+
+ OUStringBuffer aStringBuffer;
+ aStringBuffer.ensureCapacity( nCharsRead );
+ for (auto const& elem : aBuffer)
+ aStringBuffer.append( static_cast< sal_Unicode >(elem) );
+ return aStringBuffer.makeStringAndClear();
+}
+
+OUString BinaryInputStream::readCompressedUnicodeArray( sal_Int32 nChars, bool bCompressed )
+{
+ return bCompressed ?
+ // ISO-8859-1 maps all byte values 0xHH to the same Unicode code point U+00HH
+ readCharArrayUC( nChars, RTL_TEXTENCODING_ISO_8859_1 ) :
+ readUnicodeArray( nChars );
+}
+
+void BinaryInputStream::copyToStream( BinaryOutputStream& rOutStrm )
+{
+ sal_Int64 nBytes = SAL_MAX_INT64;
+ sal_Int32 nBufferSize = INPUTSTREAM_BUFFERSIZE;
+ StreamDataSequence aBuffer( nBufferSize );
+ while( nBytes > 0 )
+ {
+ sal_Int32 nReadSize = getLimitedValue< sal_Int32, sal_Int64 >( nBytes, 0, nBufferSize );
+ sal_Int32 nBytesRead = readData( aBuffer, nReadSize );
+ rOutStrm.writeData( aBuffer );
+ if( nReadSize == nBytesRead )
+ nBytes -= nReadSize;
+ else
+ nBytes = 0;
+ }
+}
+
+BinaryXInputStream::BinaryXInputStream( const Reference< XInputStream >& rxInStrm, bool bAutoClose ) :
+ BinaryStreamBase( Reference< XSeekable >( rxInStrm, UNO_QUERY ).is() ),
+ BinaryXSeekableStream( Reference< XSeekable >( rxInStrm, UNO_QUERY ) ),
+ maBuffer( INPUTSTREAM_BUFFERSIZE ),
+ mxInStrm( rxInStrm ),
+ mbAutoClose( bAutoClose && rxInStrm.is() )
+{
+ mbEof = !mxInStrm.is();
+}
+
+BinaryXInputStream::~BinaryXInputStream()
+{
+ close();
+}
+
+void BinaryXInputStream::close()
+{
+ OSL_ENSURE( !mbAutoClose || mxInStrm.is(), "BinaryXInputStream::close - invalid call" );
+ if( mxInStrm.is() ) try
+ {
+ mxInStrm->closeInput();
+ }
+ catch( Exception& )
+ {
+ OSL_FAIL( "BinaryXInputStream::close - closing input stream failed" );
+ }
+ mxInStrm.clear();
+ mbAutoClose = false;
+ BinaryXSeekableStream::close();
+}
+
+sal_Int32 BinaryXInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t /*nAtomSize*/ )
+{
+ sal_Int32 nRet = 0;
+ if( !mbEof && (nBytes > 0) ) try
+ {
+ nRet = mxInStrm->readBytes( orData, nBytes );
+ mbEof = nRet != nBytes;
+ }
+ catch( Exception& )
+ {
+ mbEof = true;
+ }
+ return nRet;
+}
+
+sal_Int32 BinaryXInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize )
+{
+ sal_Int32 nRet = 0;
+ if( !mbEof && (nBytes > 0) )
+ {
+ sal_Int32 nBufferSize = getLimitedValue< sal_Int32, sal_Int32 >( nBytes, 0, INPUTSTREAM_BUFFERSIZE );
+ sal_uInt8* opnMem = static_cast< sal_uInt8* >( opMem );
+ while( !mbEof && (nBytes > 0) )
+ {
+ sal_Int32 nReadSize = getLimitedValue< sal_Int32, sal_Int32 >( nBytes, 0, nBufferSize );
+ sal_Int32 nBytesRead = readData( maBuffer, nReadSize, nAtomSize );
+ if( nBytesRead > 0 )
+ memcpy( opnMem, maBuffer.getConstArray(), static_cast< size_t >( nBytesRead ) );
+ opnMem += nBytesRead;
+ nBytes -= nBytesRead;
+ nRet += nBytesRead;
+ }
+ }
+ return nRet;
+}
+
+void BinaryXInputStream::skip( sal_Int32 nBytes, size_t /*nAtomSize*/ )
+{
+ if( !mbEof ) try
+ {
+ mxInStrm->skipBytes( nBytes );
+ }
+ catch( Exception& )
+ {
+ mbEof = true;
+ }
+}
+
+SequenceInputStream::SequenceInputStream( const StreamDataSequence& rData ) :
+ BinaryStreamBase( true ),
+ SequenceSeekableStream( rData )
+{
+}
+
+sal_Int32 SequenceInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t /*nAtomSize*/ )
+{
+ sal_Int32 nReadBytes = 0;
+ if( !mbEof )
+ {
+ nReadBytes = getMaxBytes( nBytes );
+ orData.realloc( nReadBytes );
+ if( nReadBytes > 0 )
+ memcpy( orData.getArray(), mpData->getConstArray() + mnPos, static_cast< size_t >( nReadBytes ) );
+ mnPos += nReadBytes;
+ mbEof = nReadBytes < nBytes;
+ }
+ return nReadBytes;
+}
+
+sal_Int32 SequenceInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t /*nAtomSize*/ )
+{
+ sal_Int32 nReadBytes = 0;
+ if( !mbEof )
+ {
+ nReadBytes = getMaxBytes( nBytes );
+ if( nReadBytes > 0 )
+ memcpy( opMem, mpData->getConstArray() + mnPos, static_cast< size_t >( nReadBytes ) );
+ mnPos += nReadBytes;
+ mbEof = nReadBytes < nBytes;
+ }
+ return nReadBytes;
+}
+
+void SequenceInputStream::skip( sal_Int32 nBytes, size_t /*nAtomSize*/ )
+{
+ if( !mbEof )
+ {
+ sal_Int32 nSkipBytes = getMaxBytes( nBytes );
+ mnPos += nSkipBytes;
+ mbEof = nSkipBytes < nBytes;
+ }
+}
+
+RelativeInputStream::RelativeInputStream( BinaryInputStream& rInStrm, sal_Int64 nSize ) :
+ BinaryStreamBase( rInStrm.isSeekable() ),
+ mpInStrm( &rInStrm ),
+ mnStartPos( rInStrm.tell() ),
+ mnRelPos( 0 )
+{
+ sal_Int64 nRemaining = rInStrm.getRemaining();
+ mnSize = (nRemaining >= 0) ? ::std::min( nSize, nRemaining ) : nSize;
+ mbEof = mbEof || rInStrm.isEof() || (mnSize < 0);
+}
+
+sal_Int64 RelativeInputStream::size() const
+{
+ return mpInStrm ? mnSize : -1;
+}
+
+sal_Int64 RelativeInputStream::tell() const
+{
+ return mpInStrm ? mnRelPos : -1;
+}
+
+void RelativeInputStream::seek( sal_Int64 nPos )
+{
+ if( mpInStrm && isSeekable() && (mnStartPos >= 0) )
+ {
+ mnRelPos = getLimitedValue< sal_Int64, sal_Int64 >( nPos, 0, mnSize );
+ mpInStrm->seek( mnStartPos + mnRelPos );
+ mbEof = (mnRelPos != nPos) || mpInStrm->isEof();
+ }
+}
+
+void RelativeInputStream::close()
+{
+ mpInStrm = nullptr;
+ mbEof = true;
+}
+
+sal_Int32 RelativeInputStream::readData( StreamDataSequence& orData, sal_Int32 nBytes, size_t nAtomSize )
+{
+ sal_Int32 nReadBytes = 0;
+ if( !mbEof )
+ {
+ sal_Int32 nMaxBytes = getMaxBytes( nBytes );
+ nReadBytes = mpInStrm->readData( orData, nMaxBytes, nAtomSize );
+ mnRelPos += nReadBytes;
+ mbEof = (nMaxBytes < nBytes) || mpInStrm->isEof();
+ }
+ return nReadBytes;
+}
+
+sal_Int32 RelativeInputStream::readMemory( void* opMem, sal_Int32 nBytes, size_t nAtomSize )
+{
+ sal_Int32 nReadBytes = 0;
+ if( !mbEof )
+ {
+ sal_Int32 nMaxBytes = getMaxBytes( nBytes );
+ nReadBytes = mpInStrm->readMemory( opMem, nMaxBytes, nAtomSize );
+ mnRelPos += nReadBytes;
+ mbEof = (nMaxBytes < nBytes) || mpInStrm->isEof();
+ }
+ return nReadBytes;
+}
+
+void RelativeInputStream::skip( sal_Int32 nBytes, size_t nAtomSize )
+{
+ if( !mbEof )
+ {
+ sal_Int32 nSkipBytes = getMaxBytes( nBytes );
+ mpInStrm->skip( nSkipBytes, nAtomSize );
+ mnRelPos += nSkipBytes;
+ mbEof = nSkipBytes < nBytes;
+ }
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/helper/binaryoutputstream.cxx b/oox/source/helper/binaryoutputstream.cxx
new file mode 100644
index 0000000000..50ce7f11ce
--- /dev/null
+++ b/oox/source/helper/binaryoutputstream.cxx
@@ -0,0 +1,184 @@
+/* -*- 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/helper/binaryoutputstream.hxx>
+
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <osl/diagnose.h>
+#include <string.h>
+
+namespace oox {
+
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+const sal_Int32 OUTPUTSTREAM_BUFFERSIZE = 0x8000;
+
+} // namespace
+
+BinaryXOutputStream::BinaryXOutputStream( const Reference< XOutputStream >& rxOutStrm, bool bAutoClose ) :
+ BinaryStreamBase( Reference< XSeekable >( rxOutStrm, UNO_QUERY ).is() ),
+ BinaryXSeekableStream( Reference< XSeekable >( rxOutStrm, UNO_QUERY ) ),
+ maBuffer( OUTPUTSTREAM_BUFFERSIZE ),
+ mxOutStrm( rxOutStrm ),
+ mbAutoClose( bAutoClose && rxOutStrm.is() )
+{
+ mbEof = !mxOutStrm.is();
+}
+
+BinaryXOutputStream::~BinaryXOutputStream()
+{
+ close();
+}
+
+void BinaryXOutputStream::close()
+{
+ OSL_ENSURE( !mbAutoClose || mxOutStrm.is(), "BinaryXOutputStream::close - invalid call" );
+ if( mxOutStrm.is() ) try
+ {
+ mxOutStrm->flush();
+ if ( mbAutoClose )
+ mxOutStrm->closeOutput();
+ }
+ catch( Exception& )
+ {
+ OSL_FAIL( "BinaryXOutputStream::close - closing output stream failed" );
+ }
+ mxOutStrm.clear();
+ mbAutoClose = false;
+ BinaryXSeekableStream::close();
+}
+
+void BinaryXOutputStream::writeData( const StreamDataSequence& rData, size_t /*nAtomSize*/ )
+{
+ if( mxOutStrm.is() ) try
+ {
+ mxOutStrm->writeBytes( rData );
+ }
+ catch( Exception& )
+ {
+ OSL_FAIL( "BinaryXOutputStream::writeData - stream read error" );
+ }
+}
+
+void BinaryXOutputStream::writeMemory( const void* pMem, sal_Int32 nBytes, size_t nAtomSize )
+{
+ if( !(mxOutStrm.is() && (nBytes > 0)) )
+ return;
+
+ sal_Int32 nBufferSize = getLimitedValue< sal_Int32, sal_Int32 >( nBytes, 0, (OUTPUTSTREAM_BUFFERSIZE / nAtomSize) * nAtomSize );
+ const sal_uInt8* pnMem = static_cast< const sal_uInt8* >( pMem );
+ while( nBytes > 0 )
+ {
+ sal_Int32 nWriteSize = getLimitedValue< sal_Int32, sal_Int32 >( nBytes, 0, nBufferSize );
+ maBuffer.realloc( nWriteSize );
+ memcpy( maBuffer.getArray(), pnMem, static_cast< size_t >( nWriteSize ) );
+ writeData( maBuffer, nAtomSize );
+ pnMem += nWriteSize;
+ nBytes -= nWriteSize;
+ }
+}
+
+void
+BinaryOutputStream::writeCharArrayUC( std::u16string_view rString, rtl_TextEncoding eTextEnc )
+{
+ OString sBuf( OUStringToOString( rString, eTextEnc ) );
+ sBuf = sBuf.replace( '\0', '?' );
+ writeMemory( static_cast< const void* >( sBuf.getStr() ), sBuf.getLength() );
+}
+
+void
+BinaryOutputStream::writeUnicodeArray( const OUString& rString )
+{
+ OUString sBuf = rString.replace( '\0', '?' );
+#ifdef OSL_BIGENDIAN
+ // need a non-const buffer for swapping byte order
+ sal_Unicode notConst[sBuf.getLength()];
+ memcpy( notConst, sBuf.getStr(), sizeof(sal_Unicode)*sBuf.getLength() );
+ writeArray( notConst, sBuf.getLength() );
+#else
+ writeArray( sBuf.getStr(), sBuf.getLength() );
+#endif
+}
+
+void BinaryOutputStream::writeCompressedUnicodeArray( const OUString& rString, bool bCompressed )
+{
+ if ( bCompressed )
+ // ISO-8859-1 maps all byte values 0xHH to the same Unicode code point U+00HH
+ writeCharArrayUC( rString, RTL_TEXTENCODING_ISO_8859_1 );
+ else
+ writeUnicodeArray( rString );
+}
+
+SequenceOutputStream::SequenceOutputStream( StreamDataSequence & rData ) :
+ BinaryStreamBase( true ),
+ mpData( &rData ),
+ mnPos( 0 )
+{
+}
+
+void SequenceOutputStream::writeData( const StreamDataSequence& rData, size_t nAtomSize )
+{
+ if( mpData && rData.hasElements() )
+ writeMemory( rData.getConstArray(), rData.getLength(), nAtomSize );
+}
+
+void SequenceOutputStream::writeMemory( const void* pMem, sal_Int32 nBytes, size_t /*nAtomSize*/ )
+{
+ if( mpData && (nBytes > 0) )
+ {
+ if( mpData->getLength() - mnPos < nBytes )
+ mpData->realloc( mnPos + nBytes );
+ memcpy( mpData->getArray() + mnPos, pMem, static_cast< size_t >( nBytes ) );
+ mnPos += nBytes;
+ }
+}
+
+sal_Int64 SequenceOutputStream::size() const
+{
+ return mpData ? mpData->getLength() : -1;
+}
+
+sal_Int64 SequenceOutputStream::tell() const
+{
+ return mpData ? mnPos : -1;
+}
+
+void SequenceOutputStream::seek( sal_Int64 nPos )
+{
+ if( mpData )
+ {
+ mnPos = getLimitedValue< sal_Int32, sal_Int64 >( nPos, 0, mpData->getLength() );
+ mbEof = mnPos != nPos;
+ }
+}
+
+void SequenceOutputStream::close()
+{
+ mpData = nullptr;
+ mbEof = true;
+}
+
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/helper/binarystreambase.cxx b/oox/source/helper/binarystreambase.cxx
new file mode 100644
index 0000000000..0f35c44ac6
--- /dev/null
+++ b/oox/source/helper/binarystreambase.cxx
@@ -0,0 +1,146 @@
+/* -*- 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/helper/binarystreambase.hxx>
+#include <oox/helper/helper.hxx>
+
+#include <com/sun/star/io/XSeekable.hpp>
+#include <comphelper/diagnose_ex.hxx>
+
+namespace oox {
+
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::uno;
+
+BinaryStreamBase::~BinaryStreamBase()
+{
+}
+
+sal_Int64 BinaryStreamBase::getRemaining() const
+{
+ // do not use isSeekable(), implementations may provide stream position and size even if not seekable
+ sal_Int64 nPos = tell();
+ sal_Int64 nLen = size();
+ return ((nPos >= 0) && (nLen >= 0)) ? ::std::max< sal_Int64 >( nLen - nPos, 0 ) : -1;
+}
+
+void BinaryStreamBase::alignToBlock( sal_Int32 nBlockSize, sal_Int64 nAnchorPos )
+{
+ sal_Int64 nStrmPos = tell();
+ // nothing to do, if stream is at anchor position
+ if( mbSeekable && (0 <= nAnchorPos) && (nAnchorPos != nStrmPos) && (nBlockSize > 1) )
+ {
+ // prevent modulo with negative arguments...
+ sal_Int64 nSkipSize = (nAnchorPos < nStrmPos) ?
+ (nBlockSize - ((nStrmPos - nAnchorPos - 1) % nBlockSize) - 1) :
+ ((nAnchorPos - nStrmPos) % nBlockSize);
+ seek( nStrmPos + nSkipSize );
+ }
+}
+
+BinaryXSeekableStream::BinaryXSeekableStream( const Reference< XSeekable >& rxSeekable ) :
+ BinaryStreamBase( rxSeekable.is() ),
+ mxSeekable( rxSeekable )
+{
+}
+
+BinaryXSeekableStream::~BinaryXSeekableStream()
+{
+}
+
+sal_Int64 BinaryXSeekableStream::size() const
+{
+ if( mxSeekable.is() ) try
+ {
+ return mxSeekable->getLength();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "oox", "BinaryXSeekableStream::size" );
+ }
+ return -1;
+}
+
+sal_Int64 BinaryXSeekableStream::tell() const
+{
+ if( mxSeekable.is() ) try
+ {
+ return mxSeekable->getPosition();
+ }
+ catch( Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "oox", "BinaryXSeekableStream::tell" );
+ }
+ return -1;
+}
+
+void BinaryXSeekableStream::seek( sal_Int64 nPos )
+{
+ if( mxSeekable.is() ) try
+ {
+ mbEof = false;
+ mxSeekable->seek( nPos );
+ }
+ catch( Exception& )
+ {
+ mbEof = true;
+ }
+}
+
+void BinaryXSeekableStream::close()
+{
+ mxSeekable.clear();
+ mbEof = true;
+}
+
+SequenceSeekableStream::SequenceSeekableStream( const StreamDataSequence& rData ) :
+ BinaryStreamBase( true ),
+ mpData( &rData ),
+ mnPos( 0 )
+{
+}
+
+sal_Int64 SequenceSeekableStream::size() const
+{
+ return mpData ? mpData->getLength() : -1;
+}
+
+sal_Int64 SequenceSeekableStream::tell() const
+{
+ return mpData ? mnPos : -1;
+}
+
+void SequenceSeekableStream::seek( sal_Int64 nPos )
+{
+ if( mpData )
+ {
+ mnPos = getLimitedValue< sal_Int32, sal_Int64 >( nPos, 0, mpData->getLength() );
+ mbEof = mnPos != nPos;
+ }
+}
+
+void SequenceSeekableStream::close()
+{
+ mpData = nullptr;
+ mbEof = true;
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/helper/containerhelper.cxx b/oox/source/helper/containerhelper.cxx
new file mode 100644
index 0000000000..60e225e17f
--- /dev/null
+++ b/oox/source/helper/containerhelper.cxx
@@ -0,0 +1,126 @@
+/* -*- 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 <algorithm>
+
+#include <oox/helper/containerhelper.hxx>
+
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <osl/diagnose.h>
+
+namespace oox {
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+struct ValueRangeComp
+{
+ bool operator()( const ValueRange& rLHS, const ValueRange& rRHS ) const
+ {
+ return rLHS.mnLast < rRHS.mnFirst;
+ }
+};
+
+} // namespace
+
+void ValueRangeSet::insert( const ValueRange& rRange )
+{
+ // find the first range that contains or follows the starting point of the passed range
+ ValueRangeVector::iterator aBeg = maRanges.begin();
+ ValueRangeVector::iterator aEnd = maRanges.end();
+ ValueRangeVector::iterator aIt = ::std::lower_bound( aBeg, aEnd, rRange, ValueRangeComp() );
+ // nothing to do if found range contains passed range
+ if( (aIt != aEnd) && aIt->contains( rRange ) ) return;
+ // check if previous range can be used to merge with the passed range
+ if( (aIt != aBeg) && ((aIt - 1)->mnLast + 1 == rRange.mnFirst) ) --aIt;
+ // check if current range (aIt) can be used to merge with passed range
+ if( (aIt != aEnd) && aIt->intersects( rRange ) )
+ {
+ // set new start value to existing range
+ aIt->mnFirst = ::std::min( aIt->mnFirst, rRange.mnFirst );
+ // search first range that cannot be merged anymore (aNext)
+ ValueRangeVector::iterator aNext = aIt + 1;
+ while( (aNext != aEnd) && aNext->intersects( rRange ) ) ++aNext;
+ // set new end value to existing range
+ aIt->mnLast = ::std::max( (aNext - 1)->mnLast, rRange.mnLast );
+ // remove ranges covered by new existing range (aIt)
+ maRanges.erase( aIt + 1, aNext );
+ }
+ else
+ {
+ // merging not possible: insert new range
+ maRanges.insert( aIt, rRange );
+ }
+}
+
+OUString ContainerHelper::getUnusedName(
+ const Reference< XNameAccess >& rxNameAccess, const OUString& rSuggestedName,
+ sal_Unicode cSeparator )
+{
+ OSL_ENSURE( rxNameAccess.is(), "ContainerHelper::getUnusedName - missing XNameAccess interface" );
+
+ OUString aNewName = rSuggestedName;
+ sal_Int32 nIndex = -1;
+ while( rxNameAccess->hasByName( aNewName ) )
+ aNewName = rSuggestedName + OUStringChar(cSeparator) + OUString::number( nIndex++ );
+ return aNewName;
+}
+
+bool ContainerHelper::insertByName(
+ const Reference< XNameContainer >& rxNameContainer,
+ const OUString& rName, const Any& rObject )
+{
+ OSL_ENSURE( rxNameContainer.is(), "ContainerHelper::insertByName - missing XNameContainer interface" );
+ bool bRet = false;
+ try
+ {
+ if( rxNameContainer->hasByName( rName ) )
+ rxNameContainer->replaceByName( rName, rObject );
+ else
+ rxNameContainer->insertByName( rName, rObject );
+ bRet = true;
+ }
+ catch( Exception& )
+ {
+ }
+ OSL_ENSURE( bRet, "ContainerHelper::insertByName - cannot insert object" );
+ return bRet;
+}
+
+OUString ContainerHelper::insertByUnusedName(
+ const Reference< XNameContainer >& rxNameContainer,
+ const OUString& rSuggestedName, sal_Unicode cSeparator,
+ const Any& rObject )
+{
+ OSL_ENSURE( rxNameContainer.is(), "ContainerHelper::insertByUnusedName - missing XNameContainer interface" );
+
+ // find an unused name
+ OUString aNewName = getUnusedName( rxNameContainer, rSuggestedName, cSeparator );
+
+ // insert the new object and return its resulting name
+ insertByName( rxNameContainer, aNewName, rObject );
+ return aNewName;
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/helper/grabbagstack.cxx b/oox/source/helper/grabbagstack.cxx
new file mode 100644
index 0000000000..761fc9644a
--- /dev/null
+++ b/oox/source/helper/grabbagstack.cxx
@@ -0,0 +1,82 @@
+/* -*- 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/.
+ *
+ */
+
+#include <oox/helper/grabbagstack.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <comphelper/sequence.hxx>
+
+namespace oox
+{
+
+using namespace css::beans;
+using namespace css::uno;
+
+GrabBagStack::GrabBagStack(const OUString& aElementName)
+{
+ mCurrentElement.maElementName = aElementName;
+}
+
+GrabBagStack::~GrabBagStack()
+{}
+
+bool GrabBagStack::isStackEmpty() const
+{
+ return mStack.empty();
+}
+
+PropertyValue GrabBagStack::getRootProperty()
+{
+ while(!mStack.empty())
+ pop();
+
+ PropertyValue aProperty;
+ aProperty.Name = mCurrentElement.maElementName;
+ aProperty.Value <<= comphelper::containerToSequence(mCurrentElement.maPropertyList);
+
+ return aProperty;
+}
+
+void GrabBagStack::appendElement(const OUString& aName, const Any& aAny)
+{
+ PropertyValue aValue;
+ aValue.Name = aName;
+ aValue.Value = aAny;
+ mCurrentElement.maPropertyList.push_back(aValue);
+}
+
+void GrabBagStack::push(const OUString& aKey)
+{
+ mStack.push(mCurrentElement);
+ mCurrentElement.maElementName = aKey;
+ mCurrentElement.maPropertyList.clear();
+}
+
+void GrabBagStack::pop()
+{
+ OUString aName = mCurrentElement.maElementName;
+ Sequence<PropertyValue> aSequence(comphelper::containerToSequence(mCurrentElement.maPropertyList));
+ mCurrentElement = mStack.top();
+ mStack.pop();
+ appendElement(aName, Any(aSequence));
+}
+
+void GrabBagStack::addInt32(const OUString& aElementName, sal_Int32 aIntValue)
+{
+ appendElement(aElementName, Any(aIntValue));
+}
+
+void GrabBagStack::addString(const OUString& aElementName, const OUString& aStringValue)
+{
+ appendElement(aElementName, Any(aStringValue));
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/helper/graphichelper.cxx b/oox/source/helper/graphichelper.cxx
new file mode 100644
index 0000000000..830f013128
--- /dev/null
+++ b/oox/source/helper/graphichelper.cxx
@@ -0,0 +1,327 @@
+/* -*- 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/helper/graphichelper.hxx>
+
+#include <com/sun/star/awt/Point.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/graphic/GraphicProvider.hpp>
+#include <com/sun/star/graphic/GraphicMapper.hpp>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/seqstream.hxx>
+#include <utility>
+#include <vcl/wmfexternal.hxx>
+#include <vcl/svapp.hxx>
+#include <vcl/outdev.hxx>
+#include <tools/gen.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <oox/helper/containerhelper.hxx>
+#include <oox/helper/propertyset.hxx>
+#include <oox/token/properties.hxx>
+#include <oox/token/tokens.hxx>
+
+namespace oox {
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::graphic;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+sal_Int32 lclConvertScreenPixelToHmm( double fPixel, double fPixelPerHmm )
+{
+ return static_cast< sal_Int32 >( (fPixelPerHmm > 0.0) ? (fPixel / fPixelPerHmm + 0.5) : 0.0 );
+}
+
+} // namespace
+
+GraphicHelper::GraphicHelper( const Reference< XComponentContext >& rxContext, const Reference< XFrame >& /*rxTargetFrame*/, StorageRef xStorage ) :
+ mxContext( rxContext ),
+ mxStorage(std::move( xStorage ))
+{
+ OSL_ENSURE( mxContext.is(), "GraphicHelper::GraphicHelper - missing component context" );
+ if( mxContext.is() )
+ mxGraphicProvider.set( graphic::GraphicProvider::create( mxContext ), uno::UNO_QUERY );
+
+ //! TODO: get colors from system
+ maSystemPalette[ XML_3dDkShadow ] = Color(0x716F64);
+ maSystemPalette[ XML_3dLight ] = Color(0xF1EFE2);
+ maSystemPalette[ XML_activeBorder ] = Color(0xD4D0C8);
+ maSystemPalette[ XML_activeCaption ] = Color(0x0054E3);
+ maSystemPalette[ XML_appWorkspace ] = Color(0x808080);
+ maSystemPalette[ XML_background ] = Color(0x004E98);
+ maSystemPalette[ XML_btnFace ] = Color(0xECE9D8);
+ maSystemPalette[ XML_btnHighlight ] = Color(0xFFFFFF);
+ maSystemPalette[ XML_btnShadow ] = Color(0xACA899);
+ maSystemPalette[ XML_btnText ] = Color(0x000000);
+ maSystemPalette[ XML_captionText ] = Color(0xFFFFFF);
+ maSystemPalette[ XML_gradientActiveCaption ] = Color(0x3D95FF);
+ maSystemPalette[ XML_gradientInactiveCaption ] = Color(0xD8E4F8);
+ maSystemPalette[ XML_grayText ] = Color(0xACA899);
+ maSystemPalette[ XML_highlight ] = Color(0x316AC5);
+ maSystemPalette[ XML_highlightText ] = Color(0xFFFFFF);
+ maSystemPalette[ XML_hotLight ] = Color(0x000080);
+ maSystemPalette[ XML_inactiveBorder ] = Color(0xD4D0C8);
+ maSystemPalette[ XML_inactiveCaption ] = Color(0x7A96DF);
+ maSystemPalette[ XML_inactiveCaptionText ] = Color(0xD8E4F8);
+ maSystemPalette[ XML_infoBk ] = Color(0xFFFFE1);
+ maSystemPalette[ XML_infoText ] = Color(0x000000);
+ maSystemPalette[ XML_menu ] = Color(0xFFFFFF);
+ maSystemPalette[ XML_menuBar ] = Color(0xECE9D8);
+ maSystemPalette[ XML_menuHighlight ] = Color(0x316AC5);
+ maSystemPalette[ XML_menuText ] = Color(0x000000);
+ maSystemPalette[ XML_scrollBar ] = Color(0xD4D0C8);
+ maSystemPalette[ XML_window ] = Color(0xFFFFFF);
+ maSystemPalette[ XML_windowFrame ] = Color(0x000000);
+ maSystemPalette[ XML_windowText ] = Color(0x000000);
+
+ // Note that we cannot try to get DeviceInfo from the current frame here,
+ // because there might not be a current frame yet
+ mxDefaultOutputDevice = Application::GetDefaultDevice();
+ maDeviceInfo = mxDefaultOutputDevice->GetDeviceInfo();
+ // 100 000 is 1 meter in MM100.
+ // various unit tests rely on these values being exactly this and not the "true" values
+ Size aDefault = mxDefaultOutputDevice->LogicToPixel(Size(100000, 100000), MapMode(MapUnit::Map100thMM));
+ maDeviceInfo.PixelPerMeterX = aDefault.Width();
+ maDeviceInfo.PixelPerMeterY = aDefault.Height();
+ mfPixelPerHmmX = maDeviceInfo.PixelPerMeterX / 100000.0;
+ mfPixelPerHmmY = maDeviceInfo.PixelPerMeterY / 100000.0;
+}
+
+GraphicHelper::~GraphicHelper()
+{
+}
+
+// System colors and predefined colors ----------------------------------------
+
+::Color GraphicHelper::getSystemColor( sal_Int32 nToken, ::Color nDefaultRgb ) const
+{
+ return ContainerHelper::getMapElement( maSystemPalette, nToken, nDefaultRgb );
+}
+
+::Color GraphicHelper::getSchemeColor( sal_Int32 /*nToken*/ ) const
+{
+ OSL_FAIL( "GraphicHelper::getSchemeColor - scheme colors not implemented" );
+ return API_RGB_TRANSPARENT;
+}
+
+::Color GraphicHelper::getPaletteColor( sal_Int32 /*nPaletteIdx*/ ) const
+{
+ OSL_FAIL( "GraphicHelper::getPaletteColor - palette colors not implemented" );
+ return API_RGB_TRANSPARENT;
+}
+
+sal_Int32 GraphicHelper::getDefaultChartAreaFillStyle() const
+{
+ return XML_solidFill;
+}
+
+sal_Int32 GraphicHelper::getDefaultChartAreaLineStyle()
+{
+ return XML_solidFill;
+}
+
+sal_Int16 GraphicHelper::getDefaultChartAreaLineWidth()
+{
+ // this value is what MSO 2016 writes fixing incomplete MSO 2010 documents (0.75 pt in emu)
+ return 9525;
+}
+
+// Device info and device dependent unit conversion ---------------------------
+
+sal_Int32 GraphicHelper::convertScreenPixelXToHmm( double fPixelX ) const
+{
+ return lclConvertScreenPixelToHmm( fPixelX, mfPixelPerHmmX );
+}
+
+sal_Int32 GraphicHelper::convertScreenPixelYToHmm( double fPixelY ) const
+{
+ return lclConvertScreenPixelToHmm( fPixelY, mfPixelPerHmmY );
+}
+
+awt::Size GraphicHelper::convertScreenPixelToHmm( const awt::Size& rPixel ) const
+{
+ return awt::Size( convertScreenPixelXToHmm( rPixel.Width ), convertScreenPixelYToHmm( rPixel.Height ) );
+}
+
+double GraphicHelper::convertHmmToScreenPixelX( sal_Int32 nHmmX ) const
+{
+ return nHmmX * mfPixelPerHmmX;
+}
+
+double GraphicHelper::convertHmmToScreenPixelY( sal_Int32 nHmmY ) const
+{
+ return nHmmY * mfPixelPerHmmY;
+}
+
+awt::Point GraphicHelper::convertHmmToScreenPixel( const awt::Point& rHmm ) const
+{
+ return awt::Point(
+ static_cast< sal_Int32 >( convertHmmToScreenPixelX( rHmm.X ) + 0.5 ),
+ static_cast< sal_Int32 >( convertHmmToScreenPixelY( rHmm.Y ) + 0.5 ) );
+}
+
+awt::Size GraphicHelper::convertHmmToScreenPixel( const awt::Size& rHmm ) const
+{
+ return awt::Size(
+ static_cast< sal_Int32 >( convertHmmToScreenPixelX( rHmm.Width ) + 0.5 ),
+ static_cast< sal_Int32 >( convertHmmToScreenPixelY( rHmm.Height ) + 0.5 ) );
+}
+
+awt::Point GraphicHelper::convertHmmToAppFont( const awt::Point& rHmm ) const
+{
+ try
+ {
+ awt::Point aPixel = convertHmmToScreenPixel( rHmm );
+ MapMode aMode(MapUnit::MapAppFont);
+ ::Point aVCLPoint(aPixel.X, aPixel.Y);
+ ::Point aDevPoint = mxDefaultOutputDevice->PixelToLogic(aVCLPoint, aMode );
+ return awt::Point(aDevPoint.X(), aDevPoint.Y());
+ }
+ catch( Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("oox");
+ }
+ return awt::Point( 0, 0 );
+}
+
+awt::Size GraphicHelper::convertHmmToAppFont( const awt::Size& rHmm ) const
+{
+ try
+ {
+ awt::Size aPixel = convertHmmToScreenPixel( rHmm );
+ MapMode aMode(MapUnit::MapAppFont);
+ ::Size aVCLSize(aPixel.Width, aPixel.Height);
+ ::Size aDevSz = mxDefaultOutputDevice->PixelToLogic(aVCLSize, aMode );
+ return awt::Size(aDevSz.Width(), aDevSz.Height());
+ }
+ catch( Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("oox");
+ }
+ return awt::Size( 0, 0 );
+}
+
+
+// Graphics and graphic objects ----------------------------------------------
+
+Reference< XGraphic > GraphicHelper::importGraphic( const Reference< XInputStream >& rxInStrm,
+ const WmfExternal* pExtHeader, const bool bLazyLoad ) const
+{
+ Reference< XGraphic > xGraphic;
+ if( rxInStrm.is() && mxGraphicProvider.is() ) try
+ {
+ Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue("InputStream", rxInStrm),
+ comphelper::makePropertyValue("LazyRead", bLazyLoad) };
+
+ if ( pExtHeader && pExtHeader->mapMode > 0 )
+ {
+ aArgs.realloc( aArgs.getLength() + 1 );
+ auto pArgs = aArgs.getArray();
+ Sequence< PropertyValue > aFilterData{
+ comphelper::makePropertyValue("ExternalWidth", pExtHeader->xExt),
+ comphelper::makePropertyValue("ExternalHeight", pExtHeader->yExt),
+ comphelper::makePropertyValue("ExternalMapMode", pExtHeader->mapMode)
+ };
+ pArgs[ 2 ].Name = "FilterData";
+ pArgs[ 2 ].Value <<= aFilterData;
+ }
+
+ xGraphic = mxGraphicProvider->queryGraphic( aArgs );
+ }
+ catch( Exception& )
+ {
+ }
+ return xGraphic;
+}
+
+Reference< XGraphic > GraphicHelper::importGraphic( const StreamDataSequence& rGraphicData ) const
+{
+ Reference< XGraphic > xGraphic;
+ if( rGraphicData.hasElements() )
+ {
+ Reference< XInputStream > xInStrm( new ::comphelper::SequenceInputStream( rGraphicData ) );
+ xGraphic = importGraphic( xInStrm );
+ }
+ return xGraphic;
+}
+
+Reference< XGraphic > GraphicHelper::importEmbeddedGraphic( const OUString& rStreamName, const WmfExternal* pExtHeader ) const
+{
+ Reference< XGraphic > xGraphic;
+ OSL_ENSURE( !rStreamName.isEmpty(), "GraphicHelper::importEmbeddedGraphic - empty stream name" );
+
+ if( !rStreamName.isEmpty() )
+ {
+ initializeGraphicMapperIfNeeded();
+
+ SAL_WARN_IF(!mxGraphicMapper.is(), "oox", "GraphicHelper::importEmbeddedGraphic - graphic mapper not available");
+
+ xGraphic = mxGraphicMapper->findGraphic(rStreamName);
+ if (!xGraphic.is())
+ {
+ // Lazy-loading doesn't work with cropped TIFF images, because in case of Lazy-load TIFF images
+ // we are using MapUnit::MapPixel, but in case of cropped images we are using MapUnit::Map100thMM
+ // and the crop values are relative to original bitmap size.
+ auto xStream = mxStorage->openInputStream(rStreamName);
+ xGraphic = importGraphic(xStream, pExtHeader, !rStreamName.endsWith(".tiff"));
+ if (xGraphic.is())
+ mxGraphicMapper->putGraphic(rStreamName, xGraphic);
+ }
+ }
+ return xGraphic;
+}
+
+awt::Size GraphicHelper::getOriginalSize( const Reference< XGraphic >& xGraphic ) const
+{
+ awt::Size aSizeHmm;
+ PropertySet aPropSet( xGraphic );
+ if( aPropSet.getProperty( aSizeHmm, PROP_Size100thMM ) && (aSizeHmm.Width == 0) && (aSizeHmm.Height == 0) ) // MAPMODE_PIXEL used?
+ {
+ awt::Size aSizePixel( 0, 0 );
+ if( aPropSet.getProperty( aSizePixel, PROP_SizePixel ) )
+ aSizeHmm = convertScreenPixelToHmm( aSizePixel );
+ }
+ return aSizeHmm;
+}
+
+void GraphicHelper::setGraphicMapper(css::uno::Reference<css::graphic::XGraphicMapper> const & rGraphicMapper)
+{
+ mxGraphicMapper = rGraphicMapper;
+}
+
+void GraphicHelper::initializeGraphicMapperIfNeeded() const
+{
+ if (!mxGraphicMapper.is())
+ {
+ auto* pNonConstThis = const_cast<GraphicHelper*>(this);
+ pNonConstThis->mxGraphicMapper = graphic::GraphicMapper::create(mxContext);
+ }
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/helper/modelobjecthelper.cxx b/oox/source/helper/modelobjecthelper.cxx
new file mode 100644
index 0000000000..e38a6ee207
--- /dev/null
+++ b/oox/source/helper/modelobjecthelper.cxx
@@ -0,0 +1,170 @@
+/* -*- 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/helper/modelobjecthelper.hxx>
+
+#include <com/sun/star/awt/Gradient2.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/drawing/LineDash.hpp>
+#include <com/sun/star/drawing/Hatch.hpp>
+#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/graphic/XGraphic.hpp>
+#include <com/sun/star/awt/XBitmap.hpp>
+#include <oox/helper/containerhelper.hxx>
+#include <utility>
+#include <osl/diagnose.h>
+
+namespace oox {
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+ObjectContainer::ObjectContainer( const Reference< XMultiServiceFactory >& rxModelFactory, OUString aServiceName ) :
+ mxModelFactory( rxModelFactory ),
+ maServiceName(std::move( aServiceName )),
+ mnIndex( 0 )
+{
+ OSL_ENSURE( mxModelFactory.is(), "ObjectContainer::ObjectContainer - missing service factory" );
+}
+
+ObjectContainer::~ObjectContainer()
+{
+}
+
+bool ObjectContainer::hasObject( const OUString& rObjName ) const
+{
+ createContainer();
+ return mxContainer.is() && mxContainer->hasByName( rObjName );
+}
+
+Any ObjectContainer::getObject( const OUString& rObjName ) const
+{
+ if( hasObject( rObjName ) )
+ return mxContainer->getByName( rObjName );
+ return Any();
+}
+
+OUString ObjectContainer::insertObject( const OUString& rObjName, const Any& rObj, bool bInsertByUnusedName )
+{
+ createContainer();
+ if( mxContainer.is() )
+ {
+ if( bInsertByUnusedName )
+ return ContainerHelper::insertByUnusedName( mxContainer, rObjName + OUString::number( ++mnIndex ), ' ', rObj );
+ if( ContainerHelper::insertByName( mxContainer, rObjName, rObj ) )
+ return rObjName;
+ }
+ return OUString();
+}
+
+void ObjectContainer::createContainer() const
+{
+ if( !mxContainer.is() && mxModelFactory.is() ) try
+ {
+ mxContainer.set( mxModelFactory->createInstance( maServiceName ), UNO_QUERY_THROW );
+ mxModelFactory.clear();
+ }
+ catch( Exception& )
+ {
+ }
+ OSL_ENSURE( mxContainer.is(), "ObjectContainer::createContainer - container not found" );
+}
+
+constexpr OUStringLiteral gaDashNameBase( u"msLineDash " ); ///< Base name for all named line dashes.
+constexpr OUString gaGradientNameBase( u"msFillGradient "_ustr ); ///< Base name for all named fill gradients.
+constexpr OUString gaTransGradNameBase( u"msTransGradient "_ustr ); ///< Base name for all named fill gradients.
+constexpr OUStringLiteral gaBitmapUrlNameBase( u"msFillBitmap " ); ///< Base name for all named fill bitmap URLs.
+constexpr OUStringLiteral gaHatchNameBase( u"msFillHatch " ); ///< Base name for all named fill hatches.
+
+ModelObjectHelper::ModelObjectHelper( const Reference< XMultiServiceFactory >& rxModelFactory ) :
+ maMarkerContainer( rxModelFactory, "com.sun.star.drawing.MarkerTable" ),
+ maDashContainer( rxModelFactory, "com.sun.star.drawing.DashTable" ),
+ maGradientContainer( rxModelFactory, "com.sun.star.drawing.GradientTable" ),
+ maTransGradContainer( rxModelFactory, "com.sun.star.drawing.TransparencyGradientTable" ),
+ maBitmapUrlContainer( rxModelFactory, "com.sun.star.drawing.BitmapTable" ),
+ maHatchContainer( rxModelFactory, "com.sun.star.drawing.HatchTable" )
+{
+}
+
+bool ModelObjectHelper::hasLineMarker( const OUString& rMarkerName ) const
+{
+ return maMarkerContainer.hasObject( rMarkerName );
+}
+
+bool ModelObjectHelper::insertLineMarker( const OUString& rMarkerName, const PolyPolygonBezierCoords& rMarker )
+{
+ OSL_ENSURE( rMarker.Coordinates.hasElements(), "ModelObjectHelper::insertLineMarker - line marker without coordinates" );
+ if( rMarker.Coordinates.hasElements() )
+ return !maMarkerContainer.insertObject( rMarkerName, Any( rMarker ), false ).isEmpty();
+ return false;
+}
+
+OUString ModelObjectHelper::insertLineDash( const LineDash& rDash )
+{
+ return maDashContainer.insertObject( gaDashNameBase, Any( rDash ), true );
+}
+
+OUString ModelObjectHelper::insertFillGradient( const awt::Gradient2& rGradient )
+{
+ return maGradientContainer.insertObject( gaGradientNameBase, Any( rGradient ), true );
+}
+
+OUString ModelObjectHelper::insertFillGradient( const awt::Gradient& rGradient )
+{
+ return maGradientContainer.insertObject( gaGradientNameBase, Any( rGradient ), true );
+}
+
+OUString ModelObjectHelper::insertTransGrandient( const awt::Gradient2& rGradient )
+{
+ return maTransGradContainer.insertObject( gaTransGradNameBase, Any( rGradient ), true );
+}
+
+OUString ModelObjectHelper::insertTransGrandient( const awt::Gradient& rGradient )
+{
+ return maTransGradContainer.insertObject( gaTransGradNameBase, Any( rGradient ), true );
+}
+
+OUString ModelObjectHelper::insertFillBitmapXGraphic(uno::Reference<graphic::XGraphic> const & rxGraphic)
+{
+ uno::Reference<awt::XBitmap> xBitmap(rxGraphic, uno::UNO_QUERY);
+ if (xBitmap.is())
+ return maBitmapUrlContainer.insertObject(gaBitmapUrlNameBase, Any(xBitmap), true);
+ return OUString();
+}
+
+OUString ModelObjectHelper::insertFillHatch(const drawing::Hatch& rHatch)
+{
+ return maHatchContainer.insertObject( gaHatchNameBase, Any( rHatch ), true );
+}
+
+uno::Reference<awt::XBitmap> ModelObjectHelper::getFillBitmap(OUString const & rGraphicName)
+{
+ uno::Reference<awt::XBitmap> xBitmap;
+ uno::Any aAny = maBitmapUrlContainer.getObject(rGraphicName);
+ if (aAny.has<uno::Reference<awt::XBitmap>>())
+ xBitmap = aAny.get<uno::Reference<awt::XBitmap>>();
+ return xBitmap;
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/helper/ooxresid.cxx b/oox/source/helper/ooxresid.cxx
new file mode 100644
index 0000000000..6ad02a70b0
--- /dev/null
+++ b/oox/source/helper/ooxresid.cxx
@@ -0,0 +1,17 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
+/*
+ * 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/.
+ */
+
+#include <sal/config.h>
+#include <ooxresid.hxx>
+#include <unotools/resmgr.hxx>
+
+OUString OoxResId(TranslateId aId) { return Translate::get(aId, Translate::Create("oox")); }
+OUString URLResId(TranslateId aId) { return Translate::get(aId, Translate::Create("sd")); }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
diff --git a/oox/source/helper/progressbar.cxx b/oox/source/helper/progressbar.cxx
new file mode 100644
index 0000000000..86170b47e6
--- /dev/null
+++ b/oox/source/helper/progressbar.cxx
@@ -0,0 +1,167 @@
+/* -*- 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/helper/progressbar.hxx>
+
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <oox/helper/helper.hxx>
+
+#include <sal/log.hxx>
+
+namespace oox {
+
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+const sal_Int32 PROGRESS_RANGE = 1000000;
+
+} // namespace
+
+IProgressBar::~IProgressBar()
+{
+}
+
+ISegmentProgressBar::~ISegmentProgressBar()
+{
+}
+
+ProgressBar::ProgressBar( const Reference< XStatusIndicator >& rxIndicator, const OUString& rText ) :
+ mxIndicator( rxIndicator ),
+ mfPosition( 0 )
+{
+ if( mxIndicator.is() )
+ mxIndicator->start( rText, PROGRESS_RANGE );
+}
+
+ProgressBar::~ProgressBar()
+{
+ if( mxIndicator.is() )
+ mxIndicator->end();
+}
+
+double ProgressBar::getPosition() const
+{
+ return mfPosition;
+}
+
+void ProgressBar::setPosition( double fPosition )
+{
+ SAL_WARN_IF( (mfPosition > fPosition) || (fPosition > 1.0), "oox", "ProgressBar::setPosition - invalid position" );
+ mfPosition = getLimitedValue< double >( fPosition, mfPosition, 1.0 );
+ if( mxIndicator.is() )
+ mxIndicator->setValue( static_cast< sal_Int32 >( mfPosition * PROGRESS_RANGE ) );
+}
+
+namespace prv {
+
+namespace {
+
+class SubSegment : public ISegmentProgressBar
+{
+public:
+ explicit SubSegment( IProgressBar& rParentProgress, double fStartPos, double fLength );
+
+ virtual double getPosition() const override;
+ virtual void setPosition( double fPosition ) override;
+
+ virtual double getFreeLength() const override;
+ virtual ISegmentProgressBarRef createSegment( double fLength ) override;
+
+private:
+ IProgressBar& mrParentProgress;
+ double mfStartPos;
+ double mfLength;
+ double mfPosition;
+ double mfFreeStart;
+};
+
+}
+
+SubSegment::SubSegment( IProgressBar& rParentProgress, double fStartPos, double fLength ) :
+ mrParentProgress( rParentProgress ),
+ mfStartPos( fStartPos ),
+ mfLength( fLength ),
+ mfPosition( 0.0 ),
+ mfFreeStart( 0.0 )
+{
+}
+
+double SubSegment::getPosition() const
+{
+ return mfPosition;
+}
+
+void SubSegment::setPosition( double fPosition )
+{
+ SAL_WARN_IF( (mfPosition > fPosition) || (fPosition > 1.0), "oox", "SubSegment::setPosition - invalid position" );
+ mfPosition = getLimitedValue< double >( fPosition, mfPosition, 1.0 );
+ mrParentProgress.setPosition( mfStartPos + mfPosition * mfLength );
+}
+
+double SubSegment::getFreeLength() const
+{
+ return 1.0 - mfFreeStart;
+}
+
+ISegmentProgressBarRef SubSegment::createSegment( double fLength )
+{
+ SAL_WARN_IF( (0.0 >= fLength) || (fLength > getFreeLength()), "oox", "SubSegment::createSegment - invalid length" );
+ fLength = getLimitedValue< double >( fLength, 0.0, getFreeLength() );
+ ISegmentProgressBarRef xSegment = std::make_shared<prv::SubSegment>( *this, mfFreeStart, fLength );
+ mfFreeStart += fLength;
+ return xSegment;
+}
+
+} // namespace oox::prv
+
+SegmentProgressBar::SegmentProgressBar( const Reference< XStatusIndicator >& rxIndicator, const OUString& rText ) :
+ maProgress( rxIndicator, rText ),
+ mfFreeStart( 0.0 )
+{
+}
+
+double SegmentProgressBar::getPosition() const
+{
+ return maProgress.getPosition();
+}
+
+void SegmentProgressBar::setPosition( double fPosition )
+{
+ maProgress.setPosition( fPosition );
+}
+
+double SegmentProgressBar::getFreeLength() const
+{
+ return 1.0 - mfFreeStart;
+}
+
+ISegmentProgressBarRef SegmentProgressBar::createSegment( double fLength )
+{
+ SAL_WARN_IF( (0.0 >= fLength) || (fLength > getFreeLength()), "oox", "SegmentProgressBar::createSegment - invalid length" );
+ fLength = getLimitedValue< double >( fLength, 0.0, getFreeLength() );
+ ISegmentProgressBarRef xSegment = std::make_shared<prv::SubSegment>( maProgress, mfFreeStart, fLength );
+ mfFreeStart += fLength;
+ return xSegment;
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/helper/propertymap.cxx b/oox/source/helper/propertymap.cxx
new file mode 100644
index 0000000000..9b2bd48e57
--- /dev/null
+++ b/oox/source/helper/propertymap.cxx
@@ -0,0 +1,953 @@
+/* -*- 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/helper/propertymap.hxx>
+
+#if OSL_DEBUG_LEVEL > 0
+# include <cstdio>
+# include <com/sun/star/style/LineSpacing.hpp>
+# include <com/sun/star/text/WritingMode.hpp>
+using ::com::sun::star::style::LineSpacing;
+using ::com::sun::star::text::WritingMode;
+#include <comphelper/anytostring.hxx>
+#include <iostream>
+#endif
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/container/XIndexReplace.hpp>
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
+#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
+#include <com/sun/star/drawing/HomogenMatrix3.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <osl/diagnose.h>
+#include <mutex>
+#include <sal/log.hxx>
+#include <oox/token/properties.hxx>
+#include <oox/token/propertynames.hxx>
+using ::com::sun::star::uno::Any;
+using ::com::sun::star::uno::Reference;
+using ::com::sun::star::uno::Sequence;
+using ::com::sun::star::beans::Property;
+using ::com::sun::star::beans::PropertyValue;
+using ::com::sun::star::beans::UnknownPropertyException;
+using ::com::sun::star::beans::XPropertyChangeListener;
+using ::com::sun::star::beans::XPropertySet;
+using ::com::sun::star::beans::XPropertySetInfo;
+using ::com::sun::star::beans::XVetoableChangeListener;
+using ::com::sun::star::container::XIndexReplace;
+
+#if OSL_DEBUG_LEVEL > 0
+#define USS(x) OUStringToOString( x, RTL_TEXTENCODING_UTF8 ).getStr()
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::uno;
+using ::com::sun::star::style::LineSpacing;
+using ::com::sun::star::text::WritingMode;
+using ::com::sun::star::drawing::TextHorizontalAdjust;
+using ::com::sun::star::drawing::TextVerticalAdjust;
+#endif
+
+namespace oox {
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::drawing;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+/** This class implements a generic XPropertySet.
+
+ Properties of all names and types can be set and later retrieved.
+ TODO: move this to comphelper or better find an existing implementation
+ */
+class GenericPropertySet : public ::cppu::WeakImplHelper< XPropertySet, XPropertySetInfo >
+{
+public:
+ explicit GenericPropertySet( const PropertyMap& rPropMap );
+
+ // XPropertySet
+ virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ virtual void SAL_CALL setPropertyValue( const OUString& aPropertyName, const Any& aValue ) override;
+ virtual Any SAL_CALL getPropertyValue( const OUString& PropertyName ) override;
+ virtual void SAL_CALL addPropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& xListener ) override;
+ virtual void SAL_CALL removePropertyChangeListener( const OUString& aPropertyName, const Reference< XPropertyChangeListener >& aListener ) override;
+ virtual void SAL_CALL addVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) override;
+ virtual void SAL_CALL removeVetoableChangeListener( const OUString& PropertyName, const Reference< XVetoableChangeListener >& aListener ) override;
+
+ // XPropertySetInfo
+ virtual Sequence< Property > SAL_CALL getProperties() override;
+ virtual Property SAL_CALL getPropertyByName( const OUString& aName ) override;
+ virtual sal_Bool SAL_CALL hasPropertyByName( const OUString& Name ) override;
+
+private:
+ std::mutex mMutex;
+ PropertyNameMap maPropMap;
+};
+
+GenericPropertySet::GenericPropertySet( const PropertyMap& rPropMap )
+{
+ rPropMap.fillPropertyNameMap(maPropMap);
+}
+
+Reference< XPropertySetInfo > SAL_CALL GenericPropertySet::getPropertySetInfo()
+{
+ return this;
+}
+
+void SAL_CALL GenericPropertySet::setPropertyValue( const OUString& rPropertyName, const Any& rValue )
+{
+ std::scoped_lock aGuard( mMutex );
+ maPropMap[ rPropertyName ] = rValue;
+}
+
+Any SAL_CALL GenericPropertySet::getPropertyValue( const OUString& rPropertyName )
+{
+ PropertyNameMap::iterator aIt = maPropMap.find( rPropertyName );
+ if( aIt == maPropMap.end() )
+ throw UnknownPropertyException(rPropertyName);
+ return aIt->second;
+}
+
+// listeners are not supported by this implementation
+void SAL_CALL GenericPropertySet::addPropertyChangeListener( const OUString& , const Reference< XPropertyChangeListener >& ) {}
+void SAL_CALL GenericPropertySet::removePropertyChangeListener( const OUString& , const Reference< XPropertyChangeListener >& ) {}
+void SAL_CALL GenericPropertySet::addVetoableChangeListener( const OUString& , const Reference< XVetoableChangeListener >& ) {}
+void SAL_CALL GenericPropertySet::removeVetoableChangeListener( const OUString& , const Reference< XVetoableChangeListener >& ) {}
+
+// XPropertySetInfo
+Sequence< Property > SAL_CALL GenericPropertySet::getProperties()
+{
+ Sequence< Property > aSeq( static_cast< sal_Int32 >( maPropMap.size() ) );
+ Property* pProperty = aSeq.getArray();
+ for (auto const& prop : maPropMap)
+ {
+ pProperty->Name = prop.first;
+ pProperty->Handle = 0;
+ pProperty->Type = prop.second.getValueType();
+ pProperty->Attributes = 0;
+ ++pProperty;
+ }
+ return aSeq;
+}
+
+Property SAL_CALL GenericPropertySet::getPropertyByName( const OUString& rPropertyName )
+{
+ PropertyNameMap::iterator aIt = maPropMap.find( rPropertyName );
+ if( aIt == maPropMap.end() )
+ throw UnknownPropertyException(rPropertyName);
+ Property aProperty;
+ aProperty.Name = aIt->first;
+ aProperty.Handle = 0;
+ aProperty.Type = aIt->second.getValueType();
+ aProperty.Attributes = 0;
+ return aProperty;
+}
+
+sal_Bool SAL_CALL GenericPropertySet::hasPropertyByName( const OUString& rPropertyName )
+{
+ return maPropMap.find( rPropertyName ) != maPropMap.end();
+}
+
+} // namespace
+
+PropertyMap::PropertyMap() :
+ mpPropNames( &GetPropertyNameVector() ) // pointer instead reference to get compiler generated copy c'tor and operator=
+{
+}
+
+bool PropertyMap::hasProperty( sal_Int32 nPropId ) const
+{
+ return maProperties.find( nPropId ) != maProperties.end();
+}
+
+bool PropertyMap::setAnyProperty( sal_Int32 nPropId, const Any& rValue )
+{
+ if( nPropId < 0 )
+ return false;
+
+ maProperties[ nPropId ] = rValue;
+ return true;
+}
+
+Any PropertyMap::getProperty( sal_Int32 nPropId )
+{
+ return maProperties[ nPropId ];
+}
+
+void PropertyMap::erase( sal_Int32 nPropId )
+{
+ maProperties.erase(nPropId);
+}
+
+bool PropertyMap::empty() const
+{
+ return maProperties.empty();
+}
+
+void PropertyMap::assignUsed( const PropertyMap& rPropMap )
+{
+ maProperties.insert(rPropMap.maProperties.begin(), rPropMap.maProperties.end());
+}
+
+const OUString& PropertyMap::getPropertyName( sal_Int32 nPropId )
+{
+ OSL_ENSURE( (0 <= nPropId) && (nPropId < PROP_COUNT), "PropertyMap::getPropertyName - invalid property identifier" );
+ return GetPropertyNameVector()[ nPropId ];
+}
+
+sal_Int32 PropertyMap::getPropertyId( std::u16string_view sPropName )
+{
+ // This may use a std::map to get faster from String to ID in the
+ // future, inside the [0..PROP_COUNT[ entries. Since it is currently
+ // only used for Diagram re-creation I opted for less memory usage here
+ if(sPropName.empty())
+ return -1;
+
+ const std::vector<OUString>& rVec(GetPropertyNameVector());
+ for(size_t a(0); a < rVec.size(); a++)
+ if(rVec[a] == sPropName)
+ return a;
+
+ return -1;
+}
+
+void PropertyMap::assignAll( const PropertyMap& rPropMap )
+{
+ for (auto const& prop : rPropMap.maProperties)
+ maProperties[prop.first] = prop.second;
+}
+
+Sequence< PropertyValue > PropertyMap::makePropertyValueSequence() const
+{
+ Sequence< PropertyValue > aSeq( static_cast< sal_Int32 >( maProperties.size() ) );
+ PropertyValue* pValues = aSeq.getArray();
+ for (auto const& prop : maProperties)
+ {
+ OSL_ENSURE( (0 <= prop.first) && (prop.first < PROP_COUNT), "PropertyMap::makePropertyValueSequence - invalid property identifier" );
+ pValues->Name = (*mpPropNames)[ prop.first ];
+ pValues->Value = prop.second;
+ pValues->State = PropertyState_DIRECT_VALUE;
+ ++pValues;
+ }
+ return aSeq;
+}
+
+void PropertyMap::fillSequences( Sequence< OUString >& rNames, Sequence< Any >& rValues ) const
+{
+ rNames.realloc( static_cast< sal_Int32 >( maProperties.size() ) );
+ rValues.realloc( static_cast< sal_Int32 >( maProperties.size() ) );
+ if( maProperties.empty() )
+ return;
+
+ OUString* pNames = rNames.getArray();
+ Any* pValues = rValues.getArray();
+ for (auto const& prop : maProperties)
+ {
+ OSL_ENSURE( (0 <= prop.first) && (prop.first < PROP_COUNT), "PropertyMap::fillSequences - invalid property identifier" );
+ *pNames = (*mpPropNames)[ prop.first ];
+ *pValues = prop.second;
+ ++pNames;
+ ++pValues;
+ }
+}
+
+void PropertyMap::fillPropertyNameMap(PropertyNameMap& rMap) const
+{
+ for (auto const& prop : maProperties)
+ {
+ rMap.insert(std::pair<OUString, Any>((*mpPropNames)[prop.first], prop.second));
+ }
+}
+
+Reference< XPropertySet > PropertyMap::makePropertySet() const
+{
+ return new GenericPropertySet( *this );
+}
+
+#if OSL_DEBUG_LEVEL > 0
+static void lclDumpAnyValue( const Any& value)
+{
+ OUString strValue;
+ Sequence< OUString > strArray;
+ Sequence< Any > anyArray;
+ Sequence< PropertyValue > propArray;
+ Sequence< Sequence< PropertyValue > > propArrayArray;
+ Sequence< EnhancedCustomShapeAdjustmentValue > adjArray;
+ Sequence< EnhancedCustomShapeSegment > segArray;
+ Sequence< EnhancedCustomShapeParameterPair > ppArray;
+ EnhancedCustomShapeSegment segment;
+ EnhancedCustomShapeParameterPair pp;
+ EnhancedCustomShapeParameter par;
+ HomogenMatrix3 aMatrix;
+ sal_Int32 intValue = 0;
+ sal_uInt32 uintValue = 0;
+ sal_Int16 int16Value = 0;
+ sal_uInt16 uint16Value = 0;
+ float floatValue = 0;
+ bool boolValue = false;
+ LineSpacing spacing;
+// RectanglePoint pointValue;
+ WritingMode aWritingMode;
+ TextVerticalAdjust aTextVertAdj;
+ TextHorizontalAdjust aTextHorizAdj;
+ Reference< XIndexReplace > xNumRule;
+
+ if( value >>= strValue )
+ fprintf (stderr,"\"%s\"\n", USS( strValue ) );
+ else if( value >>= strArray ) {
+ fprintf (stderr,"%s\n", USS(value.getValueTypeName()));
+ for( int i=0; i<strArray.getLength(); i++ )
+ fprintf (stderr,"\t\t\t[%3d] \"%s\"\n", i, USS( strArray[i] ) );
+ } else if( value >>= propArray ) {
+ fprintf (stderr,"%s\n", USS(value.getValueTypeName()));
+ for( int i=0; i<propArray.getLength(); i++ ) {
+ fprintf (stderr,"\t\t\t[%3d] %s (%s) ", i, USS( propArray[i].Name ), USS(propArray[i].Value.getValueTypeName()) );
+ lclDumpAnyValue( propArray[i].Value );
+ }
+ } else if( value >>= propArrayArray ) {
+ fprintf (stderr,"%s\n", USS(value.getValueTypeName()));
+ for( int i=0; i<propArrayArray.getLength(); i++ ) {
+ fprintf (stderr,"\t\t\t[%3d] ", i);
+ lclDumpAnyValue( Any (propArrayArray[i]) );
+ }
+ } else if( value >>= anyArray ) {
+ fprintf (stderr,"%s\n", USS(value.getValueTypeName()));
+ for( int i=0; i<anyArray.getLength(); i++ ) {
+ fprintf (stderr,"\t\t\t[%3d] (%s) ", i, USS(value.getValueTypeName()) );
+ lclDumpAnyValue( anyArray[i] );
+ }
+ } else if( value >>= adjArray ) {
+ fprintf (stderr,"%s\n", USS(value.getValueTypeName()));
+ for( int i=0; i<adjArray.getLength(); i++ ) {
+ fprintf (stderr,"\t\t\t[%3d] (%s) ", i, USS(adjArray[i].Value.getValueTypeName()) );
+ lclDumpAnyValue( adjArray[i].Value );
+ }
+ } else if( value >>= segArray ) {
+ fprintf (stderr,"%s\n", USS(value.getValueTypeName()));
+ for( int i=0; i<segArray.getLength(); i++ ) {
+ fprintf (stderr,"\t\t\t[%3d] ", i );
+ lclDumpAnyValue( Any( segArray[i] ) );
+ }
+ } else if( value >>= ppArray ) {
+ fprintf (stderr,"%s\n", USS(value.getValueTypeName()));
+ for( int i=0; i<ppArray.getLength(); i++ ) {
+ fprintf (stderr,"\t\t\t[%3d] ", i );
+ lclDumpAnyValue( Any( ppArray[i] ) );
+ }
+ } else if( value >>= segment ) {
+ fprintf (stderr,"Command: %d Count: %d\n", segment.Command, segment.Count);
+ } else if( value >>= pp ) {
+ fprintf (stderr,"First: ");
+ lclDumpAnyValue( Any (pp.First) );
+ fprintf (stderr,"\t\t\t Second: ");
+ lclDumpAnyValue( Any (pp.Second) );
+ } else if( value >>= par ) {
+ fprintf (stderr,"Parameter (%s): ", USS(par.Value.getValueTypeName()));
+ lclDumpAnyValue( par.Value );
+ } else if( value >>= aMatrix ) {
+ fprintf (stderr,"Matrix\n%f %f %f\n%f %f %f\n%f %f %f\n", aMatrix.Line1.Column1, aMatrix.Line1.Column2, aMatrix.Line1.Column3, aMatrix.Line2.Column1, aMatrix.Line2.Column2, aMatrix.Line2.Column3, aMatrix.Line3.Column1, aMatrix.Line3.Column2, aMatrix.Line3.Column3);
+ } else if( value >>= intValue )
+ fprintf (stderr,"%-10" SAL_PRIdINT32 " (hex: %" SAL_PRIxUINT32 ")\n", intValue, intValue);
+ else if( value >>= uintValue )
+ fprintf (stderr,"%-10" SAL_PRIuUINT32 " (hex: %" SAL_PRIxUINT32 ")\n", uintValue, uintValue);
+ else if( value >>= int16Value )
+ fprintf (stderr,"%-10d (hex: %x)\n", int16Value, int16Value);
+ else if( value >>= uint16Value )
+ fprintf (stderr,"%-10d (hex: %x)\n", uint16Value, uint16Value);
+ else if( value >>= floatValue )
+ fprintf (stderr,"%f\n", floatValue);
+ else if( value >>= boolValue )
+ fprintf (stderr,"%-10d (bool)\n", boolValue);
+ else if( value >>= xNumRule ) {
+ fprintf (stderr, "XIndexReplace\n");
+ if (xNumRule.is()) {
+ for (int k=0; k<xNumRule->getCount(); k++) {
+ Sequence< PropertyValue > aBulletPropSeq;
+ fprintf (stderr, "level %d\n", k);
+ if (xNumRule->getByIndex (k) >>= aBulletPropSeq) {
+ for (const PropertyValue& rProp : std::as_const(aBulletPropSeq)) {
+ fprintf(stderr, "%46s = ", USS (rProp.Name));
+ lclDumpAnyValue (rProp.Value);
+ }
+ }
+ }
+ } else {
+ fprintf (stderr, "empty reference\n");
+ }
+ } else if( value >>= aWritingMode )
+ fprintf(stderr, "%d writing mode\n", static_cast<int>(aWritingMode));
+ else if( value >>= aTextVertAdj ) {
+ const char* s = "unknown";
+ switch( aTextVertAdj ) {
+ case TextVerticalAdjust_TOP:
+ s = "top";
+ break;
+ case TextVerticalAdjust_CENTER:
+ s = "center";
+ break;
+ case TextVerticalAdjust_BOTTOM:
+ s = "bottom";
+ break;
+ case TextVerticalAdjust_BLOCK:
+ s = "block";
+ break;
+ case TextVerticalAdjust::TextVerticalAdjust_MAKE_FIXED_SIZE:
+ s = "make_fixed_size";
+ break;
+ }
+ fprintf (stderr, "%s\n", s);
+ } else if( value >>= aTextHorizAdj ) {
+ const char* s = "unknown";
+ switch( aTextHorizAdj ) {
+ case TextHorizontalAdjust_LEFT:
+ s = "left";
+ break;
+ case TextHorizontalAdjust_CENTER:
+ s = "center";
+ break;
+ case TextHorizontalAdjust_RIGHT:
+ s = "right";
+ break;
+ case TextHorizontalAdjust_BLOCK:
+ s = "block";
+ break;
+ case TextHorizontalAdjust::TextHorizontalAdjust_MAKE_FIXED_SIZE:
+ s = "make_fixed_size";
+ break;
+ }
+ fprintf (stderr, "%s\n", s);
+ } else if( value >>= spacing ) {
+ fprintf (stderr, "mode: %d value: %d\n", spacing.Mode, spacing.Height);
+ } else if( value.isExtractableTo(::cppu::UnoType<sal_Int32>::get())) {
+ fprintf (stderr,"is extractable to int32\n");
+ }
+// else if( value >>= pointValue )
+// fprintf (stderr,"%d (RectanglePoint)\n", pointValue);
+ else
+ fprintf (stderr,"??? <unhandled type %s>\n", USS(value.getValueTypeName()));
+}
+
+#ifdef DBG_UTIL
+void PropertyMap::dump( const Reference< XPropertySet >& rXPropSet )
+{
+ Reference< XPropertySetInfo > info = rXPropSet->getPropertySetInfo ();
+ const Sequence< Property > props = info->getProperties ();
+
+ SAL_INFO("oox", "dump props, len: " << props.getLength ());
+
+ for (Property const & prop : props) {
+ OString name = OUStringToOString( prop.Name, RTL_TEXTENCODING_UTF8);
+ fprintf (stderr,"%30s = ", name.getStr() );
+
+ try {
+ lclDumpAnyValue (rXPropSet->getPropertyValue( prop.Name ));
+ } catch (const Exception&) {
+ fprintf (stderr,"unable to get '%s' value\n", USS(prop.Name));
+ }
+ }
+}
+#endif
+
+static void printLevel (int level)
+{
+ for (int i=0; i<level; i++)
+ fprintf (stderr, " ");
+}
+
+static const char *lclGetEnhancedParameterType( sal_uInt16 nType )
+{
+ const char* type;
+ switch (nType) {
+ case EnhancedCustomShapeParameterType::NORMAL:
+ type = "EnhancedCustomShapeParameterType::NORMAL";
+ break;
+ case EnhancedCustomShapeParameterType::EQUATION:
+ type = "EnhancedCustomShapeParameterType::EQUATION";
+ break;
+ case EnhancedCustomShapeParameterType::ADJUSTMENT:
+ type = "EnhancedCustomShapeParameterType::ADJUSTMENT";
+ break;
+ case EnhancedCustomShapeParameterType::LEFT:
+ type = "EnhancedCustomShapeParameterType::LEFT";
+ break;
+ case EnhancedCustomShapeParameterType::TOP:
+ type = "EnhancedCustomShapeParameterType::TOP";
+ break;
+ case EnhancedCustomShapeParameterType::RIGHT:
+ type = "EnhancedCustomShapeParameterType::RIGHT";
+ break;
+ case EnhancedCustomShapeParameterType::BOTTOM:
+ type = "EnhancedCustomShapeParameterType::BOTTOM";
+ break;
+ case EnhancedCustomShapeParameterType::XSTRETCH:
+ type = "EnhancedCustomShapeParameterType::XSTRETCH";
+ break;
+ case EnhancedCustomShapeParameterType::YSTRETCH:
+ type = "EnhancedCustomShapeParameterType::YSTRETCH";
+ break;
+ case EnhancedCustomShapeParameterType::HASSTROKE:
+ type = "EnhancedCustomShapeParameterType::HASSTROKE";
+ break;
+ case EnhancedCustomShapeParameterType::HASFILL:
+ type = "EnhancedCustomShapeParameterType::HASFILL";
+ break;
+ case EnhancedCustomShapeParameterType::WIDTH:
+ type = "EnhancedCustomShapeParameterType::WIDTH";
+ break;
+ case EnhancedCustomShapeParameterType::HEIGHT:
+ type = "EnhancedCustomShapeParameterType::HEIGHT";
+ break;
+ case EnhancedCustomShapeParameterType::LOGWIDTH:
+ type = "EnhancedCustomShapeParameterType::LOGWIDTH";
+ break;
+ case EnhancedCustomShapeParameterType::LOGHEIGHT:
+ type = "EnhancedCustomShapeParameterType::LOGHEIGHT";
+ break;
+ default:
+ type = "unknown";
+ break;
+ }
+ return type;
+}
+
+static void printParameterPairData(int level, EnhancedCustomShapeParameterPair const &pp)
+{
+ // These are always sal_Int32s so lets depend on that for our packing ...
+ sal_Int32 nFirstValue = {};
+ sal_Int32 nSecondValue = {}; // spurious -Werror=maybe-uninitialized
+ if (!(pp.First.Value >>= nFirstValue))
+ assert (false);
+ if (!(pp.Second.Value >>= nSecondValue))
+ assert (false);
+
+ printLevel (level);
+ fprintf (stderr, "{\n");
+ printLevel (level + 1);
+ fprintf (stderr, "%s,\n", lclGetEnhancedParameterType(pp.First.Type));
+ printLevel (level + 1);
+ fprintf (stderr, "%s,\n", lclGetEnhancedParameterType(pp.Second.Type));
+ printLevel (level + 1);
+ fprintf (stderr, "%d, %d\n", static_cast<int>(nFirstValue), static_cast<int>(nSecondValue));
+ printLevel (level);
+ fprintf (stderr, "}");
+}
+
+static const char* lclDumpAnyValueCode( const Any& value, int level)
+{
+ OUString strValue;
+ Sequence< OUString > strArray;
+ Sequence< Any > anyArray;
+ Sequence< awt::Size > sizeArray;
+ Sequence< PropertyValue > propArray;
+ Sequence< Sequence< PropertyValue > > propArrayArray;
+ Sequence< EnhancedCustomShapeAdjustmentValue > adjArray;
+ Sequence< EnhancedCustomShapeTextFrame > segTextFrame;
+ Sequence< EnhancedCustomShapeSegment > segArray;
+ Sequence< EnhancedCustomShapeParameterPair > ppArray;
+ EnhancedCustomShapeSegment segment;
+ EnhancedCustomShapeTextFrame textFrame;
+ EnhancedCustomShapeParameterPair pp;
+ EnhancedCustomShapeParameter par;
+ awt::Rectangle rect;
+ awt::Size size;
+ sal_Int32 intValue;
+ sal_uInt32 uintValue;
+ sal_Int16 int16Value;
+ sal_uInt16 uint16Value;
+ sal_Int64 int64Value;
+ float floatValue = 0;
+ bool boolValue;
+ LineSpacing spacing;
+// RectanglePoint pointValue;
+ WritingMode aWritingMode;
+ TextVerticalAdjust aTextVertAdj;
+ TextHorizontalAdjust aTextHorizAdj;
+ Reference< XIndexReplace > xNumRule;
+
+ if( value >>= strValue )
+ {
+ printLevel (level);
+ fprintf (stderr,"OUString str = \"%s\";\n", USS( strValue ) );
+ return "Any (str)";
+ }
+ else if( value >>= strArray )
+ {
+ if (strArray.getLength() == 0)
+ return "Sequence< OUString >(0)";
+
+ printLevel (level);
+ fprintf (stderr,"static const char *aStrings[] = {\n");
+ for( int i=0; i<strArray.getLength(); i++ ) {
+ printLevel (level + 1);
+ fprintf (stderr,"\"%s\"%s\n", USS( strArray[i] ), i < strArray.getLength() - 1 ? "," : "" );
+ }
+ printLevel (level);
+ fprintf (stderr,"};\n");
+ return "createStringSequence( SAL_N_ELEMENTS( aStrings ), aStrings )";
+ }
+ else if( value >>= propArray )
+ {
+ printLevel (level);
+ fprintf (stderr,"Sequence< PropertyValue > aPropSequence (%" SAL_PRIdINT32 ");\n", propArray.getLength());
+ for( int i=0; i<propArray.getLength(); i++ ) {
+ printLevel (level);
+ fprintf (stderr, "{\n");
+ printLevel (level + 1);
+ fprintf (stderr, "aPropSequence [%d].Name = \"%s\";\n", i, USS( propArray[i].Name ));
+ const char *var = lclDumpAnyValueCode( propArray[i].Value, level + 1 );
+ printLevel (level + 1);
+ fprintf (stderr, "aPropSequence [%d].Value = makeAny (%s);\n", i, var);
+ printLevel (level);
+ fprintf (stderr, "}\n");
+ }
+ return "aPropSequence";
+ }
+ else if( value >>= sizeArray )
+ {
+ printLevel (level);
+ fprintf (stderr, "Sequence< awt::Size > aSizeSequence (%" SAL_PRIdINT32 ");\n", sizeArray.getLength());
+ for( int i=0; i<sizeArray.getLength(); i++ ) {
+ printLevel (level);
+ fprintf (stderr, "{\n");
+ const char *var = lclDumpAnyValueCode (Any (sizeArray[i]), level + 1);
+ printLevel (level + 1);
+ fprintf (stderr, "aSizeSequence [%d] = %s;\n", i, var);
+ printLevel (level);
+ fprintf (stderr, "}\n");
+ }
+ return "aSizeSequence";
+ }
+ else if( value >>= propArrayArray )
+ {
+ printLevel (level);
+ fprintf (stderr,"Sequence< Sequence < PropertyValue > > aPropSequenceSequence (%" SAL_PRIdINT32 ");\n", propArrayArray.getLength());
+ for( int i=0; i<propArrayArray.getLength(); i++ ) {
+ printLevel (level);
+ fprintf (stderr, "{\n");
+ const char *var = lclDumpAnyValueCode( Any (propArrayArray[i]), level + 1 );
+ printLevel (level + 1);
+ fprintf (stderr, "aPropSequenceSequence [%d] = %s;\n", i, var);
+ printLevel (level);
+ fprintf (stderr, "}\n");
+ }
+ return "aPropSequenceSequence";
+ }
+ else if( value >>= anyArray )
+ {
+ fprintf (stderr,"%s\n", USS(value.getValueTypeName()));
+ for( int i=0; i<anyArray.getLength(); i++ ) {
+ fprintf (stderr,"\t\t\t[%3d] (%s) ", i, USS(value.getValueTypeName()) );
+ lclDumpAnyValue( anyArray[i] );
+ }
+ }
+ else if( value >>= adjArray )
+ {
+ printLevel (level);
+ fprintf (stderr,"Sequence< EnhancedCustomShapeAdjustmentValue > aAdjSequence (%" SAL_PRIdINT32 ");\n", adjArray.getLength());
+ for( int i=0; i<adjArray.getLength(); i++ ) {
+ printLevel (level);
+ fprintf (stderr, "{\n");
+ const char *var = lclDumpAnyValueCode( adjArray[i].Value, level + 1 );
+ printLevel (level + 1);
+ fprintf (stderr, "aAdjSequence [%d].Value = %s;\n", i, var);
+ if (adjArray[i].Name.getLength() > 0) {
+ printLevel (level + 1);
+ fprintf (stderr, "aAdjSequence [%d].Name = \"%s\";\n", i, USS (adjArray[i].Name));
+ }
+ printLevel (level);
+ fprintf (stderr, "}\n");
+ }
+ return "aAdjSequence";
+ }
+ else if( value >>= segArray )
+ {
+ if (segArray.getLength() == 0)
+ return "Sequence< EnhancedCustomShapeSegment >(0)";
+
+ printLevel (level);
+ fprintf (stderr,"static const sal_uInt16 nValues[] = {\n");
+ printLevel (level);
+ fprintf (stderr,"// Command, Count\n");
+ for( int i = 0; i < segArray.getLength(); i++ ) {
+ printLevel (level + 1);
+ fprintf (stderr,"%d,%d%s\n", segArray[i].Command,
+ segArray[i].Count, i < segArray.getLength() - 1 ? "," : "");
+ }
+ printLevel (level);
+ fprintf (stderr,"};\n");
+ return "createSegmentSequence( SAL_N_ELEMENTS( nValues ), nValues )";
+ }
+ else if( value >>= segTextFrame )
+ {
+ printLevel (level);
+ fprintf (stderr, "Sequence< EnhancedCustomShapeTextFrame > aTextFrameSeq (%" SAL_PRIdINT32 ");\n", segTextFrame.getLength());
+ for( int i=0; i<segTextFrame.getLength(); i++ ) {
+ printLevel (level);
+ fprintf (stderr, "{\n");
+ const char *var = lclDumpAnyValueCode (Any (segTextFrame[i]), level + 1);
+ printLevel (level + 1);
+ fprintf (stderr, "aTextFrameSeq [%d] = %s;\n", i, var);
+ printLevel (level);
+ fprintf (stderr, "}\n");
+ }
+ return "aTextFrameSeq";
+ }
+ else if( value >>= ppArray )
+ {
+ printLevel (level);
+ if (ppArray.getLength() == 0)
+ return "Sequence< EnhancedCustomShapeParameterPair >(0)";
+
+ fprintf (stderr, "static const CustomShapeProvider::ParameterPairData aData[] = {\n");
+ for( int i = 0; i < ppArray.getLength(); i++ ) {
+ printParameterPairData(level + 1, ppArray[i]);
+ fprintf (stderr,"%s\n", i < ppArray.getLength() - 1 ? "," : "");
+ }
+ printLevel (level);
+ fprintf (stderr,"};\n");
+
+ return "createParameterPairSequence(SAL_N_ELEMENTS(aData), aData)";
+ }
+ else if( value >>= segment )
+ {
+ printLevel (level);
+ fprintf (stderr, "EnhancedCustomShapeSegment aSegment;\n");
+ printLevel (level);
+ // TODO: use EnhancedCustomShapeSegmentCommand constants
+ fprintf (stderr, "aSegment.Command = %d;\n", segment.Command);
+ printLevel (level);
+ fprintf (stderr, "aSegment.Count = %d;\n", segment.Count);
+ return "aSegment";
+ }
+ else if( value >>= textFrame )
+ {
+ printLevel (level);
+ fprintf (stderr, "EnhancedCustomShapeTextFrame aTextFrame;\n");
+ printLevel (level);
+ fprintf (stderr, "{\n");
+ {
+ const char* var = lclDumpAnyValueCode( Any (textFrame.TopLeft), level + 1 );
+ printLevel (level + 1);
+ fprintf (stderr, "aTextFrame.TopLeft = %s;\n", var);
+ }
+ printLevel (level);
+ fprintf (stderr, "}\n");
+
+ printLevel (level);
+ fprintf (stderr, "{\n");
+ {
+ const char* var = lclDumpAnyValueCode( Any (textFrame.BottomRight), level + 1 );
+ printLevel (level + 1);
+ fprintf (stderr, "aTextFrame.BottomRight = %s;\n", var);
+ }
+ printLevel (level);
+ fprintf (stderr, "}\n");
+
+ return "aTextFrame";
+ }
+ else if( value >>= pp )
+ {
+ printLevel (level);
+ fprintf (stderr, "static const CustomShapeProvider::ParameterPairData aData =\n");
+ printParameterPairData(level, pp);
+ fprintf (stderr, ";\n");
+
+ return "createParameterPair(&aData)";
+ }
+ else if( value >>= par )
+ {
+ printLevel (level);
+ fprintf (stderr,"EnhancedCustomShapeParameter aParameter;\n");
+ const char* var = lclDumpAnyValueCode( par.Value, level );
+ printLevel (level);
+ fprintf (stderr,"aParameter.Value = %s;\n", var);
+ printLevel (level);
+ fprintf (stderr,"aParameter.Type = %s;\n",
+ lclGetEnhancedParameterType(par.Type));
+ return "aParameter";
+ }
+ else if( value >>= int64Value )
+ {
+ printLevel (level);
+ fprintf (stderr,"Any aAny ((sal_Int64) %" SAL_PRIdINT64 ");\n", int64Value);
+ return "aAny";
+ }
+ else if( value >>= intValue )
+ fprintf (stderr,"%" SAL_PRIdINT32 " (hex: %" SAL_PRIxUINT32 ")\n", intValue, intValue);
+ else if( value >>= uintValue )
+ fprintf (stderr,"%" SAL_PRIdINT32 " (hex: %" SAL_PRIxUINT32 ")\n", uintValue, uintValue);
+ else if( value >>= int16Value )
+ fprintf (stderr,"%d (hex: %x)\n", int16Value, int16Value);
+ else if( value >>= uint16Value )
+ fprintf (stderr,"%d (hex: %x)\n", uint16Value, uint16Value);
+ else if( value >>= floatValue )
+ fprintf (stderr,"%f\n", floatValue);
+ else if( value >>= boolValue ) {
+ if (boolValue)
+ return "(sal_Bool) sal_True";
+ else
+ return "(sal_Bool) sal_False";
+ }
+ else if( value >>= xNumRule ) {
+ fprintf (stderr, "XIndexReplace\n");
+ for (int k=0; k<xNumRule->getCount(); k++) {
+ Sequence< PropertyValue > aBulletPropSeq;
+ fprintf (stderr, "level %d\n", k);
+ if (xNumRule->getByIndex (k) >>= aBulletPropSeq) {
+ for (const PropertyValue& rProp : std::as_const(aBulletPropSeq)) {
+ fprintf(stderr, "%46s = ", USS (rProp.Name));
+ lclDumpAnyValue (rProp.Value);
+ }
+ }
+ }
+ }
+ else if( value >>= aWritingMode )
+ fprintf (stderr, "%d writing mode\n", static_cast<int>(aWritingMode));
+ else if( value >>= aTextVertAdj ) {
+ const char* s = "unknown";
+ switch( aTextVertAdj ) {
+ case TextVerticalAdjust_TOP:
+ s = "top";
+ break;
+ case TextVerticalAdjust_CENTER:
+ s = "center";
+ break;
+ case TextVerticalAdjust_BOTTOM:
+ s = "bottom";
+ break;
+ case TextVerticalAdjust_BLOCK:
+ s = "block";
+ break;
+ case TextVerticalAdjust::TextVerticalAdjust_MAKE_FIXED_SIZE:
+ s = "make_fixed_size";
+ break;
+ }
+ fprintf (stderr, "%s\n", s);
+ }
+ else if( value >>= aTextHorizAdj ) {
+ const char* s = "unknown";
+ switch( aTextHorizAdj ) {
+ case TextHorizontalAdjust_LEFT:
+ s = "left";
+ break;
+ case TextHorizontalAdjust_CENTER:
+ s = "center";
+ break;
+ case TextHorizontalAdjust_RIGHT:
+ s = "right";
+ break;
+ case TextHorizontalAdjust_BLOCK:
+ s = "block";
+ break;
+ case TextHorizontalAdjust::TextHorizontalAdjust_MAKE_FIXED_SIZE:
+ s = "make_fixed_size";
+ break;
+ }
+ fprintf (stderr, "%s\n", s);
+ }
+ else if( value >>= spacing ) {
+ fprintf (stderr, "mode: %d value: %d\n", spacing.Mode, spacing.Height);
+ }
+ else if( value >>= rect ) {
+ printLevel (level);
+ fprintf (stderr, "awt::Rectangle aRectangle;\n");
+ printLevel (level);
+ fprintf (stderr, "aRectangle.X = %" SAL_PRIdINT32 ";\n", rect.X);
+ printLevel (level);
+ fprintf (stderr, "aRectangle.Y = %" SAL_PRIdINT32 ";\n", rect.Y);
+ printLevel (level);
+ fprintf (stderr, "aRectangle.Width = %" SAL_PRIdINT32 ";\n", rect.Width);
+ printLevel (level);
+ fprintf (stderr, "aRectangle.Height = %" SAL_PRIdINT32 ";\n", rect.Height);
+ return "aRectangle";
+ }
+ else if( value >>= size ) {
+ printLevel (level);
+ fprintf (stderr, "awt::Size aSize;\n");
+ printLevel (level);
+ fprintf (stderr, "aSize.Width = %" SAL_PRIdINT32 ";\n", size.Width);
+ printLevel (level);
+ fprintf (stderr, "aSize.Height = %" SAL_PRIdINT32 ";\n", size.Height);
+ return "aSize";
+ }
+ else if( value.isExtractableTo(::cppu::UnoType<sal_Int32>::get())) {
+ fprintf (stderr,"is extractable to int32\n");
+ }
+ else
+ fprintf (stderr,"??? <unhandled type %s>\n", USS(value.getValueTypeName()));
+
+ return "";
+}
+
+void PropertyMap::dumpCode( const Reference< XPropertySet >& rXPropSet )
+{
+ Reference< XPropertySetInfo > info = rXPropSet->getPropertySetInfo ();
+ const Sequence< Property > props = info->getProperties ();
+ static constexpr OUStringLiteral sType = u"Type";
+
+ for (const Property& rProp : props) {
+
+ // ignore Type, it is set elsewhere
+ if (rProp.Name == sType)
+ continue;
+
+ OString name = OUStringToOString( rProp.Name, RTL_TEXTENCODING_UTF8);
+
+ try {
+ int level = 1;
+ printLevel (level);
+ fprintf (stderr, "{\n");
+ const char* var = lclDumpAnyValueCode (rXPropSet->getPropertyValue (rProp.Name), level + 1);
+ printLevel (level + 1);
+ fprintf (stderr,"aPropertyMap.setProperty(PROP_%s, %s);\n", name.getStr(), var);
+ printLevel (level);
+ fprintf (stderr, "}\n");
+ } catch (const Exception&) {
+ fprintf (stderr,"unable to get '%s' value\n", USS(rProp.Name));
+ }
+ }
+}
+
+void PropertyMap::dumpData(const Reference<XPropertySet>& xPropertySet)
+{
+ Reference<XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
+ const Sequence<Property> aProperties = xPropertySetInfo->getProperties();
+
+ for (const Property& rProp : aProperties)
+ {
+ std::cerr << rProp.Name << std::endl;
+ std::cerr << comphelper::anyToString(xPropertySet->getPropertyValue(rProp.Name)) << std::endl;
+ }
+}
+
+#endif
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/helper/propertyset.cxx b/oox/source/helper/propertyset.cxx
new file mode 100644
index 0000000000..3803547335
--- /dev/null
+++ b/oox/source/helper/propertyset.cxx
@@ -0,0 +1,150 @@
+/* -*- 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/helper/propertyset.hxx>
+
+#include <com/sun/star/beans/XMultiPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <oox/helper/propertymap.hxx>
+
+namespace oox {
+
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+
+void PropertySet::set( const Reference< XPropertySet >& rxPropSet )
+{
+ mxPropSet = rxPropSet;
+ mxMultiPropSet.set( mxPropSet, UNO_QUERY );
+ if( mxPropSet.is() ) try
+ {
+ mxPropSetInfo = mxPropSet->getPropertySetInfo();
+ }
+ catch( Exception& )
+ {
+ }
+}
+
+bool PropertySet::hasProperty( sal_Int32 nPropId ) const
+{
+ if( mxPropSetInfo.is() ) try
+ {
+ const OUString& rPropName = PropertyMap::getPropertyName( nPropId );
+ return mxPropSetInfo->hasPropertyByName( rPropName );
+ }
+ catch( Exception& )
+ {
+ }
+ return false;
+}
+
+// Get properties -------------------------------------------------------------
+
+Any PropertySet::getAnyProperty( sal_Int32 nPropId ) const
+{
+ Any aValue;
+ return implGetPropertyValue( aValue, PropertyMap::getPropertyName( nPropId ) ) ? aValue : Any();
+}
+
+// Set properties -------------------------------------------------------------
+
+bool PropertySet::setAnyProperty( sal_Int32 nPropId, const Any& rValue )
+{
+ return implSetPropertyValue( PropertyMap::getPropertyName( nPropId ), rValue );
+}
+
+void PropertySet::setProperties( const Sequence< OUString >& rPropNames, const Sequence< Any >& rValues )
+{
+ OSL_ENSURE( rPropNames.getLength() == rValues.getLength(),
+ "PropertySet::setProperties - length of sequences different" );
+
+ if( mxMultiPropSet.is() ) try
+ {
+ mxMultiPropSet->setPropertyValues( rPropNames, rValues );
+ return;
+ }
+ catch( Exception& )
+ {
+ SAL_WARN( "oox", "PropertySet::setProperties - cannot set all property values, fallback to single mode" );
+ }
+
+ if( mxPropSet.is() )
+ {
+ const Any* pValue = rValues.getConstArray();
+ for( const OUString& rPropName : rPropNames )
+ implSetPropertyValue( rPropName, *pValue++ );
+ }
+}
+
+void PropertySet::setProperties( const PropertyMap& rPropertyMap )
+{
+ if( !rPropertyMap.empty() )
+ {
+ Sequence< OUString > aPropNames;
+ Sequence< Any > aValues;
+ rPropertyMap.fillSequences( aPropNames, aValues );
+ setProperties( aPropNames, aValues );
+ }
+}
+
+// private --------------------------------------------------------------------
+
+bool PropertySet::implGetPropertyValue( Any& orValue, const OUString& rPropName ) const
+{
+ if( mxPropSet.is() ) try
+ {
+ orValue = mxPropSet->getPropertyValue( rPropName );
+ return true;
+ }
+ catch( const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "oox", "PropertySet::implGetPropertyValue - cannot get property \"" <<
+ rPropName << "\"");
+ }
+ return false;
+}
+
+bool PropertySet::implSetPropertyValue( const OUString& rPropName, const Any& rValue )
+{
+ if( mxPropSet.is() ) try
+ {
+ mxPropSet->setPropertyValue( rPropName, rValue );
+ return true;
+ }
+ catch( const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "oox", "PropertySet::implSetPropertyValue - cannot set property \"" <<
+ rPropName << "\"");
+ }
+ return false;
+}
+
+#ifdef DBG_UTIL
+void PropertySet::dump()
+{
+ PropertyMap::dump( mxPropSet );
+}
+#endif
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/helper/storagebase.cxx b/oox/source/helper/storagebase.cxx
new file mode 100644
index 0000000000..4646603631
--- /dev/null
+++ b/oox/source/helper/storagebase.cxx
@@ -0,0 +1,256 @@
+/* -*- 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/helper/storagebase.hxx>
+
+#include <com/sun/star/io/XStream.hpp>
+#include <osl/diagnose.h>
+#include <rtl/ustrbuf.hxx>
+#include <oox/helper/binaryinputstream.hxx>
+#include <oox/helper/binaryoutputstream.hxx>
+#include <utility>
+
+namespace oox {
+
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+void lclSplitFirstElement( OUString& orElement, OUString& orRemainder, const OUString& _aFullName )
+{
+ OUString aFullName = _aFullName;
+ sal_Int32 nSlashPos = aFullName.indexOf( '/' );
+
+ // strip leading slashes
+ while( nSlashPos == 0 )
+ {
+ aFullName = aFullName.copy(1);
+ nSlashPos = aFullName.indexOf( '/' );
+ }
+
+ if( (0 <= nSlashPos) && (nSlashPos < aFullName.getLength()) )
+ {
+ orElement = aFullName.copy( 0, nSlashPos );
+ orRemainder = aFullName.copy( nSlashPos + 1 );
+ }
+ else
+ {
+ orElement = aFullName;
+ }
+}
+
+} // namespace
+
+StorageBase::StorageBase( const Reference< XInputStream >& rxInStream, bool bBaseStreamAccess ) :
+ mxInStream( rxInStream ),
+ mbBaseStreamAccess( bBaseStreamAccess ),
+ mbReadOnly( true )
+{
+ OSL_ENSURE( mxInStream.is(), "StorageBase::StorageBase - missing base input stream" );
+}
+
+StorageBase::StorageBase( const Reference< XStream >& rxOutStream, bool bBaseStreamAccess ) :
+ mxOutStream( rxOutStream ),
+ mbBaseStreamAccess( bBaseStreamAccess ),
+ mbReadOnly( false )
+{
+ OSL_ENSURE( mxOutStream.is(), "StorageBase::StorageBase - missing base output stream" );
+}
+
+StorageBase::StorageBase( const StorageBase& rParentStorage, OUString aStorageName, bool bReadOnly ) :
+ maParentPath( rParentStorage.getPath() ),
+ maStorageName(std::move( aStorageName )),
+ mbBaseStreamAccess( false ),
+ mbReadOnly( bReadOnly )
+{
+}
+
+StorageBase::~StorageBase()
+{
+}
+
+bool StorageBase::isStorage() const
+{
+ return implIsStorage();
+}
+
+bool StorageBase::isRootStorage() const
+{
+ return implIsStorage() && maStorageName.isEmpty();
+}
+
+Reference< XStorage > StorageBase::getXStorage() const
+{
+ return implGetXStorage();
+}
+
+OUString StorageBase::getPath() const
+{
+ OUStringBuffer aBuffer( maParentPath );
+ if( !aBuffer.isEmpty() )
+ aBuffer.append( '/' );
+ aBuffer.append( maStorageName );
+ return aBuffer.makeStringAndClear();
+}
+
+void StorageBase::getElementNames( ::std::vector< OUString >& orElementNames ) const
+{
+ orElementNames.clear();
+ implGetElementNames( orElementNames );
+}
+
+StorageRef StorageBase::openSubStorage( const OUString& rStorageName, bool bCreateMissing )
+{
+ StorageRef xSubStorage;
+ OSL_ENSURE( !bCreateMissing || !mbReadOnly, "StorageBase::openSubStorage - cannot create substorage in read-only mode" );
+ if( !bCreateMissing || !mbReadOnly )
+ {
+ OUString aElement, aRemainder;
+ lclSplitFirstElement( aElement, aRemainder, rStorageName );
+ if( !aElement.isEmpty() )
+ xSubStorage = getSubStorage( aElement, bCreateMissing );
+ if( xSubStorage && !aRemainder.isEmpty() )
+ xSubStorage = xSubStorage->openSubStorage( aRemainder, bCreateMissing );
+ }
+ return xSubStorage;
+}
+
+Reference< XInputStream > StorageBase::openInputStream( const OUString& rStreamName )
+{
+ Reference< XInputStream > xInStream;
+ OUString aElement, aRemainder;
+ lclSplitFirstElement( aElement, aRemainder, rStreamName );
+ if( !aElement.isEmpty() )
+ {
+ if( !aRemainder.isEmpty() )
+ {
+ StorageRef xSubStorage = getSubStorage( aElement, false );
+ if( xSubStorage )
+ xInStream = xSubStorage->openInputStream( aRemainder );
+ }
+ else
+ {
+ xInStream = implOpenInputStream( aElement );
+ }
+ }
+ else if( mbBaseStreamAccess )
+ {
+ xInStream = mxInStream;
+ }
+ return xInStream;
+}
+
+Reference< XOutputStream > StorageBase::openOutputStream( const OUString& rStreamName )
+{
+ Reference< XOutputStream > xOutStream;
+ OSL_ENSURE( !mbReadOnly, "StorageBase::openOutputStream - cannot create output stream in read-only mode" );
+ if( !mbReadOnly )
+ {
+ OUString aElement, aRemainder;
+ lclSplitFirstElement( aElement, aRemainder, rStreamName );
+ if( !aElement.isEmpty() )
+ {
+ if( !aRemainder.isEmpty() )
+ {
+ StorageRef xSubStorage = getSubStorage( aElement, true );
+ if( xSubStorage )
+ xOutStream = xSubStorage->openOutputStream( aRemainder );
+ }
+ else
+ {
+ xOutStream = implOpenOutputStream( aElement );
+ }
+ }
+ else if( mbBaseStreamAccess )
+ {
+ xOutStream = mxOutStream->getOutputStream();
+ }
+ }
+ return xOutStream;
+}
+
+void StorageBase::copyToStorage( StorageBase& rDestStrg, const OUString& rElementName )
+{
+ OSL_ENSURE( rDestStrg.isStorage() && !rDestStrg.isReadOnly(), "StorageBase::copyToStorage - invalid destination" );
+ OSL_ENSURE( !rElementName.isEmpty(), "StorageBase::copyToStorage - invalid element name" );
+ if( !rDestStrg.isStorage() || rDestStrg.isReadOnly() || rElementName.isEmpty() )
+ return;
+
+ StorageRef xSubStrg = openSubStorage( rElementName, false );
+ if( xSubStrg )
+ {
+ StorageRef xDestSubStrg = rDestStrg.openSubStorage( rElementName, true );
+ if( xDestSubStrg )
+ xSubStrg->copyStorageToStorage( *xDestSubStrg );
+ }
+ else
+ {
+ Reference< XInputStream > xInStrm = openInputStream( rElementName );
+ if( xInStrm.is() )
+ {
+ Reference< XOutputStream > xOutStrm = rDestStrg.openOutputStream( rElementName );
+ if( xOutStrm.is() )
+ {
+ BinaryXInputStream aInStrm( xInStrm, true );
+ BinaryXOutputStream aOutStrm( xOutStrm, true );
+ aInStrm.copyToStream( aOutStrm );
+ }
+ }
+ }
+}
+
+void StorageBase::copyStorageToStorage( StorageBase& rDestStrg )
+{
+ OSL_ENSURE( rDestStrg.isStorage() && !rDestStrg.isReadOnly(), "StorageBase::copyToStorage - invalid destination" );
+ if( rDestStrg.isStorage() && !rDestStrg.isReadOnly() )
+ {
+ ::std::vector< OUString > aElements;
+ getElementNames( aElements );
+ for (auto const& elem : aElements)
+ copyToStorage(rDestStrg, elem);
+ }
+}
+
+void StorageBase::commit()
+{
+ OSL_ENSURE( !mbReadOnly, "StorageBase::commit - cannot commit in read-only mode" );
+ if( !mbReadOnly )
+ {
+ // commit all open substorages
+ maSubStorages.forEachMem( &StorageBase::commit );
+ // commit this storage
+ implCommit();
+ }
+}
+
+// private --------------------------------------------------------------------
+
+StorageRef StorageBase::getSubStorage( const OUString& rElementName, bool bCreateMissing )
+{
+ StorageRef& rxSubStrg = maSubStorages[ rElementName ];
+ if( !rxSubStrg )
+ rxSubStrg = implOpenSubStorage( rElementName, bCreateMissing );
+ return rxSubStrg;
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/helper/textinputstream.cxx b/oox/source/helper/textinputstream.cxx
new file mode 100644
index 0000000000..a48860c354
--- /dev/null
+++ b/oox/source/helper/textinputstream.cxx
@@ -0,0 +1,208 @@
+/* -*- 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/helper/textinputstream.hxx>
+
+#include <com/sun/star/io/NotConnectedException.hpp>
+#include <com/sun/star/io/TextInputStream.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <osl/diagnose.h>
+#include <rtl/tencinfo.h>
+#include <oox/helper/binaryinputstream.hxx>
+
+namespace oox {
+
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+namespace {
+
+/** Implementation of a UNO input stream wrapping a binary input stream.
+ */
+class UnoBinaryInputStream : public ::cppu::WeakImplHelper< XInputStream >
+{
+public:
+ explicit UnoBinaryInputStream( BinaryInputStream& rInStrm );
+
+ virtual sal_Int32 SAL_CALL readBytes( Sequence< sal_Int8 >& rData, sal_Int32 nBytesToRead ) override;
+ virtual sal_Int32 SAL_CALL readSomeBytes( Sequence< sal_Int8 >& rData, sal_Int32 nMaxBytesToRead ) override;
+ virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) override;
+ virtual sal_Int32 SAL_CALL available() override;
+ virtual void SAL_CALL closeInput() override;
+
+private:
+ /// @throws NotConnectedException
+ void ensureConnected() const;
+
+private:
+ BinaryInputStream* mpInStrm;
+};
+
+UnoBinaryInputStream::UnoBinaryInputStream( BinaryInputStream& rInStrm ) :
+ mpInStrm( &rInStrm )
+{
+}
+
+sal_Int32 SAL_CALL UnoBinaryInputStream::readBytes( Sequence< sal_Int8 >& rData, sal_Int32 nBytesToRead )
+{
+ ensureConnected();
+ return mpInStrm->readData( rData, nBytesToRead );
+}
+
+sal_Int32 SAL_CALL UnoBinaryInputStream::readSomeBytes( Sequence< sal_Int8 >& rData, sal_Int32 nMaxBytesToRead )
+{
+ ensureConnected();
+ return mpInStrm->readData( rData, nMaxBytesToRead );
+}
+
+void SAL_CALL UnoBinaryInputStream::skipBytes( sal_Int32 nBytesToSkip )
+{
+ ensureConnected();
+ mpInStrm->skip( nBytesToSkip );
+}
+
+sal_Int32 SAL_CALL UnoBinaryInputStream::available()
+{
+ ensureConnected();
+ throw RuntimeException( "Functionality not supported", Reference< XInputStream >() );
+}
+
+void SAL_CALL UnoBinaryInputStream::closeInput()
+{
+ ensureConnected();
+ mpInStrm->close();
+ mpInStrm = nullptr;
+}
+
+void UnoBinaryInputStream::ensureConnected() const
+{
+ if( !mpInStrm )
+ throw NotConnectedException( "Stream closed" );
+}
+
+} // namespace
+
+TextInputStream::TextInputStream( const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm, rtl_TextEncoding eTextEnc )
+{
+ init( rxContext, rxInStrm, eTextEnc );
+}
+
+TextInputStream::TextInputStream( const Reference< XComponentContext >& rxContext, BinaryInputStream& rInStrm, rtl_TextEncoding eTextEnc )
+{
+ init( rxContext, new UnoBinaryInputStream( rInStrm ), eTextEnc );
+}
+
+TextInputStream::~TextInputStream()
+{
+}
+
+bool TextInputStream::isEof() const
+{
+ if( mxTextStrm.is() ) try
+ {
+ return mxTextStrm->isEOF();
+ }
+ catch (const Exception&)
+ {
+ }
+ return true;
+}
+
+OUString TextInputStream::readLine()
+{
+ if( mxTextStrm.is() ) try
+ {
+ /* The function createFinalString() adds a character that may have
+ been buffered in the previous call of readToChar() (see below). */
+ return createFinalString( mxTextStrm->readLine() );
+ }
+ catch (const Exception&)
+ {
+ mxTextStrm.clear();
+ }
+ return OUString();
+}
+
+OUString TextInputStream::readToChar( sal_Unicode cChar, bool bIncludeChar )
+{
+ if( mxTextStrm.is() ) try
+ {
+ Sequence< sal_Unicode > aDelimiters{ cChar };
+ /* Always get the delimiter character from the UNO text input stream.
+ In difference to this implementation, it will not return it in the
+ next call but silently skip it. If caller specifies to exclude the
+ character in this call, it will be returned in the next call of one
+ of the own member functions. The function createFinalString() adds
+ a character that has been buffered in the previous call. */
+ OUString aString = createFinalString( mxTextStrm->readString( aDelimiters, false ) );
+ // remove last character from string and remember it for next call
+ if( !bIncludeChar && !aString.isEmpty() && (aString[ aString.getLength() - 1 ] == cChar) )
+ {
+ mcPendingChar = cChar;
+ aString = aString.copy( 0, aString.getLength() - 1 );
+ }
+ return aString;
+ }
+ catch (const Exception&)
+ {
+ mxTextStrm.clear();
+ }
+ return OUString();
+}
+
+Reference< XTextInputStream2 > TextInputStream::createXTextInputStream(
+ const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm, rtl_TextEncoding eTextEnc )
+{
+ Reference< XTextInputStream2 > xTextStrm;
+ const char* pcCharset = rtl_getBestMimeCharsetFromTextEncoding( eTextEnc );
+ OSL_ENSURE( pcCharset, "TextInputStream::createXTextInputStream - unsupported text encoding" );
+ if( rxContext.is() && rxInStrm.is() && pcCharset ) try
+ {
+ xTextStrm = css::io::TextInputStream::create( rxContext );
+ xTextStrm->setInputStream( rxInStrm );
+ xTextStrm->setEncoding( OUString::createFromAscii( pcCharset ) );
+ }
+ catch (const Exception&)
+ {
+ }
+ return xTextStrm;
+}
+
+// private --------------------------------------------------------------------
+
+OUString TextInputStream::createFinalString( const OUString& rString )
+{
+ if( mcPendingChar == 0 )
+ return rString;
+
+ OUString aString = OUStringChar( mcPendingChar ) + rString;
+ mcPendingChar = 0;
+ return aString;
+}
+
+void TextInputStream::init( const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStrm, rtl_TextEncoding eTextEnc )
+{
+ mcPendingChar = 0;
+ mxTextStrm = createXTextInputStream( rxContext, rxInStrm, eTextEnc );
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/source/helper/zipstorage.cxx b/oox/source/helper/zipstorage.cxx
new file mode 100644
index 0000000000..db73b14bdd
--- /dev/null
+++ b/oox/source/helper/zipstorage.cxx
@@ -0,0 +1,203 @@
+/* -*- 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/helper/zipstorage.hxx>
+
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <comphelper/diagnose_ex.hxx>
+#include <comphelper/storagehelper.hxx>
+
+namespace oox {
+
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::uno;
+
+ZipStorage::ZipStorage( const Reference< XComponentContext >& rxContext, const Reference< XInputStream >& rxInStream, bool bRepairStorage ) :
+ StorageBase( rxInStream, false )
+{
+ OSL_ENSURE( rxContext.is(), "ZipStorage::ZipStorage - missing component context" );
+ // create base storage object
+ if( !rxContext.is() )
+ return;
+
+ try
+ {
+ /* #i105325# ::comphelper::OStorageHelper::GetStorageFromInputStream()
+ cannot be used here as it will open a storage with format type
+ 'PackageFormat' that will not work with OOXML packages.
+
+ #161971# The MS-document storages should always be opened in repair
+ mode to ignore the format errors and get so much info as possible.
+ I hate this solution, but it seems to be the only consistent way to
+ handle the MS documents.
+
+ TODO: #i105410# switch to 'OFOPXMLFormat' and use its
+ implementation of relations handling.
+ */
+ mxStorage = ::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
+ ZIP_STORAGE_FORMAT_STRING, rxInStream, rxContext, bRepairStorage);
+ }
+ catch (Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("oox.storage", "ZipStorage::ZipStorage exception opening input storage");
+ }
+}
+
+ZipStorage::ZipStorage( const Reference< XComponentContext >& rxContext, const Reference< XStream >& rxStream ) :
+ StorageBase( rxStream, false )
+{
+ OSL_ENSURE( rxContext.is(), "ZipStorage::ZipStorage - missing component context" );
+ // create base storage object
+ if( rxContext.is() ) try
+ {
+ const sal_Int32 nOpenMode = ElementModes::READWRITE | ElementModes::TRUNCATE;
+ mxStorage = ::comphelper::OStorageHelper::GetStorageOfFormatFromStream(
+ OFOPXML_STORAGE_FORMAT_STRING, rxStream, nOpenMode, rxContext, true);
+ }
+ catch (Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("oox.storage", "ZipStorage::ZipStorage exception opening output storage");
+ }
+}
+
+ZipStorage::ZipStorage( const ZipStorage& rParentStorage, const Reference< XStorage >& rxStorage, const OUString& rElementName ) :
+ StorageBase( rParentStorage, rElementName, rParentStorage.isReadOnly() ),
+ mxStorage( rxStorage )
+{
+ SAL_WARN_IF(!mxStorage.is(), "oox.storage", "ZipStorage::ZipStorage "
+ " - missing storage" );
+}
+
+ZipStorage::~ZipStorage()
+{
+}
+
+bool ZipStorage::implIsStorage() const
+{
+ return mxStorage.is();
+}
+
+Reference< XStorage > ZipStorage::implGetXStorage() const
+{
+ return mxStorage;
+}
+
+void ZipStorage::implGetElementNames( ::std::vector< OUString >& orElementNames ) const
+{
+ if( mxStorage.is() ) try
+ {
+ const Sequence<OUString> aNames = mxStorage->getElementNames();
+ if( aNames.hasElements() )
+ orElementNames.insert( orElementNames.end(), aNames.begin(), aNames.end() );
+ }
+ catch (Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("oox.storage", "getElementNames");
+ }
+}
+
+StorageRef ZipStorage::implOpenSubStorage( const OUString& rElementName, bool bCreateMissing )
+{
+ Reference< XStorage > xSubXStorage;
+ bool bMissing = false;
+ if( mxStorage.is() ) try
+ {
+ // XStorage::isStorageElement may throw various exceptions...
+ if( mxStorage->isStorageElement( rElementName ) )
+ xSubXStorage = mxStorage->openStorageElement(
+ rElementName, css::embed::ElementModes::READ );
+ }
+ catch( NoSuchElementException& )
+ {
+ bMissing = true;
+ }
+ catch (Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("oox.storage", "openStorageElement");
+ }
+
+ if( bMissing && bCreateMissing ) try
+ {
+ xSubXStorage = mxStorage->openStorageElement(
+ rElementName, css::embed::ElementModes::READWRITE );
+ }
+ catch (Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("oox.storage", "openStorageElement");
+ }
+
+ StorageRef xSubStorage;
+ if( xSubXStorage.is() )
+ xSubStorage.reset( new ZipStorage( *this, xSubXStorage, rElementName ) );
+ return xSubStorage;
+}
+
+Reference< XInputStream > ZipStorage::implOpenInputStream( const OUString& rElementName )
+{
+ Reference< XInputStream > xInStream;
+ if( mxStorage.is() ) try
+ {
+ xInStream.set( mxStorage->openStreamElement( rElementName, css::embed::ElementModes::READ ), UNO_QUERY );
+ }
+ catch (Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("oox.storage", "openStreamElement");
+ }
+ return xInStream;
+}
+
+Reference< XOutputStream > ZipStorage::implOpenOutputStream( const OUString& rElementName )
+{
+ Reference< XOutputStream > xOutStream;
+ if( mxStorage.is() ) try
+ {
+ xOutStream.set( mxStorage->openStreamElement( rElementName, css::embed::ElementModes::READWRITE ), UNO_QUERY );
+ }
+ catch (Exception const&)
+ {
+ TOOLS_INFO_EXCEPTION("oox.storage", "openStreamElement");
+ }
+ return xOutStream;
+}
+
+void ZipStorage::implCommit() const
+{
+ try
+ {
+ Reference< XTransactedObject >( mxStorage, UNO_QUERY_THROW )->commit();
+ }
+ catch (Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("oox.storage", "commit");
+ }
+}
+
+} // namespace oox
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */