blob: cbc40ae5b3f85c9a6e33a018c3b59bdd9a6509ed [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER( update_precomp.py ): autogen include statement, do not remove
#include "precompiled_package.hxx"
#include <com/sun/star/packages/zip/ZipConstants.hpp>
#include <com/sun/star/embed/StorageFormats.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 <com/sun/star/xml/crypto/DigestID.hpp>
#include <com/sun/star/xml/crypto/CipherID.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 <rtl/instance.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;
namespace { struct lcl_CachedImplId : public rtl::Static< Sequence < sal_Int8 >, lcl_CachedImplId > {}; }
const ::com::sun::star::uno::Sequence < sal_Int8 >& ZipPackageStream::static_getImplementationId()
{
return lcl_CachedImplId::get();
}
ZipPackageStream::ZipPackageStream ( ZipPackage & rNewPackage,
const uno::Reference< XMultiServiceFactory >& xFactory,
sal_Bool bAllowRemoveOnInsert )
: m_xFactory( xFactory )
, rZipPackage( rNewPackage )
, bToBeCompressed ( sal_True )
, bToBeEncrypted ( sal_False )
, bHaveOwnKey ( sal_False )
, bIsEncrypted ( sal_False )
, m_nImportedStartKeyAlgorithm( 0 )
, m_nImportedEncryptionAlgorithm( 0 )
, m_nImportedChecksumAlgorithm( 0 )
, m_nImportedDerivedKeySize( 0 )
, m_nStreamMode( PACKAGE_STREAM_NOTSET )
, m_nMagicalHackPos( 0 )
, m_nMagicalHackSize( 0 )
, m_bHasSeekable( sal_False )
, m_bCompressedIsSetFromOutside( sal_False )
, m_bFromManifest( sal_False )
, m_bUseWinEncoding( 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;
Sequence < sal_Int8 > &rCachedImplId = lcl_CachedImplId::get();
if ( !rCachedImplId.getLength() )
rCachedImplId = 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 );
uno::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!" ) ),
uno::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 ( m_xBaseEncryptionData.is() )
throw ZipIOException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Encrypted stream without encryption data!\n" ) ),
uno::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" ) ),
uno::Reference< XInterface >() );
// skip header
xSeek->seek( n_ConstHeaderSize + getInitialisationVector().getLength() +
getSalt().getLength() + getDigest().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;
}
//--------------------------------------------------------------------------
sal_Int32 ZipPackageStream::GetEncryptionAlgorithm() const
{
return m_nImportedEncryptionAlgorithm ? m_nImportedEncryptionAlgorithm : rZipPackage.GetEncAlgID();
}
//--------------------------------------------------------------------------
sal_Int32 ZipPackageStream::GetBlockSize() const
{
return GetEncryptionAlgorithm() == ::com::sun::star::xml::crypto::CipherID::AES_CBC_W3C_PADDING ? 16 : 8;
}
//--------------------------------------------------------------------------
::rtl::Reference< EncryptionData > ZipPackageStream::GetEncryptionData( bool bUseWinEncoding )
{
::rtl::Reference< EncryptionData > xResult;
if ( m_xBaseEncryptionData.is() )
xResult = new EncryptionData(
*m_xBaseEncryptionData,
GetEncryptionKey( bUseWinEncoding ),
GetEncryptionAlgorithm(),
m_nImportedChecksumAlgorithm ? m_nImportedChecksumAlgorithm : rZipPackage.GetChecksumAlgID(),
m_nImportedDerivedKeySize ? m_nImportedDerivedKeySize : rZipPackage.GetDefaultDerivedKeySize(),
GetStartKeyGenID() );
return xResult;
}
//--------------------------------------------------------------------------
void ZipPackageStream::SetBaseEncryptionData( const ::rtl::Reference< BaseEncryptionData >& xData )
{
m_xBaseEncryptionData = xData;
}
//--------------------------------------------------------------------------
uno::Sequence< sal_Int8 > ZipPackageStream::GetEncryptionKey( bool bUseWinEncoding )
{
uno::Sequence< sal_Int8 > aResult;
sal_Int32 nKeyGenID = GetStartKeyGenID();
bUseWinEncoding = ( bUseWinEncoding || m_bUseWinEncoding );
if ( bHaveOwnKey && m_aStorageEncryptionKeys.getLength() )
{
::rtl::OUString aNameToFind;
if ( nKeyGenID == xml::crypto::DigestID::SHA256 )
aNameToFind = PACKAGE_ENCRYPTIONDATA_SHA256UTF8;
else if ( nKeyGenID == xml::crypto::DigestID::SHA1 )
{
aNameToFind = bUseWinEncoding ? PACKAGE_ENCRYPTIONDATA_SHA1MS1252 : PACKAGE_ENCRYPTIONDATA_SHA1UTF8;
}
else
throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No expected key is provided!" ) ), uno::Reference< uno::XInterface >() );
for ( sal_Int32 nInd = 0; nInd < m_aStorageEncryptionKeys.getLength(); nInd++ )
if ( m_aStorageEncryptionKeys[nInd].Name.equals( aNameToFind ) )
m_aStorageEncryptionKeys[nInd].Value >>= aResult;
// empty keys are not allowed here
// so it is not important whether there is no key, or the key is empty, it is an error
if ( !aResult.getLength() )
throw uno::RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "No expected key is provided!" ) ), uno::Reference< uno::XInterface >() );
}
else
aResult = m_aEncryptionKey;
if ( !aResult.getLength() || !bHaveOwnKey )
aResult = rZipPackage.GetEncryptionKey();
return aResult;
}
//--------------------------------------------------------------------------
sal_Int32 ZipPackageStream::GetStartKeyGenID()
{
// generally should all the streams use the same Start Key
// but if raw copy without password takes place, we should preserve the imported algorithm
return m_nImportedStartKeyAlgorithm ? m_nImportedStartKeyAlgorithm : rZipPackage.GetStartKeyGenID();
}
//--------------------------------------------------------------------------
uno::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 = GetEncryptionKey();
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 );
uno::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
uno::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() ) ) );
uno::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( ENCRYPTION_KEY_PROPERTY ) ), makeAny( aKey ) );
xNewPSProps->setPropertyValue( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "Encrypted" ) ), makeAny( sal_True ) );
}
// insert a new stream in the package
uno::Reference< XUnoTunnel > xTunnel;
Any aRoot = pPackage->getByHierarchicalName( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "/" ) ) );
aRoot >>= xTunnel;
uno::Reference< container::XNameContainer > xRootNameContainer( xTunnel, UNO_QUERY );
if ( !xRootNameContainer.is() )
throw RuntimeException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
uno::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
uno::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 = uno::Reference< io::XInputStream >();
xNewPSProps = uno::Reference< XPropertySet >();
xNPSTunnel = uno::Reference< XUnoTunnel >();
xNewPackStream = uno::Reference< XDataSinkEncrSupport >();
xTunnel = uno::Reference< XUnoTunnel >();
xRootNameContainer = uno::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;
::rtl::Reference< BaseEncryptionData > 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 BaseEncryptionData;
::rtl::OUString aMediaType;
sal_Int32 nEncAlgorithm = 0;
sal_Int32 nChecksumAlgorithm = 0;
sal_Int32 nDerivedKeySize = 0;
sal_Int32 nStartKeyGenID = 0;
if ( ZipFile::StaticFillData( xTempEncrData, nEncAlgorithm, nChecksumAlgorithm, nDerivedKeySize, nStartKeyGenID, 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->m_aSalt.getLength()
+ xTempEncrData->m_aInitVector.getLength()
+ xTempEncrData->m_aDigest.getLength()
+ aMediaType.getLength() * sizeof( sal_Unicode );
m_nImportedEncryptionAlgorithm = nEncAlgorithm;
m_nImportedChecksumAlgorithm = nChecksumAlgorithm;
m_nImportedDerivedKeySize = nDerivedKeySize;
m_nImportedStartKeyAlgorithm = nStartKeyGenID;
m_nMagicalHackSize = nMagHackSize;
sMediaType = aMediaType;
bOk = sal_True;
}
}
}
}
catch( Exception& )
{
}
if ( !bOk )
{
// the provided stream is not a raw stream
return sal_False;
}
m_xBaseEncryptionData = 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 uno::Reference< io::XInputStream >& aStream )
throw( RuntimeException )
{
// if seekable access is required the wrapping will be done on demand
xStream = aStream;
m_nImportedEncryptionAlgorithm = 0;
m_bHasSeekable = sal_False;
SetPackageMember ( sal_False );
aEntry.nTime = -1;
m_nStreamMode = PACKAGE_STREAM_DETECT;
}
//--------------------------------------------------------------------------
uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getRawData()
throw( RuntimeException )
{
try
{
if ( IsPackageMember() )
{
return rZipPackage.getZipFile().getRawData( aEntry, GetEncryptionData(), bIsEncrypted, rZipPackage.GetSharedMutexRef() );
}
else if ( GetOwnSeekStream().is() )
{
return new WrapStreamForShare( GetOwnSeekStream(), rZipPackage.GetSharedMutexRef() );
}
else
return uno::Reference < io::XInputStream > ();
}
catch ( ZipException & )//rException )
{
VOS_ENSURE( 0, "ZipException thrown" );//rException.Message );
return uno::Reference < io::XInputStream > ();
}
catch ( Exception & )
{
VOS_ENSURE( 0, "Exception is thrown during stream wrapping!\n" );
return uno::Reference < io::XInputStream > ();
}
}
//--------------------------------------------------------------------------
uno::Reference< io::XInputStream > SAL_CALL ZipPackageStream::getInputStream()
throw( RuntimeException )
{
try
{
if ( IsPackageMember() )
{
return rZipPackage.getZipFile().getInputStream( aEntry, GetEncryptionData(), bIsEncrypted, rZipPackage.GetSharedMutexRef() );
}
else if ( GetOwnSeekStream().is() )
{
return new WrapStreamForShare( GetOwnSeekStream(), rZipPackage.GetSharedMutexRef() );
}
else
return uno::Reference < io::XInputStream > ();
}
catch ( ZipException & )//rException )
{
VOS_ENSURE( 0,"ZipException thrown" );//rException.Message );
return uno::Reference < io::XInputStream > ();
}
catch ( Exception & )
{
VOS_ENSURE( 0, "Exception is thrown during stream wrapping!\n" );
return uno::Reference < io::XInputStream > ();
}
}
// XDataSinkEncrSupport
//--------------------------------------------------------------------------
uno::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 uno::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() )
{
uno::Reference< io::XInputStream > xResult;
try
{
xResult = rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData(), bIsEncrypted, rZipPackage.GetSharedMutexRef() );
}
catch( packages::WrongPasswordException& )
{
// workaround for the encrypted documents generated with the old OOo1.x bug.
if ( rZipPackage.GetStartKeyGenID() == xml::crypto::DigestID::SHA1 && !m_bUseWinEncoding )
{
xResult = rZipPackage.getZipFile().getDataStream( aEntry, GetEncryptionData( true ), bIsEncrypted, rZipPackage.GetSharedMutexRef() );
m_bUseWinEncoding = true;
}
else
throw;
}
return xResult;
}
else if ( m_nStreamMode == PACKAGE_STREAM_RAW )
return ZipFile::StaticGetDataFromRawStream( m_xFactory, GetOwnSeekStream(), GetEncryptionData() );
else if ( GetOwnSeekStream().is() )
{
return new WrapStreamForShare( GetOwnSeekStream(), rZipPackage.GetSharedMutexRef() );
}
else
return uno::Reference< io::XInputStream >();
}
//--------------------------------------------------------------------------
uno::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 uno::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 || !GetEncryptionData().is() )
throw packages::NoEncryptionException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
return rZipPackage.getZipFile().getWrappedRawStream( aEntry, GetEncryptionData(), 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 uno::Reference< io::XInputStream >& aStream )
throw ( io::IOException,
RuntimeException )
{
setInputStream( aStream );
m_nStreamMode = PACKAGE_STREAM_DATA;
}
//--------------------------------------------------------------------------
void SAL_CALL ZipPackageStream::setRawStream( const uno::Reference< io::XInputStream >& aStream )
throw ( packages::EncryptionNotAllowedException,
packages::NoRawFormatException,
io::IOException,
RuntimeException )
{
// wrap the stream in case it is not seekable
uno::Reference< io::XInputStream > xNewStream = ::comphelper::OSeekableInputWrapper::CheckSeekableCanWrap( aStream, m_xFactory );
uno::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!" ) ),
uno::Reference< XInterface >() );
xSeek->seek( 0 );
uno::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 uno::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, GetEncryptionData(), 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 uno::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() != embed::StorageFormats::PACKAGE && rZipPackage.getFormat() != embed::StorageFormats::OFOPXML )
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" ) ),
uno::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" ) ),
uno::Reference< XInterface >(),
2 );
}
else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( "Encrypted" ) ) )
{
if ( rZipPackage.getFormat() != embed::StorageFormats::PACKAGE )
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" ) ),
uno::Reference< XInterface >(),
2 );
bToBeEncrypted = bEnc;
if ( bToBeEncrypted && !m_xBaseEncryptionData.is() )
m_xBaseEncryptionData = new BaseEncryptionData;
}
else
throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong type for Encrypted property!\n" ) ),
uno::Reference< XInterface >(),
2 );
}
else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( ENCRYPTION_KEY_PROPERTY ) ) )
{
if ( rZipPackage.getFormat() != embed::StorageFormats::PACKAGE )
throw beans::PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
uno::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" ) ),
uno::Reference< XInterface >(),
2 );
}
if ( aNewKey.getLength() )
{
if ( !m_xBaseEncryptionData.is() )
m_xBaseEncryptionData = new BaseEncryptionData;
m_aEncryptionKey = 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;
m_aEncryptionKey.realloc( 0 );
}
m_aStorageEncryptionKeys.realloc( 0 );
}
else if ( aPropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( STORAGE_ENCRYPTION_KEYS_PROPERTY ) ) )
{
if ( rZipPackage.getFormat() != embed::StorageFormats::PACKAGE )
throw beans::PropertyVetoException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX ) ), uno::Reference< uno::XInterface >() );
uno::Sequence< beans::NamedValue > aKeys;
if ( !( aValue >>= aKeys ) )
{
throw IllegalArgumentException( ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( OSL_LOG_PREFIX "Wrong type for StorageEncryptionKeys property!\n" ) ),
uno::Reference< XInterface >(),
2 );
}
if ( aKeys.getLength() )
{
if ( !m_xBaseEncryptionData.is() )
m_xBaseEncryptionData = new BaseEncryptionData;
m_aStorageEncryptionKeys = aKeys;
// 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;
m_aStorageEncryptionKeys.realloc( 0 );
}
m_aEncryptionKey.realloc( 0 );
}
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" ) ),
uno::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" ) ),
uno::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( ENCRYPTION_KEY_PROPERTY ) ) )
{
aAny <<= m_aEncryptionKey;
return aAny;
}
else if ( PropertyName.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM( STORAGE_ENCRYPTION_KEYS_PROPERTY ) ) )
{
aAny <<= m_aStorageEncryptionKeys;
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];
}