/////////////////////////////////////////////////////////////////////////////
-// Name: zipstrm.cpp
+// Name: src/common/zipstrm.cpp
// Purpose: Streams for Zip files
// Author: Mike Wetherell
// RCS-ID: $Id$
// 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
+ #pragma hdrstop
#endif
+#if wxUSE_ZIPSTREAM
+
+#include "wx/zipstrm.h"
+
#ifndef WX_PRECOMP
- #include "wx/defs.h"
+ #include "wx/hashmap.h"
+ #include "wx/intl.h"
+ #include "wx/log.h"
+ #include "wx/utils.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/scopedptr.h"
#include "wx/wfstream.h"
-#include "wx/html/forcelnk.h"
#include "zlib.h"
// value for the 'version needed to extract' field (20 means 2.0)
IMPLEMENT_DYNAMIC_CLASS(wxZipEntry, wxArchiveEntry)
IMPLEMENT_DYNAMIC_CLASS(wxZipClassFactory, wxArchiveClassFactory)
-FORCE_LINK_ME(zipstrm)
-
/////////////////////////////////////////////////////////////////////////////
// Helpers
//
static wxString ReadString(wxInputStream& stream, wxUint16 len, wxMBConv& conv)
{
+ if (len == 0)
+ return wxEmptyString;
+
#if wxUSE_UNICODE
wxCharBuffer buf(len);
stream.Read(buf.data(), len);
return (n[3] << 24) | (n[2] << 16) | (n[1] << 8) | n[0];
}
+// Decode a little endian wxUint16 number from a character array
+//
+static inline wxUint16 CrackUint16(const char *m)
+{
+ const unsigned char *n = (const unsigned char*)m;
+ return (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__
+#if wxUSE_LOG
wxLogLevel level = wxLog::GetLogLevel();
wxLog::SetLogLevel(wxLOG_Debug - 1);
wxFileOffset result = stream.SeekI(pos);
}
+/////////////////////////////////////////////////////////////////////////////
+// Class factory
+
+static wxZipClassFactory g_wxZipClassFactory;
+
+wxZipClassFactory::wxZipClassFactory()
+{
+ if (this == &g_wxZipClassFactory)
+ PushFront();
+}
+
+const wxChar * const *
+wxZipClassFactory::GetProtocols(wxStreamProtocolType type) const
+{
+ static const wxChar *protocols[] = { _T("zip"), NULL };
+ static const wxChar *mimetypes[] = { _T("application/zip"), NULL };
+ static const wxChar *fileexts[] = { _T(".zip"), _T(".htb"), NULL };
+ static const wxChar *empty[] = { NULL };
+
+ switch (type) {
+ case wxSTREAM_PROTOCOL: return protocols;
+ case wxSTREAM_MIMETYPE: return mimetypes;
+ case wxSTREAM_FILEEXT: return fileexts;
+ default: return empty;
+ }
+}
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Read a zip header
+
+class wxZipHeader
+{
+public:
+ wxZipHeader(wxInputStream& stream, size_t size);
+
+ inline wxUint8 Read8();
+ inline wxUint16 Read16();
+ inline wxUint32 Read32();
+
+ const char *GetData() const { return m_data; }
+ size_t GetSize() const { return m_size; }
+ operator bool() const { return m_ok; }
+
+ size_t Seek(size_t pos) { m_pos = pos; return m_pos; }
+ size_t Skip(size_t size) { m_pos += size; return m_pos; }
+
+ wxZipHeader& operator>>(wxUint8& n) { n = Read8(); return *this; }
+ wxZipHeader& operator>>(wxUint16& n) { n = Read16(); return *this; }
+ wxZipHeader& operator>>(wxUint32& n) { n = Read32(); return *this; }
+
+private:
+ char m_data[64];
+ size_t m_size;
+ size_t m_pos;
+ bool m_ok;
+};
+
+wxZipHeader::wxZipHeader(wxInputStream& stream, size_t size)
+ : m_size(0),
+ m_pos(0),
+ m_ok(false)
+{
+ wxCHECK_RET(size <= sizeof(m_data), _T("buffer too small"));
+ m_size = stream.Read(m_data, size).LastRead();
+ m_ok = m_size == size;
+}
+
+inline wxUint8 wxZipHeader::Read8()
+{
+ wxASSERT(m_pos < m_size);
+ return m_data[m_pos++];
+}
+
+inline wxUint16 wxZipHeader::Read16()
+{
+ wxASSERT(m_pos + 2 <= m_size);
+ wxUint16 n = CrackUint16(m_data + m_pos);
+ m_pos += 2;
+ return n;
+}
+
+inline wxUint32 wxZipHeader::Read32()
+{
+ wxASSERT(m_pos + 4 <= m_size);
+ wxUint32 n = CrackUint32(m_data + m_pos);
+ m_pos += 4;
+ return n;
+}
+
+
/////////////////////////////////////////////////////////////////////////////
// Stored input stream
// Trival decompressor for files which are 'stored' in the zip file.
void Close() { m_pos = 0; m_lasterror = wxSTREAM_NO_ERROR; }
virtual char Peek() { return wxInputStream::Peek(); }
- virtual size_t GetSize() const { return m_len; }
+ virtual wxFileOffset GetLength() const { return m_len; }
protected:
virtual size_t OnSysRead(void *buffer, size_t size);
wxFileOffset m_pos;
wxFileOffset m_len;
- DECLARE_NO_COPY_CLASS(wxStoredInputStream)
+ wxDECLARE_NO_COPY_CLASS(wxStoredInputStream);
};
wxStoredInputStream::wxStoredInputStream(wxInputStream& stream)
size_t wxStoredInputStream::OnSysRead(void *buffer, size_t size)
{
- size_t count = wxMin(size, m_len - m_pos + (size_t)0);
+ 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;
+ if (count < size)
+ m_lasterror = m_pos == m_len ? wxSTREAM_EOF : wxSTREAM_READ_ERROR;
return count;
}
private:
wxFileOffset m_pos;
- DECLARE_NO_COPY_CLASS(wxStoredOutputStream)
+ wxDECLARE_NO_COPY_CLASS(wxStoredOutputStream);
};
size_t wxStoredOutputStream::OnSysWrite(const void *buffer, size_t size)
size_t m_start;
size_t m_end;
- DECLARE_NO_COPY_CLASS(wxTeeInputStream)
+ wxDECLARE_NO_COPY_CLASS(wxTeeInputStream);
};
wxTeeInputStream::wxTeeInputStream(wxInputStream& stream)
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();
+ if (count < size)
+ m_lasterror = m_parent_i_stream->GetLastError();
return count;
}
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;
enum { BUFSIZE = 8192 };
wxCharBuffer m_dummy;
- DECLARE_NO_COPY_CLASS(wxRawInputStream)
+ wxDECLARE_NO_COPY_CLASS(wxRawInputStream);
};
wxRawInputStream::wxRawInputStream(wxInputStream& stream)
{
public:
wxZipMemory() : m_data(NULL), m_size(0), m_capacity(0), m_ref(1) { }
- ~wxZipMemory() { delete m_data; }
wxZipMemory *AddRef() { m_ref++; return this; }
void Release() { if (--m_ref == 0) delete this; }
wxZipMemory *Unique(size_t size);
private:
+ ~wxZipMemory() { delete [] m_data; }
char *m_data;
size_t m_size;
size_t m_capacity;
int m_ref;
+
+ wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipMemory)
};
wxZipMemory *wxZipMemory::Unique(size_t size)
}
if (zm->m_capacity < size) {
- delete zm->m_data;
+ delete [] zm->m_data;
zm->m_data = new char[size];
zm->m_capacity = size;
}
// Collection of weak references to entries
WX_DECLARE_HASH_MAP(long, wxZipEntry*, wxIntegerHash,
- wxIntegerEqual, _wxOffsetZipEntryMap);
+ wxIntegerEqual, wxOffsetZipEntryMap_);
class wxZipWeakLinks
{
public:
wxZipWeakLinks() : m_ref(1) { }
- ~wxZipWeakLinks() { wxASSERT(IsEmpty()); }
void Release(const wxZipInputStream* WXUNUSED(x))
{ if (--m_ref == 0) delete this; }
{ RemoveEntry(key); if (--m_ref == 0) delete this; }
wxZipWeakLinks *AddEntry(wxZipEntry *entry, wxFileOffset key);
- void RemoveEntry(wxFileOffset key) { m_entries.erase(key); }
+ void RemoveEntry(wxFileOffset key)
+ { m_entries.erase(wx_truncate_cast(key_type, key)); }
wxZipEntry *GetEntry(wxFileOffset key) const;
bool IsEmpty() const { return m_entries.empty(); }
private:
+ ~wxZipWeakLinks() { wxASSERT(IsEmpty()); }
+
+ typedef wxOffsetZipEntryMap_::key_type key_type;
int m_ref;
- _wxOffsetZipEntryMap m_entries;
+ wxOffsetZipEntryMap_ m_entries;
+
+ wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipWeakLinks)
};
wxZipWeakLinks *wxZipWeakLinks::AddEntry(wxZipEntry *entry, wxFileOffset key)
{
- m_entries[key] = entry;
+ m_entries[wx_truncate_cast(key_type, key)] = entry;
m_ref++;
return this;
}
wxZipEntry *wxZipWeakLinks::GetEntry(wxFileOffset key) const
{
- _wxOffsetZipEntryMap::const_iterator it = m_entries.find(key);
+ wxOffsetZipEntryMap_::const_iterator it =
+ m_entries.find(wx_truncate_cast(key_type, key));
return it != m_entries.end() ? it->second : NULL;
}
const wxString& name /*=wxEmptyString*/,
const wxDateTime& dt /*=wxDateTime::Now()*/,
wxFileOffset size /*=wxInvalidOffset*/)
- :
+ :
m_SystemMadeBy(wxZIP_SYSTEM_MSDOS),
m_VersionMadeBy(wxMAJOR_VERSION * 10 + wxMINOR_VERSION),
m_VersionNeeded(VERSION_NEEDED_TO_EXTRACT),
}
wxZipEntry::wxZipEntry(const wxZipEntry& e)
- : m_SystemMadeBy(e.m_SystemMadeBy),
+ : wxArchiveEntry(e),
+ m_SystemMadeBy(e.m_SystemMadeBy),
m_VersionMadeBy(e.m_VersionMadeBy),
m_VersionNeeded(e.m_VersionNeeded),
m_Flags(e.m_Flags),
m_ExternalAttributes(e.m_ExternalAttributes),
m_Extra(AddRef(e.m_Extra)),
m_LocalExtra(AddRef(e.m_LocalExtra)),
- m_zipnotifier(e.m_zipnotifier),
+ m_zipnotifier(NULL),
m_backlink(NULL)
{
}
m_ExternalAttributes = e.m_ExternalAttributes;
Copy(m_Extra, e.m_Extra);
Copy(m_LocalExtra, e.m_LocalExtra);
- m_zipnotifier = e.m_zipnotifier;
+ m_zipnotifier = NULL;
if (m_backlink) {
m_backlink->Release(m_Key);
m_backlink = NULL;
{
bool isDir = IsDir() && !m_Name.empty();
+ // optimisations for common (and easy) cases
switch (wxFileName::GetFormat(format)) {
case wxPATH_DOS:
{
wxString name(isDir ? m_Name + _T("\\") : m_Name);
- for (size_t i = name.length() - 1; i > 0; --i)
+ for (size_t i = 0; i < name.length(); i++)
if (name[i] == _T('/'))
name[i] = _T('\\');
return name;
int mode = GetMode();
bool wasUnix = IsMadeByUnix();
- m_SystemMadeBy = system;
+ m_SystemMadeBy = (wxUint8)system;
if (!wasUnix && IsMadeByUnix()) {
SetIsDir(IsDir());
wxUint16 nameLen, extraLen;
wxUint32 compressedSize, size, crc;
- wxDataInputStream ds(stream);
+ wxZipHeader ds(stream, LOCAL_SIZE - 4);
+ if (!ds)
+ return 0;
ds >> m_VersionNeeded >> m_Flags >> m_Method;
SetDateTime(wxDateTime().SetFromDOS(ds.Read32()));
m_Size = size;
SetName(ReadString(stream, nameLen, conv), wxPATH_UNIX);
+ if (stream.LastRead() != nameLen + 0u)
+ return 0;
if (extraLen || GetLocalExtraLen()) {
Unique(m_LocalExtra, extraLen);
- if (extraLen)
+ if (extraLen) {
stream.Read(m_LocalExtra->GetData(), extraLen);
+ if (stream.LastRead() != extraLen + 0u)
+ return 0;
+ }
}
return LOCAL_SIZE + nameLen + extraLen;
size_t wxZipEntry::WriteLocal(wxOutputStream& stream, wxMBConv& conv) const
{
wxString unixName = GetName(wxPATH_UNIX);
- const wxWX2MBbuf name_buf = conv.cWX2MB(unixName);
+ const wxWX2MBbuf name_buf = unixName.mb_str(conv);
const char *name = name_buf;
if (!name) name = "";
- wxUint16 nameLen = strlen(name);
+ wxUint16 nameLen = wx_truncate_cast(wxUint16, strlen(name));
wxDataOutputStream ds(stream);
ds << m_VersionNeeded << m_Flags << m_Method;
ds.Write32(GetDateTime().GetAsDOS());
-
+
ds.Write32(m_Crc);
- ds.Write32(m_CompressedSize != wxInvalidOffset ? m_CompressedSize : 0);
- ds.Write32(m_Size != wxInvalidOffset ? m_Size : 0);
+ ds.Write32(m_CompressedSize != wxInvalidOffset ?
+ wx_truncate_cast(wxUint32, m_CompressedSize) : 0);
+ ds.Write32(m_Size != wxInvalidOffset ?
+ wx_truncate_cast(wxUint32, m_Size) : 0);
ds << nameLen;
- wxUint16 extraLen = GetLocalExtraLen();
+ wxUint16 extraLen = wx_truncate_cast(wxUint16, GetLocalExtraLen());
ds.Write16(extraLen);
stream.Write(name, nameLen);
{
wxUint16 nameLen, extraLen, commentLen;
- wxDataInputStream ds(stream);
+ wxZipHeader ds(stream, CENTRAL_SIZE - 4);
+ if (!ds)
+ return 0;
ds >> m_VersionMadeBy >> m_SystemMadeBy;
ds >> nameLen >> extraLen >> commentLen
>> m_DiskStart >> m_InternalAttributes >> m_ExternalAttributes;
SetOffset(ds.Read32());
-
+
SetName(ReadString(stream, nameLen, conv), wxPATH_UNIX);
+ if (stream.LastRead() != nameLen + 0u)
+ return 0;
if (extraLen || GetExtraLen()) {
Unique(m_Extra, extraLen);
- if (extraLen)
+ if (extraLen) {
stream.Read(m_Extra->GetData(), extraLen);
+ if (stream.LastRead() != extraLen + 0u)
+ return 0;
+ }
}
- if (commentLen)
+ if (commentLen) {
m_Comment = ReadString(stream, commentLen, conv);
- else
+ if (stream.LastRead() != commentLen + 0u)
+ return 0;
+ } else {
m_Comment.clear();
+ }
return CENTRAL_SIZE + nameLen + extraLen + commentLen;
}
size_t wxZipEntry::WriteCentral(wxOutputStream& stream, wxMBConv& conv) const
{
wxString unixName = GetName(wxPATH_UNIX);
- const wxWX2MBbuf name_buf = conv.cWX2MB(unixName);
+ const wxWX2MBbuf name_buf = unixName.mb_str(conv);
const char *name = name_buf;
if (!name) name = "";
- wxUint16 nameLen = strlen(name);
+ wxUint16 nameLen = wx_truncate_cast(wxUint16, strlen(name));
- const wxWX2MBbuf comment_buf = conv.cWX2MB(m_Comment);
+ const wxWX2MBbuf comment_buf = m_Comment.mb_str(conv);
const char *comment = comment_buf;
if (!comment) comment = "";
- wxUint16 commentLen = strlen(comment);
+ wxUint16 commentLen = wx_truncate_cast(wxUint16, strlen(comment));
- wxUint16 extraLen = GetExtraLen();
+ wxUint16 extraLen = wx_truncate_cast(wxUint16, GetExtraLen());
wxDataOutputStream ds(stream);
ds << CENTRAL_MAGIC << m_VersionMadeBy << m_SystemMadeBy;
- ds.Write16(GetVersionNeeded());
- ds.Write16(GetFlags());
- ds.Write16(GetMethod());
+ ds.Write16(wx_truncate_cast(wxUint16, GetVersionNeeded()));
+ ds.Write16(wx_truncate_cast(wxUint16, GetFlags()));
+ ds.Write16(wx_truncate_cast(wxUint16, GetMethod()));
ds.Write32(GetDateTime().GetAsDOS());
ds.Write32(GetCrc());
- ds.Write32(GetCompressedSize());
- ds.Write32(GetSize());
+ ds.Write32(wx_truncate_cast(wxUint32, GetCompressedSize()));
+ ds.Write32(wx_truncate_cast(wxUint32, GetSize()));
ds.Write16(nameLen);
ds.Write16(extraLen);
ds << commentLen << m_DiskStart << m_InternalAttributes
- << m_ExternalAttributes << (wxUint32)GetOffset();
-
+ << m_ExternalAttributes << wx_truncate_cast(wxUint32, GetOffset());
+
stream.Write(name, nameLen);
if (extraLen)
stream.Write(GetExtra(), extraLen);
//
size_t wxZipEntry::ReadDescriptor(wxInputStream& stream)
{
- wxDataInputStream ds(stream);
-
+ wxZipHeader ds(stream, SUMS_SIZE);
+ if (!ds)
+ return 0;
+
m_Crc = ds.Read32();
m_CompressedSize = ds.Read32();
m_Size = ds.Read32();
// if 1st value is the signature then this is probably an info-zip record
if (m_Crc == SUMS_MAGIC)
{
- char buf[8];
- stream.Read(buf, sizeof(buf));
- wxUint32 u1 = CrackUint32(buf);
- wxUint32 u2 = CrackUint32(buf + 4);
-
+ wxZipHeader buf(stream, 8);
+ wxUint32 u1 = buf.GetSize() >= 4 ? buf.Read32() : (wxUint32)LOCAL_MAGIC;
+ wxUint32 u2 = buf.GetSize() == 8 ? buf.Read32() : 0;
+
// look for the signature of the following record to decide which
if ((u1 == LOCAL_MAGIC || u1 == CENTRAL_MAGIC) &&
(u2 != LOCAL_MAGIC && u2 != CENTRAL_MAGIC))
{
// it's a pkzip style record after all!
- stream.Ungetch(buf, sizeof(buf));
+ if (buf.GetSize() > 0)
+ stream.Ungetch(buf.GetData(), buf.GetSize());
}
else
{
// it's an info-zip record as expected
- stream.Ungetch(buf + 4, sizeof(buf) - 4);
- m_Crc = m_CompressedSize;
+ if (buf.GetSize() > 4)
+ stream.Ungetch(buf.GetData() + 4, buf.GetSize() - 4);
+ m_Crc = wx_truncate_cast(wxUint32, m_CompressedSize);
m_CompressedSize = m_Size;
m_Size = u1;
return SUMS_SIZE + 4;
wxDataOutputStream ds(stream);
ds.Write32(crc);
- ds.Write32(compressedSize);
- ds.Write32(size);
+ ds.Write32(wx_truncate_cast(wxUint32, compressedSize));
+ ds.Write32(wx_truncate_cast(wxUint32, size));
return SUMS_SIZE;
}
wxFileOffset GetOffset() const { return m_Offset; }
wxString GetComment() const { return m_Comment; }
- void SetDiskNumber(int num) { m_DiskNumber = num; }
- void SetStartDisk(int num) { m_StartDisk = num; }
- void SetEntriesHere(int num) { m_EntriesHere = num; }
- void SetTotalEntries(int num) { m_TotalEntries = num; }
- void SetSize(wxFileOffset size) { m_Size = (wxUint32)size; }
- void SetOffset(wxFileOffset offset) { m_Offset = (wxUint32)offset; }
- void SetComment(const wxString& comment) { m_Comment = comment; }
+ void SetDiskNumber(int num)
+ { m_DiskNumber = wx_truncate_cast(wxUint16, num); }
+ void SetStartDisk(int num)
+ { m_StartDisk = wx_truncate_cast(wxUint16, num); }
+ void SetEntriesHere(int num)
+ { m_EntriesHere = wx_truncate_cast(wxUint16, num); }
+ void SetTotalEntries(int num)
+ { m_TotalEntries = wx_truncate_cast(wxUint16, num); }
+ void SetSize(wxFileOffset size)
+ { m_Size = wx_truncate_cast(wxUint32, size); }
+ void SetOffset(wxFileOffset offset)
+ { m_Offset = wx_truncate_cast(wxUint32, offset); }
+ void SetComment(const wxString& comment)
+ { m_Comment = comment; }
bool Read(wxInputStream& stream, wxMBConv& conv);
bool Write(wxOutputStream& stream, wxMBConv& conv) const;
bool wxZipEndRec::Write(wxOutputStream& stream, wxMBConv& conv) const
{
- const wxWX2MBbuf comment_buf = conv.cWX2MB(m_Comment);
+ const wxWX2MBbuf comment_buf = m_Comment.mb_str(conv);
const char *comment = comment_buf;
if (!comment) comment = "";
- wxUint16 commentLen = strlen(comment);
+ wxUint16 commentLen = (wxUint16)strlen(comment);
wxDataOutputStream ds(stream);
bool wxZipEndRec::Read(wxInputStream& stream, wxMBConv& conv)
{
- wxDataInputStream ds(stream);
+ wxZipHeader ds(stream, END_SIZE - 4);
+ if (!ds)
+ return false;
+
wxUint16 commentLen;
ds >> m_DiskNumber >> m_StartDisk >> m_EntriesHere
>> m_TotalEntries >> m_Size >> m_Offset >> commentLen;
- if (commentLen)
+ if (commentLen) {
m_Comment = ReadString(stream, commentLen, conv);
+ if (stream.LastRead() != commentLen + 0u)
+ return false;
+ }
- if (stream.IsOk())
- if (m_DiskNumber == 0 && m_StartDisk == 0 &&
- m_EntriesHere == m_TotalEntries)
- return true;
- else
- wxLogError(_("unsupported zip archive"));
+ if (m_DiskNumber != 0 || m_StartDisk != 0 ||
+ m_EntriesHere != m_TotalEntries)
+ wxLogWarning(_("assuming this is a multi-part zip concatenated"));
- return false;
+ return true;
}
{
public:
wxZipStreamLink(wxZipOutputStream *stream) : m_ref(1), m_stream(stream) { }
- ~wxZipStreamLink() { }
wxZipStreamLink *AddRef() { m_ref++; return this; }
wxZipOutputStream *GetOutputStream() const { return m_stream; }
{ m_stream = NULL; if (--m_ref == 0) delete this; }
private:
+ ~wxZipStreamLink() { }
int m_ref;
wxZipOutputStream *m_stream;
+
+ wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipStreamLink)
};
/////////////////////////////////////////////////////////////////////////////
// Input stream
-wxDECLARE_SCOPED_PTR(wxZipEntry, _wxZipEntryPtr)
-wxDEFINE_SCOPED_PTR (wxZipEntry, _wxZipEntryPtr)
+// leave the default wxZipEntryPtr free for users
+wxDECLARE_SCOPED_PTR(wxZipEntry, wxZipEntryPtr_)
+wxDEFINE_SCOPED_PTR (wxZipEntry, wxZipEntryPtr_)
// constructor
//
wxMBConv& conv /*=wxConvLocal*/)
: wxArchiveInputStream(stream, conv)
{
- m_ffile = NULL;
Init();
}
-// Compatibility constructor
+wxZipInputStream::wxZipInputStream(wxInputStream *stream,
+ wxMBConv& conv /*=wxConvLocal*/)
+ : wxArchiveInputStream(stream, conv)
+{
+ Init();
+}
+
+#if WXWIN_COMPATIBILITY_2_6 && wxUSE_FFILE
+
+// Part of the compatibility constructor, which has been made inline to
+// avoid a problem with it not being exported by mingw 3.2.3
//
-wxZipInputStream::wxZipInputStream(const wxString& archive,
- const wxString& file)
- : wxArchiveInputStream(OpenFile(archive), wxConvLocal)
+void wxZipInputStream::Init(const wxString& file)
{
// no error messages
wxLogNull nolog;
Init();
- _wxZipEntryPtr entry;
+ m_allowSeeking = true;
+ wxFFileInputStream *ffile;
+ ffile = static_cast<wxFFileInputStream*>(m_parent_i_stream);
+ wxZipEntryPtr_ entry;
- if (m_ffile->Ok()) {
+ if (ffile->Ok()) {
do {
entry.reset(GetNextEntry());
}
m_lasterror = wxSTREAM_READ_ERROR;
}
-wxInputStream& wxZipInputStream::OpenFile(const wxString& archive)
+wxInputStream* wxZipInputStream::OpenFile(const wxString& archive)
{
wxLogNull nolog;
- m_ffile = new wxFFileInputStream(archive);
- return *m_ffile;
+ return new wxFFileInputStream(archive);
}
+#endif // WXWIN_COMPATIBILITY_2_6 && wxUSE_FFILE
+
void wxZipInputStream::Init()
{
m_store = new wxStoredInputStream(*m_parent_i_stream);
m_signature = 0;
m_TotalEntries = 0;
m_lasterror = m_parent_i_stream->GetLastError();
+#if WXWIN_COMPATIBILITY_2_6
+ m_allowSeeking = false;
+#endif
}
wxZipInputStream::~wxZipInputStream()
delete m_store;
delete m_inflate;
delete m_rawin;
- delete m_ffile;
m_weaklinks->Release(this);
-
+
if (m_streamlink)
m_streamlink->Release(this);
}
else {
wxLogNull nolog;
wxFileOffset pos = m_parent_i_stream->TellI();
- // FIXME
- //if (pos != wxInvalidOffset)
- if (pos >= 0 && pos <= LONG_MAX)
+ if (pos != wxInvalidOffset)
m_offsetAdjustment = m_position = pos;
return true;
}
// Read in the end record
wxFileOffset endPos = m_parent_i_stream->TellI() - 4;
- if (!endrec.Read(*m_parent_i_stream, GetConv())) {
- if (!*m_parent_i_stream) {
- m_lasterror = wxSTREAM_READ_ERROR;
- return false;
- }
- // TODO: try this out
- wxLogWarning(_("assuming this is a multi-part zip concatenated"));
- }
+ if (!endrec.Read(*m_parent_i_stream, GetConv()))
+ return false;
m_TotalEntries = endrec.GetTotalEntries();
m_Comment = endrec.GetComment();
+ wxUint32 magic = m_TotalEntries ? CENTRAL_MAGIC : END_MAGIC;
+
// Now find the central-directory. we have the file offset of
- // the CD, so look there first.
+ // the CD, so look there first.
if (m_parent_i_stream->SeekI(endrec.GetOffset()) != wxInvalidOffset &&
- ReadSignature() == CENTRAL_MAGIC) {
- m_signature = CENTRAL_MAGIC;
+ ReadSignature() == magic) {
+ m_signature = magic;
m_position = endrec.GetOffset();
m_offsetAdjustment = 0;
return true;
}
-
+
// If it's not there, then it could be that the zip has been appended
// to a self extractor, so take the CD size (also in endrec), subtract
// it from the file offset of the end-central-directory and look there.
if (m_parent_i_stream->SeekI(endPos - endrec.GetSize())
- != wxInvalidOffset && ReadSignature() == CENTRAL_MAGIC) {
- m_signature = CENTRAL_MAGIC;
+ != wxInvalidOffset && ReadSignature() == magic) {
+ m_signature = magic;
m_position = endPos - endrec.GetSize();
m_offsetAdjustment = m_position - endrec.GetOffset();
return true;
//
bool wxZipInputStream::FindEndRecord()
{
+ if (!m_parent_i_stream->IsSeekable())
+ return false;
+
// usually it's 22 bytes in size and the last thing in the file
- {
+ {
wxLogNull nolog;
if (m_parent_i_stream->SeekI(-END_SIZE, wxFromEnd) == wxInvalidOffset)
return false;
wxFileOffset minpos = wxMax(pos - 65535L, 0);
while (pos > minpos) {
- size_t len = pos - wxMax(pos - (BUFSIZE - 3), minpos);
+ size_t len = wx_truncate_cast(size_t,
+ pos - wxMax(pos - (BUFSIZE - 3), minpos));
memcpy(buf.data() + len, buf, 3);
pos -= len;
-
+
if (m_parent_i_stream->SeekI(pos, wxFromStart) == wxInvalidOffset ||
m_parent_i_stream->Read(buf.data(), len).LastRead() != len)
return false;
if (!IsOk())
return NULL;
- _wxZipEntryPtr entry(new wxZipEntry(m_entry));
+ wxZipEntryPtr_ entry(new wxZipEntry(m_entry));
entry->m_backlink = m_weaklinks->AddEntry(entry.get(), entry->GetKey());
return entry.release();
}
if (QuietSeek(*m_parent_i_stream, m_position + 4) == wxInvalidOffset)
return wxSTREAM_READ_ERROR;
- m_position += m_entry.ReadCentral(*m_parent_i_stream, GetConv());
- if (m_parent_i_stream->GetLastError() == wxSTREAM_READ_ERROR) {
+ size_t size = m_entry.ReadCentral(*m_parent_i_stream, GetConv());
+ if (!size) {
m_signature = 0;
return wxSTREAM_READ_ERROR;
}
+ m_position += size;
m_signature = ReadSignature();
if (m_offsetAdjustment)
while (m_signature == CENTRAL_MAGIC) {
if (m_weaklinks->IsEmpty() && m_streamlink == NULL)
return wxSTREAM_EOF;
-
- m_position += m_entry.ReadCentral(*m_parent_i_stream, GetConv());
+
+ size_t size = m_entry.ReadCentral(*m_parent_i_stream, GetConv());
+ m_position += size;
m_signature = 0;
- if (m_parent_i_stream->GetLastError() == wxSTREAM_READ_ERROR)
+ if (!size)
return wxSTREAM_READ_ERROR;
wxZipEntry *entry = m_weaklinks->GetEntry(m_entry.GetOffset());
}
return wxSTREAM_EOF;
}
-
- if (m_signature != LOCAL_MAGIC) {
- wxLogError(_("error reading zip local header"));
- return wxSTREAM_READ_ERROR;
- }
- m_headerSize = m_entry.ReadLocal(*m_parent_i_stream, GetConv());
- m_signature = 0;
- m_entry.SetOffset(m_position);
- m_entry.SetKey(m_position);
+ if (m_signature == LOCAL_MAGIC) {
+ m_headerSize = m_entry.ReadLocal(*m_parent_i_stream, GetConv());
+ m_signature = 0;
+ m_entry.SetOffset(m_position);
+ m_entry.SetKey(m_position);
- if (m_parent_i_stream->GetLastError() == wxSTREAM_READ_ERROR) {
- return wxSTREAM_READ_ERROR;
- } else {
- m_TotalEntries++;
- return wxSTREAM_NO_ERROR;
+ if (m_headerSize) {
+ m_TotalEntries++;
+ return wxSTREAM_NO_ERROR;
+ }
}
+
+ wxLogError(_("error reading zip local header"));
+ return wxSTREAM_READ_ERROR;
}
wxUint32 wxZipInputStream::ReadSignature()
return false;
if (m_lasterror == wxSTREAM_READ_ERROR)
return false;
- wxCHECK(!IsOpened(), false);
+ if (IsOpened())
+ CloseEntry();
m_raw = raw;
// can only open the current entry on a non-seekable stream
wxCHECK(m_parentSeekable, false);
}
-
+
m_lasterror = wxSTREAM_READ_ERROR;
-
+
if (entry)
m_entry = *entry;
if (m_parentSeekable || AtHeader()) {
m_headerSize = m_entry.ReadLocal(*m_parent_i_stream, GetConv());
- if (m_parentSeekable) {
+ if (m_headerSize && m_parentSeekable) {
wxZipEntry *ref = m_weaklinks->GetEntry(m_entry.GetKey());
if (ref) {
Copy(ref->m_LocalExtra, m_entry.m_LocalExtra);
}
}
- m_lasterror = m_parent_i_stream->GetLastError();
+ if (m_headerSize)
+ m_lasterror = wxSTREAM_NO_ERROR;
return IsOk();
}
size_t count = m_decomp->Read(buffer, size).LastRead();
if (!m_raw)
m_crcAccumulator = crc32(m_crcAccumulator, (Byte*)buffer, count);
- m_lasterror = m_decomp->GetLastError();
+ if (count < size)
+ m_lasterror = m_decomp->GetLastError();
if (Eof()) {
if ((m_entry.GetFlags() & wxZIP_SUMS_FOLLOW) != 0) {
if (!m_raw) {
m_lasterror = wxSTREAM_READ_ERROR;
- if (m_parent_i_stream->IsOk()) {
- if (m_entry.GetSize() != TellI())
- wxLogError(_("reading zip stream (entry %s): bad length"),
- m_entry.GetName().c_str());
- else if (m_crcAccumulator != m_entry.GetCrc())
- wxLogError(_("reading zip stream (entry %s): bad crc"),
- m_entry.GetName().c_str());
- else
- m_lasterror = wxSTREAM_EOF;
- }
+ if (m_entry.GetSize() != TellI())
+ wxLogError(_("reading zip stream (entry %s): bad length"),
+ m_entry.GetName().c_str());
+ else if (m_crcAccumulator != m_entry.GetCrc())
+ wxLogError(_("reading zip stream (entry %s): bad crc"),
+ m_entry.GetName().c_str());
+ else
+ m_lasterror = wxSTREAM_EOF;
}
}
return count;
}
+#if WXWIN_COMPATIBILITY_2_6
+
// Borrowed from VS's zip stream (c) 1999 Vaclav Slavik
//
wxFileOffset wxZipInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode)
{
- if (!m_ffile || AtHeader())
+ // seeking works when the stream is created with the compatibility
+ // constructor
+ if (!m_allowSeeking)
+ return wxInvalidOffset;
+ if (!IsOpened())
+ if ((AtHeader() && !DoOpen()) || !OpenDecompressor())
+ m_lasterror = wxSTREAM_READ_ERROR;
+ if (!IsOk())
return wxInvalidOffset;
// NB: since ZIP files don't natively support seeking, we have to
{
case wxFromCurrent : nextpos = seek + pos; break;
case wxFromStart : nextpos = seek; break;
- case wxFromEnd : nextpos = GetSize() - 1 + seek; break;
+ case wxFromEnd : nextpos = GetLength() + seek; break;
default : nextpos = pos; break; /* just to fool compiler, never happens */
}
- size_t toskip;
+ wxFileOffset toskip wxDUMMY_INITIALIZE(0);
if ( nextpos >= pos )
{
toskip = nextpos - pos;
else
{
wxZipEntry current(m_entry);
- CloseEntry();
if (!OpenEntry(current))
{
m_lasterror = wxSTREAM_READ_ERROR;
if ( toskip > 0 )
{
- const size_t BUFSIZE = 4096;
+ const int BUFSIZE = 4096;
size_t sz;
char buffer[BUFSIZE];
while ( toskip > 0 )
{
- sz = wxMin(toskip, BUFSIZE);
+ sz = wx_truncate_cast(size_t, wxMin(toskip, BUFSIZE));
Read(buffer, sz);
toskip -= sz;
}
return pos;
}
+#endif // WXWIN_COMPATIBILITY_2_6
+
/////////////////////////////////////////////////////////////////////////////
// Output stream
-#include <wx/listimpl.cpp>
-WX_DEFINE_LIST(_wxZipEntryList);
+#include "wx/listimpl.cpp"
+WX_DEFINE_LIST(wxZipEntryList_)
wxZipOutputStream::wxZipOutputStream(wxOutputStream& stream,
int level /*=-1*/,
wxMBConv& conv /*=wxConvLocal*/)
- : wxArchiveOutputStream(stream, conv),
- m_store(new wxStoredOutputStream(stream)),
- m_deflate(NULL),
- m_backlink(NULL),
- m_initialData(new char[OUTPUT_LATENCY]),
- m_initialSize(0),
- m_pending(NULL),
- m_raw(false),
- m_headerOffset(0),
- m_headerSize(0),
- m_entrySize(0),
- m_comp(NULL),
- m_level(level),
- m_offsetAdjustment(wxInvalidOffset)
-{
-}
-
+ : wxArchiveOutputStream(stream, conv)
+{
+ Init(level);
+}
+
+wxZipOutputStream::wxZipOutputStream(wxOutputStream *stream,
+ int level /*=-1*/,
+ wxMBConv& conv /*=wxConvLocal*/)
+ : wxArchiveOutputStream(stream, conv)
+{
+ Init(level);
+}
+
+void wxZipOutputStream::Init(int level)
+{
+ m_store = new wxStoredOutputStream(*m_parent_o_stream);
+ m_deflate = NULL;
+ m_backlink = NULL;
+ m_initialData = new char[OUTPUT_LATENCY];
+ m_initialSize = 0;
+ m_pending = NULL;
+ m_raw = false;
+ m_headerOffset = 0;
+ m_headerSize = 0;
+ m_entrySize = 0;
+ m_comp = NULL;
+ m_level = level;
+ m_offsetAdjustment = wxInvalidOffset;
+ m_endrecWritten = false;
+}
+
wxZipOutputStream::~wxZipOutputStream()
{
Close();
- WX_CLEAR_LIST(_wxZipEntryList, m_entries);
+ WX_CLEAR_LIST(wxZipEntryList_, m_entries);
delete m_store;
delete m_deflate;
delete m_pending;
bool wxZipOutputStream::CopyEntry(wxZipEntry *entry,
wxZipInputStream& inputStream)
{
- _wxZipEntryPtr e(entry);
+ wxZipEntryPtr_ e(entry);
return
inputStream.DoOpen(e.get(), true) &&
return false;
}
- return CopyEntry(zipEntry, wx_static_cast(wxZipInputStream&, stream));
+ return CopyEntry(zipEntry, static_cast<wxZipInputStream&>(stream));
}
bool wxZipOutputStream::CopyArchiveMetaData(wxZipInputStream& inputStream)
bool wxZipOutputStream::CopyArchiveMetaData(wxArchiveInputStream& stream)
{
- return CopyArchiveMetaData(wx_static_cast(wxZipInputStream&, stream));
+ return CopyArchiveMetaData(static_cast<wxZipInputStream&>(stream));
}
void wxZipOutputStream::SetLevel(int level)
ds << LOCAL_MAGIC;
// and if this is the first entry test for seekability
- if (m_headerOffset == 0) {
+ if (m_headerOffset == 0 && m_parent_o_stream->IsSeekable()) {
+#if wxUSE_LOG
bool logging = wxLog::IsEnabled();
wxLogNull nolog;
+#endif // wxUSE_LOG
wxFileOffset here = m_parent_o_stream->TellO();
if (here != wxInvalidOffset && here >= 4) {
if (m_parent_o_stream->SeekO(here - 4) == here - 4) {
m_offsetAdjustment = here - 4;
+#if wxUSE_LOG
wxLog::EnableLogging(logging);
+#endif // wxUSE_LOG
m_parent_o_stream->SeekO(here);
}
}
void wxZipOutputStream::CreatePendingEntry(const void *buffer, size_t size)
{
wxASSERT(IsOk() && m_pending && !m_comp);
- _wxZipEntryPtr spPending(m_pending);
+ wxZipEntryPtr_ spPending(m_pending);
m_pending = NULL;
Buffer bufs[] = {
void wxZipOutputStream::CreatePendingEntry()
{
wxASSERT(IsOk() && m_pending && !m_comp);
- _wxZipEntryPtr spPending(m_pending);
+ wxZipEntryPtr_ spPending(m_pending);
m_pending = NULL;
m_lasterror = wxSTREAM_WRITE_ERROR;
{
CloseEntry();
- if (m_lasterror == wxSTREAM_WRITE_ERROR || m_entries.size() == 0)
+ if (m_lasterror == wxSTREAM_WRITE_ERROR
+ || (m_entries.size() == 0 && m_endrecWritten))
+ {
+ wxFilterOutputStream::Close();
return false;
+ }
wxZipEndRec endrec;
endrec.SetOffset(m_headerOffset);
endrec.SetComment(m_Comment);
- _wxZipEntryList::iterator it;
+ wxZipEntryList_::iterator it;
wxFileOffset size = 0;
for (it = m_entries.begin(); it != m_entries.end(); ++it) {
endrec.Write(*m_parent_o_stream, GetConv());
m_lasterror = m_parent_o_stream->GetLastError();
- if (!IsOk())
+ m_endrecWritten = true;
+
+ if (!wxFilterOutputStream::Close() || !IsOk())
return false;
m_lasterror = wxSTREAM_EOF;
return true;
}
m_headerOffset += m_headerSize + compressedSize;
- m_headerSize = m_entrySize = 0;
+ m_headerSize = 0;
+ m_entrySize = 0;
m_store->Close();
m_raw = false;
return m_comp->LastWrite();
}
-#endif // wxUSE_ZLIB && wxUSE_STREAMS && wxUSE_ZIPSTREAM
+#endif // wxUSE_ZIPSTREAM