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