From: Michael Wetherell Date: Fri, 27 Oct 2006 12:16:30 +0000 (+0000) Subject: Base wxArchiveFSHandler on wxZipFSHandler. X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/be38a31d378be07b10c97786074e8f813ddf6fcb Base wxArchiveFSHandler on wxZipFSHandler. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@42517 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/fs_arc.h b/include/wx/fs_arc.h new file mode 100644 index 0000000000..e98b3f82ad --- /dev/null +++ b/include/wx/fs_arc.h @@ -0,0 +1,56 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: fs_zip.h +// Purpose: ZIP file system +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// CVS-ID: $Id$ +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_FS_ZIP_H_ +#define _WX_FS_ZIP_H_ + +#include "wx/defs.h" + +#if wxUSE_FILESYSTEM && wxUSE_FS_ZIP && wxUSE_STREAMS + +#include "wx/filesys.h" +#include "wx/hashmap.h" + + +WX_DECLARE_STRING_HASH_MAP(int, wxZipFilenameHashMap); + + +//--------------------------------------------------------------------------- +// wxZipFSHandler +//--------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxZipFSHandler : public wxFileSystemHandler +{ + public: + wxZipFSHandler(); + virtual bool CanOpen(const wxString& location); + virtual wxFSFile* OpenFile(wxFileSystem& fs, const wxString& location); + virtual wxString FindFirst(const wxString& spec, int flags = 0); + virtual wxString FindNext(); + void Cleanup(); + virtual ~wxZipFSHandler(); + + private: + // these vars are used by FindFirst/Next: + class wxZipInputStream *m_Archive; + wxString m_Pattern, m_BaseDir, m_ZipFile; + bool m_AllowDirs, m_AllowFiles; + wxZipFilenameHashMap *m_DirsFound; + + wxString DoFind(); + + DECLARE_NO_COPY_CLASS(wxZipFSHandler) +}; + + +#endif + // wxUSE_FILESYSTEM && wxUSE_FS_ZIP && wxUSE_STREAMS + +#endif // _WX_FS_ZIP_H_ + diff --git a/src/common/fs_arc.cpp b/src/common/fs_arc.cpp new file mode 100644 index 0000000000..f96f1b8ee3 --- /dev/null +++ b/src/common/fs_arc.cpp @@ -0,0 +1,256 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: fs_zip.cpp +// Purpose: ZIP file system +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// CVS-ID: $Id$ +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#if wxUSE_FILESYSTEM && wxUSE_FS_ZIP && wxUSE_ZIPSTREAM && wxUSE_ZLIB + +#ifndef WXPRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#include "wx/filesys.h" +#include "wx/wfstream.h" +#include "wx/zipstrm.h" +#include "wx/fs_zip.h" + + +//--------------------------------------------------------------------------- +// wxZipFSInputStream +//--------------------------------------------------------------------------- +// Helper class for wxZipFSHandler + +class wxZipFSInputStream : public wxZipInputStream +{ + public: + wxZipFSInputStream(wxFSFile *file) + : wxZipInputStream(*file->GetStream()) + { + m_file = file; +#if WXWIN_COMPATIBILITY_2_6 + m_allowSeeking = true; +#endif + } + + virtual ~wxZipFSInputStream() { delete m_file; } + + private: + wxFSFile *m_file; +}; + +//---------------------------------------------------------------------------- +// wxZipFSHandler +//---------------------------------------------------------------------------- + +wxZipFSHandler::wxZipFSHandler() : wxFileSystemHandler() +{ + m_Archive = NULL; + m_ZipFile = m_Pattern = m_BaseDir = wxEmptyString; + m_AllowDirs = m_AllowFiles = true; + m_DirsFound = NULL; +} + + + +wxZipFSHandler::~wxZipFSHandler() +{ + Cleanup(); +} + + +void wxZipFSHandler::Cleanup() +{ + wxDELETE(m_Archive); + wxDELETE(m_DirsFound); +} + + + +bool wxZipFSHandler::CanOpen(const wxString& location) +{ + wxString p = GetProtocol(location); + return (p == wxT("zip")); +} + + +wxFSFile* wxZipFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location) +{ + wxString right = GetRightLocation(location); + wxString left = GetLeftLocation(location); + wxZipInputStream *s; + + if (right.Contains(wxT("./"))) + { + if (right.GetChar(0) != wxT('/')) right = wxT('/') + right; + wxFileName rightPart(right, wxPATH_UNIX); + rightPart.Normalize(wxPATH_NORM_DOTS, wxT("/"), wxPATH_UNIX); + right = rightPart.GetFullPath(wxPATH_UNIX); + } + + if (right.GetChar(0) == wxT('/')) right = right.Mid(1); + + // a new wxFileSystem object is needed here to avoid infinite recursion + wxFSFile *leftFile = wxFileSystem().OpenFile(left); + if (!leftFile) + return NULL; + + s = new wxZipFSInputStream(leftFile); + if (s && s->IsOk()) + { +#if wxUSE_DATETIME + wxDateTime dtMod; +#endif // wxUSE_DATETIME + + bool found = false; + while (!found) + { + wxZipEntry *ent = s->GetNextEntry(); + if (!ent) + break; + + if (ent->GetInternalName() == right) + { + found = true; + dtMod = ent->GetDateTime(); + } + + delete ent; + } + if (found) + { + return new wxFSFile(s, + left + wxT("#zip:") + right, + GetMimeTypeFromExt(location), + GetAnchor(location) +#if wxUSE_DATETIME + , dtMod +#endif // wxUSE_DATETIME + ); + } + } + + delete s; + return NULL; +} + + + +wxString wxZipFSHandler::FindFirst(const wxString& spec, int flags) +{ + wxString right = GetRightLocation(spec); + wxString left = GetLeftLocation(spec); + + if (!right.empty() && right.Last() == wxT('/')) right.RemoveLast(); + + if (m_Archive) + { + delete m_Archive; + m_Archive = NULL; + } + + switch (flags) + { + case wxFILE: + m_AllowDirs = false, m_AllowFiles = true; break; + case wxDIR: + m_AllowDirs = true, m_AllowFiles = false; break; + default: + m_AllowDirs = m_AllowFiles = true; break; + } + + m_ZipFile = left; + + wxFSFile *leftFile = wxFileSystem().OpenFile(left); + if (leftFile) + m_Archive = new wxZipFSInputStream(leftFile); + + m_Pattern = right.AfterLast(wxT('/')); + m_BaseDir = right.BeforeLast(wxT('/')); + if (m_BaseDir.StartsWith(wxT("/"))) + m_BaseDir = m_BaseDir.Mid(1); + + if (m_Archive) + { + if (m_AllowDirs) + { + delete m_DirsFound; + m_DirsFound = new wxZipFilenameHashMap(); + if (right.empty()) // allow "/" to match the archive root + return spec; + } + return DoFind(); + } + return wxEmptyString; +} + + + +wxString wxZipFSHandler::FindNext() +{ + if (!m_Archive) return wxEmptyString; + return DoFind(); +} + + + +wxString wxZipFSHandler::DoFind() +{ + wxString namestr, dir, filename; + wxString match = wxEmptyString; + + while (match == wxEmptyString) + { + wxZipEntry *entry = m_Archive->GetNextEntry(); + if (!entry) + { + delete m_Archive; + m_Archive = NULL; + break; + } + namestr = entry->GetName(wxPATH_UNIX); + delete entry; + + if (m_AllowDirs) + { + dir = namestr.BeforeLast(wxT('/')); + while (!dir.empty()) + { + if( m_DirsFound->find(dir) == m_DirsFound->end() ) + { + (*m_DirsFound)[dir] = 1; + filename = dir.AfterLast(wxT('/')); + dir = dir.BeforeLast(wxT('/')); + if (!filename.empty() && m_BaseDir == dir && + wxMatchWild(m_Pattern, filename, false)) + match = m_ZipFile + wxT("#zip:") + dir + wxT("/") + filename; + } + else + break; // already tranversed + } + } + + filename = namestr.AfterLast(wxT('/')); + dir = namestr.BeforeLast(wxT('/')); + if (m_AllowFiles && !filename.empty() && m_BaseDir == dir && + wxMatchWild(m_Pattern, filename, false)) + match = m_ZipFile + wxT("#zip:") + namestr; + } + + return match; +} + + + +#endif + //wxUSE_FILESYSTEM && wxUSE_FS_ZIP && wxUSE_ZIPSTREAM