X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/344d0d882117bc52e2b477d3505916a235981197..2f36b4d22beeb7f4f0cedf922c0c26d037f54477:/src/common/zipstrm.cpp diff --git a/src/common/zipstrm.cpp b/src/common/zipstrm.cpp index 03abd6b1ab..07b526d15f 100644 --- a/src/common/zipstrm.cpp +++ b/src/common/zipstrm.cpp @@ -1,8 +1,7 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: zipstrm.cpp +// Name: src/common/zipstrm.cpp // Purpose: Streams for Zip files // Author: Mike Wetherell -// RCS-ID: $Id$ // Copyright: (c) Mike Wetherell // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -11,26 +10,25 @@ #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/link.h" #include "zlib.h" // value for the 'version needed to extract' field (20 means 2.0) @@ -78,8 +76,6 @@ enum { IMPLEMENT_DYNAMIC_CLASS(wxZipEntry, wxArchiveEntry) IMPLEMENT_DYNAMIC_CLASS(wxZipClassFactory, wxArchiveClassFactory) -wxFORCE_LINK_THIS_MODULE(zipstrm) - ///////////////////////////////////////////////////////////////////////////// // Helpers @@ -88,6 +84,9 @@ wxFORCE_LINK_THIS_MODULE(zipstrm) // 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); @@ -112,12 +111,20 @@ static inline wxUint32 CrackUint32(const char *m) 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); @@ -129,6 +136,97 @@ static wxFileOffset QuietSeek(wxInputStream& stream, wxFileOffset 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[] = { wxT("zip"), NULL }; + static const wxChar *mimetypes[] = { wxT("application/zip"), NULL }; + static const wxChar *fileexts[] = { wxT(".zip"), wxT(".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), wxT("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. @@ -152,7 +250,7 @@ private: wxFileOffset m_pos; wxFileOffset m_len; - DECLARE_NO_COPY_CLASS(wxStoredInputStream) + wxDECLARE_NO_COPY_CLASS(wxStoredInputStream); }; wxStoredInputStream::wxStoredInputStream(wxInputStream& stream) @@ -169,10 +267,8 @@ size_t wxStoredInputStream::OnSysRead(void *buffer, size_t size) count = m_parent_i_stream->Read(buffer, count).LastRead(); m_pos += count; - if (m_pos == m_len && count < size) - 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; } @@ -200,7 +296,7 @@ protected: private: wxFileOffset m_pos; - DECLARE_NO_COPY_CLASS(wxStoredOutputStream) + wxDECLARE_NO_COPY_CLASS(wxStoredOutputStream); }; size_t wxStoredOutputStream::OnSysWrite(const void *buffer, size_t size) @@ -262,7 +358,7 @@ private: size_t m_start; size_t m_end; - DECLARE_NO_COPY_CLASS(wxTeeInputStream) + wxDECLARE_NO_COPY_CLASS(wxTeeInputStream); }; wxTeeInputStream::wxTeeInputStream(wxInputStream& stream) @@ -295,7 +391,8 @@ wxInputStream& wxTeeInputStream::Read(void *buffer, size_t size) 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; } @@ -309,6 +406,7 @@ size_t wxTeeInputStream::GetData(char *buffer, size_t size) 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; @@ -356,7 +454,7 @@ private: enum { BUFSIZE = 8192 }; wxCharBuffer m_dummy; - DECLARE_NO_COPY_CLASS(wxRawInputStream) + wxDECLARE_NO_COPY_CLASS(wxRawInputStream); }; wxRawInputStream::wxRawInputStream(wxInputStream& stream) @@ -541,7 +639,7 @@ static void Unique(wxZipMemory*& zm, size_t size) // Collection of weak references to entries WX_DECLARE_HASH_MAP(long, wxZipEntry*, wxIntegerHash, - wxIntegerEqual, wx__OffsetZipEntryMap); + wxIntegerEqual, wxOffsetZipEntryMap_); class wxZipWeakLinks { @@ -562,10 +660,10 @@ public: private: ~wxZipWeakLinks() { wxASSERT(IsEmpty()); } - typedef wx__OffsetZipEntryMap::key_type key_type; + typedef wxOffsetZipEntryMap_::key_type key_type; int m_ref; - wx__OffsetZipEntryMap m_entries; + wxOffsetZipEntryMap_ m_entries; wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipWeakLinks) }; @@ -579,7 +677,7 @@ wxZipWeakLinks *wxZipWeakLinks::AddEntry(wxZipEntry *entry, wxFileOffset key) wxZipEntry *wxZipWeakLinks::GetEntry(wxFileOffset key) const { - wx__OffsetZipEntryMap::const_iterator it = + wxOffsetZipEntryMap_::const_iterator it = m_entries.find(wx_truncate_cast(key_type, key)); return it != m_entries.end() ? it->second : NULL; } @@ -687,15 +785,15 @@ wxString wxZipEntry::GetName(wxPathFormat format /*=wxPATH_NATIVE*/) const 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) - if (name[i] == _T('/')) - name[i] = _T('\\'); + wxString name(isDir ? m_Name + wxT("\\") : m_Name); + for (size_t i = 0; i < name.length(); i++) + if (name[i] == wxT('/')) + name[i] = wxT('\\'); return name; } case wxPATH_UNIX: - return isDir ? m_Name + _T("/") : m_Name; + return isDir ? m_Name + wxT("/") : m_Name; default: ; @@ -735,9 +833,9 @@ wxString wxZipEntry::GetInternalName(const wxString& name, while (!internal.empty() && *internal.begin() == '/') internal.erase(0, 1); - while (!internal.empty() && internal.compare(0, 2, _T("./")) == 0) + while (!internal.empty() && internal.compare(0, 2, wxT("./")) == 0) internal.erase(0, 2); - if (internal == _T(".") || internal == _T("..")) + if (internal == wxT(".") || internal == wxT("..")) internal = wxEmptyString; return internal; @@ -869,7 +967,9 @@ size_t wxZipEntry::ReadLocal(wxInputStream& stream, wxMBConv& conv) 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())); @@ -885,11 +985,16 @@ size_t wxZipEntry::ReadLocal(wxInputStream& stream, wxMBConv& conv) 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; @@ -898,7 +1003,7 @@ size_t wxZipEntry::ReadLocal(wxInputStream& stream, wxMBConv& conv) 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 = wx_truncate_cast(wxUint16, strlen(name)); @@ -929,7 +1034,9 @@ size_t wxZipEntry::ReadCentral(wxInputStream& stream, wxMBConv& conv) { wxUint16 nameLen, extraLen, commentLen; - wxDataInputStream ds(stream); + wxZipHeader ds(stream, CENTRAL_SIZE - 4); + if (!ds) + return 0; ds >> m_VersionMadeBy >> m_SystemMadeBy; @@ -946,17 +1053,25 @@ size_t wxZipEntry::ReadCentral(wxInputStream& stream, wxMBConv& conv) 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; } @@ -964,12 +1079,12 @@ size_t wxZipEntry::ReadCentral(wxInputStream& stream, wxMBConv& conv) 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 = 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 = wx_truncate_cast(wxUint16, strlen(comment)); @@ -1008,7 +1123,9 @@ size_t wxZipEntry::WriteCentral(wxOutputStream& stream, wxMBConv& conv) const // 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(); @@ -1017,22 +1134,23 @@ size_t wxZipEntry::ReadDescriptor(wxInputStream& stream) // 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); + 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; @@ -1116,7 +1234,7 @@ wxZipEndRec::wxZipEndRec() 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 = (wxUint16)strlen(comment); @@ -1133,23 +1251,28 @@ bool wxZipEndRec::Write(wxOutputStream& stream, wxMBConv& conv) const 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; } @@ -1183,8 +1306,8 @@ private: // Input stream // leave the default wxZipEntryPtr free for users -wxDECLARE_SCOPED_PTR(wxZipEntry, wx__ZipEntryPtr) -wxDEFINE_SCOPED_PTR (wxZipEntry, wx__ZipEntryPtr) +wxDECLARE_SCOPED_PTR(wxZipEntry, wxZipEntryPtr_) +wxDEFINE_SCOPED_PTR (wxZipEntry, wxZipEntryPtr_) // constructor // @@ -1195,7 +1318,14 @@ wxZipInputStream::wxZipInputStream(wxInputStream& stream, Init(); } -#if 1 //WXWIN_COMPATIBILITY_2_6 +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 @@ -1206,10 +1336,11 @@ void wxZipInputStream::Init(const wxString& file) wxLogNull nolog; Init(); m_allowSeeking = true; - m_ffile = wx_static_cast(wxFFileInputStream*, m_parent_i_stream); - wx__ZipEntryPtr entry; + wxFFileInputStream *ffile; + ffile = static_cast(m_parent_i_stream); + wxZipEntryPtr_ entry; - if (m_ffile->Ok()) { + if (ffile->IsOk()) { do { entry.reset(GetNextEntry()); } @@ -1220,13 +1351,13 @@ void wxZipInputStream::Init(const wxString& file) m_lasterror = wxSTREAM_READ_ERROR; } -wxInputStream& wxZipInputStream::OpenFile(const wxString& archive) +wxInputStream* wxZipInputStream::OpenFile(const wxString& archive) { wxLogNull nolog; - return *new wxFFileInputStream(archive); + return new wxFFileInputStream(archive); } -#endif // WXWIN_COMPATIBILITY_2_6 +#endif // WXWIN_COMPATIBILITY_2_6 && wxUSE_FFILE void wxZipInputStream::Init() { @@ -1244,8 +1375,7 @@ void wxZipInputStream::Init() m_signature = 0; m_TotalEntries = 0; m_lasterror = m_parent_i_stream->GetLastError(); - m_ffile = NULL; -#if 1 //WXWIN_COMPATIBILITY_2_6 +#if WXWIN_COMPATIBILITY_2_6 m_allowSeeking = false; #endif } @@ -1257,7 +1387,6 @@ wxZipInputStream::~wxZipInputStream() delete m_store; delete m_inflate; delete m_rawin; - delete m_ffile; m_weaklinks->Release(this); @@ -1319,9 +1448,7 @@ bool wxZipInputStream::LoadEndRecord() 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; } @@ -1331,23 +1458,19 @@ bool wxZipInputStream::LoadEndRecord() // 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. 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; @@ -1357,8 +1480,8 @@ bool wxZipInputStream::LoadEndRecord() // 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; @@ -1436,7 +1559,7 @@ wxZipEntry *wxZipInputStream::GetNextEntry() if (!IsOk()) return NULL; - wx__ZipEntryPtr entry(new wxZipEntry(m_entry)); + wxZipEntryPtr_ entry(new wxZipEntry(m_entry)); entry->m_backlink = m_weaklinks->AddEntry(entry.get(), entry->GetKey()); return entry.release(); } @@ -1457,12 +1580,13 @@ wxStreamError wxZipInputStream::ReadCentral() 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) @@ -1491,9 +1615,10 @@ wxStreamError wxZipInputStream::ReadLocal(bool readEndRec /*=false*/) 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()); @@ -1527,22 +1652,20 @@ wxStreamError wxZipInputStream::ReadLocal(bool readEndRec /*=false*/) 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() @@ -1596,7 +1719,7 @@ bool wxZipInputStream::DoOpen(wxZipEntry *entry, bool raw) 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); @@ -1610,7 +1733,8 @@ bool wxZipInputStream::DoOpen(wxZipEntry *entry, bool raw) } } - m_lasterror = m_parent_i_stream->GetLastError(); + if (m_headerSize) + m_lasterror = wxSTREAM_NO_ERROR; return IsOk(); } @@ -1648,7 +1772,7 @@ bool wxZipInputStream::OpenDecompressor(bool raw /*=false*/) return IsOk(); } -// Can be overriden to add support for additional decompression methods +// Can be overridden to add support for additional decompression methods // wxInputStream *wxZipInputStream::OpenDecompressor(wxInputStream& stream) { @@ -1729,7 +1853,8 @@ size_t wxZipInputStream::OnSysRead(void *buffer, size_t size) 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) { @@ -1747,15 +1872,19 @@ size_t wxZipInputStream::OnSysRead(void *buffer, size_t size) 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; } } } @@ -1763,7 +1892,7 @@ size_t wxZipInputStream::OnSysRead(void *buffer, size_t size) return count; } -#if 1 //WXWIN_COMPATIBILITY_2_6 +#if WXWIN_COMPATIBILITY_2_6 // Borrowed from VS's zip stream (c) 1999 Vaclav Slavik // @@ -1835,32 +1964,46 @@ wxFileOffset wxZipInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) // Output stream #include "wx/listimpl.cpp" -WX_DEFINE_LIST(wx__ZipEntryList) +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(wx__ZipEntryList, m_entries); + WX_CLEAR_LIST(wxZipEntryList_, m_entries); delete m_store; delete m_deflate; delete m_pending; @@ -1889,7 +2032,7 @@ bool wxZipOutputStream::PutNextDirEntry( bool wxZipOutputStream::CopyEntry(wxZipEntry *entry, wxZipInputStream& inputStream) { - wx__ZipEntryPtr e(entry); + wxZipEntryPtr_ e(entry); return inputStream.DoOpen(e.get(), true) && @@ -1915,7 +2058,7 @@ bool wxZipOutputStream::CopyEntry(wxArchiveEntry *entry, return false; } - return CopyEntry(zipEntry, wx_static_cast(wxZipInputStream&, stream)); + return CopyEntry(zipEntry, static_cast(stream)); } bool wxZipOutputStream::CopyArchiveMetaData(wxZipInputStream& inputStream) @@ -1929,7 +2072,7 @@ bool wxZipOutputStream::CopyArchiveMetaData(wxZipInputStream& inputStream) bool wxZipOutputStream::CopyArchiveMetaData(wxArchiveInputStream& stream) { - return CopyArchiveMetaData(wx_static_cast(wxZipInputStream&, stream)); + return CopyArchiveMetaData(static_cast(stream)); } void wxZipOutputStream::SetLevel(int level) @@ -1984,7 +2127,7 @@ bool wxZipOutputStream::DoCreate(wxZipEntry *entry, bool raw /*=false*/) return true; } -// Can be overriden to add support for additional compression methods +// Can be overridden to add support for additional compression methods // wxOutputStream *wxZipOutputStream::OpenCompressor( wxOutputStream& stream, @@ -2059,7 +2202,7 @@ bool wxZipOutputStream::CloseCompressor(wxOutputStream *comp) void wxZipOutputStream::CreatePendingEntry(const void *buffer, size_t size) { wxASSERT(IsOk() && m_pending && !m_comp); - wx__ZipEntryPtr spPending(m_pending); + wxZipEntryPtr_ spPending(m_pending); m_pending = NULL; Buffer bufs[] = { @@ -2100,7 +2243,7 @@ void wxZipOutputStream::CreatePendingEntry(const void *buffer, size_t size) void wxZipOutputStream::CreatePendingEntry() { wxASSERT(IsOk() && m_pending && !m_comp); - wx__ZipEntryPtr spPending(m_pending); + wxZipEntryPtr_ spPending(m_pending); m_pending = NULL; m_lasterror = wxSTREAM_WRITE_ERROR; @@ -2154,8 +2297,12 @@ bool wxZipOutputStream::Close() { 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; @@ -2164,7 +2311,7 @@ bool wxZipOutputStream::Close() endrec.SetOffset(m_headerOffset); endrec.SetComment(m_Comment); - wx__ZipEntryList::iterator it; + wxZipEntryList_::iterator it; wxFileOffset size = 0; for (it = m_entries.begin(); it != m_entries.end(); ++it) { @@ -2177,7 +2324,9 @@ bool wxZipOutputStream::Close() 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; @@ -2286,4 +2435,4 @@ size_t wxZipOutputStream::OnSysWrite(const void *buffer, size_t size) return m_comp->LastWrite(); } -#endif // wxUSE_ZLIB && wxUSE_STREAMS && wxUSE_ZIPSTREAM +#endif // wxUSE_ZIPSTREAM