diff options
Diffstat (limited to 'package/source/zippackage')
-rw-r--r-- | package/source/zippackage/ContentInfo.hxx | 69 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackage.cxx | 1697 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackageBuffer.cxx | 136 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackageEntry.cxx | 136 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackageEntry.hxx | 105 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackageFolder.cxx | 803 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackageFolderEnumeration.cxx | 79 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackageFolderEnumeration.hxx | 68 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackageSink.cxx | 48 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackageSink.hxx | 48 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackageStream.cxx | 796 | ||||
-rw-r--r-- | package/source/zippackage/ZipPackageStream.hxx | 201 | ||||
-rw-r--r-- | package/source/zippackage/makefile.mk | 63 | ||||
-rw-r--r-- | package/source/zippackage/wrapstreamforshare.cxx | 180 | ||||
-rw-r--r-- | package/source/zippackage/wrapstreamforshare.hxx | 73 | ||||
-rw-r--r-- | package/source/zippackage/zipfileaccess.cxx | 492 |
16 files changed, 4994 insertions, 0 deletions
diff --git a/package/source/zippackage/ContentInfo.hxx b/package/source/zippackage/ContentInfo.hxx new file mode 100644 index 000000000000..6d88d17e3780 --- /dev/null +++ b/package/source/zippackage/ContentInfo.hxx @@ -0,0 +1,69 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _CONTENT_INFO_HXX_ +#define _CONTENT_INFO_HXX_ + +#include <com/sun/star/container/XNameContainer.hpp> +#ifndef _COM_SUN_STAR_LANG_XUNOTUNNEl_HPP_ +#include <com/sun/star/lang/XUnoTunnel.hpp> +#endif +#include <ZipPackageFolder.hxx> +#include <ZipPackageStream.hxx> + +namespace com { namespace sun { namespace star { namespace packages { +class ContentInfo : public cppu::OWeakObject +{ +public: + com::sun::star::uno::Reference < com::sun::star::lang::XUnoTunnel > xTunnel; + bool bFolder; + union + { + ZipPackageFolder *pFolder; + ZipPackageStream *pStream; + }; + ContentInfo ( ZipPackageStream * pNewStream ) + : xTunnel ( pNewStream ) + , bFolder ( false ) + , pStream ( pNewStream ) + { + } + ContentInfo ( ZipPackageFolder * pNewFolder ) + : xTunnel ( pNewFolder ) + , bFolder ( true ) + , pFolder ( pNewFolder ) + { + } + virtual ~ContentInfo () + { + if ( bFolder ) + pFolder->releaseUpwardRef(); + else + pStream->clearParent(); + } +}; +} } } } +#endif diff --git a/package/source/zippackage/ZipPackage.cxx b/package/source/zippackage/ZipPackage.cxx new file mode 100644 index 000000000000..5c22bad46a6a --- /dev/null +++ b/package/source/zippackage/ZipPackage.cxx @@ -0,0 +1,1697 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 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/beans/NamedValue.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 <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> + +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( Sequence< sal_Int8 >&, sal_Int32 ) + throw ( NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) + { return 0; } + + virtual sal_Int32 SAL_CALL readSomeBytes( 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_bHasEncryptedEntries ( sal_False ) +, m_bHasNonEncryptedEntries ( sal_False ) +, m_bInconsistent ( sal_False ) +, m_bUseManifest ( sal_True ) +, m_bForceRecovery ( sal_False ) +, m_bMediaTypeFallbackUsed ( sal_False ) +, m_nFormat( PACKAGE_FORMAT ) // 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. + +#if 0 + // As all folders and streams contain references to their parents, + // we must remove these references so that they will be deleted when + // the hash_map of the root folder is cleared, releasing all subfolders + // and substreams which in turn release theirs, etc. When m_xRootFolder is + // released when this destructor completes, the folder tree should be + // deleted fully (and automagically). + + m_pRootFolder->releaseUpwardRef(); +#endif +} + +void ZipPackage::parseManifest() +{ + if ( m_nFormat == PACKAGE_FORMAT ) + { + sal_Bool bManifestParsed = sal_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" ) ); + + Sequence < Sequence < PropertyValue > > aManifestSequence = xReader->readManifestSequence ( xSink->getInputStream() ); + sal_Int32 nLength = aManifestSequence.getLength(); + const 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; + 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); + } + + 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) + { + Sequence < sal_uInt8 > aSequence; + sal_Int32 nCount = 0, nSize = 0; + pStream->SetToBeEncrypted ( sal_True ); + + *pSalt >>= aSequence; + pStream->setSalt ( aSequence ); + + *pVector >>= aSequence; + pStream->setInitialisationVector ( aSequence ); + + *pCount >>= nCount; + pStream->setIterationCount ( nCount ); + + *pSize >>= nSize; + pStream->setSize ( nSize ); + + if ( pDigest ) + { + *pDigest >>= aSequence; + pStream->setDigest ( aSequence ); + } + + 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; + } + 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 bODF12AndOlder = ( m_pRootFolder->GetVersion().compareTo( ODFVER_012_TEXT ) >= 0 ); + if ( !m_bForceRecovery && bODF12AndOlder && 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 >() ); + } + + // 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 ( bODF12AndOlder ) + m_xRootFolder->removeByName( sMeta ); + } +} + +void ZipPackage::parseContentType() +{ + if ( m_nFormat == OFOPXML_FORMAT ) + { + 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(); + const OUString & rName = rEntry.sPath; + + 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 == PACKAGE_FORMAT ) + parseManifest(); + else if ( m_nFormat == OFOPXML_FORMAT ) + parseContentType(); +} + +// XInitialization +void SAL_CALL ZipPackage::initialize( const 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 = ZIP_FORMAT; + m_pRootFolder->setPackageFormat_Impl( m_nFormat ); + break; + } + else if ( aCommand.equals( OUString::createFromAscii( "ofopxml" ) ) ) + { + m_nFormat = OFOPXML_FORMAT; + 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 = ZIP_FORMAT; + + m_pRootFolder->setPackageFormat_Impl( m_nFormat ); + } + else if ( aNamedValue.Name.equalsAscii( "StorageFormat" ) ) + { + ::rtl::OUString aFormatName; + aNamedValue.Value >>= aFormatName; + if ( aFormatName.equals( PACKAGE_STORAGE_FORMAT_STRING ) ) + m_nFormat = PACKAGE_FORMAT; + else if ( aFormatName.equals( ZIP_STORAGE_FORMAT_STRING ) ) + m_nFormat = ZIP_FORMAT; + else if ( aFormatName.equals( OFOPXML_STORAGE_FORMAT_STRING ) ) + m_nFormat = OFOPXML_FORMAT; + 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; + } +} + +// XSingleServiceFactory +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 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 ); + 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 + { + vos::ORef < EncryptionData > xEmpty; + aZipOut.putNextEntry( *pEntry, xEmpty ); + aZipOut.write( aType, 0, nBufferLength ); + aZipOut.closeEntry(); + } + catch ( ::com::sun::star::io::IOException & r ) + { + VOS_ENSURE( 0, "Error adding mimetype to the ZipOutputStream" ); + 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< 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 Sequence + Sequence < Sequence < PropertyValue > > aManifestSequence ( aManList.size() ); + Sequence < PropertyValue > * pSequence = aManifestSequence.getArray(); + for (vector < Sequence < PropertyValue > >::const_iterator aIter = aManList.begin(), aEnd = aManList.end(); + aIter != aEnd; + aIter++, pSequence++) + *pSequence= (*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 + vos::ORef < EncryptionData > xEmpty; + aZipOut.putNextEntry( *pEntry, xEmpty ); + 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< 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 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 + vos::ORef < EncryptionData > xEmpty; + aZipOut.putNextEntry( *pEntry, xEmpty ); + 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 ( xTempOut ); + aZipOut.setMethod(DEFLATED); + aZipOut.setLevel(DEFAULT_COMPRESSION); + + try + { + if ( m_nFormat == PACKAGE_FORMAT ) + { + // 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 == OFOPXML_FORMAT ) + { + // 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 < 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 == PACKAGE_FORMAT ) + { + 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, m_aEncryptionKey, aRandomPool ); + + // Clean up random pool memory + rtl_random_destroyPool ( aRandomPool ); + + if( m_bUseManifest && m_nFormat == PACKAGE_FORMAT ) + { + WriteManifest( aZipOut, aManList ); + } + else if( m_nFormat == OFOPXML_FORMAT ) + { + 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 = 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; +} + +// XChangesBatch +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 ) ); +} + +sal_Bool SAL_CALL ZipPackage::hasPendingChanges( ) + throw(RuntimeException) +{ + return sal_False; +} +Sequence< ElementChange > SAL_CALL ZipPackage::getPendingChanges( ) + throw(RuntimeException) +{ + return 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() +{ + 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()); +} + +// XUnoTunnel +Sequence< sal_Int8 > ZipPackage::getUnoTunnelImplementationId( void ) + throw (RuntimeException) +{ + static ::cppu::OImplementationId * pId = 0; + if (! pId) + { + ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() ); + if (! pId) + { + static ::cppu::OImplementationId aId; + pId = &aId; + } + } + return pId->getImplementationId(); +} + +sal_Int64 SAL_CALL ZipPackage::getSomething( const 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 != PACKAGE_FORMAT ) + throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("HasEncryptedEntries") ) + ||aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("HasNonEncryptedEntries") ) + ||aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("IsInconsistent") ) + ||aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("MediaTypeFallbackUsed") ) ) + throw PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("EncryptionKey") ) ) + { + if (!( aValue >>= m_aEncryptionKey ) ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 2 ); + } + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("UseManifest") ) ) + { + if (!( aValue >>= m_bUseManifest ) ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), 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 != PACKAGE_FORMAT ) + // throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + Any aAny; + if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "EncryptionKey" ) ) ) + { + aAny <<= m_aEncryptionKey; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "HasEncryptedEntries" ) ) ) + { + aAny <<= m_bHasEncryptedEntries; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "HasNonEncryptedEntries" ) ) ) + { + aAny <<= m_bHasNonEncryptedEntries; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "IsInconsistent" ) ) ) + { + aAny <<= m_bInconsistent; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "UseManifest" ) ) ) + { + aAny <<= m_bUseManifest; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "MediaTypeFallbackUsed" ) ) ) + { + 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) +{ +} diff --git a/package/source/zippackage/ZipPackageBuffer.cxx b/package/source/zippackage/ZipPackageBuffer.cxx new file mode 100644 index 000000000000..e6468c8539f0 --- /dev/null +++ b/package/source/zippackage/ZipPackageBuffer.cxx @@ -0,0 +1,136 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipPackageBuffer.hxx> +#include <string.h> // for memcpy + +using namespace ::com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::io; +using com::sun::star::lang::IllegalArgumentException; + +ZipPackageBuffer::ZipPackageBuffer(sal_Int64 nNewBufferSize ) +: m_nBufferSize (nNewBufferSize) +, m_nEnd(0) +, m_nCurrent(0) +, m_bMustInitBuffer ( sal_True ) +{ +} +ZipPackageBuffer::~ZipPackageBuffer(void) +{ +} + +sal_Int32 SAL_CALL ZipPackageBuffer::readBytes( Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + if (nBytesToRead < 0) + throw BufferSizeExceededException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), *this ); + + if (nBytesToRead + m_nCurrent > m_nEnd) + nBytesToRead = static_cast < sal_Int32 > (m_nEnd - m_nCurrent); + + aData.realloc ( nBytesToRead ); + memcpy(aData.getArray(), m_aBuffer.getConstArray() + m_nCurrent, nBytesToRead); + m_nCurrent +=nBytesToRead; + return nBytesToRead; +} + +sal_Int32 SAL_CALL ZipPackageBuffer::readSomeBytes( Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + return readBytes(aData, nMaxBytesToRead); +} +void SAL_CALL ZipPackageBuffer::skipBytes( sal_Int32 nBytesToSkip ) + throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + if (nBytesToSkip < 0) + throw BufferSizeExceededException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), *this ); + + if (nBytesToSkip + m_nCurrent > m_nEnd) + nBytesToSkip = static_cast < sal_Int32 > (m_nEnd - m_nCurrent); + + m_nCurrent+=nBytesToSkip; +} +sal_Int32 SAL_CALL ZipPackageBuffer::available( ) + throw(NotConnectedException, IOException, RuntimeException) +{ + return static_cast < sal_Int32 > (m_nEnd - m_nCurrent); +} +void SAL_CALL ZipPackageBuffer::closeInput( ) + throw(NotConnectedException, IOException, RuntimeException) +{ +} +void SAL_CALL ZipPackageBuffer::writeBytes( const Sequence< sal_Int8 >& aData ) + throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ + sal_Int64 nDataLen = aData.getLength(), nCombined = m_nEnd + nDataLen; + + if ( nCombined > m_nBufferSize) + { + do + m_nBufferSize *=2; + while (nCombined > m_nBufferSize); + m_aBuffer.realloc(static_cast < sal_Int32 > (m_nBufferSize)); + m_bMustInitBuffer = sal_False; + } + else if (m_bMustInitBuffer) + { + m_aBuffer.realloc ( static_cast < sal_Int32 > ( m_nBufferSize ) ); + m_bMustInitBuffer = sal_False; + } + memcpy( m_aBuffer.getArray() + m_nCurrent, aData.getConstArray(), static_cast < sal_Int32 > (nDataLen)); + m_nCurrent+=nDataLen; + if (m_nCurrent>m_nEnd) + m_nEnd = m_nCurrent; +} +void SAL_CALL ZipPackageBuffer::flush( ) + throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ +} +void SAL_CALL ZipPackageBuffer::closeOutput( ) + throw(NotConnectedException, BufferSizeExceededException, IOException, RuntimeException) +{ +} +void SAL_CALL ZipPackageBuffer::seek( sal_Int64 location ) + throw( IllegalArgumentException, IOException, RuntimeException) +{ + if ( location > m_nEnd || location < 0 ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); + m_nCurrent = location; +} +sal_Int64 SAL_CALL ZipPackageBuffer::getPosition( ) + throw(IOException, RuntimeException) +{ + return m_nCurrent; +} +sal_Int64 SAL_CALL ZipPackageBuffer::getLength( ) + throw(IOException, RuntimeException) +{ + return m_nEnd; +} diff --git a/package/source/zippackage/ZipPackageEntry.cxx b/package/source/zippackage/ZipPackageEntry.cxx new file mode 100644 index 000000000000..7514e7b6f55a --- /dev/null +++ b/package/source/zippackage/ZipPackageEntry.cxx @@ -0,0 +1,136 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipPackageEntry.hxx> +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <osl/diagnose.h> + +#include <ZipPackageFolder.hxx> +#include <ZipPackageStream.hxx> +#include <ContentInfo.hxx> + +#include <comphelper/storagehelper.hxx> + +using namespace rtl; +using namespace com::sun::star; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::container; +using namespace com::sun::star::packages::zip; +using namespace com::sun::star::packages::zip::ZipConstants; + +ZipPackageEntry::ZipPackageEntry ( bool bNewFolder ) +: mbIsFolder ( bNewFolder ) +, mbAllowRemoveOnInsert( sal_True ) +, pParent ( NULL ) +{ +} + +ZipPackageEntry::~ZipPackageEntry() +{ + // When the entry is destroyed it must be already disconnected from the parent + OSL_ENSURE( !pParent, "The parent must be disconnected already! Memory corruption is possible!\n" ); +} + +// XChild +OUString SAL_CALL ZipPackageEntry::getName( ) + throw(RuntimeException) +{ + return msName; +} +void SAL_CALL ZipPackageEntry::setName( const OUString& aName ) + throw(RuntimeException) +{ + if ( pParent && msName.getLength() && pParent->hasByName ( msName ) ) + pParent->removeByName ( msName ); + + // unfortunately no other exception than RuntimeException can be thrown here + // usually the package is used through storage implementation, the problem should be detected there + if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( aName, sal_True ) ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Unexpected character is used in file name." ) ), Reference< XInterface >() ); + + msName = aName; + + if ( pParent ) + pParent->doInsertByName ( this, sal_False ); +} +Reference< XInterface > SAL_CALL ZipPackageEntry::getParent( ) + throw(RuntimeException) +{ + // return Reference< XInterface >( xParent, UNO_QUERY ); + return Reference< XInterface >( static_cast< ::cppu::OWeakObject* >( pParent ), UNO_QUERY ); +} + +void ZipPackageEntry::doSetParent ( ZipPackageFolder * pNewParent, sal_Bool bInsert ) +{ + // xParent = pParent = pNewParent; + pParent = pNewParent; + if ( bInsert && msName.getLength() && !pNewParent->hasByName ( msName ) ) + pNewParent->doInsertByName ( this, sal_False ); +} + +void SAL_CALL ZipPackageEntry::setParent( const Reference< XInterface >& xNewParent ) + throw(NoSupportException, RuntimeException) +{ + sal_Int64 nTest(0); + Reference < XUnoTunnel > xTunnel ( xNewParent, UNO_QUERY ); + if ( !xNewParent.is() || ( nTest = xTunnel->getSomething ( ZipPackageFolder::static_getImplementationId () ) ) == 0 ) + throw NoSupportException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + ZipPackageFolder *pNewParent = reinterpret_cast < ZipPackageFolder * > ( nTest ); + + if ( pNewParent != pParent ) + { + if ( pParent && msName.getLength() && pParent->hasByName ( msName ) && mbAllowRemoveOnInsert ) + pParent->removeByName( msName ); + doSetParent ( pNewParent, sal_True ); + } +} + //XPropertySet +Reference< beans::XPropertySetInfo > SAL_CALL ZipPackageEntry::getPropertySetInfo( ) + throw(RuntimeException) +{ + return Reference < beans::XPropertySetInfo > (); +} +void SAL_CALL ZipPackageEntry::addPropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< beans::XPropertyChangeListener >& /*xListener*/ ) + throw(beans::UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} +void SAL_CALL ZipPackageEntry::removePropertyChangeListener( const OUString& /*aPropertyName*/, const Reference< beans::XPropertyChangeListener >& /*aListener*/ ) + throw(beans::UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} +void SAL_CALL ZipPackageEntry::addVetoableChangeListener( const OUString& /*PropertyName*/, const Reference< beans::XVetoableChangeListener >& /*aListener*/ ) + throw(beans::UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} +void SAL_CALL ZipPackageEntry::removeVetoableChangeListener( const OUString& /*PropertyName*/, const Reference< beans::XVetoableChangeListener >& /*aListener*/ ) + throw(beans::UnknownPropertyException, WrappedTargetException, RuntimeException) +{ +} diff --git a/package/source/zippackage/ZipPackageEntry.hxx b/package/source/zippackage/ZipPackageEntry.hxx new file mode 100644 index 000000000000..767d84511a12 --- /dev/null +++ b/package/source/zippackage/ZipPackageEntry.hxx @@ -0,0 +1,105 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_PACKAGE_ENTRY_HXX +#define _ZIP_PACKAGE_ENTRY_HXX + +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/lang/XUnoTunnel.hpp> +#include <com/sun/star/container/XNameContainer.hpp> +#ifndef _COM_SUN_STAR_LANG_XPSERVICEINFO_HPP_ +#include <com/sun/star/lang/XServiceInfo.hpp> +#endif +#include <ZipEntry.hxx> +#include <cppuhelper/implbase5.hxx> + +class ZipPackageFolder; + +class ZipPackageEntry : public cppu::WeakImplHelper5 +< + com::sun::star::container::XNamed, + com::sun::star::container::XChild, + com::sun::star::lang::XUnoTunnel, + com::sun::star::beans::XPropertySet, + com::sun::star::lang::XServiceInfo +> +{ +protected: + ::rtl::OUString msName; + bool mbIsFolder:1; + bool mbAllowRemoveOnInsert:1; + // com::sun::star::uno::Reference < com::sun::star::container::XNameContainer > xParent; + ::rtl::OUString sMediaType; + ZipPackageFolder * pParent; +public: + ZipEntry aEntry; + ZipPackageEntry ( bool bNewFolder = sal_False ); + virtual ~ZipPackageEntry( void ); + + ::rtl::OUString & GetMediaType () { return sMediaType; } + void SetMediaType ( const ::rtl::OUString & sNewType) { sMediaType = sNewType; } + void doSetParent ( ZipPackageFolder * pNewParent, sal_Bool bInsert ); + bool IsFolder ( ) { return mbIsFolder; } + ZipPackageFolder* GetParent ( ) { return pParent; } + void SetFolder ( bool bSetFolder ) { mbIsFolder = bSetFolder; } + + void clearParent ( void ) + { + // xParent.clear(); + pParent = NULL; + } + // XNamed + virtual ::rtl::OUString SAL_CALL getName( ) + throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setName( const ::rtl::OUString& aName ) + throw(::com::sun::star::uno::RuntimeException); + // XChild + virtual ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface > SAL_CALL getParent( ) + throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setParent( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& Parent ) + throw(::com::sun::star::lang::NoSupportException, ::com::sun::star::uno::RuntimeException); + // XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) + throw(::com::sun::star::uno::RuntimeException) = 0; + // XPropertySet + virtual ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) + throw(::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) = 0; + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException) = 0; + virtual void SAL_CALL addPropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& xListener ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removePropertyChangeListener( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XPropertyChangeListener >& aListener ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL addVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL removeVetoableChangeListener( const ::rtl::OUString& PropertyName, const ::com::sun::star::uno::Reference< ::com::sun::star::beans::XVetoableChangeListener >& aListener ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); +}; +#endif diff --git a/package/source/zippackage/ZipPackageFolder.cxx b/package/source/zippackage/ZipPackageFolder.cxx new file mode 100644 index 000000000000..0bed74128467 --- /dev/null +++ b/package/source/zippackage/ZipPackageFolder.cxx @@ -0,0 +1,803 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipPackageFolder.hxx> +#include <ZipFile.hxx> +#include <ZipOutputStream.hxx> +#include <ZipPackageStream.hxx> +#include <PackageConstants.hxx> +#include <ZipPackageFolderEnumeration.hxx> +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <vos/diagnose.hxx> +#include <osl/time.h> +#include <rtl/digest.h> +#include <ContentInfo.hxx> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <EncryptedDataHeader.hxx> +#include <rtl/random.h> +#include <memory> + +using namespace com::sun::star::packages::zip::ZipConstants; +using namespace com::sun::star::packages::zip; +using namespace com::sun::star::container; +using namespace com::sun::star::packages; +using namespace com::sun::star::beans; +using namespace com::sun::star::lang; +using namespace com::sun::star::uno; +using namespace com::sun::star::io; +using namespace cppu; +using namespace rtl; +using namespace std; +using namespace ::com::sun::star; +using vos::ORef; + +Sequence < sal_Int8 > ZipPackageFolder::aImplementationId = Sequence < sal_Int8 > (); + +ZipPackageFolder::ZipPackageFolder ( const Reference< XMultiServiceFactory >& xFactory, + sal_Int16 nFormat, + sal_Bool bAllowRemoveOnInsert ) +: m_xFactory( xFactory ) +, m_nFormat( nFormat ) +{ + OSL_ENSURE( m_xFactory.is(), "No factory is provided to the package folder!" ); + + this->mbAllowRemoveOnInsert = bAllowRemoveOnInsert; + + SetFolder ( sal_True ); + aEntry.nVersion = -1; + aEntry.nFlag = 0; + aEntry.nMethod = STORED; + aEntry.nTime = -1; + aEntry.nCrc = 0; + aEntry.nCompressedSize = 0; + aEntry.nSize = 0; + aEntry.nOffset = -1; + if ( !aImplementationId.getLength() ) + { + aImplementationId = getImplementationId(); + } +} + + +ZipPackageFolder::~ZipPackageFolder() +{ +} + +sal_Bool ZipPackageFolder::LookForUnexpectedODF12Streams( const ::rtl::OUString& aPath ) +{ + sal_Bool bHasUnexpected = sal_False; + + for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end(); + !bHasUnexpected && aCI != aEnd; + aCI++) + { + const OUString &rShortName = (*aCI).first; + const ContentInfo &rInfo = *(*aCI).second; + + if ( rInfo.bFolder ) + { + if ( aPath.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "META-INF/" ) ) ) ) + { + // META-INF is not allowed to contain subfolders + bHasUnexpected = sal_True; + } + else + { + OUString sOwnPath = aPath + rShortName + OUString( RTL_CONSTASCII_USTRINGPARAM ( "/" ) ); + bHasUnexpected = rInfo.pFolder->LookForUnexpectedODF12Streams( sOwnPath ); + } + } + else + { + if ( aPath.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "META-INF/" ) ) ) ) + { + if ( !rShortName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "manifest.xml" ) ) ) + && rShortName.indexOf( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "signatures" ) ) ) == -1 ) + { + // a stream from META-INF with unexpected name + bHasUnexpected = sal_True; + } + + // streams from META-INF with expected names are allowed not to be registered in manifest.xml + } + else if ( !rInfo.pStream->IsFromManifest() ) + { + // the stream is not in META-INF and ist notregistered in manifest.xml, + // check whether it is an internal part of the package format + if ( aPath.getLength() + || !rShortName.equals( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "mimetype" ) ) ) ) + { + // if it is not "mimetype" from the root it is not a part of the package + bHasUnexpected = sal_True; + } + } + } + } + + return bHasUnexpected; +} + +void ZipPackageFolder::setChildStreamsTypeByExtension( const beans::StringPair& aPair ) +{ + ::rtl::OUString aExt; + if ( aPair.First.toChar() == (sal_Unicode)'.' ) + aExt = aPair.First; + else + aExt = ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "." ) ) + aPair.First; + + for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end(); + aCI != aEnd; + aCI++) + { + const OUString &rShortName = (*aCI).first; + const ContentInfo &rInfo = *(*aCI).second; + + if ( rInfo.bFolder ) + rInfo.pFolder->setChildStreamsTypeByExtension( aPair ); + else + { + sal_Int32 nPathLength = rShortName.getLength(); + sal_Int32 nExtLength = aExt.getLength(); + if ( nPathLength >= nExtLength && rShortName.match( aExt, nPathLength - nExtLength ) ) + rInfo.pStream->SetMediaType( aPair.Second ); + } + } +} + +void ZipPackageFolder::copyZipEntry( ZipEntry &rDest, const ZipEntry &rSource) +{ + rDest.nVersion = rSource.nVersion; + rDest.nFlag = rSource.nFlag; + rDest.nMethod = rSource.nMethod; + rDest.nTime = rSource.nTime; + rDest.nCrc = rSource.nCrc; + rDest.nCompressedSize = rSource.nCompressedSize; + rDest.nSize = rSource.nSize; + rDest.nOffset = rSource.nOffset; + rDest.sPath = rSource.sPath; + rDest.nPathLen = rSource.nPathLen; + rDest.nExtraLen = rSource.nExtraLen; +} + + // XNameContainer +void SAL_CALL ZipPackageFolder::insertByName( const OUString& aName, const Any& aElement ) + throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException) +{ + if (hasByName(aName)) + throw ElementExistException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + else + { + Reference < XUnoTunnel > xRef; + aElement >>= xRef; + if ( ( aElement >>= xRef ) ) + { + sal_Int64 nTest; + ZipPackageEntry *pEntry; + if ( ( nTest = xRef->getSomething ( ZipPackageFolder::static_getImplementationId() ) ) != 0 ) + { + ZipPackageFolder *pFolder = reinterpret_cast < ZipPackageFolder * > ( nTest ); + pEntry = static_cast < ZipPackageEntry * > ( pFolder ); + } + else if ( ( nTest = xRef->getSomething ( ZipPackageStream::static_getImplementationId() ) ) != 0 ) + { + ZipPackageStream *pStream = reinterpret_cast < ZipPackageStream * > ( nTest ); + pEntry = static_cast < ZipPackageEntry * > ( pStream ); + } + else + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); + + if (pEntry->getName() != aName ) + pEntry->setName (aName); + doInsertByName ( pEntry, sal_True ); + } + else + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 0 ); + } +} +void SAL_CALL ZipPackageFolder::removeByName( const OUString& Name ) + throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + ContentHash::iterator aIter = maContents.find ( Name ); + if ( aIter == maContents.end() ) + throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + maContents.erase( aIter ); +} + // XEnumerationAccess +Reference< XEnumeration > SAL_CALL ZipPackageFolder::createEnumeration( ) + throw(RuntimeException) +{ + return Reference < XEnumeration> (new ZipPackageFolderEnumeration(maContents)); +} + // XElementAccess +Type SAL_CALL ZipPackageFolder::getElementType( ) + throw(RuntimeException) +{ + return ::getCppuType ((const Reference< XUnoTunnel > *) 0); +} +sal_Bool SAL_CALL ZipPackageFolder::hasElements( ) + throw(RuntimeException) +{ + return maContents.size() > 0; +} + // XNameAccess +ContentInfo& ZipPackageFolder::doGetByName( const OUString& aName ) + throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + ContentHash::iterator aIter = maContents.find ( aName ); + if ( aIter == maContents.end()) + throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + return *(*aIter).second; +} +Any SAL_CALL ZipPackageFolder::getByName( const OUString& aName ) + throw(NoSuchElementException, WrappedTargetException, RuntimeException) +{ + return makeAny ( doGetByName ( aName ).xTunnel ); +} +Sequence< OUString > SAL_CALL ZipPackageFolder::getElementNames( ) + throw(RuntimeException) +{ + sal_uInt32 i=0, nSize = maContents.size(); + Sequence < OUString > aSequence ( nSize ); + OUString *pNames = aSequence.getArray(); + for ( ContentHash::const_iterator aIterator = maContents.begin(), aEnd = maContents.end(); + aIterator != aEnd; + ++i, ++aIterator) + pNames[i] = (*aIterator).first; + return aSequence; +} +sal_Bool SAL_CALL ZipPackageFolder::hasByName( const OUString& aName ) + throw(RuntimeException) +{ + return maContents.find ( aName ) != maContents.end (); +} + // XNameReplace +void SAL_CALL ZipPackageFolder::replaceByName( const OUString& aName, const Any& aElement ) + throw(IllegalArgumentException, NoSuchElementException, WrappedTargetException, RuntimeException) +{ + if ( hasByName( aName ) ) + removeByName( aName ); + else + throw NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + insertByName(aName, aElement); +} + +static void ImplSetStoredData( ZipEntry & rEntry, Reference < XInputStream> & rStream ) +{ + // It's very annoying that we have to do this, but lots of zip packages + // don't allow data descriptors for STORED streams, meaning we have to + // know the size and CRC32 of uncompressed streams before we actually + // write them ! + CRC32 aCRC32; + rEntry.nMethod = STORED; + rEntry.nCompressedSize = rEntry.nSize = aCRC32.updateStream ( rStream ); + rEntry.nCrc = aCRC32.getValue(); +} + +void ZipPackageFolder::saveContents(OUString &rPath, std::vector < Sequence < PropertyValue > > &rManList, ZipOutputStream & rZipOut, Sequence < sal_Int8 > &rEncryptionKey, rtlRandomPool &rRandomPool) + throw(RuntimeException) +{ + sal_Bool bWritingFailed = sal_False; + ZipPackageFolder *pFolder = NULL; + ZipPackageStream *pStream = NULL; + const OUString sMediaTypeProperty ( RTL_CONSTASCII_USTRINGPARAM ( "MediaType" ) ); + const OUString sVersionProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Version" ) ); + const OUString sFullPathProperty ( RTL_CONSTASCII_USTRINGPARAM ( "FullPath" ) ); + const OUString sInitialisationVectorProperty ( RTL_CONSTASCII_USTRINGPARAM ( "InitialisationVector" ) ); + const OUString sSaltProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Salt" ) ); + const OUString sIterationCountProperty ( RTL_CONSTASCII_USTRINGPARAM ( "IterationCount" ) ); + const OUString sSizeProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Size" ) ); + const OUString sDigestProperty ( RTL_CONSTASCII_USTRINGPARAM ( "Digest" ) ); + + sal_Bool bHaveEncryptionKey = rEncryptionKey.getLength() ? sal_True : sal_False; + + if ( maContents.begin() == maContents.end() && rPath.getLength() && m_nFormat != OFOPXML_FORMAT ) + { + // it is an empty subfolder, use workaround to store it + ZipEntry* pTempEntry = new ZipEntry(); + ZipPackageFolder::copyZipEntry ( *pTempEntry, aEntry ); + pTempEntry->nPathLen = (sal_Int16)( ::rtl::OUStringToOString( rPath, RTL_TEXTENCODING_UTF8 ).getLength() ); + pTempEntry->nExtraLen = -1; + pTempEntry->sPath = rPath; + + try + { + vos::ORef < EncryptionData > aEmptyEncr; + rZipOut.putNextEntry ( *pTempEntry, aEmptyEncr, sal_False ); + rZipOut.rawCloseEntry(); + } + catch ( ZipException& ) + { + VOS_ENSURE( 0, "Error writing ZipOutputStream" ); + bWritingFailed = sal_True; + } + catch ( IOException& ) + { + VOS_ENSURE( 0, "Error writing ZipOutputStream" ); + bWritingFailed = sal_True; + } + } + + for ( ContentHash::const_iterator aCI = maContents.begin(), aEnd = maContents.end(); + aCI != aEnd; + aCI++) + { + const OUString &rShortName = (*aCI).first; + const ContentInfo &rInfo = *(*aCI).second; + + Sequence < PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST); + PropertyValue *pValue = aPropSet.getArray(); + + if ( rInfo.bFolder ) + pFolder = rInfo.pFolder; + else + pStream = rInfo.pStream; + + if ( rInfo.bFolder ) + { + OUString sTempName = rPath + rShortName + OUString( RTL_CONSTASCII_USTRINGPARAM ( "/" ) ); + + pValue[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty; + pValue[PKG_MNFST_MEDIATYPE].Value <<= pFolder->GetMediaType(); + pValue[PKG_MNFST_VERSION].Name = sVersionProperty; + pValue[PKG_MNFST_VERSION].Value <<= pFolder->GetVersion(); + pValue[PKG_MNFST_FULLPATH].Name = sFullPathProperty; + pValue[PKG_MNFST_FULLPATH].Value <<= sTempName; + + pFolder->saveContents( sTempName, rManList, rZipOut, rEncryptionKey, rRandomPool); + } + else + { + // if pTempEntry is necessary, it will be released and passed to the ZipOutputStream + // and be deleted in the ZipOutputStream destructor + auto_ptr < ZipEntry > pAutoTempEntry ( new ZipEntry ); + ZipEntry* pTempEntry = pAutoTempEntry.get(); + + // In case the entry we are reading is also the entry we are writing, we will + // store the ZipEntry data in pTempEntry + + ZipPackageFolder::copyZipEntry ( *pTempEntry, pStream->aEntry ); + pTempEntry->sPath = rPath + rShortName; + pTempEntry->nPathLen = (sal_Int16)( ::rtl::OUStringToOString( pTempEntry->sPath, RTL_TEXTENCODING_UTF8 ).getLength() ); + + sal_Bool bToBeEncrypted = pStream->IsToBeEncrypted() && (bHaveEncryptionKey || pStream->HasOwnKey()); + sal_Bool bToBeCompressed = bToBeEncrypted ? sal_True : pStream->IsToBeCompressed(); + + pValue[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty; + pValue[PKG_MNFST_MEDIATYPE].Value <<= pStream->GetMediaType( ); + pValue[PKG_MNFST_VERSION].Name = sVersionProperty; + pValue[PKG_MNFST_VERSION].Value <<= ::rtl::OUString(); // no version is stored for streams currently + pValue[PKG_MNFST_FULLPATH].Name = sFullPathProperty; + pValue[PKG_MNFST_FULLPATH].Value <<= pTempEntry->sPath; + + + OSL_ENSURE( pStream->GetStreamMode() != PACKAGE_STREAM_NOTSET, "Unacceptable ZipPackageStream mode!" ); + + sal_Bool bRawStream = sal_False; + if ( pStream->GetStreamMode() == PACKAGE_STREAM_DETECT ) + bRawStream = pStream->ParsePackageRawStream(); + else if ( pStream->GetStreamMode() == PACKAGE_STREAM_RAW ) + bRawStream = sal_True; + + sal_Bool bTransportOwnEncrStreamAsRaw = sal_False; + // During the storing the original size of the stream can be changed + // TODO/LATER: get rid of this hack + sal_Int32 nOwnStreamOrigSize = bRawStream ? pStream->GetMagicalHackSize() : pStream->getSize(); + + sal_Bool bUseNonSeekableAccess = sal_False; + Reference < XInputStream > xStream; + if ( !pStream->IsPackageMember() && !bRawStream && !bToBeEncrypted && bToBeCompressed ) + { + // the stream is not a package member, not a raw stream, + // it should not be encrypted and it should be compressed, + // in this case nonseekable access can be used + + xStream = pStream->GetOwnStreamNoWrap(); + Reference < XSeekable > xSeek ( xStream, UNO_QUERY ); + + bUseNonSeekableAccess = ( xStream.is() && !xSeek.is() ); + } + + if ( !bUseNonSeekableAccess ) + { + xStream = pStream->getRawData(); + + if ( !xStream.is() ) + { + VOS_ENSURE( 0, "ZipPackageStream didn't have a stream associated with it, skipping!" ); + bWritingFailed = sal_True; + continue; + } + + Reference < XSeekable > xSeek ( xStream, UNO_QUERY ); + try + { + if ( xSeek.is() ) + { + // If the stream is a raw one, then we should be positioned + // at the beginning of the actual data + if ( !bToBeCompressed || bRawStream ) + { + // The raw stream can neither be encrypted nor connected + OSL_ENSURE( !bRawStream || !bToBeCompressed && !bToBeEncrypted, "The stream is already encrypted!\n" ); + xSeek->seek ( bRawStream ? pStream->GetMagicalHackPos() : 0 ); + ImplSetStoredData ( *pTempEntry, xStream ); + + // TODO/LATER: Get rid of hacks related to switching of Flag Method and Size properties! + } + else if ( bToBeEncrypted ) + { + // this is the correct original size + pTempEntry->nSize = static_cast < sal_Int32 > ( xSeek->getLength() ); + nOwnStreamOrigSize = pTempEntry->nSize; + } + + xSeek->seek ( 0 ); + } + else + { + // Okay, we don't have an xSeekable stream. This is possibly bad. + // check if it's one of our own streams, if it is then we know that + // each time we ask for it we'll get a new stream that will be + // at position zero...otherwise, assert and skip this stream... + if ( pStream->IsPackageMember() ) + { + // if the password has been changed than the stream should not be package member any more + if ( pStream->IsEncrypted() && pStream->IsToBeEncrypted() ) + { + // Should be handled close to the raw stream handling + bTransportOwnEncrStreamAsRaw = sal_True; + pTempEntry->nMethod = STORED; + + // TODO/LATER: get rid of this situation + // this size should be different from the one that will be stored in manifest.xml + // it is used in storing algorithms and after storing the correct size will be set + pTempEntry->nSize = pTempEntry->nCompressedSize; + } + } + else + { + VOS_ENSURE( 0, "The package component requires that every stream either be FROM a package or it must support XSeekable!" ); + continue; + } + } + } + catch ( Exception& ) + { + VOS_ENSURE( 0, "The stream provided to the package component has problems!" ); + bWritingFailed = sal_True; + continue; + } + + if ( bToBeEncrypted || bRawStream || bTransportOwnEncrStreamAsRaw ) + { + if ( bToBeEncrypted && !bTransportOwnEncrStreamAsRaw ) + { + Sequence < sal_uInt8 > aSalt ( 16 ), aVector ( 8 ); + rtl_random_getBytes ( rRandomPool, aSalt.getArray(), 16 ); + rtl_random_getBytes ( rRandomPool, aVector.getArray(), 8 ); + sal_Int32 nIterationCount = 1024; + + if ( !pStream->HasOwnKey() ) + pStream->setKey ( rEncryptionKey ); + + pStream->setInitialisationVector ( aVector ); + pStream->setSalt ( aSalt ); + pStream->setIterationCount ( nIterationCount ); + } + + // last property is digest, which is inserted later if we didn't have + // a magic header + aPropSet.realloc(PKG_SIZE_ENCR_MNFST); + + pValue = aPropSet.getArray(); + pValue[PKG_MNFST_INIVECTOR].Name = sInitialisationVectorProperty; + pValue[PKG_MNFST_INIVECTOR].Value <<= pStream->getInitialisationVector(); + pValue[PKG_MNFST_SALT].Name = sSaltProperty; + pValue[PKG_MNFST_SALT].Value <<= pStream->getSalt(); + pValue[PKG_MNFST_ITERATION].Name = sIterationCountProperty; + pValue[PKG_MNFST_ITERATION].Value <<= pStream->getIterationCount (); + + // Need to store the uncompressed size in the manifest + OSL_ENSURE( nOwnStreamOrigSize >= 0, "The stream size was not correctly initialized!\n" ); + pValue[PKG_MNFST_UCOMPSIZE].Name = sSizeProperty; + pValue[PKG_MNFST_UCOMPSIZE].Value <<= nOwnStreamOrigSize; + + if ( bRawStream || bTransportOwnEncrStreamAsRaw ) + { + pValue[PKG_MNFST_DIGEST].Name = sDigestProperty; + pValue[PKG_MNFST_DIGEST].Value <<= pStream->getDigest(); + } + } + } + + // If the entry is already stored in the zip file in the format we + // want for this write...copy it raw + if ( !bUseNonSeekableAccess && + ( bRawStream || bTransportOwnEncrStreamAsRaw || + ( pStream->IsPackageMember() && !bToBeEncrypted && + ( pStream->aEntry.nMethod == DEFLATED && bToBeCompressed ) || + ( pStream->aEntry.nMethod == STORED && !bToBeCompressed ) ) ) ) + { + // If it's a PackageMember, then it's an unbuffered stream and we need + // to get a new version of it as we can't seek backwards. + if ( pStream->IsPackageMember() ) + { + xStream = pStream->getRawData(); + if ( !xStream.is() ) + { + // Make sure that we actually _got_ a new one ! + VOS_ENSURE( 0, "ZipPackageStream didn't have a stream associated with it, skipping!" ); + continue; + } + } + + try + { + if ( bRawStream ) + xStream->skipBytes( pStream->GetMagicalHackPos() ); + + rZipOut.putNextEntry ( *pTempEntry, pStream->getEncryptionData(), sal_False ); + // the entry is provided to the ZipOutputStream that will delete it + pAutoTempEntry.release(); + + Sequence < sal_Int8 > aSeq ( n_ConstBufferSize ); + sal_Int32 nLength; + + do + { + nLength = xStream->readBytes( aSeq, n_ConstBufferSize ); + rZipOut.rawWrite(aSeq, 0, nLength); + } + while ( nLength == n_ConstBufferSize ); + + rZipOut.rawCloseEntry(); + } + catch ( ZipException& ) + { + VOS_ENSURE( 0, "Error writing ZipOutputStream" ); + bWritingFailed = sal_True; + } + catch ( IOException& ) + { + VOS_ENSURE( 0, "Error writing ZipOutputStream" ); + bWritingFailed = sal_True; + } + } + else + { + // This stream is defenitly not a raw stream + + // If nonseekable access is used the stream should be at the beginning and + // is useless after the storing. Thus if the storing fails the package should + // be thrown away ( as actually it is done currently )! + // To allow to reuse the package after the error, the optimization must be removed! + + // If it's a PackageMember, then our previous reference held a 'raw' stream + // so we need to re-get it, unencrypted, uncompressed and positioned at the + // beginning of the stream + if ( pStream->IsPackageMember() ) + { + xStream = pStream->getInputStream(); + if ( !xStream.is() ) + { + // Make sure that we actually _got_ a new one ! + VOS_ENSURE( 0, "ZipPackageStream didn't have a stream associated with it, skipping!" ); + continue; + } + } + + if ( bToBeCompressed ) + { + pTempEntry->nMethod = DEFLATED; + pTempEntry->nCrc = pTempEntry->nCompressedSize = pTempEntry->nSize = -1; + } + + try + { + rZipOut.putNextEntry ( *pTempEntry, pStream->getEncryptionData(), bToBeEncrypted); + // the entry is provided to the ZipOutputStream that will delete it + pAutoTempEntry.release(); + + sal_Int32 nLength; + Sequence < sal_Int8 > aSeq (n_ConstBufferSize); + do + { + nLength = xStream->readBytes(aSeq, n_ConstBufferSize); + rZipOut.write(aSeq, 0, nLength); + } + while ( nLength == n_ConstBufferSize ); + + rZipOut.closeEntry(); + } + catch ( ZipException& ) + { + VOS_ENSURE( 0, "Error writing ZipOutputStream" ); + bWritingFailed = sal_True; + } + catch ( IOException& ) + { + VOS_ENSURE( 0, "Error writing ZipOutputStream" ); + bWritingFailed = sal_True; + } + + if ( bToBeEncrypted ) + { + pValue[PKG_MNFST_DIGEST].Name = sDigestProperty; + pValue[PKG_MNFST_DIGEST].Value <<= pStream->getDigest(); + pStream->SetIsEncrypted ( sal_True ); + } + } + + if( !bWritingFailed ) + { + if ( !pStream->IsPackageMember() ) + { + pStream->CloseOwnStreamIfAny(); + pStream->SetPackageMember ( sal_True ); + } + + if ( bRawStream ) + { + // the raw stream was integrated and now behaves + // as usual encrypted stream + pStream->SetToBeEncrypted( sal_True ); + } + + // Remove hacky bit from entry flags + if ( pTempEntry->nFlag & ( 1 << 4 ) ) + { + pTempEntry->nFlag &= ~( 1 << 4 ); + pTempEntry->nMethod = STORED; + } + + // Then copy it back afterwards... + ZipPackageFolder::copyZipEntry ( pStream->aEntry, *pTempEntry ); + + // TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving ) + if ( pStream->IsEncrypted() ) + pStream->setSize( nOwnStreamOrigSize ); + + pStream->aEntry.nOffset *= -1; + } + } + + // folder can have a mediatype only in package format + if ( m_nFormat == PACKAGE_FORMAT || ( m_nFormat == OFOPXML_FORMAT && !rInfo.bFolder ) ) + rManList.push_back( aPropSet ); + } + + if( bWritingFailed ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +void ZipPackageFolder::releaseUpwardRef( void ) +{ + // Now it is possible that a package folder is disconnected from the package before removing of the folder. + // Such a scenario is used in storage implementation. When a new version of a folder is provided the old + // one is retrieved, removed from the package but preserved for the error handling. + // In this scenario the referencing to the parent is not really useful, since it requires disposing. + + // Actually there is no need in having a reference to the parent, it even make things more complicated and + // requires disposing mechanics. Using of a simple pointer seems to be easier solution and also a safe enough. + + clearParent(); + +#if 0 + for ( ContentHash::const_iterator aCI = maContents.begin(); + aCI!=maContents.end(); + aCI++) + { + ContentInfo &rInfo = * (*aCI).second; + if ( rInfo.bFolder )// && ! rInfo.pFolder->HasReleased () ) + rInfo.pFolder->releaseUpwardRef(); + else //if ( !rInfo.bFolder && !rInfo.pStream->HasReleased() ) + rInfo.pStream->clearParent(); + } + clearParent(); + + VOS_ENSURE ( m_refCount == 1, "Ref-count is not 1!" ); +#endif +} + +sal_Int64 SAL_CALL ZipPackageFolder::getSomething( const Sequence< sal_Int8 >& aIdentifier ) + throw(RuntimeException) +{ + sal_Int64 nMe = 0; + if ( aIdentifier.getLength() == 16 && + 0 == rtl_compareMemory(static_getImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) ) + nMe = reinterpret_cast < sal_Int64 > ( this ); + return nMe; +} +void SAL_CALL ZipPackageFolder::setPropertyValue( const OUString& aPropertyName, const Any& aValue ) + throw(UnknownPropertyException, PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("MediaType"))) + { + // TODO/LATER: activate when zip ucp is ready + // if ( m_nFormat != PACKAGE_FORMAT ) + // throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + aValue >>= sMediaType; + } + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Version"))) + aValue >>= m_sVersion; + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Size") ) ) + aValue >>= aEntry.nSize; + else + throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} +Any SAL_CALL ZipPackageFolder::getPropertyValue( const OUString& PropertyName ) + throw(UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ) + { + // TODO/LATER: activate when zip ucp is ready + // if ( m_nFormat != PACKAGE_FORMAT ) + // throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return makeAny ( sMediaType ); + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "Version" ) ) ) + return makeAny( m_sVersion ); + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "Size" ) ) ) + return makeAny ( aEntry.nSize ); + else + throw UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +void ZipPackageFolder::doInsertByName ( ZipPackageEntry *pEntry, sal_Bool bSetParent ) + throw(IllegalArgumentException, ElementExistException, WrappedTargetException, RuntimeException) +{ + if ( pEntry->IsFolder() ) + maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageFolder *> ( pEntry ) ); + else + maContents[pEntry->getName()] = new ContentInfo ( static_cast < ZipPackageStream *> ( pEntry ) ); + + if ( bSetParent ) + pEntry->setParent ( *this ); +} +OUString ZipPackageFolder::getImplementationName() + throw (RuntimeException) +{ + return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "ZipPackageFolder" ) ); +} + +Sequence< OUString > ZipPackageFolder::getSupportedServiceNames() + throw (RuntimeException) +{ + Sequence< OUString > aNames(1); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.PackageFolder" ) ); + return aNames; +} +sal_Bool SAL_CALL ZipPackageFolder::supportsService( OUString const & rServiceName ) + throw (RuntimeException) +{ + return rServiceName == getSupportedServiceNames()[0]; +} diff --git a/package/source/zippackage/ZipPackageFolderEnumeration.cxx b/package/source/zippackage/ZipPackageFolderEnumeration.cxx new file mode 100644 index 000000000000..562e42d9e266 --- /dev/null +++ b/package/source/zippackage/ZipPackageFolderEnumeration.cxx @@ -0,0 +1,79 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipPackageFolderEnumeration.hxx> +#include <ContentInfo.hxx> + +using namespace com::sun::star; +using rtl::OUString; + +ZipPackageFolderEnumeration::ZipPackageFolderEnumeration ( ContentHash &rInput) +: rContents (rInput) +, aIterator (rContents.begin()) +{ +} + +ZipPackageFolderEnumeration::~ZipPackageFolderEnumeration( void ) +{ +} + +sal_Bool SAL_CALL ZipPackageFolderEnumeration::hasMoreElements( ) + throw(uno::RuntimeException) +{ + return (aIterator != rContents.end() ); +} +uno::Any SAL_CALL ZipPackageFolderEnumeration::nextElement( ) + throw(container::NoSuchElementException, lang::WrappedTargetException, uno::RuntimeException) +{ + uno::Any aAny; + if (aIterator == rContents.end() ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + aAny <<= (*aIterator).second->xTunnel; + aIterator++; + return aAny; +} + +OUString ZipPackageFolderEnumeration::getImplementationName() + throw (uno::RuntimeException) +{ + return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "ZipPackageFolderEnumeration" ) ); +} + +uno::Sequence< OUString > ZipPackageFolderEnumeration::getSupportedServiceNames() + throw (uno::RuntimeException) +{ + uno::Sequence< OUString > aNames(1); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.PackageFolderEnumeration" ) ); + return aNames; +} +sal_Bool SAL_CALL ZipPackageFolderEnumeration::supportsService( OUString const & rServiceName ) + throw (uno::RuntimeException) +{ + return rServiceName == getSupportedServiceNames()[0]; +} diff --git a/package/source/zippackage/ZipPackageFolderEnumeration.hxx b/package/source/zippackage/ZipPackageFolderEnumeration.hxx new file mode 100644 index 000000000000..bea038d684f3 --- /dev/null +++ b/package/source/zippackage/ZipPackageFolderEnumeration.hxx @@ -0,0 +1,68 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_PACKAGE_FOLDER_ENUMERATION_HXX +#define _ZIP_PACKAGE_FOLDER_ENUMERATION_HXX + +#include <cppuhelper/implbase2.hxx> // helper for implementations +#include <com/sun/star/container/XEnumeration.hpp> +#ifndef _COM_SUN_STAR_LANG_XPSERVICEINFO_HPP_ +#include <com/sun/star/lang/XServiceInfo.hpp> +#endif +#ifndef _HASH_MAPS_HXX +#include <HashMaps.hxx> +#endif + +class ZipPackageFolderEnumeration : public cppu::WeakImplHelper2 +< + com::sun::star::container::XEnumeration, + com::sun::star::lang::XServiceInfo +> +{ +protected: + ContentHash& rContents; + ContentHash::const_iterator aIterator; +public: + //ZipPackageFolderEnumeration (std::hash_map < rtl::OUString, com::sun::star::uno::Reference < com::sun::star::container::XNamed >, hashFunc, eqFunc > &rInput); + ZipPackageFolderEnumeration (ContentHash &rInput); + virtual ~ZipPackageFolderEnumeration( void ); + + // XEnumeration + virtual sal_Bool SAL_CALL hasMoreElements( ) + throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL nextElement( ) + throw(::com::sun::star::container::NoSuchElementException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) + throw (::com::sun::star::uno::RuntimeException); + +}; +#endif diff --git a/package/source/zippackage/ZipPackageSink.cxx b/package/source/zippackage/ZipPackageSink.cxx new file mode 100644 index 000000000000..9a42138a5cb1 --- /dev/null +++ b/package/source/zippackage/ZipPackageSink.cxx @@ -0,0 +1,48 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <ZipPackageSink.hxx> + +ZipPackageSink::ZipPackageSink(void) +: xStream ( com::sun::star::uno::Reference < com::sun::star::io::XInputStream > (NULL)) +{ +} +ZipPackageSink::~ZipPackageSink(void) +{ +} +void SAL_CALL ZipPackageSink::setInputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& aStream ) + throw(::com::sun::star::uno::RuntimeException) +{ + xStream = aStream; +} +::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL ZipPackageSink::getInputStream( ) + throw(::com::sun::star::uno::RuntimeException) +{ + return xStream; +} diff --git a/package/source/zippackage/ZipPackageSink.hxx b/package/source/zippackage/ZipPackageSink.hxx new file mode 100644 index 000000000000..95dac72a836b --- /dev/null +++ b/package/source/zippackage/ZipPackageSink.hxx @@ -0,0 +1,48 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_PACKAGE_SINK_HXX +#define _ZIP_PACKAGE_SINK_HXX + +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <cppuhelper/implbase1.hxx> + +class ZipPackageSink : public ::cppu::WeakImplHelper1 +< + com::sun::star::io::XActiveDataSink +> +{ +protected: + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xStream; +public: + ZipPackageSink(); + virtual ~ZipPackageSink(); + virtual void SAL_CALL setInputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& aStream ) + throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream( ) + throw(::com::sun::star::uno::RuntimeException); +}; +#endif diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx new file mode 100644 index 000000000000..b6893b5cb2ad --- /dev/null +++ b/package/source/zippackage/ZipPackageStream.cxx @@ -0,0 +1,796 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <com/sun/star/packages/zip/ZipConstants.hpp> +#include <com/sun/star/packages/zip/ZipIOException.hpp> +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XOutputStream.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> + + +#include <ZipPackageStream.hxx> +#include <ZipPackage.hxx> +#include <ZipFile.hxx> +#include <EncryptedDataHeader.hxx> +#include <vos/diagnose.hxx> +#include "wrapstreamforshare.hxx" + +#include <comphelper/seekableinput.hxx> +#include <comphelper/storagehelper.hxx> + +#include <PackageConstants.hxx> + +using namespace com::sun::star::packages::zip::ZipConstants; +using namespace com::sun::star::packages::zip; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star; +using namespace cppu; +using namespace rtl; + +Sequence < sal_Int8 > ZipPackageStream::aImplementationId = Sequence < sal_Int8 > (); + + +ZipPackageStream::ZipPackageStream ( ZipPackage & rNewPackage, + const Reference< XMultiServiceFactory >& xFactory, + sal_Bool bAllowRemoveOnInsert ) +: m_xFactory( xFactory ) +, rZipPackage(rNewPackage) +, bToBeCompressed ( sal_True ) +, bToBeEncrypted ( sal_False ) +, bHaveOwnKey ( sal_False ) +, bIsEncrypted ( sal_False ) +, xEncryptionData ( ) +, m_nStreamMode( PACKAGE_STREAM_NOTSET ) +, m_nMagicalHackPos( 0 ) +, m_nMagicalHackSize( 0 ) +, m_bHasSeekable( sal_False ) +, m_bCompressedIsSetFromOutside( sal_False ) +, m_bFromManifest( sal_False ) +{ + OSL_ENSURE( m_xFactory.is(), "No factory is provided to ZipPackageStream!\n" ); + + this->mbAllowRemoveOnInsert = bAllowRemoveOnInsert; + + SetFolder ( sal_False ); + aEntry.nVersion = -1; + aEntry.nFlag = 0; + aEntry.nMethod = -1; + aEntry.nTime = -1; + aEntry.nCrc = -1; + aEntry.nCompressedSize = -1; + aEntry.nSize = -1; + aEntry.nOffset = -1; + aEntry.nPathLen = -1; + aEntry.nExtraLen = -1; + + if ( !aImplementationId.getLength() ) + { + aImplementationId = getImplementationId(); + } +} + +ZipPackageStream::~ZipPackageStream( void ) +{ +} + +void ZipPackageStream::setZipEntryOnLoading( const ZipEntry &rInEntry) +{ + aEntry.nVersion = rInEntry.nVersion; + aEntry.nFlag = rInEntry.nFlag; + aEntry.nMethod = rInEntry.nMethod; + aEntry.nTime = rInEntry.nTime; + aEntry.nCrc = rInEntry.nCrc; + aEntry.nCompressedSize = rInEntry.nCompressedSize; + aEntry.nSize = rInEntry.nSize; + aEntry.nOffset = rInEntry.nOffset; + aEntry.sPath = rInEntry.sPath; + aEntry.nPathLen = rInEntry.nPathLen; + aEntry.nExtraLen = rInEntry.nExtraLen; + + if ( aEntry.nMethod == STORED ) + bToBeCompressed = sal_False; +} + +//-------------------------------------------------------------------------- +void ZipPackageStream::CloseOwnStreamIfAny() +{ + if ( xStream.is() ) + { + xStream->closeInput(); + xStream = uno::Reference< io::XInputStream >(); + m_bHasSeekable = sal_False; + } +} + +//-------------------------------------------------------------------------- +uno::Reference< io::XInputStream >& ZipPackageStream::GetOwnSeekStream() +{ + if ( !m_bHasSeekable && xStream.is() ) + { + // The package component requires that every stream either be FROM a package or it must support XSeekable! + // The only exception is a nonseekable stream that is provided only for storing, if such a stream + // is accessed before commit it MUST be wrapped. + // Wrap the stream in case it is not seekable + xStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( xStream, m_xFactory ); + Reference< io::XSeekable > xSeek( xStream, UNO_QUERY ); + if ( !xSeek.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "The stream must support XSeekable!" ) ), + Reference< XInterface >() ); + + m_bHasSeekable = sal_True; + } + + return xStream; +} + +//-------------------------------------------------------------------------- +uno::Reference< io::XInputStream > ZipPackageStream::GetRawEncrStreamNoHeaderCopy() +{ + if ( m_nStreamMode != PACKAGE_STREAM_RAW || !GetOwnSeekStream().is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( xEncryptionData.isEmpty() ) + throw ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Encrypted stream without encryption data!\n" ) ), + Reference< XInterface >() ); + + uno::Reference< io::XSeekable > xSeek( GetOwnSeekStream(), UNO_QUERY ); + if ( !xSeek.is() ) + throw ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "The stream must be seekable!\n" ) ), + Reference< XInterface >() ); + + // skip header + xSeek->seek( n_ConstHeaderSize + xEncryptionData->aInitVector.getLength() + + xEncryptionData->aSalt.getLength() + xEncryptionData->aDigest.getLength() ); + + // create temporary stream + uno::Reference < io::XOutputStream > xTempOut( + m_xFactory->createInstance( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ), + uno::UNO_QUERY ); + uno::Reference < io::XInputStream > xTempIn( xTempOut, UNO_QUERY ); + uno::Reference < io::XSeekable > xTempSeek( xTempOut, UNO_QUERY ); + if ( !xTempOut.is() || !xTempIn.is() || !xTempSeek.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // copy the raw stream to the temporary file starting from the current position + ::comphelper::OStorageHelper::CopyInputToOutput( GetOwnSeekStream(), xTempOut ); + xTempOut->closeOutput(); + xTempSeek->seek( 0 ); + + return xTempIn; +} + +//-------------------------------------------------------------------------- +Reference< io::XInputStream > ZipPackageStream::TryToGetRawFromDataStream( sal_Bool bAddHeaderForEncr ) +{ + if ( m_nStreamMode != PACKAGE_STREAM_DATA || !GetOwnSeekStream().is() || (bAddHeaderForEncr && !bToBeEncrypted) ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + Sequence< sal_Int8 > aKey; + + if ( bToBeEncrypted ) + { + aKey = ( xEncryptionData.isEmpty() || !bHaveOwnKey ) ? rZipPackage.getEncryptionKey() : + xEncryptionData->aKey; + if ( !aKey.getLength() ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + try + { + // create temporary file + uno::Reference < io::XStream > xTempStream( + m_xFactory->createInstance ( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ), + uno::UNO_QUERY ); + if ( !xTempStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // create a package based on it + ZipPackage* pPackage = new ZipPackage( m_xFactory ); + Reference< XSingleServiceFactory > xPackageAsFactory( static_cast< XSingleServiceFactory* >( pPackage ) ); + if ( !xPackageAsFactory.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + Sequence< Any > aArgs( 1 ); + aArgs[0] <<= xTempStream; + pPackage->initialize( aArgs ); + + // create a new package stream + Reference< XDataSinkEncrSupport > xNewPackStream( xPackageAsFactory->createInstance(), UNO_QUERY ); + if ( !xNewPackStream.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + xNewPackStream->setDataStream( static_cast< io::XInputStream* >( + new WrapStreamForShare( GetOwnSeekStream(), rZipPackage.GetSharedMutexRef() ) ) ); + + Reference< XPropertySet > xNewPSProps( xNewPackStream, UNO_QUERY ); + if ( !xNewPSProps.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // copy all the properties of this stream to the new stream + xNewPSProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaType" ) ), makeAny( sMediaType ) ); + xNewPSProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Compressed" ) ), makeAny( bToBeCompressed ) ); + if ( bToBeEncrypted ) + { + xNewPSProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "EncryptionKey" ) ), makeAny( aKey ) ); + xNewPSProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Encrypted" ) ), makeAny( sal_True ) ); + } + + // insert a new stream in the package + Reference< XUnoTunnel > xTunnel; + Any aRoot = pPackage->getByHierarchicalName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) ); + aRoot >>= xTunnel; + Reference< container::XNameContainer > xRootNameContainer( xTunnel, UNO_QUERY ); + if ( !xRootNameContainer.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + Reference< XUnoTunnel > xNPSTunnel( xNewPackStream, UNO_QUERY ); + xRootNameContainer->insertByName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "dummy" ) ), makeAny( xNPSTunnel ) ); + + // commit the temporary package + pPackage->commitChanges(); + + // get raw stream from the temporary package + Reference< io::XInputStream > xInRaw; + if ( bAddHeaderForEncr ) + xInRaw = xNewPackStream->getRawStream(); + else + xInRaw = xNewPackStream->getPlainRawStream(); + + // create another temporary file + uno::Reference < io::XOutputStream > xTempOut( + m_xFactory->createInstance ( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.io.TempFile" ) ) ), + uno::UNO_QUERY ); + uno::Reference < io::XInputStream > xTempIn( xTempOut, UNO_QUERY ); + uno::Reference < io::XSeekable > xTempSeek( xTempOut, UNO_QUERY ); + if ( !xTempOut.is() || !xTempIn.is() || !xTempSeek.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // copy the raw stream to the temporary file + ::comphelper::OStorageHelper::CopyInputToOutput( xInRaw, xTempOut ); + xTempOut->closeOutput(); + xTempSeek->seek( 0 ); + + // close raw stream, package stream and folder + xInRaw = Reference< io::XInputStream >(); + xNewPSProps = Reference< XPropertySet >(); + xNPSTunnel = Reference< XUnoTunnel >(); + xNewPackStream = Reference< XDataSinkEncrSupport >(); + xTunnel = Reference< XUnoTunnel >(); + xRootNameContainer = Reference< container::XNameContainer >(); + + // return the stream representing the first temporary file + return xTempIn; + } + catch ( RuntimeException& ) + { + throw; + } + catch ( Exception& ) + { + } + + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +//-------------------------------------------------------------------------- +sal_Bool ZipPackageStream::ParsePackageRawStream() +{ + OSL_ENSURE( GetOwnSeekStream().is(), "A stream must be provided!\n" ); + + if ( !GetOwnSeekStream().is() ) + return sal_False; + + sal_Bool bOk = sal_False; + + vos::ORef < EncryptionData > xTempEncrData; + sal_Int32 nMagHackSize = 0; + Sequence < sal_Int8 > aHeader ( 4 ); + + try + { + if ( GetOwnSeekStream()->readBytes ( aHeader, 4 ) == 4 ) + { + const sal_Int8 *pHeader = aHeader.getConstArray(); + sal_uInt32 nHeader = ( pHeader [0] & 0xFF ) | + ( pHeader [1] & 0xFF ) << 8 | + ( pHeader [2] & 0xFF ) << 16 | + ( pHeader [3] & 0xFF ) << 24; + if ( nHeader == n_ConstHeader ) + { + // this is one of our god-awful, but extremely devious hacks, everyone cheer + xTempEncrData = new EncryptionData; + + ::rtl::OUString aMediaType; + if ( ZipFile::StaticFillData ( xTempEncrData, nMagHackSize, aMediaType, GetOwnSeekStream() ) ) + { + // We'll want to skip the data we've just read, so calculate how much we just read + // and remember it + m_nMagicalHackPos = n_ConstHeaderSize + xTempEncrData->aSalt.getLength() + + xTempEncrData->aInitVector.getLength() + + xTempEncrData->aDigest.getLength() + + aMediaType.getLength() * sizeof( sal_Unicode ); + m_nMagicalHackSize = nMagHackSize; + sMediaType = aMediaType; + + bOk = sal_True; + } + } + } + } + catch( Exception& ) + { + } + + if ( !bOk ) + { + // the provided stream is not a raw stream + return sal_False; + } + + xEncryptionData = xTempEncrData; + SetIsEncrypted ( sal_True ); + // it's already compressed and encrypted + bToBeEncrypted = bToBeCompressed = sal_False; + + return sal_True; +} + +void ZipPackageStream::SetPackageMember( sal_Bool bNewValue ) +{ + if ( bNewValue ) + { + m_nStreamMode = PACKAGE_STREAM_PACKAGEMEMBER; + m_nMagicalHackPos = 0; + m_nMagicalHackSize = 0; + } + else if ( m_nStreamMode == PACKAGE_STREAM_PACKAGEMEMBER ) + m_nStreamMode = PACKAGE_STREAM_NOTSET; // must be reset +} + +// XActiveDataSink +//-------------------------------------------------------------------------- +void SAL_CALL ZipPackageStream::setInputStream( const Reference< io::XInputStream >& aStream ) + throw(RuntimeException) +{ + // if seekable access is required the wrapping will be done on demand + xStream = aStream; + m_bHasSeekable = sal_False; + SetPackageMember ( sal_False ); + aEntry.nTime = -1; + m_nStreamMode = PACKAGE_STREAM_DETECT; +} + +//-------------------------------------------------------------------------- +Reference< io::XInputStream > SAL_CALL ZipPackageStream::getRawData() + throw(RuntimeException) +{ + try + { + if (IsPackageMember()) + { + if ( !xEncryptionData.isEmpty() && !bHaveOwnKey ) + xEncryptionData->aKey = rZipPackage.getEncryptionKey(); + return rZipPackage.getZipFile().getRawData( aEntry, xEncryptionData, bIsEncrypted, rZipPackage.GetSharedMutexRef() ); + } + else if ( GetOwnSeekStream().is() ) + { + return new WrapStreamForShare( GetOwnSeekStream(), rZipPackage.GetSharedMutexRef() ); + } + else + return Reference < io::XInputStream > (); + } + catch (ZipException &)//rException) + { + VOS_ENSURE( 0, "ZipException thrown");//rException.Message); + return Reference < io::XInputStream > (); + } + catch (Exception &) + { + VOS_ENSURE( 0, "Exception is thrown during stream wrapping!\n"); + return Reference < io::XInputStream > (); + } +} + +//-------------------------------------------------------------------------- +Reference< io::XInputStream > SAL_CALL ZipPackageStream::getInputStream( ) + throw(RuntimeException) +{ + try + { + if (IsPackageMember()) + { + if ( !xEncryptionData.isEmpty() && !bHaveOwnKey ) + xEncryptionData->aKey = rZipPackage.getEncryptionKey(); + return rZipPackage.getZipFile().getInputStream( aEntry, xEncryptionData, bIsEncrypted, rZipPackage.GetSharedMutexRef() ); + } + else if ( GetOwnSeekStream().is() ) + { + return new WrapStreamForShare( GetOwnSeekStream(), rZipPackage.GetSharedMutexRef() ); + } + else + return Reference < io::XInputStream > (); + } + catch (ZipException &)//rException) + { + VOS_ENSURE( 0,"ZipException thrown");//rException.Message); + return Reference < io::XInputStream > (); + } + catch (Exception &) + { + VOS_ENSURE( 0, "Exception is thrown during stream wrapping!\n"); + return Reference < io::XInputStream > (); + } +} + +// XDataSinkEncrSupport +//-------------------------------------------------------------------------- +Reference< io::XInputStream > SAL_CALL ZipPackageStream::getDataStream() + throw ( packages::WrongPasswordException, + io::IOException, + RuntimeException ) +{ + // There is no stream attached to this object + if ( m_nStreamMode == PACKAGE_STREAM_NOTSET ) + return Reference< io::XInputStream >(); + + // this method can not be used together with old approach + if ( m_nStreamMode == PACKAGE_STREAM_DETECT ) + throw packages::zip::ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !xEncryptionData.isEmpty() && !bHaveOwnKey ) + xEncryptionData->aKey = rZipPackage.getEncryptionKey(); + + if (IsPackageMember()) + { + if ( !xEncryptionData.isEmpty() && !bHaveOwnKey ) + xEncryptionData->aKey = rZipPackage.getEncryptionKey(); + + return rZipPackage.getZipFile().getDataStream( aEntry, xEncryptionData, bIsEncrypted, rZipPackage.GetSharedMutexRef() ); + } + else if ( m_nStreamMode == PACKAGE_STREAM_RAW ) + return ZipFile::StaticGetDataFromRawStream( GetOwnSeekStream(), xEncryptionData ); + else if ( GetOwnSeekStream().is() ) + { + return new WrapStreamForShare( GetOwnSeekStream(), rZipPackage.GetSharedMutexRef() ); + } + else + return uno::Reference< io::XInputStream >(); +} + +//-------------------------------------------------------------------------- +Reference< io::XInputStream > SAL_CALL ZipPackageStream::getRawStream() + throw ( packages::NoEncryptionException, + io::IOException, + uno::RuntimeException ) +{ + // There is no stream attached to this object + if ( m_nStreamMode == PACKAGE_STREAM_NOTSET ) + return Reference< io::XInputStream >(); + + // this method can not be used together with old approach + if ( m_nStreamMode == PACKAGE_STREAM_DETECT ) + throw packages::zip::ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if (IsPackageMember()) + { + if ( !bIsEncrypted || xEncryptionData.isEmpty() ) + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return rZipPackage.getZipFile().getWrappedRawStream( aEntry, xEncryptionData, sMediaType, rZipPackage.GetSharedMutexRef() ); + } + else if ( GetOwnSeekStream().is() ) + { + if ( m_nStreamMode == PACKAGE_STREAM_RAW ) + { + return new WrapStreamForShare( GetOwnSeekStream(), rZipPackage.GetSharedMutexRef() ); + } + else if ( m_nStreamMode == PACKAGE_STREAM_DATA && bToBeEncrypted ) + return TryToGetRawFromDataStream( sal_True ); + } + + throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + + +//-------------------------------------------------------------------------- +void SAL_CALL ZipPackageStream::setDataStream( const Reference< io::XInputStream >& aStream ) + throw ( io::IOException, + RuntimeException ) +{ + setInputStream( aStream ); + m_nStreamMode = PACKAGE_STREAM_DATA; +} + +//-------------------------------------------------------------------------- +void SAL_CALL ZipPackageStream::setRawStream( const Reference< io::XInputStream >& aStream ) + throw ( packages::EncryptionNotAllowedException, + packages::NoRawFormatException, + io::IOException, + RuntimeException) +{ + // wrap the stream in case it is not seekable + Reference< io::XInputStream > xNewStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( aStream, m_xFactory ); + Reference< io::XSeekable > xSeek( xNewStream, UNO_QUERY ); + if ( !xSeek.is() ) + throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "The stream must support XSeekable!" ) ), + Reference< XInterface >() ); + + xSeek->seek( 0 ); + Reference< io::XInputStream > xOldStream = xStream; + xStream = xNewStream; + if ( !ParsePackageRawStream() ) + { + xStream = xOldStream; + throw packages::NoRawFormatException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + // the raw stream MUST have seekable access + m_bHasSeekable = sal_True; + + SetPackageMember ( sal_False ); + aEntry.nTime = -1; + m_nStreamMode = PACKAGE_STREAM_RAW; +} + +//-------------------------------------------------------------------------- +uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getPlainRawStream() + throw ( io::IOException, + uno::RuntimeException ) +{ + // There is no stream attached to this object + if ( m_nStreamMode == PACKAGE_STREAM_NOTSET ) + return Reference< io::XInputStream >(); + + // this method can not be used together with old approach + if ( m_nStreamMode == PACKAGE_STREAM_DETECT ) + throw packages::zip::ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if (IsPackageMember()) + { + return rZipPackage.getZipFile().getRawData( aEntry, xEncryptionData, bIsEncrypted, rZipPackage.GetSharedMutexRef() ); + } + else if ( GetOwnSeekStream().is() ) + { + if ( m_nStreamMode == PACKAGE_STREAM_RAW ) + { + // the header should not be returned here + return GetRawEncrStreamNoHeaderCopy(); + } + else if ( m_nStreamMode == PACKAGE_STREAM_DATA ) + return TryToGetRawFromDataStream( sal_False ); + } + + return Reference< io::XInputStream >(); +} + +// XUnoTunnel + +//-------------------------------------------------------------------------- +sal_Int64 SAL_CALL ZipPackageStream::getSomething( const Sequence< sal_Int8 >& aIdentifier ) + throw(RuntimeException) +{ + sal_Int64 nMe = 0; + if ( aIdentifier.getLength() == 16 && + 0 == rtl_compareMemory( static_getImplementationId().getConstArray(), aIdentifier.getConstArray(), 16 ) ) + nMe = reinterpret_cast < sal_Int64 > ( this ); + return nMe; +} + +// XPropertySet +//-------------------------------------------------------------------------- +void SAL_CALL ZipPackageStream::setPropertyValue( const OUString& aPropertyName, const Any& aValue ) + throw(beans::UnknownPropertyException, beans::PropertyVetoException, IllegalArgumentException, WrappedTargetException, RuntimeException) +{ + if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("MediaType"))) + { + if ( rZipPackage.getFormat() != PACKAGE_FORMAT && rZipPackage.getFormat() != OFOPXML_FORMAT ) + throw beans::PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( aValue >>= sMediaType ) + { + if (sMediaType.getLength() > 0) + { + if ( sMediaType.indexOf (OUString( RTL_CONSTASCII_USTRINGPARAM ( "text" ) ) ) != -1 + || sMediaType.equals( OUString( RTL_CONSTASCII_USTRINGPARAM ( "application/vnd.sun.star.oleobject" ) ) ) ) + bToBeCompressed = sal_True; + else if ( !m_bCompressedIsSetFromOutside ) + bToBeCompressed = sal_False; + } + } + else + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "MediaType must be a string!\n" ) ), + Reference< XInterface >(), + 2 ); + + } + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Size") ) ) + { + if ( !( aValue >>= aEntry.nSize ) ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong type for Size property!\n" ) ), + Reference< XInterface >(), + 2 ); + } + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("Encrypted") ) ) + { + if ( rZipPackage.getFormat() != PACKAGE_FORMAT ) + throw beans::PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + sal_Bool bEnc = sal_False; + if ( aValue >>= bEnc ) + { + // In case of new raw stream, the stream must not be encrypted on storing + if ( bEnc && m_nStreamMode == PACKAGE_STREAM_RAW ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Raw stream can not be encrypted on storing" ) ), + Reference< XInterface >(), + 2 ); + + bToBeEncrypted = bEnc; + if ( bToBeEncrypted && xEncryptionData.isEmpty()) + xEncryptionData = new EncryptionData; + } + else + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong type for Encrypted property!\n" ) ), + Reference< XInterface >(), + 2 ); + + } + else if (aPropertyName.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("EncryptionKey") ) ) + { + if ( rZipPackage.getFormat() != PACKAGE_FORMAT ) + throw beans::PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + Sequence < sal_Int8 > aNewKey; + + if ( !( aValue >>= aNewKey ) ) + { + OUString sTempString; + if ( ( aValue >>= sTempString ) ) + { + sal_Int32 nPathLength = sTempString.getLength(); + Sequence < sal_Int8 > aSequence ( nPathLength ); + sal_Int8 *pArray = aSequence.getArray(); + const sal_Unicode *pChar = sTempString.getStr(); + for ( sal_Int16 i = 0; i < nPathLength; i++) + pArray[i] = static_cast < const sal_Int8 > (pChar[i]); + aNewKey = aSequence; + } + else + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong type for EncryptionKey property!\n" ) ), + Reference< XInterface >(), + 2 ); + } + + if ( aNewKey.getLength() ) + { + if ( xEncryptionData.isEmpty()) + xEncryptionData = new EncryptionData; + + xEncryptionData->aKey = aNewKey; + // In case of new raw stream, the stream must not be encrypted on storing + bHaveOwnKey = sal_True; + if ( m_nStreamMode != PACKAGE_STREAM_RAW ) + bToBeEncrypted = sal_True; + } + else + bHaveOwnKey = sal_False; + } + else if (aPropertyName.equalsAsciiL ( RTL_CONSTASCII_STRINGPARAM ( "Compressed" ) ) ) + { + sal_Bool bCompr = sal_False; + + if ( aValue >>= bCompr ) + { + // In case of new raw stream, the stream must not be encrypted on storing + if ( bCompr && m_nStreamMode == PACKAGE_STREAM_RAW ) + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Raw stream can not be encrypted on storing" ) ), + Reference< XInterface >(), + 2 ); + + bToBeCompressed = bCompr; + m_bCompressedIsSetFromOutside = sal_True; + } + else + throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong type for Compressed property!\n" ) ), + Reference< XInterface >(), + 2 ); + } + else + throw beans::UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +//-------------------------------------------------------------------------- +Any SAL_CALL ZipPackageStream::getPropertyValue( const OUString& PropertyName ) + throw(beans::UnknownPropertyException, WrappedTargetException, RuntimeException) +{ + Any aAny; + if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "MediaType" ) ) ) + { + aAny <<= sMediaType; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "Size" ) ) ) + { + aAny <<= aEntry.nSize; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "Encrypted" ) ) ) + { + aAny <<= ( m_nStreamMode == PACKAGE_STREAM_RAW ) ? sal_True : bToBeEncrypted; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "WasEncrypted" ) ) ) + { + aAny <<= bIsEncrypted; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM ( "Compressed" ) ) ) + { + aAny <<= bToBeCompressed; + return aAny; + } + else if (PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "EncryptionKey" ) ) ) + { + aAny <<= xEncryptionData.isEmpty () ? Sequence < sal_Int8 > () : xEncryptionData->aKey; + return aAny; + } + else + throw beans::UnknownPropertyException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +//-------------------------------------------------------------------------- +void ZipPackageStream::setSize (const sal_Int32 nNewSize) +{ + if (aEntry.nCompressedSize != nNewSize ) + aEntry.nMethod = DEFLATED; + aEntry.nSize = nNewSize; +} +//-------------------------------------------------------------------------- +OUString ZipPackageStream::getImplementationName() + throw (RuntimeException) +{ + return OUString ( RTL_CONSTASCII_USTRINGPARAM ( "ZipPackageStream" ) ); +} + +//-------------------------------------------------------------------------- +Sequence< OUString > ZipPackageStream::getSupportedServiceNames() + throw (RuntimeException) +{ + Sequence< OUString > aNames(1); + aNames[0] = OUString( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.packages.PackageStream" ) ); + return aNames; +} +//-------------------------------------------------------------------------- +sal_Bool SAL_CALL ZipPackageStream::supportsService( OUString const & rServiceName ) + throw (RuntimeException) +{ + return rServiceName == getSupportedServiceNames()[0]; +} + diff --git a/package/source/zippackage/ZipPackageStream.hxx b/package/source/zippackage/ZipPackageStream.hxx new file mode 100644 index 000000000000..a0d5fad6e4da --- /dev/null +++ b/package/source/zippackage/ZipPackageStream.hxx @@ -0,0 +1,201 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ +#ifndef _ZIP_PACKAGE_STREAM_HXX +#define _ZIP_PACKAGE_STREAM_HXX + +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <com/sun/star/packages/XDataSinkEncrSupport.hpp> +#include <ZipPackageEntry.hxx> +#ifndef _VOS_REF_H_ +#include <vos/ref.hxx> +#endif +#include <EncryptionData.hxx> +#ifndef _CPPUHELPER_IMPLBASE2_HXX +#include <cppuhelper/implbase2.hxx> +#endif +#include <mutexholder.hxx> + +#define PACKAGE_STREAM_NOTSET 0 +#define PACKAGE_STREAM_PACKAGEMEMBER 1 +#define PACKAGE_STREAM_DETECT 2 +#define PACKAGE_STREAM_DATA 3 +#define PACKAGE_STREAM_RAW 4 + +class ZipPackage; +struct ZipEntry; +class ZipPackageStream : public cppu::ImplInheritanceHelper2 +< + ZipPackageEntry, + ::com::sun::star::io::XActiveDataSink, + ::com::sun::star::packages::XDataSinkEncrSupport +> +{ + static com::sun::star::uno::Sequence < sal_Int8 > aImplementationId; +protected: + com::sun::star::uno::Reference < com::sun::star::io::XInputStream > xStream; + const ::com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory > m_xFactory; + ZipPackage &rZipPackage; + sal_Bool bToBeCompressed, bToBeEncrypted, bHaveOwnKey, bIsEncrypted; + vos::ORef < EncryptionData > xEncryptionData; + + sal_uInt8 m_nStreamMode; + sal_uInt32 m_nMagicalHackPos; + sal_uInt32 m_nMagicalHackSize; + + sal_Bool m_bHasSeekable; + + sal_Bool m_bCompressedIsSetFromOutside; + + sal_Bool m_bFromManifest; + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& GetOwnSeekStream(); + +public: + sal_Bool HasOwnKey () const { return bHaveOwnKey;} + sal_Bool IsToBeCompressed () const { return bToBeCompressed;} + sal_Bool IsToBeEncrypted () const { return bToBeEncrypted;} + sal_Bool IsEncrypted () const { return bIsEncrypted;} + sal_Bool IsPackageMember () const { return m_nStreamMode == PACKAGE_STREAM_PACKAGEMEMBER;} + + sal_Bool IsFromManifest() const { return m_bFromManifest; } + void SetFromManifest( sal_Bool bValue ) { m_bFromManifest = bValue; } + + vos::ORef < EncryptionData > & getEncryptionData () + { return xEncryptionData;} + const com::sun::star::uno::Sequence < sal_Int8 >& getKey () const + { return xEncryptionData->aKey;} + const com::sun::star::uno::Sequence < sal_uInt8 >& getInitialisationVector () const + { return xEncryptionData->aInitVector;} + const com::sun::star::uno::Sequence < sal_uInt8 >& getDigest () const + { return xEncryptionData->aDigest;} + const com::sun::star::uno::Sequence < sal_uInt8 >& getSalt () const + { return xEncryptionData->aSalt;} + sal_Int32 getIterationCount () const + { return xEncryptionData->nIterationCount;} + sal_Int32 getSize () const + { return aEntry.nSize;} + + sal_uInt8 GetStreamMode() const { return m_nStreamMode; } + sal_uInt32 GetMagicalHackPos() const { return m_nMagicalHackPos; } + sal_uInt32 GetMagicalHackSize() const { return m_nMagicalHackSize; } + + void SetToBeCompressed (sal_Bool bNewValue) { bToBeCompressed = bNewValue;} + void SetIsEncrypted (sal_Bool bNewValue) { bIsEncrypted = bNewValue;} + void SetToBeEncrypted (sal_Bool bNewValue) + { + bToBeEncrypted = bNewValue; + if ( bToBeEncrypted && xEncryptionData.isEmpty()) + xEncryptionData = new EncryptionData; + else if ( !bToBeEncrypted && !xEncryptionData.isEmpty() ) + xEncryptionData.unbind(); + } + void SetPackageMember (sal_Bool bNewValue); + void setKey (const com::sun::star::uno::Sequence < sal_Int8 >& rNewKey ) + { xEncryptionData->aKey = rNewKey;} + void setInitialisationVector (const com::sun::star::uno::Sequence < sal_uInt8 >& rNewVector ) + { xEncryptionData->aInitVector = rNewVector;} + void setSalt (const com::sun::star::uno::Sequence < sal_uInt8 >& rNewSalt ) + { xEncryptionData->aSalt = rNewSalt;} + void setDigest (const com::sun::star::uno::Sequence < sal_uInt8 >& rNewDigest ) + { xEncryptionData->aDigest = rNewDigest;} + void setIterationCount (const sal_Int32 nNewCount) + { xEncryptionData->nIterationCount = nNewCount;} + void setSize (const sal_Int32 nNewSize); + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > GetOwnStreamNoWrap() { return xStream; } + + void CloseOwnStreamIfAny(); + + ZipPackageStream ( ZipPackage & rNewPackage, + const ::com::sun::star::uno::Reference < com::sun::star::lang::XMultiServiceFactory >& xFactory, + sal_Bool bAllowRemoveOnInsert ); + virtual ~ZipPackageStream( void ); + + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > GetRawEncrStreamNoHeaderCopy(); + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > TryToGetRawFromDataStream( + sal_Bool bAddHeaderForEncr ); + + sal_Bool ParsePackageRawStream(); + + void setZipEntryOnLoading( const ZipEntry &rInEntry); + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getRawData() + throw(::com::sun::star::uno::RuntimeException); + + static ::com::sun::star::uno::Sequence < sal_Int8 >& static_getImplementationId() + { + return aImplementationId; + } + + // XActiveDataSink + virtual void SAL_CALL setInputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& aStream ) + throw(::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getInputStream( ) + throw(::com::sun::star::uno::RuntimeException); + + // XDataSinkEncrSupport + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getDataStream() + throw ( ::com::sun::star::packages::WrongPasswordException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getRawStream() + throw ( ::com::sun::star::packages::NoEncryptionException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL setDataStream( + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& aStream ) + throw ( ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + virtual void SAL_CALL setRawStream( + const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& aStream ) + throw ( ::com::sun::star::packages::EncryptionNotAllowedException, + ::com::sun::star::packages::NoRawFormatException, + ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + virtual ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getPlainRawStream() + throw ( ::com::sun::star::io::IOException, + ::com::sun::star::uno::RuntimeException ); + + // XUnoTunnel + virtual sal_Int64 SAL_CALL getSomething( const ::com::sun::star::uno::Sequence< sal_Int8 >& aIdentifier ) + throw(::com::sun::star::uno::RuntimeException); + + // XPropertySet + virtual void SAL_CALL setPropertyValue( const ::rtl::OUString& aPropertyName, const ::com::sun::star::uno::Any& aValue ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::beans::PropertyVetoException, ::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Any SAL_CALL getPropertyValue( const ::rtl::OUString& PropertyName ) + throw(::com::sun::star::beans::UnknownPropertyException, ::com::sun::star::lang::WrappedTargetException, ::com::sun::star::uno::RuntimeException); + + // XServiceInfo + virtual ::rtl::OUString SAL_CALL getImplementationName( ) + throw (::com::sun::star::uno::RuntimeException); + virtual sal_Bool SAL_CALL supportsService( const ::rtl::OUString& ServiceName ) + throw (::com::sun::star::uno::RuntimeException); + virtual ::com::sun::star::uno::Sequence< ::rtl::OUString > SAL_CALL getSupportedServiceNames( ) + throw (::com::sun::star::uno::RuntimeException); +}; +#endif diff --git a/package/source/zippackage/makefile.mk b/package/source/zippackage/makefile.mk new file mode 100644 index 000000000000..4bab1649b491 --- /dev/null +++ b/package/source/zippackage/makefile.mk @@ -0,0 +1,63 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* + +PRJ=..$/.. +PRJNAME=package +TARGET=zippackage +AUTOSEG=true + +ENABLE_EXCEPTIONS=TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +.IF "$(L10N_framework)"=="" + +# --- Files -------------------------------------------------------- +# the following flag un-inlines function calls and disables optimisations +#CFLAGS+=/Ob0 /Od + +SLOFILES= \ + $(SLO)$/ZipPackage.obj \ + $(SLO)$/ZipPackageBuffer.obj \ + $(SLO)$/ZipPackageEntry.obj \ + $(SLO)$/ZipPackageFolder.obj \ + $(SLO)$/ZipPackageFolderEnumeration.obj \ + $(SLO)$/ZipPackageSink.obj \ + $(SLO)$/ZipPackageStream.obj \ + $(SLO)$/wrapstreamforshare.obj \ + $(SLO)$/zipfileaccess.obj + +# $(SLO)$/InteractionRequest.obj \ +# $(SLO)$/InteractionContinuation.obj + +.ENDIF # L10N_framework + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/package/source/zippackage/wrapstreamforshare.cxx b/package/source/zippackage/wrapstreamforshare.cxx new file mode 100644 index 000000000000..d3d2eb84d1b7 --- /dev/null +++ b/package/source/zippackage/wrapstreamforshare.cxx @@ -0,0 +1,180 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <osl/diagnose.h> + +#include "wrapstreamforshare.hxx" + +using namespace ::com::sun::star; + + +WrapStreamForShare::WrapStreamForShare( const uno::Reference< io::XInputStream >& xInStream, + const SotMutexHolderRef& rMutexRef ) +: m_rMutexRef( rMutexRef ) +, m_xInStream( xInStream ) +, m_nCurPos( 0 ) +{ + m_xSeekable = uno::Reference< io::XSeekable >( m_xInStream, uno::UNO_QUERY ); + if ( !m_rMutexRef.Is() || !m_xInStream.is() || !m_xSeekable.is() ) + { + OSL_ENSURE( sal_False, "Wrong initialization of wrapping stream!\n" ); + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } +} + +WrapStreamForShare::~WrapStreamForShare() +{ +} + +// XInputStream +sal_Int32 SAL_CALL WrapStreamForShare::readBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + m_xSeekable->seek( m_nCurPos ); + + sal_Int32 nRead = m_xInStream->readBytes( aData, nBytesToRead ); + m_nCurPos += nRead; + + return nRead; +} + +sal_Int32 SAL_CALL WrapStreamForShare::readSomeBytes( uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + m_xSeekable->seek( m_nCurPos ); + + sal_Int32 nRead = m_xInStream->readSomeBytes( aData, nMaxBytesToRead ); + m_nCurPos += nRead; + + return nRead; +} + +void SAL_CALL WrapStreamForShare::skipBytes( sal_Int32 nBytesToSkip ) + throw ( io::NotConnectedException, + io::BufferSizeExceededException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + m_xSeekable->seek( m_nCurPos ); + + m_xInStream->skipBytes( nBytesToSkip ); + m_nCurPos = m_xSeekable->getPosition(); +} + +sal_Int32 SAL_CALL WrapStreamForShare::available() + throw ( io::NotConnectedException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return m_xInStream->available(); +} + +void SAL_CALL WrapStreamForShare::closeInput() + throw ( io::NotConnectedException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // the package is the owner so it will close the stream + // m_xInStream->closeInput(); + m_xInStream = uno::Reference< io::XInputStream >(); + m_xSeekable = uno::Reference< io::XSeekable >(); +} + +// XSeekable +void SAL_CALL WrapStreamForShare::seek( sal_Int64 location ) + throw ( lang::IllegalArgumentException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // let stream implementation do all the checking + m_xSeekable->seek( location ); + + m_nCurPos = m_xSeekable->getPosition(); +} + +sal_Int64 SAL_CALL WrapStreamForShare::getPosition() + throw ( io::IOException, + uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return m_nCurPos; +} + +sal_Int64 SAL_CALL WrapStreamForShare::getLength() + throw ( io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); + + if ( !m_xInStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return m_xSeekable->getLength(); +} + diff --git a/package/source/zippackage/wrapstreamforshare.hxx b/package/source/zippackage/wrapstreamforshare.hxx new file mode 100644 index 000000000000..c799e3ac9b92 --- /dev/null +++ b/package/source/zippackage/wrapstreamforshare.hxx @@ -0,0 +1,73 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +#ifndef _WRAPSTREAMFORSHARE_HXX_ +#define _WRAPSTREAMFORSHARE_HXX_ + +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> +#include <cppuhelper/implbase2.hxx> + +#include <mutexholder.hxx> + +class WrapStreamForShare : public cppu::WeakImplHelper2 < ::com::sun::star::io::XInputStream + , ::com::sun::star::io::XSeekable > +{ +protected: + SotMutexHolderRef m_rMutexRef; + ::com::sun::star::uno::Reference < ::com::sun::star::io::XInputStream > m_xInStream; + ::com::sun::star::uno::Reference < ::com::sun::star::io::XSeekable > m_xSeekable; + + sal_Int64 m_nCurPos; + +public: + WrapStreamForShare( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream >& xInStream, + const SotMutexHolderRef& rMutexRef ); + virtual ~WrapStreamForShare(); + + // XInputStream + virtual sal_Int32 SAL_CALL readBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL readSomeBytes( ::com::sun::star::uno::Sequence< sal_Int8 >& aData, sal_Int32 nMaxBytesToRead ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL skipBytes( sal_Int32 nBytesToSkip ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::BufferSizeExceededException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int32 SAL_CALL available( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual void SAL_CALL closeInput( ) + throw(::com::sun::star::io::NotConnectedException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + + //XSeekable + virtual void SAL_CALL seek( sal_Int64 location ) throw (::com::sun::star::lang::IllegalArgumentException, ::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getPosition() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + virtual sal_Int64 SAL_CALL getLength() throw (::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + +}; + +#endif + diff --git a/package/source/zippackage/zipfileaccess.cxx b/package/source/zippackage/zipfileaccess.cxx new file mode 100644 index 000000000000..9acae56ad68a --- /dev/null +++ b/package/source/zippackage/zipfileaccess.cxx @@ -0,0 +1,492 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_package.hxx" +#include <com/sun/star/lang/DisposedException.hpp> +#ifndef _COM_SUN_STAR_LANG_INVALIDARGUMENTEXCEPTION_HPP_ +#include <com/sun/star/lang/IllegalArgumentException.hpp> +#endif +#include <com/sun/star/ucb/XCommandEnvironment.hpp> +#include <com/sun/star/io/XActiveDataSink.hpp> +#include <com/sun/star/io/XStream.hpp> +#include <com/sun/star/io/XSeekable.hpp> + +#include <zipfileaccess.hxx> +#include <ZipEnumeration.hxx> +#include <ZipPackageSink.hxx> +#include <EncryptionData.hxx> + +#include <ucbhelper/content.hxx> + +#include <memory> + + +using namespace ::com::sun::star; + +// ---------------------------------------------------------------- +OZipFileAccess::OZipFileAccess( const uno::Reference< lang::XMultiServiceFactory >& xFactory ) +: m_aMutexHolder( new SotMutexHolder ) +, m_xFactory( xFactory ) +, m_pZipFile( NULL ) +, m_pListenersContainer( NULL ) +, m_bDisposed( sal_False ) +{ + if ( !xFactory.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +// ---------------------------------------------------------------- +OZipFileAccess::~OZipFileAccess() +{ + { + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + if ( !m_bDisposed ) + { + try { + m_refCount++; // dispose will use refcounting so the further distruction must be avoided + dispose(); + } catch( uno::Exception& ) + {} + } + } +} + +// ---------------------------------------------------------------- +uno::Sequence< ::rtl::OUString > OZipFileAccess::GetPatternsFromString_Impl( const ::rtl::OUString& aString ) +{ + if ( !aString.getLength() ) + return uno::Sequence< ::rtl::OUString >(); + + uno::Sequence< ::rtl::OUString > aPattern( 1 ); + sal_Int32 nInd = 0; + + const sal_Unicode* pString = aString.getStr(); + while( *pString ) + { + if ( *pString == (sal_Unicode)'\\' ) + { + pString++; + + if ( *pString == (sal_Unicode)'\\' ) + { + aPattern[nInd] += ::rtl::OUString::valueOf( (sal_Unicode)'\\' ); + pString++; + } + else if ( *pString == (sal_Unicode)'*' ) + { + aPattern[nInd] += ::rtl::OUString::valueOf( (sal_Unicode)'*' ); + pString++; + } + else + { + OSL_ENSURE( sal_False, "The backslash is not guarded!\n" ); + aPattern[nInd] += ::rtl::OUString::valueOf( (sal_Unicode)'\\' ); + } + } + else if ( *pString == (sal_Unicode)'*' ) + { + aPattern.realloc( ( ++nInd ) + 1 ); + pString++; + } + else + { + aPattern[nInd] += ::rtl::OUString::valueOf( *pString ); + pString++; + } + } + + return aPattern; +} + +// ---------------------------------------------------------------- +sal_Bool OZipFileAccess::StringGoodForPattern_Impl( const ::rtl::OUString& aString, + const uno::Sequence< ::rtl::OUString >& aPattern ) +{ + sal_Int32 nInd = aPattern.getLength() - 1; + if ( nInd < 0 ) + return sal_False; + + if ( nInd == 0 ) + { + if ( !aPattern[0].getLength() ) + return sal_True; + + return aString.equals( aPattern[0] ); + } + + sal_Int32 nBeginInd = aPattern[0].getLength(); + sal_Int32 nEndInd = aString.getLength() - aPattern[nInd].getLength(); + if ( nEndInd >= nBeginInd + && ( nEndInd == aString.getLength() || aString.copy( nEndInd ).equals( aPattern[nInd] ) ) + && ( nBeginInd == 0 || aString.copy( 0, nBeginInd ).equals( aPattern[0] ) ) ) + { + for ( sal_Int32 nCurInd = aPattern.getLength() - 2; nCurInd > 0; nCurInd-- ) + { + if ( !aPattern[nCurInd].getLength() ) + continue; + + if ( nEndInd == nBeginInd ) + return sal_False; + + // check that search does not use nEndInd position + sal_Int32 nLastInd = aString.lastIndexOf( aPattern[nCurInd], nEndInd - 1 ); + + if ( nLastInd == -1 ) + return sal_False; + + if ( nLastInd < nBeginInd ) + return sal_False; + + nEndInd = nLastInd; + } + + return sal_True; + } + + return sal_False; +} + +// XInitialization +// ---------------------------------------------------------------- +void SAL_CALL OZipFileAccess::initialize( const uno::Sequence< uno::Any >& aArguments ) + throw ( uno::Exception, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( m_pZipFile ) + throw uno::Exception( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); // initialization is allowed only one time + + if ( !aArguments.getLength() ) + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); + + OSL_ENSURE( aArguments.getLength() == 1, "Too meny arguments are provided, only the first one will be used!\n" ); + + ::rtl::OUString aParamURL; + uno::Reference< io::XStream > xStream; + uno::Reference< io::XSeekable > xSeekable; + + if ( ( aArguments[0] >>= aParamURL ) ) + { + ::ucbhelper::Content aContent ( aParamURL, uno::Reference< ::com::sun::star::ucb::XCommandEnvironment >() ); + uno::Reference < io::XActiveDataSink > xSink = new ZipPackageSink; + if ( aContent.openStream ( xSink ) ) + { + m_xContentStream = xSink->getInputStream(); + xSeekable = uno::Reference< io::XSeekable >( m_xContentStream, uno::UNO_QUERY ); + } + } + else if ( (aArguments[0] >>= xStream ) ) + { + // a writable stream can implement both XStream & XInputStream + m_xContentStream = xStream->getInputStream(); + xSeekable = uno::Reference< io::XSeekable >( xStream, uno::UNO_QUERY ); + } + else if ( !( aArguments[0] >>= m_xContentStream ) ) + { + xSeekable = uno::Reference< io::XSeekable >( m_xContentStream, uno::UNO_QUERY ); + } + else + throw lang::IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >(), 1 ); + + if ( !m_xContentStream.is() ) + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !xSeekable.is() ) + { + // TODO: after fwkbugfix02 is integrated a helper class can be used to make the stream seekable + throw io::IOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + } + + // TODO: in case xSeekable is implemented on separated XStream implementation a wrapper is required + m_pZipFile = new ZipFile( + m_xContentStream, + m_xFactory, + sal_True ); +} + +// XNameAccess +// ---------------------------------------------------------------- +uno::Any SAL_CALL OZipFileAccess::getByName( const ::rtl::OUString& aName ) + throw ( container::NoSuchElementException, + lang::WrappedTargetException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pZipFile ) + throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + EntryHash::iterator aIter = m_pZipFile->GetEntryHash().find( aName ); + if ( aIter == m_pZipFile->GetEntryHash().end() ) + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Reference< io::XInputStream > xEntryStream( m_pZipFile->getDataStream( (*aIter).second, + new EncryptionData(), + sal_False, + m_aMutexHolder ) ); + + if ( !xEntryStream.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return uno::makeAny ( xEntryStream ); +} + +// ---------------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OZipFileAccess::getElementNames() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pZipFile ) + throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + uno::Sequence< ::rtl::OUString > aNames( m_pZipFile->GetEntryHash().size() ); + sal_Int32 nLen = 0; + + for ( EntryHash::iterator aIter = m_pZipFile->GetEntryHash().begin(); aIter != m_pZipFile->GetEntryHash().end(); aIter++ ) + { + if ( aNames.getLength() < ++nLen ) + { + OSL_ENSURE( sal_False, "The size must be the same!\n" ); + aNames.realloc( nLen ); + } + + aNames[nLen-1] = (*aIter).second.sPath; + } + + if ( aNames.getLength() != nLen ) + { + OSL_ENSURE( sal_False, "The size must be the same!\n" ); + aNames.realloc( nLen ); + } + + return aNames; +} + +// ---------------------------------------------------------------- +sal_Bool SAL_CALL OZipFileAccess::hasByName( const ::rtl::OUString& aName ) + throw (uno::RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pZipFile ) + throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + EntryHash::iterator aIter = m_pZipFile->GetEntryHash().find( aName ); + + return ( aIter != m_pZipFile->GetEntryHash().end() ); +} + +// ---------------------------------------------------------------- +uno::Type SAL_CALL OZipFileAccess::getElementType() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pZipFile ) + throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return getCppuType( ( const uno::Reference< io::XInputStream >* )NULL ); +} + +// ---------------------------------------------------------------- +sal_Bool SAL_CALL OZipFileAccess::hasElements() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pZipFile ) + throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + return ( m_pZipFile->GetEntryHash().size() != 0 ); +} + +// XZipFileAccess +// ---------------------------------------------------------------- +uno::Reference< io::XInputStream > SAL_CALL OZipFileAccess::getStreamByPattern( const ::rtl::OUString& aPatternString ) + throw ( container::NoSuchElementException, + io::IOException, + uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pZipFile ) + throw io::NotConnectedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + // Code to compare strings by patterns + uno::Sequence< ::rtl::OUString > aPattern = GetPatternsFromString_Impl( aPatternString ); + + for ( EntryHash::iterator aIter = m_pZipFile->GetEntryHash().begin(); aIter != m_pZipFile->GetEntryHash().end(); aIter++ ) + { + if ( StringGoodForPattern_Impl( (*aIter).second.sPath, aPattern ) ) + { + uno::Reference< io::XInputStream > xEntryStream( m_pZipFile->getDataStream( (*aIter).second, + new EncryptionData(), + sal_False, + m_aMutexHolder ) ); + + if ( !xEntryStream.is() ) + throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + return xEntryStream; + } + } + + throw container::NoSuchElementException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); +} + +// XComponent +// ---------------------------------------------------------------- +void SAL_CALL OZipFileAccess::dispose() + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( m_pListenersContainer ) + { + lang::EventObject aSource( static_cast< ::cppu::OWeakObject* >(this) ); + m_pListenersContainer->disposeAndClear( aSource ); + delete m_pListenersContainer; + m_pListenersContainer = NULL; + } + + if ( m_pZipFile ) + { + delete m_pZipFile; + m_pZipFile = NULL; + } + + if ( m_xContentStream.is() ) + try { + m_xContentStream->closeInput(); + } catch( uno::Exception& ) + {} + + m_bDisposed = sal_True; +} + +// ---------------------------------------------------------------- +void SAL_CALL OZipFileAccess::addEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( !m_pListenersContainer ) + m_pListenersContainer = new ::cppu::OInterfaceContainerHelper( m_aMutexHolder->GetMutex() ); + m_pListenersContainer->addInterface( xListener ); +} + +// ---------------------------------------------------------------- +void SAL_CALL OZipFileAccess::removeEventListener( const uno::Reference< lang::XEventListener >& xListener ) + throw ( uno::RuntimeException ) +{ + ::osl::MutexGuard aGuard( m_aMutexHolder->GetMutex() ); + + if ( m_bDisposed ) + throw lang::DisposedException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() ); + + if ( m_pListenersContainer ) + m_pListenersContainer->removeInterface( xListener ); +} + +//------------------------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OZipFileAccess::impl_staticGetSupportedServiceNames() +{ + uno::Sequence< ::rtl::OUString > aRet(2); + aRet[0] = ::rtl::OUString::createFromAscii("com.sun.star.packages.zip.ZipFileAccess"); + aRet[1] = ::rtl::OUString::createFromAscii("com.sun.star.comp.packages.zip.ZipFileAccess"); + return aRet; +} + +//------------------------------------------------------------------------- +::rtl::OUString SAL_CALL OZipFileAccess::impl_staticGetImplementationName() +{ + return ::rtl::OUString::createFromAscii("com.sun.star.comp.package.zip.ZipFileAccess"); +} + +//------------------------------------------------------------------------- +uno::Reference< uno::XInterface > SAL_CALL OZipFileAccess::impl_staticCreateSelfInstance( + const uno::Reference< lang::XMultiServiceFactory >& xServiceManager ) +{ + return uno::Reference< uno::XInterface >( *new OZipFileAccess( xServiceManager ) ); +} + +//------------------------------------------------------------------------- +::rtl::OUString SAL_CALL OZipFileAccess::getImplementationName() + throw ( uno::RuntimeException ) +{ + return impl_staticGetImplementationName(); +} + +//------------------------------------------------------------------------- +sal_Bool SAL_CALL OZipFileAccess::supportsService( const ::rtl::OUString& ServiceName ) + throw ( uno::RuntimeException ) +{ + uno::Sequence< ::rtl::OUString > aSeq = impl_staticGetSupportedServiceNames(); + + for ( sal_Int32 nInd = 0; nInd < aSeq.getLength(); nInd++ ) + if ( ServiceName.compareTo( aSeq[nInd] ) == 0 ) + return sal_True; + + return sal_False; +} + +//------------------------------------------------------------------------- +uno::Sequence< ::rtl::OUString > SAL_CALL OZipFileAccess::getSupportedServiceNames() + throw ( uno::RuntimeException ) +{ + return impl_staticGetSupportedServiceNames(); +} + |