masterfix DEV300: #i10000# build fix
[LibreOffice.git] / package / source / zippackage / ZipPackage.cxx
blob41d944288d530d989bb0a2fa079ce6e7341b6f93
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * ( a copy is included in the LICENSE file that accompanied this code ).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER( update_precomp.py ): autogen include statement, do not remove
29 #include "precompiled_package.hxx"
30 #include <ZipPackage.hxx>
31 #include <ZipPackageSink.hxx>
32 #include <ZipEnumeration.hxx>
33 #include <ZipPackageStream.hxx>
34 #include <ZipPackageFolder.hxx>
35 #include <ZipOutputStream.hxx>
36 #include <ZipPackageBuffer.hxx>
37 #include <ZipFile.hxx>
38 #include <PackageConstants.hxx>
39 #include <com/sun/star/beans/PropertyValue.hpp>
40 #include <com/sun/star/beans/NamedValue.hpp>
41 #include <com/sun/star/packages/zip/ZipConstants.hpp>
42 #include <com/sun/star/packages/manifest/XManifestReader.hpp>
43 #include <com/sun/star/packages/manifest/XManifestWriter.hpp>
44 #include <com/sun/star/io/XStream.hpp>
45 #include <com/sun/star/io/XInputStream.hpp>
46 #include <com/sun/star/io/XOutputStream.hpp>
47 #include <com/sun/star/io/XTruncate.hpp>
48 #include <com/sun/star/io/XSeekable.hpp>
49 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
50 #include <com/sun/star/container/XNameContainer.hpp>
51 #include <com/sun/star/ucb/IOErrorCode.hpp>
52 #include <ucbhelper/content.hxx>
53 #include <cppuhelper/factory.hxx>
54 #include <cppuhelper/exc_hlp.hxx>
55 #include <com/sun/star/ucb/TransferInfo.hpp>
56 #include <com/sun/star/ucb/NameClash.hpp>
57 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
58 #include <com/sun/star/ucb/OpenMode.hpp>
59 #include <com/sun/star/ucb/XProgressHandler.hpp>
60 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
61 #include <com/sun/star/io/XActiveDataStreamer.hpp>
62 #include <com/sun/star/embed/XTransactedObject.hpp>
63 #include <com/sun/star/embed/UseBackupException.hpp>
64 #include <com/sun/star/embed/StorageFormats.hpp>
65 #include <com/sun/star/beans/NamedValue.hpp>
66 #include <com/sun/star/xml/crypto/DigestID.hpp>
67 #include <com/sun/star/xml/crypto/CipherID.hpp>
68 #include <cppuhelper/implbase1.hxx>
69 #include <ContentInfo.hxx>
70 #include <cppuhelper/typeprovider.hxx>
71 #include <rtl/uri.hxx>
72 #include <rtl/random.h>
73 #include <rtl/logfile.hxx>
74 #include <rtl/instance.hxx>
75 #include <osl/time.h>
76 #include <osl/file.hxx>
77 #include "com/sun/star/io/XAsyncOutputMonitor.hpp"
79 #include <memory>
80 #include <vector>
82 #include <ucbhelper/contentbroker.hxx>
83 #include <ucbhelper/fileidentifierconverter.hxx>
84 #include <comphelper/seekableinput.hxx>
85 #include <comphelper/storagehelper.hxx>
86 #include <comphelper/ofopxmlhelper.hxx>
87 #include <comphelper/documentconstants.hxx>
88 #include <comphelper/sequenceashashmap.hxx>
90 using namespace rtl;
91 using namespace std;
92 using namespace osl;
93 using namespace cppu;
94 using namespace ucbhelper;
95 using namespace com::sun::star;
96 using namespace com::sun::star::io;
97 using namespace com::sun::star::uno;
98 using namespace com::sun::star::ucb;
99 using namespace com::sun::star::util;
100 using namespace com::sun::star::lang;
101 using namespace com::sun::star::task;
102 using namespace com::sun::star::beans;
103 using namespace com::sun::star::packages;
104 using namespace com::sun::star::container;
105 using namespace com::sun::star::packages::zip;
106 using namespace com::sun::star::packages::manifest;
107 using namespace com::sun::star::packages::zip::ZipConstants;
109 #define LOGFILE_AUTHOR "mg115289"
112 namespace {
114 sal_Bool isLocalFile_Impl( ::rtl::OUString aURL )
116 ::rtl::OUString aSystemPath;
117 ContentBroker* pBroker = ContentBroker::get();
118 if ( !pBroker )
120 ::rtl::OUString aRet;
121 if ( FileBase::getSystemPathFromFileURL( aURL, aRet ) == FileBase::E_None )
122 aSystemPath = aRet;
124 else
126 uno::Reference< XContentProviderManager > xManager =
127 pBroker->getContentProviderManagerInterface();
130 aSystemPath = getSystemPathFromFileURL( xManager, aURL );
132 catch ( Exception& )
137 return ( aSystemPath.getLength() != 0 );
142 //===========================================================================
144 class ActiveDataStreamer : public ::cppu::WeakImplHelper1< XActiveDataStreamer >
146 uno::Reference< XStream > mStream;
147 public:
149 virtual uno::Reference< XStream > SAL_CALL getStream()
150 throw( RuntimeException )
151 { return mStream; }
153 virtual void SAL_CALL setStream( const uno::Reference< XStream >& stream )
154 throw( RuntimeException )
155 { mStream = stream; }
158 class DummyInputStream : public ::cppu::WeakImplHelper1< XInputStream >
160 virtual sal_Int32 SAL_CALL readBytes( uno::Sequence< sal_Int8 >&, sal_Int32 )
161 throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
162 { return 0; }
164 virtual sal_Int32 SAL_CALL readSomeBytes( uno::Sequence< sal_Int8 >&, sal_Int32 )
165 throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
166 { return 0; }
168 virtual void SAL_CALL skipBytes( sal_Int32 )
169 throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
172 virtual sal_Int32 SAL_CALL available()
173 throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
174 { return 0; }
176 virtual void SAL_CALL closeInput()
177 throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
181 //===========================================================================
183 ZipPackage::ZipPackage ( const uno::Reference < XMultiServiceFactory > &xNewFactory )
184 : m_aMutexHolder( new SotMutexHolder )
185 , m_nStartKeyGenerationID( xml::crypto::DigestID::SHA1 )
186 , m_nChecksumDigestID( xml::crypto::DigestID::SHA1_1K )
187 , m_nCommonEncryptionID( xml::crypto::CipherID::BLOWFISH_CFB_8 )
188 , m_bHasEncryptedEntries ( sal_False )
189 , m_bHasNonEncryptedEntries ( sal_False )
190 , m_bInconsistent ( sal_False )
191 , m_bForceRecovery ( sal_False )
192 , m_bMediaTypeFallbackUsed ( sal_False )
193 , m_nFormat( embed::StorageFormats::PACKAGE ) // package is the default format
194 , m_bAllowRemoveOnInsert( sal_True )
195 , m_eMode ( e_IMode_None )
196 , m_xFactory( xNewFactory )
197 , m_pRootFolder( NULL )
198 , m_pZipFile( NULL )
200 m_xRootFolder = m_pRootFolder = new ZipPackageFolder( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert );
203 ZipPackage::~ZipPackage( void )
205 delete m_pZipFile;
207 // All folders and streams contain pointers to their parents, when a parent diappeares
208 // it should disconnect all the children from itself during destruction automatically.
209 // So there is no need in explicit m_pRootFolder->releaseUpwardRef() call here any more
210 // since m_pRootFolder has no parent and cleaning of it's children will be done automatically
211 // during m_pRootFolder dieing by refcount.
214 //--------------------------------------------------------
215 void ZipPackage::parseManifest()
217 if ( m_nFormat == embed::StorageFormats::PACKAGE )
219 sal_Bool bManifestParsed = sal_False;
220 bool bDifferentStartKeyAlgorithm = false;
221 const OUString sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) );
222 if ( m_xRootFolder->hasByName( sMeta ) )
224 const OUString sManifest ( RTL_CONSTASCII_USTRINGPARAM( "manifest.xml" ) );
226 try {
227 uno::Reference< XUnoTunnel > xTunnel;
228 Any aAny = m_xRootFolder->getByName( sMeta );
229 aAny >>= xTunnel;
230 uno::Reference< XNameContainer > xMetaInfFolder( xTunnel, UNO_QUERY );
231 if ( xMetaInfFolder.is() && xMetaInfFolder->hasByName( sManifest ) )
233 aAny = xMetaInfFolder->getByName( sManifest );
234 aAny >>= xTunnel;
235 uno::Reference < XActiveDataSink > xSink ( xTunnel, UNO_QUERY );
236 if ( xSink.is() )
238 OUString sManifestReader ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestReader" ) );
239 uno::Reference < XManifestReader > xReader ( m_xFactory->createInstance( sManifestReader ), UNO_QUERY );
240 if ( xReader.is() )
242 const OUString sPropFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
243 const OUString sPropVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) );
244 const OUString sPropMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
245 const OUString sPropInitialisationVector ( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) );
246 const OUString sPropSalt ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) );
247 const OUString sPropIterationCount ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) );
248 const OUString sPropSize ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) );
249 const OUString sPropDigest ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) );
250 const OUString sPropDerivedKeySize ( RTL_CONSTASCII_USTRINGPARAM ( "DerivedKeySize" ) );
251 const OUString sPropDigestAlgorithm ( RTL_CONSTASCII_USTRINGPARAM ( "DigestAlgorithm" ) );
252 const OUString sPropEncryptionAlgorithm ( RTL_CONSTASCII_USTRINGPARAM ( "EncryptionAlgorithm" ) );
253 const OUString sPropStartKeyAlgorithm ( RTL_CONSTASCII_USTRINGPARAM ( "StartKeyAlgorithm" ) );
255 uno::Sequence < uno::Sequence < PropertyValue > > aManifestSequence = xReader->readManifestSequence ( xSink->getInputStream() );
256 sal_Int32 nLength = aManifestSequence.getLength();
257 const uno::Sequence < PropertyValue > *pSequence = aManifestSequence.getConstArray();
258 ZipPackageStream *pStream = NULL;
259 ZipPackageFolder *pFolder = NULL;
261 for ( sal_Int32 i = 0; i < nLength ; i++, pSequence++ )
263 OUString sPath, sMediaType, sVersion;
264 const PropertyValue *pValue = pSequence->getConstArray();
265 const Any *pSalt = NULL, *pVector = NULL, *pCount = NULL, *pSize = NULL, *pDigest = NULL, *pDigestAlg = NULL, *pEncryptionAlg = NULL, *pStartKeyAlg = NULL, *pDerivedKeySize = NULL;
266 for ( sal_Int32 j = 0, nNum = pSequence->getLength(); j < nNum; j++ )
268 if ( pValue[j].Name.equals( sPropFullPath ) )
269 pValue[j].Value >>= sPath;
270 else if ( pValue[j].Name.equals( sPropVersion ) )
271 pValue[j].Value >>= sVersion;
272 else if ( pValue[j].Name.equals( sPropMediaType ) )
273 pValue[j].Value >>= sMediaType;
274 else if ( pValue[j].Name.equals( sPropSalt ) )
275 pSalt = &( pValue[j].Value );
276 else if ( pValue[j].Name.equals( sPropInitialisationVector ) )
277 pVector = &( pValue[j].Value );
278 else if ( pValue[j].Name.equals( sPropIterationCount ) )
279 pCount = &( pValue[j].Value );
280 else if ( pValue[j].Name.equals( sPropSize ) )
281 pSize = &( pValue[j].Value );
282 else if ( pValue[j].Name.equals( sPropDigest ) )
283 pDigest = &( pValue[j].Value );
284 else if ( pValue[j].Name.equals( sPropDigestAlgorithm ) )
285 pDigestAlg = &( pValue[j].Value );
286 else if ( pValue[j].Name.equals( sPropEncryptionAlgorithm ) )
287 pEncryptionAlg = &( pValue[j].Value );
288 else if ( pValue[j].Name.equals( sPropStartKeyAlgorithm ) )
289 pStartKeyAlg = &( pValue[j].Value );
290 else if ( pValue[j].Name.equals( sPropDerivedKeySize ) )
291 pDerivedKeySize = &( pValue[j].Value );
294 if ( sPath.getLength() && hasByHierarchicalName ( sPath ) )
296 aAny = getByHierarchicalName( sPath );
297 uno::Reference < XUnoTunnel > xUnoTunnel;
298 aAny >>= xUnoTunnel;
299 sal_Int64 nTest=0;
300 if ( (nTest = xUnoTunnel->getSomething( ZipPackageFolder::static_getImplementationId() )) != 0 )
302 pFolder = reinterpret_cast < ZipPackageFolder* > ( nTest );
303 pFolder->SetMediaType ( sMediaType );
304 pFolder->SetVersion ( sVersion );
306 else
308 pStream = reinterpret_cast < ZipPackageStream* > ( xUnoTunnel->getSomething( ZipPackageStream::static_getImplementationId() ));
309 pStream->SetMediaType ( sMediaType );
310 pStream->SetFromManifest( sal_True );
312 if ( pSalt && pVector && pCount && pSize && pDigest && pDigestAlg && pEncryptionAlg )
314 uno::Sequence < sal_Int8 > aSequence;
315 sal_Int32 nCount = 0, nSize = 0, nDigestAlg = 0, nEncryptionAlg = 0, nDerivedKeySize = 16, nStartKeyAlg = xml::crypto::DigestID::SHA1;
317 pStream->SetToBeEncrypted ( sal_True );
319 *pSalt >>= aSequence;
320 pStream->setSalt ( aSequence );
322 *pVector >>= aSequence;
323 pStream->setInitialisationVector ( aSequence );
325 *pCount >>= nCount;
326 pStream->setIterationCount ( nCount );
328 *pSize >>= nSize;
329 pStream->setSize ( nSize );
331 *pDigest >>= aSequence;
332 pStream->setDigest ( aSequence );
334 *pDigestAlg >>= nDigestAlg;
335 pStream->SetImportedChecksumAlgorithm( nDigestAlg );
337 *pEncryptionAlg >>= nEncryptionAlg;
338 pStream->SetImportedEncryptionAlgorithm( nEncryptionAlg );
340 if ( pDerivedKeySize )
341 *pDerivedKeySize >>= nDerivedKeySize;
342 pStream->SetImportedDerivedKeySize( nDerivedKeySize );
344 if ( pStartKeyAlg )
345 *pStartKeyAlg >>= nStartKeyAlg;
346 pStream->SetImportedStartKeyAlgorithm( nStartKeyAlg );
348 pStream->SetToBeCompressed ( sal_True );
349 pStream->SetToBeEncrypted ( sal_True );
350 pStream->SetIsEncrypted ( sal_True );
351 if ( !m_bHasEncryptedEntries
352 && pStream->getName().equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "content.xml" ) ) ) )
354 m_bHasEncryptedEntries = sal_True;
355 m_nStartKeyGenerationID = nStartKeyAlg;
356 m_nChecksumDigestID = nDigestAlg;
357 m_nCommonEncryptionID = nEncryptionAlg;
360 else
361 m_bHasNonEncryptedEntries = sal_True;
366 bManifestParsed = sal_True;
368 else
369 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No manifes parser!" ) ), uno::Reference< uno::XInterface >() );
372 // now hide the manifest.xml file from user
373 xMetaInfFolder->removeByName( sManifest );
376 catch( Exception& )
378 if ( !m_bForceRecovery )
379 throw;
383 if ( !bManifestParsed && !m_bForceRecovery )
384 throw ZipIOException(
385 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Could not parse manifest.xml\n" ) ),
386 uno::Reference< uno::XInterface >() );
388 const OUString sMimetype ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) );
389 if ( m_xRootFolder->hasByName( sMimetype ) )
391 // get mediatype from the "mimetype" stream
392 ::rtl::OUString aPackageMediatype;
393 uno::Reference< lang::XUnoTunnel > xMimeTypeTunnel;
394 m_xRootFolder->getByName( sMimetype ) >>= xMimeTypeTunnel;
395 uno::Reference < io::XActiveDataSink > xMimeSink( xMimeTypeTunnel, UNO_QUERY );
396 if ( xMimeSink.is() )
398 uno::Reference< io::XInputStream > xMimeInStream = xMimeSink->getInputStream();
399 if ( xMimeInStream.is() )
401 // Mediatypes longer than 1024 symbols should not appear here
402 uno::Sequence< sal_Int8 > aData( 1024 );
403 sal_Int32 nRead = xMimeInStream->readBytes( aData, 1024 );
404 if ( nRead > aData.getLength() )
405 nRead = aData.getLength();
407 if ( nRead )
408 aPackageMediatype = ::rtl::OUString( ( sal_Char* )aData.getConstArray(), nRead, RTL_TEXTENCODING_ASCII_US );
413 if ( !bManifestParsed )
415 // the manifest.xml could not be successfuly parsed, this is an inconsistent package
416 if ( aPackageMediatype.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "application/vnd." ) ) == 0 )
418 // accept only types that look similar to own mediatypes
419 m_pRootFolder->SetMediaType( aPackageMediatype );
420 m_bMediaTypeFallbackUsed = sal_True;
423 else if ( !m_bForceRecovery )
425 // the mimetype stream should contain the information from manifest.xml
426 if ( !m_pRootFolder->GetMediaType().equals( aPackageMediatype ) )
427 throw ZipIOException(
428 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "mimetype conflicts with manifest.xml\n" ) ),
429 uno::Reference< uno::XInterface >() );
432 m_xRootFolder->removeByName( sMimetype );
435 m_bInconsistent = m_pRootFolder->LookForUnexpectedODF12Streams( ::rtl::OUString() );
437 sal_Bool bODF12AndNewer = ( m_pRootFolder->GetVersion().compareTo( ODFVER_012_TEXT ) >= 0 );
438 if ( !m_bForceRecovery && bODF12AndNewer )
440 if ( m_bInconsistent )
442 // this is an ODF1.2 document that contains streams not referred in the manifest.xml;
443 // in case of ODF1.2 documents without version in manifest.xml the property IsInconsistent
444 // should be checked later
445 throw ZipIOException(
446 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "there are streams not referred in manifest.xml\n" ) ),
447 uno::Reference< uno::XInterface >() );
449 else if ( bDifferentStartKeyAlgorithm )
451 // all the streams should be encrypted with the same StartKey in ODF1.2
452 // TODO/LATER: in future the exception should be thrown
453 OSL_ENSURE( false, "ODF1.2 contains different StartKey Algorithms" );
454 // throw ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "More than one Start Key Generation algorithm is specified!" ) ), uno::Reference< uno::XInterface >() );
458 // in case it is a correct ODF1.2 document, the version must be set
459 // and the META-INF folder is reserved for package format
460 if ( bODF12AndNewer )
461 m_xRootFolder->removeByName( sMeta );
465 //--------------------------------------------------------
466 void ZipPackage::parseContentType()
468 if ( m_nFormat == embed::StorageFormats::OFOPXML )
470 const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
471 try {
472 // the content type must exist in OFOPXML format!
473 if ( !m_xRootFolder->hasByName( aContentTypes ) )
474 throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong format!" ) ),
475 uno::Reference< uno::XInterface >() );
477 uno::Reference< lang::XUnoTunnel > xTunnel;
478 uno::Any aAny = m_xRootFolder->getByName( aContentTypes );
479 aAny >>= xTunnel;
480 uno::Reference < io::XActiveDataSink > xSink( xTunnel, UNO_QUERY );
481 if ( xSink.is() )
483 uno::Reference< io::XInputStream > xInStream = xSink->getInputStream();
484 if ( xInStream.is() )
486 sal_Int32 nInd = 0;
487 // here aContentTypeInfo[0] - Defaults, and aContentTypeInfo[1] - Overrides
488 uno::Sequence< uno::Sequence< beans::StringPair > > aContentTypeInfo =
489 ::comphelper::OFOPXMLHelper::ReadContentTypeSequence( xInStream, m_xFactory );
491 if ( aContentTypeInfo.getLength() != 2 )
492 throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
494 // set the implicit types fist
495 for ( nInd = 0; nInd < aContentTypeInfo[0].getLength(); nInd++ )
496 m_pRootFolder->setChildStreamsTypeByExtension( aContentTypeInfo[0][nInd] );
498 // now set the explicit types
499 for ( nInd = 0; nInd < aContentTypeInfo[1].getLength(); nInd++ )
501 ::rtl::OUString aPath;
502 if ( aContentTypeInfo[1][nInd].First.toChar() == ( sal_Unicode )'/' )
503 aPath = aContentTypeInfo[1][nInd].First.copy( 1 );
504 else
505 aPath = aContentTypeInfo[1][nInd].First;
507 if ( aPath.getLength() && hasByHierarchicalName( aPath ) )
509 uno::Any aIterAny = getByHierarchicalName( aPath );
510 uno::Reference < lang::XUnoTunnel > xIterTunnel;
511 aIterAny >>= xIterTunnel;
512 sal_Int64 nTest = xIterTunnel->getSomething( ZipPackageStream::static_getImplementationId() );
513 if ( nTest != 0 )
515 // this is a package stream, in OFOPXML format only streams can have mediatype
516 ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream* > ( nTest );
517 pStream->SetMediaType( aContentTypeInfo[1][nInd].Second );
524 m_xRootFolder->removeByName( aContentTypes );
526 catch( uno::Exception& )
528 if ( !m_bForceRecovery )
529 throw;
534 //--------------------------------------------------------
535 void ZipPackage::getZipFileContents()
537 auto_ptr < ZipEnumeration > pEnum ( m_pZipFile->entries() );
538 ZipPackageStream *pPkgStream;
539 ZipPackageFolder *pPkgFolder, *pCurrent;
540 OUString sTemp, sDirName;
541 sal_Int32 nOldIndex, nIndex, nStreamIndex;
542 FolderHash::iterator aIter;
544 while ( pEnum->hasMoreElements() )
546 nIndex = nOldIndex = 0;
547 pCurrent = m_pRootFolder;
548 const ZipEntry & rEntry = *pEnum->nextElement();
549 OUString rName = rEntry.sPath;
551 if ( m_bForceRecovery )
553 // the PKZIP Application note version 6.2 does not allows to use '\' as separator
554 // unfortunately it is used by some implementations, so we have to support it in recovery mode
555 rName = rName.replace( '\\', '/' );
558 nStreamIndex = rName.lastIndexOf ( '/' );
559 if ( nStreamIndex != -1 )
561 sDirName = rName.copy ( 0, nStreamIndex );
562 aIter = m_aRecent.find ( sDirName );
563 if ( aIter != m_aRecent.end() )
564 pCurrent = ( *aIter ).second;
567 if ( pCurrent == m_pRootFolder )
569 while ( ( nIndex = rName.indexOf( '/', nOldIndex ) ) != -1 )
571 sTemp = rName.copy ( nOldIndex, nIndex - nOldIndex );
572 if ( nIndex == nOldIndex )
573 break;
574 if ( !pCurrent->hasByName( sTemp ) )
576 pPkgFolder = new ZipPackageFolder( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert );
577 pPkgFolder->setName( sTemp );
578 pPkgFolder->doSetParent( pCurrent, sal_True );
579 pCurrent = pPkgFolder;
581 else
582 pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
583 nOldIndex = nIndex+1;
585 if ( nStreamIndex != -1 && sDirName.getLength() )
586 m_aRecent [ sDirName ] = pCurrent;
588 if ( rName.getLength() -1 != nStreamIndex )
590 nStreamIndex++;
591 sTemp = rName.copy( nStreamIndex, rName.getLength() - nStreamIndex );
592 pPkgStream = new ZipPackageStream( *this, m_xFactory, m_bAllowRemoveOnInsert );
593 pPkgStream->SetPackageMember( sal_True );
594 pPkgStream->setZipEntryOnLoading( rEntry );
595 pPkgStream->setName( sTemp );
596 pPkgStream->doSetParent( pCurrent, sal_True );
600 if ( m_nFormat == embed::StorageFormats::PACKAGE )
601 parseManifest();
602 else if ( m_nFormat == embed::StorageFormats::OFOPXML )
603 parseContentType();
606 //--------------------------------------------------------
607 void SAL_CALL ZipPackage::initialize( const uno::Sequence< Any >& aArguments )
608 throw( Exception, RuntimeException )
610 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::initialize" );
611 sal_Bool bBadZipFile = sal_False, bHaveZipFile = sal_True;
612 uno::Reference< XProgressHandler > xProgressHandler;
613 beans::NamedValue aNamedValue;
615 if ( aArguments.getLength() )
617 for( int ind = 0; ind < aArguments.getLength(); ind++ )
619 OUString aParamUrl;
620 if ( ( aArguments[ind] >>= aParamUrl ))
622 m_eMode = e_IMode_URL;
625 sal_Int32 nParam = aParamUrl.indexOf( '?' );
626 if ( nParam >= 0 )
628 m_aURL = aParamUrl.copy( 0, nParam );
629 OUString aParam = aParamUrl.copy( nParam + 1 );
631 sal_Int32 nIndex = 0;
634 ::rtl::OUString aCommand = aParam.getToken( 0, '&', nIndex );
635 if ( aCommand.equals( OUString::createFromAscii( "repairpackage" ) ) )
637 m_bForceRecovery = sal_True;
638 break;
640 else if ( aCommand.equals( OUString::createFromAscii( "purezip" ) ) )
642 m_nFormat = embed::StorageFormats::ZIP;
643 m_pRootFolder->setPackageFormat_Impl( m_nFormat );
644 break;
646 else if ( aCommand.equals( OUString::createFromAscii( "ofopxml" ) ) )
648 m_nFormat = embed::StorageFormats::OFOPXML;
649 m_pRootFolder->setPackageFormat_Impl( m_nFormat );
650 break;
653 while ( nIndex >= 0 );
655 else
656 m_aURL = aParamUrl;
658 Content aContent ( m_aURL, uno::Reference < XCommandEnvironment >() );
659 Any aAny = aContent.getPropertyValue( OUString::createFromAscii( "Size" ) );
660 sal_uInt64 aSize = 0;
661 // kind of optimisation: treat empty files as nonexistent files
662 // and write to such files directly. Note that "Size" property is optional.
663 bool bHasSizeProperty = aAny >>= aSize;
664 if( !bHasSizeProperty || ( bHasSizeProperty && aSize ) )
666 uno::Reference < XActiveDataSink > xSink = new ZipPackageSink;
667 if ( aContent.openStream ( xSink ) )
668 m_xContentStream = xSink->getInputStream();
670 else
671 bHaveZipFile = sal_False;
673 catch ( com::sun::star::uno::Exception& )
675 // Exception derived from uno::Exception thrown. This probably
676 // means the file doesn't exist...we'll create it at
677 // commitChanges time
678 bHaveZipFile = sal_False;
681 else if ( ( aArguments[ind] >>= m_xStream ) )
683 // a writable stream can implement both XStream & XInputStream
684 m_eMode = e_IMode_XStream;
685 m_xContentStream = m_xStream->getInputStream();
687 else if ( ( aArguments[ind] >>= m_xContentStream ) )
689 m_eMode = e_IMode_XInputStream;
691 else if ( ( aArguments[ind] >>= aNamedValue ) )
693 if ( aNamedValue.Name.equalsAscii( "RepairPackage" ) )
694 aNamedValue.Value >>= m_bForceRecovery;
695 else if ( aNamedValue.Name.equalsAscii( "PackageFormat" ) )
697 // setting this argument to true means Package format
698 // setting it to false means plain Zip format
700 sal_Bool bPackFormat = sal_True;
701 aNamedValue.Value >>= bPackFormat;
702 if ( !bPackFormat )
703 m_nFormat = embed::StorageFormats::ZIP;
705 m_pRootFolder->setPackageFormat_Impl( m_nFormat );
707 else if ( aNamedValue.Name.equalsAscii( "StorageFormat" ) )
709 ::rtl::OUString aFormatName;
710 sal_Int32 nFormatID = 0;
711 if ( aNamedValue.Value >>= aFormatName )
713 if ( aFormatName.equals( PACKAGE_STORAGE_FORMAT_STRING ) )
714 m_nFormat = embed::StorageFormats::PACKAGE;
715 else if ( aFormatName.equals( ZIP_STORAGE_FORMAT_STRING ) )
716 m_nFormat = embed::StorageFormats::ZIP;
717 else if ( aFormatName.equals( OFOPXML_STORAGE_FORMAT_STRING ) )
718 m_nFormat = embed::StorageFormats::OFOPXML;
719 else
720 throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
722 else if ( aNamedValue.Value >>= nFormatID )
724 if ( nFormatID != embed::StorageFormats::PACKAGE
725 && nFormatID != embed::StorageFormats::ZIP
726 && nFormatID != embed::StorageFormats::OFOPXML )
727 throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
729 m_nFormat = nFormatID;
731 else
732 throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
734 m_pRootFolder->setPackageFormat_Impl( m_nFormat );
736 else if ( aNamedValue.Name.equalsAscii( "AllowRemoveOnInsert" ) )
738 aNamedValue.Value >>= m_bAllowRemoveOnInsert;
739 m_pRootFolder->setRemoveOnInsertMode_Impl( m_bAllowRemoveOnInsert );
742 // for now the progress handler is not used, probably it will never be
743 // if ( aNamedValue.Name.equalsAscii( "ProgressHandler" )
745 else
747 // The URL is not acceptable
748 throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad arguments." ) ),
749 static_cast < ::cppu::OWeakObject * > ( this ) );
755 if ( m_xContentStream.is() )
757 // the stream must be seekable, if it is not it will be wrapped
758 m_xContentStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( m_xContentStream, m_xFactory );
759 m_xContentSeek = uno::Reference < XSeekable > ( m_xContentStream, UNO_QUERY );
760 if ( ! m_xContentSeek.is() )
761 throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "The package component _requires_ an XSeekable interface!" ) ),
762 static_cast < ::cppu::OWeakObject * > ( this ) );
764 if ( !m_xContentSeek->getLength() )
765 bHaveZipFile = sal_False;
767 else
768 bHaveZipFile = sal_False;
770 catch ( com::sun::star::uno::Exception& )
772 // Exception derived from uno::Exception thrown. This probably
773 // means the file doesn't exist...we'll create it at
774 // commitChanges time
775 bHaveZipFile = sal_False;
777 if ( bHaveZipFile )
781 m_pZipFile = new ZipFile ( m_xContentStream, m_xFactory, sal_True, m_bForceRecovery, xProgressHandler );
782 getZipFileContents();
784 catch ( IOException & )
786 bBadZipFile = sal_True;
788 catch ( ZipException & )
790 bBadZipFile = sal_True;
792 catch ( Exception & )
794 if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; }
795 throw;
798 if ( bBadZipFile )
800 // clean up the memory, and tell the UCB about the error
801 if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; }
803 throw com::sun::star::packages::zip::ZipIOException (
804 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad Zip File." ) ),
805 static_cast < ::cppu::OWeakObject * > ( this ) );
810 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::initialize" );
813 //--------------------------------------------------------
814 Any SAL_CALL ZipPackage::getByHierarchicalName( const OUString& aName )
815 throw( NoSuchElementException, RuntimeException )
817 OUString sTemp, sDirName;
818 sal_Int32 nOldIndex, nIndex, nStreamIndex;
819 FolderHash::iterator aIter;
821 if ( ( nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' )
822 return makeAny ( uno::Reference < XUnoTunnel > ( m_pRootFolder ) );
823 else
825 nStreamIndex = aName.lastIndexOf ( '/' );
826 bool bFolder = nStreamIndex == nIndex-1;
827 if ( nStreamIndex != -1 )
829 sDirName = aName.copy ( 0, nStreamIndex );
830 aIter = m_aRecent.find ( sDirName );
831 if ( aIter != m_aRecent.end() )
833 if ( bFolder )
835 sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex );
836 sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 );
837 if ( sTemp == ( *aIter ).second->getName() )
838 return makeAny ( uno::Reference < XUnoTunnel > ( ( *aIter ).second ) );
839 else
840 m_aRecent.erase ( aIter );
842 else
844 sTemp = aName.copy ( nStreamIndex + 1 );
845 if ( ( *aIter ).second->hasByName( sTemp ) )
846 return ( *aIter ).second->getByName( sTemp );
847 else
848 m_aRecent.erase( aIter );
852 else
854 if ( m_pRootFolder->hasByName ( aName ) )
855 return m_pRootFolder->getByName ( aName );
857 nOldIndex = 0;
858 ZipPackageFolder * pCurrent = m_pRootFolder;
859 ZipPackageFolder * pPrevious = NULL;
860 while ( ( nIndex = aName.indexOf( '/', nOldIndex )) != -1 )
862 sTemp = aName.copy ( nOldIndex, nIndex - nOldIndex );
863 if ( nIndex == nOldIndex )
864 break;
865 if ( pCurrent->hasByName( sTemp ) )
867 pPrevious = pCurrent;
868 pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
870 else
871 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
872 nOldIndex = nIndex+1;
874 if ( bFolder )
876 if ( nStreamIndex != -1 )
877 m_aRecent[sDirName] = pPrevious;
878 return makeAny ( uno::Reference < XUnoTunnel > ( pCurrent ) );
880 else
882 sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex );
883 if ( pCurrent->hasByName ( sTemp ) )
885 if ( nStreamIndex != -1 )
886 m_aRecent[sDirName] = pCurrent;
887 return pCurrent->getByName( sTemp );
889 else
890 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
895 //--------------------------------------------------------
896 sal_Bool SAL_CALL ZipPackage::hasByHierarchicalName( const OUString& aName )
897 throw( RuntimeException )
899 OUString sTemp, sDirName;
900 sal_Int32 nOldIndex, nIndex, nStreamIndex;
901 FolderHash::iterator aIter;
903 if ( ( nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' )
904 return sal_True;
905 else
907 nStreamIndex = aName.lastIndexOf ( '/' );
908 bool bFolder = nStreamIndex == nIndex-1;
909 if ( nStreamIndex != -1 )
911 sDirName = aName.copy ( 0, nStreamIndex );
912 aIter = m_aRecent.find ( sDirName );
913 if ( aIter != m_aRecent.end() )
915 if ( bFolder )
917 sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex );
918 sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 );
919 if ( sTemp == ( *aIter ).second->getName() )
920 return sal_True;
921 else
922 m_aRecent.erase ( aIter );
924 else
926 sTemp = aName.copy ( nStreamIndex + 1 );
927 if ( ( *aIter ).second->hasByName( sTemp ) )
928 return sal_True;
929 else
930 m_aRecent.erase( aIter );
934 else
936 if ( m_pRootFolder->hasByName ( aName ) )
937 return sal_True;
939 ZipPackageFolder * pCurrent = m_pRootFolder;
940 ZipPackageFolder * pPrevious = NULL;
941 nOldIndex = 0;
942 while ( ( nIndex = aName.indexOf( '/', nOldIndex )) != -1 )
944 sTemp = aName.copy ( nOldIndex, nIndex - nOldIndex );
945 if ( nIndex == nOldIndex )
946 break;
947 if ( pCurrent->hasByName( sTemp ) )
949 pPrevious = pCurrent;
950 pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
952 else
953 return sal_False;
954 nOldIndex = nIndex+1;
956 if ( bFolder )
958 m_aRecent[sDirName] = pPrevious;
959 return sal_True;
961 else
963 sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex );
965 if ( pCurrent->hasByName( sTemp ) )
967 m_aRecent[sDirName] = pCurrent;
968 return sal_True;
971 return sal_False;
975 //--------------------------------------------------------
976 uno::Reference< XInterface > SAL_CALL ZipPackage::createInstance()
977 throw( Exception, RuntimeException )
979 uno::Reference < XInterface > xRef = *( new ZipPackageStream ( *this, m_xFactory, m_bAllowRemoveOnInsert ) );
980 return xRef;
982 //--------------------------------------------------------
983 uno::Reference< XInterface > SAL_CALL ZipPackage::createInstanceWithArguments( const uno::Sequence< Any >& aArguments )
984 throw( Exception, RuntimeException )
986 sal_Bool bArg = sal_False;
987 uno::Reference < XInterface > xRef;
988 if ( aArguments.getLength() )
989 aArguments[0] >>= bArg;
990 if ( bArg )
991 xRef = *new ZipPackageFolder ( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert );
992 else
993 xRef = *new ZipPackageStream ( *this, m_xFactory, m_bAllowRemoveOnInsert );
995 return xRef;
998 //--------------------------------------------------------
999 void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut )
1001 const OUString sMime ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) );
1002 if ( m_xRootFolder->hasByName( sMime ) )
1003 m_xRootFolder->removeByName( sMime );
1005 ZipEntry * pEntry = new ZipEntry;
1006 sal_Int32 nBufferLength = m_pRootFolder->GetMediaType().getLength();
1007 OString sMediaType = OUStringToOString( m_pRootFolder->GetMediaType(), RTL_TEXTENCODING_ASCII_US );
1008 uno::Sequence< sal_Int8 > aType( ( sal_Int8* )sMediaType.getStr(),
1009 nBufferLength );
1012 pEntry->sPath = sMime;
1013 pEntry->nMethod = STORED;
1014 pEntry->nSize = pEntry->nCompressedSize = nBufferLength;
1015 pEntry->nTime = ZipOutputStream::getCurrentDosTime();
1017 CRC32 aCRC32;
1018 aCRC32.update( aType );
1019 pEntry->nCrc = aCRC32.getValue();
1023 aZipOut.putNextEntry( *pEntry, NULL );
1024 aZipOut.write( aType, 0, nBufferLength );
1025 aZipOut.closeEntry();
1027 catch ( ::com::sun::star::io::IOException & r )
1029 throw WrappedTargetException(
1030 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Error adding mimetype to the ZipOutputStream!" ) ),
1031 static_cast < OWeakObject * > ( this ),
1032 makeAny( r ) );
1036 //--------------------------------------------------------
1037 void ZipPackage::WriteManifest( ZipOutputStream& aZipOut, const vector< uno::Sequence < PropertyValue > >& aManList )
1039 // Write the manifest
1040 uno::Reference < XOutputStream > xManOutStream;
1041 OUString sManifestWriter( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestWriter" ) );
1042 uno::Reference < XManifestWriter > xWriter ( m_xFactory->createInstance( sManifestWriter ), UNO_QUERY );
1043 if ( xWriter.is() )
1045 ZipEntry * pEntry = new ZipEntry;
1046 ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize );
1047 xManOutStream = uno::Reference < XOutputStream > ( *pBuffer, UNO_QUERY );
1049 pEntry->sPath = OUString( RTL_CONSTASCII_USTRINGPARAM ( "META-INF/manifest.xml" ) );
1050 pEntry->nMethod = DEFLATED;
1051 pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1;
1052 pEntry->nTime = ZipOutputStream::getCurrentDosTime();
1054 // Convert vector into a uno::Sequence
1055 uno::Sequence < uno::Sequence < PropertyValue > > aManifestSequence ( aManList.size() );
1056 sal_Int32 nInd = 0;
1057 for ( vector < uno::Sequence < PropertyValue > >::const_iterator aIter = aManList.begin(), aEnd = aManList.end();
1058 aIter != aEnd;
1059 aIter++, nInd++ )
1061 aManifestSequence[nInd] = ( *aIter );
1063 xWriter->writeManifestSequence ( xManOutStream, aManifestSequence );
1065 sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() );
1066 pBuffer->realloc( nBufferLength );
1068 // the manifest.xml is never encrypted - so pass an empty reference
1069 aZipOut.putNextEntry( *pEntry, NULL );
1070 aZipOut.write( pBuffer->getSequence(), 0, nBufferLength );
1071 aZipOut.closeEntry();
1073 else
1075 VOS_ENSURE ( 0, "Couldn't get a ManifestWriter!" );
1076 IOException aException;
1077 throw WrappedTargetException(
1078 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Couldn't get a ManifestWriter!" ) ),
1079 static_cast < OWeakObject * > ( this ),
1080 makeAny( aException ) );
1084 //--------------------------------------------------------
1085 void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno::Sequence < PropertyValue > >& aManList )
1087 const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1088 const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1090 ZipEntry* pEntry = new ZipEntry;
1091 ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize );
1092 uno::Reference< io::XOutputStream > xConTypeOutStream( *pBuffer, UNO_QUERY );
1094 pEntry->sPath = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
1095 pEntry->nMethod = DEFLATED;
1096 pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1;
1097 pEntry->nTime = ZipOutputStream::getCurrentDosTime();
1099 // Convert vector into a uno::Sequence
1100 // TODO/LATER: use Defaulst entries in future
1101 uno::Sequence< beans::StringPair > aDefaultsSequence;
1102 uno::Sequence< beans::StringPair > aOverridesSequence( aManList.size() );
1103 sal_Int32 nSeqLength = 0;
1104 for ( vector< uno::Sequence< beans::PropertyValue > >::const_iterator aIter = aManList.begin(),
1105 aEnd = aManList.end();
1106 aIter != aEnd;
1107 aIter++ )
1109 ::rtl::OUString aPath;
1110 ::rtl::OUString aType;
1111 OSL_ENSURE( ( *aIter )[PKG_MNFST_MEDIATYPE].Name.equals( sMediaType ) && ( *aIter )[PKG_MNFST_FULLPATH].Name.equals( sFullPath ),
1112 "The mediatype sequence format is wrong!\n" );
1113 ( *aIter )[PKG_MNFST_MEDIATYPE].Value >>= aType;
1114 if ( aType.getLength() )
1116 // only nonempty type makes sence here
1117 nSeqLength++;
1118 ( *aIter )[PKG_MNFST_FULLPATH].Value >>= aPath;
1119 aOverridesSequence[nSeqLength-1].First = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) + aPath;
1120 aOverridesSequence[nSeqLength-1].Second = aType;
1123 aOverridesSequence.realloc( nSeqLength );
1125 ::comphelper::OFOPXMLHelper::WriteContentSequence(
1126 xConTypeOutStream, aDefaultsSequence, aOverridesSequence, m_xFactory );
1128 sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() );
1129 pBuffer->realloc( nBufferLength );
1131 // there is no encryption in this format currently
1132 aZipOut.putNextEntry( *pEntry, NULL );
1133 aZipOut.write( pBuffer->getSequence(), 0, nBufferLength );
1134 aZipOut.closeEntry();
1137 //--------------------------------------------------------
1138 void ZipPackage::ConnectTo( const uno::Reference< io::XInputStream >& xInStream )
1140 m_xContentSeek.set( xInStream, uno::UNO_QUERY_THROW );
1141 m_xContentStream = xInStream;
1143 // seek back to the beginning of the temp file so we can read segments from it
1144 m_xContentSeek->seek( 0 );
1145 if ( m_pZipFile )
1146 m_pZipFile->setInputStream( m_xContentStream );
1147 else
1148 m_pZipFile = new ZipFile ( m_xContentStream, m_xFactory, sal_False );
1151 //--------------------------------------------------------
1152 uno::Reference< io::XInputStream > ZipPackage::writeTempFile()
1154 // In case the target local file does not exist or empty
1155 // write directly to it otherwize create a temporary file to write to.
1156 // If a temporary file is created it is returned back by the method.
1157 // If the data written directly, xComponentStream will be switched here
1159 sal_Bool bUseTemp = sal_True;
1160 uno::Reference < io::XInputStream > xResult;
1161 uno::Reference < io::XInputStream > xTempIn;
1163 uno::Reference < io::XOutputStream > xTempOut;
1164 uno::Reference< io::XActiveDataStreamer > xSink;
1166 if ( m_eMode == e_IMode_URL && !m_pZipFile && isLocalFile_Impl( m_aURL ) )
1168 xSink = openOriginalForOutput();
1169 if( xSink.is() )
1171 uno::Reference< io::XStream > xStr = xSink->getStream();
1172 if( xStr.is() )
1174 xTempOut = xStr->getOutputStream();
1175 if( xTempOut.is() )
1176 bUseTemp = sal_False;
1180 else if ( m_eMode == e_IMode_XStream && !m_pZipFile )
1182 // write directly to an empty stream
1183 xTempOut = m_xStream->getOutputStream();
1184 if( xTempOut.is() )
1185 bUseTemp = sal_False;
1188 if( bUseTemp )
1190 // create temporary file
1191 const OUString sServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) );
1192 uno::Reference < io::XStream > xTempFile( m_xFactory->createInstance ( sServiceName ), UNO_QUERY_THROW );
1193 xTempOut.set( xTempFile->getOutputStream(), UNO_SET_THROW );
1194 xTempIn.set( xTempFile->getInputStream(), UNO_SET_THROW );
1197 // Hand it to the ZipOutputStream:
1198 ZipOutputStream aZipOut( m_xFactory, xTempOut );
1199 aZipOut.setMethod( DEFLATED );
1200 aZipOut.setLevel( DEFAULT_COMPRESSION );
1204 if ( m_nFormat == embed::StorageFormats::PACKAGE )
1206 // Remove the old manifest.xml file as the
1207 // manifest will be re-generated and the
1208 // META-INF directory implicitly created if does not exist
1209 const OUString sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) );
1211 if ( m_xRootFolder->hasByName( sMeta ) )
1213 const OUString sManifest ( RTL_CONSTASCII_USTRINGPARAM( "manifest.xml" ) );
1215 uno::Reference< XUnoTunnel > xTunnel;
1216 Any aAny = m_xRootFolder->getByName( sMeta );
1217 aAny >>= xTunnel;
1218 uno::Reference< XNameContainer > xMetaInfFolder( xTunnel, UNO_QUERY );
1219 if ( xMetaInfFolder.is() && xMetaInfFolder->hasByName( sManifest ) )
1220 xMetaInfFolder->removeByName( sManifest );
1223 // Write a magic file with mimetype
1224 WriteMimetypeMagicFile( aZipOut );
1226 else if ( m_nFormat == embed::StorageFormats::OFOPXML )
1228 // Remove the old [Content_Types].xml file as the
1229 // file will be re-generated
1231 const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
1233 if ( m_xRootFolder->hasByName( aContentTypes ) )
1234 m_xRootFolder->removeByName( aContentTypes );
1237 // Create a vector to store data for the manifest.xml file
1238 vector < uno::Sequence < PropertyValue > > aManList;
1240 const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1241 const OUString sVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) );
1242 const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1244 if ( m_nFormat == embed::StorageFormats::PACKAGE )
1246 uno::Sequence < PropertyValue > aPropSeq( PKG_SIZE_NOENCR_MNFST );
1247 aPropSeq [PKG_MNFST_MEDIATYPE].Name = sMediaType;
1248 aPropSeq [PKG_MNFST_MEDIATYPE].Value <<= m_pRootFolder->GetMediaType();
1249 aPropSeq [PKG_MNFST_VERSION].Name = sVersion;
1250 aPropSeq [PKG_MNFST_VERSION].Value <<= m_pRootFolder->GetVersion();
1251 aPropSeq [PKG_MNFST_FULLPATH].Name = sFullPath;
1252 aPropSeq [PKG_MNFST_FULLPATH].Value <<= OUString ( RTL_CONSTASCII_USTRINGPARAM ( "/" ) );
1254 aManList.push_back( aPropSeq );
1257 // Get a random number generator and seed it with current timestamp
1258 // This will be used to generate random salt and initialisation vectors
1259 // for encrypted streams
1260 TimeValue aTime;
1261 osl_getSystemTime( &aTime );
1262 rtlRandomPool aRandomPool = rtl_random_createPool ();
1263 rtl_random_addBytes ( aRandomPool, &aTime, 8 );
1265 // call saveContents ( it will recursively save sub-directories
1266 OUString aEmptyString;
1267 m_pRootFolder->saveContents( aEmptyString, aManList, aZipOut, GetEncryptionKey(), aRandomPool );
1269 // Clean up random pool memory
1270 rtl_random_destroyPool ( aRandomPool );
1272 if( m_nFormat == embed::StorageFormats::PACKAGE )
1274 WriteManifest( aZipOut, aManList );
1276 else if( m_nFormat == embed::StorageFormats::OFOPXML )
1278 WriteContentTypes( aZipOut, aManList );
1281 aZipOut.finish();
1283 if( bUseTemp )
1284 xResult = xTempIn;
1286 // Update our References to point to the new temp file
1287 if( !bUseTemp )
1289 // the case when the original contents were written directly
1290 xTempOut->flush();
1292 // in case the stream is based on a file it will implement the following interface
1293 // the call should be used to be sure that the contents are written to the file system
1294 uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( xTempOut, uno::UNO_QUERY );
1295 if ( asyncOutputMonitor.is() )
1296 asyncOutputMonitor->waitForCompletion();
1298 // no need to postpone switching to the new stream since the target was written directly
1299 uno::Reference< io::XInputStream > xNewStream;
1300 if ( m_eMode == e_IMode_URL )
1301 xNewStream = xSink->getStream()->getInputStream();
1302 else if ( m_eMode == e_IMode_XStream && m_xStream.is() )
1303 xNewStream = m_xStream->getInputStream();
1305 if ( xNewStream.is() )
1306 ConnectTo( xNewStream );
1309 catch ( uno::Exception& )
1311 if( bUseTemp )
1313 // no information loss appeares, thus no special handling is required
1314 uno::Any aCaught( ::cppu::getCaughtException() );
1316 // it is allowed to throw WrappedTargetException
1317 WrappedTargetException aException;
1318 if ( aCaught >>= aException )
1319 throw aException;
1321 throw WrappedTargetException(
1322 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Problem writing the original content!" ) ),
1323 static_cast < OWeakObject * > ( this ),
1324 aCaught );
1326 else
1328 // the document is written directly, although it was empty it is important to notify that the writing has failed
1329 // TODO/LATER: let the package be able to recover in this situation
1330 ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is unusable!" ) );
1331 embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), ::rtl::OUString() );
1332 throw WrappedTargetException( aErrTxt,
1333 static_cast < OWeakObject * > ( this ),
1334 makeAny ( aException ) );
1338 return xResult;
1341 //--------------------------------------------------------
1342 uno::Reference< XActiveDataStreamer > ZipPackage::openOriginalForOutput()
1344 // open and truncate the original file
1345 Content aOriginalContent ( m_aURL, uno::Reference < XCommandEnvironment >() );
1346 uno::Reference< XActiveDataStreamer > xSink = new ActiveDataStreamer;
1348 if ( m_eMode == e_IMode_URL )
1352 sal_Bool bTruncSuccess = sal_False;
1356 Exception aDetect;
1357 sal_Int64 aSize = 0;
1358 Any aAny = aOriginalContent.setPropertyValue( OUString::createFromAscii( "Size" ), makeAny( aSize ) );
1359 if( !( aAny >>= aDetect ) )
1360 bTruncSuccess = sal_True;
1362 catch( Exception& )
1366 if( !bTruncSuccess )
1368 // the file is not accessible
1369 // just try to write an empty stream to it
1371 uno::Reference< XInputStream > xTempIn = new DummyInputStream; //uno::Reference< XInputStream >( xTempOut, UNO_QUERY );
1372 aOriginalContent.writeStream( xTempIn , sal_True );
1375 OpenCommandArgument2 aArg;
1376 aArg.Mode = OpenMode::DOCUMENT;
1377 aArg.Priority = 0; // unused
1378 aArg.Sink = xSink;
1379 aArg.Properties = uno::Sequence< Property >( 0 ); // unused
1381 aOriginalContent.executeCommand( OUString::createFromAscii( "open" ), makeAny( aArg ) );
1383 catch( Exception& )
1385 // seems to be nonlocal file
1386 // temporary file mechanics should be used
1390 return xSink;
1393 //--------------------------------------------------------
1394 void SAL_CALL ZipPackage::commitChanges()
1395 throw( WrappedTargetException, RuntimeException )
1397 // lock the component for the time of commiting
1398 ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
1400 if ( m_eMode == e_IMode_XInputStream )
1402 IOException aException;
1403 throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ),
1404 static_cast < OWeakObject * > ( this ), makeAny ( aException ) );
1407 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::commitChanges" );
1409 // first the writeTempFile is called, if it returns a stream the stream should be written to the target
1410 // if no stream was returned, the file was written directly, nothing should be done
1412 uno::Reference< io::XInputStream > xTempInStream = writeTempFile();
1413 if ( xTempInStream.is() )
1415 uno::Reference< io::XSeekable > xTempSeek( xTempInStream, uno::UNO_QUERY_THROW );
1419 xTempSeek->seek( 0 );
1421 catch( uno::Exception& r )
1423 throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Temporary file should be seekable!" ) ),
1424 static_cast < OWeakObject * > ( this ), makeAny ( r ) );
1427 // connect to the temporary stream
1428 ConnectTo( xTempInStream );
1430 if ( m_eMode == e_IMode_XStream )
1432 // First truncate our output stream
1433 uno::Reference < XOutputStream > xOutputStream;
1435 // preparation for copy step
1438 xOutputStream = m_xStream->getOutputStream();
1439 uno::Reference < XTruncate > xTruncate ( xOutputStream, UNO_QUERY );
1440 if ( !xTruncate.is() )
1441 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1443 // after successful truncation the original file contents are already lost
1444 xTruncate->truncate();
1446 catch( uno::Exception& r )
1448 throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ),
1449 static_cast < OWeakObject * > ( this ), makeAny ( r ) );
1454 // then copy the contents of the tempfile to our output stream
1455 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, xOutputStream );
1456 xOutputStream->flush();
1457 uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor(
1458 xOutputStream, uno::UNO_QUERY );
1459 if ( asyncOutputMonitor.is() ) {
1460 asyncOutputMonitor->waitForCompletion();
1463 catch( uno::Exception& )
1465 // if anything goes wrong in this block the target file becomes corrupted
1466 // so an exception should be thrown as a notification about it
1467 // and the package must disconnect from the stream
1468 DisconnectFromTargetAndThrowException_Impl( xTempInStream );
1471 else if ( m_eMode == e_IMode_URL )
1473 uno::Reference< XOutputStream > aOrigFileStream;
1474 sal_Bool bCanBeCorrupted = sal_False;
1476 if( isLocalFile_Impl( m_aURL ) )
1478 // write directly in case of local file
1479 uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess > xSimpleAccess(
1480 m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ),
1481 uno::UNO_QUERY );
1482 OSL_ENSURE( xSimpleAccess.is(), "Can't instatiate SimpleFileAccess service!\n" );
1483 uno::Reference< io::XTruncate > xOrigTruncate;
1484 if ( xSimpleAccess.is() )
1488 aOrigFileStream = xSimpleAccess->openFileWrite( m_aURL );
1489 xOrigTruncate = uno::Reference< io::XTruncate >( aOrigFileStream, uno::UNO_QUERY_THROW );
1490 // after successful truncation the file is already corrupted
1491 xOrigTruncate->truncate();
1493 catch( uno::Exception& )
1497 if( xOrigTruncate.is() )
1501 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, aOrigFileStream );
1502 aOrigFileStream->closeOutput();
1504 catch( uno::Exception& )
1506 try {
1507 aOrigFileStream->closeOutput();
1508 } catch ( uno::Exception& ) {}
1510 aOrigFileStream = uno::Reference< XOutputStream >();
1511 // the original file can already be corrupted
1512 bCanBeCorrupted = sal_True;
1517 if( !aOrigFileStream.is() )
1521 uno::Reference < XPropertySet > xPropSet ( xTempInStream, UNO_QUERY );
1522 OSL_ENSURE( xPropSet.is(), "This is a temporary file that must implement XPropertySet!\n" );
1523 if ( !xPropSet.is() )
1524 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1526 OUString sTargetFolder = m_aURL.copy ( 0, m_aURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) );
1527 Content aContent ( sTargetFolder, uno::Reference < XCommandEnvironment > () );
1529 OUString sTempURL;
1530 Any aAny = xPropSet->getPropertyValue ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Uri" ) ) );
1531 aAny >>= sTempURL;
1533 TransferInfo aInfo;
1534 aInfo.NameClash = NameClash::OVERWRITE;
1535 aInfo.MoveData = sal_False;
1536 aInfo.SourceURL = sTempURL;
1537 aInfo.NewTitle = rtl::Uri::decode ( m_aURL.copy ( 1 + m_aURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) ),
1538 rtl_UriDecodeWithCharset,
1539 RTL_TEXTENCODING_UTF8 );
1540 aAny <<= aInfo;
1542 // if the file is still not corrupted, it can become after the next step
1543 aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "transfer" ) ), aAny );
1545 catch ( ::com::sun::star::uno::Exception& r )
1547 if ( bCanBeCorrupted )
1548 DisconnectFromTargetAndThrowException_Impl( xTempInStream );
1550 throw WrappedTargetException(
1551 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package may be read only!" ) ),
1552 static_cast < OWeakObject * > ( this ),
1553 makeAny ( r ) );
1559 // after successful storing it can be set to false
1560 m_bMediaTypeFallbackUsed = sal_False;
1562 RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::commitChanges" );
1565 //--------------------------------------------------------
1566 void ZipPackage::DisconnectFromTargetAndThrowException_Impl( const uno::Reference< io::XInputStream >& xTempStream )
1568 m_xStream = uno::Reference< io::XStream >( xTempStream, uno::UNO_QUERY );
1569 if ( m_xStream.is() )
1570 m_eMode = e_IMode_XStream;
1571 else
1572 m_eMode = e_IMode_XInputStream;
1574 ::rtl::OUString aTempURL;
1575 try {
1576 uno::Reference< beans::XPropertySet > xTempFile( xTempStream, uno::UNO_QUERY_THROW );
1577 uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) );
1578 aUrl >>= aTempURL;
1579 xTempFile->setPropertyValue( ::rtl::OUString::createFromAscii( "RemoveFile" ),
1580 uno::makeAny( sal_False ) );
1582 catch ( uno::Exception& )
1584 OSL_ENSURE( sal_False, "These calls are pretty simple, they should not fail!\n" );
1587 ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) );
1588 embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), aTempURL );
1589 throw WrappedTargetException( aErrTxt,
1590 static_cast < OWeakObject * > ( this ),
1591 makeAny ( aException ) );
1594 //--------------------------------------------------------
1595 const uno::Sequence< sal_Int8 > ZipPackage::GetEncryptionKey()
1597 uno::Sequence< sal_Int8 > aResult;
1599 if ( m_aStorageEncryptionKeys.getLength() )
1601 ::rtl::OUString aNameToFind;
1602 if ( m_nStartKeyGenerationID == xml::crypto::DigestID::SHA256 )
1603 aNameToFind = PACKAGE_ENCRYPTIONDATA_SHA256UTF8;
1604 else if ( m_nStartKeyGenerationID == xml::crypto::DigestID::SHA1 )
1605 aNameToFind = PACKAGE_ENCRYPTIONDATA_SHA1UTF8;
1606 else
1607 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No expected key is provided!" ) ), uno::Reference< uno::XInterface >() );
1609 for ( sal_Int32 nInd = 0; nInd < m_aStorageEncryptionKeys.getLength(); nInd++ )
1610 if ( m_aStorageEncryptionKeys[nInd].Name.equals( aNameToFind ) )
1611 m_aStorageEncryptionKeys[nInd].Value >>= aResult;
1613 // empty keys are not allowed here
1614 // so it is not important whether there is no key, or the key is empty, it is an error
1615 if ( !aResult.getLength() )
1616 throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No expected key is provided!" ) ), uno::Reference< uno::XInterface >() );
1618 else
1619 aResult = m_aEncryptionKey;
1621 return aResult;
1624 //--------------------------------------------------------
1625 sal_Bool SAL_CALL ZipPackage::hasPendingChanges()
1626 throw( RuntimeException )
1628 return sal_False;
1630 //--------------------------------------------------------
1631 Sequence< ElementChange > SAL_CALL ZipPackage::getPendingChanges()
1632 throw( RuntimeException )
1634 return uno::Sequence < ElementChange > ();
1638 * Function to create a new component instance; is needed by factory helper implementation.
1639 * @param xMgr service manager to if the components needs other component instances
1641 uno::Reference < XInterface >SAL_CALL ZipPackage_createInstance(
1642 const uno::Reference< XMultiServiceFactory > & xMgr )
1644 return uno::Reference< XInterface >( *new ZipPackage( xMgr ) );
1647 //--------------------------------------------------------
1648 OUString ZipPackage::static_getImplementationName()
1650 return OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.comp.ZipPackage" ) );
1653 //--------------------------------------------------------
1654 Sequence< OUString > ZipPackage::static_getSupportedServiceNames()
1656 uno::Sequence< OUString > aNames( 1 );
1657 aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.Package" ) );
1658 return aNames;
1660 //--------------------------------------------------------
1661 sal_Bool SAL_CALL ZipPackage::static_supportsService( OUString const & rServiceName )
1663 return rServiceName == getSupportedServiceNames()[0];
1666 //--------------------------------------------------------
1667 OUString ZipPackage::getImplementationName()
1668 throw ( RuntimeException )
1670 return static_getImplementationName();
1673 //--------------------------------------------------------
1674 Sequence< OUString > ZipPackage::getSupportedServiceNames()
1675 throw ( RuntimeException )
1677 return static_getSupportedServiceNames();
1679 //--------------------------------------------------------
1680 sal_Bool SAL_CALL ZipPackage::supportsService( OUString const & rServiceName )
1681 throw ( RuntimeException )
1683 return static_supportsService ( rServiceName );
1685 //--------------------------------------------------------
1686 uno::Reference < XSingleServiceFactory > ZipPackage::createServiceFactory( uno::Reference < XMultiServiceFactory > const & rServiceFactory )
1688 return cppu::createSingleFactory ( rServiceFactory,
1689 static_getImplementationName(),
1690 ZipPackage_createInstance,
1691 static_getSupportedServiceNames() );
1694 namespace { struct lcl_ImplId : public rtl::Static< ::cppu::OImplementationId, lcl_ImplId > {}; }
1696 //--------------------------------------------------------
1697 Sequence< sal_Int8 > ZipPackage::getUnoTunnelImplementationId( void )
1698 throw ( RuntimeException )
1700 ::cppu::OImplementationId &rId = lcl_ImplId::get();
1701 return rId.getImplementationId();
1704 //--------------------------------------------------------
1705 sal_Int64 SAL_CALL ZipPackage::getSomething( const uno::Sequence< sal_Int8 >& aIdentifier )
1706 throw( RuntimeException )
1708 if ( aIdentifier.getLength() == 16 && 0 == rtl_compareMemory( getUnoTunnelImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) )
1709 return reinterpret_cast < sal_Int64 > ( this );
1710 return 0;
1713 //--------------------------------------------------------
1714 uno::Reference< XPropertySetInfo > SAL_CALL ZipPackage::getPropertySetInfo()
1715 throw( RuntimeException )
1717 return uno::Reference < XPropertySetInfo > ();
1720 //--------------------------------------------------------
1721 void SAL_CALL ZipPackage::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
1722 throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException )
1724 if ( m_nFormat != embed::StorageFormats::PACKAGE )
1725 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1727 if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( HAS_ENCRYPTED_ENTRIES_PROPERTY ) )
1728 ||aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( HAS_NONENCRYPTED_ENTRIES_PROPERTY ) )
1729 ||aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( IS_INCONSISTENT_PROPERTY ) )
1730 ||aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( MEDIATYPE_FALLBACK_USED_PROPERTY ) ) )
1731 throw PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1732 else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_KEY_PROPERTY ) ) )
1734 if ( !( aValue >>= m_aEncryptionKey ) )
1735 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 );
1737 m_aStorageEncryptionKeys.realloc( 0 );
1739 else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( STORAGE_ENCRYPTION_KEYS_PROPERTY ) ) )
1741 // this property is only necessary to support raw passwords in storage API;
1742 // because of this support the storage has to operate with more than one key dependent on storage generation algorithm;
1743 // when this support is removed, the storage will get only one key from outside
1744 // TODO/LATER: Get rid of this property as well as of support of raw passwords in storages
1745 uno::Sequence< beans::NamedValue > aKeys;
1746 if ( !( aValue >>= aKeys ) || ( aKeys.getLength() && aKeys.getLength() < 2 ) )
1747 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 );
1749 if ( aKeys.getLength() )
1751 bool bHasSHA256 = false;
1752 bool bHasSHA1 = false;
1753 for ( sal_Int32 nInd = 0; nInd < aKeys.getLength(); nInd++ )
1755 if ( aKeys[nInd].Name.equals( PACKAGE_ENCRYPTIONDATA_SHA256UTF8 ) )
1756 bHasSHA256 = true;
1757 if ( aKeys[nInd].Name.equals( PACKAGE_ENCRYPTIONDATA_SHA1UTF8 ) )
1758 bHasSHA1 = true;
1761 if ( !bHasSHA256 || !bHasSHA1 )
1762 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Expected keys are not provided!" ) ), uno::Reference< uno::XInterface >(), 2 );
1765 m_aStorageEncryptionKeys = aKeys;
1766 m_aEncryptionKey.realloc( 0 );
1768 else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_ALGORITHMS_PROPERTY ) ) )
1770 uno::Sequence< beans::NamedValue > aAlgorithms;
1771 if ( m_pZipFile || !( aValue >>= aAlgorithms ) || aAlgorithms.getLength() == 0 )
1773 // the algorithms can not be changed if the file has a persistence based on the algorithms ( m_pZipFile )
1774 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "unexpected algorithms list is provided." ) ), uno::Reference< uno::XInterface >(), 2 );
1777 for ( sal_Int32 nInd = 0; nInd < aAlgorithms.getLength(); nInd++ )
1779 if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "StartKeyGenerationAlgorithm" ) ) )
1781 sal_Int32 nID = 0;
1782 if ( !( aAlgorithms[nInd].Value >>= nID )
1783 || ( nID != xml::crypto::DigestID::SHA256 && nID != xml::crypto::DigestID::SHA1 ) )
1784 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected start key generation algorithm is provided!" ) ), uno::Reference< uno::XInterface >(), 2 );
1786 m_nStartKeyGenerationID = nID;
1788 else if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "EncryptionAlgorithm" ) ) )
1790 sal_Int32 nID = 0;
1791 if ( !( aAlgorithms[nInd].Value >>= nID )
1792 || ( nID != xml::crypto::CipherID::AES_CBC_W3C_PADDING && nID != xml::crypto::CipherID::BLOWFISH_CFB_8 ) )
1793 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected start key generation algorithm is provided!" ) ), uno::Reference< uno::XInterface >(), 2 );
1795 m_nCommonEncryptionID = nID;
1797 else if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ChecksumAlgorithm" ) ) )
1799 sal_Int32 nID = 0;
1800 if ( !( aAlgorithms[nInd].Value >>= nID )
1801 || ( nID != xml::crypto::DigestID::SHA1_1K && nID != xml::crypto::DigestID::SHA256_1K ) )
1802 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected start key generation algorithm is provided!" ) ), uno::Reference< uno::XInterface >(), 2 );
1804 m_nChecksumDigestID = nID;
1806 else
1808 OSL_ENSURE( sal_False, "Unexpected encryption algorithm is provided!" );
1809 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "unexpected algorithms list is provided." ) ), uno::Reference< uno::XInterface >(), 2 );
1813 else
1814 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1817 //--------------------------------------------------------
1818 Any SAL_CALL ZipPackage::getPropertyValue( const OUString& PropertyName )
1819 throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1821 // TODO/LATER: Activate the check when zip-ucp is ready
1822 // if ( m_nFormat != embed::StorageFormats::PACKAGE )
1823 // throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1825 Any aAny;
1826 if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( ENCRYPTION_KEY_PROPERTY ) ) )
1828 aAny <<= m_aEncryptionKey;
1829 return aAny;
1831 else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_ALGORITHMS_PROPERTY ) ) )
1833 ::comphelper::SequenceAsHashMap aAlgorithms;
1834 aAlgorithms[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StartKeyGenerationAlgorithm" ) ) ] <<= m_nStartKeyGenerationID;
1835 aAlgorithms[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EncryptionAlgorithm" ) ) ] <<= m_nCommonEncryptionID;
1836 aAlgorithms[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ChecksumAlgorithm" ) ) ] <<= m_nChecksumDigestID;
1837 aAny <<= aAlgorithms.getAsConstNamedValueList();
1838 return aAny;
1840 if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( STORAGE_ENCRYPTION_KEYS_PROPERTY ) ) )
1842 aAny <<= m_aStorageEncryptionKeys;
1843 return aAny;
1845 else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( HAS_ENCRYPTED_ENTRIES_PROPERTY ) ) )
1847 aAny <<= m_bHasEncryptedEntries;
1848 return aAny;
1850 else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( HAS_NONENCRYPTED_ENTRIES_PROPERTY ) ) )
1852 aAny <<= m_bHasNonEncryptedEntries;
1853 return aAny;
1855 else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( IS_INCONSISTENT_PROPERTY ) ) )
1857 aAny <<= m_bInconsistent;
1858 return aAny;
1860 else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( MEDIATYPE_FALLBACK_USED_PROPERTY ) ) )
1862 aAny <<= m_bMediaTypeFallbackUsed;
1863 return aAny;
1865 throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1867 //--------------------------------------------------------
1868 void SAL_CALL ZipPackage::addPropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ )
1869 throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1872 //--------------------------------------------------------
1873 void SAL_CALL ZipPackage::removePropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*aListener*/ )
1874 throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1877 //--------------------------------------------------------
1878 void SAL_CALL ZipPackage::addVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ )
1879 throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1882 //--------------------------------------------------------
1883 void SAL_CALL ZipPackage::removeVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ )
1884 throw( UnknownPropertyException, WrappedTargetException, RuntimeException )