include/tools/zcodec.hxx       |   14 +++++++++++
 tools/source/zcodec/zcodec.cxx |   52 +++++++++++++++++++++++++++++++++++------
 2 files changed, 59 insertions(+), 7 deletions(-)

New commits:
commit 932257c50c1dc9302b14862424e24e975f88bcc2
Author:     offtkp <parisop...@gmail.com>
AuthorDate: Wed Jun 1 02:13:13 2022 +0300
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Sun Jun 12 09:29:53 2022 +0200

    Add compression support for GZ through ZCodec
    
    ZCodec uses zlib to deflate. That file has code
    to allow for compressing to GZ but it's wrapped in defines.
    
    There's places in code where there's need for zlib headers
    (ie. svx/source/gallery2/codec.cxx:71) and there will be need
    for gz header compression when EMZ/WMZ/SVGZ export support
    is added.
    
    Made compression functions care about mbGzLib bool. Also added
    a SetCompressionMetadata function to set metadata which are otherwise
    impossible to know (such as filename, which is needed in the header)
    
    Change-Id: Ic01050262b0b15e0632564b139c66656afac4611
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135213
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/include/tools/zcodec.hxx b/include/tools/zcodec.hxx
index 745d44e9199e..a86dbec70b62 100644
--- a/include/tools/zcodec.hxx
+++ b/include/tools/zcodec.hxx
@@ -23,6 +23,7 @@
 #include <tools/toolsdllapi.h>
 #include <tools/long.hxx>
 #include <memory>
+#include <rtl/string.hxx>
 
 #define ZCODEC_NO_COMPRESSION       0
 #define ZCODEC_DEFAULT_COMPRESSION  6
@@ -31,6 +32,7 @@ class SvStream;
 
 // The overall client call protocol is one of:
 // * BeginCompression, Compress, EndCompression
+// * BeginCompression, SetCompressionMetadata, Compress, EndCompression (for 
gz files)
 // * BeginCompression, Decompress, EndCompression
 // * BeginCompression, Write*, EndCompression
 // * BeginCompression, Read*, EndCompression
@@ -47,6 +49,10 @@ class SAL_WARN_UNUSED TOOLS_DLLPUBLIC ZCodec
     SvStream*       mpOStm;
     std::unique_ptr<sal_uInt8[]> mpOutBuf;
     size_t          mnOutBufSize;
+    sal_uInt32      mnUncompressedSize;
+    sal_uInt32      mnInBufCRC32;
+    sal_uInt32      mnLastModifiedTime;
+    OString         msFilename;
 
     int             mnCompressLevel;
     bool            mbGzLib;
@@ -69,6 +75,14 @@ public:
     void            BeginCompression( int nCompressLevel = 
ZCODEC_DEFAULT_COMPRESSION, bool gzLib = false );
     tools::Long            EndCompression();
 
+    /**
+     * @brief Set metadata for gzlib compression
+     *
+     * @param sFilename the uncompressed file filename
+     * @param nLastModifiedTime the files last modified time in unix format
+     */
+    void            SetCompressionMetadata( const OString& sFilename,
+                            sal_uInt32 nLastModifiedTime, sal_uInt32 
nInBufCRC32 );
     void            Compress( SvStream& rIStm, SvStream& rOStm );
     tools::Long            Decompress( SvStream& rIStm, SvStream& rOStm );
     bool            AttemptDecompression( SvStream& rIStm, SvStream& rOStm );
diff --git a/tools/source/zcodec/zcodec.cxx b/tools/source/zcodec/zcodec.cxx
index 80daa1507a19..16248939f3d6 100644
--- a/tools/source/zcodec/zcodec.cxx
+++ b/tools/source/zcodec/zcodec.cxx
@@ -29,14 +29,15 @@
 #include <tools/long.hxx>
 
 /* gzip flag byte */
-//      GZ_ASCII_FLAG   0x01 /* bit 0 set: file probably ascii text */
-#define GZ_HEAD_CRC     0x02 /* bit 1 set: header CRC present */
-#define GZ_EXTRA_FIELD  0x04 /* bit 2 set: extra field present */
-#define GZ_ORIG_NAME    0x08 /* bit 3 set: original file name present */
-#define GZ_COMMENT      0x10 /* bit 4 set: file comment present */
-#define GZ_RESERVED     0xE0 /* bits 5..7: reserved */
-
+//                   GZ_ASCII_FLAG     = 0x01;   /* bit 0 set: file probably 
ascii text */
+constexpr sal_uInt8  GZ_HEAD_CRC       = 0x02;   /* bit 1 set: header CRC 
present */
+constexpr sal_uInt8  GZ_EXTRA_FIELD    = 0x04;   /* bit 2 set: extra field 
present */
+constexpr sal_uInt8  GZ_ORIG_NAME      = 0x08;   /* bit 3 set: original file 
name present */
+constexpr sal_uInt8  GZ_COMMENT        = 0x10;   /* bit 4 set: file comment 
present */
+constexpr sal_uInt8  GZ_RESERVED       = 0xE0;   /* bits 5..7: reserved */
 constexpr sal_uInt16 GZ_MAGIC_BYTES_LE = 0x8B1F; /* gzip magic bytes, little 
endian */
+constexpr sal_uInt8  GZ_DEFLATE        = 0x08;
+constexpr sal_uInt8  GZ_FS_UNKNOWN     = 0xFF;
 
 ZCodec::ZCodec( size_t nInBufSize, size_t nOutBufSize )
     : meState(STATE_INIT)
@@ -109,6 +110,25 @@ tools::Long ZCodec::EndCompression()
 
             retvalue = pStream->total_in;
             deflateEnd( pStream );
+            if ( mbGzLib )
+            {
+                // metadata must be set to compress as gz format
+                assert(!msFilename.isEmpty());
+                // overwrite zlib checksum
+                mpOStm->Seek(STREAM_SEEK_TO_END);
+                mpOStm->SeekRel(-4);
+                mpOStm->WriteUInt32( mnInBufCRC32 );       // Uncompressed 
buffer CRC32
+                mpOStm->WriteUInt32( mnUncompressedSize ); // Uncompressed 
size mod 2^32
+                mpOStm->Seek( 0 );
+                mpOStm->WriteUInt16( GZ_MAGIC_BYTES_LE )   // Magic bytes
+                        .WriteUInt8( GZ_DEFLATE )          // Compression 
algorithm
+                        .WriteUInt8( GZ_ORIG_NAME )        // Filename
+                        .WriteUInt32( mnLastModifiedTime ) // Modification time
+                        .WriteUInt8( 0 )                   // Extra flags
+                        .WriteUInt8( GZ_FS_UNKNOWN )       // Operating system
+                        .WriteBytes( msFilename.pData->buffer, 
msFilename.pData->length );
+                mpOStm->WriteUInt8( 0 ); // null terminate the filename string
+            }
         }
         else
         {
@@ -122,10 +142,20 @@ tools::Long ZCodec::EndCompression()
     return mbStatus ? retvalue : -1;
 }
 
+void ZCodec::SetCompressionMetadata( const OString& sFilename, sal_uInt32 
nLastModifiedTime, sal_uInt32 nInBufCRC32 )
+{
+    assert( mbGzLib );
+    msFilename = sFilename;
+    mnLastModifiedTime = nLastModifiedTime;
+    mnInBufCRC32 = nInBufCRC32;
+}
+
 void ZCodec::Compress( SvStream& rIStm, SvStream& rOStm )
 {
     assert(meState == STATE_INIT);
     mpOStm = &rOStm;
+    rIStm.Seek(0);
+    mnUncompressedSize = rIStm.TellEnd();
     InitCompress();
     mpInBuf.reset(new sal_uInt8[ mnInBufSize ]);
     auto pStream = static_cast<z_stream*>(mpsC_Stream);
@@ -265,6 +295,14 @@ void ZCodec::ImplWriteBack()
 void ZCodec::InitCompress()
 {
     assert(meState == STATE_INIT);
+    if (mbGzLib)
+    {
+        // Seek just enough so that the zlib header is overwritten after 
compression
+        // with the gz header
+        // 10 header bytes + filename length + null terminator - 2 bytes for
+        // zlib header that gets overwritten
+        mpOStm->Seek(10 + msFilename.getLength() + 1 - 2);
+    }
     meState = STATE_COMPRESS;
     auto pStream = static_cast<z_stream*>(mpsC_Stream);
     mbStatus = deflateInit2_(

Reply via email to