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