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 .
22 #include <ZipPackageFolder.hxx>
23 #include <ZipFile.hxx>
24 #include <ZipOutputStream.hxx>
25 #include <ZipPackageStream.hxx>
26 #include <PackageConstants.hxx>
27 #include <ZipPackageFolderEnumeration.hxx>
28 #include <com/sun/star/packages/zip/ZipConstants.hpp>
29 #include <com/sun/star/embed/StorageFormats.hpp>
30 #include <osl/diagnose.h>
32 #include <rtl/digest.h>
33 #include <ContentInfo.hxx>
34 #include <com/sun/star/beans/PropertyValue.hpp>
35 #include <com/sun/star/io/XSeekable.hpp>
36 #include <EncryptedDataHeader.hxx>
37 #include <rtl/random.h>
38 #include <rtl/instance.hxx>
41 using namespace com::sun::star
;
42 using namespace com::sun::star::packages::zip::ZipConstants
;
43 using namespace com::sun::star::packages::zip
;
44 using namespace com::sun::star::packages
;
45 using namespace com::sun::star::container
;
46 using namespace com::sun::star::beans
;
47 using namespace com::sun::star::lang
;
48 using namespace com::sun::star::io
;
51 using namespace ::com::sun::star
;
53 namespace { struct lcl_CachedImplId
: public rtl::Static
< uno::Sequence
< sal_Int8
>, lcl_CachedImplId
> {}; }
55 ZipPackageFolder::ZipPackageFolder ( sal_Int32 nFormat
,
56 sal_Bool bAllowRemoveOnInsert
)
57 : m_nFormat( nFormat
)
59 this->mbAllowRemoveOnInsert
= bAllowRemoveOnInsert
;
61 SetFolder ( sal_True
);
64 aEntry
.nMethod
= STORED
;
67 aEntry
.nCompressedSize
= 0;
70 uno::Sequence
< sal_Int8
> &rCachedImplId
= lcl_CachedImplId::get();
71 if ( !rCachedImplId
.getLength() )
72 rCachedImplId
= getImplementationId();
76 ZipPackageFolder::~ZipPackageFolder()
80 sal_Bool
ZipPackageFolder::LookForUnexpectedODF12Streams( const OUString
& aPath
)
82 sal_Bool bHasUnexpected
= sal_False
;
84 for ( ContentHash::const_iterator aCI
= maContents
.begin(), aEnd
= maContents
.end();
85 !bHasUnexpected
&& aCI
!= aEnd
;
88 const OUString
&rShortName
= (*aCI
).first
;
89 const ContentInfo
&rInfo
= *(*aCI
).second
;
93 if ( aPath
== "META-INF/" )
95 // META-INF is not allowed to contain subfolders
96 bHasUnexpected
= sal_True
;
100 OUString sOwnPath
= aPath
+ rShortName
+ "/";
101 bHasUnexpected
= rInfo
.pFolder
->LookForUnexpectedODF12Streams( sOwnPath
);
106 if ( aPath
== "META-INF/" )
108 if ( rShortName
!= "manifest.xml"
109 && rShortName
.indexOf( "signatures" ) == -1 )
111 // a stream from META-INF with unexpected name
112 bHasUnexpected
= sal_True
;
115 // streams from META-INF with expected names are allowed not to be registered in manifest.xml
117 else if ( !rInfo
.pStream
->IsFromManifest() )
119 // the stream is not in META-INF and ist notregistered in manifest.xml,
120 // check whether it is an internal part of the package format
121 if ( !aPath
.isEmpty() || rShortName
!= "mimetype" )
123 // if it is not "mimetype" from the root it is not a part of the package
124 bHasUnexpected
= sal_True
;
130 return bHasUnexpected
;
133 void ZipPackageFolder::setChildStreamsTypeByExtension( const beans::StringPair
& aPair
)
136 if ( aPair
.First
.toChar() == (sal_Unicode
)'.' )
139 aExt
= "." + aPair
.First
;
141 for ( ContentHash::const_iterator aCI
= maContents
.begin(), aEnd
= maContents
.end();
145 const OUString
&rShortName
= (*aCI
).first
;
146 const ContentInfo
&rInfo
= *(*aCI
).second
;
149 rInfo
.pFolder
->setChildStreamsTypeByExtension( aPair
);
152 sal_Int32 nPathLength
= rShortName
.getLength();
153 sal_Int32 nExtLength
= aExt
.getLength();
154 if ( nPathLength
>= nExtLength
&& rShortName
.match( aExt
, nPathLength
- nExtLength
) )
155 rInfo
.pStream
->SetMediaType( aPair
.Second
);
160 void ZipPackageFolder::copyZipEntry( ZipEntry
&rDest
, const ZipEntry
&rSource
)
162 rDest
.nVersion
= rSource
.nVersion
;
163 rDest
.nFlag
= rSource
.nFlag
;
164 rDest
.nMethod
= rSource
.nMethod
;
165 rDest
.nTime
= rSource
.nTime
;
166 rDest
.nCrc
= rSource
.nCrc
;
167 rDest
.nCompressedSize
= rSource
.nCompressedSize
;
168 rDest
.nSize
= rSource
.nSize
;
169 rDest
.nOffset
= rSource
.nOffset
;
170 rDest
.sPath
= rSource
.sPath
;
171 rDest
.nPathLen
= rSource
.nPathLen
;
172 rDest
.nExtraLen
= rSource
.nExtraLen
;
175 const ::com::sun::star::uno::Sequence
< sal_Int8
>& ZipPackageFolder::static_getImplementationId()
177 return lcl_CachedImplId::get();
181 void SAL_CALL
ZipPackageFolder::insertByName( const OUString
& aName
, const uno::Any
& aElement
)
182 throw(IllegalArgumentException
, ElementExistException
, WrappedTargetException
, uno::RuntimeException
)
184 if (hasByName(aName
))
185 throw ElementExistException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
188 uno::Reference
< XUnoTunnel
> xRef
;
190 if ( ( aElement
>>= xRef
) )
193 ZipPackageEntry
*pEntry
;
194 if ( ( nTest
= xRef
->getSomething ( ZipPackageFolder::static_getImplementationId() ) ) != 0 )
196 ZipPackageFolder
*pFolder
= reinterpret_cast < ZipPackageFolder
* > ( nTest
);
197 pEntry
= static_cast < ZipPackageEntry
* > ( pFolder
);
199 else if ( ( nTest
= xRef
->getSomething ( ZipPackageStream::static_getImplementationId() ) ) != 0 )
201 ZipPackageStream
*pStream
= reinterpret_cast < ZipPackageStream
* > ( nTest
);
202 pEntry
= static_cast < ZipPackageEntry
* > ( pStream
);
205 throw IllegalArgumentException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>(), 0 );
207 if (pEntry
->getName() != aName
)
208 pEntry
->setName (aName
);
209 doInsertByName ( pEntry
, sal_True
);
212 throw IllegalArgumentException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>(), 0 );
215 void SAL_CALL
ZipPackageFolder::removeByName( const OUString
& Name
)
216 throw(NoSuchElementException
, WrappedTargetException
, uno::RuntimeException
)
218 ContentHash::iterator aIter
= maContents
.find ( Name
);
219 if ( aIter
== maContents
.end() )
220 throw NoSuchElementException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
221 maContents
.erase( aIter
);
223 // XEnumerationAccess
224 uno::Reference
< XEnumeration
> SAL_CALL
ZipPackageFolder::createEnumeration( )
225 throw(uno::RuntimeException
)
227 return uno::Reference
< XEnumeration
> (new ZipPackageFolderEnumeration(maContents
));
230 uno::Type SAL_CALL
ZipPackageFolder::getElementType( )
231 throw(uno::RuntimeException
)
233 return ::getCppuType ((const uno::Reference
< XUnoTunnel
> *) 0);
235 sal_Bool SAL_CALL
ZipPackageFolder::hasElements( )
236 throw(uno::RuntimeException
)
238 return maContents
.size() > 0;
241 ContentInfo
& ZipPackageFolder::doGetByName( const OUString
& aName
)
242 throw(NoSuchElementException
, WrappedTargetException
, uno::RuntimeException
)
244 ContentHash::iterator aIter
= maContents
.find ( aName
);
245 if ( aIter
== maContents
.end())
246 throw NoSuchElementException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
247 return *(*aIter
).second
;
249 uno::Any SAL_CALL
ZipPackageFolder::getByName( const OUString
& aName
)
250 throw(NoSuchElementException
, WrappedTargetException
, uno::RuntimeException
)
252 return uno::makeAny ( doGetByName ( aName
).xTunnel
);
254 uno::Sequence
< OUString
> SAL_CALL
ZipPackageFolder::getElementNames( )
255 throw(uno::RuntimeException
)
257 sal_uInt32 i
=0, nSize
= maContents
.size();
258 uno::Sequence
< OUString
> aSequence ( nSize
);
259 for ( ContentHash::const_iterator aIterator
= maContents
.begin(), aEnd
= maContents
.end();
262 aSequence
[i
] = (*aIterator
).first
;
265 sal_Bool SAL_CALL
ZipPackageFolder::hasByName( const OUString
& aName
)
266 throw(uno::RuntimeException
)
268 return maContents
.find ( aName
) != maContents
.end ();
271 void SAL_CALL
ZipPackageFolder::replaceByName( const OUString
& aName
, const uno::Any
& aElement
)
272 throw(IllegalArgumentException
, NoSuchElementException
, WrappedTargetException
, uno::RuntimeException
)
274 if ( hasByName( aName
) )
275 removeByName( aName
);
277 throw NoSuchElementException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
278 insertByName(aName
, aElement
);
281 static void ImplSetStoredData( ZipEntry
& rEntry
, uno::Reference
< XInputStream
> & rStream
)
283 // It's very annoying that we have to do this, but lots of zip packages
284 // don't allow data descriptors for STORED streams, meaning we have to
285 // know the size and CRC32 of uncompressed streams before we actually
288 rEntry
.nMethod
= STORED
;
289 rEntry
.nCompressedSize
= rEntry
.nSize
= aCRC32
.updateStream ( rStream
);
290 rEntry
.nCrc
= aCRC32
.getValue();
293 bool ZipPackageFolder::saveChild( const OUString
&rShortName
, const ContentInfo
&rInfo
, OUString
&rPath
, std::vector
< uno::Sequence
< PropertyValue
> > &rManList
, ZipOutputStream
& rZipOut
, const uno::Sequence
< sal_Int8
>& rEncryptionKey
, rtlRandomPool
&rRandomPool
)
295 bool bSuccess
= true;
297 const OUString
sMediaTypeProperty ("MediaType");
298 const OUString
sVersionProperty ("Version");
299 const OUString
sFullPathProperty ("FullPath");
300 const OUString
sInitialisationVectorProperty ("InitialisationVector");
301 const OUString
sSaltProperty ("Salt");
302 const OUString
sIterationCountProperty ("IterationCount");
303 const OUString
sSizeProperty ("Size");
304 const OUString
sDigestProperty ("Digest");
305 const OUString
sEncryptionAlgProperty ("EncryptionAlgorithm");
306 const OUString
sStartKeyAlgProperty ("StartKeyAlgorithm");
307 const OUString
sDigestAlgProperty ("DigestAlgorithm");
308 const OUString
sDerivedKeySizeProperty ("DerivedKeySize");
310 uno::Sequence
< PropertyValue
> aPropSet (PKG_SIZE_NOENCR_MNFST
);
312 OSL_ENSURE( ( rInfo
.bFolder
&& rInfo
.pFolder
) || ( !rInfo
.bFolder
&& rInfo
.pStream
), "A valid child object is expected!" );
315 OUString sTempName
= rPath
+ rShortName
+ "/";
317 if ( !rInfo
.pFolder
->GetMediaType().isEmpty() )
319 aPropSet
[PKG_MNFST_MEDIATYPE
].Name
= sMediaTypeProperty
;
320 aPropSet
[PKG_MNFST_MEDIATYPE
].Value
<<= rInfo
.pFolder
->GetMediaType();
321 aPropSet
[PKG_MNFST_VERSION
].Name
= sVersionProperty
;
322 aPropSet
[PKG_MNFST_VERSION
].Value
<<= rInfo
.pFolder
->GetVersion();
323 aPropSet
[PKG_MNFST_FULLPATH
].Name
= sFullPathProperty
;
324 aPropSet
[PKG_MNFST_FULLPATH
].Value
<<= sTempName
;
327 aPropSet
.realloc( 0 );
329 rInfo
.pFolder
->saveContents( sTempName
, rManList
, rZipOut
, rEncryptionKey
, rRandomPool
);
333 // if pTempEntry is necessary, it will be released and passed to the ZipOutputStream
334 // and be deleted in the ZipOutputStream destructor
335 auto_ptr
< ZipEntry
> pAutoTempEntry ( new ZipEntry
);
336 ZipEntry
* pTempEntry
= pAutoTempEntry
.get();
338 // In case the entry we are reading is also the entry we are writing, we will
339 // store the ZipEntry data in pTempEntry
341 ZipPackageFolder::copyZipEntry ( *pTempEntry
, rInfo
.pStream
->aEntry
);
342 pTempEntry
->sPath
= rPath
+ rShortName
;
343 pTempEntry
->nPathLen
= (sal_Int16
)( OUStringToOString( pTempEntry
->sPath
, RTL_TEXTENCODING_UTF8
).getLength() );
345 sal_Bool bToBeEncrypted
= rInfo
.pStream
->IsToBeEncrypted() && (rEncryptionKey
.getLength() || rInfo
.pStream
->HasOwnKey());
346 sal_Bool bToBeCompressed
= bToBeEncrypted
? sal_True
: rInfo
.pStream
->IsToBeCompressed();
348 aPropSet
[PKG_MNFST_MEDIATYPE
].Name
= sMediaTypeProperty
;
349 aPropSet
[PKG_MNFST_MEDIATYPE
].Value
<<= rInfo
.pStream
->GetMediaType( );
350 aPropSet
[PKG_MNFST_VERSION
].Name
= sVersionProperty
;
351 aPropSet
[PKG_MNFST_VERSION
].Value
<<= OUString(); // no version is stored for streams currently
352 aPropSet
[PKG_MNFST_FULLPATH
].Name
= sFullPathProperty
;
353 aPropSet
[PKG_MNFST_FULLPATH
].Value
<<= pTempEntry
->sPath
;
356 OSL_ENSURE( rInfo
.pStream
->GetStreamMode() != PACKAGE_STREAM_NOTSET
, "Unacceptable ZipPackageStream mode!" );
358 sal_Bool bRawStream
= sal_False
;
359 if ( rInfo
.pStream
->GetStreamMode() == PACKAGE_STREAM_DETECT
)
360 bRawStream
= rInfo
.pStream
->ParsePackageRawStream();
361 else if ( rInfo
.pStream
->GetStreamMode() == PACKAGE_STREAM_RAW
)
362 bRawStream
= sal_True
;
364 sal_Bool bTransportOwnEncrStreamAsRaw
= sal_False
;
365 // During the storing the original size of the stream can be changed
366 // TODO/LATER: get rid of this hack
367 sal_Int64 nOwnStreamOrigSize
= bRawStream
? rInfo
.pStream
->GetMagicalHackSize() : rInfo
.pStream
->getSize();
369 sal_Bool bUseNonSeekableAccess
= sal_False
;
370 uno::Reference
< XInputStream
> xStream
;
371 if ( !rInfo
.pStream
->IsPackageMember() && !bRawStream
&& !bToBeEncrypted
&& bToBeCompressed
)
373 // the stream is not a package member, not a raw stream,
374 // it should not be encrypted and it should be compressed,
375 // in this case nonseekable access can be used
377 xStream
= rInfo
.pStream
->GetOwnStreamNoWrap();
378 uno::Reference
< XSeekable
> xSeek ( xStream
, uno::UNO_QUERY
);
380 bUseNonSeekableAccess
= ( xStream
.is() && !xSeek
.is() );
383 if ( !bUseNonSeekableAccess
)
385 xStream
= rInfo
.pStream
->getRawData();
389 OSL_FAIL( "ZipPackageStream didn't have a stream associated with it, skipping!" );
394 uno::Reference
< XSeekable
> xSeek ( xStream
, uno::UNO_QUERY
);
399 // If the stream is a raw one, then we should be positioned
400 // at the beginning of the actual data
401 if ( !bToBeCompressed
|| bRawStream
)
403 // The raw stream can neither be encrypted nor connected
404 OSL_ENSURE( !bRawStream
|| !(bToBeCompressed
|| bToBeEncrypted
), "The stream is already encrypted!\n" );
405 xSeek
->seek ( bRawStream
? rInfo
.pStream
->GetMagicalHackPos() : 0 );
406 ImplSetStoredData ( *pTempEntry
, xStream
);
408 // TODO/LATER: Get rid of hacks related to switching of Flag Method and Size properties!
410 else if ( bToBeEncrypted
)
412 // this is the correct original size
413 pTempEntry
->nSize
= xSeek
->getLength();
414 nOwnStreamOrigSize
= pTempEntry
->nSize
;
421 // Okay, we don't have an xSeekable stream. This is possibly bad.
422 // check if it's one of our own streams, if it is then we know that
423 // each time we ask for it we'll get a new stream that will be
424 // at position zero...otherwise, assert and skip this stream...
425 if ( rInfo
.pStream
->IsPackageMember() )
427 // if the password has been changed than the stream should not be package member any more
428 if ( rInfo
.pStream
->IsEncrypted() && rInfo
.pStream
->IsToBeEncrypted() )
430 // Should be handled close to the raw stream handling
431 bTransportOwnEncrStreamAsRaw
= sal_True
;
432 pTempEntry
->nMethod
= STORED
;
434 // TODO/LATER: get rid of this situation
435 // this size should be different from the one that will be stored in manifest.xml
436 // it is used in storing algorithms and after storing the correct size will be set
437 pTempEntry
->nSize
= pTempEntry
->nCompressedSize
;
447 catch ( uno::Exception
& )
453 if ( bToBeEncrypted
|| bRawStream
|| bTransportOwnEncrStreamAsRaw
)
455 if ( bToBeEncrypted
&& !bTransportOwnEncrStreamAsRaw
)
457 uno::Sequence
< sal_Int8
> aSalt( 16 ), aVector( rInfo
.pStream
->GetBlockSize() );
458 rtl_random_getBytes ( rRandomPool
, aSalt
.getArray(), 16 );
459 rtl_random_getBytes ( rRandomPool
, aVector
.getArray(), aVector
.getLength() );
460 sal_Int32 nIterationCount
= 1024;
462 if ( !rInfo
.pStream
->HasOwnKey() )
463 rInfo
.pStream
->setKey ( rEncryptionKey
);
465 rInfo
.pStream
->setInitialisationVector ( aVector
);
466 rInfo
.pStream
->setSalt ( aSalt
);
467 rInfo
.pStream
->setIterationCount ( nIterationCount
);
470 // last property is digest, which is inserted later if we didn't have
472 aPropSet
.realloc(PKG_SIZE_ENCR_MNFST
);
474 aPropSet
[PKG_MNFST_INIVECTOR
].Name
= sInitialisationVectorProperty
;
475 aPropSet
[PKG_MNFST_INIVECTOR
].Value
<<= rInfo
.pStream
->getInitialisationVector();
476 aPropSet
[PKG_MNFST_SALT
].Name
= sSaltProperty
;
477 aPropSet
[PKG_MNFST_SALT
].Value
<<= rInfo
.pStream
->getSalt();
478 aPropSet
[PKG_MNFST_ITERATION
].Name
= sIterationCountProperty
;
479 aPropSet
[PKG_MNFST_ITERATION
].Value
<<= rInfo
.pStream
->getIterationCount ();
481 // Need to store the uncompressed size in the manifest
482 OSL_ENSURE( nOwnStreamOrigSize
>= 0, "The stream size was not correctly initialized!\n" );
483 aPropSet
[PKG_MNFST_UCOMPSIZE
].Name
= sSizeProperty
;
484 aPropSet
[PKG_MNFST_UCOMPSIZE
].Value
<<= nOwnStreamOrigSize
;
486 if ( bRawStream
|| bTransportOwnEncrStreamAsRaw
)
488 ::rtl::Reference
< EncryptionData
> xEncData
= rInfo
.pStream
->GetEncryptionData();
489 if ( !xEncData
.is() )
490 throw uno::RuntimeException();
492 aPropSet
[PKG_MNFST_DIGEST
].Name
= sDigestProperty
;
493 aPropSet
[PKG_MNFST_DIGEST
].Value
<<= rInfo
.pStream
->getDigest();
494 aPropSet
[PKG_MNFST_ENCALG
].Name
= sEncryptionAlgProperty
;
495 aPropSet
[PKG_MNFST_ENCALG
].Value
<<= xEncData
->m_nEncAlg
;
496 aPropSet
[PKG_MNFST_STARTALG
].Name
= sStartKeyAlgProperty
;
497 aPropSet
[PKG_MNFST_STARTALG
].Value
<<= xEncData
->m_nStartKeyGenID
;
498 aPropSet
[PKG_MNFST_DIGESTALG
].Name
= sDigestAlgProperty
;
499 aPropSet
[PKG_MNFST_DIGESTALG
].Value
<<= xEncData
->m_nCheckAlg
;
500 aPropSet
[PKG_MNFST_DERKEYSIZE
].Name
= sDerivedKeySizeProperty
;
501 aPropSet
[PKG_MNFST_DERKEYSIZE
].Value
<<= xEncData
->m_nDerivedKeySize
;
506 // If the entry is already stored in the zip file in the format we
507 // want for this write...copy it raw
508 if ( !bUseNonSeekableAccess
509 && ( bRawStream
|| bTransportOwnEncrStreamAsRaw
510 || ( rInfo
.pStream
->IsPackageMember() && !bToBeEncrypted
511 && ( ( rInfo
.pStream
->aEntry
.nMethod
== DEFLATED
&& bToBeCompressed
)
512 || ( rInfo
.pStream
->aEntry
.nMethod
== STORED
&& !bToBeCompressed
) ) ) ) )
514 // If it's a PackageMember, then it's an unbuffered stream and we need
515 // to get a new version of it as we can't seek backwards.
516 if ( rInfo
.pStream
->IsPackageMember() )
518 xStream
= rInfo
.pStream
->getRawData();
521 // Make sure that we actually _got_ a new one !
530 xStream
->skipBytes( rInfo
.pStream
->GetMagicalHackPos() );
532 rZipOut
.putNextEntry ( *pTempEntry
, rInfo
.pStream
, sal_False
);
533 // the entry is provided to the ZipOutputStream that will delete it
534 pAutoTempEntry
.release();
536 uno::Sequence
< sal_Int8
> aSeq ( n_ConstBufferSize
);
541 nLength
= xStream
->readBytes( aSeq
, n_ConstBufferSize
);
542 rZipOut
.rawWrite(aSeq
, 0, nLength
);
544 while ( nLength
== n_ConstBufferSize
);
546 rZipOut
.rawCloseEntry();
548 catch ( ZipException
& )
552 catch ( IOException
& )
559 // This stream is defenitly not a raw stream
561 // If nonseekable access is used the stream should be at the beginning and
562 // is useless after the storing. Thus if the storing fails the package should
563 // be thrown away ( as actually it is done currently )!
564 // To allow to reuse the package after the error, the optimization must be removed!
566 // If it's a PackageMember, then our previous reference held a 'raw' stream
567 // so we need to re-get it, unencrypted, uncompressed and positioned at the
568 // beginning of the stream
569 if ( rInfo
.pStream
->IsPackageMember() )
571 xStream
= rInfo
.pStream
->getInputStream();
574 // Make sure that we actually _got_ a new one !
580 if ( bToBeCompressed
)
582 pTempEntry
->nMethod
= DEFLATED
;
583 pTempEntry
->nCrc
= -1;
584 pTempEntry
->nCompressedSize
= pTempEntry
->nSize
= -1;
589 rZipOut
.putNextEntry ( *pTempEntry
, rInfo
.pStream
, bToBeEncrypted
);
590 // the entry is provided to the ZipOutputStream that will delete it
591 pAutoTempEntry
.release();
594 uno::Sequence
< sal_Int8
> aSeq (n_ConstBufferSize
);
597 nLength
= xStream
->readBytes(aSeq
, n_ConstBufferSize
);
598 rZipOut
.write(aSeq
, 0, nLength
);
600 while ( nLength
== n_ConstBufferSize
);
602 rZipOut
.closeEntry();
604 catch ( ZipException
& )
608 catch ( IOException
& )
613 if ( bToBeEncrypted
)
615 ::rtl::Reference
< EncryptionData
> xEncData
= rInfo
.pStream
->GetEncryptionData();
616 if ( !xEncData
.is() )
617 throw uno::RuntimeException();
619 aPropSet
[PKG_MNFST_DIGEST
].Name
= sDigestProperty
;
620 aPropSet
[PKG_MNFST_DIGEST
].Value
<<= rInfo
.pStream
->getDigest();
621 aPropSet
[PKG_MNFST_ENCALG
].Name
= sEncryptionAlgProperty
;
622 aPropSet
[PKG_MNFST_ENCALG
].Value
<<= xEncData
->m_nEncAlg
;
623 aPropSet
[PKG_MNFST_STARTALG
].Name
= sStartKeyAlgProperty
;
624 aPropSet
[PKG_MNFST_STARTALG
].Value
<<= xEncData
->m_nStartKeyGenID
;
625 aPropSet
[PKG_MNFST_DIGESTALG
].Name
= sDigestAlgProperty
;
626 aPropSet
[PKG_MNFST_DIGESTALG
].Value
<<= xEncData
->m_nCheckAlg
;
627 aPropSet
[PKG_MNFST_DERKEYSIZE
].Name
= sDerivedKeySizeProperty
;
628 aPropSet
[PKG_MNFST_DERKEYSIZE
].Value
<<= xEncData
->m_nDerivedKeySize
;
630 rInfo
.pStream
->SetIsEncrypted ( sal_True
);
636 if ( !rInfo
.pStream
->IsPackageMember() )
638 rInfo
.pStream
->CloseOwnStreamIfAny();
639 rInfo
.pStream
->SetPackageMember ( sal_True
);
644 // the raw stream was integrated and now behaves
645 // as usual encrypted stream
646 rInfo
.pStream
->SetToBeEncrypted( sal_True
);
649 // Then copy it back afterwards...
650 ZipPackageFolder::copyZipEntry ( rInfo
.pStream
->aEntry
, *pTempEntry
);
652 // Remove hacky bit from entry flags
653 if ( rInfo
.pStream
->aEntry
.nFlag
& ( 1 << 4 ) )
655 rInfo
.pStream
->aEntry
.nFlag
&= ~( 1 << 4 );
656 rInfo
.pStream
->aEntry
.nMethod
= STORED
;
659 // TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving )
660 if ( rInfo
.pStream
->IsEncrypted() )
661 rInfo
.pStream
->setSize( nOwnStreamOrigSize
);
663 rInfo
.pStream
->aEntry
.nOffset
*= -1;
667 // folder can have a mediatype only in package format
668 if ( aPropSet
.getLength()
669 && ( m_nFormat
== embed::StorageFormats::PACKAGE
|| ( m_nFormat
== embed::StorageFormats::OFOPXML
&& !rInfo
.bFolder
) ) )
670 rManList
.push_back( aPropSet
);
675 void ZipPackageFolder::saveContents( OUString
&rPath
, std::vector
< uno::Sequence
< PropertyValue
> > &rManList
, ZipOutputStream
& rZipOut
, const uno::Sequence
< sal_Int8
>& rEncryptionKey
, rtlRandomPool
&rRandomPool
)
676 throw( uno::RuntimeException
)
678 bool bWritingFailed
= false;
680 if ( maContents
.begin() == maContents
.end() && !rPath
.isEmpty() && m_nFormat
!= embed::StorageFormats::OFOPXML
)
682 // it is an empty subfolder, use workaround to store it
683 ZipEntry
* pTempEntry
= new ZipEntry();
684 ZipPackageFolder::copyZipEntry ( *pTempEntry
, aEntry
);
685 pTempEntry
->nPathLen
= (sal_Int16
)( OUStringToOString( rPath
, RTL_TEXTENCODING_UTF8
).getLength() );
686 pTempEntry
->nExtraLen
= -1;
687 pTempEntry
->sPath
= rPath
;
691 rZipOut
.putNextEntry( *pTempEntry
, NULL
, sal_False
);
692 rZipOut
.rawCloseEntry();
694 catch ( ZipException
& )
696 bWritingFailed
= true;
698 catch ( IOException
& )
700 bWritingFailed
= true;
704 bool bMimeTypeStreamStored
= false;
705 OUString
aMimeTypeStreamName("mimetype");
706 if ( m_nFormat
== embed::StorageFormats::ZIP
&& rPath
.isEmpty() )
708 // let the "mimtype" stream in root folder be stored as the first stream if it is zip format
709 ContentHash::iterator aIter
= maContents
.find ( aMimeTypeStreamName
);
710 if ( aIter
!= maContents
.end() && !(*aIter
).second
->bFolder
)
712 bMimeTypeStreamStored
= true;
713 bWritingFailed
= !saveChild( (*aIter
).first
, *(*aIter
).second
, rPath
, rManList
, rZipOut
, rEncryptionKey
, rRandomPool
);
717 for ( ContentHash::const_iterator aCI
= maContents
.begin(), aEnd
= maContents
.end();
721 const OUString
&rShortName
= (*aCI
).first
;
722 const ContentInfo
&rInfo
= *(*aCI
).second
;
724 if ( !bMimeTypeStreamStored
|| !rShortName
.equals( aMimeTypeStreamName
) )
725 bWritingFailed
= !saveChild( rShortName
, rInfo
, rPath
, rManList
, rZipOut
, rEncryptionKey
, rRandomPool
);
729 throw uno::RuntimeException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
732 void ZipPackageFolder::releaseUpwardRef( void )
734 // Now it is possible that a package folder is disconnected from the package before removing of the folder.
735 // Such a scenario is used in storage implementation. When a new version of a folder is provided the old
736 // one is retrieved, removed from the package but preserved for the error handling.
737 // In this scenario the referencing to the parent is not really useful, since it requires disposing.
739 // Actually there is no need in having a reference to the parent, it even make things more complicated and
740 // requires disposing mechanics. Using of a simple pointer seems to be easier solution and also a safe enough.
745 for ( ContentHash::const_iterator aCI
= maContents
.begin();
746 aCI
!=maContents
.end();
749 ContentInfo
&rInfo
= * (*aCI
).second
;
750 if ( rInfo
.bFolder
)// && ! rInfo.pFolder->HasReleased () )
751 rInfo
.pFolder
->releaseUpwardRef();
752 else //if ( !rInfo.bFolder && !rInfo.pStream->HasReleased() )
753 rInfo
.pStream
->clearParent();
757 OSL_ENSURE ( m_refCount
== 1, "Ref-count is not 1!" );
761 sal_Int64 SAL_CALL
ZipPackageFolder::getSomething( const uno::Sequence
< sal_Int8
>& aIdentifier
)
762 throw(uno::RuntimeException
)
765 if ( aIdentifier
.getLength() == 16 &&
766 0 == memcmp(static_getImplementationId().getConstArray(), aIdentifier
.getConstArray(), 16 ) )
767 nMe
= reinterpret_cast < sal_Int64
> ( this );
770 void SAL_CALL
ZipPackageFolder::setPropertyValue( const OUString
& aPropertyName
, const uno::Any
& aValue
)
771 throw(UnknownPropertyException
, PropertyVetoException
, IllegalArgumentException
, WrappedTargetException
, uno::RuntimeException
)
773 if ( aPropertyName
== "MediaType" )
775 // TODO/LATER: activate when zip ucp is ready
776 // if ( m_nFormat != embed::StorageFormats::PACKAGE )
777 // throw UnknownPropertyException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
779 aValue
>>= sMediaType
;
781 else if ( aPropertyName
== "Version" )
782 aValue
>>= m_sVersion
;
783 else if ( aPropertyName
== "Size" )
784 aValue
>>= aEntry
.nSize
;
786 throw UnknownPropertyException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
788 uno::Any SAL_CALL
ZipPackageFolder::getPropertyValue( const OUString
& PropertyName
)
789 throw(UnknownPropertyException
, WrappedTargetException
, uno::RuntimeException
)
791 if ( PropertyName
== "MediaType" )
793 // TODO/LATER: activate when zip ucp is ready
794 // if ( m_nFormat != embed::StorageFormats::PACKAGE )
795 // throw UnknownPropertyException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
797 return uno::makeAny ( sMediaType
);
799 else if ( PropertyName
== "Version" )
800 return uno::makeAny( m_sVersion
);
801 else if ( PropertyName
== "Size" )
802 return uno::makeAny ( aEntry
.nSize
);
804 throw UnknownPropertyException(OSL_LOG_PREFIX
, uno::Reference
< uno::XInterface
>() );
807 void ZipPackageFolder::doInsertByName ( ZipPackageEntry
*pEntry
, sal_Bool bSetParent
)
808 throw(IllegalArgumentException
, ElementExistException
, WrappedTargetException
, uno::RuntimeException
)
812 if ( pEntry
->IsFolder() )
813 maContents
[pEntry
->getName()] = new ContentInfo ( static_cast < ZipPackageFolder
*> ( pEntry
) );
815 maContents
[pEntry
->getName()] = new ContentInfo ( static_cast < ZipPackageStream
*> ( pEntry
) );
817 catch(const uno::Exception
& rEx
)
823 pEntry
->setParent ( *this );
825 OUString
ZipPackageFolder::getImplementationName()
826 throw (uno::RuntimeException
)
828 return OUString("ZipPackageFolder");
831 uno::Sequence
< OUString
> ZipPackageFolder::getSupportedServiceNames()
832 throw (uno::RuntimeException
)
834 uno::Sequence
< OUString
> aNames(1);
835 aNames
[0] = "com.sun.star.packages.PackageFolder";
838 sal_Bool SAL_CALL
ZipPackageFolder::supportsService( OUString
const & rServiceName
)
839 throw (uno::RuntimeException
)
841 return rServiceName
== getSupportedServiceNames()[0];
844 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */