Coverage Report

Created: 2025-10-08 19:34

/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
}