/Externals/wxWidgets3/src/common/fs_arc.cpp
C++ | 523 lines | 388 code | 100 blank | 35 comment | 65 complexity | 5ba2a60a07d3f460cebb521d3e4645ff MD5 | raw file
- /////////////////////////////////////////////////////////////////////////////
- // Name: src/common/fs_arc.cpp
- // Purpose: wxArchive file system
- // Author: Vaclav Slavik, Mike Wetherell
- // Copyright: (c) 1999 Vaclav Slavik, (c) 2006 Mike Wetherell
- // Licence: wxWindows licence
- /////////////////////////////////////////////////////////////////////////////
- #include "wx/wxprec.h"
- #ifdef __BORLANDC__
- #pragma hdrstop
- #endif
- #if wxUSE_FS_ARCHIVE
- #include "wx/fs_arc.h"
- #ifndef WX_PRECOMP
- #include "wx/intl.h"
- #include "wx/log.h"
- #endif
- #include "wx/archive.h"
- #include "wx/private/fileback.h"
- //---------------------------------------------------------------------------
- // wxArchiveFSCacheDataImpl
- //
- // Holds the catalog of an archive file, and if it is being read from a
- // non-seekable stream, a copy of its backing file.
- //
- // This class is actually the reference counted implementation for the
- // wxArchiveFSCacheData class below. It was done that way to allow sharing
- // between instances of wxFileSystem, though that's a feature not used in this
- // version.
- //---------------------------------------------------------------------------
- WX_DECLARE_STRING_HASH_MAP(wxArchiveEntry*, wxArchiveFSEntryHash);
- struct wxArchiveFSEntry
- {
- wxArchiveEntry *entry;
- wxArchiveFSEntry *next;
- };
- class wxArchiveFSCacheDataImpl
- {
- public:
- wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory,
- const wxBackingFile& backer);
- wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory,
- wxInputStream *stream);
- ~wxArchiveFSCacheDataImpl();
- void Release() { if (--m_refcount == 0) delete this; }
- wxArchiveFSCacheDataImpl *AddRef() { m_refcount++; return this; }
- wxArchiveEntry *Get(const wxString& name);
- wxInputStream *NewStream() const;
- wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse);
- private:
- wxArchiveFSEntry *AddToCache(wxArchiveEntry *entry);
- void CloseStreams();
- int m_refcount;
- wxArchiveFSEntryHash m_hash;
- wxArchiveFSEntry *m_begin;
- wxArchiveFSEntry **m_endptr;
- wxBackingFile m_backer;
- wxInputStream *m_stream;
- wxArchiveInputStream *m_archive;
- };
- wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl(
- const wxArchiveClassFactory& factory,
- const wxBackingFile& backer)
- : m_refcount(1),
- m_begin(NULL),
- m_endptr(&m_begin),
- m_backer(backer),
- m_stream(new wxBackedInputStream(backer)),
- m_archive(factory.NewStream(*m_stream))
- {
- }
- wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl(
- const wxArchiveClassFactory& factory,
- wxInputStream *stream)
- : m_refcount(1),
- m_begin(NULL),
- m_endptr(&m_begin),
- m_stream(stream),
- m_archive(factory.NewStream(*m_stream))
- {
- }
- wxArchiveFSCacheDataImpl::~wxArchiveFSCacheDataImpl()
- {
- WX_CLEAR_HASH_MAP(wxArchiveFSEntryHash, m_hash);
- wxArchiveFSEntry *entry = m_begin;
- while (entry)
- {
- wxArchiveFSEntry *next = entry->next;
- delete entry;
- entry = next;
- }
- CloseStreams();
- }
- wxArchiveFSEntry *wxArchiveFSCacheDataImpl::AddToCache(wxArchiveEntry *entry)
- {
- m_hash[entry->GetName(wxPATH_UNIX)] = entry;
- wxArchiveFSEntry *fse = new wxArchiveFSEntry;
- *m_endptr = fse;
- (*m_endptr)->entry = entry;
- (*m_endptr)->next = NULL;
- m_endptr = &(*m_endptr)->next;
- return fse;
- }
- void wxArchiveFSCacheDataImpl::CloseStreams()
- {
- wxDELETE(m_archive);
- wxDELETE(m_stream);
- }
- wxArchiveEntry *wxArchiveFSCacheDataImpl::Get(const wxString& name)
- {
- wxArchiveFSEntryHash::iterator it = m_hash.find(name);
- if (it != m_hash.end())
- return it->second;
- if (!m_archive)
- return NULL;
- wxArchiveEntry *entry;
- while ((entry = m_archive->GetNextEntry()) != NULL)
- {
- AddToCache(entry);
- if (entry->GetName(wxPATH_UNIX) == name)
- return entry;
- }
- CloseStreams();
- return NULL;
- }
- wxInputStream* wxArchiveFSCacheDataImpl::NewStream() const
- {
- if (m_backer)
- return new wxBackedInputStream(m_backer);
- else
- return NULL;
- }
- wxArchiveFSEntry *wxArchiveFSCacheDataImpl::GetNext(wxArchiveFSEntry *fse)
- {
- wxArchiveFSEntry *next = fse ? fse->next : m_begin;
- if (!next && m_archive)
- {
- wxArchiveEntry *entry = m_archive->GetNextEntry();
- if (entry)
- next = AddToCache(entry);
- else
- CloseStreams();
- }
- return next;
- }
- //---------------------------------------------------------------------------
- // wxArchiveFSCacheData
- //
- // This is the inteface for wxArchiveFSCacheDataImpl above. Holds the catalog
- // of an archive file, and if it is being read from a non-seekable stream, a
- // copy of its backing file.
- //---------------------------------------------------------------------------
- class wxArchiveFSCacheData
- {
- public:
- wxArchiveFSCacheData() : m_impl(NULL) { }
- wxArchiveFSCacheData(const wxArchiveClassFactory& factory,
- const wxBackingFile& backer);
- wxArchiveFSCacheData(const wxArchiveClassFactory& factory,
- wxInputStream *stream);
- wxArchiveFSCacheData(const wxArchiveFSCacheData& data);
- wxArchiveFSCacheData& operator=(const wxArchiveFSCacheData& data);
- ~wxArchiveFSCacheData() { if (m_impl) m_impl->Release(); }
- wxArchiveEntry *Get(const wxString& name) { return m_impl->Get(name); }
- wxInputStream *NewStream() const { return m_impl->NewStream(); }
- wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse)
- { return m_impl->GetNext(fse); }
- private:
- wxArchiveFSCacheDataImpl *m_impl;
- };
- wxArchiveFSCacheData::wxArchiveFSCacheData(
- const wxArchiveClassFactory& factory,
- const wxBackingFile& backer)
- : m_impl(new wxArchiveFSCacheDataImpl(factory, backer))
- {
- }
- wxArchiveFSCacheData::wxArchiveFSCacheData(
- const wxArchiveClassFactory& factory,
- wxInputStream *stream)
- : m_impl(new wxArchiveFSCacheDataImpl(factory, stream))
- {
- }
- wxArchiveFSCacheData::wxArchiveFSCacheData(const wxArchiveFSCacheData& data)
- : m_impl(data.m_impl ? data.m_impl->AddRef() : NULL)
- {
- }
- wxArchiveFSCacheData& wxArchiveFSCacheData::operator=(
- const wxArchiveFSCacheData& data)
- {
- if (data.m_impl != m_impl)
- {
- if (m_impl)
- m_impl->Release();
- m_impl = data.m_impl;
- if (m_impl)
- m_impl->AddRef();
- }
- return *this;
- }
- //---------------------------------------------------------------------------
- // wxArchiveFSCache
- //
- // wxArchiveFSCacheData caches a single archive, and this class holds a
- // collection of them to cache all the archives accessed by this instance
- // of wxFileSystem.
- //---------------------------------------------------------------------------
- WX_DECLARE_STRING_HASH_MAP(wxArchiveFSCacheData, wxArchiveFSCacheDataHash);
- class wxArchiveFSCache
- {
- public:
- wxArchiveFSCache() { }
- ~wxArchiveFSCache() { }
- wxArchiveFSCacheData* Add(const wxString& name,
- const wxArchiveClassFactory& factory,
- wxInputStream *stream);
- wxArchiveFSCacheData *Get(const wxString& name);
- private:
- wxArchiveFSCacheDataHash m_hash;
- };
- wxArchiveFSCacheData* wxArchiveFSCache::Add(
- const wxString& name,
- const wxArchiveClassFactory& factory,
- wxInputStream *stream)
- {
- wxArchiveFSCacheData& data = m_hash[name];
- if (stream->IsSeekable())
- data = wxArchiveFSCacheData(factory, stream);
- else
- data = wxArchiveFSCacheData(factory, wxBackingFile(stream));
- return &data;
- }
- wxArchiveFSCacheData *wxArchiveFSCache::Get(const wxString& name)
- {
- wxArchiveFSCacheDataHash::iterator it;
- if ((it = m_hash.find(name)) != m_hash.end())
- return &it->second;
- return NULL;
- }
- //----------------------------------------------------------------------------
- // wxArchiveFSHandler
- //----------------------------------------------------------------------------
- wxIMPLEMENT_DYNAMIC_CLASS(wxArchiveFSHandler, wxFileSystemHandler);
- wxArchiveFSHandler::wxArchiveFSHandler()
- : wxFileSystemHandler()
- {
- m_Archive = NULL;
- m_FindEntry = NULL;
- m_ZipFile = m_Pattern = m_BaseDir = wxEmptyString;
- m_AllowDirs = m_AllowFiles = true;
- m_DirsFound = NULL;
- m_cache = NULL;
- }
- wxArchiveFSHandler::~wxArchiveFSHandler()
- {
- Cleanup();
- delete m_cache;
- }
- void wxArchiveFSHandler::Cleanup()
- {
- wxDELETE(m_DirsFound);
- }
- bool wxArchiveFSHandler::CanOpen(const wxString& location)
- {
- wxString p = GetProtocol(location);
- return wxArchiveClassFactory::Find(p) != NULL;
- }
- wxFSFile* wxArchiveFSHandler::OpenFile(
- wxFileSystem& WXUNUSED(fs),
- const wxString& location)
- {
- wxString right = GetRightLocation(location);
- wxString left = GetLeftLocation(location);
- wxString protocol = GetProtocol(location);
- wxString key = left + wxT("#") + protocol + wxT(":");
- 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.empty() && right.GetChar(0) == wxT('/')) right = right.Mid(1);
- if (!m_cache)
- m_cache = new wxArchiveFSCache;
- const wxArchiveClassFactory *factory;
- factory = wxArchiveClassFactory::Find(protocol);
- if (!factory)
- return NULL;
- wxArchiveFSCacheData *cached = m_cache->Get(key);
- if (!cached)
- {
- wxFSFile *leftFile = m_fs.OpenFile(left);
- if (!leftFile)
- return NULL;
- cached = m_cache->Add(key, *factory, leftFile->DetachStream());
- delete leftFile;
- }
- wxArchiveEntry *entry = cached->Get(right);
- if (!entry)
- return NULL;
- wxInputStream *leftStream = cached->NewStream();
- if (!leftStream)
- {
- wxFSFile *leftFile = m_fs.OpenFile(left);
- if (!leftFile)
- return NULL;
- leftStream = leftFile->DetachStream();
- delete leftFile;
- }
- wxArchiveInputStream *s = factory->NewStream(leftStream);
- if ( !s )
- return NULL;
- s->OpenEntry(*entry);
- if (!s->IsOk())
- {
- delete s;
- return NULL;
- }
- return new wxFSFile(s,
- key + right,
- wxEmptyString,
- GetAnchor(location)
- #if wxUSE_DATETIME
- , entry->GetDateTime()
- #endif // wxUSE_DATETIME
- );
- }
- wxString wxArchiveFSHandler::FindFirst(const wxString& spec, int flags)
- {
- wxString right = GetRightLocation(spec);
- wxString left = GetLeftLocation(spec);
- wxString protocol = GetProtocol(spec);
- wxString key = left + wxT("#") + protocol + wxT(":");
- if (!right.empty() && right.Last() == wxT('/')) right.RemoveLast();
- if (!m_cache)
- m_cache = new wxArchiveFSCache;
- const wxArchiveClassFactory *factory;
- factory = wxArchiveClassFactory::Find(protocol);
- if (!factory)
- return wxEmptyString;
- m_Archive = m_cache->Get(key);
- if (!m_Archive)
- {
- wxFSFile *leftFile = m_fs.OpenFile(left);
- if (!leftFile)
- return wxEmptyString;
- m_Archive = m_cache->Add(key, *factory, leftFile->DetachStream());
- delete leftFile;
- }
- m_FindEntry = 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 = key;
- 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 wxArchiveFilenameHashMap();
- if (right.empty()) // allow "/" to match the archive root
- return spec;
- }
- return DoFind();
- }
- return wxEmptyString;
- }
- wxString wxArchiveFSHandler::FindNext()
- {
- if (!m_Archive) return wxEmptyString;
- return DoFind();
- }
- wxString wxArchiveFSHandler::DoFind()
- {
- wxString namestr, dir, filename;
- wxString match = wxEmptyString;
- while (match == wxEmptyString)
- {
- m_FindEntry = m_Archive->GetNext(m_FindEntry);
- if (!m_FindEntry)
- {
- m_Archive = NULL;
- m_FindEntry = NULL;
- break;
- }
- namestr = m_FindEntry->entry->GetName(wxPATH_UNIX);
- 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 + 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 + namestr;
- }
- return match;
- }
- #endif // wxUSE_FS_ARCHIVE