+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()
+{
+ delete m_archive;
+ m_archive = NULL;
+ delete m_stream;
+ m_stream = NULL;
+}
+
+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;
+}
+