openMSX
CompressedFileAdapter.cc
Go to the documentation of this file.
2 #include "FileException.hh"
3 #include "hash_set.hh"
4 #include "xxhash.hh"
5 #include <cstring>
6 
7 using std::string;
8 
9 namespace openmsx {
10 
12  template<typename Ptr> const string& operator()(const Ptr& p) const {
13  return p->cachedURL;
14  }
15 };
17  GetURLFromDecompressed, XXHasher> decompressCache;
18 
19 
20 CompressedFileAdapter::CompressedFileAdapter(std::unique_ptr<FileBase> file_)
21  : file(std::move(file_)), pos(0)
22 {
23 }
24 
26 {
27  auto it = decompressCache.find(getURL());
28  decompressed.reset();
29  if (it != end(decompressCache) && it->unique()) {
30  // delete last user of Decompressed, remove from cache
31  decompressCache.erase(it);
32  }
33 }
34 
35 void CompressedFileAdapter::decompress()
36 {
37  if (decompressed) return;
38 
39  string url = getURL();
40  auto it = decompressCache.find(url);
41  if (it != end(decompressCache)) {
42  decompressed = *it;
43  } else {
44  decompressed = std::make_shared<Decompressed>();
45  decompress(*file, *decompressed);
46  decompressed->cachedModificationDate = getModificationDate();
47  decompressed->cachedURL = std::move(url);
48  decompressCache.insert_noDuplicateCheck(decompressed);
49  }
50 
51  // close original file after succesful decompress
52  file.reset();
53 }
54 
55 void CompressedFileAdapter::read(void* buffer, size_t num)
56 {
57  decompress();
58  if (decompressed->size < (pos + num)) {
59  throw FileException("Read beyond end of file");
60  }
61  const auto& buf = decompressed->buf;
62  memcpy(buffer, buf.data() + pos, num);
63  pos += num;
64 }
65 
66 void CompressedFileAdapter::write(const void* /*buffer*/, size_t /*num*/)
67 {
68  throw FileException("Writing to compressed files not yet supported");
69 }
70 
72 {
73  decompress();
74  return { decompressed->buf.data(), decompressed->size };
75 }
76 
78 {
79  // nothing
80 }
81 
83 {
84  decompress();
85  return decompressed->size;
86 }
87 
88 void CompressedFileAdapter::seek(size_t newpos)
89 {
90  pos = newpos;
91 }
92 
94 {
95  return pos;
96 }
97 
98 void CompressedFileAdapter::truncate(size_t /*size*/)
99 {
100  throw FileException("Truncating compressed files not yet supported.");
101 }
102 
104 {
105  // nothing because writing is not supported
106 }
107 
109 {
110  return file ? file->getURL() : decompressed->cachedURL;
111 }
112 
114 {
115  decompress();
116  return decompressed->originalName;
117 }
118 
120 {
121  return true;
122 }
123 
125 {
126  return file ? file->getModificationDate()
127  : decompressed->cachedModificationDate;
128 }
129 
130 } // namespace openmsx
span< uint8_t > mmap() final override
bool erase(const K &key)
Definition: hash_set.hh:479
std::string getURL() const final override
Definition: span.hh:34
std::string getOriginalName() final override
void read(void *buffer, size_t num) final override
STL namespace.
virtual void decompress(FileBase &file, Decompressed &decompressed)=0
const string & operator()(const Ptr &p) const
void write(const void *buffer, size_t num) final override
iterator insert_noDuplicateCheck(V &&value)
Definition: hash_set.hh:447
CompressedFileAdapter(std::unique_ptr< FileBase > file)
void seek(size_t pos) final override
Thanks to enen for testing this on a real cartridge:
Definition: Autofire.cc:5
void truncate(size_t size) final override
time_t getModificationDate() final override
iterator find(const K &key)
Definition: hash_set.hh:546
bool isReadOnly() const final override