wxWidgets/include/wx/zipstrm.h
2005-09-23 12:56:45 +00:00

556 lines
18 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: zipstrm.h
// Purpose: Streams for Zip files
// Author: Mike Wetherell
// RCS-ID: $Id$
// Copyright: (c) Mike Wetherell
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifndef _WX_WXZIPSTREAM_H__
#define _WX_WXZIPSTREAM_H__
#include "wx/defs.h"
#if wxUSE_ZLIB && wxUSE_STREAMS && wxUSE_ZIPSTREAM
#include "wx/archive.h"
#include "wx/hashmap.h"
#include "wx/filename.h"
// some methods from wxZipInputStream and wxZipOutputStream stream do not get
// exported/imported when compiled with Mingw versions before 3.4.2. So they
// are imported/exported individually as a workaround
#if (defined(__GNUWIN32__) || defined(__MINGW32__)) \
&& (!defined __GNUC__ \
|| !defined __GNUC_MINOR__ \
|| !defined __GNUC_PATCHLEVEL__ \
|| __GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__ < 30402)
#define WXZIPFIX WXDLLIMPEXP_BASE
#else
#define WXZIPFIX
#endif
/////////////////////////////////////////////////////////////////////////////
// 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);
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, wx__ZipEntryList, class WXDLLIMPEXP_BASE);
class WXDLLIMPEXP_BASE wxZipOutputStream : public wxArchiveOutputStream
{
public:
wxZipOutputStream(wxOutputStream& stream,
int level = -1,
wxMBConv& conv = wxConvLocal);
virtual WXZIPFIX ~wxZipOutputStream();
bool PutNextEntry(wxZipEntry *entry) { return DoCreate(entry); }
bool WXZIPFIX PutNextEntry(const wxString& name,
const wxDateTime& dt = wxDateTime::Now(),
wxFileOffset size = wxInvalidOffset);
bool WXZIPFIX PutNextDirEntry(const wxString& name,
const wxDateTime& dt = wxDateTime::Now());
bool WXZIPFIX CopyEntry(wxZipEntry *entry, wxZipInputStream& inputStream);
bool WXZIPFIX CopyArchiveMetaData(wxZipInputStream& inputStream);
void WXZIPFIX Sync();
bool WXZIPFIX CloseEntry();
bool WXZIPFIX Close();
void SetComment(const wxString& comment) { m_Comment = comment; }
int GetLevel() const { return m_level; }
void WXZIPFIX SetLevel(int level);
protected:
virtual size_t WXZIPFIX OnSysWrite(const void *buffer, size_t size);
virtual wxFileOffset OnSysTell() const { return m_entrySize; }
// this protected interface isn't yet finalised
struct Buffer { const char *m_data; size_t m_size; };
virtual wxOutputStream* WXZIPFIX OpenCompressor(wxOutputStream& stream,
wxZipEntry& entry,
const Buffer bufs[]);
virtual bool WXZIPFIX CloseCompressor(wxOutputStream *comp);
bool IsParentSeekable() const
{ return m_offsetAdjustment != wxInvalidOffset; }
private:
bool WXZIPFIX PutNextEntry(wxArchiveEntry *entry);
bool WXZIPFIX CopyEntry(wxArchiveEntry *entry, wxArchiveInputStream& stream);
bool WXZIPFIX 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;
wx__ZipEntryList 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);
#if 1 //WXWIN_COMPATIBILITY_2_6
wxZipInputStream(const wxString& archive, const wxString& file)
: wxArchiveInputStream(OpenFile(archive), wxConvLocal) { Init(file); }
#endif
virtual WXZIPFIX ~wxZipInputStream();
bool OpenEntry(wxZipEntry& entry) { return DoOpen(&entry); }
bool WXZIPFIX CloseEntry();
wxZipEntry *GetNextEntry();
wxString WXZIPFIX GetComment();
int WXZIPFIX GetTotalEntries();
virtual wxFileOffset GetLength() const { return m_entry.GetSize(); }
protected:
size_t WXZIPFIX OnSysRead(void *buffer, size_t size);
wxFileOffset OnSysTell() const { return m_decomp ? m_decomp->TellI() : 0; }
#if 1 //WXWIN_COMPATIBILITY_2_6
wxFileOffset WXZIPFIX OnSysSeek(wxFileOffset seek, wxSeekMode mode);
#endif
// this protected interface isn't yet finalised
virtual wxInputStream* WXZIPFIX OpenDecompressor(wxInputStream& stream);
virtual bool WXZIPFIX CloseDecompressor(wxInputStream *decomp);
private:
void Init();
void Init(const wxString& file);
wxInputStream& OpenFile(const wxString& archive);
wxArchiveEntry *DoGetNextEntry() { return GetNextEntry(); }
bool WXZIPFIX OpenEntry(wxArchiveEntry& entry);
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);
#if 1 //WXWIN_COMPATIBILITY_2_6
bool m_allowSeeking;
friend class wxZipFSInputStream;
#endif
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
/////////////////////////////////////////////////////////////////////////////
// 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
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__