Update ooo320-m1
[ooovba.git] / package / source / zippackage / ZipPackageFolder.cxx
blobc2f717c3042d1f0f8862b3abbbba4948868424b8
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ZipPackageFolder.cxx,v $
10 * $Revision: 1.85 $
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>
41 #include <osl/time.h>
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>
48 #include <memory>
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;
58 using namespace cppu;
59 using namespace rtl;
60 using namespace std;
61 using namespace ::com::sun::star;
62 using vos::ORef;
64 Sequence < sal_Int8 > ZipPackageFolder::aImplementationId = Sequence < sal_Int8 > ();
66 ZipPackageFolder::ZipPackageFolder ( const Reference< XMultiServiceFactory >& xFactory,
67 sal_Int16 nFormat,
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 );
77 aEntry.nVersion = -1;
78 aEntry.nFlag = 0;
79 aEntry.nMethod = STORED;
80 aEntry.nTime = -1;
81 aEntry.nCrc = 0;
82 aEntry.nCompressedSize = 0;
83 aEntry.nSize = 0;
84 aEntry.nOffset = -1;
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;
102 aCI++)
104 const OUString &rShortName = (*aCI).first;
105 const ContentInfo &rInfo = *(*aCI).second;
107 if ( rInfo.bFolder )
109 if ( aPath.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "META-INF/" ) ) ) )
111 // META-INF is not allowed to contain subfolders
112 bHasUnexpected = sal_True;
114 else
116 OUString sOwnPath = aPath + rShortName + OUString( RTL_CONSTASCII_USTRINGPARAM ( "/" ) );
117 bHasUnexpected = rInfo.pFolder->LookForUnexpectedODF12Streams( sOwnPath );
120 else
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)'.' )
154 aExt = aPair.First;
155 else
156 aExt = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "." ) ) + aPair.First;
158 for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
159 aCI != aEnd;
160 aCI++)
162 const OUString &rShortName = (*aCI).first;
163 const ContentInfo &rInfo = *(*aCI).second;
165 if ( rInfo.bFolder )
166 rInfo.pFolder->setChildStreamsTypeByExtension( aPair );
167 else
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;
192 // XNameContainer
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 >() );
198 else
200 Reference < XUnoTunnel > xRef;
201 aElement >>= xRef;
202 if ( ( aElement >>= xRef ) )
204 sal_Int64 nTest;
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 );
216 else
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 );
223 else
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));
241 // XElementAccess
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;
252 // XNameAccess
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();
273 aIterator != aEnd;
274 ++i, ++aIterator)
275 pNames[i] = (*aIterator).first;
276 return aSequence;
278 sal_Bool SAL_CALL ZipPackageFolder::hasByName( const OUString& aName )
279 throw(RuntimeException)
281 return maContents.find ( aName ) != maContents.end ();
283 // XNameReplace
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 );
289 else
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
299 // write them !
300 CRC32 aCRC32;
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();
351 aCI != aEnd;
352 aCI++)
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();
360 if ( rInfo.bFolder )
361 pFolder = rInfo.pFolder;
362 else
363 pStream = rInfo.pStream;
365 if ( rInfo.bFolder )
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);
378 else
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();
434 if ( !xStream.is() )
436 VOS_ENSURE( 0, "ZipPackageStream didn't have a stream associated with it, skipping!" );
437 bWritingFailed = sal_True;
438 continue;
441 Reference < XSeekable > xSeek ( xStream, UNO_QUERY );
444 if ( xSeek.is() )
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;
464 xSeek->seek ( 0 );
466 else
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;
487 else
489 VOS_ENSURE( 0, "The package component requires that every stream either be FROM a package or it must support XSeekable!" );
490 continue;
494 catch ( Exception& )
496 VOS_ENSURE( 0, "The stream provided to the package component has problems!" );
497 bWritingFailed = sal_True;
498 continue;
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
519 // a magic header
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();
556 if ( !xStream.is() )
558 // Make sure that we actually _got_ a new one !
559 VOS_ENSURE( 0, "ZipPackageStream didn't have a stream associated with it, skipping!" );
560 continue;
566 if ( bRawStream )
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 );
574 sal_Int32 nLength;
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;
596 else
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();
611 if ( !xStream.is() )
613 // Make sure that we actually _got_ a new one !
614 VOS_ENSURE( 0, "ZipPackageStream didn't have a stream associated with it, skipping!" );
615 continue;
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();
631 sal_Int32 nLength;
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 );
669 if ( bRawStream )
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 );
699 if( bWritingFailed )
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.
713 clearParent();
715 #if 0
716 for ( ContentHash::const_iterator aCI = maContents.begin();
717 aCI!=maContents.end();
718 aCI++)
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();
726 clearParent();
728 VOS_ENSURE ( m_refCount == 1, "Ref-count is not 1!" );
729 #endif
732 sal_Int64 SAL_CALL ZipPackageFolder::getSomething( const Sequence< sal_Int8 >& aIdentifier )
733 throw(RuntimeException)
735 sal_Int64 nMe = 0;
736 if ( aIdentifier.getLength() == 16 &&
737 0 == rtl_compareMemory(static_getImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) )
738 nMe = reinterpret_cast < sal_Int64 > ( this );
739 return nMe;
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;
756 else
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 );
774 else
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 ) );
783 else
784 maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageStream *> ( pEntry ) );
786 if ( bSetParent )
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" ) );
800 return aNames;
802 sal_Bool SAL_CALL ZipPackageFolder::supportsService( OUString const & rServiceName )
803 throw (RuntimeException)
805 return rServiceName == getSupportedServiceNames()[0];