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