Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/package/source/zippackage/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 52 kB image not shown  

Quelle  ZipPackageStream.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <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 <com/sun/star/xml/crypto/KDFID.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 <unotools/tempfile.hxx>

#include <rtl/random.h>
#include <sal/log.hxx>
#include <o3tl/unreachable.hxx>
#include <comphelper/diagnose_ex.hxx>

#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

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_nStreamMode( PACKAGE_STREAM_NOTSET )
, m_nMagicalHackPos( 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;

    // this is called first, parseManifest may overwrite it if it's encrypted
    assert(m_nOwnStreamOrigSize == 0);
    m_nOwnStreamOrigSize = aEntry.nSize;
}

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
    rtl::Reference < utl::TempFileFastService > xTempFile = new utl::TempFileFastService;
    uno::Reference < io::XInputStream > xTempIn = xTempFile->getInputStream();

    // copy the raw stream to the temporary file starting from the current position
    ::comphelper::OStorageHelper::CopyInputToOutput( GetOwnSeekStream(), xTempFile );
    xTempFile->closeOutput();
    xTempFile->seek( 0 );

    return xTempIn;
}

sal_Int32 ZipPackageStream::GetEncryptionAlgorithm() const
{
    return m_oImportedAlgorithms
        ? m_oImportedAlgorithms->nImportedEncryptionAlgorithm
        : m_rZipPackage.GetEncAlgID();
}

sal_Int32 ZipPackageStream::GetIVSize() const
{
    switch (GetEncryptionAlgorithm())
    {
        case css::xml::crypto::CipherID::BLOWFISH_CFB_8:
            return 8;
        case css::xml::crypto::CipherID::AES_CBC_W3C_PADDING:
            return 16;
        case css::xml::crypto::CipherID::AES_GCM_W3C:
            return 12;
        default:
            O3TL_UNREACHABLE;
    }
}

::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_oImportedAlgorithms ? m_oImportedAlgorithms->oImportedChecksumAlgorithm : m_rZipPackage.GetChecksumAlgID(),
            m_oImportedAlgorithms ? m_oImportedAlgorithms->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
                ? PACKAGE_ENCRYPTIONDATA_SHA1MS1252
                : (bugs == Bugs::WrongSHA1)
                    ? PACKAGE_ENCRYPTIONDATA_SHA1UTF8
                    : PACKAGE_ENCRYPTIONDATA_SHA1CORRECT;
        }
        else
            throw uno::RuntimeException(THROW_WHERE "No expected key is provided!" );

        for (const auto& rKey : 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_oImportedAlgorithms
        ? m_oImportedAlgorithms->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(new utl::TempFileFastService);

        // 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(u"MediaType"_ustr, Any( msMediaType ) );
        xNewPSProps->setPropertyValue(u"Compressed"_ustr, Any( m_bToBeCompressed ) );
        if ( m_bToBeEncrypted )
        {
            xNewPSProps->setPropertyValue(ENCRYPTION_KEY_PROPERTY, Any( aKey ) );
            xNewPSProps->setPropertyValue(u"Encrypted"_ustr, Any( true ) );
        }

        // insert a new stream in the package
        Any aRoot = pPackage->getByHierarchicalName(u"/"_ustr);
        auto xRootNameContainer = aRoot.queryThrow<container::XNameContainer>();

        xRootNameContainer->insertByName(u"dummy"_ustr, Any( xNewPackStream ) );

        // 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
        rtl::Reference < utl::TempFileFastService > xTempOut = new utl::TempFileFastService;

        // copy the raw stream to the temporary file
        ::comphelper::OStorageHelper::CopyInputToOutput( xInRaw, xTempOut );
        xTempOut->closeOutput();
        xTempOut->seek( 0 );

        // close raw stream, package stream and folder
        xInRaw.clear();
        xNewPSProps.clear();
        xNewPackStream.clear();
        xRootNameContainer.clear();

        // return the stream representing the first temporary file
        return xTempOut;
    }
    catch ( RuntimeException& )
    {
        throw;
    }
    catch ( Exception& )
    {
    }

    throw io::IOException(THROW_WHERE );
}

