wxZlibStreams fixes; allow them to be used as deflate [de]compressor in gz/zip files (patch 792562)

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@23945 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2003-09-26 20:07:22 +00:00
parent 6bb7cee4e9
commit 0915d0b2e2
6 changed files with 222 additions and 110 deletions

View File

@@ -63,6 +63,7 @@ All:
- wxHTTP::GetResponse() added (David Nock) - wxHTTP::GetResponse() added (David Nock)
- added conversions to/from UTF 16/32 LE/BE (Andreas Pflug) - added conversions to/from UTF 16/32 LE/BE (Andreas Pflug)
- wxFileName::Normalize(wxPATH_NORM_ALL) doesn't lower filename case any more - wxFileName::Normalize(wxPATH_NORM_ALL) doesn't lower filename case any more
- seeveral wxZlibStreams bug fixes enhancements (M.J.Wetherell)
All (GUI): All (GUI):

View 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 This function returns a reference on the current object, so the user can test
any states of the stream right away. 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}}

View 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 Puts the specified character in the output queue and increments the
stream position. 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}}

View File

@@ -6,6 +6,10 @@
This stream uncompresses all data read from it. It uses the "filtered" This stream uncompresses all data read from it. It uses the "filtered"
stream to get new compressed data. 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} \wxheading{Derived from}
\helpref{wxFilterInputStream}{wxfilterinputstream} \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 This stream compresses all data written to it, and passes the compressed data
to the "filtered" stream. to the "filtered" stream.
The stream is not seekable, \helpref{SeekO()}{wxoutputstreamseeko} returns
{\it wxInvalidOffset}.
\wxheading{Derived from} \wxheading{Derived from}
\helpref{wxFilterOutputStream}{wxfilteroutputstream} \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}}} \latexignore{\rtfignore{\wxheading{Members}}}
\membersection{wxZlibOutputStream::wxZlibOutputStream} \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 Creates a new write-only compressed stream. {\it level} means level of
compression. It is number between 0 and 9 (including these values) where 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 0 means no compression and 9 best but slowest compression. -1 is default
value (currently equivalent to 6). 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}

View File

@@ -2,7 +2,7 @@
// Name: zstream.h // Name: zstream.h
// Purpose: Memory stream classes // Purpose: Memory stream classes
// Author: Guilhem Lavaux // Author: Guilhem Lavaux
// Modified by: // Modified by: Mike Wetherell
// Created: 11/07/98 // Created: 11/07/98
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) Guilhem Lavaux // Copyright: (c) Guilhem Lavaux
@@ -21,36 +21,59 @@
#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 { class WXDLLIMPEXP_BASE wxZlibInputStream: public wxFilterInputStream {
public: 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: protected:
size_t OnSysRead(void *buffer, size_t size); size_t OnSysRead(void *buffer, size_t size);
off_t OnSysTell() const { return m_pos; }
protected: protected:
size_t m_z_size; size_t m_z_size;
unsigned char *m_z_buffer; unsigned char *m_z_buffer;
struct z_stream_s *m_inflate; struct z_stream_s *m_inflate;
off_t m_pos;
DECLARE_NO_COPY_CLASS(wxZlibInputStream) DECLARE_NO_COPY_CLASS(wxZlibInputStream)
}; };
class WXDLLIMPEXP_BASE wxZlibOutputStream: public wxFilterOutputStream { class WXDLLIMPEXP_BASE wxZlibOutputStream: public wxFilterOutputStream {
public: 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: protected:
size_t OnSysWrite(const void *buffer, size_t size); size_t OnSysWrite(const void *buffer, size_t size);
off_t OnSysTell() const { return m_pos; }
virtual void DoFlush(bool final);
protected: protected:
size_t m_z_size; size_t m_z_size;
unsigned char *m_z_buffer; unsigned char *m_z_buffer;
struct z_stream_s *m_deflate; struct z_stream_s *m_deflate;
off_t m_pos;
DECLARE_NO_COPY_CLASS(wxZlibOutputStream) DECLARE_NO_COPY_CLASS(wxZlibOutputStream)
}; };

View File

@@ -1,8 +1,8 @@
///////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////
// Name: zstream.cpp // Name: zstream.cpp
// Purpose: Compressed stream classes // Purpose: Compressed stream classes
// Author: Guilhem Lavaux // Author: Guilhem Lavaux
// Modified by: // Modified by: Mike Wetherell
// Created: 11/07/98 // Created: 11/07/98
// RCS-ID: $Id$ // RCS-ID: $Id$
// Copyright: (c) Guilhem Lavaux // Copyright: (c) Guilhem Lavaux
@@ -37,34 +37,46 @@
#include "zlib.h" #include "zlib.h"
#endif #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 = NULL;
m_inflate = new z_stream_s;
m_inflate->zalloc = (alloc_func)0;
m_inflate->zfree = (free_func)0;
m_inflate->opaque = (voidpf)0;
int err = inflateInit(m_inflate);
if (err != Z_OK) {
inflateEnd(m_inflate);
delete m_inflate;
return;
}
m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE]; m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE];
m_z_size = ZSTREAM_BUFFER_SIZE; m_z_size = ZSTREAM_BUFFER_SIZE;
m_pos = 0;
m_inflate->avail_in = 0; if (m_z_buffer) {
m_inflate->next_in = NULL; m_inflate = new z_stream_s;
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;
int bits = (flags & wxZLIB_NO_HEADER) ? -MAX_WBITS : MAX_WBITS;
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->next_out = (unsigned char *)buffer;
m_inflate->avail_out = size; 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, m_z_size);
m_parent_i_stream->Read(m_z_buffer, wxMin(m_z_size, size));
m_inflate->next_in = m_z_buffer; m_inflate->next_in = m_z_buffer;
m_inflate->avail_in = m_parent_i_stream->LastRead(); m_inflate->avail_in = m_parent_i_stream->LastRead();
wxStreamError err = m_parent_i_stream->GetLastError(); if (m_inflate->avail_in == 0) {
if ( err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF) if (m_parent_i_stream->Eof())
{ wxLogError(_("Can't read inflate stream: unexpected EOF in underlying stream."));
m_lasterror = err; m_lasterror = wxSTREAM_READ_ERROR;
return 0; // failed to read anything break;
}
if ( m_inflate->avail_in == 0 )
{
// EOF
m_lasterror = wxSTREAM_EOF;
break;
} }
} }
err = inflate(m_inflate, Z_FINISH); err = inflate(m_inflate, Z_NO_FLUSH);
if (err == Z_STREAM_END)
return (size - m_inflate->avail_out);
} }
return size-m_inflate->avail_out; 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;
}
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;
}
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 = NULL;
m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE];
m_deflate = new z_stream_s; m_z_size = ZSTREAM_BUFFER_SIZE;
m_pos = 0;
m_deflate->zalloc = (alloc_func)0;
m_deflate->zfree = (free_func)0;
m_deflate->opaque = (voidpf)0;
if ( level == -1 ) if ( level == -1 )
{ {
level = Z_DEFAULT_COMPRESSION; level = Z_DEFAULT_COMPRESSION;
} }
else else
{ {
wxASSERT_MSG(level >= 0 && level <= 9, wxT("wxZlibOutputStream compression level must be between 0 and 9!")); wxASSERT_MSG(level >= 0 && level <= 9, wxT("wxZlibOutputStream compression level must be between 0 and 9!"));
} }
err = deflateInit(m_deflate, level); if (m_z_buffer) {
if (err != Z_OK) { m_deflate = new z_stream_s;
deflateEnd(m_deflate);
return; 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;
if (deflateInit2(m_deflate, level, Z_DEFLATED, bits,
8, Z_DEFAULT_STRATEGY) == Z_OK)
return;
}
} }
m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE]; wxLogError(_("Can't initialize zlib deflate stream."));
m_z_size = ZSTREAM_BUFFER_SIZE; m_lasterror = wxSTREAM_WRITE_ERROR;
m_deflate->avail_in = 0;
m_deflate->next_out = m_z_buffer;
m_deflate->avail_out = m_z_size;
} }
wxZlibOutputStream::~wxZlibOutputStream() wxZlibOutputStream::~wxZlibOutputStream()
{ {
int err; if (m_deflate && m_z_buffer)
DoFlush(true);
Sync();
err = deflate(m_deflate, Z_FINISH);
if (err != Z_STREAM_END)
{
wxLogDebug( wxT("wxZlibOutputStream: an error occured while closing the stream.\n") );
return;
}
deflateEnd(m_deflate); deflateEnd(m_deflate);
delete m_deflate; delete m_deflate;
delete[] m_z_buffer; delete[] m_z_buffer;
} }
void wxZlibOutputStream::Sync() void wxZlibOutputStream::DoFlush(bool final)
{ {
int err; wxASSERT_MSG(m_deflate && m_z_buffer, wxT("Deflate stream not open"));
m_parent_o_stream->Write(m_z_buffer, m_z_size-m_deflate->avail_out); if (!m_deflate || !m_z_buffer)
m_deflate->next_out = m_z_buffer; m_lasterror = wxSTREAM_WRITE_ERROR;
m_deflate->avail_out = m_z_size; if (!IsOk())
err = deflate(m_deflate, Z_FULL_FLUSH);
if (err != Z_OK) {
return; return;
}
// Fixed by "Stefan Csomor" <csomor@advancedconcepts.ch> int err = Z_OK;
while( m_deflate->avail_out == 0 ) bool done = false;
{
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
m_parent_o_stream->Write(m_z_buffer, m_z_size-m_deflate->avail_out); while (err == Z_OK || err == Z_STREAM_END) {
m_deflate->next_out = m_z_buffer; size_t len = m_z_size - m_deflate->avail_out;
m_deflate->avail_out = m_z_size; 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->next_in = (unsigned char *)buffer;
m_deflate->avail_in = size; 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) { if (m_deflate->avail_out == 0) {
m_parent_o_stream->Write(m_z_buffer, m_z_size); m_parent_o_stream->Write(m_z_buffer, m_z_size);
if ( !*m_parent_o_stream ) if (m_parent_o_stream->LastWrite() != m_z_size) {
return (size - m_deflate->avail_in); m_lasterror = wxSTREAM_WRITE_ERROR;
wxLogDebug(wxT("wxZlibOutputStream: Error writing to underlying stream"));
break;
}
m_deflate->next_out = m_z_buffer; m_deflate->next_out = m_z_buffer;
m_deflate->avail_out = m_z_size; m_deflate->avail_out = m_z_size;
} }
err = deflate(m_deflate, Z_NO_FLUSH); 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;
} }