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