| /************************************************************** |
| * |
| * 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 <ZipPackage.hxx> |
| #include <ZipPackageSink.hxx> |
| #include <ZipEnumeration.hxx> |
| #include <ZipPackageStream.hxx> |
| #include <ZipPackageFolder.hxx> |
| #include <ZipOutputStream.hxx> |
| #include <ZipPackageBuffer.hxx> |
| #include <ZipFile.hxx> |
| #include <PackageConstants.hxx> |
| #include <com/sun/star/beans/PropertyValue.hpp> |
| #include <com/sun/star/beans/NamedValue.hpp> |
| #include <com/sun/star/packages/zip/ZipConstants.hpp> |
| #include <com/sun/star/packages/manifest/XManifestReader.hpp> |
| #include <com/sun/star/packages/manifest/XManifestWriter.hpp> |
| #include <com/sun/star/io/XStream.hpp> |
| #include <com/sun/star/io/XInputStream.hpp> |
| #include <com/sun/star/io/XOutputStream.hpp> |
| #include <com/sun/star/io/XTruncate.hpp> |
| #include <com/sun/star/io/XSeekable.hpp> |
| #include <com/sun/star/lang/XMultiServiceFactory.hpp> |
| #include <com/sun/star/container/XNameContainer.hpp> |
| #include <com/sun/star/ucb/IOErrorCode.hpp> |
| #include <ucbhelper/content.hxx> |
| #include <cppuhelper/factory.hxx> |
| #include <cppuhelper/exc_hlp.hxx> |
| #include <com/sun/star/ucb/TransferInfo.hpp> |
| #include <com/sun/star/ucb/NameClash.hpp> |
| #include <com/sun/star/ucb/OpenCommandArgument2.hpp> |
| #include <com/sun/star/ucb/OpenMode.hpp> |
| #include <com/sun/star/ucb/XProgressHandler.hpp> |
| #include <com/sun/star/ucb/XSimpleFileAccess.hpp> |
| #include <com/sun/star/io/XActiveDataStreamer.hpp> |
| #include <com/sun/star/embed/XTransactedObject.hpp> |
| #include <com/sun/star/embed/UseBackupException.hpp> |
| #include <com/sun/star/embed/StorageFormats.hpp> |
| #include <com/sun/star/beans/NamedValue.hpp> |
| #include <com/sun/star/xml/crypto/DigestID.hpp> |
| #include <com/sun/star/xml/crypto/CipherID.hpp> |
| #include <cppuhelper/implbase1.hxx> |
| #include <ContentInfo.hxx> |
| #include <cppuhelper/typeprovider.hxx> |
| #include <rtl/uri.hxx> |
| #include <rtl/random.h> |
| #include <rtl/logfile.hxx> |
| #include <rtl/instance.hxx> |
| #include <osl/time.h> |
| #include <osl/file.hxx> |
| #include "com/sun/star/io/XAsyncOutputMonitor.hpp" |
| |
| #include <memory> |
| #include <vector> |
| |
| #include <ucbhelper/contentbroker.hxx> |
| #include <ucbhelper/fileidentifierconverter.hxx> |
| #include <comphelper/seekableinput.hxx> |
| #include <comphelper/storagehelper.hxx> |
| #include <comphelper/ofopxmlhelper.hxx> |
| #include <comphelper/documentconstants.hxx> |
| #include <comphelper/sequenceashashmap.hxx> |
| |
| 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 dieing 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 successfuly 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 sence 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 commiting |
| ::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 ) |
| { |
| } |