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