Version 6.1.4.1, tag libreoffice-6.1.4.1
[LibreOffice.git] / package / source / zippackage / ZipPackageStream.cxx
blob908a093cb62d45eaa2b9bca20b8749a4147c3566
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 <memory>
21 #include <ZipPackageStream.hxx>
23 #include <com/sun/star/beans/PropertyValue.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/io/TempFile.hpp>
29 #include <com/sun/star/io/XInputStream.hpp>
30 #include <com/sun/star/io/XOutputStream.hpp>
31 #include <com/sun/star/io/XStream.hpp>
32 #include <com/sun/star/io/XSeekable.hpp>
33 #include <com/sun/star/xml/crypto/DigestID.hpp>
34 #include <com/sun/star/xml/crypto/CipherID.hpp>
36 #include <string.h>
38 #include <CRC32.hxx>
39 #include <ZipOutputEntry.hxx>
40 #include <ZipOutputStream.hxx>
41 #include <ZipPackage.hxx>
42 #include <ZipPackageFolder.hxx>
43 #include <ZipFile.hxx>
44 #include <EncryptedDataHeader.hxx>
45 #include <osl/diagnose.h>
46 #include "wrapstreamforshare.hxx"
48 #include <comphelper/seekableinput.hxx>
49 #include <comphelper/storagehelper.hxx>
50 #include <cppuhelper/exc_hlp.hxx>
51 #include <cppuhelper/supportsservice.hxx>
52 #include <cppuhelper/typeprovider.hxx>
54 #include <rtl/instance.hxx>
55 #include <rtl/random.h>
57 #include <PackageConstants.hxx>
59 #include <algorithm>
60 #include <thread>
62 using namespace com::sun::star::packages::zip::ZipConstants;
63 using namespace com::sun::star::packages::zip;
64 using namespace com::sun::star::uno;
65 using namespace com::sun::star::lang;
66 using namespace com::sun::star;
67 using namespace cppu;
69 #if OSL_DEBUG_LEVEL > 0
70 #define THROW_WHERE SAL_WHERE
71 #else
72 #define THROW_WHERE ""
73 #endif
75 namespace { struct lcl_CachedImplId : public rtl::Static< cppu::OImplementationId, lcl_CachedImplId > {}; }
77 css::uno::Sequence < sal_Int8 > ZipPackageStream::static_getImplementationId()
79 return lcl_CachedImplId::get().getImplementationId();
82 ZipPackageStream::ZipPackageStream ( ZipPackage & rNewPackage,
83 const uno::Reference< XComponentContext >& xContext,
84 sal_Int32 nFormat,
85 bool bAllowRemoveOnInsert )
86 : m_rZipPackage( rNewPackage )
87 , m_bToBeCompressed ( true )
88 , m_bToBeEncrypted ( false )
89 , m_bHaveOwnKey ( false )
90 , m_bIsEncrypted ( false )
91 , m_nImportedStartKeyAlgorithm( 0 )
92 , m_nImportedEncryptionAlgorithm( 0 )
93 , m_nImportedChecksumAlgorithm( 0 )
94 , m_nImportedDerivedKeySize( 0 )
95 , m_nStreamMode( PACKAGE_STREAM_NOTSET )
96 , m_nMagicalHackPos( 0 )
97 , m_nMagicalHackSize( 0 )
98 , m_nOwnStreamOrigSize( 0 )
99 , m_bHasSeekable( false )
100 , m_bCompressedIsSetFromOutside( false )
101 , m_bFromManifest( false )
102 , m_bUseWinEncoding( false )
103 , m_bRawStream( false )
105 m_xContext = xContext;
106 m_nFormat = nFormat;
107 mbAllowRemoveOnInsert = bAllowRemoveOnInsert;
108 SetFolder ( false );
109 aEntry.nVersion = -1;
110 aEntry.nFlag = 0;
111 aEntry.nMethod = -1;
112 aEntry.nTime = -1;
113 aEntry.nCrc = -1;
114 aEntry.nCompressedSize = -1;
115 aEntry.nSize = -1;
116 aEntry.nOffset = -1;
117 aEntry.nPathLen = -1;
118 aEntry.nExtraLen = -1;
121 ZipPackageStream::~ZipPackageStream()
125 void ZipPackageStream::setZipEntryOnLoading( const ZipEntry &rInEntry )
127 aEntry.nVersion = rInEntry.nVersion;
128 aEntry.nFlag = rInEntry.nFlag;
129 aEntry.nMethod = rInEntry.nMethod;
130 aEntry.nTime = rInEntry.nTime;
131 aEntry.nCrc = rInEntry.nCrc;
132 aEntry.nCompressedSize = rInEntry.nCompressedSize;
133 aEntry.nSize = rInEntry.nSize;
134 aEntry.nOffset = rInEntry.nOffset;
135 aEntry.sPath = rInEntry.sPath;
136 aEntry.nPathLen = rInEntry.nPathLen;
137 aEntry.nExtraLen = rInEntry.nExtraLen;
139 if ( aEntry.nMethod == STORED )
140 m_bToBeCompressed = false;
143 uno::Reference< io::XInputStream > const & ZipPackageStream::GetOwnSeekStream()
145 if ( !m_bHasSeekable && m_xStream.is() )
147 // The package component requires that every stream either be FROM a package or it must support XSeekable!
148 // The only exception is a nonseekable stream that is provided only for storing, if such a stream
149 // is accessed before commit it MUST be wrapped.
150 // Wrap the stream in case it is not seekable
151 m_xStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( m_xStream, m_xContext );
152 uno::Reference< io::XSeekable > xSeek( m_xStream, UNO_QUERY_THROW );
154 m_bHasSeekable = true;
157 return m_xStream;
160 uno::Reference< io::XInputStream > ZipPackageStream::GetRawEncrStreamNoHeaderCopy()
162 if ( m_nStreamMode != PACKAGE_STREAM_RAW || !GetOwnSeekStream().is() )
163 throw io::IOException(THROW_WHERE );
165 if ( m_xBaseEncryptionData.is() )
166 throw ZipIOException(THROW_WHERE "Encrypted stream without encryption data!" );
168 uno::Reference< io::XSeekable > xSeek( GetOwnSeekStream(), UNO_QUERY );
169 if ( !xSeek.is() )
170 throw ZipIOException(THROW_WHERE "The stream must be seekable!" );
172 // skip header
173 xSeek->seek( n_ConstHeaderSize + m_xBaseEncryptionData->m_aInitVector.getLength() +
174 m_xBaseEncryptionData->m_aSalt.getLength() + m_xBaseEncryptionData->m_aDigest.getLength() );
176 // create temporary stream
177 uno::Reference < io::XTempFile > xTempFile = io::TempFile::create(m_xContext);
178 uno::Reference < io::XOutputStream > xTempOut = xTempFile->getOutputStream();
179 uno::Reference < io::XInputStream > xTempIn = xTempFile->getInputStream();
180 uno::Reference < io::XSeekable > xTempSeek( xTempOut, UNO_QUERY_THROW );
182 // copy the raw stream to the temporary file starting from the current position
183 ::comphelper::OStorageHelper::CopyInputToOutput( GetOwnSeekStream(), xTempOut );
184 xTempOut->closeOutput();
185 xTempSeek->seek( 0 );
187 return xTempIn;
190 sal_Int32 ZipPackageStream::GetEncryptionAlgorithm() const
192 return m_nImportedEncryptionAlgorithm ? m_nImportedEncryptionAlgorithm : m_rZipPackage.GetEncAlgID();
195 sal_Int32 ZipPackageStream::GetBlockSize() const
197 return GetEncryptionAlgorithm() == css::xml::crypto::CipherID::AES_CBC_W3C_PADDING ? 16 : 8;
200 ::rtl::Reference<EncryptionData> ZipPackageStream::GetEncryptionData(Bugs const bugs)
202 ::rtl::Reference< EncryptionData > xResult;
203 if ( m_xBaseEncryptionData.is() )
204 xResult = new EncryptionData(
205 *m_xBaseEncryptionData,
206 GetEncryptionKey(bugs),
207 GetEncryptionAlgorithm(),
208 m_nImportedChecksumAlgorithm ? m_nImportedChecksumAlgorithm : m_rZipPackage.GetChecksumAlgID(),
209 m_nImportedDerivedKeySize ? m_nImportedDerivedKeySize : m_rZipPackage.GetDefaultDerivedKeySize(),
210 GetStartKeyGenID(),
211 bugs != Bugs::None);
213 return xResult;
216 uno::Sequence<sal_Int8> ZipPackageStream::GetEncryptionKey(Bugs const bugs)
218 uno::Sequence< sal_Int8 > aResult;
219 sal_Int32 nKeyGenID = GetStartKeyGenID();
220 bool const bUseWinEncoding = (bugs == Bugs::WinEncodingWrongSHA1 || m_bUseWinEncoding);
222 if ( m_bHaveOwnKey && m_aStorageEncryptionKeys.getLength() )
224 OUString aNameToFind;
225 if ( nKeyGenID == xml::crypto::DigestID::SHA256 )
226 aNameToFind = PACKAGE_ENCRYPTIONDATA_SHA256UTF8;
227 else if ( nKeyGenID == xml::crypto::DigestID::SHA1 )
229 aNameToFind = bUseWinEncoding
230 ? OUString(PACKAGE_ENCRYPTIONDATA_SHA1MS1252)
231 : (bugs == Bugs::WrongSHA1)
232 ? OUString(PACKAGE_ENCRYPTIONDATA_SHA1UTF8)
233 : OUString(PACKAGE_ENCRYPTIONDATA_SHA1CORRECT);
235 else
236 throw uno::RuntimeException(THROW_WHERE "No expected key is provided!" );
238 for ( sal_Int32 nInd = 0; nInd < m_aStorageEncryptionKeys.getLength(); nInd++ )
239 if ( m_aStorageEncryptionKeys[nInd].Name == aNameToFind )
240 m_aStorageEncryptionKeys[nInd].Value >>= aResult;
242 // empty keys are not allowed here
243 // so it is not important whether there is no key, or the key is empty, it is an error
244 if ( !aResult.getLength() )
245 throw uno::RuntimeException(THROW_WHERE "No expected key is provided!" );
247 else
248 aResult = m_aEncryptionKey;
250 if ( !aResult.getLength() || !m_bHaveOwnKey )
251 aResult = m_rZipPackage.GetEncryptionKey();
253 return aResult;
256 sal_Int32 ZipPackageStream::GetStartKeyGenID()
258 // generally should all the streams use the same Start Key
259 // but if raw copy without password takes place, we should preserve the imported algorithm
260 return m_nImportedStartKeyAlgorithm ? m_nImportedStartKeyAlgorithm : m_rZipPackage.GetStartKeyGenID();
263 uno::Reference< io::XInputStream > ZipPackageStream::TryToGetRawFromDataStream( bool bAddHeaderForEncr )
265 if ( m_nStreamMode != PACKAGE_STREAM_DATA || !GetOwnSeekStream().is() || ( bAddHeaderForEncr && !m_bToBeEncrypted ) )
266 throw packages::NoEncryptionException(THROW_WHERE );
268 Sequence< sal_Int8 > aKey;
270 if ( m_bToBeEncrypted )
272 aKey = GetEncryptionKey();
273 if ( !aKey.getLength() )
274 throw packages::NoEncryptionException(THROW_WHERE );
279 // create temporary file
280 uno::Reference < io::XStream > xTempStream(
281 io::TempFile::create(m_xContext),
282 uno::UNO_QUERY_THROW );
284 // create a package based on it
285 ZipPackage* pPackage = new ZipPackage( m_xContext );
286 uno::Reference< XSingleServiceFactory > xPackageAsFactory( static_cast< XSingleServiceFactory* >( pPackage ) );
287 if ( !xPackageAsFactory.is() )
288 throw RuntimeException(THROW_WHERE );
290 Sequence< Any > aArgs( 1 );
291 aArgs[0] <<= xTempStream;
292 pPackage->initialize( aArgs );
294 // create a new package stream
295 uno::Reference< XDataSinkEncrSupport > xNewPackStream( xPackageAsFactory->createInstance(), UNO_QUERY_THROW );
296 xNewPackStream->setDataStream( static_cast< io::XInputStream* >(
297 new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() ) ) );
299 uno::Reference< XPropertySet > xNewPSProps( xNewPackStream, UNO_QUERY_THROW );
301 // copy all the properties of this stream to the new stream
302 xNewPSProps->setPropertyValue("MediaType", makeAny( msMediaType ) );
303 xNewPSProps->setPropertyValue("Compressed", makeAny( m_bToBeCompressed ) );
304 if ( m_bToBeEncrypted )
306 xNewPSProps->setPropertyValue(ENCRYPTION_KEY_PROPERTY, makeAny( aKey ) );
307 xNewPSProps->setPropertyValue("Encrypted", makeAny( true ) );
310 // insert a new stream in the package
311 uno::Reference< XUnoTunnel > xTunnel;
312 Any aRoot = pPackage->getByHierarchicalName("/");
313 aRoot >>= xTunnel;
314 uno::Reference< container::XNameContainer > xRootNameContainer( xTunnel, UNO_QUERY_THROW );
316 uno::Reference< XUnoTunnel > xNPSTunnel( xNewPackStream, UNO_QUERY );
317 xRootNameContainer->insertByName("dummy", makeAny( xNPSTunnel ) );
319 // commit the temporary package
320 pPackage->commitChanges();
322 // get raw stream from the temporary package
323 uno::Reference< io::XInputStream > xInRaw;
324 if ( bAddHeaderForEncr )
325 xInRaw = xNewPackStream->getRawStream();
326 else
327 xInRaw = xNewPackStream->getPlainRawStream();
329 // create another temporary file
330 uno::Reference < io::XOutputStream > xTempOut(
331 io::TempFile::create(m_xContext),
332 uno::UNO_QUERY_THROW );
333 uno::Reference < io::XInputStream > xTempIn( xTempOut, UNO_QUERY_THROW );
334 uno::Reference < io::XSeekable > xTempSeek( xTempOut, UNO_QUERY_THROW );
336 // copy the raw stream to the temporary file
337 ::comphelper::OStorageHelper::CopyInputToOutput( xInRaw, xTempOut );
338 xTempOut->closeOutput();
339 xTempSeek->seek( 0 );
341 // close raw stream, package stream and folder
342 xInRaw.clear();
343 xNewPSProps.clear();
344 xNPSTunnel.clear();
345 xNewPackStream.clear();
346 xTunnel.clear();
347 xRootNameContainer.clear();
349 // return the stream representing the first temporary file
350 return xTempIn;
352 catch ( RuntimeException& )
354 throw;
356 catch ( Exception& )
360 throw io::IOException(THROW_WHERE );
363 bool ZipPackageStream::ParsePackageRawStream()
365 OSL_ENSURE( GetOwnSeekStream().is(), "A stream must be provided!" );
367 if ( !GetOwnSeekStream().is() )
368 return false;
370 bool bOk = false;
372 ::rtl::Reference< BaseEncryptionData > xTempEncrData;
373 sal_Int32 nMagHackSize = 0;
374 Sequence < sal_Int8 > aHeader ( 4 );
378 if ( GetOwnSeekStream()->readBytes ( aHeader, 4 ) == 4 )
380 const sal_Int8 *pHeader = aHeader.getConstArray();
381 sal_uInt32 nHeader = ( pHeader [0] & 0xFF ) |
382 ( pHeader [1] & 0xFF ) << 8 |
383 ( pHeader [2] & 0xFF ) << 16 |
384 ( pHeader [3] & 0xFF ) << 24;
385 if ( nHeader == n_ConstHeader )
387 // this is one of our god-awful, but extremely devious hacks, everyone cheer
388 xTempEncrData = new BaseEncryptionData;
390 OUString aMediaType;
391 sal_Int32 nEncAlgorithm = 0;
392 sal_Int32 nChecksumAlgorithm = 0;
393 sal_Int32 nDerivedKeySize = 0;
394 sal_Int32 nStartKeyGenID = 0;
395 if ( ZipFile::StaticFillData( xTempEncrData, nEncAlgorithm, nChecksumAlgorithm, nDerivedKeySize, nStartKeyGenID, nMagHackSize, aMediaType, GetOwnSeekStream() ) )
397 // We'll want to skip the data we've just read, so calculate how much we just read
398 // and remember it
399 m_nMagicalHackPos = n_ConstHeaderSize + xTempEncrData->m_aSalt.getLength()
400 + xTempEncrData->m_aInitVector.getLength()
401 + xTempEncrData->m_aDigest.getLength()
402 + aMediaType.getLength() * sizeof( sal_Unicode );
403 m_nImportedEncryptionAlgorithm = nEncAlgorithm;
404 m_nImportedChecksumAlgorithm = nChecksumAlgorithm;
405 m_nImportedDerivedKeySize = nDerivedKeySize;
406 m_nImportedStartKeyAlgorithm = nStartKeyGenID;
407 m_nMagicalHackSize = 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 = xTempEncrData;
426 SetIsEncrypted ( true );
427 // it's already compressed and encrypted
428 m_bToBeEncrypted = m_bToBeCompressed = false;
430 return true;
433 static void deflateZipEntry(ZipOutputEntry *pZipEntry,
434 const uno::Reference< io::XInputStream >& xInStream)
436 sal_Int32 nLength = 0;
437 uno::Sequence< sal_Int8 > aSeq(n_ConstBufferSize);
440 nLength = xInStream->readBytes(aSeq, n_ConstBufferSize);
441 if (nLength != n_ConstBufferSize)
442 aSeq.realloc(nLength);
444 pZipEntry->write(aSeq);
446 while (nLength == n_ConstBufferSize);
447 pZipEntry->closeEntry();
450 class DeflateThread: public comphelper::ThreadTask
452 ZipOutputEntry *mpEntry;
453 uno::Reference< io::XInputStream > mxInStream;
455 public:
456 DeflateThread( const std::shared_ptr<comphelper::ThreadTaskTag>& pTag, ZipOutputEntry *pEntry,
457 const uno::Reference< io::XInputStream >& xInStream )
458 : comphelper::ThreadTask(pTag)
459 , mpEntry(pEntry)
460 , mxInStream(xInStream)
463 private:
464 virtual void doWork() override
468 mpEntry->createBufferFile();
469 deflateZipEntry(mpEntry, mxInStream);
470 mxInStream.clear();
471 mpEntry->closeBufferFile();
472 mpEntry->setFinished();
474 catch (const uno::Exception&)
476 mpEntry->setParallelDeflateException(::cppu::getCaughtException());
479 if (mpEntry->m_xOutStream.is())
480 mpEntry->closeBufferFile();
481 if (!mpEntry->m_aTempURL.isEmpty())
482 mpEntry->deleteBufferFile();
484 catch (uno::Exception const&)
487 mpEntry->setFinished();
492 static void ImplSetStoredData( ZipEntry & rEntry, uno::Reference< io::XInputStream> const & rStream )
494 // It's very annoying that we have to do this, but lots of zip packages
495 // don't allow data descriptors for STORED streams, meaning we have to
496 // know the size and CRC32 of uncompressed streams before we actually
497 // write them !
498 CRC32 aCRC32;
499 rEntry.nMethod = STORED;
500 rEntry.nCompressedSize = rEntry.nSize = aCRC32.updateStream ( rStream );
501 rEntry.nCrc = aCRC32.getValue();
504 bool ZipPackageStream::saveChild(
505 const OUString &rPath,
506 std::vector < uno::Sequence < beans::PropertyValue > > &rManList,
507 ZipOutputStream & rZipOut,
508 const uno::Sequence < sal_Int8 >& rEncryptionKey,
509 sal_Int32 nPBKDF2IterationCount,
510 const rtlRandomPool &rRandomPool)
512 bool bSuccess = true;
514 const OUString sMediaTypeProperty ("MediaType");
515 const OUString sVersionProperty ("Version");
516 const OUString sFullPathProperty ("FullPath");
517 const OUString sInitialisationVectorProperty ("InitialisationVector");
518 const OUString sSaltProperty ("Salt");
519 const OUString sIterationCountProperty ("IterationCount");
520 const OUString sSizeProperty ("Size");
521 const OUString sDigestProperty ("Digest");
522 const OUString sEncryptionAlgProperty ("EncryptionAlgorithm");
523 const OUString sStartKeyAlgProperty ("StartKeyAlgorithm");
524 const OUString sDigestAlgProperty ("DigestAlgorithm");
525 const OUString sDerivedKeySizeProperty ("DerivedKeySize");
527 uno::Sequence < beans::PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST);
529 // In case the entry we are reading is also the entry we are writing, we will
530 // store the ZipEntry data in pTempEntry
532 // if pTempEntry is necessary, it will be released and passed to the ZipOutputStream
533 // and be deleted in the ZipOutputStream destructor
534 std::unique_ptr < ZipEntry > pAutoTempEntry ( new ZipEntry(aEntry) );
535 ZipEntry* pTempEntry = pAutoTempEntry.get();
537 pTempEntry->sPath = rPath;
538 pTempEntry->nPathLen = static_cast<sal_Int16>( OUStringToOString( pTempEntry->sPath, RTL_TEXTENCODING_UTF8 ).getLength() );
540 const bool bToBeEncrypted = m_bToBeEncrypted && (rEncryptionKey.getLength() || m_bHaveOwnKey);
541 const bool bToBeCompressed = bToBeEncrypted || m_bToBeCompressed;
543 aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty;
544 aPropSet[PKG_MNFST_MEDIATYPE].Value <<= GetMediaType( );
545 aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
546 aPropSet[PKG_MNFST_VERSION].Value <<= OUString(); // no version is stored for streams currently
547 aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
548 aPropSet[PKG_MNFST_FULLPATH].Value <<= pTempEntry->sPath;
550 OSL_ENSURE( m_nStreamMode != PACKAGE_STREAM_NOTSET, "Unacceptable ZipPackageStream mode!" );
552 m_bRawStream = false;
553 if ( m_nStreamMode == PACKAGE_STREAM_DETECT )
554 m_bRawStream = ParsePackageRawStream();
555 else if ( m_nStreamMode == PACKAGE_STREAM_RAW )
556 m_bRawStream = true;
558 bool bParallelDeflate = false;
559 bool bTransportOwnEncrStreamAsRaw = false;
560 // During the storing the original size of the stream can be changed
561 // TODO/LATER: get rid of this hack
562 m_nOwnStreamOrigSize = m_bRawStream ? m_nMagicalHackSize : aEntry.nSize;
564 bool bUseNonSeekableAccess = false;
565 uno::Reference < io::XInputStream > xStream;
566 if ( !IsPackageMember() && !m_bRawStream && !bToBeEncrypted && bToBeCompressed )
568 // the stream is not a package member, not a raw stream,
569 // it should not be encrypted and it should be compressed,
570 // in this case nonseekable access can be used
572 xStream = m_xStream;
573 uno::Reference < io::XSeekable > xSeek ( xStream, uno::UNO_QUERY );
575 bUseNonSeekableAccess = ( xStream.is() && !xSeek.is() );
578 if ( !bUseNonSeekableAccess )
580 xStream = getRawData();
582 if ( !xStream.is() )
584 OSL_FAIL( "ZipPackageStream didn't have a stream associated with it, skipping!" );
585 bSuccess = false;
586 return bSuccess;
589 uno::Reference < io::XSeekable > xSeek ( xStream, uno::UNO_QUERY );
592 if ( xSeek.is() )
594 // If the stream is a raw one, then we should be positioned
595 // at the beginning of the actual data
596 if ( !bToBeCompressed || m_bRawStream )
598 // The raw stream can neither be encrypted nor connected
599 OSL_ENSURE( !m_bRawStream || !(bToBeCompressed || bToBeEncrypted), "The stream is already encrypted!" );
600 xSeek->seek ( m_bRawStream ? m_nMagicalHackPos : 0 );
601 ImplSetStoredData ( *pTempEntry, xStream );
603 // TODO/LATER: Get rid of hacks related to switching of Flag Method and Size properties!
605 else if ( bToBeEncrypted )
607 // this is the correct original size
608 pTempEntry->nSize = xSeek->getLength();
609 m_nOwnStreamOrigSize = pTempEntry->nSize;
612 xSeek->seek ( 0 );
614 else
616 // Okay, we don't have an xSeekable stream. This is possibly bad.
617 // check if it's one of our own streams, if it is then we know that
618 // each time we ask for it we'll get a new stream that will be
619 // at position zero...otherwise, assert and skip this stream...
620 if ( IsPackageMember() )
622 // if the password has been changed than the stream should not be package member any more
623 if ( m_bIsEncrypted && m_bToBeEncrypted )
625 // Should be handled close to the raw stream handling
626 bTransportOwnEncrStreamAsRaw = true;
627 pTempEntry->nMethod = STORED;
629 // TODO/LATER: get rid of this situation
630 // this size should be different from the one that will be stored in manifest.xml
631 // it is used in storing algorithms and after storing the correct size will be set
632 pTempEntry->nSize = pTempEntry->nCompressedSize;
635 else
637 bSuccess = false;
638 return bSuccess;
642 catch ( uno::Exception& )
644 bSuccess = false;
645 return bSuccess;
648 if ( bToBeEncrypted || m_bRawStream || bTransportOwnEncrStreamAsRaw )
650 if ( bToBeEncrypted && !bTransportOwnEncrStreamAsRaw )
652 uno::Sequence < sal_Int8 > aSalt( 16 ), aVector( GetBlockSize() );
653 rtl_random_getBytes ( rRandomPool, aSalt.getArray(), 16 );
654 rtl_random_getBytes ( rRandomPool, aVector.getArray(), aVector.getLength() );
655 if ( !m_bHaveOwnKey )
657 m_aEncryptionKey = rEncryptionKey;
658 m_aStorageEncryptionKeys.realloc( 0 );
661 setInitialisationVector ( aVector );
662 setSalt ( aSalt );
663 setIterationCount(nPBKDF2IterationCount);
666 // last property is digest, which is inserted later if we didn't have
667 // a magic header
668 aPropSet.realloc(PKG_SIZE_ENCR_MNFST);
670 aPropSet[PKG_MNFST_INIVECTOR].Name = sInitialisationVectorProperty;
671 aPropSet[PKG_MNFST_INIVECTOR].Value <<= m_xBaseEncryptionData->m_aInitVector;
672 aPropSet[PKG_MNFST_SALT].Name = sSaltProperty;
673 aPropSet[PKG_MNFST_SALT].Value <<= m_xBaseEncryptionData->m_aSalt;
674 aPropSet[PKG_MNFST_ITERATION].Name = sIterationCountProperty;
675 aPropSet[PKG_MNFST_ITERATION].Value <<= m_xBaseEncryptionData->m_nIterationCount;
677 // Need to store the uncompressed size in the manifest
678 OSL_ENSURE( m_nOwnStreamOrigSize >= 0, "The stream size was not correctly initialized!" );
679 aPropSet[PKG_MNFST_UCOMPSIZE].Name = sSizeProperty;
680 aPropSet[PKG_MNFST_UCOMPSIZE].Value <<= m_nOwnStreamOrigSize;
682 if ( m_bRawStream || bTransportOwnEncrStreamAsRaw )
684 ::rtl::Reference< EncryptionData > xEncData = GetEncryptionData();
685 if ( !xEncData.is() )
686 throw uno::RuntimeException();
688 aPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
689 aPropSet[PKG_MNFST_DIGEST].Value <<= m_xBaseEncryptionData->m_aDigest;
690 aPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
691 aPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
692 aPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
693 aPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID;
694 aPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
695 aPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg;
696 aPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
697 aPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
702 // If the entry is already stored in the zip file in the format we
703 // want for this write...copy it raw
704 if ( !bUseNonSeekableAccess
705 && ( m_bRawStream || bTransportOwnEncrStreamAsRaw
706 || ( IsPackageMember() && !bToBeEncrypted
707 && ( ( aEntry.nMethod == DEFLATED && bToBeCompressed )
708 || ( aEntry.nMethod == STORED && !bToBeCompressed ) ) ) ) )
710 // If it's a PackageMember, then it's an unbuffered stream and we need
711 // to get a new version of it as we can't seek backwards.
712 if ( IsPackageMember() )
714 xStream = getRawData();
715 if ( !xStream.is() )
717 // Make sure that we actually _got_ a new one !
718 bSuccess = false;
719 return bSuccess;
725 if ( m_bRawStream )
726 xStream->skipBytes( m_nMagicalHackPos );
728 ZipOutputStream::setEntry(pTempEntry);
729 rZipOut.writeLOC(pTempEntry);
730 // the entry is provided to the ZipOutputStream that will delete it
731 pAutoTempEntry.release();
733 uno::Sequence < sal_Int8 > aSeq ( n_ConstBufferSize );
734 sal_Int32 nLength;
738 nLength = xStream->readBytes( aSeq, n_ConstBufferSize );
739 if (nLength != n_ConstBufferSize)
740 aSeq.realloc(nLength);
742 rZipOut.rawWrite(aSeq);
744 while ( nLength == n_ConstBufferSize );
746 rZipOut.rawCloseEntry();
748 catch ( ZipException& )
750 bSuccess = false;
752 catch ( io::IOException& )
754 bSuccess = false;
757 else
759 // This stream is definitely not a raw stream
761 // If nonseekable access is used the stream should be at the beginning and
762 // is useless after the storing. Thus if the storing fails the package should
763 // be thrown away ( as actually it is done currently )!
764 // To allow to reuse the package after the error, the optimization must be removed!
766 // If it's a PackageMember, then our previous reference held a 'raw' stream
767 // so we need to re-get it, unencrypted, uncompressed and positioned at the
768 // beginning of the stream
769 if ( IsPackageMember() )
771 xStream = getInputStream();
772 if ( !xStream.is() )
774 // Make sure that we actually _got_ a new one !
775 bSuccess = false;
776 return bSuccess;
780 if ( bToBeCompressed )
782 pTempEntry->nMethod = DEFLATED;
783 pTempEntry->nCrc = -1;
784 pTempEntry->nCompressedSize = pTempEntry->nSize = -1;
787 uno::Reference< io::XSeekable > xSeek(xStream, uno::UNO_QUERY);
788 // It's not worth to deflate jpegs to save ~1% in a slow process
789 // Unfortunately, does not work for streams protected by password
790 if (xSeek.is() && msMediaType.endsWith("/jpeg") && !m_bToBeEncrypted && !m_bToBeCompressed)
792 ImplSetStoredData(*pTempEntry, xStream);
793 xSeek->seek(0);
798 ZipOutputStream::setEntry(pTempEntry);
799 // the entry is provided to the ZipOutputStream that will delete it
800 pAutoTempEntry.release();
802 if (pTempEntry->nMethod == STORED)
804 sal_Int32 nLength;
805 uno::Sequence< sal_Int8 > aSeq(n_ConstBufferSize);
806 rZipOut.writeLOC(pTempEntry, bToBeEncrypted);
809 nLength = xStream->readBytes(aSeq, n_ConstBufferSize);
810 if (nLength != n_ConstBufferSize)
811 aSeq.realloc(nLength);
813 rZipOut.rawWrite(aSeq);
815 while ( nLength == n_ConstBufferSize );
816 rZipOut.rawCloseEntry(bToBeEncrypted);
818 else
820 // tdf#89236 Encrypting in parallel does not work
821 bParallelDeflate = !bToBeEncrypted;
822 // Do not deflate small streams in a thread
823 if (xSeek.is() && xSeek->getLength() < 100000)
824 bParallelDeflate = false;
826 if (bParallelDeflate)
828 // tdf#93553 limit to a useful amount of threads. Taking number of available
829 // cores and allow 4-times the amount for having the queue well filled. The
830 // 2nd parameter is the time to wait between cleanups in 10th of a second.
831 // Both values may be added to the configuration settings if needed.
832 static sal_Int32 nAllowedThreads(comphelper::ThreadPool::getPreferredConcurrency() * 4);
833 rZipOut.reduceScheduledThreadsToGivenNumberOrLess(nAllowedThreads);
835 // Start a new thread deflating this zip entry
836 ZipOutputEntry *pZipEntry = new ZipOutputEntry(
837 m_xContext, *pTempEntry, this, bToBeEncrypted);
838 rZipOut.addDeflatingThread( pZipEntry, new DeflateThread(rZipOut.getThreadTaskTag(), pZipEntry, xStream) );
840 else
842 rZipOut.writeLOC(pTempEntry, bToBeEncrypted);
843 ZipOutputEntry aZipEntry(rZipOut.getStream(), m_xContext, *pTempEntry, this, bToBeEncrypted);
844 deflateZipEntry(&aZipEntry, xStream);
845 rZipOut.rawCloseEntry(bToBeEncrypted);
849 catch ( ZipException& )
851 bSuccess = false;
853 catch ( io::IOException& )
855 bSuccess = false;
858 if ( bToBeEncrypted )
860 ::rtl::Reference< EncryptionData > xEncData = GetEncryptionData();
861 if ( !xEncData.is() )
862 throw uno::RuntimeException();
864 aPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
865 aPropSet[PKG_MNFST_DIGEST].Value <<= m_xBaseEncryptionData->m_aDigest;
866 aPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
867 aPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
868 aPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
869 aPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID;
870 aPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
871 aPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg;
872 aPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
873 aPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
875 SetIsEncrypted ( true );
879 if (bSuccess && !bParallelDeflate)
880 successfullyWritten(pTempEntry);
882 if ( aPropSet.getLength()
883 && ( m_nFormat == embed::StorageFormats::PACKAGE || m_nFormat == embed::StorageFormats::OFOPXML ) )
884 rManList.push_back( aPropSet );
886 return bSuccess;
889 void ZipPackageStream::successfullyWritten( ZipEntry const *pEntry )
891 if ( !IsPackageMember() )
893 if ( m_xStream.is() )
895 m_xStream->closeInput();
896 m_xStream.clear();
897 m_bHasSeekable = false;
899 SetPackageMember ( true );
902 if ( m_bRawStream )
904 // the raw stream was integrated and now behaves
905 // as usual encrypted stream
906 SetToBeEncrypted( true );
909 // Then copy it back afterwards...
910 aEntry = *pEntry;
912 // TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving )
913 if ( m_bIsEncrypted )
914 setSize( m_nOwnStreamOrigSize );
916 aEntry.nOffset *= -1;
919 void ZipPackageStream::SetPackageMember( bool bNewValue )
921 if ( bNewValue )
923 m_nStreamMode = PACKAGE_STREAM_PACKAGEMEMBER;
924 m_nMagicalHackPos = 0;
925 m_nMagicalHackSize = 0;
927 else if ( m_nStreamMode == PACKAGE_STREAM_PACKAGEMEMBER )
928 m_nStreamMode = PACKAGE_STREAM_NOTSET; // must be reset
931 // XActiveDataSink
932 void SAL_CALL ZipPackageStream::setInputStream( const uno::Reference< io::XInputStream >& aStream )
934 // if seekable access is required the wrapping will be done on demand
935 m_xStream = aStream;
936 m_nImportedEncryptionAlgorithm = 0;
937 m_bHasSeekable = false;
938 SetPackageMember ( false );
939 aEntry.nTime = -1;
940 m_nStreamMode = PACKAGE_STREAM_DETECT;
943 uno::Reference< io::XInputStream > ZipPackageStream::getRawData()
947 if ( IsPackageMember() )
949 return m_rZipPackage.getZipFile().getRawData( aEntry, GetEncryptionData(), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef(), false/*bUseBufferedStream*/ );
951 else if ( GetOwnSeekStream().is() )
953 return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() );
955 else
956 return uno::Reference < io::XInputStream > ();
958 catch ( ZipException & )//rException )
960 OSL_FAIL( "ZipException thrown" );//rException.Message);
961 return uno::Reference < io::XInputStream > ();
963 catch ( Exception & )
965 OSL_FAIL( "Exception is thrown during stream wrapping!" );
966 return uno::Reference < io::XInputStream > ();
970 uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getInputStream()
974 if ( IsPackageMember() )
976 return m_rZipPackage.getZipFile().getInputStream( aEntry, GetEncryptionData(), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() );
978 else if ( GetOwnSeekStream().is() )
980 return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() );
982 else
983 return uno::Reference < io::XInputStream > ();
985 catch ( ZipException & )//rException )
987 OSL_FAIL( "ZipException thrown" );//rException.Message);
988 return uno::Reference < io::XInputStream > ();
990 catch ( Exception &ex )
992 SAL_WARN( "package", "Exception is thrown during stream wrapping!" << ex);
993 return uno::Reference < io::XInputStream > ();
997 // XDataSinkEncrSupport
998 uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getDataStream()
1000 // There is no stream attached to this object
1001 if ( m_nStreamMode == PACKAGE_STREAM_NOTSET )
1002 return uno::Reference< io::XInputStream >();
1004 // this method can not be used together with old approach
1005 if ( m_nStreamMode == PACKAGE_STREAM_DETECT )
1006 throw packages::zip::ZipIOException(THROW_WHERE );
1008 if ( IsPackageMember() )
1010 uno::Reference< io::XInputStream > xResult;
1013 xResult = m_rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData(Bugs::None), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() );
1015 catch( const packages::WrongPasswordException& )
1017 if ( m_rZipPackage.GetStartKeyGenID() == xml::crypto::DigestID::SHA1 )
1019 SAL_WARN("package", "ZipPackageStream::getDataStream(): SHA1 mismatch, trying fallbacks...");
1021 { // tdf#114939 try with legacy StarOffice SHA1 bug
1022 xResult = m_rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData(Bugs::WrongSHA1), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() );
1023 return xResult;
1025 catch (const packages::WrongPasswordException&)
1027 /* ignore and try next... */
1032 // rhbz#1013844 / fdo#47482 workaround for the encrypted
1033 // OpenOffice.org 1.0 documents generated by Libreoffice <=
1034 // 3.6 with the new encryption format and using SHA256, but
1035 // missing a specified startkey of SHA256
1037 // force SHA256 and see if that works
1038 m_nImportedStartKeyAlgorithm = xml::crypto::DigestID::SHA256;
1039 xResult = m_rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData(), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() );
1040 return xResult;
1042 catch (const packages::WrongPasswordException&)
1044 // if that didn't work, restore to SHA1 and trundle through the *other* earlier
1045 // bug fix
1046 m_nImportedStartKeyAlgorithm = xml::crypto::DigestID::SHA1;
1049 // workaround for the encrypted documents generated with the old OOo1.x bug.
1050 if ( !m_bUseWinEncoding )
1052 xResult = m_rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData(Bugs::WinEncodingWrongSHA1), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() );
1053 m_bUseWinEncoding = true;
1055 else
1056 throw;
1058 else
1059 throw;
1061 return xResult;
1063 else if ( m_nStreamMode == PACKAGE_STREAM_RAW )
1064 return ZipFile::StaticGetDataFromRawStream( m_rZipPackage.GetSharedMutexRef(), m_xContext, GetOwnSeekStream(), GetEncryptionData() );
1065 else if ( GetOwnSeekStream().is() )
1067 return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() );
1069 else
1070 return uno::Reference< io::XInputStream >();
1073 uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getRawStream()
1075 // There is no stream attached to this object
1076 if ( m_nStreamMode == PACKAGE_STREAM_NOTSET )
1077 return uno::Reference< io::XInputStream >();
1079 // this method can not be used together with old approach
1080 if ( m_nStreamMode == PACKAGE_STREAM_DETECT )
1081 throw packages::zip::ZipIOException(THROW_WHERE );
1083 if ( IsPackageMember() )
1085 if ( !m_bIsEncrypted || !GetEncryptionData().is() )
1086 throw packages::NoEncryptionException(THROW_WHERE );
1088 return m_rZipPackage.getZipFile().getWrappedRawStream( aEntry, GetEncryptionData(), msMediaType, m_rZipPackage.GetSharedMutexRef() );
1090 else if ( GetOwnSeekStream().is() )
1092 if ( m_nStreamMode == PACKAGE_STREAM_RAW )
1094 return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() );
1096 else if ( m_nStreamMode == PACKAGE_STREAM_DATA && m_bToBeEncrypted )
1097 return TryToGetRawFromDataStream( true );
1100 throw packages::NoEncryptionException(THROW_WHERE );
1103 void SAL_CALL ZipPackageStream::setDataStream( const uno::Reference< io::XInputStream >& aStream )
1105 setInputStream( aStream );
1106 m_nStreamMode = PACKAGE_STREAM_DATA;
1109 void SAL_CALL ZipPackageStream::setRawStream( const uno::Reference< io::XInputStream >& aStream )
1111 // wrap the stream in case it is not seekable
1112 uno::Reference< io::XInputStream > xNewStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( aStream, m_xContext );
1113 uno::Reference< io::XSeekable > xSeek( xNewStream, UNO_QUERY_THROW );
1114 xSeek->seek( 0 );
1115 uno::Reference< io::XInputStream > xOldStream = m_xStream;
1116 m_xStream = xNewStream;
1117 if ( !ParsePackageRawStream() )
1119 m_xStream = xOldStream;
1120 throw packages::NoRawFormatException(THROW_WHERE );
1123 // the raw stream MUST have seekable access
1124 m_bHasSeekable = true;
1126 SetPackageMember ( false );
1127 aEntry.nTime = -1;
1128 m_nStreamMode = PACKAGE_STREAM_RAW;
1131 uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getPlainRawStream()
1133 // There is no stream attached to this object
1134 if ( m_nStreamMode == PACKAGE_STREAM_NOTSET )
1135 return uno::Reference< io::XInputStream >();
1137 // this method can not be used together with old approach
1138 if ( m_nStreamMode == PACKAGE_STREAM_DETECT )
1139 throw packages::zip::ZipIOException(THROW_WHERE );
1141 if ( IsPackageMember() )
1143 return m_rZipPackage.getZipFile().getRawData( aEntry, GetEncryptionData(), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() );
1145 else if ( GetOwnSeekStream().is() )
1147 if ( m_nStreamMode == PACKAGE_STREAM_RAW )
1149 // the header should not be returned here
1150 return GetRawEncrStreamNoHeaderCopy();
1152 else if ( m_nStreamMode == PACKAGE_STREAM_DATA )
1153 return TryToGetRawFromDataStream( false );
1156 return uno::Reference< io::XInputStream >();
1159 // XUnoTunnel
1161 sal_Int64 SAL_CALL ZipPackageStream::getSomething( const Sequence< sal_Int8 >& aIdentifier )
1163 sal_Int64 nMe = 0;
1164 if ( aIdentifier.getLength() == 16 &&
1165 0 == memcmp( static_getImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) )
1166 nMe = reinterpret_cast < sal_Int64 > ( this );
1167 return nMe;
1170 // XPropertySet
1171 void SAL_CALL ZipPackageStream::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
1173 if ( aPropertyName == "MediaType" )
1175 if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE && m_rZipPackage.getFormat() != embed::StorageFormats::OFOPXML )
1176 throw beans::PropertyVetoException(THROW_WHERE );
1178 if ( !(aValue >>= msMediaType) )
1179 throw IllegalArgumentException(THROW_WHERE "MediaType must be a string!",
1180 uno::Reference< XInterface >(),
1181 2 );
1183 if ( !msMediaType.isEmpty() )
1185 if ( msMediaType.indexOf ( "text" ) != -1
1186 || msMediaType == "application/vnd.sun.star.oleobject" )
1187 m_bToBeCompressed = true;
1188 else if ( !m_bCompressedIsSetFromOutside )
1189 m_bToBeCompressed = false;
1192 else if ( aPropertyName == "Size" )
1194 if ( !( aValue >>= aEntry.nSize ) )
1195 throw IllegalArgumentException(THROW_WHERE "Wrong type for Size property!",
1196 uno::Reference< XInterface >(),
1197 2 );
1199 else if ( aPropertyName == "Encrypted" )
1201 if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE )
1202 throw beans::PropertyVetoException(THROW_WHERE );
1204 bool bEnc = false;
1205 if ( !(aValue >>= bEnc) )
1206 throw IllegalArgumentException(THROW_WHERE "Wrong type for Encrypted property!",
1207 uno::Reference< XInterface >(),
1208 2 );
1210 // In case of new raw stream, the stream must not be encrypted on storing
1211 if ( bEnc && m_nStreamMode == PACKAGE_STREAM_RAW )
1212 throw IllegalArgumentException(THROW_WHERE "Raw stream can not be encrypted on storing",
1213 uno::Reference< XInterface >(),
1214 2 );
1216 m_bToBeEncrypted = bEnc;
1217 if ( m_bToBeEncrypted && !m_xBaseEncryptionData.is() )
1218 m_xBaseEncryptionData = new BaseEncryptionData;
1221 else if ( aPropertyName == ENCRYPTION_KEY_PROPERTY )
1223 if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE )
1224 throw beans::PropertyVetoException(THROW_WHERE );
1226 uno::Sequence< sal_Int8 > aNewKey;
1228 if ( !( aValue >>= aNewKey ) )
1230 OUString sTempString;
1231 if ( !(aValue >>= sTempString) )
1232 throw IllegalArgumentException(THROW_WHERE "Wrong type for EncryptionKey property!",
1233 uno::Reference< XInterface >(),
1234 2 );
1236 sal_Int32 nPathLength = sTempString.getLength();
1237 Sequence < sal_Int8 > aSequence ( nPathLength );
1238 sal_Int8 *pArray = aSequence.getArray();
1239 const sal_Unicode *pChar = sTempString.getStr();
1240 for ( sal_Int32 i = 0; i < nPathLength; i++ )
1241 pArray[i] = static_cast < sal_Int8 > ( pChar[i] );
1242 aNewKey = aSequence;
1245 if ( aNewKey.getLength() )
1247 if ( !m_xBaseEncryptionData.is() )
1248 m_xBaseEncryptionData = new BaseEncryptionData;
1250 m_aEncryptionKey = aNewKey;
1251 // In case of new raw stream, the stream must not be encrypted on storing
1252 m_bHaveOwnKey = true;
1253 if ( m_nStreamMode != PACKAGE_STREAM_RAW )
1254 m_bToBeEncrypted = true;
1256 else
1258 m_bHaveOwnKey = false;
1259 m_aEncryptionKey.realloc( 0 );
1262 m_aStorageEncryptionKeys.realloc( 0 );
1264 else if ( aPropertyName == STORAGE_ENCRYPTION_KEYS_PROPERTY )
1266 if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE )
1267 throw beans::PropertyVetoException(THROW_WHERE );
1269 uno::Sequence< beans::NamedValue > aKeys;
1270 if ( !( aValue >>= aKeys ) )
1272 throw IllegalArgumentException(THROW_WHERE "Wrong type for StorageEncryptionKeys property!",
1273 uno::Reference< XInterface >(),
1274 2 );
1277 if ( aKeys.getLength() )
1279 if ( !m_xBaseEncryptionData.is() )
1280 m_xBaseEncryptionData = new BaseEncryptionData;
1282 m_aStorageEncryptionKeys = aKeys;
1284 // In case of new raw stream, the stream must not be encrypted on storing
1285 m_bHaveOwnKey = true;
1286 if ( m_nStreamMode != PACKAGE_STREAM_RAW )
1287 m_bToBeEncrypted = true;
1289 else
1291 m_bHaveOwnKey = false;
1292 m_aStorageEncryptionKeys.realloc( 0 );
1295 m_aEncryptionKey.realloc( 0 );
1297 else if ( aPropertyName == "Compressed" )
1299 bool bCompr = false;
1301 if ( !(aValue >>= bCompr) )
1302 throw IllegalArgumentException(THROW_WHERE "Wrong type for Compressed property!",
1303 uno::Reference< XInterface >(),
1304 2 );
1306 // In case of new raw stream, the stream must not be encrypted on storing
1307 if ( bCompr && m_nStreamMode == PACKAGE_STREAM_RAW )
1308 throw IllegalArgumentException(THROW_WHERE "Raw stream can not be encrypted on storing",
1309 uno::Reference< XInterface >(),
1310 2 );
1312 m_bToBeCompressed = bCompr;
1313 m_bCompressedIsSetFromOutside = true;
1315 else
1316 throw beans::UnknownPropertyException(THROW_WHERE );
1319 Any SAL_CALL ZipPackageStream::getPropertyValue( const OUString& PropertyName )
1321 if ( PropertyName == "MediaType" )
1323 return Any(msMediaType);
1325 else if ( PropertyName == "Size" )
1327 return Any(aEntry.nSize);
1329 else if ( PropertyName == "Encrypted" )
1331 return Any((m_nStreamMode == PACKAGE_STREAM_RAW) || m_bToBeEncrypted);
1333 else if ( PropertyName == "WasEncrypted" )
1335 return Any(m_bIsEncrypted);
1337 else if ( PropertyName == "Compressed" )
1339 return Any(m_bToBeCompressed);
1341 else if ( PropertyName == ENCRYPTION_KEY_PROPERTY )
1343 return Any(m_aEncryptionKey);
1345 else if ( PropertyName == STORAGE_ENCRYPTION_KEYS_PROPERTY )
1347 return Any(m_aStorageEncryptionKeys);
1349 else
1350 throw beans::UnknownPropertyException(THROW_WHERE );
1353 void ZipPackageStream::setSize ( const sal_Int64 nNewSize )
1355 if ( aEntry.nCompressedSize != nNewSize )
1356 aEntry.nMethod = DEFLATED;
1357 aEntry.nSize = nNewSize;
1359 OUString ZipPackageStream::getImplementationName()
1361 return OUString ("ZipPackageStream");
1364 Sequence< OUString > ZipPackageStream::getSupportedServiceNames()
1366 Sequence<OUString> aNames { "com.sun.star.packages.PackageStream" };
1367 return aNames;
1370 sal_Bool SAL_CALL ZipPackageStream::supportsService( OUString const & rServiceName )
1372 return cppu::supportsService(this, rServiceName);
1375 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */