Branch data Line data Source code
1 : : /**
2 : : * @file bitstream_symbol.c
3 : : * @brief Fixed-width symbol and UTF-8 codepoint read/write.
4 : : */
5 : :
6 : : #include "bitstream_internal.h"
7 : :
8 : : /* ── Symbol ──────────────────────────────────────────────────────────── */
9 : :
10 : 42 : tp_result tp_bs_read_symbol(tp_bitstream_reader *r, unsigned int bps, uint32_t *out)
11 : : {
12 [ + + + + : 42 : if (!r || !out || bps == 0 || bps > 32)
+ + + + ]
13 : 4 : return TP_ERR_INVALID_PARAM;
14 : :
15 : : uint64_t val;
16 : 38 : tp_result rc = tp_bs_read_bits(r, bps, &val);
17 [ + - ]: 38 : if (rc == TP_OK)
18 : 38 : *out = (uint32_t)val;
19 : 38 : return rc;
20 : : }
21 : :
22 : 41 : tp_result tp_bs_write_symbol(tp_bitstream_writer *w, uint32_t val, unsigned int bps)
23 : : {
24 [ + + + + : 41 : if (!w || bps == 0 || bps > 32)
+ + ]
25 : 3 : return TP_ERR_INVALID_PARAM;
26 : 38 : return tp_bs_write_bits(w, val, bps);
27 : : }
28 : :
29 : : /* ── UTF-8 ───────────────────────────────────────────────────────────── */
30 : :
31 : 29 : tp_result tp_bs_read_utf8(tp_bitstream_reader *r, uint32_t *out)
32 : : {
33 [ + + + + ]: 29 : if (!r || !out)
34 : 2 : return TP_ERR_INVALID_PARAM;
35 : :
36 : : uint8_t first;
37 : 27 : tp_result rc = tp_bs_read_u8(r, &first);
38 [ + + ]: 27 : if (rc != TP_OK)
39 : 1 : return rc;
40 : :
41 : : uint32_t cp;
42 : : uint8_t cont;
43 : :
44 [ + + ]: 26 : if ((first & 0x80) == 0) {
45 : 3 : *out = first;
46 : 3 : return TP_OK;
47 [ + + ]: 23 : } else if ((first & 0xE0) == 0xC0) {
48 : 6 : cp = first & 0x1F;
49 : 6 : cont = 1;
50 [ + + ]: 17 : } else if ((first & 0xF0) == 0xE0) {
51 : 8 : cp = first & 0x0F;
52 : 8 : cont = 2;
53 [ + + ]: 9 : } else if ((first & 0xF8) == 0xF0) {
54 : 6 : cp = first & 0x07;
55 : 6 : cont = 3;
56 : : } else {
57 : 3 : return TP_ERR_INVALID_UTF8;
58 : : }
59 : :
60 [ + + ]: 54 : for (uint8_t i = 0; i < cont; i++) {
61 : : uint8_t b;
62 : 40 : rc = tp_bs_read_u8(r, &b);
63 [ + + ]: 40 : if (rc != TP_OK)
64 : 6 : return rc;
65 [ + + ]: 37 : if ((b & 0xC0) != 0x80)
66 : 3 : return TP_ERR_INVALID_UTF8;
67 : 34 : cp = (cp << 6) | (b & 0x3F);
68 : : }
69 : :
70 : : /* Reject overlong encodings */
71 [ + + + + ]: 14 : if (cont == 1 && cp < 0x80)
72 : 1 : return TP_ERR_INVALID_UTF8;
73 [ + + + + ]: 13 : if (cont == 2 && cp < 0x800)
74 : 1 : return TP_ERR_INVALID_UTF8;
75 [ + + + + ]: 12 : if (cont == 3 && cp < 0x10000)
76 : 1 : return TP_ERR_INVALID_UTF8;
77 : :
78 : : /* Reject surrogates U+D800..U+DFFF */
79 [ + + + + ]: 11 : if (cp >= 0xD800 && cp <= 0xDFFF)
80 : 2 : return TP_ERR_INVALID_UTF8;
81 : :
82 : 9 : *out = cp;
83 : 9 : return TP_OK;
84 : : }
85 : :
86 : 22 : tp_result tp_bs_write_utf8(tp_bitstream_writer *w, uint32_t cp)
87 : : {
88 [ + + ]: 22 : if (!w)
89 : 1 : return TP_ERR_INVALID_PARAM;
90 : :
91 : : /* Reject surrogates U+D800..U+DFFF */
92 [ + + + + ]: 21 : if (cp >= 0xD800 && cp <= 0xDFFF)
93 : 6 : return TP_ERR_INVALID_UTF8;
94 : :
95 : : /* Allocation failure paths are excluded from coverage (LCOV_EXCL). */
96 [ + + ]: 15 : if (cp <= 0x7F) {
97 : 3 : return tp_bs_write_u8(w, (uint8_t)cp);
98 [ + + ]: 12 : } else if (cp <= 0x7FF) {
99 : 3 : tp_result rc = tp_bs_write_u8(w, (uint8_t)(0xC0 | (cp >> 6)));
100 [ - + ]: 3 : if (rc != TP_OK)
101 : : return rc; /* LCOV_EXCL_LINE */
102 : 3 : return tp_bs_write_u8(w, (uint8_t)(0x80 | (cp & 0x3F)));
103 [ + + ]: 9 : } else if (cp <= 0xFFFF) {
104 : 3 : tp_result rc = tp_bs_write_u8(w, (uint8_t)(0xE0 | (cp >> 12)));
105 [ - + ]: 3 : if (rc != TP_OK)
106 : : return rc; /* LCOV_EXCL_LINE */
107 : 3 : rc = tp_bs_write_u8(w, (uint8_t)(0x80 | ((cp >> 6) & 0x3F)));
108 [ - + ]: 3 : if (rc != TP_OK)
109 : : return rc; /* LCOV_EXCL_LINE */
110 : 3 : return tp_bs_write_u8(w, (uint8_t)(0x80 | (cp & 0x3F)));
111 [ + + ]: 6 : } else if (cp <= 0x10FFFF) {
112 : 3 : tp_result rc = tp_bs_write_u8(w, (uint8_t)(0xF0 | (cp >> 18)));
113 [ - + ]: 3 : if (rc != TP_OK)
114 : : return rc; /* LCOV_EXCL_LINE */
115 : 3 : rc = tp_bs_write_u8(w, (uint8_t)(0x80 | ((cp >> 12) & 0x3F)));
116 [ - + ]: 3 : if (rc != TP_OK)
117 : : return rc; /* LCOV_EXCL_LINE */
118 : 3 : rc = tp_bs_write_u8(w, (uint8_t)(0x80 | ((cp >> 6) & 0x3F)));
119 [ - + ]: 3 : if (rc != TP_OK)
120 : : return rc; /* LCOV_EXCL_LINE */
121 : 3 : return tp_bs_write_u8(w, (uint8_t)(0x80 | (cp & 0x3F)));
122 : : }
123 : :
124 : 3 : return TP_ERR_INVALID_UTF8;
125 : : }
|