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