]> git.saurik.com Git - wxWidgets.git/commitdiff
wxZlibStreams fixes; allow them to be used as deflate [de]compressor in gz/zip files...
authorVadim Zeitlin <vadim@wxwidgets.org>
Fri, 26 Sep 2003 20:07:22 +0000 (20:07 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Fri, 26 Sep 2003 20:07:22 +0000 (20:07 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@23945 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

docs/changes.txt
docs/latex/wx/inputstr.tex
docs/latex/wx/outptstr.tex
docs/latex/wx/strmzlib.tex
include/wx/zstream.h
src/common/zstream.cpp

index 9615494b60779755610c50b066cb739addaa0b64..4ab6e287cd9e650279f873489ba56a8f5a94dad7 100644 (file)
@@ -63,6 +63,7 @@ All:
 - wxHTTP::GetResponse() added (David Nock)
 - added conversions to/from UTF 16/32 LE/BE (Andreas Pflug)
 - wxFileName::Normalize(wxPATH_NORM_ALL) doesn't lower filename case any more
 - wxHTTP::GetResponse() added (David Nock)
 - added conversions to/from UTF 16/32 LE/BE (Andreas Pflug)
 - wxFileName::Normalize(wxPATH_NORM_ALL) doesn't lower filename case any more
+- seeveral wxZlibStreams bug fixes enhancements (M.J.Wetherell)
 
 All (GUI):
 
 
 All (GUI):
 
index a46d41fa391a078626ea418090f2cb280b6f93c3..daf42acc31ca724ccd4088f6af8441414bb03231 100644 (file)
@@ -79,7 +79,7 @@ The data is read until an error is raised by one of the two streams.
 This function returns a reference on the current object, so the user can test
 any states of the stream right away.
 
 This function returns a reference on the current object, so the user can test
 any states of the stream right away.
 
-\membersection{wxInputStream::SeekI}
+\membersection{wxInputStream::SeekI}\label{wxinputstreamseeki}
 
 \func{off\_t}{SeekI}{\param{off\_t}{ pos}, \param{wxSeekMode}{ mode = wxFromStart}}
 
 
 \func{off\_t}{SeekI}{\param{off\_t}{ pos}, \param{wxSeekMode}{ mode = wxFromStart}}
 
index 0eb87f886e86123ea0cfb98ccea22b8b4d7d24ce..b01a4b9a0f5a5655873ba9a425d1b158cc892fb8 100644 (file)
@@ -43,7 +43,7 @@ Returns the number of bytes written during the last Write().
 Puts the specified character in the output queue and increments the
 stream position.
 
 Puts the specified character in the output queue and increments the
 stream position.
 
-\membersection{wxOutputStream::SeekO}
+\membersection{wxOutputStream::SeekO}\label{wxoutputstreamseeko}
 
 \func{off\_t}{SeekO}{\param{off\_t}{ pos}, \param{wxSeekMode}{ mode}}
 
 
 \func{off\_t}{SeekO}{\param{off\_t}{ pos}, \param{wxSeekMode}{ mode}}
 
index 33ba7ee7086d24049f09155fd66152589fa4780e..a16745b8fb889a23528e3d175b1149fc32c7f16a 100644 (file)
@@ -6,6 +6,10 @@
 This stream uncompresses all data read from it. It uses the "filtered"
 stream to get new compressed data.
 
 This stream uncompresses all data read from it. It uses the "filtered"
 stream to get new compressed data.
 
+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{Derived from}
 
 \helpref{wxFilterInputStream}{wxfilterinputstream}
@@ -16,7 +20,28 @@ stream to get new compressed data.
 
 \wxheading{See also}
 
 
 \wxheading{See also}
 
-\helpref{wxInputStream}{wxinputstream}
+\helpref{wxInputStream}{wxinputstream}, 
+ \helpref{wxZlibOutputStream}{wxzliboutputstream}.
+
+\latexignore{\rtfignore{\wxheading{Members}}}
+
+\membersection{wxZlibInputStream::wxZlibInputStream}
+
+\func{}{wxZlibInputStream}{\param{wxInputStream\&}{ stream}, \param{int}{ flags = 0}}
+
+{\it flags} should be omitted for normal usage. The flag {\it wxZLIB\_NO_HEADER}
+ is needed when wxZlibInputStream is used as an 'inflate' decompressor for gzip
+or zip files.
+
+{\it wxZLIB\_NO_HEADER} is currently the only flag:
+
+\begin{verbatim}
+// Flags
+enum {
+    wxZLIB_NO_HEADER = 1   // required for use in Gzip and Zip files
+}
+\end{verbatim}
+
 
 % -----------------------------------------------------------------------------
 % wxZlibOutputStream
 
 % -----------------------------------------------------------------------------
 % wxZlibOutputStream
@@ -26,6 +51,9 @@ stream to get new compressed data.
 This stream compresses all data written to it, and passes the compressed data
 to the "filtered" stream.
 
 This stream compresses all data written to it, and passes the compressed data
 to the "filtered" stream.
 
+The stream is not seekable, \helpref{SeekO()}{wxoutputstreamseeko} returns
+ {\it wxInvalidOffset}.
+
 \wxheading{Derived from}
 
 \helpref{wxFilterOutputStream}{wxfilteroutputstream}
 \wxheading{Derived from}
 
 \helpref{wxFilterOutputStream}{wxfilteroutputstream}
@@ -36,16 +64,39 @@ to the "filtered" stream.
 
 \wxheading{See also}
 
 
 \wxheading{See also}
 
-\helpref{wxOutputStream}{wxoutputstream}
+\helpref{wxOutputStream}{wxoutputstream},
+ \helpref{wxZlibInputStream}{wxzlibinputstream}
 
 
 \latexignore{\rtfignore{\wxheading{Members}}}
 
 \membersection{wxZlibOutputStream::wxZlibOutputStream}
 
 
 
 \latexignore{\rtfignore{\wxheading{Members}}}
 
 \membersection{wxZlibOutputStream::wxZlibOutputStream}
 
-\func{}{wxZlibOutputStream}{\param{wxOutputStream\&}{ stream},\param{int}{ level = -1}}
+\func{}{wxZlibOutputStream}{\param{wxOutputStream\&}{ stream}, \param{int}{ level = -1}, \param{int}{ flags = 0}}
 
 Creates a new write-only compressed stream. {\it level} means level of 
 compression. It is number between 0 and 9 (including these values) where
 0 means no compression and 9 best but slowest compression. -1 is default
 value (currently equivalent to 6).
 
 Creates a new write-only compressed stream. {\it level} means level of 
 compression. It is number between 0 and 9 (including these values) where
 0 means no compression and 9 best but slowest compression. -1 is default
 value (currently equivalent to 6).
+
+{\it flags} should be omitted for normal usage. The flag {\it wxZLIB\_NO_HEADER}
+ suppresses the generation of the zlib header and checksum, and is required
+when wxZlibOutputStream is used as a 'deflate' compressor for gzip or zip files.
+
+The following symbols can be use for the compression level and flags:
+
+\begin{verbatim}
+// Compression level
+enum {
+    wxZ_DEFAULT_COMPRESSION = -1,
+    wxZ_NO_COMPRESSION = 0,
+    wxZ_BEST_SPEED = 1,
+    wxZ_BEST_COMPRESSION = 9
+}
+
+// Flags
+enum {
+    wxZLIB_NO_HEADER = 1   // required for use in Gzip and Zip files
+}
+\end{verbatim}
+
index 165ea240d264471f0aef7e81e91b19322288a601..66be16c5df42343fa6c27ceffac6fffdb6641e3e 100644 (file)
@@ -2,7 +2,7 @@
 // Name:        zstream.h
 // Purpose:     Memory stream classes
 // Author:      Guilhem Lavaux
 // Name:        zstream.h
 // Purpose:     Memory stream classes
 // Author:      Guilhem Lavaux
-// Modified by:
+// Modified by: Mike Wetherell
 // Created:     11/07/98
 // RCS-ID:      $Id$
 // Copyright:   (c) Guilhem Lavaux
 // Created:     11/07/98
 // RCS-ID:      $Id$
 // Copyright:   (c) Guilhem Lavaux
 
 #include "wx/stream.h"
 
 
 #include "wx/stream.h"
 
+// Compression level
+enum {
+    wxZ_DEFAULT_COMPRESSION = -1,
+    wxZ_NO_COMPRESSION = 0,
+    wxZ_BEST_SPEED = 1,
+    wxZ_BEST_COMPRESSION = 9
+};
+
+// Flags
+enum {
+    wxZLIB_NO_HEADER = 1   // required for use in Gzip and Zip files
+};
+
 class WXDLLIMPEXP_BASE wxZlibInputStream: public wxFilterInputStream {
  public:
 class WXDLLIMPEXP_BASE wxZlibInputStream: public wxFilterInputStream {
  public:
-  wxZlibInputStream(wxInputStream& stream);
+  wxZlibInputStream(wxInputStream& stream, int flags = 0);
   virtual ~wxZlibInputStream();
 
   virtual ~wxZlibInputStream();
 
+  char Peek() { return wxInputStream::Peek(); }
+  size_t GetSize() const { return wxInputStream::GetSize(); }
+
  protected:
   size_t OnSysRead(void *buffer, size_t size);
  protected:
   size_t OnSysRead(void *buffer, size_t size);
+  off_t OnSysTell() const { return m_pos; }
 
  protected:
   size_t m_z_size;
   unsigned char *m_z_buffer;
   struct z_stream_s *m_inflate;
 
  protected:
   size_t m_z_size;
   unsigned char *m_z_buffer;
   struct z_stream_s *m_inflate;
+  off_t m_pos;
 
     DECLARE_NO_COPY_CLASS(wxZlibInputStream)
 };
 
 class WXDLLIMPEXP_BASE wxZlibOutputStream: public wxFilterOutputStream {
  public:
 
     DECLARE_NO_COPY_CLASS(wxZlibInputStream)
 };
 
 class WXDLLIMPEXP_BASE wxZlibOutputStream: public wxFilterOutputStream {
  public:
-  wxZlibOutputStream(wxOutputStream& stream, int level = -1);
+  wxZlibOutputStream(wxOutputStream& stream, int level = -1, int flags = 0);
   virtual ~wxZlibOutputStream();
 
   virtual ~wxZlibOutputStream();
 
-  void Sync();
+  void Sync() { DoFlush(false); }
+  size_t GetSize() const { return (size_t)m_pos; }
 
  protected:
   size_t OnSysWrite(const void *buffer, size_t size);
 
  protected:
   size_t OnSysWrite(const void *buffer, size_t size);
+  off_t OnSysTell() const { return m_pos; }
+
+  virtual void DoFlush(bool final);
 
  protected:
   size_t m_z_size;
   unsigned char *m_z_buffer;
   struct z_stream_s *m_deflate;
 
  protected:
   size_t m_z_size;
   unsigned char *m_z_buffer;
   struct z_stream_s *m_deflate;
+  off_t m_pos;
 
     DECLARE_NO_COPY_CLASS(wxZlibOutputStream)
 };
 
     DECLARE_NO_COPY_CLASS(wxZlibOutputStream)
 };
index c58f98f71649847163aedfcaf5a7247e84845f3a..c9d2b701c5a02731ea84f4cf212d7ec3643b77c7 100644 (file)
@@ -1,8 +1,8 @@
-/////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
 // Name:        zstream.cpp
 // Purpose:     Compressed stream classes
 // Author:      Guilhem Lavaux
 // Name:        zstream.cpp
 // Purpose:     Compressed stream classes
 // Author:      Guilhem Lavaux
-// Modified by:
+// Modified by: Mike Wetherell
 // Created:     11/07/98
 // RCS-ID:      $Id$
 // Copyright:   (c) Guilhem Lavaux
 // Created:     11/07/98
 // RCS-ID:      $Id$
 // Copyright:   (c) Guilhem Lavaux
    #include "zlib.h"
 #endif
 
    #include "zlib.h"
 #endif
 
-#define ZSTREAM_BUFFER_SIZE 1024
+enum {
+#ifdef __WIN16__
+    ZSTREAM_BUFFER_SIZE = 4096
+#else
+    ZSTREAM_BUFFER_SIZE = 16384
+#endif
+};
 
 //////////////////////
 // wxZlibInputStream
 //////////////////////
 
 
 //////////////////////
 // wxZlibInputStream
 //////////////////////
 
-wxZlibInputStream::wxZlibInputStream(wxInputStream& stream)
+wxZlibInputStream::wxZlibInputStream(wxInputStream& stream, int flags)
   : wxFilterInputStream(stream)
 {
   : wxFilterInputStream(stream)
 {
-  // I need a private stream buffer.
-  m_inflate = new z_stream_s;
+  m_inflate = NULL;
+  m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE];
+  m_z_size = ZSTREAM_BUFFER_SIZE;
+  m_pos = 0;
 
 
-  m_inflate->zalloc = (alloc_func)0;
-  m_inflate->zfree = (free_func)0;
-  m_inflate->opaque = (voidpf)0;
+  if (m_z_buffer) {
+    m_inflate = new z_stream_s;
 
 
-  int err = inflateInit(m_inflate);
-  if (err != Z_OK) {
-    inflateEnd(m_inflate);
-    delete m_inflate;
-    return;
-  }
+    if (m_inflate) {
+      m_inflate->zalloc = (alloc_func)0;
+      m_inflate->zfree = (free_func)0;
+      m_inflate->opaque = (voidpf)0;
+      m_inflate->avail_in = 0;
+      m_inflate->next_in = NULL;
+      m_inflate->next_out = NULL;
 
 
-  m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE];
-  m_z_size = ZSTREAM_BUFFER_SIZE;
+      int bits = (flags & wxZLIB_NO_HEADER) ? -MAX_WBITS : MAX_WBITS;
 
 
-  m_inflate->avail_in = 0;
-  m_inflate->next_in = NULL;
+      if (inflateInit2(m_inflate, bits) == Z_OK)
+        return;
+    }
+  }
+
+  wxLogError(_("Can't initialize zlib inflate stream."));
+  m_lasterror = wxSTREAM_READ_ERROR;
 }
 
 wxZlibInputStream::~wxZlibInputStream()
 }
 
 wxZlibInputStream::~wxZlibInputStream()
@@ -77,150 +89,175 @@ wxZlibInputStream::~wxZlibInputStream()
 
 size_t wxZlibInputStream::OnSysRead(void *buffer, size_t size)
 {
 
 size_t wxZlibInputStream::OnSysRead(void *buffer, size_t size)
 {
-  int err;
+  wxASSERT_MSG(m_inflate && m_z_buffer, wxT("Inflate stream not open"));
+
+  if (!m_inflate || !m_z_buffer)
+    m_lasterror = wxSTREAM_READ_ERROR;
+  if (!IsOk() || !size)
+    return 0;
 
 
+  int err = Z_OK;
   m_inflate->next_out = (unsigned char *)buffer;
   m_inflate->avail_out = size;
 
   m_inflate->next_out = (unsigned char *)buffer;
   m_inflate->avail_out = size;
 
-  while (m_inflate->avail_out > 0) {
+  while (err == Z_OK && m_inflate->avail_out > 0) {
     if (m_inflate->avail_in == 0) {
     if (m_inflate->avail_in == 0) {
-
-      m_parent_i_stream->Read(m_z_buffer, wxMin(m_z_size, size));
+      m_parent_i_stream->Read(m_z_buffer, m_z_size);
       m_inflate->next_in = m_z_buffer;
       m_inflate->avail_in = m_parent_i_stream->LastRead();
 
       m_inflate->next_in = m_z_buffer;
       m_inflate->avail_in = m_parent_i_stream->LastRead();
 
-      wxStreamError err = m_parent_i_stream->GetLastError();
-      if ( err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF)
-      { 
-        m_lasterror = err;
-        return 0; // failed to read anything
+      if (m_inflate->avail_in == 0) {
+        if (m_parent_i_stream->Eof())
+          wxLogError(_("Can't read inflate stream: unexpected EOF in underlying stream."));
+        m_lasterror = wxSTREAM_READ_ERROR;
+        break;
       }
       }
+    }
+    err = inflate(m_inflate, Z_NO_FLUSH);
+  }
 
 
-      if ( m_inflate->avail_in == 0 )
-      {
-          // EOF
-          m_lasterror = wxSTREAM_EOF;
-          break;
-      }
+  if (err == Z_STREAM_END) {
+    // Unread any data taken from past the end of the deflate stream, so that
+    // any additional data can be read from the underlying stream (the crc
+    // in a gzip for example)
+    if (m_inflate->avail_in) {
+      m_parent_i_stream->Ungetch(m_inflate->next_in, m_inflate->avail_in);
+      m_inflate->avail_in = 0;
     }
     }
-    err = inflate(m_inflate, Z_FINISH);
-    if (err == Z_STREAM_END)
-      return (size - m_inflate->avail_out);
+    m_lasterror = wxSTREAM_EOF;
+  } else if (err != Z_OK) {
+    wxLogError(_("Can't read from inflate stream (zlib error %d)."), err);
+    m_lasterror = wxSTREAM_READ_ERROR;
   }
 
   }
 
-  return size-m_inflate->avail_out;
+  size -= m_inflate->avail_out;
+  m_pos += size;
+  return size;
 }
 
 //////////////////////
 // wxZlibOutputStream
 //////////////////////
 
 }
 
 //////////////////////
 // wxZlibOutputStream
 //////////////////////
 
-wxZlibOutputStream::wxZlibOutputStream(wxOutputStream& stream, int level)
+wxZlibOutputStream::wxZlibOutputStream(wxOutputStream& stream,
+                                       int level,
+                                       int flags)
  : wxFilterOutputStream(stream)
 {
  : wxFilterOutputStream(stream)
 {
-  int err;
-
-  m_deflate = new z_stream_s;
-
-  m_deflate->zalloc = (alloc_func)0;
-  m_deflate->zfree = (free_func)0;
-  m_deflate->opaque = (voidpf)0;
+  m_deflate = NULL;
+  m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE];
+  m_z_size = ZSTREAM_BUFFER_SIZE;
+  m_pos = 0;
 
   if ( level == -1 )
   {
 
   if ( level == -1 )
   {
-      level = Z_DEFAULT_COMPRESSION;
+    level = Z_DEFAULT_COMPRESSION;
   }
   else
   {
     wxASSERT_MSG(level >= 0 && level <= 9, wxT("wxZlibOutputStream compression level must be between 0 and 9!"));
   }
 
   }
   else
   {
     wxASSERT_MSG(level >= 0 && level <= 9, wxT("wxZlibOutputStream compression level must be between 0 and 9!"));
   }
 
-  err = deflateInit(m_deflate, level);
-  if (err != Z_OK) {
-    deflateEnd(m_deflate);
-    return;
-  }
+  if (m_z_buffer) {
+     m_deflate = new z_stream_s;
 
 
-  m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE];
-  m_z_size = ZSTREAM_BUFFER_SIZE;
+     if (m_deflate) {
+        m_deflate->zalloc = (alloc_func)0;
+        m_deflate->zfree = (free_func)0;
+        m_deflate->opaque = (voidpf)0;
+        m_deflate->avail_in = 0;
+        m_deflate->next_out = m_z_buffer;
+        m_deflate->avail_out = m_z_size;
+
+        int bits = (flags & wxZLIB_NO_HEADER) ? -MAX_WBITS : MAX_WBITS;
 
 
-  m_deflate->avail_in = 0;
-  m_deflate->next_out = m_z_buffer;
-  m_deflate->avail_out = m_z_size;
+        if (deflateInit2(m_deflate, level, Z_DEFLATED, bits, 
+                         8, Z_DEFAULT_STRATEGY) == Z_OK)
+          return;
+     }
+  }
+
+  wxLogError(_("Can't initialize zlib deflate stream."));
+  m_lasterror = wxSTREAM_WRITE_ERROR;
 }
 
 wxZlibOutputStream::~wxZlibOutputStream()
 {
 }
 
 wxZlibOutputStream::~wxZlibOutputStream()
 {
-  int err;
-
-  Sync();
-
-  err = deflate(m_deflate, Z_FINISH);
-  if (err != Z_STREAM_END) 
-  {
-    wxLogDebug( wxT("wxZlibOutputStream: an error occured while closing the stream.\n") );
-    return;
-  }
-
+  if (m_deflate && m_z_buffer)
+    DoFlush(true);
   deflateEnd(m_deflate);
   delete m_deflate;
 
   delete[] m_z_buffer;
 }
 
   deflateEnd(m_deflate);
   delete m_deflate;
 
   delete[] m_z_buffer;
 }
 
