]> git.sesse.net Git - fjl/blob - input.c
b7f703992cc3baafea9086cde2f6076e25c7ec9e
[fjl] / input.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4
5 #include "input.h"
6
7 void init_data_source(struct data_source* source, input_func_t* input_func, void* userdata)
8 {
9         memset(source, 0, sizeof(*source));
10         source->bytes = (uint8_t*)malloc(bytereservoir_size);
11         source->input_func = input_func;
12         source->userdata = userdata;
13 }
14
15 void possibly_refill_slow_path(struct data_source* source, unsigned num_bits)
16 {
17         // First, make sure there's stuff in the byte reservoir if we can.
18         assert(source->bytes_available <= bytereservoir_size);
19
20         // Read data from the source until we have enough to satisfy the request.
21         while (source->bits_available + 8 * source->bytes_available < num_bits) {
22                 const size_t bytes_to_read = bytereservoir_size - source->bytes_available;
23                 const ssize_t bytes_read =
24                         (*source->input_func)(source->userdata,
25                                               source->bytes + source->bytes_available,
26                                               bytes_to_read);
27                 assert(bytes_read <= bytes_to_read);
28                 assert(bytes_read >= (ssize_t)-1);
29
30                 // TODO: We need better error handling here. setjmp()/longjmp()
31                 // should hopefully do the trick, but we need to take care for
32                 // suspension.
33                 if (bytes_read == (ssize_t)-1) {
34                         fprintf(stderr, "Input function returned error\n");
35                         exit(1);
36                 }
37                 if (bytes_read == 0) {
38                         fprintf(stderr, "Premature EOF\n");
39                         exit(1);
40                 }
41                 
42                 source->bytes_available += bytes_read;
43         }
44
45         // Fill the bit reservoir one by one byte until we have enough.
46         while (source->bits_available < num_bits) {
47                 assert(source->bytes_available > 0);
48                 assert(source->bits_available + 8 <= bitreservoir_size);
49                 uint8_t byte = *(source->bytes);
50                 ++source->bytes;
51                 --source->bytes_available;
52                 source->bits |= ((bitreservoir_t)byte << (bitreservoir_size - source->bits_available - 8));
53                 source->bits_available += 8;
54         }
55 }