Mercurial > foo_out_sdl
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/foosdk/sdk/foobar2000/helpers/readers.h Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,338 @@ +#pragma once + +class NOVTABLE reader_membuffer_base : public file_readonly { +public: + reader_membuffer_base() : m_offset(0) {} + + t_size read(void * p_buffer, t_size p_bytes, abort_callback & p_abort) override; + + void write(const void * p_buffer, t_size p_bytes, abort_callback & p_abort) override { throw exception_io_denied(); } + + t_filesize get_size(abort_callback & p_abort) override { return get_buffer_size(); } + t_filesize get_position(abort_callback & p_abort) override { return m_offset; } + void seek(t_filesize position, abort_callback & p_abort) override; + void reopen(abort_callback & p_abort) override { seek(0, p_abort); } + + bool can_seek() override { return true; } + bool is_in_memory() override { return true; } + +protected: + virtual const void * get_buffer() = 0; + virtual t_size get_buffer_size() = 0; + //virtual t_filetimestamp get_timestamp(abort_callback & p_abort) = 0; + bool get_content_type(pfc::string_base &) override { return false; } + 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; } +private: + t_size m_offset; +}; + +class reader_membuffer_simple : public reader_membuffer_base { +public: + 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) {} + 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) { + m_data.resize(size); + if ( ptr != nullptr ) memcpy(m_data.get_ptr(), ptr, size); + } + const void * get_buffer() { return m_data.get_ptr(); } + void* _get_write_buffer() { return m_data.get_ptr(); } + t_size get_buffer_size() { return m_data.get_size(); } + t_filetimestamp get_timestamp(abort_callback & p_abort) { return m_ts; } + bool is_remote() { return m_isRemote; } + +private: + pfc::mem_block m_data; + t_filetimestamp m_ts; + bool m_isRemote; +}; + +class reader_membuffer_mirror : public reader_membuffer_base +{ +public: + t_filetimestamp get_timestamp(abort_callback & p_abort) { return m_timestamp; } + bool is_remote() { return m_remote; } + + //! Returns false when the object could not be mirrored (too big) or did not need mirroring. + static bool g_create(service_ptr_t<file> & p_out, const service_ptr_t<file> & p_src, abort_callback & p_abort) { + service_ptr_t<reader_membuffer_mirror> ptr = new service_impl_t<reader_membuffer_mirror>(); + if (!ptr->init(p_src, p_abort)) return false; + p_out = ptr.get_ptr(); + return true; + } + bool get_content_type(pfc::string_base & out) { + if (m_contentType.is_empty()) return false; + out = m_contentType; return true; + } +private: + const void * get_buffer() { return m_buffer.get_ptr(); } + t_size get_buffer_size() { return m_buffer.get_size(); } + + bool init(const service_ptr_t<file> & p_src, abort_callback & p_abort) { + if (p_src->is_in_memory()) return false;//already buffered + if (!p_src->get_content_type(m_contentType)) m_contentType.reset(); + m_remote = p_src->is_remote(); + + t_size size = pfc::downcast_guarded<t_size>(p_src->get_size(p_abort)); + + m_buffer.set_size(size); + + p_src->reopen(p_abort); + + p_src->read_object(m_buffer.get_ptr(), size, p_abort); + + m_timestamp = p_src->get_timestamp(p_abort); + + return true; + } + + + t_filetimestamp m_timestamp; + pfc::array_t<char> m_buffer; + bool m_remote; + pfc::string8 m_contentType; + +}; + +class reader_limited : public file_readonly_t<file_v2> { + service_ptr_t<file> r; + t_filesize begin; + t_filesize end; + +public: + static file::ptr g_create(file::ptr base, t_filesize offset, t_filesize size, abort_callback & abort) { + service_ptr_t<reader_limited> r = new service_impl_t<reader_limited>(); + if (offset + size < offset) throw pfc::exception_overflow(); + r->init(base, offset, offset + size, abort); + return r; + } + reader_limited() { begin = 0;end = 0; } + reader_limited(const service_ptr_t<file> & p_r, t_filesize p_begin, t_filesize p_end, abort_callback & p_abort) { + r = p_r; + begin = p_begin; + end = p_end; + reopen(p_abort); + } + + void init(const service_ptr_t<file> & p_r, t_filesize p_begin, t_filesize p_end, abort_callback & p_abort) { + r = p_r; + begin = p_begin; + end = p_end; + reopen(p_abort); + } + + service_ptr get_metadata(abort_callback& a) override {return r->get_metadata_(a);} + t_filestats2 get_stats2(uint32_t f, abort_callback& a) override { + auto ret = r->get_stats2_(f, a); + ret.m_size = this->get_size(a); + return ret; + } + t_filetimestamp get_timestamp(abort_callback & p_abort) override { return r->get_timestamp(p_abort); } + + t_size read(void *p_buffer, t_size p_bytes, abort_callback & p_abort) override { + t_filesize pos; + pos = r->get_position(p_abort); + if (p_bytes > end - pos) p_bytes = (t_size)(end - pos); + return r->read(p_buffer, p_bytes, p_abort); + } + + t_filesize get_size(abort_callback & p_abort) override { return end - begin; } + + t_filesize get_position(abort_callback & p_abort) override { + return r->get_position(p_abort) - begin; + } + + void seek(t_filesize position, abort_callback & p_abort) override { + if (position > end) throw exception_io_seek_out_of_range(); + r->seek(position + begin, p_abort); + } + bool can_seek() override { return r->can_seek(); } + bool is_remote() override { return r->is_remote(); } + + bool get_content_type(pfc::string_base & out) override { return r->get_content_type(out); } + + void reopen(abort_callback & p_abort) override { + seekInternal(begin, p_abort); + } +private: + void seekInternal(t_filesize position, abort_callback & abort) { + if (r->can_seek()) { + r->seek(position, abort); + } else { + t_filesize positionWas = r->get_position(abort); + if (positionWas == filesize_invalid || positionWas > position) { + r->reopen(abort); + try { r->skip_object(position, abort); } + catch (exception_io_data const &) { throw exception_io_seek_out_of_range(); } + } else { + t_filesize skipMe = position - positionWas; + if (skipMe > 0) { + try { r->skip_object(skipMe, abort); } + catch (exception_io_data const &) { throw exception_io_seek_out_of_range(); } + } + } + } + } +}; + + + +// A more clever version of reader_membuffer_*. +// Behaves more nicely with large files within 32bit address space. +class reader_bigmem : public file_readonly_t<file_v2> { +public: + reader_bigmem() : m_offset() {} + t_size read(void * p_buffer, t_size p_bytes, abort_callback & p_abort) override { + pfc::min_acc(p_bytes, remaining()); + m_mem.read(p_buffer, p_bytes, m_offset); + m_offset += p_bytes; + return p_bytes; + } + void read_object(void * p_buffer, t_size p_bytes, abort_callback & p_abort) override { + if (p_bytes > remaining()) throw exception_io_data_truncation(); + m_mem.read(p_buffer, p_bytes, m_offset); + m_offset += p_bytes; + } + t_filesize skip(t_filesize p_bytes, abort_callback & p_abort) override { + pfc::min_acc(p_bytes, (t_filesize)remaining()); + m_offset += (size_t)p_bytes; + return p_bytes; + } + void skip_object(t_filesize p_bytes, abort_callback & p_abort) override { + if (p_bytes > remaining()) throw exception_io_data_truncation(); + m_offset += (size_t)p_bytes; + } + + t_filesize get_size(abort_callback & p_abort) override { p_abort.check(); return m_mem.size(); } + t_filesize get_position(abort_callback & p_abort) override { p_abort.check(); return m_offset; } + void seek(t_filesize p_position, abort_callback & p_abort) override { + if (p_position > m_mem.size()) throw exception_io_seek_out_of_range(); + m_offset = (size_t)p_position; + } + bool can_seek() override { return true; } + bool is_in_memory() override { return true; } + void reopen(abort_callback & p_abort) override { seek(0, p_abort); } + + // To be overridden by individual derived classes + bool get_content_type(pfc::string_base & p_out) override { return false; } + bool is_remote() override { return false; } + service_ptr get_metadata(abort_callback&) override { return nullptr; } + + t_filestats2 get_stats2(uint32_t f, abort_callback& a) override { + t_filestats2 ret; + ret.set_file(); + ret.m_size = get_size(a); + if ( f & stats2_timestamp ) ret.m_timestamp = this->get_timestamp(a); + return ret; + } +protected: + void resize(size_t newSize) { + m_offset = 0; + m_mem.resize(newSize); + } + size_t remaining() const { return m_mem.size() - m_offset; } + pfc::bigmem m_mem; + size_t m_offset; +}; + +class reader_bigmem_mirror : public reader_bigmem { +public: + reader_bigmem_mirror() {} + + void init(file::ptr source, abort_callback & abort) { + source->reopen(abort); + m_metadata = source->get_metadata_(abort); + t_filesize fs = source->get_size(abort); + if (fs > 1024 * 1024 * 1024) { // reject > 1GB + throw std::bad_alloc(); + } + size_t s = (size_t)fs; + resize(s); + for (size_t walk = 0; walk < m_mem._sliceCount(); ++walk) { + source->read(m_mem._slicePtr(walk), m_mem._sliceSize(walk), abort); + } + + if (!source->get_content_type(m_contentType)) m_contentType.reset(); + m_isRemote = source->is_remote(); + m_stats2 = source->get_stats2_(stats2_all, abort); + } + + bool get_content_type(pfc::string_base & p_out) override { + if (m_contentType.is_empty()) return false; + p_out = m_contentType; return true; + } + t_filetimestamp get_timestamp(abort_callback & p_abort) override { return m_stats2.m_timestamp; } + bool is_remote() override { return m_isRemote; } + service_ptr get_metadata(abort_callback&) override { return m_metadata; } + t_filestats2 get_stats2(uint32_t f, abort_callback& a) override { + a.check(); (void)f; return m_stats2; + } +private: + service_ptr m_metadata; + t_filestats2 m_stats2; + pfc::string8 m_contentType; + bool m_isRemote = false; +}; + +class file_chain : public file_v2 { +public: + service_ptr get_metadata(abort_callback& a) override { + return m_file->get_metadata_(a); + } + t_filestats2 get_stats2(uint32_t f, abort_callback& a) override { + return m_file->get_stats2_(f, a); + } + t_size read(void * p_buffer, t_size p_bytes, abort_callback & p_abort) override { + return m_file->read(p_buffer, p_bytes, p_abort); + } + void read_object(void * p_buffer, t_size p_bytes, abort_callback & p_abort) override { + m_file->read_object(p_buffer, p_bytes, p_abort); + } + t_filesize skip(t_filesize p_bytes, abort_callback & p_abort) override { + return m_file->skip(p_bytes, p_abort); + } + void skip_object(t_filesize p_bytes, abort_callback & p_abort) override { + m_file->skip_object(p_bytes, p_abort); + } + void write(const void * p_buffer, t_size p_bytes, abort_callback & p_abort) override { + m_file->write(p_buffer, p_bytes, p_abort); + } + + t_filesize get_size(abort_callback & p_abort) override { + return m_file->get_size(p_abort); + } + + t_filesize get_position(abort_callback & p_abort) override { + return m_file->get_position(p_abort); + } + + void resize(t_filesize p_size, abort_callback & p_abort) override { + m_file->resize(p_size, p_abort); + } + + void seek(t_filesize p_position, abort_callback & p_abort) override { + m_file->seek(p_position, p_abort); + } + + void seek_ex(t_sfilesize p_position, t_seek_mode p_mode, abort_callback & p_abort) override { + m_file->seek_ex(p_position, p_mode, p_abort); + } + + bool can_seek() override { return m_file->can_seek(); } + bool get_content_type(pfc::string_base & p_out) override { return m_file->get_content_type(p_out); } + bool is_in_memory() override { return m_file->is_in_memory(); } + void on_idle(abort_callback & p_abort) override { m_file->on_idle(p_abort); } + t_filetimestamp get_timestamp(abort_callback & p_abort) override { return m_file->get_timestamp(p_abort); } + void reopen(abort_callback & p_abort) override { m_file->reopen(p_abort); } + bool is_remote() override { return m_file->is_remote(); } + + file_chain(file::ptr chain) : m_file(chain) {} +private: + file::ptr m_file; +}; + +class file_chain_readonly : public file_chain { +public: + void write(const void * p_buffer, t_size p_bytes, abort_callback & p_abort) override { throw exception_io_denied(); } + void resize(t_filesize p_size, abort_callback & p_abort) override { throw exception_io_denied(); } + file_chain_readonly(file::ptr chain) : file_chain(chain) {} + static file::ptr create(file::ptr chain) { return new service_impl_t< file_chain_readonly >(chain); } +};
