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