diff options
Diffstat (limited to 'oox/source/helper')
-rw-r--r-- | oox/source/helper/attributelist.cxx | 372 | ||||
-rw-r--r-- | oox/source/helper/binaryinputstream.cxx | 322 | ||||
-rw-r--r-- | oox/source/helper/binaryoutputstream.cxx | 184 | ||||
-rw-r--r-- | oox/source/helper/binarystreambase.cxx | 146 | ||||
-rw-r--r-- | oox/source/helper/containerhelper.cxx | 126 | ||||
-rw-r--r-- | oox/source/helper/grabbagstack.cxx | 82 | ||||
-rw-r--r-- | oox/source/helper/graphichelper.cxx | 327 | ||||
-rw-r--r-- | oox/source/helper/modelobjecthelper.cxx | 170 | ||||
-rw-r--r-- | oox/source/helper/ooxresid.cxx | 17 | ||||
-rw-r--r-- | oox/source/helper/progressbar.cxx | 167 | ||||
-rw-r--r-- | oox/source/helper/propertymap.cxx | 953 | ||||
-rw-r--r-- | oox/source/helper/propertyset.cxx | 150 | ||||
-rw-r--r-- | oox/source/helper/storagebase.cxx | 256 | ||||
-rw-r--r-- | oox/source/helper/textinputstream.cxx | 208 | ||||
-rw-r--r-- | oox/source/helper/zipstorage.cxx | 203 |
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: */ |