package/inc/ZipOutputEntry.hxx | 29 -- package/inc/ZipOutputStream.hxx | 23 + package/inc/ZipPackageFolder.hxx | 1 package/inc/ZipPackageStream.hxx | 6 package/source/zipapi/ZipOutputEntry.cxx | 307 ++++------------------- package/source/zipapi/ZipOutputStream.cxx | 210 +++++++++++++-- package/source/zippackage/ContentInfo.hxx | 2 package/source/zippackage/ZipPackage.cxx | 30 +- package/source/zippackage/ZipPackageFolder.cxx | 36 -- package/source/zippackage/ZipPackageStream.cxx | 159 +++++++---- package/source/zippackage/wrapstreamforshare.cxx | 4 11 files changed, 396 insertions(+), 411 deletions(-)
New commits: commit 91ed64991ccb066797b10f782ac2af9aefdb2bf8 Author: Matúš Kukan <[email protected]> Date: Tue Oct 21 15:17:13 2014 +0200 package: Finally implement parallel zip entries deflating For that: 1, create ZipPackageStream::successfullyWritten to be called after the content is written 2, Do not take mutex when reading from WrapStreamForShare - threads should be using different streams anyway, but there is only one common mutex. :-/ Change-Id: I90303e49206b19454dd4141e24cc8be29c433045 diff --git a/package/inc/ZipOutputEntry.hxx b/package/inc/ZipOutputEntry.hxx index c24d5a9..9e396ce 100644 --- a/package/inc/ZipOutputEntry.hxx +++ b/package/inc/ZipOutputEntry.hxx @@ -54,6 +54,9 @@ public: ~ZipOutputEntry(); css::uno::Sequence< sal_Int8 > getData(); + ZipEntry* getZipEntry() { return m_pCurrentEntry; } + ZipPackageStream* getZipPackageStream() { return m_pCurrentStream; } + bool isEncrypt() { return m_bEncryptCurrentEntry; } void closeEntry(); void write(const css::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength); diff --git a/package/inc/ZipOutputStream.hxx b/package/inc/ZipOutputStream.hxx index f11b883..ddc921d 100644 --- a/package/inc/ZipOutputStream.hxx +++ b/package/inc/ZipOutputStream.hxx @@ -23,10 +23,12 @@ #include <com/sun/star/io/XOutputStream.hpp> #include <ByteChucker.hxx> +#include <osl/thread.hxx> #include <vector> struct ZipEntry; +class ZipOutputEntry; class ZipPackageStream; class ZipOutputStream @@ -35,14 +37,17 @@ class ZipOutputStream ::std::vector < ZipEntry * > m_aZipList; ByteChucker m_aChucker; - bool m_bFinished; ZipEntry *m_pCurrentEntry; + std::vector< osl::Thread* > m_aWorkers; + std::vector< ZipOutputEntry* > m_aEntries; public: ZipOutputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > &xOStream ); ~ZipOutputStream(); + void addDeflatingThread( ZipOutputEntry *pEntry, osl::Thread *pThread ); + void writeLOC( ZipEntry *pEntry, bool bEncrypt = false ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); void rawWrite( ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) diff --git a/package/inc/ZipPackageStream.hxx b/package/inc/ZipPackageStream.hxx index 8f9b76a..b639a1f 100644 --- a/package/inc/ZipPackageStream.hxx +++ b/package/inc/ZipPackageStream.hxx @@ -63,14 +63,13 @@ private: sal_uInt8 m_nStreamMode; sal_uInt32 m_nMagicalHackPos; sal_uInt32 m_nMagicalHackSize; + sal_Int64 m_nOwnStreamOrigSize; bool m_bHasSeekable; - bool m_bCompressedIsSetFromOutside; - bool m_bFromManifest; - bool m_bUseWinEncoding; + bool m_bRawStream; ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > GetOwnSeekStream(); @@ -138,6 +137,7 @@ public: void setZipEntryOnLoading( const ZipEntry &rInEntry); ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getRawData() throw(::com::sun::star::uno::RuntimeException); + void successfullyWritten( ZipEntry *pEntry ); static ::com::sun::star::uno::Sequence < sal_Int8 > static_getImplementationId(); diff --git a/package/source/zipapi/ZipOutputEntry.cxx b/package/source/zipapi/ZipOutputEntry.cxx index f43b5c7..a5fbe25 100644 --- a/package/source/zipapi/ZipOutputEntry.cxx +++ b/package/source/zipapi/ZipOutputEntry.cxx @@ -47,14 +47,13 @@ ZipOutputEntry::ZipOutputEntry( const uno::Reference< uno::XComponentContext >& , m_pCurrentEntry(&rEntry) , m_nDigested(0) , m_bEncryptCurrentEntry(bEncrypt) -, m_pCurrentStream(NULL) +, m_pCurrentStream(pStream) { assert(m_pCurrentEntry->nMethod == DEFLATED && "Use ZipPackageStream::rawWrite() for STORED entries"); if (m_bEncryptCurrentEntry) { m_xCipherContext = ZipFile::StaticGetCipher( rxContext, pStream->GetEncryptionData(), true ); m_xDigestContext = ZipFile::StaticGetDigestContextForChecksum( rxContext, pStream->GetEncryptionData() ); - m_pCurrentStream = pStream; } } diff --git a/package/source/zipapi/ZipOutputStream.cxx b/package/source/zipapi/ZipOutputStream.cxx index c9b6e08..c191b34 100644 --- a/package/source/zipapi/ZipOutputStream.cxx +++ b/package/source/zipapi/ZipOutputStream.cxx @@ -27,6 +27,7 @@ #include <PackageConstants.hxx> #include <ZipEntry.hxx> +#include <ZipOutputEntry.hxx> #include <ZipPackageStream.hxx> using namespace com::sun::star; @@ -39,15 +40,12 @@ using namespace com::sun::star::packages::zip::ZipConstants; ZipOutputStream::ZipOutputStream( const uno::Reference < io::XOutputStream > &xOStream ) : m_xStream(xOStream) , m_aChucker(xOStream) -, m_bFinished(false) , m_pCurrentEntry(NULL) { } ZipOutputStream::~ZipOutputStream( void ) { - for (sal_Int32 i = 0, nEnd = m_aZipList.size(); i < nEnd; i++) - delete m_aZipList[i]; } void ZipOutputStream::setEntry( ZipEntry *pEntry ) @@ -66,6 +64,13 @@ void ZipOutputStream::setEntry( ZipEntry *pEntry ) } } +void ZipOutputStream::addDeflatingThread( ZipOutputEntry *pEntry, osl::Thread *pThread ) +{ + m_aWorkers.push_back(pThread); + m_aEntries.push_back(pEntry); + pThread->create(); +} + void ZipOutputStream::rawWrite( Sequence< sal_Int8 >& rBuffer, sal_Int32 /*nNewOffset*/, sal_Int32 nNewLength ) throw(IOException, RuntimeException) { @@ -85,21 +90,38 @@ void ZipOutputStream::rawCloseEntry( bool bEncrypt ) m_pCurrentEntry = NULL; } -void ZipOutputStream::finish( ) +void ZipOutputStream::finish() throw(IOException, RuntimeException) { - if (m_bFinished) - return; + assert(!m_aZipList.empty() && "Zip file must have at least one entry!"); - if (m_aZipList.size() < 1) - OSL_FAIL("Zip file must have at least one entry!\n"); + // Wait for all threads to finish & write + for (size_t i = 0; i < m_aWorkers.size(); i++) + { + m_aWorkers[i]->join(); + delete m_aWorkers[i]; + } + + for (size_t i = 0; i < m_aEntries.size(); i++) + { + writeLOC(m_aEntries[i]->getZipEntry(), m_aEntries[i]->isEncrypt()); + uno::Sequence< sal_Int8 > aCompressedData = m_aEntries[i]->getData(); + rawWrite(aCompressedData, 0, aCompressedData.getLength()); + rawCloseEntry(m_aEntries[i]->isEncrypt()); + + m_aEntries[i]->getZipPackageStream()->successfullyWritten(m_aEntries[i]->getZipEntry()); + delete m_aEntries[i]; + } sal_Int32 nOffset= static_cast < sal_Int32 > (m_aChucker.GetPosition()); - for (sal_Int32 i =0, nEnd = m_aZipList.size(); i < nEnd; i++) + for (size_t i = 0; i < m_aZipList.size(); i++) + { writeCEN( *m_aZipList[i] ); + delete m_aZipList[i]; + } writeEND( nOffset, static_cast < sal_Int32 > (m_aChucker.GetPosition()) - nOffset); - m_bFinished = true; m_xStream->flush(); + m_aZipList.clear(); } void ZipOutputStream::writeEND(sal_uInt32 nOffset, sal_uInt32 nLength) diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx index acec90b..c65d903 100644 --- a/package/source/zippackage/ZipPackageStream.cxx +++ b/package/source/zippackage/ZipPackageStream.cxx @@ -90,10 +90,12 @@ ZipPackageStream::ZipPackageStream ( ZipPackage & rNewPackage, , m_nStreamMode( PACKAGE_STREAM_NOTSET ) , m_nMagicalHackPos( 0 ) , m_nMagicalHackSize( 0 ) +, m_nOwnStreamOrigSize( 0 ) , m_bHasSeekable( false ) , m_bCompressedIsSetFromOutside( false ) , m_bFromManifest( false ) , m_bUseWinEncoding( false ) +, m_bRawStream( false ) { m_xContext = xContext; m_nFormat = nFormat; @@ -437,6 +439,35 @@ bool ZipPackageStream::ParsePackageRawStream() return true; } +class DeflateThread: public osl::Thread +{ + ZipOutputEntry *mpEntry; + uno::Reference< io::XInputStream > mxInStream; + +public: + DeflateThread( ZipOutputEntry *pEntry, + const uno::Reference< io::XInputStream >& xInStream ) + : mpEntry(pEntry) + , mxInStream(xInStream) + {} + +private: + virtual void SAL_CALL run() SAL_OVERRIDE + { + sal_Int32 nLength = 0; + uno::Sequence< sal_Int8 > aSeq(n_ConstBufferSize); + do + { + nLength = mxInStream->readBytes(aSeq, n_ConstBufferSize); + mpEntry->write(aSeq, 0, nLength); + } + while (nLength == n_ConstBufferSize); + mpEntry->closeEntry(); + + mxInStream.clear(); + } +}; + static void ImplSetStoredData( ZipEntry & rEntry, uno::Reference< io::XInputStream> & rStream ) { // It's very annoying that we have to do this, but lots of zip packages @@ -497,20 +528,21 @@ bool ZipPackageStream::saveChild( OSL_ENSURE( m_nStreamMode != PACKAGE_STREAM_NOTSET, "Unacceptable ZipPackageStream mode!" ); - bool bRawStream = false; + m_bRawStream = false; if ( m_nStreamMode == PACKAGE_STREAM_DETECT ) - bRawStream = ParsePackageRawStream(); + m_bRawStream = ParsePackageRawStream(); else if ( m_nStreamMode == PACKAGE_STREAM_RAW ) - bRawStream = true; + m_bRawStream = true; + bool bParallelDeflate = false; bool bTransportOwnEncrStreamAsRaw = false; // During the storing the original size of the stream can be changed // TODO/LATER: get rid of this hack - sal_Int64 nOwnStreamOrigSize = bRawStream ? m_nMagicalHackSize : aEntry.nSize; + m_nOwnStreamOrigSize = m_bRawStream ? m_nMagicalHackSize : aEntry.nSize; bool bUseNonSeekableAccess = false; uno::Reference < io::XInputStream > xStream; - if ( !IsPackageMember() && !bRawStream && !bToBeEncrypted && bToBeCompressed ) + if ( !IsPackageMember() && !m_bRawStream && !bToBeEncrypted && bToBeCompressed ) { // the stream is not a package member, not a raw stream, // it should not be encrypted and it should be compressed, @@ -540,11 +572,11 @@ bool ZipPackageStream::saveChild( { // If the stream is a raw one, then we should be positioned // at the beginning of the actual data - if ( !bToBeCompressed || bRawStream ) + if ( !bToBeCompressed || m_bRawStream ) { // The raw stream can neither be encrypted nor connected - OSL_ENSURE( !bRawStream || !(bToBeCompressed || bToBeEncrypted), "The stream is already encrypted!\n" ); - xSeek->seek ( bRawStream ? m_nMagicalHackPos : 0 ); + OSL_ENSURE( !m_bRawStream || !(bToBeCompressed || bToBeEncrypted), "The stream is already encrypted!\n" ); + xSeek->seek ( m_bRawStream ? m_nMagicalHackPos : 0 ); ImplSetStoredData ( *pTempEntry, xStream ); // TODO/LATER: Get rid of hacks related to switching of Flag Method and Size properties! @@ -553,7 +585,7 @@ bool ZipPackageStream::saveChild( { // this is the correct original size pTempEntry->nSize = xSeek->getLength(); - nOwnStreamOrigSize = pTempEntry->nSize; + m_nOwnStreamOrigSize = pTempEntry->nSize; } xSeek->seek ( 0 ); @@ -592,7 +624,7 @@ bool ZipPackageStream::saveChild( return bSuccess; } - if ( bToBeEncrypted || bRawStream || bTransportOwnEncrStreamAsRaw ) + if ( bToBeEncrypted || m_bRawStream || bTransportOwnEncrStreamAsRaw ) { if ( bToBeEncrypted && !bTransportOwnEncrStreamAsRaw ) { @@ -624,11 +656,11 @@ bool ZipPackageStream::saveChild( aPropSet[PKG_MNFST_ITERATION].Value <<= m_xBaseEncryptionData->m_nIterationCount; // Need to store the uncompressed size in the manifest - OSL_ENSURE( nOwnStreamOrigSize >= 0, "The stream size was not correctly initialized!\n" ); + OSL_ENSURE( m_nOwnStreamOrigSize >= 0, "The stream size was not correctly initialized!\n" ); aPropSet[PKG_MNFST_UCOMPSIZE].Name = sSizeProperty; - aPropSet[PKG_MNFST_UCOMPSIZE].Value <<= nOwnStreamOrigSize; + aPropSet[PKG_MNFST_UCOMPSIZE].Value <<= m_nOwnStreamOrigSize; - if ( bRawStream || bTransportOwnEncrStreamAsRaw ) + if ( m_bRawStream || bTransportOwnEncrStreamAsRaw ) { ::rtl::Reference< EncryptionData > xEncData = GetEncryptionData(); if ( !xEncData.is() ) @@ -651,7 +683,7 @@ bool ZipPackageStream::saveChild( // 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 + && ( m_bRawStream || bTransportOwnEncrStreamAsRaw || ( IsPackageMember() && !bToBeEncrypted && ( ( aEntry.nMethod == DEFLATED && bToBeCompressed ) || ( aEntry.nMethod == STORED && !bToBeCompressed ) ) ) ) ) @@ -671,7 +703,7 @@ bool ZipPackageStream::saveChild( try { - if ( bRawStream ) + if ( m_bRawStream ) xStream->skipBytes( m_nMagicalHackPos ); ZipOutputStream::setEntry(pTempEntry); @@ -733,35 +765,29 @@ bool ZipPackageStream::saveChild( try { ZipOutputStream::setEntry(pTempEntry); - rZipOut.writeLOC(pTempEntry, bToBeEncrypted); // the entry is provided to the ZipOutputStream that will delete it pAutoTempEntry.release(); - sal_Int32 nLength; - uno::Sequence < sal_Int8 > aSeq (n_ConstBufferSize); if (pTempEntry->nMethod == STORED) { + sal_Int32 nLength; + uno::Sequence< sal_Int8 > aSeq(n_ConstBufferSize); + rZipOut.writeLOC(pTempEntry, bToBeEncrypted); do { nLength = xStream->readBytes(aSeq, n_ConstBufferSize); rZipOut.rawWrite(aSeq, 0, nLength); } while ( nLength == n_ConstBufferSize ); + rZipOut.rawCloseEntry(bToBeEncrypted); } else { - ZipOutputEntry aZipEntry(m_xContext, *pTempEntry, this, bToBeEncrypted); - do - { - nLength = xStream->readBytes(aSeq, n_ConstBufferSize); - aZipEntry.write(aSeq, 0, nLength); - } - while ( nLength == n_ConstBufferSize ); - aZipEntry.closeEntry(); - uno::Sequence< sal_Int8 > aCompressedData = aZipEntry.getData(); - rZipOut.rawWrite(aCompressedData, 0, aCompressedData.getLength()); + bParallelDeflate = true; + // Start a new thread deflating this zip entry + ZipOutputEntry *pZipEntry = new ZipOutputEntry(m_xContext, *pTempEntry, this, bToBeEncrypted); + rZipOut.addDeflatingThread( pZipEntry, new DeflateThread(pZipEntry, xStream) ); } - rZipOut.rawCloseEntry(bToBeEncrypted); } catch ( ZipException& ) { @@ -793,36 +819,39 @@ bool ZipPackageStream::saveChild( } } - if( bSuccess ) - { - if ( !IsPackageMember() ) - { - CloseOwnStreamIfAny(); - SetPackageMember ( true ); - } + if (bSuccess && !bParallelDeflate) + successfullyWritten(pTempEntry); - if ( bRawStream ) - { - // the raw stream was integrated and now behaves - // as usual encrypted stream - SetToBeEncrypted( true ); - } + if ( aPropSet.getLength() + && ( m_nFormat == embed::StorageFormats::PACKAGE || m_nFormat == embed::StorageFormats::OFOPXML ) ) + rManList.push_back( aPropSet ); - // Then copy it back afterwards... - ZipPackageFolder::copyZipEntry ( aEntry, *pTempEntry ); + return bSuccess; +} - // TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving ) - if ( IsEncrypted() ) - setSize( nOwnStreamOrigSize ); +void ZipPackageStream::successfullyWritten( ZipEntry *pEntry ) +{ + if ( !IsPackageMember() ) + { + CloseOwnStreamIfAny(); + SetPackageMember ( true ); + } - aEntry.nOffset *= -1; + if ( m_bRawStream ) + { + // the raw stream was integrated and now behaves + // as usual encrypted stream + SetToBeEncrypted( true ); } - if ( aPropSet.getLength() - && ( m_nFormat == embed::StorageFormats::PACKAGE || m_nFormat == embed::StorageFormats::OFOPXML ) ) - rManList.push_back( aPropSet ); + // Then copy it back afterwards... + ZipPackageFolder::copyZipEntry( aEntry, *pEntry ); - return bSuccess; + // TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving ) + if ( IsEncrypted() ) + setSize( m_nOwnStreamOrigSize ); + + aEntry.nOffset *= -1; } void ZipPackageStream::SetPackageMember( bool bNewValue ) diff --git a/package/source/zippackage/wrapstreamforshare.cxx b/package/source/zippackage/wrapstreamforshare.cxx index 4f737bf..c74e4b2 100644 --- a/package/source/zippackage/wrapstreamforshare.cxx +++ b/package/source/zippackage/wrapstreamforshare.cxx @@ -54,8 +54,6 @@ sal_Int32 SAL_CALL WrapStreamForShare::readBytes( uno::Sequence< sal_Int8 >& aDa io::IOException, uno::RuntimeException, std::exception ) { - ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); - if ( !m_xInStream.is() ) throw io::IOException(THROW_WHERE ); @@ -73,8 +71,6 @@ sal_Int32 SAL_CALL WrapStreamForShare::readSomeBytes( uno::Sequence< sal_Int8 >& io::IOException, uno::RuntimeException, std::exception ) { - ::osl::MutexGuard aGuard( m_rMutexRef->GetMutex() ); - if ( !m_xInStream.is() ) throw io::IOException(THROW_WHERE ); commit 3bfa5a6355eb06496f03410cf3f651382915f2e8 Author: Matúš Kukan <[email protected]> Date: Tue Oct 21 10:37:02 2014 +0200 package: Call writeLOC always after putNextEntry explicitly Preparation step to parallel deflating. Rename putNextEntry to setEntry and make it a static function. We need to call setEntry before starting thread but writeLOC after. Change-Id: I99a9ffa7dc4c18b47c621847b48bf8469bfb789a diff --git a/package/inc/ZipOutputStream.hxx b/package/inc/ZipOutputStream.hxx index 2d78eb7..f11b883 100644 --- a/package/inc/ZipOutputStream.hxx +++ b/package/inc/ZipOutputStream.hxx @@ -37,33 +37,30 @@ class ZipOutputStream ByteChucker m_aChucker; bool m_bFinished; ZipEntry *m_pCurrentEntry; - bool m_bEncrypt; public: ZipOutputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > &xOStream ); ~ZipOutputStream(); - // rawWrite to support a direct write to the output stream + void writeLOC( ZipEntry *pEntry, bool bEncrypt = false ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); void rawWrite( ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); - void rawCloseEntry() + void rawCloseEntry( bool bEncrypt = false ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); - void putNextEntry( ZipEntry& rEntry, bool bEncrypt = false ) - throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); void finish() throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); static sal_uInt32 getCurrentDosTime(); + static void setEntry( ZipEntry *pEntry ); private: void writeEND(sal_uInt32 nOffset, sal_uInt32 nLength) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); void writeCEN( const ZipEntry &rEntry ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); - sal_Int32 writeLOC( const ZipEntry &rEntry ) - throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); void writeEXT( const ZipEntry &rEntry ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); }; diff --git a/package/source/zipapi/ZipOutputStream.cxx b/package/source/zipapi/ZipOutputStream.cxx index 25cdb18..c9b6e08 100644 --- a/package/source/zipapi/ZipOutputStream.cxx +++ b/package/source/zipapi/ZipOutputStream.cxx @@ -50,28 +50,20 @@ ZipOutputStream::~ZipOutputStream( void ) delete m_aZipList[i]; } -void ZipOutputStream::putNextEntry( ZipEntry& rEntry, bool bEncrypt ) - throw(IOException, RuntimeException) +void ZipOutputStream::setEntry( ZipEntry *pEntry ) { - assert(!m_pCurrentEntry && "Forgot to close an entry before putNextEntry()?"); - if (rEntry.nTime == -1) - rEntry.nTime = getCurrentDosTime(); - if (rEntry.nMethod == -1) - rEntry.nMethod = DEFLATED; - rEntry.nVersion = 20; - rEntry.nFlag = 1 << 11; - if (rEntry.nSize == -1 || rEntry.nCompressedSize == -1 || - rEntry.nCrc == -1) + if (pEntry->nTime == -1) + pEntry->nTime = getCurrentDosTime(); + if (pEntry->nMethod == -1) + pEntry->nMethod = DEFLATED; + pEntry->nVersion = 20; + pEntry->nFlag = 1 << 11; + if (pEntry->nSize == -1 || pEntry->nCompressedSize == -1 || + pEntry->nCrc == -1) { - rEntry.nSize = rEntry.nCompressedSize = 0; - rEntry.nFlag |= 8; + pEntry->nSize = pEntry->nCompressedSize = 0; + pEntry->nFlag |= 8; } - m_bEncrypt = bEncrypt; - - sal_Int32 nLOCLength = writeLOC(rEntry); - rEntry.nOffset = m_aChucker.GetPosition() - nLOCLength; - m_aZipList.push_back( &rEntry ); - m_pCurrentEntry = &rEntry; } void ZipOutputStream::rawWrite( Sequence< sal_Int8 >& rBuffer, sal_Int32 /*nNewOffset*/, sal_Int32 nNewLength ) @@ -80,13 +72,14 @@ void ZipOutputStream::rawWrite( Sequence< sal_Int8 >& rBuffer, sal_Int32 /*nNewO m_aChucker.WriteBytes( Sequence< sal_Int8 >(rBuffer.getConstArray(), nNewLength) ); } -void ZipOutputStream::rawCloseEntry() +void ZipOutputStream::rawCloseEntry( bool bEncrypt ) throw(IOException, RuntimeException) { + assert(m_pCurrentEntry && "Forgot to call writeLOC()?"); if ( m_pCurrentEntry->nMethod == DEFLATED && ( m_pCurrentEntry->nFlag & 8 ) ) writeEXT(*m_pCurrentEntry); - if (m_bEncrypt) + if (bEncrypt) m_pCurrentEntry->nMethod = STORED; m_pCurrentEntry = NULL; @@ -192,9 +185,14 @@ void ZipOutputStream::writeEXT( const ZipEntry &rEntry ) } } -sal_Int32 ZipOutputStream::writeLOC( const ZipEntry &rEntry ) +void ZipOutputStream::writeLOC( ZipEntry *pEntry, bool bEncrypt ) throw(IOException, RuntimeException) { + assert(!m_pCurrentEntry && "Forgot to close an entry with rawCloseEntry()?"); + m_pCurrentEntry = pEntry; + m_aZipList.push_back( m_pCurrentEntry ); + const ZipEntry &rEntry = *m_pCurrentEntry; + if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( rEntry.sPath, true ) ) throw IOException("Unexpected character is used in file name." ); @@ -206,7 +204,7 @@ sal_Int32 ZipOutputStream::writeLOC( const ZipEntry &rEntry ) m_aChucker << rEntry.nFlag; // If it's an encrypted entry, we pretend its stored plain text - if (m_bEncrypt) + if (bEncrypt) m_aChucker << static_cast < sal_Int16 > ( STORED ); else m_aChucker << rEntry.nMethod; @@ -240,7 +238,7 @@ sal_Int32 ZipOutputStream::writeLOC( const ZipEntry &rEntry ) Sequence < sal_Int8 > aSequence( (sal_Int8*)sUTF8Name.getStr(), sUTF8Name.getLength() ); m_aChucker.WriteBytes( aSequence ); - return LOCHDR + nNameLength; + m_pCurrentEntry->nOffset = m_aChucker.GetPosition() - (LOCHDR + nNameLength); } sal_uInt32 ZipOutputStream::getCurrentDosTime() diff --git a/package/source/zippackage/ZipPackage.cxx b/package/source/zippackage/ZipPackage.cxx index c67e193..bc69704 100644 --- a/package/source/zippackage/ZipPackage.cxx +++ b/package/source/zippackage/ZipPackage.cxx @@ -984,7 +984,8 @@ void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut ) try { - aZipOut.putNextEntry(*pEntry); + ZipOutputStream::setEntry(pEntry); + aZipOut.writeLOC(pEntry); aZipOut.rawWrite(aType, 0, nBufferLength); aZipOut.rawCloseEntry(); } @@ -1026,7 +1027,8 @@ void ZipPackage::WriteManifest( ZipOutputStream& aZipOut, const vector< uno::Seq pBuffer->realloc( nBufferLength ); // the manifest.xml is never encrypted - so pass an empty reference - aZipOut.putNextEntry(*pEntry); + ZipOutputStream::setEntry(pEntry); + aZipOut.writeLOC(pEntry); ZipOutputEntry aZipEntry(m_xContext, *pEntry, NULL); aZipEntry.write(pBuffer->getSequence(), 0, nBufferLength); aZipEntry.closeEntry(); @@ -1080,7 +1082,8 @@ void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno: pBuffer->realloc( nBufferLength ); // there is no encryption in this format currently - aZipOut.putNextEntry(*pEntry); + ZipOutputStream::setEntry(pEntry); + aZipOut.writeLOC(pEntry); ZipOutputEntry aZipEntry(m_xContext, *pEntry, NULL); aZipEntry.write(pBuffer->getSequence(), 0, nBufferLength); aZipEntry.closeEntry(); diff --git a/package/source/zippackage/ZipPackageFolder.cxx b/package/source/zippackage/ZipPackageFolder.cxx index a6b2e5c..cb72ed1 100644 --- a/package/source/zippackage/ZipPackageFolder.cxx +++ b/package/source/zippackage/ZipPackageFolder.cxx @@ -337,7 +337,8 @@ void ZipPackageFolder::saveContents( try { - rZipOut.putNextEntry( *pTempEntry ); + ZipOutputStream::setEntry(pTempEntry); + rZipOut.writeLOC(pTempEntry); rZipOut.rawCloseEntry(); } catch ( ZipException& ) diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx index 94e7089..acec90b 100644 --- a/package/source/zippackage/ZipPackageStream.cxx +++ b/package/source/zippackage/ZipPackageStream.cxx @@ -674,7 +674,8 @@ bool ZipPackageStream::saveChild( if ( bRawStream ) xStream->skipBytes( m_nMagicalHackPos ); - rZipOut.putNextEntry(*pTempEntry); + ZipOutputStream::setEntry(pTempEntry); + rZipOut.writeLOC(pTempEntry); // the entry is provided to the ZipOutputStream that will delete it pAutoTempEntry.release(); @@ -731,7 +732,8 @@ bool ZipPackageStream::saveChild( try { - rZipOut.putNextEntry(*pTempEntry, bToBeEncrypted); + ZipOutputStream::setEntry(pTempEntry); + rZipOut.writeLOC(pTempEntry, bToBeEncrypted); // the entry is provided to the ZipOutputStream that will delete it pAutoTempEntry.release(); sal_Int32 nLength; @@ -759,7 +761,7 @@ bool ZipPackageStream::saveChild( uno::Sequence< sal_Int8 > aCompressedData = aZipEntry.getData(); rZipOut.rawWrite(aCompressedData, 0, aCompressedData.getLength()); } - rZipOut.rawCloseEntry(); + rZipOut.rawCloseEntry(bToBeEncrypted); } catch ( ZipException& ) { commit 1a74cf3b8c71c36c98f8db8cd304c5c0315a1f3d Author: Matúš Kukan <[email protected]> Date: Tue Oct 21 12:21:22 2014 +0200 package: Do not use hacky bit 1<<4 in ZipEntry::nFlag Change-Id: I504f5c0c9aa9b655ffb53d9820a33677dad6aa08 diff --git a/package/inc/ZipOutputStream.hxx b/package/inc/ZipOutputStream.hxx index 0c8dafe..2d78eb7 100644 --- a/package/inc/ZipOutputStream.hxx +++ b/package/inc/ZipOutputStream.hxx @@ -37,6 +37,7 @@ class ZipOutputStream ByteChucker m_aChucker; bool m_bFinished; ZipEntry *m_pCurrentEntry; + bool m_bEncrypt; public: ZipOutputStream( diff --git a/package/source/zipapi/ZipOutputStream.cxx b/package/source/zipapi/ZipOutputStream.cxx index d4f0456..25cdb18 100644 --- a/package/source/zipapi/ZipOutputStream.cxx +++ b/package/source/zipapi/ZipOutputStream.cxx @@ -66,10 +66,7 @@ void ZipOutputStream::putNextEntry( ZipEntry& rEntry, bool bEncrypt ) rEntry.nSize = rEntry.nCompressedSize = 0; rEntry.nFlag |= 8; } - if (bEncrypt) - { - rEntry.nFlag |= 1 << 4; - } + m_bEncrypt = bEncrypt; sal_Int32 nLOCLength = writeLOC(rEntry); rEntry.nOffset = m_aChucker.GetPosition() - nLOCLength; @@ -88,6 +85,10 @@ void ZipOutputStream::rawCloseEntry() { if ( m_pCurrentEntry->nMethod == DEFLATED && ( m_pCurrentEntry->nFlag & 8 ) ) writeEXT(*m_pCurrentEntry); + + if (m_bEncrypt) + m_pCurrentEntry->nMethod = STORED; + m_pCurrentEntry = NULL; } @@ -144,19 +145,8 @@ void ZipOutputStream::writeCEN( const ZipEntry &rEntry ) m_aChucker << CENSIG; m_aChucker << rEntry.nVersion; m_aChucker << rEntry.nVersion; - if (rEntry.nFlag & (1 << 4) ) - { - // If it's an encrypted entry, we pretend its stored plain text - ZipEntry *pEntry = const_cast < ZipEntry * > ( &rEntry ); - pEntry->nFlag &= ~(1 <<4 ); - m_aChucker << rEntry.nFlag; - m_aChucker << static_cast < sal_Int16 > ( STORED ); - } - else - { - m_aChucker << rEntry.nFlag; - m_aChucker << rEntry.nMethod; - } + m_aChucker << rEntry.nFlag; + m_aChucker << rEntry.nMethod; bool bWrite64Header = false; m_aChucker << static_cast < sal_uInt32> ( rEntry.nTime ); @@ -214,19 +204,12 @@ sal_Int32 ZipOutputStream::writeLOC( const ZipEntry &rEntry ) m_aChucker << LOCSIG; m_aChucker << rEntry.nVersion; - if (rEntry.nFlag & (1 << 4) ) - { - // If it's an encrypted entry, we pretend its stored plain text - sal_Int16 nTmpFlag = rEntry.nFlag; - nTmpFlag &= ~(1 <<4 ); - m_aChucker << nTmpFlag; + m_aChucker << rEntry.nFlag; + // If it's an encrypted entry, we pretend its stored plain text + if (m_bEncrypt) m_aChucker << static_cast < sal_Int16 > ( STORED ); - } else - { - m_aChucker << rEntry.nFlag; m_aChucker << rEntry.nMethod; - } bool bWrite64Header = false; diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx index ad7596d..94e7089 100644 --- a/package/source/zippackage/ZipPackageStream.cxx +++ b/package/source/zippackage/ZipPackageStream.cxx @@ -809,13 +809,6 @@ bool ZipPackageStream::saveChild( // Then copy it back afterwards... ZipPackageFolder::copyZipEntry ( aEntry, *pTempEntry ); - // Remove hacky bit from entry flags - if ( aEntry.nFlag & ( 1 << 4 ) ) - { - aEntry.nFlag &= ~( 1 << 4 ); - aEntry.nMethod = STORED; - } - // TODO/LATER: get rid of this hack ( the encrypted stream size property is changed during saving ) if ( IsEncrypted() ) setSize( nOwnStreamOrigSize ); commit 95c86f3abd312a2867e83abe2870b4590126b5e9 Author: Matúš Kukan <[email protected]> Date: Tue Oct 21 09:29:19 2014 +0200 There is no XZipOutputEntry interface Change-Id: Ib8fa3351ba25416a13d6c8bf63bd5fc8e43703c5 diff --git a/package/inc/ZipOutputEntry.hxx b/package/inc/ZipOutputEntry.hxx index e04cebf..c24d5a9 100644 --- a/package/inc/ZipOutputEntry.hxx +++ b/package/inc/ZipOutputEntry.hxx @@ -19,7 +19,6 @@ #ifndef INCLUDED_PACKAGE_INC_ZIPOUTPUTENTRY_HXX #define INCLUDED_PACKAGE_INC_ZIPOUTPUTENTRY_HXX -#include <com/sun/star/io/IOException.hpp> #include <com/sun/star/uno/Reference.hxx> #include <com/sun/star/uno/XComponentContext.hpp> #include <com/sun/star/xml/crypto/XCipherContext.hpp> @@ -56,11 +55,8 @@ public: css::uno::Sequence< sal_Int8 > getData(); - // XZipOutputEntry interfaces - void SAL_CALL closeEntry( ) - throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); - void SAL_CALL write( const ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) - throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + void closeEntry(); + void write(const css::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength); private: void doDeflate(); diff --git a/package/source/zipapi/ZipOutputEntry.cxx b/package/source/zipapi/ZipOutputEntry.cxx index bcbb6eb..f43b5c7 100644 --- a/package/source/zipapi/ZipOutputEntry.cxx +++ b/package/source/zipapi/ZipOutputEntry.cxx @@ -68,8 +68,7 @@ uno::Sequence< sal_Int8 > ZipOutputEntry::getData() return m_pBuffer->getSequence(); } -void SAL_CALL ZipOutputEntry::closeEntry() - throw(IOException, RuntimeException) +void ZipOutputEntry::closeEntry() { m_aDeflater.finish(); while (!m_aDeflater.finished()) @@ -120,8 +119,7 @@ void SAL_CALL ZipOutputEntry::closeEntry() } } -void SAL_CALL ZipOutputEntry::write( const Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) - throw(IOException, RuntimeException) +void ZipOutputEntry::write( const Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) { if (!m_aDeflater.finished()) { commit 59c5919b4b9f8000e5c99b1ea2a3aaecf36803ed Author: Matúš Kukan <[email protected]> Date: Tue Oct 21 09:20:24 2014 +0200 package: Use memory stream for compressing zip entries Change-Id: Ibf81dc3cd8a9a9da3dfd6ee6e587a522c4d56a44 diff --git a/package/inc/ZipOutputEntry.hxx b/package/inc/ZipOutputEntry.hxx index 73bd8a4..e04cebf 100644 --- a/package/inc/ZipOutputEntry.hxx +++ b/package/inc/ZipOutputEntry.hxx @@ -29,19 +29,19 @@ #include <CRC32.hxx> struct ZipEntry; -class ZipOutputStream; +class ZipPackageBuffer; class ZipPackageStream; class ZipOutputEntry { ::com::sun::star::uno::Sequence< sal_Int8 > m_aDeflateBuffer; - ZipUtils::Deflater m_aDeflater; + ZipUtils::Deflater m_aDeflater; + css::uno::Reference< ZipPackageBuffer > m_pBuffer; ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XCipherContext > m_xCipherContext; ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XDigestContext > m_xDigestContext; CRC32 m_aCRC; - ZipOutputStream* m_pZipOutputStream; ZipEntry *m_pCurrentEntry; sal_Int16 m_nDigested; bool m_bEncryptCurrentEntry; @@ -50,10 +50,12 @@ class ZipOutputEntry public: ZipOutputEntry( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& rxContext, - ZipOutputStream *pZipOutputStream, ZipEntry& rEntry, ZipPackageStream* pStream, bool bEncrypt = false); + ZipEntry& rEntry, ZipPackageStream* pStream, bool bEncrypt = false); ~ZipOutputEntry(); + css::uno::Sequence< sal_Int8 > getData(); + // XZipOutputEntry interfaces void SAL_CALL closeEntry( ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); diff --git a/package/inc/ZipOutputStream.hxx b/package/inc/ZipOutputStream.hxx index 6775bd0..0c8dafe 100644 --- a/package/inc/ZipOutputStream.hxx +++ b/package/inc/ZipOutputStream.hxx @@ -53,7 +53,6 @@ public: throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); void finish() throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); - ByteChucker& getChucker(); static sal_uInt32 getCurrentDosTime(); diff --git a/package/source/zipapi/ZipOutputEntry.cxx b/package/source/zipapi/ZipOutputEntry.cxx index ca08abb..bcbb6eb 100644 --- a/package/source/zipapi/ZipOutputEntry.cxx +++ b/package/source/zipapi/ZipOutputEntry.cxx @@ -24,11 +24,10 @@ #include <osl/time.h> -#include <ByteChucker.hxx> #include <PackageConstants.hxx> #include <ZipEntry.hxx> #include <ZipFile.hxx> -#include <ZipOutputStream.hxx> +#include <ZipPackageBuffer.hxx> #include <ZipPackageStream.hxx> using namespace com::sun::star; @@ -39,13 +38,12 @@ using namespace com::sun::star::packages::zip::ZipConstants; /** This class is used to deflate Zip entries */ ZipOutputEntry::ZipOutputEntry( const uno::Reference< uno::XComponentContext >& rxContext, - ZipOutputStream* pOutputStream, ZipEntry& rEntry, ZipPackageStream* pStream, bool bEncrypt) : m_aDeflateBuffer(n_ConstBufferSize) , m_aDeflater(DEFAULT_COMPRESSION, true) -, m_pZipOutputStream(pOutputStream) +, m_pBuffer(new ZipPackageBuffer(n_ConstBufferSize)) , m_pCurrentEntry(&rEntry) , m_nDigested(0) , m_bEncryptCurrentEntry(bEncrypt) @@ -64,6 +62,12 @@ ZipOutputEntry::~ZipOutputEntry( void ) { } +uno::Sequence< sal_Int8 > ZipOutputEntry::getData() +{ + m_pBuffer->realloc(m_pBuffer->getPosition()); + return m_pBuffer->getSequence(); +} + void SAL_CALL ZipOutputEntry::closeEntry() throw(IOException, RuntimeException) { @@ -151,7 +155,7 @@ void ZipOutputEntry::doDeflate() // FIXME64: uno::Sequence not 64bit safe. uno::Sequence< sal_Int8 > aEncryptionBuffer = m_xCipherContext->convertWithCipherContext( aTmpBuffer ); - m_pZipOutputStream->getChucker().WriteBytes( aEncryptionBuffer ); + m_pBuffer->writeBytes( aEncryptionBuffer ); // the sizes as well as checksum for encrypted streams is calculated here m_pCurrentEntry->nCompressedSize += aEncryptionBuffer.getLength(); @@ -160,7 +164,7 @@ void ZipOutputEntry::doDeflate() } else { - m_pZipOutputStream->getChucker().WriteBytes ( aTmpBuffer ); + m_pBuffer->writeBytes ( aTmpBuffer ); } } @@ -170,7 +174,7 @@ void ZipOutputEntry::doDeflate() uno::Sequence< sal_Int8 > aEncryptionBuffer = m_xCipherContext->finalizeCipherContextAndDispose(); if ( aEncryptionBuffer.getLength() ) { - m_pZipOutputStream->getChucker().WriteBytes( aEncryptionBuffer ); + m_pBuffer->writeBytes( aEncryptionBuffer ); // the sizes as well as checksum for encrypted streams is calculated hier m_pCurrentEntry->nCompressedSize += aEncryptionBuffer.getLength(); diff --git a/package/source/zipapi/ZipOutputStream.cxx b/package/source/zipapi/ZipOutputStream.cxx index 29c19c4..d4f0456 100644 --- a/package/source/zipapi/ZipOutputStream.cxx +++ b/package/source/zipapi/ZipOutputStream.cxx @@ -108,11 +108,6 @@ void ZipOutputStream::finish( ) m_xStream->flush(); } -ByteChucker& ZipOutputStream::getChucker() -{ - return m_aChucker; -} - void ZipOutputStream::writeEND(sal_uInt32 nOffset, sal_uInt32 nLength) throw(IOException, RuntimeException) { diff --git a/package/source/zippackage/ZipPackage.cxx b/package/source/zippackage/ZipPackage.cxx index d202fb0..c67e193 100644 --- a/package/source/zippackage/ZipPackage.cxx +++ b/package/source/zippackage/ZipPackage.cxx @@ -1027,9 +1027,11 @@ void ZipPackage::WriteManifest( ZipOutputStream& aZipOut, const vector< uno::Seq // the manifest.xml is never encrypted - so pass an empty reference aZipOut.putNextEntry(*pEntry); - ZipOutputEntry aZipEntry(m_xContext, &aZipOut, *pEntry, NULL); + ZipOutputEntry aZipEntry(m_xContext, *pEntry, NULL); aZipEntry.write(pBuffer->getSequence(), 0, nBufferLength); aZipEntry.closeEntry(); + uno::Sequence< sal_Int8 > aCompressedData = aZipEntry.getData(); + aZipOut.rawWrite(aCompressedData, 0, aCompressedData.getLength()); aZipOut.rawCloseEntry(); } @@ -1079,9 +1081,11 @@ void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno: // there is no encryption in this format currently aZipOut.putNextEntry(*pEntry); - ZipOutputEntry aZipEntry(m_xContext, &aZipOut, *pEntry, NULL); + ZipOutputEntry aZipEntry(m_xContext, *pEntry, NULL); aZipEntry.write(pBuffer->getSequence(), 0, nBufferLength); aZipEntry.closeEntry(); + uno::Sequence< sal_Int8 > aCompressedData = aZipEntry.getData(); + aZipOut.rawWrite(aCompressedData, 0, aCompressedData.getLength()); aZipOut.rawCloseEntry(); } diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx index 79aa26a..ad7596d 100644 --- a/package/source/zippackage/ZipPackageStream.cxx +++ b/package/source/zippackage/ZipPackageStream.cxx @@ -748,7 +748,7 @@ bool ZipPackageStream::saveChild( } else { - ZipOutputEntry aZipEntry(m_xContext, &rZipOut, *pTempEntry, this, bToBeEncrypted); + ZipOutputEntry aZipEntry(m_xContext, *pTempEntry, this, bToBeEncrypted); do { nLength = xStream->readBytes(aSeq, n_ConstBufferSize); @@ -756,6 +756,8 @@ bool ZipPackageStream::saveChild( } while ( nLength == n_ConstBufferSize ); aZipEntry.closeEntry(); + uno::Sequence< sal_Int8 > aCompressedData = aZipEntry.getData(); + rZipOut.rawWrite(aCompressedData, 0, aCompressedData.getLength()); } rZipOut.rawCloseEntry(); } commit 74ded0584bcf6be7b21d3c1e563434034d68ffa8 Author: Matúš Kukan <[email protected]> Date: Mon Oct 20 22:54:49 2014 +0200 ZipOutputEntry: m_pCurrentEntry is always set Change-Id: Ib6a69a83f4a378df838b2231b9eba7fba49cd9f1 diff --git a/package/source/zipapi/ZipOutputEntry.cxx b/package/source/zipapi/ZipOutputEntry.cxx index b73f0a2..ca08abb 100644 --- a/package/source/zipapi/ZipOutputEntry.cxx +++ b/package/source/zipapi/ZipOutputEntry.cxx @@ -64,62 +64,55 @@ ZipOutputEntry::~ZipOutputEntry( void ) { } -void SAL_CALL ZipOutputEntry::closeEntry( ) +void SAL_CALL ZipOutputEntry::closeEntry() throw(IOException, RuntimeException) { - ZipEntry *pEntry = m_pCurrentEntry; - if (pEntry) + m_aDeflater.finish(); + while (!m_aDeflater.finished()) + doDeflate(); + + if ((m_pCurrentEntry->nFlag & 8) == 0) { - m_aDeflater.finish(); - while (!m_aDeflater.finished()) - doDeflate(); - if ((pEntry->nFlag & 8) == 0) + if (m_pCurrentEntry->nSize != m_aDeflater.getTotalIn()) { - if (pEntry->nSize != m_aDeflater.getTotalIn()) - { - OSL_FAIL("Invalid entry size"); - } - if (pEntry->nCompressedSize != m_aDeflater.getTotalOut()) - { - // Different compression strategies make the merit of this - // test somewhat dubious - pEntry->nCompressedSize = m_aDeflater.getTotalOut(); - } - if (pEntry->nCrc != m_aCRC.getValue()) - { - OSL_FAIL("Invalid entry CRC-32"); - } + OSL_FAIL("Invalid entry size"); } - else + if (m_pCurrentEntry->nCompressedSize != m_aDeflater.getTotalOut()) { - if ( !m_bEncryptCurrentEntry ) - { - pEntry->nSize = m_aDeflater.getTotalIn(); - pEntry->nCompressedSize = m_aDeflater.getTotalOut(); - } - pEntry->nCrc = m_aCRC.getValue(); + // Different compression strategies make the merit of this + // test somewhat dubious + m_pCurrentEntry->nCompressedSize = m_aDeflater.getTotalOut(); } - m_aDeflater.reset(); - m_aCRC.reset(); - - if (m_bEncryptCurrentEntry) + if (m_pCurrentEntry->nCrc != m_aCRC.getValue()) { - m_bEncryptCurrentEntry = false; - - m_xCipherContext.clear(); + OSL_FAIL("Invalid entry CRC-32"); + } + } + else + { + if ( !m_bEncryptCurrentEntry ) + { + m_pCurrentEntry->nSize = m_aDeflater.getTotalIn(); + m_pCurrentEntry->nCompressedSize = m_aDeflater.getTotalOut(); + } + m_pCurrentEntry->nCrc = m_aCRC.getValue(); + } + m_aDeflater.reset(); + m_aCRC.reset(); - uno::Sequence< sal_Int8 > aDigestSeq; - if ( m_xDigestContext.is() ) - { - aDigestSeq = m_xDigestContext->finalizeDigestAndDispose(); - m_xDigestContext.clear(); - } + if (m_bEncryptCurrentEntry) + { + m_xCipherContext.clear(); - if ( m_pCurrentStream ) - m_pCurrentStream->setDigest( aDigestSeq ); + uno::Sequence< sal_Int8 > aDigestSeq; + if ( m_xDigestContext.is() ) + { + aDigestSeq = m_xDigestContext->finalizeDigestAndDispose(); + m_xDigestContext.clear(); } - m_pCurrentEntry = NULL; - m_pCurrentStream = NULL; + + if ( m_pCurrentStream ) + m_pCurrentStream->setDigest( aDigestSeq ); } } commit 57f9e0bb6c4d640ee62205703b1c7ec4f12fdbc3 Author: Matúš Kukan <[email protected]> Date: Mon Oct 20 22:02:48 2014 +0200 package: Zipping STORED entry is the same as rawWrite and we don't encrypt it Change-Id: Ie3f8ac261a70c9a2b5182fc7d36938d0a46ec045 diff --git a/package/source/zipapi/ZipOutputEntry.cxx b/package/source/zipapi/ZipOutputEntry.cxx index 4e2f6d4..b73f0a2 100644 --- a/package/source/zipapi/ZipOutputEntry.cxx +++ b/package/source/zipapi/ZipOutputEntry.cxx @@ -51,6 +51,7 @@ ZipOutputEntry::ZipOutputEntry( const uno::Reference< uno::XComponentContext >& , m_bEncryptCurrentEntry(bEncrypt) , m_pCurrentStream(NULL) { + assert(m_pCurrentEntry->nMethod == DEFLATED && "Use ZipPackageStream::rawWrite() for STORED entries"); if (m_bEncryptCurrentEntry) { m_xCipherContext = ZipFile::StaticGetCipher( rxContext, pStream->GetEncryptionData(), true ); @@ -69,49 +70,37 @@ void SAL_CALL ZipOutputEntry::closeEntry( ) ZipEntry *pEntry = m_pCurrentEntry; if (pEntry) { - switch (pEntry->nMethod) + m_aDeflater.finish(); + while (!m_aDeflater.finished()) + doDeflate(); + if ((pEntry->nFlag & 8) == 0) { - case DEFLATED: - m_aDeflater.finish(); - while (!m_aDeflater.finished()) - doDeflate(); - if ((pEntry->nFlag & 8) == 0) - { - if (pEntry->nSize != m_aDeflater.getTotalIn()) - { - OSL_FAIL("Invalid entry size"); - } - if (pEntry->nCompressedSize != m_aDeflater.getTotalOut()) - { - // Different compression strategies make the merit of this - // test somewhat dubious - pEntry->nCompressedSize = m_aDeflater.getTotalOut(); - } - if (pEntry->nCrc != m_aCRC.getValue()) - { - OSL_FAIL("Invalid entry CRC-32"); - } - } - else - { - if ( !m_bEncryptCurrentEntry ) - { - pEntry->nSize = m_aDeflater.getTotalIn(); - pEntry->nCompressedSize = m_aDeflater.getTotalOut(); - } - pEntry->nCrc = m_aCRC.getValue(); - } - m_aDeflater.reset(); - m_aCRC.reset(); - break; - case STORED: - if (!((pEntry->nFlag & 8) == 0)) - OSL_FAIL( "Serious error, one of compressed size, size or CRC was -1 in a STORED stream"); - break; - default: - OSL_FAIL("Invalid compression method"); - break; + if (pEntry->nSize != m_aDeflater.getTotalIn()) + { + OSL_FAIL("Invalid entry size"); + } + if (pEntry->nCompressedSize != m_aDeflater.getTotalOut()) + { + // Different compression strategies make the merit of this + // test somewhat dubious + pEntry->nCompressedSize = m_aDeflater.getTotalOut(); + } + if (pEntry->nCrc != m_aCRC.getValue()) + { + OSL_FAIL("Invalid entry CRC-32"); + } } + else + { + if ( !m_bEncryptCurrentEntry ) + { + pEntry->nSize = m_aDeflater.getTotalIn(); + pEntry->nCompressedSize = m_aDeflater.getTotalOut(); + } + pEntry->nCrc = m_aCRC.getValue(); + } + m_aDeflater.reset(); + m_aCRC.reset(); if (m_bEncryptCurrentEntry) { @@ -137,24 +126,13 @@ void SAL_CALL ZipOutputEntry::closeEntry( ) void SAL_CALL ZipOutputEntry::write( const Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) throw(IOException, RuntimeException) { - switch (m_pCurrentEntry->nMethod) + if (!m_aDeflater.finished()) { - case DEFLATED: - if (!m_aDeflater.finished()) - { - m_aDeflater.setInputSegment(rBuffer, nNewOffset, nNewLength); - while (!m_aDeflater.needsInput()) - doDeflate(); - if (!m_bEncryptCurrentEntry) - m_aCRC.updateSegment(rBuffer, nNewOffset, nNewLength); - } - break; - case STORED: - { - Sequence < sal_Int8 > aTmpBuffer ( rBuffer.getConstArray(), nNewLength ); - m_pZipOutputStream->getChucker().WriteBytes( aTmpBuffer ); - } - break; + m_aDeflater.setInputSegment(rBuffer, nNewOffset, nNewLength); + while (!m_aDeflater.needsInput()) + doDeflate(); + if (!m_bEncryptCurrentEntry) + m_aCRC.updateSegment(rBuffer, nNewOffset, nNewLength); } } diff --git a/package/source/zippackage/ZipPackage.cxx b/package/source/zippackage/ZipPackage.cxx index 5c12cf0..d202fb0 100644 --- a/package/source/zippackage/ZipPackage.cxx +++ b/package/source/zippackage/ZipPackage.cxx @@ -985,9 +985,7 @@ void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut ) try { aZipOut.putNextEntry(*pEntry); - ZipOutputEntry aZipEntry(m_xContext, &aZipOut, *pEntry, NULL); - aZipEntry.write(aType, 0, nBufferLength); - aZipEntry.closeEntry(); + aZipOut.rawWrite(aType, 0, nBufferLength); aZipOut.rawCloseEntry(); } catch ( const ::com::sun::star::io::IOException & r ) diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx index 8d433ad..79aa26a 100644 --- a/package/source/zippackage/ZipPackageStream.cxx +++ b/package/source/zippackage/ZipPackageStream.cxx @@ -485,8 +485,8 @@ bool ZipPackageStream::saveChild( pTempEntry->sPath = rPath; pTempEntry->nPathLen = (sal_Int16)( OUStringToOString( pTempEntry->sPath, RTL_TEXTENCODING_UTF8 ).getLength() ); - bool bToBeEncrypted = m_bToBeEncrypted && (rEncryptionKey.getLength() || m_bHaveOwnKey); - bool bToBeCompressed = bToBeEncrypted ? sal_True : m_bToBeCompressed; + const bool bToBeEncrypted = m_bToBeEncrypted && (rEncryptionKey.getLength() || m_bHaveOwnKey); + const bool bToBeCompressed = bToBeEncrypted ? sal_True : m_bToBeCompressed; aPropSet[PKG_MNFST_MEDIATYPE].Name = sMediaTypeProperty; aPropSet[PKG_MNFST_MEDIATYPE].Value <<= GetMediaType( ); @@ -732,20 +732,31 @@ bool ZipPackageStream::saveChild( try { rZipOut.putNextEntry(*pTempEntry, bToBeEncrypted); - ZipOutputEntry aZipEntry(m_xContext, &rZipOut, *pTempEntry, this, bToBeEncrypted); // the entry is provided to the ZipOutputStream that will delete it pAutoTempEntry.release(); - sal_Int32 nLength; uno::Sequence < sal_Int8 > aSeq (n_ConstBufferSize); - do + + if (pTempEntry->nMethod == STORED) { - nLength = xStream->readBytes(aSeq, n_ConstBufferSize); - aZipEntry.write(aSeq, 0, nLength); + do + { + nLength = xStream->readBytes(aSeq, n_ConstBufferSize); + rZipOut.rawWrite(aSeq, 0, nLength); + } + while ( nLength == n_ConstBufferSize ); + } + else + { + ZipOutputEntry aZipEntry(m_xContext, &rZipOut, *pTempEntry, this, bToBeEncrypted); + do + { + nLength = xStream->readBytes(aSeq, n_ConstBufferSize); + aZipEntry.write(aSeq, 0, nLength); + } + while ( nLength == n_ConstBufferSize ); + aZipEntry.closeEntry(); } - while ( nLength == n_ConstBufferSize ); - - aZipEntry.closeEntry(); rZipOut.rawCloseEntry(); } catch ( ZipException& ) commit 906e76b09ebfe98161a74e398b42c655c8971cab Author: Matúš Kukan <[email protected]> Date: Mon Oct 20 21:13:50 2014 +0200 package: Move most ZipOutputEntry's methods back to ZipOutputStream We want to use ZipOutputEntry only for deflating (and maybe rename it). ca13a9377e4a36436e4c82bb33648d0f3b6db6f5 was not a good idea because the data still needs to be written sequentially anyway. Otherwise it's hard to get offset positions of individual entries right. Since this commit rawCloseEntry needs to be called always; also when we use write&closeEntry because we don't call writeEXT in closeEntry anymore. Need to rename and add comments later. Change-Id: I03bd48ca6e108e6253a77a137746165909ca3c3d diff --git a/package/inc/ZipOutputEntry.hxx b/package/inc/ZipOutputEntry.hxx index a1d03d3..73bd8a4 100644 --- a/package/inc/ZipOutputEntry.hxx +++ b/package/inc/ZipOutputEntry.hxx @@ -19,16 +19,17 @@ #ifndef INCLUDED_PACKAGE_INC_ZIPOUTPUTENTRY_HXX #define INCLUDED_PACKAGE_INC_ZIPOUTPUTENTRY_HXX +#include <com/sun/star/io/IOException.hpp> #include <com/sun/star/uno/Reference.hxx> #include <com/sun/star/uno/XComponentContext.hpp> #include <com/sun/star/xml/crypto/XCipherContext.hpp> #include <com/sun/star/xml/crypto/XDigestContext.hpp> #include <package/Deflater.hxx> -#include <ByteChucker.hxx> #include <CRC32.hxx> struct ZipEntry; +class ZipOutputStream; class ZipPackageStream; class ZipOutputEntry @@ -40,7 +41,7 @@ class ZipOutputEntry ::com::sun::star::uno::Reference< ::com::sun::star::xml::crypto::XDigestContext > m_xDigestContext; CRC32 m_aCRC; - ByteChucker &m_rChucker; + ZipOutputStream* m_pZipOutputStream; ZipEntry *m_pCurrentEntry; sal_Int16 m_nDigested; bool m_bEncryptCurrentEntry; @@ -49,29 +50,18 @@ class ZipOutputEntry public: ZipOutputEntry( const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XComponentContext >& rxContext, - ByteChucker& rChucker, ZipEntry& rEntry, ZipPackageStream* pStream, bool bEncrypt = false); + ZipOutputStream *pZipOutputStream, ZipEntry& rEntry, ZipPackageStream* pStream, bool bEncrypt = false); ~ZipOutputEntry(); - // rawWrite to support a direct write to the output stream - void SAL_CALL rawWrite( ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) - throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); - void SAL_CALL rawCloseEntry( ) - throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); - // XZipOutputEntry interfaces void SAL_CALL closeEntry( ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); void SAL_CALL write( const ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); - static sal_uInt32 getCurrentDosTime ( ); private: void doDeflate(); - sal_Int32 writeLOC( const ZipEntry &rEntry ) - throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); - void writeEXT( const ZipEntry &rEntry ) - throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); }; #endif diff --git a/package/inc/ZipOutputStream.hxx b/package/inc/ZipOutputStream.hxx index 95c27f3..6775bd0 100644 --- a/package/inc/ZipOutputStream.hxx +++ b/package/inc/ZipOutputStream.hxx @@ -27,6 +27,7 @@ #include <vector> struct ZipEntry; +class ZipPackageStream; class ZipOutputStream { @@ -35,22 +36,36 @@ class ZipOutputStream ByteChucker m_aChucker; bool m_bFinished; + ZipEntry *m_pCurrentEntry; public: ZipOutputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > &xOStream ); ~ZipOutputStream(); - void addEntry( ZipEntry *pZipEntry ); + // rawWrite to support a direct write to the output stream + void rawWrite( ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + void rawCloseEntry() + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + + void putNextEntry( ZipEntry& rEntry, bool bEncrypt = false ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); void finish() throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); ByteChucker& getChucker(); + static sal_uInt32 getCurrentDosTime(); + private: void writeEND(sal_uInt32 nOffset, sal_uInt32 nLength) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); void writeCEN( const ZipEntry &rEntry ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + sal_Int32 writeLOC( const ZipEntry &rEntry ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); + void writeEXT( const ZipEntry &rEntry ) + throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); }; #endif diff --git a/package/source/zipapi/ZipOutputEntry.cxx b/package/source/zipapi/ZipOutputEntry.cxx index a3e3cc8..4e2f6d4 100644 --- a/package/source/zipapi/ZipOutputEntry.cxx +++ b/package/source/zipapi/ZipOutputEntry.cxx @@ -24,9 +24,11 @@ #include <osl/time.h> +#include <ByteChucker.hxx> #include <PackageConstants.hxx> #include <ZipEntry.hxx> #include <ZipFile.hxx> +#include <ZipOutputStream.hxx> #include <ZipPackageStream.hxx> using namespace com::sun::star; @@ -37,43 +39,24 @@ using namespace com::sun::star::packages::zip::ZipConstants; /** This class is used to deflate Zip entries */ ZipOutputEntry::ZipOutputEntry( const uno::Reference< uno::XComponentContext >& rxContext, - ByteChucker& rChucker, + ZipOutputStream* pOutputStream, ZipEntry& rEntry, ZipPackageStream* pStream, bool bEncrypt) : m_aDeflateBuffer(n_ConstBufferSize) , m_aDeflater(DEFAULT_COMPRESSION, true) -, m_rChucker(rChucker) +, m_pZipOutputStream(pOutputStream) , m_pCurrentEntry(&rEntry) , m_nDigested(0) -, m_bEncryptCurrentEntry(false) +, m_bEncryptCurrentEntry(bEncrypt) , m_pCurrentStream(NULL) { - if (rEntry.nTime == -1) - rEntry.nTime = getCurrentDosTime(); - if (rEntry.nMethod == -1) - rEntry.nMethod = DEFLATED; - rEntry.nVersion = 20; - rEntry.nFlag = 1 << 11; - if (rEntry.nSize == -1 || rEntry.nCompressedSize == -1 || - rEntry.nCrc == -1) + if (m_bEncryptCurrentEntry) { - rEntry.nSize = rEntry.nCompressedSize = 0; - rEntry.nFlag |= 8; - } - - if (bEncrypt) - { - m_bEncryptCurrentEntry = true; - m_xCipherContext = ZipFile::StaticGetCipher( rxContext, pStream->GetEncryptionData(), true ); m_xDigestContext = ZipFile::StaticGetDigestContextForChecksum( rxContext, pStream->GetEncryptionData() ); - m_nDigested = 0; - rEntry.nFlag |= 1 << 4; m_pCurrentStream = pStream; } - sal_Int32 nLOCLength = writeLOC(rEntry); - rEntry.nOffset = m_rChucker.GetPosition() - nLOCLength; } ZipOutputEntry::~ZipOutputEntry( void ) @@ -117,7 +100,6 @@ void SAL_CALL ZipOutputEntry::closeEntry( ) pEntry->nCompressedSize = m_aDeflater.getTotalOut(); } pEntry->nCrc = m_aCRC.getValue(); - writeEXT(*pEntry); } m_aDeflater.reset(); m_aCRC.reset(); @@ -170,27 +152,12 @@ void SAL_CALL ZipOutputEntry::write( const Sequence< sal_Int8 >& rBuffer, sal_In case STORED: { Sequence < sal_Int8 > aTmpBuffer ( rBuffer.getConstArray(), nNewLength ); - m_rChucker.WriteBytes( aTmpBuffer ); + m_pZipOutputStream->getChucker().WriteBytes( aTmpBuffer ); } break; } } -void SAL_CALL ZipOutputEntry::rawWrite( Sequence< sal_Int8 >& rBuffer, sal_Int32 /*nNewOffset*/, sal_Int32 nNewLength ) - throw(IOException, RuntimeException) -{ - Sequence < sal_Int8 > aTmpBuffer ( rBuffer.getConstArray(), nNewLength ); - m_rChucker.WriteBytes( aTmpBuffer ); -} - -void SAL_CALL ZipOutputEntry::rawCloseEntry( ) - throw(IOException, RuntimeException) -{ - if ( m_pCurrentEntry->nMethod == DEFLATED && ( m_pCurrentEntry->nFlag & 8 ) ) - writeEXT(*m_pCurrentEntry); - m_pCurrentEntry = NULL; -} - void ZipOutputEntry::doDeflate() { sal_Int32 nLength = m_aDeflater.doDeflateSegment(m_aDeflateBuffer, 0, m_aDeflateBuffer.getLength()); @@ -213,7 +180,7 @@ void ZipOutputEntry::doDeflate() // FIXME64: uno::Sequence not 64bit safe. uno::Sequence< sal_Int8 > aEncryptionBuffer = m_xCipherContext->convertWithCipherContext( aTmpBuffer ); - m_rChucker.WriteBytes( aEncryptionBuffer ); + m_pZipOutputStream->getChucker().WriteBytes( aEncryptionBuffer ); // the sizes as well as checksum for encrypted streams is calculated here m_pCurrentEntry->nCompressedSize += aEncryptionBuffer.getLength(); @@ -222,7 +189,7 @@ void ZipOutputEntry::doDeflate() } else { - m_rChucker.WriteBytes ( aTmpBuffer ); + m_pZipOutputStream->getChucker().WriteBytes ( aTmpBuffer ); } } @@ -232,7 +199,7 @@ void ZipOutputEntry::doDeflate() uno::Sequence< sal_Int8 > aEncryptionBuffer = m_xCipherContext->finalizeCipherContextAndDispose(); if ( aEncryptionBuffer.getLength() ) { - m_rChucker.WriteBytes( aEncryptionBuffer ); + m_pZipOutputStream->getChucker().WriteBytes( aEncryptionBuffer ); // the sizes as well as checksum for encrypted streams is calculated hier m_pCurrentEntry->nCompressedSize += aEncryptionBuffer.getLength(); @@ -242,126 +209,4 @@ void ZipOutputEntry::doDeflate() } } -static sal_uInt32 getTruncated( sal_Int64 nNum, bool *pIsTruncated ) -{ - if( nNum >= 0xffffffff ) - { - *pIsTruncated = true; - return 0xffffffff; - } - else - return static_cast< sal_uInt32 >( nNum ); -} - -void ZipOutputEntry::writeEXT( const ZipEntry &rEntry ) - throw(IOException, RuntimeException) -{ - bool bWrite64Header = false; - - m_rChucker << EXTSIG; - m_rChucker << static_cast < sal_uInt32> ( rEntry.nCrc ); - m_rChucker << getTruncated( rEntry.nCompressedSize, &bWrite64Header ); - m_rChucker << getTruncated( rEntry.nSize, &bWrite64Header ); - - if( bWrite64Header ) - { - // FIXME64: need to append a ZIP64 header instead of throwing - // We're about to silently lose people's data - which they are - // unlikely to appreciate so fail instead: - throw IOException( "File contains streams that are too large." ); - } -} - -sal_Int32 ZipOutputEntry::writeLOC( const ZipEntry &rEntry ) - throw(IOException, RuntimeException) -{ - if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( rEntry.sPath, true ) ) - throw IOException("Unexpected character is used in file name." ); - - OString sUTF8Name = OUStringToOString( rEntry.sPath, RTL_TEXTENCODING_UTF8 ); - sal_Int16 nNameLength = static_cast < sal_Int16 > ( sUTF8Name.getLength() ); - - m_rChucker << LOCSIG; - m_rChucker << rEntry.nVersion; - - if (rEntry.nFlag & (1 << 4) ) - { - // If it's an encrypted entry, we pretend its stored plain text - sal_Int16 nTmpFlag = rEntry.nFlag; - nTmpFlag &= ~(1 <<4 ); - m_rChucker << nTmpFlag; - m_rChucker << static_cast < sal_Int16 > ( STORED ); - } - else - { - m_rChucker << rEntry.nFlag; - m_rChucker << rEntry.nMethod; - } - - bool bWrite64Header = false; - - m_rChucker << static_cast < sal_uInt32 > (rEntry.nTime); - if ((rEntry.nFlag & 8) == 8 ) - { - m_rChucker << static_cast < sal_Int32 > (0); - m_rChucker << static_cast < sal_Int32 > (0); - m_rChucker << static_cast < sal_Int32 > (0); - } - else - { - m_rChucker << static_cast < sal_uInt32 > (rEntry.nCrc); - m_rChucker << getTruncated( rEntry.nCompressedSize, &bWrite64Header ); - m_rChucker << getTruncated( rEntry.nSize, &bWrite64Header ); - } - m_rChucker << nNameLength; - m_rChucker << static_cast < sal_Int16 > (0); - - if( bWrite64Header ) - { - // FIXME64: need to append a ZIP64 header instead of throwing - // We're about to silently lose people's data - which they are - // unlikely to appreciate so fail instead: - throw IOException( "File contains streams that are too large." ); - } - - Sequence < sal_Int8 > aSequence( (sal_Int8*)sUTF8Name.getStr(), sUTF8Name.getLength() ); - m_rChucker.WriteBytes( aSequence ); - - return LOCHDR + nNameLength; -} -sal_uInt32 ZipOutputEntry::getCurrentDosTime( ) -{ - oslDateTime aDateTime; - TimeValue aTimeValue; - osl_getSystemTime ( &aTimeValue ); - osl_getDateTimeFromTimeValue( &aTimeValue, &aDateTime); - - // at year 2108, there is an overflow - // -> some decision needs to be made - // how to handle the ZIP file format (just overflow?) - - // if the current system time is before 1980, - // then the time traveller will have to make a decision - // how to handle the ZIP file format before it is invented - // (just underflow?) - - assert(aDateTime.Year > 1980 && aDateTime.Year < 2108); - - sal_uInt32 nYear = static_cast <sal_uInt32> (aDateTime.Year); - - if (nYear>=1980) - nYear-=1980; - else if (nYear>=80) - { - nYear-=80; - } - sal_uInt32 nResult = static_cast < sal_uInt32>( ( ( ( aDateTime.Day) + - ( 32 * (aDateTime.Month)) + - ( 512 * nYear ) ) << 16) | - ( ( aDateTime.Seconds/2) + - ( 32 * aDateTime.Minutes) + - ( 2048 * static_cast <sal_uInt32 > (aDateTime.Hours) ) ) ); - return nResult; -} - /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/package/source/zipapi/ZipOutputStream.cxx b/package/source/zipapi/ZipOutputStream.cxx index 7cd5acd..29c19c4 100644 --- a/package/source/zipapi/ZipOutputStream.cxx +++ b/package/source/zipapi/ZipOutputStream.cxx @@ -23,8 +23,11 @@ #include <com/sun/star/io/XOutputStream.hpp> #include <comphelper/storagehelper.hxx> +#include <osl/time.h> + #include <PackageConstants.hxx> #include <ZipEntry.hxx> +#include <ZipPackageStream.hxx> using namespace com::sun::star; using namespace com::sun::star::io; @@ -37,6 +40,7 @@ ZipOutputStream::ZipOutputStream( const uno::Reference < io::XOutputStream > &xO : m_xStream(xOStream) , m_aChucker(xOStream) , m_bFinished(false) +, m_pCurrentEntry(NULL) { } @@ -46,9 +50,45 @@ ZipOutputStream::~ZipOutputStream( void ) delete m_aZipList[i]; } -void ZipOutputStream::addEntry( ZipEntry *pZipEntry ) +void ZipOutputStream::putNextEntry( ZipEntry& rEntry, bool bEncrypt ) + throw(IOException, RuntimeException) +{ + assert(!m_pCurrentEntry && "Forgot to close an entry before putNextEntry()?"); + if (rEntry.nTime == -1) + rEntry.nTime = getCurrentDosTime(); + if (rEntry.nMethod == -1) + rEntry.nMethod = DEFLATED; + rEntry.nVersion = 20; + rEntry.nFlag = 1 << 11; + if (rEntry.nSize == -1 || rEntry.nCompressedSize == -1 || + rEntry.nCrc == -1) + { + rEntry.nSize = rEntry.nCompressedSize = 0; + rEntry.nFlag |= 8; + } + if (bEncrypt) + { + rEntry.nFlag |= 1 << 4; + } + + sal_Int32 nLOCLength = writeLOC(rEntry); + rEntry.nOffset = m_aChucker.GetPosition() - nLOCLength; + m_aZipList.push_back( &rEntry ); + m_pCurrentEntry = &rEntry; +} + +void ZipOutputStream::rawWrite( Sequence< sal_Int8 >& rBuffer, sal_Int32 /*nNewOffset*/, sal_Int32 nNewLength ) + throw(IOException, RuntimeException) +{ + m_aChucker.WriteBytes( Sequence< sal_Int8 >(rBuffer.getConstArray(), nNewLength) ); +} + +void ZipOutputStream::rawCloseEntry() + throw(IOException, RuntimeException) { - m_aZipList.push_back( pZipEntry ); + if ( m_pCurrentEntry->nMethod == DEFLATED && ( m_pCurrentEntry->nFlag & 8 ) ) + writeEXT(*m_pCurrentEntry); + m_pCurrentEntry = NULL; } void ZipOutputStream::finish( ) @@ -148,4 +188,116 @@ void ZipOutputStream::writeCEN( const ZipEntry &rEntry ) m_aChucker.WriteBytes( aSequence ); } +void ZipOutputStream::writeEXT( const ZipEntry &rEntry ) + throw(IOException, RuntimeException) +{ + bool bWrite64Header = false; + + m_aChucker << EXTSIG; + m_aChucker << static_cast < sal_uInt32> ( rEntry.nCrc ); + m_aChucker << getTruncated( rEntry.nCompressedSize, &bWrite64Header ); + m_aChucker << getTruncated( rEntry.nSize, &bWrite64Header ); + + if( bWrite64Header ) + { + // FIXME64: need to append a ZIP64 header instead of throwing + // We're about to silently lose people's data - which they are + // unlikely to appreciate so fail instead: + throw IOException( "File contains streams that are too large." ); + } +} + +sal_Int32 ZipOutputStream::writeLOC( const ZipEntry &rEntry ) + throw(IOException, RuntimeException) +{ + if ( !::comphelper::OStorageHelper::IsValidZipEntryFileName( rEntry.sPath, true ) ) + throw IOException("Unexpected character is used in file name." ); + + OString sUTF8Name = OUStringToOString( rEntry.sPath, RTL_TEXTENCODING_UTF8 ); + sal_Int16 nNameLength = static_cast < sal_Int16 > ( sUTF8Name.getLength() ); + + m_aChucker << LOCSIG; + m_aChucker << rEntry.nVersion; + + if (rEntry.nFlag & (1 << 4) ) + { + // If it's an encrypted entry, we pretend its stored plain text + sal_Int16 nTmpFlag = rEntry.nFlag; + nTmpFlag &= ~(1 <<4 ); + m_aChucker << nTmpFlag; + m_aChucker << static_cast < sal_Int16 > ( STORED ); + } + else + { + m_aChucker << rEntry.nFlag; + m_aChucker << rEntry.nMethod; + } + + bool bWrite64Header = false; + + m_aChucker << static_cast < sal_uInt32 > (rEntry.nTime); + if ((rEntry.nFlag & 8) == 8 ) + { + m_aChucker << static_cast < sal_Int32 > (0); + m_aChucker << static_cast < sal_Int32 > (0); + m_aChucker << static_cast < sal_Int32 > (0); + } + else + { + m_aChucker << static_cast < sal_uInt32 > (rEntry.nCrc); + m_aChucker << getTruncated( rEntry.nCompressedSize, &bWrite64Header ); + m_aChucker << getTruncated( rEntry.nSize, &bWrite64Header ); + } + m_aChucker << nNameLength; + m_aChucker << static_cast < sal_Int16 > (0); + + if( bWrite64Header ) + { + // FIXME64: need to append a ZIP64 header instead of throwing + // We're about to silently lose people's data - which they are + // unlikely to appreciate so fail instead: + throw IOException( "File contains streams that are too large." ); + } + + Sequence < sal_Int8 > aSequence( (sal_Int8*)sUTF8Name.getStr(), sUTF8Name.getLength() ); + m_aChucker.WriteBytes( aSequence ); + + return LOCHDR + nNameLength; +} + +sal_uInt32 ZipOutputStream::getCurrentDosTime() +{ + oslDateTime aDateTime; + TimeValue aTimeValue; + osl_getSystemTime ( &aTimeValue ); + osl_getDateTimeFromTimeValue( &aTimeValue, &aDateTime); + + // at year 2108, there is an overflow + // -> some decision needs to be made + // how to handle the ZIP file format (just overflow?) + + // if the current system time is before 1980, + // then the time traveller will have to make a decision + // how to handle the ZIP file format before it is invented + // (just underflow?) + + assert(aDateTime.Year > 1980 && aDateTime.Year < 2108); + + sal_uInt32 nYear = static_cast <sal_uInt32> (aDateTime.Year); + + if (nYear>=1980) + nYear-=1980; + else if (nYear>=80) + { + nYear-=80; + } + sal_uInt32 nResult = static_cast < sal_uInt32>( ( ( ( aDateTime.Day) + + ( 32 * (aDateTime.Month)) + + ( 512 * nYear ) ) << 16) | + ( ( aDateTime.Seconds/2) + + ( 32 * aDateTime.Minutes) + + ( 2048 * static_cast <sal_uInt32 > (aDateTime.Hours) ) ) ); + return nResult; +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/package/source/zippackage/ZipPackage.cxx b/package/source/zippackage/ZipPackage.cxx index 63fee5d..5c12cf0 100644 --- a/package/source/zippackage/ZipPackage.cxx +++ b/package/source/zippackage/ZipPackage.cxx @@ -976,7 +976,7 @@ void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut ) pEntry->sPath = sMime; pEntry->nMethod = STORED; pEntry->nSize = pEntry->nCompressedSize = nBufferLength; - pEntry->nTime = ZipOutputEntry::getCurrentDosTime(); + pEntry->nTime = ZipOutputStream::getCurrentDosTime(); CRC32 aCRC32; aCRC32.update( aType ); @@ -984,10 +984,11 @@ void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut ) try { - ZipOutputEntry aZipEntry(m_xContext, aZipOut.getChucker(), *pEntry, NULL); + aZipOut.putNextEntry(*pEntry); + ZipOutputEntry aZipEntry(m_xContext, &aZipOut, *pEntry, NULL); aZipEntry.write(aType, 0, nBufferLength); aZipEntry.closeEntry(); - aZipOut.addEntry(pEntry); + aZipOut.rawCloseEntry(); } catch ( const ::com::sun::star::io::IOException & r ) { @@ -1010,7 +1011,7 @@ void ZipPackage::WriteManifest( ZipOutputStream& aZipOut, const vector< uno::Seq pEntry->nMethod = DEFLATED; pEntry->nCrc = -1; pEntry->nSize = pEntry->nCompressedSize = -1; - pEntry->nTime = ZipOutputEntry::getCurrentDosTime(); + pEntry->nTime = ZipOutputStream::getCurrentDosTime(); // Convert vector into a uno::Sequence uno::Sequence < uno::Sequence < PropertyValue > > aManifestSequence ( aManList.size() ); @@ -1027,10 +1028,11 @@ void ZipPackage::WriteManifest( ZipOutputStream& aZipOut, const vector< uno::Seq pBuffer->realloc( nBufferLength ); // the manifest.xml is never encrypted - so pass an empty reference - ZipOutputEntry aZipEntry(m_xContext, aZipOut.getChucker(), *pEntry, NULL); + aZipOut.putNextEntry(*pEntry); + ZipOutputEntry aZipEntry(m_xContext, &aZipOut, *pEntry, NULL); aZipEntry.write(pBuffer->getSequence(), 0, nBufferLength); aZipEntry.closeEntry(); - aZipOut.addEntry(pEntry); + aZipOut.rawCloseEntry(); } void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno::Sequence < PropertyValue > >& aManList ) @@ -1043,7 +1045,7 @@ void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno: pEntry->nMethod = DEFLATED; pEntry->nCrc = -1; pEntry->nSize = pEntry->nCompressedSize = -1; - pEntry->nTime = ZipOutputEntry::getCurrentDosTime(); + pEntry->nTime = ZipOutputStream::getCurrentDosTime(); // Convert vector into a uno::Sequence // TODO/LATER: use Defaulst entries in future @@ -1078,10 +1080,11 @@ void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno: pBuffer->realloc( nBufferLength ); // there is no encryption in this format currently - ZipOutputEntry aZipEntry(m_xContext, aZipOut.getChucker(), *pEntry, NULL); + aZipOut.putNextEntry(*pEntry); + ZipOutputEntry aZipEntry(m_xContext, &aZipOut, *pEntry, NULL); aZipEntry.write(pBuffer->getSequence(), 0, nBufferLength); aZipEntry.closeEntry(); - aZipOut.addEntry(pEntry); + aZipOut.rawCloseEntry(); } void ZipPackage::ConnectTo( const uno::Reference< io::XInputStream >& xInStream ) diff --git a/package/source/zippackage/ZipPackageFolder.cxx b/package/source/zippackage/ZipPackageFolder.cxx index c2e5a4f..a6b2e5c 100644 --- a/package/source/zippackage/ZipPackageFolder.cxx +++ b/package/source/zippackage/ZipPackageFolder.cxx @@ -21,7 +21,6 @@ #include <ZipPackageFolder.hxx> #include <ZipFile.hxx> -#include <ZipOutputEntry.hxx> #include <ZipOutputStream.hxx> #include <ZipPackageStream.hxx> #include <PackageConstants.hxx> @@ -338,9 +337,8 @@ void ZipPackageFolder::saveContents( try { - ZipOutputEntry aZipEntry(m_xContext, rZipOut.getChucker(), *pTempEntry, NULL, false); - aZipEntry.rawCloseEntry(); - rZipOut.addEntry(pTempEntry); + rZipOut.putNextEntry( *pTempEntry ); + rZipOut.rawCloseEntry(); } catch ( ZipException& ) { diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx index 4ff73ce..8d433ad 100644 --- a/package/source/zippackage/ZipPackageStream.cxx +++ b/package/source/zippackage/ZipPackageStream.cxx @@ -674,7 +674,7 @@ bool ZipPackageStream::saveChild( if ( bRawStream ) xStream->skipBytes( m_nMagicalHackPos ); - ZipOutputEntry aZipEntry(m_xContext, rZipOut.getChucker(), *pTempEntry, this, false); + rZipOut.putNextEntry(*pTempEntry); // the entry is provided to the ZipOutputStream that will delete it pAutoTempEntry.release(); @@ -684,12 +684,11 @@ bool ZipPackageStream::saveChild( do { nLength = xStream->readBytes( aSeq, n_ConstBufferSize ); - aZipEntry.rawWrite(aSeq, 0, nLength); + rZipOut.rawWrite(aSeq, 0, nLength); } while ( nLength == n_ConstBufferSize ); - aZipEntry.rawCloseEntry(); - rZipOut.addEntry(pTempEntry); + rZipOut.rawCloseEntry(); } catch ( ZipException& ) { @@ -732,7 +731,8 @@ bool ZipPackageStream::saveChild( try { - ZipOutputEntry aZipEntry(m_xContext, rZipOut.getChucker(), *pTempEntry, this, bToBeEncrypted); + rZipOut.putNextEntry(*pTempEntry, bToBeEncrypted); + ZipOutputEntry aZipEntry(m_xContext, &rZipOut, *pTempEntry, this, bToBeEncrypted); // the entry is provided to the ZipOutputStream that will delete it pAutoTempEntry.release(); @@ -746,7 +746,7 @@ bool ZipPackageStream::saveChild( while ( nLength == n_ConstBufferSize ); aZipEntry.closeEntry(); - rZipOut.addEntry(pTempEntry); + rZipOut.rawCloseEntry(); } catch ( ZipException& ) { commit 902dfbd18f5fc38847390cf2faae00172c7f733c Author: Matúš Kukan <[email protected]> Date: Mon Oct 20 12:34:42 2014 +0200 ZipPackageFolder: releaseUpwardRef only calls clearParent, remove it. Since commit 0c5bb3f42d38b3c16015dc0a45defd1b1dad4f92. Change-Id: I5511f9dc829aca42790f05cb8fb3ebd83b2acad4 diff --git a/package/inc/ZipPackageFolder.hxx b/package/inc/ZipPackageFolder.hxx index 52a64e6..1f4e84db 100644 --- a/package/inc/ZipPackageFolder.hxx +++ b/package/inc/ZipPackageFolder.hxx @@ -82,7 +82,6 @@ public: const com::sun::star::uno::Sequence< sal_Int8 > &rEncryptionKey, const rtlRandomPool & rRandomPool) const throw(::com::sun::star::uno::RuntimeException); - void releaseUpwardRef(); // XNameContainer virtual void SAL_CALL insertByName( const OUString& aName, const ::com::sun::star::uno::Any& aElement ) diff --git a/package/source/zippackage/ContentInfo.hxx b/package/source/zippackage/ContentInfo.hxx index 1911999..4b66395 100644 --- a/package/source/zippackage/ContentInfo.hxx +++ b/package/source/zippackage/ContentInfo.hxx @@ -50,7 +50,7 @@ public: virtual ~ContentInfo () { if ( bFolder ) - pFolder->releaseUpwardRef(); + pFolder->clearParent(); else pStream->clearParent(); } diff --git a/package/source/zippackage/ZipPackageFolder.cxx b/package/source/zippackage/ZipPackageFolder.cxx index 4420fdc..c2e5a4f 100644 --- a/package/source/zippackage/ZipPackageFolder.cxx +++ b/package/source/zippackage/ZipPackageFolder.cxx @@ -392,35 +392,6 @@ void ZipPackageFolder::saveContents( throw uno::RuntimeException(THROW_WHERE ); } -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(); - - OSL_ENSURE ( m_refCount == 1, "Ref-count is not 1!" ); -#endif -} - sal_Int64 SAL_CALL ZipPackageFolder::getSomething( const uno::Sequence< sal_Int8 >& aIdentifier ) throw(uno::RuntimeException, std::exception) {
_______________________________________________ Libreoffice-commits mailing list [email protected] http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits
