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