]> git.saurik.com Git - wxWidgets.git/blobdiff - include/wx/zipstrm.h
Don't automatically define WX_PRECOMP when building using configure.
[wxWidgets.git] / include / wx / zipstrm.h
index 489a73020dff1e52a483e1577dfc0a3026cc13ed..976a17050b9156409de9aabaad723eb0e6591458 100644 (file)
@@ -1,13 +1,14 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        zipstream.h
-// Purpose:     wxZipInputStream for reading files from ZIP archive
-// Author:      Vaclav Slavik
-// Copyright:   (c) 1999 Vaclav Slavik
+// Name:        zipstrm.h
+// Purpose:     Streams for Zip files
+// Author:      Mike Wetherell
+// RCS-ID:      $Id$
+// Copyright:   (c) Mike Wetherell
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-#ifndef __ZIPSTREAM_H__
-#define __ZIPSTREAM_H__
+#ifndef _WX_WXZIPSTREAM_H__
+#define _WX_WXZIPSTREAM_H__
 
 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
 #pragma interface "zipstrm.h"
 
 #include "wx/defs.h"
 
-#if wxUSE_STREAMS && wxUSE_ZIPSTREAM && wxUSE_ZLIB
+#if wxUSE_ZLIB && wxUSE_STREAMS && wxUSE_ZIPSTREAM
 
-#include "wx/stream.h"
+#include "wx/archive.h"
+#include "wx/hashmap.h"
+#include "wx/filename.h"
 
-//--------------------------------------------------------------------------------
-// wxZipInputStream
-//                  This class is input stream from ZIP archive. The archive
-//                  must be local file (accessible via FILE*)
-//--------------------------------------------------------------------------------
 
