]> git.saurik.com Git - wxWidgets.git/commitdiff
added wxGzipIOStreams (patch 792932)
authorVadim Zeitlin <vadim@wxwidgets.org>
Fri, 26 Sep 2003 20:24:36 +0000 (20:24 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Fri, 26 Sep 2003 20:24:36 +0000 (20:24 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@23949 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

13 files changed:
build/bakefiles/files.bkl
configure.in
docs/latex/wx/classes.tex
docs/latex/wx/gzstream.tex [new file with mode: 0644]
include/wx/chkconf.h
include/wx/gzstream.h [new file with mode: 0644]
include/wx/mac/setup0.h
include/wx/msw/setup0.h
include/wx/os2/setup0.h
include/wx/univ/setup0.h
setup.h.in
setup.h_vms
src/common/gzstream.cpp [new file with mode: 0644]

index 48dcc1db56869fe10c1525885d22f5d683abd288..4735bb89a3b6a3370370fbd6de8b212631601862 100644 (file)
@@ -155,6 +155,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
     src/common/filesys.cpp
     src/common/fmapbase.cpp
     src/common/fs_zip.cpp
+    src/common/gzstream.cpp
     src/common/hash.cpp
     src/common/hashmap.cpp
     src/common/init.cpp
@@ -233,6 +234,7 @@ IMPORTANT: please read docs/tech/tn0016.txt before modifying this file!
     wx/fontmap.h
     wx/fs_mem.h
     wx/fs_zip.h
+    wx/gzstream.h
     wx/hash.h
     wx/hashmap.h
     wx/hashset.h
index 9130131f6b1c40b18bb80f62d45db59d7d01a4a9..5a3fb2bef57221fa8c0c61cfbadcf8c8a42e971c 100644 (file)
@@ -478,6 +478,7 @@ if test $DEBUG_CONFIGURE = 1; then
   DEFAULT_wxUSE_FS_ZIP=no
   DEFAULT_wxUSE_BUSYINFO=no
   DEFAULT_wxUSE_ZIPSTREAM=no
+  DEFAULT_wxUSE_GZSTREAM=no
   DEFAULT_wxUSE_VALIDATORS=no
 
   DEFAULT_wxUSE_ACCEL=no
@@ -656,6 +657,7 @@ else
   DEFAULT_wxUSE_FS_ZIP=yes
   DEFAULT_wxUSE_BUSYINFO=yes
   DEFAULT_wxUSE_ZIPSTREAM=yes
+  DEFAULT_wxUSE_GZSTREAM=yes
   DEFAULT_wxUSE_VALIDATORS=yes
 
   DEFAULT_wxUSE_ACCEL=yes
@@ -866,6 +868,7 @@ WX_ARG_ENABLE(unicode,       [  --enable-unicode        compile wxString with Un
 WX_ARG_ENABLE(wave,          [  --enable-wave           use wxWave class], wxUSE_WAVE)
 WX_ARG_ENABLE(wxprintfv,     [  --enable-wxprintfv      use wxWindows implementation of vprintf()], wxUSE_EXPERIMENTAL_PRINTF)
 WX_ARG_ENABLE(zipstream,     [  --enable-zipstream      use wxZipInputStream], wxUSE_ZIPSTREAM)
+WX_ARG_ENABLE(gzstream,      [  --enable-gzstream       use wxGzipInputStream], wxUSE_GZSTREAM)
 
 WX_ARG_ENABLE(url,           [  --enable-url            use wxURL class], wxUSE_URL)
 WX_ARG_ENABLE(protocol,      [  --enable-protocol       use wxProtocol class], wxUSE_PROTOCOL)
@@ -4355,6 +4358,10 @@ if test "$wxUSE_ZIPSTREAM" = "yes"; then
   AC_DEFINE(wxUSE_ZIPSTREAM)
 fi
 
+if test "$wxUSE_GZSTREAM" = "yes"; then
+  AC_DEFINE(wxUSE_GZSTREAM)
+fi
+
 if test "$wxUSE_ON_FATAL_EXCEPTION" = "yes"; then
   AC_DEFINE(wxUSE_ON_FATAL_EXCEPTION)
 fi
index 959a7de195889ec10c94f19b369ab06e0a0376f2..473d8dc7dffd7f65086e64b8e4099e95e98e49bf 100644 (file)
 \input gridrend.tex
 \input gridtbl.tex
 \input gridsizr.tex
+\input gzstream.tex
 \input hashmap.tex
 \input hash.tex
 \input helpinst.tex
diff --git a/docs/latex/wx/gzstream.tex b/docs/latex/wx/gzstream.tex
new file mode 100644 (file)
index 0000000..cf4a0b3
--- /dev/null
@@ -0,0 +1,173 @@
+%
+% automatically generated by HelpGen $Revision$ from
+% gzstream.h at 20/Aug/03 18:41:55
+%
+
+%
+% wxGzipInputStream
+%
+
+\section{\class{wxGzipInputStream}}\label{wxgzipinputstream}
+
+A stream filter to decompress gzipped data. The gzip format is specified in
+RFC-1952.
+
+A gzip stream can contain the original filename and timestamp of the
+compressed data. These fields can be obtained using the
+ \helpref{GetName()}{wxgzipinputstreamgetname} and
+ \helpref{GetDateTime()}{wxgzipinputstreamgetdatetime} accessors.
+
+If the stream turns out not to be a gzip stream (i.e. the signature bytes
+0x1f, 0x8b are not found), then the constructor unreads the bytes read and
+sets the stream state to {\it wxSTREAM\_EOF}.
+
+So given a possibly gzipped stream '{\it maybe\_gzipped}' you can construct
+a decompressed stream '{\it decompressed}' with something like:
+
+\begin{verbatim}
+wxGzipInputStream gzip(maybe_gzipped);
+wxInputStream *decompressed = &gzip;
+if (gzip.Eof())
+    decompressed = &maybe_gzipped;
+
+\end{verbatim}
+The stream will not read past the end of the gzip data, therefore you
+can read another gzip entry concatenated by creating another
+ {\it wxGzipInputStream} on the same underlying stream.
+
+The stream is not seekable, \helpref{SeekI()}{wxinputstreamseeki} returns
+ {\it wxInvalidOffset}.  Also \helpref{GetSize()}{wxstreambasegetsize} is
+not supported, it always returns $0$.
+
+\wxheading{Derived from}
+
+\helpref{wxFilterInputStream}{wxfilterinputstream}
+
+\wxheading{Include files}
+
+<wx/gzstream.h>
+
+\wxheading{See also}
+
+\helpref{wxGzipOutputStream}{wxgzipoutputstream}, 
+ \helpref{wxZlibInputStream}{wxzlibinputstream},
+ \helpref{wxInputStream}{wxinputstream}.
+
+\latexignore{\rtfignore{\wxheading{Members}}}
+
+
+\membersection{wxGzipInputStream::wxGzipInputStream}\label{wxgzipinputstreamwxgzipinputstream}
+
+\func{}{wxGzipInputStream}{\param{wxInputStream\& }{stream}, \param{wxMBConv\& }{conv = wxConvFile}}
+
+Constructs an object to decompress a gzipped stream.
+
+The constructor reads the gzip header. If the original file name and timestamp
+are present, then they can be obtained through the 
+ \helpref{GetName()}{wxgzipinputstreamgetname} and
+ \helpref{GetDateTime()}{wxgzipinputstreamgetdatetime} accessors.
+
+The filename in the header is stored using an 8-bit character set. In a
+Unicode build {\it conv} is used to translate the filename into Unicode (it
+has no effect on the stream data). RFC-1952 specifies that the character set
+should be ISO-8859-1, however the default here is to use {\it wxConvFile}
+ which more closely matches the behaviour of the gzip program. In
+a non-Unicode build {\it conv} is ignored.
+
+If the first two bytes are not the gzip signature, then the data is not
+gzipped after all. The stream state is set to {\it wxSTREAM\_EOF}, and the
+two bytes are unread so that the underlying stream can be read directly.
+
+
+\membersection{wxGzipInputStream::\destruct{wxGzipInputStream}}\label{wxgzipinputstreamdtor}
+
+\func{}{\destruct{wxGzipInputStream}}{\void}
+
+Destructor.
+
+
+\membersection{wxGzipInputStream::GetDateTime}\label{wxgzipinputstreamgetdatetime}
+
+\constfunc{wxDateTime}{GetDateTime}{\void}
+
+Returns the original modification time of gzipped data, as obtained from the
+gzip header.
+
+
+\membersection{wxGzipInputStream::GetName}\label{wxgzipinputstreamgetname}
+
+\constfunc{wxString}{GetName}{\void}
+
+Returns the original filename of gzipped data, with any directory components
+removed.
+
+
+%
+% wxGzipOutputStream
+%
+
+\section{\class{wxGzipOutputStream}}\label{wxgzipoutputstream}
+
+A stream filter to compress gzipped data. The gzip format is specified in
+RFC-1952.
+
+The stream is not seekable, \helpref{SeekO()}{wxoutputstreamseeko} returns 
+ {\it wxInvalidOffset}.
+
+
+\wxheading{Derived from}
+
+\helpref{wxFilterOutputStream}{wxfilteroutputstream}
+
+\wxheading{Include files}
+
+<wx/gzstream.h>
+
+\wxheading{See also}
+
+\helpref{wxGzipInputStream}{wxgzipinputstream}, 
+ \helpref{wxZlibOutputStream}{wxzliboutputstream},
+ \helpref{wxOutputStream}{wxoutputstream}.
+
+\latexignore{\rtfignore{\wxheading{Members}}}
+
+
+\membersection{wxGzipOutputStream::wxGzipOutputStream}\label{wxgzipoutputstreamwxgzipoutputstream}
+
+\func{}{wxGzipOutputStream}{\param{wxOutputStream\& }{stream}, \param{const wxString\& }{originalName = wxEmptyString}, \param{int }{level = -1}, \param{wxMBConv\& }{conv = wxConvFile}}
+
+If the {\it originalName} is given, then it is written to the gzip header
+with any directory components removed. On a Unicode build it is first
+converted to an 8-bit encoding using {\it conv}. RFC-1952 specifies that
+the character set should be ISO-8859-1, however the default here is to
+use {\it wxConvFile} which more closely matches the behaviour of the gzip
+program. In a non-Unicode build {\it conv} is ignored. {\it conv} has no
+effect on the stream data.
+
+If {\it originalName} specifies a file that exists then it's current
+modification time is also written to the gzip header as the timestamp.
+Otherwise the current time is used for the timestamp.
+
+{\it level} is the compression level. It can be an integer between $0$ (no
+compression) and $9$ (most compression). $-1$ specifies that the default
+compression should be used, and is currently equivalent to $6$.
+
+You can also use the following constants from <wx/zstream.h>:
+
+\begin{verbatim}
+// Compression level
+enum {
+    wxZ_DEFAULT_COMPRESSION = -1,
+    wxZ_NO_COMPRESSION = 0,
+    wxZ_BEST_SPEED = 1,
+    wxZ_BEST_COMPRESSION = 9
+}
+\end{verbatim}
+
+
+\membersection{wxGzipOutputStream::\destruct{wxGzipOutputStream}}\label{wxgzipoutputstreamdtor}
+
+\func{}{\destruct{wxGzipOutputStream}}{\void}
+
+Destructor.
+
index 2049b2d2247858fa0a6dd77690c62d0a55319e5b..afbb47412421b0e02adb4687ef25c3e8c76ea913 100644 (file)
 #   endif
 #endif /* wxUSE_PROTOCOL */
 
+#if wxUSE_GZSTREAM
+#   if !wxUSE_ZLIB
+#       ifdef wxABORT_ON_CONFIG_ERROR
+#           error "wxUSE_GZSTREAM requires wxUSE_ZLIB"
+#       else
+#           undef wxUSE_ZLIB
+#           define wxUSE_ZLIB 1
+#       endif
+#   endif
+#endif /* wxUSE_GZSTREAM */
+
 /* have to test for wxUSE_HTML before wxUSE_FILESYSTEM */
 #if wxUSE_HTML
 #   if !wxUSE_FILESYSTEM
diff --git a/include/wx/gzstream.h b/include/wx/gzstream.h
new file mode 100644 (file)
index 0000000..9a340fe
--- /dev/null
@@ -0,0 +1,87 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        gzstream.h
+// Purpose:     Streams for Gzip files
+// Author:      Mike Wetherell
+// RCS-ID:      $Id$
+// Copyright:   (c) 2003 Mike Wetherell
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_GZSTREAM_H__
+#define _WX_GZSTREAM_H__
+
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
+#pragma interface "gzstream.h"
+#endif
+
+#include "wx/defs.h"
+
+#if wxUSE_STREAMS && wxUSE_GZSTREAM && wxUSE_ZLIB 
+
+#include "wx/datetime.h"
+
+
+/////////////////////////////////////////////////////////////////////////////
+// wxGzipInputStream 
+
+class WXDLLIMPEXP_BASE wxGzipInputStream : public wxFilterInputStream
+{
+public:
+    wxGzipInputStream(wxInputStream& stream, wxMBConv& conv = wxConvFile);
+    virtual ~wxGzipInputStream();
+
+    wxString GetName() const { return m_name; }
+
+#if wxUSE_DATETIME
+    wxDateTime GetDateTime() const { return m_datetime; }
+#endif
+
+    virtual char Peek() { return wxInputStream::Peek(); }
+    virtual size_t GetSize() const { return m_decomp ? m_decomp->GetSize() : 0; }
+
+protected:
+    virtual size_t OnSysRead(void *buffer, size_t size);
+    virtual off_t OnSysTell() const { return m_decomp ? m_decomp->TellI() : 0; }
+
+private:
+    wxInputStream *m_decomp;
+    wxUint32 m_crc;
+    wxString m_name;
+
+#if wxUSE_DATETIME
+    wxDateTime m_datetime;
+#endif
+
+    DECLARE_NO_COPY_CLASS(wxGzipInputStream)
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// wxGzipOutputStream 
+
+class WXDLLIMPEXP_BASE wxGzipOutputStream : public wxFilterOutputStream
+{
+public:
+    wxGzipOutputStream(wxOutputStream& stream,
+                       const wxString& originalName = wxEmptyString,
+                       int level = -1,
+                       wxMBConv& conv = wxConvFile);
+    virtual ~wxGzipOutputStream();
+
+    virtual void Sync();
+
+protected:
+    virtual size_t OnSysWrite(const void *buffer, size_t size);
+    virtual off_t OnSysTell() const { return m_comp ? m_comp->TellO() : 0; }
+
+private:
+    wxOutputStream *m_comp;
+    wxUint32 m_crc;
+
+    DECLARE_NO_COPY_CLASS(wxGzipOutputStream)
+};
+
+
+#endif // wxUSE_STREAMS && wxUSE_GZSTREAM && wxUSE_ZLIB 
+
+#endif // _WX_GZSTREAM_H__
index 37dcda793ebfb67679aad98544fd7e54d3d4ff54..2d1ff52d2c930a7a42835489cd3583882cb64b08 100644 (file)
 #define wxUSE_ZIPSTREAM     1
 
 // Set to 1 to compile wxZlibInput/OutputStream classes. Also required by
-// wxUSE_LIBPNG.
+// wxUSE_LIBPNG and wxUSE_GZSTREAM.
 #define wxUSE_ZLIB          1
 
+// Set to 1 to compile wxGzipInput/OutputStream classes. Requires wxUSE_ZLIB.
+#define wxUSE_GZSTREAM      1
+
 // If enabled, the code written by Apple will be used to write, in a portable
 // way, float on the disk. See extended.c for the license which is different
 // from wxWindows one.
index b3e126f6148df2527b1682fa470e853a2a64b07e..6a7378edb80cd995ec40ebf27f05c3985f0e83d9 100644 (file)
 #define wxUSE_ZIPSTREAM     1
 
 // Set to 1 to compile wxZlibInput/OutputStream classes. Also required by
-// wxUSE_LIBPNG.
+// wxUSE_LIBPNG and wxUSE_GZSTREAM.
 #define wxUSE_ZLIB          1
 
+// Set to 1 to compile wxGzipInput/OutputStream classes. Requires wxUSE_ZLIB.
+#define wxUSE_GZSTREAM      1
+
 // If enabled, the code written by Apple will be used to write, in a portable
 // way, float on the disk. See extended.c for the license which is different
 // from wxWindows one.
index 05f9f45b40a39922a04a4edc81470f519b113732..58d1b1297cb31e4214b21e0963f9994f70ebd2a4 100644 (file)
                                   // and make the library thread safe
 #define wxUSE_ZLIB          1
                                   // Use zlib for compression in streams and PNG code
+#define wxUSE_GZSTREAM      1
+                                  // Set to 1 to compile wxGzipInput/OutputStream classes.
+                                  // Requires wxUSE_ZLIB.
 #define wxUSE_IMAGE         1
                                   // Set to 1 for wxImage support (recommended).
 #define wxUSE_LIBPNG        1
index 367fe2a3269393d1f5804e24e59a0671819207b6..139649749218c044924b27368afe2caa0b77ce3b 100644 (file)
 #define wxUSE_ZIPSTREAM 1
 
 // Set to 1 to compile wxZlibInput/OutputStream classes. Also required by
-// wxUSE_LIBPNG.
-#define wxUSE_ZLIB 1
+// wxUSE_LIBPNG and wxUSE_GZSTREAM.
+#define wxUSE_ZLIB          1
+
+// Set to 1 to compile wxGzipInput/OutputStream classes. Requires wxUSE_ZLIB.
+#define wxUSE_GZSTREAM      1
 
 // Set to 1 to enable virtual Internet filesystem (requires wxUSE_FILESYSTEM)
 #define wxUSE_FS_INET 1
index 3d02255d6f1a48c176ced68f34eca24586f15fe0..da237db11fb395fa1ce4fb049a79c26d6e776771 100644 (file)
  */
 #define wxUSE_ZIPSTREAM 0
 
+/*
+ * Use gzip streams, requires wxUSE_ZLIB
+ */
+#define wxUSE_GZSTREAM 0
+
 /*
  * wxPalette class
  */
index 5c3b90e444ad4ff5380bdb295824a3efc04e7a4c..e85b6d24c4cd8159f1e081d931873e258b93515e 100644 (file)
  */
 #define wxUSE_ZIPSTREAM 1
 
+/*
+ * Use gzip streams, requires wxUSE_ZLIB
+ */
+#define wxUSE_GZSTREAM 1
+
 /*
  * wxPalette class
  */
diff --git a/src/common/gzstream.cpp b/src/common/gzstream.cpp
new file mode 100644 (file)
index 0000000..6e1098a
--- /dev/null
@@ -0,0 +1,296 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        gzstream.cpp
+// Purpose:     Streams for Gzip files
+// Author:      Mike Wetherell
+// RCS-ID:      $Id$
+// Copyright:   (c) 2003 Mike Wetherell
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
+#pragma implementation "gzstream.h"
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+  #pragma hdrstop
+#endif
+
+#if wxUSE_STREAMS && wxUSE_GZSTREAM && wxUSE_ZLIB 
+
+#include "wx/log.h"
+#include "wx/intl.h"
+#include "wx/datstrm.h"
+#include "wx/txtstrm.h"
+#include "wx/filename.h"
+#include "wx/zstream.h"
+#include "wx/gzstream.h"
+
+#if defined(__WXMSW__) && !defined(__WX_SETUP_H__) && !defined(wxUSE_ZLIB_H_IN_PATH)
+   #include "../zlib/zlib.h"
+#else
+   #include "zlib.h"
+#endif
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Notes:
+//
+// See RFC-1952 and the Gzip/Zlib sources for the details of the Gzip format
+//
+// Errors are displayed with wxLogError, but not errors from the compressor
+// or underlying stream, since they will display their own errors.
+//
+// Gzip doesn't use flag 2 to indicate a header crc, so I think it's
+// probably better not to use it for the moment.
+//
+
+// Flags
+enum {
+    GZ_ASCII_FLAG   = 0x01,
+    GZ_HEAD_CRC     = 0x02,
+    GZ_EXTRA_FIELD  = 0x04,
+    GZ_ORIG_NAME    = 0x08,
+    GZ_COMMENT      = 0x10,
+    GZ_RESERVED     = 0xE0
+};
+
+// Extra flags
+enum {
+    GZ_SLOWEST = 2,
+    GZ_FASTEST = 4
+};
+
+const wxUint16 GZ_MAGIC = 0x8b1f;
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Input stream
+
+wxGzipInputStream::wxGzipInputStream(wxInputStream& stream,
+                                     wxMBConv& conv /*=wxConvFile*/)
+  : wxFilterInputStream(stream)
+{
+    m_decomp = NULL;
+    m_crc = crc32(0, Z_NULL, 0);
+
+    // Try to read the Gzip magic numbers 0x1f, 0x8b. If not found then the
+    // underlying stream isn't gzipped after all, so unread the bytes taken
+    // so that the underlying stream can be read directly instead.
+    wxUint8 magic[2];
+    size_t n = m_parent_i_stream->Read(magic, sizeof(magic)).LastRead();
+
+    if (n < sizeof(magic) || ((magic[1] << 8) | magic[0]) != GZ_MAGIC) {
+        if (n)
+            m_parent_i_stream->Ungetch(magic, n);
+        // Set EOF rather than error to indicate no gzip data
+        m_lasterror = wxSTREAM_EOF;
+        return;
+    }
+
+    wxDataInputStream ds(*m_parent_i_stream);
+
+    // read method, flags, timestamp, extra flags and OS-code
+    int method = ds.Read8();
+    int flags = ds.Read8();
+#if wxUSE_DATETIME
+    wxUint32 datetime = ds.Read32();
+    if (datetime)   // zero means not set (not -1 as usual for time_t)
+        m_datetime = wxLongLong(0, datetime) * 1000L;
+#else
+    ds.Read32();
+#endif
+    ds.Read8();
+    ds.Read8();
+
+    if (flags & GZ_HEAD_CRC)
+        ds.Read16();
+
+    if (flags & GZ_EXTRA_FIELD)
+        for (int i = ds.Read16(); i > 0 && m_parent_i_stream->IsOk(); i--)
+            m_parent_i_stream->GetC();
+
+    // RFC-1952 specifies ISO-8859-1 for these fields
+    if (flags & GZ_ORIG_NAME) {
+#if wxUSE_UNICODE
+        wxTextInputStream tis(*m_parent_i_stream, wxT(" \t"), conv);
+#else
+        wxTextInputStream tis(*m_parent_i_stream);
+        (void)conv;
+#endif
+        wxChar c;
+        while ((c = tis.GetChar()) != 0 && m_parent_i_stream->IsOk())
+            m_name += c;
+    }
+
+    if (flags & GZ_COMMENT)
+        while (m_parent_i_stream->GetC() != 0 && m_parent_i_stream->IsOk())
+            ;   // empty loop
+
+    m_lasterror = wxSTREAM_READ_ERROR;
+    if (!*m_parent_i_stream) {
+        wxLogDebug(wxT("Error reading Gzip header"));
+        return;
+    }
+
+    if (flags & GZ_RESERVED)
+        wxLogWarning(_("Unsupported flag in Gzip header"));
+
+    switch (method) {
+        case Z_DEFLATED:
+            m_decomp = new wxZlibInputStream(*m_parent_i_stream, wxZLIB_NO_HEADER);
+            break;
+
+        default:
+            wxLogError(_("unsupported compression method in Gzip stream"));
+            return; 
+    }
+
+    if (m_decomp)
+        m_lasterror = m_decomp->GetLastError();
+}
+
+
+wxGzipInputStream::~wxGzipInputStream()
+{
+    delete m_decomp;
+}
+
+
+size_t wxGzipInputStream::OnSysRead(void *buffer, size_t size)
+{
+    wxASSERT_MSG(m_decomp, wxT("Gzip not open"));
+
+    if (!m_decomp)
+        m_lasterror = wxSTREAM_READ_ERROR;
+    if (!IsOk() || !size)
+        return 0;
+
+    m_decomp->Read(buffer, size);
+    m_crc = crc32(m_crc, (Byte*)buffer, m_decomp->LastRead());
+
+    if (m_decomp->Eof()) {
+        wxDataInputStream ds(*m_parent_i_stream);
+        m_lasterror = wxSTREAM_READ_ERROR;
+
+        if (m_parent_i_stream->IsOk() && ds.Read32() != m_crc)
+            wxLogError(_("reading Gzip stream: bad crc"));
+        else if (m_parent_i_stream->IsOk() && ds.Read32() != (wxUint32)TellI())
+            wxLogError(_("reading Gzip stream: incorrect length"));
+        else if (m_parent_i_stream->IsOk())
+            m_lasterror = wxSTREAM_EOF;
+    } 
+    else if (!*m_decomp) {
+        m_lasterror = wxSTREAM_READ_ERROR;
+    }
+
+    return m_decomp->LastRead();
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Output stream
+
+wxGzipOutputStream::wxGzipOutputStream(
+                            wxOutputStream& stream,
+                            const wxString& originalName /*=wxEmptyString*/,
+                            int level /*=-1*/,
+                            wxMBConv& conv /*=wxConvFile*/)
+  : wxFilterOutputStream(stream)
+{
+    m_comp = NULL;
+    m_crc = crc32(0, Z_NULL, 0);
+
+    wxFileName filename(originalName);
+
+#if wxUSE_DATETIME
+    wxDateTime datetime;
+
+    if (filename.FileExists())
+        datetime = filename.GetModificationTime();
+    else
+        datetime = wxDateTime::Now();
+
+    wxUint32 timestamp = (datetime.GetValue() / 1000L).GetLo();
+#else
+    wxUint32 timestamp = 0;
+#endif
+
+    // RFC-1952 specifies ISO-8859-1 for the name. Also it should be just the
+    // name part, no directory, folded to lowercase if case insensitive
+    wxString name = filename.GetFullName();
+    const wxWX2MBbuf mbName = conv.cWX2MB(name);
+    
+    wxDataOutputStream ds(*m_parent_o_stream);
+
+    // write signature, method, flags, timestamp, extra flags and OS-code
+    ds.Write16(GZ_MAGIC);
+    ds.Write8(Z_DEFLATED);
+    ds.Write8(mbName && *mbName ? GZ_ORIG_NAME : 0);
+    ds.Write32(timestamp);
+    ds.Write8(level == 1 ? GZ_FASTEST : level == 9 ? GZ_SLOWEST : 0);
+    ds.Write8(255);
+
+    if (mbName && *mbName)
+        m_parent_o_stream->Write(mbName, strlen(mbName) + 1);
+
+    m_lasterror = wxSTREAM_WRITE_ERROR;
+    if (!*m_parent_o_stream) {
+        wxLogDebug(wxT("Error writing Gzip header"));
+        return;
+    }
+
+    m_comp = new wxZlibOutputStream(*m_parent_o_stream, level, wxZLIB_NO_HEADER);
+
+    if (m_comp)
+        m_lasterror = m_comp->GetLastError();
+}
+
+
+wxGzipOutputStream::~wxGzipOutputStream()
+{
+    if (m_comp && m_comp->IsOk()) {
+        wxUint32 len = (wxUint32)m_comp->TellO();
+        delete m_comp;
+        if (m_parent_o_stream->IsOk()) {
+            wxDataOutputStream ds(*m_parent_o_stream);
+            ds.Write32(m_crc);
+            ds.Write32(len);    // underlying stream will report errors
+        }
+    } else {
+        delete m_comp;
+    }
+}
+
+
+void wxGzipOutputStream::Sync()
+{
+    wxASSERT_MSG(m_comp, wxT("Gzip not open"));
+
+    if (!m_comp)
+        m_lasterror = wxSTREAM_WRITE_ERROR;
+    if (IsOk())
+        m_comp->Sync();
+}
+
+
+size_t wxGzipOutputStream::OnSysWrite(const void *buffer, size_t size)
+{
+    wxASSERT_MSG(m_comp, wxT("Gzip not open"));
+
+    if (!m_comp)
+        m_lasterror = wxSTREAM_WRITE_ERROR;
+    if (!IsOk() || !size)
+        return 0;
+
+    if (m_comp->Write(buffer, size).LastWrite() != size)
+        m_lasterror = wxSTREAM_WRITE_ERROR;
+    m_crc = crc32(m_crc, (Byte*)buffer, size);
+
+    return m_comp->LastWrite();
+}
+
+
+#endif // wxUSE_STREAMS && wxUSE_GZSTREAM && wxUSE_ZLIB