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