1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/common/zipstrm.cpp 
   3 // Purpose:     Streams for Zip files 
   4 // Author:      Mike Wetherell 
   6 // Copyright:   (c) Mike Wetherell 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 // For compilers that support precompilation, includes "wx.h". 
  11 #include "wx/wxprec.h" 
  21 #if wxUSE_ZLIB && wxUSE_STREAMS && wxUSE_ZIPSTREAM 
  23 #include "wx/zipstrm.h" 
  26 #include "wx/datstrm.h" 
  27 #include "wx/zstream.h" 
  28 #include "wx/mstream.h" 
  30 #include "wx/buffer.h" 
  31 #include "wx/ptr_scpd.h" 
  32 #include "wx/wfstream.h" 
  36 // value for the 'version needed to extract' field (20 means 2.0) 
  38     VERSION_NEEDED_TO_EXTRACT 
= 20 
  41 // signatures for the various records (PKxx) 
  43     CENTRAL_MAGIC 
= 0x02014b50,     // central directory record 
  44     LOCAL_MAGIC   
= 0x04034b50,     // local header 
  45     END_MAGIC     
= 0x06054b50,     // end of central directory record 
  46     SUMS_MAGIC    
= 0x08074b50      // data descriptor (info-zip) 
  49 // unix file attributes. zip stores them in the high 16 bits of the 
  50 // 'external attributes' field, hence the extra zeros. 
  52     wxZIP_S_IFMT  
= 0xF0000000, 
  53     wxZIP_S_IFDIR 
= 0x40000000, 
  54     wxZIP_S_IFREG 
= 0x80000000 
  57 // minimum sizes for the various records 
  65 // The number of bytes that must be written to an wxZipOutputStream before 
  66 // a zip entry is created. The purpose of this latency is so that 
  67 // OpenCompressor() can see a little data before deciding which compressor 
  73 // Some offsets into the local header 
  78 IMPLEMENT_DYNAMIC_CLASS(wxZipEntry
, wxArchiveEntry
) 
  79 IMPLEMENT_DYNAMIC_CLASS(wxZipClassFactory
, wxArchiveClassFactory
) 
  81 wxFORCE_LINK_THIS_MODULE(zipstrm
) 
  84 ///////////////////////////////////////////////////////////////////////////// 
  87 // read a string of a given length 
  89 static wxString 
ReadString(wxInputStream
& stream
, wxUint16 len
, wxMBConv
& conv
) 
  92     wxCharBuffer 
buf(len
); 
  93     stream
.Read(buf
.data(), len
); 
  94     wxString 
str(buf
, conv
); 
  99         wxStringBuffer 
buf(str
, len
); 
 100         stream
.Read(buf
, len
); 
 107 // Decode a little endian wxUint32 number from a character array 
 109 static inline wxUint32 
CrackUint32(const char *m
) 
 111     const unsigned char *n 
= (const unsigned char*)m
; 
 112     return (n
[3] << 24) | (n
[2] << 16) | (n
[1] << 8) | n
[0]; 
 115 // Temporarily lower the logging level in debug mode to avoid a warning 
 116 // from SeekI about seeking on a stream with data written back to it. 
 118 static wxFileOffset 
QuietSeek(wxInputStream
& stream
, wxFileOffset pos
) 
 121     wxLogLevel level 
= wxLog::GetLogLevel(); 
 122     wxLog::SetLogLevel(wxLOG_Debug 
- 1); 
 123     wxFileOffset result 
= stream
.SeekI(pos
); 
 124     wxLog::SetLogLevel(level
); 
 127     return stream
.SeekI(pos
); 
 132 ///////////////////////////////////////////////////////////////////////////// 
 138     wxZipHeader(wxInputStream
& stream
, size_t size
); 
 140     inline wxUint8 
Read8(); 
 141     inline wxUint16 
Read16(); 
 142     inline wxUint32 
Read32(); 
 144     const char *GetData() const             { return m_data
; } 
 145     size_t GetSize() const                  { return m_size
; } 
 146     operator bool() const                   { return m_ok
; } 
 148     size_t Seek(size_t pos
)                 { m_pos 
= pos
; return m_pos
; } 
 149     size_t Skip(size_t size
)                { m_pos 
+= size
; return m_pos
; } 
 151     wxZipHeader
& operator>>(wxUint8
& n
)     { n 
= Read8();  return *this; } 
 152     wxZipHeader
& operator>>(wxUint16
& n
)    { n 
= Read16(); return *this; } 
 153     wxZipHeader
& operator>>(wxUint32
& n
)    { n 
= Read32(); return *this; } 
 162 wxZipHeader::wxZipHeader(wxInputStream
& stream
, size_t size
) 
 167     wxCHECK_RET(size 
<= sizeof(m_data
), _T("buffer too small")); 
 168     m_size 
= stream
.Read(m_data
, size
).LastRead(); 
 169     m_ok 
= m_size 
== size
; 
 172 wxUint8 
wxZipHeader::Read8() 
 174     wxASSERT(m_pos 
< m_size
); 
 175     return *wx_reinterpret_cast(wxUint8
*, m_data 
+ m_pos
++); 
 178 wxUint16 
wxZipHeader::Read16() 
 180     wxASSERT(m_pos 
+ 2 <= m_size
); 
 181     wxUint16 n 
= *wx_reinterpret_cast(wxUint16
*, m_data 
+ m_pos
); 
 183     return wxUINT16_SWAP_ON_BE(n
); 
 186 wxUint32 
wxZipHeader::Read32() 
 188     wxASSERT(m_pos 
+ 4 <= m_size
); 
 189     wxUint32 n 
= *wx_reinterpret_cast(wxUint32
*, m_data 
+ m_pos
); 
 191     return wxUINT32_SWAP_ON_BE(n
); 
 195 ///////////////////////////////////////////////////////////////////////////// 
 196 // Stored input stream 
 197 // Trival decompressor for files which are 'stored' in the zip file. 
 199 class wxStoredInputStream 
: public wxFilterInputStream
 
 202     wxStoredInputStream(wxInputStream
& stream
); 
 204     void Open(wxFileOffset len
) { Close(); m_len 
= len
; } 
 205     void Close() { m_pos 
= 0; m_lasterror 
= wxSTREAM_NO_ERROR
; } 
 207     virtual char Peek() { return wxInputStream::Peek(); } 
 208     virtual wxFileOffset 
GetLength() const { return m_len
; } 
 211     virtual size_t OnSysRead(void *buffer
, size_t size
); 
 212     virtual wxFileOffset 
OnSysTell() const { return m_pos
; } 
 218     DECLARE_NO_COPY_CLASS(wxStoredInputStream
) 
 221 wxStoredInputStream::wxStoredInputStream(wxInputStream
& stream
) 
 222   : wxFilterInputStream(stream
), 
 228 size_t wxStoredInputStream::OnSysRead(void *buffer
, size_t size
) 
 230     size_t count 
= wx_truncate_cast(size_t, 
 231                 wxMin(size 
+ wxFileOffset(0), m_len 
- m_pos 
+ size_t(0))); 
 232     count 
= m_parent_i_stream
->Read(buffer
, count
).LastRead(); 
 236         m_lasterror 
= m_pos 
== m_len 
? wxSTREAM_EOF 
: wxSTREAM_READ_ERROR
; 
 242 ///////////////////////////////////////////////////////////////////////////// 
 243 // Stored output stream 
 244 // Trival compressor for files which are 'stored' in the zip file. 
 246 class wxStoredOutputStream 
: public wxFilterOutputStream
 
 249     wxStoredOutputStream(wxOutputStream
& stream
) : 
 250         wxFilterOutputStream(stream
), m_pos(0) { } 
 254         m_lasterror 
= wxSTREAM_NO_ERROR
; 
 259     virtual size_t OnSysWrite(const void *buffer
, size_t size
); 
 260     virtual wxFileOffset 
OnSysTell() const { return m_pos
; } 
 264     DECLARE_NO_COPY_CLASS(wxStoredOutputStream
) 
 267 size_t wxStoredOutputStream::OnSysWrite(const void *buffer
, size_t size
) 
 269     if (!IsOk() || !size
) 
 271     size_t count 
= m_parent_o_stream
->Write(buffer
, size
).LastWrite(); 
 273         m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
 279 ///////////////////////////////////////////////////////////////////////////// 
 282 // Used to handle the unusal case of raw copying an entry of unknown 
 283 // length. This can only happen when the zip being copied from is being 
 284 // read from a non-seekable stream, and also was original written to a 
 285 // non-seekable stream. 
 287 // In this case there's no option but to decompress the stream to find 
 288 // it's length, but we can still write the raw compressed data to avoid the 
 289 // compression overhead (which is the greater one). 
 291 // Usage is like this: 
 292 //  m_rawin = new wxRawInputStream(*m_parent_i_stream); 
 293 //  m_decomp = m_rawin->Open(OpenDecompressor(m_rawin->GetTee())); 
 295 // The wxRawInputStream owns a wxTeeInputStream object, the role of which 
 296 // is something like the unix 'tee' command; it is a transparent filter, but 
 297 // allows the data read to be read a second time via an extra method 'GetData'. 
 299 // The wxRawInputStream then draws data through the tee using a decompressor 
 300 // then instead of returning the decompressed data, retuns the raw data 
 301 // from wxTeeInputStream::GetData(). 
 303 class wxTeeInputStream 
: public wxFilterInputStream
 
 306     wxTeeInputStream(wxInputStream
& stream
); 
 308     size_t GetCount() const { return m_end 
- m_start
; } 
 309     size_t GetData(char *buffer
, size_t size
); 
 314     wxInputStream
& Read(void *buffer
, size_t size
); 
 317     virtual size_t OnSysRead(void *buffer
, size_t size
); 
 318     virtual wxFileOffset 
OnSysTell() const { return m_pos
; } 
 322     wxMemoryBuffer m_buf
; 
 326     DECLARE_NO_COPY_CLASS(wxTeeInputStream
) 
 329 wxTeeInputStream::wxTeeInputStream(wxInputStream
& stream
) 
 330   : wxFilterInputStream(stream
), 
 331     m_pos(0), m_buf(8192), m_start(0), m_end(0) 
 335 void wxTeeInputStream::Open() 
 337     m_pos 
= m_start 
= m_end 
= 0; 
 338     m_lasterror 
= wxSTREAM_NO_ERROR
; 
 341 bool wxTeeInputStream::Final() 
 343     bool final 
= m_end 
== m_buf
.GetDataLen(); 
 344     m_end 
= m_buf
.GetDataLen(); 
 348 wxInputStream
& wxTeeInputStream::Read(void *buffer
, size_t size
) 
 350     size_t count 
= wxInputStream::Read(buffer
, size
).LastRead(); 
 351     m_end 
= m_buf
.GetDataLen(); 
 352     m_buf
.AppendData(buffer
, count
); 
 356 size_t wxTeeInputStream::OnSysRead(void *buffer
, size_t size
) 
 358     size_t count 
= m_parent_i_stream
->Read(buffer
, size
).LastRead(); 
 360         m_lasterror 
= m_parent_i_stream
->GetLastError(); 
 364 size_t wxTeeInputStream::GetData(char *buffer
, size_t size
) 
 367         size_t len 
= m_buf
.GetDataLen(); 
 368         len 
= len 
> m_wbacksize 
? len 
- m_wbacksize 
: 0; 
 369         m_buf
.SetDataLen(len
); 
 371             wxFAIL
; // we've already returned data that's now being ungot 
 374         m_parent_i_stream
->Reset(); 
 375         m_parent_i_stream
