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