X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/00375592f92f68c4ca3f44d8e839bcfd47adc4e1..5ac1d44aa499901b1a2e194292ba7a93112196ae:/src/common/zipstrm.cpp?ds=sidebyside diff --git a/src/common/zipstrm.cpp b/src/common/zipstrm.cpp index 1f291dbc43..60284d99a1 100644 --- a/src/common/zipstrm.cpp +++ b/src/common/zipstrm.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: zipstrm.cpp +// Name: src/common/zipstrm.cpp // Purpose: Streams for Zip files // Author: Mike Wetherell // RCS-ID: $Id$ @@ -7,34 +7,29 @@ // 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_ZLIB && wxUSE_STREAMS && wxUSE_ZIPSTREAM + #ifndef WX_PRECOMP - #include "wx/defs.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/wfstream.h" -#include "wx/html/forcelnk.h" +#include "wx/link.h" #include "zlib.h" // value for the 'version needed to extract' field (20 means 2.0) @@ -82,7 +77,7 @@ enum { IMPLEMENT_DYNAMIC_CLASS(wxZipEntry, wxArchiveEntry) IMPLEMENT_DYNAMIC_CLASS(wxZipClassFactory, wxArchiveClassFactory) -FORCE_LINK_ME(zipstrm) +wxFORCE_LINK_THIS_MODULE(zipstrm) ///////////////////////////////////////////////////////////////////////////// @@ -116,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 defined(__WXDEBUG__) && wxUSE_LOG wxLogLevel level = wxLog::GetLogLevel(); wxLog::SetLogLevel(wxLOG_Debug - 1); wxFileOffset result = stream.SeekI(pos); @@ -133,6 +136,69 @@ static wxFileOffset QuietSeek(wxInputStream& stream, wxFileOffset pos) } +///////////////////////////////////////////////////////////////////////////// +// 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; +} + +wxUint8 wxZipHeader::Read8() +{ + wxASSERT(m_pos < m_size); + return m_data[m_pos++]; +} + +wxUint16 wxZipHeader::Read16() +{ + wxASSERT(m_pos + 2 <= m_size); + wxUint16 n = CrackUint16(m_data + m_pos); + m_pos += 2; + return n; +} + +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. @@ -146,7 +212,7 @@ public: 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); @@ -168,14 +234,13 @@ 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; } @@ -298,7 +363,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; } @@ -312,6 +378,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; @@ -481,12 +548,14 @@ public: wxZipMemory *Unique(size_t size); private: - ~wxZipMemory() { delete m_data; } + ~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) @@ -501,7 +570,7 @@ 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; } @@ -542,7 +611,7 @@ static void Unique(wxZipMemory*& zm, size_t size) // Collection of weak references to entries WX_DECLARE_HASH_MAP(long, wxZipEntry*, wxIntegerHash, - wxIntegerEqual, _wxOffsetZipEntryMap); + wxIntegerEqual, wx__OffsetZipEntryMap); class wxZipWeakLinks { @@ -555,27 +624,33 @@ public: { 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 wx__OffsetZipEntryMap::key_type key_type; + int m_ref; - _wxOffsetZipEntryMap m_entries; + wx__OffsetZipEntryMap 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); + wx__OffsetZipEntryMap::const_iterator it = + m_entries.find(wx_truncate_cast(key_type, key)); return it != m_entries.end() ? it->second : NULL; } @@ -587,7 +662,7 @@ wxZipEntry::wxZipEntry( 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), @@ -620,7 +695,8 @@ wxZipEntry::~wxZipEntry() } 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), @@ -638,7 +714,7 @@ wxZipEntry::wxZipEntry(const wxZipEntry& e) 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) { } @@ -664,7 +740,7 @@ wxZipEntry& wxZipEntry::operator=(const wxZipEntry& e) 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; @@ -677,6 +753,7 @@ wxString wxZipEntry::GetName(wxPathFormat format /*=wxPATH_NATIVE*/) const { bool isDir = IsDir() && !m_Name.empty(); + // optimisations for common (and easy) cases switch (wxFileName::GetFormat(format)) { case wxPATH_DOS: { @@ -741,7 +818,7 @@ void wxZipEntry::SetSystemMadeBy(int system) int mode = GetMode(); bool wasUnix = IsMadeByUnix(); - m_SystemMadeBy = system; + m_SystemMadeBy = (wxUint8)system; if (!wasUnix && IsMadeByUnix()) { SetIsDir(IsDir()); @@ -862,7 +939,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())); @@ -878,11 +957,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; @@ -894,19 +978,21 @@ size_t wxZipEntry::WriteLocal(wxOutputStream& stream, wxMBConv& conv) const const wxWX2MBbuf name_buf = conv.cWX2MB(unixName); 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); @@ -920,7 +1006,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; @@ -935,19 +1023,27 @@ size_t wxZipEntry::ReadCentral(wxInputStream& stream, wxMBConv& conv) 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; } @@ -958,32 +1054,32 @@ size_t wxZipEntry::WriteCentral(wxOutputStream& stream, wxMBConv& conv) const const wxWX2MBbuf name_buf = conv.cWX2MB(unixName); 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 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); @@ -999,8 +1095,10 @@ 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(); m_Size = ds.Read32(); @@ -1008,23 +1106,24 @@ 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); - 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; @@ -1044,8 +1143,8 @@ size_t wxZipEntry::WriteDescriptor(wxOutputStream& stream, wxUint32 crc, 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; } @@ -1067,13 +1166,20 @@ public: 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; @@ -1103,7 +1209,7 @@ bool wxZipEndRec::Write(wxOutputStream& stream, wxMBConv& conv) const const wxWX2MBbuf comment_buf = conv.cWX2MB(m_Comment); const char *comment = comment_buf; if (!comment) comment = ""; - wxUint16 commentLen = strlen(comment); + wxUint16 commentLen = (wxUint16)strlen(comment); wxDataOutputStream ds(stream); @@ -1117,23 +1223,26 @@ 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; } @@ -1158,14 +1267,17 @@ private: 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, wx__ZipEntryPtr) +wxDEFINE_SCOPED_PTR (wxZipEntry, wx__ZipEntryPtr) // constructor // @@ -1173,20 +1285,22 @@ wxZipInputStream::wxZipInputStream(wxInputStream& stream, wxMBConv& conv /*=wxConvLocal*/) : wxArchiveInputStream(stream, conv) { - m_ffile = NULL; Init(); } -// Compatibility constructor +#if 1 //WXWIN_COMPATIBILITY_2_6 + +// 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; + m_ffile = wx_static_cast(wxFFileInputStream*, m_parent_i_stream); + wx__ZipEntryPtr entry; if (m_ffile->Ok()) { do { @@ -1202,10 +1316,11 @@ wxZipInputStream::wxZipInputStream(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 + void wxZipInputStream::Init() { m_store = new wxStoredInputStream(*m_parent_i_stream); @@ -1222,6 +1337,10 @@ 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 + m_allowSeeking = false; +#endif } wxZipInputStream::~wxZipInputStream() @@ -1234,7 +1353,7 @@ wxZipInputStream::~wxZipInputStream() delete m_ffile; m_weaklinks->Release(this); - + if (m_streamlink) m_streamlink->Release(this); } @@ -1293,9 +1412,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; } @@ -1305,20 +1422,14 @@ 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(); // 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; @@ -1326,7 +1437,7 @@ bool wxZipInputStream::LoadEndRecord() 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. @@ -1348,8 +1459,11 @@ bool wxZipInputStream::LoadEndRecord() // 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; @@ -1373,10 +1487,11 @@ bool wxZipInputStream::FindEndRecord() 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; @@ -1406,7 +1521,7 @@ wxZipEntry *wxZipInputStream::GetNextEntry() if (!IsOk()) return NULL; - _wxZipEntryPtr entry(new wxZipEntry(m_entry)); + wx__ZipEntryPtr entry(new wxZipEntry(m_entry)); entry->m_backlink = m_weaklinks->AddEntry(entry.get(), entry->GetKey()); return entry.release(); } @@ -1427,12 +1542,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) @@ -1460,10 +1576,11 @@ wxStreamError wxZipInputStream::ReadLocal(bool readEndRec /*=false*/) 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()); @@ -1496,7 +1613,7 @@ wxStreamError wxZipInputStream::ReadLocal(bool readEndRec /*=false*/) } return wxSTREAM_EOF; } - + if (m_signature != LOCAL_MAGIC) { wxLogError(_("error reading zip local header")); return wxSTREAM_READ_ERROR; @@ -1507,7 +1624,7 @@ wxStreamError wxZipInputStream::ReadLocal(bool readEndRec /*=false*/) m_entry.SetOffset(m_position); m_entry.SetKey(m_position); - if (m_parent_i_stream->GetLastError() == wxSTREAM_READ_ERROR) { + if (!m_headerSize) { return wxSTREAM_READ_ERROR; } else { m_TotalEntries++; @@ -1537,7 +1654,8 @@ bool wxZipInputStream::DoOpen(wxZipEntry *entry, bool raw) return false; if (m_lasterror == wxSTREAM_READ_ERROR) return false; - wxCHECK(!IsOpened(), false); + if (IsOpened()) + CloseEntry(); m_raw = raw; @@ -1547,9 +1665,9 @@ bool wxZipInputStream::DoOpen(wxZipEntry *entry, bool 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; @@ -1565,7 +1683,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); @@ -1579,7 +1697,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(); } @@ -1698,7 +1817,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) { @@ -1716,27 +1836,34 @@ 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; } } return count; } +#if 1 //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 @@ -1751,11 +1878,11 @@ wxFileOffset wxZipInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) { 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; @@ -1763,7 +1890,6 @@ wxFileOffset wxZipInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) else { wxZipEntry current(m_entry); - CloseEntry(); if (!OpenEntry(current)) { m_lasterror = wxSTREAM_READ_ERROR; @@ -1774,12 +1900,12 @@ wxFileOffset wxZipInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) 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; } @@ -1789,12 +1915,14 @@ wxFileOffset wxZipInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) return pos; } +#endif // WXWIN_COMPATIBILITY_2_6 + ///////////////////////////////////////////////////////////////////////////// // Output stream -#include -WX_DEFINE_LIST(_wxZipEntryList); +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wx__ZipEntryList) wxZipOutputStream::wxZipOutputStream(wxOutputStream& stream, int level /*=-1*/, @@ -1815,11 +1943,11 @@ wxZipOutputStream::wxZipOutputStream(wxOutputStream& stream, m_offsetAdjustment(wxInvalidOffset) { } - + wxZipOutputStream::~wxZipOutputStream() { Close(); - WX_CLEAR_LIST(_wxZipEntryList, m_entries); + WX_CLEAR_LIST(wx__ZipEntryList, m_entries); delete m_store; delete m_deflate; delete m_pending; @@ -1848,7 +1976,7 @@ bool wxZipOutputStream::PutNextDirEntry( bool wxZipOutputStream::CopyEntry(wxZipEntry *entry, wxZipInputStream& inputStream) { - _wxZipEntryPtr e(entry); + wx__ZipEntryPtr e(entry); return inputStream.DoOpen(e.get(), true) && @@ -1914,15 +2042,19 @@ bool wxZipOutputStream::DoCreate(wxZipEntry *entry, bool raw /*=false*/) 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); } } @@ -2014,7 +2146,7 @@ bool wxZipOutputStream::CloseCompressor(wxOutputStream *comp) void wxZipOutputStream::CreatePendingEntry(const void *buffer, size_t size) { wxASSERT(IsOk() && m_pending && !m_comp); - _wxZipEntryPtr spPending(m_pending); + wx__ZipEntryPtr spPending(m_pending); m_pending = NULL; Buffer bufs[] = { @@ -2055,7 +2187,7 @@ void wxZipOutputStream::CreatePendingEntry(const void *buffer, size_t size) void wxZipOutputStream::CreatePendingEntry() { wxASSERT(IsOk() && m_pending && !m_comp); - _wxZipEntryPtr spPending(m_pending); + wx__ZipEntryPtr spPending(m_pending); m_pending = NULL; m_lasterror = wxSTREAM_WRITE_ERROR; @@ -2119,7 +2251,7 @@ bool wxZipOutputStream::Close() endrec.SetOffset(m_headerOffset); endrec.SetComment(m_Comment); - _wxZipEntryList::iterator it; + wx__ZipEntryList::iterator it; wxFileOffset size = 0; for (it = m_entries.begin(); it != m_entries.end(); ++it) { @@ -2191,7 +2323,8 @@ bool wxZipOutputStream::CloseEntry() } m_headerOffset += m_headerSize + compressedSize; - m_headerSize = m_entrySize = 0; + m_headerSize = 0; + m_entrySize = 0; m_store->Close(); m_raw = false;