->Ungetch(m_wback
, m_wbacksize
); 
 382     if (size 
> GetCount()) 
 385         memcpy(buffer
, m_buf 
+ m_start
, size
); 
 387         wxASSERT(m_start 
<= m_end
); 
 390     if (m_start 
== m_end 
&& m_start 
> 0 && m_buf
.GetDataLen() > 0) { 
 391         size_t len 
= m_buf
.GetDataLen(); 
 392         char *buf 
= (char*)m_buf
.GetWriteBuf(len
); 
 394         memmove(buf
, buf 
+ m_end
, len
); 
 395         m_buf
.UngetWriteBuf(len
); 
 402 class wxRawInputStream 
: public wxFilterInputStream
 
 405     wxRawInputStream(wxInputStream
& stream
); 
 406     virtual ~wxRawInputStream() { delete m_tee
; } 
 408     wxInputStream
* Open(wxInputStream 
*decomp
); 
 409     wxInputStream
& GetTee() const { return *m_tee
; } 
 412     virtual size_t OnSysRead(void *buffer
, size_t size
); 
 413     virtual wxFileOffset 
OnSysTell() const { return m_pos
; } 
 417     wxTeeInputStream 
*m_tee
; 
 419     enum { BUFSIZE 
= 8192 }; 
 420     wxCharBuffer m_dummy
; 
 422     DECLARE_NO_COPY_CLASS(wxRawInputStream
) 
 425 wxRawInputStream::wxRawInputStream(wxInputStream
& stream
) 
 426   : wxFilterInputStream(stream
), 
 428     m_tee(new wxTeeInputStream(stream
)), 
 433 wxInputStream 
*wxRawInputStream::Open(wxInputStream 
*decomp
) 
 436         m_parent_i_stream 
= decomp
; 
 438         m_lasterror 
= wxSTREAM_NO_ERROR
; 
 446 size_t wxRawInputStream::OnSysRead(void *buffer
, size_t size
) 
 448     char *buf 
= (char*)buffer
; 
 451     while (count 
< size 
&& IsOk()) 
 453         while (m_parent_i_stream
->IsOk() && m_tee
->GetCount() == 0) 
 454             m_parent_i_stream
->Read(m_dummy
.data(), BUFSIZE
); 
 456         size_t n 
= m_tee
->GetData(buf 
+ count
, size 
- count
); 
 459         if (n 
== 0 && m_tee
->Final()) 
 460             m_lasterror 
= m_parent_i_stream
->GetLastError(); 
 468 ///////////////////////////////////////////////////////////////////////////// 
 469 // Zlib streams than can be reused without recreating. 
 471 class wxZlibOutputStream2 
: public wxZlibOutputStream
 
 474     wxZlibOutputStream2(wxOutputStream
& stream
, int level
) : 
 475         wxZlibOutputStream(stream
, level
, wxZLIB_NO_HEADER
) { } 
 477     bool Open(wxOutputStream
& stream
); 
 478     bool Close() { DoFlush(true); m_pos 
= wxInvalidOffset
; return IsOk(); } 
 481 bool wxZlibOutputStream2::Open(wxOutputStream
& stream
) 
 483     wxCHECK(m_pos 
== wxInvalidOffset
, false); 
 485     m_deflate
->next_out 
= m_z_buffer
; 
 486     m_deflate
->avail_out 
= m_z_size
; 
 488     m_lasterror 
= wxSTREAM_NO_ERROR
; 
 489     m_parent_o_stream 
= &stream
; 
 491     if (deflateReset(m_deflate
) != Z_OK
) { 
 492         wxLogError(_("can't re-initialize zlib deflate stream")); 
 493         m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
 500 class wxZlibInputStream2 
: public wxZlibInputStream
 
 503     wxZlibInputStream2(wxInputStream
& stream
) : 
 504         wxZlibInputStream(stream
, wxZLIB_NO_HEADER
) { } 
 506     bool Open(wxInputStream
& stream
); 
 509 bool wxZlibInputStream2::Open(wxInputStream
& stream
) 
 511     m_inflate
->avail_in 
= 0; 
 513     m_lasterror 
= wxSTREAM_NO_ERROR
; 
 514     m_parent_i_stream 
= &stream
; 
 516     if (inflateReset(m_inflate
) != Z_OK
) { 
 517         wxLogError(_("can't re-initialize zlib inflate stream")); 
 518         m_lasterror 
= wxSTREAM_READ_ERROR
; 
 526 ///////////////////////////////////////////////////////////////////////////// 
 527 // Class to hold wxZipEntry's Extra and LocalExtra fields 
 532     wxZipMemory() : m_data(NULL
), m_size(0), m_capacity(0), m_ref(1) { } 
 534     wxZipMemory 
*AddRef() { m_ref
++; return this; } 
 535     void Release() { if (--m_ref 
== 0) delete this; } 
 537     char *GetData() const { return m_data
; } 
 538     size_t GetSize() const { return m_size
; } 
 539     size_t GetCapacity() const { return m_capacity
; } 
 541     wxZipMemory 
*Unique(size_t size
); 
 544     ~wxZipMemory() { delete [] m_data
; } 
 551     wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipMemory
) 
 554 wxZipMemory 
*wxZipMemory::Unique(size_t size
) 
 560         zm 
= new wxZipMemory
; 
 565     if (zm
->m_capacity 
< size
) { 
 566         delete [] zm
->m_data
; 
 567         zm
->m_data 
= new char[size
]; 
 568         zm
->m_capacity 
= size
; 
 575 static inline wxZipMemory 
*AddRef(wxZipMemory 
*zm
) 
 582 static inline void Release(wxZipMemory 
*zm
) 
 588 static void Copy(wxZipMemory
*& dest
, wxZipMemory 
*src
) 
 594 static void Unique(wxZipMemory
*& zm
, size_t size
) 
 597         zm 
= new wxZipMemory
; 
 599         zm 
= zm
->Unique(size
); 
 603 ///////////////////////////////////////////////////////////////////////////// 
 604 // Collection of weak references to entries 
 606 WX_DECLARE_HASH_MAP(long, wxZipEntry
*, wxIntegerHash
, 
 607                     wxIntegerEqual
, wx__OffsetZipEntryMap
); 
 612     wxZipWeakLinks() : m_ref(1) { } 
 614     void Release(const wxZipInputStream
* WXUNUSED(x
)) 
 615         { if (--m_ref 
== 0) delete this; } 
 616     void Release(wxFileOffset key
) 
 617         { RemoveEntry(key
); if (--m_ref 
== 0) delete this; } 
 619     wxZipWeakLinks 
*AddEntry(wxZipEntry 
*entry
, wxFileOffset key
); 
 620     void RemoveEntry(wxFileOffset key
) 
 621         { m_entries
.erase(wx_truncate_cast(key_type
, key
)); } 
 622     wxZipEntry 
*GetEntry(wxFileOffset key
) const; 
 623     bool IsEmpty() const { return m_entries
.empty(); } 
 626     ~wxZipWeakLinks() { wxASSERT(IsEmpty()); } 
 628     typedef wx__OffsetZipEntryMap::key_type key_type
; 
 631     wx__OffsetZipEntryMap m_entries
; 
 633     wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipWeakLinks
) 
 636 wxZipWeakLinks 
*wxZipWeakLinks::AddEntry(wxZipEntry 
*entry
, wxFileOffset key
) 
 638     m_entries
[wx_truncate_cast(key_type
, key
)] = entry
; 
 643 wxZipEntry 
*wxZipWeakLinks::GetEntry(wxFileOffset key
) const 
 645     wx__OffsetZipEntryMap::const_iterator it 
= 
 646         m_entries
.find(wx_truncate_cast(key_type
, key
)); 
 647     return it 
!= m_entries
.end() ?  it
->second 
: NULL
; 
 651 ///////////////////////////////////////////////////////////////////////////// 
 654 wxZipEntry::wxZipEntry( 
 655     const wxString
& name 
/*=wxEmptyString*/, 
 656     const wxDateTime
& dt 
/*=wxDateTime::Now()*/, 
 657     wxFileOffset size    
/*=wxInvalidOffset*/) 
 659     m_SystemMadeBy(wxZIP_SYSTEM_MSDOS
), 
 660     m_VersionMadeBy(wxMAJOR_VERSION 
* 10 + wxMINOR_VERSION
), 
 661     m_VersionNeeded(VERSION_NEEDED_TO_EXTRACT
), 
 663     m_Method(wxZIP_METHOD_DEFAULT
), 
 666     m_CompressedSize(wxInvalidOffset
), 
 668     m_Key(wxInvalidOffset
), 
 669     m_Offset(wxInvalidOffset
), 
 671     m_InternalAttributes(0), 
 672     m_ExternalAttributes(0), 
 682 wxZipEntry::~wxZipEntry() 
 685         m_backlink
->Release(m_Key
); 
 687     Release(m_LocalExtra
); 
 690 wxZipEntry::wxZipEntry(const wxZipEntry
& e
) 
 692     m_SystemMadeBy(e
.m_SystemMadeBy
), 
 693     m_VersionMadeBy(e
.m_VersionMadeBy
), 
 694     m_VersionNeeded(e
.m_VersionNeeded
), 
 696     m_Method(e
.m_Method
), 
 697     m_DateTime(e
.m_DateTime
), 
 699     m_CompressedSize(e
.m_CompressedSize
), 
 703     m_Offset(e
.m_Offset
), 
 704     m_Comment(e
.m_Comment
), 
 705     m_DiskStart(e
.m_DiskStart
), 
 706     m_InternalAttributes(e
.m_InternalAttributes
), 
 707     m_ExternalAttributes(e
.m_ExternalAttributes
), 
 708     m_Extra(AddRef(e
.m_Extra
)), 
 709     m_LocalExtra(AddRef(e
.m_LocalExtra
)), 
 715 wxZipEntry
& wxZipEntry::operator=(const wxZipEntry
& e
) 
 718         m_SystemMadeBy 
= e
.m_SystemMadeBy
; 
 719         m_VersionMadeBy 
= e
.m_VersionMadeBy
; 
 720         m_VersionNeeded 
= e
.m_VersionNeeded
; 
 722         m_Method 
= e
.m_Method
; 
 723         m_DateTime 
= e
.m_DateTime
; 
 725         m_CompressedSize 
= e
.m_CompressedSize
; 
 729         m_Offset 
= e
.m_Offset
; 
 730         m_Comment 
= e
.m_Comment
; 
 731         m_DiskStart 
= e
.m_DiskStart
; 
 732         m_InternalAttributes 
= e
.m_InternalAttributes
; 
 733         m_ExternalAttributes 
= e
.m_ExternalAttributes
; 
 734         Copy(m_Extra
, e
.m_Extra
); 
 735         Copy(m_LocalExtra
, e
.m_LocalExtra
); 
 736         m_zipnotifier 
= NULL
; 
 738             m_backlink
->Release(m_Key
); 
 745 wxString 
wxZipEntry::GetName(wxPathFormat format 
/*=wxPATH_NATIVE*/) const 
 747     bool isDir 
= IsDir() && !m_Name
.empty(); 
 749     // optimisations for common (and easy) cases 
 750     switch (wxFileName::GetFormat(format
)) { 
 753             wxString 
name(isDir 
? m_Name 
+ _T("\\") : m_Name
); 
 754             for (size_t i 
= name
.length() - 1; i 
> 0; --i
) 
 755                 if (name
[i
] == _T('/')) 
 761             return isDir 
? m_Name 
+ _T("/") : m_Name
; 
 770         fn
.AssignDir(m_Name
, wxPATH_UNIX
); 
 772         fn
.Assign(m_Name
, wxPATH_UNIX
); 
 774     return fn
.GetFullPath(format
); 
 777 // Static - Internally tars and zips use forward slashes for the path 
 778 // separator, absolute paths aren't allowed, and directory names have a 
 779 // trailing slash.  This function converts a path into this internal format, 
 780 // but without a trailing slash for a directory. 
 782 wxString 
wxZipEntry::GetInternalName(const wxString
& name
, 
 783                                      wxPathFormat format 
/*=wxPATH_NATIVE*/, 
 784                                      bool *pIsDir        
/*=NULL*/) 
 788     if (wxFileName::GetFormat(format
) != wxPATH_UNIX
) 
 789         internal 
= wxFileName(name
, format
).GetFullPath(wxPATH_UNIX
); 
 793     bool isDir 
= !internal
.empty() && internal
.Last() == '/'; 
 797         internal
.erase(internal
.length() - 1); 
 799     while (!internal
.empty() && *internal
.begin() == '/') 
 800         internal
.erase(0, 1); 
 801     while (!internal
.empty() && internal
.compare(0, 2, _T("./")) == 0) 
 802         internal
.erase(0, 2); 
 803     if (internal 
== _T(".") || internal 
== _T("..")) 
 804         internal 
= wxEmptyString
; 
 809 void wxZipEntry::SetSystemMadeBy(int system
) 
 811     int mode 
= GetMode(); 
 812     bool wasUnix 
= IsMadeByUnix(); 
 814     m_SystemMadeBy 
= (wxUint8
)system
; 
 816     if (!wasUnix 
&& IsMadeByUnix()) { 
 819     } else if (wasUnix 
&& !IsMadeByUnix()) { 
 820         m_ExternalAttributes 
&= 0xffff; 
 824 void wxZipEntry::SetIsDir(bool isDir 
/*=true*/) 
 827         m_ExternalAttributes 
|= wxZIP_A_SUBDIR
; 
 829         m_ExternalAttributes 
&= ~wxZIP_A_SUBDIR
; 
 831     if (IsMadeByUnix()) { 
 832         m_ExternalAttributes 
&= ~wxZIP_S_IFMT
; 
 834             m_ExternalAttributes 
|= wxZIP_S_IFDIR
; 
 836             m_ExternalAttributes 
|= wxZIP_S_IFREG
; 
 840 // Return unix style permission bits 
 842 int wxZipEntry::GetMode() const 
 844     // return unix permissions if present 
 846         return (m_ExternalAttributes 
>> 16) & 0777; 
 848     // otherwise synthesize from the dos attribs 
 850     if (m_ExternalAttributes 
& wxZIP_A_RDONLY
) 
 852     if (m_ExternalAttributes 
& wxZIP_A_SUBDIR
) 
 858 // Set unix permissions 
 860 void wxZipEntry::SetMode(int mode
) 
 862     // Set dos attrib bits to be compatible 
 864         m_ExternalAttributes 
&= ~wxZIP_A_RDONLY
; 
 866         m_ExternalAttributes 
|= wxZIP_A_RDONLY
; 
 868     // set the actual unix permission bits if the system type allows 
 869     if (IsMadeByUnix()) { 
 870         m_ExternalAttributes 
&= ~(0777L << 16); 
 871         m_ExternalAttributes 
|= (mode 
& 0777L) << 16; 
 875 const char *wxZipEntry::GetExtra() const 
 877     return m_Extra 
? m_Extra
->GetData() : NULL
; 
 880 size_t wxZipEntry::GetExtraLen() const 
 882     return m_Extra 
? m_Extra
->GetSize() : 0; 
 885 void wxZipEntry::SetExtra(const char *extra
, size_t len
) 
 887     Unique(m_Extra
, len
); 
 889         memcpy(m_Extra
->GetData(), extra
, len
); 
 892 const char *wxZipEntry::GetLocalExtra() const 
 894     return m_LocalExtra 
? m_LocalExtra
->GetData() : NULL
; 
 897 size_t  wxZipEntry::GetLocalExtraLen() const 
 899     return m_LocalExtra 
? m_LocalExtra
->GetSize() : 0; 
 902 void wxZipEntry::SetLocalExtra(const char *extra
, size_t len
) 
 904     Unique(m_LocalExtra
, len
); 
 906         memcpy(m_LocalExtra
->GetData(), extra
, len
); 
 909 void wxZipEntry::SetNotifier(wxZipNotifier
& notifier
) 
 911     wxArchiveEntry::UnsetNotifier(); 
 912     m_zipnotifier 
= ¬ifier
; 
 913     m_zipnotifier
->OnEntryUpdated(*this); 
 916 void wxZipEntry::Notify() 
 919         m_zipnotifier
->OnEntryUpdated(*this); 
 920     else if (GetNotifier()) 
 921         GetNotifier()->OnEntryUpdated(*this); 
 924 void wxZipEntry::UnsetNotifier() 
 926     wxArchiveEntry::UnsetNotifier(); 
 927     m_zipnotifier 
= NULL
; 
 930 size_t wxZipEntry::ReadLocal(wxInputStream
& stream
, wxMBConv
& conv
) 
 932     wxUint16 nameLen
, extraLen
; 
 933     wxUint32 compressedSize
, size
, crc
; 
 935     wxZipHeader 
ds(stream
, LOCAL_SIZE 
- 4); 
 939     ds 
>> m_VersionNeeded 
>> m_Flags 
>> m_Method
; 
 940     SetDateTime(wxDateTime().SetFromDOS(ds
.Read32())); 
 941     ds 
>> crc 
>> compressedSize 
>> size 
>> nameLen 
>> extraLen
; 
 943     bool sumsValid 
= (m_Flags 
& wxZIP_SUMS_FOLLOW
) == 0; 
 945     if (sumsValid 
|| crc
) 
 947     if ((sumsValid 
|| compressedSize
) || m_Method 
== wxZIP_METHOD_STORE
) 
 948         m_CompressedSize 
= compressedSize
; 
 949     if ((sumsValid 
|| size
) || m_Method 
== wxZIP_METHOD_STORE
) 
 952     SetName(ReadString(stream
, nameLen
, conv
), wxPATH_UNIX
); 
 953     if (stream
.LastRead() != nameLen 
+ 0u) 
 956     if (extraLen 
|| GetLocalExtraLen()) { 
 957         Unique(m_LocalExtra
, extraLen
); 
 959             stream
.Read(m_LocalExtra
->GetData(), extraLen
); 
 960             if (stream
.LastRead() != extraLen 
+ 0u) 
 965     return LOCAL_SIZE 
+ nameLen 
+ extraLen
; 
 968 size_t wxZipEntry::WriteLocal(wxOutputStream
& stream
, wxMBConv
& conv
) const 
 970     wxString unixName 
= GetName(wxPATH_UNIX
); 
 971     const wxWX2MBbuf name_buf 
= conv
.cWX2MB(unixName
); 
 972     const char *name 
= name_buf
; 
 973     if (!name
) name 
= ""; 
 974     wxUint16 nameLen 
= wx_truncate_cast(wxUint16
, strlen(name
)); 
 976     wxDataOutputStream 
ds(stream
); 
 978     ds 
<< m_VersionNeeded 
<< m_Flags 
<< m_Method
; 
 979     ds
.Write32(GetDateTime().GetAsDOS()); 
 982     ds
.Write32(m_CompressedSize 
!= wxInvalidOffset 
? 
 983                wx_truncate_cast(wxUint32
, m_CompressedSize
) : 0); 
 984     ds
.Write32(m_Size 
!= wxInvalidOffset 
? 
 985                wx_truncate_cast(wxUint32
, m_Size
) : 0); 
 988     wxUint16 extraLen 
= wx_truncate_cast(wxUint16
, GetLocalExtraLen()); 
 989     ds
.Write16(extraLen
); 
 991     stream
.Write(name
, nameLen
); 
 993         stream
.Write(m_LocalExtra
->GetData(), extraLen
); 
 995     return LOCAL_SIZE 
+ nameLen 
+ extraLen
; 
 998 size_t wxZipEntry::ReadCentral(wxInputStream
& stream
, wxMBConv
& conv
) 
1000     wxUint16 nameLen
, extraLen
, commentLen
; 
1002     wxZipHeader 
ds(stream
, CENTRAL_SIZE 
- 4); 
1006     ds 
>> m_VersionMadeBy 
>> m_SystemMadeBy
; 
1008     SetVersionNeeded(ds
.Read16()); 
1009     SetFlags(ds
.Read16()); 
1010     SetMethod(ds
.Read16()); 
1011     SetDateTime(wxDateTime().SetFromDOS(ds
.Read32())); 
1012     SetCrc(ds
.Read32()); 
1013     SetCompressedSize(ds
.Read32()); 
1014     SetSize(ds
.Read32()); 
1016     ds 
>> nameLen 
>> extraLen 
>> commentLen
 
1017        >> m_DiskStart 
>> m_InternalAttributes 
>> m_ExternalAttributes
; 
1018     SetOffset(ds
.Read32()); 
1020     SetName(ReadString(stream
, nameLen
, conv
), wxPATH_UNIX
); 
1021     if (stream
.LastRead() != nameLen 
+ 0u) 
1024     if (extraLen 
|| GetExtraLen()) { 
1025         Unique(m_Extra
, extraLen
); 
1027             stream
.Read(m_Extra
->GetData(), extraLen
); 
1028             if (stream
.LastRead() != extraLen 
+ 0u) 
1034         m_Comment 
= ReadString(stream
, commentLen
, conv
); 
1035         if (stream
.LastRead() != commentLen 
+ 0u) 
1041     return CENTRAL_SIZE 
+ nameLen 
+ extraLen 
+ commentLen
; 
1044 size_t wxZipEntry::WriteCentral(wxOutputStream
& stream
, wxMBConv
& conv
) const 
1046     wxString unixName 
= GetName(wxPATH_UNIX
); 
1047     const wxWX2MBbuf name_buf 
= conv
.cWX2MB(unixName
); 
1048     const char *name 
= name_buf
; 
1049     if (!name
) name 
= ""; 
1050     wxUint16 nameLen 
= wx_truncate_cast(wxUint16
, strlen(name
)); 
1052     const wxWX2MBbuf comment_buf 
= conv
.cWX2MB(m_Comment
); 
1053     const char *comment 
= comment_buf
; 
1054     if (!comment
) comment 
= ""; 
1055     wxUint16 commentLen 
= wx_truncate_cast(wxUint16
, strlen(comment
)); 
1057     wxUint16 extraLen 
= wx_truncate_cast(wxUint16
, GetExtraLen()); 
1059     wxDataOutputStream 
ds(stream
); 
1061     ds 
<< CENTRAL_MAGIC 
<< m_VersionMadeBy 
<< m_SystemMadeBy
; 
1063     ds
.Write16(wx_truncate_cast(wxUint16
, GetVersionNeeded())); 
1064     ds
.Write16(wx_truncate_cast(wxUint16
, GetFlags())); 
1065     ds
.Write16(wx_truncate_cast(wxUint16
, GetMethod())); 
1066     ds
.Write32(GetDateTime().GetAsDOS()); 
1067     ds
.Write32(GetCrc()); 
1068     ds
.Write32(wx_truncate_cast(wxUint32
, GetCompressedSize())); 
1069     ds
.Write32(wx_truncate_cast(wxUint32
, GetSize())); 
1070     ds
.Write16(nameLen
); 
1071     ds
.Write16(extraLen
); 
1073     ds 
<< commentLen 
<< m_DiskStart 
<< m_InternalAttributes
 
1074        << m_ExternalAttributes 
<< wx_truncate_cast(wxUint32
, GetOffset()); 
1076     stream
.Write(name
, nameLen
); 
1078         stream
.Write(GetExtra(), extraLen
); 
1079     stream
.Write(comment
, commentLen
); 
1081     return CENTRAL_SIZE 
+ nameLen 
+ extraLen 
+ commentLen
; 
1084 // Info-zip prefixes this record with a signature, but pkzip doesn't. So if 
1085 // the 1st value is the signature then it is probably an info-zip record, 
1086 // though there is a small chance that it is in fact a pkzip record which 
1087 // happens to have the signature as it's CRC. 
1089 size_t wxZipEntry::ReadDescriptor(wxInputStream
& stream
) 
1091     wxZipHeader 
ds(stream
, SUMS_SIZE
); 
1095     m_Crc 
= ds
.Read32(); 
1096     m_CompressedSize 
= ds
.Read32(); 
1097     m_Size 
= ds
.Read32(); 
1099     // if 1st value is the signature then this is probably an info-zip record 
1100     if (m_Crc 
== SUMS_MAGIC
) 
1102         wxZipHeader 
buf(stream
, 8); 
1103         wxUint32 u1 
= buf
.GetSize() >= 4 ? buf
.Read32() : (wxUint32
)LOCAL_MAGIC
; 
1104         wxUint32 u2 
= buf
.GetSize() == 8 ? buf
.Read32() : 0; 
1106         // look for the signature of the following record to decide which 
1107         if ((u1 
== LOCAL_MAGIC 
|| u1 
== CENTRAL_MAGIC
) && 
1108             (u2 
!= LOCAL_MAGIC 
&& u2 
!= CENTRAL_MAGIC
)) 
1110             // it's a pkzip style record after all! 
1111             if (buf
.GetSize() > 0) 
1112                 stream
.Ungetch(buf
.GetData(), buf
.GetSize()); 
1116             // it's an info-zip record as expected 
1117             if (buf
.GetSize() > 4) 
1118                 stream
.Ungetch(buf
.GetData() + 4, buf
.GetSize() - 4); 
1119             m_Crc 
= wx_truncate_cast(wxUint32
, m_CompressedSize
); 
1120             m_CompressedSize 
= m_Size
; 
1122             return SUMS_SIZE 
+ 4; 
1129 size_t wxZipEntry::WriteDescriptor(wxOutputStream
& stream
, wxUint32 crc
, 
1130                                    wxFileOffset compressedSize
, wxFileOffset size
) 
1133     m_CompressedSize 
= compressedSize
; 
1136     wxDataOutputStream 
ds(stream
); 
1139     ds
.Write32(wx_truncate_cast(wxUint32
, compressedSize
)); 
1140     ds
.Write32(wx_truncate_cast(wxUint32
, size
)); 
1146 ///////////////////////////////////////////////////////////////////////////// 
1147 // wxZipEndRec - holds the end of central directory record 
1154     int GetDiskNumber() const                   { return m_DiskNumber
; } 
1155     int GetStartDisk() const                    { return m_StartDisk
; } 
1156     int GetEntriesHere() const                  { return m_EntriesHere
; } 
1157     int GetTotalEntries() const                 { return m_TotalEntries
; } 
1158     wxFileOffset 
GetSize() const                { return m_Size
; } 
1159     wxFileOffset 
GetOffset() const              { return m_Offset
; } 
1160     wxString 
GetComment() const                 { return m_Comment
; } 
1162     void SetDiskNumber(int num
) 
1163         { m_DiskNumber 
= wx_truncate_cast(wxUint16
, num
); } 
1164     void SetStartDisk(int num
) 
1165         { m_StartDisk 
= wx_truncate_cast(wxUint16
, num
); } 
1166     void SetEntriesHere(int num
) 
1167         { m_EntriesHere 
= wx_truncate_cast(wxUint16
, num
); } 
1168     void SetTotalEntries(int num
) 
1169         { m_TotalEntries 
= wx_truncate_cast(wxUint16
, num
); } 
1170     void SetSize(wxFileOffset size
) 
1171         { m_Size 
= wx_truncate_cast(wxUint32
, size
); } 
1172     void SetOffset(wxFileOffset offset
) 
1173         { m_Offset 
= wx_truncate_cast(wxUint32
, offset
); } 
1174     void SetComment(const wxString
& comment
) 
1175         { m_Comment 
= comment
; } 
1177     bool Read(wxInputStream
& stream
, wxMBConv
& conv
); 
1178     bool Write(wxOutputStream
& stream
, wxMBConv
& conv
) const; 
1181     wxUint16 m_DiskNumber
; 
1182     wxUint16 m_StartDisk
; 
1183     wxUint16 m_EntriesHere
; 
1184     wxUint16 m_TotalEntries
; 
1190 wxZipEndRec::wxZipEndRec() 
1200 bool wxZipEndRec::Write(wxOutputStream
& stream
, wxMBConv
& conv
) const 
1202     const wxWX2MBbuf comment_buf 
= conv
.cWX2MB(m_Comment
); 
1203     const char *comment 
= comment_buf
; 
1204     if (!comment
) comment 
= ""; 
1205     wxUint16 commentLen 
= (wxUint16
)strlen(comment
); 
1207     wxDataOutputStream 
ds(stream
); 
1209     ds 
<< END_MAGIC 
<< m_DiskNumber 
<< m_StartDisk 
<< m_EntriesHere
 
1210        << m_TotalEntries 
<< m_Size 
<< m_Offset 
<< commentLen
; 
1212     stream
.Write(comment
, commentLen
); 
1214     return stream
.IsOk(); 
1217 bool wxZipEndRec::Read(wxInputStream
& stream
, wxMBConv
& conv
) 
1219     wxZipHeader 
ds(stream
, END_SIZE 
- 4); 
1223     wxUint16 commentLen
; 
1225     ds 
>> m_DiskNumber 
>> m_StartDisk 
>> m_EntriesHere
 
1226        >> m_TotalEntries 
>> m_Size 
>> m_Offset 
>> commentLen
; 
1229         m_Comment 
= ReadString(stream
, commentLen
, conv
); 
1230         if (stream
.LastRead() != commentLen 
+ 0u) 
1234     if (m_DiskNumber 
!= 0 || m_StartDisk 
!= 0 || 
1235             m_EntriesHere 
!= m_TotalEntries
) 
1236         wxLogWarning(_("assuming this is a multi-part zip concatenated")); 
1242 ///////////////////////////////////////////////////////////////////////////// 
1243 // A weak link from an input stream to an output stream 
1245 class wxZipStreamLink
 
1248     wxZipStreamLink(wxZipOutputStream 
*stream
) : m_ref(1), m_stream(stream
) { } 
1250     wxZipStreamLink 
*AddRef() { m_ref
++; return this; } 
1251     wxZipOutputStream 
*GetOutputStream() const { return m_stream
; } 
1253     void Release(class wxZipInputStream 
*WXUNUSED(s
)) 
1254         { if (--m_ref 
== 0) delete this; } 
1255     void Release(class wxZipOutputStream 
*WXUNUSED(s
)) 
1256         { m_stream 
= NULL
; if (--m_ref 
== 0) delete this; } 
1259     ~wxZipStreamLink() { } 
1262     wxZipOutputStream 
*m_stream
; 
1264     wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipStreamLink
) 
1268 ///////////////////////////////////////////////////////////////////////////// 
1271 // leave the default wxZipEntryPtr free for users 
1272 wxDECLARE_SCOPED_PTR(wxZipEntry
, wx__ZipEntryPtr
) 
1273 wxDEFINE_SCOPED_PTR (wxZipEntry
, wx__ZipEntryPtr
) 
1277 wxZipInputStream::wxZipInputStream(wxInputStream
& stream
, 
1278                                    wxMBConv
& conv 
/*=wxConvLocal*/) 
1279   : wxArchiveInputStream(stream
, conv
) 
1284 #if 1 //WXWIN_COMPATIBILITY_2_6 
1286 // Part of the compatibility constructor, which has been made inline to 
1287 // avoid a problem with it not being exported by mingw 3.2.3 
1289 void wxZipInputStream::Init(const wxString
& file
) 
1291     // no error messages 
1294     m_allowSeeking 
= true; 
1295     m_ffile 
= wx_static_cast(wxFFileInputStream
*, m_parent_i_stream
); 
1296     wx__ZipEntryPtr entry
; 
1298     if (m_ffile
->Ok()) { 
1300             entry
.reset(GetNextEntry()); 
1302         while (entry
.get() != NULL 
&& entry
->GetInternalName() != file
); 
1305     if (entry
.get() == NULL
) 
1306         m_lasterror 
= wxSTREAM_READ_ERROR
; 
1309 wxInputStream
& wxZipInputStream::OpenFile(const wxString
& archive
) 
1312     return *new wxFFileInputStream(archive
); 
1315 #endif // WXWIN_COMPATIBILITY_2_6 
1317 void wxZipInputStream::Init() 
1319     m_store 
= new wxStoredInputStream(*m_parent_i_stream
); 
1325     m_parentSeekable 
= false; 
1326     m_weaklinks 
= new wxZipWeakLinks
; 
1327     m_streamlink 
= NULL
; 
1328     m_offsetAdjustment 
= 0; 
1329     m_position 
= wxInvalidOffset
; 
1332     m_lasterror 
= m_parent_i_stream
->GetLastError(); 
1334 #if 1 //WXWIN_COMPATIBILITY_2_6 
1335     m_allowSeeking 
= false; 
1339 wxZipInputStream::~wxZipInputStream() 
1341     CloseDecompressor(m_decomp
); 
1348     m_weaklinks
->Release(this); 
1351         m_streamlink
->Release(this); 
1354 wxString 
wxZipInputStream::GetComment() 
1356     if (m_position 
== wxInvalidOffset
) 
1357         if (!LoadEndRecord()) 
1358             return wxEmptyString
; 
1360     if (!m_parentSeekable 
&& Eof() && m_signature
) { 
1361         m_lasterror 
= wxSTREAM_NO_ERROR
; 
1362         m_lasterror 
= ReadLocal(true); 
1368 int wxZipInputStream::GetTotalEntries() 
1370     if (m_position 
== wxInvalidOffset
) 
1372     return m_TotalEntries
; 
1375 wxZipStreamLink 
*wxZipInputStream::MakeLink(wxZipOutputStream 
*out
) 
1377     wxZipStreamLink 
*link 
= NULL
; 
1379     if (!m_parentSeekable 
&& (IsOpened() || !Eof())) { 
1380         link 
= new wxZipStreamLink(out
); 
1382             m_streamlink
->Release(this); 
1383         m_streamlink 
= link
->AddRef(); 
1389 bool wxZipInputStream::LoadEndRecord() 
1391     wxCHECK(m_position 
== wxInvalidOffset
, false); 
1397     // First find the end-of-central-directory record. 
1398     if (!FindEndRecord()) { 
1399         // failed, so either this is a non-seekable stream (ok), or not a zip 
1400         if (m_parentSeekable
) { 
1401             m_lasterror 
= wxSTREAM_READ_ERROR
; 
1402             wxLogError(_("invalid zip file")); 
1407             wxFileOffset pos 
= m_parent_i_stream
->TellI(); 
1408             if (pos 
!= wxInvalidOffset
) 
1409                 m_offsetAdjustment 
= m_position 
= pos
; 
1416     // Read in the end record 
1417     wxFileOffset endPos 
= m_parent_i_stream
->TellI() - 4; 
1418     if (!endrec
.Read(*m_parent_i_stream
, GetConv())) 
1421     m_TotalEntries 
= endrec
.GetTotalEntries(); 
1422     m_Comment 
= endrec
.GetComment(); 
1424     // Now find the central-directory. we have the file offset of 
1425     // the CD, so look there first. 
1426     if (m_parent_i_stream
->SeekI(endrec
.GetOffset()) != wxInvalidOffset 
&& 
1427             ReadSignature() == CENTRAL_MAGIC
) { 
1428         m_signature 
= CENTRAL_MAGIC
; 
1429         m_position 
= endrec
.GetOffset(); 
1430         m_offsetAdjustment 
= 0; 
1434     // If it's not there, then it could be that the zip has been appended 
1435     // to a self extractor, so take the CD size (also in endrec), subtract 
1436     // it from the file offset of the end-central-directory and look there. 
1437     if (m_parent_i_stream
->SeekI(endPos 
- endrec
.GetSize()) 
1438             != wxInvalidOffset 
&& ReadSignature() == CENTRAL_MAGIC
) { 
1439         m_signature 
= CENTRAL_MAGIC
; 
1440         m_position 
= endPos 
- endrec
.GetSize(); 
1441         m_offsetAdjustment 
= m_position 
- endrec
.GetOffset(); 
1445     wxLogError(_("can't find central directory in zip")); 
1446     m_lasterror 
= wxSTREAM_READ_ERROR
; 
1450 // Find the end-of-central-directory record. 
1451 // If found the stream will be positioned just past the 4 signature bytes. 
1453 bool wxZipInputStream::FindEndRecord() 
1455     if (!m_parent_i_stream
->IsSeekable()) 
1458     // usually it's 22 bytes in size and the last thing in the file 
1461         if (m_parent_i_stream
->SeekI(-END_SIZE
, wxFromEnd
) == wxInvalidOffset
) 
1465     m_parentSeekable 
= true; 
1468     if (m_parent_i_stream
->Read(magic
, 4).LastRead() != 4) 
1470     if ((m_signature 
= CrackUint32(magic
)) == END_MAGIC
) 
1473     // unfortunately, the record has a comment field that can be up to 65535 
1474     // bytes in length, so if the signature not found then search backwards. 
1475     wxFileOffset pos 
= m_parent_i_stream
->TellI(); 
1476     const int BUFSIZE 
= 1024; 
1477     wxCharBuffer 
buf(BUFSIZE
); 
1479     memcpy(buf
.data(), magic
, 3); 
1480     wxFileOffset minpos 
= wxMax(pos 
- 65535L, 0); 
1482     while (pos 
> minpos
) { 
1483         size_t len 
= wx_truncate_cast(size_t, 
1484                         pos 
- wxMax(pos 
- (BUFSIZE 
- 3), minpos
)); 
1485         memcpy(buf
.data() + len
, buf
, 3); 
1488         if (m_parent_i_stream
->SeekI(pos
, wxFromStart
) == wxInvalidOffset 
|| 
1489                 m_parent_i_stream
->Read(buf
.data(), len
).LastRead() != len
) 
1492         char *p 
= buf
.data() + len
; 
1494         while (p
-- > buf
.data()) { 
1495             if ((m_signature 
= CrackUint32(p
)) == END_MAGIC
) { 
1496                 size_t remainder 
= buf
.data() + len 
- p
; 
1498                     m_parent_i_stream
->Ungetch(p 
+ 4, remainder 
- 4); 
1507 wxZipEntry 
*wxZipInputStream::GetNextEntry() 
1509     if (m_position 
== wxInvalidOffset
) 
1510         if (!LoadEndRecord()) 
1513     m_lasterror 
= m_parentSeekable 
? ReadCentral() : ReadLocal(); 
1517     wx__ZipEntryPtr 
entry(new wxZipEntry(m_entry
)); 
1518     entry
->m_backlink 
= m_weaklinks
->AddEntry(entry
.get(), entry
->GetKey()); 
1519     return entry
.release(); 
1522 wxStreamError 
wxZipInputStream::ReadCentral() 
1527     if (m_signature 
== END_MAGIC
) 
1528         return wxSTREAM_EOF
; 
1530     if (m_signature 
!= CENTRAL_MAGIC
) { 
1531         wxLogError(_("error reading zip central directory")); 
1532         return wxSTREAM_READ_ERROR
; 
1535     if (QuietSeek(*m_parent_i_stream
, m_position 
+ 4) == wxInvalidOffset
) 
1536         return wxSTREAM_READ_ERROR
; 
1538     size_t size 
= m_entry
.ReadCentral(*m_parent_i_stream
, GetConv()); 
1541         return wxSTREAM_READ_ERROR
; 
1545     m_signature 
= ReadSignature(); 
1547     if (m_offsetAdjustment
) 
1548         m_entry
.SetOffset(m_entry
.GetOffset() + m_offsetAdjustment
); 
1549     m_entry
.SetKey(m_entry
.GetOffset()); 
1551     return wxSTREAM_NO_ERROR
; 
1554 wxStreamError 
wxZipInputStream::ReadLocal(bool readEndRec 
/*=false*/) 
1560         m_signature 
= ReadSignature(); 
1562     if (m_signature 
== CENTRAL_MAGIC 
|| m_signature 
== END_MAGIC
) { 
1563         if (m_streamlink 
&& !m_streamlink
->GetOutputStream()) { 
1564             m_streamlink
->Release(this); 
1565             m_streamlink 
= NULL
; 
1569     while (m_signature 
== CENTRAL_MAGIC
) { 
1570         if (m_weaklinks
->IsEmpty() && m_streamlink 
== NULL
) 
1571             return wxSTREAM_EOF
; 
1573         size_t size 
= m_entry
.ReadCentral(*m_parent_i_stream
, GetConv()); 
1577             return wxSTREAM_READ_ERROR
; 
1579         wxZipEntry 
*entry 
= m_weaklinks
->GetEntry(m_entry
.GetOffset()); 
1581             entry
->SetSystemMadeBy(m_entry
.GetSystemMadeBy()); 
1582             entry
->SetVersionMadeBy(m_entry
.GetVersionMadeBy()); 
1583             entry
->SetComment(m_entry
.GetComment()); 
1584             entry
->SetDiskStart(m_entry
.GetDiskStart()); 
1585             entry
->SetInternalAttributes(m_entry
.GetInternalAttributes()); 
1586             entry
->SetExternalAttributes(m_entry
.GetExternalAttributes()); 
1587             Copy(entry
->m_Extra
, m_entry
.m_Extra
); 
1589             m_weaklinks
->RemoveEntry(entry
->GetOffset()); 
1592         m_signature 
= ReadSignature(); 
1595     if (m_signature 
== END_MAGIC
) { 
1596         if (readEndRec 
|| m_streamlink
) { 
1598             endrec
.Read(*m_parent_i_stream
, GetConv()); 
1599             m_Comment 
= endrec
.GetComment(); 
1602                 m_streamlink
->GetOutputStream()->SetComment(endrec
.GetComment()); 
1603                 m_streamlink
->Release(this); 
1604                 m_streamlink 
= NULL
; 
1607         return wxSTREAM_EOF
; 
1610     if (m_signature 
!= LOCAL_MAGIC
) { 
1611         wxLogError(_("error reading zip local header")); 
1612         return wxSTREAM_READ_ERROR
; 
1615     m_headerSize 
= m_entry
.ReadLocal(*m_parent_i_stream
, GetConv()); 
1617     m_entry
.SetOffset(m_position
); 
1618     m_entry
.SetKey(m_position
); 
1620     if (!m_headerSize
) { 
1621         return wxSTREAM_READ_ERROR
; 
1624         return wxSTREAM_NO_ERROR
; 
1628 wxUint32 
wxZipInputStream::ReadSignature() 
1631     m_parent_i_stream
->Read(magic
, 4); 
1632     return m_parent_i_stream
->LastRead() == 4 ? CrackUint32(magic
) : 0; 
1635 bool wxZipInputStream::OpenEntry(wxArchiveEntry
& entry
) 
1637     wxZipEntry 
*zipEntry 
= wxStaticCast(&entry
, wxZipEntry
); 
1638     return zipEntry 
? OpenEntry(*zipEntry
) : false; 
1643 bool wxZipInputStream::DoOpen(wxZipEntry 
*entry
, bool raw
) 
1645     if (m_position 
== wxInvalidOffset
) 
1646         if (!LoadEndRecord()) 
1648     if (m_lasterror 
== wxSTREAM_READ_ERROR
) 
1656         if (AfterHeader() && entry
->GetKey() == m_entry
.GetOffset()) 
1658         // can only open the current entry on a non-seekable stream 
1659         wxCHECK(m_parentSeekable
, false); 
1662     m_lasterror 
= wxSTREAM_READ_ERROR
; 
1667     if (m_parentSeekable
) { 
1668         if (QuietSeek(*m_parent_i_stream
, m_entry
.GetOffset()) 
1671         if (ReadSignature() != LOCAL_MAGIC
) { 
1672             wxLogError(_("bad zipfile offset to entry")); 
1677     if (m_parentSeekable 
|| AtHeader()) { 
1678         m_headerSize 
= m_entry
.ReadLocal(*m_parent_i_stream
, GetConv()); 
1679         if (m_headerSize 
&& m_parentSeekable
) { 
1680             wxZipEntry 
*ref 
= m_weaklinks
->GetEntry(m_entry
.GetKey()); 
1682                 Copy(ref
->m_LocalExtra
, m_entry
.m_LocalExtra
); 
1684                 m_weaklinks
->RemoveEntry(ref
->GetKey()); 
1686             if (entry 
&& entry 
!= ref
) { 
1687                 Copy(entry
->m_LocalExtra
, m_entry
.m_LocalExtra
); 
1694         m_lasterror 
= wxSTREAM_NO_ERROR
; 
1698 bool wxZipInputStream::OpenDecompressor(bool raw 
/*=false*/) 
1700     wxASSERT(AfterHeader()); 
1702     wxFileOffset compressedSize 
= m_entry
.GetCompressedSize(); 
1708         if (compressedSize 
!= wxInvalidOffset
) { 
1709             m_store
->Open(compressedSize
); 
1713                 m_rawin 
= new wxRawInputStream(*m_parent_i_stream
); 
1714             m_decomp 
= m_rawin
->Open(OpenDecompressor(m_rawin
->GetTee())); 
1717         if (compressedSize 
!= wxInvalidOffset 
&& 
1718                 (m_entry
.GetMethod() != wxZIP_METHOD_DEFLATE 
|| 
1719                  wxZlibInputStream::CanHandleGZip())) { 
1720             m_store
->Open(compressedSize
); 
1721             m_decomp 
= OpenDecompressor(*m_store
); 
1723             m_decomp 
= OpenDecompressor(*m_parent_i_stream
); 
1727     m_crcAccumulator 
= crc32(0, Z_NULL
, 0); 
1728     m_lasterror 
= m_decomp 
? m_decomp
->GetLastError() : wxSTREAM_READ_ERROR
; 
1732 // Can be overriden to add support for additional decompression methods 
1734 wxInputStream 
*wxZipInputStream::OpenDecompressor(wxInputStream
& stream
) 
1736     switch (m_entry
.GetMethod()) { 
1737         case wxZIP_METHOD_STORE
: 
1738             if (m_entry
.GetSize() == wxInvalidOffset
) { 
1739                 wxLogError(_("stored file length not in Zip header")); 
1742             m_store
->Open(m_entry
.GetSize()); 
1745         case wxZIP_METHOD_DEFLATE
: 
1747                 m_inflate 
= new wxZlibInputStream2(stream
); 
1749                 m_inflate
->Open(stream
); 
1753             wxLogError(_("unsupported Zip compression method")); 
1759 bool wxZipInputStream::CloseDecompressor(wxInputStream 
*decomp
) 
1761     if (decomp 
&& decomp 
== m_rawin
) 
1762         return CloseDecompressor(m_rawin
->GetFilterInputStream()); 
1763     if (decomp 
!= m_store 
&& decomp 
!= m_inflate
) 
1768 // Closes the current entry and positions the underlying stream at the start 
1769 // of the next entry 
1771 bool wxZipInputStream::CloseEntry() 
1775     if (m_lasterror 
== wxSTREAM_READ_ERROR
) 
1778     if (!m_parentSeekable
) { 
1779         if (!IsOpened() && !OpenDecompressor(true)) 
1782         const int BUFSIZE 
= 8192; 
1783         wxCharBuffer 
buf(BUFSIZE
); 
1785             Read(buf
.data(), BUFSIZE
); 
1787         m_position 
+= m_headerSize 
+ m_entry
.GetCompressedSize(); 
1790     if (m_lasterror 
== wxSTREAM_EOF
) 
1791         m_lasterror 
= wxSTREAM_NO_ERROR
; 
1793     CloseDecompressor(m_decomp
); 
1795     m_entry 
= wxZipEntry(); 
1802 size_t wxZipInputStream::OnSysRead(void *buffer
, size_t size
) 
1805         if ((AtHeader() && !DoOpen()) || !OpenDecompressor()) 
1806             m_lasterror 
= wxSTREAM_READ_ERROR
; 
1807     if (!IsOk() || !size
) 
1810     size_t count 
= m_decomp
->Read(buffer
, size
).LastRead(); 
1812         m_crcAccumulator 
= crc32(m_crcAccumulator
, (Byte
*)buffer
, count
); 
1814         m_lasterror 
= m_decomp
->GetLastError(); 
1817         if ((m_entry
.GetFlags() & wxZIP_SUMS_FOLLOW
) != 0) { 
1818             m_headerSize 
+= m_entry
.ReadDescriptor(*m_parent_i_stream
); 
1819             wxZipEntry 
*entry 
= m_weaklinks
->GetEntry(m_entry
.GetKey()); 
1822                 entry
->SetCrc(m_entry
.GetCrc()); 
1823                 entry
->SetCompressedSize(m_entry
.GetCompressedSize()); 
1824                 entry
->SetSize(m_entry
.GetSize()); 
1830             m_lasterror 
= wxSTREAM_READ_ERROR
; 
1832             if (m_entry
.GetSize() != TellI()) 
1833                 wxLogError(_("reading zip stream (entry %s): bad length"), 
1834                            m_entry
.GetName().c_str()); 
1835             else if (m_crcAccumulator 
!= m_entry
.GetCrc()) 
1836                 wxLogError(_("reading zip stream (entry %s): bad crc"), 
1837                            m_entry
.GetName().c_str()); 
1839                 m_lasterror 
= wxSTREAM_EOF
; 
1846 #if 1 //WXWIN_COMPATIBILITY_2_6 
1848 // Borrowed from VS's zip stream (c) 1999 Vaclav Slavik 
1850 wxFileOffset 
wxZipInputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
) 
1852     // seeking works when the stream is created with the compatibility 
1854     if (!m_allowSeeking
) 
1855         return wxInvalidOffset
; 
1857         if ((AtHeader() && !DoOpen()) || !OpenDecompressor()) 
1858             m_lasterror 
= wxSTREAM_READ_ERROR
; 
1860         return wxInvalidOffset
; 
1862     // NB: since ZIP files don't natively support seeking, we have to 
1863     //     implement a brute force workaround -- reading all the data 
1864     //     between current and the new position (or between beginning of 
1865     //     the file and new position...) 
1867     wxFileOffset nextpos
; 
1868     wxFileOffset pos 
= TellI(); 
1872         case wxFromCurrent 
: nextpos 
= seek 
+ pos
; break; 
1873         case wxFromStart 
: nextpos 
= seek
; break; 
1874         case wxFromEnd 
: nextpos 
= GetLength() + seek
; break; 
1875         default : nextpos 
= pos
; break; /* just to fool compiler, never happens */ 
1878     wxFileOffset toskip 
wxDUMMY_INITIALIZE(0); 
1879     if ( nextpos 
>= pos 
) 
1881         toskip 
= nextpos 
- pos
; 
1885         wxZipEntry 
current(m_entry
); 
1886         if (!OpenEntry(current
)) 
1888             m_lasterror 
= wxSTREAM_READ_ERROR
; 
1896         const int BUFSIZE 
= 4096; 
1898         char buffer
[BUFSIZE
]; 
1899         while ( toskip 
> 0 ) 
1901             sz 
= wx_truncate_cast(size_t, wxMin(toskip
, BUFSIZE
)); 
1911 #endif // WXWIN_COMPATIBILITY_2_6 
1914 ///////////////////////////////////////////////////////////////////////////// 
1917 #include "wx/listimpl.cpp" 
1918 WX_DEFINE_LIST(wx__ZipEntryList
) 
1920 wxZipOutputStream::wxZipOutputStream(wxOutputStream
& stream
, 
1922                                      wxMBConv
& conv 
/*=wxConvLocal*/) 
1923   : wxArchiveOutputStream(stream
, conv
), 
1924     m_store(new wxStoredOutputStream(stream
)), 
1927     m_initialData(new char[OUTPUT_LATENCY
]), 
1936     m_offsetAdjustment(wxInvalidOffset
) 
1940 wxZipOutputStream::~wxZipOutputStream() 
1943     WX_CLEAR_LIST(wx__ZipEntryList
, m_entries
); 
1947     delete [] m_initialData
; 
1949         m_backlink
->Release(this); 
1952 bool wxZipOutputStream::PutNextEntry( 
1953     const wxString
& name
, 
1954     const wxDateTime
& dt 
/*=wxDateTime::Now()*/, 
1955     wxFileOffset size    
/*=wxInvalidOffset*/) 
1957     return PutNextEntry(new wxZipEntry(name
, dt
, size
)); 
1960 bool wxZipOutputStream::PutNextDirEntry( 
1961     const wxString
& name
, 
1962     const wxDateTime
& dt 
/*=wxDateTime::Now()*/) 
1964     wxZipEntry 
*entry 
= new wxZipEntry(name
, dt
); 
1966     return PutNextEntry(entry
); 
1969 bool wxZipOutputStream::CopyEntry(wxZipEntry 
*entry
, 
1970                                   wxZipInputStream
& inputStream
) 
1972     wx__ZipEntryPtr 
e(entry
); 
1975         inputStream
.DoOpen(e
.get(), true) && 
1976         DoCreate(e
.release(), true) && 
1977         Write(inputStream
).IsOk() && inputStream
.Eof(); 
1980 bool wxZipOutputStream::PutNextEntry(wxArchiveEntry 
*entry
) 
1982     wxZipEntry 
*zipEntry 
= wxStaticCast(entry
, wxZipEntry
); 
1985     return PutNextEntry(zipEntry
); 
1988 bool wxZipOutputStream::CopyEntry(wxArchiveEntry 
*entry
, 
1989                                   wxArchiveInputStream
& stream
) 
1991     wxZipEntry 
*zipEntry 
= wxStaticCast(entry
, wxZipEntry
); 
1993     if (!zipEntry 
|| !stream
.OpenEntry(*zipEntry
)) { 
1998     return CopyEntry(zipEntry
, wx_static_cast(wxZipInputStream
&, stream
)); 
2001 bool wxZipOutputStream::CopyArchiveMetaData(wxZipInputStream
& inputStream
) 
2003     m_Comment 
= inputStream
.GetComment(); 
2005         m_backlink
->Release(this); 
2006     m_backlink 
= inputStream
.MakeLink(this); 
2010 bool wxZipOutputStream::CopyArchiveMetaData(wxArchiveInputStream
& stream
) 
2012     return CopyArchiveMetaData(wx_static_cast(wxZipInputStream
&, stream
)); 
2015 void wxZipOutputStream::SetLevel(int level
) 
2017     if (level 
!= m_level
) { 
2018         if (m_comp 
!= m_deflate
) 
2025 bool wxZipOutputStream::DoCreate(wxZipEntry 
*entry
, bool raw 
/*=false*/) 
2033     // write the signature bytes right away 
2034     wxDataOutputStream 
ds(*m_parent_o_stream
); 
2037     // and if this is the first entry test for seekability 
2038     if (m_headerOffset 
== 0 && m_parent_o_stream
->IsSeekable()) { 
2040         bool logging 
= wxLog::IsEnabled(); 
2043         wxFileOffset here 
= m_parent_o_stream
->TellO(); 
2045         if (here 
!= wxInvalidOffset 
&& here 
>= 4) { 
2046             if (m_parent_o_stream
->SeekO(here 
- 4) == here 
- 4) { 
2047                 m_offsetAdjustment 
= here 
- 4; 
2049                 wxLog::EnableLogging(logging
); 
2051                 m_parent_o_stream
->SeekO(here
); 
2056     m_pending
->SetOffset(m_headerOffset
); 
2058     m_crcAccumulator 
= crc32(0, Z_NULL
, 0); 
2063     m_lasterror 
= wxSTREAM_NO_ERROR
; 
2067 // Can be overriden to add support for additional compression methods 
2069 wxOutputStream 
*wxZipOutputStream::OpenCompressor( 
2070     wxOutputStream
& stream
, 
2072     const Buffer bufs
[]) 
2074     if (entry
.GetMethod() == wxZIP_METHOD_DEFAULT
) { 
2076                 && (IsParentSeekable() 
2077                     || entry
.GetCompressedSize() != wxInvalidOffset
 
2078                     || entry
.GetSize() != wxInvalidOffset
)) { 
2079             entry
.SetMethod(wxZIP_METHOD_STORE
); 
2082             for (int i 
= 0; bufs
[i
].m_data
; ++i
) 
2083                 size 
+= bufs
[i
].m_size
; 
2084             entry
.SetMethod(size 
<= 6 ? 
2085                             wxZIP_METHOD_STORE 
: wxZIP_METHOD_DEFLATE
); 
2089     switch (entry
.GetMethod()) { 
2090         case wxZIP_METHOD_STORE
: 
2091             if (entry
.GetCompressedSize() == wxInvalidOffset
) 
2092                 entry
.SetCompressedSize(entry
.GetSize()); 
2095         case wxZIP_METHOD_DEFLATE
: 
2097             int defbits 
= wxZIP_DEFLATE_NORMAL
; 
2098             switch (GetLevel()) { 
2100                     defbits 
= wxZIP_DEFLATE_SUPERFAST
; 
2102                 case 2: case 3: case 4: 
2103                     defbits 
= wxZIP_DEFLATE_FAST
; 
2106                     defbits 
= wxZIP_DEFLATE_EXTRA
; 
2109             entry
.SetFlags((entry
.GetFlags() & ~wxZIP_DEFLATE_MASK
) | 
2110                             defbits 
| wxZIP_SUMS_FOLLOW
); 
2113                 m_deflate 
= new wxZlibOutputStream2(stream
, GetLevel()); 
2115                 m_deflate
->Open(stream
); 
2121             wxLogError(_("unsupported Zip compression method")); 
2127 bool wxZipOutputStream::CloseCompressor(wxOutputStream 
*comp
) 
2129     if (comp 
== m_deflate
) 
2131     else if (comp 
!= m_store
) 
2136 // This is called when OUPUT_LATENCY bytes has been written to the 
2137 // wxZipOutputStream to actually create the zip entry. 
2139 void wxZipOutputStream::CreatePendingEntry(const void *buffer
, size_t size
) 
2141     wxASSERT(IsOk() && m_pending 
&& !m_comp
); 
2142     wx__ZipEntryPtr 
spPending(m_pending
); 
2146         { m_initialData
, m_initialSize 
}, 
2147         { (const char*)buffer
, size 
}, 
2154         m_comp 
= OpenCompressor(*m_store
, *spPending
, 
2155                                 m_initialSize 
? bufs 
: bufs 
+ 1); 
2157     if (IsParentSeekable() 
2158         || (spPending
->m_Crc
 
2159             && spPending
->m_CompressedSize 
!= wxInvalidOffset
 
2160             && spPending
->m_Size 
!= wxInvalidOffset
)) 
2161         spPending
->m_Flags 
&= ~wxZIP_SUMS_FOLLOW
; 
2163         if (spPending
->m_CompressedSize 
!= wxInvalidOffset
) 
2164             spPending
->m_Flags 
|= wxZIP_SUMS_FOLLOW
; 
2166     m_headerSize 
= spPending
->WriteLocal(*m_parent_o_stream
, GetConv()); 
2167     m_lasterror 
= m_parent_o_stream
->GetLastError(); 
2170         m_entries
.push_back(spPending
.release()); 
2171         OnSysWrite(m_initialData
, m_initialSize
); 
2177 // This is called to write out the zip entry when Close has been called 
2178 // before OUTPUT_LATENCY bytes has been written to the wxZipOutputStream. 
2180 void wxZipOutputStream::CreatePendingEntry() 
2182     wxASSERT(IsOk() && m_pending 
&& !m_comp
); 
2183     wx__ZipEntryPtr 
spPending(m_pending
); 
2185     m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
2188         // Initially compresses the data to memory, then fall back to 'store' 
2189         // if the compressor makes the data larger rather than smaller. 
2190         wxMemoryOutputStream mem
; 
2191         Buffer bufs
[] = { { m_initialData
, m_initialSize 
}, { NULL
, 0 } }; 
2192         wxOutputStream 
*comp 
= OpenCompressor(mem
, *spPending
, bufs
); 
2196         if (comp 
!= m_store
) { 
2197             bool ok 
= comp
->Write(m_initialData
, m_initialSize
).IsOk(); 
2198             CloseCompressor(comp
); 
2203         m_entrySize 
= m_initialSize
; 
2204         m_crcAccumulator 
= crc32(0, (Byte
*)m_initialData
, m_initialSize
); 
2206         if (mem
.GetSize() > 0 && mem
.GetSize() < m_initialSize
) { 
2207             m_initialSize 
= mem
.GetSize(); 
2208             mem
.CopyTo(m_initialData
, m_initialSize
); 
2210             spPending
->SetMethod(wxZIP_METHOD_STORE
); 
2213         spPending
->SetSize(m_entrySize
); 
2214         spPending
->SetCrc(m_crcAccumulator
); 
2215         spPending
->SetCompressedSize(m_initialSize
); 
2218     spPending
->m_Flags 
&= ~wxZIP_SUMS_FOLLOW
; 
2219     m_headerSize 
= spPending
->WriteLocal(*m_parent_o_stream
, GetConv()); 
2221     if (m_parent_o_stream
->IsOk()) { 
2222         m_entries
.push_back(spPending
.release()); 
2224         m_store
->Write(m_initialData
, m_initialSize
); 
2228     m_lasterror 
= m_parent_o_stream
->GetLastError(); 
2231 // Write the 'central directory' and the 'end-central-directory' records. 
2233 bool wxZipOutputStream::Close() 
2237     if (m_lasterror 
== wxSTREAM_WRITE_ERROR 
|| m_entries
.size() == 0) 
2242     endrec
.SetEntriesHere(m_entries
.size()); 
2243     endrec
.SetTotalEntries(m_entries
.size()); 
2244     endrec
.SetOffset(m_headerOffset
); 
2245     endrec
.SetComment(m_Comment
); 
2247     wx__ZipEntryList::iterator it
; 
2248     wxFileOffset size 
= 0; 
2250     for (it 
= m_entries
.begin(); it 
!= m_entries
.end(); ++it
) { 
2251         size 
+= (*it
)->WriteCentral(*m_parent_o_stream
, GetConv()); 
2256     endrec
.SetSize(size
); 
2257     endrec
.Write(*m_parent_o_stream
, GetConv()); 
2259     m_lasterror 
= m_parent_o_stream
->GetLastError(); 
2262     m_lasterror 
= wxSTREAM_EOF
; 
2266 // Finish writing the current entry 
2268 bool wxZipOutputStream::CloseEntry() 
2270     if (IsOk() && m_pending
) 
2271         CreatePendingEntry(); 
2277     CloseCompressor(m_comp
); 
2280     wxFileOffset compressedSize 
= m_store
->TellO(); 
2282     wxZipEntry
& entry 
= *m_entries
.back(); 
2284     // When writing raw the crc and size can't be checked 
2286         m_crcAccumulator 
= entry
.GetCrc(); 
2287         m_entrySize 
= entry
.GetSize(); 
2290     // Write the sums in the trailing 'data descriptor' if necessary 
2291     if (entry
.m_Flags 
& wxZIP_SUMS_FOLLOW
) { 
2292         wxASSERT(!IsParentSeekable()); 
2294             entry
.WriteDescriptor(*m_parent_o_stream
, m_crcAccumulator
, 
2295                                   compressedSize
, m_entrySize
); 
2296         m_lasterror 
= m_parent_o_stream
->GetLastError(); 
2299     // If the local header didn't have the correct crc and size written to 
2300     // it then seek back and fix it 
2301     else if (m_crcAccumulator 
!= entry
.GetCrc() 
2302             || m_entrySize 
!= entry
.GetSize() 
2303             || compressedSize 
!= entry
.GetCompressedSize()) 
2305         if (IsParentSeekable()) { 
2306             wxFileOffset here 
= m_parent_o_stream
->TellO(); 
2307             wxFileOffset headerOffset 
= m_headerOffset 
+ m_offsetAdjustment
; 
2308             m_parent_o_stream
->SeekO(headerOffset 
+ SUMS_OFFSET
); 
2309             entry
.WriteDescriptor(*m_parent_o_stream
, m_crcAccumulator
, 
2310                                   compressedSize
, m_entrySize
); 
2311             m_parent_o_stream
->SeekO(here
); 
2312             m_lasterror 
= m_parent_o_stream
->GetLastError(); 
2314             m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
2318     m_headerOffset 
+= m_headerSize 
+ compressedSize
; 
2325         m_lasterror 
= m_parent_o_stream
->GetLastError(); 
2327         wxLogError(_("error writing zip entry '%s': bad crc or length"), 
2328                    entry
.GetName().c_str()); 
2332 void wxZipOutputStream::Sync() 
2334     if (IsOk() && m_pending
) 
2335         CreatePendingEntry(NULL
, 0); 
2337         m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
2340         m_lasterror 
= m_comp
->GetLastError(); 
2344 size_t wxZipOutputStream::OnSysWrite(const void *buffer
, size_t size
) 
2346     if (IsOk() && m_pending
) { 
2347         if (m_initialSize 
+ size 
< OUTPUT_LATENCY
) { 
2348             memcpy(m_initialData 
+ m_initialSize
, buffer
, size
); 
2349             m_initialSize 
+= size
; 
2352             CreatePendingEntry(buffer
, size
); 
2357         m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
2358     if (!IsOk() || !size
) 
2361     if (m_comp
->Write(buffer
, size
).LastWrite() != size
) 
2362         m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
2363     m_crcAccumulator 
= crc32(m_crcAccumulator
, (Byte
*)buffer
, size
); 
2364     m_entrySize 
+= m_comp
->LastWrite(); 
2366     return m_comp
->LastWrite(); 
2369 #endif // wxUSE_ZLIB && wxUSE_STREAMS && wxUSE_ZIPSTREAM