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 : 1005083178 : static inline uint8_t read_bit_msb(const uint8_t *buf, uint64_t bit_pos)
16 : : {
17 : 1005083178 : size_t byte_idx = (size_t)(bit_pos / 8);
18 : 1005083178 : uint8_t bit_idx = (uint8_t)(7 - (bit_pos % 8));
19 : 1005083178 : return (uint8_t)((buf[byte_idx] >> bit_idx) & 1);
20 : : }
21 : :
22 : : /* ── Stateless ROM functions ─────────────────────────────────────────── */
23 : :
24 : 151086009 : tp_result tp_bs_read_bits_at(const uint8_t *buf, uint64_t bit_pos, unsigned int n, uint64_t *out)
25 : : {
26 [ + + + + : 151086009 : if (!buf || !out || n == 0 || n > 64)
+ + + + ]
27 : 5 : return TP_ERR_INVALID_PARAM;
28 : :
29 : 151086004 : uint64_t val = 0;
30 [ + + ]: 1156168799 : for (unsigned int i = 0; i < n; i++) {
31 : 1005082795 : val = (val << 1) | read_bit_msb(buf, bit_pos + i);
32 : : }
33 : 151086004 : *out = val;
34 : 151086004 : return TP_OK;
35 : : }
36 : :
37 : 75 : 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 [ + + + + : 75 : if (!buf || !out || n == 0 || n > 64)
+ + - + ]
41 : 4 : return TP_ERR_INVALID_PARAM;
42 : :
43 : : uint64_t raw;
44 : : /* Allocation failure paths are excluded from coverage (LCOV_EXCL). */
45 : 71 : tp_result rc = tp_bs_read_bits_at(buf, bit_pos, n, &raw);
46 [ - + ]: 71 : if (rc != TP_OK)
47 : : return rc; /* LCOV_EXCL_LINE */
48 : :
49 : : /* Sign-extend */
50 [ + + + + ]: 71 : if (n < 64 && (raw & ((uint64_t)1 << (n - 1)))) {
51 : 36 : raw |= ~(((uint64_t)1 << n) - 1);
52 : : }
53 : 71 : *out = (int64_t)raw;
54 : 71 : 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)
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 : 150614020 : tp_result tp_bs_read_bits(tp_bitstream_reader *r, unsigned int n, uint64_t *out)
89 : : {
90 [ + + + + : 150614020 : if (!r || !out || n == 0 || n > 64)
+ + + + ]
91 : 5 : return TP_ERR_INVALID_PARAM;
92 [ + + ]: 150614015 : if (r->pos + n > r->bit_len)
93 : 64 : return TP_ERR_EOF;
94 : :
95 : 150613951 : tp_result rc = tp_bs_read_bits_at(r->buf, r->pos, n, out);
96 [ + - ]: 150613951 : if (rc == TP_OK)
97 : 150613951 : r->pos += n;
98 : 150613951 : return rc;
99 : : }
100 : :
101 : 71 : tp_result tp_bs_read_bits_signed(tp_bitstream_reader *r, unsigned int n, int64_t *out)
102 : : {
103 [ + + + - : 71 : if (!r || !out || n == 0 || n > 64)
+ - - + ]
104 : 2 : return TP_ERR_INVALID_PARAM;
105 [ + + ]: 69 : if (r->pos + n > r->bit_len)
106 : 1 : return TP_ERR_EOF;
107 : :
108 : 68 : tp_result rc = tp_bs_read_bits_signed_at(r->buf, r->pos, n, out);
109 [ + - ]: 68 : if (rc == TP_OK)
110 : 68 : r->pos += n;
111 : 68 : return rc;
112 : : }
113 : :
114 : 388 : tp_result tp_bs_read_bit(tp_bitstream_reader *r, uint8_t *out)
115 : : {
116 [ + + - + ]: 388 : if (!r || !out)
117 : 2 : return TP_ERR_INVALID_PARAM;
118 [ + + ]: 386 : if (r->pos >= r->bit_len)
119 : 3 : return TP_ERR_EOF;
120 : :
121 : 383 : *out = read_bit_msb(r->buf, r->pos);
122 : 383 : r->pos++;
123 : 383 : return TP_OK;
124 : : }
125 : :
126 : 471961 : tp_result tp_bs_peek_bits(tp_bitstream_reader *r, unsigned int n, uint64_t *out)
127 : : {
128 [ + + + - : 471961 : if (!r || !out || n == 0 || n > 64)
+ - - + ]
129 : 2 : return TP_ERR_INVALID_PARAM;
130 [ + + ]: 471959 : if (r->pos + n > r->bit_len)
131 : 5 : return TP_ERR_EOF;
132 : :
133 : 471954 : return tp_bs_read_bits_at(r->buf, r->pos, n, out);
134 : : }
135 : :
136 : 16 : tp_result tp_bs_read_bits32(tp_bitstream_reader *r, unsigned int n, uint32_t *out)
137 : : {
138 [ + + + - : 16 : if (!r || !out || n == 0 || n > 32)
+ + + + ]
139 : 4 : return TP_ERR_INVALID_PARAM;
140 : :
141 : : uint64_t val;
142 : 12 : tp_result rc = tp_bs_read_bits(r, n, &val);
143 [ + - ]: 12 : if (rc == TP_OK)
144 : 12 : *out = (uint32_t)val;
145 : 12 : return rc;
146 : : }
147 : :
148 : : /* ── Byte-level read ─────────────────────────────────────────────────── */
149 : :
150 : 3996 : tp_result tp_bs_read_u8(tp_bitstream_reader *r, uint8_t *out)
151 : : {
152 : : uint64_t val;
153 : 3996 : tp_result rc = tp_bs_read_bits(r, 8, &val);
154 [ + + ]: 3996 : if (rc == TP_OK)
155 : 3984 : *out = (uint8_t)val;
156 : 3996 : return rc;
157 : : }
158 : :
159 : 634 : tp_result tp_bs_read_u16(tp_bitstream_reader *r, uint16_t *out)
160 : : {
161 : : uint64_t val;
162 : 634 : tp_result rc = tp_bs_read_bits(r, 16, &val);
163 [ + + ]: 634 : if (rc == TP_OK)
164 : 632 : *out = (uint16_t)val;
165 : 634 : return rc;
166 : : }
167 : :
168 : 3780 : tp_result tp_bs_read_u32(tp_bitstream_reader *r, uint32_t *out)
169 : : {
170 : : uint64_t val;
171 : 3780 : tp_result rc = tp_bs_read_bits(r, 32, &val);
172 [ + + ]: 3780 : if (rc == TP_OK)
173 : 3771 : *out = (uint32_t)val;
174 : 3780 : return rc;
175 : : }
176 : :
177 : 57 : tp_result tp_bs_read_u64(tp_bitstream_reader *r, uint64_t *out)
178 : : {
179 : 57 : return tp_bs_read_bits(r, 64, out);
180 : : }
181 : :
182 : 5 : tp_result tp_bs_read_bytes(tp_bitstream_reader *r, uint8_t *buf, size_t n)
183 : : {
184 [ + + + + ]: 5 : if (!r || !buf)
185 : 3 : return TP_ERR_INVALID_PARAM;
186 : :
187 [ + + ]: 7 : for (size_t i = 0; i < n; i++) {
188 : 6 : tp_result rc = tp_bs_read_u8(r, &buf[i]);
189 [ + + ]: 6 : if (rc != TP_OK)
190 : 1 : return rc;
191 : : }
192 : 1 : return TP_OK;
193 : : }
194 : :
195 : 946 : tp_result tp_bs_reader_direct_ptr(tp_bitstream_reader *r, const uint8_t **ptr, size_t n)
196 : : {
197 [ + + - + ]: 946 : if (!r || !ptr)
198 : 1 : return TP_ERR_INVALID_PARAM;
199 [ + + ]: 945 : if (!tp_bs_reader_is_byte_aligned(r))
200 : 2 : return TP_ERR_NOT_ALIGNED;
201 [ + + ]: 943 : if (r->pos + (uint64_t)n * 8 > r->bit_len)
202 : 18 : return TP_ERR_EOF;
203 : :
204 : 925 : *ptr = r->buf + (r->pos / 8);
205 : 925 : r->pos += (uint64_t)n * 8;
206 : 925 : return TP_OK;
207 : : }
|