Kaydet (Commit) 9f495d12 authored tarafından Matúš Kukan's avatar Matúš Kukan

Split ZipPackageFolder::saveChild into two functions

And make them static. Probably would be better to kill ContentInfo and
add saveChild as pure virtual into ZipPackageEntry, from which are both
ZipPackageFolder and ZipPackageStream inheriting.

This will also create a bit more sensible call graph when profiling.

Change-Id: If8151332cfa6359e8736c912b7a5633a9162ab36
üst 04ebf437
...@@ -79,10 +79,13 @@ public: ...@@ -79,10 +79,13 @@ public:
void setPackageFormat_Impl( sal_Int32 nFormat ) { m_nFormat = nFormat; } void setPackageFormat_Impl( sal_Int32 nFormat ) { m_nFormat = nFormat; }
void setRemoveOnInsertMode_Impl( bool bRemove ) { this->mbAllowRemoveOnInsert = bRemove; } void setRemoveOnInsertMode_Impl( bool bRemove ) { this->mbAllowRemoveOnInsert = bRemove; }
bool saveChild(const OUString &rShortName, const com::sun::star::packages::ContentInfo &rInfo, OUString &rPath, std::vector < com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > > &rManList, ZipOutputStream & rZipOut, const com::sun::star::uno::Sequence < sal_Int8 >& rEncryptionKey, rtlRandomPool & rRandomPool) const;
// Recursive functions // Recursive functions
void saveContents(OUString &rPath, std::vector < com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > > &rManList, ZipOutputStream & rZipOut, const com::sun::star::uno::Sequence< sal_Int8 > &rEncryptionKey, rtlRandomPool & rRandomPool) const void saveContents(
const OUString &rPath,
std::vector < com::sun::star::uno::Sequence < com::sun::star::beans::PropertyValue > > &rManList,
ZipOutputStream & rZipOut,
const com::sun::star::uno::Sequence< sal_Int8 > &rEncryptionKey,
const rtlRandomPool & rRandomPool) const
throw(::com::sun::star::uno::RuntimeException); throw(::com::sun::star::uno::RuntimeException);
void releaseUpwardRef(); void releaseUpwardRef();
......
...@@ -294,7 +294,57 @@ static void ImplSetStoredData( ZipEntry & rEntry, uno::Reference< XInputStream> ...@@ -294,7 +294,57 @@ static void ImplSetStoredData( ZipEntry & rEntry, uno::Reference< XInputStream>
rEntry.nCrc = aCRC32.getValue(); rEntry.nCrc = aCRC32.getValue();
} }
bool ZipPackageFolder::saveChild( const OUString &rShortName, const ContentInfo &rInfo, OUString &rPath, std::vector < uno::Sequence < PropertyValue > > &rManList, ZipOutputStream & rZipOut, const uno::Sequence < sal_Int8 >& rEncryptionKey, rtlRandomPool &rRandomPool) const static bool ZipPackageFolder_saveChild(
const ContentInfo &rInfo,
const OUString &rPath,
std::vector < uno::Sequence < PropertyValue > > &rManList,
ZipOutputStream & rZipOut,
const uno::Sequence < sal_Int8 >& rEncryptionKey,
const rtlRandomPool &rRandomPool,
sal_Int32 nFormat)
{
bool bSuccess = true;
const OUString sMediaTypeProperty ("MediaType");
const OUString sVersionProperty ("Version");
const OUString sFullPathProperty ("FullPath");
uno::Sequence < PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST);
assert( rInfo.bFolder && rInfo.pFolder && "A valid child object is expected!" );
OUString sTempName = rPath + "/";
if ( !rInfo.pFolder->GetMediaType().isEmpty() )
{
aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty;
aPropSet[PKG_MNFST_MEDIATYPE].Value <<= rInfo.pFolder->GetMediaType();
aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
aPropSet[PKG_MNFST_VERSION].Value <<= rInfo.pFolder->GetVersion();
aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
aPropSet[PKG_MNFST_FULLPATH].Value <<= sTempName;
}
else
aPropSet.realloc( 0 );
rInfo.pFolder->saveContents( sTempName, rManList, rZipOut, rEncryptionKey, rRandomPool);
// folder can have a mediatype only in package format
if ( aPropSet.getLength()
&& ( nFormat == embed::StorageFormats::PACKAGE || ( nFormat == embed::StorageFormats::OFOPXML && !rInfo.bFolder ) ) )
rManList.push_back( aPropSet );
return bSuccess;
}
static bool ZipPackageStream_saveChild(
const ContentInfo &rInfo,
const OUString &rPath,
std::vector < uno::Sequence < PropertyValue > > &rManList,
ZipOutputStream & rZipOut,
const uno::Sequence < sal_Int8 >& rEncryptionKey,
const rtlRandomPool &rRandomPool,
sal_Int32 nFormat)
{ {
bool bSuccess = true; bool bSuccess = true;
...@@ -309,311 +359,165 @@ bool ZipPackageFolder::saveChild( const OUString &rShortName, const ContentInfo ...@@ -309,311 +359,165 @@ bool ZipPackageFolder::saveChild( const OUString &rShortName, const ContentInfo
const OUString sEncryptionAlgProperty ("EncryptionAlgorithm"); const OUString sEncryptionAlgProperty ("EncryptionAlgorithm");
const OUString sStartKeyAlgProperty ("StartKeyAlgorithm"); const OUString sStartKeyAlgProperty ("StartKeyAlgorithm");
const OUString sDigestAlgProperty ("DigestAlgorithm"); const OUString sDigestAlgProperty ("DigestAlgorithm");
const OUString sDerivedKeySizeProperty ("DerivedKeySize"); const OUString sDerivedKeySizeProperty ("DerivedKeySize");
uno::Sequence < PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST); uno::Sequence < PropertyValue > aPropSet (PKG_SIZE_NOENCR_MNFST);
OSL_ENSURE( ( rInfo.bFolder && rInfo.pFolder ) || ( !rInfo.bFolder && rInfo.pStream ), "A valid child object is expected!" ); assert( !rInfo.bFolder && rInfo.pStream && "A valid child object is expected!" );
if ( rInfo.bFolder )
{
OUString sTempName = rPath + rShortName + "/";
if ( !rInfo.pFolder->GetMediaType().isEmpty() ) // if pTempEntry is necessary, it will be released and passed to the ZipOutputStream
{ // and be deleted in the ZipOutputStream destructor
aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty; unique_ptr < ZipEntry > pAutoTempEntry ( new ZipEntry );
aPropSet[PKG_MNFST_MEDIATYPE].Value <<= rInfo.pFolder->GetMediaType(); ZipEntry* pTempEntry = pAutoTempEntry.get();
aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
aPropSet[PKG_MNFST_VERSION].Value <<= rInfo.pFolder->GetVersion();
aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
aPropSet[PKG_MNFST_FULLPATH].Value <<= sTempName;
}
else
aPropSet.realloc( 0 );
rInfo.pFolder->saveContents( sTempName, rManList, rZipOut, rEncryptionKey, rRandomPool); // In case the entry we are reading is also the entry we are writing, we will
} // store the ZipEntry data in pTempEntry
else
{
// if pTempEntry is necessary, it will be released and passed to the ZipOutputStream
// and be deleted in the ZipOutputStream destructor
unique_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 ZipPackageFolder::copyZipEntry ( *pTempEntry, rInfo.pStream->aEntry );
// store the ZipEntry data in pTempEntry pTempEntry->sPath = rPath;
pTempEntry->nPathLen = (sal_Int16)( OUStringToOString( pTempEntry->sPath, RTL_TEXTENCODING_UTF8 ).getLength() );
ZipPackageFolder::copyZipEntry ( *pTempEntry, rInfo.pStream->aEntry ); bool bToBeEncrypted = rInfo.pStream->IsToBeEncrypted() && (rEncryptionKey.getLength() || rInfo.pStream->HasOwnKey());
pTempEntry->sPath = rPath + rShortName; bool bToBeCompressed = bToBeEncrypted ? sal_True : rInfo.pStream->IsToBeCompressed();
pTempEntry->nPathLen = (sal_Int16)( OUStringToOString( pTempEntry->sPath, RTL_TEXTENCODING_UTF8 ).getLength() );
bool bToBeEncrypted = rInfo.pStream->IsToBeEncrypted() && (rEncryptionKey.getLength() || rInfo.pStream->HasOwnKey()); aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty;
bool bToBeCompressed = bToBeEncrypted ? sal_True : rInfo.pStream->IsToBeCompressed(); aPropSet[PKG_MNFST_MEDIATYPE].Value <<= rInfo.pStream->GetMediaType( );
aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
aPropSet[PKG_MNFST_VERSION].Value <<= OUString(); // no version is stored for streams currently
aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
aPropSet[PKG_MNFST_FULLPATH].Value <<= pTempEntry->sPath;
aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty; OSL_ENSURE( rInfo.pStream->GetStreamMode() != PACKAGE_STREAM_NOTSET, "Unacceptable ZipPackageStream mode!" );
aPropSet[PKG_MNFST_MEDIATYPE].Value <<= rInfo.pStream->GetMediaType( );
aPropSet[PKG_MNFST_VERSION].Name = sVersionProperty;
aPropSet[PKG_MNFST_VERSION].Value <<= OUString(); // no version is stored for streams currently
aPropSet[PKG_MNFST_FULLPATH].Name = sFullPathProperty;
aPropSet[PKG_MNFST_FULLPATH].Value <<= pTempEntry->sPath;
OSL_ENSURE( rInfo.pStream->GetStreamMode() != PACKAGE_STREAM_NOTSET, "Unacceptable ZipPackageStream mode!" ); bool bRawStream = false;
if ( rInfo.pStream->GetStreamMode() == PACKAGE_STREAM_DETECT )
bRawStream = rInfo.pStream->ParsePackageRawStream();
else if ( rInfo.pStream->GetStreamMode() == PACKAGE_STREAM_RAW )
bRawStream = true;
bool bRawStream = false; bool bTransportOwnEncrStreamAsRaw = false;
if ( rInfo.pStream->GetStreamMode() == PACKAGE_STREAM_DETECT ) // During the storing the original size of the stream can be changed
bRawStream = rInfo.pStream->ParsePackageRawStream(); // TODO/LATER: get rid of this hack
else if ( rInfo.pStream->GetStreamMode() == PACKAGE_STREAM_RAW ) sal_Int64 nOwnStreamOrigSize = bRawStream ? rInfo.pStream->GetMagicalHackSize() : rInfo.pStream->getSize();
bRawStream = true;
bool bTransportOwnEncrStreamAsRaw = false; bool bUseNonSeekableAccess = false;
// During the storing the original size of the stream can be changed uno::Reference < XInputStream > xStream;
// TODO/LATER: get rid of this hack if ( !rInfo.pStream->IsPackageMember() && !bRawStream && !bToBeEncrypted && bToBeCompressed )
sal_Int64 nOwnStreamOrigSize = bRawStream ? rInfo.pStream->GetMagicalHackSize() : rInfo.pStream->getSize(); {
// 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
bool bUseNonSeekableAccess = false; xStream = rInfo.pStream->GetOwnStreamNoWrap();
uno::Reference < XInputStream > xStream; uno::Reference < XSeekable > xSeek ( xStream, uno::UNO_QUERY );
if ( !rInfo.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 = rInfo.pStream->GetOwnStreamNoWrap(); bUseNonSeekableAccess = ( xStream.is() && !xSeek.is() );
uno::Reference < XSeekable > xSeek ( xStream, uno::UNO_QUERY ); }
bUseNonSeekableAccess = ( xStream.is() && !xSeek.is() ); if ( !bUseNonSeekableAccess )
} {
xStream = rInfo.pStream->getRawData();
if ( !bUseNonSeekableAccess ) if ( !xStream.is() )
{ {
xStream = rInfo.pStream->getRawData(); OSL_FAIL( "ZipPackageStream didn't have a stream associated with it, skipping!" );
bSuccess = false;
if ( !xStream.is() ) return bSuccess;
{ }
OSL_FAIL( "ZipPackageStream didn't have a stream associated with it, skipping!" );
bSuccess = false;
return bSuccess;
}
uno::Reference < XSeekable > xSeek ( xStream, uno::UNO_QUERY ); uno::Reference < XSeekable > xSeek ( xStream, uno::UNO_QUERY );
try try
{
if ( xSeek.is() )
{ {
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 )
{ {
// If the stream is a raw one, then we should be positioned // The raw stream can neither be encrypted nor connected
// at the beginning of the actual data OSL_ENSURE( !bRawStream || !(bToBeCompressed || bToBeEncrypted), "The stream is already encrypted!\n" );
if ( !bToBeCompressed || bRawStream ) xSeek->seek ( bRawStream ? rInfo.pStream->GetMagicalHackPos() : 0 );
{ ImplSetStoredData ( *pTempEntry, xStream );
// The raw stream can neither be encrypted nor connected
OSL_ENSURE( !bRawStream || !(bToBeCompressed || bToBeEncrypted), "The stream is already encrypted!\n" );
xSeek->seek ( bRawStream ? rInfo.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 = xSeek->getLength();
nOwnStreamOrigSize = pTempEntry->nSize;
}
xSeek->seek ( 0 ); // TODO/LATER: Get rid of hacks related to switching of Flag Method and Size properties!
} }
else else if ( bToBeEncrypted )
{ {
// Okay, we don't have an xSeekable stream. This is possibly bad. // this is the correct original size
// check if it's one of our own streams, if it is then we know that pTempEntry->nSize = xSeek->getLength();
// each time we ask for it we'll get a new stream that will be nOwnStreamOrigSize = pTempEntry->nSize;
// at position zero...otherwise, assert and skip this stream...
if ( rInfo.pStream->IsPackageMember() )
{
// if the password has been changed than the stream should not be package member any more
if ( rInfo.pStream->IsEncrypted() && rInfo.pStream->IsToBeEncrypted() )
{
// Should be handled close to the raw stream handling
bTransportOwnEncrStreamAsRaw = 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
{
bSuccess = false;
return bSuccess;
}
} }
}
catch ( uno::Exception& )
{
bSuccess = false;
return bSuccess;
}
if ( bToBeEncrypted || bRawStream || bTransportOwnEncrStreamAsRaw ) xSeek->seek ( 0 );
}
else
{ {
if ( bToBeEncrypted && !bTransportOwnEncrStreamAsRaw ) // 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 ( rInfo.pStream->IsPackageMember() )
{ {
uno::Sequence < sal_Int8 > aSalt( 16 ), aVector( rInfo.pStream->GetBlockSize() ); // if the password has been changed than the stream should not be package member any more
rtl_random_getBytes ( rRandomPool, aSalt.getArray(), 16 ); if ( rInfo.pStream->IsEncrypted() && rInfo.pStream->IsToBeEncrypted() )
rtl_random_getBytes ( rRandomPool, aVector.getArray(), aVector.getLength() ); {
sal_Int32 nIterationCount = 1024; // Should be handled close to the raw stream handling
bTransportOwnEncrStreamAsRaw = true;
if ( !rInfo.pStream->HasOwnKey() ) pTempEntry->nMethod = STORED;
rInfo.pStream->setKey ( rEncryptionKey );
// TODO/LATER: get rid of this situation
rInfo.pStream->setInitialisationVector ( aVector ); // this size should be different from the one that will be stored in manifest.xml
rInfo.pStream->setSalt ( aSalt ); // it is used in storing algorithms and after storing the correct size will be set
rInfo.pStream->setIterationCount ( nIterationCount ); pTempEntry->nSize = pTempEntry->nCompressedSize;
} }
// last property is digest, which is inserted later if we didn't have
// a magic header
aPropSet.realloc(PKG_SIZE_ENCR_MNFST);
aPropSet[PKG_MNFST_INIVECTOR].Name = sInitialisationVectorProperty;
aPropSet[PKG_MNFST_INIVECTOR].Value <<= rInfo.pStream->getInitialisationVector();
aPropSet[PKG_MNFST_SALT].Name = sSaltProperty;
aPropSet[PKG_MNFST_SALT].Value <<= rInfo.pStream->getSalt();
aPropSet[PKG_MNFST_ITERATION].Name = sIterationCountProperty;
aPropSet[PKG_MNFST_ITERATION].Value <<= rInfo.pStream->getIterationCount ();
// Need to store the uncompressed size in the manifest
OSL_ENSURE( nOwnStreamOrigSize >= 0, "The stream size was not correctly initialized!\n" );
aPropSet[PKG_MNFST_UCOMPSIZE].Name = sSizeProperty;
aPropSet[PKG_MNFST_UCOMPSIZE].Value <<= nOwnStreamOrigSize;
if ( bRawStream || bTransportOwnEncrStreamAsRaw )
{
::rtl::Reference< EncryptionData > xEncData = rInfo.pStream->GetEncryptionData();
if ( !xEncData.is() )
throw uno::RuntimeException();
aPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
aPropSet[PKG_MNFST_DIGEST].Value <<= rInfo.pStream->getDigest();
aPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
aPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
aPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
aPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID;
aPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
aPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg;
aPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
aPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
} }
} else
}
// 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
|| ( rInfo.pStream->IsPackageMember() && !bToBeEncrypted
&& ( ( rInfo.pStream->aEntry.nMethod == DEFLATED && bToBeCompressed )
|| ( rInfo.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 ( rInfo.pStream->IsPackageMember() )
{
xStream = rInfo.pStream->getRawData();
if ( !xStream.is() )
{ {
// Make sure that we actually _got_ a new one !
bSuccess = false; bSuccess = false;
return bSuccess; return bSuccess;
} }
} }
try
{
if ( bRawStream )
xStream->skipBytes( rInfo.pStream->GetMagicalHackPos() );
rZipOut.putNextEntry ( *pTempEntry, rInfo.pStream, false );
// the entry is provided to the ZipOutputStream that will delete it
pAutoTempEntry.release();
uno::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& )
{
bSuccess = false;
}
catch ( IOException& )
{
bSuccess = false;
}
} }
else catch ( uno::Exception& )
{ {
// This stream is defenitly not a raw stream bSuccess = false;
return bSuccess;
// 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 if ( bToBeEncrypted || bRawStream || bTransportOwnEncrStreamAsRaw )
// so we need to re-get it, unencrypted, uncompressed and positioned at the {
// beginning of the stream if ( bToBeEncrypted && !bTransportOwnEncrStreamAsRaw )
if ( rInfo.pStream->IsPackageMember() )
{ {
xStream = rInfo.pStream->getInputStream(); uno::Sequence < sal_Int8 > aSalt( 16 ), aVector( rInfo.pStream->GetBlockSize() );
if ( !xStream.is() ) rtl_random_getBytes ( rRandomPool, aSalt.getArray(), 16 );
{ rtl_random_getBytes ( rRandomPool, aVector.getArray(), aVector.getLength() );
// Make sure that we actually _got_ a new one ! sal_Int32 nIterationCount = 1024;
bSuccess = false;
return bSuccess;
}
}
if ( bToBeCompressed ) if ( !rInfo.pStream->HasOwnKey() )
{ rInfo.pStream->setKey ( rEncryptionKey );
pTempEntry->nMethod = DEFLATED;
pTempEntry->nCrc = -1; rInfo.pStream->setInitialisationVector ( aVector );
pTempEntry->nCompressedSize = pTempEntry->nSize = -1; rInfo.pStream->setSalt ( aSalt );
rInfo.pStream->setIterationCount ( nIterationCount );
} }
try // last property is digest, which is inserted later if we didn't have
{ // a magic header
rZipOut.putNextEntry ( *pTempEntry, rInfo.pStream, bToBeEncrypted); aPropSet.realloc(PKG_SIZE_ENCR_MNFST);
// the entry is provided to the ZipOutputStream that will delete it
pAutoTempEntry.release();
sal_Int32 nLength; aPropSet[PKG_MNFST_INIVECTOR].Name = sInitialisationVectorProperty;
uno::Sequence < sal_Int8 > aSeq (n_ConstBufferSize); aPropSet[PKG_MNFST_INIVECTOR].Value <<= rInfo.pStream->getInitialisationVector();
do aPropSet[PKG_MNFST_SALT].Name = sSaltProperty;
{ aPropSet[PKG_MNFST_SALT].Value <<= rInfo.pStream->getSalt();
nLength = xStream->readBytes(aSeq, n_ConstBufferSize); aPropSet[PKG_MNFST_ITERATION].Name = sIterationCountProperty;
rZipOut.write(aSeq, 0, nLength); aPropSet[PKG_MNFST_ITERATION].Value <<= rInfo.pStream->getIterationCount ();
}
while ( nLength == n_ConstBufferSize );
rZipOut.closeEntry(); // Need to store the uncompressed size in the manifest
} OSL_ENSURE( nOwnStreamOrigSize >= 0, "The stream size was not correctly initialized!\n" );
catch ( ZipException& ) aPropSet[PKG_MNFST_UCOMPSIZE].Name = sSizeProperty;
{ aPropSet[PKG_MNFST_UCOMPSIZE].Value <<= nOwnStreamOrigSize;
bSuccess = false;
}
catch ( IOException& )
{
bSuccess = false;
}
if ( bToBeEncrypted ) if ( bRawStream || bTransportOwnEncrStreamAsRaw )
{ {
::rtl::Reference< EncryptionData > xEncData = rInfo.pStream->GetEncryptionData(); ::rtl::Reference< EncryptionData > xEncData = rInfo.pStream->GetEncryptionData();
if ( !xEncData.is() ) if ( !xEncData.is() )
...@@ -629,53 +533,184 @@ bool ZipPackageFolder::saveChild( const OUString &rShortName, const ContentInfo ...@@ -629,53 +533,184 @@ bool ZipPackageFolder::saveChild( const OUString &rShortName, const ContentInfo
aPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg; aPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg;
aPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty; aPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
aPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize; aPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
rInfo.pStream->SetIsEncrypted ( true );
} }
} }
}
if( bSuccess ) // 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
|| ( rInfo.pStream->IsPackageMember() && !bToBeEncrypted
&& ( ( rInfo.pStream->aEntry.nMethod == DEFLATED && bToBeCompressed )
|| ( rInfo.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 ( rInfo.pStream->IsPackageMember() )
{ {
if ( !rInfo.pStream->IsPackageMember() ) xStream = rInfo.pStream->getRawData();
if ( !xStream.is() )
{ {
rInfo.pStream->CloseOwnStreamIfAny(); // Make sure that we actually _got_ a new one !
rInfo.pStream->SetPackageMember ( true ); bSuccess = false;
return bSuccess;
} }
}
try
{
if ( bRawStream ) if ( bRawStream )
xStream->skipBytes( rInfo.pStream->GetMagicalHackPos() );
rZipOut.putNextEntry ( *pTempEntry, rInfo.pStream, false );
// the entry is provided to the ZipOutputStream that will delete it
pAutoTempEntry.release();
uno::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& )
{
bSuccess = false;
}
catch ( IOException& )
{
bSuccess = false;
}
}
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 ( rInfo.pStream->IsPackageMember() )
{
xStream = rInfo.pStream->getInputStream();
if ( !xStream.is() )
{ {
// the raw stream was integrated and now behaves // Make sure that we actually _got_ a new one !
// as usual encrypted stream bSuccess = false;
rInfo.pStream->SetToBeEncrypted( true ); return bSuccess;
} }
}
if ( bToBeCompressed )
{
pTempEntry->nMethod = DEFLATED;
pTempEntry->nCrc = -1;
pTempEntry->nCompressedSize = pTempEntry->nSize = -1;
}
// Then copy it back afterwards... try
ZipPackageFolder::copyZipEntry ( rInfo.pStream->aEntry, *pTempEntry ); {
rZipOut.putNextEntry ( *pTempEntry, rInfo.pStream, bToBeEncrypted);
// the entry is provided to the ZipOutputStream that will delete it
pAutoTempEntry.release();
// Remove hacky bit from entry flags sal_Int32 nLength;
if ( rInfo.pStream->aEntry.nFlag & ( 1 << 4 ) ) uno::Sequence < sal_Int8 > aSeq (n_ConstBufferSize);
do
{ {
rInfo.pStream->aEntry.nFlag &= ~( 1 << 4 ); nLength = xStream->readBytes(aSeq, n_ConstBufferSize);
rInfo.pStream->aEntry.nMethod = STORED; rZipOut.write(aSeq, 0, nLength);
} }
while ( nLength == n_ConstBufferSize );
// TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving ) rZipOut.closeEntry();
if ( rInfo.pStream->IsEncrypted() ) }
rInfo.pStream->setSize( nOwnStreamOrigSize ); catch ( ZipException& )
{
bSuccess = false;
}
catch ( IOException& )
{
bSuccess = false;
}
rInfo.pStream->aEntry.nOffset *= -1; if ( bToBeEncrypted )
{
::rtl::Reference< EncryptionData > xEncData = rInfo.pStream->GetEncryptionData();
if ( !xEncData.is() )
throw uno::RuntimeException();
aPropSet[PKG_MNFST_DIGEST].Name = sDigestProperty;
aPropSet[PKG_MNFST_DIGEST].Value <<= rInfo.pStream->getDigest();
aPropSet[PKG_MNFST_ENCALG].Name = sEncryptionAlgProperty;
aPropSet[PKG_MNFST_ENCALG].Value <<= xEncData->m_nEncAlg;
aPropSet[PKG_MNFST_STARTALG].Name = sStartKeyAlgProperty;
aPropSet[PKG_MNFST_STARTALG].Value <<= xEncData->m_nStartKeyGenID;
aPropSet[PKG_MNFST_DIGESTALG].Name = sDigestAlgProperty;
aPropSet[PKG_MNFST_DIGESTALG].Value <<= xEncData->m_nCheckAlg;
aPropSet[PKG_MNFST_DERKEYSIZE].Name = sDerivedKeySizeProperty;
aPropSet[PKG_MNFST_DERKEYSIZE].Value <<= xEncData->m_nDerivedKeySize;
rInfo.pStream->SetIsEncrypted ( true );
} }
} }
if( bSuccess )
{
if ( !rInfo.pStream->IsPackageMember() )
{
rInfo.pStream->CloseOwnStreamIfAny();
rInfo.pStream->SetPackageMember ( true );
}
if ( bRawStream )
{
// the raw stream was integrated and now behaves
// as usual encrypted stream
rInfo.pStream->SetToBeEncrypted( true );
}
// Then copy it back afterwards...
ZipPackageFolder::copyZipEntry ( rInfo.pStream->aEntry, *pTempEntry );
// Remove hacky bit from entry flags
if ( rInfo.pStream->aEntry.nFlag & ( 1 << 4 ) )
{
rInfo.pStream->aEntry.nFlag &= ~( 1 << 4 );
rInfo.pStream->aEntry.nMethod = STORED;
}
// TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving )
if ( rInfo.pStream->IsEncrypted() )
rInfo.pStream->setSize( nOwnStreamOrigSize );
rInfo.pStream->aEntry.nOffset *= -1;
}
// folder can have a mediatype only in package format // folder can have a mediatype only in package format
if ( aPropSet.getLength() if ( aPropSet.getLength()
&& ( m_nFormat == embed::StorageFormats::PACKAGE || ( m_nFormat == embed::StorageFormats::OFOPXML && !rInfo.bFolder ) ) ) && ( nFormat == embed::StorageFormats::PACKAGE || ( nFormat == embed::StorageFormats::OFOPXML && !rInfo.bFolder ) ) )
rManList.push_back( aPropSet ); rManList.push_back( aPropSet );
return bSuccess; return bSuccess;
} }
void ZipPackageFolder::saveContents( OUString &rPath, std::vector < uno::Sequence < PropertyValue > > &rManList, ZipOutputStream & rZipOut, const uno::Sequence < sal_Int8 >& rEncryptionKey, rtlRandomPool &rRandomPool ) const void ZipPackageFolder::saveContents(
const OUString &rPath,
std::vector < uno::Sequence < PropertyValue > > &rManList,
ZipOutputStream & rZipOut,
const uno::Sequence < sal_Int8 >& rEncryptionKey,
const rtlRandomPool &rRandomPool ) const
throw( uno::RuntimeException ) throw( uno::RuntimeException )
{ {
bool bWritingFailed = false; bool bWritingFailed = false;
...@@ -708,12 +743,13 @@ void ZipPackageFolder::saveContents( OUString &rPath, std::vector < uno::Sequenc ...@@ -708,12 +743,13 @@ void ZipPackageFolder::saveContents( OUString &rPath, std::vector < uno::Sequenc
OUString aMimeTypeStreamName("mimetype"); OUString aMimeTypeStreamName("mimetype");
if ( m_nFormat == embed::StorageFormats::ZIP && rPath.isEmpty() ) if ( m_nFormat == embed::StorageFormats::ZIP && rPath.isEmpty() )
{ {
// let the "mimtype" stream in root folder be stored as the first stream if it is zip format // let the "mimetype" stream in root folder be stored as the first stream if it is zip format
ContentHash::const_iterator aIter = maContents.find ( aMimeTypeStreamName ); ContentHash::const_iterator aIter = maContents.find ( aMimeTypeStreamName );
if ( aIter != maContents.end() && !(*aIter).second->bFolder ) if ( aIter != maContents.end() && !(*aIter).second->bFolder )
{ {
bMimeTypeStreamStored = true; bMimeTypeStreamStored = true;
bWritingFailed = !saveChild( (*aIter).first, *(*aIter).second, rPath, rManList, rZipOut, rEncryptionKey, rRandomPool ); bWritingFailed = !ZipPackageStream_saveChild(
*aIter->second, rPath + aIter->first, rManList, rZipOut, rEncryptionKey, rRandomPool, m_nFormat );
} }
} }
...@@ -725,7 +761,18 @@ void ZipPackageFolder::saveContents( OUString &rPath, std::vector < uno::Sequenc ...@@ -725,7 +761,18 @@ void ZipPackageFolder::saveContents( OUString &rPath, std::vector < uno::Sequenc
const ContentInfo &rInfo = *(*aCI).second; const ContentInfo &rInfo = *(*aCI).second;
if ( !bMimeTypeStreamStored || !rShortName.equals( aMimeTypeStreamName ) ) if ( !bMimeTypeStreamStored || !rShortName.equals( aMimeTypeStreamName ) )
bWritingFailed = !saveChild( rShortName, rInfo, rPath, rManList, rZipOut, rEncryptionKey, rRandomPool ); {
if (rInfo.bFolder)
{
bWritingFailed = !ZipPackageFolder_saveChild(
rInfo, rPath + rShortName, rManList, rZipOut, rEncryptionKey, rRandomPool, m_nFormat );
}
else
{
bWritingFailed = !ZipPackageStream_saveChild(
rInfo, rPath + rShortName, rManList, rZipOut, rEncryptionKey, rRandomPool, m_nFormat );
}
}
} }
if( bWritingFailed ) if( bWritingFailed )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment