zipstrm.cpp
来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 2,276 行 · 第 1/5 页
CPP
2,276 行
/////////////////////////////////////////////////////////////////////////////
// Name: zipstrm.cpp
// Purpose: Streams for Zip files
// Author: Mike Wetherell
// RCS-ID: $Id: zipstrm.cpp,v 1.31.2.4 2006/01/18 16:32:47 JS Exp $
// Copyright: (c) Mike Wetherell
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "zipstrm.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#ifndef WX_PRECOMP
#include "wx/defs.h"
#endif
#if wxUSE_ZLIB && wxUSE_STREAMS && wxUSE_ZIPSTREAM
#include "wx/zipstrm.h"
#include "wx/log.h"
#include "wx/intl.h"
#include "wx/datstrm.h"
#include "wx/zstream.h"
#include "wx/mstream.h"
#include "wx/utils.h"
#include "wx/buffer.h"
#include "wx/ptr_scpd.h"
#include "wx/wfstream.h"
#include "zlib.h"
// value for the 'version needed to extract' field (20 means 2.0)
enum {
VERSION_NEEDED_TO_EXTRACT = 20
};
// signatures for the various records (PKxx)
enum {
CENTRAL_MAGIC = 0x02014b50, // central directory record
LOCAL_MAGIC = 0x04034b50, // local header
END_MAGIC = 0x06054b50, // end of central directory record
SUMS_MAGIC = 0x08074b50 // data descriptor (info-zip)
};
// unix file attributes. zip stores them in the high 16 bits of the
// 'external attributes' field, hence the extra zeros.
enum {
wxZIP_S_IFMT = 0xF0000000,
wxZIP_S_IFDIR = 0x40000000,
wxZIP_S_IFREG = 0x80000000
};
// minimum sizes for the various records
enum {
CENTRAL_SIZE = 46,
LOCAL_SIZE = 30,
END_SIZE = 22,
SUMS_SIZE = 12
};
// The number of bytes that must be written to an wxZipOutputStream before
// a zip entry is created. The purpose of this latency is so that
// OpenCompressor() can see a little data before deciding which compressor
// it should use.
enum {
OUTPUT_LATENCY = 4096
};
// Some offsets into the local header
enum {
SUMS_OFFSET = 14
};
IMPLEMENT_DYNAMIC_CLASS(wxZipEntry, wxArchiveEntry)
IMPLEMENT_DYNAMIC_CLASS(wxZipClassFactory, wxArchiveClassFactory)
//FORCE_LINK_ME(zipstrm)
int _wx_link_dummy_func_zipstrm();
int _wx_link_dummy_func_zipstrm()
{
return 1;
}
/////////////////////////////////////////////////////////////////////////////
// Helpers
// read a string of a given length
//
static wxString ReadString(wxInputStream& stream, wxUint16 len, wxMBConv& conv)
{
#if wxUSE_UNICODE
wxCharBuffer buf(len);
stream.Read(buf.data(), len);
wxString str(buf, conv);
#else
wxString str;
(void)conv;
{
wxStringBuffer buf(str, len);
stream.Read(buf, len);
}
#endif
return str;
}
// Decode a little endian wxUint32 number from a character array
//
static inline wxUint32 CrackUint32(const char *m)
{
const unsigned char *n = (const unsigned char*)m;
return (n[3] << 24) | (n[2] << 16) | (n[1] << 8) | n[0];
}
// Temporarily lower the logging level in debug mode to avoid a warning
// from SeekI about seeking on a stream with data written back to it.
//
static wxFileOffset QuietSeek(wxInputStream& stream, wxFileOffset pos)
{
#ifdef __WXDEBUG__
wxLogLevel level = wxLog::GetLogLevel();
wxLog::SetLogLevel(wxLOG_Debug - 1);
wxFileOffset result = stream.SeekI(pos);
wxLog::SetLogLevel(level);
return result;
#else
return stream.SeekI(pos);
#endif
}
/////////////////////////////////////////////////////////////////////////////
// Stored input stream
// Trival decompressor for files which are 'stored' in the zip file.
class wxStoredInputStream : public wxFilterInputStream
{
public:
wxStoredInputStream(wxInputStream& stream);
void Open(wxFileOffset len) { Close(); m_len = len; }
void Close() { m_pos = 0; m_lasterror = wxSTREAM_NO_ERROR; }
virtual char Peek() { return wxInputStream::Peek(); }
virtual wxFileOffset GetLength() const { return m_len; }
protected:
virtual size_t OnSysRead(void *buffer, size_t size);
virtual wxFileOffset OnSysTell() const { return m_pos; }
private:
wxFileOffset m_pos;
wxFileOffset m_len;
DECLARE_NO_COPY_CLASS(wxStoredInputStream)
};
wxStoredInputStream::wxStoredInputStream(wxInputStream& stream)
: wxFilterInputStream(stream),
m_pos(0),
m_len(0)
{
}
size_t wxStoredInputStream::OnSysRead(void *buffer, size_t size)
{
size_t count = wx_truncate_cast(size_t,
wxMin(size + wxFileOffset(0), m_len - m_pos + size_t(0)));
count = m_parent_i_stream->Read(buffer, count).LastRead();
m_pos += count;
if (m_pos == m_len)
m_lasterror = wxSTREAM_EOF;
else if (!*m_parent_i_stream)
m_lasterror = wxSTREAM_READ_ERROR;
return count;
}
/////////////////////////////////////////////////////////////////////////////
// Stored output stream
// Trival compressor for files which are 'stored' in the zip file.
class wxStoredOutputStream : public wxFilterOutputStream
{
public:
wxStoredOutputStream(wxOutputStream& stream) :
wxFilterOutputStream(stream), m_pos(0) { }
bool Close() {
m_pos = 0;
m_lasterror = wxSTREAM_NO_ERROR;
return true;
}
protected:
virtual size_t OnSysWrite(const void *buffer, size_t size);
virtual wxFileOffset OnSysTell() const { return m_pos; }
private:
wxFileOffset m_pos;
DECLARE_NO_COPY_CLASS(wxStoredOutputStream)
};
size_t wxStoredOutputStream::OnSysWrite(const void *buffer, size_t size)
{
if (!IsOk() || !size)
return 0;
size_t count = m_parent_o_stream->Write(buffer, size).LastWrite();
if (count != size)
m_lasterror = wxSTREAM_WRITE_ERROR;
m_pos += count;
return count;
}
/////////////////////////////////////////////////////////////////////////////
// wxRawInputStream
//
// Used to handle the unusal case of raw copying an entry of unknown
// length. This can only happen when the zip being copied from is being
// read from a non-seekable stream, and also was original written to a
// non-seekable stream.
//
// In this case there's no option but to decompress the stream to find
// it's length, but we can still write the raw compressed data to avoid the
// compression overhead (which is the greater one).
//
// Usage is like this:
// m_rawin = new wxRawInputStream(*m_parent_i_stream);
// m_decomp = m_rawin->Open(OpenDecompressor(m_rawin->GetTee()));
//
// The wxRawInputStream owns a wxTeeInputStream object, the role of which
// is something like the unix 'tee' command; it is a transparent filter, but
// allows the data read to be read a second time via an extra method 'GetData'.
//
// The wxRawInputStream then draws data through the tee using a decompressor
// then instead of returning the decompressed data, retuns the raw data
// from wxTeeInputStream::GetData().
class wxTeeInputStream : public wxFilterInputStream
{
public:
wxTeeInputStream(wxInputStream& stream);
size_t GetCount() const { return m_end - m_start; }
size_t GetData(char *buffer, size_t size);
void Open();
bool Final();
wxInputStream& Read(void *buffer, size_t size);
protected:
virtual size_t OnSysRead(void *buffer, size_t size);
virtual wxFileOffset OnSysTell() const { return m_pos; }
private:
wxFileOffset m_pos;
wxMemoryBuffer m_buf;
size_t m_start;
size_t m_end;
DECLARE_NO_COPY_CLASS(wxTeeInputStream)
};
wxTeeInputStream::wxTeeInputStream(wxInputStream& stream)
: wxFilterInputStream(stream),
m_pos(0), m_buf(8192), m_start(0), m_end(0)
{
}
void wxTeeInputStream::Open()
{
m_pos = m_start = m_end = 0;
m_lasterror = wxSTREAM_NO_ERROR;
}
bool wxTeeInputStream::Final()
{
bool final = m_end == m_buf.GetDataLen();
m_end = m_buf.GetDataLen();
return final;
}
wxInputStream& wxTeeInputStream::Read(void *buffer, size_t size)
{
size_t count = wxInputStream::Read(buffer, size).LastRead();
m_end = m_buf.GetDataLen();
m_buf.AppendData(buffer, count);
return *this;
}
size_t wxTeeInputStream::OnSysRead(void *buffer, size_t size)
{
size_t count = m_parent_i_stream->Read(buffer, size).LastRead();
m_lasterror = m_parent_i_stream->GetLastError();
return count;
}
size_t wxTeeInputStream::GetData(char *buffer, size_t size)
{
if (m_wbacksize) {
size_t len = m_buf.GetDataLen();
len = len > m_wbacksize ? len - m_wbacksize : 0;
m_buf.SetDataLen(len);
if (m_end > len) {
wxFAIL; // we've already returned data that's now being ungot
m_end = len;
}
m_parent_i_stream->Reset();
m_parent_i_stream->Ungetch(m_wback, m_wbacksize);
free(m_wback);
m_wback = NULL;
m_wbacksize = 0;
m_wbackcur = 0;
}
if (size > GetCount())
size = GetCount();
if (size) {
memcpy(buffer, m_buf + m_start, size);
m_start += size;
wxASSERT(m_start <= m_end);
}
if (m_start == m_end && m_start > 0 && m_buf.GetDataLen() > 0) {
size_t len = m_buf.GetDataLen();
char *buf = (char*)m_buf.GetWriteBuf(len);
len -= m_end;
memmove(buf, buf + m_end, len);
m_buf.UngetWriteBuf(len);
m_start = m_end = 0;
}
return size;
}
class wxRawInputStream : public wxFilterInputStream
{
public:
wxRawInputStream(wxInputStream& stream);
virtual ~wxRawInputStream() { delete m_tee; }
wxInputStream* Open(wxInputStream *decomp);
wxInputStream& GetTee() const { return *m_tee; }
protected:
virtual size_t OnSysRead(void *buffer, size_t size);
virtual wxFileOffset OnSysTell() const { return m_pos; }
private:
wxFileOffset m_pos;
wxTeeInputStream *m_tee;
enum { BUFSIZE = 8192 };
wxCharBuffer m_dummy;
DECLARE_NO_COPY_CLASS(wxRawInputStream)
};
wxRawInputStream::wxRawInputStream(wxInputStream& stream)
: wxFilterInputStream(stream),
m_pos(0),
m_tee(new wxTeeInputStream(stream)),
m_dummy(BUFSIZE)
{
}
wxInputStream *wxRawInputStream::Open(wxInputStream *decomp)
{
if (decomp) {
m_parent_i_stream = decomp;
m_pos = 0;
m_lasterror = wxSTREAM_NO_ERROR;
m_tee->Open();
return this;
} else {
return NULL;
}
}
size_t wxRawInputStream::OnSysRead(void *buffer, size_t size)
{
char *buf = (char*)buffer;
size_t count = 0;
while (count < size && IsOk())
{
while (m_parent_i_stream->IsOk() && m_tee->GetCount() == 0)
m_parent_i_stream->Read(m_dummy.data(), BUFSIZE);
size_t n = m_tee->GetData(buf + count, size - count);
count += n;
if (n == 0 && m_tee->Final())
m_lasterror = m_parent_i_stream->GetLastError();
}
m_pos += count;
return count;
}
/////////////////////////////////////////////////////////////////////////////
// Zlib streams than can be reused without recreating.
class wxZlibOutputStream2 : public wxZlibOutputStream
{
public:
wxZlibOutputStream2(wxOutputStream& stream, int level) :
wxZlibOutputStream(stream, level, wxZLIB_NO_HEADER) { }
bool Open(wxOutputStream& stream);
bool Close() { DoFlush(true); m_pos = wxInvalidOffset; return IsOk(); }
};
bool wxZlibOutputStream2::Open(wxOutputStream& stream)
{
wxCHECK(m_pos == wxInvalidOffset, false);
m_deflate->next_out = m_z_buffer;
m_deflate->avail_out = m_z_size;
m_pos = 0;
m_lasterror = wxSTREAM_NO_ERROR;
m_parent_o_stream = &stream;
if (deflateReset(m_deflate) != Z_OK) {
wxLogError(_("can't re-initialize zlib deflate stream"));
m_lasterror = wxSTREAM_WRITE_ERROR;
return false;
}
return true;
}
class wxZlibInputStream2 : public wxZlibInputStream
{
public:
wxZlibInputStream2(wxInputStream& stream) :
wxZlibInputStream(stream, wxZLIB_NO_HEADER) { }
bool Open(wxInputStream& stream);
};
bool wxZlibInputStream2::Open(wxInputStream& stream)
{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?