comparison 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
comparison
equal deleted inserted replaced
0:e9bb126753e7 1:20d02a178406
1 #include "StdAfx.h"
2
3 #include "seekabilizer.h"
4
5 enum {backread_on_seek = 1024};
6
7 void seekabilizer_backbuffer::initialize(t_size p_size)
8 {
9 m_depth = m_cursor = 0;
10
11 m_buffer.set_size(p_size);
12 }
13
14 void seekabilizer_backbuffer::write(const void * p_buffer,t_size p_bytes)
15 {
16 if (p_bytes >= m_buffer.get_size())
17 {
18 memcpy(m_buffer.get_ptr(),(const t_uint8*)p_buffer + p_bytes - m_buffer.get_size(),m_buffer.get_size());
19 m_cursor = 0;
20 m_depth = m_buffer.get_size();
21 }
22 else
23 {
24 const t_uint8* sourceptr = (const t_uint8*) p_buffer;
25 t_size remaining = p_bytes;
26 while(remaining > 0)
27 {
28 t_size delta = m_buffer.get_size() - m_cursor;
29 if (delta > remaining) delta = remaining;
30
31 memcpy(m_buffer.get_ptr() + m_cursor,sourceptr,delta);
32
33 sourceptr += delta;
34 remaining -= delta;
35 m_cursor = (m_cursor + delta) % m_buffer.get_size();
36
37 m_depth = pfc::min_t<t_size>(m_buffer.get_size(),m_depth + delta);
38
39 }
40 }
41 }
42
43 void seekabilizer_backbuffer::read(t_size p_backlogdepth,void * p_buffer,t_size p_bytes) const
44 {
45 PFC_ASSERT(p_backlogdepth <= m_depth);
46 PFC_ASSERT(p_backlogdepth >= p_bytes);
47
48
49 t_uint8* targetptr = (t_uint8*) p_buffer;
50 t_size remaining = p_bytes;
51 t_size cursor = (m_cursor + m_buffer.get_size() - p_backlogdepth) % m_buffer.get_size();
52
53 while(remaining > 0)
54 {
55 t_size delta = m_buffer.get_size() - cursor;
56 if (delta > remaining) delta = remaining;
57
58 memcpy(targetptr,m_buffer.get_ptr() + cursor,delta);
59
60 targetptr += delta;
61 remaining -= delta;
62 cursor = (cursor + delta) % m_buffer.get_size();
63 }
64 }
65
66 t_size seekabilizer_backbuffer::get_depth() const
67 {
68 return m_depth;
69 }
70
71 t_size seekabilizer_backbuffer::get_max_depth() const
72 {
73 return m_buffer.get_size();
74 }
75
76 void seekabilizer_backbuffer::reset()
77 {
78 m_depth = m_cursor = 0;
79 }
80
81
82 void seekabilizer::initialize(service_ptr_t<file> p_base,t_size p_buffer_size,abort_callback & p_abort) {
83 m_buffer.initialize(p_buffer_size);
84 m_file = p_base;
85 m_position = m_position_base = 0;
86 m_size = m_file->get_size(p_abort);
87 }
88
89 void seekabilizer::g_seekabilize(service_ptr_t<file> & p_reader,t_size p_buffer_size,abort_callback & p_abort) {
90 if (p_reader.is_valid() && (p_reader->is_remote() || !p_reader->can_seek()) && p_buffer_size > 0) {
91 auto instance = fb2k::service_new<seekabilizer>();
92 instance->initialize(p_reader,p_buffer_size,p_abort);
93 p_reader = instance.get_ptr();
94 }
95 }
96
97 t_size seekabilizer::read(void * p_buffer,t_size p_bytes,abort_callback & p_abort) {
98 p_abort.check_e();
99
100 if (m_position > m_position_base + pfc::max_t<t_size>(m_buffer.get_max_depth(),backread_on_seek) && m_file->can_seek()) {
101 m_buffer.reset();
102 t_filesize target = m_position;
103 if (target < backread_on_seek) target = 0;
104 else target -= backread_on_seek;
105 m_file->seek(target,p_abort);
106 m_position_base = target;
107 }
108
109 //seek ahead
110 while(m_position > m_position_base) {
111 enum {tempsize = 1024};
112 t_uint8 temp[tempsize];
113 t_size delta = (t_size) pfc::min_t<t_filesize>(tempsize,m_position - m_position_base);
114 t_size bytes_read = 0;
115 bytes_read = m_file->read(temp,delta,p_abort);
116 m_buffer.write(temp,bytes_read);
117 m_position_base += bytes_read;
118
119 if (bytes_read < delta) {
120 return 0;
121 }
122 }
123
124 t_size done = 0;
125 t_uint8 * targetptr = (t_uint8*) p_buffer;
126
127 //try to read backbuffer
128 if (m_position < m_position_base) {
129 if (m_position_base - m_position > (t_filesize)m_buffer.get_depth()) throw exception_io_seek_out_of_range();
130 t_size backread_depth = (t_size) (m_position_base - m_position);
131 t_size delta = pfc::min_t<t_size>(backread_depth,p_bytes-done);
132 m_buffer.read(backread_depth,targetptr,delta);
133 done += delta;
134 m_position += delta;
135 }
136
137 //regular read
138 if (done < p_bytes)
139 {
140 t_size bytes_read;
141 bytes_read = m_file->read(targetptr+done,p_bytes-done,p_abort);
142
143 m_buffer.write(targetptr+done,bytes_read);
144
145 done += bytes_read;
146 m_position += bytes_read;
147 m_position_base += bytes_read;
148 }
149
150 return done;
151 }
152
153 t_filesize seekabilizer::get_size(abort_callback & p_abort) {
154 p_abort.check_e();
155 return m_size;
156 }
157
158 t_filesize seekabilizer::get_position(abort_callback & p_abort) {
159 p_abort.check_e();
160 return m_position;
161 }
162
163 void seekabilizer::seek(t_filesize p_position,abort_callback & p_abort) {
164 PFC_ASSERT(m_position_base >= m_buffer.get_depth());
165 p_abort.check_e();
166
167 if (m_size != filesize_invalid && p_position > m_size) throw exception_io_seek_out_of_range();
168
169 t_filesize lowest = m_position_base - m_buffer.get_depth();
170
171 if (p_position < lowest) {
172 if (m_file->can_seek()) {
173 m_buffer.reset();
174 t_filesize target = p_position;
175 t_size delta = m_buffer.get_max_depth();
176 if (delta > backread_on_seek) delta = backread_on_seek;
177 if (target > delta) target -= delta;
178 else target = 0;
179 m_file->seek(target,p_abort);
180 m_position_base = target;
181 }
182 else {
183 m_buffer.reset();
184 m_file->reopen(p_abort);
185 m_position_base = 0;
186 }
187 }
188
189 m_position = p_position;
190 }
191
192 bool seekabilizer::can_seek()
193 {
194 return true;
195 }
196
197 bool seekabilizer::get_content_type(pfc::string_base & p_out) {return m_file->get_content_type(p_out);}
198
199 bool seekabilizer::is_in_memory() {return false;}
200
201 void seekabilizer::on_idle(abort_callback & p_abort) {return m_file->on_idle(p_abort);}
202
203 t_filetimestamp seekabilizer::get_timestamp(abort_callback & p_abort) {
204 p_abort.check_e();
205 return m_file->get_timestamp(p_abort);
206 }
207
208 void seekabilizer::reopen(abort_callback & p_abort) {
209 if (m_position_base - m_buffer.get_depth() == 0) {
210 seek(0,p_abort);
211 } else {
212 m_position = m_position_base = 0;
213 m_buffer.reset();
214 m_file->reopen(p_abort);
215 }
216 }
217
218 bool seekabilizer::is_remote()
219 {
220 return m_file->is_remote();
221 }
222
223 service_ptr seekabilizer::get_metadata(abort_callback& a) {
224 return m_file->get_metadata_(a);
225 }
226
227 t_filestats2 seekabilizer::get_stats2(uint32_t s2flags, abort_callback& a) {
228 return m_file->get_stats2_(s2flags, a);
229 }
230
231 size_t seekabilizer::lowLevelIO(const GUID& guid, size_t arg1, void* arg2, size_t arg2size, abort_callback& abort) {
232 return m_file->lowLevelIO_(guid, arg1, arg2, arg2size, abort);
233 }