filter/source/xsltfilter/OleHandler.cxx | 2 include/package/Deflater.hxx | 1 package/inc/CRC32.hxx | 2 package/inc/ZipOutputEntry.hxx | 29 -- package/inc/ZipOutputStream.hxx | 23 + package/inc/ZipPackageFolder.hxx | 1 package/inc/ZipPackageStream.hxx | 11 package/source/zipapi/CRC32.cxx | 7 package/source/zipapi/Deflater.cxx | 8 package/source/zipapi/ZipFile.cxx | 4 package/source/zipapi/ZipOutputEntry.cxx | 307 ++++------------------- package/source/zipapi/ZipOutputStream.cxx | 204 +++++++++++++-- package/source/zippackage/ContentInfo.hxx | 2 package/source/zippackage/ZipPackage.cxx | 34 +- package/source/zippackage/ZipPackageFolder.cxx | 36 -- package/source/zippackage/ZipPackageStream.cxx | 194 ++++++++++---- package/source/zippackage/wrapstreamforshare.cxx | 4 17 files changed, 441 insertions(+), 428 deletions(-)
New commits: commit 0843ade74e5848c0babad509b10c334b01847be2 Author: Matúš Kukan <matus.ku...@collabora.com> Date: Wed Nov 12 21:25:55 2014 +0100 package: Do not bother with deflating jpeg images It takes a lot of time and we can save ~1% of size if at all. Rather store them uncompressed in the zip file. With png, we can save a bit more, although it's still only about 4% - 8%? Change-Id: I43a3e3812882e4ce85e7af9d0aaab454d98c4860 diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx index 5eaa6e951..64b48d3 100644 --- a/package/source/zippackage/ZipPackageStream.cxx +++ b/package/source/zippackage/ZipPackageStream.cxx @@ -773,6 +773,14 @@ bool ZipPackageStream::saveChild( pTempEntry->nCompressedSize = pTempEntry->nSize = -1; } + uno::Reference< io::XSeekable > xSeek(xStream, uno::UNO_QUERY); + // It's not worth to deflate jpegs to save ~1% in a slow process + if (xSeek.is() && msMediaType.endsWith("/jpeg")) + { + ImplSetStoredData(*pTempEntry, xStream); + xSeek->seek(0); + } + try { ZipOutputStream::setEntry(pTempEntry); @@ -799,7 +807,6 @@ bool ZipPackageStream::saveChild( { bParallelDeflate = true; // Do not deflate small streams in a thread - uno::Reference< io::XSeekable > xSeek( xStream, uno::UNO_QUERY ); if (xSeek.is() && xSeek->getLength() < 100000) bParallelDeflate = false; commit d09b6209f1f374b6069089d8583c9ee373e3c1e5 Author: Matúš Kukan <matus.ku...@collabora.com> Date: Tue Nov 4 09:18:57 2014 +0100 package: Do not deflate small streams in a thread Change-Id: Iae804a34f344aa793a6d5c13315f7bc1eb64c0a2 diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx index 90f0df8..5eaa6e951 100644 --- a/package/source/zippackage/ZipPackageStream.cxx +++ b/package/source/zippackage/ZipPackageStream.cxx @@ -798,6 +798,11 @@ bool ZipPackageStream::saveChild( else { bParallelDeflate = true; + // Do not deflate small streams in a thread + uno::Reference< io::XSeekable > xSeek( xStream, uno::UNO_QUERY ); + if (xSeek.is() && xSeek->getLength() < 100000) + bParallelDeflate = false; + if (bParallelDeflate) { // Start a new thread deflating this zip entry commit 062cf187026f55001ab4661b89242d13c6ed71d7 Author: Matúš Kukan <matus.ku...@collabora.com> Date: Tue Oct 28 20:58:29 2014 +0100 ZipPackageStream::getRawData can be private Change-Id: I66cbbfb2aa6abc6c8ebe34d9ea69855436c23edd diff --git a/package/inc/ZipPackageStream.hxx b/package/inc/ZipPackageStream.hxx index ff6d3db..af2c721 100644 --- a/package/inc/ZipPackageStream.hxx +++ b/package/inc/ZipPackageStream.hxx @@ -71,7 +71,10 @@ private: bool m_bUseWinEncoding; bool m_bRawStream; + /// Check that m_xStream implements io::XSeekable and return it ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > GetOwnSeekStream(); + ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream > SAL_CALL getRawData() + throw(::com::sun::star::uno::RuntimeException); public: bool IsEncrypted () const { return m_bIsEncrypted;} @@ -135,8 +138,6 @@ public: const rtlRandomPool &rRandomPool ) SAL_OVERRIDE; 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(); commit 7088166a67d1270f93ac15bccbc89343b2271fa5 Author: Matúš Kukan <matus.ku...@collabora.com> Date: Mon Oct 27 14:26:54 2014 +0100 Simplify input parameters to just take the sequence Change-Id: Ic2538ca8b0f7261064e1dfbf3884dd452003c797 diff --git a/filter/source/xsltfilter/OleHandler.cxx b/filter/source/xsltfilter/OleHandler.cxx index edd0678..14ef6bd 100644 --- a/filter/source/xsltfilter/OleHandler.cxx +++ b/filter/source/xsltfilter/OleHandler.cxx @@ -197,7 +197,7 @@ namespace XSLT // Compress the bytes Sequence<sal_Int8> output(oledata.getLength()); boost::scoped_ptr< ::ZipUtils::Deflater> compresser(new ::ZipUtils::Deflater((sal_Int32) 3, false)); - compresser->setInputSegment(oledata, 0, oledata.getLength()); + compresser->setInputSegment(oledata); compresser->finish(); int compressedDataLength = compresser->doDeflateSegment(output, 0, oledata.getLength()); compresser.reset(); diff --git a/include/package/Deflater.hxx b/include/package/Deflater.hxx index bd6d815..d2be247 100644 --- a/include/package/Deflater.hxx +++ b/include/package/Deflater.hxx @@ -46,6 +46,7 @@ public: ~Deflater(); Deflater(sal_Int32 nSetLevel, bool bNowrap); void SAL_CALL setInputSegment( const ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ); + void SAL_CALL setInputSegment( const ::com::sun::star::uno::Sequence< sal_Int8 >& rBuffer ); bool SAL_CALL needsInput( ); void SAL_CALL finish( ); bool SAL_CALL finished( ) { return bFinished;} diff --git a/package/inc/CRC32.hxx b/package/inc/CRC32.hxx index daaf4b5..cfc66c4 100644 --- a/package/inc/CRC32.hxx +++ b/package/inc/CRC32.hxx @@ -35,7 +35,7 @@ public: sal_Int64 SAL_CALL updateStream (::com::sun::star::uno::Reference < ::com::sun::star::io::XInputStream > & xStream) throw(::com::sun::star::uno::RuntimeException); - void SAL_CALL updateSegment(const ::com::sun::star::uno::Sequence< sal_Int8 > &b, sal_Int32 off, sal_Int32 len) + void SAL_CALL updateSegment(const ::com::sun::star::uno::Sequence< sal_Int8 > &b, sal_Int32 len) throw(::com::sun::star::uno::RuntimeException); void SAL_CALL update(const ::com::sun::star::uno::Sequence< sal_Int8 > &b) throw(::com::sun::star::uno::RuntimeException); diff --git a/package/inc/ZipOutputEntry.hxx b/package/inc/ZipOutputEntry.hxx index 9e396ce..26ebb15 100644 --- a/package/inc/ZipOutputEntry.hxx +++ b/package/inc/ZipOutputEntry.hxx @@ -59,7 +59,7 @@ public: bool isEncrypt() { return m_bEncryptCurrentEntry; } void closeEntry(); - void write(const css::uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength); + void write(const css::uno::Sequence< sal_Int8 >& rBuffer); private: void doDeflate(); diff --git a/package/inc/ZipOutputStream.hxx b/package/inc/ZipOutputStream.hxx index 4e8e4ff..acf6dc4 100644 --- a/package/inc/ZipOutputStream.hxx +++ b/package/inc/ZipOutputStream.hxx @@ -50,7 +50,7 @@ public: 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 ) + void rawWrite( const css::uno::Sequence< sal_Int8 >& rBuffer ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); void rawCloseEntry( bool bEncrypt = false ) throw(::com::sun::star::io::IOException, ::com::sun::star::uno::RuntimeException); diff --git a/package/source/zipapi/CRC32.cxx b/package/source/zipapi/CRC32.cxx index 6aee4d5..39b4f4c 100644 --- a/package/source/zipapi/CRC32.cxx +++ b/package/source/zipapi/CRC32.cxx @@ -47,11 +47,10 @@ sal_Int32 SAL_CALL CRC32::getValue() } /** Update CRC32 with specified sequence of bytes */ -void SAL_CALL CRC32::updateSegment(const Sequence< sal_Int8 > &b, - sal_Int32 off, sal_Int32 len) +void SAL_CALL CRC32::updateSegment(const Sequence< sal_Int8 > &b, sal_Int32 len) throw(RuntimeException) { - nCRC = rtl_crc32(nCRC, b.getConstArray()+off, len ); + nCRC = rtl_crc32(nCRC, b.getConstArray(), len ); } /** Update CRC32 with specified sequence of bytes */ @@ -70,7 +69,7 @@ sal_Int64 SAL_CALL CRC32::updateStream( Reference < XInputStream > & xStream ) do { nLength = xStream->readBytes ( aSeq, n_ConstBufferSize ); - updateSegment ( aSeq, 0, nLength ); + updateSegment ( aSeq, nLength ); nTotal += nLength; } while ( nLength == n_ConstBufferSize ); diff --git a/package/source/zipapi/Deflater.cxx b/package/source/zipapi/Deflater.cxx index a76362f..42628d7 100644 --- a/package/source/zipapi/Deflater.cxx +++ b/package/source/zipapi/Deflater.cxx @@ -92,13 +92,11 @@ sal_Int32 Deflater::doDeflateBytes (uno::Sequence < sal_Int8 > &rBuffer, sal_Int } } -void SAL_CALL Deflater::setInputSegment( const uno::Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) +void SAL_CALL Deflater::setInputSegment( const uno::Sequence< sal_Int8 >& rBuffer ) { - OSL_ASSERT( !(nNewOffset < 0 || nNewLength < 0 || nNewOffset + nNewLength > rBuffer.getLength())); - sInBuffer = rBuffer; - nOffset = nNewOffset; - nLength = nNewLength; + nOffset = 0; + nLength = rBuffer.getLength(); } bool SAL_CALL Deflater::needsInput( ) diff --git a/package/source/zipapi/ZipFile.cxx b/package/source/zipapi/ZipFile.cxx index 839a1c4..1fd536f 100644 --- a/package/source/zipapi/ZipFile.cxx +++ b/package/source/zipapi/ZipFile.cxx @@ -1073,7 +1073,7 @@ sal_Int32 ZipFile::getCRC( sal_Int64 nOffset, sal_Int64 nSize ) ++ind) { sal_Int64 nLen = ::std::min(nBlockSize, nSize - ind * nBlockSize); - aCRC.updateSegment(aBuffer, 0, static_cast<sal_Int32>(nLen)); + aCRC.updateSegment(aBuffer, static_cast<sal_Int32>(nLen)); } return aCRC.getValue(); @@ -1102,7 +1102,7 @@ void ZipFile::getSizeAndCRC( sal_Int64 nOffset, sal_Int64 nCompressedSize, sal_I do { nLastInflated = aInflaterLocal.doInflateSegment( aData, 0, nBlockSize ); - aCRC.updateSegment( aData, 0, nLastInflated ); + aCRC.updateSegment( aData, nLastInflated ); nInBlock += nLastInflated; } while( !aInflater.finished() && nLastInflated ); diff --git a/package/source/zipapi/ZipOutputEntry.cxx b/package/source/zipapi/ZipOutputEntry.cxx index a5fbe25..54600d59 100644 --- a/package/source/zipapi/ZipOutputEntry.cxx +++ b/package/source/zipapi/ZipOutputEntry.cxx @@ -118,15 +118,15 @@ void ZipOutputEntry::closeEntry() } } -void ZipOutputEntry::write( const Sequence< sal_Int8 >& rBuffer, sal_Int32 nNewOffset, sal_Int32 nNewLength ) +void ZipOutputEntry::write( const Sequence< sal_Int8 >& rBuffer ) { if (!m_aDeflater.finished()) { - m_aDeflater.setInputSegment(rBuffer, nNewOffset, nNewLength); + m_aDeflater.setInputSegment(rBuffer); while (!m_aDeflater.needsInput()) doDeflate(); if (!m_bEncryptCurrentEntry) - m_aCRC.updateSegment(rBuffer, nNewOffset, nNewLength); + m_aCRC.updateSegment(rBuffer, rBuffer.getLength()); } } diff --git a/package/source/zipapi/ZipOutputStream.cxx b/package/source/zipapi/ZipOutputStream.cxx index fcfe35f..902816e 100644 --- a/package/source/zipapi/ZipOutputStream.cxx +++ b/package/source/zipapi/ZipOutputStream.cxx @@ -71,10 +71,10 @@ void ZipOutputStream::addDeflatingThread( ZipOutputEntry *pEntry, comphelper::Th m_aEntries.push_back(pEntry); } -void ZipOutputStream::rawWrite( Sequence< sal_Int8 >& rBuffer, sal_Int32 /*nNewOffset*/, sal_Int32 nNewLength ) +void ZipOutputStream::rawWrite( const Sequence< sal_Int8 >& rBuffer ) throw(IOException, RuntimeException) { - m_aChucker.WriteBytes( Sequence< sal_Int8 >(rBuffer.getConstArray(), nNewLength) ); + m_aChucker.WriteBytes( rBuffer ); } void ZipOutputStream::rawCloseEntry( bool bEncrypt ) @@ -100,8 +100,7 @@ void ZipOutputStream::finish() 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()); + rawWrite(m_aEntries[i]->getData()); rawCloseEntry(m_aEntries[i]->isEncrypt()); m_aEntries[i]->getZipPackageStream()->successfullyWritten(m_aEntries[i]->getZipEntry()); diff --git a/package/source/zippackage/ZipPackage.cxx b/package/source/zippackage/ZipPackage.cxx index 80d4d4f..2e64af8 100644 --- a/package/source/zippackage/ZipPackage.cxx +++ b/package/source/zippackage/ZipPackage.cxx @@ -983,7 +983,7 @@ void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut ) ZipEntry * pEntry = new ZipEntry; sal_Int32 nBufferLength = m_pRootFolder->GetMediaType().getLength(); OString sMediaType = OUStringToOString( m_pRootFolder->GetMediaType(), RTL_TEXTENCODING_ASCII_US ); - uno::Sequence< sal_Int8 > aType( ( sal_Int8* )sMediaType.getStr(), + const uno::Sequence< sal_Int8 > aType( ( sal_Int8* )sMediaType.getStr(), nBufferLength ); pEntry->sPath = sMime; @@ -999,7 +999,7 @@ void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut ) { ZipOutputStream::setEntry(pEntry); aZipOut.writeLOC(pEntry); - aZipOut.rawWrite(aType, 0, nBufferLength); + aZipOut.rawWrite(aType); aZipOut.rawCloseEntry(); } catch ( const ::com::sun::star::io::IOException & r ) @@ -1043,10 +1043,9 @@ void ZipPackage::WriteManifest( ZipOutputStream& aZipOut, const vector< uno::Seq ZipOutputStream::setEntry(pEntry); aZipOut.writeLOC(pEntry); ZipOutputEntry aZipEntry(m_xContext, *pEntry, NULL); - aZipEntry.write(pBuffer->getSequence(), 0, nBufferLength); + aZipEntry.write(pBuffer->getSequence()); aZipEntry.closeEntry(); - uno::Sequence< sal_Int8 > aCompressedData = aZipEntry.getData(); - aZipOut.rawWrite(aCompressedData, 0, aCompressedData.getLength()); + aZipOut.rawWrite(aZipEntry.getData()); aZipOut.rawCloseEntry(); } @@ -1098,10 +1097,9 @@ void ZipPackage::WriteContentTypes( ZipOutputStream& aZipOut, const vector< uno: ZipOutputStream::setEntry(pEntry); aZipOut.writeLOC(pEntry); ZipOutputEntry aZipEntry(m_xContext, *pEntry, NULL); - aZipEntry.write(pBuffer->getSequence(), 0, nBufferLength); + aZipEntry.write(pBuffer->getSequence()); aZipEntry.closeEntry(); - uno::Sequence< sal_Int8 > aCompressedData = aZipEntry.getData(); - aZipOut.rawWrite(aCompressedData, 0, aCompressedData.getLength()); + aZipOut.rawWrite(aZipEntry.getData()); aZipOut.rawCloseEntry(); } diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx index d5e0d62..90f0df8 100644 --- a/package/source/zippackage/ZipPackageStream.cxx +++ b/package/source/zippackage/ZipPackageStream.cxx @@ -447,7 +447,10 @@ static void deflateZipEntry(ZipOutputEntry *pZipEntry, do { nLength = xInStream->readBytes(aSeq, n_ConstBufferSize); - pZipEntry->write(aSeq, 0, nLength); + if (nLength != n_ConstBufferSize) + aSeq.realloc(nLength); + + pZipEntry->write(aSeq); } while (nLength == n_ConstBufferSize); pZipEntry->closeEntry(); @@ -722,7 +725,10 @@ bool ZipPackageStream::saveChild( do { nLength = xStream->readBytes( aSeq, n_ConstBufferSize ); - rZipOut.rawWrite(aSeq, 0, nLength); + if (nLength != n_ConstBufferSize) + aSeq.realloc(nLength); + + rZipOut.rawWrite(aSeq); } while ( nLength == n_ConstBufferSize ); @@ -781,7 +787,10 @@ bool ZipPackageStream::saveChild( do { nLength = xStream->readBytes(aSeq, n_ConstBufferSize); - rZipOut.rawWrite(aSeq, 0, nLength); + if (nLength != n_ConstBufferSize) + aSeq.realloc(nLength); + + rZipOut.rawWrite(aSeq); } while ( nLength == n_ConstBufferSize ); rZipOut.rawCloseEntry(bToBeEncrypted); @@ -800,8 +809,7 @@ bool ZipPackageStream::saveChild( rZipOut.writeLOC(pTempEntry, bToBeEncrypted); ZipOutputEntry aZipEntry(m_xContext, *pTempEntry, this, bToBeEncrypted); deflateZipEntry(&aZipEntry, xStream); - uno::Sequence< sal_Int8 > aCompressedData = aZipEntry.getData(); - rZipOut.rawWrite(aCompressedData, 0, aCompressedData.getLength()); + rZipOut.rawWrite(aZipEntry.getData()); rZipOut.rawCloseEntry(bToBeEncrypted); } } commit a42aa52acbbff738a00299de172ca85cb001d840 Author: Matúš Kukan <matus.ku...@collabora.com> Date: Fri Oct 24 14:43:06 2014 +0200 package: Add possibility to disable deflating in a thread Change-Id: I4d98b6f8b3315b731206700eb65f08463299dda3 diff --git a/package/source/zippackage/ZipPackageStream.cxx b/package/source/zippackage/ZipPackageStream.cxx index 9f29a68..d5e0d62 100644 --- a/package/source/zippackage/ZipPackageStream.cxx +++ b/package/source/zippackage/ZipPackageStream.cxx @@ -439,6 +439,20 @@ bool ZipPackageStream::ParsePackageRawStream() return true; } +static void deflateZipEntry(ZipOutputEntry *pZipEntry, + const uno::Reference< io::XInputStream >& xInStream) +{ + sal_Int32 nLength = 0; + uno::Sequence< sal_Int8 > aSeq(n_ConstBufferSize); + do + { + nLength = xInStream->readBytes(aSeq, n_ConstBufferSize); + pZipEntry->write(aSeq, 0, nLength); + } + while (nLength == n_ConstBufferSize); + pZipEntry->closeEntry(); +} + class DeflateThread: public comphelper::ThreadTask { ZipOutputEntry *mpEntry; @@ -454,16 +468,7 @@ public: private: virtual void doWork() 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(); - + deflateZipEntry(mpEntry, mxInStream); mxInStream.clear(); } }; @@ -784,9 +789,21 @@ bool ZipPackageStream::saveChild( else { 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) ); + if (bParallelDeflate) + { + // Start a new thread deflating this zip entry + ZipOutputEntry *pZipEntry = new ZipOutputEntry(m_xContext, *pTempEntry, this, bToBeEncrypted); + rZipOut.addDeflatingThread( pZipEntry, new DeflateThread(pZipEntry, xStream) ); + } + else + { + rZipOut.writeLOC(pTempEntry, bToBeEncrypted); + ZipOutputEntry aZipEntry(m_xContext, *pTempEntry, this, bToBeEncrypted); + deflateZipEntry(&aZipEntry, xStream); + uno::Sequence< sal_Int8 > aCompressedData = aZipEntry.getData(); + rZipOut.rawWrite(aCompressedData, 0, aCompressedData.getLength()); + rZipOut.rawCloseEntry(bToBeEncrypted); + } } } catch ( ZipException& ) commit fbf714b45625c50bb1c736ef231b5dbbab0016a1 Author: Matúš Kukan <matus.ku...@collabora.com> 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..4e8e4ff 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 <comphelper/threadpool.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; + comphelper::ThreadPool &m_rSharedThreadPool; + std::vector< ZipOutputEntry* > m_aEntries; public: ZipOutputStream( const ::com::sun::star::uno::Reference< ::com::sun::star::io::XOutputStream > &xOStream ); ~ZipOutputStream(); + void addDeflatingThread( ZipOutputEntry *pEntry, comphelper::ThreadTask *pThreadTask ); + 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 356d42b..ff6d3db 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..fcfe35f 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,13 @@ 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) +, m_rSharedThreadPool(comphelper::ThreadPool::getSharedOptimalPool()) { } 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 +65,12 @@ void ZipOutputStream::setEntry( ZipEntry *pEntry ) } } +void ZipOutputStream::addDeflatingThread( ZipOutputEntry *pEntry, comphelper::ThreadTask *pThread ) +{ + m_rSharedThreadPool.pushTask(pThread); + m_aEntries.push_back(pEntry); +} + void ZipOutputStream::rawWrite( Sequence< sal_Int8 >& rBuffer, sal_Int32 /*nNewOffset*/, sal_Int32 nNewLength ) throw(IOException, RuntimeException) { @@ -85,21 +90,33 @@ 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!"); + + // Wait for all threads to finish & write + m_rSharedThreadPool.waitUntilEmpty(); + 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()); - if (m_aZipList.size() < 1) - OSL_FAIL("Zip file must have at least one entry!\n"); + 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 ca2ad01..9f29a68 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 comphelper::ThreadTask +{ + ZipOutputEntry *mpEntry; + uno::Reference< io::XInputStream > mxInStream; + +public: + DeflateThread( ZipOutputEntry *pEntry, + const uno::Reference< io::XInputStream >& xInStream ) + : mpEntry(pEntry) + , mxInStream(xInStream) + {} + +private: + virtual void doWork() 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 db5552631b13e5a1d330929cd5093bd0f9894ec8 Author: Matúš Kukan <matus.ku...@collabora.com> 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 a802fd5..80d4d4f 100644 --- a/package/source/zippackage/ZipPackage.cxx +++ b/package/source/zippackage/ZipPackage.cxx @@ -997,7 +997,8 @@ void ZipPackage::WriteMimetypeMagicFile( ZipOutputStream& aZipOut ) try { - aZipOut.putNextEntry(*pEntry); + ZipOutputStream::setEntry(pEntry); + aZipOut.writeLOC(pEntry); aZipOut.rawWrite(aType, 0, nBufferLength); aZipOut.rawCloseEntry(); } @@ -1039,7 +1040,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(); @@ -1093,7 +1095,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 c5f8a31..ca2ad01 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 30f80f12fb1db4c9c6f19fcfda4e796891b6e03c Author: Matúš Kukan <matus.ku...@collabora.com> 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 590ff0e..c5f8a31 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 ef8e7eabe1e53a99bbfeac0297faa9592cd18175 Author: Matúš Kukan <matus.ku...@collabora.com> 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 3e3b8483d7866e96bc75ddda283416c6829714af Author: Matúš Kukan <matus.ku...@collabora.com> 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 23a737e..a802fd5 100644 --- a/package/source/zippackage/ZipPackage.cxx +++ b/package/source/zippackage/ZipPackage.cxx @@ -1040,9 +1040,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(); } @@ -1092,9 +1094,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 edc1c7aa..590ff0e 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 3e7ab1ac1dc91544bdc58949ac62853b0ee33760 Author: Matúš Kukan <matus.ku...@collabora.com> 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 4d1cb2dc5f1cae97ea44bded3b68d57076e21731 Author: Matúš Kukan <matus.ku...@collabora.com> 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 a05320a..23a737e 100644 --- a/package/source/zippackage/ZipPackage.cxx +++ b/package/source/zippackage/ZipPackage.cxx @@ -998,9 +998,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 7547e9c..edc1c7aa 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 2d92a84a6aac37e34d1699fdebe0270468b4f746 Author: Matúš Kukan <matus.ku...@collabora.com> 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 a631cab..a05320a 100644 --- a/package/source/zippackage/ZipPackage.cxx +++ b/package/source/zippackage/ZipPackage.cxx @@ -989,7 +989,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 ); @@ -997,10 +997,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 ) { @@ -1023,7 +1024,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() ); @@ -1040,10 +1041,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 ) @@ -1056,7 +1058,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 @@ -1091,10 +1093,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 a4651d7..7547e9c 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 ); ... etc. - the rest is truncated
_______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits