|
1
|
1 #pragma once
|
|
|
2
|
|
|
3 class NOVTABLE reader_membuffer_base : public file_readonly {
|
|
|
4 public:
|
|
|
5 reader_membuffer_base() : m_offset(0) {}
|
|
|
6
|
|
|
7 t_size read(void * p_buffer, t_size p_bytes, abort_callback & p_abort) override;
|
|
|
8
|
|
|
9 void write(const void * p_buffer, t_size p_bytes, abort_callback & p_abort) override { throw exception_io_denied(); }
|
|
|
10
|
|
|
11 t_filesize get_size(abort_callback & p_abort) override { return get_buffer_size(); }
|
|
|
12 t_filesize get_position(abort_callback & p_abort) override { return m_offset; }
|
|
|
13 void seek(t_filesize position, abort_callback & p_abort) override;
|
|
|
14 void reopen(abort_callback & p_abort) override { seek(0, p_abort); }
|
|
|
15
|
|
|
16 bool can_seek() override { return true; }
|
|
|
17 bool is_in_memory() override { return true; }
|
|
|
18
|
|
|
19 protected:
|
|
|
20 virtual const void * get_buffer() = 0;
|
|
|
21 virtual t_size get_buffer_size() = 0;
|
|
|
22 //virtual t_filetimestamp get_timestamp(abort_callback & p_abort) = 0;
|
|
|
23 bool get_content_type(pfc::string_base &) override { return false; }
|
|
|
24 inline void seek_internal(t_size p_offset) { if (p_offset > get_buffer_size()) throw exception_io_seek_out_of_range(); m_offset = p_offset; }
|
|
|
25 private:
|
|
|
26 t_size m_offset;
|
|
|
27 };
|
|
|
28
|
|
|
29 class reader_membuffer_simple : public reader_membuffer_base {
|
|
|
30 public:
|
|
|
31 reader_membuffer_simple(pfc::mem_block&& block, t_filetimestamp ts = filetimestamp_invalid, bool is_remote = false) : m_data(std::move(block)), m_ts(ts), m_isRemote(is_remote) {}
|
|
|
32 reader_membuffer_simple(const void * ptr, t_size size, t_filetimestamp ts = filetimestamp_invalid, bool is_remote = false) : m_ts(ts), m_isRemote(is_remote) {
|
|
|
33 m_data.resize(size);
|
|
|
34 if ( ptr != nullptr ) memcpy(m_data.get_ptr(), ptr, size);
|
|
|
35 }
|
|
|
36 const void * get_buffer() { return m_data.get_ptr(); }
|
|
|
37 void* _get_write_buffer() { return m_data.get_ptr(); }
|
|
|
38 t_size get_buffer_size() { return m_data.get_size(); }
|
|
|
39 t_filetimestamp get_timestamp(abort_callback & p_abort) { return m_ts; }
|
|
|
40 bool is_remote() { return m_isRemote; }
|
|
|
41
|
|
|
42 private:
|
|
|
43 pfc::mem_block m_data;
|
|
|
44 t_filetimestamp m_ts;
|
|
|
45 bool m_isRemote;
|
|
|
46 };
|
|
|
47
|
|
|
48 class reader_membuffer_mirror : public reader_membuffer_base
|
|
|
49 {
|
|
|
50 public:
|
|
|
51 t_filetimestamp get_timestamp(abort_callback & p_abort) { return m_timestamp; }
|
|
|
52 bool is_remote() { return m_remote; }
|
|
|
53
|
|
|
54 //! Returns false when the object could not be mirrored (too big) or did not need mirroring.
|
|
|
55 static bool g_create(service_ptr_t<file> & p_out, const service_ptr_t<file> & p_src, abort_callback & p_abort) {
|
|
|
56 service_ptr_t<reader_membuffer_mirror> ptr = new service_impl_t<reader_membuffer_mirror>();
|
|
|
57 if (!ptr->init(p_src, p_abort)) return false;
|
|
|
58 p_out = ptr.get_ptr();
|
|
|
59 return true;
|
|
|
60 }
|
|
|
61 bool get_content_type(pfc::string_base & out) {
|
|
|
62 if (m_contentType.is_empty()) return false;
|
|
|
63 out = m_contentType; return true;
|
|
|
64 }
|
|
|
65 private:
|
|
|
66 const void * get_buffer() { return m_buffer.get_ptr(); }
|
|
|
67 t_size get_buffer_size() { return m_buffer.get_size(); }
|
|
|
68
|
|
|
69 bool init(const service_ptr_t<file> & p_src, abort_callback & p_abort) {
|
|
|
70 if (p_src->is_in_memory()) return false;//already buffered
|
|
|
71 if (!p_src->get_content_type(m_contentType)) m_contentType.reset();
|
|
|
72 m_remote = p_src->is_remote();
|
|
|
73
|
|
|
74 t_size size = pfc::downcast_guarded<t_size>(p_src->get_size(p_abort));
|
|
|
75
|
|
|
76 m_buffer.set_size(size);
|
|
|
77
|
|
|
78 p_src->reopen(p_abort);
|
|
|
79
|
|
|
80 p_src->read_object(m_buffer.get_ptr(), size, p_abort);
|
|
|
81
|
|
|
82 m_timestamp = p_src->get_timestamp(p_abort);
|
|
|
83
|
|
|
84 return true;
|
|
|
85 }
|
|
|
86
|
|
|
87
|
|
|
88 t_filetimestamp m_timestamp;
|
|
|
89 pfc::array_t<char> m_buffer;
|
|
|
90 bool m_remote;
|
|
|
91 pfc::string8 m_contentType;
|
|
|
92
|
|
|
93 };
|
|
|
94
|
|
|
95 class reader_limited : public file_readonly_t<file_v2> {
|
|
|
96 service_ptr_t<file> r;
|
|
|
97 t_filesize begin;
|
|
|
98 t_filesize end;
|
|
|
99
|
|
|
100 public:
|
|
|
101 static file::ptr g_create(file::ptr base, t_filesize offset, t_filesize size, abort_callback & abort) {
|
|
|
102 service_ptr_t<reader_limited> r = new service_impl_t<reader_limited>();
|
|
|
103 if (offset + size < offset) throw pfc::exception_overflow();
|
|
|
104 r->init(base, offset, offset + size, abort);
|
|
|
105 return r;
|
|
|
106 }
|
|
|
107 reader_limited() { begin = 0;end = 0; }
|
|
|
108 reader_limited(const service_ptr_t<file> & p_r, t_filesize p_begin, t_filesize p_end, abort_callback & p_abort) {
|
|
|
109 r = p_r;
|
|
|
110 begin = p_begin;
|
|
|
111 end = p_end;
|
|
|
112 reopen(p_abort);
|
|
|
113 }
|
|
|
114
|
|
|
115 void init(const service_ptr_t<file> & p_r, t_filesize p_begin, t_filesize p_end, abort_callback & p_abort) {
|
|
|
116 r = p_r;
|
|
|
117 begin = p_begin;
|
|
|
118 end = p_end;
|
|
|
119 reopen(p_abort);
|
|
|
120 }
|
|
|
121
|
|
|
122 service_ptr get_metadata(abort_callback& a) override {return r->get_metadata_(a);}
|
|
|
123 t_filestats2 get_stats2(uint32_t f, abort_callback& a) override {
|
|
|
124 auto ret = r->get_stats2_(f, a);
|
|
|
125 ret.m_size = this->get_size(a);
|
|
|
126 return ret;
|
|
|
127 }
|
|
|
128 t_filetimestamp get_timestamp(abort_callback & p_abort) override { return r->get_timestamp(p_abort); }
|
|
|
129
|
|
|
130 t_size read(void *p_buffer, t_size p_bytes, abort_callback & p_abort) override {
|
|
|
131 t_filesize pos;
|
|
|
132 pos = r->get_position(p_abort);
|
|
|
133 if (p_bytes > end - pos) p_bytes = (t_size)(end - pos);
|
|
|
134 return r->read(p_buffer, p_bytes, p_abort);
|
|
|
135 }
|
|
|
136
|
|
|
137 t_filesize get_size(abort_callback & p_abort) override { return end - begin; }
|
|
|
138
|
|
|
139 t_filesize get_position(abort_callback & p_abort) override {
|
|
|
140 return r->get_position(p_abort) - begin;
|
|
|
141 }
|
|
|
142
|
|
|
143 void seek(t_filesize position, abort_callback & p_abort) override {
|
|
|
144 if (position > end) throw exception_io_seek_out_of_range();
|
|
|
145 r->seek(position + begin, p_abort);
|
|
|
146 }
|
|
|
147 bool can_seek() override { return r->can_seek(); }
|
|
|
148 bool is_remote() override { return r->is_remote(); }
|
|
|
149
|
|
|
150 bool get_content_type(pfc::string_base & out) override { return r->get_content_type(out); }
|
|
|
151
|
|
|
152 void reopen(abort_callback & p_abort) override {
|
|
|
153 seekInternal(begin, p_abort);
|
|
|
154 }
|
|
|
155 private:
|
|
|
156 void seekInternal(t_filesize position, abort_callback & abort) {
|
|
|
157 if (r->can_seek()) {
|
|
|
158 r->seek(position, abort);
|
|
|
159 } else {
|
|
|
160 t_filesize positionWas = r->get_position(abort);
|
|
|
161 if (positionWas == filesize_invalid || positionWas > position) {
|
|
|
162 r->reopen(abort);
|
|
|
163 try { r->skip_object(position, abort); }
|
|
|
164 catch (exception_io_data const &) { throw exception_io_seek_out_of_range(); }
|
|
|
165 } else {
|
|
|
166 t_filesize skipMe = position - positionWas;
|
|
|
167 if (skipMe > 0) {
|
|
|
168 try { r->skip_object(skipMe, abort); }
|
|
|
169 catch (exception_io_data const &) { throw exception_io_seek_out_of_range(); }
|
|
|
170 }
|
|
|
171 }
|
|
|
172 }
|
|
|
173 }
|
|
|
174 };
|
|
|
175
|
|
|
176
|
|
|
177
|
|
|
178 // A more clever version of reader_membuffer_*.
|
|
|
179 // Behaves more nicely with large files within 32bit address space.
|
|
|
180 class reader_bigmem : public file_readonly_t<file_v2> {
|
|
|
181 public:
|
|
|
182 reader_bigmem() : m_offset() {}
|
|
|
183 t_size read(void * p_buffer, t_size p_bytes, abort_callback & p_abort) override {
|
|
|
184 pfc::min_acc(p_bytes, remaining());
|
|
|
185 m_mem.read(p_buffer, p_bytes, m_offset);
|
|
|
186 m_offset += p_bytes;
|
|
|
187 return p_bytes;
|
|
|
188 }
|
|
|
189 void read_object(void * p_buffer, t_size p_bytes, abort_callback & p_abort) override {
|
|
|
190 if (p_bytes > remaining()) throw exception_io_data_truncation();
|
|
|
191 m_mem.read(p_buffer, p_bytes, m_offset);
|
|
|
192 m_offset += p_bytes;
|
|
|
193 }
|
|
|
194 t_filesize skip(t_filesize p_bytes, abort_callback & p_abort) override {
|
|
|
195 pfc::min_acc(p_bytes, (t_filesize)remaining());
|
|
|
196 m_offset += (size_t)p_bytes;
|
|
|
197 return p_bytes;
|
|
|
198 }
|
|
|
199 void skip_object(t_filesize p_bytes, abort_callback & p_abort) override {
|
|
|
200 if (p_bytes > remaining()) throw exception_io_data_truncation();
|
|
|
201 m_offset += (size_t)p_bytes;
|
|
|
202 }
|
|
|
203
|
|
|
204 t_filesize get_size(abort_callback & p_abort) override { p_abort.check(); return m_mem.size(); }
|
|
|
205 t_filesize get_position(abort_callback & p_abort) override { p_abort.check(); return m_offset; }
|
|
|
206 void seek(t_filesize p_position, abort_callback & p_abort) override {
|
|
|
207 if (p_position > m_mem.size()) throw exception_io_seek_out_of_range();
|
|
|
208 m_offset = (size_t)p_position;
|
|
|
209 }
|
|
|
210 bool can_seek() override { return true; }
|
|
|
211 bool is_in_memory() override { return true; }
|
|
|
212 void reopen(abort_callback & p_abort) override { seek(0, p_abort); }
|
|
|
213
|
|
|
214 // To be overridden by individual derived classes
|
|
|
215 bool get_content_type(pfc::string_base & p_out) override { return false; }
|
|
|
216 bool is_remote() override { return false; }
|
|
|
217 service_ptr get_metadata(abort_callback&) override { return nullptr; }
|
|
|
218
|
|
|
219 t_filestats2 get_stats2(uint32_t f, abort_callback& a) override {
|
|
|
220 t_filestats2 ret;
|
|
|
221 ret.set_file();
|
|
|
222 ret.m_size = get_size(a);
|
|
|
223 if ( f & stats2_timestamp ) ret.m_timestamp = this->get_timestamp(a);
|
|
|
224 return ret;
|
|
|
225 }
|
|
|
226 protected:
|
|
|
227 void resize(size_t newSize) {
|
|
|
228 m_offset = 0;
|
|
|
229 m_mem.resize(newSize);
|
|
|
230 }
|
|
|
231 size_t remaining() const { return m_mem.size() - m_offset; }
|
|
|
232 pfc::bigmem m_mem;
|
|
|
233 size_t m_offset;
|
|
|
234 };
|
|
|
235
|
|
|
236 class reader_bigmem_mirror : public reader_bigmem {
|
|
|
237 public:
|
|
|
238 reader_bigmem_mirror() {}
|
|
|
239
|
|
|
240 void init(file::ptr source, abort_callback & abort) {
|
|
|
241 source->reopen(abort);
|
|
|
242 m_metadata = source->get_metadata_(abort);
|
|
|
243 t_filesize fs = source->get_size(abort);
|
|
|
244 if (fs > 1024 * 1024 * 1024) { // reject > 1GB
|
|
|
245 throw std::bad_alloc();
|
|
|
246 }
|
|
|
247 size_t s = (size_t)fs;
|
|
|
248 resize(s);
|
|
|
249 for (size_t walk = 0; walk < m_mem._sliceCount(); ++walk) {
|
|
|
250 source->read(m_mem._slicePtr(walk), m_mem._sliceSize(walk), abort);
|
|
|
251 }
|
|
|
252
|
|
|
253 if (!source->get_content_type(m_contentType)) m_contentType.reset();
|
|
|
254 m_isRemote = source->is_remote();
|
|
|
255 m_stats2 = source->get_stats2_(stats2_all, abort);
|
|
|
256 }
|
|
|
257
|
|
|
258 bool get_content_type(pfc::string_base & p_out) override {
|
|
|
259 if (m_contentType.is_empty()) return false;
|
|
|
260 p_out = m_contentType; return true;
|
|
|
261 }
|
|
|
262 t_filetimestamp get_timestamp(abort_callback & p_abort) override { return m_stats2.m_timestamp; }
|
|
|
263 bool is_remote() override { return m_isRemote; }
|
|
|
264 service_ptr get_metadata(abort_callback&) override { return m_metadata; }
|
|
|
265 t_filestats2 get_stats2(uint32_t f, abort_callback& a) override {
|
|
|
266 a.check(); (void)f; return m_stats2;
|
|
|
267 }
|
|
|
268 private:
|
|
|
269 service_ptr m_metadata;
|
|
|
270 t_filestats2 m_stats2;
|
|
|
271 pfc::string8 m_contentType;
|
|
|
272 bool m_isRemote = false;
|
|
|
273 };
|
|
|
274
|
|
|
275 class file_chain : public file_v2 {
|
|
|
276 public:
|
|
|
277 service_ptr get_metadata(abort_callback& a) override {
|
|
|
278 return m_file->get_metadata_(a);
|
|
|
279 }
|
|
|
280 t_filestats2 get_stats2(uint32_t f, abort_callback& a) override {
|
|
|
281 return m_file->get_stats2_(f, a);
|
|
|
282 }
|
|
|
283 t_size read(void * p_buffer, t_size p_bytes, abort_callback & p_abort) override {
|
|
|
284 return m_file->read(p_buffer, p_bytes, p_abort);
|
|
|
285 }
|
|
|
286 void read_object(void * p_buffer, t_size p_bytes, abort_callback & p_abort) override {
|
|
|
287 m_file->read_object(p_buffer, p_bytes, p_abort);
|
|
|
288 }
|
|
|
289 t_filesize skip(t_filesize p_bytes, abort_callback & p_abort) override {
|
|
|
290 return m_file->skip(p_bytes, p_abort);
|
|
|
291 }
|
|
|
292 void skip_object(t_filesize p_bytes, abort_callback & p_abort) override {
|
|
|
293 m_file->skip_object(p_bytes, p_abort);
|
|
|
294 }
|
|
|
295 void write(const void * p_buffer, t_size p_bytes, abort_callback & p_abort) override {
|
|
|
296 m_file->write(p_buffer, p_bytes, p_abort);
|
|
|
297 }
|
|
|
298
|
|
|
299 t_filesize get_size(abort_callback & p_abort) override {
|
|
|
300 return m_file->get_size(p_abort);
|
|
|
301 }
|
|
|
302
|
|
|
303 t_filesize get_position(abort_callback & p_abort) override {
|
|
|
304 return m_file->get_position(p_abort);
|
|
|
305 }
|
|
|
306
|
|
|
307 void resize(t_filesize p_size, abort_callback & p_abort) override {
|
|
|
308 m_file->resize(p_size, p_abort);
|
|
|
309 }
|
|
|
310
|
|
|
311 void seek(t_filesize p_position, abort_callback & p_abort) override {
|
|
|
312 m_file->seek(p_position, p_abort);
|
|
|
313 }
|
|
|
314
|
|
|
315 void seek_ex(t_sfilesize p_position, t_seek_mode p_mode, abort_callback & p_abort) override {
|
|
|
316 m_file->seek_ex(p_position, p_mode, p_abort);
|
|
|
317 }
|
|
|
318
|
|
|
319 bool can_seek() override { return m_file->can_seek(); }
|
|
|
320 bool get_content_type(pfc::string_base & p_out) override { return m_file->get_content_type(p_out); }
|
|
|
321 bool is_in_memory() override { return m_file->is_in_memory(); }
|
|
|
322 void on_idle(abort_callback & p_abort) override { m_file->on_idle(p_abort); }
|
|
|
323 t_filetimestamp get_timestamp(abort_callback & p_abort) override { return m_file->get_timestamp(p_abort); }
|
|
|
324 void reopen(abort_callback & p_abort) override { m_file->reopen(p_abort); }
|
|
|
325 bool is_remote() override { return m_file->is_remote(); }
|
|
|
326
|
|
|
327 file_chain(file::ptr chain) : m_file(chain) {}
|
|
|
328 private:
|
|
|
329 file::ptr m_file;
|
|
|
330 };
|
|
|
331
|
|
|
332 class file_chain_readonly : public file_chain {
|
|
|
333 public:
|
|
|
334 void write(const void * p_buffer, t_size p_bytes, abort_callback & p_abort) override { throw exception_io_denied(); }
|
|
|
335 void resize(t_filesize p_size, abort_callback & p_abort) override { throw exception_io_denied(); }
|
|
|
336 file_chain_readonly(file::ptr chain) : file_chain(chain) {}
|
|
|
337 static file::ptr create(file::ptr chain) { return new service_impl_t< file_chain_readonly >(chain); }
|
|
|
338 };
|