6 #include "bytesource.h"
8 #define MARKER_CHAR 0xff
9 #define STUFF_MARKER 0x00
11 void init_byte_source(struct byte_source* source, raw_input_func_t* input_func, void* userdata)
13 // TODO: should this size be a different constant?
14 memset(source, 0, sizeof(*source));
15 source->bytes = (uint8_t*)malloc(BYTESOURCE_CHUNK_SIZE);
16 source->input_func = input_func;
17 source->userdata = userdata;
20 uint8_t byte_source_read_marker(struct byte_source* source)
22 assert(source->bytes_available >= 2);
23 assert(source->bytes[0] == MARKER_CHAR);
24 assert(source->bytes[1] != STUFF_MARKER);
26 uint8_t ret = source->bytes[1];
28 memmove(source->bytes, source->bytes + 2, source->bytes_available - 2);
29 source->bytes_available -= 2;
34 ssize_t byte_source_input_func(void* source, uint8_t* buf, size_t len)
36 struct byte_source* src = (struct byte_source*)source;
38 // If there's no data in the buffer (or only a partial marker), we have
39 // to read in more from our upstream src.
40 while (src->bytes_available == 0 ||
41 (src->bytes_available == 1 && src->bytes[0] == MARKER_CHAR)) {
42 const unsigned space_left = BYTESOURCE_CHUNK_SIZE - src->bytes_available;
43 const size_t bytes_to_read = (len > space_left ? space_left : len);
44 assert(bytes_to_read <= BYTESOURCE_CHUNK_SIZE);
45 const ssize_t bytes_read =
46 (*src->input_func)(src->userdata,
47 src->bytes + src->bytes_available,
49 assert(bytes_read >= -1);
50 assert(bytes_read <= bytes_to_read);
52 if (bytes_read == -1) {
54 } else if (bytes_read == 0) {
55 if (src->bytes_available == 1) {
56 // EOF in the middle of a marker => read error
59 assert(src->bytes_available == 0);
64 src->bytes_available += bytes_read;
67 // Now unstuff as much as we can. First of all, if there's a 0xFF at the
68 // end of the buffer, we don't include it this time; the unstuff function
69 // will only give us an error since it can't decide if it's a marker or
71 unsigned bytes_to_unstuff = src->bytes_available;
72 bool end_marker = false;
73 assert(bytes_to_unstuff > 0);
74 if (src->bytes[bytes_to_unstuff - 1] == 0xff) {
79 int unstuffed_bytes = (*unstuff_choice)(buf, src->bytes, bytes_to_unstuff);
80 assert(unstuffed_bytes != 0);
81 if (unstuffed_bytes > 0) {
82 // Fast path: No markers in the data. We can basically just
85 src->bytes_available = 1;
88 src->bytes_available = 0;
91 return unstuffed_bytes;
94 // Slow path: There was a marker in the data. Unstuff manually until
95 // we hit the marker, then return that.
96 assert(unstuffed_bytes == -1);
98 unsigned bytes_written = 0;
99 for (bytes_read = 0; bytes_read < src->bytes_available; ++bytes_read) {
100 buf[bytes_written++] = src->bytes[bytes_read];
101 if (src->bytes[bytes_read] != MARKER_CHAR) {
105 assert(bytes_read < src->bytes_available);
106 if (src->bytes[bytes_read + 1] == STUFF_MARKER) {
107 // Skip the stuff byte.
111 // OK, this is our marker.
116 memmove(src->bytes, src->bytes + bytes_read, src->bytes_available - bytes_read);
117 src->bytes_available -= bytes_read;
118 assert(bytes_written >= 1);
119 return bytes_written - 1;