]> git.sesse.net Git - fjl/blobdiff - bitsource.c
Rename input.h to bitsource.h (and friends).
[fjl] / bitsource.c
diff --git a/bitsource.c b/bitsource.c
new file mode 100644 (file)
index 0000000..72b143b
--- /dev/null
@@ -0,0 +1,59 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include "bitsource.h"
+
+#define MARKER_CHAR 0xff
+#define STUFF_MARKER 0x00
+
+void init_bit_source(struct bit_source* source, input_func_t* input_func, void* userdata)
+{
+       memset(source, 0, sizeof(*source));
+       source->bytes = (uint8_t*)malloc(BYTERESERVOIR_SIZE);
+       source->input_func = input_func;
+       source->userdata = userdata;
+}
+
+void possibly_refill_slow_path(struct bit_source* source, unsigned num_bits)
+{
+       // First, make sure there's stuff in the byte reservoir if we can.
+       assert(source->bytes_available <= BYTERESERVOIR_SIZE);
+
+       // Read data from the source until we have enough to satisfy the request.
+       while (source->bits_available + 8 * source->bytes_available < num_bits) {
+               const size_t bytes_to_read = BYTERESERVOIR_SIZE - source->bytes_available;
+               const ssize_t bytes_read =
+                       (*source->input_func)(source->userdata,
+                                             source->bytes + source->bytes_available,
+                                             bytes_to_read);
+               assert(bytes_read <= (ssize_t)bytes_to_read);
+               assert(bytes_read >= (ssize_t)-1);
+
+               // TODO: We need better error handling here. setjmp()/longjmp()
+               // should hopefully do the trick, but we need to take care for
+               // suspension.
+               if (bytes_read == (ssize_t)-1) {
+                       fprintf(stderr, "Input function returned error\n");
+                       exit(1);
+               }
+               if (bytes_read == 0) {
+                       fprintf(stderr, "Premature EOF\n");
+                       exit(1);
+               }
+               
+               source->bytes_available += bytes_read;
+       }
+
+       // Fill the bit reservoir one by one byte until we have enough.
+       while (source->bits_available < num_bits) {
+               assert(source->bytes_available > 0);
+               assert(source->bits_available + 8 <= BITRESERVOIR_SIZE);
+               uint8_t byte = *(source->bytes);
+               ++source->bytes;
+               --source->bytes_available;
+               source->bits |= ((bitreservoir_t)byte << (BITRESERVOIR_SIZE - source->bits_available - 8));
+               source->bits_available += 8;
+       }
+}