xref: /AOO41X/main/package/source/zippackage/ZipPackage.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
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.
14  *
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 ).
20  *
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.
25  *
26  ************************************************************************/
27 
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"
78 
79 #include <memory>
80 #include <vector>
81 
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>
89 
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;
108 
109 #define LOGFILE_AUTHOR "mg115289"
110 
111 
112 namespace {
113 
114 sal_Bool isLocalFile_Impl( ::rtl::OUString aURL )
115 {
116 	::rtl::OUString aSystemPath;
117     ContentBroker* pBroker = ContentBroker::get();
118     if ( !pBroker )
119     {
120 		::rtl::OUString aRet;
121         if ( FileBase::getSystemPathFromFileURL( aURL, aRet ) == FileBase::E_None )
122 			aSystemPath = aRet;
123     }
124     else
125     {
126         uno::Reference< XContentProviderManager > xManager =
127 				pBroker->getContentProviderManagerInterface();
128         try
129         {
130            	aSystemPath = getSystemPathFromFileURL( xManager, aURL );
131         }
132         catch ( Exception& )
133         {
134         }
135     }
136 
137     return ( aSystemPath.getLength() != 0 );
138 }
139 
140 }
141 
142 //===========================================================================
143 
144 class ActiveDataStreamer : public ::cppu::WeakImplHelper1< XActiveDataStreamer >
145 {
146 	uno::Reference< XStream > mStream;
147 public:
148 
149 	virtual uno::Reference< XStream > SAL_CALL getStream()
150 			throw( RuntimeException )
151 			{ return mStream; }
152 
153 	virtual void SAL_CALL setStream( const uno::Reference< XStream >& stream )
154 			throw( RuntimeException )
155 			{ mStream = stream; }
156 };
157 
158 class DummyInputStream : public ::cppu::WeakImplHelper1< XInputStream >
159 {
160     virtual sal_Int32 SAL_CALL readBytes( uno::Sequence< sal_Int8 >&, sal_Int32 )
161 			throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
162 		{ return 0; }
163 
164     virtual sal_Int32 SAL_CALL readSomeBytes( uno::Sequence< sal_Int8 >&, sal_Int32 )
165 			throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
166 		{ return 0; }
167 
168     virtual void SAL_CALL skipBytes( sal_Int32 )
169 			throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
170 		{}
171 
172     virtual sal_Int32 SAL_CALL available()
173 			throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
174 		{ return 0; }
175 
176     virtual void SAL_CALL closeInput()
177 			throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
178 		{}
179 };
180 
181 //===========================================================================
182 
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 )
199 {
200 	m_xRootFolder = m_pRootFolder = new ZipPackageFolder( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert );
201 }
202 
203 ZipPackage::~ZipPackage( void )
204 {
205 	delete m_pZipFile;
206 
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.
212 }
213 
214 //--------------------------------------------------------
215 void ZipPackage::parseManifest()
216 {
217 	if ( m_nFormat == embed::StorageFormats::PACKAGE )
218 	{
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 ) )
223 		{
224 			const OUString sManifest ( RTL_CONSTASCII_USTRINGPARAM( "manifest.xml" ) );
225 
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 ) )
232 				{
233 					aAny = xMetaInfFolder->getByName( sManifest );
234 					aAny >>= xTunnel;
235 					uno::Reference < XActiveDataSink > xSink ( xTunnel, UNO_QUERY );
236 					if ( xSink.is() )
237 					{
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() )
241 						{
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" ) );
254 
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;
260 
261 							for ( sal_Int32 i = 0; i < nLength ; i++, pSequence++ )
262 							{
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++ )
267 								{
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 );
292 								}
293 
294 								if ( sPath.getLength() && hasByHierarchicalName ( sPath ) )
295 								{
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 )
301 									{
302 										pFolder = reinterpret_cast < ZipPackageFolder* > ( nTest );
303 										pFolder->SetMediaType ( sMediaType );
304 										pFolder->SetVersion ( sVersion );
305 									}
306 									else
307 									{
308 										pStream = reinterpret_cast < ZipPackageStream* > ( xUnoTunnel->getSomething( ZipPackageStream::static_getImplementationId() ));
309 										pStream->SetMediaType ( sMediaType );
310                                         pStream->SetFromManifest( sal_True );
311 
312 										if ( pSalt && pVector && pCount && pSize && pDigest && pDigestAlg && pEncryptionAlg )
313 										{
314 											uno::Sequence < sal_Int8 > aSequence;
315 											sal_Int32 nCount = 0, nSize = 0, nDigestAlg = 0, nEncryptionAlg = 0, nDerivedKeySize = 16, nStartKeyAlg = xml::crypto::DigestID::SHA1;
316 
317                                             pStream->SetToBeEncrypted ( sal_True );
318 
319 											*pSalt >>= aSequence;
320 											pStream->setSalt ( aSequence );
321 
322 											*pVector >>= aSequence;
323 											pStream->setInitialisationVector ( aSequence );
324 
325 											*pCount >>= nCount;
326 											pStream->setIterationCount ( nCount );
327 
328 											*pSize >>= nSize;
329 											pStream->setSize ( nSize );
330 
331                                             *pDigest >>= aSequence;
332                                             pStream->setDigest ( aSequence );
333 
334                                             *pDigestAlg >>= nDigestAlg;
335                                             pStream->SetImportedChecksumAlgorithm( nDigestAlg );
336 
337                                             *pEncryptionAlg >>= nEncryptionAlg;
338                                             pStream->SetImportedEncryptionAlgorithm( nEncryptionAlg );
339 
340                                             if ( pDerivedKeySize )
341                                                 *pDerivedKeySize >>= nDerivedKeySize;
342                                             pStream->SetImportedDerivedKeySize( nDerivedKeySize );
343 
344                                             if ( pStartKeyAlg )
345                                                 *pStartKeyAlg >>= nStartKeyAlg;
346                                             pStream->SetImportedStartKeyAlgorithm( nStartKeyAlg );
347 
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" ) ) ) )
353                                             {
354 												m_bHasEncryptedEntries = sal_True;
355                                                 m_nStartKeyGenerationID = nStartKeyAlg;
356                                                 m_nChecksumDigestID = nDigestAlg;
357                                                 m_nCommonEncryptionID = nEncryptionAlg;
358                                             }
359 										}
360                                         else
361                                             m_bHasNonEncryptedEntries = sal_True;
362 									}
363 								}
364 							}
365 
366 							bManifestParsed = sal_True;
367 						}
368 						else
369                             throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No manifes parser!" ) ), uno::Reference< uno::XInterface >() );
370 					}
371 
372 					// now hide the manifest.xml file from user
373 					xMetaInfFolder->removeByName( sManifest );
374 				}
375 			}
376 			catch( Exception& )
377 			{
378 				if ( !m_bForceRecovery )
379 					throw;
380 			}
381 		}
382 
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 >() );
387 
388 		const OUString sMimetype ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) );
389 		if ( m_xRootFolder->hasByName( sMimetype ) )
390 		{
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() )
397             {
398                 uno::Reference< io::XInputStream > xMimeInStream = xMimeSink->getInputStream();
399                 if ( xMimeInStream.is() )
400                 {
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();
406 
407                     if ( nRead )
408                         aPackageMediatype = ::rtl::OUString( ( sal_Char* )aData.getConstArray(), nRead, RTL_TEXTENCODING_ASCII_US );
409                 }
410             }
411 
412 
413             if ( !bManifestParsed )
414             {
415                 // the manifest.xml could not be successfuly parsed, this is an inconsistent package
416                 if ( aPackageMediatype.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "application/vnd." ) ) == 0 )
417                 {
418                     // accept only types that look similar to own mediatypes
419                     m_pRootFolder->SetMediaType( aPackageMediatype );
420                     m_bMediaTypeFallbackUsed = sal_True;
421                 }
422             }
423             else if ( !m_bForceRecovery )
424             {
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 >() );
430             }
431 
432             m_xRootFolder->removeByName( sMimetype );
433         }
434 
435         m_bInconsistent = m_pRootFolder->LookForUnexpectedODF12Streams( ::rtl::OUString() );
436 
437         sal_Bool bODF12AndNewer = ( m_pRootFolder->GetVersion().compareTo( ODFVER_012_TEXT ) >= 0 );
438         if ( !m_bForceRecovery && bODF12AndNewer )
439         {
440             if ( m_bInconsistent )
441             {
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 >() );
448             }
449             else if ( bDifferentStartKeyAlgorithm )
450             {
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 >() );
455             }
456         }
457 
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 );
462 	}
463 }
464 
465 //--------------------------------------------------------
466 void ZipPackage::parseContentType()
467 {
468 	if ( m_nFormat == embed::StorageFormats::OFOPXML )
469 	{
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 >() );
476 
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() )
482 			{
483 				uno::Reference< io::XInputStream > xInStream = xSink->getInputStream();
484 				if ( xInStream.is() )
485 				{
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 );
490 
491 					if ( aContentTypeInfo.getLength() != 2 )
492 						throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
493 
494 					// set the implicit types fist
495 					for ( nInd = 0; nInd < aContentTypeInfo[0].getLength(); nInd++ )
496 						m_pRootFolder->setChildStreamsTypeByExtension( aContentTypeInfo[0][nInd] );
497 
498 					// now set the explicit types
499 					for ( nInd = 0; nInd < aContentTypeInfo[1].getLength(); nInd++ )
500 					{
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;
506 
507 						if ( aPath.getLength() && hasByHierarchicalName( aPath ) )
508 						{
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 )
514 							{
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 );
518 							}
519 						}
520 					}
521 				}
522 			}
523 
524 			m_xRootFolder->removeByName( aContentTypes );
525 		}
526 		catch( uno::Exception& )
527 		{
528 			if ( !m_bForceRecovery )
529 				throw;
530 		}
531 	}
532 }
533 
534 //--------------------------------------------------------
535 void ZipPackage::getZipFileContents()
536 {
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;
543 
544 	while ( pEnum->hasMoreElements() )
545 	{
546 		nIndex = nOldIndex = 0;
547 		pCurrent = m_pRootFolder;
548 		const ZipEntry & rEntry = *pEnum->nextElement();
549 		OUString rName = rEntry.sPath;
550 
551         if ( m_bForceRecovery )
552         {
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( '\\', '/' );
556         }
557 
558 		nStreamIndex = rName.lastIndexOf ( '/' );
559 		if ( nStreamIndex != -1 )
560 		{
561 			sDirName = rName.copy ( 0, nStreamIndex );
562 			aIter = m_aRecent.find ( sDirName );
563 			if ( aIter != m_aRecent.end() )
564 				pCurrent = ( *aIter ).second;
565 		}
566 
567 		if ( pCurrent == m_pRootFolder )
568 		{
569 			while ( ( nIndex = rName.indexOf( '/', nOldIndex ) ) != -1 )
570 			{
571 				sTemp = rName.copy ( nOldIndex, nIndex - nOldIndex );
572 				if ( nIndex == nOldIndex )
573 					break;
574 				if ( !pCurrent->hasByName( sTemp ) )
575 				{
576 					pPkgFolder = new ZipPackageFolder( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert );
577 					pPkgFolder->setName( sTemp );
578 					pPkgFolder->doSetParent( pCurrent, sal_True );
579 					pCurrent = pPkgFolder;
580 				}
581 				else
582 					pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
583 				nOldIndex = nIndex+1;
584 			}
585 			if ( nStreamIndex != -1 && sDirName.getLength() )
586 				m_aRecent [ sDirName ] = pCurrent;
587 		}
588 		if ( rName.getLength() -1 != nStreamIndex )
589 		{
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 );
597 		}
598 	}
599 
600 	if ( m_nFormat == embed::StorageFormats::PACKAGE )
601 		parseManifest();
602 	else if ( m_nFormat == embed::StorageFormats::OFOPXML )
603 		parseContentType();
604 }
605 
606 //--------------------------------------------------------
607 void SAL_CALL ZipPackage::initialize( const uno::Sequence< Any >& aArguments )
608 		throw( Exception, RuntimeException )
609 {
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;
614 
615 	if ( aArguments.getLength() )
616 	{
617 		for( int ind = 0; ind < aArguments.getLength(); ind++ )
618 		{
619 			OUString aParamUrl;
620 			if ( ( aArguments[ind] >>= aParamUrl ))
621 			{
622 				m_eMode = e_IMode_URL;
623 				try
624 				{
625 					sal_Int32 nParam = aParamUrl.indexOf( '?' );
626 					if ( nParam >= 0 )
627 					{
628 						m_aURL = aParamUrl.copy( 0, nParam );
629 						OUString aParam = aParamUrl.copy( nParam + 1 );
630 
631               			sal_Int32 nIndex = 0;
632 						do
633 						{
634 							::rtl::OUString aCommand = aParam.getToken( 0, '&', nIndex );
635 							if ( aCommand.equals( OUString::createFromAscii( "repairpackage" ) ) )
636 							{
637 								m_bForceRecovery = sal_True;
638 								break;
639 							}
640 							else if ( aCommand.equals( OUString::createFromAscii( "purezip" ) ) )
641 							{
642 								m_nFormat = embed::StorageFormats::ZIP;
643 								m_pRootFolder->setPackageFormat_Impl( m_nFormat );
644 								break;
645 							}
646 							else if ( aCommand.equals( OUString::createFromAscii( "ofopxml" ) ) )
647 							{
648 								m_nFormat = embed::StorageFormats::OFOPXML;
649 								m_pRootFolder->setPackageFormat_Impl( m_nFormat );
650 								break;
651 							}
652 						}
653 						while ( nIndex >= 0 );
654 					}
655 					else
656 						m_aURL = aParamUrl;
657 
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 ) )
665 					{
666 						uno::Reference < XActiveDataSink > xSink = new ZipPackageSink;
667 						if ( aContent.openStream ( xSink ) )
668 							m_xContentStream = xSink->getInputStream();
669 					}
670 					else
671 						bHaveZipFile = sal_False;
672 				}
673 				catch ( com::sun::star::uno::Exception& )
674 				{
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;
679 				}
680 			}
681 			else if ( ( aArguments[ind] >>= m_xStream ) )
682 			{
683 				// a writable stream can implement both XStream & XInputStream
684 				m_eMode = e_IMode_XStream;
685 				m_xContentStream = m_xStream->getInputStream();
686 			}
687 			else if ( ( aArguments[ind] >>= m_xContentStream ) )
688 			{
689 				m_eMode = e_IMode_XInputStream;
690 			}
691 			else if ( ( aArguments[ind] >>= aNamedValue ) )
692 			{
693 				if ( aNamedValue.Name.equalsAscii( "RepairPackage" ) )
694 					aNamedValue.Value >>= m_bForceRecovery;
695 				else if ( aNamedValue.Name.equalsAscii( "PackageFormat" ) )
696 				{
697 					// setting this argument to true means Package format
698 					// setting it to false means plain Zip format
699 
700 					sal_Bool bPackFormat = sal_True;
701 					aNamedValue.Value >>= bPackFormat;
702 					if ( !bPackFormat )
703 						m_nFormat = embed::StorageFormats::ZIP;
704 
705 					m_pRootFolder->setPackageFormat_Impl( m_nFormat );
706 				}
707 				else if ( aNamedValue.Name.equalsAscii( "StorageFormat" ) )
708 				{
709 					::rtl::OUString aFormatName;
710                     sal_Int32 nFormatID = 0;
711                     if ( aNamedValue.Value >>= aFormatName )
712                     {
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 );
721                     }
722                     else if ( aNamedValue.Value >>= nFormatID )
723                     {
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 );
728 
729                         m_nFormat = nFormatID;
730                     }
731                     else
732                         throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
733 
734 					m_pRootFolder->setPackageFormat_Impl( m_nFormat );
735 				}
736 				else if ( aNamedValue.Name.equalsAscii( "AllowRemoveOnInsert" ) )
737 				{
738 					aNamedValue.Value >>= m_bAllowRemoveOnInsert;
739 					m_pRootFolder->setRemoveOnInsertMode_Impl( m_bAllowRemoveOnInsert );
740 				}
741 
742 				// for now the progress handler is not used, probably it will never be
743 				// if ( aNamedValue.Name.equalsAscii( "ProgressHandler" )
744 			}
745 			else
746 			{
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 ) );
750 			}
751 		}
752 
753 		try
754 		{
755 			if ( m_xContentStream.is() )
756 			{
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 ) );
763 
764 				if ( !m_xContentSeek->getLength() )
765 					bHaveZipFile = sal_False;
766 			}
767 			else
768 				bHaveZipFile = sal_False;
769 		}
770 		catch ( com::sun::star::uno::Exception& )
771 		{
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;
776 		}
777 		if ( bHaveZipFile )
778 		{
779 			try
780 			{
781 				m_pZipFile = new ZipFile ( m_xContentStream, m_xFactory, sal_True, m_bForceRecovery, xProgressHandler );
782 				getZipFileContents();
783 			}
784 			catch ( IOException & )
785 			{
786 				bBadZipFile = sal_True;
787 			}
788 			catch ( ZipException & )
789 			{
790 				bBadZipFile = sal_True;
791 			}
792 			catch ( Exception & )
793 			{
794 				if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; }
795 				throw;
796 			}
797 
798 			if ( bBadZipFile )
799 			{
800 				// clean up the memory, and tell the UCB about the error
801 				if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; }
802 
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 ) );
806 			}
807 		}
808 	}
809 
810 	RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::initialize" );
811 }
812 
813 //--------------------------------------------------------
814 Any SAL_CALL ZipPackage::getByHierarchicalName( const OUString& aName )
815 		throw( NoSuchElementException, RuntimeException )
816 {
817 	OUString sTemp, sDirName;
818 	sal_Int32 nOldIndex, nIndex, nStreamIndex;
819 	FolderHash::iterator aIter;
820 
821 	if ( ( nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' )
822 		return makeAny ( uno::Reference < XUnoTunnel > ( m_pRootFolder ) );
823 	else
824 	{
825 		nStreamIndex = aName.lastIndexOf ( '/' );
826 		bool bFolder = nStreamIndex == nIndex-1;
827 		if ( nStreamIndex != -1 )
828 		{
829 			sDirName = aName.copy ( 0, nStreamIndex );
830 			aIter = m_aRecent.find ( sDirName );
831 			if ( aIter != m_aRecent.end() )
832 			{
833 				if ( bFolder )
834 				{
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 );
841 				}
842 				else
843 				{
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 );
849 				}
850 			}
851 		}
852 		else
853 		{
854 			if ( m_pRootFolder->hasByName ( aName ) )
855 				return m_pRootFolder->getByName ( aName );
856 		}
857 		nOldIndex = 0;
858 		ZipPackageFolder * pCurrent = m_pRootFolder;
859 		ZipPackageFolder * pPrevious = NULL;
860 		while ( ( nIndex = aName.indexOf( '/', nOldIndex )) != -1 )
861 		{
862 			sTemp = aName.copy ( nOldIndex, nIndex - nOldIndex );
863 			if ( nIndex == nOldIndex )
864 				break;
865 			if ( pCurrent->hasByName( sTemp ) )
866 			{
867 				pPrevious = pCurrent;
868 				pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
869 			}
870 			else
871 				throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
872 			nOldIndex = nIndex+1;
873 		}
874 		if ( bFolder )
875 		{
876 			if ( nStreamIndex != -1 )
877 				m_aRecent[sDirName] = pPrevious;
878 			return makeAny ( uno::Reference < XUnoTunnel > ( pCurrent ) );
879 		}
880 		else
881 		{
882 			sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex );
883 			if ( pCurrent->hasByName ( sTemp ) )
884 			{
885 				if ( nStreamIndex != -1 )
886 					m_aRecent[sDirName] = pCurrent;
887 				return pCurrent->getByName( sTemp );
888 			}
889 			else
890 				throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
891 		}
892 	}
893 }
894 
895 //--------------------------------------------------------
896 sal_Bool SAL_CALL ZipPackage::hasByHierarchicalName( const OUString& aName )
897 		throw( RuntimeException )
898 {
899 	OUString sTemp, sDirName;
900 	sal_Int32 nOldIndex, nIndex, nStreamIndex;
901 	FolderHash::iterator aIter;
902 
903 	if ( ( nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' )
904 		return sal_True;
905 	else
906 	{
907 		nStreamIndex = aName.lastIndexOf ( '/' );
908 		bool bFolder = nStreamIndex == nIndex-1;
909 		if ( nStreamIndex != -1 )
910 		{
911 			sDirName = aName.copy ( 0, nStreamIndex );
912 			aIter = m_aRecent.find ( sDirName );
913 			if ( aIter != m_aRecent.end() )
914 			{
915 				if ( bFolder )
916 				{
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 );
923 				}
924 				else
925 				{
926 					sTemp = aName.copy ( nStreamIndex + 1 );
927 					if ( ( *aIter ).second->hasByName( sTemp ) )
928 						return sal_True;
929 					else
930 						m_aRecent.erase( aIter );
931 				}
932 			}
933 		}
934 		else
935 		{
936 			if ( m_pRootFolder->hasByName ( aName ) )
937 				return sal_True;
938 		}
939 		ZipPackageFolder * pCurrent = m_pRootFolder;
940 		ZipPackageFolder * pPrevious = NULL;
941 		nOldIndex = 0;
942 		while ( ( nIndex = aName.indexOf( '/', nOldIndex )) != -1 )
943 		{
944 			sTemp = aName.copy ( nOldIndex, nIndex - nOldIndex );
945 			if ( nIndex == nOldIndex )
946 				break;
947 			if ( pCurrent->hasByName( sTemp ) )
948 			{
949 				pPrevious = pCurrent;
950 				pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
951 			}
952 			else
953 				return sal_False;
954 			nOldIndex = nIndex+1;
955 		}
956 		if ( bFolder )
957 		{
958 			m_aRecent[sDirName] = pPrevious;
959 			return sal_True;
960 		}
961 		else
962 		{
963 			sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex );
964 
965 			if ( pCurrent->hasByName( sTemp ) )
966 			{
967 				m_aRecent[sDirName] = pCurrent;
968 				return sal_True;
969 			}
970 		}
971 		return sal_False;
972 	}
973 }
974 
975 //--------------------------------------------------------
976 uno::Reference< XInterface > SAL_CALL ZipPackage::createInstance()
977 		throw( Exception, RuntimeException )
978 {
979 	uno::Reference < XInterface > xRef = *( new ZipPackageStream ( *this, m_xFactory, m_bAllowRemoveOnInsert ) );
980 	return xRef;
981 }
982 //--------------------------------------------------------
983 uno::Reference< XInterface > SAL_CALL ZipPackage::createInstanceWithArguments( const uno::Sequence< Any >& aArguments )
984 		throw( Exception, RuntimeException )
985 {
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 );
994 
995 	return xRef;
996 }
997 
998 //--------------------------------------------------------
999 void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut )
1000 {
1001 	const OUString sMime ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) );
1002 	if ( m_xRootFolder->hasByName( sMime ) )
1003 		m_xRootFolder->removeByName( sMime );
1004 
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 );
1010 
1011 
1012 	pEntry->sPath = sMime;
1013 	pEntry->nMethod = STORED;
1014 	pEntry->nSize = pEntry->nCompressedSize = nBufferLength;
1015 	pEntry->nTime = ZipOutputStream::getCurrentDosTime();
1016 
1017 	CRC32 aCRC32;
1018 	aCRC32.update( aType );
1019 	pEntry->nCrc = aCRC32.getValue();
1020 
1021 	try
1022 	{
1023 		aZipOut.putNextEntry( *pEntry, NULL );
1024 		aZipOut.write( aType, 0, nBufferLength );
1025 		aZipOut.closeEntry();
1026 	}
1027 	catch ( ::com::sun::star::io::IOException & r )
1028 	{
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 ) );
1033 	}
1034 }
1035 
1036 //--------------------------------------------------------
1037 void ZipPackage::WriteManifest( ZipOutputStream& aZipOut, const vector< uno::Sequence < PropertyValue > >& aManList )
1038 {
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() )
1044     {
1045         ZipEntry * pEntry = new ZipEntry;
1046         ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize );
1047         xManOutStream = uno::Reference < XOutputStream > ( *pBuffer, UNO_QUERY );
1048 
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();
1053 
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++ )
1060         {
1061             aManifestSequence[nInd] = ( *aIter );
1062         }
1063         xWriter->writeManifestSequence ( xManOutStream,  aManifestSequence );
1064 
1065         sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() );
1066         pBuffer->realloc( nBufferLength );
1067 
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();
1072     }
1073     else
1074     {
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 ) );
1081     }
1082 }
1083 
1084 //--------------------------------------------------------
1085 void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno::Sequence < PropertyValue > >& aManList )
1086 {
1087     const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1088     const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1089 
1090     ZipEntry* pEntry = new ZipEntry;
1091     ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize );
1092     uno::Reference< io::XOutputStream > xConTypeOutStream( *pBuffer, UNO_QUERY );
1093 
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();
1098 
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++ )
1108     {
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() )
1115         {
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;
1121         }
1122     }
1123     aOverridesSequence.realloc( nSeqLength );
1124 
1125     ::comphelper::OFOPXMLHelper::WriteContentSequence(
1126             xConTypeOutStream, aDefaultsSequence, aOverridesSequence, m_xFactory );
1127 
1128     sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() );
1129     pBuffer->realloc( nBufferLength );
1130 
1131     // there is no encryption in this format currently
1132     aZipOut.putNextEntry( *pEntry, NULL );
1133     aZipOut.write( pBuffer->getSequence(), 0, nBufferLength );
1134     aZipOut.closeEntry();
1135 }
1136 
1137 //--------------------------------------------------------
1138 void ZipPackage::ConnectTo( const uno::Reference< io::XInputStream >& xInStream )
1139 {
1140     m_xContentSeek.set( xInStream, uno::UNO_QUERY_THROW );
1141     m_xContentStream = xInStream;
1142 
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 );
1149 }
1150 
1151 //--------------------------------------------------------
1152 uno::Reference< io::XInputStream > ZipPackage::writeTempFile()
1153 {
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
1158 
1159     sal_Bool bUseTemp = sal_True;
1160     uno::Reference < io::XInputStream > xResult;
1161     uno::Reference < io::XInputStream > xTempIn;
1162 
1163     uno::Reference < io::XOutputStream > xTempOut;
1164     uno::Reference< io::XActiveDataStreamer > xSink;
1165 
1166     if ( m_eMode == e_IMode_URL && !m_pZipFile && isLocalFile_Impl( m_aURL ) )
1167     {
1168         xSink = openOriginalForOutput();
1169         if( xSink.is() )
1170         {
1171             uno::Reference< io::XStream > xStr = xSink->getStream();
1172             if( xStr.is() )
1173             {
1174                 xTempOut = xStr->getOutputStream();
1175                 if( xTempOut.is() )
1176                     bUseTemp = sal_False;
1177             }
1178         }
1179     }
1180     else if ( m_eMode == e_IMode_XStream && !m_pZipFile )
1181     {
1182         // write directly to an empty stream
1183         xTempOut = m_xStream->getOutputStream();
1184         if( xTempOut.is() )
1185             bUseTemp = sal_False;
1186     }
1187 
1188     if( bUseTemp )
1189     {
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 );
1195     }
1196 
1197     // Hand it to the ZipOutputStream:
1198     ZipOutputStream aZipOut( m_xFactory, xTempOut );
1199     aZipOut.setMethod( DEFLATED );
1200     aZipOut.setLevel( DEFAULT_COMPRESSION );
1201 
1202     try
1203     {
1204         if ( m_nFormat == embed::StorageFormats::PACKAGE )
1205         {
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" ) );
1210 
1211             if ( m_xRootFolder->hasByName( sMeta ) )
1212             {
1213                 const OUString sManifest ( RTL_CONSTASCII_USTRINGPARAM( "manifest.xml" ) );
1214 
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 );
1221             }
1222 
1223             // Write a magic file with mimetype
1224             WriteMimetypeMagicFile( aZipOut );
1225         }
1226         else if ( m_nFormat == embed::StorageFormats::OFOPXML )
1227         {
1228             // Remove the old [Content_Types].xml file as the
1229             // file will be re-generated
1230 
1231             const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
1232 
1233             if ( m_xRootFolder->hasByName( aContentTypes ) )
1234                 m_xRootFolder->removeByName( aContentTypes );
1235         }
1236 
1237         // Create a vector to store data for the manifest.xml file
1238         vector < uno::Sequence < PropertyValue > > aManList;
1239 
1240         const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1241         const OUString sVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) );
1242         const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1243 
1244         if ( m_nFormat == embed::StorageFormats::PACKAGE )
1245         {
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 ( "/" ) );
1253 
1254             aManList.push_back( aPropSeq );
1255         }
1256 
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 );
1264 
1265         // call saveContents ( it will recursively save sub-directories
1266         OUString aEmptyString;
1267         m_pRootFolder->saveContents( aEmptyString, aManList, aZipOut, GetEncryptionKey(), aRandomPool );
1268 
1269         // Clean up random pool memory
1270         rtl_random_destroyPool ( aRandomPool );
1271 
1272         if( m_nFormat == embed::StorageFormats::PACKAGE )
1273         {
1274             WriteManifest( aZipOut, aManList );
1275         }
1276         else if( m_nFormat == embed::StorageFormats::OFOPXML )
1277         {
1278             WriteContentTypes( aZipOut, aManList );
1279         }
1280 
1281         aZipOut.finish();
1282 
1283         if( bUseTemp )
1284             xResult = xTempIn;
1285 
1286         // Update our References to point to the new temp file
1287         if( !bUseTemp )
1288         {
1289             // the case when the original contents were written directly
1290             xTempOut->flush();
1291 
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();
1297 
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();
1304 
1305             if ( xNewStream.is() )
1306                 ConnectTo( xNewStream );
1307         }
1308     }
1309     catch ( uno::Exception& )
1310     {
1311         if( bUseTemp )
1312         {
1313             // no information loss appeares, thus no special handling is required
1314                uno::Any aCaught( ::cppu::getCaughtException() );
1315 
1316             // it is allowed to throw WrappedTargetException
1317             WrappedTargetException aException;
1318             if ( aCaught >>= aException )
1319                 throw aException;
1320 
1321             throw WrappedTargetException(
1322                     OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Problem writing the original content!" ) ),
1323                     static_cast < OWeakObject * > ( this ),
1324                     aCaught );
1325         }
1326         else
1327         {
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 ) );
1335         }
1336     }
1337 
1338     return xResult;
1339 }
1340 
1341 //--------------------------------------------------------
1342 uno::Reference< XActiveDataStreamer > ZipPackage::openOriginalForOutput()
1343 {
1344 	// open and truncate the original file
1345 	Content aOriginalContent ( m_aURL, uno::Reference < XCommandEnvironment >() );
1346 	uno::Reference< XActiveDataStreamer > xSink = new ActiveDataStreamer;
1347 
1348 	if ( m_eMode == e_IMode_URL )
1349 	{
1350 		try
1351 		{
1352 			sal_Bool bTruncSuccess = sal_False;
1353 
1354 			try
1355 			{
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;
1361 			}
1362 			catch( Exception& )
1363 			{
1364 			}
1365 
1366 			if( !bTruncSuccess )
1367 			{
1368 				// the file is not accessible
1369 				// just try to write an empty stream to it
1370 
1371 				uno::Reference< XInputStream > xTempIn = new DummyInputStream; //uno::Reference< XInputStream >( xTempOut, UNO_QUERY );
1372 				aOriginalContent.writeStream( xTempIn , sal_True );
1373 			}
1374 
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
1380 
1381 			aOriginalContent.executeCommand( OUString::createFromAscii( "open" ), makeAny( aArg ) );
1382 		}
1383 		catch( Exception& )
1384 		{
1385 			// seems to be nonlocal file
1386 			// temporary file mechanics should be used
1387 		}
1388 	}
1389 
1390 	return xSink;
1391 }
1392 
1393 //--------------------------------------------------------
1394 void SAL_CALL ZipPackage::commitChanges()
1395         throw( WrappedTargetException, RuntimeException )
1396 {
1397     // lock the component for the time of commiting
1398     ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
1399 
1400     if ( m_eMode == e_IMode_XInputStream )
1401     {
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 ) );
1405     }
1406 
1407     RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::commitChanges" );
1408 
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
1411 
1412     uno::Reference< io::XInputStream > xTempInStream = writeTempFile();
1413     if ( xTempInStream.is() )
1414     {
1415         uno::Reference< io::XSeekable > xTempSeek( xTempInStream, uno::UNO_QUERY_THROW );
1416 
1417         try
1418         {
1419             xTempSeek->seek( 0 );
1420         }
1421         catch( uno::Exception& r )
1422         {
1423             throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Temporary file should be seekable!" ) ),
1424                     static_cast < OWeakObject * > ( this ), makeAny ( r ) );
1425         }
1426 
1427         // connect to the temporary stream
1428         ConnectTo( xTempInStream );
1429 
1430         if ( m_eMode == e_IMode_XStream )
1431         {
1432             // First truncate our output stream
1433             uno::Reference < XOutputStream > xOutputStream;
1434 
1435             // preparation for copy step
1436             try
1437             {
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 >() );
1442 
1443                 // after successful truncation the original file contents are already lost
1444                 xTruncate->truncate();
1445             }
1446             catch( uno::Exception& r )
1447             {
1448                 throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ),
1449                         static_cast < OWeakObject * > ( this ), makeAny ( r ) );
1450             }
1451 
1452             try
1453             {
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();
1461                 }
1462             }
1463             catch( uno::Exception& )
1464             {
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 );
1469             }
1470         }
1471         else if ( m_eMode == e_IMode_URL )
1472         {
1473             uno::Reference< XOutputStream > aOrigFileStream;
1474             sal_Bool bCanBeCorrupted = sal_False;
1475 
1476             if( isLocalFile_Impl( m_aURL ) )
1477             {
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() )
1485                 {
1486                     try
1487                     {
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();
1492                     }
1493                     catch( uno::Exception& )
1494                     {}
1495                 }
1496 
1497                 if( xOrigTruncate.is() )
1498                 {
1499                     try
1500                     {
1501                         ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, aOrigFileStream );
1502                         aOrigFileStream->closeOutput();
1503                     }
1504                     catch( uno::Exception& )
1505                     {
1506                         try {
1507                             aOrigFileStream->closeOutput();
1508                         } catch ( uno::Exception& ) {}
1509 
1510                         aOrigFileStream = uno::Reference< XOutputStream >();
1511                         // the original file can already be corrupted
1512                         bCanBeCorrupted = sal_True;
1513                     }
1514                 }
1515             }
1516 
1517             if( !aOrigFileStream.is() )
1518             {
1519                 try
1520                 {
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 >() );
1525 
1526                     OUString sTargetFolder = m_aURL.copy ( 0, m_aURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) );
1527                     Content aContent ( sTargetFolder, uno::Reference < XCommandEnvironment > () );
1528 
1529                     OUString sTempURL;
1530                     Any aAny = xPropSet->getPropertyValue ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Uri" ) ) );
1531                     aAny >>= sTempURL;
1532 
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;
1541 
1542                     // if the file is still not corrupted, it can become after the next step
1543                     aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "transfer" ) ), aAny );
1544                 }
1545                 catch ( ::com::sun::star::uno::Exception& r )
1546                 {
1547                     if ( bCanBeCorrupted )
1548                         DisconnectFromTargetAndThrowException_Impl( xTempInStream );
1549 
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 ) );
1554                 }
1555             }
1556         }
1557     }
1558 
1559     // after successful storing it can be set to false
1560     m_bMediaTypeFallbackUsed = sal_False;
1561 
1562     RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::commitChanges" );
1563 }
1564 
1565 //--------------------------------------------------------
1566 void ZipPackage::DisconnectFromTargetAndThrowException_Impl( const uno::Reference< io::XInputStream >& xTempStream )
1567 {
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;
1573 
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 ) );
1581 	}
1582 	catch ( uno::Exception& )
1583 	{
1584 		OSL_ENSURE( sal_False, "These calls are pretty simple, they should not fail!\n" );
1585 	}
1586 
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 ) );
1592 }
1593 
1594 //--------------------------------------------------------
1595 const uno::Sequence< sal_Int8 > ZipPackage::GetEncryptionKey()
1596 {
1597     uno::Sequence< sal_Int8 > aResult;
1598 
1599     if ( m_aStorageEncryptionKeys.getLength() )
1600     {
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 >() );
1608 
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;
1612 
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 >() );
1617     }
1618     else
1619         aResult = m_aEncryptionKey;
1620 
1621     return aResult;
1622 }
1623 
1624 //--------------------------------------------------------
1625 sal_Bool SAL_CALL ZipPackage::hasPendingChanges()
1626 		throw( RuntimeException )
1627 {
1628 	return sal_False;
1629 }
1630 //--------------------------------------------------------
1631 Sequence< ElementChange > SAL_CALL ZipPackage::getPendingChanges()
1632 		throw( RuntimeException )
1633 {
1634 	return uno::Sequence < ElementChange > ();
1635 }
1636 
1637 /**
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
1640  */
1641 uno::Reference < XInterface >SAL_CALL ZipPackage_createInstance(
1642 	const uno::Reference< XMultiServiceFactory > & xMgr )
1643 {
1644 	return uno::Reference< XInterface >( *new ZipPackage( xMgr ) );
1645 }
1646 
1647 //--------------------------------------------------------
1648 OUString ZipPackage::static_getImplementationName()
1649 {
1650 	return OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.comp.ZipPackage" ) );
1651 }
1652 
1653 //--------------------------------------------------------
1654 Sequence< OUString > ZipPackage::static_getSupportedServiceNames()
1655 {
1656 	uno::Sequence< OUString > aNames( 1 );
1657 	aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.Package" ) );
1658 	return aNames;
1659 }
1660 //--------------------------------------------------------
1661 sal_Bool SAL_CALL ZipPackage::static_supportsService( OUString const & rServiceName )
1662 {
1663 	return rServiceName == getSupportedServiceNames()[0];
1664 }
1665 
1666 //--------------------------------------------------------
1667 OUString ZipPackage::getImplementationName()
1668 	throw ( RuntimeException )
1669 {
1670 	return static_getImplementationName();
1671 }
1672 
1673 //--------------------------------------------------------
1674 Sequence< OUString > ZipPackage::getSupportedServiceNames()
1675 	throw ( RuntimeException )
1676 {
1677 	return static_getSupportedServiceNames();
1678 }
1679 //--------------------------------------------------------
1680 sal_Bool SAL_CALL ZipPackage::supportsService( OUString const & rServiceName )
1681 	throw ( RuntimeException )
1682 {
1683 	return static_supportsService ( rServiceName );
1684 }
1685 //--------------------------------------------------------
1686 uno::Reference < XSingleServiceFactory > ZipPackage::createServiceFactory( uno::Reference < XMultiServiceFactory > const & rServiceFactory )
1687 {
1688 	return cppu::createSingleFactory ( rServiceFactory,
1689 										   static_getImplementationName(),
1690 										   ZipPackage_createInstance,
1691 										   static_getSupportedServiceNames() );
1692 }
1693 
1694 namespace { struct lcl_ImplId : public rtl::Static< ::cppu::OImplementationId, lcl_ImplId > {}; }
1695 
1696 //--------------------------------------------------------
1697 Sequence< sal_Int8 > ZipPackage::getUnoTunnelImplementationId( void )
1698 	throw ( RuntimeException )
1699 {
1700     ::cppu::OImplementationId &rId = lcl_ImplId::get();
1701     return rId.getImplementationId();
1702 }
1703 
1704 //--------------------------------------------------------
1705 sal_Int64 SAL_CALL ZipPackage::getSomething( const uno::Sequence< sal_Int8 >& aIdentifier )
1706 	throw( RuntimeException )
1707 {
1708 	if ( aIdentifier.getLength() == 16 && 0 == rtl_compareMemory( getUnoTunnelImplementationId().getConstArray(),  aIdentifier.getConstArray(), 16 ) )
1709 		return reinterpret_cast < sal_Int64 > ( this );
1710 	return 0;
1711 }
1712 
1713 //--------------------------------------------------------
1714 uno::Reference< XPropertySetInfo > SAL_CALL ZipPackage::getPropertySetInfo()
1715 		throw( RuntimeException )
1716 {
1717 	return uno::Reference < XPropertySetInfo > ();
1718 }
1719 
1720 //--------------------------------------------------------
1721 void SAL_CALL ZipPackage::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
1722 		throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException )
1723 {
1724 	if ( m_nFormat != embed::StorageFormats::PACKAGE )
1725 		throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1726 
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 ) ) )
1733 	{
1734 		if ( !( aValue >>= m_aEncryptionKey ) )
1735 			throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 );
1736 
1737         m_aStorageEncryptionKeys.realloc( 0 );
1738 	}
1739 	else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( STORAGE_ENCRYPTION_KEYS_PROPERTY ) ) )
1740 	{
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 );
1748 
1749         if ( aKeys.getLength() )
1750         {
1751             bool bHasSHA256 = false;
1752             bool bHasSHA1 = false;
1753             for ( sal_Int32 nInd = 0; nInd < aKeys.getLength(); nInd++ )
1754             {
1755                 if ( aKeys[nInd].Name.equals( PACKAGE_ENCRYPTIONDATA_SHA256UTF8 ) )
1756                     bHasSHA256 = true;
1757                 if ( aKeys[nInd].Name.equals( PACKAGE_ENCRYPTIONDATA_SHA1UTF8 ) )
1758                     bHasSHA1 = true;
1759             }
1760 
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 );
1763         }
1764 
1765         m_aStorageEncryptionKeys = aKeys;
1766         m_aEncryptionKey.realloc( 0 );
1767 	}
1768 	else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_ALGORITHMS_PROPERTY ) ) )
1769 	{
1770         uno::Sequence< beans::NamedValue > aAlgorithms;
1771 		if ( m_pZipFile || !( aValue >>= aAlgorithms ) || aAlgorithms.getLength() == 0 )
1772         {
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 );
1775         }
1776 
1777         for ( sal_Int32 nInd = 0; nInd < aAlgorithms.getLength(); nInd++ )
1778         {
1779             if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "StartKeyGenerationAlgorithm" ) ) )
1780             {
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 );
1785 
1786                 m_nStartKeyGenerationID = nID;
1787             }
1788             else if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "EncryptionAlgorithm" ) ) )
1789             {
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 );
1794 
1795                 m_nCommonEncryptionID = nID;
1796             }
1797             else if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ChecksumAlgorithm" ) ) )
1798             {
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 );
1803 
1804                 m_nChecksumDigestID = nID;
1805             }
1806             else
1807             {
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 );
1810             }
1811         }
1812 	}
1813 	else
1814 		throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1815 }
1816 
1817 //--------------------------------------------------------
1818 Any SAL_CALL ZipPackage::getPropertyValue( const OUString& PropertyName )
1819 		throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1820 {
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 >() );
1824 
1825 	Any aAny;
1826 	if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( ENCRYPTION_KEY_PROPERTY ) ) )
1827 	{
1828 		aAny <<= m_aEncryptionKey;
1829 		return aAny;
1830 	}
1831 	else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_ALGORITHMS_PROPERTY ) ) )
1832 	{
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;
1839     }
1840 	if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( STORAGE_ENCRYPTION_KEYS_PROPERTY ) ) )
1841 	{
1842 		aAny <<= m_aStorageEncryptionKeys;
1843 		return aAny;
1844 	}
1845 	else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( HAS_ENCRYPTED_ENTRIES_PROPERTY ) ) )
1846 	{
1847 		aAny <<= m_bHasEncryptedEntries;
1848 		return aAny;
1849 	}
1850 	else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( HAS_NONENCRYPTED_ENTRIES_PROPERTY ) ) )
1851 	{
1852 		aAny <<= m_bHasNonEncryptedEntries;
1853 		return aAny;
1854 	}
1855 	else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( IS_INCONSISTENT_PROPERTY ) ) )
1856 	{
1857 		aAny <<= m_bInconsistent;
1858 		return aAny;
1859 	}
1860 	else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( MEDIATYPE_FALLBACK_USED_PROPERTY ) ) )
1861 	{
1862 		aAny <<= m_bMediaTypeFallbackUsed;
1863 		return aAny;
1864 	}
1865 	throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1866 }
1867 //--------------------------------------------------------
1868 void SAL_CALL ZipPackage::addPropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ )
1869 		throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1870 {
1871 }
1872 //--------------------------------------------------------
1873 void SAL_CALL ZipPackage::removePropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*aListener*/ )
1874 		throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1875 {
1876 }
1877 //--------------------------------------------------------
1878 void SAL_CALL ZipPackage::addVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ )
1879 		throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1880 {
1881 }
1882 //--------------------------------------------------------
1883 void SAL_CALL ZipPackage::removeVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ )
1884 		throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1885 {
1886 }
1887