+/////////////////////////////////////////////////////////////////////////////
+// constants
+
+// Compression Method, only 0 (store) and 8 (deflate) are supported here
+//
+enum wxZipMethod
+{
+    wxZIP_METHOD_STORE,
+    wxZIP_METHOD_SHRINK,
+    wxZIP_METHOD_REDUCE1,
+    wxZIP_METHOD_REDUCE2,
+    wxZIP_METHOD_REDUCE3,
+    wxZIP_METHOD_REDUCE4,
+    wxZIP_METHOD_IMPLODE,
+    wxZIP_METHOD_TOKENIZE,
+    wxZIP_METHOD_DEFLATE,
+    wxZIP_METHOD_DEFLATE64,
+    wxZIP_METHOD_BZIP2 = 12,
+    wxZIP_METHOD_DEFAULT = 0xffff
+};
+
+// Originating File-System.
+// 
+// These are Pkware's values. Note that Info-zip disagree on some of them,
+// most notably NTFS.
+//
+enum wxZipSystem
+{
+    wxZIP_SYSTEM_MSDOS,
+    wxZIP_SYSTEM_AMIGA,
+    wxZIP_SYSTEM_OPENVMS,
+    wxZIP_SYSTEM_UNIX,
+    wxZIP_SYSTEM_VM_CMS,
+    wxZIP_SYSTEM_ATARI_ST,
+    wxZIP_SYSTEM_OS2_HPFS,
+    wxZIP_SYSTEM_MACINTOSH,
+    wxZIP_SYSTEM_Z_SYSTEM,
+    wxZIP_SYSTEM_CPM,
+    wxZIP_SYSTEM_WINDOWS_NTFS,
+    wxZIP_SYSTEM_MVS,
+    wxZIP_SYSTEM_VSE,
+    wxZIP_SYSTEM_ACORN_RISC,
+    wxZIP_SYSTEM_VFAT,
+    wxZIP_SYSTEM_ALTERNATE_MVS,
+    wxZIP_SYSTEM_BEOS,
+    wxZIP_SYSTEM_TANDEM,
+    wxZIP_SYSTEM_OS_400
+};
+
+// Dos/Win file attributes
+//
+enum wxZipAttributes
+{
+    wxZIP_A_RDONLY = 0x01,
+    wxZIP_A_HIDDEN = 0x02,
+    wxZIP_A_SYSTEM = 0x04,
+    wxZIP_A_SUBDIR = 0x10,
+    wxZIP_A_ARCH   = 0x20,
+
+    wxZIP_A_MASK   = 0x37
+};
+
+// Values for the flags field in the zip headers
+//
+enum wxZipFlags
+{
+    wxZIP_ENCRYPTED         = 0x0001,
+    wxZIP_DEFLATE_NORMAL    = 0x0000,   // normal compression
+    wxZIP_DEFLATE_EXTRA     = 0x0002,   // extra compression
+    wxZIP_DEFLATE_FAST      = 0x0004,   // fast compression
+    wxZIP_DEFLATE_SUPERFAST = 0x0006,   // superfast compression
+    wxZIP_DEFLATE_MASK      = 0x0006,
+    wxZIP_SUMS_FOLLOW       = 0x0008,   // crc and sizes come after the data
+    wxZIP_ENHANCED          = 0x0010,
+    wxZIP_PATCH             = 0x0020,
+    wxZIP_STRONG_ENC        = 0x0040,
+    wxZIP_UNUSED            = 0x0F80,
+    wxZIP_RESERVED          = 0xF000
+};
+
+// Forward decls
+//
+class WXDLLIMPEXP_BASE wxZipEntry;
+class WXDLLIMPEXP_BASE wxZipInputStream;
+
+
+/////////////////////////////////////////////////////////////////////////////
+// wxZipNotifier
+
+class WXDLLIMPEXP_BASE wxZipNotifier
+{
+public:
+    virtual ~wxZipNotifier() { }
+
+    virtual void OnEntryUpdated(wxZipEntry& entry) = 0;
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Zip Entry - holds the meta data for a file in the zip
+
+class WXDLLIMPEXP_BASE wxZipEntry : public wxArchiveEntry
+{
+public:
+    wxZipEntry(const wxString& name = wxEmptyString,
+               const wxDateTime& dt = wxDateTime::Now(),
+               wxFileOffset size = wxInvalidOffset);
+    virtual ~wxZipEntry();
+
+    wxZipEntry(const wxZipEntry& entry);
+    wxZipEntry& operator=(const wxZipEntry& entry);
+
+    // Get accessors
+    wxDateTime   GetDateTime() const            { return m_DateTime; }
+    wxFileOffset GetSize() const                { return m_Size; }
+    wxFileOffset GetOffset() const              { return m_Offset; }
+    wxString     GetInternalName() const        { return m_Name; }
+    int          GetMethod() const              { return m_Method; }
+    int          GetFlags() const               { return m_Flags; }
+    wxUint32     GetCrc() const                 { return m_Crc; }
+    wxFileOffset GetCompressedSize() const      { return m_CompressedSize; }
+    int          GetSystemMadeBy() const        { return m_SystemMadeBy; }
+    wxString     GetComment() const             { return m_Comment; }
+    wxUint32     GetExternalAttributes() const  { return m_ExternalAttributes; }
+    wxPathFormat GetInternalFormat() const      { return wxPATH_UNIX; }
+    int          GetMode() const;
+    const char  *GetLocalExtra() const;
+    size_t       GetLocalExtraLen() const;
+    const char  *GetExtra() const;
+    size_t       GetExtraLen() const;
+    wxString     GetName(wxPathFormat format = wxPATH_NATIVE) const;
+
+    // is accessors
+    inline bool IsDir() const;
+    inline bool IsText() const;
+    inline bool IsReadOnly() const;
+    inline bool IsMadeByUnix() const;
+
+    // set accessors
+    void SetDateTime(const wxDateTime& dt)      { m_DateTime = dt; }
+    void SetSize(wxFileOffset size)             { m_Size = size; }
+    void SetMethod(int method)                  { m_Method = (wxUint16)method; }
+    void SetComment(const wxString& comment)    { m_Comment = comment; }
+    void SetExternalAttributes(wxUint32 attr )  { m_ExternalAttributes = attr; }
+    void SetSystemMadeBy(int system);
+    void SetMode(int mode);
+    void SetExtra(const char *extra, size_t len);
+    void SetLocalExtra(const char *extra, size_t len);
 
-class WXDLLIMPEXP_BASE wxZipInputStream : public wxInputStream
+    inline void SetName(const wxString& name,
+                        wxPathFormat format = wxPATH_NATIVE);
+
+    static wxString GetInternalName(const wxString& name,
+                                    wxPathFormat format = wxPATH_NATIVE,
+                                    bool *pIsDir = NULL);
+
+    // set is accessors
+    void SetIsDir(bool isDir = true);
+    inline void SetIsReadOnly(bool isReadOnly = true);
+    inline void SetIsText(bool isText = true);
+
+    wxZipEntry *Clone() const                   { return ZipClone(); }
+
+    void SetNotifier(wxZipNotifier& notifier);
+    void UnsetNotifier();
+
+protected:
+    // Internal attributes
+    enum { TEXT_ATTR = 1 };
+
+    // protected Get accessors
+    int GetVersionNeeded() const                { return m_VersionNeeded; }
+    wxFileOffset GetKey() const                 { return m_Key; }
+    int GetVersionMadeBy() const                { return m_VersionMadeBy; }
+    int GetDiskStart() const                    { return m_DiskStart; }
+    int GetInternalAttributes() const           { return m_InternalAttributes; }
+
+    void SetVersionNeeded(int version)          { m_VersionNeeded = (wxUint16)version; }
+    void SetOffset(wxFileOffset offset)         { m_Offset = offset; }
+    void SetFlags(int flags)                    { m_Flags = (wxUint16)flags; }
+    void SetVersionMadeBy(int version)          { m_VersionMadeBy = (wxUint8)version; }
+    void SetCrc(wxUint32 crc)                   { m_Crc = crc; }
+    void SetCompressedSize(wxFileOffset size)   { m_CompressedSize = size; }
+    void SetKey(wxFileOffset offset)            { m_Key = offset; }
+    void SetDiskStart(int start)                { m_DiskStart = (wxUint16)start; }
+    void SetInternalAttributes(int attr)        { m_InternalAttributes = (wxUint16)attr; }
+
+    virtual wxZipEntry *ZipClone() const        { return new wxZipEntry(*this); }
+
+    void Notify();
+
+private:
+    wxArchiveEntry* DoClone() const             { return ZipClone(); }
+
+    size_t ReadLocal(wxInputStream& stream, wxMBConv& conv);
+    size_t WriteLocal(wxOutputStream& stream, wxMBConv& conv) const;
+
+    size_t ReadCentral(wxInputStream& stream, wxMBConv& conv);
+    size_t WriteCentral(wxOutputStream& stream, wxMBConv& conv) const;
+
+    size_t ReadDescriptor(wxInputStream& stream);
+    size_t WriteDescriptor(wxOutputStream& stream, wxUint32 crc,
+                           wxFileOffset compressedSize, wxFileOffset size);
+
+    wxUint8      m_SystemMadeBy;       // one of enum wxZipSystem
+    wxUint8      m_VersionMadeBy;      // major * 10 + minor
+
+    wxUint16     m_VersionNeeded;      // ver needed to extract (20 i.e. v2.0)
+    wxUint16     m_Flags;
+    wxUint16     m_Method;             // compression method (one of wxZipMethod)
+    wxDateTime   m_DateTime;
+    wxUint32     m_Crc;
+    wxFileOffset m_CompressedSize;
+    wxFileOffset m_Size;
+    wxString     m_Name;               // in internal format
+    wxFileOffset m_Key;                // the original offset for copied entries
+    wxFileOffset m_Offset;             // file offset of the entry
+
+    wxString     m_Comment;
+    wxUint16     m_DiskStart;          // for multidisk archives, not unsupported
+    wxUint16     m_InternalAttributes; // bit 0 set for text files
+    wxUint32     m_ExternalAttributes; // system specific depends on SystemMadeBy
+
+    class wxZipMemory *m_Extra;
+    class wxZipMemory *m_LocalExtra;
+
+    wxZipNotifier *m_zipnotifier;
+    class wxZipWeakLinks *m_backlink;
+
+    friend class wxZipInputStream;
+    friend class wxZipOutputStream;
+
+    DECLARE_DYNAMIC_CLASS(wxZipEntry)
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// wxZipOutputStream 
+
+WX_DECLARE_LIST_WITH_DECL(wxZipEntry, _wxZipEntryList, class WXDLLIMPEXP_BASE);
+
+class WXDLLIMPEXP_BASE wxZipOutputStream : public wxArchiveOutputStream
 {
 public:
+    wxZipOutputStream(wxOutputStream& stream,
+                      int level = -1,
+                      wxMBConv& conv = wxConvLocal);
+    virtual ~wxZipOutputStream();
+
+    bool PutNextEntry(wxZipEntry *entry)        { return DoCreate(entry); }
+
+    bool PutNextEntry(const wxString& name,
+                      const wxDateTime& dt = wxDateTime::Now(),
+                      wxFileOffset size = wxInvalidOffset);
+
+    bool PutNextDirEntry(const wxString& name,
+                         const wxDateTime& dt = wxDateTime::Now());
+
+    bool CopyEntry(wxZipEntry *entry, wxZipInputStream& inputStream);
+    bool CopyArchiveMetaData(wxZipInputStream& inputStream);
+
+    void Sync();
+    bool CloseEntry();
+    bool Close();
+
+    void SetComment(const wxString& comment)    { m_Comment = comment; }
+
+    int  GetLevel() const                       { return m_level; }
+    void SetLevel(int level);
+    
+protected:
+    virtual size_t OnSysWrite(const void *buffer, size_t size);
+    virtual wxFileOffset OnSysTell() const      { return m_entrySize; }
+
+    struct Buffer { const char *m_data; size_t m_size; };
+    virtual wxOutputStream *OpenCompressor(wxOutputStream& stream,
+                                           wxZipEntry& entry,
+                                           const Buffer bufs[]);
+    virtual bool CloseCompressor(wxOutputStream *comp);
+
+    bool IsParentSeekable() const               { return m_offsetAdjustment
+                                                        != wxInvalidOffset; }
+
+private:
+    bool PutNextEntry(wxArchiveEntry *entry);
+    bool CopyEntry(wxArchiveEntry *entry, wxArchiveInputStream& stream);
+    bool CopyArchiveMetaData(wxArchiveInputStream& stream);
+
+    bool IsOpened() const                       { return m_comp || m_pending; }
+
+    bool DoCreate(wxZipEntry *entry, bool raw = false);
+    void CreatePendingEntry(const void *buffer, size_t size);
+    void CreatePendingEntry();
+
+    class wxStoredOutputStream *m_store;
+    class wxZlibOutputStream2 *m_deflate;
+    class wxZipStreamLink *m_backlink;
+    _wxZipEntryList m_entries;
+    char *m_initialData;
+    size_t m_initialSize;
+    wxZipEntry *m_pending;
+    bool m_raw;
+    wxFileOffset m_headerOffset;
+    size_t m_headerSize;
+    wxFileOffset m_entrySize;
+    wxUint32 m_crcAccumulator;
+    wxOutputStream *m_comp;
+    int m_level;
+    wxFileOffset m_offsetAdjustment;
+    wxString m_Comment;
+
+    DECLARE_NO_COPY_CLASS(wxZipOutputStream)
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// wxZipInputStream 
+
+class WXDLLIMPEXP_BASE wxZipInputStream : public wxArchiveInputStream
+{
+public:
+    typedef wxZipEntry entry_type;
+
+    wxZipInputStream(wxInputStream& stream, wxMBConv& conv = wxConvLocal);
     wxZipInputStream(const wxString& archive, const wxString& file);
-            // archive is name of .zip archive, file is name of file to be extracted.
-            // Remember that archive must be local file accesible via fopen, fread functions!
-    ~wxZipInputStream();
+    virtual ~wxZipInputStream();
+
+    bool OpenEntry(wxZipEntry& entry)   { return DoOpen(&entry); }
+    bool CloseEntry();
+
+    wxZipEntry *GetNextEntry();
 
-    virtual size_t GetSize() const {return m_Size;}
-    virtual bool Eof() const;
+    wxString GetComment();
+    int GetTotalEntries();
+
+    virtual wxFileOffset GetLength() const { return m_entry.GetSize(); }
 
 protected:
-    virtual size_t OnSysRead(void *buffer, size_t bufsize);
-    virtual wxFileOffset OnSysSeek(wxFileOffset seek, wxSeekMode mode);
-    virtual wxFileOffset OnSysTell() const {return m_Pos;}
+    size_t OnSysRead(void *buffer, size_t size);
+    wxFileOffset OnSysTell() const { return m_decomp ? m_decomp->TellI() : 0; }
+    wxFileOffset OnSysSeek(wxFileOffset seek, wxSeekMode mode);
+
+    virtual wxInputStream *OpenDecompressor(wxInputStream& stream);
+    virtual bool CloseDecompressor(wxInputStream *decomp);
 
 private:
-    size_t m_Size;
-    wxFileOffset m_Pos;
+    void Init();
+    wxInputStream& OpenFile(const wxString& archive);
+
+    wxArchiveEntry *DoGetNextEntry()    { return GetNextEntry(); }
+
+    bool OpenEntry(wxArchiveEntry& entry);
 
-    // this void* is handle of archive . I'm sorry it is void and not proper
-    // type but I don't want to make unzip.h header public.
-    void *m_Archive;
+    wxStreamError ReadLocal(bool readEndRec = false);
+    wxStreamError ReadCentral();
+
+    wxUint32 ReadSignature();
+    bool FindEndRecord();
+    bool LoadEndRecord();
+    
+    bool AtHeader() const       { return m_headerSize == 0; }
+    bool AfterHeader() const    { return m_headerSize > 0 && !m_decomp; }
+    bool IsOpened() const       { return m_decomp != NULL; }
+
+    wxZipStreamLink *MakeLink(wxZipOutputStream *out);
+
+    bool DoOpen(wxZipEntry *entry = NULL, bool raw = false);
+    bool OpenDecompressor(bool raw = false);
+
+    class wxStoredInputStream *m_store;
+    class wxZlibInputStream2 *m_inflate;
+    class wxRawInputStream *m_rawin;
+    class wxFFileInputStream *m_ffile;
+    wxZipEntry m_entry;
+    bool m_raw;
+    size_t m_headerSize;
+    wxUint32 m_crcAccumulator;
+    wxInputStream *m_decomp;
+    bool m_parentSeekable;
+    class wxZipWeakLinks *m_weaklinks;
+    class wxZipStreamLink *m_streamlink;
+    wxFileOffset m_offsetAdjustment;
+    wxFileOffset m_position;
+    wxUint32 m_signature;
+    size_t m_TotalEntries;
+    wxString m_Comment;
+
+    friend bool wxZipOutputStream::CopyEntry(
+                    wxZipEntry *entry, wxZipInputStream& inputStream);
+    friend bool wxZipOutputStream::CopyArchiveMetaData(
+                    wxZipInputStream& inputStream);
 
     DECLARE_NO_COPY_CLASS(wxZipInputStream)
 };
 
 
+/////////////////////////////////////////////////////////////////////////////
+// Iterators
+
+#if wxUSE_STL || defined WX_TEST_ARCHIVE_ITERATOR
+typedef wxArchiveIterator<wxZipInputStream> wxZipIter;
+typedef wxArchiveIterator<wxZipInputStream,
+         std::pair<wxString, wxZipEntry*> > wxZipPairIter;
 #endif
-   // wxUSE_STREAMS && wxUSE_ZIPSTREAM && wxUSE_ZLIB
 
+
+/////////////////////////////////////////////////////////////////////////////
+// wxZipClassFactory
+
+class WXDLLIMPEXP_BASE wxZipClassFactory : public wxArchiveClassFactory
+{
+public:
+    typedef wxZipEntry        entry_type;
+    typedef wxZipInputStream  instream_type;
+    typedef wxZipOutputStream outstream_type;
+    typedef wxZipNotifier     notifier_type;
+#if wxUSE_STL || defined WX_TEST_ARCHIVE_ITERATOR
+    typedef wxZipIter         iter_type;
+    typedef wxZipPairIter     pairiter_type;
 #endif
-   // __ZIPSTREAM_H__
+
+    wxZipEntry *NewEntry() const
+        { return new wxZipEntry; }
+    wxZipInputStream *NewStream(wxInputStream& stream) const
+        { return new wxZipInputStream(stream, GetConv()); }
+    wxZipOutputStream *NewStream(wxOutputStream& stream) const
+        { return new wxZipOutputStream(stream, -1, GetConv()); }
+
+    wxString GetInternalName(const wxString& name,
+                             wxPathFormat format = wxPATH_NATIVE) const
+        { return wxZipEntry::GetInternalName(name, format); }
+
+protected:
+    wxArchiveEntry *DoNewEntry() const
+        { return NewEntry(); }
+    wxArchiveInputStream *DoNewStream(wxInputStream& stream) const
+        { return NewStream(stream); }
+    wxArchiveOutputStream *DoNewStream(wxOutputStream& stream) const
+        { return NewStream(stream); }
+
+private:
+    DECLARE_DYNAMIC_CLASS(wxZipClassFactory)
+};
+
+
+/////////////////////////////////////////////////////////////////////////////
+// wxZipEntry inlines
+
+inline bool wxZipEntry::IsText() const
+{
+    return (m_InternalAttributes & TEXT_ATTR) != 0;
+}
+
+inline bool wxZipEntry::IsDir() const
+{
+    return (m_ExternalAttributes & wxZIP_A_SUBDIR) != 0;
+}
+
+inline bool wxZipEntry::IsReadOnly() const
+{
+    return (m_ExternalAttributes & wxZIP_A_RDONLY) != 0;
+}
+
+inline bool wxZipEntry::IsMadeByUnix() const
+{
+    const int pattern =
+        (1 << wxZIP_SYSTEM_OPENVMS) |
+        (1 << wxZIP_SYSTEM_UNIX) |
+        (1 << wxZIP_SYSTEM_ATARI_ST) |
+        (1 << wxZIP_SYSTEM_ACORN_RISC) |
+        (1 << wxZIP_SYSTEM_BEOS) | (1 << wxZIP_SYSTEM_TANDEM);
+
+    // note: some unix zippers put madeby = dos
+    return (m_SystemMadeBy == wxZIP_SYSTEM_MSDOS
+            && (m_ExternalAttributes & ~0xFFFF))
+        || ((pattern >> m_SystemMadeBy) & 1);
+}
+
+inline void wxZipEntry::SetIsText(bool isText)
+{
+    if (isText)
+        m_InternalAttributes |= TEXT_ATTR;
+    else
+        m_InternalAttributes &= ~TEXT_ATTR;
+}
+
+inline void wxZipEntry::SetIsReadOnly(bool isReadOnly)
+{
+    if (isReadOnly)
+        SetMode(GetMode() & ~0222);
+    else
+        SetMode(GetMode() | 0200);
+}
+
+inline void wxZipEntry::SetName(const wxString& name,
+                                wxPathFormat format /*=wxPATH_NATIVE*/)
+{
+    bool isDir;
+    m_Name = GetInternalName(name, format, &isDir);
+    SetIsDir(isDir);
+}
+
+
+#endif // wxUSE_ZLIB && wxUSE_STREAMS && wxUSE_ZIPSTREAM
+
+#endif // _WX_WXZIPSTREAM_H__