-void wxZlibOutputStream::Sync()
+void wxZlibOutputStream::DoFlush(bool final)
 {
 {
-  int err;
-
-  m_parent_o_stream->Write(m_z_buffer, m_z_size-m_deflate->avail_out);
-  m_deflate->next_out  = m_z_buffer;
-  m_deflate->avail_out = m_z_size;
+  wxASSERT_MSG(m_deflate && m_z_buffer, wxT("Deflate stream not open"));
 
 
-  err = deflate(m_deflate, Z_FULL_FLUSH);
-  if (err != Z_OK) {
+  if (!m_deflate || !m_z_buffer)
+    m_lasterror = wxSTREAM_WRITE_ERROR;
+  if (!IsOk())
     return;
     return;
-  }
 
 
-  // Fixed by "Stefan Csomor" <csomor@advancedconcepts.ch>
-  while( m_deflate->avail_out == 0 )
-  {
-     m_parent_o_stream->Write(m_z_buffer, m_z_size );
-     m_deflate->next_out  = m_z_buffer;
-     m_deflate->avail_out = m_z_size;
-     err = deflate(m_deflate, Z_FULL_FLUSH);
-     if (err != Z_OK) {
-        return;
-     }
-  }
-  // End
+  int err = Z_OK;
+  bool done = false;
 
 
-  m_parent_o_stream->Write(m_z_buffer, m_z_size-m_deflate->avail_out);
-  m_deflate->next_out  = m_z_buffer;
-  m_deflate->avail_out = m_z_size;
+  while (err == Z_OK || err == Z_STREAM_END) {
+    size_t len = m_z_size  - m_deflate->avail_out;
+    if (len) {
+      if (m_parent_o_stream->Write(m_z_buffer, len).LastWrite() != len) {
+        m_lasterror = wxSTREAM_WRITE_ERROR;
+        wxLogDebug(wxT("wxZlibOutputStream: Error writing to underlying stream"));
+        break;
+      }
+      m_deflate->next_out = m_z_buffer;
+      m_deflate->avail_out = m_z_size;
+    }
+
+    if (done)
+      break;
+    err = deflate(m_deflate, final ? Z_FINISH : Z_FULL_FLUSH);
+    done = m_deflate->avail_out != 0 || err == Z_STREAM_END;
+  }
 }
 
 size_t wxZlibOutputStream::OnSysWrite(const void *buffer, size_t size)
 {
 }
 
 size_t wxZlibOutputStream::OnSysWrite(const void *buffer, size_t size)
 {
-  int err;
+  wxASSERT_MSG(m_deflate && m_z_buffer, wxT("Deflate stream not open"));
 
 
+  if (!m_deflate || !m_z_buffer)
+    m_lasterror = wxSTREAM_WRITE_ERROR;
+  if (!IsOk() || !size)
+    return 0;
+
+  int err = Z_OK;
   m_deflate->next_in = (unsigned char *)buffer;
   m_deflate->avail_in = size;
 
   m_deflate->next_in = (unsigned char *)buffer;
   m_deflate->avail_in = size;
 
-  while (m_deflate->avail_in > 0) {
-
+  while (err == Z_OK && m_deflate->avail_in > 0) {
     if (m_deflate->avail_out == 0) {
       m_parent_o_stream->Write(m_z_buffer, m_z_size);
     if (m_deflate->avail_out == 0) {
       m_parent_o_stream->Write(m_z_buffer, m_z_size);
-      if ( !*m_parent_o_stream )
-        return (size - m_deflate->avail_in);
+      if (m_parent_o_stream->LastWrite() != m_z_size) {
+        m_lasterror = wxSTREAM_WRITE_ERROR;
+        wxLogDebug(wxT("wxZlibOutputStream: Error writing to underlying stream"));
+        break;
+      }
 
       m_deflate->next_out = m_z_buffer;
       m_deflate->avail_out = m_z_size;
     }
 
     err = deflate(m_deflate, Z_NO_FLUSH);
 
       m_deflate->next_out = m_z_buffer;
       m_deflate->avail_out = m_z_size;
     }
 
     err = deflate(m_deflate, Z_NO_FLUSH);
-    if (err != Z_OK)
-      return (size - m_deflate->avail_in);
   }
   }
+
+  if (err != Z_OK) {
+    m_lasterror = wxSTREAM_WRITE_ERROR;
+    wxLogError(_("Can't write to deflate stream (zlib error %d)."), err);
+  }
+
+  size -= m_deflate->avail_in;
+  m_pos += size;
   return size;
 }
 
   return size;
 }