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