Branch data Line data Source code
1 : : /**
2 : : * @file bitstream_read.c
3 : : * @brief Bit-level and byte-level read operations.
4 : : */
5 : :
6 : : #include "bitstream_internal.h"
7 : :
8 : : #include <string.h>
9 : :
10 : : /* ── Internal helpers ────────────────────────────────────────────────── */
11 : :
12 : : /**
13 : : * Read a single bit from buf at the given absolute bit position (MSB-first).
14 : : */
15 : 1015742822 : static inline uint8_t read_bit_msb(const uint8_t *buf, uint64_t bit_pos)
16 : : {
17 : 1015742822 : size_t byte_idx = (size_t)(bit_pos / 8);
18 : 1015742822 : uint8_t bit_idx = (uint8_t)(7 - (bit_pos % 8));
19 : 1015742822 : return (uint8_t)((buf[byte_idx] >> bit_idx) & 1);
20 : : }
21 : :
22 : : /* ── Stateless ROM functions ─────────────────────────────────────────── */
23 : :
24 : 152624334 : tp_result tp_bs_read_bits_at(const uint8_t *buf, uint64_t bit_pos, unsigned int n, uint64_t *out)
25 : : {
26 [ + + + + : 152624334 : if (!buf || !out || n == 0 || n > 64)
+ + + + ]
27 : 9 : return TP_ERR_INVALID_PARAM;
28 : :
29 : 152624325 : uint64_t val = 0;
30 [ + + ]: 1168358734 : for (unsigned int i = 0; i < n; i++) {
31 : 1015734409 : val = (val << 1) | read_bit_msb(buf, bit_pos + i);
32 : : }
33 : 152624325 : *out = val;
34 : 152624325 : return TP_OK;
35 : : }
36 : :
37 : 81 : tp_result tp_bs_read_bits_signed_at(const uint8_t *buf, uint64_t bit_pos, unsigned int n,
38 : : int64_t *out)
39 : : {
40 [ + + + + : 81 : if (!buf || !out || n == 0 || n > 64)
+ + + + ]
41 : 8 : return TP_ERR_INVALID_PARAM;
42 : :
43 : : uint64_t raw;
44 : : /* Allocation failure paths are excluded from coverage (LCOV_EXCL). */
45 : 73 : tp_result rc = tp_bs_read_bits_at(buf, bit_pos, n, &raw);
46 : 73 : if (rc != TP_OK) /* LCOV_EXCL_BR_LINE */
47 : : return rc; /* LCOV_EXCL_LINE */
48 : :
49 : : /* Sign-extend */
50 [ + + + + ]: 73 : if (n < 64 && (raw & ((uint64_t)1 << (n - 1)))) {
51 : 37 : raw |= ~(((uint64_t)1 << n) - 1);
52 : : }
53 : 73 : *out = (int64_t)raw;
54 : 73 : return TP_OK;
55 : : }
56 : :
57 : 9 : tp_result tp_bs_read_varint_u_at(const uint8_t *buf, uint64_t bit_pos, uint64_t *out,
58 : : unsigned int *bits_read)
59 : : {
60 [ + + + + : 9 : if (!buf || !out || !bits_read)
+ + ]
61 : 4 : return TP_ERR_INVALID_PARAM;
62 : :
63 : 5 : uint64_t val = 0;
64 : 5 : unsigned int shift = 0;
65 : 5 : unsigned int total_bits = 0;
66 : :
67 [ + + ]: 17 : for (int group = 0; group < TP_VARINT_MAX_GROUPS; group++) {
68 : : uint64_t byte_val;
69 : 16 : tp_result rc = tp_bs_read_bits_at(buf, bit_pos + total_bits, 8, &byte_val);
70 : 16 : if (rc != TP_OK) /* LCOV_EXCL_BR_LINE */
71 : : return rc; /* LCOV_EXCL_LINE */
72 : 16 : total_bits += 8;
73 : :
74 : 16 : val |= (byte_val & 0x7F) << shift;
75 [ + + ]: 16 : if ((byte_val & 0x80) == 0) {
76 : 4 : *out = val;
77 : 4 : *bits_read = total_bits;
78 : 4 : return TP_OK;
79 : : }
80 : 12 : shift += 7;
81 : : }
82 : :
83 : 1 : return TP_ERR_OVERFLOW;
84 : : }
85 : :
86 : : /* ── Bit-level read ──────────────────────────────────────────────────── */
87 : :
88 : 152027948 : tp_result tp_bs_read_bits(tp_bitstream_reader *r, unsigned int n, uint64_t *out)
89 : : {
90 [ + + + + : 152027948 : if (!r || !out || n == 0 || n > 64)
+ + + + ]
91 : 9 : return TP_ERR_INVALID_PARAM;
92 [ + + ]: 152027939 : if (r->pos + n > r->bit_len)
93 : 147 : return TP_ERR_EOF;
94 : :
95 : : /* Both guards above are exactly what tp_bs_read_bits_at
96 : : validates, so this cannot fail here. */
97 : 152027792 : tp_result rc = tp_bs_read_bits_at(r->buf, r->pos, n, out);
98 : 152027792 : r->pos += n;
99 : 152027792 : return rc;
100 : : }
101 : :
102 : 75 : tp_result tp_bs_read_bits_signed(tp_bitstream_reader *r, unsigned int n, int64_t *out)
103 : : {
104 [ + + + + : 75 : if (!r || !out || n == 0 || n > 64)
+ + + + ]
105 : 6 : return TP_ERR_INVALID_PARAM;
106 [ + + ]: 69 : if (r->pos + n > r->bit_len)
107 : 1 : return TP_ERR_EOF;
108 : :
109 : : /* Both guards above are exactly what tp_bs_read_bits_signed_at
110 : : validates, so this cannot fail here. */
111 : 68 : tp_result rc = tp_bs_read_bits_signed_at(r->buf, r->pos, n, out);
112 : 68 : r->pos += n;
113 : 68 : return rc;
114 : : }
115 : :
116 : 8420 : tp_result tp_bs_read_bit(tp_bitstream_reader *r, uint8_t *out)
117 : : {
118 [ + + + + ]: 8420 : if (!r || !out)
119 : 4 : return TP_ERR_INVALID_PARAM;
120 [ + + ]: 8416 : if (r->pos >= r->bit_len)
121 : 3 : return TP_ERR_EOF;
122 : :
123 : 8413 : *out = read_bit_msb(r->buf, r->pos);
124 : 8413 : r->pos++;
125 : 8413 : return TP_OK;
126 : : }
127 : :
128 : 587536 : tp_result tp_bs_peek_bits(tp_bitstream_reader *r, unsigned int n, uint64_t *out)
129 : : {
130 [ + + + + : 587536 : if (!r || !out || n == 0 || n > 64)
+ + + + ]
131 : 6 : return TP_ERR_INVALID_PARAM;
132 [ + + ]: 587530 : if (r->pos + n > r->bit_len)
133 : 6 : return TP_ERR_EOF;
134 : :
135 : 587524 : return tp_bs_read_bits_at(r->buf, r->pos, n, out);
136 : : }
137 : :
138 : 21 : tp_result tp_bs_read_bits32(tp_bitstream_reader *r, unsigned int n, uint32_t *out)
139 : : {
140 [ + + + + : 21 : if (!r || !out || n == 0 || n > 32)
+ + + + ]
141 : 8 : return TP_ERR_INVALID_PARAM;
142 : :
143 : : uint64_t val;
144 : 13 : tp_result rc = tp_bs_read_bits(r, n, &val);
145 [ + - ]: 13 : if (rc == TP_OK)
146 : 13 : *out = (uint32_t)val;
147 : 13 : return rc;
148 : : }
149 : :
150 : : /* ── Byte-level read ─────────────────────────────────────────────────── */
151 : :
152 : 20952 : tp_result tp_bs_read_u8(tp_bitstream_reader *r, uint8_t *out)
153 : : {
154 : : uint64_t val;
155 : 20952 : tp_result rc = tp_bs_read_bits(r, 8, &val);
156 [ + + ]: 20952 : if (rc == TP_OK)
157 : 20940 : *out = (uint8_t)val;
158 : 20952 : return rc;
159 : : }
160 : :
161 : 3447 : tp_result tp_bs_read_u16(tp_bitstream_reader *r, uint16_t *out)
162 : : {
163 : : uint64_t val;
164 : 3447 : tp_result rc = tp_bs_read_bits(r, 16, &val);
165 [ + + ]: 3447 : if (rc == TP_OK)
166 : 3445 : *out = (uint16_t)val;
167 : 3447 : return rc;
168 : : }
169 : :
170 : 20778 : tp_result tp_bs_read_u32(tp_bitstream_reader *r, uint32_t *out)
171 : : {
172 : : uint64_t val;
173 : 20778 : tp_result rc = tp_bs_read_bits(r, 32, &val);
174 [ + + ]: 20778 : if (rc == TP_OK)
175 : 20757 : *out = (uint32_t)val;
176 : 20778 : return rc;
177 : : }
178 : :
179 : 9827 : tp_result tp_bs_read_u64(tp_bitstream_reader *r, uint64_t *out)
180 : : {
181 : 9827 : return tp_bs_read_bits(r, 64, out);
182 : : }
183 : :
184 : 5 : tp_result tp_bs_read_bytes(tp_bitstream_reader *r, uint8_t *buf, size_t n)
185 : : {
186 [ + + + + ]: 5 : if (!r || !buf)
187 : 3 : return TP_ERR_INVALID_PARAM;
188 : :
189 [ + + ]: 7 : for (size_t i = 0; i < n; i++) {
190 : 6 : tp_result rc = tp_bs_read_u8(r, &buf[i]);
191 [ + + ]: 6 : if (rc != TP_OK)
192 : 1 : return rc;
193 : : }
194 : 1 : return TP_OK;
195 : : }
196 : :
197 : 10455 : tp_result tp_bs_reader_direct_ptr(tp_bitstream_reader *r, const uint8_t **ptr, size_t n)
198 : : {
199 [ + + + + ]: 10455 : if (!r || !ptr)
200 : 3 : return TP_ERR_INVALID_PARAM;
201 [ + + ]: 10452 : if (!tp_bs_reader_is_byte_aligned(r))
202 : 2 : return TP_ERR_NOT_ALIGNED;
203 [ + + ]: 10450 : if (r->pos + (uint64_t)n * 8 > r->bit_len)
204 : 244 : return TP_ERR_EOF;
205 : :
206 : 10206 : *ptr = r->buf + (r->pos / 8);
207 : 10206 : r->pos += (uint64_t)n * 8;
208 : 10206 : return TP_OK;
209 : : }
|