diff options
Diffstat (limited to '')
-rw-r--r-- | package/source/zippackage/ZipPackageStream.cxx | 1315 |
1 files changed, 1315 insertions, 0 deletions
diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx new file mode 100644 index 000000000..b63bf24ea --- /dev/null +++ b/package/source/zippackage/ZipPackageStream.cxx @@ -0,0 +1,1315 @@ +/* -*- 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 <ZipPackageStream.hxx> + +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#include <com/sun/star/packages/NoRawFormatException.hpp> +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <com/sun/star/embed/StorageFormats.hpp> +#include <com/sun/star/packages/zip/ZipIOException.hpp> +#include <com/sun/star/packages/NoEncryptionException.hpp> +#include <com/sun/star/packages/zip/ZipException.hpp> +#include <com/sun/star/packages/WrongPasswordException.hpp> +#include <com/sun/star/io/TempFile.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/xml/crypto/DigestID.hpp> +#include <com/sun/star/xml/crypto/CipherID.hpp> + +#include <CRC32.hxx> +#include <ZipOutputEntry.hxx> +#include <ZipOutputStream.hxx> +#include <ZipPackage.hxx> +#include <ZipFile.hxx> +#include <EncryptedDataHeader.hxx> +#include <osl/diagnose.h> +#include "wrapstreamforshare.hxx" + +#include <comphelper/seekableinput.hxx> +#include <comphelper/servicehelper.hxx> +#include <comphelper/storagehelper.hxx> +#include <cppuhelper/supportsservice.hxx> + +#include <rtl/random.h> +#include <sal/log.hxx> +#include <tools/diagnose_ex.h> + +#include <PackageConstants.hxx> + +#include <algorithm> +#include <cstddef> + +using namespace com::sun::star::packages::zip::ZipConstants; +using namespace com::sun::star::packages::zip; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star; +using namespace cppu; + +#if OSL_DEBUG_LEVEL > 0 +#define THROW_WHERE SAL_WHERE +#else +#define THROW_WHERE "" +#endif + +const css::uno::Sequence < sal_Int8 > & ZipPackageStream::getUnoTunnelId() +{ + static const comphelper::UnoIdInit lcl_CachedImplId; + return lcl_CachedImplId.getSeq(); +} + +ZipPackageStream::ZipPackageStream ( ZipPackage & rNewPackage, + const uno::Reference< XComponentContext >& xContext, + sal_Int32 nFormat, + bool bAllowRemoveOnInsert ) +: m_rZipPackage( rNewPackage ) +, m_bToBeCompressed ( true ) +, m_bToBeEncrypted ( false ) +, m_bHaveOwnKey ( false ) +, m_bIsEncrypted ( false ) +, m_nImportedStartKeyAlgorithm( 0 ) +, m_nImportedEncryptionAlgorithm( 0 ) +, m_nImportedChecksumAlgorithm( 0 ) +, m_nImportedDerivedKeySize( 0 ) +, m_nStreamMode( PACKAGE_STREAM_NOTSET ) +, m_nMagicalHackPos( 0 ) +, m_nMagicalHackSize( 0 ) +, m_nOwnStreamOrigSize( 0 ) +, m_bHasSeekable( false ) +, m_bCompressedIsSetFromOutside( false ) +, m_bFromManifest( false ) +, m_bUseWinEncoding( false ) +, m_bRawStream( false ) +{ + m_xContext = xContext; + m_nFormat = nFormat; + mbAllowRemoveOnInsert = bAllowRemoveOnInsert; + SetFolder ( false ); + aEntry.nVersion = -1; + aEntry.nFlag = 0; + aEntry.nMethod = -1; + aEntry.nTime = -1; + aEntry.nCrc = -1; + aEntry.nCompressedSize = -1; + aEntry.nSize = -1; + aEntry.nOffset = -1; + aEntry.nPathLen = -1; + aEntry.nExtraLen = -1; +} + +ZipPackageStream::~ZipPackageStream() +{ +} + +void ZipPackageStream::setZipEntryOnLoading( const ZipEntry &rInEntry ) +{ + aEntry.nVersion = rInEntry.nVersion; + aEntry.nFlag = rInEntry.nFlag; + aEntry.nMethod = rInEntry.nMethod; + aEntry.nTime = rInEntry.nTime; + aEntry.nCrc = rInEntry.nCrc; + aEntry.nCompressedSize = rInEntry.nCompressedSize; + aEntry.nSize = rInEntry.nSize; + aEntry.nOffset = rInEntry.nOffset; + aEntry.sPath = rInEntry.sPath; + aEntry.nPathLen = rInEntry.nPathLen; + aEntry.nExtraLen = rInEntry.nExtraLen; + + if ( aEntry.nMethod == STORED ) + m_bToBeCompressed = false; +} + +uno::Reference< io::XInputStream > const & ZipPackageStream::GetOwnSeekStream() +{ + if ( !m_bHasSeekable && m_xStream.is() ) + { + // The package component requires that every stream either be FROM a package or it must support XSeekable! + // The only exception is a nonseekable stream that is provided only for storing, if such a stream + // is accessed before commit it MUST be wrapped. + // Wrap the stream in case it is not seekable + m_xStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( m_xStream, m_xContext ); + uno::Reference< io::XSeekable > xSeek( m_xStream, UNO_QUERY_THROW ); + + m_bHasSeekable = true; + } + + return m_xStream; +} + +uno::Reference< io::XInputStream > ZipPackageStream::GetRawEncrStreamNoHeaderCopy() +{ + if ( m_nStreamMode != PACKAGE_STREAM_RAW || !GetOwnSeekStream().is() ) + throw io::IOException(THROW_WHERE ); + + if ( m_xBaseEncryptionData.is() ) + throw ZipIOException(THROW_WHERE "Encrypted stream without encryption data!" ); + + uno::Reference< io::XSeekable > xSeek( GetOwnSeekStream(), UNO_QUERY ); + if ( !xSeek.is() ) + throw ZipIOException(THROW_WHERE "The stream must be seekable!" ); + + // skip header + xSeek->seek( n_ConstHeaderSize + m_xBaseEncryptionData->m_aInitVector.getLength() + + m_xBaseEncryptionData->m_aSalt.getLength() + m_xBaseEncryptionData->m_aDigest.getLength() ); + + // create temporary stream + uno::Reference < io::XTempFile > xTempFile = io::TempFile::create(m_xContext); + uno::Reference < io::XOutputStream > xTempOut = xTempFile->getOutputStream(); + uno::Reference < io::XInputStream > xTempIn = xTempFile->getInputStream(); + uno::Reference < io::XSeekable > xTempSeek( xTempOut, UNO_QUERY_THROW ); + + // copy the raw stream to the temporary file starting from the current position + ::comphelper::OStorageHelper::CopyInputToOutput( GetOwnSeekStream(), xTempOut ); + xTempOut->closeOutput(); + xTempSeek->seek( 0 ); + + return xTempIn; +} + +sal_Int32 ZipPackageStream::GetEncryptionAlgorithm() const +{ + return m_nImportedEncryptionAlgorithm ? m_nImportedEncryptionAlgorithm : m_rZipPackage.GetEncAlgID(); +} + +sal_Int32 ZipPackageStream::GetBlockSize() const +{ + return GetEncryptionAlgorithm() == css::xml::crypto::CipherID::AES_CBC_W3C_PADDING ? 16 : 8; +} + +::rtl::Reference<EncryptionData> ZipPackageStream::GetEncryptionData(Bugs const bugs) +{ + ::rtl::Reference< EncryptionData > xResult; + if ( m_xBaseEncryptionData.is() ) + xResult = new EncryptionData( + *m_xBaseEncryptionData, + GetEncryptionKey(bugs), + GetEncryptionAlgorithm(), + m_nImportedChecksumAlgorithm ? m_nImportedChecksumAlgorithm : m_rZipPackage.GetChecksumAlgID(), + m_nImportedDerivedKeySize ? m_nImportedDerivedKeySize : m_rZipPackage.GetDefaultDerivedKeySize(), + GetStartKeyGenID(), + bugs != Bugs::None); + + return xResult; +} + +uno::Sequence<sal_Int8> ZipPackageStream::GetEncryptionKey(Bugs const bugs) +{ + uno::Sequence< sal_Int8 > aResult; + sal_Int32 nKeyGenID = GetStartKeyGenID(); + bool const bUseWinEncoding = (bugs == Bugs::WinEncodingWrongSHA1 || m_bUseWinEncoding); + + if ( m_bHaveOwnKey && m_aStorageEncryptionKeys.hasElements() ) + { + OUString aNameToFind; + if ( nKeyGenID == xml::crypto::DigestID::SHA256 ) + aNameToFind = PACKAGE_ENCRYPTIONDATA_SHA256UTF8; + else if ( nKeyGenID == xml::crypto::DigestID::SHA1 ) + { + aNameToFind = bUseWinEncoding + ? OUString(PACKAGE_ENCRYPTIONDATA_SHA1MS1252) + : (bugs == Bugs::WrongSHA1) + ? OUString(PACKAGE_ENCRYPTIONDATA_SHA1UTF8) + : OUString(PACKAGE_ENCRYPTIONDATA_SHA1CORRECT); + } + else + throw uno::RuntimeException(THROW_WHERE "No expected key is provided!" ); + + for ( const auto& rKey : std::as_const(m_aStorageEncryptionKeys) ) + if ( rKey.Name == aNameToFind ) + rKey.Value >>= aResult; + + // empty keys are not allowed here + // so it is not important whether there is no key, or the key is empty, it is an error + if ( !aResult.hasElements() ) + throw uno::RuntimeException(THROW_WHERE "No expected key is provided!" ); + } + else + aResult = m_aEncryptionKey; + + if ( !aResult.hasElements() || !m_bHaveOwnKey ) + aResult = m_rZipPackage.GetEncryptionKey(); + + return aResult; +} + +sal_Int32 ZipPackageStream::GetStartKeyGenID() const +{ + // generally should all the streams use the same Start Key + // but if raw copy without password takes place, we should preserve the imported algorithm + return m_nImportedStartKeyAlgorithm ? m_nImportedStartKeyAlgorithm : m_rZipPackage.GetStartKeyGenID(); +} + +uno::Reference< io::XInputStream > ZipPackageStream::TryToGetRawFromDataStream( bool bAddHeaderForEncr ) +{ + if ( m_nStreamMode != PACKAGE_STREAM_DATA || !GetOwnSeekStream().is() || ( bAddHeaderForEncr && !m_bToBeEncrypted ) ) + throw packages::NoEncryptionException(THROW_WHERE ); + + Sequence< sal_Int8 > aKey; + + if ( m_bToBeEncrypted ) + { + aKey = GetEncryptionKey(); + if ( !aKey.hasElements() ) + throw packages::NoEncryptionException(THROW_WHERE ); + } + + try + { + // create temporary file + uno::Reference < io::XStream > xTempStream( + io::TempFile::create(m_xContext), + uno::UNO_QUERY_THROW ); + + // create a package based on it + rtl::Reference<ZipPackage> pPackage = new ZipPackage( m_xContext ); + + Sequence< Any > aArgs{ Any(xTempStream) }; + pPackage->initialize( aArgs ); + + // create a new package stream + uno::Reference< XDataSinkEncrSupport > xNewPackStream( pPackage->createInstance(), UNO_QUERY_THROW ); + xNewPackStream->setDataStream( + new WrapStreamForShare(GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef())); + + uno::Reference< XPropertySet > xNewPSProps( xNewPackStream, UNO_QUERY_THROW ); + + // copy all the properties of this stream to the new stream + xNewPSProps->setPropertyValue("MediaType", Any( msMediaType ) ); + xNewPSProps->setPropertyValue("Compressed", Any( m_bToBeCompressed ) ); + if ( m_bToBeEncrypted ) + { + xNewPSProps->setPropertyValue(ENCRYPTION_KEY_PROPERTY, Any( aKey ) ); + xNewPSProps->setPropertyValue("Encrypted", Any( true ) ); + } + + // insert a new stream in the package + uno::Reference< XUnoTunnel > xTunnel; + Any aRoot = pPackage->getByHierarchicalName("/"); + aRoot >>= xTunnel; + uno::Reference< container::XNameContainer > xRootNameContainer( xTunnel, UNO_QUERY_THROW ); + + uno::Reference< XUnoTunnel > xNPSTunnel( xNewPackStream, UNO_QUERY ); + xRootNameContainer->insertByName("dummy", Any( xNPSTunnel ) ); + + // commit the temporary package + pPackage->commitChanges(); + + // get raw stream from the temporary package + uno::Reference< io::XInputStream > xInRaw; + if ( bAddHeaderForEncr ) + xInRaw = xNewPackStream->getRawStream(); + else + xInRaw = xNewPackStream->getPlainRawStream(); + + // create another temporary file + uno::Reference < io::XOutputStream > xTempOut( + io::TempFile::create(m_xContext), + uno::UNO_QUERY_THROW ); + uno::Reference < io::XInputStream > xTempIn( xTempOut, UNO_QUERY_THROW ); + uno::Reference < io::XSeekable > xTempSeek( xTempOut, UNO_QUERY_THROW ); + + // copy the raw stream to the temporary file + ::comphelper::OStorageHelper::CopyInputToOutput( xInRaw, xTempOut ); + xTempOut->closeOutput(); + xTempSeek->seek( 0 ); + + // close raw stream, package stream and folder + xInRaw.clear(); + xNewPSProps.clear(); + xNPSTunnel.clear(); + xNewPackStream.clear(); + xTunnel.clear(); + xRootNameContainer.clear(); + + // return the stream representing the first temporary file + return xTempIn; + } + catch ( RuntimeException& ) + { + throw; + } + catch ( Exception& ) + { + } + + throw io::IOException(THROW_WHERE ); +} + +bool ZipPackageStream::ParsePackageRawStream() +{ + OSL_ENSURE( GetOwnSeekStream().is(), "A stream must be provided!" ); + + if ( !GetOwnSeekStream().is() ) + return false; + + bool bOk = false; + + ::rtl::Reference< BaseEncryptionData > xTempEncrData; + Sequence < sal_Int8 > aHeader ( 4 ); + + try + { + if ( GetOwnSeekStream()->readBytes ( aHeader, 4 ) == 4 ) + { + const sal_Int8 *pHeader = aHeader.getConstArray(); + sal_uInt32 nHeader = ( pHeader [0] & 0xFF ) | + ( pHeader [1] & 0xFF ) << 8 | + ( pHeader [2] & 0xFF ) << 16 | + ( pHeader [3] & 0xFF ) << 24; + if ( nHeader == n_ConstHeader ) + { + // this is one of our god-awful, but extremely devious hacks, everyone cheer + xTempEncrData = new BaseEncryptionData; + + OUString aMediaType; + sal_Int32 nEncAlgorithm = 0; + sal_Int32 nChecksumAlgorithm = 0; + sal_Int32 nDerivedKeySize = 0; + sal_Int32 nStartKeyGenID = 0; + sal_Int32 nMagHackSize = 0; + if ( ZipFile::StaticFillData( xTempEncrData, nEncAlgorithm, nChecksumAlgorithm, nDerivedKeySize, nStartKeyGenID, nMagHackSize, aMediaType, GetOwnSeekStream() ) ) + { + // We'll want to skip the data we've just read, so calculate how much we just read + // and remember it + m_nMagicalHackPos = n_ConstHeaderSize + xTempEncrData->m_aSalt.getLength() + + xTempEncrData->m_aInitVector.getLength() + + xTempEncrData->m_aDigest.getLength() + + aMediaType.getLength() * sizeof( sal_Unicode ); + m_nImportedEncryptionAlgorithm = nEncAlgorithm; + m_nImportedChecksumAlgorithm = nChecksumAlgorithm; + m_nImportedDerivedKeySize = nDerivedKeySize; + m_nImportedStartKeyAlgorithm = nStartKeyGenID; + m_nMagicalHackSize = nMagHackSize; + msMediaType = aMediaType; + + bOk = true; + } + } + } + } + catch( Exception& ) + { + } + + if ( !bOk ) + { + // the provided stream is not a raw stream + return false; + } + + m_xBaseEncryptionData = xTempEncrData; + SetIsEncrypted ( true ); + // it's already compressed and encrypted + m_bToBeEncrypted = m_bToBeCompressed = false; + + return true; +} + +static void ImplSetStoredData( ZipEntry & rEntry, uno::Reference< io::XInputStream> const & rStream ) +{ + // It's very annoying that we have to do this, but lots of zip packages + // don't allow data descriptors for STORED streams, meaning we have to + // know the size and CRC32 of uncompressed streams before we actually + // write them ! + CRC32 aCRC32; + rEntry.nMethod = STORED; + rEntry.nCompressedSize = rEntry.nSize = aCRC32.updateStream ( rStream ); + rEntry.nCrc = aCRC32.getValue(); +} + +bool ZipPackageStream::saveChild( + const OUString &rPath, + std::vector < uno::Sequence < beans::PropertyValue > > &rManList, + ZipOutputStream & rZipOut, + const uno::Sequence < sal_Int8 >& rEncryptionKey, + sal_Int32 nPBKDF2IterationCount, + const rtlRandomPool &rRandomPool) +{ + bool bSuccess = true; + + static const OUStringLiteral sDigestProperty (u"Digest"); + static const OUStringLiteral sEncryptionAlgProperty (u"EncryptionAlgorithm"); + static const OUStringLiteral sStartKeyAlgProperty (u"StartKeyAlgorithm"); + static const OUStringLiteral sDigestAlgProperty (u"DigestAlgorithm"); + static const OUStringLiteral sDerivedKeySizeProperty (u"DerivedKeySize"); + + uno::Sequence < beans::PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST); + + // In case the entry we are reading is also the entry we are writing, we will + // store the ZipEntry data in pTempEntry + + // if pTempEntry is necessary, it will be released and passed to the ZipOutputStream + // and be deleted in the ZipOutputStream destructor + std::unique_ptr < ZipEntry > pAutoTempEntry ( new ZipEntry(aEntry) ); + ZipEntry* pTempEntry = pAutoTempEntry.get(); + + pTempEntry->sPath = rPath; + pTempEntry->nPathLen = static_cast<sal_Int16>( OUStringToOString( pTempEntry->sPath, RTL_TEXTENCODING_UTF8 ).getLength() ); + + const bool bToBeEncrypted = m_bToBeEncrypted && (rEncryptionKey.hasElements() || m_bHaveOwnKey); + const bool bToBeCompressed = bToBeEncrypted || m_bToBeCompressed; + + auto pPropSet = aPropSet.getArray(); + pPropSet[PKG_MNFST_MEDIATYPE].Name = "MediaType"; + pPropSet[PKG_MNFST_MEDIATYPE].Value <<= GetMediaType( ); + pPropSet[PKG_MNFST_VERSION].Name = "Version"; + pPropSet[PKG_MNFST_VERSION].Value <<= OUString(); // no version is stored for streams currently + pPropSet[PKG_MNFST_FULLPATH].Name = "FullPath"; + pPropSet[PKG_MNFST_FULLPATH].Value <<= pTempEntry->sPath; + + OSL_ENSURE( m_nStreamMode != PACKAGE_STREAM_NOTSET, "Unacceptable ZipPackageStream mode!" ); + + m_bRawStream = false; + if ( m_nStreamMode == PACKAGE_STREAM_DETECT ) + m_bRawStream = ParsePackageRawStream(); + else if ( m_nStreamMode == PACKAGE_STREAM_RAW ) + m_bRawStream = true; + + bool bBackgroundThreadDeflate = false; + bool bTransportOwnEncrStreamAsRaw = false; + // During the storing the original size of the stream can be changed + // TODO/LATER: get rid of this hack + m_nOwnStreamOrigSize = m_bRawStream ? m_nMagicalHackSize : aEntry.nSize; + + bool bUseNonSeekableAccess = false; + uno::Reference < io::XInputStream > xStream; + if ( !IsPackageMember() && !m_bRawStream && !bToBeEncrypted && bToBeCompressed ) + { + // the stream is not a package member, not a raw stream, + // it should not be encrypted and it should be compressed, + // in this case nonseekable access can be used + + xStream = m_xStream; + uno::Reference < io::XSeekable > xSeek ( xStream, uno::UNO_QUERY ); + + bUseNonSeekableAccess = ( xStream.is() && !xSeek.is() ); + } + + if ( !bUseNonSeekableAccess ) + { + xStream = getRawData(); + + if ( !xStream.is() ) + { + OSL_FAIL( "ZipPackageStream didn't have a stream associated with it, skipping!" ); + bSuccess = false; + return bSuccess; + } + + uno::Reference < io::XSeekable > xSeek ( xStream, uno::UNO_QUERY ); + try + { + if ( xSeek.is() ) + { + // If the stream is a raw one, then we should be positioned + // at the beginning of the actual data + if ( !bToBeCompressed || m_bRawStream ) + { + // The raw stream can neither be encrypted nor connected + OSL_ENSURE( !m_bRawStream || !(bToBeCompressed || bToBeEncrypted), "The stream is already encrypted!" ); + xSeek->seek ( m_bRawStream ? m_nMagicalHackPos : 0 ); + ImplSetStoredData ( *pTempEntry, xStream ); + + // TODO/LATER: Get rid of hacks related to switching of Flag Method and Size properties! + } + else if ( bToBeEncrypted ) + { + // this is the correct original size + pTempEntry->nSize = xSeek->getLength(); + m_nOwnStreamOrigSize = pTempEntry->nSize; + } + + xSeek->seek ( 0 ); + } + else + { + // Okay, we don't have an xSeekable stream. This is possibly bad. + // check if it's one of our own streams, if it is then we know that + // each time we ask for it we'll get a new stream that will be + // at position zero...otherwise, assert and skip this stream... + if ( IsPackageMember() ) + { + // if the password has been changed then the stream should not be package member any more + if ( m_bIsEncrypted && m_bToBeEncrypted ) + { + // Should be handled close to the raw stream handling + bTransportOwnEncrStreamAsRaw = true; + pTempEntry->nMethod = STORED; + + // TODO/LATER: get rid of this situation + // this size should be different from the one that will be stored in manifest.xml + // it is used in storing algorithms and after storing the correct size will be set + pTempEntry->nSize = pTempEntry->nCompressedSize; + } + } + else + { + bSuccess = false; + return bSuccess; + } + } + } + catch ( uno::Exception& ) + { + bSuccess = false; + return bSuccess; + } + + if ( bToBeEncrypted || m_bRawStream || bTransportOwnEncrStreamAsRaw ) + { + if ( bToBeEncrypted && !bTransportOwnEncrStreamAsRaw ) + { + uno::Sequence < sal_Int8 > aSalt( 16 ), aVector( GetBlockSize() ); + rtl_random_getBytes ( rRandomPool, aSalt.getArray(), 16 ); + rtl_random_getBytes ( rRandomPool, aVector.getArray(), aVector.getLength() ); + if ( !m_bHaveOwnKey ) + { + m_aEncryptionKey = rEncryptionKey; + m_aStorageEncryptionKeys.realloc( 0 ); + } + + setInitialisationVector ( aVector ); + setSalt ( aSalt ); + setIterationCount(nPBKDF2IterationCount); + } + + // last property is digest, which is inserted later if we didn't have + // a magic header + aPropSet.realloc(PKG_SIZE_ENCR_MNFST); + pPropSet = aPropSet.getArray(); + pPropSet[PKG_MNFST_INIVECTOR].Name = "InitialisationVector"; + pPropSet[PKG_MNFST_INIVECTOR].Value <<= m_xBaseEncryptionData->m_aInitVector; + pPropSet[PKG_MNFST_SALT].Name = "Salt"; + pPropSet[PKG_MNFST_SALT].Value <<= m_xBaseEncryptionData->m_aSalt; + pPropSet[PKG_MNFST_ITERATION].Name = "IterationCount"; + pPropSet[PKG_MNFST_ITERATION].Value <<= m_xBaseEncryptionData->m_nIterationCount; + + // Need to store the uncompressed size in the manifest + OSL_ENSURE( m_nOwnStreamOrigSize >= 0, "The stream size was not correctly initialized!" ); + pPropSet[PKG_MNFST_UCOMPSIZE].Name = "Size"; + pPropSet[PKG_MNFST_UCOMPSIZE].Value <<= m_nOwnStreamOrigSize; + + if ( m_bRawStream || bTransportOwnEncrStreamAsRaw ) + { + ::rtl::Reference< EncryptionData > xEncData = GetEncryptionData(); + if ( !xEncData.is() ) + throw uno::RuntimeException(); + + pPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty; + pPropSet[PKG_MNFST_DIGEST].Value <<= m_xBaseEncryptionData->m_aDigest; + pPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty; + pPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg; + pPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty; + pPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID; + pPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty; + pPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg; + pPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty; + pPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize; + } + } + } + + // If the entry is already stored in the zip file in the format we + // want for this write...copy it raw + if ( !bUseNonSeekableAccess + && ( m_bRawStream || bTransportOwnEncrStreamAsRaw + || ( IsPackageMember() && !bToBeEncrypted + && ( ( aEntry.nMethod == DEFLATED && bToBeCompressed ) + || ( aEntry.nMethod == STORED && !bToBeCompressed ) ) ) ) ) + { + // If it's a PackageMember, then it's an unbuffered stream and we need + // to get a new version of it as we can't seek backwards. + if ( IsPackageMember() ) + { + xStream = getRawData(); + if ( !xStream.is() ) + { + // Make sure that we actually _got_ a new one ! + bSuccess = false; + return bSuccess; + } + } + + try + { + if ( m_bRawStream ) + xStream->skipBytes( m_nMagicalHackPos ); + + ZipOutputStream::setEntry(pTempEntry); + rZipOut.writeLOC(pTempEntry); + // the entry is provided to the ZipOutputStream that will delete it + pAutoTempEntry.release(); + + uno::Sequence < sal_Int8 > aSeq ( n_ConstBufferSize ); + sal_Int32 nLength; + + do + { + nLength = xStream->readBytes( aSeq, n_ConstBufferSize ); + if (nLength != n_ConstBufferSize) + aSeq.realloc(nLength); + + rZipOut.rawWrite(aSeq); + } + while ( nLength == n_ConstBufferSize ); + + rZipOut.rawCloseEntry(); + } + catch ( ZipException& ) + { + bSuccess = false; + } + catch ( io::IOException& ) + { + bSuccess = false; + } + } + else + { + // This stream is definitely not a raw stream + + // If nonseekable access is used the stream should be at the beginning and + // is useless after the storing. Thus if the storing fails the package should + // be thrown away ( as actually it is done currently )! + // To allow to reuse the package after the error, the optimization must be removed! + + // If it's a PackageMember, then our previous reference held a 'raw' stream + // so we need to re-get it, unencrypted, uncompressed and positioned at the + // beginning of the stream + if ( IsPackageMember() ) + { + xStream = getInputStream(); + if ( !xStream.is() ) + { + // Make sure that we actually _got_ a new one ! + bSuccess = false; + return bSuccess; + } + } + + if ( bToBeCompressed ) + { + pTempEntry->nMethod = DEFLATED; + pTempEntry->nCrc = -1; + pTempEntry->nCompressedSize = pTempEntry->nSize = -1; + } + + uno::Reference< io::XSeekable > xSeek(xStream, uno::UNO_QUERY); + // It's not worth to deflate jpegs to save ~1% in a slow process + // Unfortunately, does not work for streams protected by password + if (xSeek.is() && msMediaType.endsWith("/jpeg") && !m_bToBeEncrypted && !m_bToBeCompressed) + { + ImplSetStoredData(*pTempEntry, xStream); + xSeek->seek(0); + } + + try + { + ZipOutputStream::setEntry(pTempEntry); + // the entry is provided to the ZipOutputStream that will delete it + pAutoTempEntry.release(); + + if (pTempEntry->nMethod == STORED) + { + sal_Int32 nLength; + uno::Sequence< sal_Int8 > aSeq(n_ConstBufferSize); + rZipOut.writeLOC(pTempEntry, bToBeEncrypted); + do + { + nLength = xStream->readBytes(aSeq, n_ConstBufferSize); + if (nLength != n_ConstBufferSize) + aSeq.realloc(nLength); + + rZipOut.rawWrite(aSeq); + } + while ( nLength == n_ConstBufferSize ); + rZipOut.rawCloseEntry(bToBeEncrypted); + } + else + { + // tdf#89236 Encrypting in a background thread does not work + bBackgroundThreadDeflate = !bToBeEncrypted; + // Do not deflate small streams using threads. XSeekable's getLength() + // gives the full size, XInputStream's available() may not be + // the full size, but it appears that at this point it usually is. + sal_Int64 estimatedSize = xSeek.is() ? xSeek->getLength() : xStream->available(); + + if (estimatedSize > 1000000) + { + // Use ThreadDeflater which will split the stream into blocks and compress + // them in threads, but not in background (i.e. writeStream() will block). + // This is suitable for large data. + bBackgroundThreadDeflate = false; + rZipOut.writeLOC(pTempEntry, bToBeEncrypted); + ZipOutputEntryParallel aZipEntry(rZipOut.getStream(), m_xContext, *pTempEntry, this, bToBeEncrypted); + aZipEntry.writeStream(xStream); + rZipOut.rawCloseEntry(bToBeEncrypted); + } + else if (bBackgroundThreadDeflate && estimatedSize > 100000) + { + // tdf#93553 limit to a useful amount of pending tasks. Having way too many + // tasks pending may use a lot of memory. Take number of available + // cores and allow 4-times the amount for having the queue well filled. The + // 2nd parameter is the time to wait between cleanups in 10th of a second. + // Both values may be added to the configuration settings if needed. + static std::size_t nAllowedTasks(comphelper::ThreadPool::getPreferredConcurrency() * 4); //TODO: overflow + rZipOut.reduceScheduledThreadTasksToGivenNumberOrLess(nAllowedTasks); + + // Start a new thread task deflating this zip entry + ZipOutputEntryInThread *pZipEntry = new ZipOutputEntryInThread( + m_xContext, *pTempEntry, this, bToBeEncrypted); + rZipOut.addDeflatingThreadTask( pZipEntry, + pZipEntry->createTask( rZipOut.getThreadTaskTag(), xStream) ); + } + else + { + bBackgroundThreadDeflate = false; + rZipOut.writeLOC(pTempEntry, bToBeEncrypted); + ZipOutputEntry aZipEntry(rZipOut.getStream(), m_xContext, *pTempEntry, this, bToBeEncrypted); + aZipEntry.writeStream(xStream); + rZipOut.rawCloseEntry(bToBeEncrypted); + } + } + } + catch ( ZipException& ) + { + bSuccess = false; + } + catch ( io::IOException& ) + { + bSuccess = false; + } + + if ( bToBeEncrypted ) + { + ::rtl::Reference< EncryptionData > xEncData = GetEncryptionData(); + if ( !xEncData.is() ) + throw uno::RuntimeException(); + + pPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty; + pPropSet[PKG_MNFST_DIGEST].Value <<= m_xBaseEncryptionData->m_aDigest; + pPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty; + pPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg; + pPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty; + pPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID; + pPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty; + pPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg; + pPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty; + pPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize; + + SetIsEncrypted ( true ); + } + } + + if (bSuccess && !bBackgroundThreadDeflate) + successfullyWritten(pTempEntry); + + if ( aPropSet.hasElements() + && ( m_nFormat == embed::StorageFormats::PACKAGE || m_nFormat == embed::StorageFormats::OFOPXML ) ) + rManList.push_back( aPropSet ); + + return bSuccess; +} + +void ZipPackageStream::successfullyWritten( ZipEntry const *pEntry ) +{ + if ( !IsPackageMember() ) + { + if ( m_xStream.is() ) + { + m_xStream->closeInput(); + m_xStream.clear(); + m_bHasSeekable = false; + } + SetPackageMember ( true ); + } + + if ( m_bRawStream ) + { + // the raw stream was integrated and now behaves + // as usual encrypted stream + SetToBeEncrypted( true ); + } + + // Then copy it back afterwards... + aEntry = *pEntry; + + // TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving ) + if ( m_bIsEncrypted ) + setSize( m_nOwnStreamOrigSize ); + + aEntry.nOffset *= -1; +} + +void ZipPackageStream::SetPackageMember( bool bNewValue ) +{ + if ( bNewValue ) + { + m_nStreamMode = PACKAGE_STREAM_PACKAGEMEMBER; + m_nMagicalHackPos = 0; + m_nMagicalHackSize = 0; + } + else if ( m_nStreamMode == PACKAGE_STREAM_PACKAGEMEMBER ) + m_nStreamMode = PACKAGE_STREAM_NOTSET; // must be reset +} + +// XActiveDataSink +void SAL_CALL ZipPackageStream::setInputStream( const uno::Reference< io::XInputStream >& aStream ) +{ + // if seekable access is required the wrapping will be done on demand + m_xStream = aStream; + m_nImportedEncryptionAlgorithm = 0; + m_bHasSeekable = false; + SetPackageMember ( false ); + aEntry.nTime = -1; + m_nStreamMode = PACKAGE_STREAM_DETECT; +} + +uno::Reference< io::XInputStream > ZipPackageStream::getRawData() +{ + try + { + if ( IsPackageMember() ) + { + return m_rZipPackage.getZipFile().getRawData( aEntry, GetEncryptionData(), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef(), false/*bUseBufferedStream*/ ); + } + else if ( GetOwnSeekStream().is() ) + { + return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() ); + } + else + return uno::Reference < io::XInputStream > (); + } + catch ( ZipException & )//rException ) + { + TOOLS_WARN_EXCEPTION( "package", "" ); + return uno::Reference < io::XInputStream > (); + } + catch ( Exception & ) + { + TOOLS_WARN_EXCEPTION( "package", "Exception is thrown during stream wrapping!" ); + return uno::Reference < io::XInputStream > (); + } +} + +uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getInputStream() +{ + try + { + if ( IsPackageMember() ) + { + return m_rZipPackage.getZipFile().getInputStream( aEntry, GetEncryptionData(), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() ); + } + else if ( GetOwnSeekStream().is() ) + { + return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() ); + } + else + return uno::Reference < io::XInputStream > (); + } + catch ( ZipException & )//rException ) + { + TOOLS_WARN_EXCEPTION( "package", "" ); + return uno::Reference < io::XInputStream > (); + } + catch ( const Exception & ) + { + TOOLS_WARN_EXCEPTION( "package", "Exception is thrown during stream wrapping!"); + return uno::Reference < io::XInputStream > (); + } +} + +// XDataSinkEncrSupport +uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getDataStream() +{ + // There is no stream attached to this object + if ( m_nStreamMode == PACKAGE_STREAM_NOTSET ) + return uno::Reference< io::XInputStream >(); + + // this method can not be used together with old approach + if ( m_nStreamMode == PACKAGE_STREAM_DETECT ) + throw packages::zip::ZipIOException(THROW_WHERE ); + + if ( IsPackageMember() ) + { + uno::Reference< io::XInputStream > xResult; + try + { + xResult = m_rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData(Bugs::None), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() ); + } + catch( const packages::WrongPasswordException& ) + { + if ( m_rZipPackage.GetStartKeyGenID() == xml::crypto::DigestID::SHA1 ) + { + SAL_WARN("package", "ZipPackageStream::getDataStream(): SHA1 mismatch, trying fallbacks..."); + try + { // tdf#114939 try with legacy StarOffice SHA1 bug + xResult = m_rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData(Bugs::WrongSHA1), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() ); + return xResult; + } + catch (const packages::WrongPasswordException&) + { + /* ignore and try next... */ + } + + try + { + // rhbz#1013844 / fdo#47482 workaround for the encrypted + // OpenOffice.org 1.0 documents generated by Libreoffice <= + // 3.6 with the new encryption format and using SHA256, but + // missing a specified startkey of SHA256 + + // force SHA256 and see if that works + m_nImportedStartKeyAlgorithm = xml::crypto::DigestID::SHA256; + xResult = m_rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData(), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() ); + return xResult; + } + catch (const packages::WrongPasswordException&) + { + // if that didn't work, restore to SHA1 and trundle through the *other* earlier + // bug fix + m_nImportedStartKeyAlgorithm = xml::crypto::DigestID::SHA1; + } + + // workaround for the encrypted documents generated with the old OOo1.x bug. + if ( !m_bUseWinEncoding ) + { + xResult = m_rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData(Bugs::WinEncodingWrongSHA1), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() ); + m_bUseWinEncoding = true; + } + else + throw; + } + else + throw; + } + return xResult; + } + else if ( m_nStreamMode == PACKAGE_STREAM_RAW ) + return ZipFile::StaticGetDataFromRawStream( m_rZipPackage.GetSharedMutexRef(), m_xContext, GetOwnSeekStream(), GetEncryptionData() ); + else if ( GetOwnSeekStream().is() ) + { + return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() ); + } + else + return uno::Reference< io::XInputStream >(); +} + +uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getRawStream() +{ + // There is no stream attached to this object + if ( m_nStreamMode == PACKAGE_STREAM_NOTSET ) + return uno::Reference< io::XInputStream >(); + + // this method can not be used together with old approach + if ( m_nStreamMode == PACKAGE_STREAM_DETECT ) + throw packages::zip::ZipIOException(THROW_WHERE ); + + if ( IsPackageMember() ) + { + if ( !m_bIsEncrypted || !GetEncryptionData().is() ) + throw packages::NoEncryptionException(THROW_WHERE ); + + return m_rZipPackage.getZipFile().getWrappedRawStream( aEntry, GetEncryptionData(), msMediaType, m_rZipPackage.GetSharedMutexRef() ); + } + else if ( GetOwnSeekStream().is() ) + { + if ( m_nStreamMode == PACKAGE_STREAM_RAW ) + { + return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() ); + } + else if ( m_nStreamMode == PACKAGE_STREAM_DATA && m_bToBeEncrypted ) + return TryToGetRawFromDataStream( true ); + } + + throw packages::NoEncryptionException(THROW_WHERE ); +} + +void SAL_CALL ZipPackageStream::setDataStream( const uno::Reference< io::XInputStream >& aStream ) +{ + setInputStream( aStream ); + m_nStreamMode = PACKAGE_STREAM_DATA; +} + +void SAL_CALL ZipPackageStream::setRawStream( const uno::Reference< io::XInputStream >& aStream ) +{ + // wrap the stream in case it is not seekable + uno::Reference< io::XInputStream > xNewStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( aStream, m_xContext ); + uno::Reference< io::XSeekable > xSeek( xNewStream, UNO_QUERY_THROW ); + xSeek->seek( 0 ); + uno::Reference< io::XInputStream > xOldStream = m_xStream; + m_xStream = xNewStream; + if ( !ParsePackageRawStream() ) + { + m_xStream = xOldStream; + throw packages::NoRawFormatException(THROW_WHERE ); + } + + // the raw stream MUST have seekable access + m_bHasSeekable = true; + + SetPackageMember ( false ); + aEntry.nTime = -1; + m_nStreamMode = PACKAGE_STREAM_RAW; +} + +uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getPlainRawStream() +{ + // There is no stream attached to this object + if ( m_nStreamMode == PACKAGE_STREAM_NOTSET ) + return uno::Reference< io::XInputStream >(); + + // this method can not be used together with old approach + if ( m_nStreamMode == PACKAGE_STREAM_DETECT ) + throw packages::zip::ZipIOException(THROW_WHERE ); + + if ( IsPackageMember() ) + { + return m_rZipPackage.getZipFile().getRawData( aEntry, GetEncryptionData(), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() ); + } + else if ( GetOwnSeekStream().is() ) + { + if ( m_nStreamMode == PACKAGE_STREAM_RAW ) + { + // the header should not be returned here + return GetRawEncrStreamNoHeaderCopy(); + } + else if ( m_nStreamMode == PACKAGE_STREAM_DATA ) + return TryToGetRawFromDataStream( false ); + } + + return uno::Reference< io::XInputStream >(); +} + +// XUnoTunnel + +sal_Int64 SAL_CALL ZipPackageStream::getSomething( const Sequence< sal_Int8 >& aIdentifier ) +{ + return comphelper::getSomethingImpl(aIdentifier, this); +} + +// XPropertySet +void SAL_CALL ZipPackageStream::setPropertyValue( const OUString& aPropertyName, const Any& aValue ) +{ + if ( aPropertyName == "MediaType" ) + { + if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE && m_rZipPackage.getFormat() != embed::StorageFormats::OFOPXML ) + throw beans::PropertyVetoException(THROW_WHERE ); + + if ( !(aValue >>= msMediaType) ) + throw IllegalArgumentException(THROW_WHERE "MediaType must be a string!", + uno::Reference< XInterface >(), + 2 ); + + if ( !msMediaType.isEmpty() ) + { + if ( msMediaType.indexOf ( "text" ) != -1 + || msMediaType == "application/vnd.sun.star.oleobject" ) + m_bToBeCompressed = true; + else if ( !m_bCompressedIsSetFromOutside ) + m_bToBeCompressed = false; + } + } + else if ( aPropertyName == "Size" ) + { + if ( !( aValue >>= aEntry.nSize ) ) + throw IllegalArgumentException(THROW_WHERE "Wrong type for Size property!", + uno::Reference< XInterface >(), + 2 ); + } + else if ( aPropertyName == "Encrypted" ) + { + if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE ) + throw beans::PropertyVetoException(THROW_WHERE ); + + bool bEnc = false; + if ( !(aValue >>= bEnc) ) + throw IllegalArgumentException(THROW_WHERE "Wrong type for Encrypted property!", + uno::Reference< XInterface >(), + 2 ); + + // In case of new raw stream, the stream must not be encrypted on storing + if ( bEnc && m_nStreamMode == PACKAGE_STREAM_RAW ) + throw IllegalArgumentException(THROW_WHERE "Raw stream can not be encrypted on storing", + uno::Reference< XInterface >(), + 2 ); + + m_bToBeEncrypted = bEnc; + if ( m_bToBeEncrypted && !m_xBaseEncryptionData.is() ) + m_xBaseEncryptionData = new BaseEncryptionData; + + } + else if ( aPropertyName == ENCRYPTION_KEY_PROPERTY ) + { + if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE ) + throw beans::PropertyVetoException(THROW_WHERE ); + + uno::Sequence< sal_Int8 > aNewKey; + + if ( !( aValue >>= aNewKey ) ) + { + OUString sTempString; + if ( !(aValue >>= sTempString) ) + throw IllegalArgumentException(THROW_WHERE "Wrong type for EncryptionKey property!", + uno::Reference< XInterface >(), + 2 ); + + sal_Int32 nPathLength = sTempString.getLength(); + Sequence < sal_Int8 > aSequence ( nPathLength ); + sal_Int8 *pArray = aSequence.getArray(); + const sal_Unicode *pChar = sTempString.getStr(); + for ( sal_Int32 i = 0; i < nPathLength; i++ ) + pArray[i] = static_cast < sal_Int8 > ( pChar[i] ); + aNewKey = aSequence; + } + + if ( aNewKey.hasElements() ) + { + if ( !m_xBaseEncryptionData.is() ) + m_xBaseEncryptionData = new BaseEncryptionData; + + m_aEncryptionKey = aNewKey; + // In case of new raw stream, the stream must not be encrypted on storing + m_bHaveOwnKey = true; + if ( m_nStreamMode != PACKAGE_STREAM_RAW ) + m_bToBeEncrypted = true; + } + else + { + m_bHaveOwnKey = false; + m_aEncryptionKey.realloc( 0 ); + } + + m_aStorageEncryptionKeys.realloc( 0 ); + } + else if ( aPropertyName == STORAGE_ENCRYPTION_KEYS_PROPERTY ) + { + if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE ) + throw beans::PropertyVetoException(THROW_WHERE ); + + uno::Sequence< beans::NamedValue > aKeys; + if ( !( aValue >>= aKeys ) ) + { + throw IllegalArgumentException(THROW_WHERE "Wrong type for StorageEncryptionKeys property!", + uno::Reference< XInterface >(), + 2 ); + } + + if ( aKeys.hasElements() ) + { + if ( !m_xBaseEncryptionData.is() ) + m_xBaseEncryptionData = new BaseEncryptionData; + + m_aStorageEncryptionKeys = aKeys; + + // In case of new raw stream, the stream must not be encrypted on storing + m_bHaveOwnKey = true; + if ( m_nStreamMode != PACKAGE_STREAM_RAW ) + m_bToBeEncrypted = true; + } + else + { + m_bHaveOwnKey = false; + m_aStorageEncryptionKeys.realloc( 0 ); + } + + m_aEncryptionKey.realloc( 0 ); + } + else if ( aPropertyName == "Compressed" ) + { + bool bCompr = false; + + if ( !(aValue >>= bCompr) ) + throw IllegalArgumentException(THROW_WHERE "Wrong type for Compressed property!", + uno::Reference< XInterface >(), + 2 ); + + // In case of new raw stream, the stream must not be encrypted on storing + if ( bCompr && m_nStreamMode == PACKAGE_STREAM_RAW ) + throw IllegalArgumentException(THROW_WHERE "Raw stream can not be encrypted on storing", + uno::Reference< XInterface >(), + 2 ); + + m_bToBeCompressed = bCompr; + m_bCompressedIsSetFromOutside = true; + } + else + throw beans::UnknownPropertyException(aPropertyName); +} + +Any SAL_CALL ZipPackageStream::getPropertyValue( const OUString& PropertyName ) +{ + if ( PropertyName == "MediaType" ) + { + return Any(msMediaType); + } + else if ( PropertyName == "Size" ) + { + return Any(aEntry.nSize); + } + else if ( PropertyName == "Encrypted" ) + { + return Any((m_nStreamMode == PACKAGE_STREAM_RAW) || m_bToBeEncrypted); + } + else if ( PropertyName == "WasEncrypted" ) + { + return Any(m_bIsEncrypted); + } + else if ( PropertyName == "Compressed" ) + { + return Any(m_bToBeCompressed); + } + else if ( PropertyName == ENCRYPTION_KEY_PROPERTY ) + { + return Any(m_aEncryptionKey); + } + else if ( PropertyName == STORAGE_ENCRYPTION_KEYS_PROPERTY ) + { + return Any(m_aStorageEncryptionKeys); + } + else + throw beans::UnknownPropertyException(PropertyName); +} + +void ZipPackageStream::setSize ( const sal_Int64 nNewSize ) +{ + if ( aEntry.nCompressedSize != nNewSize ) + aEntry.nMethod = DEFLATED; + aEntry.nSize = nNewSize; +} +OUString ZipPackageStream::getImplementationName() +{ + return "ZipPackageStream"; +} + +Sequence< OUString > ZipPackageStream::getSupportedServiceNames() +{ + return { "com.sun.star.packages.PackageStream" }; +} + +sal_Bool SAL_CALL ZipPackageStream::supportsService( OUString const & rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |