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 <string.h>
21 :
22 : #include <ZipPackageFolder.hxx>
23 : #include <ZipFile.hxx>
24 : #include <ZipOutputStream.hxx>
25 : #include <ZipPackageStream.hxx>
26 : #include <PackageConstants.hxx>
27 : #include <ZipPackageFolderEnumeration.hxx>
28 : #include <com/sun/star/packages/zip/ZipConstants.hpp>
29 : #include <com/sun/star/embed/StorageFormats.hpp>
30 : #include <osl/diagnose.h>
31 : #include <osl/time.h>
32 : #include <rtl/digest.h>
33 : #include <ContentInfo.hxx>
34 : #include <com/sun/star/beans/PropertyValue.hpp>
35 : #include <com/sun/star/io/XSeekable.hpp>
36 : #include <EncryptedDataHeader.hxx>
37 : #include <rtl/random.h>
38 : #include <rtl/instance.hxx>
39 : #include <memory>
40 :
41 : using namespace com::sun::star;
42 : using namespace com::sun::star::packages::zip::ZipConstants;
43 : using namespace com::sun::star::packages::zip;
44 : using namespace com::sun::star::packages;
45 : using namespace com::sun::star::container;
46 : using namespace com::sun::star::beans;
47 : using namespace com::sun::star::lang;
48 : using namespace com::sun::star::io;
49 : using namespace cppu;
50 : using namespace std;
51 : using namespace ::com::sun::star;
52 :
53 : namespace { struct lcl_CachedImplId : public rtl::Static< uno::Sequence < sal_Int8 >, lcl_CachedImplId > {}; }
54 :
55 10446 : ZipPackageFolder::ZipPackageFolder ( const uno::Reference< XMultiServiceFactory >& xFactory,
56 : sal_Int32 nFormat,
57 : sal_Bool bAllowRemoveOnInsert )
58 : : m_xFactory( xFactory )
59 10446 : , m_nFormat( nFormat )
60 : {
61 : OSL_ENSURE( m_xFactory.is(), "No factory is provided to the package folder!" );
62 :
63 10446 : this->mbAllowRemoveOnInsert = bAllowRemoveOnInsert;
64 :
65 10446 : SetFolder ( sal_True );
66 10446 : aEntry.nVersion = -1;
67 10446 : aEntry.nFlag = 0;
68 10446 : aEntry.nMethod = STORED;
69 10446 : aEntry.nTime = -1;
70 10446 : aEntry.nCrc = 0;
71 10446 : aEntry.nCompressedSize = 0;
72 10446 : aEntry.nSize = 0;
73 10446 : aEntry.nOffset = -1;
74 10446 : uno::Sequence < sal_Int8 > &rCachedImplId = lcl_CachedImplId::get();
75 10446 : if ( !rCachedImplId.getLength() )
76 15 : rCachedImplId = getImplementationId();
77 10446 : }
78 :
79 :
80 15622 : ZipPackageFolder::~ZipPackageFolder()
81 : {
82 15622 : }
83 :
84 865 : sal_Bool ZipPackageFolder::LookForUnexpectedODF12Streams( const OUString& aPath )
85 : {
86 865 : sal_Bool bHasUnexpected = sal_False;
87 :
88 4268 : for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
89 2134 : !bHasUnexpected && aCI != aEnd;
90 : ++aCI)
91 : {
92 1269 : const OUString &rShortName = (*aCI).first;
93 1269 : const ContentInfo &rInfo = *(*aCI).second;
94 :
95 1269 : if ( rInfo.bFolder )
96 : {
97 802 : if ( aPath == "META-INF/" )
98 : {
99 : // META-INF is not allowed to contain subfolders
100 0 : bHasUnexpected = sal_True;
101 : }
102 : else
103 : {
104 802 : OUString sOwnPath = aPath + rShortName + "/";
105 802 : bHasUnexpected = rInfo.pFolder->LookForUnexpectedODF12Streams( sOwnPath );
106 : }
107 : }
108 : else
109 : {
110 467 : if ( aPath == "META-INF/" )
111 : {
112 0 : if ( rShortName != "manifest.xml"
113 0 : && rShortName.indexOf( "signatures" ) == -1 )
114 : {
115 : // a stream from META-INF with unexpected name
116 0 : bHasUnexpected = sal_True;
117 : }
118 :
119 : // streams from META-INF with expected names are allowed not to be registered in manifest.xml
120 : }
121 467 : else if ( !rInfo.pStream->IsFromManifest() )
122 : {
123 : // the stream is not in META-INF and ist notregistered in manifest.xml,
124 : // check whether it is an internal part of the package format
125 0 : if ( !aPath.isEmpty() || rShortName != "mimetype" )
126 : {
127 : // if it is not "mimetype" from the root it is not a part of the package
128 0 : bHasUnexpected = sal_True;
129 : }
130 : }
131 : }
132 : }
133 :
134 865 : return bHasUnexpected;
135 : }
136 :
137 1685 : void ZipPackageFolder::setChildStreamsTypeByExtension( const beans::StringPair& aPair )
138 : {
139 1685 : OUString aExt;
140 1685 : if ( aPair.First.toChar() == (sal_Unicode)'.' )
141 0 : aExt = aPair.First;
142 : else
143 1685 : aExt = "." + aPair.First;
144 :
145 6631 : for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
146 : aCI != aEnd;
147 : ++aCI)
148 : {
149 4946 : const OUString &rShortName = (*aCI).first;
150 4946 : const ContentInfo &rInfo = *(*aCI).second;
151 :
152 4946 : if ( rInfo.bFolder )
153 1444 : rInfo.pFolder->setChildStreamsTypeByExtension( aPair );
154 : else
155 : {
156 3502 : sal_Int32 nPathLength = rShortName.getLength();
157 3502 : sal_Int32 nExtLength = aExt.getLength();
158 3502 : if ( nPathLength >= nExtLength && rShortName.match( aExt, nPathLength - nExtLength ) )
159 1426 : rInfo.pStream->SetMediaType( aPair.Second );
160 : }
161 1685 : }
162 1685 : }
163 :
164 494 : void ZipPackageFolder::copyZipEntry( ZipEntry &rDest, const ZipEntry &rSource)
165 : {
166 494 : rDest.nVersion = rSource.nVersion;
167 494 : rDest.nFlag = rSource.nFlag;
168 494 : rDest.nMethod = rSource.nMethod;
169 494 : rDest.nTime = rSource.nTime;
170 494 : rDest.nCrc = rSource.nCrc;
171 494 : rDest.nCompressedSize = rSource.nCompressedSize;
172 494 : rDest.nSize = rSource.nSize;
173 494 : rDest.nOffset = rSource.nOffset;
174 494 : rDest.sPath = rSource.sPath;
175 494 : rDest.nPathLen = rSource.nPathLen;
176 494 : rDest.nExtraLen = rSource.nExtraLen;
177 494 : }
178 :
179 4214 : const ::com::sun::star::uno::Sequence < sal_Int8 >& ZipPackageFolder::static_getImplementationId()
180 : {
181 4214 : return lcl_CachedImplId::get();
182 : }
183 :
184 : // XNameContainer
185 1040 : void SAL_CALL ZipPackageFolder::insertByName( const OUString& aName, const uno::Any& aElement )
186 : throw(IllegalArgumentException, ElementExistException, WrappedTargetException, uno::RuntimeException)
187 : {
188 1040 : if (hasByName(aName))
189 0 : throw ElementExistException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
190 : else
191 : {
192 1040 : uno::Reference < XUnoTunnel > xRef;
193 1040 : aElement >>= xRef;
194 1040 : if ( ( aElement >>= xRef ) )
195 : {
196 : sal_Int64 nTest;
197 : ZipPackageEntry *pEntry;
198 1040 : if ( ( nTest = xRef->getSomething ( ZipPackageFolder::static_getImplementationId() ) ) != 0 )
199 : {
200 149 : ZipPackageFolder *pFolder = reinterpret_cast < ZipPackageFolder * > ( nTest );
201 149 : pEntry = static_cast < ZipPackageEntry * > ( pFolder );
202 : }
203 891 : else if ( ( nTest = xRef->getSomething ( ZipPackageStream::static_getImplementationId() ) ) != 0 )
204 : {
205 891 : ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream * > ( nTest );
206 891 : pEntry = static_cast < ZipPackageEntry * > ( pStream );
207 : }
208 : else
209 0 : throw IllegalArgumentException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >(), 0 );
210 :
211 1040 : if (pEntry->getName() != aName )
212 1040 : pEntry->setName (aName);
213 1040 : doInsertByName ( pEntry, sal_True );
214 : }
215 : else
216 0 : throw IllegalArgumentException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >(), 0 );
217 : }
218 1040 : }
219 387 : void SAL_CALL ZipPackageFolder::removeByName( const OUString& Name )
220 : throw(NoSuchElementException, WrappedTargetException, uno::RuntimeException)
221 : {
222 387 : ContentHash::iterator aIter = maContents.find ( Name );
223 387 : if ( aIter == maContents.end() )
224 0 : throw NoSuchElementException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
225 387 : maContents.erase( aIter );
226 387 : }
227 : // XEnumerationAccess
228 4793 : uno::Reference< XEnumeration > SAL_CALL ZipPackageFolder::createEnumeration( )
229 : throw(uno::RuntimeException)
230 : {
231 4793 : return uno::Reference < XEnumeration> (new ZipPackageFolderEnumeration(maContents));
232 : }
233 : // XElementAccess
234 0 : uno::Type SAL_CALL ZipPackageFolder::getElementType( )
235 : throw(uno::RuntimeException)
236 : {
237 0 : return ::getCppuType ((const uno::Reference< XUnoTunnel > *) 0);
238 : }
239 0 : sal_Bool SAL_CALL ZipPackageFolder::hasElements( )
240 : throw(uno::RuntimeException)
241 : {
242 0 : return maContents.size() > 0;
243 : }
244 : // XNameAccess
245 6786 : ContentInfo& ZipPackageFolder::doGetByName( const OUString& aName )
246 : throw(NoSuchElementException, WrappedTargetException, uno::RuntimeException)
247 : {
248 6786 : ContentHash::iterator aIter = maContents.find ( aName );
249 6786 : if ( aIter == maContents.end())
250 0 : throw NoSuchElementException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
251 6786 : return *(*aIter).second;
252 : }
253 5185 : uno::Any SAL_CALL ZipPackageFolder::getByName( const OUString& aName )
254 : throw(NoSuchElementException, WrappedTargetException, uno::RuntimeException)
255 : {
256 5185 : return uno::makeAny ( doGetByName ( aName ).xTunnel );
257 : }
258 0 : uno::Sequence< OUString > SAL_CALL ZipPackageFolder::getElementNames( )
259 : throw(uno::RuntimeException)
260 : {
261 0 : sal_uInt32 i=0, nSize = maContents.size();
262 0 : uno::Sequence < OUString > aSequence ( nSize );
263 0 : for ( ContentHash::const_iterator aIterator = maContents.begin(), aEnd = maContents.end();
264 : aIterator != aEnd;
265 : ++i, ++aIterator)
266 0 : aSequence[i] = (*aIterator).first;
267 0 : return aSequence;
268 : }
269 19236 : sal_Bool SAL_CALL ZipPackageFolder::hasByName( const OUString& aName )
270 : throw(uno::RuntimeException)
271 : {
272 19236 : return maContents.find ( aName ) != maContents.end ();
273 : }
274 : // XNameReplace
275 0 : void SAL_CALL ZipPackageFolder::replaceByName( const OUString& aName, const uno::Any& aElement )
276 : throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, uno::RuntimeException)
277 : {
278 0 : if ( hasByName( aName ) )
279 0 : removeByName( aName );
280 : else
281 0 : throw NoSuchElementException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
282 0 : insertByName(aName, aElement);
283 0 : }
284 :
285 5 : static void ImplSetStoredData( ZipEntry & rEntry, uno::Reference< XInputStream> & rStream )
286 : {
287 : // It's very annoying that we have to do this, but lots of zip packages
288 : // don't allow data descriptors for STORED streams, meaning we have to
289 : // know the size and CRC32 of uncompressed streams before we actually
290 : // write them !
291 5 : CRC32 aCRC32;
292 5 : rEntry.nMethod = STORED;
293 5 : rEntry.nCompressedSize = rEntry.nSize = aCRC32.updateStream ( rStream );
294 5 : rEntry.nCrc = aCRC32.getValue();
295 5 : }
296 :
297 374 : bool ZipPackageFolder::saveChild( const OUString &rShortName, const ContentInfo &rInfo, OUString &rPath, std::vector < uno::Sequence < PropertyValue > > &rManList, ZipOutputStream & rZipOut, const uno::Sequence < sal_Int8 >& rEncryptionKey, rtlRandomPool &rRandomPool)
298 : {
299 374 : bool bSuccess = true;
300 :
301 374 : const OUString sMediaTypeProperty ("MediaType");
302 374 : const OUString sVersionProperty ("Version");
303 374 : const OUString sFullPathProperty ("FullPath");
304 374 : const OUString sInitialisationVectorProperty ("InitialisationVector");
305 374 : const OUString sSaltProperty ("Salt");
306 374 : const OUString sIterationCountProperty ("IterationCount");
307 374 : const OUString sSizeProperty ("Size");
308 374 : const OUString sDigestProperty ("Digest");
309 374 : const OUString sEncryptionAlgProperty ("EncryptionAlgorithm");
310 374 : const OUString sStartKeyAlgProperty ("StartKeyAlgorithm");
311 374 : const OUString sDigestAlgProperty ("DigestAlgorithm");
312 374 : const OUString sDerivedKeySizeProperty ("DerivedKeySize");
313 :
314 374 : uno::Sequence < PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST);
315 :
316 : OSL_ENSURE( ( rInfo.bFolder && rInfo.pFolder ) || ( !rInfo.bFolder && rInfo.pStream ), "A valid child object is expected!" );
317 374 : if ( rInfo.bFolder )
318 : {
319 139 : OUString sTempName = rPath + rShortName + "/";
320 :
321 139 : if ( !rInfo.pFolder->GetMediaType().isEmpty() )
322 : {
323 3 : aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty;
324 3 : aPropSet[PKG_MNFST_MEDIATYPE].Value <<= rInfo.pFolder->GetMediaType();
325 3 : aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
326 3 : aPropSet[PKG_MNFST_VERSION].Value <<= rInfo.pFolder->GetVersion();
327 3 : aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
328 3 : aPropSet[PKG_MNFST_FULLPATH].Value <<= sTempName;
329 : }
330 : else
331 136 : aPropSet.realloc( 0 );
332 :
333 139 : rInfo.pFolder->saveContents( sTempName, rManList, rZipOut, rEncryptionKey, rRandomPool);
334 : }
335 : else
336 : {
337 : // if pTempEntry is necessary, it will be released and passed to the ZipOutputStream
338 : // and be deleted in the ZipOutputStream destructor
339 235 : auto_ptr < ZipEntry > pAutoTempEntry ( new ZipEntry );
340 235 : ZipEntry* pTempEntry = pAutoTempEntry.get();
341 :
342 : // In case the entry we are reading is also the entry we are writing, we will
343 : // store the ZipEntry data in pTempEntry
344 :
345 235 : ZipPackageFolder::copyZipEntry ( *pTempEntry, rInfo.pStream->aEntry );
346 235 : pTempEntry->sPath = rPath + rShortName;
347 235 : pTempEntry->nPathLen = (sal_Int16)( OUStringToOString( pTempEntry->sPath, RTL_TEXTENCODING_UTF8 ).getLength() );
348 :
349 235 : sal_Bool bToBeEncrypted = rInfo.pStream->IsToBeEncrypted() && (rEncryptionKey.getLength() || rInfo.pStream->HasOwnKey());
350 235 : sal_Bool bToBeCompressed = bToBeEncrypted ? sal_True : rInfo.pStream->IsToBeCompressed();
351 :
352 235 : aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty;
353 235 : aPropSet[PKG_MNFST_MEDIATYPE].Value <<= rInfo.pStream->GetMediaType( );
354 235 : aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
355 235 : aPropSet[PKG_MNFST_VERSION].Value <<= OUString(); // no version is stored for streams currently
356 235 : aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
357 235 : aPropSet[PKG_MNFST_FULLPATH].Value <<= pTempEntry->sPath;
358 :
359 :
360 : OSL_ENSURE( rInfo.pStream->GetStreamMode() != PACKAGE_STREAM_NOTSET, "Unacceptable ZipPackageStream mode!" );
361 :
362 235 : sal_Bool bRawStream = sal_False;
363 235 : if ( rInfo.pStream->GetStreamMode() == PACKAGE_STREAM_DETECT )
364 0 : bRawStream = rInfo.pStream->ParsePackageRawStream();
365 235 : else if ( rInfo.pStream->GetStreamMode() == PACKAGE_STREAM_RAW )
366 0 : bRawStream = sal_True;
367 :
368 235 : sal_Bool bTransportOwnEncrStreamAsRaw = sal_False;
369 : // During the storing the original size of the stream can be changed
370 : // TODO/LATER: get rid of this hack
371 235 : sal_Int64 nOwnStreamOrigSize = bRawStream ? rInfo.pStream->GetMagicalHackSize() : rInfo.pStream->getSize();
372 :
373 235 : sal_Bool bUseNonSeekableAccess = sal_False;
374 235 : uno::Reference < XInputStream > xStream;
375 235 : if ( !rInfo.pStream->IsPackageMember() && !bRawStream && !bToBeEncrypted && bToBeCompressed )
376 : {
377 : // the stream is not a package member, not a raw stream,
378 : // it should not be encrypted and it should be compressed,
379 : // in this case nonseekable access can be used
380 :
381 226 : xStream = rInfo.pStream->GetOwnStreamNoWrap();
382 226 : uno::Reference < XSeekable > xSeek ( xStream, uno::UNO_QUERY );
383 :
384 226 : bUseNonSeekableAccess = ( xStream.is() && !xSeek.is() );
385 : }
386 :
387 235 : if ( !bUseNonSeekableAccess )
388 : {
389 235 : xStream = rInfo.pStream->getRawData();
390 :
391 235 : if ( !xStream.is() )
392 : {
393 : OSL_FAIL( "ZipPackageStream didn't have a stream associated with it, skipping!" );
394 0 : bSuccess = false;
395 0 : return bSuccess;
396 : }
397 :
398 235 : uno::Reference < XSeekable > xSeek ( xStream, uno::UNO_QUERY );
399 : try
400 : {
401 235 : if ( xSeek.is() )
402 : {
403 : // If the stream is a raw one, then we should be positioned
404 : // at the beginning of the actual data
405 235 : if ( !bToBeCompressed || bRawStream )
406 : {
407 : // The raw stream can neither be encrypted nor connected
408 : OSL_ENSURE( !bRawStream || !(bToBeCompressed || bToBeEncrypted), "The stream is already encrypted!\n" );
409 5 : xSeek->seek ( bRawStream ? rInfo.pStream->GetMagicalHackPos() : 0 );
410 5 : ImplSetStoredData ( *pTempEntry, xStream );
411 :
412 : // TODO/LATER: Get rid of hacks related to switching of Flag Method and Size properties!
413 : }
414 230 : else if ( bToBeEncrypted )
415 : {
416 : // this is the correct original size
417 4 : pTempEntry->nSize = xSeek->getLength();
418 4 : nOwnStreamOrigSize = pTempEntry->nSize;
419 : }
420 :
421 235 : xSeek->seek ( 0 );
422 : }
423 : else
424 : {
425 : // Okay, we don't have an xSeekable stream. This is possibly bad.
426 : // check if it's one of our own streams, if it is then we know that
427 : // each time we ask for it we'll get a new stream that will be
428 : // at position zero...otherwise, assert and skip this stream...
429 0 : if ( rInfo.pStream->IsPackageMember() )
430 : {
431 : // if the password has been changed than the stream should not be package member any more
432 0 : if ( rInfo.pStream->IsEncrypted() && rInfo.pStream->IsToBeEncrypted() )
433 : {
434 : // Should be handled close to the raw stream handling
435 0 : bTransportOwnEncrStreamAsRaw = sal_True;
436 0 : pTempEntry->nMethod = STORED;
437 :
438 : // TODO/LATER: get rid of this situation
439 : // this size should be different from the one that will be stored in manifest.xml
440 : // it is used in storing algorithms and after storing the correct size will be set
441 0 : pTempEntry->nSize = pTempEntry->nCompressedSize;
442 : }
443 : }
444 : else
445 : {
446 0 : bSuccess = false;
447 0 : return bSuccess;
448 : }
449 : }
450 : }
451 0 : catch ( uno::Exception& )
452 : {
453 0 : bSuccess = false;
454 0 : return bSuccess;
455 : }
456 :
457 235 : if ( bToBeEncrypted || bRawStream || bTransportOwnEncrStreamAsRaw )
458 : {
459 4 : if ( bToBeEncrypted && !bTransportOwnEncrStreamAsRaw )
460 : {
461 4 : uno::Sequence < sal_Int8 > aSalt( 16 ), aVector( rInfo.pStream->GetBlockSize() );
462 4 : rtl_random_getBytes ( rRandomPool, aSalt.getArray(), 16 );
463 4 : rtl_random_getBytes ( rRandomPool, aVector.getArray(), aVector.getLength() );
464 4 : sal_Int32 nIterationCount = 1024;
465 :
466 4 : if ( !rInfo.pStream->HasOwnKey() )
467 4 : rInfo.pStream->setKey ( rEncryptionKey );
468 :
469 4 : rInfo.pStream->setInitialisationVector ( aVector );
470 4 : rInfo.pStream->setSalt ( aSalt );
471 4 : rInfo.pStream->setIterationCount ( nIterationCount );
472 : }
473 :
474 : // last property is digest, which is inserted later if we didn't have
475 : // a magic header
476 4 : aPropSet.realloc(PKG_SIZE_ENCR_MNFST);
477 :
478 4 : aPropSet[PKG_MNFST_INIVECTOR].Name = sInitialisationVectorProperty;
479 4 : aPropSet[PKG_MNFST_INIVECTOR].Value <<= rInfo.pStream->getInitialisationVector();
480 4 : aPropSet[PKG_MNFST_SALT].Name = sSaltProperty;
481 4 : aPropSet[PKG_MNFST_SALT].Value <<= rInfo.pStream->getSalt();
482 4 : aPropSet[PKG_MNFST_ITERATION].Name = sIterationCountProperty;
483 4 : aPropSet[PKG_MNFST_ITERATION].Value <<= rInfo.pStream->getIterationCount ();
484 :
485 : // Need to store the uncompressed size in the manifest
486 : OSL_ENSURE( nOwnStreamOrigSize >= 0, "The stream size was not correctly initialized!\n" );
487 4 : aPropSet[PKG_MNFST_UCOMPSIZE].Name = sSizeProperty;
488 4 : aPropSet[PKG_MNFST_UCOMPSIZE].Value <<= nOwnStreamOrigSize;
489 :
490 4 : if ( bRawStream || bTransportOwnEncrStreamAsRaw )
491 : {
492 0 : ::rtl::Reference< EncryptionData > xEncData = rInfo.pStream->GetEncryptionData();
493 0 : if ( !xEncData.is() )
494 0 : throw uno::RuntimeException();
495 :
496 0 : aPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
497 0 : aPropSet[PKG_MNFST_DIGEST].Value <<= rInfo.pStream->getDigest();
498 0 : aPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
499 0 : aPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
500 0 : aPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
501 0 : aPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID;
502 0 : aPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
503 0 : aPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg;
504 0 : aPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
505 0 : aPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
506 : }
507 235 : }
508 : }
509 :
510 : // If the entry is already stored in the zip file in the format we
511 : // want for this write...copy it raw
512 470 : if ( !bUseNonSeekableAccess
513 : && ( bRawStream || bTransportOwnEncrStreamAsRaw
514 235 : || ( rInfo.pStream->IsPackageMember() && !bToBeEncrypted
515 : && ( ( rInfo.pStream->aEntry.nMethod == DEFLATED && bToBeCompressed )
516 : || ( rInfo.pStream->aEntry.nMethod == STORED && !bToBeCompressed ) ) ) ) )
517 : {
518 : // If it's a PackageMember, then it's an unbuffered stream and we need
519 : // to get a new version of it as we can't seek backwards.
520 0 : if ( rInfo.pStream->IsPackageMember() )
521 : {
522 0 : xStream = rInfo.pStream->getRawData();
523 0 : if ( !xStream.is() )
524 : {
525 : // Make sure that we actually _got_ a new one !
526 0 : bSuccess = false;
527 0 : return bSuccess;
528 : }
529 : }
530 :
531 : try
532 : {
533 0 : if ( bRawStream )
534 0 : xStream->skipBytes( rInfo.pStream->GetMagicalHackPos() );
535 :
536 0 : rZipOut.putNextEntry ( *pTempEntry, rInfo.pStream, sal_False );
537 : // the entry is provided to the ZipOutputStream that will delete it
538 0 : pAutoTempEntry.release();
539 :
540 0 : uno::Sequence < sal_Int8 > aSeq ( n_ConstBufferSize );
541 : sal_Int32 nLength;
542 :
543 0 : do
544 : {
545 0 : nLength = xStream->readBytes( aSeq, n_ConstBufferSize );
546 0 : rZipOut.rawWrite(aSeq, 0, nLength);
547 : }
548 : while ( nLength == n_ConstBufferSize );
549 :
550 0 : rZipOut.rawCloseEntry();
551 : }
552 0 : catch ( ZipException& )
553 : {
554 0 : bSuccess = false;
555 : }
556 0 : catch ( IOException& )
557 : {
558 0 : bSuccess = false;
559 : }
560 : }
561 : else
562 : {
563 : // This stream is defenitly not a raw stream
564 :
565 : // If nonseekable access is used the stream should be at the beginning and
566 : // is useless after the storing. Thus if the storing fails the package should
567 : // be thrown away ( as actually it is done currently )!
568 : // To allow to reuse the package after the error, the optimization must be removed!
569 :
570 : // If it's a PackageMember, then our previous reference held a 'raw' stream
571 : // so we need to re-get it, unencrypted, uncompressed and positioned at the
572 : // beginning of the stream
573 235 : if ( rInfo.pStream->IsPackageMember() )
574 : {
575 0 : xStream = rInfo.pStream->getInputStream();
576 0 : if ( !xStream.is() )
577 : {
578 : // Make sure that we actually _got_ a new one !
579 0 : bSuccess = false;
580 0 : return bSuccess;
581 : }
582 : }
583 :
584 235 : if ( bToBeCompressed )
585 : {
586 230 : pTempEntry->nMethod = DEFLATED;
587 230 : pTempEntry->nCrc = -1;
588 230 : pTempEntry->nCompressedSize = pTempEntry->nSize = -1;
589 : }
590 :
591 : try
592 : {
593 235 : rZipOut.putNextEntry ( *pTempEntry, rInfo.pStream, bToBeEncrypted);
594 : // the entry is provided to the ZipOutputStream that will delete it
595 235 : pAutoTempEntry.release();
596 :
597 : sal_Int32 nLength;
598 235 : uno::Sequence < sal_Int8 > aSeq (n_ConstBufferSize);
599 239 : do
600 : {
601 239 : nLength = xStream->readBytes(aSeq, n_ConstBufferSize);
602 239 : rZipOut.write(aSeq, 0, nLength);
603 : }
604 : while ( nLength == n_ConstBufferSize );
605 :
606 235 : rZipOut.closeEntry();
607 : }
608 0 : catch ( ZipException& )
609 : {
610 0 : bSuccess = false;
611 : }
612 0 : catch ( IOException& )
613 : {
614 0 : bSuccess = false;
615 : }
616 :
617 235 : if ( bToBeEncrypted )
618 : {
619 4 : ::rtl::Reference< EncryptionData > xEncData = rInfo.pStream->GetEncryptionData();
620 4 : if ( !xEncData.is() )
621 0 : throw uno::RuntimeException();
622 :
623 4 : aPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
624 4 : aPropSet[PKG_MNFST_DIGEST].Value <<= rInfo.pStream->getDigest();
625 4 : aPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
626 4 : aPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
627 4 : aPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
628 4 : aPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID;
629 4 : aPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
630 4 : aPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg;
631 4 : aPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
632 4 : aPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
633 :
634 4 : rInfo.pStream->SetIsEncrypted ( sal_True );
635 : }
636 : }
637 :
638 235 : if( bSuccess )
639 : {
640 235 : if ( !rInfo.pStream->IsPackageMember() )
641 : {
642 235 : rInfo.pStream->CloseOwnStreamIfAny();
643 235 : rInfo.pStream->SetPackageMember ( sal_True );
644 : }
645 :
646 235 : if ( bRawStream )
647 : {
648 : // the raw stream was integrated and now behaves
649 : // as usual encrypted stream
650 0 : rInfo.pStream->SetToBeEncrypted( sal_True );
651 : }
652 :
653 : // Then copy it back afterwards...
654 235 : ZipPackageFolder::copyZipEntry ( rInfo.pStream->aEntry, *pTempEntry );
655 :
656 : // Remove hacky bit from entry flags
657 235 : if ( rInfo.pStream->aEntry.nFlag & ( 1 << 4 ) )
658 : {
659 4 : rInfo.pStream->aEntry.nFlag &= ~( 1 << 4 );
660 4 : rInfo.pStream->aEntry.nMethod = STORED;
661 : }
662 :
663 : // TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving )
664 235 : if ( rInfo.pStream->IsEncrypted() )
665 4 : rInfo.pStream->setSize( nOwnStreamOrigSize );
666 :
667 235 : rInfo.pStream->aEntry.nOffset *= -1;
668 235 : }
669 : }
670 :
671 : // folder can have a mediatype only in package format
672 576 : if ( aPropSet.getLength()
673 202 : && ( m_nFormat == embed::StorageFormats::PACKAGE || ( m_nFormat == embed::StorageFormats::OFOPXML && !rInfo.bFolder ) ) )
674 238 : rManList.push_back( aPropSet );
675 :
676 374 : return bSuccess;
677 : }
678 :
679 172 : void ZipPackageFolder::saveContents( OUString &rPath, std::vector < uno::Sequence < PropertyValue > > &rManList, ZipOutputStream & rZipOut, const uno::Sequence < sal_Int8 >& rEncryptionKey, rtlRandomPool &rRandomPool )
680 : throw( uno::RuntimeException )
681 : {
682 172 : bool bWritingFailed = false;
683 :
684 172 : if ( maContents.begin() == maContents.end() && !rPath.isEmpty() && m_nFormat != embed::StorageFormats::OFOPXML )
685 : {
686 : // it is an empty subfolder, use workaround to store it
687 24 : ZipEntry* pTempEntry = new ZipEntry();
688 24 : ZipPackageFolder::copyZipEntry ( *pTempEntry, aEntry );
689 24 : pTempEntry->nPathLen = (sal_Int16)( OUStringToOString( rPath, RTL_TEXTENCODING_UTF8 ).getLength() );
690 24 : pTempEntry->nExtraLen = -1;
691 24 : pTempEntry->sPath = rPath;
692 :
693 : try
694 : {
695 24 : rZipOut.putNextEntry( *pTempEntry, NULL, sal_False );
696 24 : rZipOut.rawCloseEntry();
697 : }
698 0 : catch ( ZipException& )
699 : {
700 0 : bWritingFailed = true;
701 : }
702 0 : catch ( IOException& )
703 : {
704 0 : bWritingFailed = true;
705 : }
706 : }
707 :
708 172 : bool bMimeTypeStreamStored = false;
709 172 : OUString aMimeTypeStreamName("mimetype");
710 172 : if ( m_nFormat == embed::StorageFormats::ZIP && rPath.isEmpty() )
711 : {
712 : // let the "mimtype" stream in root folder be stored as the first stream if it is zip format
713 0 : ContentHash::iterator aIter = maContents.find ( aMimeTypeStreamName );
714 0 : if ( aIter != maContents.end() && !(*aIter).second->bFolder )
715 : {
716 0 : bMimeTypeStreamStored = true;
717 0 : bWritingFailed = !saveChild( (*aIter).first, *(*aIter).second, rPath, rManList, rZipOut, rEncryptionKey, rRandomPool );
718 : }
719 : }
720 :
721 546 : for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end();
722 : aCI != aEnd;
723 : ++aCI)
724 : {
725 374 : const OUString &rShortName = (*aCI).first;
726 374 : const ContentInfo &rInfo = *(*aCI).second;
727 :
728 374 : if ( !bMimeTypeStreamStored || !rShortName.equals( aMimeTypeStreamName ) )
729 374 : bWritingFailed = !saveChild( rShortName, rInfo, rPath, rManList, rZipOut, rEncryptionKey, rRandomPool );
730 : }
731 :
732 172 : if( bWritingFailed )
733 0 : throw uno::RuntimeException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
734 172 : }
735 :
736 2885 : void ZipPackageFolder::releaseUpwardRef( void )
737 : {
738 : // Now it is possible that a package folder is disconnected from the package before removing of the folder.
739 : // Such a scenario is used in storage implementation. When a new version of a folder is provided the old
740 : // one is retrieved, removed from the package but preserved for the error handling.
741 : // In this scenario the referencing to the parent is not really useful, since it requires disposing.
742 :
743 : // Actually there is no need in having a reference to the parent, it even make things more complicated and
744 : // requires disposing mechanics. Using of a simple pointer seems to be easier solution and also a safe enough.
745 :
746 2885 : clearParent();
747 :
748 : #if 0
749 : for ( ContentHash::const_iterator aCI = maContents.begin();
750 : aCI!=maContents.end();
751 : aCI++)
752 : {
753 : ContentInfo &rInfo = * (*aCI).second;
754 : if ( rInfo.bFolder )// && ! rInfo.pFolder->HasReleased () )
755 : rInfo.pFolder->releaseUpwardRef();
756 : else //if ( !rInfo.bFolder && !rInfo.pStream->HasReleased() )
757 : rInfo.pStream->clearParent();
758 : }
759 : clearParent();
760 :
761 : OSL_ENSURE ( m_refCount == 1, "Ref-count is not 1!" );
762 : #endif
763 2885 : }
764 :
765 1428 : sal_Int64 SAL_CALL ZipPackageFolder::getSomething( const uno::Sequence< sal_Int8 >& aIdentifier )
766 : throw(uno::RuntimeException)
767 : {
768 1428 : sal_Int64 nMe = 0;
769 2856 : if ( aIdentifier.getLength() == 16 &&
770 1428 : 0 == memcmp(static_getImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) )
771 1428 : nMe = reinterpret_cast < sal_Int64 > ( this );
772 1428 : return nMe;
773 : }
774 762 : void SAL_CALL ZipPackageFolder::setPropertyValue( const OUString& aPropertyName, const uno::Any& aValue )
775 : throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, uno::RuntimeException)
776 : {
777 762 : if ( aPropertyName == "MediaType" )
778 : {
779 : // TODO/LATER: activate when zip ucp is ready
780 : // if ( m_nFormat != embed::StorageFormats::PACKAGE )
781 : // throw UnknownPropertyException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
782 :
783 381 : aValue >>= sMediaType;
784 : }
785 381 : else if ( aPropertyName == "Version" )
786 381 : aValue >>= m_sVersion;
787 0 : else if ( aPropertyName == "Size" )
788 0 : aValue >>= aEntry.nSize;
789 : else
790 0 : throw UnknownPropertyException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
791 762 : }
792 8458 : uno::Any SAL_CALL ZipPackageFolder::getPropertyValue( const OUString& PropertyName )
793 : throw(UnknownPropertyException, WrappedTargetException, uno::RuntimeException)
794 : {
795 8458 : if ( PropertyName == "MediaType" )
796 : {
797 : // TODO/LATER: activate when zip ucp is ready
798 : // if ( m_nFormat != embed::StorageFormats::PACKAGE )
799 : // throw UnknownPropertyException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
800 :
801 4229 : return uno::makeAny ( sMediaType );
802 : }
803 4229 : else if ( PropertyName == "Version" )
804 4229 : return uno::makeAny( m_sVersion );
805 0 : else if ( PropertyName == "Size" )
806 0 : return uno::makeAny ( aEntry.nSize );
807 : else
808 0 : throw UnknownPropertyException(OSL_LOG_PREFIX, uno::Reference< uno::XInterface >() );
809 : }
810 :
811 8712 : void ZipPackageFolder::doInsertByName ( ZipPackageEntry *pEntry, sal_Bool bSetParent )
812 : throw(IllegalArgumentException, ElementExistException, WrappedTargetException, uno::RuntimeException)
813 : {
814 : try
815 : {
816 8712 : if ( pEntry->IsFolder() )
817 2962 : maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageFolder *> ( pEntry ) );
818 : else
819 5750 : maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageStream *> ( pEntry ) );
820 : }
821 0 : catch(const uno::Exception& rEx)
822 : {
823 : (void)rEx;
824 0 : throw;
825 : }
826 8712 : if ( bSetParent )
827 1040 : pEntry->setParent ( *this );
828 8712 : }
829 0 : OUString ZipPackageFolder::getImplementationName()
830 : throw (uno::RuntimeException)
831 : {
832 0 : return OUString("ZipPackageFolder");
833 : }
834 :
835 0 : uno::Sequence< OUString > ZipPackageFolder::getSupportedServiceNames()
836 : throw (uno::RuntimeException)
837 : {
838 0 : uno::Sequence< OUString > aNames(1);
839 0 : aNames[0] = "com.sun.star.packages.PackageFolder";
840 0 : return aNames;
841 : }
842 0 : sal_Bool SAL_CALL ZipPackageFolder::supportsService( OUString const & rServiceName )
843 : throw (uno::RuntimeException)
844 : {
845 0 : return rServiceName == getSupportedServiceNames()[0];
846 : }
847 :
848 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|