Fix GNU C++ version check
[LibreOffice.git] / package / source / zippackage / ZipPackageStream.cxx
blob8280a048c7c52d99c34ee95692e6c31b382f22a3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <ZipPackageStream.hxx>
22 #include <com/sun/star/beans/PropertyValue.hpp>
23 #include <com/sun/star/container/XNameContainer.hpp>
24 #include <com/sun/star/packages/NoRawFormatException.hpp>
25 #include <com/sun/star/packages/zip/ZipConstants.hpp>
26 #include <com/sun/star/embed/StorageFormats.hpp>
27 #include <com/sun/star/packages/zip/ZipIOException.hpp>
28 #include <com/sun/star/packages/NoEncryptionException.hpp>
29 #include <com/sun/star/packages/zip/ZipException.hpp>
30 #include <com/sun/star/packages/WrongPasswordException.hpp>
31 #include <com/sun/star/io/TempFile.hpp>
32 #include <com/sun/star/io/XInputStream.hpp>
33 #include <com/sun/star/io/XOutputStream.hpp>
34 #include <com/sun/star/io/XStream.hpp>
35 #include <com/sun/star/io/XSeekable.hpp>
36 #include <com/sun/star/xml/crypto/DigestID.hpp>
37 #include <com/sun/star/xml/crypto/CipherID.hpp>
38 #include <com/sun/star/xml/crypto/KDFID.hpp>
40 #include <CRC32.hxx>
41 #include <ZipOutputEntry.hxx>
42 #include <ZipOutputStream.hxx>
43 #include <ZipPackage.hxx>
44 #include <ZipFile.hxx>
45 #include <EncryptedDataHeader.hxx>
46 #include <osl/diagnose.h>
47 #include "wrapstreamforshare.hxx"
49 #include <comphelper/seekableinput.hxx>
50 #include <comphelper/servicehelper.hxx>
51 #include <comphelper/storagehelper.hxx>
52 #include <cppuhelper/supportsservice.hxx>
53 #include <unotools/tempfile.hxx>
55 #include <rtl/random.h>
56 #include <sal/log.hxx>
57 #include <o3tl/unreachable.hxx>
58 #include <comphelper/diagnose_ex.hxx>
60 #include <PackageConstants.hxx>
62 #include <algorithm>
63 #include <cstddef>
65 using namespace com::sun::star::packages::zip::ZipConstants;
66 using namespace com::sun::star::packages::zip;
67 using namespace com::sun::star::uno;
68 using namespace com::sun::star::lang;
69 using namespace com::sun::star;
70 using namespace cppu;
72 #if OSL_DEBUG_LEVEL > 0
73 #define THROW_WHERE SAL_WHERE
74 #else
75 #define THROW_WHERE ""
76 #endif
78 ZipPackageStream::ZipPackageStream ( ZipPackage & rNewPackage,
79 const uno::Reference< XComponentContext >& xContext,
80 sal_Int32 nFormat,
81 bool bAllowRemoveOnInsert )
82 : m_rZipPackage( rNewPackage )
83 , m_bToBeCompressed ( true )
84 , m_bToBeEncrypted ( false )
85 , m_bHaveOwnKey ( false )
86 , m_bIsEncrypted ( false )
87 , m_nStreamMode( PACKAGE_STREAM_NOTSET )
88 , m_nMagicalHackPos( 0 )
89 , m_nOwnStreamOrigSize( 0 )
90 , m_bHasSeekable( false )
91 , m_bCompressedIsSetFromOutside( false )
92 , m_bFromManifest( false )
93 , m_bUseWinEncoding( false )
94 , m_bRawStream( false )
96 m_xContext = xContext;
97 m_nFormat = nFormat;
98 mbAllowRemoveOnInsert = bAllowRemoveOnInsert;
99 SetFolder ( false );
100 aEntry.nVersion = -1;
101 aEntry.nFlag = 0;
102 aEntry.nMethod = -1;
103 aEntry.nTime = -1;
104 aEntry.nCrc = -1;
105 aEntry.nCompressedSize = -1;
106 aEntry.nSize = -1;
107 aEntry.nOffset = -1;
108 aEntry.nPathLen = -1;
109 aEntry.nExtraLen = -1;
112 ZipPackageStream::~ZipPackageStream()
116 void ZipPackageStream::setZipEntryOnLoading( const ZipEntry &rInEntry )
118 aEntry.nVersion = rInEntry.nVersion;
119 aEntry.nFlag = rInEntry.nFlag;
120 aEntry.nMethod = rInEntry.nMethod;
121 aEntry.nTime = rInEntry.nTime;
122 aEntry.nCrc = rInEntry.nCrc;
123 aEntry.nCompressedSize = rInEntry.nCompressedSize;
124 aEntry.nSize = rInEntry.nSize;
125 aEntry.nOffset = rInEntry.nOffset;
126 aEntry.sPath = rInEntry.sPath;
127 aEntry.nPathLen = rInEntry.nPathLen;
128 aEntry.nExtraLen = rInEntry.nExtraLen;
130 if ( aEntry.nMethod == STORED )
131 m_bToBeCompressed = false;
133 // this is called first, parseManifest may overwrite it if it's encrypted
134 assert(m_nOwnStreamOrigSize == 0);
135 m_nOwnStreamOrigSize = aEntry.nSize;
138 uno::Reference< io::XInputStream > const & ZipPackageStream::GetOwnSeekStream()
140 if ( !m_bHasSeekable && m_xStream.is() )
142 // The package component requires that every stream either be FROM a package or it must support XSeekable!
143 // The only exception is a nonseekable stream that is provided only for storing, if such a stream
144 // is accessed before commit it MUST be wrapped.
145 // Wrap the stream in case it is not seekable
146 m_xStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( m_xStream, m_xContext );
147 uno::Reference< io::XSeekable > xSeek( m_xStream, UNO_QUERY_THROW );
149 m_bHasSeekable = true;
152 return m_xStream;
155 uno::Reference< io::XInputStream > ZipPackageStream::GetRawEncrStreamNoHeaderCopy()
157 if ( m_nStreamMode != PACKAGE_STREAM_RAW || !GetOwnSeekStream().is() )
158 throw io::IOException(THROW_WHERE );
160 if ( m_xBaseEncryptionData.is() )
161 throw ZipIOException(THROW_WHERE "Encrypted stream without encryption data!" );
163 uno::Reference< io::XSeekable > xSeek( GetOwnSeekStream(), UNO_QUERY );
164 if ( !xSeek.is() )
165 throw ZipIOException(THROW_WHERE "The stream must be seekable!" );
167 // skip header
168 xSeek->seek( n_ConstHeaderSize + m_xBaseEncryptionData->m_aInitVector.getLength() +
169 m_xBaseEncryptionData->m_aSalt.getLength() + m_xBaseEncryptionData->m_aDigest.getLength() );
171 // create temporary stream
172 rtl::Reference < utl::TempFileFastService > xTempFile = new utl::TempFileFastService;
173 uno::Reference < io::XInputStream > xTempIn = xTempFile->getInputStream();
175 // copy the raw stream to the temporary file starting from the current position
176 ::comphelper::OStorageHelper::CopyInputToOutput( GetOwnSeekStream(), xTempFile );
177 xTempFile->closeOutput();
178 xTempFile->seek( 0 );
180 return xTempIn;
183 sal_Int32 ZipPackageStream::GetEncryptionAlgorithm() const
185 return m_oImportedAlgorithms
186 ? m_oImportedAlgorithms->nImportedEncryptionAlgorithm
187 : m_rZipPackage.GetEncAlgID();
190 sal_Int32 ZipPackageStream::GetIVSize() const
192 switch (GetEncryptionAlgorithm())
194 case css::xml::crypto::CipherID::BLOWFISH_CFB_8:
195 return 8;
196 case css::xml::crypto::CipherID::AES_CBC_W3C_PADDING:
197 return 16;
198 case css::xml::crypto::CipherID::AES_GCM_W3C:
199 return 12;
200 default:
201 O3TL_UNREACHABLE;
205 ::rtl::Reference<EncryptionData> ZipPackageStream::GetEncryptionData(Bugs const bugs)
207 ::rtl::Reference< EncryptionData > xResult;
208 if ( m_xBaseEncryptionData.is() )
209 xResult = new EncryptionData(
210 *m_xBaseEncryptionData,
211 GetEncryptionKey(bugs),
212 GetEncryptionAlgorithm(),
213 m_oImportedAlgorithms ? m_oImportedAlgorithms->oImportedChecksumAlgorithm : m_rZipPackage.GetChecksumAlgID(),
214 m_oImportedAlgorithms ? m_oImportedAlgorithms->nImportedDerivedKeySize : m_rZipPackage.GetDefaultDerivedKeySize(),
215 GetStartKeyGenID(),
216 bugs != Bugs::None);
218 return xResult;
221 uno::Sequence<sal_Int8> ZipPackageStream::GetEncryptionKey(Bugs const bugs)
223 uno::Sequence< sal_Int8 > aResult;
224 sal_Int32 nKeyGenID = GetStartKeyGenID();
225 bool const bUseWinEncoding = (bugs == Bugs::WinEncodingWrongSHA1 || m_bUseWinEncoding);
227 if ( m_bHaveOwnKey && m_aStorageEncryptionKeys.hasElements() )
229 OUString aNameToFind;
230 if ( nKeyGenID == xml::crypto::DigestID::SHA256 )
231 aNameToFind = PACKAGE_ENCRYPTIONDATA_SHA256UTF8;
232 else if ( nKeyGenID == xml::crypto::DigestID::SHA1 )
234 aNameToFind = bUseWinEncoding
235 ? PACKAGE_ENCRYPTIONDATA_SHA1MS1252
236 : (bugs == Bugs::WrongSHA1)
237 ? PACKAGE_ENCRYPTIONDATA_SHA1UTF8
238 : PACKAGE_ENCRYPTIONDATA_SHA1CORRECT;
240 else
241 throw uno::RuntimeException(THROW_WHERE "No expected key is provided!" );
243 for (const auto& rKey : m_aStorageEncryptionKeys)
244 if ( rKey.Name == aNameToFind )
245 rKey.Value >>= aResult;
247 // empty keys are not allowed here
248 // so it is not important whether there is no key, or the key is empty, it is an error
249 if ( !aResult.hasElements() )
250 throw uno::RuntimeException(THROW_WHERE "No expected key is provided!" );
252 else
253 aResult = m_aEncryptionKey;
255 if ( !aResult.hasElements() || !m_bHaveOwnKey )
256 aResult = m_rZipPackage.GetEncryptionKey();
258 return aResult;
261 sal_Int32 ZipPackageStream::GetStartKeyGenID() const
263 // generally should all the streams use the same Start Key
264 // but if raw copy without password takes place, we should preserve the imported algorithm
265 return m_oImportedAlgorithms
266 ? m_oImportedAlgorithms->nImportedStartKeyAlgorithm
267 : m_rZipPackage.GetStartKeyGenID();
270 uno::Reference< io::XInputStream > ZipPackageStream::TryToGetRawFromDataStream( bool bAddHeaderForEncr )
272 if ( m_nStreamMode != PACKAGE_STREAM_DATA || !GetOwnSeekStream().is() || ( bAddHeaderForEncr && !m_bToBeEncrypted ) )
273 throw packages::NoEncryptionException(THROW_WHERE );
275 Sequence< sal_Int8 > aKey;
277 if ( m_bToBeEncrypted )
279 aKey = GetEncryptionKey();
280 if ( !aKey.hasElements() )
281 throw packages::NoEncryptionException(THROW_WHERE );
286 // create temporary file
287 uno::Reference < io::XStream > xTempStream(new utl::TempFileFastService);
289 // create a package based on it
290 rtl::Reference<ZipPackage> pPackage = new ZipPackage( m_xContext );
292 Sequence< Any > aArgs{ Any(xTempStream) };
293 pPackage->initialize( aArgs );
295 // create a new package stream
296 uno::Reference< XDataSinkEncrSupport > xNewPackStream( pPackage->createInstance(), UNO_QUERY_THROW );
297 xNewPackStream->setDataStream(
298 new WrapStreamForShare(GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef()));
300 uno::Reference< XPropertySet > xNewPSProps( xNewPackStream, UNO_QUERY_THROW );
302 // copy all the properties of this stream to the new stream
303 xNewPSProps->setPropertyValue(u"MediaType"_ustr, Any( msMediaType ) );
304 xNewPSProps->setPropertyValue(u"Compressed"_ustr, Any( m_bToBeCompressed ) );
305 if ( m_bToBeEncrypted )
307 xNewPSProps->setPropertyValue(ENCRYPTION_KEY_PROPERTY, Any( aKey ) );
308 xNewPSProps->setPropertyValue(u"Encrypted"_ustr, Any( true ) );
311 // insert a new stream in the package
312 Any aRoot = pPackage->getByHierarchicalName(u"/"_ustr);
313 auto xRootNameContainer = aRoot.queryThrow<container::XNameContainer>();
315 xRootNameContainer->insertByName(u"dummy"_ustr, Any( xNewPackStream ) );
317 // commit the temporary package
318 pPackage->commitChanges();
320 // get raw stream from the temporary package
321 uno::Reference< io::XInputStream > xInRaw;
322 if ( bAddHeaderForEncr )
323 xInRaw = xNewPackStream->getRawStream();
324 else
325 xInRaw = xNewPackStream->getPlainRawStream();
327 // create another temporary file
328 rtl::Reference < utl::TempFileFastService > xTempOut = new utl::TempFileFastService;
329 uno::Reference < io::XInputStream > xTempIn( xTempOut );
331 // copy the raw stream to the temporary file
332 ::comphelper::OStorageHelper::CopyInputToOutput( xInRaw, xTempOut );
333 xTempOut->closeOutput();
334 xTempOut->seek( 0 );
336 // close raw stream, package stream and folder
337 xInRaw.clear();
338 xNewPSProps.clear();
339 xNewPackStream.clear();
340 xRootNameContainer.clear();
342 // return the stream representing the first temporary file
343 return xTempIn;
345 catch ( RuntimeException& )
347 throw;
349 catch ( Exception& )
353 throw io::IOException(THROW_WHERE );
356 // presumably the purpose of this is to transfer encrypted streams between
357 // storages, needed for password-protected macros in documents, which is
358 // tragically a feature that exists
359 bool ZipPackageStream::ParsePackageRawStream()
361 OSL_ENSURE( GetOwnSeekStream().is(), "A stream must be provided!" );
363 if ( !GetOwnSeekStream().is() )
364 return false;
366 bool bOk = false;
368 ::rtl::Reference< BaseEncryptionData > xTempEncrData;
369 Sequence < sal_Int8 > aHeader ( 4 );
373 if ( GetOwnSeekStream()->readBytes ( aHeader, 4 ) == 4 )
375 const sal_Int8 *pHeader = aHeader.getConstArray();
376 sal_uInt32 nHeader = ( pHeader [0] & 0xFF ) |
377 ( pHeader [1] & 0xFF ) << 8 |
378 ( pHeader [2] & 0xFF ) << 16 |
379 ( pHeader [3] & 0xFF ) << 24;
380 if ( nHeader == n_ConstHeader )
382 // this is one of our god-awful, but extremely devious hacks, everyone cheer
383 xTempEncrData = new BaseEncryptionData;
385 OUString aMediaType;
386 sal_Int32 nEncAlgorithm = 0;
387 sal_Int32 nChecksumAlgorithm = 0;
388 sal_Int32 nDerivedKeySize = 0;
389 sal_Int32 nStartKeyGenID = 0;
390 sal_Int32 nMagHackSize = 0;
391 if ( ZipFile::StaticFillData( xTempEncrData, nEncAlgorithm, nChecksumAlgorithm, nDerivedKeySize, nStartKeyGenID, nMagHackSize, aMediaType, GetOwnSeekStream() ) )
393 // We'll want to skip the data we've just read, so calculate how much we just read
394 // and remember it
395 m_nMagicalHackPos = n_ConstHeaderSize + xTempEncrData->m_aSalt.getLength()
396 + xTempEncrData->m_aInitVector.getLength()
397 + xTempEncrData->m_aDigest.getLength()
398 + aMediaType.getLength() * sizeof( sal_Unicode );
399 m_oImportedAlgorithms.emplace(ImportedAlgorithms{
400 .nImportedStartKeyAlgorithm = nStartKeyGenID,
401 .nImportedEncryptionAlgorithm = nEncAlgorithm,
402 .oImportedChecksumAlgorithm = nChecksumAlgorithm == 0
403 ? ::std::optional<sal_Int32>{}
404 : ::std::optional<sal_Int32>{nChecksumAlgorithm},
405 .nImportedDerivedKeySize = nDerivedKeySize,
407 m_nOwnStreamOrigSize = nMagHackSize;
408 msMediaType = aMediaType;
410 bOk = true;
415 catch( Exception& )
419 if ( !bOk )
421 // the provided stream is not a raw stream
422 return false;
425 m_xBaseEncryptionData = std::move(xTempEncrData);
426 SetIsEncrypted ( true );
427 // it's already compressed and encrypted
428 m_bToBeEncrypted = m_bToBeCompressed = false;
430 return true;
433 static void ImplSetStoredData( ZipEntry & rEntry, uno::Reference< io::XInputStream> const & rStream )
435 // It's very annoying that we have to do this, but lots of zip packages
436 // don't allow data descriptors for STORED streams, meaning we have to
437 // know the size and CRC32 of uncompressed streams before we actually
438 // write them !
439 CRC32 aCRC32;
440 rEntry.nMethod = STORED;
441 rEntry.nCompressedSize = rEntry.nSize = aCRC32.updateStream ( rStream );
442 rEntry.nCrc = aCRC32.getValue();
445 bool ZipPackageStream::saveChild(
446 const OUString &rPath,
447 std::vector < uno::Sequence < beans::PropertyValue > > &rManList,
448 ZipOutputStream & rZipOut,
449 const uno::Sequence < sal_Int8 >& rEncryptionKey,
450 ::std::optional<sal_Int32> const oPBKDF2IterationCount,
451 ::std::optional<::std::tuple<sal_Int32, sal_Int32, sal_Int32>> const oArgon2Args)
453 static constexpr OUString sDigestProperty (u"Digest"_ustr);
454 static constexpr OUString sEncryptionAlgProperty (u"EncryptionAlgorithm"_ustr);
455 static constexpr OUString sStartKeyAlgProperty (u"StartKeyAlgorithm"_ustr);
456 static constexpr OUString sDigestAlgProperty (u"DigestAlgorithm"_ustr);
457 static constexpr OUString sDerivedKeySizeProperty (u"DerivedKeySize"_ustr);
459 uno::Sequence < beans::PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST);
461 // In case the entry we are reading is also the entry we are writing, we will
462 // store the ZipEntry data in pTempEntry
464 // if pTempEntry is necessary, it will be released and passed to the ZipOutputStream
465 // and be deleted in the ZipOutputStream destructor
466 std::unique_ptr < ZipEntry > pAutoTempEntry ( new ZipEntry(aEntry) );
467 ZipEntry* pTempEntry = pAutoTempEntry.get();
469 pTempEntry->sPath = rPath;
470 pTempEntry->nPathLen = static_cast<sal_Int16>( OUStringToOString( pTempEntry->sPath, RTL_TEXTENCODING_UTF8 ).getLength() );
472 const bool bToBeEncrypted = m_bToBeEncrypted && (rEncryptionKey.hasElements() || m_bHaveOwnKey);
473 const bool bToBeCompressed = bToBeEncrypted || m_bToBeCompressed;
475 auto pPropSet = aPropSet.getArray();
476 pPropSet[PKG_MNFST_MEDIATYPE].Name = "MediaType";
477 pPropSet[PKG_MNFST_MEDIATYPE].Value <<= GetMediaType( );
478 pPropSet[PKG_MNFST_VERSION].Name = "Version";
479 pPropSet[PKG_MNFST_VERSION].Value <<= OUString(); // no version is stored for streams currently
480 pPropSet[PKG_MNFST_FULLPATH].Name = "FullPath";
481 pPropSet[PKG_MNFST_FULLPATH].Value <<= pTempEntry->sPath;
483 OSL_ENSURE( m_nStreamMode != PACKAGE_STREAM_NOTSET, "Unacceptable ZipPackageStream mode!" );
485 m_bRawStream = false;
486 if ( m_nStreamMode == PACKAGE_STREAM_DETECT )
487 m_bRawStream = ParsePackageRawStream();
488 else if ( m_nStreamMode == PACKAGE_STREAM_RAW )
489 m_bRawStream = true;
491 bool bBackgroundThreadDeflate = false;
492 bool bTransportOwnEncrStreamAsRaw = false;
493 // During the storing the original size of the stream can be changed
494 // TODO/LATER: get rid of this hack
495 if (!m_bRawStream)
497 m_nOwnStreamOrigSize = aEntry.nSize;
500 bool bUseNonSeekableAccess = false;
501 uno::Reference < io::XInputStream > xStream;
502 if ( !IsPackageMember() && !m_bRawStream && !bToBeEncrypted && bToBeCompressed )
504 // the stream is not a package member, not a raw stream,
505 // it should not be encrypted and it should be compressed,
506 // in this case nonseekable access can be used
508 xStream = m_xStream;
509 uno::Reference < io::XSeekable > xSeek ( xStream, uno::UNO_QUERY );
511 bUseNonSeekableAccess = ( xStream.is() && !xSeek.is() );
514 if ( !bUseNonSeekableAccess )
516 xStream = getRawData();
518 if ( !xStream.is() )
520 OSL_FAIL( "ZipPackageStream didn't have a stream associated with it, skipping!" );
521 return false;
524 uno::Reference < io::XSeekable > xSeek ( xStream, uno::UNO_QUERY );
527 if ( xSeek.is() )
529 // If the stream is a raw one, then we should be positioned
530 // at the beginning of the actual data
531 if ( !bToBeCompressed || m_bRawStream )
533 // The raw stream can neither be encrypted nor connected
534 OSL_ENSURE( !m_bRawStream || !(bToBeCompressed || bToBeEncrypted), "The stream is already encrypted!" );
535 xSeek->seek ( m_bRawStream ? m_nMagicalHackPos : 0 );
536 ImplSetStoredData ( *pTempEntry, xStream );
538 else if ( bToBeEncrypted )
540 // this is the correct original size
541 m_nOwnStreamOrigSize = xSeek->getLength();
544 xSeek->seek ( 0 );
546 else
548 // Okay, we don't have an xSeekable stream. This is possibly bad.
549 // check if it's one of our own streams, if it is then we know that
550 // each time we ask for it we'll get a new stream that will be
551 // at position zero...otherwise, assert and skip this stream...
552 if ( IsPackageMember() )
554 // if the password has been changed then the stream should not be package member any more
555 if ( m_bIsEncrypted && m_bToBeEncrypted )
557 // Should be handled close to the raw stream handling
558 bTransportOwnEncrStreamAsRaw = true;
559 pTempEntry->nMethod = STORED;
561 // TODO/LATER: get rid of this situation
562 // this size should be different from the one that will be stored in manifest.xml
563 // it is used in storing algorithms and after storing the correct size will be set
564 pTempEntry->nSize = pTempEntry->nCompressedSize;
567 else
569 return false;
573 catch ( uno::Exception& )
575 return false;
578 if ( bToBeEncrypted || m_bRawStream || bTransportOwnEncrStreamAsRaw )
580 if ( bToBeEncrypted && !bTransportOwnEncrStreamAsRaw )
582 uno::Sequence<sal_Int8> aSalt(16);
583 // note: for GCM it's particularly important that IV is unique
584 uno::Sequence<sal_Int8> aVector(GetIVSize());
585 if (rtl_random_getBytes(nullptr, aSalt.getArray(), 16) != rtl_Random_E_None)
587 throw uno::RuntimeException(u"rtl_random_getBytes failed"_ustr);
589 if (rtl_random_getBytes(nullptr, aVector.getArray(), aVector.getLength()) != rtl_Random_E_None)
591 throw uno::RuntimeException(u"rtl_random_getBytes failed"_ustr);
593 if ( !m_bHaveOwnKey )
595 m_aEncryptionKey = rEncryptionKey;
596 m_aStorageEncryptionKeys.realloc( 0 );
599 setInitialisationVector ( aVector );
600 setSalt ( aSalt );
601 setIterationCount(oPBKDF2IterationCount);
602 setArgon2Args(oArgon2Args);
605 // last property is digest, which is inserted later if we didn't have
606 // a magic header
607 aPropSet.realloc(PKG_SIZE_ENCR_MNFST);
608 pPropSet = aPropSet.getArray();
609 pPropSet[PKG_MNFST_INIVECTOR].Name = "InitialisationVector";
610 pPropSet[PKG_MNFST_INIVECTOR].Value <<= m_xBaseEncryptionData->m_aInitVector;
611 pPropSet[PKG_MNFST_SALT].Name = "Salt";
612 pPropSet[PKG_MNFST_SALT].Value <<= m_xBaseEncryptionData->m_aSalt;
613 if (m_xBaseEncryptionData->m_oArgon2Args)
615 pPropSet[PKG_MNFST_KDF].Name = "KeyDerivationFunction";
616 pPropSet[PKG_MNFST_KDF].Value <<= xml::crypto::KDFID::Argon2id;
617 pPropSet[PKG_MNFST_ARGON2ARGS].Name = "Argon2Args";
618 uno::Sequence<sal_Int32> const args{
619 ::std::get<0>(*m_xBaseEncryptionData->m_oArgon2Args),
620 ::std::get<1>(*m_xBaseEncryptionData->m_oArgon2Args),
621 ::std::get<2>(*m_xBaseEncryptionData->m_oArgon2Args) };
622 pPropSet[PKG_MNFST_ARGON2ARGS].Value <<= args;
624 else if (m_xBaseEncryptionData->m_oPBKDFIterationCount)
626 pPropSet[PKG_MNFST_KDF].Name = "KeyDerivationFunction";
627 pPropSet[PKG_MNFST_KDF].Value <<= xml::crypto::KDFID::PBKDF2;
628 pPropSet[PKG_MNFST_ITERATION].Name = "IterationCount";
629 pPropSet[PKG_MNFST_ITERATION].Value <<= *m_xBaseEncryptionData->m_oPBKDFIterationCount;
631 else
633 pPropSet[PKG_MNFST_KDF].Name = "KeyDerivationFunction";
634 pPropSet[PKG_MNFST_KDF].Value <<= xml::crypto::KDFID::PGP_RSA_OAEP_MGF1P;
637 // Need to store the uncompressed size in the manifest
638 OSL_ENSURE( m_nOwnStreamOrigSize >= 0, "The stream size was not correctly initialized!" );
639 pPropSet[PKG_MNFST_UCOMPSIZE].Name = "Size";
640 pPropSet[PKG_MNFST_UCOMPSIZE].Value <<= m_nOwnStreamOrigSize;
642 if ( m_bRawStream || bTransportOwnEncrStreamAsRaw )
644 ::rtl::Reference< EncryptionData > xEncData = GetEncryptionData();
645 if ( !xEncData.is() )
646 throw uno::RuntimeException();
648 pPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
649 pPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
650 pPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
651 pPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID;
652 if (xEncData->m_oCheckAlg)
654 assert(xEncData->m_nEncAlg != xml::crypto::CipherID::AES_GCM_W3C);
655 pPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
656 pPropSet[PKG_MNFST_DIGEST].Value <<= m_xBaseEncryptionData->m_aDigest;
657 pPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
658 pPropSet[PKG_MNFST_DIGESTALG].Value <<= *xEncData->m_oCheckAlg;
660 pPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
661 pPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
666 bool bSuccess = true;
667 // If the entry is already stored in the zip file in the format we
668 // want for this write...copy it raw
669 if ( !bUseNonSeekableAccess
670 && ( m_bRawStream || bTransportOwnEncrStreamAsRaw
671 || ( IsPackageMember() && !bToBeEncrypted
672 && ( ( aEntry.nMethod == DEFLATED && bToBeCompressed )
673 || ( aEntry.nMethod == STORED && !bToBeCompressed ) ) ) ) )
675 // If it's a PackageMember, then it's an unbuffered stream and we need
676 // to get a new version of it as we can't seek backwards.
677 if ( IsPackageMember() )
679 xStream = getRawData();
680 if ( !xStream.is() )
682 // Make sure that we actually _got_ a new one !
683 return false;
689 if ( m_bRawStream )
690 xStream->skipBytes( m_nMagicalHackPos );
692 ZipOutputStream::setEntry(*pTempEntry);
693 rZipOut.writeLOC(std::move(pAutoTempEntry));
695 uno::Sequence < sal_Int8 > aSeq ( n_ConstBufferSize );
696 sal_Int32 nLength;
700 nLength = xStream->readBytes( aSeq, n_ConstBufferSize );
701 if (nLength != n_ConstBufferSize)
702 aSeq.realloc(nLength);
704 rZipOut.rawWrite(aSeq);
706 while ( nLength == n_ConstBufferSize );
708 rZipOut.rawCloseEntry();
710 catch ( ZipException& )
712 bSuccess = false;
714 catch ( io::IOException& )
716 bSuccess = false;
719 else
721 // This stream is definitely not a raw stream
723 // If nonseekable access is used the stream should be at the beginning and
724 // is useless after the storing. Thus if the storing fails the package should
725 // be thrown away ( as actually it is done currently )!
726 // To allow to reuse the package after the error, the optimization must be removed!
728 // If it's a PackageMember, then our previous reference held a 'raw' stream
729 // so we need to re-get it, unencrypted, uncompressed and positioned at the
730 // beginning of the stream
731 if ( IsPackageMember() )
733 xStream = getInputStream();
734 if ( !xStream.is() )
736 // Make sure that we actually _got_ a new one !
737 return false;
741 if ( bToBeCompressed )
743 pTempEntry->nMethod = DEFLATED;
744 pTempEntry->nCrc = -1;
745 pTempEntry->nCompressedSize = pTempEntry->nSize = -1;
748 uno::Reference< io::XSeekable > xSeek(xStream, uno::UNO_QUERY);
749 // It's not worth to deflate jpegs to save ~1% in a slow process
750 // Unfortunately, does not work for streams protected by password
751 if (xSeek.is() && msMediaType.endsWith("/jpeg") && !m_bToBeEncrypted && !m_bToBeCompressed)
753 ImplSetStoredData(*pTempEntry, xStream);
754 xSeek->seek(0);
759 ZipOutputStream::setEntry(*pTempEntry);
760 // the entry is provided to the ZipOutputStream that will delete it
762 if (pTempEntry->nMethod == STORED)
764 sal_Int32 nLength;
765 uno::Sequence< sal_Int8 > aSeq(n_ConstBufferSize);
766 rZipOut.writeLOC(std::move(pAutoTempEntry), bToBeEncrypted);
769 nLength = xStream->readBytes(aSeq, n_ConstBufferSize);
770 if (nLength != n_ConstBufferSize)
771 aSeq.realloc(nLength);
773 rZipOut.rawWrite(aSeq);
775 while ( nLength == n_ConstBufferSize );
776 rZipOut.rawCloseEntry(bToBeEncrypted);
778 else
780 // tdf#89236 Encrypting in a background thread does not work
781 bBackgroundThreadDeflate = !bToBeEncrypted;
782 // Do not deflate small streams using threads. XSeekable's getLength()
783 // gives the full size, XInputStream's available() may not be
784 // the full size, but it appears that at this point it usually is.
785 sal_Int64 estimatedSize = xSeek.is() ? xSeek->getLength() : xStream->available();
787 if (estimatedSize > 1000000)
789 // Use ThreadDeflater which will split the stream into blocks and compress
790 // them in threads, but not in background (i.e. writeStream() will block).
791 // This is suitable for large data.
792 bBackgroundThreadDeflate = false;
793 rZipOut.writeLOC(std::move(pAutoTempEntry), bToBeEncrypted);
794 ZipOutputEntryParallel aZipEntry(rZipOut.getStream(), m_xContext, pTempEntry, this, bToBeEncrypted);
795 aZipEntry.writeStream(xStream);
796 rZipOut.rawCloseEntry(bToBeEncrypted);
798 else if (bBackgroundThreadDeflate && estimatedSize > 100000)
800 // tdf#93553 limit to a useful amount of pending tasks. Having way too many
801 // tasks pending may use a lot of memory. Take number of available
802 // cores and allow 4-times the amount for having the queue well filled. The
803 // 2nd parameter is the time to wait between cleanups in 10th of a second.
804 // Both values may be added to the configuration settings if needed.
805 static std::size_t nAllowedTasks(comphelper::ThreadPool::getPreferredConcurrency() * 4); //TODO: overflow
806 rZipOut.reduceScheduledThreadTasksToGivenNumberOrLess(nAllowedTasks);
808 // Start a new thread task deflating this zip entry
809 ZipOutputEntryInThread *pZipEntry = new ZipOutputEntryInThread(
810 m_xContext, std::move(pAutoTempEntry), this, bToBeEncrypted);
811 rZipOut.addDeflatingThreadTask( pZipEntry,
812 pZipEntry->createTask( rZipOut.getThreadTaskTag(), xStream) );
814 else
816 bBackgroundThreadDeflate = false;
817 rZipOut.writeLOC(std::move(pAutoTempEntry), bToBeEncrypted);
818 ZipOutputEntry aZipEntry(rZipOut.getStream(), m_xContext, pTempEntry, this, bToBeEncrypted);
819 aZipEntry.writeStream(xStream);
820 rZipOut.rawCloseEntry(bToBeEncrypted);
824 catch ( ZipException& )
826 bSuccess = false;
828 catch ( io::IOException& )
830 bSuccess = false;
833 if ( bToBeEncrypted )
835 ::rtl::Reference< EncryptionData > xEncData = GetEncryptionData();
836 if ( !xEncData.is() )
837 throw uno::RuntimeException();
839 // very confusing: half the encryption properties are
840 // unconditionally added above and the other half conditionally;
841 // assert that we have the expected group and not duplicates
842 assert(std::any_of(aPropSet.begin(), aPropSet.end(), [](auto const& it){ return it.Name == "Salt"; }));
843 assert(!std::any_of(aPropSet.begin(), aPropSet.end(), [](auto const& it){ return it.Name == sEncryptionAlgProperty; }));
845 pPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
846 pPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
847 pPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
848 pPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID;
849 if (xEncData->m_oCheckAlg)
851 assert(xEncData->m_nEncAlg != xml::crypto::CipherID::AES_GCM_W3C);
852 pPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
853 pPropSet[PKG_MNFST_DIGEST].Value <<= m_xBaseEncryptionData->m_aDigest;
854 pPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
855 pPropSet[PKG_MNFST_DIGESTALG].Value <<= *xEncData->m_oCheckAlg;
857 pPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
858 pPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
860 SetIsEncrypted ( true );
864 if (bSuccess && !bBackgroundThreadDeflate)
865 successfullyWritten(pTempEntry);
867 if ( aPropSet.hasElements()
868 && ( m_nFormat == embed::StorageFormats::PACKAGE || m_nFormat == embed::StorageFormats::OFOPXML ) )
869 rManList.push_back( aPropSet );
871 return bSuccess;
874 void ZipPackageStream::successfullyWritten( ZipEntry const *pEntry )
876 if ( !IsPackageMember() )
878 if ( m_xStream.is() )
880 m_xStream->closeInput();
881 m_xStream.clear();
882 m_bHasSeekable = false;
884 SetPackageMember ( true );
887 if ( m_bRawStream )
889 // the raw stream was integrated and now behaves
890 // as usual encrypted stream
891 SetToBeEncrypted( true );
894 // Then copy it back afterwards...
895 aEntry = *pEntry;
897 aEntry.nOffset *= -1;
900 void ZipPackageStream::SetPackageMember( bool bNewValue )
902 if ( bNewValue )
904 m_nStreamMode = PACKAGE_STREAM_PACKAGEMEMBER;
905 m_nMagicalHackPos = 0;
907 else if ( m_nStreamMode == PACKAGE_STREAM_PACKAGEMEMBER )
908 m_nStreamMode = PACKAGE_STREAM_NOTSET; // must be reset
911 // XActiveDataSink
912 void SAL_CALL ZipPackageStream::setInputStream( const uno::Reference< io::XInputStream >& aStream )
914 // if seekable access is required the wrapping will be done on demand
915 m_xStream = aStream;
916 m_oImportedAlgorithms.reset();
917 m_bHasSeekable = false;
918 SetPackageMember ( false );
919 aEntry.nTime = -1;
920 m_nStreamMode = PACKAGE_STREAM_DETECT;
923 uno::Reference< io::XInputStream > ZipPackageStream::getRawData()
927 if ( IsPackageMember() )
929 ::std::optional<sal_Int64> oDecryptedSize;
930 if (m_bIsEncrypted)
932 oDecryptedSize.emplace(m_nOwnStreamOrigSize);
934 return m_rZipPackage.getZipFile().getRawData( aEntry, GetEncryptionData(),
935 oDecryptedSize, m_rZipPackage.GetSharedMutexRef(), false/*bUseBufferedStream*/ );
937 else if ( GetOwnSeekStream().is() )
939 return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() );
941 else
942 return uno::Reference < io::XInputStream > ();
944 catch ( ZipException & )//rException )
946 TOOLS_WARN_EXCEPTION( "package", "" );
947 return uno::Reference < io::XInputStream > ();
949 catch ( Exception & )
951 TOOLS_WARN_EXCEPTION( "package", "Exception is thrown during stream wrapping!" );
952 return uno::Reference < io::XInputStream > ();
956 uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getInputStream()
960 if ( IsPackageMember() )
962 ::std::optional<sal_Int64> oDecryptedSize;
963 if (m_bIsEncrypted)
965 oDecryptedSize.emplace(m_nOwnStreamOrigSize);
967 return m_rZipPackage.getZipFile().getInputStream(aEntry, GetEncryptionData(),
968 oDecryptedSize, m_rZipPackage.GetSharedMutexRef());
970 else if ( GetOwnSeekStream().is() )
972 return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() );
974 else
975 return uno::Reference < io::XInputStream > ();
977 catch ( ZipException & )//rException )
979 TOOLS_WARN_EXCEPTION( "package", "" );
980 return uno::Reference < io::XInputStream > ();
982 catch ( const Exception & )
984 TOOLS_WARN_EXCEPTION( "package", "Exception is thrown during stream wrapping!");
985 return uno::Reference < io::XInputStream > ();
989 // XDataSinkEncrSupport
990 uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getDataStream()
992 // There is no stream attached to this object
993 if ( m_nStreamMode == PACKAGE_STREAM_NOTSET )
994 return uno::Reference< io::XInputStream >();
996 // this method can not be used together with old approach
997 if ( m_nStreamMode == PACKAGE_STREAM_DETECT )
998 throw packages::zip::ZipIOException(THROW_WHERE );
1000 if ( IsPackageMember() )
1002 uno::Reference< io::XInputStream > xResult;
1003 ::std::optional<sal_Int64> oDecryptedSize;
1004 if (m_bIsEncrypted)
1006 oDecryptedSize.emplace(m_nOwnStreamOrigSize);
1010 xResult = m_rZipPackage.getZipFile().getDataStream(aEntry,
1011 GetEncryptionData(Bugs::None), oDecryptedSize,
1012 m_rZipPackage.GetSharedMutexRef());
1014 catch( const packages::WrongPasswordException& )
1016 // note: due to SHA1 check this fallback is only done for
1017 // * ODF 1.2 files written by OOo < 3.4beta / LO < 3.5
1018 // * ODF 1.1/OOoXML files written by any version
1019 if (m_oImportedAlgorithms
1020 && m_oImportedAlgorithms->nImportedStartKeyAlgorithm == xml::crypto::DigestID::SHA1)
1022 SAL_WARN("package", "ZipPackageStream::getDataStream(): SHA1 mismatch, trying fallbacks...");
1024 { // tdf#114939 try with legacy StarOffice SHA1 bug
1025 xResult = m_rZipPackage.getZipFile().getDataStream(aEntry,
1026 GetEncryptionData(Bugs::WrongSHA1), oDecryptedSize,
1027 m_rZipPackage.GetSharedMutexRef());
1028 return xResult;
1030 catch (const packages::WrongPasswordException&)
1032 /* ignore and try next... */
1037 // rhbz#1013844 / fdo#47482 workaround for the encrypted
1038 // OpenOffice.org 1.0 documents generated by Libreoffice <=
1039 // 3.6 with the new encryption format and using SHA256, but
1040 // missing a specified startkey of SHA256
1042 // force SHA256 and see if that works
1043 m_oImportedAlgorithms->nImportedStartKeyAlgorithm = xml::crypto::DigestID::SHA256;
1044 xResult = m_rZipPackage.getZipFile().getDataStream(aEntry,
1045 GetEncryptionData(), oDecryptedSize,
1046 m_rZipPackage.GetSharedMutexRef());
1047 return xResult;
1049 catch (const packages::WrongPasswordException&)
1051 // if that didn't work, restore to SHA1 and trundle through the *other* earlier
1052 // bug fix
1053 m_oImportedAlgorithms->nImportedStartKeyAlgorithm = xml::crypto::DigestID::SHA1;
1056 // workaround for the encrypted documents generated with the old OOo1.x bug.
1057 if ( !m_bUseWinEncoding )
1059 xResult = m_rZipPackage.getZipFile().getDataStream(aEntry,
1060 GetEncryptionData(Bugs::WinEncodingWrongSHA1),
1061 oDecryptedSize, m_rZipPackage.GetSharedMutexRef());
1062 m_bUseWinEncoding = true;
1064 else
1065 throw;
1067 else
1068 throw;
1070 return xResult;
1072 else if ( m_nStreamMode == PACKAGE_STREAM_RAW )
1073 return ZipFile::StaticGetDataFromRawStream( m_rZipPackage.GetSharedMutexRef(), m_xContext, GetOwnSeekStream(), GetEncryptionData() );
1074 else if ( GetOwnSeekStream().is() )
1076 return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() );
1078 else
1079 return uno::Reference< io::XInputStream >();
1082 uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getRawStream()
1084 // There is no stream attached to this object
1085 if ( m_nStreamMode == PACKAGE_STREAM_NOTSET )
1086 return uno::Reference< io::XInputStream >();
1088 // this method can not be used together with old approach
1089 if ( m_nStreamMode == PACKAGE_STREAM_DETECT )
1090 throw packages::zip::ZipIOException(THROW_WHERE );
1092 if ( IsPackageMember() )
1094 if ( !m_bIsEncrypted || !GetEncryptionData().is() )
1095 throw packages::NoEncryptionException(THROW_WHERE );
1097 return m_rZipPackage.getZipFile().getWrappedRawStream(aEntry, GetEncryptionData(),
1098 m_nOwnStreamOrigSize, msMediaType, m_rZipPackage.GetSharedMutexRef());
1100 else if ( GetOwnSeekStream().is() )
1102 if ( m_nStreamMode == PACKAGE_STREAM_RAW )
1104 return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() );
1106 else if ( m_nStreamMode == PACKAGE_STREAM_DATA && m_bToBeEncrypted )
1107 return TryToGetRawFromDataStream( true );
1110 throw packages::NoEncryptionException(THROW_WHERE );
1113 void SAL_CALL ZipPackageStream::setDataStream( const uno::Reference< io::XInputStream >& aStream )
1115 setInputStream( aStream );
1116 m_nStreamMode = PACKAGE_STREAM_DATA;
1119 void SAL_CALL ZipPackageStream::setRawStream( const uno::Reference< io::XInputStream >& aStream )
1121 // wrap the stream in case it is not seekable
1122 uno::Reference< io::XInputStream > xNewStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( aStream, m_xContext );
1123 uno::Reference< io::XSeekable > xSeek( xNewStream, UNO_QUERY_THROW );
1124 xSeek->seek( 0 );
1125 uno::Reference< io::XInputStream > xOldStream = m_xStream;
1126 m_xStream = std::move(xNewStream);
1127 if ( !ParsePackageRawStream() )
1129 m_xStream = std::move(xOldStream);
1130 throw packages::NoRawFormatException(THROW_WHERE );
1133 // the raw stream MUST have seekable access
1134 m_bHasSeekable = true;
1136 SetPackageMember ( false );
1137 aEntry.nTime = -1;
1138 m_nStreamMode = PACKAGE_STREAM_RAW;
1141 uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getPlainRawStream()
1143 // There is no stream attached to this object
1144 if ( m_nStreamMode == PACKAGE_STREAM_NOTSET )
1145 return uno::Reference< io::XInputStream >();
1147 // this method can not be used together with old approach
1148 if ( m_nStreamMode == PACKAGE_STREAM_DETECT )
1149 throw packages::zip::ZipIOException(THROW_WHERE );
1151 if ( IsPackageMember() )
1153 ::std::optional<sal_Int64> oDecryptedSize;
1154 if (m_bIsEncrypted)
1156 oDecryptedSize.emplace(m_nOwnStreamOrigSize);
1158 return m_rZipPackage.getZipFile().getRawData(aEntry, GetEncryptionData(),
1159 oDecryptedSize, m_rZipPackage.GetSharedMutexRef());
1161 else if ( GetOwnSeekStream().is() )
1163 if ( m_nStreamMode == PACKAGE_STREAM_RAW )
1165 // the header should not be returned here
1166 return GetRawEncrStreamNoHeaderCopy();
1168 else if ( m_nStreamMode == PACKAGE_STREAM_DATA )
1169 return TryToGetRawFromDataStream( false );
1172 return uno::Reference< io::XInputStream >();
1175 // XPropertySet
1176 void SAL_CALL ZipPackageStream::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
1178 if ( aPropertyName == "MediaType" )
1180 if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE && m_rZipPackage.getFormat() != embed::StorageFormats::OFOPXML )
1181 throw beans::PropertyVetoException(THROW_WHERE );
1183 if ( !(aValue >>= msMediaType) )
1184 throw IllegalArgumentException(THROW_WHERE "MediaType must be a string!",
1185 uno::Reference< XInterface >(),
1186 2 );
1188 if ( !msMediaType.isEmpty() )
1190 if ( msMediaType.indexOf ( "text" ) != -1
1191 || msMediaType == "application/vnd.sun.star.oleobject" )
1192 m_bToBeCompressed = true;
1193 else if ( !m_bCompressedIsSetFromOutside )
1194 m_bToBeCompressed = false;
1197 else if ( aPropertyName == "Size" )
1199 if (!(aValue >>= m_nOwnStreamOrigSize))
1200 throw IllegalArgumentException(THROW_WHERE "Wrong type for Size property!",
1201 uno::Reference< XInterface >(),
1202 2 );
1204 else if ( aPropertyName == "Encrypted" )
1206 if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE )
1207 throw beans::PropertyVetoException(THROW_WHERE );
1209 bool bEnc = false;
1210 if ( !(aValue >>= bEnc) )
1211 throw IllegalArgumentException(THROW_WHERE "Wrong type for Encrypted property!",
1212 uno::Reference< XInterface >(),
1213 2 );
1215 // In case of new raw stream, the stream must not be encrypted on storing
1216 if ( bEnc && m_nStreamMode == PACKAGE_STREAM_RAW )
1217 throw IllegalArgumentException(THROW_WHERE "Raw stream can not be encrypted on storing",
1218 uno::Reference< XInterface >(),
1219 2 );
1221 m_bToBeEncrypted = bEnc;
1222 if ( m_bToBeEncrypted && !m_xBaseEncryptionData.is() )
1223 m_xBaseEncryptionData = new BaseEncryptionData;
1226 else if ( aPropertyName == ENCRYPTION_KEY_PROPERTY )
1228 if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE )
1229 throw beans::PropertyVetoException(THROW_WHERE );
1231 uno::Sequence< sal_Int8 > aNewKey;
1233 if ( !( aValue >>= aNewKey ) )
1235 OUString sTempString;
1236 if ( !(aValue >>= sTempString) )
1237 throw IllegalArgumentException(THROW_WHERE "Wrong type for EncryptionKey property!",
1238 uno::Reference< XInterface >(),
1239 2 );
1241 sal_Int32 nPathLength = sTempString.getLength();
1242 Sequence < sal_Int8 > aSequence ( nPathLength );
1243 sal_Int8 *pArray = aSequence.getArray();
1244 const sal_Unicode *pChar = sTempString.getStr();
1245 for ( sal_Int32 i = 0; i < nPathLength; i++ )
1246 pArray[i] = static_cast < sal_Int8 > ( pChar[i] );
1247 aNewKey = std::move(aSequence);
1250 if ( aNewKey.hasElements() )
1252 if ( !m_xBaseEncryptionData.is() )
1253 m_xBaseEncryptionData = new BaseEncryptionData;
1255 m_aEncryptionKey = std::move(aNewKey);
1256 // In case of new raw stream, the stream must not be encrypted on storing
1257 m_bHaveOwnKey = true;
1258 if ( m_nStreamMode != PACKAGE_STREAM_RAW )
1259 m_bToBeEncrypted = true;
1261 else
1263 m_bHaveOwnKey = false;
1264 m_aEncryptionKey.realloc( 0 );
1267 m_aStorageEncryptionKeys.realloc( 0 );
1269 else if ( aPropertyName == STORAGE_ENCRYPTION_KEYS_PROPERTY )
1271 if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE )
1272 throw beans::PropertyVetoException(THROW_WHERE );
1274 uno::Sequence< beans::NamedValue > aKeys;
1275 if ( !( aValue >>= aKeys ) )
1277 throw IllegalArgumentException(THROW_WHERE "Wrong type for StorageEncryptionKeys property!",
1278 uno::Reference< XInterface >(),
1279 2 );
1282 if ( aKeys.hasElements() )
1284 if ( !m_xBaseEncryptionData.is() )
1285 m_xBaseEncryptionData = new BaseEncryptionData;
1287 m_aStorageEncryptionKeys = std::move(aKeys);
1289 // In case of new raw stream, the stream must not be encrypted on storing
1290 m_bHaveOwnKey = true;
1291 if ( m_nStreamMode != PACKAGE_STREAM_RAW )
1292 m_bToBeEncrypted = true;
1294 else
1296 m_bHaveOwnKey = false;
1297 m_aStorageEncryptionKeys.realloc( 0 );
1300 m_aEncryptionKey.realloc( 0 );
1302 else if ( aPropertyName == "Compressed" )
1304 bool bCompr = false;
1306 if ( !(aValue >>= bCompr) )
1307 throw IllegalArgumentException(THROW_WHERE "Wrong type for Compressed property!",
1308 uno::Reference< XInterface >(),
1309 2 );
1311 // In case of new raw stream, the stream must not be encrypted on storing
1312 if ( bCompr && m_nStreamMode == PACKAGE_STREAM_RAW )
1313 throw IllegalArgumentException(THROW_WHERE "Raw stream can not be encrypted on storing",
1314 uno::Reference< XInterface >(),
1315 2 );
1317 m_bToBeCompressed = bCompr;
1318 m_bCompressedIsSetFromOutside = true;
1320 else
1321 throw beans::UnknownPropertyException(aPropertyName);
1324 Any SAL_CALL ZipPackageStream::getPropertyValue( const OUString& PropertyName )
1326 if ( PropertyName == "MediaType" )
1328 return Any(msMediaType);
1330 else if ( PropertyName == "Size" )
1332 return Any(m_nOwnStreamOrigSize);
1334 else if ( PropertyName == "Encrypted" )
1336 return Any((m_nStreamMode == PACKAGE_STREAM_RAW) || m_bToBeEncrypted);
1338 else if ( PropertyName == "WasEncrypted" )
1340 return Any(m_bIsEncrypted);
1342 else if ( PropertyName == "Compressed" )
1344 return Any(m_bToBeCompressed);
1346 else if ( PropertyName == ENCRYPTION_KEY_PROPERTY )
1348 return Any(m_aEncryptionKey);
1350 else if ( PropertyName == STORAGE_ENCRYPTION_KEYS_PROPERTY )
1352 return Any(m_aStorageEncryptionKeys);
1354 else
1355 throw beans::UnknownPropertyException(PropertyName);
1358 void ZipPackageStream::setSize ( const sal_Int64 nNewSize )
1360 m_nOwnStreamOrigSize = nNewSize;
1363 OUString ZipPackageStream::getImplementationName()
1365 return u"ZipPackageStream"_ustr;
1368 Sequence< OUString > ZipPackageStream::getSupportedServiceNames()
1370 return { u"com.sun.star.packages.PackageStream"_ustr };
1373 sal_Bool SAL_CALL ZipPackageStream::supportsService( OUString const & rServiceName )
1375 return cppu::supportsService(this, rServiceName);
1378 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */