1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER( update_precomp.py ): autogen include statement, do not remove
25 #include "precompiled_package.hxx"
26 #include <ZipPackage.hxx>
27 #include <ZipPackageSink.hxx>
28 #include <ZipEnumeration.hxx>
29 #include <ZipPackageStream.hxx>
30 #include <ZipPackageFolder.hxx>
31 #include <ZipOutputStream.hxx>
32 #include <ZipPackageBuffer.hxx>
33 #include <ZipFile.hxx>
34 #include <PackageConstants.hxx>
35 #include <com/sun/star/beans/PropertyValue.hpp>
36 #include <com/sun/star/beans/NamedValue.hpp>
37 #include <com/sun/star/packages/zip/ZipConstants.hpp>
38 #include <com/sun/star/packages/manifest/XManifestReader.hpp>
39 #include <com/sun/star/packages/manifest/XManifestWriter.hpp>
40 #include <com/sun/star/io/XStream.hpp>
41 #include <com/sun/star/io/XInputStream.hpp>
42 #include <com/sun/star/io/XOutputStream.hpp>
43 #include <com/sun/star/io/XTruncate.hpp>
44 #include <com/sun/star/io/XSeekable.hpp>
45 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
46 #include <com/sun/star/container/XNameContainer.hpp>
47 #include <com/sun/star/ucb/IOErrorCode.hpp>
48 #include <ucbhelper/content.hxx>
49 #include <cppuhelper/factory.hxx>
50 #include <cppuhelper/exc_hlp.hxx>
51 #include <com/sun/star/ucb/TransferInfo.hpp>
52 #include <com/sun/star/ucb/NameClash.hpp>
53 #include <com/sun/star/ucb/OpenCommandArgument2.hpp>
54 #include <com/sun/star/ucb/OpenMode.hpp>
55 #include <com/sun/star/ucb/XProgressHandler.hpp>
56 #include <com/sun/star/ucb/XSimpleFileAccess.hpp>
57 #include <com/sun/star/io/XActiveDataStreamer.hpp>
58 #include <com/sun/star/embed/XTransactedObject.hpp>
59 #include <com/sun/star/embed/UseBackupException.hpp>
60 #include <com/sun/star/embed/StorageFormats.hpp>
61 #include <com/sun/star/beans/NamedValue.hpp>
62 #include <com/sun/star/xml/crypto/DigestID.hpp>
63 #include <com/sun/star/xml/crypto/CipherID.hpp>
64 #include <cppuhelper/implbase1.hxx>
65 #include <ContentInfo.hxx>
66 #include <cppuhelper/typeprovider.hxx>
67 #include <rtl/uri.hxx>
68 #include <rtl/random.h>
69 #include <rtl/logfile.hxx>
70 #include <rtl/instance.hxx>
71 #include <osl/time.h>
72 #include <osl/file.hxx>
73 #include "com/sun/star/io/XAsyncOutputMonitor.hpp"
74 
75 #include <memory>
76 #include <vector>
77 
78 #include <ucbhelper/contentbroker.hxx>
79 #include <ucbhelper/fileidentifierconverter.hxx>
80 #include <comphelper/seekableinput.hxx>
81 #include <comphelper/storagehelper.hxx>
82 #include <comphelper/ofopxmlhelper.hxx>
83 #include <comphelper/documentconstants.hxx>
84 #include <comphelper/sequenceashashmap.hxx>
85 
86 using namespace rtl;
87 using namespace std;
88 using namespace osl;
89 using namespace cppu;
90 using namespace ucbhelper;
91 using namespace com::sun::star;
92 using namespace com::sun::star::io;
93 using namespace com::sun::star::uno;
94 using namespace com::sun::star::ucb;
95 using namespace com::sun::star::util;
96 using namespace com::sun::star::lang;
97 using namespace com::sun::star::task;
98 using namespace com::sun::star::beans;
99 using namespace com::sun::star::packages;
100 using namespace com::sun::star::container;
101 using namespace com::sun::star::packages::zip;
102 using namespace com::sun::star::packages::manifest;
103 using namespace com::sun::star::packages::zip::ZipConstants;
104 
105 #define LOGFILE_AUTHOR "mg115289"
106 
107 
108 namespace {
109 
isLocalFile_Impl(::rtl::OUString aURL)110 sal_Bool isLocalFile_Impl( ::rtl::OUString aURL )
111 {
112 	::rtl::OUString aSystemPath;
113     ContentBroker* pBroker = ContentBroker::get();
114     if ( !pBroker )
115     {
116 		::rtl::OUString aRet;
117         if ( FileBase::getSystemPathFromFileURL( aURL, aRet ) == FileBase::E_None )
118 			aSystemPath = aRet;
119     }
120     else
121     {
122         uno::Reference< XContentProviderManager > xManager =
123 				pBroker->getContentProviderManagerInterface();
124         try
125         {
126            	aSystemPath = getSystemPathFromFileURL( xManager, aURL );
127         }
128         catch ( Exception& )
129         {
130         }
131     }
132 
133     return ( aSystemPath.getLength() != 0 );
134 }
135 
136 }
137 
138 //===========================================================================
139 
140 class ActiveDataStreamer : public ::cppu::WeakImplHelper1< XActiveDataStreamer >
141 {
142 	uno::Reference< XStream > mStream;
143 public:
144 
getStream()145 	virtual uno::Reference< XStream > SAL_CALL getStream()
146 			throw( RuntimeException )
147 			{ return mStream; }
148 
setStream(const uno::Reference<XStream> & stream)149 	virtual void SAL_CALL setStream( const uno::Reference< XStream >& stream )
150 			throw( RuntimeException )
151 			{ mStream = stream; }
152 };
153 
154 class DummyInputStream : public ::cppu::WeakImplHelper1< XInputStream >
155 {
readBytes(uno::Sequence<sal_Int8> &,sal_Int32)156     virtual sal_Int32 SAL_CALL readBytes( uno::Sequence< sal_Int8 >&, sal_Int32 )
157 			throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
158 		{ return 0; }
159 
readSomeBytes(uno::Sequence<sal_Int8> &,sal_Int32)160     virtual sal_Int32 SAL_CALL readSomeBytes( uno::Sequence< sal_Int8 >&, sal_Int32 )
161 			throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
162 		{ return 0; }
163 
skipBytes(sal_Int32)164     virtual void SAL_CALL skipBytes( sal_Int32 )
165 			throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
166 		{}
167 
available()168     virtual sal_Int32 SAL_CALL available()
169 			throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
170 		{ return 0; }
171 
closeInput()172     virtual void SAL_CALL closeInput()
173 			throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException )
174 		{}
175 };
176 
177 //===========================================================================
178 
ZipPackage(const uno::Reference<XMultiServiceFactory> & xNewFactory)179 ZipPackage::ZipPackage ( const uno::Reference < XMultiServiceFactory > &xNewFactory )
180 : m_aMutexHolder( new SotMutexHolder )
181 , m_nStartKeyGenerationID( xml::crypto::DigestID::SHA1 )
182 , m_nChecksumDigestID( xml::crypto::DigestID::SHA1_1K )
183 , m_nCommonEncryptionID( xml::crypto::CipherID::BLOWFISH_CFB_8 )
184 , m_bHasEncryptedEntries ( sal_False )
185 , m_bHasNonEncryptedEntries ( sal_False )
186 , m_bInconsistent ( sal_False )
187 , m_bForceRecovery ( sal_False )
188 , m_bMediaTypeFallbackUsed ( sal_False )
189 , m_nFormat( embed::StorageFormats::PACKAGE ) // package is the default format
190 , m_bAllowRemoveOnInsert( sal_True )
191 , m_eMode ( e_IMode_None )
192 , m_xFactory( xNewFactory )
193 , m_pRootFolder( NULL )
194 , m_pZipFile( NULL )
195 {
196 	m_xRootFolder = m_pRootFolder = new ZipPackageFolder( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert );
197 }
198 
~ZipPackage(void)199 ZipPackage::~ZipPackage( void )
200 {
201 	delete m_pZipFile;
202 
203 	// All folders and streams contain pointers to their parents, when a parent diappeares
204 	// it should disconnect all the children from itself during destruction automatically.
205 	// So there is no need in explicit m_pRootFolder->releaseUpwardRef() call here any more
206 	// since m_pRootFolder has no parent and cleaning of it's children will be done automatically
207 	// during m_pRootFolder dying by refcount.
208 }
209 
210 //--------------------------------------------------------
parseManifest()211 void ZipPackage::parseManifest()
212 {
213 	if ( m_nFormat == embed::StorageFormats::PACKAGE )
214 	{
215 		sal_Bool bManifestParsed = sal_False;
216         bool bDifferentStartKeyAlgorithm = false;
217 		const OUString sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) );
218 		if ( m_xRootFolder->hasByName( sMeta ) )
219 		{
220 			const OUString sManifest ( RTL_CONSTASCII_USTRINGPARAM( "manifest.xml" ) );
221 
222 			try {
223 				uno::Reference< XUnoTunnel > xTunnel;
224 				Any aAny = m_xRootFolder->getByName( sMeta );
225 				aAny >>= xTunnel;
226 				uno::Reference< XNameContainer > xMetaInfFolder( xTunnel, UNO_QUERY );
227 				if ( xMetaInfFolder.is() && xMetaInfFolder->hasByName( sManifest ) )
228 				{
229 					aAny = xMetaInfFolder->getByName( sManifest );
230 					aAny >>= xTunnel;
231 					uno::Reference < XActiveDataSink > xSink ( xTunnel, UNO_QUERY );
232 					if ( xSink.is() )
233 					{
234 						OUString sManifestReader ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestReader" ) );
235 						uno::Reference < XManifestReader > xReader ( m_xFactory->createInstance( sManifestReader ), UNO_QUERY );
236 						if ( xReader.is() )
237 						{
238 							const OUString sPropFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
239 							const OUString sPropVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) );
240 							const OUString sPropMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
241 							const OUString sPropInitialisationVector ( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) );
242 							const OUString sPropSalt ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) );
243 							const OUString sPropIterationCount ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) );
244 							const OUString sPropSize ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) );
245 							const OUString sPropDigest ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) );
246 							const OUString sPropDerivedKeySize ( RTL_CONSTASCII_USTRINGPARAM ( "DerivedKeySize" ) );
247 							const OUString sPropDigestAlgorithm ( RTL_CONSTASCII_USTRINGPARAM ( "DigestAlgorithm" ) );
248 							const OUString sPropEncryptionAlgorithm ( RTL_CONSTASCII_USTRINGPARAM ( "EncryptionAlgorithm" ) );
249 							const OUString sPropStartKeyAlgorithm ( RTL_CONSTASCII_USTRINGPARAM ( "StartKeyAlgorithm" ) );
250 
251 							uno::Sequence < uno::Sequence < PropertyValue > > aManifestSequence = xReader->readManifestSequence ( xSink->getInputStream() );
252 							sal_Int32 nLength = aManifestSequence.getLength();
253 							const uno::Sequence < PropertyValue > *pSequence = aManifestSequence.getConstArray();
254 							ZipPackageStream *pStream = NULL;
255 							ZipPackageFolder *pFolder = NULL;
256 
257 							for ( sal_Int32 i = 0; i < nLength ; i++, pSequence++ )
258 							{
259 								OUString sPath, sMediaType, sVersion;
260 								const PropertyValue *pValue = pSequence->getConstArray();
261 								const Any *pSalt = NULL, *pVector = NULL, *pCount = NULL, *pSize = NULL, *pDigest = NULL, *pDigestAlg = NULL, *pEncryptionAlg = NULL, *pStartKeyAlg = NULL, *pDerivedKeySize = NULL;
262 								for ( sal_Int32 j = 0, nNum = pSequence->getLength(); j < nNum; j++ )
263 								{
264 									if ( pValue[j].Name.equals( sPropFullPath ) )
265 										pValue[j].Value >>= sPath;
266 									else if ( pValue[j].Name.equals( sPropVersion ) )
267 										pValue[j].Value >>= sVersion;
268 									else if ( pValue[j].Name.equals( sPropMediaType ) )
269 										pValue[j].Value >>= sMediaType;
270 									else if ( pValue[j].Name.equals( sPropSalt ) )
271 										pSalt = &( pValue[j].Value );
272 									else if ( pValue[j].Name.equals( sPropInitialisationVector ) )
273 										pVector = &( pValue[j].Value );
274 									else if ( pValue[j].Name.equals( sPropIterationCount ) )
275 										pCount = &( pValue[j].Value );
276 									else if ( pValue[j].Name.equals( sPropSize ) )
277 										pSize = &( pValue[j].Value );
278 									else if ( pValue[j].Name.equals( sPropDigest ) )
279 										pDigest = &( pValue[j].Value );
280 									else if ( pValue[j].Name.equals( sPropDigestAlgorithm ) )
281 										pDigestAlg = &( pValue[j].Value );
282 									else if ( pValue[j].Name.equals( sPropEncryptionAlgorithm ) )
283 										pEncryptionAlg = &( pValue[j].Value );
284 									else if ( pValue[j].Name.equals( sPropStartKeyAlgorithm ) )
285 										pStartKeyAlg = &( pValue[j].Value );
286 									else if ( pValue[j].Name.equals( sPropDerivedKeySize ) )
287 										pDerivedKeySize = &( pValue[j].Value );
288 								}
289 
290 								if ( sPath.getLength() && hasByHierarchicalName ( sPath ) )
291 								{
292 									aAny = getByHierarchicalName( sPath );
293 									uno::Reference < XUnoTunnel > xUnoTunnel;
294 									aAny >>= xUnoTunnel;
295 									sal_Int64 nTest=0;
296 									if ( (nTest = xUnoTunnel->getSomething( ZipPackageFolder::static_getImplementationId() )) != 0 )
297 									{
298 										pFolder = reinterpret_cast < ZipPackageFolder* > ( nTest );
299 										pFolder->SetMediaType ( sMediaType );
300 										pFolder->SetVersion ( sVersion );
301 									}
302 									else
303 									{
304 										pStream = reinterpret_cast < ZipPackageStream* > ( xUnoTunnel->getSomething( ZipPackageStream::static_getImplementationId() ));
305 										pStream->SetMediaType ( sMediaType );
306                                         pStream->SetFromManifest( sal_True );
307 
308 										if ( pSalt && pVector && pCount && pSize && pDigest && pDigestAlg && pEncryptionAlg )
309 										{
310 											uno::Sequence < sal_Int8 > aSequence;
311 											sal_Int32 nCount = 0, nSize = 0, nDigestAlg = 0, nEncryptionAlg = 0, nDerivedKeySize = 16, nStartKeyAlg = xml::crypto::DigestID::SHA1;
312 
313                                             pStream->SetToBeEncrypted ( sal_True );
314 
315 											*pSalt >>= aSequence;
316 											pStream->setSalt ( aSequence );
317 
318 											*pVector >>= aSequence;
319 											pStream->setInitialisationVector ( aSequence );
320 
321 											*pCount >>= nCount;
322 											pStream->setIterationCount ( nCount );
323 
324 											*pSize >>= nSize;
325 											pStream->setSize ( nSize );
326 
327                                             *pDigest >>= aSequence;
328                                             pStream->setDigest ( aSequence );
329 
330                                             *pDigestAlg >>= nDigestAlg;
331                                             pStream->SetImportedChecksumAlgorithm( nDigestAlg );
332 
333                                             *pEncryptionAlg >>= nEncryptionAlg;
334                                             pStream->SetImportedEncryptionAlgorithm( nEncryptionAlg );
335 
336                                             if ( pDerivedKeySize )
337                                                 *pDerivedKeySize >>= nDerivedKeySize;
338                                             pStream->SetImportedDerivedKeySize( nDerivedKeySize );
339 
340                                             if ( pStartKeyAlg )
341                                                 *pStartKeyAlg >>= nStartKeyAlg;
342                                             pStream->SetImportedStartKeyAlgorithm( nStartKeyAlg );
343 
344 											pStream->SetToBeCompressed ( sal_True );
345 											pStream->SetToBeEncrypted ( sal_True );
346 											pStream->SetIsEncrypted ( sal_True );
347 											if ( !m_bHasEncryptedEntries
348                                               && pStream->getName().equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "content.xml" ) ) ) )
349                                             {
350 												m_bHasEncryptedEntries = sal_True;
351                                                 m_nStartKeyGenerationID = nStartKeyAlg;
352                                                 m_nChecksumDigestID = nDigestAlg;
353                                                 m_nCommonEncryptionID = nEncryptionAlg;
354                                             }
355 										}
356                                         else
357                                             m_bHasNonEncryptedEntries = sal_True;
358 									}
359 								}
360 							}
361 
362 							bManifestParsed = sal_True;
363 						}
364 						else
365                             throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No manifes parser!" ) ), uno::Reference< uno::XInterface >() );
366 					}
367 
368 					// now hide the manifest.xml file from user
369 					xMetaInfFolder->removeByName( sManifest );
370 				}
371 			}
372 			catch( Exception& )
373 			{
374 				if ( !m_bForceRecovery )
375 					throw;
376 			}
377 		}
378 
379         if ( !bManifestParsed && !m_bForceRecovery )
380             throw ZipIOException(
381                 ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Could not parse manifest.xml\n" ) ),
382                 uno::Reference< uno::XInterface >() );
383 
384 		const OUString sMimetype ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) );
385 		if ( m_xRootFolder->hasByName( sMimetype ) )
386 		{
387             // get mediatype from the "mimetype" stream
388             ::rtl::OUString aPackageMediatype;
389             uno::Reference< lang::XUnoTunnel > xMimeTypeTunnel;
390             m_xRootFolder->getByName( sMimetype ) >>= xMimeTypeTunnel;
391             uno::Reference < io::XActiveDataSink > xMimeSink( xMimeTypeTunnel, UNO_QUERY );
392             if ( xMimeSink.is() )
393             {
394                 uno::Reference< io::XInputStream > xMimeInStream = xMimeSink->getInputStream();
395                 if ( xMimeInStream.is() )
396                 {
397                     // Mediatypes longer than 1024 symbols should not appear here
398                     uno::Sequence< sal_Int8 > aData( 1024 );
399                     sal_Int32 nRead = xMimeInStream->readBytes( aData, 1024 );
400                     if ( nRead > aData.getLength() )
401                         nRead = aData.getLength();
402 
403                     if ( nRead )
404                         aPackageMediatype = ::rtl::OUString( ( sal_Char* )aData.getConstArray(), nRead, RTL_TEXTENCODING_ASCII_US );
405                 }
406             }
407 
408 
409             if ( !bManifestParsed )
410             {
411                 // the manifest.xml could not be successfully parsed, this is an inconsistent package
412                 if ( aPackageMediatype.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "application/vnd." ) ) == 0 )
413                 {
414                     // accept only types that look similar to own mediatypes
415                     m_pRootFolder->SetMediaType( aPackageMediatype );
416                     m_bMediaTypeFallbackUsed = sal_True;
417                 }
418             }
419             else if ( !m_bForceRecovery )
420             {
421                 // the mimetype stream should contain the information from manifest.xml
422                 if ( !m_pRootFolder->GetMediaType().equals( aPackageMediatype ) )
423                     throw ZipIOException(
424                         ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "mimetype conflicts with manifest.xml\n" ) ),
425                         uno::Reference< uno::XInterface >() );
426             }
427 
428             m_xRootFolder->removeByName( sMimetype );
429         }
430 
431         m_bInconsistent = m_pRootFolder->LookForUnexpectedODF12Streams( ::rtl::OUString() );
432 
433         sal_Bool bODF12AndNewer = ( m_pRootFolder->GetVersion().compareTo( ODFVER_012_TEXT ) >= 0 );
434         if ( !m_bForceRecovery && bODF12AndNewer )
435         {
436             if ( m_bInconsistent )
437             {
438                 // this is an ODF1.2 document that contains streams not referred in the manifest.xml;
439                 // in case of ODF1.2 documents without version in manifest.xml the property IsInconsistent
440                 // should be checked later
441                 throw ZipIOException(
442                     ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "there are streams not referred in manifest.xml\n" ) ),
443                     uno::Reference< uno::XInterface >() );
444             }
445             else if ( bDifferentStartKeyAlgorithm )
446             {
447                 // all the streams should be encrypted with the same StartKey in ODF1.2
448                 // TODO/LATER: in future the exception should be thrown
449                 OSL_ENSURE( false, "ODF1.2 contains different StartKey Algorithms" );
450                 // throw ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "More than one Start Key Generation algorithm is specified!" ) ), uno::Reference< uno::XInterface >() );
451             }
452         }
453 
454         // in case it is a correct ODF1.2 document, the version must be set
455         // and the META-INF folder is reserved for package format
456         if ( bODF12AndNewer )
457             m_xRootFolder->removeByName( sMeta );
458 	}
459 }
460 
461 //--------------------------------------------------------
parseContentType()462 void ZipPackage::parseContentType()
463 {
464 	if ( m_nFormat == embed::StorageFormats::OFOPXML )
465 	{
466 		const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
467 		try {
468 			// the content type must exist in OFOPXML format!
469 			if ( !m_xRootFolder->hasByName( aContentTypes ) )
470 				throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong format!" ) ),
471 										uno::Reference< uno::XInterface >() );
472 
473 			uno::Reference< lang::XUnoTunnel > xTunnel;
474 			uno::Any aAny = m_xRootFolder->getByName( aContentTypes );
475 			aAny >>= xTunnel;
476 			uno::Reference < io::XActiveDataSink > xSink( xTunnel, UNO_QUERY );
477 			if ( xSink.is() )
478 			{
479 				uno::Reference< io::XInputStream > xInStream = xSink->getInputStream();
480 				if ( xInStream.is() )
481 				{
482 					sal_Int32 nInd = 0;
483 					// here aContentTypeInfo[0] - Defaults, and aContentTypeInfo[1] - Overrides
484 					uno::Sequence< uno::Sequence< beans::StringPair > > aContentTypeInfo =
485 						::comphelper::OFOPXMLHelper::ReadContentTypeSequence( xInStream, m_xFactory );
486 
487 					if ( aContentTypeInfo.getLength() != 2 )
488 						throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
489 
490 					// set the implicit types fist
491 					for ( nInd = 0; nInd < aContentTypeInfo[0].getLength(); nInd++ )
492 						m_pRootFolder->setChildStreamsTypeByExtension( aContentTypeInfo[0][nInd] );
493 
494 					// now set the explicit types
495 					for ( nInd = 0; nInd < aContentTypeInfo[1].getLength(); nInd++ )
496 					{
497 						::rtl::OUString aPath;
498 						if ( aContentTypeInfo[1][nInd].First.toChar() == ( sal_Unicode )'/' )
499 							aPath = aContentTypeInfo[1][nInd].First.copy( 1 );
500 						else
501 							aPath = aContentTypeInfo[1][nInd].First;
502 
503 						if ( aPath.getLength() && hasByHierarchicalName( aPath ) )
504 						{
505 							uno::Any aIterAny = getByHierarchicalName( aPath );
506 							uno::Reference < lang::XUnoTunnel > xIterTunnel;
507 							aIterAny >>= xIterTunnel;
508 							sal_Int64 nTest = xIterTunnel->getSomething( ZipPackageStream::static_getImplementationId() );
509 							if ( nTest != 0 )
510 							{
511 								// this is a package stream, in OFOPXML format only streams can have mediatype
512 								ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream* > ( nTest );
513 								pStream->SetMediaType( aContentTypeInfo[1][nInd].Second );
514 							}
515 						}
516 					}
517 				}
518 			}
519 
520 			m_xRootFolder->removeByName( aContentTypes );
521 		}
522 		catch( uno::Exception& )
523 		{
524 			if ( !m_bForceRecovery )
525 				throw;
526 		}
527 	}
528 }
529 
530 //--------------------------------------------------------
getZipFileContents()531 void ZipPackage::getZipFileContents()
532 {
533 	auto_ptr < ZipEnumeration > pEnum ( m_pZipFile->entries() );
534 	ZipPackageStream *pPkgStream;
535 	ZipPackageFolder *pPkgFolder, *pCurrent;
536 	OUString sTemp, sDirName;
537 	sal_Int32 nOldIndex, nIndex, nStreamIndex;
538 	FolderHash::iterator aIter;
539 
540 	while ( pEnum->hasMoreElements() )
541 	{
542 		nIndex = nOldIndex = 0;
543 		pCurrent = m_pRootFolder;
544 		const ZipEntry & rEntry = *pEnum->nextElement();
545 		OUString rName = rEntry.sPath;
546 
547         if ( m_bForceRecovery )
548         {
549             // the PKZIP Application note version 6.2 does not allows to use '\' as separator
550             // unfortunately it is used by some implementations, so we have to support it in recovery mode
551             rName = rName.replace( '\\', '/' );
552         }
553 
554 		nStreamIndex = rName.lastIndexOf ( '/' );
555 		if ( nStreamIndex != -1 )
556 		{
557 			sDirName = rName.copy ( 0, nStreamIndex );
558 			aIter = m_aRecent.find ( sDirName );
559 			if ( aIter != m_aRecent.end() )
560 				pCurrent = ( *aIter ).second;
561 		}
562 
563 		if ( pCurrent == m_pRootFolder )
564 		{
565 			while ( ( nIndex = rName.indexOf( '/', nOldIndex ) ) != -1 )
566 			{
567 				sTemp = rName.copy ( nOldIndex, nIndex - nOldIndex );
568 				if ( nIndex == nOldIndex )
569 					break;
570 				if ( !pCurrent->hasByName( sTemp ) )
571 				{
572 					pPkgFolder = new ZipPackageFolder( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert );
573 					pPkgFolder->setName( sTemp );
574 					pPkgFolder->doSetParent( pCurrent, sal_True );
575 					pCurrent = pPkgFolder;
576 				}
577 				else
578 					pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
579 				nOldIndex = nIndex+1;
580 			}
581 			if ( nStreamIndex != -1 && sDirName.getLength() )
582 				m_aRecent [ sDirName ] = pCurrent;
583 		}
584 		if ( rName.getLength() -1 != nStreamIndex )
585 		{
586 			nStreamIndex++;
587 			sTemp = rName.copy( nStreamIndex, rName.getLength() - nStreamIndex );
588 			pPkgStream = new ZipPackageStream( *this, m_xFactory, m_bAllowRemoveOnInsert );
589 			pPkgStream->SetPackageMember( sal_True );
590 			pPkgStream->setZipEntryOnLoading( rEntry );
591 			pPkgStream->setName( sTemp );
592 			pPkgStream->doSetParent( pCurrent, sal_True );
593 		}
594 	}
595 
596 	if ( m_nFormat == embed::StorageFormats::PACKAGE )
597 		parseManifest();
598 	else if ( m_nFormat == embed::StorageFormats::OFOPXML )
599 		parseContentType();
600 }
601 
602 //--------------------------------------------------------
initialize(const uno::Sequence<Any> & aArguments)603 void SAL_CALL ZipPackage::initialize( const uno::Sequence< Any >& aArguments )
604 		throw( Exception, RuntimeException )
605 {
606 	RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::initialize" );
607 	sal_Bool bBadZipFile = sal_False, bHaveZipFile = sal_True;
608 	uno::Reference< XProgressHandler > xProgressHandler;
609 	beans::NamedValue aNamedValue;
610 
611 	if ( aArguments.getLength() )
612 	{
613 		for( int ind = 0; ind < aArguments.getLength(); ind++ )
614 		{
615 			OUString aParamUrl;
616 			if ( ( aArguments[ind] >>= aParamUrl ))
617 			{
618 				m_eMode = e_IMode_URL;
619 				try
620 				{
621 					sal_Int32 nParam = aParamUrl.indexOf( '?' );
622 					if ( nParam >= 0 )
623 					{
624 						m_aURL = aParamUrl.copy( 0, nParam );
625 						OUString aParam = aParamUrl.copy( nParam + 1 );
626 
627               			sal_Int32 nIndex = 0;
628 						do
629 						{
630 							::rtl::OUString aCommand = aParam.getToken( 0, '&', nIndex );
631 							if ( aCommand.equals( OUString::createFromAscii( "repairpackage" ) ) )
632 							{
633 								m_bForceRecovery = sal_True;
634 								break;
635 							}
636 							else if ( aCommand.equals( OUString::createFromAscii( "purezip" ) ) )
637 							{
638 								m_nFormat = embed::StorageFormats::ZIP;
639 								m_pRootFolder->setPackageFormat_Impl( m_nFormat );
640 								break;
641 							}
642 							else if ( aCommand.equals( OUString::createFromAscii( "ofopxml" ) ) )
643 							{
644 								m_nFormat = embed::StorageFormats::OFOPXML;
645 								m_pRootFolder->setPackageFormat_Impl( m_nFormat );
646 								break;
647 							}
648 						}
649 						while ( nIndex >= 0 );
650 					}
651 					else
652 						m_aURL = aParamUrl;
653 
654 					Content aContent ( m_aURL, uno::Reference < XCommandEnvironment >() );
655 					Any aAny = aContent.getPropertyValue( OUString::createFromAscii( "Size" ) );
656 					sal_uInt64 aSize = 0;
657 					// kind of optimisation: treat empty files as nonexistent files
658 					// and write to such files directly. Note that "Size" property is optional.
659 					bool bHasSizeProperty = aAny >>= aSize;
660 					if( !bHasSizeProperty || ( bHasSizeProperty && aSize ) )
661 					{
662 						uno::Reference < XActiveDataSink > xSink = new ZipPackageSink;
663 						if ( aContent.openStream ( xSink ) )
664 							m_xContentStream = xSink->getInputStream();
665 					}
666 					else
667 						bHaveZipFile = sal_False;
668 				}
669 				catch ( com::sun::star::uno::Exception& )
670 				{
671 					// Exception derived from uno::Exception thrown. This probably
672 					// means the file doesn't exist...we'll create it at
673 					// commitChanges time
674 					bHaveZipFile = sal_False;
675 				}
676 			}
677 			else if ( ( aArguments[ind] >>= m_xStream ) )
678 			{
679 				// a writable stream can implement both XStream & XInputStream
680 				m_eMode = e_IMode_XStream;
681 				m_xContentStream = m_xStream->getInputStream();
682 			}
683 			else if ( ( aArguments[ind] >>= m_xContentStream ) )
684 			{
685 				m_eMode = e_IMode_XInputStream;
686 			}
687 			else if ( ( aArguments[ind] >>= aNamedValue ) )
688 			{
689 				if ( aNamedValue.Name.equalsAscii( "RepairPackage" ) )
690 					aNamedValue.Value >>= m_bForceRecovery;
691 				else if ( aNamedValue.Name.equalsAscii( "PackageFormat" ) )
692 				{
693 					// setting this argument to true means Package format
694 					// setting it to false means plain Zip format
695 
696 					sal_Bool bPackFormat = sal_True;
697 					aNamedValue.Value >>= bPackFormat;
698 					if ( !bPackFormat )
699 						m_nFormat = embed::StorageFormats::ZIP;
700 
701 					m_pRootFolder->setPackageFormat_Impl( m_nFormat );
702 				}
703 				else if ( aNamedValue.Name.equalsAscii( "StorageFormat" ) )
704 				{
705 					::rtl::OUString aFormatName;
706                     sal_Int32 nFormatID = 0;
707                     if ( aNamedValue.Value >>= aFormatName )
708                     {
709                         if ( aFormatName.equals( PACKAGE_STORAGE_FORMAT_STRING ) )
710                             m_nFormat = embed::StorageFormats::PACKAGE;
711                         else if ( aFormatName.equals( ZIP_STORAGE_FORMAT_STRING ) )
712                             m_nFormat = embed::StorageFormats::ZIP;
713                         else if ( aFormatName.equals( OFOPXML_STORAGE_FORMAT_STRING ) )
714                             m_nFormat = embed::StorageFormats::OFOPXML;
715                         else
716                             throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
717                     }
718                     else if ( aNamedValue.Value >>= nFormatID )
719                     {
720                         if ( nFormatID != embed::StorageFormats::PACKAGE
721                           && nFormatID != embed::StorageFormats::ZIP
722                           && nFormatID != embed::StorageFormats::OFOPXML )
723                             throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
724 
725                         m_nFormat = nFormatID;
726                     }
727                     else
728                         throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
729 
730 					m_pRootFolder->setPackageFormat_Impl( m_nFormat );
731 				}
732 				else if ( aNamedValue.Name.equalsAscii( "AllowRemoveOnInsert" ) )
733 				{
734 					aNamedValue.Value >>= m_bAllowRemoveOnInsert;
735 					m_pRootFolder->setRemoveOnInsertMode_Impl( m_bAllowRemoveOnInsert );
736 				}
737 
738 				// for now the progress handler is not used, probably it will never be
739 				// if ( aNamedValue.Name.equalsAscii( "ProgressHandler" )
740 			}
741 			else
742 			{
743 				// The URL is not acceptable
744 				throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad arguments." ) ),
745 					static_cast < ::cppu::OWeakObject * > ( this ) );
746 			}
747 		}
748 
749 		try
750 		{
751 			if ( m_xContentStream.is() )
752 			{
753 				// the stream must be seekable, if it is not it will be wrapped
754 				m_xContentStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( m_xContentStream, m_xFactory );
755 				m_xContentSeek = uno::Reference < XSeekable > ( m_xContentStream, UNO_QUERY );
756 				if ( ! m_xContentSeek.is() )
757 					throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "The package component _requires_ an XSeekable interface!" ) ),
758 							static_cast < ::cppu::OWeakObject * > ( this ) );
759 
760 				if ( !m_xContentSeek->getLength() )
761 					bHaveZipFile = sal_False;
762 			}
763 			else
764 				bHaveZipFile = sal_False;
765 		}
766 		catch ( com::sun::star::uno::Exception& )
767 		{
768 			// Exception derived from uno::Exception thrown. This probably
769 			// means the file doesn't exist...we'll create it at
770 			// commitChanges time
771 			bHaveZipFile = sal_False;
772 		}
773 		if ( bHaveZipFile )
774 		{
775 			try
776 			{
777 				m_pZipFile = new ZipFile ( m_xContentStream, m_xFactory, sal_True, m_bForceRecovery, xProgressHandler );
778 				getZipFileContents();
779 			}
780 			catch ( IOException & )
781 			{
782 				bBadZipFile = sal_True;
783 			}
784 			catch ( ZipException & )
785 			{
786 				bBadZipFile = sal_True;
787 			}
788 			catch ( Exception & )
789 			{
790 				if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; }
791 				throw;
792 			}
793 
794 			if ( bBadZipFile )
795 			{
796 				// clean up the memory, and tell the UCB about the error
797 				if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; }
798 
799 				throw com::sun::star::packages::zip::ZipIOException (
800 					OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad Zip File." ) ),
801 					static_cast < ::cppu::OWeakObject * > ( this ) );
802 			}
803 		}
804 	}
805 
806 	RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::initialize" );
807 }
808 
809 //--------------------------------------------------------
getByHierarchicalName(const OUString & aName)810 Any SAL_CALL ZipPackage::getByHierarchicalName( const OUString& aName )
811 		throw( NoSuchElementException, RuntimeException )
812 {
813 	OUString sTemp, sDirName;
814 	sal_Int32 nOldIndex, nIndex, nStreamIndex;
815 	FolderHash::iterator aIter;
816 
817 	if ( ( nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' )
818 		return makeAny ( uno::Reference < XUnoTunnel > ( m_pRootFolder ) );
819 	else
820 	{
821 		nStreamIndex = aName.lastIndexOf ( '/' );
822 		bool bFolder = nStreamIndex == nIndex-1;
823 		if ( nStreamIndex != -1 )
824 		{
825 			sDirName = aName.copy ( 0, nStreamIndex );
826 			aIter = m_aRecent.find ( sDirName );
827 			if ( aIter != m_aRecent.end() )
828 			{
829 				if ( bFolder )
830 				{
831 					sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex );
832 					sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 );
833 					if ( sTemp == ( *aIter ).second->getName() )
834 						return makeAny ( uno::Reference < XUnoTunnel > ( ( *aIter ).second ) );
835 					else
836 						m_aRecent.erase ( aIter );
837 				}
838 				else
839 				{
840 					sTemp = aName.copy ( nStreamIndex + 1 );
841 					if ( ( *aIter ).second->hasByName( sTemp ) )
842 						return ( *aIter ).second->getByName( sTemp );
843 					else
844 						m_aRecent.erase( aIter );
845 				}
846 			}
847 		}
848 		else
849 		{
850 			if ( m_pRootFolder->hasByName ( aName ) )
851 				return m_pRootFolder->getByName ( aName );
852 		}
853 		nOldIndex = 0;
854 		ZipPackageFolder * pCurrent = m_pRootFolder;
855 		ZipPackageFolder * pPrevious = NULL;
856 		while ( ( nIndex = aName.indexOf( '/', nOldIndex )) != -1 )
857 		{
858 			sTemp = aName.copy ( nOldIndex, nIndex - nOldIndex );
859 			if ( nIndex == nOldIndex )
860 				break;
861 			if ( pCurrent->hasByName( sTemp ) )
862 			{
863 				pPrevious = pCurrent;
864 				pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
865 			}
866 			else
867 				throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
868 			nOldIndex = nIndex+1;
869 		}
870 		if ( bFolder )
871 		{
872 			if ( nStreamIndex != -1 )
873 				m_aRecent[sDirName] = pPrevious;
874 			return makeAny ( uno::Reference < XUnoTunnel > ( pCurrent ) );
875 		}
876 		else
877 		{
878 			sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex );
879 			if ( pCurrent->hasByName ( sTemp ) )
880 			{
881 				if ( nStreamIndex != -1 )
882 					m_aRecent[sDirName] = pCurrent;
883 				return pCurrent->getByName( sTemp );
884 			}
885 			else
886 				throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
887 		}
888 	}
889 }
890 
891 //--------------------------------------------------------
hasByHierarchicalName(const OUString & aName)892 sal_Bool SAL_CALL ZipPackage::hasByHierarchicalName( const OUString& aName )
893 		throw( RuntimeException )
894 {
895 	OUString sTemp, sDirName;
896 	sal_Int32 nOldIndex, nIndex, nStreamIndex;
897 	FolderHash::iterator aIter;
898 
899 	if ( ( nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' )
900 		return sal_True;
901 	else
902 	{
903 		nStreamIndex = aName.lastIndexOf ( '/' );
904 		bool bFolder = nStreamIndex == nIndex-1;
905 		if ( nStreamIndex != -1 )
906 		{
907 			sDirName = aName.copy ( 0, nStreamIndex );
908 			aIter = m_aRecent.find ( sDirName );
909 			if ( aIter != m_aRecent.end() )
910 			{
911 				if ( bFolder )
912 				{
913 					sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex );
914 					sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 );
915 					if ( sTemp == ( *aIter ).second->getName() )
916 						return sal_True;
917 					else
918 						m_aRecent.erase ( aIter );
919 				}
920 				else
921 				{
922 					sTemp = aName.copy ( nStreamIndex + 1 );
923 					if ( ( *aIter ).second->hasByName( sTemp ) )
924 						return sal_True;
925 					else
926 						m_aRecent.erase( aIter );
927 				}
928 			}
929 		}
930 		else
931 		{
932 			if ( m_pRootFolder->hasByName ( aName ) )
933 				return sal_True;
934 		}
935 		ZipPackageFolder * pCurrent = m_pRootFolder;
936 		ZipPackageFolder * pPrevious = NULL;
937 		nOldIndex = 0;
938 		while ( ( nIndex = aName.indexOf( '/', nOldIndex )) != -1 )
939 		{
940 			sTemp = aName.copy ( nOldIndex, nIndex - nOldIndex );
941 			if ( nIndex == nOldIndex )
942 				break;
943 			if ( pCurrent->hasByName( sTemp ) )
944 			{
945 				pPrevious = pCurrent;
946 				pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
947 			}
948 			else
949 				return sal_False;
950 			nOldIndex = nIndex+1;
951 		}
952 		if ( bFolder )
953 		{
954 			m_aRecent[sDirName] = pPrevious;
955 			return sal_True;
956 		}
957 		else
958 		{
959 			sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex );
960 
961 			if ( pCurrent->hasByName( sTemp ) )
962 			{
963 				m_aRecent[sDirName] = pCurrent;
964 				return sal_True;
965 			}
966 		}
967 		return sal_False;
968 	}
969 }
970 
971 //--------------------------------------------------------
createInstance()972 uno::Reference< XInterface > SAL_CALL ZipPackage::createInstance()
973 		throw( Exception, RuntimeException )
974 {
975 	uno::Reference < XInterface > xRef = *( new ZipPackageStream ( *this, m_xFactory, m_bAllowRemoveOnInsert ) );
976 	return xRef;
977 }
978 //--------------------------------------------------------
createInstanceWithArguments(const uno::Sequence<Any> & aArguments)979 uno::Reference< XInterface > SAL_CALL ZipPackage::createInstanceWithArguments( const uno::Sequence< Any >& aArguments )
980 		throw( Exception, RuntimeException )
981 {
982 	sal_Bool bArg = sal_False;
983 	uno::Reference < XInterface > xRef;
984 	if ( aArguments.getLength() )
985 		aArguments[0] >>= bArg;
986 	if ( bArg )
987 		xRef = *new ZipPackageFolder ( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert );
988 	else
989 		xRef = *new ZipPackageStream ( *this, m_xFactory, m_bAllowRemoveOnInsert );
990 
991 	return xRef;
992 }
993 
994 //--------------------------------------------------------
WriteMimetypeMagicFile(ZipOutputStream & aZipOut)995 void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut )
996 {
997 	const OUString sMime ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) );
998 	if ( m_xRootFolder->hasByName( sMime ) )
999 		m_xRootFolder->removeByName( sMime );
1000 
1001 	ZipEntry * pEntry = new ZipEntry;
1002 	sal_Int32 nBufferLength = m_pRootFolder->GetMediaType().getLength();
1003 	OString sMediaType = OUStringToOString( m_pRootFolder->GetMediaType(), RTL_TEXTENCODING_ASCII_US );
1004 	uno::Sequence< sal_Int8 > aType( ( sal_Int8* )sMediaType.getStr(),
1005 								nBufferLength );
1006 
1007 
1008 	pEntry->sPath = sMime;
1009 	pEntry->nMethod = STORED;
1010 	pEntry->nSize = pEntry->nCompressedSize = nBufferLength;
1011 	pEntry->nTime = ZipOutputStream::getCurrentDosTime();
1012 
1013 	CRC32 aCRC32;
1014 	aCRC32.update( aType );
1015 	pEntry->nCrc = aCRC32.getValue();
1016 
1017 	try
1018 	{
1019 		aZipOut.putNextEntry( *pEntry, NULL );
1020 		aZipOut.write( aType, 0, nBufferLength );
1021 		aZipOut.closeEntry();
1022 	}
1023 	catch ( ::com::sun::star::io::IOException & r )
1024 	{
1025 		throw WrappedTargetException(
1026 				OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Error adding mimetype to the ZipOutputStream!" ) ),
1027 				static_cast < OWeakObject * > ( this ),
1028 				makeAny( r ) );
1029 	}
1030 }
1031 
1032 //--------------------------------------------------------
WriteManifest(ZipOutputStream & aZipOut,const vector<uno::Sequence<PropertyValue>> & aManList)1033 void ZipPackage::WriteManifest( ZipOutputStream& aZipOut, const vector< uno::Sequence < PropertyValue > >& aManList )
1034 {
1035     // Write the manifest
1036     uno::Reference < XOutputStream > xManOutStream;
1037     OUString sManifestWriter( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestWriter" ) );
1038     uno::Reference < XManifestWriter > xWriter ( m_xFactory->createInstance( sManifestWriter ), UNO_QUERY );
1039     if ( xWriter.is() )
1040     {
1041         ZipEntry * pEntry = new ZipEntry;
1042         ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize );
1043         xManOutStream = uno::Reference < XOutputStream > ( *pBuffer, UNO_QUERY );
1044 
1045         pEntry->sPath = OUString( RTL_CONSTASCII_USTRINGPARAM ( "META-INF/manifest.xml" ) );
1046         pEntry->nMethod = DEFLATED;
1047         pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1;
1048         pEntry->nTime = ZipOutputStream::getCurrentDosTime();
1049 
1050         // Convert vector into a uno::Sequence
1051         uno::Sequence < uno::Sequence < PropertyValue > > aManifestSequence ( aManList.size() );
1052         sal_Int32 nInd = 0;
1053         for ( vector < uno::Sequence < PropertyValue > >::const_iterator aIter = aManList.begin(), aEnd = aManList.end();
1054              aIter != aEnd;
1055              aIter++, nInd++ )
1056         {
1057             aManifestSequence[nInd] = ( *aIter );
1058         }
1059         xWriter->writeManifestSequence ( xManOutStream,  aManifestSequence );
1060 
1061         sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() );
1062         pBuffer->realloc( nBufferLength );
1063 
1064         // the manifest.xml is never encrypted - so pass an empty reference
1065         aZipOut.putNextEntry( *pEntry, NULL );
1066         aZipOut.write( pBuffer->getSequence(), 0, nBufferLength );
1067         aZipOut.closeEntry();
1068     }
1069     else
1070     {
1071         VOS_ENSURE ( 0, "Couldn't get a ManifestWriter!" );
1072         IOException aException;
1073         throw WrappedTargetException(
1074                 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Couldn't get a ManifestWriter!" ) ),
1075                 static_cast < OWeakObject * > ( this ),
1076                 makeAny( aException ) );
1077     }
1078 }
1079 
1080 //--------------------------------------------------------
WriteContentTypes(ZipOutputStream & aZipOut,const vector<uno::Sequence<PropertyValue>> & aManList)1081 void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno::Sequence < PropertyValue > >& aManList )
1082 {
1083     const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1084     const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1085 
1086     ZipEntry* pEntry = new ZipEntry;
1087     ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize );
1088     uno::Reference< io::XOutputStream > xConTypeOutStream( *pBuffer, UNO_QUERY );
1089 
1090     pEntry->sPath = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
1091     pEntry->nMethod = DEFLATED;
1092     pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1;
1093     pEntry->nTime = ZipOutputStream::getCurrentDosTime();
1094 
1095     // Convert vector into a uno::Sequence
1096     // TODO/LATER: use Defaulst entries in future
1097     uno::Sequence< beans::StringPair > aDefaultsSequence;
1098     uno::Sequence< beans::StringPair > aOverridesSequence( aManList.size() );
1099     sal_Int32 nSeqLength = 0;
1100     for ( vector< uno::Sequence< beans::PropertyValue > >::const_iterator aIter = aManList.begin(),
1101             aEnd = aManList.end();
1102          aIter != aEnd;
1103          aIter++ )
1104     {
1105         ::rtl::OUString aPath;
1106         ::rtl::OUString aType;
1107         OSL_ENSURE( ( *aIter )[PKG_MNFST_MEDIATYPE].Name.equals( sMediaType ) && ( *aIter )[PKG_MNFST_FULLPATH].Name.equals( sFullPath ),
1108                     "The mediatype sequence format is wrong!\n" );
1109         ( *aIter )[PKG_MNFST_MEDIATYPE].Value >>= aType;
1110         if ( aType.getLength() )
1111         {
1112             // only nonempty type makes sense here
1113             nSeqLength++;
1114             ( *aIter )[PKG_MNFST_FULLPATH].Value >>= aPath;
1115             aOverridesSequence[nSeqLength-1].First = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) + aPath;
1116             aOverridesSequence[nSeqLength-1].Second = aType;
1117         }
1118     }
1119     aOverridesSequence.realloc( nSeqLength );
1120 
1121     ::comphelper::OFOPXMLHelper::WriteContentSequence(
1122             xConTypeOutStream, aDefaultsSequence, aOverridesSequence, m_xFactory );
1123 
1124     sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() );
1125     pBuffer->realloc( nBufferLength );
1126 
1127     // there is no encryption in this format currently
1128     aZipOut.putNextEntry( *pEntry, NULL );
1129     aZipOut.write( pBuffer->getSequence(), 0, nBufferLength );
1130     aZipOut.closeEntry();
1131 }
1132 
1133 //--------------------------------------------------------
ConnectTo(const uno::Reference<io::XInputStream> & xInStream)1134 void ZipPackage::ConnectTo( const uno::Reference< io::XInputStream >& xInStream )
1135 {
1136     m_xContentSeek.set( xInStream, uno::UNO_QUERY_THROW );
1137     m_xContentStream = xInStream;
1138 
1139     // seek back to the beginning of the temp file so we can read segments from it
1140     m_xContentSeek->seek( 0 );
1141     if ( m_pZipFile )
1142         m_pZipFile->setInputStream( m_xContentStream );
1143     else
1144         m_pZipFile = new ZipFile ( m_xContentStream, m_xFactory, sal_False );
1145 }
1146 
1147 //--------------------------------------------------------
writeTempFile()1148 uno::Reference< io::XInputStream > ZipPackage::writeTempFile()
1149 {
1150     // In case the target local file does not exist or empty
1151     // write directly to it otherwize create a temporary file to write to.
1152     // If a temporary file is created it is returned back by the method.
1153     // If the data written directly, xComponentStream will be switched here
1154 
1155     sal_Bool bUseTemp = sal_True;
1156     uno::Reference < io::XInputStream > xResult;
1157     uno::Reference < io::XInputStream > xTempIn;
1158 
1159     uno::Reference < io::XOutputStream > xTempOut;
1160     uno::Reference< io::XActiveDataStreamer > xSink;
1161 
1162     if ( m_eMode == e_IMode_URL && !m_pZipFile && isLocalFile_Impl( m_aURL ) )
1163     {
1164         xSink = openOriginalForOutput();
1165         if( xSink.is() )
1166         {
1167             uno::Reference< io::XStream > xStr = xSink->getStream();
1168             if( xStr.is() )
1169             {
1170                 xTempOut = xStr->getOutputStream();
1171                 if( xTempOut.is() )
1172                     bUseTemp = sal_False;
1173             }
1174         }
1175     }
1176     else if ( m_eMode == e_IMode_XStream && !m_pZipFile )
1177     {
1178         // write directly to an empty stream
1179         xTempOut = m_xStream->getOutputStream();
1180         if( xTempOut.is() )
1181             bUseTemp = sal_False;
1182     }
1183 
1184     if( bUseTemp )
1185     {
1186         // create temporary file
1187         const OUString sServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) );
1188         uno::Reference < io::XStream > xTempFile( m_xFactory->createInstance ( sServiceName ), UNO_QUERY_THROW );
1189         xTempOut.set( xTempFile->getOutputStream(), UNO_SET_THROW );
1190         xTempIn.set( xTempFile->getInputStream(), UNO_SET_THROW );
1191     }
1192 
1193     // Hand it to the ZipOutputStream:
1194     ZipOutputStream aZipOut( m_xFactory, xTempOut );
1195     aZipOut.setMethod( DEFLATED );
1196     aZipOut.setLevel( DEFAULT_COMPRESSION );
1197 
1198     try
1199     {
1200         if ( m_nFormat == embed::StorageFormats::PACKAGE )
1201         {
1202             // Remove the old manifest.xml file as the
1203             // manifest will be re-generated and the
1204             // META-INF directory implicitly created if does not exist
1205             const OUString sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) );
1206 
1207             if ( m_xRootFolder->hasByName( sMeta ) )
1208             {
1209                 const OUString sManifest ( RTL_CONSTASCII_USTRINGPARAM( "manifest.xml" ) );
1210 
1211                 uno::Reference< XUnoTunnel > xTunnel;
1212                 Any aAny = m_xRootFolder->getByName( sMeta );
1213                 aAny >>= xTunnel;
1214                 uno::Reference< XNameContainer > xMetaInfFolder( xTunnel, UNO_QUERY );
1215                 if ( xMetaInfFolder.is() && xMetaInfFolder->hasByName( sManifest ) )
1216                     xMetaInfFolder->removeByName( sManifest );
1217             }
1218 
1219             // Write a magic file with mimetype
1220             WriteMimetypeMagicFile( aZipOut );
1221         }
1222         else if ( m_nFormat == embed::StorageFormats::OFOPXML )
1223         {
1224             // Remove the old [Content_Types].xml file as the
1225             // file will be re-generated
1226 
1227             const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
1228 
1229             if ( m_xRootFolder->hasByName( aContentTypes ) )
1230                 m_xRootFolder->removeByName( aContentTypes );
1231         }
1232 
1233         // Create a vector to store data for the manifest.xml file
1234         vector < uno::Sequence < PropertyValue > > aManList;
1235 
1236         const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1237         const OUString sVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) );
1238         const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1239 
1240         if ( m_nFormat == embed::StorageFormats::PACKAGE )
1241         {
1242             uno::Sequence < PropertyValue > aPropSeq( PKG_SIZE_NOENCR_MNFST );
1243             aPropSeq [PKG_MNFST_MEDIATYPE].Name = sMediaType;
1244             aPropSeq [PKG_MNFST_MEDIATYPE].Value <<= m_pRootFolder->GetMediaType();
1245             aPropSeq [PKG_MNFST_VERSION].Name = sVersion;
1246             aPropSeq [PKG_MNFST_VERSION].Value <<= m_pRootFolder->GetVersion();
1247             aPropSeq [PKG_MNFST_FULLPATH].Name = sFullPath;
1248             aPropSeq [PKG_MNFST_FULLPATH].Value <<= OUString ( RTL_CONSTASCII_USTRINGPARAM ( "/" ) );
1249 
1250             aManList.push_back( aPropSeq );
1251         }
1252 
1253         // Get a random number generator and seed it with current timestamp
1254         // This will be used to generate random salt and initialisation vectors
1255         // for encrypted streams
1256         TimeValue aTime;
1257         osl_getSystemTime( &aTime );
1258         rtlRandomPool aRandomPool = rtl_random_createPool ();
1259         rtl_random_addBytes ( aRandomPool, &aTime, 8 );
1260 
1261         // call saveContents ( it will recursively save sub-directories
1262         OUString aEmptyString;
1263         m_pRootFolder->saveContents( aEmptyString, aManList, aZipOut, GetEncryptionKey(), aRandomPool );
1264 
1265         // Clean up random pool memory
1266         rtl_random_destroyPool ( aRandomPool );
1267 
1268         if( m_nFormat == embed::StorageFormats::PACKAGE )
1269         {
1270             WriteManifest( aZipOut, aManList );
1271         }
1272         else if( m_nFormat == embed::StorageFormats::OFOPXML )
1273         {
1274             WriteContentTypes( aZipOut, aManList );
1275         }
1276 
1277         aZipOut.finish();
1278 
1279         if( bUseTemp )
1280             xResult = xTempIn;
1281 
1282         // Update our References to point to the new temp file
1283         if( !bUseTemp )
1284         {
1285             // the case when the original contents were written directly
1286             xTempOut->flush();
1287 
1288             // in case the stream is based on a file it will implement the following interface
1289             // the call should be used to be sure that the contents are written to the file system
1290             uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( xTempOut, uno::UNO_QUERY );
1291             if ( asyncOutputMonitor.is() )
1292                 asyncOutputMonitor->waitForCompletion();
1293 
1294             // no need to postpone switching to the new stream since the target was written directly
1295             uno::Reference< io::XInputStream > xNewStream;
1296             if ( m_eMode == e_IMode_URL )
1297                 xNewStream = xSink->getStream()->getInputStream();
1298             else if ( m_eMode == e_IMode_XStream && m_xStream.is() )
1299                 xNewStream = m_xStream->getInputStream();
1300 
1301             if ( xNewStream.is() )
1302                 ConnectTo( xNewStream );
1303         }
1304     }
1305     catch ( uno::Exception& )
1306     {
1307         if( bUseTemp )
1308         {
1309             // no information loss appeares, thus no special handling is required
1310                uno::Any aCaught( ::cppu::getCaughtException() );
1311 
1312             // it is allowed to throw WrappedTargetException
1313             WrappedTargetException aException;
1314             if ( aCaught >>= aException )
1315                 throw aException;
1316 
1317             throw WrappedTargetException(
1318                     OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Problem writing the original content!" ) ),
1319                     static_cast < OWeakObject * > ( this ),
1320                     aCaught );
1321         }
1322         else
1323         {
1324             // the document is written directly, although it was empty it is important to notify that the writing has failed
1325             // TODO/LATER: let the package be able to recover in this situation
1326             ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is unusable!" ) );
1327             embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), ::rtl::OUString() );
1328             throw WrappedTargetException( aErrTxt,
1329                                             static_cast < OWeakObject * > ( this ),
1330                                             makeAny ( aException ) );
1331         }
1332     }
1333 
1334     return xResult;
1335 }
1336 
1337 //--------------------------------------------------------
openOriginalForOutput()1338 uno::Reference< XActiveDataStreamer > ZipPackage::openOriginalForOutput()
1339 {
1340 	// open and truncate the original file
1341 	Content aOriginalContent ( m_aURL, uno::Reference < XCommandEnvironment >() );
1342 	uno::Reference< XActiveDataStreamer > xSink = new ActiveDataStreamer;
1343 
1344 	if ( m_eMode == e_IMode_URL )
1345 	{
1346 		try
1347 		{
1348 			sal_Bool bTruncSuccess = sal_False;
1349 
1350 			try
1351 			{
1352 				Exception aDetect;
1353 				sal_Int64 aSize = 0;
1354 				Any aAny = aOriginalContent.setPropertyValue( OUString::createFromAscii( "Size" ), makeAny( aSize ) );
1355 				if( !( aAny >>= aDetect ) )
1356 					bTruncSuccess = sal_True;
1357 			}
1358 			catch( Exception& )
1359 			{
1360 			}
1361 
1362 			if( !bTruncSuccess )
1363 			{
1364 				// the file is not accessible
1365 				// just try to write an empty stream to it
1366 
1367 				uno::Reference< XInputStream > xTempIn = new DummyInputStream; //uno::Reference< XInputStream >( xTempOut, UNO_QUERY );
1368 				aOriginalContent.writeStream( xTempIn , sal_True );
1369 			}
1370 
1371 			OpenCommandArgument2 aArg;
1372 	   		aArg.Mode		= OpenMode::DOCUMENT;
1373 	   		aArg.Priority	= 0; // unused
1374    			aArg.Sink       = xSink;
1375    			aArg.Properties = uno::Sequence< Property >( 0 ); // unused
1376 
1377 			aOriginalContent.executeCommand( OUString::createFromAscii( "open" ), makeAny( aArg ) );
1378 		}
1379 		catch( Exception& )
1380 		{
1381 			// seems to be nonlocal file
1382 			// temporary file mechanics should be used
1383 		}
1384 	}
1385 
1386 	return xSink;
1387 }
1388 
1389 //--------------------------------------------------------
commitChanges()1390 void SAL_CALL ZipPackage::commitChanges()
1391         throw( WrappedTargetException, RuntimeException )
1392 {
1393     // lock the component for the time of committing
1394     ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
1395 
1396     if ( m_eMode == e_IMode_XInputStream )
1397     {
1398         IOException aException;
1399         throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ),
1400                 static_cast < OWeakObject * > ( this ), makeAny ( aException ) );
1401     }
1402 
1403     RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::commitChanges" );
1404 
1405     // first the writeTempFile is called, if it returns a stream the stream should be written to the target
1406     // if no stream was returned, the file was written directly, nothing should be done
1407 
1408     uno::Reference< io::XInputStream > xTempInStream = writeTempFile();
1409     if ( xTempInStream.is() )
1410     {
1411         uno::Reference< io::XSeekable > xTempSeek( xTempInStream, uno::UNO_QUERY_THROW );
1412 
1413         try
1414         {
1415             xTempSeek->seek( 0 );
1416         }
1417         catch( uno::Exception& r )
1418         {
1419             throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Temporary file should be seekable!" ) ),
1420                     static_cast < OWeakObject * > ( this ), makeAny ( r ) );
1421         }
1422 
1423         // connect to the temporary stream
1424         ConnectTo( xTempInStream );
1425 
1426         if ( m_eMode == e_IMode_XStream )
1427         {
1428             // First truncate our output stream
1429             uno::Reference < XOutputStream > xOutputStream;
1430 
1431             // preparation for copy step
1432             try
1433             {
1434                 xOutputStream = m_xStream->getOutputStream();
1435                 uno::Reference < XTruncate > xTruncate ( xOutputStream, UNO_QUERY );
1436                 if ( !xTruncate.is() )
1437                     throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1438 
1439                 // after successful truncation the original file contents are already lost
1440                 xTruncate->truncate();
1441             }
1442             catch( uno::Exception& r )
1443             {
1444                 throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ),
1445                         static_cast < OWeakObject * > ( this ), makeAny ( r ) );
1446             }
1447 
1448             try
1449             {
1450                 // then copy the contents of the tempfile to our output stream
1451                 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, xOutputStream );
1452                 xOutputStream->flush();
1453                 uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor(
1454                     xOutputStream, uno::UNO_QUERY );
1455                 if ( asyncOutputMonitor.is() ) {
1456                     asyncOutputMonitor->waitForCompletion();
1457                 }
1458             }
1459             catch( uno::Exception& )
1460             {
1461                 // if anything goes wrong in this block the target file becomes corrupted
1462                 // so an exception should be thrown as a notification about it
1463                 // and the package must disconnect from the stream
1464                 DisconnectFromTargetAndThrowException_Impl( xTempInStream );
1465             }
1466         }
1467         else if ( m_eMode == e_IMode_URL )
1468         {
1469             uno::Reference< XOutputStream > aOrigFileStream;
1470             sal_Bool bCanBeCorrupted = sal_False;
1471 
1472             if( isLocalFile_Impl( m_aURL ) )
1473             {
1474                 // write directly in case of local file
1475                 uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess > xSimpleAccess(
1476                     m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ),
1477                     uno::UNO_QUERY );
1478                 OSL_ENSURE( xSimpleAccess.is(), "Can't instatiate SimpleFileAccess service!\n" );
1479                 uno::Reference< io::XTruncate > xOrigTruncate;
1480                 if ( xSimpleAccess.is() )
1481                 {
1482                     try
1483                     {
1484                         aOrigFileStream = xSimpleAccess->openFileWrite( m_aURL );
1485                         xOrigTruncate = uno::Reference< io::XTruncate >( aOrigFileStream, uno::UNO_QUERY_THROW );
1486                         // after successful truncation the file is already corrupted
1487                         xOrigTruncate->truncate();
1488                     }
1489                     catch( uno::Exception& )
1490                     {}
1491                 }
1492 
1493                 if( xOrigTruncate.is() )
1494                 {
1495                     try
1496                     {
1497                         ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, aOrigFileStream );
1498                         aOrigFileStream->closeOutput();
1499                     }
1500                     catch( uno::Exception& )
1501                     {
1502                         try {
1503                             aOrigFileStream->closeOutput();
1504                         } catch ( uno::Exception& ) {}
1505 
1506                         aOrigFileStream = uno::Reference< XOutputStream >();
1507                         // the original file can already be corrupted
1508                         bCanBeCorrupted = sal_True;
1509                     }
1510                 }
1511             }
1512 
1513             if( !aOrigFileStream.is() )
1514             {
1515                 try
1516                 {
1517                     uno::Reference < XPropertySet > xPropSet ( xTempInStream, UNO_QUERY );
1518                     OSL_ENSURE( xPropSet.is(), "This is a temporary file that must implement XPropertySet!\n" );
1519                     if ( !xPropSet.is() )
1520                         throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1521 
1522                     OUString sTargetFolder = m_aURL.copy ( 0, m_aURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) );
1523                     Content aContent ( sTargetFolder, uno::Reference < XCommandEnvironment > () );
1524 
1525                     OUString sTempURL;
1526                     Any aAny = xPropSet->getPropertyValue ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Uri" ) ) );
1527                     aAny >>= sTempURL;
1528 
1529                     TransferInfo aInfo;
1530                     aInfo.NameClash = NameClash::OVERWRITE;
1531                     aInfo.MoveData = sal_False;
1532                     aInfo.SourceURL = sTempURL;
1533                     aInfo.NewTitle = rtl::Uri::decode ( m_aURL.copy ( 1 + m_aURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) ),
1534                                                         rtl_UriDecodeWithCharset,
1535                                                         RTL_TEXTENCODING_UTF8 );
1536                     aAny <<= aInfo;
1537 
1538                     // if the file is still not corrupted, it can become after the next step
1539                     aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "transfer" ) ), aAny );
1540                 }
1541                 catch ( ::com::sun::star::uno::Exception& r )
1542                 {
1543                     if ( bCanBeCorrupted )
1544                         DisconnectFromTargetAndThrowException_Impl( xTempInStream );
1545 
1546                     throw WrappedTargetException(
1547                                                 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package may be read only!" ) ),
1548                                                 static_cast < OWeakObject * > ( this ),
1549                                                 makeAny ( r ) );
1550                 }
1551             }
1552         }
1553     }
1554 
1555     // after successful storing it can be set to false
1556     m_bMediaTypeFallbackUsed = sal_False;
1557 
1558     RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::commitChanges" );
1559 }
1560 
1561 //--------------------------------------------------------
DisconnectFromTargetAndThrowException_Impl(const uno::Reference<io::XInputStream> & xTempStream)1562 void ZipPackage::DisconnectFromTargetAndThrowException_Impl( const uno::Reference< io::XInputStream >& xTempStream )
1563 {
1564 	m_xStream = uno::Reference< io::XStream >( xTempStream, uno::UNO_QUERY );
1565 	if ( m_xStream.is() )
1566 		m_eMode = e_IMode_XStream;
1567 	else
1568 		m_eMode = e_IMode_XInputStream;
1569 
1570 	::rtl::OUString aTempURL;
1571 	try {
1572 		uno::Reference< beans::XPropertySet > xTempFile( xTempStream, uno::UNO_QUERY_THROW );
1573 		uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) );
1574 		aUrl >>= aTempURL;
1575 		xTempFile->setPropertyValue( ::rtl::OUString::createFromAscii( "RemoveFile" ),
1576 									 uno::makeAny( sal_False ) );
1577 	}
1578 	catch ( uno::Exception& )
1579 	{
1580 		OSL_ENSURE( sal_False, "These calls are pretty simple, they should not fail!\n" );
1581 	}
1582 
1583 	::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) );
1584 	embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), aTempURL );
1585 	throw WrappedTargetException( aErrTxt,
1586 									static_cast < OWeakObject * > ( this ),
1587 									makeAny ( aException ) );
1588 }
1589 
1590 //--------------------------------------------------------
GetEncryptionKey()1591 const uno::Sequence< sal_Int8 > ZipPackage::GetEncryptionKey()
1592 {
1593     uno::Sequence< sal_Int8 > aResult;
1594 
1595     if ( m_aStorageEncryptionKeys.getLength() )
1596     {
1597         ::rtl::OUString aNameToFind;
1598         if ( m_nStartKeyGenerationID == xml::crypto::DigestID::SHA256 )
1599             aNameToFind = PACKAGE_ENCRYPTIONDATA_SHA256UTF8;
1600         else if ( m_nStartKeyGenerationID == xml::crypto::DigestID::SHA1 )
1601             aNameToFind = PACKAGE_ENCRYPTIONDATA_SHA1UTF8;
1602         else
1603             throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No expected key is provided!" ) ), uno::Reference< uno::XInterface >() );
1604 
1605         for ( sal_Int32 nInd = 0; nInd < m_aStorageEncryptionKeys.getLength(); nInd++ )
1606             if ( m_aStorageEncryptionKeys[nInd].Name.equals( aNameToFind ) )
1607                 m_aStorageEncryptionKeys[nInd].Value >>= aResult;
1608 
1609         // empty keys are not allowed here
1610         // so it is not important whether there is no key, or the key is empty, it is an error
1611         if ( !aResult.getLength() )
1612             throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No expected key is provided!" ) ), uno::Reference< uno::XInterface >() );
1613     }
1614     else
1615         aResult = m_aEncryptionKey;
1616 
1617     return aResult;
1618 }
1619 
1620 //--------------------------------------------------------
hasPendingChanges()1621 sal_Bool SAL_CALL ZipPackage::hasPendingChanges()
1622 		throw( RuntimeException )
1623 {
1624 	return sal_False;
1625 }
1626 //--------------------------------------------------------
getPendingChanges()1627 Sequence< ElementChange > SAL_CALL ZipPackage::getPendingChanges()
1628 		throw( RuntimeException )
1629 {
1630 	return uno::Sequence < ElementChange > ();
1631 }
1632 
1633 /**
1634  * Function to create a new component instance; is needed by factory helper implementation.
1635  * @param xMgr service manager to if the components needs other component instances
1636  */
ZipPackage_createInstance(const uno::Reference<XMultiServiceFactory> & xMgr)1637 uno::Reference < XInterface >SAL_CALL ZipPackage_createInstance(
1638 	const uno::Reference< XMultiServiceFactory > & xMgr )
1639 {
1640 	return uno::Reference< XInterface >( *new ZipPackage( xMgr ) );
1641 }
1642 
1643 //--------------------------------------------------------
static_getImplementationName()1644 OUString ZipPackage::static_getImplementationName()
1645 {
1646 	return OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.comp.ZipPackage" ) );
1647 }
1648 
1649 //--------------------------------------------------------
static_getSupportedServiceNames()1650 Sequence< OUString > ZipPackage::static_getSupportedServiceNames()
1651 {
1652 	uno::Sequence< OUString > aNames( 1 );
1653 	aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.Package" ) );
1654 	return aNames;
1655 }
1656 //--------------------------------------------------------
static_supportsService(OUString const & rServiceName)1657 sal_Bool SAL_CALL ZipPackage::static_supportsService( OUString const & rServiceName )
1658 {
1659 	return rServiceName == getSupportedServiceNames()[0];
1660 }
1661 
1662 //--------------------------------------------------------
getImplementationName()1663 OUString ZipPackage::getImplementationName()
1664 	throw ( RuntimeException )
1665 {
1666 	return static_getImplementationName();
1667 }
1668 
1669 //--------------------------------------------------------
getSupportedServiceNames()1670 Sequence< OUString > ZipPackage::getSupportedServiceNames()
1671 	throw ( RuntimeException )
1672 {
1673 	return static_getSupportedServiceNames();
1674 }
1675 //--------------------------------------------------------
supportsService(OUString const & rServiceName)1676 sal_Bool SAL_CALL ZipPackage::supportsService( OUString const & rServiceName )
1677 	throw ( RuntimeException )
1678 {
1679 	return static_supportsService ( rServiceName );
1680 }
1681 //--------------------------------------------------------
createServiceFactory(uno::Reference<XMultiServiceFactory> const & rServiceFactory)1682 uno::Reference < XSingleServiceFactory > ZipPackage::createServiceFactory( uno::Reference < XMultiServiceFactory > const & rServiceFactory )
1683 {
1684 	return cppu::createSingleFactory ( rServiceFactory,
1685 										   static_getImplementationName(),
1686 										   ZipPackage_createInstance,
1687 										   static_getSupportedServiceNames() );
1688 }
1689 
1690 namespace { struct lcl_ImplId : public rtl::Static< ::cppu::OImplementationId, lcl_ImplId > {}; }
1691 
1692 //--------------------------------------------------------
getUnoTunnelImplementationId(void)1693 Sequence< sal_Int8 > ZipPackage::getUnoTunnelImplementationId( void )
1694 	throw ( RuntimeException )
1695 {
1696     ::cppu::OImplementationId &rId = lcl_ImplId::get();
1697     return rId.getImplementationId();
1698 }
1699 
1700 //--------------------------------------------------------
getSomething(const uno::Sequence<sal_Int8> & aIdentifier)1701 sal_Int64 SAL_CALL ZipPackage::getSomething( const uno::Sequence< sal_Int8 >& aIdentifier )
1702 	throw( RuntimeException )
1703 {
1704 	if ( aIdentifier.getLength() == 16 && 0 == rtl_compareMemory( getUnoTunnelImplementationId().getConstArray(),  aIdentifier.getConstArray(), 16 ) )
1705 		return reinterpret_cast < sal_Int64 > ( this );
1706 	return 0;
1707 }
1708 
1709 //--------------------------------------------------------
getPropertySetInfo()1710 uno::Reference< XPropertySetInfo > SAL_CALL ZipPackage::getPropertySetInfo()
1711 		throw( RuntimeException )
1712 {
1713 	return uno::Reference < XPropertySetInfo > ();
1714 }
1715 
1716 //--------------------------------------------------------
setPropertyValue(const OUString & aPropertyName,const Any & aValue)1717 void SAL_CALL ZipPackage::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
1718 		throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException )
1719 {
1720 	if ( m_nFormat != embed::StorageFormats::PACKAGE )
1721 		throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1722 
1723 	if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( HAS_ENCRYPTED_ENTRIES_PROPERTY ) )
1724 	  ||aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( HAS_NONENCRYPTED_ENTRIES_PROPERTY ) )
1725 	  ||aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( IS_INCONSISTENT_PROPERTY ) )
1726 	  ||aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( MEDIATYPE_FALLBACK_USED_PROPERTY ) ) )
1727 		throw PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1728 	else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_KEY_PROPERTY ) ) )
1729 	{
1730 		if ( !( aValue >>= m_aEncryptionKey ) )
1731 			throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 );
1732 
1733         m_aStorageEncryptionKeys.realloc( 0 );
1734 	}
1735 	else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( STORAGE_ENCRYPTION_KEYS_PROPERTY ) ) )
1736 	{
1737         // this property is only necessary to support raw passwords in storage API;
1738         // because of this support the storage has to operate with more than one key dependent on storage generation algorithm;
1739         // when this support is removed, the storage will get only one key from outside
1740         // TODO/LATER: Get rid of this property as well as of support of raw passwords in storages
1741         uno::Sequence< beans::NamedValue > aKeys;
1742 		if ( !( aValue >>= aKeys ) || ( aKeys.getLength() && aKeys.getLength() < 2 ) )
1743 			throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 );
1744 
1745         if ( aKeys.getLength() )
1746         {
1747             bool bHasSHA256 = false;
1748             bool bHasSHA1 = false;
1749             for ( sal_Int32 nInd = 0; nInd < aKeys.getLength(); nInd++ )
1750             {
1751                 if ( aKeys[nInd].Name.equals( PACKAGE_ENCRYPTIONDATA_SHA256UTF8 ) )
1752                     bHasSHA256 = true;
1753                 if ( aKeys[nInd].Name.equals( PACKAGE_ENCRYPTIONDATA_SHA1UTF8 ) )
1754                     bHasSHA1 = true;
1755             }
1756 
1757             if ( !bHasSHA256 || !bHasSHA1 )
1758                 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Expected keys are not provided!" ) ), uno::Reference< uno::XInterface >(), 2 );
1759         }
1760 
1761         m_aStorageEncryptionKeys = aKeys;
1762         m_aEncryptionKey.realloc( 0 );
1763 	}
1764 	else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_ALGORITHMS_PROPERTY ) ) )
1765 	{
1766         uno::Sequence< beans::NamedValue > aAlgorithms;
1767 		if ( m_pZipFile || !( aValue >>= aAlgorithms ) || aAlgorithms.getLength() == 0 )
1768         {
1769             // the algorithms can not be changed if the file has a persistence based on the algorithms ( m_pZipFile )
1770 			throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "unexpected algorithms list is provided." ) ), uno::Reference< uno::XInterface >(), 2 );
1771         }
1772 
1773         for ( sal_Int32 nInd = 0; nInd < aAlgorithms.getLength(); nInd++ )
1774         {
1775             if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "StartKeyGenerationAlgorithm" ) ) )
1776             {
1777                 sal_Int32 nID = 0;
1778                 if ( !( aAlgorithms[nInd].Value >>= nID )
1779                   || ( nID != xml::crypto::DigestID::SHA256 && nID != xml::crypto::DigestID::SHA1 ) )
1780                     throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected start key generation algorithm is provided!" ) ), uno::Reference< uno::XInterface >(), 2 );
1781 
1782                 m_nStartKeyGenerationID = nID;
1783             }
1784             else if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "EncryptionAlgorithm" ) ) )
1785             {
1786                 sal_Int32 nID = 0;
1787                 if ( !( aAlgorithms[nInd].Value >>= nID )
1788                   || ( nID != xml::crypto::CipherID::AES_CBC_W3C_PADDING && nID != xml::crypto::CipherID::BLOWFISH_CFB_8 ) )
1789                     throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected start key generation algorithm is provided!" ) ), uno::Reference< uno::XInterface >(), 2 );
1790 
1791                 m_nCommonEncryptionID = nID;
1792             }
1793             else if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ChecksumAlgorithm" ) ) )
1794             {
1795                 sal_Int32 nID = 0;
1796                 if ( !( aAlgorithms[nInd].Value >>= nID )
1797                   || ( nID != xml::crypto::DigestID::SHA1_1K && nID != xml::crypto::DigestID::SHA256_1K ) )
1798                     throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected start key generation algorithm is provided!" ) ), uno::Reference< uno::XInterface >(), 2 );
1799 
1800                 m_nChecksumDigestID = nID;
1801             }
1802             else
1803             {
1804                 OSL_ENSURE( sal_False, "Unexpected encryption algorithm is provided!" );
1805                 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "unexpected algorithms list is provided." ) ), uno::Reference< uno::XInterface >(), 2 );
1806             }
1807         }
1808 	}
1809 	else
1810 		throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1811 }
1812 
1813 //--------------------------------------------------------
getPropertyValue(const OUString & PropertyName)1814 Any SAL_CALL ZipPackage::getPropertyValue( const OUString& PropertyName )
1815 		throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1816 {
1817 	// TODO/LATER: Activate the check when zip-ucp is ready
1818 	// if ( m_nFormat != embed::StorageFormats::PACKAGE )
1819 	//	throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1820 
1821 	Any aAny;
1822 	if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( ENCRYPTION_KEY_PROPERTY ) ) )
1823 	{
1824 		aAny <<= m_aEncryptionKey;
1825 		return aAny;
1826 	}
1827 	else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_ALGORITHMS_PROPERTY ) ) )
1828 	{
1829         ::comphelper::SequenceAsHashMap aAlgorithms;
1830         aAlgorithms[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StartKeyGenerationAlgorithm" ) ) ] <<= m_nStartKeyGenerationID;
1831         aAlgorithms[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EncryptionAlgorithm" ) ) ] <<= m_nCommonEncryptionID;
1832         aAlgorithms[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ChecksumAlgorithm" ) ) ] <<= m_nChecksumDigestID;
1833         aAny <<= aAlgorithms.getAsConstNamedValueList();
1834         return aAny;
1835     }
1836 	if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( STORAGE_ENCRYPTION_KEYS_PROPERTY ) ) )
1837 	{
1838 		aAny <<= m_aStorageEncryptionKeys;
1839 		return aAny;
1840 	}
1841 	else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( HAS_ENCRYPTED_ENTRIES_PROPERTY ) ) )
1842 	{
1843 		aAny <<= m_bHasEncryptedEntries;
1844 		return aAny;
1845 	}
1846 	else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( HAS_NONENCRYPTED_ENTRIES_PROPERTY ) ) )
1847 	{
1848 		aAny <<= m_bHasNonEncryptedEntries;
1849 		return aAny;
1850 	}
1851 	else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( IS_INCONSISTENT_PROPERTY ) ) )
1852 	{
1853 		aAny <<= m_bInconsistent;
1854 		return aAny;
1855 	}
1856 	else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( MEDIATYPE_FALLBACK_USED_PROPERTY ) ) )
1857 	{
1858 		aAny <<= m_bMediaTypeFallbackUsed;
1859 		return aAny;
1860 	}
1861 	throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1862 }
1863 //--------------------------------------------------------
addPropertyChangeListener(const OUString &,const uno::Reference<XPropertyChangeListener> &)1864 void SAL_CALL ZipPackage::addPropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ )
1865 		throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1866 {
1867 }
1868 //--------------------------------------------------------
removePropertyChangeListener(const OUString &,const uno::Reference<XPropertyChangeListener> &)1869 void SAL_CALL ZipPackage::removePropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*aListener*/ )
1870 		throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1871 {
1872 }
1873 //--------------------------------------------------------
addVetoableChangeListener(const OUString &,const uno::Reference<XVetoableChangeListener> &)1874 void SAL_CALL ZipPackage::addVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ )
1875 		throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1876 {
1877 }
1878 //--------------------------------------------------------
removeVetoableChangeListener(const OUString &,const uno::Reference<XVetoableChangeListener> &)1879 void SAL_CALL ZipPackage::removeVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ )
1880 		throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1881 {
1882 }
1883