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