Mercurial > foo_out_sdl
diff foosdk/sdk/foobar2000/helpers/seekabilizer.cpp @ 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/seekabilizer.cpp Mon Jan 05 02:15:46 2026 -0500 @@ -0,0 +1,233 @@ +#include "StdAfx.h" + +#include "seekabilizer.h" + +enum {backread_on_seek = 1024}; + +void seekabilizer_backbuffer::initialize(t_size p_size) +{ + m_depth = m_cursor = 0; + + m_buffer.set_size(p_size); +} + +void seekabilizer_backbuffer::write(const void * p_buffer,t_size p_bytes) +{ + if (p_bytes >= m_buffer.get_size()) + { + memcpy(m_buffer.get_ptr(),(const t_uint8*)p_buffer + p_bytes - m_buffer.get_size(),m_buffer.get_size()); + m_cursor = 0; + m_depth = m_buffer.get_size(); + } + else + { + const t_uint8* sourceptr = (const t_uint8*) p_buffer; + t_size remaining = p_bytes; + while(remaining > 0) + { + t_size delta = m_buffer.get_size() - m_cursor; + if (delta > remaining) delta = remaining; + + memcpy(m_buffer.get_ptr() + m_cursor,sourceptr,delta); + + sourceptr += delta; + remaining -= delta; + m_cursor = (m_cursor + delta) % m_buffer.get_size(); + + m_depth = pfc::min_t<t_size>(m_buffer.get_size(),m_depth + delta); + + } + } +} + +void seekabilizer_backbuffer::read(t_size p_backlogdepth,void * p_buffer,t_size p_bytes) const +{ + PFC_ASSERT(p_backlogdepth <= m_depth); + PFC_ASSERT(p_backlogdepth >= p_bytes); + + + t_uint8* targetptr = (t_uint8*) p_buffer; + t_size remaining = p_bytes; + t_size cursor = (m_cursor + m_buffer.get_size() - p_backlogdepth) % m_buffer.get_size(); + + while(remaining > 0) + { + t_size delta = m_buffer.get_size() - cursor; + if (delta > remaining) delta = remaining; + + memcpy(targetptr,m_buffer.get_ptr() + cursor,delta); + + targetptr += delta; + remaining -= delta; + cursor = (cursor + delta) % m_buffer.get_size(); + } +} + +t_size seekabilizer_backbuffer::get_depth() const +{ + return m_depth; +} + +t_size seekabilizer_backbuffer::get_max_depth() const +{ + return m_buffer.get_size(); +} + +void seekabilizer_backbuffer::reset() +{ + m_depth = m_cursor = 0; +} + + +void seekabilizer::initialize(service_ptr_t<file> p_base,t_size p_buffer_size,abort_callback & p_abort) { + m_buffer.initialize(p_buffer_size); + m_file = p_base; + m_position = m_position_base = 0; + m_size = m_file->get_size(p_abort); +} + +void seekabilizer::g_seekabilize(service_ptr_t<file> & p_reader,t_size p_buffer_size,abort_callback & p_abort) { + if (p_reader.is_valid() && (p_reader->is_remote() || !p_reader->can_seek()) && p_buffer_size > 0) { + auto instance = fb2k::service_new<seekabilizer>(); + instance->initialize(p_reader,p_buffer_size,p_abort); + p_reader = instance.get_ptr(); + } +} + +t_size seekabilizer::read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) { + p_abort.check_e(); + + if (m_position > m_position_base + pfc::max_t<t_size>(m_buffer.get_max_depth(),backread_on_seek) && m_file->can_seek()) { + m_buffer.reset(); + t_filesize target = m_position; + if (target < backread_on_seek) target = 0; + else target -= backread_on_seek; + m_file->seek(target,p_abort); + m_position_base = target; + } + + //seek ahead + while(m_position > m_position_base) { + enum {tempsize = 1024}; + t_uint8 temp[tempsize]; + t_size delta = (t_size) pfc::min_t<t_filesize>(tempsize,m_position - m_position_base); + t_size bytes_read = 0; + bytes_read = m_file->read(temp,delta,p_abort); + m_buffer.write(temp,bytes_read); + m_position_base += bytes_read; + + if (bytes_read < delta) { + return 0; + } + } + + t_size done = 0; + t_uint8 * targetptr = (t_uint8*) p_buffer; + + //try to read backbuffer + if (m_position < m_position_base) { + if (m_position_base - m_position > (t_filesize)m_buffer.get_depth()) throw exception_io_seek_out_of_range(); + t_size backread_depth = (t_size) (m_position_base - m_position); + t_size delta = pfc::min_t<t_size>(backread_depth,p_bytes-done); + m_buffer.read(backread_depth,targetptr,delta); + done += delta; + m_position += delta; + } + + //regular read + if (done < p_bytes) + { + t_size bytes_read; + bytes_read = m_file->read(targetptr+done,p_bytes-done,p_abort); + + m_buffer.write(targetptr+done,bytes_read); + + done += bytes_read; + m_position += bytes_read; + m_position_base += bytes_read; + } + + return done; +} + +t_filesize seekabilizer::get_size(abort_callback & p_abort) { + p_abort.check_e(); + return m_size; +} + +t_filesize seekabilizer::get_position(abort_callback & p_abort) { + p_abort.check_e(); + return m_position; +} + +void seekabilizer::seek(t_filesize p_position,abort_callback & p_abort) { + PFC_ASSERT(m_position_base >= m_buffer.get_depth()); + p_abort.check_e(); + + if (m_size != filesize_invalid && p_position > m_size) throw exception_io_seek_out_of_range(); + + t_filesize lowest = m_position_base - m_buffer.get_depth(); + + if (p_position < lowest) { + if (m_file->can_seek()) { + m_buffer.reset(); + t_filesize target = p_position; + t_size delta = m_buffer.get_max_depth(); + if (delta > backread_on_seek) delta = backread_on_seek; + if (target > delta) target -= delta; + else target = 0; + m_file->seek(target,p_abort); + m_position_base = target; + } + else { + m_buffer.reset(); + m_file->reopen(p_abort); + m_position_base = 0; + } + } + + m_position = p_position; +} + +bool seekabilizer::can_seek() +{ + return true; +} + +bool seekabilizer::get_content_type(pfc::string_base & p_out) {return m_file->get_content_type(p_out);} + +bool seekabilizer::is_in_memory() {return false;} + +void seekabilizer::on_idle(abort_callback & p_abort) {return m_file->on_idle(p_abort);} + +t_filetimestamp seekabilizer::get_timestamp(abort_callback & p_abort) { + p_abort.check_e(); + return m_file->get_timestamp(p_abort); +} + +void seekabilizer::reopen(abort_callback & p_abort) { + if (m_position_base - m_buffer.get_depth() == 0) { + seek(0,p_abort); + } else { + m_position = m_position_base = 0; + m_buffer.reset(); + m_file->reopen(p_abort); + } +} + +bool seekabilizer::is_remote() +{ + return m_file->is_remote(); +} + +service_ptr seekabilizer::get_metadata(abort_callback& a) { + return m_file->get_metadata_(a); +} + +t_filestats2 seekabilizer::get_stats2(uint32_t s2flags, abort_callback& a) { + return m_file->get_stats2_(s2flags, a); +} + +size_t seekabilizer::lowLevelIO(const GUID& guid, size_t arg1, void* arg2, size_t arg2size, abort_callback& abort) { + return m_file->lowLevelIO_(guid, arg1, arg2, arg2size, abort); +}
