1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     Streams for Zip files 
   4 // Author:      Mike Wetherell 
   6 // Copyright:   (c) Mike Wetherell 
   7 // Licence:     wxWindows licence 
   8 ///////////////////////////////////////////////////////////////////////////// 
  10 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  11   #pragma implementation "zipstrm.h" 
  14 // For compilers that support precompilation, includes "wx.h". 
  15 #include "wx/wxprec.h" 
  25 #if wxUSE_ZLIB && wxUSE_STREAMS && wxUSE_ZIPSTREAM 
  27 #include "wx/zipstrm.h" 
  30 #include "wx/datstrm.h" 
  31 #include "wx/zstream.h" 
  32 #include "wx/mstream.h" 
  34 #include "wx/buffer.h" 
  35 #include "wx/ptr_scpd.h" 
  36 #include "wx/wfstream.h" 
  39 // value for the 'version needed to extract' field (20 means 2.0) 
  41     VERSION_NEEDED_TO_EXTRACT 
= 20 
  44 // signatures for the various records (PKxx) 
  46     CENTRAL_MAGIC 
= 0x02014b50,     // central directory record 
  47     LOCAL_MAGIC   
= 0x04034b50,     // local header 
  48     END_MAGIC     
= 0x06054b50,     // end of central directory record 
  49     SUMS_MAGIC    
= 0x08074b50      // data descriptor (info-zip) 
  52 // unix file attributes. zip stores them in the high 16 bits of the 
  53 // 'external attributes' field, hence the extra zeros. 
  55     wxZIP_S_IFMT  
= 0xF0000000, 
  56     wxZIP_S_IFDIR 
= 0x40000000, 
  57     wxZIP_S_IFREG 
= 0x80000000 
  60 // minimum sizes for the various records 
  68 // The number of bytes that must be written to an wxZipOutputStream before 
  69 // a zip entry is created. The purpose of this latency is so that 
  70 // OpenCompressor() can see a little data before deciding which compressor 
  76 // Some offsets into the local header 
  81 IMPLEMENT_DYNAMIC_CLASS(wxZipEntry
, wxArchiveEntry
) 
  82 IMPLEMENT_DYNAMIC_CLASS(wxZipClassFactory
, wxArchiveClassFactory
) 
  84 //FORCE_LINK_ME(zipstrm) 
  85 int _wx_link_dummy_func_zipstrm(); 
  86 int _wx_link_dummy_func_zipstrm() 
  92 ///////////////////////////////////////////////////////////////////////////// 
  95 // read a string of a given length 
  97 static wxString 
ReadString(wxInputStream
& stream
, wxUint16 len
, wxMBConv
& conv
) 
 100     wxCharBuffer 
buf(len
); 
 101     stream
.Read(buf
.data(), len
); 
 102     wxString 
str(buf
, conv
); 
 107         wxStringBuffer 
buf(str
, len
); 
 108         stream
.Read(buf
, len
); 
 115 // Decode a little endian wxUint32 number from a character array 
 117 static inline wxUint32 
CrackUint32(const char *m
) 
 119     const unsigned char *n 
= (const unsigned char*)m
; 
 120     return (n
[3] << 24) | (n
[2] << 16) | (n
[1] << 8) | n
[0]; 
 123 // Temporarily lower the logging level in debug mode to avoid a warning 
 124 // from SeekI about seeking on a stream with data written back to it. 
 126 static wxFileOffset 
QuietSeek(wxInputStream
& stream
, wxFileOffset pos
) 
 129     wxLogLevel level 
= wxLog::GetLogLevel(); 
 130     wxLog::SetLogLevel(wxLOG_Debug 
- 1); 
 131     wxFileOffset result 
= stream
.SeekI(pos
); 
 132     wxLog::SetLogLevel(level
); 
 135     return stream
.SeekI(pos
); 
 140 ///////////////////////////////////////////////////////////////////////////// 
 141 // Stored input stream 
 142 // Trival decompressor for files which are 'stored' in the zip file. 
 144 class wxStoredInputStream 
: public wxFilterInputStream
 
 147     wxStoredInputStream(wxInputStream
& stream
); 
 149     void Open(wxFileOffset len
) { Close(); m_len 
= len
; } 
 150     void Close() { m_pos 
= 0; m_lasterror 
= wxSTREAM_NO_ERROR
; } 
 152     virtual char Peek() { return wxInputStream::Peek(); } 
 153     virtual wxFileOffset 
GetLength() const { return m_len
; } 
 156     virtual size_t OnSysRead(void *buffer
, size_t size
); 
 157     virtual wxFileOffset 
OnSysTell() const { return m_pos
; } 
 163     DECLARE_NO_COPY_CLASS(wxStoredInputStream
) 
 166 wxStoredInputStream::wxStoredInputStream(wxInputStream
& stream
) 
 167   : wxFilterInputStream(stream
), 
 173 size_t wxStoredInputStream::OnSysRead(void *buffer
, size_t size
) 
 175     size_t count 
= wxMin(size
, (size_t)(m_len 
- m_pos
)); 
 176     count 
= m_parent_i_stream
->Read(buffer
, count
).LastRead(); 
 180         m_lasterror 
= wxSTREAM_EOF
; 
 181     else if (!*m_parent_i_stream
) 
 182         m_lasterror 
= wxSTREAM_READ_ERROR
; 
 188 ///////////////////////////////////////////////////////////////////////////// 
 189 // Stored output stream 
 190 // Trival compressor for files which are 'stored' in the zip file. 
 192 class wxStoredOutputStream 
: public wxFilterOutputStream
 
 195     wxStoredOutputStream(wxOutputStream
& stream
) : 
 196         wxFilterOutputStream(stream
), m_pos(0) { } 
 200         m_lasterror 
= wxSTREAM_NO_ERROR
; 
 205     virtual size_t OnSysWrite(const void *buffer
, size_t size
); 
 206     virtual wxFileOffset 
OnSysTell() const { return m_pos
; } 
 210     DECLARE_NO_COPY_CLASS(wxStoredOutputStream
) 
 213 size_t wxStoredOutputStream::OnSysWrite(const void *buffer
, size_t size
) 
 215     if (!IsOk() || !size
) 
 217     size_t count 
= m_parent_o_stream
->Write(buffer
, size
).LastWrite(); 
 219         m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
 225 ///////////////////////////////////////////////////////////////////////////// 
 228 // Used to handle the unusal case of raw copying an entry of unknown 
 229 // length. This can only happen when the zip being copied from is being 
 230 // read from a non-seekable stream, and also was original written to a 
 231 // non-seekable stream. 
 233 // In this case there's no option but to decompress the stream to find 
 234 // it's length, but we can still write the raw compressed data to avoid the 
 235 // compression overhead (which is the greater one). 
 237 // Usage is like this: 
 238 //  m_rawin = new wxRawInputStream(*m_parent_i_stream); 
 239 //  m_decomp = m_rawin->Open(OpenDecompressor(m_rawin->GetTee())); 
 241 // The wxRawInputStream owns a wxTeeInputStream object, the role of which 
 242 // is something like the unix 'tee' command; it is a transparent filter, but 
 243 // allows the data read to be read a second time via an extra method 'GetData'. 
 245 // The wxRawInputStream then draws data through the tee using a decompressor 
 246 // then instead of returning the decompressed data, retuns the raw data 
 247 // from wxTeeInputStream::GetData(). 
 249 class wxTeeInputStream 
: public wxFilterInputStream
 
 252     wxTeeInputStream(wxInputStream
& stream
); 
 254     size_t GetCount() const { return m_end 
- m_start
; } 
 255     size_t GetData(char *buffer
, size_t size
); 
 260     wxInputStream
& Read(void *buffer
, size_t size
); 
 263     virtual size_t OnSysRead(void *buffer
, size_t size
); 
 264     virtual wxFileOffset 
OnSysTell() const { return m_pos
; } 
 268     wxMemoryBuffer m_buf
; 
 272     DECLARE_NO_COPY_CLASS(wxTeeInputStream
) 
 275 wxTeeInputStream::wxTeeInputStream(wxInputStream
& stream
) 
 276   : wxFilterInputStream(stream
), 
 277     m_pos(0), m_buf(8192), m_start(0), m_end(0) 
 281 void wxTeeInputStream::Open() 
 283     m_pos 
= m_start 
= m_end 
= 0; 
 284     m_lasterror 
= wxSTREAM_NO_ERROR
; 
 287 bool wxTeeInputStream::Final() 
 289     bool final 
= m_end 
== m_buf
.GetDataLen(); 
 290     m_end 
= m_buf
.GetDataLen(); 
 294 wxInputStream
& wxTeeInputStream::Read(void *buffer
, size_t size
) 
 296     size_t count 
= wxInputStream::Read(buffer
, size
).LastRead(); 
 297     m_end 
= m_buf
.GetDataLen(); 
 298     m_buf
.AppendData(buffer
, count
); 
 302 size_t wxTeeInputStream::OnSysRead(void *buffer
, size_t size
) 
 304     size_t count 
= m_parent_i_stream
->Read(buffer
, size
).LastRead(); 
 305     m_lasterror 
= m_parent_i_stream
->GetLastError(); 
 309 size_t wxTeeInputStream::GetData(char *buffer
, size_t size
) 
 312         size_t len 
= m_buf
.GetDataLen(); 
 313         len 