// presumably the purpose of this is to transfer encrypted streams between
// storages, needed for password-protected macros in documents, which is
// tragically a feature that exists
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_oImportedAlgorithms.emplace(ImportedAlgorithms{
                        .nImportedStartKeyAlgorithm = nStartKeyGenID,
                        .nImportedEncryptionAlgorithm = nEncAlgorithm,
                        .oImportedChecksumAlgorithm = nChecksumAlgorithm == 0
                            ? ::std::optional<sal_Int32>{}
                            : ::std::optional<sal_Int32>{nChecksumAlgorithm},
                        .nImportedDerivedKeySize = nDerivedKeySize,
                        });
                    m_nOwnStreamOrigSize = nMagHackSize;
                    msMediaType = aMediaType;

                    bOk = true;
                }
            }
        }
    }
    catch( Exception& )
    {
    }

    if ( !bOk )
    {
        // the provided stream is not a raw stream
        return false;
    }

    m_xBaseEncryptionData = std::move(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,
        ::std::optional<sal_Int32> const oPBKDF2IterationCount,
        ::std::optional<::std::tuple<sal_Int32, sal_Int32, sal_Int32>> const oArgon2Args)
{
    static constexpr OUString sDigestProperty (u"Digest"_ustr);
    static constexpr OUString sEncryptionAlgProperty    (u"EncryptionAlgorithm"_ustr);
    static constexpr OUString sStartKeyAlgProperty  (u"StartKeyAlgorithm"_ustr);
    static constexpr OUString sDigestAlgProperty    (u"DigestAlgorithm"_ustr);
    static constexpr OUString sDerivedKeySizeProperty  (u"DerivedKeySize"_ustr);

    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
    if (!m_bRawStream)
    {
        m_nOwnStreamOrigSize = 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)
    {
        // this should work for XUnbufferedStream/OInputCompStream at least
        if (pTempEntry->nSize == -1)
        {   // this is needed in writeLOC to detect Zip64
            pTempEntry->nSize = xStream->available();
        }
    }
    else
    {
        xStream = getRawData();

        if ( !xStream.is() )
        {
            OSL_FAIL( "ZipPackageStream didn't have a stream associated with it, skipping!" );
            return false;
        }

        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 );
                }
                else if ( bToBeEncrypted )
                {
                    // this is the correct original size
                    m_nOwnStreamOrigSize = xSeek->getLength();
                }

                if (pTempEntry->nSize == -1)
                {   // this is needed in writeLOC to detect Zip64
                    pTempEntry->nSize = xSeek->getLength();
                }

                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
                {
                    return false;
                }
            }
        }
        catch ( uno::Exception& )
        {
            return false;
        }

        if ( bToBeEncrypted || m_bRawStream || bTransportOwnEncrStreamAsRaw )
        {
            if ( bToBeEncrypted && !bTransportOwnEncrStreamAsRaw )
            {
                uno::Sequence<sal_Int8> aSalt(16);
                // note: for GCM it's particularly important that IV is unique
                uno::Sequence<sal_Int8> aVector(GetIVSize());
                if (rtl_random_getBytes(nullptr, aSalt.getArray(), 16) != rtl_Random_E_None)
                {
                    throw uno::RuntimeException(u"rtl_random_getBytes failed"_ustr);
                }
                if (rtl_random_getBytes(nullptr, aVector.getArray(), aVector.getLength()) != rtl_Random_E_None)
                {
                    throw uno::RuntimeException(u"rtl_random_getBytes failed"_ustr);
                }
                if ( !m_bHaveOwnKey )
                {
                    m_aEncryptionKey = rEncryptionKey;
                    m_aStorageEncryptionKeys.realloc( 0 );
                }

                setInitialisationVector ( aVector );
                setSalt ( aSalt );
                setIterationCount(oPBKDF2IterationCount);
                setArgon2Args(oArgon2Args);
            }

            // 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;
            if (m_xBaseEncryptionData->m_oArgon2Args)
            {
                pPropSet[PKG_MNFST_KDF].Name = "KeyDerivationFunction";
                pPropSet[PKG_MNFST_KDF].Value <<= xml::crypto::KDFID::Argon2id;
                pPropSet[PKG_MNFST_ARGON2ARGS].Name = "Argon2Args";
                uno::Sequence<sal_Int32> const args{
                    ::std::get<0>(*m_xBaseEncryptionData->m_oArgon2Args),
                    ::std::get<1>(*m_xBaseEncryptionData->m_oArgon2Args),
                    ::std::get<2>(*m_xBaseEncryptionData->m_oArgon2Args) };
                pPropSet[PKG_MNFST_ARGON2ARGS].Value <<= args;
            }
            else if (m_xBaseEncryptionData->m_oPBKDFIterationCount)
            {
                pPropSet[PKG_MNFST_KDF].Name = "KeyDerivationFunction";
                pPropSet[PKG_MNFST_KDF].Value <<= xml::crypto::KDFID::PBKDF2;
                pPropSet[PKG_MNFST_ITERATION].Name = "IterationCount";
                pPropSet[PKG_MNFST_ITERATION].Value <<= *m_xBaseEncryptionData->m_oPBKDFIterationCount;
            }
            else
            {
                pPropSet[PKG_MNFST_KDF].Name = "KeyDerivationFunction";
                pPropSet[PKG_MNFST_KDF].Value <<= xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P;
            }

            // 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_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;
                if (xEncData->m_oCheckAlg)
                {
                    assert(xEncData->m_nEncAlg != xml::crypto::CipherID::AES_GCM_W3C);
                    pPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
                    pPropSet[PKG_MNFST_DIGEST].Value <<= m_xBaseEncryptionData->m_aDigest;
                    pPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
                    pPropSet[PKG_MNFST_DIGESTALG].Value <<= *xEncData->m_oCheckAlg;
                }
                pPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
                pPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
            }
        }
    }

    bool bSuccess = true;
    // 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 !
                return false;
            }
        }

        try
        {
            if ( m_bRawStream )
                xStream->skipBytes( m_nMagicalHackPos );

            ZipOutputStream::setEntry(*pTempEntry);
            rZipOut.writeLOC(std::move(pAutoTempEntry));

            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 !
                return false;
            }
        }

        if ( bToBeCompressed )
        {
            pTempEntry->nMethod = DEFLATED;
            pTempEntry->nCrc = -1;
            pTempEntry->nCompressedSize = -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

            if (pTempEntry->nMethod == STORED)
            {
                sal_Int32 nLength;
                uno::Sequence< sal_Int8 > aSeq(n_ConstBufferSize);
                rZipOut.writeLOC(std::move(pAutoTempEntry), 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(std::move(pAutoTempEntry), 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, std::move(pAutoTempEntry), this, bToBeEncrypted);
                    rZipOut.addDeflatingThreadTask( pZipEntry,
                            pZipEntry->createTask( rZipOut.getThreadTaskTag(), xStream) );
                }
                else
                {
                    bBackgroundThreadDeflate = false;
                    rZipOut.writeLOC(std::move(pAutoTempEntry), 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();

            // very confusing: half the encryption properties are
            // unconditionally added above and the other half conditionally;
            // assert that we have the expected group and not duplicates
            assert(std::any_of(aPropSet.begin(), aPropSet.end(), [](auto const& it){ return it.Name == "Salt"; }));
            assert(!std::any_of(aPropSet.begin(), aPropSet.end(), [](auto const& it){ return it.Name == sEncryptionAlgProperty; }));

            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;
            if (xEncData->m_oCheckAlg)
            {
                assert(xEncData->m_nEncAlg != xml::crypto::CipherID::AES_GCM_W3C);
                pPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
                pPropSet[PKG_MNFST_DIGEST].Value <<= m_xBaseEncryptionData->m_aDigest;
                pPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
                pPropSet[PKG_MNFST_DIGESTALG].Value <<= *xEncData->m_oCheckAlg;
            }
            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;

    aEntry.nOffset *= -1;
}

void ZipPackageStream::SetPackageMember( bool bNewValue )
{
    if ( bNewValue )
    {
        m_nStreamMode = PACKAGE_STREAM_PACKAGEMEMBER;
        m_nMagicalHackPos = 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 >&&nbsp;aStream )
{
    // if seekable access is required the wrapping will be done on demand
    m_xStream = aStream;
    m_oImportedAlgorithms.reset();
    m_bHasSeekable = false;
    SetPackageMember ( false );
    aEntry.nTime = -1;
    m_nStreamMode = PACKAGE_STREAM_DETECT;
}

uno::Reference< io::XInputStream > ZipPackageStream::getRawData()
{
    try
    {
        if ( IsPackageMember() )
        {
            ::std::optional<sal_Int64> oDecryptedSize;
            if (m_bIsEncrypted)
            {
                oDecryptedSize.emplace(m_nOwnStreamOrigSize);
            }
            return m_rZipPackage.getZipFile().getRawData( aEntry, GetEncryptionData(),
                oDecryptedSize, 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() )
        {
            ::std::optional<sal_Int64> oDecryptedSize;
            if (m_bIsEncrypted)
            {
                oDecryptedSize.emplace(m_nOwnStreamOrigSize);
            }
            return m_rZipPackage.getZipFile().getInputStream(aEntry, GetEncryptionData(),
                    oDecryptedSize, 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;
        ::std::optional<sal_Int64> oDecryptedSize;
        if (m_bIsEncrypted)
        {
            oDecryptedSize.emplace(m_nOwnStreamOrigSize);
        }
        try
        {
            xResult = m_rZipPackage.getZipFile().getDataStream(aEntry,
                GetEncryptionData(Bugs::None), oDecryptedSize,
                m_rZipPackage.GetSharedMutexRef());
        }
        catchconst packages::WrongPasswordException& )
        {
            // note: due to SHA1 check this fallback is only done for
            // * ODF 1.2 files written by OOo < 3.4beta / LO < 3.5
            // * ODF 1.1/OOoXML files written by any version
            if (m_oImportedAlgorithms
                && m_oImportedAlgorithms->nImportedStartKeyAlgorithm == 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), oDecryptedSize,
                        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_oImportedAlgorithms->nImportedStartKeyAlgorithm = xml::crypto::DigestID::SHA256;
                    xResult = m_rZipPackage.getZipFile().getDataStream(aEntry,
                        GetEncryptionData(), oDecryptedSize,
                        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_oImportedAlgorithms->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),
                        oDecryptedSize, 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(),
            m_nOwnStreamOrigSize, 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 >&&nbsp;aStream )
{
    setInputStream( aStream );
    m_nStreamMode = PACKAGE_STREAM_DATA;
}

void SAL_CALL ZipPackageStream::setRawStream( const uno::Reference< io::XInputStream >&&nbsp;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 = std::move(xNewStream);
    if ( !ParsePackageRawStream() )
    {
        m_xStream = std::move(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() )
    {
        ::std::optional<sal_Int64> oDecryptedSize;
        if (m_bIsEncrypted)
        {
            oDecryptedSize.emplace(m_nOwnStreamOrigSize);
        }
        return m_rZipPackage.getZipFile().getRawData(aEntry, GetEncryptionData(),
            oDecryptedSize, 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 >();
}

// 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 >>= m_nOwnStreamOrigSize))
            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 = std::move(aSequence);
        }

        if ( aNewKey.hasElements() )
        {
            if ( !m_xBaseEncryptionData.is() )
                m_xBaseEncryptionData = new BaseEncryptionData;

            m_aEncryptionKey = std::move(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 = std::move(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(m_nOwnStreamOrigSize);
    }
    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 )
{
    m_nOwnStreamOrigSize = nNewSize;
}

OUString ZipPackageStream::getImplementationName()
{
    return u"ZipPackageStream"_ustr;
}

Sequence< OUString > ZipPackageStream::getSupportedServiceNames()
{
    return { u"com.sun.star.packages.PackageStream"_ustr };
}

sal_Bool SAL_CALL ZipPackageStream::supportsService( OUString const & rServiceName )
{
    return cppu::supportsService(this, rServiceName);
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=93 H=88 G=90

¤ Dauer der Verarbeitung: 0.7 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.