bump product version to 6.4.0.3
[LibreOffice.git] / package / source / zippackage / ZipPackageStream.cxx
blob745157cfd02ee43be6285272cfa7485aa8024550
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/packages/NoRawFormatException.hpp>
24 #include <com/sun/star/packages/zip/ZipConstants.hpp>
25 #include <com/sun/star/embed/StorageFormats.hpp>
26 #include <com/sun/star/packages/zip/ZipIOException.hpp>
27 #include <com/sun/star/io/TempFile.hpp>
28 #include <com/sun/star/io/XInputStream.hpp>
29 #include <com/sun/star/io/XOutputStream.hpp>
30 #include <com/sun/star/io/XStream.hpp>
31 #include <com/sun/star/io/XSeekable.hpp>
32 #include <com/sun/star/xml/crypto/DigestID.hpp>
33 #include <com/sun/star/xml/crypto/CipherID.hpp>
35 #include <string.h>
37 #include <CRC32.hxx>
38 #include <ThreadedDeflater.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/servicehelper.hxx>
50 #include <comphelper/storagehelper.hxx>
51 #include <cppuhelper/exc_hlp.hxx>
52 #include <cppuhelper/supportsservice.hxx>
53 #include <cppuhelper/typeprovider.hxx>
55 #include <rtl/instance.hxx>
56 #include <rtl/random.h>
57 #include <sal/log.hxx>
58 #include <tools/diagnose_ex.h>
60 #include <PackageConstants.hxx>
62 #include <algorithm>
63 #include <thread>
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 namespace { struct lcl_CachedImplId : public rtl::Static< cppu::OImplementationId, lcl_CachedImplId > {}; }
80 css::uno::Sequence < sal_Int8 > ZipPackageStream::getUnoTunnelId()
82 return lcl_CachedImplId::get().getImplementationId();
85 ZipPackageStream::ZipPackageStream ( ZipPackage & rNewPackage,
86 const uno::Reference< XComponentContext >& xContext,
87 sal_Int32 nFormat,
88 bool bAllowRemoveOnInsert )
89 : m_rZipPackage( rNewPackage )
90 , m_bToBeCompressed ( true )
91 , m_bToBeEncrypted ( false )
92 , m_bHaveOwnKey ( false )
93 , m_bIsEncrypted ( false )
94 , m_nImportedStartKeyAlgorithm( 0 )
95 , m_nImportedEncryptionAlgorithm( 0 )
96 , m_nImportedChecksumAlgorithm( 0 )
97 , m_nImportedDerivedKeySize( 0 )
98 , m_nStreamMode( PACKAGE_STREAM_NOTSET )
99 , m_nMagicalHackPos( 0 )
100 , m_nMagicalHackSize( 0 )
101 , m_nOwnStreamOrigSize( 0 )
102 , m_bHasSeekable( false )
103 , m_bCompressedIsSetFromOutside( false )
104 , m_bFromManifest( false )
105 , m_bUseWinEncoding( false )
106 , m_bRawStream( false )
108 m_xContext = xContext;
109 m_nFormat = nFormat;
110 mbAllowRemoveOnInsert = bAllowRemoveOnInsert;
111 SetFolder ( false );
112 aEntry.nVersion = -1;
113 aEntry.nFlag = 0;
114 aEntry.nMethod = -1;
115 aEntry.nTime = -1;
116 aEntry.nCrc = -1;
117 aEntry.nCompressedSize = -1;
118 aEntry.nSize = -1;
119 aEntry.nOffset = -1;
120 aEntry.nPathLen = -1;
121 aEntry.nExtraLen = -1;
124 ZipPackageStream::~ZipPackageStream()
128 void ZipPackageStream::setZipEntryOnLoading( const ZipEntry &rInEntry )
130 aEntry.nVersion = rInEntry.nVersion;
131 aEntry.nFlag = rInEntry.nFlag;
132 aEntry.nMethod = rInEntry.nMethod;
133 aEntry.nTime = rInEntry.nTime;
134 aEntry.nCrc = rInEntry.nCrc;
135 aEntry.nCompressedSize = rInEntry.nCompressedSize;
136 aEntry.nSize = rInEntry.nSize;
137 aEntry.nOffset = rInEntry.nOffset;
138 aEntry.sPath = rInEntry.sPath;
139 aEntry.nPathLen = rInEntry.nPathLen;
140 aEntry.nExtraLen = rInEntry.nExtraLen;
142 if ( aEntry.nMethod == STORED )
143 m_bToBeCompressed = false;
146 uno::Reference< io::XInputStream > const & ZipPackageStream::GetOwnSeekStream()
148 if ( !m_bHasSeekable && m_xStream.is() )
150 // The package component requires that every stream either be FROM a package or it must support XSeekable!
151 // The only exception is a nonseekable stream that is provided only for storing, if such a stream
152 // is accessed before commit it MUST be wrapped.
153 // Wrap the stream in case it is not seekable
154 m_xStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( m_xStream, m_xContext );
155 uno::Reference< io::XSeekable > xSeek( m_xStream, UNO_QUERY_THROW );
157 m_bHasSeekable = true;
160 return m_xStream;
163 uno::Reference< io::XInputStream > ZipPackageStream::GetRawEncrStreamNoHeaderCopy()
165 if ( m_nStreamMode != PACKAGE_STREAM_RAW || !GetOwnSeekStream().is() )
166 throw io::IOException(THROW_WHERE );
168 if ( m_xBaseEncryptionData.is() )
169 throw ZipIOException(THROW_WHERE "Encrypted stream without encryption data!" );
171 uno::Reference< io::XSeekable > xSeek( GetOwnSeekStream(), UNO_QUERY );
172 if ( !xSeek.is() )
173 throw ZipIOException(THROW_WHERE "The stream must be seekable!" );
175 // skip header
176 xSeek->seek( n_ConstHeaderSize + m_xBaseEncryptionData->m_aInitVector.getLength() +
177 m_xBaseEncryptionData->m_aSalt.getLength() + m_xBaseEncryptionData->m_aDigest.getLength() );
179 // create temporary stream
180 uno::Reference < io::XTempFile > xTempFile = io::TempFile::create(m_xContext);
181 uno::Reference < io::XOutputStream > xTempOut = xTempFile->getOutputStream();
182 uno::Reference < io::XInputStream > xTempIn = xTempFile->getInputStream();
183 uno::Reference < io::XSeekable > xTempSeek( xTempOut, UNO_QUERY_THROW );
185 // copy the raw stream to the temporary file starting from the current position
186 ::comphelper::OStorageHelper::CopyInputToOutput( GetOwnSeekStream(), xTempOut );
187 xTempOut->closeOutput();
188 xTempSeek->seek( 0 );
190 return xTempIn;
193 sal_Int32 ZipPackageStream::GetEncryptionAlgorithm() const
195 return m_nImportedEncryptionAlgorithm ? m_nImportedEncryptionAlgorithm : m_rZipPackage.GetEncAlgID();
198 sal_Int32 ZipPackageStream::GetBlockSize() const
200 return GetEncryptionAlgorithm() == css::xml::crypto::CipherID::AES_CBC_W3C_PADDING ? 16 : 8;
203 ::rtl::Reference<EncryptionData> ZipPackageStream::GetEncryptionData(Bugs const bugs)
205 ::rtl::Reference< EncryptionData > xResult;
206 if ( m_xBaseEncryptionData.is() )
207 xResult = new EncryptionData(
208 *m_xBaseEncryptionData,
209 GetEncryptionKey(bugs),
210 GetEncryptionAlgorithm(),
211 m_nImportedChecksumAlgorithm ? m_nImportedChecksumAlgorithm : m_rZipPackage.GetChecksumAlgID(),
212 m_nImportedDerivedKeySize ? m_nImportedDerivedKeySize : m_rZipPackage.GetDefaultDerivedKeySize(),
213 GetStartKeyGenID(),
214 bugs != Bugs::None);
216 return xResult;
219 uno::Sequence<sal_Int8> ZipPackageStream::GetEncryptionKey(Bugs const bugs)
221 uno::Sequence< sal_Int8 > aResult;
222 sal_Int32 nKeyGenID = GetStartKeyGenID();
223 bool const bUseWinEncoding = (bugs == Bugs::WinEncodingWrongSHA1 || m_bUseWinEncoding);
225 if ( m_bHaveOwnKey && m_aStorageEncryptionKeys.hasElements() )
227 OUString aNameToFind;
228 if ( nKeyGenID == xml::crypto::DigestID::SHA256 )
229 aNameToFind = PACKAGE_ENCRYPTIONDATA_SHA256UTF8;
230 else if ( nKeyGenID == xml::crypto::DigestID::SHA1 )
232 aNameToFind = bUseWinEncoding
233 ? OUString(PACKAGE_ENCRYPTIONDATA_SHA1MS1252)
234 : (bugs == Bugs::WrongSHA1)
235 ? OUString(PACKAGE_ENCRYPTIONDATA_SHA1UTF8)
236 : OUString(PACKAGE_ENCRYPTIONDATA_SHA1CORRECT);
238 else
239 throw uno::RuntimeException(THROW_WHERE "No expected key is provided!" );
241 for ( const auto& rKey : std::as_const(m_aStorageEncryptionKeys) )
242 if ( rKey.Name == aNameToFind )
243 rKey.Value >>= aResult;
245 // empty keys are not allowed here
246 // so it is not important whether there is no key, or the key is empty, it is an error
247 if ( !aResult.hasElements() )
248 throw uno::RuntimeException(THROW_WHERE "No expected key is provided!" );
250 else
251 aResult = m_aEncryptionKey;
253 if ( !aResult.hasElements() || !m_bHaveOwnKey )
254 aResult = m_rZipPackage.GetEncryptionKey();
256 return aResult;
259 sal_Int32 ZipPackageStream::GetStartKeyGenID() const
261 // generally should all the streams use the same Start Key
262 // but if raw copy without password takes place, we should preserve the imported algorithm
263 return m_nImportedStartKeyAlgorithm ? m_nImportedStartKeyAlgorithm : m_rZipPackage.GetStartKeyGenID();
266 uno::Reference< io::XInputStream > ZipPackageStream::TryToGetRawFromDataStream( bool bAddHeaderForEncr )
268 if ( m_nStreamMode != PACKAGE_STREAM_DATA || !GetOwnSeekStream().is() || ( bAddHeaderForEncr && !m_bToBeEncrypted ) )
269 throw packages::NoEncryptionException(THROW_WHERE );
271 Sequence< sal_Int8 > aKey;
273 if ( m_bToBeEncrypted )
275 aKey = GetEncryptionKey();
276 if ( !aKey.hasElements() )
277 throw packages::NoEncryptionException(THROW_WHERE );
282 // create temporary file
283 uno::Reference < io::XStream > xTempStream(
284 io::TempFile::create(m_xContext),
285 uno::UNO_QUERY_THROW );
287 // create a package based on it
288 ZipPackage* pPackage = new ZipPackage( m_xContext );
289 uno::Reference< XSingleServiceFactory > xPackageAsFactory( static_cast< XSingleServiceFactory* >( pPackage ) );
290 if ( !xPackageAsFactory.is() )
291 throw RuntimeException(THROW_WHERE );
293 Sequence< Any > aArgs( 1 );
294 aArgs[0] <<= xTempStream;
295 pPackage->initialize( aArgs );
297 // create a new package stream
298 uno::Reference< XDataSinkEncrSupport > xNewPackStream( xPackageAsFactory->createInstance(), UNO_QUERY_THROW );
299 xNewPackStream->setDataStream(
300 new WrapStreamForShare(GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef()));
302 uno::Reference< XPropertySet > xNewPSProps( xNewPackStream, UNO_QUERY_THROW );
304 // copy all the properties of this stream to the new stream
305 xNewPSProps->setPropertyValue("MediaType", makeAny( msMediaType ) );
306 xNewPSProps->setPropertyValue("Compressed", makeAny( m_bToBeCompressed ) );
307 if ( m_bToBeEncrypted )
309 xNewPSProps->setPropertyValue(ENCRYPTION_KEY_PROPERTY, makeAny( aKey ) );
310 xNewPSProps->setPropertyValue("Encrypted", makeAny( true ) );
313 // insert a new stream in the package
314 uno::Reference< XUnoTunnel > xTunnel;
315 Any aRoot = pPackage->getByHierarchicalName("/");
316 aRoot >>= xTunnel;
317 uno::Reference< container::XNameContainer > xRootNameContainer( xTunnel, UNO_QUERY_THROW );
319 uno::Reference< XUnoTunnel > xNPSTunnel( xNewPackStream, UNO_QUERY );
320 xRootNameContainer->insertByName("dummy", makeAny( xNPSTunnel ) );
322 // commit the temporary package
323 pPackage->commitChanges();
325 // get raw stream from the temporary package
326 uno::Reference< io::XInputStream > xInRaw;
327 if ( bAddHeaderForEncr )
328 xInRaw = xNewPackStream->getRawStream();
329 else
330 xInRaw = xNewPackStream->getPlainRawStream();
332 // create another temporary file
333 uno::Reference < io::XOutputStream > xTempOut(
334 io::TempFile::create(m_xContext),
335 uno::UNO_QUERY_THROW );
336 uno::Reference < io::XInputStream > xTempIn( xTempOut, UNO_QUERY_THROW );
337 uno::Reference < io::XSeekable > xTempSeek( xTempOut, UNO_QUERY_THROW );
339 // copy the raw stream to the temporary file
340 ::comphelper::OStorageHelper::CopyInputToOutput( xInRaw, xTempOut );
341 xTempOut->closeOutput();
342 xTempSeek->seek( 0 );
344 // close raw stream, package stream and folder
345 xInRaw.clear();
346 xNewPSProps.clear();
347 xNPSTunnel.clear();
348 xNewPackStream.clear();
349 xTunnel.clear();
350 xRootNameContainer.clear();
352 // return the stream representing the first temporary file
353 return xTempIn;
355 catch ( RuntimeException& )
357 throw;
359 catch ( Exception& )
363 throw io::IOException(THROW_WHERE );
366 bool ZipPackageStream::ParsePackageRawStream()
368 OSL_ENSURE( GetOwnSeekStream().is(), "A stream must be provided!" );
370 if ( !GetOwnSeekStream().is() )
371 return false;
373 bool bOk = false;
375 ::rtl::Reference< BaseEncryptionData > xTempEncrData;
376 sal_Int32 nMagHackSize = 0;
377 Sequence < sal_Int8 > aHeader ( 4 );
381 if ( GetOwnSeekStream()->readBytes ( aHeader, 4 ) == 4 )
383 const sal_Int8 *pHeader = aHeader.getConstArray();
384 sal_uInt32 nHeader = ( pHeader [0] & 0xFF ) |
385 ( pHeader [1] & 0xFF ) << 8 |
386 ( pHeader [2] & 0xFF ) << 16 |
387 ( pHeader [3] & 0xFF ) << 24;
388 if ( nHeader == n_ConstHeader )
390 // this is one of our god-awful, but extremely devious hacks, everyone cheer
391 xTempEncrData = new BaseEncryptionData;
393 OUString aMediaType;
394 sal_Int32 nEncAlgorithm = 0;
395 sal_Int32 nChecksumAlgorithm = 0;
396 sal_Int32 nDerivedKeySize = 0;
397 sal_Int32 nStartKeyGenID = 0;
398 if ( ZipFile::StaticFillData( xTempEncrData, nEncAlgorithm, nChecksumAlgorithm, nDerivedKeySize, nStartKeyGenID, nMagHackSize, aMediaType, GetOwnSeekStream() ) )
400 // We'll want to skip the data we've just read, so calculate how much we just read
401 // and remember it
402 m_nMagicalHackPos = n_ConstHeaderSize + xTempEncrData->m_aSalt.getLength()
403 + xTempEncrData->m_aInitVector.getLength()
404 + xTempEncrData->m_aDigest.getLength()
405 + aMediaType.getLength() * sizeof( sal_Unicode );
406 m_nImportedEncryptionAlgorithm = nEncAlgorithm;
407 m_nImportedChecksumAlgorithm = nChecksumAlgorithm;
408 m_nImportedDerivedKeySize = nDerivedKeySize;
409 m_nImportedStartKeyAlgorithm = nStartKeyGenID;
410 m_nMagicalHackSize = nMagHackSize;
411 msMediaType = aMediaType;
413 bOk = true;
418 catch( Exception& )
422 if ( !bOk )
424 // the provided stream is not a raw stream
425 return false;
428 m_xBaseEncryptionData = xTempEncrData;
429 SetIsEncrypted ( true );
430 // it's already compressed and encrypted
431 m_bToBeEncrypted = m_bToBeCompressed = false;
433 return true;
436 static void ImplSetStoredData( ZipEntry & rEntry, uno::Reference< io::XInputStream> const & rStream )
438 // It's very annoying that we have to do this, but lots of zip packages
439 // don't allow data descriptors for STORED streams, meaning we have to
440 // know the size and CRC32 of uncompressed streams before we actually
441 // write them !
442 CRC32 aCRC32;
443 rEntry.nMethod = STORED;
444 rEntry.nCompressedSize = rEntry.nSize = aCRC32.updateStream ( rStream );
445 rEntry.nCrc = aCRC32.getValue();
448 bool ZipPackageStream::saveChild(
449 const OUString &rPath,
450 std::vector < uno::Sequence < beans::PropertyValue > > &rManList,
451 ZipOutputStream & rZipOut,
452 const uno::Sequence < sal_Int8 >& rEncryptionKey,
453 sal_Int32 nPBKDF2IterationCount,
454 const rtlRandomPool &rRandomPool)
456 bool bSuccess = true;
458 const OUString sMediaTypeProperty ("MediaType");
459 const OUString sVersionProperty ("Version");
460 const OUString sFullPathProperty ("FullPath");
461 const OUString sInitialisationVectorProperty ("InitialisationVector");
462 const OUString sSaltProperty ("Salt");
463 const OUString sIterationCountProperty ("IterationCount");
464 const OUString sSizeProperty ("Size");
465 const OUString sDigestProperty ("Digest");
466 const OUString sEncryptionAlgProperty ("EncryptionAlgorithm");
467 const OUString sStartKeyAlgProperty ("StartKeyAlgorithm");
468 const OUString sDigestAlgProperty ("DigestAlgorithm");
469 const OUString sDerivedKeySizeProperty ("DerivedKeySize");
471 uno::Sequence < beans::PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST);
473 // In case the entry we are reading is also the entry we are writing, we will
474 // store the ZipEntry data in pTempEntry
476 // if pTempEntry is necessary, it will be released and passed to the ZipOutputStream
477 // and be deleted in the ZipOutputStream destructor
478 std::unique_ptr < ZipEntry > pAutoTempEntry ( new ZipEntry(aEntry) );
479 ZipEntry* pTempEntry = pAutoTempEntry.get();
481 pTempEntry->sPath = rPath;
482 pTempEntry->nPathLen = static_cast<sal_Int16>( OUStringToOString( pTempEntry->sPath, RTL_TEXTENCODING_UTF8 ).getLength() );
484 const bool bToBeEncrypted = m_bToBeEncrypted && (rEncryptionKey.hasElements() || m_bHaveOwnKey);
485 const bool bToBeCompressed = bToBeEncrypted || m_bToBeCompressed;
487 aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty;
488 aPropSet[PKG_MNFST_MEDIATYPE].Value <<= GetMediaType( );
489 aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
490 aPropSet[PKG_MNFST_VERSION].Value <<= OUString(); // no version is stored for streams currently
491 aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
492 aPropSet[PKG_MNFST_FULLPATH].Value <<= pTempEntry->sPath;
494 OSL_ENSURE( m_nStreamMode != PACKAGE_STREAM_NOTSET, "Unacceptable ZipPackageStream mode!" );
496 m_bRawStream = false;
497 if ( m_nStreamMode == PACKAGE_STREAM_DETECT )
498 m_bRawStream = ParsePackageRawStream();
499 else if ( m_nStreamMode == PACKAGE_STREAM_RAW )
500 m_bRawStream = true;
502 bool bBackgroundThreadDeflate = false;
503 bool bTransportOwnEncrStreamAsRaw = false;
504 // During the storing the original size of the stream can be changed
505 // TODO/LATER: get rid of this hack
506 m_nOwnStreamOrigSize = m_bRawStream ? m_nMagicalHackSize : aEntry.nSize;
508 bool bUseNonSeekableAccess = false;
509 uno::Reference < io::XInputStream > xStream;
510 if ( !IsPackageMember() && !m_bRawStream && !bToBeEncrypted && bToBeCompressed )
512 // the stream is not a package member, not a raw stream,
513 // it should not be encrypted and it should be compressed,
514 // in this case nonseekable access can be used
516 xStream = m_xStream;
517 uno::Reference < io::XSeekable > xSeek ( xStream, uno::UNO_QUERY );
519 bUseNonSeekableAccess = ( xStream.is() && !xSeek.is() );
522 if ( !bUseNonSeekableAccess )
524 xStream = getRawData();
526 if ( !xStream.is() )
528 OSL_FAIL( "ZipPackageStream didn't have a stream associated with it, skipping!" );
529 bSuccess = false;
530 return bSuccess;
533 uno::Reference < io::XSeekable > xSeek ( xStream, uno::UNO_QUERY );
536 if ( xSeek.is() )
538 // If the stream is a raw one, then we should be positioned
539 // at the beginning of the actual data
540 if ( !bToBeCompressed || m_bRawStream )
542 // The raw stream can neither be encrypted nor connected
543 OSL_ENSURE( !m_bRawStream || !(bToBeCompressed || bToBeEncrypted), "The stream is already encrypted!" );
544 xSeek->seek ( m_bRawStream ? m_nMagicalHackPos : 0 );
545 ImplSetStoredData ( *pTempEntry, xStream );
547 // TODO/LATER: Get rid of hacks related to switching of Flag Method and Size properties!
549 else if ( bToBeEncrypted )
551 // this is the correct original size
552 pTempEntry->nSize = xSeek->getLength();
553 m_nOwnStreamOrigSize = pTempEntry->nSize;
556 xSeek->seek ( 0 );
558 else
560 // Okay, we don't have an xSeekable stream. This is possibly bad.
561 // check if it's one of our own streams, if it is then we know that
562 // each time we ask for it we'll get a new stream that will be
563 // at position zero...otherwise, assert and skip this stream...
564 if ( IsPackageMember() )
566 // if the password has been changed then the stream should not be package member any more
567 if ( m_bIsEncrypted && m_bToBeEncrypted )
569 // Should be handled close to the raw stream handling
570 bTransportOwnEncrStreamAsRaw = true;
571 pTempEntry->nMethod = STORED;
573 // TODO/LATER: get rid of this situation
574 // this size should be different from the one that will be stored in manifest.xml
575 // it is used in storing algorithms and after storing the correct size will be set
576 pTempEntry->nSize = pTempEntry->nCompressedSize;
579 else
581 bSuccess = false;
582 return bSuccess;
586 catch ( uno::Exception& )
588 bSuccess = false;
589 return bSuccess;
592 if ( bToBeEncrypted || m_bRawStream || bTransportOwnEncrStreamAsRaw )
594 if ( bToBeEncrypted && !bTransportOwnEncrStreamAsRaw )
596 uno::Sequence < sal_Int8 > aSalt( 16 ), aVector( GetBlockSize() );
597 rtl_random_getBytes ( rRandomPool, aSalt.getArray(), 16 );
598 rtl_random_getBytes ( rRandomPool, aVector.getArray(), aVector.getLength() );
599 if ( !m_bHaveOwnKey )
601 m_aEncryptionKey = rEncryptionKey;
602 m_aStorageEncryptionKeys.realloc( 0 );
605 setInitialisationVector ( aVector );
606 setSalt ( aSalt );
607 setIterationCount(nPBKDF2IterationCount);
610 // last property is digest, which is inserted later if we didn't have
611 // a magic header
612 aPropSet.realloc(PKG_SIZE_ENCR_MNFST);
614 aPropSet[PKG_MNFST_INIVECTOR].Name = sInitialisationVectorProperty;
615 aPropSet[PKG_MNFST_INIVECTOR].Value <<= m_xBaseEncryptionData->m_aInitVector;
616 aPropSet[PKG_MNFST_SALT].Name = sSaltProperty;
617 aPropSet[PKG_MNFST_SALT].Value <<= m_xBaseEncryptionData->m_aSalt;
618 aPropSet[PKG_MNFST_ITERATION].Name = sIterationCountProperty;
619 aPropSet[PKG_MNFST_ITERATION].Value <<= m_xBaseEncryptionData->m_nIterationCount;
621 // Need to store the uncompressed size in the manifest
622 OSL_ENSURE( m_nOwnStreamOrigSize >= 0, "The stream size was not correctly initialized!" );
623 aPropSet[PKG_MNFST_UCOMPSIZE].Name = sSizeProperty;
624 aPropSet[PKG_MNFST_UCOMPSIZE].Value <<= m_nOwnStreamOrigSize;
626 if ( m_bRawStream || bTransportOwnEncrStreamAsRaw )
628 ::rtl::Reference< EncryptionData > xEncData = GetEncryptionData();
629 if ( !xEncData.is() )
630 throw uno::RuntimeException();
632 aPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
633 aPropSet[PKG_MNFST_DIGEST].Value <<= m_xBaseEncryptionData->m_aDigest;
634 aPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
635 aPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
636 aPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
637 aPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID;
638 aPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
639 aPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg;
640 aPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
641 aPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
646 // If the entry is already stored in the zip file in the format we
647 // want for this write...copy it raw
648 if ( !bUseNonSeekableAccess
649 && ( m_bRawStream || bTransportOwnEncrStreamAsRaw
650 || ( IsPackageMember() && !bToBeEncrypted
651 && ( ( aEntry.nMethod == DEFLATED && bToBeCompressed )
652 || ( aEntry.nMethod == STORED && !bToBeCompressed ) ) ) ) )
654 // If it's a PackageMember, then it's an unbuffered stream and we need
655 // to get a new version of it as we can't seek backwards.
656 if ( IsPackageMember() )
658 xStream = getRawData();
659 if ( !xStream.is() )
661 // Make sure that we actually _got_ a new one !
662 bSuccess = false;
663 return bSuccess;
669 if ( m_bRawStream )
670 xStream->skipBytes( m_nMagicalHackPos );
672 ZipOutputStream::setEntry(pTempEntry);
673 rZipOut.writeLOC(pTempEntry);
674 // the entry is provided to the ZipOutputStream that will delete it
675 pAutoTempEntry.release();
677 uno::Sequence < sal_Int8 > aSeq ( n_ConstBufferSize );
678 sal_Int32 nLength;
682 nLength = xStream->readBytes( aSeq, n_ConstBufferSize );
683 if (nLength != n_ConstBufferSize)
684 aSeq.realloc(nLength);
686 rZipOut.rawWrite(aSeq);
688 while ( nLength == n_ConstBufferSize );
690 rZipOut.rawCloseEntry();
692 catch ( ZipException& )
694 bSuccess = false;
696 catch ( io::IOException& )
698 bSuccess = false;
701 else
703 // This stream is definitely not a raw stream
705 // If nonseekable access is used the stream should be at the beginning and
706 // is useless after the storing. Thus if the storing fails the package should
707 // be thrown away ( as actually it is done currently )!
708 // To allow to reuse the package after the error, the optimization must be removed!
710 // If it's a PackageMember, then our previous reference held a 'raw' stream
711 // so we need to re-get it, unencrypted, uncompressed and positioned at the
712 // beginning of the stream
713 if ( IsPackageMember() )
715 xStream = getInputStream();
716 if ( !xStream.is() )
718 // Make sure that we actually _got_ a new one !
719 bSuccess = false;
720 return bSuccess;
724 if ( bToBeCompressed )
726 pTempEntry->nMethod = DEFLATED;
727 pTempEntry->nCrc = -1;
728 pTempEntry->nCompressedSize = pTempEntry->nSize = -1;
731 uno::Reference< io::XSeekable > xSeek(xStream, uno::UNO_QUERY);
732 // It's not worth to deflate jpegs to save ~1% in a slow process
733 // Unfortunately, does not work for streams protected by password
734 if (xSeek.is() && msMediaType.endsWith("/jpeg") && !m_bToBeEncrypted && !m_bToBeCompressed)
736 ImplSetStoredData(*pTempEntry, xStream);
737 xSeek->seek(0);
742 ZipOutputStream::setEntry(pTempEntry);
743 // the entry is provided to the ZipOutputStream that will delete it
744 pAutoTempEntry.release();
746 if (pTempEntry->nMethod == STORED)
748 sal_Int32 nLength;
749 uno::Sequence< sal_Int8 > aSeq(n_ConstBufferSize);
750 rZipOut.writeLOC(pTempEntry, bToBeEncrypted);
753 nLength = xStream->readBytes(aSeq, n_ConstBufferSize);
754 if (nLength != n_ConstBufferSize)
755 aSeq.realloc(nLength);
757 rZipOut.rawWrite(aSeq);
759 while ( nLength == n_ConstBufferSize );
760 rZipOut.rawCloseEntry(bToBeEncrypted);
762 else
764 // tdf#89236 Encrypting in a background thread does not work
765 bBackgroundThreadDeflate = !bToBeEncrypted;
766 // Do not deflate small streams using threads. XSeekable's getLength()
767 // gives the full size, XInputStream's available() may not be
768 // the full size, but it appears that at this point it usually is.
769 sal_Int64 estimatedSize = xSeek.is() ? xSeek->getLength() : xStream->available();
771 if (estimatedSize > 1000000)
773 // Use ThreadDeflater which will split the stream into blocks and compress
774 // them in threads, but not in background (i.e. writeStream() will block).
775 // This is suitable for large data.
776 bBackgroundThreadDeflate = false;
777 rZipOut.writeLOC(pTempEntry, bToBeEncrypted);
778 ZipOutputEntryParallel aZipEntry(rZipOut.getStream(), m_xContext, *pTempEntry, this, bToBeEncrypted);
779 aZipEntry.writeStream(xStream);
780 rZipOut.rawCloseEntry(bToBeEncrypted);
782 else if (bBackgroundThreadDeflate && estimatedSize > 100000)
784 // tdf#93553 limit to a useful amount of pending tasks. Having way too many
785 // tasks pending may use a lot of memory. Take number of available
786 // cores and allow 4-times the amount for having the queue well filled. The
787 // 2nd parameter is the time to wait between cleanups in 10th of a second.
788 // Both values may be added to the configuration settings if needed.
789 static sal_Int32 nAllowedTasks(comphelper::ThreadPool::getPreferredConcurrency() * 4);
790 rZipOut.reduceScheduledThreadTasksToGivenNumberOrLess(nAllowedTasks);
792 // Start a new thread task deflating this zip entry
793 ZipOutputEntryInThread *pZipEntry = new ZipOutputEntryInThread(
794 m_xContext, *pTempEntry, this, bToBeEncrypted);
795 rZipOut.addDeflatingThreadTask( pZipEntry,
796 pZipEntry->createTask( rZipOut.getThreadTaskTag(), xStream) );
798 else
800 bBackgroundThreadDeflate = false;
801 rZipOut.writeLOC(pTempEntry, bToBeEncrypted);
802 ZipOutputEntry aZipEntry(rZipOut.getStream(), m_xContext, *pTempEntry, this, bToBeEncrypted);
803 aZipEntry.writeStream(xStream);
804 rZipOut.rawCloseEntry(bToBeEncrypted);
808 catch ( ZipException& )
810 bSuccess = false;
812 catch ( io::IOException& )
814 bSuccess = false;
817 if ( bToBeEncrypted )
819 ::rtl::Reference< EncryptionData > xEncData = GetEncryptionData();
820 if ( !xEncData.is() )
821 throw uno::RuntimeException();
823 aPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
824 aPropSet[PKG_MNFST_DIGEST].Value <<= m_xBaseEncryptionData->m_aDigest;
825 aPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
826 aPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
827 aPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
828 aPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID;
829 aPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
830 aPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg;
831 aPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
832 aPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
834 SetIsEncrypted ( true );
838 if (bSuccess && !bBackgroundThreadDeflate)
839 successfullyWritten(pTempEntry);
841 if ( aPropSet.hasElements()
842 && ( m_nFormat == embed::StorageFormats::PACKAGE || m_nFormat == embed::StorageFormats::OFOPXML ) )
843 rManList.push_back( aPropSet );
845 return bSuccess;
848 void ZipPackageStream::successfullyWritten( ZipEntry const *pEntry )
850 if ( !IsPackageMember() )
852 if ( m_xStream.is() )
854 m_xStream->closeInput();
855 m_xStream.clear();
856 m_bHasSeekable = false;
858 SetPackageMember ( true );
861 if ( m_bRawStream )
863 // the raw stream was integrated and now behaves
864 // as usual encrypted stream
865 SetToBeEncrypted( true );
868 // Then copy it back afterwards...
869 aEntry = *pEntry;
871 // TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving )
872 if ( m_bIsEncrypted )
873 setSize( m_nOwnStreamOrigSize );
875 aEntry.nOffset *= -1;
878 void ZipPackageStream::SetPackageMember( bool bNewValue )
880 if ( bNewValue )
882 m_nStreamMode = PACKAGE_STREAM_PACKAGEMEMBER;
883 m_nMagicalHackPos = 0;
884 m_nMagicalHackSize = 0;
886 else if ( m_nStreamMode == PACKAGE_STREAM_PACKAGEMEMBER )
887 m_nStreamMode = PACKAGE_STREAM_NOTSET; // must be reset
890 // XActiveDataSink
891 void SAL_CALL ZipPackageStream::setInputStream( const uno::Reference< io::XInputStream >& aStream )
893 // if seekable access is required the wrapping will be done on demand
894 m_xStream = aStream;
895 m_nImportedEncryptionAlgorithm = 0;
896 m_bHasSeekable = false;
897 SetPackageMember ( false );
898 aEntry.nTime = -1;
899 m_nStreamMode = PACKAGE_STREAM_DETECT;
902 uno::Reference< io::XInputStream > ZipPackageStream::getRawData()
906 if ( IsPackageMember() )
908 return m_rZipPackage.getZipFile().getRawData( aEntry, GetEncryptionData(), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef(), false/*bUseBufferedStream*/ );
910 else if ( GetOwnSeekStream().is() )
912 return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() );
914 else
915 return uno::Reference < io::XInputStream > ();
917 catch ( ZipException & )//rException )
919 OSL_FAIL( "ZipException thrown" );//rException.Message);
920 return uno::Reference < io::XInputStream > ();
922 catch ( Exception & )
924 OSL_FAIL( "Exception is thrown during stream wrapping!" );
925 return uno::Reference < io::XInputStream > ();
929 uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getInputStream()
933 if ( IsPackageMember() )
935 return m_rZipPackage.getZipFile().getInputStream( aEntry, GetEncryptionData(), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() );
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 OSL_FAIL( "ZipException thrown" );//rException.Message);
947 return uno::Reference < io::XInputStream > ();
949 catch ( const Exception & )
951 TOOLS_WARN_EXCEPTION( "package", "Exception is thrown during stream wrapping!");
952 return uno::Reference < io::XInputStream > ();
956 // XDataSinkEncrSupport
957 uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getDataStream()
959 // There is no stream attached to this object
960 if ( m_nStreamMode == PACKAGE_STREAM_NOTSET )
961 return uno::Reference< io::XInputStream >();
963 // this method can not be used together with old approach
964 if ( m_nStreamMode == PACKAGE_STREAM_DETECT )
965 throw packages::zip::ZipIOException(THROW_WHERE );
967 if ( IsPackageMember() )
969 uno::Reference< io::XInputStream > xResult;
972 xResult = m_rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData(Bugs::None), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() );
974 catch( const packages::WrongPasswordException& )
976 if ( m_rZipPackage.GetStartKeyGenID() == xml::crypto::DigestID::SHA1 )
978 SAL_WARN("package", "ZipPackageStream::getDataStream(): SHA1 mismatch, trying fallbacks...");
980 { // tdf#114939 try with legacy StarOffice SHA1 bug
981 xResult = m_rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData(Bugs::WrongSHA1), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() );
982 return xResult;
984 catch (const packages::WrongPasswordException&)
986 /* ignore and try next... */
991 // rhbz#1013844 / fdo#47482 workaround for the encrypted
992 // OpenOffice.org 1.0 documents generated by Libreoffice <=
993 // 3.6 with the new encryption format and using SHA256, but
994 // missing a specified startkey of SHA256
996 // force SHA256 and see if that works
997 m_nImportedStartKeyAlgorithm = xml::crypto::DigestID::SHA256;
998 xResult = m_rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData(), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() );
999 return xResult;
1001 catch (const packages::WrongPasswordException&)
1003 // if that didn't work, restore to SHA1 and trundle through the *other* earlier
1004 // bug fix
1005 m_nImportedStartKeyAlgorithm = xml::crypto::DigestID::SHA1;
1008 // workaround for the encrypted documents generated with the old OOo1.x bug.
1009 if ( !m_bUseWinEncoding )
1011 xResult = m_rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData(Bugs::WinEncodingWrongSHA1), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() );
1012 m_bUseWinEncoding = true;
1014 else
1015 throw;
1017 else
1018 throw;
1020 return xResult;
1022 else if ( m_nStreamMode == PACKAGE_STREAM_RAW )
1023 return ZipFile::StaticGetDataFromRawStream( m_rZipPackage.GetSharedMutexRef(), m_xContext, GetOwnSeekStream(), GetEncryptionData() );
1024 else if ( GetOwnSeekStream().is() )
1026 return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() );
1028 else
1029 return uno::Reference< io::XInputStream >();
1032 uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getRawStream()
1034 // There is no stream attached to this object
1035 if ( m_nStreamMode == PACKAGE_STREAM_NOTSET )
1036 return uno::Reference< io::XInputStream >();
1038 // this method can not be used together with old approach
1039 if ( m_nStreamMode == PACKAGE_STREAM_DETECT )
1040 throw packages::zip::ZipIOException(THROW_WHERE );
1042 if ( IsPackageMember() )
1044 if ( !m_bIsEncrypted || !GetEncryptionData().is() )
1045 throw packages::NoEncryptionException(THROW_WHERE );
1047 return m_rZipPackage.getZipFile().getWrappedRawStream( aEntry, GetEncryptionData(), msMediaType, m_rZipPackage.GetSharedMutexRef() );
1049 else if ( GetOwnSeekStream().is() )
1051 if ( m_nStreamMode == PACKAGE_STREAM_RAW )
1053 return new WrapStreamForShare( GetOwnSeekStream(), m_rZipPackage.GetSharedMutexRef() );
1055 else if ( m_nStreamMode == PACKAGE_STREAM_DATA && m_bToBeEncrypted )
1056 return TryToGetRawFromDataStream( true );
1059 throw packages::NoEncryptionException(THROW_WHERE );
1062 void SAL_CALL ZipPackageStream::setDataStream( const uno::Reference< io::XInputStream >& aStream )
1064 setInputStream( aStream );
1065 m_nStreamMode = PACKAGE_STREAM_DATA;
1068 void SAL_CALL ZipPackageStream::setRawStream( const uno::Reference< io::XInputStream >& aStream )
1070 // wrap the stream in case it is not seekable
1071 uno::Reference< io::XInputStream > xNewStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( aStream, m_xContext );
1072 uno::Reference< io::XSeekable > xSeek( xNewStream, UNO_QUERY_THROW );
1073 xSeek->seek( 0 );
1074 uno::Reference< io::XInputStream > xOldStream = m_xStream;
1075 m_xStream = xNewStream;
1076 if ( !ParsePackageRawStream() )
1078 m_xStream = xOldStream;
1079 throw packages::NoRawFormatException(THROW_WHERE );
1082 // the raw stream MUST have seekable access
1083 m_bHasSeekable = true;
1085 SetPackageMember ( false );
1086 aEntry.nTime = -1;
1087 m_nStreamMode = PACKAGE_STREAM_RAW;
1090 uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getPlainRawStream()
1092 // There is no stream attached to this object
1093 if ( m_nStreamMode == PACKAGE_STREAM_NOTSET )
1094 return uno::Reference< io::XInputStream >();
1096 // this method can not be used together with old approach
1097 if ( m_nStreamMode == PACKAGE_STREAM_DETECT )
1098 throw packages::zip::ZipIOException(THROW_WHERE );
1100 if ( IsPackageMember() )
1102 return m_rZipPackage.getZipFile().getRawData( aEntry, GetEncryptionData(), m_bIsEncrypted, m_rZipPackage.GetSharedMutexRef() );
1104 else if ( GetOwnSeekStream().is() )
1106 if ( m_nStreamMode == PACKAGE_STREAM_RAW )
1108 // the header should not be returned here
1109 return GetRawEncrStreamNoHeaderCopy();
1111 else if ( m_nStreamMode == PACKAGE_STREAM_DATA )
1112 return TryToGetRawFromDataStream( false );
1115 return uno::Reference< io::XInputStream >();
1118 // XUnoTunnel
1120 sal_Int64 SAL_CALL ZipPackageStream::getSomething( const Sequence< sal_Int8 >& aIdentifier )
1122 sal_Int64 nMe = 0;
1123 if ( isUnoTunnelId<ZipPackageStream>(aIdentifier) )
1124 nMe = reinterpret_cast < sal_Int64 > ( this );
1125 return nMe;
1128 // XPropertySet
1129 void SAL_CALL ZipPackageStream::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
1131 if ( aPropertyName == "MediaType" )
1133 if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE && m_rZipPackage.getFormat() != embed::StorageFormats::OFOPXML )
1134 throw beans::PropertyVetoException(THROW_WHERE );
1136 if ( !(aValue >>= msMediaType) )
1137 throw IllegalArgumentException(THROW_WHERE "MediaType must be a string!",
1138 uno::Reference< XInterface >(),
1139 2 );
1141 if ( !msMediaType.isEmpty() )
1143 if ( msMediaType.indexOf ( "text" ) != -1
1144 || msMediaType == "application/vnd.sun.star.oleobject" )
1145 m_bToBeCompressed = true;
1146 else if ( !m_bCompressedIsSetFromOutside )
1147 m_bToBeCompressed = false;
1150 else if ( aPropertyName == "Size" )
1152 if ( !( aValue >>= aEntry.nSize ) )
1153 throw IllegalArgumentException(THROW_WHERE "Wrong type for Size property!",
1154 uno::Reference< XInterface >(),
1155 2 );
1157 else if ( aPropertyName == "Encrypted" )
1159 if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE )
1160 throw beans::PropertyVetoException(THROW_WHERE );
1162 bool bEnc = false;
1163 if ( !(aValue >>= bEnc) )
1164 throw IllegalArgumentException(THROW_WHERE "Wrong type for Encrypted property!",
1165 uno::Reference< XInterface >(),
1166 2 );
1168 // In case of new raw stream, the stream must not be encrypted on storing
1169 if ( bEnc && m_nStreamMode == PACKAGE_STREAM_RAW )
1170 throw IllegalArgumentException(THROW_WHERE "Raw stream can not be encrypted on storing",
1171 uno::Reference< XInterface >(),
1172 2 );
1174 m_bToBeEncrypted = bEnc;
1175 if ( m_bToBeEncrypted && !m_xBaseEncryptionData.is() )
1176 m_xBaseEncryptionData = new BaseEncryptionData;
1179 else if ( aPropertyName == ENCRYPTION_KEY_PROPERTY )
1181 if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE )
1182 throw beans::PropertyVetoException(THROW_WHERE );
1184 uno::Sequence< sal_Int8 > aNewKey;
1186 if ( !( aValue >>= aNewKey ) )
1188 OUString sTempString;
1189 if ( !(aValue >>= sTempString) )
1190 throw IllegalArgumentException(THROW_WHERE "Wrong type for EncryptionKey property!",
1191 uno::Reference< XInterface >(),
1192 2 );
1194 sal_Int32 nPathLength = sTempString.getLength();
1195 Sequence < sal_Int8 > aSequence ( nPathLength );
1196 sal_Int8 *pArray = aSequence.getArray();
1197 const sal_Unicode *pChar = sTempString.getStr();
1198 for ( sal_Int32 i = 0; i < nPathLength; i++ )
1199 pArray[i] = static_cast < sal_Int8 > ( pChar[i] );
1200 aNewKey = aSequence;
1203 if ( aNewKey.hasElements() )
1205 if ( !m_xBaseEncryptionData.is() )
1206 m_xBaseEncryptionData = new BaseEncryptionData;
1208 m_aEncryptionKey = aNewKey;
1209 // In case of new raw stream, the stream must not be encrypted on storing
1210 m_bHaveOwnKey = true;
1211 if ( m_nStreamMode != PACKAGE_STREAM_RAW )
1212 m_bToBeEncrypted = true;
1214 else
1216 m_bHaveOwnKey = false;
1217 m_aEncryptionKey.realloc( 0 );
1220 m_aStorageEncryptionKeys.realloc( 0 );
1222 else if ( aPropertyName == STORAGE_ENCRYPTION_KEYS_PROPERTY )
1224 if ( m_rZipPackage.getFormat() != embed::StorageFormats::PACKAGE )
1225 throw beans::PropertyVetoException(THROW_WHERE );
1227 uno::Sequence< beans::NamedValue > aKeys;
1228 if ( !( aValue >>= aKeys ) )
1230 throw IllegalArgumentException(THROW_WHERE "Wrong type for StorageEncryptionKeys property!",
1231 uno::Reference< XInterface >(),
1232 2 );
1235 if ( aKeys.hasElements() )
1237 if ( !m_xBaseEncryptionData.is() )
1238 m_xBaseEncryptionData = new BaseEncryptionData;
1240 m_aStorageEncryptionKeys = aKeys;
1242 // In case of new raw stream, the stream must not be encrypted on storing
1243 m_bHaveOwnKey = true;
1244 if ( m_nStreamMode != PACKAGE_STREAM_RAW )
1245 m_bToBeEncrypted = true;
1247 else
1249 m_bHaveOwnKey = false;
1250 m_aStorageEncryptionKeys.realloc( 0 );
1253 m_aEncryptionKey.realloc( 0 );
1255 else if ( aPropertyName == "Compressed" )
1257 bool bCompr = false;
1259 if ( !(aValue >>= bCompr) )
1260 throw IllegalArgumentException(THROW_WHERE "Wrong type for Compressed property!",
1261 uno::Reference< XInterface >(),
1262 2 );
1264 // In case of new raw stream, the stream must not be encrypted on storing
1265 if ( bCompr && m_nStreamMode == PACKAGE_STREAM_RAW )
1266 throw IllegalArgumentException(THROW_WHERE "Raw stream can not be encrypted on storing",
1267 uno::Reference< XInterface >(),
1268 2 );
1270 m_bToBeCompressed = bCompr;
1271 m_bCompressedIsSetFromOutside = true;
1273 else
1274 throw beans::UnknownPropertyException(aPropertyName);
1277 Any SAL_CALL ZipPackageStream::getPropertyValue( const OUString& PropertyName )
1279 if ( PropertyName == "MediaType" )
1281 return Any(msMediaType);
1283 else if ( PropertyName == "Size" )
1285 return Any(aEntry.nSize);
1287 else if ( PropertyName == "Encrypted" )
1289 return Any((m_nStreamMode == PACKAGE_STREAM_RAW) || m_bToBeEncrypted);
1291 else if ( PropertyName == "WasEncrypted" )
1293 return Any(m_bIsEncrypted);
1295 else if ( PropertyName == "Compressed" )
1297 return Any(m_bToBeCompressed);
1299 else if ( PropertyName == ENCRYPTION_KEY_PROPERTY )
1301 return Any(m_aEncryptionKey);
1303 else if ( PropertyName == STORAGE_ENCRYPTION_KEYS_PROPERTY )
1305 return Any(m_aStorageEncryptionKeys);
1307 else
1308 throw beans::UnknownPropertyException(PropertyName);
1311 void ZipPackageStream::setSize ( const sal_Int64 nNewSize )
1313 if ( aEntry.nCompressedSize != nNewSize )
1314 aEntry.nMethod = DEFLATED;
1315 aEntry.nSize = nNewSize;
1317 OUString ZipPackageStream::getImplementationName()
1319 return "ZipPackageStream";
1322 Sequence< OUString > ZipPackageStream::getSupportedServiceNames()
1324 Sequence<OUString> aNames { "com.sun.star.packages.PackageStream" };
1325 return aNames;
1328 sal_Bool SAL_CALL ZipPackageStream::supportsService( OUString const & rServiceName )
1330 return cppu::supportsService(this, rServiceName);
1333 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */