/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER( update_precomp.py ): autogen include statement, do not remove #include "precompiled_package.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "com/sun/star/io/XAsyncOutputMonitor.hpp" #include #include #include #include #include #include #include #include #include using namespace rtl; using namespace std; using namespace osl; using namespace cppu; using namespace ucbhelper; using namespace com::sun::star; using namespace com::sun::star::io; using namespace com::sun::star::uno; using namespace com::sun::star::ucb; using namespace com::sun::star::util; using namespace com::sun::star::lang; using namespace com::sun::star::task; using namespace com::sun::star::beans; using namespace com::sun::star::packages; using namespace com::sun::star::container; using namespace com::sun::star::packages::zip; using namespace com::sun::star::packages::manifest; using namespace com::sun::star::packages::zip::ZipConstants; #define LOGFILE_AUTHOR "mg115289" namespace { sal_Bool isLocalFile_Impl( ::rtl::OUString aURL ) { ::rtl::OUString aSystemPath; ContentBroker* pBroker = ContentBroker::get(); if ( !pBroker ) { ::rtl::OUString aRet; if ( FileBase::getSystemPathFromFileURL( aURL, aRet ) == FileBase::E_None ) aSystemPath = aRet; } else { uno::Reference< XContentProviderManager > xManager = pBroker->getContentProviderManagerInterface(); try { aSystemPath = getSystemPathFromFileURL( xManager, aURL ); } catch ( Exception& ) { } } return ( aSystemPath.getLength() != 0 ); } } //=========================================================================== class ActiveDataStreamer : public ::cppu::WeakImplHelper1< XActiveDataStreamer > { uno::Reference< XStream > mStream; public: virtual uno::Reference< XStream > SAL_CALL getStream() throw( RuntimeException ) { return mStream; } virtual void SAL_CALL setStream( const uno::Reference< XStream >& stream ) throw( RuntimeException ) { mStream = stream; } }; class DummyInputStream : public ::cppu::WeakImplHelper1< XInputStream > { virtual sal_Int32 SAL_CALL readBytes( uno::Sequence< sal_Int8 >&, sal_Int32 ) throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException ) { return 0; } virtual sal_Int32 SAL_CALL readSomeBytes( uno::Sequence< sal_Int8 >&, sal_Int32 ) throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException ) { return 0; } virtual void SAL_CALL skipBytes( sal_Int32 ) throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException ) {} virtual sal_Int32 SAL_CALL available() throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException ) { return 0; } virtual void SAL_CALL closeInput() throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException ) {} }; //=========================================================================== ZipPackage::ZipPackage ( const uno::Reference < XMultiServiceFactory > &xNewFactory ) : m_aMutexHolder( new SotMutexHolder ) , m_nStartKeyGenerationID( xml::crypto::DigestID::SHA1 ) , m_nChecksumDigestID( xml::crypto::DigestID::SHA1_1K ) , m_nCommonEncryptionID( xml::crypto::CipherID::BLOWFISH_CFB_8 ) , m_bHasEncryptedEntries ( sal_False ) , m_bHasNonEncryptedEntries ( sal_False ) , m_bInconsistent ( sal_False ) , m_bForceRecovery ( sal_False ) , m_bMediaTypeFallbackUsed ( sal_False ) , m_nFormat( embed::StorageFormats::PACKAGE ) // package is the default format , m_bAllowRemoveOnInsert( sal_True ) , m_eMode ( e_IMode_None ) , m_xFactory( xNewFactory ) , m_pRootFolder( NULL ) , m_pZipFile( NULL ) { m_xRootFolder = m_pRootFolder = new ZipPackageFolder( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert ); } ZipPackage::~ZipPackage( void ) { delete m_pZipFile; // All folders and streams contain pointers to their parents, when a parent diappeares // it should disconnect all the children from itself during destruction automatically. // So there is no need in explicit m_pRootFolder->releaseUpwardRef() call here any more // since m_pRootFolder has no parent and cleaning of it's children will be done automatically // during m_pRootFolder dying by refcount. } //-------------------------------------------------------- void ZipPackage::parseManifest() { if ( m_nFormat == embed::StorageFormats::PACKAGE ) { sal_Bool bManifestParsed = sal_False; bool bDifferentStartKeyAlgorithm = false; const OUString sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) ); if ( m_xRootFolder->hasByName( sMeta ) ) { const OUString sManifest ( RTL_CONSTASCII_USTRINGPARAM( "manifest.xml" ) ); try { uno::Reference< XUnoTunnel > xTunnel; Any aAny = m_xRootFolder->getByName( sMeta ); aAny >>= xTunnel; uno::Reference< XNameContainer > xMetaInfFolder( xTunnel, UNO_QUERY ); if ( xMetaInfFolder.is() && xMetaInfFolder->hasByName( sManifest ) ) { aAny = xMetaInfFolder->getByName( sManifest ); aAny >>= xTunnel; uno::Reference < XActiveDataSink > xSink ( xTunnel, UNO_QUERY ); if ( xSink.is() ) { OUString sManifestReader ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestReader" ) ); uno::Reference < XManifestReader > xReader ( m_xFactory->createInstance( sManifestReader ), UNO_QUERY ); if ( xReader.is() ) { const OUString sPropFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) ); const OUString sPropVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) ); const OUString sPropMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) ); const OUString sPropInitialisationVector ( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) ); const OUString sPropSalt ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) ); const OUString sPropIterationCount ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) ); const OUString sPropSize ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) ); const OUString sPropDigest ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) ); const OUString sPropDerivedKeySize ( RTL_CONSTASCII_USTRINGPARAM ( "DerivedKeySize" ) ); const OUString sPropDigestAlgorithm ( RTL_CONSTASCII_USTRINGPARAM ( "DigestAlgorithm" ) ); const OUString sPropEncryptionAlgorithm ( RTL_CONSTASCII_USTRINGPARAM ( "EncryptionAlgorithm" ) ); const OUString sPropStartKeyAlgorithm ( RTL_CONSTASCII_USTRINGPARAM ( "StartKeyAlgorithm" ) ); uno::Sequence < uno::Sequence < PropertyValue > > aManifestSequence = xReader->readManifestSequence ( xSink->getInputStream() ); sal_Int32 nLength = aManifestSequence.getLength(); const uno::Sequence < PropertyValue > *pSequence = aManifestSequence.getConstArray(); ZipPackageStream *pStream = NULL; ZipPackageFolder *pFolder = NULL; for ( sal_Int32 i = 0; i < nLength ; i++, pSequence++ ) { OUString sPath, sMediaType, sVersion; const PropertyValue *pValue = pSequence->getConstArray(); const Any *pSalt = NULL, *pVector = NULL, *pCount = NULL, *pSize = NULL, *pDigest = NULL, *pDigestAlg = NULL, *pEncryptionAlg = NULL, *pStartKeyAlg = NULL, *pDerivedKeySize = NULL; for ( sal_Int32 j = 0, nNum = pSequence->getLength(); j < nNum; j++ ) { if ( pValue[j].Name.equals( sPropFullPath ) ) pValue[j].Value >>= sPath; else if ( pValue[j].Name.equals( sPropVersion ) ) pValue[j].Value >>= sVersion; else if ( pValue[j].Name.equals( sPropMediaType ) ) pValue[j].Value >>= sMediaType; else if ( pValue[j].Name.equals( sPropSalt ) ) pSalt = &( pValue[j].Value ); else if ( pValue[j].Name.equals( sPropInitialisationVector ) ) pVector = &( pValue[j].Value ); else if ( pValue[j].Name.equals( sPropIterationCount ) ) pCount = &( pValue[j].Value ); else if ( pValue[j].Name.equals( sPropSize ) ) pSize = &( pValue[j].Value ); else if ( pValue[j].Name.equals( sPropDigest ) ) pDigest = &( pValue[j].Value ); else if ( pValue[j].Name.equals( sPropDigestAlgorithm ) ) pDigestAlg = &( pValue[j].Value ); else if ( pValue[j].Name.equals( sPropEncryptionAlgorithm ) ) pEncryptionAlg = &( pValue[j].Value ); else if ( pValue[j].Name.equals( sPropStartKeyAlgorithm ) ) pStartKeyAlg = &( pValue[j].Value ); else if ( pValue[j].Name.equals( sPropDerivedKeySize ) ) pDerivedKeySize = &( pValue[j].Value ); } if ( sPath.getLength() && hasByHierarchicalName ( sPath ) ) { aAny = getByHierarchicalName( sPath ); uno::Reference < XUnoTunnel > xUnoTunnel; aAny >>= xUnoTunnel; sal_Int64 nTest=0; if ( (nTest = xUnoTunnel->getSomething( ZipPackageFolder::static_getImplementationId() )) != 0 ) { pFolder = reinterpret_cast < ZipPackageFolder* > ( nTest ); pFolder->SetMediaType ( sMediaType ); pFolder->SetVersion ( sVersion ); } else { pStream = reinterpret_cast < ZipPackageStream* > ( xUnoTunnel->getSomething( ZipPackageStream::static_getImplementationId() )); pStream->SetMediaType ( sMediaType ); pStream->SetFromManifest( sal_True ); if ( pSalt && pVector && pCount && pSize && pDigest && pDigestAlg && pEncryptionAlg ) { uno::Sequence < sal_Int8 > aSequence; sal_Int32 nCount = 0, nSize = 0, nDigestAlg = 0, nEncryptionAlg = 0, nDerivedKeySize = 16, nStartKeyAlg = xml::crypto::DigestID::SHA1; pStream->SetToBeEncrypted ( sal_True ); *pSalt >>= aSequence; pStream->setSalt ( aSequence ); *pVector >>= aSequence; pStream->setInitialisationVector ( aSequence ); *pCount >>= nCount; pStream->setIterationCount ( nCount ); *pSize >>= nSize; pStream->setSize ( nSize ); *pDigest >>= aSequence; pStream->setDigest ( aSequence ); *pDigestAlg >>= nDigestAlg; pStream->SetImportedChecksumAlgorithm( nDigestAlg ); *pEncryptionAlg >>= nEncryptionAlg; pStream->SetImportedEncryptionAlgorithm( nEncryptionAlg ); if ( pDerivedKeySize ) *pDerivedKeySize >>= nDerivedKeySize; pStream->SetImportedDerivedKeySize( nDerivedKeySize ); if ( pStartKeyAlg ) *pStartKeyAlg >>= nStartKeyAlg; pStream->SetImportedStartKeyAlgorithm( nStartKeyAlg ); pStream->SetToBeCompressed ( sal_True ); pStream->SetToBeEncrypted ( sal_True ); pStream->SetIsEncrypted ( sal_True ); if ( !m_bHasEncryptedEntries && pStream->getName().equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "content.xml" ) ) ) ) { m_bHasEncryptedEntries = sal_True; m_nStartKeyGenerationID = nStartKeyAlg; m_nChecksumDigestID = nDigestAlg; m_nCommonEncryptionID = nEncryptionAlg; } } else m_bHasNonEncryptedEntries = sal_True; } } } bManifestParsed = sal_True; } else throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No manifes parser!" ) ), uno::Reference< uno::XInterface >() ); } // now hide the manifest.xml file from user xMetaInfFolder->removeByName( sManifest ); } } catch( Exception& ) { if ( !m_bForceRecovery ) throw; } } if ( !bManifestParsed && !m_bForceRecovery ) throw ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Could not parse manifest.xml\n" ) ), uno::Reference< uno::XInterface >() ); const OUString sMimetype ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) ); if ( m_xRootFolder->hasByName( sMimetype ) ) { // get mediatype from the "mimetype" stream ::rtl::OUString aPackageMediatype; uno::Reference< lang::XUnoTunnel > xMimeTypeTunnel; m_xRootFolder->getByName( sMimetype ) >>= xMimeTypeTunnel; uno::Reference < io::XActiveDataSink > xMimeSink( xMimeTypeTunnel, UNO_QUERY ); if ( xMimeSink.is() ) { uno::Reference< io::XInputStream > xMimeInStream = xMimeSink->getInputStream(); if ( xMimeInStream.is() ) { // Mediatypes longer than 1024 symbols should not appear here uno::Sequence< sal_Int8 > aData( 1024 ); sal_Int32 nRead = xMimeInStream->readBytes( aData, 1024 ); if ( nRead > aData.getLength() ) nRead = aData.getLength(); if ( nRead ) aPackageMediatype = ::rtl::OUString( ( sal_Char* )aData.getConstArray(), nRead, RTL_TEXTENCODING_ASCII_US ); } } if ( !bManifestParsed ) { // the manifest.xml could not be successfully parsed, this is an inconsistent package if ( aPackageMediatype.compareToAscii( RTL_CONSTASCII_STRINGPARAM( "application/vnd." ) ) == 0 ) { // accept only types that look similar to own mediatypes m_pRootFolder->SetMediaType( aPackageMediatype ); m_bMediaTypeFallbackUsed = sal_True; } } else if ( !m_bForceRecovery ) { // the mimetype stream should contain the information from manifest.xml if ( !m_pRootFolder->GetMediaType().equals( aPackageMediatype ) ) throw ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "mimetype conflicts with manifest.xml\n" ) ), uno::Reference< uno::XInterface >() ); } m_xRootFolder->removeByName( sMimetype ); } m_bInconsistent = m_pRootFolder->LookForUnexpectedODF12Streams( ::rtl::OUString() ); sal_Bool bODF12AndNewer = ( m_pRootFolder->GetVersion().compareTo( ODFVER_012_TEXT ) >= 0 ); if ( !m_bForceRecovery && bODF12AndNewer ) { if ( m_bInconsistent ) { // this is an ODF1.2 document that contains streams not referred in the manifest.xml; // in case of ODF1.2 documents without version in manifest.xml the property IsInconsistent // should be checked later throw ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "there are streams not referred in manifest.xml\n" ) ), uno::Reference< uno::XInterface >() ); } else if ( bDifferentStartKeyAlgorithm ) { // all the streams should be encrypted with the same StartKey in ODF1.2 // TODO/LATER: in future the exception should be thrown OSL_ENSURE( false, "ODF1.2 contains different StartKey Algorithms" ); // throw ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "More than one Start Key Generation algorithm is specified!" ) ), uno::Reference< uno::XInterface >() ); } } // in case it is a correct ODF1.2 document, the version must be set // and the META-INF folder is reserved for package format if ( bODF12AndNewer ) m_xRootFolder->removeByName( sMeta ); } } //-------------------------------------------------------- void ZipPackage::parseContentType() { if ( m_nFormat == embed::StorageFormats::OFOPXML ) { const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) ); try { // the content type must exist in OFOPXML format! if ( !m_xRootFolder->hasByName( aContentTypes ) ) throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong format!" ) ), uno::Reference< uno::XInterface >() ); uno::Reference< lang::XUnoTunnel > xTunnel; uno::Any aAny = m_xRootFolder->getByName( aContentTypes ); aAny >>= xTunnel; uno::Reference < io::XActiveDataSink > xSink( xTunnel, UNO_QUERY ); if ( xSink.is() ) { uno::Reference< io::XInputStream > xInStream = xSink->getInputStream(); if ( xInStream.is() ) { sal_Int32 nInd = 0; // here aContentTypeInfo[0] - Defaults, and aContentTypeInfo[1] - Overrides uno::Sequence< uno::Sequence< beans::StringPair > > aContentTypeInfo = ::comphelper::OFOPXMLHelper::ReadContentTypeSequence( xInStream, m_xFactory ); if ( aContentTypeInfo.getLength() != 2 ) throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // set the implicit types fist for ( nInd = 0; nInd < aContentTypeInfo[0].getLength(); nInd++ ) m_pRootFolder->setChildStreamsTypeByExtension( aContentTypeInfo[0][nInd] ); // now set the explicit types for ( nInd = 0; nInd < aContentTypeInfo[1].getLength(); nInd++ ) { ::rtl::OUString aPath; if ( aContentTypeInfo[1][nInd].First.toChar() == ( sal_Unicode )'/' ) aPath = aContentTypeInfo[1][nInd].First.copy( 1 ); else aPath = aContentTypeInfo[1][nInd].First; if ( aPath.getLength() && hasByHierarchicalName( aPath ) ) { uno::Any aIterAny = getByHierarchicalName( aPath ); uno::Reference < lang::XUnoTunnel > xIterTunnel; aIterAny >>= xIterTunnel; sal_Int64 nTest = xIterTunnel->getSomething( ZipPackageStream::static_getImplementationId() ); if ( nTest != 0 ) { // this is a package stream, in OFOPXML format only streams can have mediatype ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream* > ( nTest ); pStream->SetMediaType( aContentTypeInfo[1][nInd].Second ); } } } } } m_xRootFolder->removeByName( aContentTypes ); } catch( uno::Exception& ) { if ( !m_bForceRecovery ) throw; } } } //-------------------------------------------------------- void ZipPackage::getZipFileContents() { auto_ptr < ZipEnumeration > pEnum ( m_pZipFile->entries() ); ZipPackageStream *pPkgStream; ZipPackageFolder *pPkgFolder, *pCurrent; OUString sTemp, sDirName; sal_Int32 nOldIndex, nIndex, nStreamIndex; FolderHash::iterator aIter; while ( pEnum->hasMoreElements() ) { nIndex = nOldIndex = 0; pCurrent = m_pRootFolder; const ZipEntry & rEntry = *pEnum->nextElement(); OUString rName = rEntry.sPath; if ( m_bForceRecovery ) { // the PKZIP Application note version 6.2 does not allows to use '\' as separator // unfortunately it is used by some implementations, so we have to support it in recovery mode rName = rName.replace( '\\', '/' ); } nStreamIndex = rName.lastIndexOf ( '/' ); if ( nStreamIndex != -1 ) { sDirName = rName.copy ( 0, nStreamIndex ); aIter = m_aRecent.find ( sDirName ); if ( aIter != m_aRecent.end() ) pCurrent = ( *aIter ).second; } if ( pCurrent == m_pRootFolder ) { while ( ( nIndex = rName.indexOf( '/', nOldIndex ) ) != -1 ) { sTemp = rName.copy ( nOldIndex, nIndex - nOldIndex ); if ( nIndex == nOldIndex ) break; if ( !pCurrent->hasByName( sTemp ) ) { pPkgFolder = new ZipPackageFolder( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert ); pPkgFolder->setName( sTemp ); pPkgFolder->doSetParent( pCurrent, sal_True ); pCurrent = pPkgFolder; } else pCurrent = pCurrent->doGetByName( sTemp ).pFolder; nOldIndex = nIndex+1; } if ( nStreamIndex != -1 && sDirName.getLength() ) m_aRecent [ sDirName ] = pCurrent; } if ( rName.getLength() -1 != nStreamIndex ) { nStreamIndex++; sTemp = rName.copy( nStreamIndex, rName.getLength() - nStreamIndex ); pPkgStream = new ZipPackageStream( *this, m_xFactory, m_bAllowRemoveOnInsert ); pPkgStream->SetPackageMember( sal_True ); pPkgStream->setZipEntryOnLoading( rEntry ); pPkgStream->setName( sTemp ); pPkgStream->doSetParent( pCurrent, sal_True ); } } if ( m_nFormat == embed::StorageFormats::PACKAGE ) parseManifest(); else if ( m_nFormat == embed::StorageFormats::OFOPXML ) parseContentType(); } //-------------------------------------------------------- void SAL_CALL ZipPackage::initialize( const uno::Sequence< Any >& aArguments ) throw( Exception, RuntimeException ) { RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::initialize" ); sal_Bool bBadZipFile = sal_False, bHaveZipFile = sal_True; uno::Reference< XProgressHandler > xProgressHandler; beans::NamedValue aNamedValue; if ( aArguments.getLength() ) { for( int ind = 0; ind < aArguments.getLength(); ind++ ) { OUString aParamUrl; if ( ( aArguments[ind] >>= aParamUrl )) { m_eMode = e_IMode_URL; try { sal_Int32 nParam = aParamUrl.indexOf( '?' ); if ( nParam >= 0 ) { m_aURL = aParamUrl.copy( 0, nParam ); OUString aParam = aParamUrl.copy( nParam + 1 ); sal_Int32 nIndex = 0; do { ::rtl::OUString aCommand = aParam.getToken( 0, '&', nIndex ); if ( aCommand.equals( OUString::createFromAscii( "repairpackage" ) ) ) { m_bForceRecovery = sal_True; break; } else if ( aCommand.equals( OUString::createFromAscii( "purezip" ) ) ) { m_nFormat = embed::StorageFormats::ZIP; m_pRootFolder->setPackageFormat_Impl( m_nFormat ); break; } else if ( aCommand.equals( OUString::createFromAscii( "ofopxml" ) ) ) { m_nFormat = embed::StorageFormats::OFOPXML; m_pRootFolder->setPackageFormat_Impl( m_nFormat ); break; } } while ( nIndex >= 0 ); } else m_aURL = aParamUrl; Content aContent ( m_aURL, uno::Reference < XCommandEnvironment >() ); Any aAny = aContent.getPropertyValue( OUString::createFromAscii( "Size" ) ); sal_uInt64 aSize = 0; // kind of optimisation: treat empty files as nonexistent files // and write to such files directly. Note that "Size" property is optional. bool bHasSizeProperty = aAny >>= aSize; if( !bHasSizeProperty || ( bHasSizeProperty && aSize ) ) { uno::Reference < XActiveDataSink > xSink = new ZipPackageSink; if ( aContent.openStream ( xSink ) ) m_xContentStream = xSink->getInputStream(); } else bHaveZipFile = sal_False; } catch ( com::sun::star::uno::Exception& ) { // Exception derived from uno::Exception thrown. This probably // means the file doesn't exist...we'll create it at // commitChanges time bHaveZipFile = sal_False; } } else if ( ( aArguments[ind] >>= m_xStream ) ) { // a writable stream can implement both XStream & XInputStream m_eMode = e_IMode_XStream; m_xContentStream = m_xStream->getInputStream(); } else if ( ( aArguments[ind] >>= m_xContentStream ) ) { m_eMode = e_IMode_XInputStream; } else if ( ( aArguments[ind] >>= aNamedValue ) ) { if ( aNamedValue.Name.equalsAscii( "RepairPackage" ) ) aNamedValue.Value >>= m_bForceRecovery; else if ( aNamedValue.Name.equalsAscii( "PackageFormat" ) ) { // setting this argument to true means Package format // setting it to false means plain Zip format sal_Bool bPackFormat = sal_True; aNamedValue.Value >>= bPackFormat; if ( !bPackFormat ) m_nFormat = embed::StorageFormats::ZIP; m_pRootFolder->setPackageFormat_Impl( m_nFormat ); } else if ( aNamedValue.Name.equalsAscii( "StorageFormat" ) ) { ::rtl::OUString aFormatName; sal_Int32 nFormatID = 0; if ( aNamedValue.Value >>= aFormatName ) { if ( aFormatName.equals( PACKAGE_STORAGE_FORMAT_STRING ) ) m_nFormat = embed::StorageFormats::PACKAGE; else if ( aFormatName.equals( ZIP_STORAGE_FORMAT_STRING ) ) m_nFormat = embed::StorageFormats::ZIP; else if ( aFormatName.equals( OFOPXML_STORAGE_FORMAT_STRING ) ) m_nFormat = embed::StorageFormats::OFOPXML; else throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); } else if ( aNamedValue.Value >>= nFormatID ) { if ( nFormatID != embed::StorageFormats::PACKAGE && nFormatID != embed::StorageFormats::ZIP && nFormatID != embed::StorageFormats::OFOPXML ) throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); m_nFormat = nFormatID; } else throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); m_pRootFolder->setPackageFormat_Impl( m_nFormat ); } else if ( aNamedValue.Name.equalsAscii( "AllowRemoveOnInsert" ) ) { aNamedValue.Value >>= m_bAllowRemoveOnInsert; m_pRootFolder->setRemoveOnInsertMode_Impl( m_bAllowRemoveOnInsert ); } // for now the progress handler is not used, probably it will never be // if ( aNamedValue.Name.equalsAscii( "ProgressHandler" ) } else { // The URL is not acceptable throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad arguments." ) ), static_cast < ::cppu::OWeakObject * > ( this ) ); } } try { if ( m_xContentStream.is() ) { // the stream must be seekable, if it is not it will be wrapped m_xContentStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( m_xContentStream, m_xFactory ); m_xContentSeek = uno::Reference < XSeekable > ( m_xContentStream, UNO_QUERY ); if ( ! m_xContentSeek.is() ) throw com::sun::star::uno::Exception ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "The package component _requires_ an XSeekable interface!" ) ), static_cast < ::cppu::OWeakObject * > ( this ) ); if ( !m_xContentSeek->getLength() ) bHaveZipFile = sal_False; } else bHaveZipFile = sal_False; } catch ( com::sun::star::uno::Exception& ) { // Exception derived from uno::Exception thrown. This probably // means the file doesn't exist...we'll create it at // commitChanges time bHaveZipFile = sal_False; } if ( bHaveZipFile ) { try { m_pZipFile = new ZipFile ( m_xContentStream, m_xFactory, sal_True, m_bForceRecovery, xProgressHandler ); getZipFileContents(); } catch ( IOException & ) { bBadZipFile = sal_True; } catch ( ZipException & ) { bBadZipFile = sal_True; } catch ( Exception & ) { if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; } throw; } if ( bBadZipFile ) { // clean up the memory, and tell the UCB about the error if( m_pZipFile ) { delete m_pZipFile; m_pZipFile = NULL; } throw com::sun::star::packages::zip::ZipIOException ( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Bad Zip File." ) ), static_cast < ::cppu::OWeakObject * > ( this ) ); } } } RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::initialize" ); } //-------------------------------------------------------- Any SAL_CALL ZipPackage::getByHierarchicalName( const OUString& aName ) throw( NoSuchElementException, RuntimeException ) { OUString sTemp, sDirName; sal_Int32 nOldIndex, nIndex, nStreamIndex; FolderHash::iterator aIter; if ( ( nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' ) return makeAny ( uno::Reference < XUnoTunnel > ( m_pRootFolder ) ); else { nStreamIndex = aName.lastIndexOf ( '/' ); bool bFolder = nStreamIndex == nIndex-1; if ( nStreamIndex != -1 ) { sDirName = aName.copy ( 0, nStreamIndex ); aIter = m_aRecent.find ( sDirName ); if ( aIter != m_aRecent.end() ) { if ( bFolder ) { sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex ); sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 ); if ( sTemp == ( *aIter ).second->getName() ) return makeAny ( uno::Reference < XUnoTunnel > ( ( *aIter ).second ) ); else m_aRecent.erase ( aIter ); } else { sTemp = aName.copy ( nStreamIndex + 1 ); if ( ( *aIter ).second->hasByName( sTemp ) ) return ( *aIter ).second->getByName( sTemp ); else m_aRecent.erase( aIter ); } } } else { if ( m_pRootFolder->hasByName ( aName ) ) return m_pRootFolder->getByName ( aName ); } nOldIndex = 0; ZipPackageFolder * pCurrent = m_pRootFolder; ZipPackageFolder * pPrevious = NULL; while ( ( nIndex = aName.indexOf( '/', nOldIndex )) != -1 ) { sTemp = aName.copy ( nOldIndex, nIndex - nOldIndex ); if ( nIndex == nOldIndex ) break; if ( pCurrent->hasByName( sTemp ) ) { pPrevious = pCurrent; pCurrent = pCurrent->doGetByName( sTemp ).pFolder; } else throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); nOldIndex = nIndex+1; } if ( bFolder ) { if ( nStreamIndex != -1 ) m_aRecent[sDirName] = pPrevious; return makeAny ( uno::Reference < XUnoTunnel > ( pCurrent ) ); } else { sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex ); if ( pCurrent->hasByName ( sTemp ) ) { if ( nStreamIndex != -1 ) m_aRecent[sDirName] = pCurrent; return pCurrent->getByName( sTemp ); } else throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); } } } //-------------------------------------------------------- sal_Bool SAL_CALL ZipPackage::hasByHierarchicalName( const OUString& aName ) throw( RuntimeException ) { OUString sTemp, sDirName; sal_Int32 nOldIndex, nIndex, nStreamIndex; FolderHash::iterator aIter; if ( ( nIndex = aName.getLength() ) == 1 && *aName.getStr() == '/' ) return sal_True; else { nStreamIndex = aName.lastIndexOf ( '/' ); bool bFolder = nStreamIndex == nIndex-1; if ( nStreamIndex != -1 ) { sDirName = aName.copy ( 0, nStreamIndex ); aIter = m_aRecent.find ( sDirName ); if ( aIter != m_aRecent.end() ) { if ( bFolder ) { sal_Int32 nDirIndex = aName.lastIndexOf ( '/', nStreamIndex ); sTemp = aName.copy ( nDirIndex == -1 ? 0 : nDirIndex+1, nStreamIndex-nDirIndex-1 ); if ( sTemp == ( *aIter ).second->getName() ) return sal_True; else m_aRecent.erase ( aIter ); } else { sTemp = aName.copy ( nStreamIndex + 1 ); if ( ( *aIter ).second->hasByName( sTemp ) ) return sal_True; else m_aRecent.erase( aIter ); } } } else { if ( m_pRootFolder->hasByName ( aName ) ) return sal_True; } ZipPackageFolder * pCurrent = m_pRootFolder; ZipPackageFolder * pPrevious = NULL; nOldIndex = 0; while ( ( nIndex = aName.indexOf( '/', nOldIndex )) != -1 ) { sTemp = aName.copy ( nOldIndex, nIndex - nOldIndex ); if ( nIndex == nOldIndex ) break; if ( pCurrent->hasByName( sTemp ) ) { pPrevious = pCurrent; pCurrent = pCurrent->doGetByName( sTemp ).pFolder; } else return sal_False; nOldIndex = nIndex+1; } if ( bFolder ) { m_aRecent[sDirName] = pPrevious; return sal_True; } else { sTemp = aName.copy( nOldIndex, aName.getLength() - nOldIndex ); if ( pCurrent->hasByName( sTemp ) ) { m_aRecent[sDirName] = pCurrent; return sal_True; } } return sal_False; } } //-------------------------------------------------------- uno::Reference< XInterface > SAL_CALL ZipPackage::createInstance() throw( Exception, RuntimeException ) { uno::Reference < XInterface > xRef = *( new ZipPackageStream ( *this, m_xFactory, m_bAllowRemoveOnInsert ) ); return xRef; } //-------------------------------------------------------- uno::Reference< XInterface > SAL_CALL ZipPackage::createInstanceWithArguments( const uno::Sequence< Any >& aArguments ) throw( Exception, RuntimeException ) { sal_Bool bArg = sal_False; uno::Reference < XInterface > xRef; if ( aArguments.getLength() ) aArguments[0] >>= bArg; if ( bArg ) xRef = *new ZipPackageFolder ( m_xFactory, m_nFormat, m_bAllowRemoveOnInsert ); else xRef = *new ZipPackageStream ( *this, m_xFactory, m_bAllowRemoveOnInsert ); return xRef; } //-------------------------------------------------------- void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut ) { const OUString sMime ( RTL_CONSTASCII_USTRINGPARAM ( "mimetype" ) ); if ( m_xRootFolder->hasByName( sMime ) ) m_xRootFolder->removeByName( sMime ); ZipEntry * pEntry = new ZipEntry; sal_Int32 nBufferLength = m_pRootFolder->GetMediaType().getLength(); OString sMediaType = OUStringToOString( m_pRootFolder->GetMediaType(), RTL_TEXTENCODING_ASCII_US ); uno::Sequence< sal_Int8 > aType( ( sal_Int8* )sMediaType.getStr(), nBufferLength ); pEntry->sPath = sMime; pEntry->nMethod = STORED; pEntry->nSize = pEntry->nCompressedSize = nBufferLength; pEntry->nTime = ZipOutputStream::getCurrentDosTime(); CRC32 aCRC32; aCRC32.update( aType ); pEntry->nCrc = aCRC32.getValue(); try { aZipOut.putNextEntry( *pEntry, NULL ); aZipOut.write( aType, 0, nBufferLength ); aZipOut.closeEntry(); } catch ( ::com::sun::star::io::IOException & r ) { throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Error adding mimetype to the ZipOutputStream!" ) ), static_cast < OWeakObject * > ( this ), makeAny( r ) ); } } //-------------------------------------------------------- void ZipPackage::WriteManifest( ZipOutputStream& aZipOut, const vector< uno::Sequence < PropertyValue > >& aManList ) { // Write the manifest uno::Reference < XOutputStream > xManOutStream; OUString sManifestWriter( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.manifest.ManifestWriter" ) ); uno::Reference < XManifestWriter > xWriter ( m_xFactory->createInstance( sManifestWriter ), UNO_QUERY ); if ( xWriter.is() ) { ZipEntry * pEntry = new ZipEntry; ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize ); xManOutStream = uno::Reference < XOutputStream > ( *pBuffer, UNO_QUERY ); pEntry->sPath = OUString( RTL_CONSTASCII_USTRINGPARAM ( "META-INF/manifest.xml" ) ); pEntry->nMethod = DEFLATED; pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1; pEntry->nTime = ZipOutputStream::getCurrentDosTime(); // Convert vector into a uno::Sequence uno::Sequence < uno::Sequence < PropertyValue > > aManifestSequence ( aManList.size() ); sal_Int32 nInd = 0; for ( vector < uno::Sequence < PropertyValue > >::const_iterator aIter = aManList.begin(), aEnd = aManList.end(); aIter != aEnd; aIter++, nInd++ ) { aManifestSequence[nInd] = ( *aIter ); } xWriter->writeManifestSequence ( xManOutStream, aManifestSequence ); sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() ); pBuffer->realloc( nBufferLength ); // the manifest.xml is never encrypted - so pass an empty reference aZipOut.putNextEntry( *pEntry, NULL ); aZipOut.write( pBuffer->getSequence(), 0, nBufferLength ); aZipOut.closeEntry(); } else { VOS_ENSURE ( 0, "Couldn't get a ManifestWriter!" ); IOException aException; throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Couldn't get a ManifestWriter!" ) ), static_cast < OWeakObject * > ( this ), makeAny( aException ) ); } } //-------------------------------------------------------- void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno::Sequence < PropertyValue > >& aManList ) { const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) ); const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) ); ZipEntry* pEntry = new ZipEntry; ZipPackageBuffer *pBuffer = new ZipPackageBuffer( n_ConstBufferSize ); uno::Reference< io::XOutputStream > xConTypeOutStream( *pBuffer, UNO_QUERY ); pEntry->sPath = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) ); pEntry->nMethod = DEFLATED; pEntry->nCrc = pEntry->nSize = pEntry->nCompressedSize = -1; pEntry->nTime = ZipOutputStream::getCurrentDosTime(); // Convert vector into a uno::Sequence // TODO/LATER: use Defaulst entries in future uno::Sequence< beans::StringPair > aDefaultsSequence; uno::Sequence< beans::StringPair > aOverridesSequence( aManList.size() ); sal_Int32 nSeqLength = 0; for ( vector< uno::Sequence< beans::PropertyValue > >::const_iterator aIter = aManList.begin(), aEnd = aManList.end(); aIter != aEnd; aIter++ ) { ::rtl::OUString aPath; ::rtl::OUString aType; OSL_ENSURE( ( *aIter )[PKG_MNFST_MEDIATYPE].Name.equals( sMediaType ) && ( *aIter )[PKG_MNFST_FULLPATH].Name.equals( sFullPath ), "The mediatype sequence format is wrong!\n" ); ( *aIter )[PKG_MNFST_MEDIATYPE].Value >>= aType; if ( aType.getLength() ) { // only nonempty type makes sense here nSeqLength++; ( *aIter )[PKG_MNFST_FULLPATH].Value >>= aPath; aOverridesSequence[nSeqLength-1].First = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) + aPath; aOverridesSequence[nSeqLength-1].Second = aType; } } aOverridesSequence.realloc( nSeqLength ); ::comphelper::OFOPXMLHelper::WriteContentSequence( xConTypeOutStream, aDefaultsSequence, aOverridesSequence, m_xFactory ); sal_Int32 nBufferLength = static_cast < sal_Int32 > ( pBuffer->getPosition() ); pBuffer->realloc( nBufferLength ); // there is no encryption in this format currently aZipOut.putNextEntry( *pEntry, NULL ); aZipOut.write( pBuffer->getSequence(), 0, nBufferLength ); aZipOut.closeEntry(); } //-------------------------------------------------------- void ZipPackage::ConnectTo( const uno::Reference< io::XInputStream >& xInStream ) { m_xContentSeek.set( xInStream, uno::UNO_QUERY_THROW ); m_xContentStream = xInStream; // seek back to the beginning of the temp file so we can read segments from it m_xContentSeek->seek( 0 ); if ( m_pZipFile ) m_pZipFile->setInputStream( m_xContentStream ); else m_pZipFile = new ZipFile ( m_xContentStream, m_xFactory, sal_False ); } //-------------------------------------------------------- uno::Reference< io::XInputStream > ZipPackage::writeTempFile() { // In case the target local file does not exist or empty // write directly to it otherwize create a temporary file to write to. // If a temporary file is created it is returned back by the method. // If the data written directly, xComponentStream will be switched here sal_Bool bUseTemp = sal_True; uno::Reference < io::XInputStream > xResult; uno::Reference < io::XInputStream > xTempIn; uno::Reference < io::XOutputStream > xTempOut; uno::Reference< io::XActiveDataStreamer > xSink; if ( m_eMode == e_IMode_URL && !m_pZipFile && isLocalFile_Impl( m_aURL ) ) { xSink = openOriginalForOutput(); if( xSink.is() ) { uno::Reference< io::XStream > xStr = xSink->getStream(); if( xStr.is() ) { xTempOut = xStr->getOutputStream(); if( xTempOut.is() ) bUseTemp = sal_False; } } } else if ( m_eMode == e_IMode_XStream && !m_pZipFile ) { // write directly to an empty stream xTempOut = m_xStream->getOutputStream(); if( xTempOut.is() ) bUseTemp = sal_False; } if( bUseTemp ) { // create temporary file const OUString sServiceName ( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.io.TempFile" ) ); uno::Reference < io::XStream > xTempFile( m_xFactory->createInstance ( sServiceName ), UNO_QUERY_THROW ); xTempOut.set( xTempFile->getOutputStream(), UNO_SET_THROW ); xTempIn.set( xTempFile->getInputStream(), UNO_SET_THROW ); } // Hand it to the ZipOutputStream: ZipOutputStream aZipOut( m_xFactory, xTempOut ); aZipOut.setMethod( DEFLATED ); aZipOut.setLevel( DEFAULT_COMPRESSION ); try { if ( m_nFormat == embed::StorageFormats::PACKAGE ) { // Remove the old manifest.xml file as the // manifest will be re-generated and the // META-INF directory implicitly created if does not exist const OUString sMeta ( RTL_CONSTASCII_USTRINGPARAM ( "META-INF" ) ); if ( m_xRootFolder->hasByName( sMeta ) ) { const OUString sManifest ( RTL_CONSTASCII_USTRINGPARAM( "manifest.xml" ) ); uno::Reference< XUnoTunnel > xTunnel; Any aAny = m_xRootFolder->getByName( sMeta ); aAny >>= xTunnel; uno::Reference< XNameContainer > xMetaInfFolder( xTunnel, UNO_QUERY ); if ( xMetaInfFolder.is() && xMetaInfFolder->hasByName( sManifest ) ) xMetaInfFolder->removeByName( sManifest ); } // Write a magic file with mimetype WriteMimetypeMagicFile( aZipOut ); } else if ( m_nFormat == embed::StorageFormats::OFOPXML ) { // Remove the old [Content_Types].xml file as the // file will be re-generated const ::rtl::OUString aContentTypes( RTL_CONSTASCII_USTRINGPARAM ( "[Content_Types].xml" ) ); if ( m_xRootFolder->hasByName( aContentTypes ) ) m_xRootFolder->removeByName( aContentTypes ); } // Create a vector to store data for the manifest.xml file vector < uno::Sequence < PropertyValue > > aManList; const OUString sMediaType ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) ); const OUString sVersion ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) ); const OUString sFullPath ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) ); if ( m_nFormat == embed::StorageFormats::PACKAGE ) { uno::Sequence < PropertyValue > aPropSeq( PKG_SIZE_NOENCR_MNFST ); aPropSeq [PKG_MNFST_MEDIATYPE].Name = sMediaType; aPropSeq [PKG_MNFST_MEDIATYPE].Value <<= m_pRootFolder->GetMediaType(); aPropSeq [PKG_MNFST_VERSION].Name = sVersion; aPropSeq [PKG_MNFST_VERSION].Value <<= m_pRootFolder->GetVersion(); aPropSeq [PKG_MNFST_FULLPATH].Name = sFullPath; aPropSeq [PKG_MNFST_FULLPATH].Value <<= OUString ( RTL_CONSTASCII_USTRINGPARAM ( "/" ) ); aManList.push_back( aPropSeq ); } // Get a random number generator and seed it with current timestamp // This will be used to generate random salt and initialisation vectors // for encrypted streams TimeValue aTime; osl_getSystemTime( &aTime ); rtlRandomPool aRandomPool = rtl_random_createPool (); rtl_random_addBytes ( aRandomPool, &aTime, 8 ); // call saveContents ( it will recursively save sub-directories OUString aEmptyString; m_pRootFolder->saveContents( aEmptyString, aManList, aZipOut, GetEncryptionKey(), aRandomPool ); // Clean up random pool memory rtl_random_destroyPool ( aRandomPool ); if( m_nFormat == embed::StorageFormats::PACKAGE ) { WriteManifest( aZipOut, aManList ); } else if( m_nFormat == embed::StorageFormats::OFOPXML ) { WriteContentTypes( aZipOut, aManList ); } aZipOut.finish(); if( bUseTemp ) xResult = xTempIn; // Update our References to point to the new temp file if( !bUseTemp ) { // the case when the original contents were written directly xTempOut->flush(); // in case the stream is based on a file it will implement the following interface // the call should be used to be sure that the contents are written to the file system uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( xTempOut, uno::UNO_QUERY ); if ( asyncOutputMonitor.is() ) asyncOutputMonitor->waitForCompletion(); // no need to postpone switching to the new stream since the target was written directly uno::Reference< io::XInputStream > xNewStream; if ( m_eMode == e_IMode_URL ) xNewStream = xSink->getStream()->getInputStream(); else if ( m_eMode == e_IMode_XStream && m_xStream.is() ) xNewStream = m_xStream->getInputStream(); if ( xNewStream.is() ) ConnectTo( xNewStream ); } } catch ( uno::Exception& ) { if( bUseTemp ) { // no information loss appeares, thus no special handling is required uno::Any aCaught( ::cppu::getCaughtException() ); // it is allowed to throw WrappedTargetException WrappedTargetException aException; if ( aCaught >>= aException ) throw aException; throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Problem writing the original content!" ) ), static_cast < OWeakObject * > ( this ), aCaught ); } else { // the document is written directly, although it was empty it is important to notify that the writing has failed // TODO/LATER: let the package be able to recover in this situation ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is unusable!" ) ); embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), ::rtl::OUString() ); throw WrappedTargetException( aErrTxt, static_cast < OWeakObject * > ( this ), makeAny ( aException ) ); } } return xResult; } //-------------------------------------------------------- uno::Reference< XActiveDataStreamer > ZipPackage::openOriginalForOutput() { // open and truncate the original file Content aOriginalContent ( m_aURL, uno::Reference < XCommandEnvironment >() ); uno::Reference< XActiveDataStreamer > xSink = new ActiveDataStreamer; if ( m_eMode == e_IMode_URL ) { try { sal_Bool bTruncSuccess = sal_False; try { Exception aDetect; sal_Int64 aSize = 0; Any aAny = aOriginalContent.setPropertyValue( OUString::createFromAscii( "Size" ), makeAny( aSize ) ); if( !( aAny >>= aDetect ) ) bTruncSuccess = sal_True; } catch( Exception& ) { } if( !bTruncSuccess ) { // the file is not accessible // just try to write an empty stream to it uno::Reference< XInputStream > xTempIn = new DummyInputStream; //uno::Reference< XInputStream >( xTempOut, UNO_QUERY ); aOriginalContent.writeStream( xTempIn , sal_True ); } OpenCommandArgument2 aArg; aArg.Mode = OpenMode::DOCUMENT; aArg.Priority = 0; // unused aArg.Sink = xSink; aArg.Properties = uno::Sequence< Property >( 0 ); // unused aOriginalContent.executeCommand( OUString::createFromAscii( "open" ), makeAny( aArg ) ); } catch( Exception& ) { // seems to be nonlocal file // temporary file mechanics should be used } } return xSink; } //-------------------------------------------------------- void SAL_CALL ZipPackage::commitChanges() throw( WrappedTargetException, RuntimeException ) { // lock the component for the time of committing ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); if ( m_eMode == e_IMode_XInputStream ) { IOException aException; throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ), static_cast < OWeakObject * > ( this ), makeAny ( aException ) ); } RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "{ ZipPackage::commitChanges" ); // first the writeTempFile is called, if it returns a stream the stream should be written to the target // if no stream was returned, the file was written directly, nothing should be done uno::Reference< io::XInputStream > xTempInStream = writeTempFile(); if ( xTempInStream.is() ) { uno::Reference< io::XSeekable > xTempSeek( xTempInStream, uno::UNO_QUERY_THROW ); try { xTempSeek->seek( 0 ); } catch( uno::Exception& r ) { throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "Temporary file should be seekable!" ) ), static_cast < OWeakObject * > ( this ), makeAny ( r ) ); } // connect to the temporary stream ConnectTo( xTempInStream ); if ( m_eMode == e_IMode_XStream ) { // First truncate our output stream uno::Reference < XOutputStream > xOutputStream; // preparation for copy step try { xOutputStream = m_xStream->getOutputStream(); uno::Reference < XTruncate > xTruncate ( xOutputStream, UNO_QUERY ); if ( !xTruncate.is() ) throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // after successful truncation the original file contents are already lost xTruncate->truncate(); } catch( uno::Exception& r ) { throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ), static_cast < OWeakObject * > ( this ), makeAny ( r ) ); } try { // then copy the contents of the tempfile to our output stream ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, xOutputStream ); xOutputStream->flush(); uno::Reference< io::XAsyncOutputMonitor > asyncOutputMonitor( xOutputStream, uno::UNO_QUERY ); if ( asyncOutputMonitor.is() ) { asyncOutputMonitor->waitForCompletion(); } } catch( uno::Exception& ) { // if anything goes wrong in this block the target file becomes corrupted // so an exception should be thrown as a notification about it // and the package must disconnect from the stream DisconnectFromTargetAndThrowException_Impl( xTempInStream ); } } else if ( m_eMode == e_IMode_URL ) { uno::Reference< XOutputStream > aOrigFileStream; sal_Bool bCanBeCorrupted = sal_False; if( isLocalFile_Impl( m_aURL ) ) { // write directly in case of local file uno::Reference< ::com::sun::star::ucb::XSimpleFileAccess > xSimpleAccess( m_xFactory->createInstance( ::rtl::OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), uno::UNO_QUERY ); OSL_ENSURE( xSimpleAccess.is(), "Can't instatiate SimpleFileAccess service!\n" ); uno::Reference< io::XTruncate > xOrigTruncate; if ( xSimpleAccess.is() ) { try { aOrigFileStream = xSimpleAccess->openFileWrite( m_aURL ); xOrigTruncate = uno::Reference< io::XTruncate >( aOrigFileStream, uno::UNO_QUERY_THROW ); // after successful truncation the file is already corrupted xOrigTruncate->truncate(); } catch( uno::Exception& ) {} } if( xOrigTruncate.is() ) { try { ::comphelper::OStorageHelper::CopyInputToOutput( xTempInStream, aOrigFileStream ); aOrigFileStream->closeOutput(); } catch( uno::Exception& ) { try { aOrigFileStream->closeOutput(); } catch ( uno::Exception& ) {} aOrigFileStream = uno::Reference< XOutputStream >(); // the original file can already be corrupted bCanBeCorrupted = sal_True; } } } if( !aOrigFileStream.is() ) { try { uno::Reference < XPropertySet > xPropSet ( xTempInStream, UNO_QUERY ); OSL_ENSURE( xPropSet.is(), "This is a temporary file that must implement XPropertySet!\n" ); if ( !xPropSet.is() ) throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); OUString sTargetFolder = m_aURL.copy ( 0, m_aURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) ); Content aContent ( sTargetFolder, uno::Reference < XCommandEnvironment > () ); OUString sTempURL; Any aAny = xPropSet->getPropertyValue ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "Uri" ) ) ); aAny >>= sTempURL; TransferInfo aInfo; aInfo.NameClash = NameClash::OVERWRITE; aInfo.MoveData = sal_False; aInfo.SourceURL = sTempURL; aInfo.NewTitle = rtl::Uri::decode ( m_aURL.copy ( 1 + m_aURL.lastIndexOf ( static_cast < sal_Unicode > ( '/' ) ) ), rtl_UriDecodeWithCharset, RTL_TEXTENCODING_UTF8 ); aAny <<= aInfo; // if the file is still not corrupted, it can become after the next step aContent.executeCommand ( OUString ( RTL_CONSTASCII_USTRINGPARAM ( "transfer" ) ), aAny ); } catch ( ::com::sun::star::uno::Exception& r ) { if ( bCanBeCorrupted ) DisconnectFromTargetAndThrowException_Impl( xTempInStream ); throw WrappedTargetException( OUString( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package may be read only!" ) ), static_cast < OWeakObject * > ( this ), makeAny ( r ) ); } } } } // after successful storing it can be set to false m_bMediaTypeFallbackUsed = sal_False; RTL_LOGFILE_TRACE_AUTHOR ( "package", LOGFILE_AUTHOR, "} ZipPackage::commitChanges" ); } //-------------------------------------------------------- void ZipPackage::DisconnectFromTargetAndThrowException_Impl( const uno::Reference< io::XInputStream >& xTempStream ) { m_xStream = uno::Reference< io::XStream >( xTempStream, uno::UNO_QUERY ); if ( m_xStream.is() ) m_eMode = e_IMode_XStream; else m_eMode = e_IMode_XInputStream; ::rtl::OUString aTempURL; try { uno::Reference< beans::XPropertySet > xTempFile( xTempStream, uno::UNO_QUERY_THROW ); uno::Any aUrl = xTempFile->getPropertyValue( ::rtl::OUString::createFromAscii( "Uri" ) ); aUrl >>= aTempURL; xTempFile->setPropertyValue( ::rtl::OUString::createFromAscii( "RemoveFile" ), uno::makeAny( sal_False ) ); } catch ( uno::Exception& ) { OSL_ENSURE( sal_False, "These calls are pretty simple, they should not fail!\n" ); } ::rtl::OUString aErrTxt( RTL_CONSTASCII_USTRINGPARAM ( OSL_LOG_PREFIX "This package is read only!" ) ); embed::UseBackupException aException( aErrTxt, uno::Reference< uno::XInterface >(), aTempURL ); throw WrappedTargetException( aErrTxt, static_cast < OWeakObject * > ( this ), makeAny ( aException ) ); } //-------------------------------------------------------- const uno::Sequence< sal_Int8 > ZipPackage::GetEncryptionKey() { uno::Sequence< sal_Int8 > aResult; if ( m_aStorageEncryptionKeys.getLength() ) { ::rtl::OUString aNameToFind; if ( m_nStartKeyGenerationID == xml::crypto::DigestID::SHA256 ) aNameToFind = PACKAGE_ENCRYPTIONDATA_SHA256UTF8; else if ( m_nStartKeyGenerationID == xml::crypto::DigestID::SHA1 ) aNameToFind = PACKAGE_ENCRYPTIONDATA_SHA1UTF8; else throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No expected key is provided!" ) ), uno::Reference< uno::XInterface >() ); for ( sal_Int32 nInd = 0; nInd < m_aStorageEncryptionKeys.getLength(); nInd++ ) if ( m_aStorageEncryptionKeys[nInd].Name.equals( aNameToFind ) ) m_aStorageEncryptionKeys[nInd].Value >>= aResult; // empty keys are not allowed here // so it is not important whether there is no key, or the key is empty, it is an error if ( !aResult.getLength() ) throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No expected key is provided!" ) ), uno::Reference< uno::XInterface >() ); } else aResult = m_aEncryptionKey; return aResult; } //-------------------------------------------------------- sal_Bool SAL_CALL ZipPackage::hasPendingChanges() throw( RuntimeException ) { return sal_False; } //-------------------------------------------------------- Sequence< ElementChange > SAL_CALL ZipPackage::getPendingChanges() throw( RuntimeException ) { return uno::Sequence < ElementChange > (); } /** * Function to create a new component instance; is needed by factory helper implementation. * @param xMgr service manager to if the components needs other component instances */ uno::Reference < XInterface >SAL_CALL ZipPackage_createInstance( const uno::Reference< XMultiServiceFactory > & xMgr ) { return uno::Reference< XInterface >( *new ZipPackage( xMgr ) ); } //-------------------------------------------------------- OUString ZipPackage::static_getImplementationName() { return OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.comp.ZipPackage" ) ); } //-------------------------------------------------------- Sequence< OUString > ZipPackage::static_getSupportedServiceNames() { uno::Sequence< OUString > aNames( 1 ); aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.Package" ) ); return aNames; } //-------------------------------------------------------- sal_Bool SAL_CALL ZipPackage::static_supportsService( OUString const & rServiceName ) { return rServiceName == getSupportedServiceNames()[0]; } //-------------------------------------------------------- OUString ZipPackage::getImplementationName() throw ( RuntimeException ) { return static_getImplementationName(); } //-------------------------------------------------------- Sequence< OUString > ZipPackage::getSupportedServiceNames() throw ( RuntimeException ) { return static_getSupportedServiceNames(); } //-------------------------------------------------------- sal_Bool SAL_CALL ZipPackage::supportsService( OUString const & rServiceName ) throw ( RuntimeException ) { return static_supportsService ( rServiceName ); } //-------------------------------------------------------- uno::Reference < XSingleServiceFactory > ZipPackage::createServiceFactory( uno::Reference < XMultiServiceFactory > const & rServiceFactory ) { return cppu::createSingleFactory ( rServiceFactory, static_getImplementationName(), ZipPackage_createInstance, static_getSupportedServiceNames() ); } namespace { struct lcl_ImplId : public rtl::Static< ::cppu::OImplementationId, lcl_ImplId > {}; } //-------------------------------------------------------- Sequence< sal_Int8 > ZipPackage::getUnoTunnelImplementationId( void ) throw ( RuntimeException ) { ::cppu::OImplementationId &rId = lcl_ImplId::get(); return rId.getImplementationId(); } //-------------------------------------------------------- sal_Int64 SAL_CALL ZipPackage::getSomething( const uno::Sequence< sal_Int8 >& aIdentifier ) throw( RuntimeException ) { if ( aIdentifier.getLength() == 16 && 0 == rtl_compareMemory( getUnoTunnelImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) ) return reinterpret_cast < sal_Int64 > ( this ); return 0; } //-------------------------------------------------------- uno::Reference< XPropertySetInfo > SAL_CALL ZipPackage::getPropertySetInfo() throw( RuntimeException ) { return uno::Reference < XPropertySetInfo > (); } //-------------------------------------------------------- void SAL_CALL ZipPackage::setPropertyValue( const OUString& aPropertyName, const Any& aValue ) throw( UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException ) { if ( m_nFormat != embed::StorageFormats::PACKAGE ) throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( HAS_ENCRYPTED_ENTRIES_PROPERTY ) ) ||aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( HAS_NONENCRYPTED_ENTRIES_PROPERTY ) ) ||aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( IS_INCONSISTENT_PROPERTY ) ) ||aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( MEDIATYPE_FALLBACK_USED_PROPERTY ) ) ) throw PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_KEY_PROPERTY ) ) ) { if ( !( aValue >>= m_aEncryptionKey ) ) throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 ); m_aStorageEncryptionKeys.realloc( 0 ); } else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( STORAGE_ENCRYPTION_KEYS_PROPERTY ) ) ) { // this property is only necessary to support raw passwords in storage API; // because of this support the storage has to operate with more than one key dependent on storage generation algorithm; // when this support is removed, the storage will get only one key from outside // TODO/LATER: Get rid of this property as well as of support of raw passwords in storages uno::Sequence< beans::NamedValue > aKeys; if ( !( aValue >>= aKeys ) || ( aKeys.getLength() && aKeys.getLength() < 2 ) ) throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 ); if ( aKeys.getLength() ) { bool bHasSHA256 = false; bool bHasSHA1 = false; for ( sal_Int32 nInd = 0; nInd < aKeys.getLength(); nInd++ ) { if ( aKeys[nInd].Name.equals( PACKAGE_ENCRYPTIONDATA_SHA256UTF8 ) ) bHasSHA256 = true; if ( aKeys[nInd].Name.equals( PACKAGE_ENCRYPTIONDATA_SHA1UTF8 ) ) bHasSHA1 = true; } if ( !bHasSHA256 || !bHasSHA1 ) throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Expected keys are not provided!" ) ), uno::Reference< uno::XInterface >(), 2 ); } m_aStorageEncryptionKeys = aKeys; m_aEncryptionKey.realloc( 0 ); } else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_ALGORITHMS_PROPERTY ) ) ) { uno::Sequence< beans::NamedValue > aAlgorithms; if ( m_pZipFile || !( aValue >>= aAlgorithms ) || aAlgorithms.getLength() == 0 ) { // the algorithms can not be changed if the file has a persistence based on the algorithms ( m_pZipFile ) throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "unexpected algorithms list is provided." ) ), uno::Reference< uno::XInterface >(), 2 ); } for ( sal_Int32 nInd = 0; nInd < aAlgorithms.getLength(); nInd++ ) { if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "StartKeyGenerationAlgorithm" ) ) ) { sal_Int32 nID = 0; if ( !( aAlgorithms[nInd].Value >>= nID ) || ( nID != xml::crypto::DigestID::SHA256 && nID != xml::crypto::DigestID::SHA1 ) ) throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected start key generation algorithm is provided!" ) ), uno::Reference< uno::XInterface >(), 2 ); m_nStartKeyGenerationID = nID; } else if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "EncryptionAlgorithm" ) ) ) { sal_Int32 nID = 0; if ( !( aAlgorithms[nInd].Value >>= nID ) || ( nID != xml::crypto::CipherID::AES_CBC_W3C_PADDING && nID != xml::crypto::CipherID::BLOWFISH_CFB_8 ) ) throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected start key generation algorithm is provided!" ) ), uno::Reference< uno::XInterface >(), 2 ); m_nCommonEncryptionID = nID; } else if ( aAlgorithms[nInd].Name.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "ChecksumAlgorithm" ) ) ) { sal_Int32 nID = 0; if ( !( aAlgorithms[nInd].Value >>= nID ) || ( nID != xml::crypto::DigestID::SHA1_1K && nID != xml::crypto::DigestID::SHA256_1K ) ) throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected start key generation algorithm is provided!" ) ), uno::Reference< uno::XInterface >(), 2 ); m_nChecksumDigestID = nID; } else { OSL_ENSURE( sal_False, "Unexpected encryption algorithm is provided!" ); throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "unexpected algorithms list is provided." ) ), uno::Reference< uno::XInterface >(), 2 ); } } } else throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); } //-------------------------------------------------------- Any SAL_CALL ZipPackage::getPropertyValue( const OUString& PropertyName ) throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) { // TODO/LATER: Activate the check when zip-ucp is ready // if ( m_nFormat != embed::StorageFormats::PACKAGE ) // throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); Any aAny; if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( ENCRYPTION_KEY_PROPERTY ) ) ) { aAny <<= m_aEncryptionKey; return aAny; } else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_ALGORITHMS_PROPERTY ) ) ) { ::comphelper::SequenceAsHashMap aAlgorithms; aAlgorithms[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "StartKeyGenerationAlgorithm" ) ) ] <<= m_nStartKeyGenerationID; aAlgorithms[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EncryptionAlgorithm" ) ) ] <<= m_nCommonEncryptionID; aAlgorithms[ ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ChecksumAlgorithm" ) ) ] <<= m_nChecksumDigestID; aAny <<= aAlgorithms.getAsConstNamedValueList(); return aAny; } if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( STORAGE_ENCRYPTION_KEYS_PROPERTY ) ) ) { aAny <<= m_aStorageEncryptionKeys; return aAny; } else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( HAS_ENCRYPTED_ENTRIES_PROPERTY ) ) ) { aAny <<= m_bHasEncryptedEntries; return aAny; } else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( HAS_NONENCRYPTED_ENTRIES_PROPERTY ) ) ) { aAny <<= m_bHasNonEncryptedEntries; return aAny; } else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( IS_INCONSISTENT_PROPERTY ) ) ) { aAny <<= m_bInconsistent; return aAny; } else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( MEDIATYPE_FALLBACK_USED_PROPERTY ) ) ) { aAny <<= m_bMediaTypeFallbackUsed; return aAny; } throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); } //-------------------------------------------------------- void SAL_CALL ZipPackage::addPropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*xListener*/ ) throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) { } //-------------------------------------------------------- void SAL_CALL ZipPackage::removePropertyChangeListener( const OUString& /*aPropertyName*/, const uno::Reference< XPropertyChangeListener >& /*aListener*/ ) throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) { } //-------------------------------------------------------- void SAL_CALL ZipPackage::addVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ ) throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) { } //-------------------------------------------------------- void SAL_CALL ZipPackage::removeVetoableChangeListener( const OUString& /*PropertyName*/, const uno::Reference< XVetoableChangeListener >& /*aListener*/ ) throw( UnknownPropertyException, WrappedTargetException, RuntimeException ) { }