Mercurial > foo_out_sdl
comparison foosdk/sdk/foobar2000/helpers/readers.h @ 1:20d02a178406 default tip
*: check in everything else
yay
| author | Paper <paper@tflc.us> |
|---|---|
| date | Mon, 05 Jan 2026 02:15:46 -0500 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 0:e9bb126753e7 | 1:20d02a178406 |
|---|---|
| 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 }; |
