/work/toxcore/bin_unpack.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* SPDX-License-Identifier: GPL-3.0-or-later |
2 | | * Copyright © 2022-2025 The TokTok team. |
3 | | */ |
4 | | |
5 | | #include "bin_unpack.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 "mem.h" |
14 | | |
15 | | struct Bin_Unpack { |
16 | | const Memory *mem; |
17 | | |
18 | | const uint8_t *bytes; |
19 | | uint32_t bytes_size; |
20 | | cmp_ctx_t ctx; |
21 | | }; |
22 | | |
23 | | static bool buf_reader(cmp_ctx_t *_Nonnull ctx, void *_Nonnull data, size_t limit) |
24 | 219k | { |
25 | 219k | uint8_t *bytes = (uint8_t *)data; |
26 | 219k | Bin_Unpack *reader = (Bin_Unpack *)ctx->buf; |
27 | 219k | assert(reader != nullptr && reader->bytes != nullptr); |
28 | 219k | if (limit > reader->bytes_size) { |
29 | 4.54k | return false; |
30 | 4.54k | } |
31 | 215k | memcpy(bytes, reader->bytes, limit); |
32 | 215k | reader->bytes += limit; |
33 | 215k | reader->bytes_size -= limit; |
34 | 215k | return true; |
35 | 219k | } |
36 | | |
37 | | static bool buf_skipper(cmp_ctx_t *_Nonnull ctx, size_t count) |
38 | 0 | { |
39 | 0 | Bin_Unpack *reader = (Bin_Unpack *)ctx->buf; |
40 | 0 | assert(reader != nullptr && reader->bytes != nullptr); |
41 | 0 | if (count > reader->bytes_size) { |
42 | 0 | return false; |
43 | 0 | } |
44 | 0 | reader->bytes += count; |
45 | 0 | reader->bytes_size -= count; |
46 | 0 | return true; |
47 | 0 | } |
48 | | |
49 | | static size_t null_writer(cmp_ctx_t *_Nonnull ctx, const void *_Nonnull data, size_t count) |
50 | 0 | { |
51 | 0 | assert(count == 0); |
52 | 0 | return 0; |
53 | 0 | } |
54 | | |
55 | | static void bin_unpack_init(Bin_Unpack *_Nonnull bu, const Memory *_Nonnull mem, const uint8_t *_Nonnull buf, uint32_t buf_size) |
56 | 22.3k | { |
57 | 22.3k | bu->mem = mem; |
58 | 22.3k | bu->bytes = buf; |
59 | 22.3k | bu->bytes_size = buf_size; |
60 | 22.3k | cmp_init(&bu->ctx, bu, buf_reader, buf_skipper, null_writer); |
61 | 22.3k | } |
62 | | |
63 | | bool bin_unpack_obj(const Memory *mem, bin_unpack_cb *callback, void *obj, const uint8_t *buf, uint32_t buf_size) |
64 | 22.3k | { |
65 | 22.3k | Bin_Unpack bu; |
66 | 22.3k | bin_unpack_init(&bu, mem, buf, buf_size); |
67 | 22.3k | return callback(obj, &bu); |
68 | 22.3k | } |
69 | | |
70 | | bool bin_unpack_array(Bin_Unpack *bu, uint32_t *size) |
71 | 22.3k | { |
72 | 22.3k | return cmp_read_array(&bu->ctx, size) && *size <= bu->bytes_size; |
73 | 22.3k | } |
74 | | |
75 | | bool bin_unpack_array_fixed(Bin_Unpack *bu, uint32_t required_size, uint32_t *actual_size) |
76 | 48.5k | { |
77 | 48.5k | uint32_t size = 0; |
78 | 48.5k | const bool success = cmp_read_array(&bu->ctx, &size) && size == required_size; |
79 | 48.5k | if (actual_size != nullptr) { |
80 | 21.4k | *actual_size = size; |
81 | 21.4k | } |
82 | 48.5k | return success; |
83 | 48.5k | } |
84 | | |
85 | | bool bin_unpack_bool(Bin_Unpack *bu, bool *val) |
86 | 17.3k | { |
87 | 17.3k | return cmp_read_bool(&bu->ctx, val); |
88 | 17.3k | } |
89 | | |
90 | | bool bin_unpack_u08(Bin_Unpack *bu, uint8_t *val) |
91 | 19.3k | { |
92 | 19.3k | return cmp_read_uchar(&bu->ctx, val); |
93 | 19.3k | } |
94 | | |
95 | | bool bin_unpack_u16(Bin_Unpack *bu, uint16_t *val) |
96 | 39.0k | { |
97 | 39.0k | return cmp_read_ushort(&bu->ctx, val); |
98 | 39.0k | } |
99 | | |
100 | | bool bin_unpack_u32(Bin_Unpack *bu, uint32_t *val) |
101 | 23.6k | { |
102 | 23.6k | return cmp_read_uint(&bu->ctx, val); |
103 | 23.6k | } |
104 | | |
105 | | bool bin_unpack_u64(Bin_Unpack *bu, uint64_t *val) |
106 | 273 | { |
107 | 273 | return cmp_read_ulong(&bu->ctx, val); |
108 | 273 | } |
109 | | |
110 | | bool bin_unpack_nil(Bin_Unpack *bu) |
111 | 90 | { |
112 | 90 | return cmp_read_nil(&bu->ctx); |
113 | 90 | } |
114 | | |
115 | | bool bin_unpack_bin(Bin_Unpack *bu, uint8_t **data_ptr, uint32_t *data_length_ptr) |
116 | 606 | { |
117 | 606 | uint32_t bin_size; |
118 | 606 | if (!bin_unpack_bin_size(bu, &bin_size) || bin_size > bu->bytes_size) { |
119 | | // There aren't as many bytes as this bin claims to want to allocate. |
120 | 60 | return false; |
121 | 60 | } |
122 | 546 | uint8_t *const data = (uint8_t *)mem_balloc(bu->mem, bin_size); |
123 | | |
124 | 546 | if (data == nullptr) { |
125 | 1 | return false; |
126 | 1 | } |
127 | | |
128 | 545 | if (!bin_unpack_bin_b(bu, data, bin_size)) { |
129 | 0 | mem_delete(bu->mem, data); |
130 | 0 | return false; |
131 | 0 | } |
132 | | |
133 | 545 | *data_ptr = data; |
134 | 545 | *data_length_ptr = bin_size; |
135 | 545 | return true; |
136 | 545 | } |
137 | | |
138 | | bool bin_unpack_bin_max(Bin_Unpack *bu, uint8_t *data, uint16_t *data_length_ptr, uint16_t max_data_length) |
139 | 1.25k | { |
140 | 1.25k | uint32_t bin_size; |
141 | 1.25k | if (!bin_unpack_bin_size(bu, &bin_size) || bin_size > max_data_length) { |
142 | 80 | return false; |
143 | 80 | } |
144 | | |
145 | 1.17k | *data_length_ptr = bin_size; |
146 | | |
147 | 1.17k | return bin_unpack_bin_b(bu, data, bin_size); |
148 | 1.25k | } |
149 | | |
150 | | bool bin_unpack_bin_fixed(Bin_Unpack *bu, uint8_t *data, uint32_t data_length) |
151 | 3.75k | { |
152 | 3.75k | uint32_t bin_size; |
153 | 3.75k | if (!bin_unpack_bin_size(bu, &bin_size) || bin_size != data_length) { |
154 | 322 | return false; |
155 | 322 | } |
156 | | |
157 | 3.43k | return bin_unpack_bin_b(bu, data, bin_size); |
158 | 3.75k | } |
159 | | |
160 | | bool bin_unpack_bin_size(Bin_Unpack *bu, uint32_t *size) |
161 | 5.61k | { |
162 | 5.61k | return cmp_read_bin_size(&bu->ctx, size); |
163 | 5.61k | } |
164 | | |
165 | | bool bin_unpack_u08_b(Bin_Unpack *bu, uint8_t *val) |
166 | 18 | { |
167 | 18 | return bin_unpack_bin_b(bu, val, 1); |
168 | 18 | } |
169 | | |
170 | | bool bin_unpack_u16_b(Bin_Unpack *bu, uint16_t *val) |
171 | 9 | { |
172 | 9 | uint8_t hi = 0; |
173 | 9 | uint8_t lo = 0; |
174 | 9 | if (!(bin_unpack_u08_b(bu, &hi) |
175 | 9 | && bin_unpack_u08_b(bu, &lo))) { |
176 | 0 | return false; |
177 | 0 | } |
178 | 9 | *val = ((uint16_t)hi << 8) | lo; |
179 | 9 | return true; |
180 | 9 | } |
181 | | |
182 | | bool bin_unpack_u32_b(Bin_Unpack *bu, uint32_t *val) |
183 | 4 | { |
184 | 4 | uint16_t hi = 0; |
185 | 4 | uint16_t lo = 0; |
186 | 4 | if (!(bin_unpack_u16_b(bu, &hi) |
187 | 4 | && bin_unpack_u16_b(bu, &lo))) { |
188 | 0 | return false; |
189 | 0 | } |
190 | 4 | *val = ((uint32_t)hi << 16) | lo; |
191 | 4 | return true; |
192 | 4 | } |
193 | | |
194 | | bool bin_unpack_u64_b(Bin_Unpack *bu, uint64_t *val) |
195 | 2 | { |
196 | 2 | uint32_t hi = 0; |
197 | 2 | uint32_t lo = 0; |
198 | 2 | if (!(bin_unpack_u32_b(bu, &hi) |
199 | 2 | && bin_unpack_u32_b(bu, &lo))) { |
200 | 0 | return false; |
201 | 0 | } |
202 | 2 | *val = ((uint64_t)hi << 32) | lo; |
203 | 2 | return true; |
204 | 2 | } |
205 | | |
206 | | bool bin_unpack_bin_b(Bin_Unpack *bu, uint8_t *data, uint32_t length) |
207 | 5.16k | { |
208 | 5.16k | return bu->ctx.read(&bu->ctx, data, length); |
209 | 5.16k | } |