Branch data Line data Source code
1 : : /**
2 : : * @file bitstream_write.c
3 : : * @brief Bit-level and byte-level write operations, buffer append, bulk copy.
4 : : */
5 : :
6 : : #include "bitstream_internal.h"
7 : :
8 : : #include <stdlib.h>
9 : : #include <string.h>
10 : :
11 : : /* ── Internal helpers ────────────────────────────────────────────────── */
12 : :
13 : 191193 : static tp_result ensure_capacity(tp_bitstream_writer *w, uint64_t n_bits)
14 : : {
15 : 191193 : size_t needed_bytes = (size_t)((w->pos + n_bits + 7) / 8);
16 [ + + ]: 191193 : if (needed_bytes <= w->cap)
17 : 191127 : return TP_OK;
18 : :
19 : : size_t new_cap;
20 [ + + ]: 66 : if (w->growth > 0) {
21 : 43 : new_cap = w->cap + w->growth;
22 : : } else {
23 : 23 : new_cap = w->cap * 2;
24 : : }
25 [ + + ]: 72 : while (new_cap < needed_bytes)
26 [ + - ]: 6 : new_cap = w->growth > 0 ? new_cap + w->growth : new_cap * 2;
27 : :
28 : : /* Allocation failure paths are excluded from coverage (LCOV_EXCL). */
29 : 66 : uint8_t *new_buf = realloc(w->buf, new_cap);
30 [ - + ]: 66 : if (!new_buf)
31 : : return TP_ERR_ALLOC; /* LCOV_EXCL_LINE */
32 : :
33 : 66 : memset(new_buf + w->cap, 0, new_cap - w->cap);
34 : 66 : w->buf = new_buf;
35 : 66 : w->cap = new_cap;
36 : 66 : return TP_OK;
37 : : }
38 : :
39 : 1204957 : static inline void write_bit_msb(uint8_t *buf, uint64_t bit_pos, uint8_t val)
40 : : {
41 : 1204957 : size_t byte_idx = (size_t)(bit_pos / 8);
42 : 1204957 : uint8_t bit_idx = (uint8_t)(7 - (bit_pos % 8));
43 [ + + ]: 1204957 : if (val)
44 : 456582 : buf[byte_idx] = (uint8_t)(buf[byte_idx] | (1u << bit_idx));
45 : : else
46 : 748375 : buf[byte_idx] = (uint8_t)(buf[byte_idx] & ~(1u << bit_idx));
47 : 1204957 : }
48 : :
49 : : /* ── Bit-level write ─────────────────────────────────────────────────── */
50 : :
51 : 191023 : tp_result tp_bs_write_bits(tp_bitstream_writer *w, uint64_t value, unsigned int n)
52 : : {
53 [ + + + + : 191023 : if (!w || n == 0 || n > 64)
+ + ]
54 : 14 : return TP_ERR_INVALID_PARAM;
55 : :
56 : 191009 : tp_result rc = ensure_capacity(w, n);
57 [ - + ]: 191009 : if (rc != TP_OK)
58 : : return rc; /* LCOV_EXCL_LINE */
59 : :
60 [ + + ]: 1395907 : for (unsigned int i = 0; i < n; i++) {
61 : 1204898 : uint8_t bit = (uint8_t)((value >> (n - 1 - i)) & 1);
62 : 1204898 : write_bit_msb(w->buf, w->pos, bit);
63 : 1204898 : w->pos++;
64 : : }
65 : 191009 : return TP_OK;
66 : : }
67 : :
68 : 71 : tp_result tp_bs_write_bits_signed(tp_bitstream_writer *w, int64_t value, unsigned int n)
69 : : {
70 [ + + + + : 71 : if (!w || n == 0 || n > 64)
+ + ]
71 : 6 : return TP_ERR_INVALID_PARAM;
72 : :
73 : : /* Mask to n bits -- this truncates the sign extension so only the
74 : : * low n bits are written, exactly as they would appear in a two's
75 : : * complement representation. On read-back, tp_bs_read_bits_signed()
76 : : * will re-extend the MSB. */
77 : 65 : uint64_t raw = (uint64_t)value;
78 [ + + ]: 65 : if (n < 64)
79 : 61 : raw &= ((uint64_t)1 << n) - 1;
80 : :
81 : 65 : return tp_bs_write_bits(w, raw, n);
82 : : }
83 : :
84 : 29 : tp_result tp_bs_write_bit(tp_bitstream_writer *w, uint8_t value)
85 : : {
86 [ + + ]: 29 : if (!w)
87 : 2 : return TP_ERR_INVALID_PARAM;
88 : :
89 : 27 : tp_result rc = ensure_capacity(w, 1);
90 [ - + ]: 27 : if (rc != TP_OK)
91 : : return rc; /* LCOV_EXCL_LINE */
92 : :
93 : 27 : write_bit_msb(w->buf, w->pos, value & 1);
94 : 27 : w->pos++;
95 : 27 : return TP_OK;
96 : : }
97 : :
98 : 281 : tp_result tp_bs_writer_align_to_byte(tp_bitstream_writer *w)
99 : : {
100 [ + + ]: 281 : if (!w)
101 : 2 : return TP_ERR_INVALID_PARAM;
102 : 279 : uint64_t rem = w->pos % 8;
103 [ + + ]: 279 : if (rem != 0) {
104 : 154 : uint8_t pad = (uint8_t)(8 - rem);
105 : 154 : tp_result rc = ensure_capacity(w, pad);
106 [ - + ]: 154 : if (rc != TP_OK)
107 : : return rc; /* LCOV_EXCL_LINE */
108 : : /* Zero bits are already there from calloc/memset */
109 : 154 : w->pos += pad;
110 : : }
111 : 279 : return TP_OK;
112 : : }
113 : :
114 : : /* ── Byte-level write ────────────────────────────────────────────────── */
115 : :
116 : 1890 : tp_result tp_bs_write_u8(tp_bitstream_writer *w, uint8_t val)
117 : : {
118 : 1890 : return tp_bs_write_bits(w, val, 8);
119 : : }
120 : :
121 : 216 : tp_result tp_bs_write_u16(tp_bitstream_writer *w, uint16_t val)
122 : : {
123 : 216 : return tp_bs_write_bits(w, val, 16);
124 : : }
125 : :
126 : 1476 : tp_result tp_bs_write_u32(tp_bitstream_writer *w, uint32_t val)
127 : : {
128 : 1476 : return tp_bs_write_bits(w, val, 32);
129 : : }
130 : :
131 : 25 : tp_result tp_bs_write_u64(tp_bitstream_writer *w, uint64_t val)
132 : : {
133 : 25 : return tp_bs_write_bits(w, val, 64);
134 : : }
135 : :
136 : 75 : tp_result tp_bs_write_bytes(tp_bitstream_writer *w, const uint8_t *buf, size_t n)
137 : : {
138 [ + + + + : 75 : if (!w || (!buf && n > 0))
+ + ]
139 : 4 : return TP_ERR_INVALID_PARAM;
140 : :
141 [ + + ]: 457 : for (size_t i = 0; i < n; i++) {
142 : 386 : tp_result rc = tp_bs_write_u8(w, buf[i]);
143 [ - + ]: 386 : if (rc != TP_OK)
144 : : return rc; /* LCOV_EXCL_LINE */
145 : : }
146 : 71 : return TP_OK;
147 : : }
148 : :
149 : : /* ── Buffer append ───────────────────────────────────────────────────── */
150 : :
151 : 4 : tp_result tp_bs_writer_append_buffer(tp_bitstream_writer *w, const uint8_t *buf, uint64_t bit_len)
152 : : {
153 [ + + + + : 4 : if (!w || (!buf && bit_len > 0))
+ - ]
154 : 2 : return TP_ERR_INVALID_PARAM;
155 : :
156 : 2 : tp_result rc = ensure_capacity(w, bit_len);
157 [ - + ]: 2 : if (rc != TP_OK)
158 : : return rc; /* LCOV_EXCL_LINE */
159 : :
160 [ + + ]: 22 : for (uint64_t i = 0; i < bit_len; i++) {
161 : 20 : size_t byte_idx = (size_t)(i / 8);
162 : 20 : uint8_t bit_idx = (uint8_t)(7 - (i % 8));
163 : 20 : uint8_t bit = (uint8_t)((buf[byte_idx] >> bit_idx) & 1);
164 : 20 : write_bit_msb(w->buf, w->pos, bit);
165 : 20 : w->pos++;
166 : : }
167 : 2 : return TP_OK;
168 : : }
169 : :
170 : : /* ── Bulk copy ───────────────────────────────────────────────────────── */
171 : :
172 : 3 : tp_result tp_bs_copy_bits(tp_bitstream_reader *r, tp_bitstream_writer *w, uint64_t n_bits)
173 : : {
174 [ + + - + ]: 3 : if (!r || !w)
175 : 1 : return TP_ERR_INVALID_PARAM;
176 [ + + ]: 2 : if (r->pos + n_bits > r->bit_len)
177 : 1 : return TP_ERR_EOF;
178 : :
179 : 1 : tp_result rc = ensure_capacity(w, n_bits);
180 [ - + ]: 1 : if (rc != TP_OK)
181 : : return rc; /* LCOV_EXCL_LINE */
182 : :
183 [ + + ]: 13 : for (uint64_t i = 0; i < n_bits; i++) {
184 : 12 : size_t byte_idx = (size_t)(r->pos / 8);
185 : 12 : uint8_t bit_idx = (uint8_t)(7 - (r->pos % 8));
186 : 12 : uint8_t bit = (uint8_t)((r->buf[byte_idx] >> bit_idx) & 1);
187 : 12 : write_bit_msb(w->buf, w->pos, bit);
188 : 12 : r->pos++;
189 : 12 : w->pos++;
190 : : }
191 : 1 : return TP_OK;
192 : : }
|