PageRenderTime 57ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/Externals/wxWidgets3/src/common/fs_arc.cpp

https://gitlab.com/Hexexpeck/dolphin-emulator
C++ | 523 lines | 388 code | 100 blank | 35 comment | 65 complexity | 5ba2a60a07d3f460cebb521d3e4645ff MD5 | raw file
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: src/common/fs_arc.cpp
  3. // Purpose: wxArchive file system
  4. // Author: Vaclav Slavik, Mike Wetherell
  5. // Copyright: (c) 1999 Vaclav Slavik, (c) 2006 Mike Wetherell
  6. // Licence: wxWindows licence
  7. /////////////////////////////////////////////////////////////////////////////
  8. #include "wx/wxprec.h"
  9. #ifdef __BORLANDC__
  10. #pragma hdrstop
  11. #endif
  12. #if wxUSE_FS_ARCHIVE
  13. #include "wx/fs_arc.h"
  14. #ifndef WX_PRECOMP
  15. #include "wx/intl.h"
  16. #include "wx/log.h"
  17. #endif
  18. #include "wx/archive.h"
  19. #include "wx/private/fileback.h"
  20. //---------------------------------------------------------------------------
  21. // wxArchiveFSCacheDataImpl
  22. //
  23. // Holds the catalog of an archive file, and if it is being read from a
  24. // non-seekable stream, a copy of its backing file.
  25. //
  26. // This class is actually the reference counted implementation for the
  27. // wxArchiveFSCacheData class below. It was done that way to allow sharing
  28. // between instances of wxFileSystem, though that's a feature not used in this
  29. // version.
  30. //---------------------------------------------------------------------------
  31. WX_DECLARE_STRING_HASH_MAP(wxArchiveEntry*, wxArchiveFSEntryHash);
  32. struct wxArchiveFSEntry
  33. {
  34. wxArchiveEntry *entry;
  35. wxArchiveFSEntry *next;
  36. };
  37. class wxArchiveFSCacheDataImpl
  38. {
  39. public:
  40. wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory,
  41. const wxBackingFile& backer);
  42. wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory,
  43. wxInputStream *stream);
  44. ~wxArchiveFSCacheDataImpl();
  45. void Release() { if (--m_refcount == 0) delete this; }
  46. wxArchiveFSCacheDataImpl *AddRef() { m_refcount++; return this; }
  47. wxArchiveEntry *Get(const wxString& name);
  48. wxInputStream *NewStream() const;
  49. wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse);
  50. private:
  51. wxArchiveFSEntry *AddToCache(wxArchiveEntry *entry);
  52. void CloseStreams();
  53. int m_refcount;
  54. wxArchiveFSEntryHash m_hash;
  55. wxArchiveFSEntry *m_begin;
  56. wxArchiveFSEntry **m_endptr;
  57. wxBackingFile m_backer;
  58. wxInputStream *m_stream;
  59. wxArchiveInputStream *m_archive;
  60. };
  61. wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl(
  62. const wxArchiveClassFactory& factory,
  63. const wxBackingFile& backer)
  64. : m_refcount(1),
  65. m_begin(NULL),
  66. m_endptr(&m_begin),
  67. m_backer(backer),
  68. m_stream(new wxBackedInputStream(backer)),
  69. m_archive(factory.NewStream(*m_stream))
  70. {
  71. }
  72. wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl(
  73. const wxArchiveClassFactory& factory,
  74. wxInputStream *stream)
  75. : m_refcount(1),
  76. m_begin(NULL),
  77. m_endptr(&m_begin),
  78. m_stream(stream),
  79. m_archive(factory.NewStream(*m_stream))
  80. {
  81. }
  82. wxArchiveFSCacheDataImpl::~wxArchiveFSCacheDataImpl()
  83. {
  84. WX_CLEAR_HASH_MAP(wxArchiveFSEntryHash, m_hash);
  85. wxArchiveFSEntry *entry = m_begin;
  86. while (entry)
  87. {
  88. wxArchiveFSEntry *next = entry->next;
  89. delete entry;
  90. entry = next;
  91. }
  92. CloseStreams();
  93. }
  94. wxArchiveFSEntry *wxArchiveFSCacheDataImpl::AddToCache(wxArchiveEntry *entry)
  95. {
  96. m_hash[entry->GetName(wxPATH_UNIX)] = entry;
  97. wxArchiveFSEntry *fse = new wxArchiveFSEntry;
  98. *m_endptr = fse;
  99. (*m_endptr)->entry = entry;
  100. (*m_endptr)->next = NULL;
  101. m_endptr = &(*m_endptr)->next;
  102. return fse;
  103. }
  104. void wxArchiveFSCacheDataImpl::CloseStreams()
  105. {
  106. wxDELETE(m_archive);
  107. wxDELETE(m_stream);
  108. }
  109. wxArchiveEntry *wxArchiveFSCacheDataImpl::Get(const wxString& name)
  110. {
  111. wxArchiveFSEntryHash::iterator it = m_hash.find(name);
  112. if (it != m_hash.end())
  113. return it->second;
  114. if (!m_archive)
  115. return NULL;
  116. wxArchiveEntry *entry;
  117. while ((entry = m_archive->GetNextEntry()) != NULL)
  118. {
  119. AddToCache(entry);
  120. if (entry->GetName(wxPATH_UNIX) == name)
  121. return entry;
  122. }
  123. CloseStreams();
  124. return NULL;
  125. }
  126. wxInputStream* wxArchiveFSCacheDataImpl::NewStream() const
  127. {
  128. if (m_backer)
  129. return new wxBackedInputStream(m_backer);
  130. else
  131. return NULL;
  132. }
  133. wxArchiveFSEntry *wxArchiveFSCacheDataImpl::GetNext(wxArchiveFSEntry *fse)
  134. {
  135. wxArchiveFSEntry *next = fse ? fse->next : m_begin;
  136. if (!next && m_archive)
  137. {
  138. wxArchiveEntry *entry = m_archive->GetNextEntry();
  139. if (entry)
  140. next = AddToCache(entry);
  141. else
  142. CloseStreams();
  143. }
  144. return next;
  145. }
  146. //---------------------------------------------------------------------------
  147. // wxArchiveFSCacheData
  148. //
  149. // This is the inteface for wxArchiveFSCacheDataImpl above. Holds the catalog
  150. // of an archive file, and if it is being read from a non-seekable stream, a
  151. // copy of its backing file.
  152. //---------------------------------------------------------------------------
  153. class wxArchiveFSCacheData
  154. {
  155. public:
  156. wxArchiveFSCacheData() : m_impl(NULL) { }
  157. wxArchiveFSCacheData(const wxArchiveClassFactory& factory,
  158. const wxBackingFile& backer);
  159. wxArchiveFSCacheData(const wxArchiveClassFactory& factory,
  160. wxInputStream *stream);
  161. wxArchiveFSCacheData(const wxArchiveFSCacheData& data);
  162. wxArchiveFSCacheData& operator=(const wxArchiveFSCacheData& data);
  163. ~wxArchiveFSCacheData() { if (m_impl) m_impl->Release(); }
  164. wxArchiveEntry *Get(const wxString& name) { return m_impl->Get(name); }
  165. wxInputStream *NewStream() const { return m_impl->NewStream(); }
  166. wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse)
  167. { return m_impl->GetNext(fse); }
  168. private:
  169. wxArchiveFSCacheDataImpl *m_impl;
  170. };
  171. wxArchiveFSCacheData::wxArchiveFSCacheData(
  172. const wxArchiveClassFactory& factory,
  173. const wxBackingFile& backer)
  174. : m_impl(new wxArchiveFSCacheDataImpl(factory, backer))
  175. {
  176. }
  177. wxArchiveFSCacheData::wxArchiveFSCacheData(
  178. const wxArchiveClassFactory& factory,
  179. wxInputStream *stream)
  180. : m_impl(new wxArchiveFSCacheDataImpl(factory, stream))
  181. {
  182. }
  183. wxArchiveFSCacheData::wxArchiveFSCacheData(const wxArchiveFSCacheData& data)
  184. : m_impl(data.m_impl ? data.m_impl->AddRef() : NULL)
  185. {
  186. }
  187. wxArchiveFSCacheData& wxArchiveFSCacheData::operator=(
  188. const wxArchiveFSCacheData& data)
  189. {
  190. if (data.m_impl != m_impl)
  191. {
  192. if (m_impl)
  193. m_impl->Release();
  194. m_impl = data.m_impl;
  195. if (m_impl)
  196. m_impl->AddRef();
  197. }
  198. return *this;
  199. }
  200. //---------------------------------------------------------------------------
  201. // wxArchiveFSCache
  202. //
  203. // wxArchiveFSCacheData caches a single archive, and this class holds a
  204. // collection of them to cache all the archives accessed by this instance
  205. // of wxFileSystem.
  206. //---------------------------------------------------------------------------
  207. WX_DECLARE_STRING_HASH_MAP(wxArchiveFSCacheData, wxArchiveFSCacheDataHash);
  208. class wxArchiveFSCache
  209. {
  210. public:
  211. wxArchiveFSCache() { }
  212. ~wxArchiveFSCache() { }
  213. wxArchiveFSCacheData* Add(const wxString& name,
  214. const wxArchiveClassFactory& factory,
  215. wxInputStream *stream);
  216. wxArchiveFSCacheData *Get(const wxString& name);
  217. private:
  218. wxArchiveFSCacheDataHash m_hash;
  219. };
  220. wxArchiveFSCacheData* wxArchiveFSCache::Add(
  221. const wxString& name,
  222. const wxArchiveClassFactory& factory,
  223. wxInputStream *stream)
  224. {
  225. wxArchiveFSCacheData& data = m_hash[name];
  226. if (stream->IsSeekable())
  227. data = wxArchiveFSCacheData(factory, stream);
  228. else
  229. data = wxArchiveFSCacheData(factory, wxBackingFile(stream));
  230. return &data;
  231. }
  232. wxArchiveFSCacheData *wxArchiveFSCache::Get(const wxString& name)
  233. {
  234. wxArchiveFSCacheDataHash::iterator it;
  235. if ((it = m_hash.find(name)) != m_hash.end())
  236. return &it->second;
  237. return NULL;
  238. }
  239. //----------------------------------------------------------------------------
  240. // wxArchiveFSHandler
  241. //----------------------------------------------------------------------------
  242. wxIMPLEMENT_DYNAMIC_CLASS(wxArchiveFSHandler, wxFileSystemHandler);
  243. wxArchiveFSHandler::wxArchiveFSHandler()
  244. : wxFileSystemHandler()
  245. {
  246. m_Archive = NULL;
  247. m_FindEntry = NULL;
  248. m_ZipFile = m_Pattern = m_BaseDir = wxEmptyString;
  249. m_AllowDirs = m_AllowFiles = true;
  250. m_DirsFound = NULL;
  251. m_cache = NULL;
  252. }
  253. wxArchiveFSHandler::~wxArchiveFSHandler()
  254. {
  255. Cleanup();
  256. delete m_cache;
  257. }
  258. void wxArchiveFSHandler::Cleanup()
  259. {
  260. wxDELETE(m_DirsFound);
  261. }
  262. bool wxArchiveFSHandler::CanOpen(const wxString& location)
  263. {
  264. wxString p = GetProtocol(location);
  265. return wxArchiveClassFactory::Find(p) != NULL;
  266. }
  267. wxFSFile* wxArchiveFSHandler::OpenFile(
  268. wxFileSystem& WXUNUSED(fs),
  269. const wxString& location)
  270. {
  271. wxString right = GetRightLocation(location);
  272. wxString left = GetLeftLocation(location);
  273. wxString protocol = GetProtocol(location);
  274. wxString key = left + wxT("#") + protocol + wxT(":");
  275. if (right.Contains(wxT("./")))
  276. {
  277. if (right.GetChar(0) != wxT('/')) right = wxT('/') + right;
  278. wxFileName rightPart(right, wxPATH_UNIX);
  279. rightPart.Normalize(wxPATH_NORM_DOTS, wxT("/"), wxPATH_UNIX);
  280. right = rightPart.GetFullPath(wxPATH_UNIX);
  281. }
  282. if (!right.empty() && right.GetChar(0) == wxT('/')) right = right.Mid(1);
  283. if (!m_cache)
  284. m_cache = new wxArchiveFSCache;
  285. const wxArchiveClassFactory *factory;
  286. factory = wxArchiveClassFactory::Find(protocol);
  287. if (!factory)
  288. return NULL;
  289. wxArchiveFSCacheData *cached = m_cache->Get(key);
  290. if (!cached)
  291. {
  292. wxFSFile *leftFile = m_fs.OpenFile(left);
  293. if (!leftFile)
  294. return NULL;
  295. cached = m_cache->Add(key, *factory, leftFile->DetachStream());
  296. delete leftFile;
  297. }
  298. wxArchiveEntry *entry = cached->Get(right);
  299. if (!entry)
  300. return NULL;
  301. wxInputStream *leftStream = cached->NewStream();
  302. if (!leftStream)
  303. {
  304. wxFSFile *leftFile = m_fs.OpenFile(left);
  305. if (!leftFile)
  306. return NULL;
  307. leftStream = leftFile->DetachStream();
  308. delete leftFile;
  309. }
  310. wxArchiveInputStream *s = factory->NewStream(leftStream);
  311. if ( !s )
  312. return NULL;
  313. s->OpenEntry(*entry);
  314. if (!s->IsOk())
  315. {
  316. delete s;
  317. return NULL;
  318. }
  319. return new wxFSFile(s,
  320. key + right,
  321. wxEmptyString,
  322. GetAnchor(location)
  323. #if wxUSE_DATETIME
  324. , entry->GetDateTime()
  325. #endif // wxUSE_DATETIME
  326. );
  327. }
  328. wxString wxArchiveFSHandler::FindFirst(const wxString& spec, int flags)
  329. {
  330. wxString right = GetRightLocation(spec);
  331. wxString left = GetLeftLocation(spec);
  332. wxString protocol = GetProtocol(spec);
  333. wxString key = left + wxT("#") + protocol + wxT(":");
  334. if (!right.empty() && right.Last() == wxT('/')) right.RemoveLast();
  335. if (!m_cache)
  336. m_cache = new wxArchiveFSCache;
  337. const wxArchiveClassFactory *factory;
  338. factory = wxArchiveClassFactory::Find(protocol);
  339. if (!factory)
  340. return wxEmptyString;
  341. m_Archive = m_cache->Get(key);
  342. if (!m_Archive)
  343. {
  344. wxFSFile *leftFile = m_fs.OpenFile(left);
  345. if (!leftFile)
  346. return wxEmptyString;
  347. m_Archive = m_cache->Add(key, *factory, leftFile->DetachStream());
  348. delete leftFile;
  349. }
  350. m_FindEntry = NULL;
  351. switch (flags)
  352. {
  353. case wxFILE:
  354. m_AllowDirs = false, m_AllowFiles = true; break;
  355. case wxDIR:
  356. m_AllowDirs = true, m_AllowFiles = false; break;
  357. default:
  358. m_AllowDirs = m_AllowFiles = true; break;
  359. }
  360. m_ZipFile = key;
  361. m_Pattern = right.AfterLast(wxT('/'));
  362. m_BaseDir = right.BeforeLast(wxT('/'));
  363. if (m_BaseDir.StartsWith(wxT("/")))
  364. m_BaseDir = m_BaseDir.Mid(1);
  365. if (m_Archive)
  366. {
  367. if (m_AllowDirs)
  368. {
  369. delete m_DirsFound;
  370. m_DirsFound = new wxArchiveFilenameHashMap();
  371. if (right.empty()) // allow "/" to match the archive root
  372. return spec;
  373. }
  374. return DoFind();
  375. }
  376. return wxEmptyString;
  377. }
  378. wxString wxArchiveFSHandler::FindNext()
  379. {
  380. if (!m_Archive) return wxEmptyString;
  381. return DoFind();
  382. }
  383. wxString wxArchiveFSHandler::DoFind()
  384. {
  385. wxString namestr, dir, filename;
  386. wxString match = wxEmptyString;
  387. while (match == wxEmptyString)
  388. {
  389. m_FindEntry = m_Archive->GetNext(m_FindEntry);
  390. if (!m_FindEntry)
  391. {
  392. m_Archive = NULL;
  393. m_FindEntry = NULL;
  394. break;
  395. }
  396. namestr = m_FindEntry->entry->GetName(wxPATH_UNIX);
  397. if (m_AllowDirs)
  398. {
  399. dir = namestr.BeforeLast(wxT('/'));
  400. while (!dir.empty())
  401. {
  402. if( m_DirsFound->find(dir) == m_DirsFound->end() )
  403. {
  404. (*m_DirsFound)[dir] = 1;
  405. filename = dir.AfterLast(wxT('/'));
  406. dir = dir.BeforeLast(wxT('/'));
  407. if (!filename.empty() && m_BaseDir == dir &&
  408. wxMatchWild(m_Pattern, filename, false))
  409. match = m_ZipFile + dir + wxT("/") + filename;
  410. }
  411. else
  412. break; // already tranversed
  413. }
  414. }
  415. filename = namestr.AfterLast(wxT('/'));
  416. dir = namestr.BeforeLast(wxT('/'));
  417. if (m_AllowFiles && !filename.empty() && m_BaseDir == dir &&
  418. wxMatchWild(m_Pattern, filename, false))
  419. match = m_ZipFile + namestr;
  420. }
  421. return match;
  422. }
  423. #endif // wxUSE_FS_ARCHIVE