1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ZipPackageFolder.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_package.hxx"
33 #include <ZipPackageFolder.hxx>
34 #include <ZipFile.hxx>
35 #include <ZipOutputStream.hxx>
36 #include <ZipPackageStream.hxx>
37 #include <PackageConstants.hxx>
38 #include <ZipPackageFolderEnumeration.hxx>
39 #include <com/sun/star/packages/zip/ZipConstants.hpp>
40 #include <vos/diagnose.hxx>
42 #include <rtl/digest.h>
43 #include <ContentInfo.hxx>
44 #include <com/sun/star/beans/PropertyValue.hpp>
45 #include <com/sun/star/io/XSeekable.hpp>
46 #include <EncryptedDataHeader.hxx>
47 #include <rtl/random.h>
50 using namespace com::sun::star::packages::zip::ZipConstants
;
51 using namespace com::sun::star::packages::zip
;
52 using namespace com::sun::star::container
;
53 using namespace com::sun::star::packages
;
54 using namespace com::sun::star::beans
;
55 using namespace com::sun::star::lang
;
56 using namespace com::sun::star::uno
;
57 using namespace com::sun::star::io
;
61 using namespace ::com::sun::star
;
64 Sequence
< sal_Int8
> ZipPackageFolder::aImplementationId
= Sequence
< sal_Int8
> ();
66 ZipPackageFolder::ZipPackageFolder ( const Reference
< XMultiServiceFactory
>& xFactory
,
68 sal_Bool bAllowRemoveOnInsert
)
69 : m_xFactory( xFactory
)
70 , m_nFormat( nFormat
)
72 OSL_ENSURE( m_xFactory
.is(), "No factory is provided to the package folder!" );
74 this->mbAllowRemoveOnInsert
= bAllowRemoveOnInsert
;
76 SetFolder ( sal_True
);
79 aEntry
.nMethod
= STORED
;
82 aEntry
.nCompressedSize
= 0;
85 if ( !aImplementationId
.getLength() )
87 aImplementationId
= getImplementationId();
92 ZipPackageFolder::~ZipPackageFolder()
96 sal_Bool
ZipPackageFolder::LookForUnexpectedODF12Streams( const ::rtl::OUString
& aPath
)
98 sal_Bool bHasUnexpected
= sal_False
;
100 for ( ContentHash::const_iterator aCI
= maContents
.begin(), aEnd
= maContents
.end();
101 !bHasUnexpected
&& aCI
!= aEnd
;
104 const OUString
&rShortName
= (*aCI
).first
;
105 const ContentInfo
&rInfo
= *(*aCI
).second
;
109 if ( aPath
.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "META-INF/" ) ) ) )
111 // META-INF is not allowed to contain subfolders
112 bHasUnexpected
= sal_True
;
116 OUString sOwnPath
= aPath
+ rShortName
+ OUString( RTL_CONSTASCII_USTRINGPARAM ( "/" ) );
117 bHasUnexpected
= rInfo
.pFolder
->LookForUnexpectedODF12Streams( sOwnPath
);
122 if ( aPath
.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "META-INF/" ) ) ) )
124 if ( !rShortName
.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "manifest.xml" ) ) )
125 && rShortName
.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "signatures" ) ) ) == -1 )
127 // a stream from META-INF with unexpected name
128 bHasUnexpected
= sal_True
;
131 // streams from META-INF with expected names are allowed not to be registered in manifest.xml
133 else if ( !rInfo
.pStream
->IsFromManifest() )
135 // the stream is not in META-INF and ist notregistered in manifest.xml,
136 // check whether it is an internal part of the package format
137 if ( aPath
.getLength()
138 || !rShortName
.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "mimetype" ) ) ) )
140 // if it is not "mimetype" from the root it is not a part of the package
141 bHasUnexpected
= sal_True
;
147 return bHasUnexpected
;
150 void ZipPackageFolder::setChildStreamsTypeByExtension( const beans::StringPair
& aPair
)
152 ::rtl::OUString aExt
;
153 if ( aPair
.First
.toChar() == (sal_Unicode
)'.' )
156 aExt
= ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "." ) ) + aPair
.First
;
158 for ( ContentHash::const_iterator aCI
= maContents
.begin(), aEnd
= maContents
.end();
162 const OUString
&rShortName
= (*aCI
).first
;
163 const ContentInfo
&rInfo
= *(*aCI
).second
;
166 rInfo
.pFolder
->setChildStreamsTypeByExtension( aPair
);
169 sal_Int32 nPathLength
= rShortName
.getLength();
170 sal_Int32 nExtLength
= aExt
.getLength();
171 if ( nPathLength
>= nExtLength
&& rShortName
.match( aExt
, nPathLength
- nExtLength
) )
172 rInfo
.pStream
->SetMediaType( aPair
.Second
);
177 void ZipPackageFolder::copyZipEntry( ZipEntry
&rDest
, const ZipEntry
&rSource
)
179 rDest
.nVersion
= rSource
.nVersion
;
180 rDest
.nFlag
= rSource
.nFlag
;
181 rDest
.nMethod
= rSource
.nMethod
;
182 rDest
.nTime
= rSource
.nTime
;
183 rDest
.nCrc
= rSource
.nCrc
;
184 rDest
.nCompressedSize
= rSource
.nCompressedSize
;
185 rDest
.nSize
= rSource
.nSize
;
186 rDest
.nOffset
= rSource
.nOffset
;
187 rDest
.sPath
= rSource
.sPath
;
188 rDest
.nPathLen
= rSource
.nPathLen
;
189 rDest
.nExtraLen
= rSource
.nExtraLen
;
193 void SAL_CALL
ZipPackageFolder::insertByName( const OUString
& aName
, const Any
& aElement
)
194 throw(IllegalArgumentException
, ElementExistException
, WrappedTargetException
, RuntimeException
)
196 if (hasByName(aName
))
197 throw ElementExistException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
200 Reference
< XUnoTunnel
> xRef
;
202 if ( ( aElement
>>= xRef
) )
205 ZipPackageEntry
*pEntry
;
206 if ( ( nTest
= xRef
->getSomething ( ZipPackageFolder::static_getImplementationId() ) ) != 0 )
208 ZipPackageFolder
*pFolder
= reinterpret_cast < ZipPackageFolder
* > ( nTest
);
209 pEntry
= static_cast < ZipPackageEntry
* > ( pFolder
);
211 else if ( ( nTest
= xRef
->getSomething ( ZipPackageStream::static_getImplementationId() ) ) != 0 )
213 ZipPackageStream
*pStream
= reinterpret_cast < ZipPackageStream
* > ( nTest
);
214 pEntry
= static_cast < ZipPackageEntry
* > ( pStream
);
217 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>(), 0 );
219 if (pEntry
->getName() != aName
)
220 pEntry
->setName (aName
);
221 doInsertByName ( pEntry
, sal_True
);
224 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>(), 0 );
227 void SAL_CALL
ZipPackageFolder::removeByName( const OUString
& Name
)
228 throw(NoSuchElementException
, WrappedTargetException
, RuntimeException
)
230 ContentHash::iterator aIter
= maContents
.find ( Name
);
231 if ( aIter
== maContents
.end() )
232 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
233 maContents
.erase( aIter
);
235 // XEnumerationAccess
236 Reference
< XEnumeration
> SAL_CALL
ZipPackageFolder::createEnumeration( )
237 throw(RuntimeException
)
239 return Reference
< XEnumeration
> (new ZipPackageFolderEnumeration(maContents
));
242 Type SAL_CALL
ZipPackageFolder::getElementType( )
243 throw(RuntimeException
)
245 return ::getCppuType ((const Reference
< XUnoTunnel
> *) 0);
247 sal_Bool SAL_CALL
ZipPackageFolder::hasElements( )
248 throw(RuntimeException
)
250 return maContents
.size() > 0;
253 ContentInfo
& ZipPackageFolder::doGetByName( const OUString
& aName
)
254 throw(NoSuchElementException
, WrappedTargetException
, RuntimeException
)
256 ContentHash::iterator aIter
= maContents
.find ( aName
);
257 if ( aIter
== maContents
.end())
258 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
259 return *(*aIter
).second
;
261 Any SAL_CALL
ZipPackageFolder::getByName( const OUString
& aName
)
262 throw(NoSuchElementException
, WrappedTargetException
, RuntimeException
)
264 return makeAny ( doGetByName ( aName
).xTunnel
);
266 Sequence
< OUString
> SAL_CALL
ZipPackageFolder::getElementNames( )
267 throw(RuntimeException
)
269 sal_uInt32 i
=0, nSize
= maContents
.size();
270 Sequence
< OUString
> aSequence ( nSize
);
271 OUString
*pNames
= aSequence
.getArray();
272 for ( ContentHash::const_iterator aIterator
= maContents
.begin(), aEnd
= maContents
.end();
275 pNames
[i
] = (*aIterator
).first
;
278 sal_Bool SAL_CALL
ZipPackageFolder::hasByName( const OUString
& aName
)
279 throw(RuntimeException
)
281 return maContents
.find ( aName
) != maContents
.end ();
284 void SAL_CALL
ZipPackageFolder::replaceByName( const OUString
& aName
, const Any
& aElement
)
285 throw(IllegalArgumentException
, NoSuchElementException
, WrappedTargetException
, RuntimeException
)
287 if ( hasByName( aName
) )
288 removeByName( aName
);
290 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
291 insertByName(aName
, aElement
);
294 static void ImplSetStoredData( ZipEntry
& rEntry
, Reference
< XInputStream
> & rStream
)
296 // It's very annoying that we have to do this, but lots of zip packages
297 // don't allow data descriptors for STORED streams, meaning we have to
298 // know the size and CRC32 of uncompressed streams before we actually
301 rEntry
.nMethod
= STORED
;
302 rEntry
.nCompressedSize
= rEntry
.nSize
= aCRC32
.updateStream ( rStream
);
303 rEntry
.nCrc
= aCRC32
.getValue();
306 void ZipPackageFolder::saveContents(OUString
&rPath
, std::vector
< Sequence
< PropertyValue
> > &rManList
, ZipOutputStream
& rZipOut
, Sequence
< sal_Int8
> &rEncryptionKey
, rtlRandomPool
&rRandomPool
)
307 throw(RuntimeException
)
309 sal_Bool bWritingFailed
= sal_False
;
310 ZipPackageFolder
*pFolder
= NULL
;
311 ZipPackageStream
*pStream
= NULL
;
312 const OUString
sMediaTypeProperty ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
313 const OUString
sVersionProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) );
314 const OUString
sFullPathProperty ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
315 const OUString
sInitialisationVectorProperty ( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) );
316 const OUString
sSaltProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) );
317 const OUString
sIterationCountProperty ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) );
318 const OUString
sSizeProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) );
319 const OUString
sDigestProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) );
321 sal_Bool bHaveEncryptionKey
= rEncryptionKey
.getLength() ? sal_True
: sal_False
;
323 if ( maContents
.begin() == maContents
.end() && rPath
.getLength() && m_nFormat
!= OFOPXML_FORMAT
)
325 // it is an empty subfolder, use workaround to store it
326 ZipEntry
* pTempEntry
= new ZipEntry();
327 ZipPackageFolder::copyZipEntry ( *pTempEntry
, aEntry
);
328 pTempEntry
->nPathLen
= (sal_Int16
)( ::rtl::OUStringToOString( rPath
, RTL_TEXTENCODING_UTF8
).getLength() );
329 pTempEntry
->nExtraLen
= -1;
330 pTempEntry
->sPath
= rPath
;
334 vos::ORef
< EncryptionData
> aEmptyEncr
;
335 rZipOut
.putNextEntry ( *pTempEntry
, aEmptyEncr
, sal_False
);
336 rZipOut
.rawCloseEntry();
338 catch ( ZipException
& )
340 VOS_ENSURE( 0, "Error writing ZipOutputStream" );
341 bWritingFailed
= sal_True
;
343 catch ( IOException
& )
345 VOS_ENSURE( 0, "Error writing ZipOutputStream" );
346 bWritingFailed
= sal_True
;
350 for ( ContentHash::const_iterator aCI
= maContents
.begin(), aEnd
= maContents
.end();
354 const OUString
&rShortName
= (*aCI
).first
;
355 const ContentInfo
&rInfo
= *(*aCI
).second
;
357 Sequence
< PropertyValue
> aPropSet (PKG_SIZE_NOENCR_MNFST
);
358 PropertyValue
*pValue
= aPropSet
.getArray();
361 pFolder
= rInfo
.pFolder
;
363 pStream
= rInfo
.pStream
;
367 OUString sTempName
= rPath
+ rShortName
+ OUString( RTL_CONSTASCII_USTRINGPARAM ( "/" ) );
369 pValue
[PKG_MNFST_MEDIATYPE
].Name
= sMediaTypeProperty
;
370 pValue
[PKG_MNFST_MEDIATYPE
].Value
<<= pFolder
->GetMediaType();
371 pValue
[PKG_MNFST_VERSION
].Name
= sVersionProperty
;
372 pValue
[PKG_MNFST_VERSION
].Value
<<= pFolder
->GetVersion();
373 pValue
[PKG_MNFST_FULLPATH
].Name
= sFullPathProperty
;
374 pValue
[PKG_MNFST_FULLPATH
].Value
<<= sTempName
;
376 pFolder
->saveContents( sTempName
, rManList
, rZipOut
, rEncryptionKey
, rRandomPool
);
380 // if pTempEntry is necessary, it will be released and passed to the ZipOutputStream
381 // and be deleted in the ZipOutputStream destructor
382 auto_ptr
< ZipEntry
> pAutoTempEntry ( new ZipEntry
);
383 ZipEntry
* pTempEntry
= pAutoTempEntry
.get();
385 // In case the entry we are reading is also the entry we are writing, we will
386 // store the ZipEntry data in pTempEntry
388 ZipPackageFolder::copyZipEntry ( *pTempEntry
, pStream
->aEntry
);
389 pTempEntry
->sPath
= rPath
+ rShortName
;
390 pTempEntry
->nPathLen
= (sal_Int16
)( ::rtl::OUStringToOString( pTempEntry
->sPath
, RTL_TEXTENCODING_UTF8
).getLength() );
392 sal_Bool bToBeEncrypted
= pStream
->IsToBeEncrypted() && (bHaveEncryptionKey
|| pStream
->HasOwnKey());
393 sal_Bool bToBeCompressed
= bToBeEncrypted
? sal_True
: pStream
->IsToBeCompressed();
395 pValue
[PKG_MNFST_MEDIATYPE
].Name
= sMediaTypeProperty
;
396 pValue
[PKG_MNFST_MEDIATYPE
].Value
<<= pStream
->GetMediaType( );
397 pValue
[PKG_MNFST_VERSION
].Name
= sVersionProperty
;
398 pValue
[PKG_MNFST_VERSION
].Value
<<= ::rtl::OUString(); // no version is stored for streams currently
399 pValue
[PKG_MNFST_FULLPATH
].Name
= sFullPathProperty
;
400 pValue
[PKG_MNFST_FULLPATH
].Value
<<= pTempEntry
->sPath
;
403 OSL_ENSURE( pStream
->GetStreamMode() != PACKAGE_STREAM_NOTSET
, "Unacceptable ZipPackageStream mode!" );
405 sal_Bool bRawStream
= sal_False
;
406 if ( pStream
->GetStreamMode() == PACKAGE_STREAM_DETECT
)
407 bRawStream
= pStream
->ParsePackageRawStream();
408 else if ( pStream
->GetStreamMode() == PACKAGE_STREAM_RAW
)
409 bRawStream
= sal_True
;
411 sal_Bool bTransportOwnEncrStreamAsRaw
= sal_False
;
412 // During the storing the original size of the stream can be changed
413 // TODO/LATER: get rid of this hack
414 sal_Int32 nOwnStreamOrigSize
= bRawStream
? pStream
->GetMagicalHackSize() : pStream
->getSize();
416 sal_Bool bUseNonSeekableAccess
= sal_False
;
417 Reference
< XInputStream
> xStream
;
418 if ( !pStream
->IsPackageMember() && !bRawStream
&& !bToBeEncrypted
&& bToBeCompressed
)
420 // the stream is not a package member, not a raw stream,
421 // it should not be encrypted and it should be compressed,
422 // in this case nonseekable access can be used
424 xStream
= pStream
->GetOwnStreamNoWrap();
425 Reference
< XSeekable
> xSeek ( xStream
, UNO_QUERY
);
427 bUseNonSeekableAccess
= ( xStream
.is() && !xSeek
.is() );
430 if ( !bUseNonSeekableAccess
)
432 xStream
= pStream
->getRawData();
436 VOS_ENSURE( 0, "ZipPackageStream didn't have a stream associated with it, skipping!" );
437 bWritingFailed
= sal_True
;
441 Reference
< XSeekable
> xSeek ( xStream
, UNO_QUERY
);
446 // If the stream is a raw one, then we should be positioned
447 // at the beginning of the actual data
448 if ( !bToBeCompressed
|| bRawStream
)
450 // The raw stream can neither be encrypted nor connected
451 OSL_ENSURE( !bRawStream
|| !bToBeCompressed
&& !bToBeEncrypted
, "The stream is already encrypted!\n" );
452 xSeek
->seek ( bRawStream
? pStream
->GetMagicalHackPos() : 0 );
453 ImplSetStoredData ( *pTempEntry
, xStream
);
455 // TODO/LATER: Get rid of hacks related to switching of Flag Method and Size properties!
457 else if ( bToBeEncrypted
)
459 // this is the correct original size
460 pTempEntry
->nSize
= static_cast < sal_Int32
> ( xSeek
->getLength() );
461 nOwnStreamOrigSize
= pTempEntry
->nSize
;
468 // Okay, we don't have an xSeekable stream. This is possibly bad.
469 // check if it's one of our own streams, if it is then we know that
470 // each time we ask for it we'll get a new stream that will be
471 // at position zero...otherwise, assert and skip this stream...
472 if ( pStream
->IsPackageMember() )
474 // if the password has been changed than the stream should not be package member any more
475 if ( pStream
->IsEncrypted() && pStream
->IsToBeEncrypted() )
477 // Should be handled close to the raw stream handling
478 bTransportOwnEncrStreamAsRaw
= sal_True
;
479 pTempEntry
->nMethod
= STORED
;
481 // TODO/LATER: get rid of this situation
482 // this size should be different from the one that will be stored in manifest.xml
483 // it is used in storing algorithms and after storing the correct size will be set
484 pTempEntry
->nSize
= pTempEntry
->nCompressedSize
;
489 VOS_ENSURE( 0, "The package component requires that every stream either be FROM a package or it must support XSeekable!" );
496 VOS_ENSURE( 0, "The stream provided to the package component has problems!" );
497 bWritingFailed
= sal_True
;
501 if ( bToBeEncrypted
|| bRawStream
|| bTransportOwnEncrStreamAsRaw
)
503 if ( bToBeEncrypted
&& !bTransportOwnEncrStreamAsRaw
)
505 Sequence
< sal_uInt8
> aSalt ( 16 ), aVector ( 8 );
506 rtl_random_getBytes ( rRandomPool
, aSalt
.getArray(), 16 );
507 rtl_random_getBytes ( rRandomPool
, aVector
.getArray(), 8 );
508 sal_Int32 nIterationCount
= 1024;
510 if ( !pStream
->HasOwnKey() )
511 pStream
->setKey ( rEncryptionKey
);
513 pStream
->setInitialisationVector ( aVector
);
514 pStream
->setSalt ( aSalt
);
515 pStream
->setIterationCount ( nIterationCount
);
518 // last property is digest, which is inserted later if we didn't have
520 aPropSet
.realloc(PKG_SIZE_ENCR_MNFST
);
522 pValue
= aPropSet
.getArray();
523 pValue
[PKG_MNFST_INIVECTOR
].Name
= sInitialisationVectorProperty
;
524 pValue
[PKG_MNFST_INIVECTOR
].Value
<<= pStream
->getInitialisationVector();
525 pValue
[PKG_MNFST_SALT
].Name
= sSaltProperty
;
526 pValue
[PKG_MNFST_SALT
].Value
<<= pStream
->getSalt();
527 pValue
[PKG_MNFST_ITERATION
].Name
= sIterationCountProperty
;
528 pValue
[PKG_MNFST_ITERATION
].Value
<<= pStream
->getIterationCount ();
530 // Need to store the uncompressed size in the manifest
531 OSL_ENSURE( nOwnStreamOrigSize
>= 0, "The stream size was not correctly initialized!\n" );
532 pValue
[PKG_MNFST_UCOMPSIZE
].Name
= sSizeProperty
;
533 pValue
[PKG_MNFST_UCOMPSIZE
].Value
<<= nOwnStreamOrigSize
;
535 if ( bRawStream
|| bTransportOwnEncrStreamAsRaw
)
537 pValue
[PKG_MNFST_DIGEST
].Name
= sDigestProperty
;
538 pValue
[PKG_MNFST_DIGEST
].Value
<<= pStream
->getDigest();
543 // If the entry is already stored in the zip file in the format we
544 // want for this write...copy it raw
545 if ( !bUseNonSeekableAccess
&&
546 ( bRawStream
|| bTransportOwnEncrStreamAsRaw
||
547 ( pStream
->IsPackageMember() && !bToBeEncrypted
&&
548 ( pStream
->aEntry
.nMethod
== DEFLATED
&& bToBeCompressed
) ||
549 ( pStream
->aEntry
.nMethod
== STORED
&& !bToBeCompressed
) ) ) )
551 // If it's a PackageMember, then it's an unbuffered stream and we need
552 // to get a new version of it as we can't seek backwards.
553 if ( pStream
->IsPackageMember() )
555 xStream
= pStream
->getRawData();
558 // Make sure that we actually _got_ a new one !
559 VOS_ENSURE( 0, "ZipPackageStream didn't have a stream associated with it, skipping!" );
567 xStream
->skipBytes( pStream
->GetMagicalHackPos() );
569 rZipOut
.putNextEntry ( *pTempEntry
, pStream
->getEncryptionData(), sal_False
);
570 // the entry is provided to the ZipOutputStream that will delete it
571 pAutoTempEntry
.release();
573 Sequence
< sal_Int8
> aSeq ( n_ConstBufferSize
);
578 nLength
= xStream
->readBytes( aSeq
, n_ConstBufferSize
);
579 rZipOut
.rawWrite(aSeq
, 0, nLength
);
581 while ( nLength
== n_ConstBufferSize
);
583 rZipOut
.rawCloseEntry();
585 catch ( ZipException
& )
587 VOS_ENSURE( 0, "Error writing ZipOutputStream" );
588 bWritingFailed
= sal_True
;
590 catch ( IOException
& )
592 VOS_ENSURE( 0, "Error writing ZipOutputStream" );
593 bWritingFailed
= sal_True
;
598 // This stream is defenitly not a raw stream
600 // If nonseekable access is used the stream should be at the beginning and
601 // is useless after the storing. Thus if the storing fails the package should
602 // be thrown away ( as actually it is done currently )!
603 // To allow to reuse the package after the error, the optimization must be removed!
605 // If it's a PackageMember, then our previous reference held a 'raw' stream
606 // so we need to re-get it, unencrypted, uncompressed and positioned at the
607 // beginning of the stream
608 if ( pStream
->IsPackageMember() )
610 xStream
= pStream
->getInputStream();
613 // Make sure that we actually _got_ a new one !
614 VOS_ENSURE( 0, "ZipPackageStream didn't have a stream associated with it, skipping!" );
619 if ( bToBeCompressed
)
621 pTempEntry
->nMethod
= DEFLATED
;
622 pTempEntry
->nCrc
= pTempEntry
->nCompressedSize
= pTempEntry
->nSize
= -1;
627 rZipOut
.putNextEntry ( *pTempEntry
, pStream
->getEncryptionData(), bToBeEncrypted
);
628 // the entry is provided to the ZipOutputStream that will delete it
629 pAutoTempEntry
.release();
632 Sequence
< sal_Int8
> aSeq (n_ConstBufferSize
);
635 nLength
= xStream
->readBytes(aSeq
, n_ConstBufferSize
);
636 rZipOut
.write(aSeq
, 0, nLength
);
638 while ( nLength
== n_ConstBufferSize
);
640 rZipOut
.closeEntry();
642 catch ( ZipException
& )
644 VOS_ENSURE( 0, "Error writing ZipOutputStream" );
645 bWritingFailed
= sal_True
;
647 catch ( IOException
& )
649 VOS_ENSURE( 0, "Error writing ZipOutputStream" );
650 bWritingFailed
= sal_True
;
653 if ( bToBeEncrypted
)
655 pValue
[PKG_MNFST_DIGEST
].Name
= sDigestProperty
;
656 pValue
[PKG_MNFST_DIGEST
].Value
<<= pStream
->getDigest();
657 pStream
->SetIsEncrypted ( sal_True
);
661 if( !bWritingFailed
)
663 if ( !pStream
->IsPackageMember() )
665 pStream
->CloseOwnStreamIfAny();
666 pStream
->SetPackageMember ( sal_True
);
671 // the raw stream was integrated and now behaves
672 // as usual encrypted stream
673 pStream
->SetToBeEncrypted( sal_True
);
676 // Remove hacky bit from entry flags
677 if ( pTempEntry
->nFlag
& ( 1 << 4 ) )
679 pTempEntry
->nFlag
&= ~( 1 << 4 );
680 pTempEntry
->nMethod
= STORED
;
683 // Then copy it back afterwards...
684 ZipPackageFolder::copyZipEntry ( pStream
->aEntry
, *pTempEntry
);
686 // TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving )
687 if ( pStream
->IsEncrypted() )
688 pStream
->setSize( nOwnStreamOrigSize
);
690 pStream
->aEntry
.nOffset
*= -1;
694 // folder can have a mediatype only in package format
695 if ( m_nFormat
== PACKAGE_FORMAT
|| ( m_nFormat
== OFOPXML_FORMAT
&& !rInfo
.bFolder
) )
696 rManList
.push_back( aPropSet
);
700 throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
703 void ZipPackageFolder::releaseUpwardRef( void )
705 // Now it is possible that a package folder is disconnected from the package before removing of the folder.
706 // Such a scenario is used in storage implementation. When a new version of a folder is provided the old
707 // one is retrieved, removed from the package but preserved for the error handling.
708 // In this scenario the referencing to the parent is not really useful, since it requires disposing.
710 // Actually there is no need in having a reference to the parent, it even make things more complicated and
711 // requires disposing mechanics. Using of a simple pointer seems to be easier solution and also a safe enough.
716 for ( ContentHash::const_iterator aCI
= maContents
.begin();
717 aCI
!=maContents
.end();
720 ContentInfo
&rInfo
= * (*aCI
).second
;
721 if ( rInfo
.bFolder
)// && ! rInfo.pFolder->HasReleased () )
722 rInfo
.pFolder
->releaseUpwardRef();
723 else //if ( !rInfo.bFolder && !rInfo.pStream->HasReleased() )
724 rInfo
.pStream
->clearParent();
728 VOS_ENSURE ( m_refCount
== 1, "Ref-count is not 1!" );
732 sal_Int64 SAL_CALL
ZipPackageFolder::getSomething( const Sequence
< sal_Int8
>& aIdentifier
)
733 throw(RuntimeException
)
736 if ( aIdentifier
.getLength() == 16 &&
737 0 == rtl_compareMemory(static_getImplementationId().getConstArray(), aIdentifier
.getConstArray(), 16 ) )
738 nMe
= reinterpret_cast < sal_Int64
> ( this );
741 void SAL_CALL
ZipPackageFolder::setPropertyValue( const OUString
& aPropertyName
, const Any
& aValue
)
742 throw(UnknownPropertyException
, PropertyVetoException
, IllegalArgumentException
, WrappedTargetException
, RuntimeException
)
744 if (aPropertyName
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("MediaType")))
746 // TODO/LATER: activate when zip ucp is ready
747 // if ( m_nFormat != PACKAGE_FORMAT )
748 // throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
750 aValue
>>= sMediaType
;
752 else if (aPropertyName
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Version")))
753 aValue
>>= m_sVersion
;
754 else if (aPropertyName
.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Size") ) )
755 aValue
>>= aEntry
.nSize
;
757 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
759 Any SAL_CALL
ZipPackageFolder::getPropertyValue( const OUString
& PropertyName
)
760 throw(UnknownPropertyException
, WrappedTargetException
, RuntimeException
)
762 if (PropertyName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) )
764 // TODO/LATER: activate when zip ucp is ready
765 // if ( m_nFormat != PACKAGE_FORMAT )
766 // throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
768 return makeAny ( sMediaType
);
770 else if (PropertyName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "Version" ) ) )
771 return makeAny( m_sVersion
);
772 else if (PropertyName
.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "Size" ) ) )
773 return makeAny ( aEntry
.nSize
);
775 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX
) ), uno::Reference
< uno::XInterface
>() );
778 void ZipPackageFolder::doInsertByName ( ZipPackageEntry
*pEntry
, sal_Bool bSetParent
)
779 throw(IllegalArgumentException
, ElementExistException
, WrappedTargetException
, RuntimeException
)
781 if ( pEntry
->IsFolder() )
782 maContents
[pEntry
->getName()] = new ContentInfo ( static_cast < ZipPackageFolder
*> ( pEntry
) );
784 maContents
[pEntry
->getName()] = new ContentInfo ( static_cast < ZipPackageStream
*> ( pEntry
) );
787 pEntry
->setParent ( *this );
789 OUString
ZipPackageFolder::getImplementationName()
790 throw (RuntimeException
)
792 return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "ZipPackageFolder" ) );
795 Sequence
< OUString
> ZipPackageFolder::getSupportedServiceNames()
796 throw (RuntimeException
)
798 Sequence
< OUString
> aNames(1);
799 aNames
[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.PackageFolder" ) );
802 sal_Bool SAL_CALL
ZipPackageFolder::supportsService( OUString
const & rServiceName
)
803 throw (RuntimeException
)
805 return rServiceName
== getSupportedServiceNames()[0];