Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: GPL-3.0-or-later |
2 | | * Copyright © 2022-2026 The TokTok team. |
3 | | */ |
4 | | |
5 | | #include "bin_pack.h" |
6 | | |
7 | | #include <assert.h> |
8 | | #include <string.h> |
9 | | |
10 | | #include "../third_party/cmp/cmp.h" |
11 | | #include "attributes.h" |
12 | | #include "ccompat.h" |
13 | | #include "logger.h" |
14 | | |
15 | | struct Bin_Pack { |
16 | | uint8_t *_Nullable bytes; |
17 | | uint32_t bytes_size; |
18 | | uint32_t bytes_pos; |
19 | | cmp_ctx_t ctx; |
20 | | }; |
21 | | |
22 | | static bool null_reader(cmp_ctx_t *_Nonnull ctx, void *_Nullable data, size_t limit) |
23 | 0 | { |
24 | 0 | assert(limit == 0); |
25 | 0 | return false; |
26 | 0 | } |
27 | | |
28 | | static bool null_skipper(cmp_ctx_t *_Nonnull ctx, size_t count) |
29 | 0 | { |
30 | 0 | assert(count == 0); |
31 | 0 | return false; |
32 | 0 | } |
33 | | |
34 | | static size_t buf_writer(cmp_ctx_t *_Nonnull ctx, const void *_Nullable data, size_t count) |
35 | 5.04M | { |
36 | 5.04M | const uint8_t *const bytes = (const uint8_t *)data; |
37 | | |
38 | 5.04M | if (count == 0) { |
39 | 1 | return 0; |
40 | 1 | } |
41 | | |
42 | 5.04M | if (bytes == nullptr) { |
43 | 0 | return 0; |
44 | 0 | } |
45 | 5.04M | Bin_Pack *const bp = (Bin_Pack *)ctx->buf; |
46 | 5.04M | assert(bp != nullptr); |
47 | 5.04M | const uint32_t new_pos = bp->bytes_pos + count; |
48 | 5.04M | if (new_pos < bp->bytes_pos) { |
49 | | // 32 bit overflow. |
50 | 0 | return 0; |
51 | 0 | } |
52 | 5.04M | if (bp->bytes != nullptr) { |
53 | 2.51M | if (new_pos > bp->bytes_size) { |
54 | | // Buffer too small. |
55 | 1 | return 0; |
56 | 1 | } |
57 | 2.51M | memcpy(&bp->bytes[bp->bytes_pos], bytes, count); |
58 | 2.51M | } |
59 | 5.04M | bp->bytes_pos += count; |
60 | 5.04M | return count; |
61 | 5.04M | } |
62 | | |
63 | | static void bin_pack_init(Bin_Pack *_Nonnull bp, uint8_t *_Nullable buf, uint32_t buf_size) |
64 | 630k | { |
65 | 630k | bp->bytes = buf; |
66 | 630k | bp->bytes_size = buf_size; |
67 | 630k | bp->bytes_pos = 0; |
68 | 630k | cmp_init(&bp->ctx, bp, null_reader, null_skipper, buf_writer); |
69 | 630k | } |
70 | | |
71 | | uint32_t bin_pack_obj_size(bin_pack_cb *callback, const void *obj, const Logger *logger) |
72 | 82.8k | { |
73 | 82.8k | Bin_Pack bp; |
74 | 82.8k | bin_pack_init(&bp, nullptr, 0); |
75 | 82.8k | if (!callback(obj, logger, &bp)) { |
76 | 0 | return UINT32_MAX; |
77 | 0 | } |
78 | 82.8k | return bp.bytes_pos; |
79 | 82.8k | } |
80 | | |
81 | | bool bin_pack_obj(bin_pack_cb *callback, const void *obj, const Logger *logger, uint8_t *buf, uint32_t buf_size) |
82 | 81.2k | { |
83 | 81.2k | Bin_Pack bp; |
84 | 81.2k | bin_pack_init(&bp, buf, buf_size); |
85 | 81.2k | return callback(obj, logger, &bp); |
86 | 81.2k | } |
87 | | |
88 | | uint32_t bin_pack_obj_array_b_size(bin_pack_array_cb *callback, const void *arr, uint32_t arr_size, const Logger *logger) |
89 | 233k | { |
90 | 233k | Bin_Pack bp; |
91 | 233k | bin_pack_init(&bp, nullptr, 0); |
92 | 233k | if (arr == nullptr) { |
93 | 0 | assert(arr_size == 0); |
94 | 0 | } |
95 | 671k | for (uint32_t i = 0; i < arr_size; ++i) { |
96 | 438k | if (!callback(arr, i, logger, &bp)) { |
97 | 188 | return UINT32_MAX; |
98 | 188 | } |
99 | 438k | } |
100 | 232k | return bp.bytes_pos; |
101 | 233k | } |
102 | | |
103 | | bool bin_pack_obj_array_b(bin_pack_array_cb *callback, const void *arr, uint32_t arr_size, const Logger *logger, uint8_t *buf, uint32_t buf_size) |
104 | 233k | { |
105 | 233k | Bin_Pack bp; |
106 | 233k | bin_pack_init(&bp, buf, buf_size); |
107 | 233k | if (arr == nullptr) { |
108 | 0 | assert(arr_size == 0); |
109 | 0 | } |
110 | 671k | for (uint32_t i = 0; i < arr_size; ++i) { |
111 | 438k | if (!callback(arr, i, logger, &bp)) { |
112 | 188 | return false; |
113 | 188 | } |
114 | 438k | } |
115 | 232k | return true; |
116 | 233k | } |
117 | | |
118 | | bool bin_pack_obj_array(Bin_Pack *bp, bin_pack_array_cb *callback, const void *arr, uint32_t arr_size, const Logger *logger) |
119 | 3.17k | { |
120 | 3.17k | if (arr == nullptr) { |
121 | 2.66k | assert(arr_size == 0); |
122 | 2.66k | return bin_pack_array(bp, 0); |
123 | 2.66k | } |
124 | | |
125 | 506 | if (!bin_pack_array(bp, arr_size)) { |
126 | 0 | return false; |
127 | 0 | } |
128 | | |
129 | 2.35k | for (uint32_t i = 0; i < arr_size; ++i) { |
130 | 1.85k | if (!callback(arr, i, logger, bp)) { |
131 | 0 | return false; |
132 | 0 | } |
133 | 1.85k | } |
134 | | |
135 | 506 | return true; |
136 | 506 | } |
137 | | |
138 | | bool bin_pack_array(Bin_Pack *bp, uint32_t size) |
139 | 10.7k | { |
140 | 10.7k | return cmp_write_array(&bp->ctx, size); |
141 | 10.7k | } |
142 | | |
143 | | bool bin_pack_bool(Bin_Pack *bp, bool val) |
144 | 304 | { |
145 | 304 | return cmp_write_bool(&bp->ctx, val); |
146 | 304 | } |
147 | | |
148 | | bool bin_pack_u08(Bin_Pack *bp, uint8_t val) |
149 | 1.04k | { |
150 | 1.04k | return cmp_write_uinteger(&bp->ctx, val); |
151 | 1.04k | } |
152 | | |
153 | | bool bin_pack_u16(Bin_Pack *bp, uint16_t val) |
154 | 2.43k | { |
155 | 2.43k | return cmp_write_uinteger(&bp->ctx, val); |
156 | 2.43k | } |
157 | | |
158 | | bool bin_pack_u32(Bin_Pack *bp, uint32_t val) |
159 | 5.41k | { |
160 | 5.41k | return cmp_write_uinteger(&bp->ctx, val); |
161 | 5.41k | } |
162 | | |
163 | | bool bin_pack_u64(Bin_Pack *bp, uint64_t val) |
164 | 168 | { |
165 | 168 | return cmp_write_uinteger(&bp->ctx, val); |
166 | 168 | } |
167 | | |
168 | | bool bin_pack_bin(Bin_Pack *bp, const uint8_t *data, uint32_t length) |
169 | 4.72k | { |
170 | 4.72k | if (length == 0) { |
171 | 828 | return cmp_write_bin_marker(&bp->ctx, 0); |
172 | 828 | } |
173 | | |
174 | 3.89k | if (data == nullptr) { |
175 | 1 | return false; |
176 | 1 | } |
177 | | |
178 | 3.89k | return cmp_write_bin(&bp->ctx, data, length); |
179 | 3.89k | } |
180 | | |
181 | | bool bin_pack_str(Bin_Pack *bp, const char *data, uint32_t length) |
182 | 249 | { |
183 | 249 | if (length == 0) { |
184 | 5 | return cmp_write_str_marker(&bp->ctx, 0); |
185 | 5 | } |
186 | | |
187 | 244 | if (data == nullptr) { |
188 | 1 | return false; |
189 | 1 | } |
190 | | |
191 | 243 | return cmp_write_str(&bp->ctx, data, length); |
192 | 244 | } |
193 | | |
194 | | bool bin_pack_nil(Bin_Pack *bp) |
195 | 76 | { |
196 | 76 | return cmp_write_nil(&bp->ctx); |
197 | 76 | } |
198 | | |
199 | | bool bin_pack_bin_marker(Bin_Pack *bp, uint32_t size) |
200 | 2 | { |
201 | 2 | return cmp_write_bin_marker(&bp->ctx, size); |
202 | 2 | } |
203 | | |
204 | | bool bin_pack_u08_b(Bin_Pack *bp, uint8_t val) |
205 | 3.10M | { |
206 | 3.10M | return bp->ctx.write(&bp->ctx, &val, 1) == 1; |
207 | 3.10M | } |
208 | | |
209 | | bool bin_pack_u16_b(Bin_Pack *bp, uint16_t val) |
210 | 1.03M | { |
211 | 1.03M | return bin_pack_u08_b(bp, (val >> 8) & 0xff) |
212 | 1.03M | && bin_pack_u08_b(bp, val & 0xff); |
213 | 1.03M | } |
214 | | |
215 | | bool bin_pack_u32_b(Bin_Pack *bp, uint32_t val) |
216 | 6 | { |
217 | 6 | return bin_pack_u16_b(bp, (val >> 16) & 0xffff) |
218 | 6 | && bin_pack_u16_b(bp, val & 0xffff); |
219 | 6 | } |
220 | | |
221 | | bool bin_pack_u64_b(Bin_Pack *bp, uint64_t val) |
222 | 3 | { |
223 | 3 | return bin_pack_u32_b(bp, (val >> 32) & 0xffffffff) |
224 | 3 | && bin_pack_u32_b(bp, val & 0xffffffff); |
225 | 3 | } |
226 | | |
227 | | bool bin_pack_bin_b(Bin_Pack *bp, const uint8_t *data, uint32_t length) |
228 | 1.91M | { |
229 | 1.91M | if (length > 0 && data == nullptr) { |
230 | 1 | return false; |
231 | 1 | } |
232 | | |
233 | 1.91M | return bp->ctx.write(&bp->ctx, data, length) == length; |
234 | 1.91M | } |