1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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>
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
;
72 #if OSL_DEBUG_LEVEL > 0
73 #define THROW_WHERE SAL_WHERE
75 #define THROW_WHERE ""
78 ZipPackageStream::ZipPackageStream ( ZipPackage
& rNewPackage
,
79 const uno::Reference
< XComponentContext
>& xContext
,
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
;
98 mbAllowRemoveOnInsert
= bAllowRemoveOnInsert
;
100 aEntry
.nVersion
= -1;
105 aEntry
.nCompressedSize
= -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;
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
);
165 throw ZipIOException(THROW_WHERE
"The stream must be seekable!" );
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 );
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
:
196 case css::xml::crypto::CipherID::AES_CBC_W3C_PADDING
:
198 case css::xml::crypto::CipherID::AES_GCM_W3C
:
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(),
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
;
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!" );
253 aResult
= m_aEncryptionKey
;
255 if ( !aResult
.hasElements() || !m_bHaveOwnKey
)
256 aResult
= m_rZipPackage
.GetEncryptionKey();
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();
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();
336 // close raw stream, package stream and folder
339 xNewPackStream
.clear();
340 xRootNameContainer
.clear();
342 // return the stream representing the first temporary file
345 catch ( RuntimeException
& )
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() )
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
;
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
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
;
421 // the provided stream is not a raw stream
425 m_xBaseEncryptionData
= std::move(xTempEncrData
);
426 SetIsEncrypted ( true );
427 // it's already compressed and encrypted
428 m_bToBeEncrypted
= m_bToBeCompressed
= false;
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
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
)
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
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
509 uno::Reference
< io::XSeekable
> xSeek ( xStream
, uno::UNO_QUERY
);
511 bUseNonSeekableAccess
= ( xStream
.is() && !xSeek
.is() );
514 if ( !bUseNonSeekableAccess
)
516 xStream
= getRawData();
520 OSL_FAIL( "ZipPackageStream didn't have a stream associated with it, skipping!" );
524 uno::Reference
< io::XSeekable
> xSeek ( xStream
, uno::UNO_QUERY
);
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();
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
;
573 catch ( uno::Exception
& )
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
);
601 setIterationCount(oPBKDF2IterationCount
);
602 setArgon2Args(oArgon2Args
);
605 // last property is digest, which is inserted later if we didn't have
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
;
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();
682 // Make sure that we actually _got_ a new one !
690 xStream
->skipBytes( m_nMagicalHackPos
);
692 ZipOutputStream::setEntry(*pTempEntry
);
693 rZipOut
.writeLOC(std::move(pAutoTempEntry
));
695 uno::Sequence
< sal_Int8
> aSeq ( n_ConstBufferSize
);
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
& )
714 catch ( io::IOException
& )
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();
736 // Make sure that we actually _got_ a new one !
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
);
759 ZipOutputStream::setEntry(*pTempEntry
);
760 // the entry is provided to the ZipOutputStream that will delete it
762 if (pTempEntry
->nMethod
== STORED
)
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
);
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
) );
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
& )
828 catch ( io::IOException
& )
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
);
874 void ZipPackageStream::successfullyWritten( ZipEntry
const *pEntry
)
876 if ( !IsPackageMember() )
878 if ( m_xStream
.is() )
880 m_xStream
->closeInput();
882 m_bHasSeekable
= false;
884 SetPackageMember ( true );
889 // the raw stream was integrated and now behaves
890 // as usual encrypted stream
891 SetToBeEncrypted( true );
894 // Then copy it back afterwards...
897 aEntry
.nOffset
*= -1;
900 void ZipPackageStream::SetPackageMember( bool 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
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
916 m_oImportedAlgorithms
.reset();
917 m_bHasSeekable
= false;
918 SetPackageMember ( false );
920 m_nStreamMode
= PACKAGE_STREAM_DETECT
;
923 uno::Reference
< io::XInputStream
> ZipPackageStream::getRawData()
927 if ( IsPackageMember() )
929 ::std::optional
<sal_Int64
> oDecryptedSize
;
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() );
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
;
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() );
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
;
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());
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());
1049 catch (const packages::WrongPasswordException
&)
1051 // if that didn't work, restore to SHA1 and trundle through the *other* earlier
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;
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() );
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
);
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 );
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
;
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
>();
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
>(),
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
>(),
1204 else if ( aPropertyName
== "Encrypted" )
1206 if ( m_rZipPackage
.getFormat() != embed::StorageFormats::PACKAGE
)
1207 throw beans::PropertyVetoException(THROW_WHERE
);
1210 if ( !(aValue
>>= bEnc
) )
1211 throw IllegalArgumentException(THROW_WHERE
"Wrong type for Encrypted property!",
1212 uno::Reference
< XInterface
>(),
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
>(),
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
>(),
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;
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
>(),
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;
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
>(),
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
>(),
1317 m_bToBeCompressed
= bCompr
;
1318 m_bCompressedIsSetFromOutside
= true;
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
);
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: */