xref: /AOO41X/main/package/source/zippackage/ZipPackage.cxx (revision f8d3702f22fb9b9ebad4f0e66f8e214aadb1c7d1)
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 dieing 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 successfuly 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     sal_Bool mustHaveEncryption = sal_False;
540 
541     while ( pEnum->hasMoreElements() )
542     {
543         nIndex = nOldIndex = 0;
544         pCurrent = m_pRootFolder;
545         const ZipEntry & rEntry = *pEnum->nextElement();
546         OUString rName = rEntry.sPath;
547 
548         if ( m_bForceRecovery )
549         {
550             // the PKZIP Application note version 6.2 does not allows to use '\' as separator
551             // unfortunately it is used by some implementations, so we have to support it in recovery mode
552             rName = rName.replace( '\\', '/' );
553         }
554 
555         nStreamIndex = rName.lastIndexOf ( '/' );
556         if ( nStreamIndex != -1 )
557         {
558             sDirName = rName.copy ( 0, nStreamIndex );
559             aIter = m_aRecent.find ( sDirName );
560             if ( aIter != m_aRecent.end() )
561                 pCurrent = ( *aIter ).second;
562         }
563 
564         if ( pCurrent == m_pRootFolder )
565         {
566             while ( ( nIndex = rName.indexOf( '/', nOldIndex ) ) != -1 )
567             {
568                 sTemp = rName.copy ( nOldIndex, nIndex - nOldIndex );
569                 if ( nIndex == nOldIndex )
570                     break;
571                 if ( !pCurrent->hasByName( sTemp ) )
572                 {
573                     pPkgFolder = new ZipPackageFolder( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert );
574                     pPkgFolder->setName( sTemp );
575                     pPkgFolder->doSetParent( pCurrent, sal_True );
576                     pCurrent = pPkgFolder;
577                 }
578                 else
579                     pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
580                 nOldIndex = nIndex+1;
581             }
582             if ( nStreamIndex != -1 && sDirName.getLength() )
583                 m_aRecent [ sDirName ] = pCurrent;
584         }
585         if ( rName.getLength() -1 != nStreamIndex )
586         {
587             nStreamIndex++;
588             sTemp = rName.copy( nStreamIndex, rName.getLength() - nStreamIndex );
589             pPkgStream = new ZipPackageStream( *this, m_xFactory, m_bAllowRemoveOnInsert );
590             pPkgStream->SetPackageMember( sal_True );
591             pPkgStream->setZipEntryOnLoading( rEntry );
592             pPkgStream->setName( sTemp );
593             pPkgStream->doSetParent( pCurrent, sal_True );
594         }
595         if ( ( rEntry.nMethod == STORED ) && rEntry.bHasDataDescriptor )
596             mustHaveEncryption = sal_True;
597     }
598 
599     if ( m_nFormat == embed::StorageFormats::PACKAGE )
600         parseManifest();
601     else if ( m_nFormat == embed::StorageFormats::OFOPXML )
602         parseContentType();
603     if ( mustHaveEncryption && !m_bHasEncryptedEntries )
604         throw ZipException( OUString( RTL_CONSTASCII_USTRINGPARAM ( "inconsistent ZIP entries" ) ), uno::Reference < XInterface > () );
605 }
606 
607 //--------------------------------------------------------
initialize(const uno::Sequence<Any> & aArguments)608 void SAL_CALL ZipPackage::initialize( const uno::Sequence< Any >& aArguments )
609         throw( Exception, RuntimeException )
610 {
611     RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::initialize" );
612     sal_Bool bBadZipFile = sal_False, bHaveZipFile = sal_True;
613     uno::Reference< XProgressHandler > xProgressHandler;
614     beans::NamedValue aNamedValue;
615 
616     if ( aArguments.getLength() )
617     {
618         for( int ind = 0; ind < aArguments.getLength(); ind++ )
619         {
620             OUString aParamUrl;
621             if ( ( aArguments[ind] >>= aParamUrl ))
622             {
623                 m_eMode = e_IMode_URL;
624                 try
625                 {
626                     sal_Int32 nParam = aParamUrl.indexOf( '?' );
627                     if ( nParam >= 0 )
628                     {
629                         m_aURL = aParamUrl.copy( 0, nParam );
630                         OUString aParam = aParamUrl.copy( nParam + 1 );
631 
632                         sal_Int32 nIndex = 0;
633                         do
634                         {
635                             ::rtl::OUString aCommand = aParam.getToken( 0, '&', nIndex );
636                             if ( aCommand.equals( OUString::createFromAscii( "repairpackage" ) ) )
637                             {
638                                 m_bForceRecovery = sal_True;
639                                 break;
640                             }
641                             else if ( aCommand.equals( OUString::createFromAscii( "purezip" ) ) )
642                             {
643                                 m_nFormat = embed::StorageFormats::ZIP;
644                                 m_pRootFolder->setPackageFormat_Impl( m_nFormat );
645                                 break;
646                             }
647                             else if ( aCommand.equals( OUString::createFromAscii( "ofopxml" ) ) )
648                             {
649                                 m_nFormat = embed::StorageFormats::OFOPXML;
650                                 m_pRootFolder->setPackageFormat_Impl( m_nFormat );
651                                 break;
652                             }
653                         }
654                         while ( nIndex >= 0 );
655                     }
656                     else
657                         m_aURL = aParamUrl;
658 
659                     Content aContent ( m_aURL, uno::Reference < XCommandEnvironment >() );
660                     Any aAny = aContent.getPropertyValue( OUString::createFromAscii( "Size" ) );
661                     sal_uInt64 aSize = 0;
662                     // kind of optimisation: treat empty files as nonexistent files
663                     // and write to such files directly. Note that "Size" property is optional.
664                     bool bHasSizeProperty = aAny >>= aSize;
665                     if( !bHasSizeProperty || ( bHasSizeProperty && aSize ) )
666                     {
667                         uno::Reference < XActiveDataSink > xSink = new ZipPackageSink;
668                         if ( aContent.openStream ( xSink ) )
669                             m_xContentStream = xSink->getInputStream();
670                     }
671                     else
672                         bHaveZipFile = sal_False;
673                 }
674                 catch ( com::sun::star::uno::Exception& )
675                 {
676                     // Exception derived from uno::Exception thrown. This probably
677                     // means the file doesn't exist...we'll create it at
678                     // commitChanges time
679                     bHaveZipFile = sal_False;
680                 }
681             }
682             else if ( ( aArguments[ind] >>= m_xStream ) )
683             {
684                 // a writable stream can implement both XStream & XInputStream
685                 m_eMode = e_IMode_XStream;
686                 m_xContentStream = m_xStream->getInputStream();
687             }
688             else if ( ( aArguments[ind] >>= m_xContentStream ) )
689             {
690                 m_eMode = e_IMode_XInputStream;
691             }
692             else if ( ( aArguments[ind] >>= aNamedValue ) )
693             {
694                 if ( aNamedValue.Name.equalsAscii( "RepairPackage" ) )
695                     aNamedValue.Value >>= m_bForceRecovery;
696                 else if ( aNamedValue.Name.equalsAscii( "PackageFormat" ) )
697                 {
698                     // setting this argument to true means Package format
699                     // setting it to false means plain Zip format
700 
701                     sal_Bool bPackFormat = sal_True;
702                     aNamedValue.Value >>= bPackFormat;
703                     if ( !bPackFormat )
704                         m_nFormat = embed::StorageFormats::ZIP;
705 
706                     m_pRootFolder->setPackageFormat_Impl( m_nFormat );
707                 }
708                 else if ( aNamedValue.Name.equalsAscii( "StorageFormat" ) )
709                 {
710                     ::rtl::OUString aFormatName;
711                     sal_Int32 nFormatID = 0;
712                     if ( aNamedValue.Value >>= aFormatName )
713                     {
714                         if ( aFormatName.equals( PACKAGE_STORAGE_FORMAT_STRING ) )
715                             m_nFormat = embed::StorageFormats::PACKAGE;
716                         else if ( aFormatName.equals( ZIP_STORAGE_FORMAT_STRING ) )
717                             m_nFormat = embed::StorageFormats::ZIP;
718                         else if ( aFormatName.equals( OFOPXML_STORAGE_FORMAT_STRING ) )
719                             m_nFormat = embed::StorageFormats::OFOPXML;
720                         else
721                             throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
722                     }
723                     else if ( aNamedValue.Value >>= nFormatID )
724                     {
725                         if ( nFormatID != embed::StorageFormats::PACKAGE
726                           && nFormatID != embed::StorageFormats::ZIP
727                           && nFormatID != embed::StorageFormats::OFOPXML )
728                             throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
729 
730                         m_nFormat = nFormatID;
731                     }
732                     else
733                         throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 );
734 
735                     m_pRootFolder->setPackageFormat_Impl( m_nFormat );
736                 }
737                 else if ( aNamedValue.Name.equalsAscii( "AllowRemoveOnInsert" ) )
738                 {
739                     aNamedValue.Value >>= m_bAllowRemoveOnInsert;
740                     m_pRootFolder->setRemoveOnInsertMode_Impl( m_bAllowRemoveOnInsert );
741                 }
742 
743                 // for now the progress handler is not used, probably it will never be
744                 // if ( aNamedValue.Name.equalsAscii( "ProgressHandler" )
745             }
746             else
747             {
748                 // The URL is not acceptable
749                 throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad arguments." ) ),
750                     static_cast < ::cppu::OWeakObject * > ( this ) );
751             }
752         }
753 
754         try
755         {
756             if ( m_xContentStream.is() )
757             {
758                 // the stream must be seekable, if it is not it will be wrapped
759                 m_xContentStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( m_xContentStream, m_xFactory );
760                 m_xContentSeek = uno::Reference < XSeekable > ( m_xContentStream, UNO_QUERY );
761                 if ( ! m_xContentSeek.is() )
762                     throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "The package component _requires_ an XSeekable interface!" ) ),
763                             static_cast < ::cppu::OWeakObject * > ( this ) );
764 
765                 if ( !m_xContentSeek->getLength() )
766                     bHaveZipFile = sal_False;
767             }
768             else
769                 bHaveZipFile = sal_False;
770         }
771         catch ( com::sun::star::uno::Exception& )
772         {
773             // Exception derived from uno::Exception thrown. This probably
774             // means the file doesn't exist...we'll create it at
775             // commitChanges time
776             bHaveZipFile = sal_False;
777         }
778         if ( bHaveZipFile )
779         {
780             try
781             {
782                 m_pZipFile = new ZipFile ( m_xContentStream, m_xFactory, sal_True, m_bForceRecovery, xProgressHandler );
783                 getZipFileContents();
784             }
785             catch ( IOException & )
786             {
787                 bBadZipFile = sal_True;
788             }
789             catch ( ZipException & )
790             {
791                 bBadZipFile = sal_True;
792             }
793             catch ( Exception & )
794             {
795                 if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; }
796                 throw;
797             }
798 
799             if ( bBadZipFile )
800             {
801                 // clean up the memory, and tell the UCB about the error
802                 if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; }
803 
804                 throw com::sun::star::packages::zip::ZipIOException (
805                     OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad Zip File." ) ),
806                     static_cast < ::cppu::OWeakObject * > ( this ) );
807             }
808         }
809     }
810 
811     RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::initialize" );
812 }
813 
814 //--------------------------------------------------------
getByHierarchicalName(const OUString & aName)815 Any SAL_CALL ZipPackage::getByHierarchicalName( const OUString& aName )
816         throw( NoSuchElementException, RuntimeException )
817 {
818     OUString sTemp, sDirName;
819     sal_Int32 nOldIndex, nIndex, nStreamIndex;
820     FolderHash::iterator aIter;
821 
822     if ( ( nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' )
823         return makeAny ( uno::Reference < XUnoTunnel > ( m_pRootFolder ) );
824     else
825     {
826         nStreamIndex = aName.lastIndexOf ( '/' );
827         bool bFolder = nStreamIndex == nIndex-1;
828         if ( nStreamIndex != -1 )
829         {
830             sDirName = aName.copy ( 0, nStreamIndex );
831             aIter = m_aRecent.find ( sDirName );
832             if ( aIter != m_aRecent.end() )
833             {
834                 if ( bFolder )
835                 {
836                     sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex );
837                     sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 );
838                     if ( sTemp == ( *aIter ).second->getName() )
839                         return makeAny ( uno::Reference < XUnoTunnel > ( ( *aIter ).second ) );
840                     else
841                         m_aRecent.erase ( aIter );
842                 }
843                 else
844                 {
845                     sTemp = aName.copy ( nStreamIndex + 1 );
846                     if ( ( *aIter ).second->hasByName( sTemp ) )
847                         return ( *aIter ).second->getByName( sTemp );
848                     else
849                         m_aRecent.erase( aIter );
850                 }
851             }
852         }
853         else
854         {
855             if ( m_pRootFolder->hasByName ( aName ) )
856                 return m_pRootFolder->getByName ( aName );
857         }
858         nOldIndex = 0;
859         ZipPackageFolder * pCurrent = m_pRootFolder;
860         ZipPackageFolder * pPrevious = NULL;
861         while ( ( nIndex = aName.indexOf( '/', nOldIndex )) != -1 )
862         {
863             sTemp = aName.copy ( nOldIndex, nIndex - nOldIndex );
864             if ( nIndex == nOldIndex )
865                 break;
866             if ( pCurrent->hasByName( sTemp ) )
867             {
868                 pPrevious = pCurrent;
869                 pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
870             }
871             else
872                 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
873             nOldIndex = nIndex+1;
874         }
875         if ( bFolder )
876         {
877             if ( nStreamIndex != -1 )
878                 m_aRecent[sDirName] = pPrevious;
879             return makeAny ( uno::Reference < XUnoTunnel > ( pCurrent ) );
880         }
881         else
882         {
883             sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex );
884             if ( pCurrent->hasByName ( sTemp ) )
885             {
886                 if ( nStreamIndex != -1 )
887                     m_aRecent[sDirName] = pCurrent;
888                 return pCurrent->getByName( sTemp );
889             }
890             else
891                 throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
892         }
893     }
894 }
895 
896 //--------------------------------------------------------
hasByHierarchicalName(const OUString & aName)897 sal_Bool SAL_CALL ZipPackage::hasByHierarchicalName( const OUString& aName )
898         throw( RuntimeException )
899 {
900     OUString sTemp, sDirName;
901     sal_Int32 nOldIndex, nIndex, nStreamIndex;
902     FolderHash::iterator aIter;
903 
904     if ( ( nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' )
905         return sal_True;
906     else
907     {
908         nStreamIndex = aName.lastIndexOf ( '/' );
909         bool bFolder = nStreamIndex == nIndex-1;
910         if ( nStreamIndex != -1 )
911         {
912             sDirName = aName.copy ( 0, nStreamIndex );
913             aIter = m_aRecent.find ( sDirName );
914             if ( aIter != m_aRecent.end() )
915             {
916                 if ( bFolder )
917                 {
918                     sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex );
919                     sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 );
920                     if ( sTemp == ( *aIter ).second->getName() )
921                         return sal_True;
922                     else
923                         m_aRecent.erase ( aIter );
924                 }
925                 else
926                 {
927                     sTemp = aName.copy ( nStreamIndex + 1 );
928                     if ( ( *aIter ).second->hasByName( sTemp ) )
929                         return sal_True;
930                     else
931                         m_aRecent.erase( aIter );
932                 }
933             }
934         }
935         else
936         {
937             if ( m_pRootFolder->hasByName ( aName ) )
938                 return sal_True;
939         }
940         ZipPackageFolder * pCurrent = m_pRootFolder;
941         ZipPackageFolder * pPrevious = NULL;
942         nOldIndex = 0;
943         while ( ( nIndex = aName.indexOf( '/', nOldIndex )) != -1 )
944         {
945             sTemp = aName.copy ( nOldIndex, nIndex - nOldIndex );
946             if ( nIndex == nOldIndex )
947                 break;
948             if ( pCurrent->hasByName( sTemp ) )
949             {
950                 pPrevious = pCurrent;
951                 pCurrent = pCurrent->doGetByName( sTemp ).pFolder;
952             }
953             else
954                 return sal_False;
955             nOldIndex = nIndex+1;
956         }
957         if ( bFolder )
958         {
959             m_aRecent[sDirName] = pPrevious;
960             return sal_True;
961         }
962         else
963         {
964             sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex );
965 
966             if ( pCurrent->hasByName( sTemp ) )
967             {
968                 m_aRecent[sDirName] = pCurrent;
969                 return sal_True;
970             }
971         }
972         return sal_False;
973     }
974 }
975 
976 //--------------------------------------------------------
createInstance()977 uno::Reference< XInterface > SAL_CALL ZipPackage::createInstance()
978         throw( Exception, RuntimeException )
979 {
980     uno::Reference < XInterface > xRef = *( new ZipPackageStream ( *this, m_xFactory, m_bAllowRemoveOnInsert ) );
981     return xRef;
982 }
983 //--------------------------------------------------------
createInstanceWithArguments(const uno::Sequence<Any> & aArguments)984 uno::Reference< XInterface > SAL_CALL ZipPackage::createInstanceWithArguments( const uno::Sequence< Any >& aArguments )
985         throw( Exception, RuntimeException )
986 {
987     sal_Bool bArg = sal_False;
988     uno::Reference < XInterface > xRef;
989     if ( aArguments.getLength() )
990         aArguments[0] >>= bArg;
991     if ( bArg )
992         xRef = *new ZipPackageFolder ( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert );
993     else
994         xRef = *new ZipPackageStream ( *this, m_xFactory, m_bAllowRemoveOnInsert );
995 
996     return xRef;
997 }
998 
999 //--------------------------------------------------------
WriteMimetypeMagicFile(ZipOutputStream & aZipOut)1000 void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut )
1001 {
1002     const OUString sMime ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) );
1003     if ( m_xRootFolder->hasByName( sMime ) )
1004         m_xRootFolder->removeByName( sMime );
1005 
1006     ZipEntry * pEntry = new ZipEntry;
1007     sal_Int32 nBufferLength = m_pRootFolder->GetMediaType().getLength();
1008     OString sMediaType = OUStringToOString( m_pRootFolder->GetMediaType(), RTL_TEXTENCODING_ASCII_US );
1009     uno::Sequence< sal_Int8 > aType( ( sal_Int8* )sMediaType.getStr(),
1010                                 nBufferLength );
1011 
1012 
1013     pEntry->sPath = sMime;
1014     pEntry->nMethod = STORED;
1015     pEntry->nSize = pEntry->nCompressedSize = nBufferLength;
1016     pEntry->nTime = ZipOutputStream::getCurrentDosTime();
1017 
1018     CRC32 aCRC32;
1019     aCRC32.update( aType );
1020     pEntry->nCrc = aCRC32.getValue();
1021 
1022     try
1023     {
1024         aZipOut.putNextEntry( *pEntry, NULL );
1025         aZipOut.write( aType, 0, nBufferLength );
1026         aZipOut.closeEntry();
1027     }
1028     catch ( ::com::sun::star::io::IOException & r )
1029     {
1030         throw WrappedTargetException(
1031                 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Error adding mimetype to the ZipOutputStream!" ) ),
1032                 static_cast < OWeakObject * > ( this ),
1033                 makeAny( r ) );
1034     }
1035 }
1036 
1037 //--------------------------------------------------------
WriteManifest(ZipOutputStream & aZipOut,const vector<uno::Sequence<PropertyValue>> & aManList)1038 void ZipPackage::WriteManifest( ZipOutputStream& aZipOut, const vector< uno::Sequence < PropertyValue > >& aManList )
1039 {
1040     // Write the manifest
1041     uno::Reference < XOutputStream > xManOutStream;
1042     OUString sManifestWriter( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestWriter" ) );
1043     uno::Reference < XManifestWriter > xWriter ( m_xFactory->createInstance( sManifestWriter ), UNO_QUERY );
1044     if ( xWriter.is() )
1045     {
1046         ZipEntry * pEntry = new ZipEntry;
1047         ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize );
1048         xManOutStream = uno::Reference < XOutputStream > ( *pBuffer, UNO_QUERY );
1049 
1050         pEntry->sPath = OUString( RTL_CONSTASCII_USTRINGPARAM ( "META-INF/manifest.xml" ) );
1051         pEntry->nMethod = DEFLATED;
1052         pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1;
1053         pEntry->nTime = ZipOutputStream::getCurrentDosTime();
1054 
1055         // Convert vector into a uno::Sequence
1056         uno::Sequence < uno::Sequence < PropertyValue > > aManifestSequence ( aManList.size() );
1057         sal_Int32 nInd = 0;
1058         for ( vector < uno::Sequence < PropertyValue > >::const_iterator aIter = aManList.begin(), aEnd = aManList.end();
1059              aIter != aEnd;
1060              aIter++, nInd++ )
1061         {
1062             aManifestSequence[nInd] = ( *aIter );
1063         }
1064         xWriter->writeManifestSequence ( xManOutStream,  aManifestSequence );
1065 
1066         sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() );
1067         pBuffer->realloc( nBufferLength );
1068 
1069         // the manifest.xml is never encrypted - so pass an empty reference
1070         aZipOut.putNextEntry( *pEntry, NULL );
1071         aZipOut.write( pBuffer->getSequence(), 0, nBufferLength );
1072         aZipOut.closeEntry();
1073     }
1074     else
1075     {
1076         VOS_ENSURE ( 0, "Couldn't get a ManifestWriter!" );
1077         IOException aException;
1078         throw WrappedTargetException(
1079                 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Couldn't get a ManifestWriter!" ) ),
1080                 static_cast < OWeakObject * > ( this ),
1081                 makeAny( aException ) );
1082     }
1083 }
1084 
1085 //--------------------------------------------------------
WriteContentTypes(ZipOutputStream & aZipOut,const vector<uno::Sequence<PropertyValue>> & aManList)1086 void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno::Sequence < PropertyValue > >& aManList )
1087 {
1088     const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1089     const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1090 
1091     ZipEntry* pEntry = new ZipEntry;
1092     ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize );
1093     uno::Reference< io::XOutputStream > xConTypeOutStream( *pBuffer, UNO_QUERY );
1094 
1095     pEntry->sPath = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
1096     pEntry->nMethod = DEFLATED;
1097     pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1;
1098     pEntry->nTime = ZipOutputStream::getCurrentDosTime();
1099 
1100     // Convert vector into a uno::Sequence
1101     // TODO/LATER: use Defaulst entries in future
1102     uno::Sequence< beans::StringPair > aDefaultsSequence;
1103     uno::Sequence< beans::StringPair > aOverridesSequence( aManList.size() );
1104     sal_Int32 nSeqLength = 0;
1105     for ( vector< uno::Sequence< beans::PropertyValue > >::const_iterator aIter = aManList.begin(),
1106             aEnd = aManList.end();
1107          aIter != aEnd;
1108          aIter++ )
1109     {
1110         ::rtl::OUString aPath;
1111         ::rtl::OUString aType;
1112         OSL_ENSURE( ( *aIter )[PKG_MNFST_MEDIATYPE].Name.equals( sMediaType ) && ( *aIter )[PKG_MNFST_FULLPATH].Name.equals( sFullPath ),
1113                     "The mediatype sequence format is wrong!\n" );
1114         ( *aIter )[PKG_MNFST_MEDIATYPE].Value >>= aType;
1115         if ( aType.getLength() )
1116         {
1117             // only nonempty type makes sence here
1118             nSeqLength++;
1119             ( *aIter )[PKG_MNFST_FULLPATH].Value >>= aPath;
1120             aOverridesSequence[nSeqLength-1].First = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) + aPath;
1121             aOverridesSequence[nSeqLength-1].Second = aType;
1122         }
1123     }
1124     aOverridesSequence.realloc( nSeqLength );
1125 
1126     ::comphelper::OFOPXMLHelper::WriteContentSequence(
1127             xConTypeOutStream, aDefaultsSequence, aOverridesSequence, m_xFactory );
1128 
1129     sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() );
1130     pBuffer->realloc( nBufferLength );
1131 
1132     // there is no encryption in this format currently
1133     aZipOut.putNextEntry( *pEntry, NULL );
1134     aZipOut.write( pBuffer->getSequence(), 0, nBufferLength );
1135     aZipOut.closeEntry();
1136 }
1137 
1138 //--------------------------------------------------------
ConnectTo(const uno::Reference<io::XInputStream> & xInStream)1139 void ZipPackage::ConnectTo( const uno::Reference< io::XInputStream >& xInStream )
1140 {
1141     m_xContentSeek.set( xInStream, uno::UNO_QUERY_THROW );
1142     m_xContentStream = xInStream;
1143 
1144     // seek back to the beginning of the temp file so we can read segments from it
1145     m_xContentSeek->seek( 0 );
1146     if ( m_pZipFile )
1147         m_pZipFile->setInputStream( m_xContentStream );
1148     else
1149         m_pZipFile = new ZipFile ( m_xContentStream, m_xFactory, sal_False );
1150 }
1151 
1152 //--------------------------------------------------------
writeTempFile()1153 uno::Reference< io::XInputStream > ZipPackage::writeTempFile()
1154 {
1155     // In case the target local file does not exist or empty
1156     // write directly to it otherwize create a temporary file to write to.
1157     // If a temporary file is created it is returned back by the method.
1158     // If the data written directly, xComponentStream will be switched here
1159 
1160     sal_Bool bUseTemp = sal_True;
1161     uno::Reference < io::XInputStream > xResult;
1162     uno::Reference < io::XInputStream > xTempIn;
1163 
1164     uno::Reference < io::XOutputStream > xTempOut;
1165     uno::Reference< io::XActiveDataStreamer > xSink;
1166 
1167     if ( m_eMode == e_IMode_URL && !m_pZipFile && isLocalFile_Impl( m_aURL ) )
1168     {
1169         xSink = openOriginalForOutput();
1170         if( xSink.is() )
1171         {
1172             uno::Reference< io::XStream > xStr = xSink->getStream();
1173             if( xStr.is() )
1174             {
1175                 xTempOut = xStr->getOutputStream();
1176                 if( xTempOut.is() )
1177                     bUseTemp = sal_False;
1178             }
1179         }
1180     }
1181     else if ( m_eMode == e_IMode_XStream && !m_pZipFile )
1182     {
1183         // write directly to an empty stream
1184         xTempOut = m_xStream->getOutputStream();
1185         if( xTempOut.is() )
1186             bUseTemp = sal_False;
1187     }
1188 
1189     if( bUseTemp )
1190     {
1191         // create temporary file
1192         const OUString sServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) );
1193         uno::Reference < io::XStream > xTempFile( m_xFactory->createInstance ( sServiceName ), UNO_QUERY_THROW );
1194         xTempOut.set( xTempFile->getOutputStream(), UNO_SET_THROW );
1195         xTempIn.set( xTempFile->getInputStream(), UNO_SET_THROW );
1196     }
1197 
1198     // Hand it to the ZipOutputStream:
1199     ZipOutputStream aZipOut( m_xFactory, xTempOut );
1200     aZipOut.setMethod( DEFLATED );
1201     aZipOut.setLevel( DEFAULT_COMPRESSION );
1202 
1203     try
1204     {
1205         if ( m_nFormat == embed::StorageFormats::PACKAGE )
1206         {
1207             // Remove the old manifest.xml file as the
1208             // manifest will be re-generated and the
1209             // META-INF directory implicitly created if does not exist
1210             const OUString sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) );
1211 
1212             if ( m_xRootFolder->hasByName( sMeta ) )
1213             {
1214                 const OUString sManifest ( RTL_CONSTASCII_USTRINGPARAM( "manifest.xml" ) );
1215 
1216                 uno::Reference< XUnoTunnel > xTunnel;
1217                 Any aAny = m_xRootFolder->getByName( sMeta );
1218                 aAny >>= xTunnel;
1219                 uno::Reference< XNameContainer > xMetaInfFolder( xTunnel, UNO_QUERY );
1220                 if ( xMetaInfFolder.is() && xMetaInfFolder->hasByName( sManifest ) )
1221                     xMetaInfFolder->removeByName( sManifest );
1222             }
1223 
1224             // Write a magic file with mimetype
1225             WriteMimetypeMagicFile( aZipOut );
1226         }
1227         else if ( m_nFormat == embed::StorageFormats::OFOPXML )
1228         {
1229             // Remove the old [Content_Types].xml file as the
1230             // file will be re-generated
1231 
1232             const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) );
1233 
1234             if ( m_xRootFolder->hasByName( aContentTypes ) )
1235                 m_xRootFolder->removeByName( aContentTypes );
1236         }
1237 
1238         // Create a vector to store data for the manifest.xml file
1239         vector < uno::Sequence < PropertyValue > > aManList;
1240 
1241         const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) );
1242         const OUString sVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) );
1243         const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) );
1244 
1245         if ( m_nFormat == embed::StorageFormats::PACKAGE )
1246         {
1247             uno::Sequence < PropertyValue > aPropSeq( PKG_SIZE_NOENCR_MNFST );
1248             aPropSeq [PKG_MNFST_MEDIATYPE].Name = sMediaType;
1249             aPropSeq [PKG_MNFST_MEDIATYPE].Value <<= m_pRootFolder->GetMediaType();
1250             aPropSeq [PKG_MNFST_VERSION].Name = sVersion;
1251             aPropSeq [PKG_MNFST_VERSION].Value <<= m_pRootFolder->GetVersion();
1252             aPropSeq [PKG_MNFST_FULLPATH].Name = sFullPath;
1253             aPropSeq [PKG_MNFST_FULLPATH].Value <<= OUString ( RTL_CONSTASCII_USTRINGPARAM ( "/" ) );
1254 
1255             aManList.push_back( aPropSeq );
1256         }
1257 
1258         // Get a random number generator and seed it with current timestamp
1259         // This will be used to generate random salt and initialisation vectors
1260         // for encrypted streams
1261         TimeValue aTime;
1262         osl_getSystemTime( &aTime );
1263         rtlRandomPool aRandomPool = rtl_random_createPool ();
1264         rtl_random_addBytes ( aRandomPool, &aTime, 8 );
1265 
1266         // call saveContents ( it will recursively save sub-directories
1267         OUString aEmptyString;
1268         m_pRootFolder->saveContents( aEmptyString, aManList, aZipOut, GetEncryptionKey(), aRandomPool );
1269 
1270         // Clean up random pool memory
1271         rtl_random_destroyPool ( aRandomPool );
1272 
1273         if( m_nFormat == embed::StorageFormats::PACKAGE )
1274         {
1275             WriteManifest( aZipOut, aManList );
1276         }
1277         else if( m_nFormat == embed::StorageFormats::OFOPXML )
1278         {
1279             WriteContentTypes( aZipOut, aManList );
1280         }
1281 
1282         aZipOut.finish();
1283 
1284         if( bUseTemp )
1285             xResult = xTempIn;
1286 
1287         // Update our References to point to the new temp file
1288         if( !bUseTemp )
1289         {
1290             // the case when the original contents were written directly
1291             xTempOut->flush();
1292 
1293             // in case the stream is based on a file it will implement the following interface
1294             // the call should be used to be sure that the contents are written to the file system
1295             uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( xTempOut, uno::UNO_QUERY );
1296             if ( asyncOutputMonitor.is() )
1297                 asyncOutputMonitor->waitForCompletion();
1298 
1299             // no need to postpone switching to the new stream since the target was written directly
1300             uno::Reference< io::XInputStream > xNewStream;
1301             if ( m_eMode == e_IMode_URL )
1302                 xNewStream = xSink->getStream()->getInputStream();
1303             else if ( m_eMode == e_IMode_XStream && m_xStream.is() )
1304                 xNewStream = m_xStream->getInputStream();
1305 
1306             if ( xNewStream.is() )
1307                 ConnectTo( xNewStream );
1308         }
1309     }
1310     catch ( uno::Exception& )
1311     {
1312         if( bUseTemp )
1313         {
1314             // no information loss appeares, thus no special handling is required
1315                uno::Any aCaught( ::cppu::getCaughtException() );
1316 
1317             // it is allowed to throw WrappedTargetException
1318             WrappedTargetException aException;
1319             if ( aCaught >>= aException )
1320                 throw aException;
1321 
1322             throw WrappedTargetException(
1323                     OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Problem writing the original content!" ) ),
1324                     static_cast < OWeakObject * > ( this ),
1325                     aCaught );
1326         }
1327         else
1328         {
1329             // the document is written directly, although it was empty it is important to notify that the writing has failed
1330             // TODO/LATER: let the package be able to recover in this situation
1331             ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is unusable!" ) );
1332             embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), ::rtl::OUString() );
1333             throw WrappedTargetException( aErrTxt,
1334                                             static_cast < OWeakObject * > ( this ),
1335                                             makeAny ( aException ) );
1336         }
1337     }
1338 
1339     return xResult;
1340 }
1341 
1342 //--------------------------------------------------------
openOriginalForOutput()1343 uno::Reference< XActiveDataStreamer > ZipPackage::openOriginalForOutput()
1344 {
1345     // open and truncate the original file
1346     Content aOriginalContent ( m_aURL, uno::Reference < XCommandEnvironment >() );
1347     uno::Reference< XActiveDataStreamer > xSink = new ActiveDataStreamer;
1348 
1349     if ( m_eMode == e_IMode_URL )
1350     {
1351         try
1352         {
1353             sal_Bool bTruncSuccess = sal_False;
1354 
1355             try
1356             {
1357                 Exception aDetect;
1358                 sal_Int64 aSize = 0;
1359                 Any aAny = aOriginalContent.setPropertyValue( OUString::createFromAscii( "Size" ), makeAny( aSize ) );
1360                 if( !( aAny >>= aDetect ) )
1361                     bTruncSuccess = sal_True;
1362             }
1363             catch( Exception& )
1364             {
1365             }
1366 
1367             if( !bTruncSuccess )
1368             {
1369                 // the file is not accessible
1370                 // just try to write an empty stream to it
1371 
1372                 uno::Reference< XInputStream > xTempIn = new DummyInputStream; //uno::Reference< XInputStream >( xTempOut, UNO_QUERY );
1373                 aOriginalContent.writeStream( xTempIn , sal_True );
1374             }
1375 
1376             OpenCommandArgument2 aArg;
1377             aArg.Mode       = OpenMode::DOCUMENT;
1378             aArg.Priority   = 0; // unused
1379             aArg.Sink       = xSink;
1380             aArg.Properties = uno::Sequence< Property >( 0 ); // unused
1381 
1382             aOriginalContent.executeCommand( OUString::createFromAscii( "open" ), makeAny( aArg ) );
1383         }
1384         catch( Exception& )
1385         {
1386             // seems to be nonlocal file
1387             // temporary file mechanics should be used
1388         }
1389     }
1390 
1391     return xSink;
1392 }
1393 
1394 //--------------------------------------------------------
commitChanges()1395 void SAL_CALL ZipPackage::commitChanges()
1396         throw( WrappedTargetException, RuntimeException )
1397 {
1398     // lock the component for the time of commiting
1399     ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() );
1400 
1401     if ( m_eMode == e_IMode_XInputStream )
1402     {
1403         IOException aException;
1404         throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ),
1405                 static_cast < OWeakObject * > ( this ), makeAny ( aException ) );
1406     }
1407 
1408     RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::commitChanges" );
1409 
1410     // first the writeTempFile is called, if it returns a stream the stream should be written to the target
1411     // if no stream was returned, the file was written directly, nothing should be done
1412 
1413     uno::Reference< io::XInputStream > xTempInStream = writeTempFile();
1414     if ( xTempInStream.is() )
1415     {
1416         uno::Reference< io::XSeekable > xTempSeek( xTempInStream, uno::UNO_QUERY_THROW );
1417 
1418         try
1419         {
1420             xTempSeek->seek( 0 );
1421         }
1422         catch( uno::Exception& r )
1423         {
1424             throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Temporary file should be seekable!" ) ),
1425                     static_cast < OWeakObject * > ( this ), makeAny ( r ) );
1426         }
1427 
1428         // connect to the temporary stream
1429         ConnectTo( xTempInStream );
1430 
1431         if ( m_eMode == e_IMode_XStream )
1432         {
1433             // First truncate our output stream
1434             uno::Reference < XOutputStream > xOutputStream;
1435 
1436             // preparation for copy step
1437             try
1438             {
1439                 xOutputStream = m_xStream->getOutputStream();
1440                 uno::Reference < XTruncate > xTruncate ( xOutputStream, UNO_QUERY );
1441                 if ( !xTruncate.is() )
1442                     throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1443 
1444                 // after successful truncation the original file contents are already lost
1445                 xTruncate->truncate();
1446             }
1447             catch( uno::Exception& r )
1448             {
1449                 throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ),
1450                         static_cast < OWeakObject * > ( this ), makeAny ( r ) );
1451             }
1452 
1453             try
1454             {
1455                 // then copy the contents of the tempfile to our output stream
1456                 ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, xOutputStream );
1457                 xOutputStream->flush();
1458                 uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor(
1459                     xOutputStream, uno::UNO_QUERY );
1460                 if ( asyncOutputMonitor.is() ) {
1461                     asyncOutputMonitor->waitForCompletion();
1462                 }
1463             }
1464             catch( uno::Exception& )
1465             {
1466                 // if anything goes wrong in this block the target file becomes corrupted
1467                 // so an exception should be thrown as a notification about it
1468                 // and the package must disconnect from the stream
1469                 DisconnectFromTargetAndThrowException_Impl( xTempInStream );
1470             }
1471         }
1472         else if ( m_eMode == e_IMode_URL )
1473         {
1474             uno::Reference< XOutputStream > aOrigFileStream;
1475             sal_Bool bCanBeCorrupted = sal_False;
1476 
1477             if( isLocalFile_Impl( m_aURL ) )
1478             {
1479                 // write directly in case of local file
1480                 uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess > xSimpleAccess(
1481                     m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ),
1482                     uno::UNO_QUERY );
1483                 OSL_ENSURE( xSimpleAccess.is(), "Can't instatiate SimpleFileAccess service!\n" );
1484                 uno::Reference< io::XTruncate > xOrigTruncate;
1485                 if ( xSimpleAccess.is() )
1486                 {
1487                     try
1488                     {
1489                         aOrigFileStream = xSimpleAccess->openFileWrite( m_aURL );
1490                         xOrigTruncate = uno::Reference< io::XTruncate >( aOrigFileStream, uno::UNO_QUERY_THROW );
1491                         // after successful truncation the file is already corrupted
1492                         xOrigTruncate->truncate();
1493                     }
1494                     catch( uno::Exception& )
1495                     {}
1496                 }
1497 
1498                 if( xOrigTruncate.is() )
1499                 {
1500                     try
1501                     {
1502                         ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, aOrigFileStream );
1503                         aOrigFileStream->closeOutput();
1504                     }
1505                     catch( uno::Exception& )
1506                     {
1507                         try {
1508                             aOrigFileStream->closeOutput();
1509                         } catch ( uno::Exception& ) {}
1510 
1511                         aOrigFileStream = uno::Reference< XOutputStream >();
1512                         // the original file can already be corrupted
1513                         bCanBeCorrupted = sal_True;
1514                     }
1515                 }
1516             }
1517 
1518             if( !aOrigFileStream.is() )
1519             {
1520                 try
1521                 {
1522                     uno::Reference < XPropertySet > xPropSet ( xTempInStream, UNO_QUERY );
1523                     OSL_ENSURE( xPropSet.is(), "This is a temporary file that must implement XPropertySet!\n" );
1524                     if ( !xPropSet.is() )
1525                         throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1526 
1527                     OUString sTargetFolder = m_aURL.copy ( 0, m_aURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) );
1528                     Content aContent ( sTargetFolder, uno::Reference < XCommandEnvironment > () );
1529 
1530                     OUString sTempURL;
1531                     Any aAny = xPropSet->getPropertyValue ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Uri" ) ) );
1532                     aAny >>= sTempURL;
1533 
1534                     TransferInfo aInfo;
1535                     aInfo.NameClash = NameClash::OVERWRITE;
1536                     aInfo.MoveData = sal_False;
1537                     aInfo.SourceURL = sTempURL;
1538                     aInfo.NewTitle = rtl::Uri::decode ( m_aURL.copy ( 1 + m_aURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) ),
1539                                                         rtl_UriDecodeWithCharset,
1540                                                         RTL_TEXTENCODING_UTF8 );
1541                     aAny <<= aInfo;
1542 
1543                     // if the file is still not corrupted, it can become after the next step
1544                     aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "transfer" ) ), aAny );
1545                 }
1546                 catch ( ::com::sun::star::uno::Exception& r )
1547                 {
1548                     if ( bCanBeCorrupted )
1549                         DisconnectFromTargetAndThrowException_Impl( xTempInStream );
1550 
1551                     throw WrappedTargetException(
1552                                                 OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package may be read only!" ) ),
1553                                                 static_cast < OWeakObject * > ( this ),
1554                                                 makeAny ( r ) );
1555                 }
1556             }
1557         }
1558     }
1559 
1560     // after successful storing it can be set to false
1561     m_bMediaTypeFallbackUsed = sal_False;
1562 
1563     RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::commitChanges" );
1564 }
1565 
1566 //--------------------------------------------------------
DisconnectFromTargetAndThrowException_Impl(const uno::Reference<io::XInputStream> & xTempStream)1567 void ZipPackage::DisconnectFromTargetAndThrowException_Impl( const uno::Reference< io::XInputStream >& xTempStream )
1568 {
1569     m_xStream = uno::Reference< io::XStream >( xTempStream, uno::UNO_QUERY );
1570     if ( m_xStream.is() )
1571         m_eMode = e_IMode_XStream;
1572     else
1573         m_eMode = e_IMode_XInputStream;
1574 
1575     ::rtl::OUString aTempURL;
1576     try {
1577         uno::Reference< beans::XPropertySet > xTempFile( xTempStream, uno::UNO_QUERY_THROW );
1578         uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) );
1579         aUrl >>= aTempURL;
1580         xTempFile->setPropertyValue( ::rtl::OUString::createFromAscii( "RemoveFile" ),
1581                                      uno::makeAny( sal_False ) );
1582     }
1583     catch ( uno::Exception& )
1584     {
1585         OSL_ENSURE( sal_False, "These calls are pretty simple, they should not fail!\n" );
1586     }
1587 
1588     ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) );
1589     embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), aTempURL );
1590     throw WrappedTargetException( aErrTxt,
1591                                     static_cast < OWeakObject * > ( this ),
1592                                     makeAny ( aException ) );
1593 }
1594 
1595 //--------------------------------------------------------
GetEncryptionKey()1596 const uno::Sequence< sal_Int8 > ZipPackage::GetEncryptionKey()
1597 {
1598     uno::Sequence< sal_Int8 > aResult;
1599 
1600     if ( m_aStorageEncryptionKeys.getLength() )
1601     {
1602         ::rtl::OUString aNameToFind;
1603         if ( m_nStartKeyGenerationID == xml::crypto::DigestID::SHA256 )
1604             aNameToFind = PACKAGE_ENCRYPTIONDATA_SHA256UTF8;
1605         else if ( m_nStartKeyGenerationID == xml::crypto::DigestID::SHA1 )
1606             aNameToFind = PACKAGE_ENCRYPTIONDATA_SHA1UTF8;
1607         else
1608             throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No expected key is provided!" ) ), uno::Reference< uno::XInterface >() );
1609 
1610         for ( sal_Int32 nInd = 0; nInd < m_aStorageEncryptionKeys.getLength(); nInd++ )
1611             if ( m_aStorageEncryptionKeys[nInd].Name.equals( aNameToFind ) )
1612                 m_aStorageEncryptionKeys[nInd].Value >>= aResult;
1613 
1614         // empty keys are not allowed here
1615         // so it is not important whether there is no key, or the key is empty, it is an error
1616         if ( !aResult.getLength() )
1617             throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No expected key is provided!" ) ), uno::Reference< uno::XInterface >() );
1618     }
1619     else
1620         aResult = m_aEncryptionKey;
1621 
1622     return aResult;
1623 }
1624 
1625 //--------------------------------------------------------
hasPendingChanges()1626 sal_Bool SAL_CALL ZipPackage::hasPendingChanges()
1627         throw( RuntimeException )
1628 {
1629     return sal_False;
1630 }
1631 //--------------------------------------------------------
getPendingChanges()1632 Sequence< ElementChange > SAL_CALL ZipPackage::getPendingChanges()
1633         throw( RuntimeException )
1634 {
1635     return uno::Sequence < ElementChange > ();
1636 }
1637 
1638 /**
1639  * Function to create a new component instance; is needed by factory helper implementation.
1640  * @param xMgr service manager to if the components needs other component instances
1641  */
ZipPackage_createInstance(const uno::Reference<XMultiServiceFactory> & xMgr)1642 uno::Reference < XInterface >SAL_CALL ZipPackage_createInstance(
1643     const uno::Reference< XMultiServiceFactory > & xMgr )
1644 {
1645     return uno::Reference< XInterface >( *new ZipPackage( xMgr ) );
1646 }
1647 
1648 //--------------------------------------------------------
static_getImplementationName()1649 OUString ZipPackage::static_getImplementationName()
1650 {
1651     return OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.comp.ZipPackage" ) );
1652 }
1653 
1654 //--------------------------------------------------------
static_getSupportedServiceNames()1655 Sequence< OUString > ZipPackage::static_getSupportedServiceNames()
1656 {
1657     uno::Sequence< OUString > aNames( 1 );
1658     aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.Package" ) );
1659     return aNames;
1660 }
1661 //--------------------------------------------------------
static_supportsService(OUString const & rServiceName)1662 sal_Bool SAL_CALL ZipPackage::static_supportsService( OUString const & rServiceName )
1663 {
1664     return rServiceName == getSupportedServiceNames()[0];
1665 }
1666 
1667 //--------------------------------------------------------
getImplementationName()1668 OUString ZipPackage::getImplementationName()
1669     throw ( RuntimeException )
1670 {
1671     return static_getImplementationName();
1672 }
1673 
1674 //--------------------------------------------------------
getSupportedServiceNames()1675 Sequence< OUString > ZipPackage::getSupportedServiceNames()
1676     throw ( RuntimeException )
1677 {
1678     return static_getSupportedServiceNames();
1679 }
1680 //--------------------------------------------------------
supportsService(OUString const & rServiceName)1681 sal_Bool SAL_CALL ZipPackage::supportsService( OUString const & rServiceName )
1682     throw ( RuntimeException )
1683 {
1684     return static_supportsService ( rServiceName );
1685 }
1686 //--------------------------------------------------------
createServiceFactory(uno::Reference<XMultiServiceFactory> const & rServiceFactory)1687 uno::Reference < XSingleServiceFactory > ZipPackage::createServiceFactory( uno::Reference < XMultiServiceFactory > const & rServiceFactory )
1688 {
1689     return cppu::createSingleFactory ( rServiceFactory,
1690                                            static_getImplementationName(),
1691                                            ZipPackage_createInstance,
1692                                            static_getSupportedServiceNames() );
1693 }
1694 
1695 namespace { struct lcl_ImplId : public rtl::Static< ::cppu::OImplementationId, lcl_ImplId > {}; }
1696 
1697 //--------------------------------------------------------
getUnoTunnelImplementationId(void)1698 Sequence< sal_Int8 > ZipPackage::getUnoTunnelImplementationId( void )
1699     throw ( RuntimeException )
1700 {
1701     ::cppu::OImplementationId &rId = lcl_ImplId::get();
1702     return rId.getImplementationId();
1703 }
1704 
1705 //--------------------------------------------------------
getSomething(const uno::Sequence<sal_Int8> & aIdentifier)1706 sal_Int64 SAL_CALL ZipPackage::getSomething( const uno::Sequence< sal_Int8 >& aIdentifier )
1707     throw( RuntimeException )
1708 {
1709     if ( aIdentifier.getLength() == 16 && 0 == rtl_compareMemory( getUnoTunnelImplementationId().getConstArray(),  aIdentifier.getConstArray(), 16 ) )
1710         return reinterpret_cast < sal_Int64 > ( this );
1711     return 0;
1712 }
1713 
1714 //--------------------------------------------------------
getPropertySetInfo()1715 uno::Reference< XPropertySetInfo > SAL_CALL ZipPackage::getPropertySetInfo()
1716         throw( RuntimeException )
1717 {
1718     return uno::Reference < XPropertySetInfo > ();
1719 }
1720 
1721 //--------------------------------------------------------
setPropertyValue(const OUString & aPropertyName,const Any & aValue)1722 void SAL_CALL ZipPackage::setPropertyValue( const OUString& aPropertyName, const Any& aValue )
1723         throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException )
1724 {
1725     if ( m_nFormat != embed::StorageFormats::PACKAGE )
1726         throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1727 
1728     if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( HAS_ENCRYPTED_ENTRIES_PROPERTY ) )
1729       ||aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( HAS_NONENCRYPTED_ENTRIES_PROPERTY ) )
1730       ||aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( IS_INCONSISTENT_PROPERTY ) )
1731       ||aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( MEDIATYPE_FALLBACK_USED_PROPERTY ) ) )
1732         throw PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1733     else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_KEY_PROPERTY ) ) )
1734     {
1735         if ( !( aValue >>= m_aEncryptionKey ) )
1736             throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 );
1737 
1738         m_aStorageEncryptionKeys.realloc( 0 );
1739     }
1740     else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( STORAGE_ENCRYPTION_KEYS_PROPERTY ) ) )
1741     {
1742         // this property is only necessary to support raw passwords in storage API;
1743         // because of this support the storage has to operate with more than one key dependent on storage generation algorithm;
1744         // when this support is removed, the storage will get only one key from outside
1745         // TODO/LATER: Get rid of this property as well as of support of raw passwords in storages
1746         uno::Sequence< beans::NamedValue > aKeys;
1747         if ( !( aValue >>= aKeys ) || ( aKeys.getLength() && aKeys.getLength() < 2 ) )
1748             throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 );
1749 
1750         if ( aKeys.getLength() )
1751         {
1752             bool bHasSHA256 = false;
1753             bool bHasSHA1 = false;
1754             for ( sal_Int32 nInd = 0; nInd < aKeys.getLength(); nInd++ )
1755             {
1756                 if ( aKeys[nInd].Name.equals( PACKAGE_ENCRYPTIONDATA_SHA256UTF8 ) )
1757                     bHasSHA256 = true;
1758                 if ( aKeys[nInd].Name.equals( PACKAGE_ENCRYPTIONDATA_SHA1UTF8 ) )
1759                     bHasSHA1 = true;
1760             }
1761 
1762             if ( !bHasSHA256 || !bHasSHA1 )
1763                 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Expected keys are not provided!" ) ), uno::Reference< uno::XInterface >(), 2 );
1764         }
1765 
1766         m_aStorageEncryptionKeys = aKeys;
1767         m_aEncryptionKey.realloc( 0 );
1768     }
1769     else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_ALGORITHMS_PROPERTY ) ) )
1770     {
1771         uno::Sequence< beans::NamedValue > aAlgorithms;
1772         if ( m_pZipFile || !( aValue >>= aAlgorithms ) || aAlgorithms.getLength() == 0 )
1773         {
1774             // the algorithms can not be changed if the file has a persistence based on the algorithms ( m_pZipFile )
1775             throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "unexpected algorithms list is provided." ) ), uno::Reference< uno::XInterface >(), 2 );
1776         }
1777 
1778         for ( sal_Int32 nInd = 0; nInd < aAlgorithms.getLength(); nInd++ )
1779         {
1780             if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "StartKeyGenerationAlgorithm" ) ) )
1781             {
1782                 sal_Int32 nID = 0;
1783                 if ( !( aAlgorithms[nInd].Value >>= nID )
1784                   || ( nID != xml::crypto::DigestID::SHA256 && nID != xml::crypto::DigestID::SHA1 ) )
1785                     throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected start key generation algorithm is provided!" ) ), uno::Reference< uno::XInterface >(), 2 );
1786 
1787                 m_nStartKeyGenerationID = nID;
1788             }
1789             else if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "EncryptionAlgorithm" ) ) )
1790             {
1791                 sal_Int32 nID = 0;
1792                 if ( !( aAlgorithms[nInd].Value >>= nID )
1793                   || ( nID != xml::crypto::CipherID::AES_CBC_W3C_PADDING && nID != xml::crypto::CipherID::BLOWFISH_CFB_8 ) )
1794                     throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected start key generation algorithm is provided!" ) ), uno::Reference< uno::XInterface >(), 2 );
1795 
1796                 m_nCommonEncryptionID = nID;
1797             }
1798             else if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ChecksumAlgorithm" ) ) )
1799             {
1800                 sal_Int32 nID = 0;
1801                 if ( !( aAlgorithms[nInd].Value >>= nID )
1802                   || ( nID != xml::crypto::DigestID::SHA1_1K && nID != xml::crypto::DigestID::SHA256_1K ) )
1803                     throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected start key generation algorithm is provided!" ) ), uno::Reference< uno::XInterface >(), 2 );
1804 
1805                 m_nChecksumDigestID = nID;
1806             }
1807             else
1808             {
1809                 OSL_ENSURE( sal_False, "Unexpected encryption algorithm is provided!" );
1810                 throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "unexpected algorithms list is provided." ) ), uno::Reference< uno::XInterface >(), 2 );
1811             }
1812         }
1813     }
1814     else
1815         throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1816 }
1817 
1818 //--------------------------------------------------------
getPropertyValue(const OUString & PropertyName)1819 Any SAL_CALL ZipPackage::getPropertyValue( const OUString& PropertyName )
1820         throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1821 {
1822     // TODO/LATER: Activate the check when zip-ucp is ready
1823     // if ( m_nFormat != embed::StorageFormats::PACKAGE )
1824     //  throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1825 
1826     Any aAny;
1827     if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( ENCRYPTION_KEY_PROPERTY ) ) )
1828     {
1829         aAny <<= m_aEncryptionKey;
1830         return aAny;
1831     }
1832     else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_ALGORITHMS_PROPERTY ) ) )
1833     {
1834         ::comphelper::SequenceAsHashMap aAlgorithms;
1835         aAlgorithms[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StartKeyGenerationAlgorithm" ) ) ] <<= m_nStartKeyGenerationID;
1836         aAlgorithms[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EncryptionAlgorithm" ) ) ] <<= m_nCommonEncryptionID;
1837         aAlgorithms[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ChecksumAlgorithm" ) ) ] <<= m_nChecksumDigestID;
1838         aAny <<= aAlgorithms.getAsConstNamedValueList();
1839         return aAny;
1840     }
1841     if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( STORAGE_ENCRYPTION_KEYS_PROPERTY ) ) )
1842     {
1843         aAny <<= m_aStorageEncryptionKeys;
1844         return aAny;
1845     }
1846     else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( HAS_ENCRYPTED_ENTRIES_PROPERTY ) ) )
1847     {
1848         aAny <<= m_bHasEncryptedEntries;
1849         return aAny;
1850     }
1851     else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( HAS_NONENCRYPTED_ENTRIES_PROPERTY ) ) )
1852     {
1853         aAny <<= m_bHasNonEncryptedEntries;
1854         return aAny;
1855     }
1856     else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( IS_INCONSISTENT_PROPERTY ) ) )
1857     {
1858         aAny <<= m_bInconsistent;
1859         return aAny;
1860     }
1861     else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( MEDIATYPE_FALLBACK_USED_PROPERTY ) ) )
1862     {
1863         aAny <<= m_bMediaTypeFallbackUsed;
1864         return aAny;
1865     }
1866     throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
1867 }
1868 //--------------------------------------------------------
addPropertyChangeListener(const OUString &,const uno::Reference<XPropertyChangeListener> &)1869 void SAL_CALL ZipPackage::addPropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ )
1870         throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1871 {
1872 }
1873 //--------------------------------------------------------
removePropertyChangeListener(const OUString &,const uno::Reference<XPropertyChangeListener> &)1874 void SAL_CALL ZipPackage::removePropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*aListener*/ )
1875         throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1876 {
1877 }
1878 //--------------------------------------------------------
addVetoableChangeListener(const OUString &,const uno::Reference<XVetoableChangeListener> &)1879 void SAL_CALL ZipPackage::addVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ )
1880         throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1881 {
1882 }
1883 //--------------------------------------------------------
removeVetoableChangeListener(const OUString &,const uno::Reference<XVetoableChangeListener> &)1884 void SAL_CALL ZipPackage::removeVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ )
1885         throw( UnknownPropertyException, WrappedTargetException, RuntimeException )
1886 {
1887 }
1888