Branch data Line data Source code
1 : : /**
2 : : * @file bitstream.c
3 : : * @brief Reader/writer construction, destruction, and common result helpers.
4 : : */
5 : :
6 : : #include "bitstream_internal.h"
7 : :
8 : : #include <stdlib.h>
9 : : #include <string.h>
10 : :
11 : : /* ── Result string ───────────────────────────────────────────────────── */
12 : :
13 : 21 : const char *tp_result_str(tp_result result)
14 : : {
15 [ + + + + : 21 : switch (result) {
+ + + + +
+ + + + +
+ + + ]
16 : 2 : case TP_OK:
17 : 2 : return "OK";
18 : 2 : case TP_ERR_EOF:
19 : 2 : return "read past end of stream";
20 : 1 : case TP_ERR_ALLOC:
21 : 1 : return "memory allocation failed";
22 : 2 : case TP_ERR_INVALID_PARAM:
23 : 2 : return "invalid parameter";
24 : 1 : case TP_ERR_INVALID_POSITION:
25 : 1 : return "seek beyond bounds";
26 : 1 : case TP_ERR_NOT_ALIGNED:
27 : 1 : return "not byte-aligned";
28 : 1 : case TP_ERR_OVERFLOW:
29 : 1 : return "varint overflow";
30 : 1 : case TP_ERR_INVALID_UTF8:
31 : 1 : return "invalid UTF-8";
32 : 1 : case TP_ERR_BAD_MAGIC:
33 : 1 : return "bad magic bytes";
34 : 1 : case TP_ERR_VERSION:
35 : 1 : return "unsupported version";
36 : 1 : case TP_ERR_CORRUPT:
37 : 1 : return "data corrupt";
38 : 1 : case TP_ERR_NOT_FOUND:
39 : 1 : return "key not found";
40 : 1 : case TP_ERR_TRUNCATED:
41 : 1 : return "data truncated";
42 : 1 : case TP_ERR_JSON_SYNTAX:
43 : 1 : return "JSON syntax error";
44 : 1 : case TP_ERR_JSON_DEPTH:
45 : 1 : return "JSON nesting too deep";
46 : 1 : case TP_ERR_JSON_TYPE:
47 : 1 : return "JSON type mismatch";
48 : 2 : default:
49 : 2 : return "unknown error";
50 : : }
51 : : }
52 : :
53 : : /* ── Value helpers ───────────────────────────────────────────────────── */
54 : :
55 : 21340 : tp_value tp_value_null(void)
56 : : {
57 : : tp_value v;
58 : 21340 : memset(&v, 0, sizeof(v));
59 : 21340 : v.type = TP_NULL;
60 : 21340 : return v;
61 : : }
62 : :
63 : 24 : tp_value tp_value_bool(bool val)
64 : : {
65 : : tp_value v;
66 : 24 : memset(&v, 0, sizeof(v));
67 : 24 : v.type = TP_BOOL;
68 : 24 : v.data.bool_val = val;
69 : 24 : return v;
70 : : }
71 : :
72 : 556 : tp_value tp_value_int(int64_t val)
73 : : {
74 : : tp_value v;
75 : 556 : memset(&v, 0, sizeof(v));
76 : 556 : v.type = TP_INT;
77 : 556 : v.data.int_val = val;
78 : 556 : return v;
79 : : }
80 : :
81 : 10079 : tp_value tp_value_uint(uint64_t val)
82 : : {
83 : : tp_value v;
84 : 10079 : memset(&v, 0, sizeof(v));
85 : 10079 : v.type = TP_UINT;
86 : 10079 : v.data.uint_val = val;
87 : 10079 : return v;
88 : : }
89 : :
90 : 9 : tp_value tp_value_float32(float val)
91 : : {
92 : : tp_value v;
93 : 9 : memset(&v, 0, sizeof(v));
94 : 9 : v.type = TP_FLOAT32;
95 : 9 : v.data.float32_val = val;
96 : 9 : return v;
97 : : }
98 : :
99 : 20 : tp_value tp_value_float64(double val)
100 : : {
101 : : tp_value v;
102 : 20 : memset(&v, 0, sizeof(v));
103 : 20 : v.type = TP_FLOAT64;
104 : 20 : v.data.float64_val = val;
105 : 20 : return v;
106 : : }
107 : :
108 : 12 : tp_value tp_value_string(const char *str)
109 : : {
110 : : tp_value v;
111 : 12 : memset(&v, 0, sizeof(v));
112 : 12 : v.type = TP_STRING;
113 : 12 : v.data.string_val.str = str;
114 [ + - ]: 12 : v.data.string_val.str_len = str ? strlen(str) : 0;
115 : 12 : return v;
116 : : }
117 : :
118 : 46 : tp_value tp_value_string_n(const char *str, size_t len)
119 : : {
120 : : tp_value v;
121 : 46 : memset(&v, 0, sizeof(v));
122 : 46 : v.type = TP_STRING;
123 : 46 : v.data.string_val.str = str;
124 : 46 : v.data.string_val.str_len = len;
125 : 46 : return v;
126 : : }
127 : :
128 : 9 : tp_value tp_value_blob(const uint8_t *data, size_t len)
129 : : {
130 : : tp_value v;
131 : 9 : memset(&v, 0, sizeof(v));
132 : 9 : v.type = TP_BLOB;
133 : 9 : v.data.blob_val.data = data;
134 : 9 : v.data.blob_val.len = len;
135 : 9 : return v;
136 : : }
137 : :
138 : : /* ── Reader lifecycle ────────────────────────────────────────────────── */
139 : :
140 : : static const size_t DEFAULT_WRITER_CAP = 256;
141 : :
142 : 22875 : tp_result tp_bs_reader_create(tp_bitstream_reader **out, const uint8_t *buf, uint64_t bit_len)
143 : : {
144 [ + + ]: 22875 : if (!out)
145 : 2 : return TP_ERR_INVALID_PARAM;
146 : :
147 : : /* Allocation failure paths are excluded from coverage (LCOV_EXCL). */
148 : 22873 : tp_bitstream_reader *r = calloc(1, sizeof(*r));
149 [ - + ]: 22873 : if (!r)
150 : : return TP_ERR_ALLOC; /* LCOV_EXCL_LINE */
151 : :
152 : 22873 : r->buf = buf;
153 : 22873 : r->bit_len = bit_len;
154 : 22873 : r->pos = 0;
155 : 22873 : r->order = TP_BIT_ORDER_MSB_FIRST;
156 : 22873 : r->owns_buf = false;
157 : 22873 : *out = r;
158 : 22873 : return TP_OK;
159 : : }
160 : :
161 : 6 : tp_result tp_bs_reader_create_copy(tp_bitstream_reader **out, const uint8_t *buf, uint64_t bit_len)
162 : : {
163 [ + + ]: 6 : if (!out)
164 : 2 : return TP_ERR_INVALID_PARAM;
165 : :
166 : 4 : size_t byte_len = (size_t)((bit_len + 7) / 8);
167 : 4 : uint8_t *copy = malloc(byte_len);
168 [ - + - - ]: 4 : if (!copy && byte_len > 0)
169 : : return TP_ERR_ALLOC; /* LCOV_EXCL_LINE */
170 : :
171 [ + + + + ]: 4 : if (buf && byte_len > 0)
172 : 2 : memcpy(copy, buf, byte_len);
173 : :
174 : 4 : tp_bitstream_reader *r = calloc(1, sizeof(*r));
175 [ - + ]: 4 : if (!r) {
176 : : /* LCOV_EXCL_START */
177 : : free(copy);
178 : : return TP_ERR_ALLOC;
179 : : /* LCOV_EXCL_STOP */
180 : : }
181 : :
182 : 4 : r->buf = copy;
183 : 4 : r->bit_len = bit_len;
184 : 4 : r->pos = 0;
185 : 4 : r->order = TP_BIT_ORDER_MSB_FIRST;
186 : 4 : r->owns_buf = true;
187 : 4 : *out = r;
188 : 4 : return TP_OK;
189 : : }
190 : :
191 : 22883 : tp_result tp_bs_reader_destroy(tp_bitstream_reader **reader)
192 : : {
193 [ + + ]: 22883 : if (!reader)
194 : 2 : return TP_ERR_INVALID_PARAM;
195 [ + + ]: 22881 : if (*reader) {
196 [ + + ]: 22877 : if ((*reader)->owns_buf)
197 : 4 : free((void *)(*reader)->buf);
198 : 22877 : free(*reader);
199 : 22877 : *reader = NULL;
200 : : }
201 : 22881 : return TP_OK;
202 : : }
203 : :
204 : 3 : tp_result tp_bs_reader_set_bit_order(tp_bitstream_reader *r, tp_bit_order order)
205 : : {
206 [ + + ]: 3 : if (!r)
207 : 2 : return TP_ERR_INVALID_PARAM;
208 : 1 : r->order = order;
209 : 1 : return TP_OK;
210 : : }
211 : :
212 : : /* ── Writer lifecycle ────────────────────────────────────────────────── */
213 : :
214 : 334 : tp_result tp_bs_writer_create(tp_bitstream_writer **out, size_t initial_cap, size_t growth)
215 : : {
216 [ + + ]: 334 : if (!out)
217 : 2 : return TP_ERR_INVALID_PARAM;
218 : :
219 : 332 : tp_bitstream_writer *w = calloc(1, sizeof(*w));
220 [ - + ]: 332 : if (!w)
221 : : return TP_ERR_ALLOC; /* LCOV_EXCL_LINE */
222 : :
223 [ + + ]: 332 : w->cap = initial_cap > 0 ? initial_cap : DEFAULT_WRITER_CAP;
224 : 332 : w->growth = growth;
225 : 332 : w->pos = 0;
226 : 332 : w->buf = calloc(1, w->cap);
227 [ - + ]: 332 : if (!w->buf) {
228 : : /* LCOV_EXCL_START */
229 : : free(w);
230 : : return TP_ERR_ALLOC;
231 : : /* LCOV_EXCL_STOP */
232 : : }
233 : :
234 : 332 : *out = w;
235 : 332 : return TP_OK;
236 : : }
237 : :
238 : 338 : tp_result tp_bs_writer_destroy(tp_bitstream_writer **writer)
239 : : {
240 [ + + ]: 338 : if (!writer)
241 : 2 : return TP_ERR_INVALID_PARAM;
242 [ + + ]: 336 : if (*writer) {
243 : 332 : free((*writer)->buf);
244 : 332 : free(*writer);
245 : 332 : *writer = NULL;
246 : : }
247 : 336 : return TP_OK;
248 : : }
249 : :
250 : : /* ── Reader cursor ───────────────────────────────────────────────────── */
251 : :
252 : 14 : uint64_t tp_bs_reader_position(const tp_bitstream_reader *r)
253 : : {
254 [ + + ]: 14 : return r ? r->pos : 0;
255 : : }
256 : :
257 : 4 : uint64_t tp_bs_reader_remaining(const tp_bitstream_reader *r)
258 : : {
259 [ + + - + ]: 4 : if (!r || r->pos >= r->bit_len)
260 : 2 : return 0;
261 : 2 : return r->bit_len - r->pos;
262 : : }
263 : :
264 : 4 : uint64_t tp_bs_reader_length(const tp_bitstream_reader *r)
265 : : {
266 [ + + ]: 4 : return r ? r->bit_len : 0;
267 : : }
268 : :
269 : 33335 : tp_result tp_bs_reader_seek(tp_bitstream_reader *r, uint64_t bit_pos)
270 : : {
271 [ + + ]: 33335 : if (!r)
272 : 1 : return TP_ERR_INVALID_PARAM;
273 [ + + ]: 33334 : if (bit_pos > r->bit_len)
274 : 18 : return TP_ERR_INVALID_POSITION;
275 : 33316 : r->pos = bit_pos;
276 : 33316 : return TP_OK;
277 : : }
278 : :
279 : 471848 : tp_result tp_bs_reader_advance(tp_bitstream_reader *r, uint64_t n)
280 : : {
281 [ + + ]: 471848 : if (!r)
282 : 1 : return TP_ERR_INVALID_PARAM;
283 [ + + ]: 471847 : if (r->pos + n > r->bit_len)
284 : 42 : return TP_ERR_EOF;
285 : 471805 : r->pos += n;
286 : 471805 : return TP_OK;
287 : : }
288 : :
289 : 948 : tp_result tp_bs_reader_align_to_byte(tp_bitstream_reader *r)
290 : : {
291 [ + + ]: 948 : if (!r)
292 : 2 : return TP_ERR_INVALID_PARAM;
293 : 946 : uint64_t rem = r->pos % 8;
294 [ + + ]: 946 : if (rem != 0) {
295 : 861 : uint64_t skip = 8 - rem;
296 [ + + ]: 861 : if (r->pos + skip > r->bit_len)
297 : 3 : return TP_ERR_EOF;
298 : 858 : r->pos += skip;
299 : : }
300 : 943 : return TP_OK;
301 : : }
302 : :
303 : 950 : bool tp_bs_reader_is_byte_aligned(const tp_bitstream_reader *r)
304 : : {
305 [ + + + + ]: 950 : return r ? (r->pos % 8 == 0) : false;
306 : : }
307 : :
308 : : /* ── Writer position ─────────────────────────────────────────────────── */
309 : :
310 : 1066 : uint64_t tp_bs_writer_position(const tp_bitstream_writer *w)
311 : : {
312 [ + + ]: 1066 : return w ? w->pos : 0;
313 : : }
314 : :
315 : : /* ── Buffer access ───────────────────────────────────────────────────── */
316 : :
317 : 235 : tp_result tp_bs_writer_get_buffer(const tp_bitstream_writer *w, const uint8_t **buf,
318 : : uint64_t *bit_len)
319 : : {
320 [ + + + + : 235 : if (!w || !buf || !bit_len)
+ + ]
321 : 4 : return TP_ERR_INVALID_PARAM;
322 : 231 : *buf = w->buf;
323 : 231 : *bit_len = w->pos;
324 : 231 : return TP_OK;
325 : : }
326 : :
327 : 214 : tp_result tp_bs_writer_detach_buffer(tp_bitstream_writer *w, uint8_t **buf, size_t *byte_len,
328 : : uint64_t *bit_len)
329 : : {
330 [ + + + + : 214 : if (!w || !buf || !byte_len || !bit_len)
+ + + + ]
331 : 4 : return TP_ERR_INVALID_PARAM;
332 : 210 : *buf = w->buf;
333 : 210 : *byte_len = (size_t)((w->pos + 7) / 8);
334 : 210 : *bit_len = w->pos;
335 : :
336 : : /* Reset writer to empty state */
337 : 210 : w->buf = calloc(1, w->cap);
338 [ - + ]: 210 : if (!w->buf) {
339 : : /* LCOV_EXCL_START */
340 : : w->cap = 0;
341 : : w->pos = 0;
342 : : return TP_ERR_ALLOC;
343 : : /* LCOV_EXCL_STOP */
344 : : }
345 : 210 : w->pos = 0;
346 : 210 : return TP_OK;
347 : : }
348 : :
349 : 11 : tp_result tp_bs_reader_get_buffer(const tp_bitstream_reader *r, const uint8_t **buf,
350 : : uint64_t *bit_len)
351 : : {
352 [ + + + - : 11 : if (!r || !buf || !bit_len)
- + ]
353 : 1 : return TP_ERR_INVALID_PARAM;
354 : 10 : *buf = r->buf;
355 : 10 : *bit_len = r->bit_len;
356 : 10 : return TP_OK;
357 : : }
358 : :
359 : 68 : tp_result tp_bs_writer_to_reader(tp_bitstream_writer *w, tp_bitstream_reader **reader)
360 : : {
361 [ + + + + ]: 68 : if (!w || !reader)
362 : 2 : return TP_ERR_INVALID_PARAM;
363 : 66 : return tp_bs_reader_create(reader, w->buf, w->pos);
364 : : }
|