9 unsigned long maxlength;
10 struct fileblock *next;
13 static unsigned long file_length;
15 static struct fileblock *first;
16 static unsigned long first_pos;
18 static struct fileblock *current;
19 static unsigned long current_pos; /* includes current_offset */
20 static unsigned long current_offset;
22 static struct fileblock *thrown;
24 #define BLOCK_OVERHEAD 16
25 #define block_len (_block_len - BLOCK_OVERHEAD)
26 int _block_len = 8192;
31 #define debug(...) do { } while (0)
34 unsigned long fb_len()
39 int fb_seek_set(unsigned long pos)
41 debug(stderr, "fb_seek_set(%ld), first %ld/%ld\n", pos, first_pos, file_length);
43 if (pos < first_pos || pos >= file_length)
47 current_pos = first_pos;
49 return fb_seek_inc(pos - current_pos);
52 int fb_seek_end(unsigned long offset)
54 debug(stderr, "fb_seek_end(%ld)\n", offset);
56 if (offset > file_length)
59 return fb_seek_set(file_length - offset);
62 int fb_seek_inc(unsigned long offset)
66 debug(stderr, "fb_seek_inc(%ld), current %ld/%ld\n", offset, current_pos, file_length);
68 if (offset >= file_length - current_pos)
71 while ((l = current->length - current_offset) < offset) {
75 current = current->next;
78 current_pos += offset;
79 current_offset += offset;
83 int fb_seek_dec(unsigned long offset)
85 debug(stderr, "fb_seek_dec(%ld), current %ld\n", offset, current_pos);
87 if (offset > current_pos)
90 if (offset <= current_offset) {
91 current_pos -= offset;
92 current_offset -= offset;
96 return fb_seek_set(current_pos - offset);
99 unsigned long fb_tell(void)
104 void fb_throw(unsigned long maxlen, void (* f)(void *, unsigned long))
106 struct fileblock *fb;
111 while (file_length - first_pos - first->length > maxlen) {
112 debug(stderr, "fb_throw(%ld), first %ld/%ld, length %ld\n", maxlen, first_pos, first->length, file_length);
120 first_pos += fb->length;
121 if (current_pos < first_pos) {
123 current_pos = first_pos;
126 f(fb->data, fb->length);
130 static struct fileblock *fb_alloc(void)
132 struct fileblock *fb;
136 thrown = thrown->next;
141 fb = malloc(sizeof(*fb));
146 fb->data = malloc(block_len);
150 /* Halve the block size and try again, down to 1 page */
151 if (_block_len < 4096) {
160 fb->maxlength = block_len;
164 int fb_write(const void *data, unsigned long len)
169 debug(stderr, "fb_write(%ld), current %ld\n", len, current_pos);
179 p = current->data + current_offset;
180 l = current->maxlength - current_offset;
189 if (file_length < current_pos)
190 file_length = current_pos;
193 if (current->length < current_offset)
194 current->length = current_offset;
199 if (!current->next) {
200 current->next = fb_alloc();
205 current = current->next;
210 int fb_peek(void *data, unsigned long len)
212 struct fileblock *fb;
213 unsigned long fb_pos;
214 unsigned long fb_offset;
218 fb_pos = current_pos;
219 fb_offset = current_offset;
220 ret = fb_read(data, len);
222 current_pos = fb_pos;
223 current_offset = fb_offset;
227 int fb_read(void *data, unsigned long len)
229 unsigned long readlen;
233 debug(stderr, "fb_read(%ld), current %ld\n", len, current_pos);
235 if (file_length - current_pos < len)
236 len = file_length - current_pos;
240 p = current->data + current_offset;
241 l = current->length - current_offset;
255 current = current->next;
260 void *fb_read_block(unsigned long *len)
265 debug(stderr, "fb_read_block(), current %ld/%ld\n", current_pos, current->length);
267 if (current_pos >= file_length)
270 if (current_offset >= current->length) {
271 current = current->next;
275 p = current->data + current_offset;
276 l = current->length - current_offset;
285 int fb_trim(unsigned long len)
287 struct fileblock *fb;
288 struct fileblock *fbnext;
289 unsigned long fb_pos;
291 debug(stderr, "fb_trim(%ld), length %ld\n", len, file_length);
293 if (len > file_length - first_pos)
297 for (fb = first, fb_pos = first_pos;
298 fb_pos + fb->length < file_length;
299 fb_pos += fb->length, fb = fb->next);
301 fb->length = file_length - fb_pos;
305 fb->next = fbnext->next;
310 if (current_pos > file_length)
311 fb_seek_set(file_length);