= len 
> m_wbacksize 
? len 
- m_wbacksize 
: 0; 
 314         m_buf
.SetDataLen(len
); 
 316             wxFAIL
; // we've already returned data that's now being ungot 
 319         m_parent_i_stream
->Ungetch(m_wback
, m_wbacksize
); 
 326     if (size 
> GetCount()) 
 329         memcpy(buffer
, m_buf 
+ m_start
, size
); 
 331         wxASSERT(m_start 
<= m_end
); 
 334     if (m_start 
== m_end 
&& m_start 
> 0 && m_buf
.GetDataLen() > 0) { 
 335         size_t len 
= m_buf
.GetDataLen(); 
 336         char *buf 
= (char*)m_buf
.GetWriteBuf(len
); 
 338         memmove(buf
, buf 
+ m_end
, len
); 
 339         m_buf
.UngetWriteBuf(len
); 
 346 class wxRawInputStream 
: public wxFilterInputStream
 
 349     wxRawInputStream(wxInputStream
& stream
); 
 350     virtual ~wxRawInputStream() { delete m_tee
; } 
 352     wxInputStream
* Open(wxInputStream 
*decomp
); 
 353     wxInputStream
& GetTee() const { return *m_tee
; } 
 356     virtual size_t OnSysRead(void *buffer
, size_t size
); 
 357     virtual wxFileOffset 
OnSysTell() const { return m_pos
; } 
 361     wxTeeInputStream 
*m_tee
; 
 363     enum { BUFSIZE 
= 8192 }; 
 364     wxCharBuffer m_dummy
; 
 366     DECLARE_NO_COPY_CLASS(wxRawInputStream
) 
 369 wxRawInputStream::wxRawInputStream(wxInputStream
& stream
) 
 370   : wxFilterInputStream(stream
), 
 372     m_tee(new wxTeeInputStream(stream
)), 
 377 wxInputStream 
*wxRawInputStream::Open(wxInputStream 
*decomp
) 
 380         m_parent_i_stream 
= decomp
; 
 382         m_lasterror 
= wxSTREAM_NO_ERROR
; 
 390 size_t wxRawInputStream::OnSysRead(void *buffer
, size_t size
) 
 392     char *buf 
= (char*)buffer
; 
 395     while (count 
< size 
&& IsOk()) 
 397         while (m_parent_i_stream
->IsOk() && m_tee
->GetCount() == 0) 
 398             m_parent_i_stream
->Read(m_dummy
.data(), BUFSIZE
); 
 400         size_t n 
= m_tee
->GetData(buf 
+ count
, size 
- count
); 
 403         if (n 
== 0 && m_tee
->Final()) 
 404             m_lasterror 
= m_parent_i_stream
->GetLastError(); 
 412 ///////////////////////////////////////////////////////////////////////////// 
 413 // Zlib streams than can be reused without recreating. 
 415 class wxZlibOutputStream2 
: public wxZlibOutputStream
 
 418     wxZlibOutputStream2(wxOutputStream
& stream
, int level
) : 
 419         wxZlibOutputStream(stream
, level
, wxZLIB_NO_HEADER
) { } 
 421     bool Open(wxOutputStream
& stream
); 
 422     bool Close() { DoFlush(true); m_pos 
= wxInvalidOffset
; return IsOk(); } 
 425 bool wxZlibOutputStream2::Open(wxOutputStream
& stream
) 
 427     wxCHECK(m_pos 
== wxInvalidOffset
, false); 
 429     m_deflate
->next_out 
= m_z_buffer
; 
 430     m_deflate
->avail_out 
= m_z_size
; 
 432     m_lasterror 
= wxSTREAM_NO_ERROR
; 
 433     m_parent_o_stream 
= &stream
; 
 435     if (deflateReset(m_deflate
) != Z_OK
) { 
 436         wxLogError(_("can't re-initialize zlib deflate stream")); 
 437         m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
 444 class wxZlibInputStream2 
: public wxZlibInputStream
 
 447     wxZlibInputStream2(wxInputStream
& stream
) : 
 448         wxZlibInputStream(stream
, wxZLIB_NO_HEADER
) { } 
 450     bool Open(wxInputStream
& stream
); 
 453 bool wxZlibInputStream2::Open(wxInputStream
& stream
) 
 455     m_inflate
->avail_in 
= 0; 
 457     m_lasterror 
= wxSTREAM_NO_ERROR
; 
 458     m_parent_i_stream 
= &stream
; 
 460     if (inflateReset(m_inflate
) != Z_OK
) { 
 461         wxLogError(_("can't re-initialize zlib inflate stream")); 
 462         m_lasterror 
= wxSTREAM_READ_ERROR
; 
 470 ///////////////////////////////////////////////////////////////////////////// 
 471 // Class to hold wxZipEntry's Extra and LocalExtra fields 
 476     wxZipMemory() : m_data(NULL
), m_size(0), m_capacity(0), m_ref(1) { } 
 478     wxZipMemory 
*AddRef() { m_ref
++; return this; } 
 479     void Release() { if (--m_ref 
== 0) delete this; } 
 481     char *GetData() const { return m_data
; } 
 482     size_t GetSize() const { return m_size
; } 
 483     size_t GetCapacity() const { return m_capacity
; } 
 485     wxZipMemory 
*Unique(size_t size
); 
 488     ~wxZipMemory() { delete m_data
; } 
 496 wxZipMemory 
*wxZipMemory::Unique(size_t size
) 
 502         zm 
= new wxZipMemory
; 
 507     if (zm
->m_capacity 
< size
) { 
 509         zm
->m_data 
= new char[size
]; 
 510         zm
->m_capacity 
= size
; 
 517 static inline wxZipMemory 
*AddRef(wxZipMemory 
*zm
) 
 524 static inline void Release(wxZipMemory 
*zm
) 
 530 static void Copy(wxZipMemory
*& dest
, wxZipMemory 
*src
) 
 536 static void Unique(wxZipMemory
*& zm
, size_t size
) 
 539         zm 
= new wxZipMemory
; 
 541         zm 
= zm
->Unique(size
); 
 545 ///////////////////////////////////////////////////////////////////////////// 
 546 // Collection of weak references to entries 
 548 WX_DECLARE_HASH_MAP(long, wxZipEntry
*, wxIntegerHash
, 
 549                     wxIntegerEqual
, wx__OffsetZipEntryMap
); 
 554     wxZipWeakLinks() : m_ref(1) { } 
 556     void Release(const wxZipInputStream
* WXUNUSED(x
)) 
 557         { if (--m_ref 
== 0) delete this; } 
 558     void Release(wxFileOffset key
) 
 559         { RemoveEntry(key
); if (--m_ref 
== 0) delete this; } 
 561     wxZipWeakLinks 
*AddEntry(wxZipEntry 
*entry
, wxFileOffset key
); 
 562     void RemoveEntry(wxFileOffset key
) 
 563         { m_entries
.erase((wx__OffsetZipEntryMap::key_type
)key
); } 
 564     wxZipEntry 
*GetEntry(wxFileOffset key
) const; 
 565     bool IsEmpty() const { return m_entries
.empty(); } 
 568     ~wxZipWeakLinks() { wxASSERT(IsEmpty()); } 
 571     wx__OffsetZipEntryMap m_entries
; 
 574 wxZipWeakLinks 
*wxZipWeakLinks::AddEntry(wxZipEntry 
*entry
, wxFileOffset key
) 
 576     m_entries
[(wx__OffsetZipEntryMap::key_type
)key
] = entry
; 
 581 wxZipEntry 
*wxZipWeakLinks::GetEntry(wxFileOffset key
) const 
 583     wx__OffsetZipEntryMap::const_iterator it 
= 
 584         m_entries
.find((wx__OffsetZipEntryMap::key_type
)key
); 
 585     return it 
!= m_entries
.end() ?  it
->second 
: NULL
; 
 589 ///////////////////////////////////////////////////////////////////////////// 
 592 wxZipEntry::wxZipEntry( 
 593     const wxString
& name 
/*=wxEmptyString*/, 
 594     const wxDateTime
& dt 
/*=wxDateTime::Now()*/, 
 595     wxFileOffset size    
/*=wxInvalidOffset*/) 
 597     m_SystemMadeBy(wxZIP_SYSTEM_MSDOS
), 
 598     m_VersionMadeBy(wxMAJOR_VERSION 
* 10 + wxMINOR_VERSION
), 
 599     m_VersionNeeded(VERSION_NEEDED_TO_EXTRACT
), 
 601     m_Method(wxZIP_METHOD_DEFAULT
), 
 604     m_CompressedSize(wxInvalidOffset
), 
 606     m_Key(wxInvalidOffset
), 
 607     m_Offset(wxInvalidOffset
), 
 609     m_InternalAttributes(0), 
 610     m_ExternalAttributes(0), 
 620 wxZipEntry::~wxZipEntry() 
 623         m_backlink
->Release(m_Key
); 
 625     Release(m_LocalExtra
); 
 628 wxZipEntry::wxZipEntry(const wxZipEntry
& e
) 
 630     m_SystemMadeBy(e
.m_SystemMadeBy
), 
 631     m_VersionMadeBy(e
.m_VersionMadeBy
), 
 632     m_VersionNeeded(e
.m_VersionNeeded
), 
 634     m_Method(e
.m_Method
), 
 635     m_DateTime(e
.m_DateTime
), 
 637     m_CompressedSize(e
.m_CompressedSize
), 
 641     m_Offset(e
.m_Offset
), 
 642     m_Comment(e
.m_Comment
), 
 643     m_DiskStart(e
.m_DiskStart
), 
 644     m_InternalAttributes(e
.m_InternalAttributes
), 
 645     m_ExternalAttributes(e
.m_ExternalAttributes
), 
 646     m_Extra(AddRef(e
.m_Extra
)), 
 647     m_LocalExtra(AddRef(e
.m_LocalExtra
)), 
 653 wxZipEntry
& wxZipEntry::operator=(const wxZipEntry
& e
) 
 656         m_SystemMadeBy 
= e
.m_SystemMadeBy
; 
 657         m_VersionMadeBy 
= e
.m_VersionMadeBy
; 
 658         m_VersionNeeded 
= e
.m_VersionNeeded
; 
 660         m_Method 
= e
.m_Method
; 
 661         m_DateTime 
= e
.m_DateTime
; 
 663         m_CompressedSize 
= e
.m_CompressedSize
; 
 667         m_Offset 
= e
.m_Offset
; 
 668         m_Comment 
= e
.m_Comment
; 
 669         m_DiskStart 
= e
.m_DiskStart
; 
 670         m_InternalAttributes 
= e
.m_InternalAttributes
; 
 671         m_ExternalAttributes 
= e
.m_ExternalAttributes
; 
 672         Copy(m_Extra
, e
.m_Extra
); 
 673         Copy(m_LocalExtra
, e
.m_LocalExtra
); 
 674         m_zipnotifier 
= NULL
; 
 676             m_backlink
->Release(m_Key
); 
 683 wxString 
wxZipEntry::GetName(wxPathFormat format 
/*=wxPATH_NATIVE*/) const 
 685     bool isDir 
= IsDir() && !m_Name
.empty(); 
 687     // optimisations for common (and easy) cases 
 688     switch (wxFileName::GetFormat(format
)) { 
 691             wxString 
name(isDir 
? m_Name 
+ _T("\\") : m_Name
); 
 692             for (size_t i 
= name
.length() - 1; i 
> 0; --i
) 
 693                 if (name
[i
] == _T('/')) 
 699             return isDir 
? m_Name 
+ _T("/") : m_Name
; 
 708         fn
.AssignDir(m_Name
, wxPATH_UNIX
); 
 710         fn
.Assign(m_Name
, wxPATH_UNIX
); 
 712     return fn
.GetFullPath(format
); 
 715 // Static - Internally tars and zips use forward slashes for the path 
 716 // separator, absolute paths aren't allowed, and directory names have a 
 717 // trailing slash.  This function converts a path into this internal format, 
 718 // but without a trailing slash for a directory. 
 720 wxString 
wxZipEntry::GetInternalName(const wxString
& name
, 
 721                                      wxPathFormat format 
/*=wxPATH_NATIVE*/, 
 722                                      bool *pIsDir        
/*=NULL*/) 
 726     if (wxFileName::GetFormat(format
) != wxPATH_UNIX
) 
 727         internal 
= wxFileName(name
, format
).GetFullPath(wxPATH_UNIX
); 
 731     bool isDir 
= !internal
.empty() && internal
.Last() == '/'; 
 735         internal
.erase(internal
.length() - 1); 
 737     while (!internal
.empty() && *internal
.begin() == '/') 
 738         internal
.erase(0, 1); 
 739     while (!internal
.empty() && internal
.compare(0, 2, _T("./")) == 0) 
 740         internal
.erase(0, 2); 
 741     if (internal 
== _T(".") || internal 
== _T("..")) 
 742         internal 
= wxEmptyString
; 
 747 void wxZipEntry::SetSystemMadeBy(int system
) 
 749     int mode 
= GetMode(); 
 750     bool wasUnix 
= IsMadeByUnix(); 
 752     m_SystemMadeBy 
= (wxUint8
)system
; 
 754     if (!wasUnix 
&& IsMadeByUnix()) { 
 757     } else if (wasUnix 
&& !IsMadeByUnix()) { 
 758         m_ExternalAttributes 
&= 0xffff; 
 762 void wxZipEntry::SetIsDir(bool isDir 
/*=true*/) 
 765         m_ExternalAttributes 
|= wxZIP_A_SUBDIR
; 
 767         m_ExternalAttributes 
&= ~wxZIP_A_SUBDIR
; 
 769     if (IsMadeByUnix()) { 
 770         m_ExternalAttributes 
&= ~wxZIP_S_IFMT
; 
 772             m_ExternalAttributes 
|= wxZIP_S_IFDIR
; 
 774             m_ExternalAttributes 
|= wxZIP_S_IFREG
; 
 778 // Return unix style permission bits 
 780 int wxZipEntry::GetMode() const 
 782     // return unix permissions if present 
 784         return (m_ExternalAttributes 
>> 16) & 0777; 
 786     // otherwise synthesize from the dos attribs 
 788     if (m_ExternalAttributes 
& wxZIP_A_RDONLY
) 
 790     if (m_ExternalAttributes 
& wxZIP_A_SUBDIR
) 
 796 // Set unix permissions 
 798 void wxZipEntry::SetMode(int mode
) 
 800     // Set dos attrib bits to be compatible 
 802         m_ExternalAttributes 
&= ~wxZIP_A_RDONLY
; 
 804         m_ExternalAttributes 
|= wxZIP_A_RDONLY
; 
 806     // set the actual unix permission bits if the system type allows 
 807     if (IsMadeByUnix()) { 
 808         m_ExternalAttributes 
&= ~(0777L << 16); 
 809         m_ExternalAttributes 
|= (mode 
& 0777L) << 16; 
 813 const char *wxZipEntry::GetExtra() const 
 815     return m_Extra 
? m_Extra
->GetData() : NULL
; 
 818 size_t wxZipEntry::GetExtraLen() const 
 820     return m_Extra 
? m_Extra
->GetSize() : 0; 
 823 void wxZipEntry::SetExtra(const char *extra
, size_t len
) 
 825     Unique(m_Extra
, len
); 
 827         memcpy(m_Extra
->GetData(), extra
, len
); 
 830 const char *wxZipEntry::GetLocalExtra() const 
 832     return m_LocalExtra 
? m_LocalExtra
->GetData() : NULL
; 
 835 size_t  wxZipEntry::GetLocalExtraLen() const 
 837     return m_LocalExtra 
? m_LocalExtra
->GetSize() : 0; 
 840 void wxZipEntry::SetLocalExtra(const char *extra
, size_t len
) 
 842     Unique(m_LocalExtra
, len
); 
 844         memcpy(m_LocalExtra
->GetData(), extra
, len
); 
 847 void wxZipEntry::SetNotifier(wxZipNotifier
& notifier
) 
 849     wxArchiveEntry::UnsetNotifier(); 
 850     m_zipnotifier 
= ¬ifier
; 
 851     m_zipnotifier
->OnEntryUpdated(*this); 
 854 void wxZipEntry::Notify() 
 857         m_zipnotifier
->OnEntryUpdated(*this); 
 858     else if (GetNotifier()) 
 859         GetNotifier()->OnEntryUpdated(*this); 
 862 void wxZipEntry::UnsetNotifier() 
 864     wxArchiveEntry::UnsetNotifier(); 
 865     m_zipnotifier 
= NULL
; 
 868 size_t wxZipEntry::ReadLocal(wxInputStream
& stream
, wxMBConv
& conv
) 
 870     wxUint16 nameLen
, extraLen
; 
 871     wxUint32 compressedSize
, size
, crc
; 
 873     wxDataInputStream 
ds(stream
); 
 875     ds 
>> m_VersionNeeded 
>> m_Flags 
>> m_Method
; 
 876     SetDateTime(wxDateTime().SetFromDOS(ds
.Read32())); 
 877     ds 
>> crc 
>> compressedSize 
>> size 
>> nameLen 
>> extraLen
; 
 879     bool sumsValid 
= (m_Flags 
& wxZIP_SUMS_FOLLOW
) == 0; 
 881     if (sumsValid 
|| crc
) 
 883     if ((sumsValid 
|| compressedSize
) || m_Method 
== wxZIP_METHOD_STORE
) 
 884         m_CompressedSize 
= compressedSize
; 
 885     if ((sumsValid 
|| size
) || m_Method 
== wxZIP_METHOD_STORE
) 
 888     SetName(ReadString(stream
, nameLen
, conv
), wxPATH_UNIX
); 
 890     if (extraLen 
|| GetLocalExtraLen()) { 
 891         Unique(m_LocalExtra
, extraLen
); 
 893             stream
.Read(m_LocalExtra
->GetData(), extraLen
); 
 896     return LOCAL_SIZE 
+ nameLen 
+ extraLen
; 
 899 size_t wxZipEntry::WriteLocal(wxOutputStream
& stream
, wxMBConv
& conv
) const 
 901     wxString unixName 
= GetName(wxPATH_UNIX
); 
 902     const wxWX2MBbuf name_buf 
= conv
.cWX2MB(unixName
); 
 903     const char *name 
= name_buf
; 
 904     if (!name
) name 
= ""; 
 905     wxUint16 nameLen 
= (wxUint16
)strlen(name
); 
 907     wxDataOutputStream 
ds(stream
); 
 909     ds 
<< m_VersionNeeded 
<< m_Flags 
<< m_Method
; 
 910     ds
.Write32(GetDateTime().GetAsDOS()); 
 913     ds
.Write32(m_CompressedSize 
!= wxInvalidOffset 
? (wxUint32
)m_CompressedSize 
: 0); 
 914     ds
.Write32(m_Size 
!= wxInvalidOffset 
? (wxUint32
)m_Size 
: 0); 
 917     wxUint16 extraLen 
= (wxUint16
)GetLocalExtraLen(); 
 918     ds
.Write16(extraLen
); 
 920     stream
.Write(name
, nameLen
); 
 922         stream
.Write(m_LocalExtra
->GetData(), extraLen
); 
 924     return LOCAL_SIZE 
+ nameLen 
+ extraLen
; 
 927 size_t wxZipEntry::ReadCentral(wxInputStream
& stream
, wxMBConv
& conv
) 
 929     wxUint16 nameLen
, extraLen
, commentLen
; 
 931     wxDataInputStream 
ds(stream
); 
 933     ds 
>> m_VersionMadeBy 
>> m_SystemMadeBy
; 
 935     SetVersionNeeded(ds
.Read16()); 
 936     SetFlags(ds
.Read16()); 
 937     SetMethod(ds
.Read16()); 
 938     SetDateTime(wxDateTime().SetFromDOS(ds
.Read32())); 
 940     SetCompressedSize(ds
.Read32()); 
 941     SetSize(ds
.Read32()); 
 943     ds 
>> nameLen 
>> extraLen 
>> commentLen
 
 944        >> m_DiskStart 
>> m_InternalAttributes 
>> m_ExternalAttributes
; 
 945     SetOffset(ds
.Read32()); 
 947     SetName(ReadString(stream
, nameLen
, conv
), wxPATH_UNIX
); 
 949     if (extraLen 
|| GetExtraLen()) { 
 950         Unique(m_Extra
, extraLen
); 
 952             stream
.Read(m_Extra
->GetData(), extraLen
); 
 956         m_Comment 
= ReadString(stream
, commentLen
, conv
); 
 960     return CENTRAL_SIZE 
+ nameLen 
+ extraLen 
+ commentLen
; 
 963 size_t wxZipEntry::WriteCentral(wxOutputStream
& stream
, wxMBConv
& conv
) const 
 965     wxString unixName 
= GetName(wxPATH_UNIX
); 
 966     const wxWX2MBbuf name_buf 
= conv
.cWX2MB(unixName
); 
 967     const char *name 
= name_buf
; 
 968     if (!name
) name 
= ""; 
 969     wxUint16 nameLen 
= (wxUint16
)strlen(name
); 
 971     const wxWX2MBbuf comment_buf 
= conv
.cWX2MB(m_Comment
); 
 972     const char *comment 
= comment_buf
; 
 973     if (!comment
) comment 
= ""; 
 974     wxUint16 commentLen 
= (wxUint16
)strlen(comment
); 
 976     wxUint16 extraLen 
= (wxUint16
)GetExtraLen(); 
 978     wxDataOutputStream 
ds(stream
); 
 980     ds 
<< CENTRAL_MAGIC 
<< m_VersionMadeBy 
<< m_SystemMadeBy
; 
 982     ds
.Write16((wxUint16
)GetVersionNeeded()); 
 983     ds
.Write16((wxUint16
)GetFlags()); 
 984     ds
.Write16((wxUint16
)GetMethod()); 
 985     ds
.Write32(GetDateTime().GetAsDOS()); 
 986     ds
.Write32(GetCrc()); 
 987     ds
.Write32((wxUint32
)GetCompressedSize()); 
 988     ds
.Write32((wxUint32
)GetSize()); 
 990     ds
.Write16(extraLen
); 
 992     ds 
<< commentLen 
<< m_DiskStart 
<< m_InternalAttributes
 
 993        << m_ExternalAttributes 
<< (wxUint32
)GetOffset(); 
 995     stream
.Write(name
, nameLen
); 
 997         stream
.Write(GetExtra(), extraLen
); 
 998     stream
.Write(comment
, commentLen
); 
1000     return CENTRAL_SIZE 
+ nameLen 
+ extraLen 
+ commentLen
; 
1003 // Info-zip prefixes this record with a signature, but pkzip doesn't. So if 
1004 // the 1st value is the signature then it is probably an info-zip record, 
1005 // though there is a small chance that it is in fact a pkzip record which 
1006 // happens to have the signature as it's CRC. 
1008 size_t wxZipEntry::ReadDescriptor(wxInputStream
& stream
) 
1010     wxDataInputStream 
ds(stream
); 
1012     m_Crc 
= ds
.Read32(); 
1013     m_CompressedSize 
= ds
.Read32(); 
1014     m_Size 
= ds
.Read32(); 
1016     // if 1st value is the signature then this is probably an info-zip record 
1017     if (m_Crc 
== SUMS_MAGIC
) 
1020         stream
.Read(buf
, sizeof(buf
)); 
1021         wxUint32 u1 
= CrackUint32(buf
); 
1022         wxUint32 u2 
= CrackUint32(buf 
+ 4); 
1024         // look for the signature of the following record to decide which 
1025         if ((u1 
== LOCAL_MAGIC 
|| u1 
== CENTRAL_MAGIC
) && 
1026             (u2 
!= LOCAL_MAGIC 
&& u2 
!= CENTRAL_MAGIC
)) 
1028             // it's a pkzip style record after all! 
1029             stream
.Ungetch(buf
, sizeof(buf
)); 
1033             // it's an info-zip record as expected 
1034             stream
.Ungetch(buf 
+ 4, sizeof(buf
) - 4); 
1035             m_Crc 
= (wxUint32
)m_CompressedSize
; 
1036             m_CompressedSize 
= m_Size
; 
1038             return SUMS_SIZE 
+ 4; 
1045 size_t wxZipEntry::WriteDescriptor(wxOutputStream
& stream
, wxUint32 crc
, 
1046                                    wxFileOffset compressedSize
, wxFileOffset size
) 
1049     m_CompressedSize 
= compressedSize
; 
1052     wxDataOutputStream 
ds(stream
); 
1055     ds
.Write32((wxUint32
)compressedSize
); 
1056     ds
.Write32((wxUint32
)size
); 
1062 ///////////////////////////////////////////////////////////////////////////// 
1063 // wxZipEndRec - holds the end of central directory record 
1070     int GetDiskNumber() const                   { return m_DiskNumber
; } 
1071     int GetStartDisk() const                    { return m_StartDisk
; } 
1072     int GetEntriesHere() const                  { return m_EntriesHere
; } 
1073     int GetTotalEntries() const                 { return m_TotalEntries
; } 
1074     wxFileOffset 
GetSize() const                { return m_Size
; } 
1075     wxFileOffset 
GetOffset() const              { return m_Offset
; } 
1076     wxString 
GetComment() const                 { return m_Comment
; } 
1078     void SetDiskNumber(int num
)                 { m_DiskNumber 
= (wxUint16
)num
; } 
1079     void SetStartDisk(int num
)                  { m_StartDisk 
= (wxUint16
)num
; } 
1080     void SetEntriesHere(int num
)                { m_EntriesHere 
= (wxUint16
)num
; } 
1081     void SetTotalEntries(int num
)               { m_TotalEntries 
= (wxUint16
)num
; } 
1082     void SetSize(wxFileOffset size
)             { m_Size 
= (wxUint32
)size
; } 
1083     void SetOffset(wxFileOffset offset
)         { m_Offset 
= (wxUint32
)offset
; } 
1084     void SetComment(const wxString
& comment
)    { m_Comment 
= comment
; } 
1086     bool Read(wxInputStream
& stream
, wxMBConv
& conv
); 
1087     bool Write(wxOutputStream
& stream
, wxMBConv
& conv
) const; 
1090     wxUint16 m_DiskNumber
; 
1091     wxUint16 m_StartDisk
; 
1092     wxUint16 m_EntriesHere
; 
1093     wxUint16 m_TotalEntries
; 
1099 wxZipEndRec::wxZipEndRec() 
1109 bool wxZipEndRec::Write(wxOutputStream
& stream
, wxMBConv
& conv
) const 
1111     const wxWX2MBbuf comment_buf 
= conv
.cWX2MB(m_Comment
); 
1112     const char *comment 
= comment_buf
; 
1113     if (!comment
) comment 
= ""; 
1114     wxUint16 commentLen 
= (wxUint16
)strlen(comment
); 
1116     wxDataOutputStream 
ds(stream
); 
1118     ds 
<< END_MAGIC 
<< m_DiskNumber 
<< m_StartDisk 
<< m_EntriesHere
 
1119        << m_TotalEntries 
<< m_Size 
<< m_Offset 
<< commentLen
; 
1121     stream
.Write(comment
, commentLen
); 
1123     return stream
.IsOk(); 
1126 bool wxZipEndRec::Read(wxInputStream
& stream
, wxMBConv
& conv
) 
1128     wxDataInputStream 
ds(stream
); 
1129     wxUint16 commentLen
; 
1131     ds 
>> m_DiskNumber 
>> m_StartDisk 
>> m_EntriesHere
 
1132        >> m_TotalEntries 
>> m_Size 
>> m_Offset 
>> commentLen
; 
1135         m_Comment 
= ReadString(stream
, commentLen
, conv
); 
1138         if (m_DiskNumber 
== 0 && m_StartDisk 
== 0 && 
1139                 m_EntriesHere 
== m_TotalEntries
) 
1142             wxLogError(_("unsupported zip archive")); 
1148 ///////////////////////////////////////////////////////////////////////////// 
1149 // A weak link from an input stream to an output stream 
1151 class wxZipStreamLink
 
1154     wxZipStreamLink(wxZipOutputStream 
*stream
) : m_ref(1), m_stream(stream
) { } 
1156     wxZipStreamLink 
*AddRef() { m_ref
++; return this; } 
1157     wxZipOutputStream 
*GetOutputStream() const { return m_stream
; } 
1159     void Release(class wxZipInputStream 
*WXUNUSED(s
)) 
1160         { if (--m_ref 
== 0) delete this; } 
1161     void Release(class wxZipOutputStream 
*WXUNUSED(s
)) 
1162         { m_stream 
= NULL
; if (--m_ref 
== 0) delete this; } 
1165     ~wxZipStreamLink() { } 
1168     wxZipOutputStream 
*m_stream
; 
1172 ///////////////////////////////////////////////////////////////////////////// 
1175 // leave the default wxZipEntryPtr free for users 
1176 wxDECLARE_SCOPED_PTR(wxZipEntry
, wx__ZipEntryPtr
) 
1177 wxDEFINE_SCOPED_PTR (wxZipEntry
, wx__ZipEntryPtr
) 
1181 wxZipInputStream::wxZipInputStream(wxInputStream
& stream
, 
1182                                    wxMBConv
& conv 
/*=wxConvLocal*/) 
1183   : wxArchiveInputStream(stream
, conv
) 
1185 #if 1 //WXWIN_COMPATIBILITY_2_6 
1186     m_allowSeeking 
= false; 
1192 #if 1 //WXWIN_COMPATIBILITY_2_6 
1194 // Compatibility constructor 
1196 wxZipInputStream::wxZipInputStream(const wxString
& archive
, 
1197                                    const wxString
& file
) 
1198   : wxArchiveInputStream(OpenFile(archive
), wxConvLocal
) 
1200     // no error messages 
1203     m_allowSeeking 
= true; 
1204     wx__ZipEntryPtr entry
; 
1206     if (m_ffile
->Ok()) { 
1208             entry
.reset(GetNextEntry()); 
1210         while (entry
.get() != NULL 
&& entry
->GetInternalName() != file
); 
1213     if (entry
.get() == NULL
) 
1214         m_lasterror 
= wxSTREAM_READ_ERROR
; 
1217 wxInputStream
& wxZipInputStream::OpenFile(const wxString
& archive
) 
1220     m_ffile 
= new wxFFileInputStream(archive
); 
1224 #endif // WXWIN_COMPATIBILITY_2_6 
1226 void wxZipInputStream::Init() 
1228     m_store 
= new wxStoredInputStream(*m_parent_i_stream
); 
1234     m_parentSeekable 
= false; 
1235     m_weaklinks 
= new wxZipWeakLinks
; 
1236     m_streamlink 
= NULL
; 
1237     m_offsetAdjustment 
= 0; 
1238     m_position 
= wxInvalidOffset
; 
1241     m_lasterror 
= m_parent_i_stream
->GetLastError(); 
1244 wxZipInputStream::~wxZipInputStream() 
1246     CloseDecompressor(m_decomp
); 
1253     m_weaklinks
->Release(this); 
1256         m_streamlink
->Release(this); 
1259 wxString 
wxZipInputStream::GetComment() 
1261     if (m_position 
== wxInvalidOffset
) 
1262         if (!LoadEndRecord()) 
1263             return wxEmptyString
; 
1265     if (!m_parentSeekable 
&& Eof() && m_signature
) { 
1266         m_lasterror 
= wxSTREAM_NO_ERROR
; 
1267         m_lasterror 
= ReadLocal(true); 
1273 int wxZipInputStream::GetTotalEntries() 
1275     if (m_position 
== wxInvalidOffset
) 
1277     return m_TotalEntries
; 
1280 wxZipStreamLink 
*wxZipInputStream::MakeLink(wxZipOutputStream 
*out
) 
1282     wxZipStreamLink 
*link 
= NULL
; 
1284     if (!m_parentSeekable 
&& (IsOpened() || !Eof())) { 
1285         link 
= new wxZipStreamLink(out
); 
1287             m_streamlink
->Release(this); 
1288         m_streamlink 
= link
->AddRef(); 
1294 bool wxZipInputStream::LoadEndRecord() 
1296     wxCHECK(m_position 
== wxInvalidOffset
, false); 
1302     // First find the end-of-central-directory record. 
1303     if (!FindEndRecord()) { 
1304         // failed, so either this is a non-seekable stream (ok), or not a zip 
1305         if (m_parentSeekable
) { 
1306             m_lasterror 
= wxSTREAM_READ_ERROR
; 
1307             wxLogError(_("invalid zip file")); 
1312             wxFileOffset pos 
= m_parent_i_stream
->TellI(); 
1314             //if (pos != wxInvalidOffset) 
1315             if (pos 
>= 0 && pos 
<= LONG_MAX
) 
1316                 m_offsetAdjustment 
= m_position 
= pos
; 
1323     // Read in the end record 
1324     wxFileOffset endPos 
= m_parent_i_stream
->TellI() - 4; 
1325     if (!endrec
.Read(*m_parent_i_stream
, GetConv())) { 
1326         if (!*m_parent_i_stream
) { 
1327             m_lasterror 
= wxSTREAM_READ_ERROR
; 
1330         // TODO: try this out 
1331         wxLogWarning(_("assuming this is a multi-part zip concatenated")); 
1334     m_TotalEntries 
= endrec
.GetTotalEntries(); 
1335     m_Comment 
= endrec
.GetComment(); 
1337     // Now find the central-directory. we have the file offset of 
1338     // the CD, so look there first. 
1339     if (m_parent_i_stream
->SeekI(endrec
.GetOffset()) != wxInvalidOffset 
&& 
1340             ReadSignature() == CENTRAL_MAGIC
) { 
1341         m_signature 
= CENTRAL_MAGIC
; 
1342         m_position 
= endrec
.GetOffset(); 
1343         m_offsetAdjustment 
= 0; 
1347     // If it's not there, then it could be that the zip has been appended 
1348     // to a self extractor, so take the CD size (also in endrec), subtract 
1349     // it from the file offset of the end-central-directory and look there. 
1350     if (m_parent_i_stream
->SeekI(endPos 
- endrec
.GetSize()) 
1351             != wxInvalidOffset 
&& ReadSignature() == CENTRAL_MAGIC
) { 
1352         m_signature 
= CENTRAL_MAGIC
; 
1353         m_position 
= endPos 
- endrec
.GetSize(); 
1354         m_offsetAdjustment 
= m_position 
- endrec
.GetOffset(); 
1358     wxLogError(_("can't find central directory in zip")); 
1359     m_lasterror 
= wxSTREAM_READ_ERROR
; 
1363 // Find the end-of-central-directory record. 
1364 // If found the stream will be positioned just past the 4 signature bytes. 
1366 bool wxZipInputStream::FindEndRecord() 
1368     if (!m_parent_i_stream
->IsSeekable()) 
1371     // usually it's 22 bytes in size and the last thing in the file 
1374         if (m_parent_i_stream
->SeekI(-END_SIZE
, wxFromEnd
) == wxInvalidOffset
) 
1378     m_parentSeekable 
= true; 
1381     if (m_parent_i_stream
->Read(magic
, 4).LastRead() != 4) 
1383     if ((m_signature 
= CrackUint32(magic
)) == END_MAGIC
) 
1386     // unfortunately, the record has a comment field that can be up to 65535 
1387     // bytes in length, so if the signature not found then search backwards. 
1388     wxFileOffset pos 
= m_parent_i_stream
->TellI(); 
1389     const int BUFSIZE 
= 1024; 
1390     wxCharBuffer 
buf(BUFSIZE
); 
1392     memcpy(buf
.data(), magic
, 3); 
1393     wxFileOffset minpos 
= wxMax(pos 
- 65535L, 0); 
1395     while (pos 
> minpos
) { 
1396         size_t len 
= (size_t)(pos 
- wxMax(pos 
- (BUFSIZE 
- 3), minpos
)); 
1397         memcpy(buf
.data() + len
, buf
, 3); 
1400         if (m_parent_i_stream
->SeekI(pos
, wxFromStart
) == wxInvalidOffset 
|| 
1401                 m_parent_i_stream
->Read(buf
.data(), len
).LastRead() != len
) 
1404         char *p 
= buf
.data() + len
; 
1406         while (p
-- > buf
.data()) { 
1407             if ((m_signature 
= CrackUint32(p
)) == END_MAGIC
) { 
1408                 size_t remainder 
= buf
.data() + len 
- p
; 
1410                     m_parent_i_stream
->Ungetch(p 
+ 4, remainder 
- 4); 
1419 wxZipEntry 
*wxZipInputStream::GetNextEntry() 
1421     if (m_position 
== wxInvalidOffset
) 
1422         if (!LoadEndRecord()) 
1425     m_lasterror 
= m_parentSeekable 
? ReadCentral() : ReadLocal(); 
1429     wx__ZipEntryPtr 
entry(new wxZipEntry(m_entry
)); 
1430     entry
->m_backlink 
= m_weaklinks
->AddEntry(entry
.get(), entry
->GetKey()); 
1431     return entry
.release(); 
1434 wxStreamError 
wxZipInputStream::ReadCentral() 
1439     if (m_signature 
== END_MAGIC
) 
1440         return wxSTREAM_EOF
; 
1442     if (m_signature 
!= CENTRAL_MAGIC
) { 
1443         wxLogError(_("error reading zip central directory")); 
1444         return wxSTREAM_READ_ERROR
; 
1447     if (QuietSeek(*m_parent_i_stream
, m_position 
+ 4) == wxInvalidOffset
) 
1448         return wxSTREAM_READ_ERROR
; 
1450     m_position 
+= m_entry
.ReadCentral(*m_parent_i_stream
, GetConv()); 
1451     if (m_parent_i_stream
->GetLastError() == wxSTREAM_READ_ERROR
) { 
1453         return wxSTREAM_READ_ERROR
; 
1456     m_signature 
= ReadSignature(); 
1458     if (m_offsetAdjustment
) 
1459         m_entry
.SetOffset(m_entry
.GetOffset() + m_offsetAdjustment
); 
1460     m_entry
.SetKey(m_entry
.GetOffset()); 
1462     return wxSTREAM_NO_ERROR
; 
1465 wxStreamError 
wxZipInputStream::ReadLocal(bool readEndRec 
/*=false*/) 
1471         m_signature 
= ReadSignature(); 
1473     if (m_signature 
== CENTRAL_MAGIC 
|| m_signature 
== END_MAGIC
) { 
1474         if (m_streamlink 
&& !m_streamlink
->GetOutputStream()) { 
1475             m_streamlink
->Release(this); 
1476             m_streamlink 
= NULL
; 
1480     while (m_signature 
== CENTRAL_MAGIC
) { 
1481         if (m_weaklinks
->IsEmpty() && m_streamlink 
== NULL
) 
1482             return wxSTREAM_EOF
; 
1484         m_position 
+= m_entry
.ReadCentral(*m_parent_i_stream
, GetConv()); 
1486         if (m_parent_i_stream
->GetLastError() == wxSTREAM_READ_ERROR
) 
1487             return wxSTREAM_READ_ERROR
; 
1489         wxZipEntry 
*entry 
= m_weaklinks
->GetEntry(m_entry
.GetOffset()); 
1491             entry
->SetSystemMadeBy(m_entry
.GetSystemMadeBy()); 
1492             entry
->SetVersionMadeBy(m_entry
.GetVersionMadeBy()); 
1493             entry
->SetComment(m_entry
.GetComment()); 
1494             entry
->SetDiskStart(m_entry
.GetDiskStart()); 
1495             entry
->SetInternalAttributes(m_entry
.GetInternalAttributes()); 
1496             entry
->SetExternalAttributes(m_entry
.GetExternalAttributes()); 
1497             Copy(entry
->m_Extra
, m_entry
.m_Extra
); 
1499             m_weaklinks
->RemoveEntry(entry
->GetOffset()); 
1502         m_signature 
= ReadSignature(); 
1505     if (m_signature 
== END_MAGIC
) { 
1506         if (readEndRec 
|| m_streamlink
) { 
1508             endrec
.Read(*m_parent_i_stream
, GetConv()); 
1509             m_Comment 
= endrec
.GetComment(); 
1512                 m_streamlink
->GetOutputStream()->SetComment(endrec
.GetComment()); 
1513                 m_streamlink
->Release(this); 
1514                 m_streamlink 
= NULL
; 
1517         return wxSTREAM_EOF
; 
1520     if (m_signature 
!= LOCAL_MAGIC
) { 
1521         wxLogError(_("error reading zip local header")); 
1522         return wxSTREAM_READ_ERROR
; 
1525     m_headerSize 
= m_entry
.ReadLocal(*m_parent_i_stream
, GetConv()); 
1527     m_entry
.SetOffset(m_position
); 
1528     m_entry
.SetKey(m_position
); 
1530     if (m_parent_i_stream
->GetLastError() == wxSTREAM_READ_ERROR
) { 
1531         return wxSTREAM_READ_ERROR
; 
1534         return wxSTREAM_NO_ERROR
; 
1538 wxUint32 
wxZipInputStream::ReadSignature() 
1541     m_parent_i_stream
->Read(magic
, 4); 
1542     return m_parent_i_stream
->LastRead() == 4 ? CrackUint32(magic
) : 0; 
1545 bool wxZipInputStream::OpenEntry(wxArchiveEntry
& entry
) 
1547     wxZipEntry 
*zipEntry 
= wxStaticCast(&entry
, wxZipEntry
); 
1548     return zipEntry 
? OpenEntry(*zipEntry
) : false; 
1553 bool wxZipInputStream::DoOpen(wxZipEntry 
*entry
, bool raw
) 
1555     if (m_position 
== wxInvalidOffset
) 
1556         if (!LoadEndRecord()) 
1558     if (m_lasterror 
== wxSTREAM_READ_ERROR
) 
1560     wxCHECK(!IsOpened(), false); 
1565         if (AfterHeader() && entry
->GetKey() == m_entry
.GetOffset()) 
1567         // can only open the current entry on a non-seekable stream 
1568         wxCHECK(m_parentSeekable
, false); 
1571     m_lasterror 
= wxSTREAM_READ_ERROR
; 
1576     if (m_parentSeekable
) { 
1577         if (QuietSeek(*m_parent_i_stream
, m_entry
.GetOffset()) 
1580         if (ReadSignature() != LOCAL_MAGIC
) { 
1581             wxLogError(_("bad zipfile offset to entry")); 
1586     if (m_parentSeekable 
|| AtHeader()) { 
1587         m_headerSize 
= m_entry
.ReadLocal(*m_parent_i_stream
, GetConv()); 
1588         if (m_parentSeekable
) { 
1589             wxZipEntry 
*ref 
= m_weaklinks
->GetEntry(m_entry
.GetKey()); 
1591                 Copy(ref
->m_LocalExtra
, m_entry
.m_LocalExtra
); 
1593                 m_weaklinks
->RemoveEntry(ref
->GetKey()); 
1595             if (entry 
&& entry 
!= ref
) { 
1596                 Copy(entry
->m_LocalExtra
, m_entry
.m_LocalExtra
); 
1602     m_lasterror 
= m_parent_i_stream
->GetLastError(); 
1606 bool wxZipInputStream::OpenDecompressor(bool raw 
/*=false*/) 
1608     wxASSERT(AfterHeader()); 
1610     wxFileOffset compressedSize 
= m_entry
.GetCompressedSize(); 
1616         if (compressedSize 
!= wxInvalidOffset
) { 
1617             m_store
->Open(compressedSize
); 
1621                 m_rawin 
= new wxRawInputStream(*m_parent_i_stream
); 
1622             m_decomp 
= m_rawin
->Open(OpenDecompressor(m_rawin
->GetTee())); 
1625         if (compressedSize 
!= wxInvalidOffset 
&& 
1626                 (m_entry
.GetMethod() != wxZIP_METHOD_DEFLATE 
|| 
1627                  wxZlibInputStream::CanHandleGZip())) { 
1628             m_store
->Open(compressedSize
); 
1629             m_decomp 
= OpenDecompressor(*m_store
); 
1631             m_decomp 
= OpenDecompressor(*m_parent_i_stream
); 
1635     m_crcAccumulator 
= crc32(0, Z_NULL
, 0); 
1636     m_lasterror 
= m_decomp 
? m_decomp
->GetLastError() : wxSTREAM_READ_ERROR
; 
1640 // Can be overriden to add support for additional decompression methods 
1642 wxInputStream 
*wxZipInputStream::OpenDecompressor(wxInputStream
& stream
) 
1644     switch (m_entry
.GetMethod()) { 
1645         case wxZIP_METHOD_STORE
: 
1646             if (m_entry
.GetSize() == wxInvalidOffset
) { 
1647                 wxLogError(_("stored file length not in Zip header")); 
1650             m_store
->Open(m_entry
.GetSize()); 
1653         case wxZIP_METHOD_DEFLATE
: 
1655                 m_inflate 
= new wxZlibInputStream2(stream
); 
1657                 m_inflate
->Open(stream
); 
1661             wxLogError(_("unsupported Zip compression method")); 
1667 bool wxZipInputStream::CloseDecompressor(wxInputStream 
*decomp
) 
1669     if (decomp 
&& decomp 
== m_rawin
) 
1670         return CloseDecompressor(m_rawin
->GetFilterInputStream()); 
1671     if (decomp 
!= m_store 
&& decomp 
!= m_inflate
) 
1676 // Closes the current entry and positions the underlying stream at the start 
1677 // of the next entry 
1679 bool wxZipInputStream::CloseEntry() 
1683     if (m_lasterror 
== wxSTREAM_READ_ERROR
) 
1686     if (!m_parentSeekable
) { 
1687         if (!IsOpened() && !OpenDecompressor(true)) 
1690         const int BUFSIZE 
= 8192; 
1691         wxCharBuffer 
buf(BUFSIZE
); 
1693             Read(buf
.data(), BUFSIZE
); 
1695         m_position 
+= m_headerSize 
+ m_entry
.GetCompressedSize(); 
1698     if (m_lasterror 
== wxSTREAM_EOF
) 
1699         m_lasterror 
= wxSTREAM_NO_ERROR
; 
1701     CloseDecompressor(m_decomp
); 
1703     m_entry 
= wxZipEntry(); 
1710 size_t wxZipInputStream::OnSysRead(void *buffer
, size_t size
) 
1713         if ((AtHeader() && !DoOpen()) || !OpenDecompressor()) 
1714             m_lasterror 
= wxSTREAM_READ_ERROR
; 
1715     if (!IsOk() || !size
) 
1718     size_t count 
= m_decomp
->Read(buffer
, size
).LastRead(); 
1720         m_crcAccumulator 
= crc32(m_crcAccumulator
, (Byte
*)buffer
, count
); 
1721     m_lasterror 
= m_decomp
->GetLastError(); 
1724         if ((m_entry
.GetFlags() & wxZIP_SUMS_FOLLOW
) != 0) { 
1725             m_headerSize 
+= m_entry
.ReadDescriptor(*m_parent_i_stream
); 
1726             wxZipEntry 
*entry 
= m_weaklinks
->GetEntry(m_entry
.GetKey()); 
1729                 entry
->SetCrc(m_entry
.GetCrc()); 
1730                 entry
->SetCompressedSize(m_entry
.GetCompressedSize()); 
1731                 entry
->SetSize(m_entry
.GetSize()); 
1737             m_lasterror 
= wxSTREAM_READ_ERROR
; 
1739             if (m_parent_i_stream
->IsOk()) { 
1740                 if (m_entry
.GetSize() != TellI()) 
1741                     wxLogError(_("reading zip stream (entry %s): bad length"), 
1742                                m_entry
.GetName().c_str()); 
1743                 else if (m_crcAccumulator 
!= m_entry
.GetCrc()) 
1744                     wxLogError(_("reading zip stream (entry %s): bad crc"), 
1745                                m_entry
.GetName().c_str()); 
1747                     m_lasterror 
= wxSTREAM_EOF
; 
1755 #if 1 //WXWIN_COMPATIBILITY_2_6 
1757 // Borrowed from VS's zip stream (c) 1999 Vaclav Slavik 
1759 wxFileOffset 
wxZipInputStream::OnSysSeek(wxFileOffset seek
, wxSeekMode mode
) 
1761     // seeking works when the stream is created with the compatibility 
1763     if (!m_allowSeeking
) 
1764         return wxInvalidOffset
; 
1766         if ((AtHeader() && !DoOpen()) || !OpenDecompressor()) 
1767             m_lasterror 
= wxSTREAM_READ_ERROR
; 
1769         return wxInvalidOffset
; 
1771     // NB: since ZIP files don't natively support seeking, we have to 
1772     //     implement a brute force workaround -- reading all the data 
1773     //     between current and the new position (or between beginning of 
1774     //     the file and new position...) 
1776     wxFileOffset nextpos
; 
1777     wxFileOffset pos 
= TellI(); 
1781         case wxFromCurrent 
: nextpos 
= seek 
+ pos
; break; 
1782         case wxFromStart 
: nextpos 
= seek
; break; 
1783         case wxFromEnd 
: nextpos 
= GetLength() + seek
; break; 
1784         default : nextpos 
= pos
; break; /* just to fool compiler, never happens */ 
1787     size_t toskip 
wxDUMMY_INITIALIZE(0); 
1788     if ( nextpos 
>= pos 
) 
1790         toskip 
= (size_t)(nextpos 
- pos
); 
1794         wxZipEntry 
current(m_entry
); 
1796         if (!OpenEntry(current
)) 
1798             m_lasterror 
= wxSTREAM_READ_ERROR
; 
1801         toskip 
= (size_t)nextpos
; 
1806         const size_t BUFSIZE 
= 4096; 
1808         char buffer
[BUFSIZE
]; 
1809         while ( toskip 
> 0 ) 
1811             sz 
= wxMin(toskip
, BUFSIZE
); 
1821 #endif // WXWIN_COMPATIBILITY_2_6 
1824 ///////////////////////////////////////////////////////////////////////////// 
1827 #include "wx/listimpl.cpp" 
1828 WX_DEFINE_LIST(wx__ZipEntryList
); 
1830 wxZipOutputStream::wxZipOutputStream(wxOutputStream
& stream
, 
1832                                      wxMBConv
& conv 
/*=wxConvLocal*/) 
1833   : wxArchiveOutputStream(stream
, conv
), 
1834     m_store(new wxStoredOutputStream(stream
)), 
1837     m_initialData(new char[OUTPUT_LATENCY
]), 
1846     m_offsetAdjustment(wxInvalidOffset
) 
1850 wxZipOutputStream::~wxZipOutputStream() 
1853     WX_CLEAR_LIST(wx__ZipEntryList
, m_entries
); 
1857     delete [] m_initialData
; 
1859         m_backlink
->Release(this); 
1862 bool wxZipOutputStream::PutNextEntry( 
1863     const wxString
& name
, 
1864     const wxDateTime
& dt 
/*=wxDateTime::Now()*/, 
1865     wxFileOffset size    
/*=wxInvalidOffset*/) 
1867     return PutNextEntry(new wxZipEntry(name
, dt
, size
)); 
1870 bool wxZipOutputStream::PutNextDirEntry( 
1871     const wxString
& name
, 
1872     const wxDateTime
& dt 
/*=wxDateTime::Now()*/) 
1874     wxZipEntry 
*entry 
= new wxZipEntry(name
, dt
); 
1876     return PutNextEntry(entry
); 
1879 bool wxZipOutputStream::CopyEntry(wxZipEntry 
*entry
, 
1880                                   wxZipInputStream
& inputStream
) 
1882     wx__ZipEntryPtr 
e(entry
); 
1885         inputStream
.DoOpen(e
.get(), true) && 
1886         DoCreate(e
.release(), true) && 
1887         Write(inputStream
).IsOk() && inputStream
.Eof(); 
1890 bool wxZipOutputStream::PutNextEntry(wxArchiveEntry 
*entry
) 
1892     wxZipEntry 
*zipEntry 
= wxStaticCast(entry
, wxZipEntry
); 
1895     return PutNextEntry(zipEntry
); 
1898 bool wxZipOutputStream::CopyEntry(wxArchiveEntry 
*entry
, 
1899                                   wxArchiveInputStream
& stream
) 
1901     wxZipEntry 
*zipEntry 
= wxStaticCast(entry
, wxZipEntry
); 
1903     if (!zipEntry 
|| !stream
.OpenEntry(*zipEntry
)) { 
1908     return CopyEntry(zipEntry
, wx_static_cast(wxZipInputStream
&, stream
)); 
1911 bool wxZipOutputStream::CopyArchiveMetaData(wxZipInputStream
& inputStream
) 
1913     m_Comment 
= inputStream
.GetComment(); 
1915         m_backlink
->Release(this); 
1916     m_backlink 
= inputStream
.MakeLink(this); 
1920 bool wxZipOutputStream::CopyArchiveMetaData(wxArchiveInputStream
& stream
) 
1922     return CopyArchiveMetaData(wx_static_cast(wxZipInputStream
&, stream
)); 
1925 void wxZipOutputStream::SetLevel(int level
) 
1927     if (level 
!= m_level
) { 
1928         if (m_comp 
!= m_deflate
) 
1935 bool wxZipOutputStream::DoCreate(wxZipEntry 
*entry
, bool raw 
/*=false*/) 
1943     // write the signature bytes right away 
1944     wxDataOutputStream 
ds(*m_parent_o_stream
); 
1947     // and if this is the first entry test for seekability 
1948     if (m_headerOffset 
== 0 && m_parent_o_stream
->IsSeekable()) { 
1950         bool logging 
= wxLog::IsEnabled(); 
1953         wxFileOffset here 
= m_parent_o_stream
->TellO(); 
1955         if (here 
!= wxInvalidOffset 
&& here 
>= 4) { 
1956             if (m_parent_o_stream
->SeekO(here 
- 4) == here 
- 4) { 
1957                 m_offsetAdjustment 
= here 
- 4; 
1959                 wxLog::EnableLogging(logging
); 
1961                 m_parent_o_stream
->SeekO(here
); 
1966     m_pending
->SetOffset(m_headerOffset
); 
1968     m_crcAccumulator 
= crc32(0, Z_NULL
, 0); 
1973     m_lasterror 
= wxSTREAM_NO_ERROR
; 
1977 // Can be overriden to add support for additional compression methods 
1979 wxOutputStream 
*wxZipOutputStream::OpenCompressor( 
1980     wxOutputStream
& stream
, 
1982     const Buffer bufs
[]) 
1984     if (entry
.GetMethod() == wxZIP_METHOD_DEFAULT
) { 
1986                 && (IsParentSeekable() 
1987                     || entry
.GetCompressedSize() != wxInvalidOffset
 
1988                     || entry
.GetSize() != wxInvalidOffset
)) { 
1989             entry
.SetMethod(wxZIP_METHOD_STORE
); 
1992             for (int i 
= 0; bufs
[i
].m_data
; ++i
) 
1993                 size 
+= bufs
[i
].m_size
; 
1994             entry
.SetMethod(size 
<= 6 ? 
1995                             wxZIP_METHOD_STORE 
: wxZIP_METHOD_DEFLATE
); 
1999     switch (entry
.GetMethod()) { 
2000         case wxZIP_METHOD_STORE
: 
2001             if (entry
.GetCompressedSize() == wxInvalidOffset
) 
2002                 entry
.SetCompressedSize(entry
.GetSize()); 
2005         case wxZIP_METHOD_DEFLATE
: 
2007             int defbits 
= wxZIP_DEFLATE_NORMAL
; 
2008             switch (GetLevel()) { 
2010                     defbits 
= wxZIP_DEFLATE_SUPERFAST
; 
2012                 case 2: case 3: case 4: 
2013                     defbits 
= wxZIP_DEFLATE_FAST
; 
2016                     defbits 
= wxZIP_DEFLATE_EXTRA
; 
2019             entry
.SetFlags((entry
.GetFlags() & ~wxZIP_DEFLATE_MASK
) | 
2020                             defbits 
| wxZIP_SUMS_FOLLOW
); 
2023                 m_deflate 
= new wxZlibOutputStream2(stream
, GetLevel()); 
2025                 m_deflate
->Open(stream
); 
2031             wxLogError(_("unsupported Zip compression method")); 
2037 bool wxZipOutputStream::CloseCompressor(wxOutputStream 
*comp
) 
2039     if (comp 
== m_deflate
) 
2041     else if (comp 
!= m_store
) 
2046 // This is called when OUPUT_LATENCY bytes has been written to the 
2047 // wxZipOutputStream to actually create the zip entry. 
2049 void wxZipOutputStream::CreatePendingEntry(const void *buffer
, size_t size
) 
2051     wxASSERT(IsOk() && m_pending 
&& !m_comp
); 
2052     wx__ZipEntryPtr 
spPending(m_pending
); 
2056         { m_initialData
, m_initialSize 
}, 
2057         { (const char*)buffer
, size 
}, 
2064         m_comp 
= OpenCompressor(*m_store
, *spPending
, 
2065                                 m_initialSize 
? bufs 
: bufs 
+ 1); 
2067     if (IsParentSeekable() 
2068         || (spPending
->m_Crc
 
2069             && spPending
->m_CompressedSize 
!= wxInvalidOffset
 
2070             && spPending
->m_Size 
!= wxInvalidOffset
)) 
2071         spPending
->m_Flags 
&= ~wxZIP_SUMS_FOLLOW
; 
2073         if (spPending
->m_CompressedSize 
!= wxInvalidOffset
) 
2074             spPending
->m_Flags 
|= wxZIP_SUMS_FOLLOW
; 
2076     m_headerSize 
= spPending
->WriteLocal(*m_parent_o_stream
, GetConv()); 
2077     m_lasterror 
= m_parent_o_stream
->GetLastError(); 
2080         m_entries
.push_back(spPending
.release()); 
2081         OnSysWrite(m_initialData
, m_initialSize
); 
2087 // This is called to write out the zip entry when Close has been called 
2088 // before OUTPUT_LATENCY bytes has been written to the wxZipOutputStream. 
2090 void wxZipOutputStream::CreatePendingEntry() 
2092     wxASSERT(IsOk() && m_pending 
&& !m_comp
); 
2093     wx__ZipEntryPtr 
spPending(m_pending
); 
2095     m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
2098         // Initially compresses the data to memory, then fall back to 'store' 
2099         // if the compressor makes the data larger rather than smaller. 
2100         wxMemoryOutputStream mem
; 
2101         Buffer bufs
[] = { { m_initialData
, m_initialSize 
}, { NULL
, 0 } }; 
2102         wxOutputStream 
*comp 
= OpenCompressor(mem
, *spPending
, bufs
); 
2106         if (comp 
!= m_store
) { 
2107             bool ok 
= comp
->Write(m_initialData
, m_initialSize
).IsOk(); 
2108             CloseCompressor(comp
); 
2113         m_entrySize 
= m_initialSize
; 
2114         m_crcAccumulator 
= crc32(0, (Byte
*)m_initialData
, m_initialSize
); 
2116         if (mem
.GetSize() > 0 && mem
.GetSize() < m_initialSize
) { 
2117             m_initialSize 
= mem
.GetSize(); 
2118             mem
.CopyTo(m_initialData
, m_initialSize
); 
2120             spPending
->SetMethod(wxZIP_METHOD_STORE
); 
2123         spPending
->SetSize(m_entrySize
); 
2124         spPending
->SetCrc(m_crcAccumulator
); 
2125         spPending
->SetCompressedSize(m_initialSize
); 
2128     spPending
->m_Flags 
&= ~wxZIP_SUMS_FOLLOW
; 
2129     m_headerSize 
= spPending
->WriteLocal(*m_parent_o_stream
, GetConv()); 
2131     if (m_parent_o_stream
->IsOk()) { 
2132         m_entries
.push_back(spPending
.release()); 
2134         m_store
->Write(m_initialData
, m_initialSize
); 
2138     m_lasterror 
= m_parent_o_stream
->GetLastError(); 
2141 // Write the 'central directory' and the 'end-central-directory' records. 
2143 bool wxZipOutputStream::Close() 
2147     if (m_lasterror 
== wxSTREAM_WRITE_ERROR 
|| m_entries
.size() == 0) 
2152     endrec
.SetEntriesHere(m_entries
.size()); 
2153     endrec
.SetTotalEntries(m_entries
.size()); 
2154     endrec
.SetOffset(m_headerOffset
); 
2155     endrec
.SetComment(m_Comment
); 
2157     wx__ZipEntryList::iterator it
; 
2158     wxFileOffset size 
= 0; 
2160     for (it 
= m_entries
.begin(); it 
!= m_entries
.end(); ++it
) { 
2161         size 
+= (*it
)->WriteCentral(*m_parent_o_stream
, GetConv()); 
2166     endrec
.SetSize(size
); 
2167     endrec
.Write(*m_parent_o_stream
, GetConv()); 
2169     m_lasterror 
= m_parent_o_stream
->GetLastError(); 
2172     m_lasterror 
= wxSTREAM_EOF
; 
2176 // Finish writing the current entry 
2178 bool wxZipOutputStream::CloseEntry() 
2180     if (IsOk() && m_pending
) 
2181         CreatePendingEntry(); 
2187     CloseCompressor(m_comp
); 
2190     wxFileOffset compressedSize 
= m_store
->TellO(); 
2192     wxZipEntry
& entry 
= *m_entries
.back(); 
2194     // When writing raw the crc and size can't be checked 
2196         m_crcAccumulator 
= entry
.GetCrc(); 
2197         m_entrySize 
= entry
.GetSize(); 
2200     // Write the sums in the trailing 'data descriptor' if necessary 
2201     if (entry
.m_Flags 
& wxZIP_SUMS_FOLLOW
) { 
2202         wxASSERT(!IsParentSeekable()); 
2204             entry
.WriteDescriptor(*m_parent_o_stream
, m_crcAccumulator
, 
2205                                   compressedSize
, m_entrySize
); 
2206         m_lasterror 
= m_parent_o_stream
->GetLastError(); 
2209     // If the local header didn't have the correct crc and size written to 
2210     // it then seek back and fix it 
2211     else if (m_crcAccumulator 
!= entry
.GetCrc() 
2212             || m_entrySize 
!= entry
.GetSize() 
2213             || compressedSize 
!= entry
.GetCompressedSize()) 
2215         if (IsParentSeekable()) { 
2216             wxFileOffset here 
= m_parent_o_stream
->TellO(); 
2217             wxFileOffset headerOffset 
= m_headerOffset 
+ m_offsetAdjustment
; 
2218             m_parent_o_stream
->SeekO(headerOffset 
+ SUMS_OFFSET
); 
2219             entry
.WriteDescriptor(*m_parent_o_stream
, m_crcAccumulator
, 
2220                                   compressedSize
, m_entrySize
); 
2221             m_parent_o_stream
->SeekO(here
); 
2222             m_lasterror 
= m_parent_o_stream
->GetLastError(); 
2224             m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
2228     m_headerOffset 
+= m_headerSize 
+ compressedSize
; 
2235         m_lasterror 
= m_parent_o_stream
->GetLastError(); 
2237         wxLogError(_("error writing zip entry '%s': bad crc or length"), 
2238                    entry
.GetName().c_str()); 
2242 void wxZipOutputStream::Sync() 
2244     if (IsOk() && m_pending
) 
2245         CreatePendingEntry(NULL
, 0); 
2247         m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
2250         m_lasterror 
= m_comp
->GetLastError(); 
2254 size_t wxZipOutputStream::OnSysWrite(const void *buffer
, size_t size
) 
2256     if (IsOk() && m_pending
) { 
2257         if (m_initialSize 
+ size 
< OUTPUT_LATENCY
) { 
2258             memcpy(m_initialData 
+ m_initialSize
, buffer
, size
); 
2259             m_initialSize 
+= size
; 
2262             CreatePendingEntry(buffer
, size
); 
2267         m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
2268     if (!IsOk() || !size
) 
2271     if (m_comp
->Write(buffer
, size
).LastWrite() != size
) 
2272         m_lasterror 
= wxSTREAM_WRITE_ERROR
; 
2273     m_crcAccumulator 
= crc32(m_crcAccumulator
, (Byte
*)buffer
, size
); 
2274     m_entrySize 
+= m_comp
->LastWrite(); 
2276     return m_comp
->LastWrite(); 
2279 #endif // wxUSE_ZLIB && wxUSE_STREAMS && wxUSE_ZIPSTREAM