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