/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 The TokTok team. |
3 | | */ |
4 | | |
5 | | #include "bin_unpack.h" |
6 | | |
7 | | #include <assert.h> |
8 | | #include <stdlib.h> |
9 | | #include <string.h> |
10 | | |
11 | | #include "../third_party/cmp/cmp.h" |
12 | | #include "ccompat.h" |
13 | | |
14 | | struct Bin_Unpack { |
15 | | const uint8_t *bytes; |
16 | | uint32_t bytes_size; |
17 | | cmp_ctx_t ctx; |
18 | | }; |
19 | | |
20 | | non_null() |
21 | | static bool buf_reader(cmp_ctx_t *ctx, void *data, size_t limit) |
22 | 162k | { |
23 | 162k | Bin_Unpack *reader = (Bin_Unpack *)ctx->buf; |
24 | 162k | assert(reader != nullptr && reader->bytes != nullptr); |
25 | 162k | if (limit > reader->bytes_size) { |
26 | 5.62k | return false; |
27 | 5.62k | } |
28 | 156k | memcpy(data, reader->bytes, limit); |
29 | 156k | reader->bytes += limit; |
30 | 156k | reader->bytes_size -= limit; |
31 | 156k | return true; |
32 | 162k | } |
33 | | |
34 | | non_null() |
35 | | static bool buf_skipper(cmp_ctx_t *ctx, size_t count) |
36 | 0 | { |
37 | 0 | Bin_Unpack *reader = (Bin_Unpack *)ctx->buf; |
38 | 0 | assert(reader != nullptr && reader->bytes != nullptr); |
39 | 0 | if (count > reader->bytes_size) { |
40 | 0 | return false; |
41 | 0 | } |
42 | 0 | reader->bytes += count; |
43 | 0 | reader->bytes_size -= count; |
44 | 0 | return true; |
45 | 0 | } |
46 | | |
47 | | non_null() |
48 | | static size_t null_writer(cmp_ctx_t *ctx, const void *data, size_t count) |
49 | 0 | { |
50 | 0 | assert(count == 0); |
51 | 0 | return 0; |
52 | 0 | } |
53 | | |
54 | | non_null() |
55 | | static void bin_unpack_init(Bin_Unpack *bu, const uint8_t *buf, uint32_t buf_size) |
56 | 15.2k | { |
57 | 15.2k | bu->bytes = buf; |
58 | 15.2k | bu->bytes_size = buf_size; |
59 | 15.2k | cmp_init(&bu->ctx, bu, buf_reader, buf_skipper, null_writer); |
60 | 15.2k | } |
61 | | |
62 | | bool bin_unpack_obj(bin_unpack_cb *callback, void *obj, const uint8_t *buf, uint32_t buf_size) |
63 | 15.2k | { |
64 | 15.2k | Bin_Unpack bu; |
65 | 15.2k | bin_unpack_init(&bu, buf, buf_size); |
66 | 15.2k | return callback(obj, &bu); |
67 | 15.2k | } |
68 | | |
69 | | bool bin_unpack_array(Bin_Unpack *bu, uint32_t *size) |
70 | 15.2k | { |
71 | 15.2k | return cmp_read_array(&bu->ctx, size) && *size <= bu->bytes_size; |
72 | 15.2k | } |
73 | | |
74 | | bool bin_unpack_array_fixed(Bin_Unpack *bu, uint32_t required_size, uint32_t *actual_size) |
75 | 32.6k | { |
76 | 32.6k | uint32_t size = 0; |
77 | 32.6k | const bool success = cmp_read_array(&bu->ctx, &size) && size == required_size; |
78 | 32.6k | if (actual_size != nullptr) { |
79 | 14.5k | *actual_size = size; |
80 | 14.5k | } |
81 | 32.6k | return success; |
82 | 32.6k | } |
83 | | |
84 | | bool bin_unpack_bool(Bin_Unpack *bu, bool *val) |
85 | 11.7k | { |
86 | 11.7k | return cmp_read_bool(&bu->ctx, val); |
87 | 11.7k | } |
88 | | |
89 | | bool bin_unpack_u08(Bin_Unpack *bu, uint8_t *val) |
90 | 16.5k | { |
91 | 16.5k | return cmp_read_uchar(&bu->ctx, val); |
92 | 16.5k | } |
93 | | |
94 | | bool bin_unpack_u16(Bin_Unpack *bu, uint16_t *val) |
95 | 30.5k | { |
96 | 30.5k | return cmp_read_ushort(&bu->ctx, val); |
97 | 30.5k | } |
98 | | |
99 | | bool bin_unpack_u32(Bin_Unpack *bu, uint32_t *val) |
100 | 20.7k | { |
101 | 20.7k | return cmp_read_uint(&bu->ctx, val); |
102 | 20.7k | } |
103 | | |
104 | | bool bin_unpack_u64(Bin_Unpack *bu, uint64_t *val) |
105 | 148 | { |
106 | 148 | return cmp_read_ulong(&bu->ctx, val); |
107 | 148 | } |
108 | | |
109 | | bool bin_unpack_nil(Bin_Unpack *bu) |
110 | 94 | { |
111 | 94 | return cmp_read_nil(&bu->ctx); |
112 | 94 | } |
113 | | |
114 | | bool bin_unpack_bin(Bin_Unpack *bu, uint8_t **data_ptr, uint32_t *data_length_ptr) |
115 | 487 | { |
116 | 487 | uint32_t bin_size; |
117 | 487 | if (!bin_unpack_bin_size(bu, &bin_size) || bin_size > bu->bytes_size) { |
118 | | // There aren't as many bytes as this bin claims to want to allocate. |
119 | 57 | return false; |
120 | 57 | } |
121 | 430 | uint8_t *const data = (uint8_t *)malloc(bin_size); |
122 | | |
123 | 430 | if (!bin_unpack_bin_b(bu, data, bin_size)) { |
124 | 0 | free(data); |
125 | 0 | return false; |
126 | 0 | } |
127 | | |
128 | 430 | *data_ptr = data; |
129 | 430 | *data_length_ptr = bin_size; |
130 | 430 | return true; |
131 | 430 | } |
132 | | |
133 | | bool bin_unpack_bin_max(Bin_Unpack *bu, uint8_t *data, uint16_t *data_length_ptr, uint16_t max_data_length) |
134 | 1.42k | { |
135 | 1.42k | uint32_t bin_size; |
136 | 1.42k | if (!bin_unpack_bin_size(bu, &bin_size) || bin_size > max_data_length) { |
137 | 85 | return false; |
138 | 85 | } |
139 | | |
140 | 1.34k | *data_length_ptr = bin_size; |
141 | | |
142 | 1.34k | return bin_unpack_bin_b(bu, data, bin_size); |
143 | 1.42k | } |
144 | | |
145 | | bool bin_unpack_bin_fixed(Bin_Unpack *bu, uint8_t *data, uint32_t data_length) |
146 | 5.32k | { |
147 | 5.32k | uint32_t bin_size; |
148 | 5.32k | if (!bin_unpack_bin_size(bu, &bin_size) || bin_size != data_length) { |
149 | 1.64k | return false; |
150 | 1.64k | } |
151 | | |
152 | 3.68k | return bin_unpack_bin_b(bu, data, bin_size); |
153 | 5.32k | } |
154 | | |
155 | | bool bin_unpack_bin_size(Bin_Unpack *bu, uint32_t *size) |
156 | 7.23k | { |
157 | 7.23k | return cmp_read_bin_size(&bu->ctx, size); |
158 | 7.23k | } |
159 | | |
160 | | bool bin_unpack_u08_b(Bin_Unpack *bu, uint8_t *val) |
161 | 18 | { |
162 | 18 | return bin_unpack_bin_b(bu, val, 1); |
163 | 18 | } |
164 | | |
165 | | bool bin_unpack_u16_b(Bin_Unpack *bu, uint16_t *val) |
166 | 9 | { |
167 | 9 | uint8_t hi = 0; |
168 | 9 | uint8_t lo = 0; |
169 | 9 | if (!(bin_unpack_u08_b(bu, &hi) |
170 | 9 | && bin_unpack_u08_b(bu, &lo))) { |
171 | 0 | return false; |
172 | 0 | } |
173 | 9 | *val = ((uint16_t)hi << 8) | lo; |
174 | 9 | return true; |
175 | 9 | } |
176 | | |
177 | | bool bin_unpack_u32_b(Bin_Unpack *bu, uint32_t *val) |
178 | 4 | { |
179 | 4 | uint16_t hi = 0; |
180 | 4 | uint16_t lo = 0; |
181 | 4 | if (!(bin_unpack_u16_b(bu, &hi) |
182 | 4 | && bin_unpack_u16_b(bu, &lo))) { |
183 | 0 | return false; |
184 | 0 | } |
185 | 4 | *val = ((uint32_t)hi << 16) | lo; |
186 | 4 | return true; |
187 | 4 | } |
188 | | |
189 | | bool bin_unpack_u64_b(Bin_Unpack *bu, uint64_t *val) |
190 | 2 | { |
191 | 2 | uint32_t hi = 0; |
192 | 2 | uint32_t lo = 0; |
193 | 2 | if (!(bin_unpack_u32_b(bu, &hi) |
194 | 2 | && bin_unpack_u32_b(bu, &lo))) { |
195 | 0 | return false; |
196 | 0 | } |
197 | 2 | *val = ((uint64_t)hi << 32) | lo; |
198 | 2 | return true; |
199 | 2 | } |
200 | | |
201 | | bool bin_unpack_bin_b(Bin_Unpack *bu, uint8_t *data, uint32_t length) |
202 | 5.47k | { |
203 | 5.47k | return bu->ctx.read(&bu->ctx, data, length); |
204 | 5.47k | } |