Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libcbor/src/cbor/internal/builder_callbacks.c
39566 views
1
/*
2
* Copyright (c) 2014-2020 Pavel Kalvoda <[email protected]>
3
*
4
* libcbor is free software; you can redistribute it and/or modify
5
* it under the terms of the MIT license. See LICENSE for details.
6
*/
7
8
#include "builder_callbacks.h"
9
10
#include <string.h>
11
12
#include "../arrays.h"
13
#include "../bytestrings.h"
14
#include "../common.h"
15
#include "../floats_ctrls.h"
16
#include "../ints.h"
17
#include "../maps.h"
18
#include "../strings.h"
19
#include "../tags.h"
20
#include "unicode.h"
21
22
// `_cbor_builder_append` takes ownership of `item`. If adding the item to
23
// parent container fails, `item` will be deallocated to prevent memory.
24
void _cbor_builder_append(cbor_item_t *item,
25
struct _cbor_decoder_context *ctx) {
26
if (ctx->stack->size == 0) {
27
/* Top level item */
28
ctx->root = item;
29
return;
30
}
31
/* Part of a bigger structure */
32
switch (ctx->stack->top->item->type) {
33
// Handle Arrays and Maps since they can contain subitems of any type.
34
// Byte/string construction from chunks is handled in the respective chunk
35
// handlers.
36
case CBOR_TYPE_ARRAY: {
37
if (cbor_array_is_definite(ctx->stack->top->item)) {
38
// We don't need an explicit check for whether the item still belongs
39
// into this array because if there are extra items, they will cause a
40
// syntax error when decoded.
41
CBOR_ASSERT(ctx->stack->top->subitems > 0);
42
// This should never happen since the definite array should be
43
// preallocated for the expected number of items.
44
if (!cbor_array_push(ctx->stack->top->item, item)) {
45
ctx->creation_failed = true;
46
cbor_decref(&item);
47
break;
48
}
49
cbor_decref(&item);
50
ctx->stack->top->subitems--;
51
if (ctx->stack->top->subitems == 0) {
52
cbor_item_t *stack_item = ctx->stack->top->item;
53
_cbor_stack_pop(ctx->stack);
54
_cbor_builder_append(stack_item, ctx);
55
}
56
} else {
57
/* Indefinite array, don't bother with subitems */
58
if (!cbor_array_push(ctx->stack->top->item, item)) {
59
ctx->creation_failed = true;
60
}
61
cbor_decref(&item);
62
}
63
break;
64
}
65
case CBOR_TYPE_MAP: {
66
// Handle both definite and indefinite maps the same initially.
67
// Note: We use 0 and 1 subitems to distinguish between keys and values in
68
// indefinite items
69
if (ctx->stack->top->subitems % 2) {
70
// Odd record, this is a value.
71
ctx->creation_failed =
72
!_cbor_map_add_value(ctx->stack->top->item, item);
73
// Adding a value never fails since the memory is allocated when the
74
// key is added
75
CBOR_ASSERT(!ctx->creation_failed);
76
} else {
77
// Even record, this is a key.
78
if (!_cbor_map_add_key(ctx->stack->top->item, item)) {
79
ctx->creation_failed = true;
80
cbor_decref(&item);
81
break;
82
}
83
}
84
cbor_decref(&item);
85
if (cbor_map_is_definite(ctx->stack->top->item)) {
86
CBOR_ASSERT(ctx->stack->top->subitems > 0);
87
ctx->stack->top->subitems--;
88
if (ctx->stack->top->subitems == 0) {
89
cbor_item_t *map_entry = ctx->stack->top->item;
90
_cbor_stack_pop(ctx->stack);
91
_cbor_builder_append(map_entry, ctx);
92
}
93
} else {
94
ctx->stack->top->subitems ^=
95
1; /* Flip the indicator for indefinite items */
96
}
97
break;
98
}
99
case CBOR_TYPE_TAG: {
100
CBOR_ASSERT(ctx->stack->top->subitems == 1);
101
cbor_tag_set_item(ctx->stack->top->item, item);
102
cbor_decref(&item); /* Give up on our reference */
103
cbor_item_t *tagged_item = ctx->stack->top->item;
104
_cbor_stack_pop(ctx->stack);
105
_cbor_builder_append(tagged_item, ctx);
106
break;
107
}
108
// We have an item to append but nothing to append it to.
109
default: {
110
cbor_decref(&item);
111
ctx->syntax_error = true;
112
}
113
}
114
}
115
116
#define CHECK_RES(ctx, res) \
117
do { \
118
if (res == NULL) { \
119
ctx->creation_failed = true; \
120
return; \
121
} \
122
} while (0)
123
124
// Check that the length fits into size_t. If not, we cannot possibly allocate
125
// the required memory and should fail fast.
126
#define CHECK_LENGTH(ctx, length) \
127
do { \
128
if (length > SIZE_MAX) { \
129
ctx->creation_failed = true; \
130
return; \
131
} \
132
} while (0)
133
134
#define PUSH_CTX_STACK(ctx, res, subitems) \
135
do { \
136
if (_cbor_stack_push(ctx->stack, res, subitems) == NULL) { \
137
cbor_decref(&res); \
138
ctx->creation_failed = true; \
139
} \
140
} while (0)
141
142
void cbor_builder_uint8_callback(void *context, uint8_t value) {
143
struct _cbor_decoder_context *ctx = context;
144
cbor_item_t *res = cbor_new_int8();
145
CHECK_RES(ctx, res);
146
cbor_mark_uint(res);
147
cbor_set_uint8(res, value);
148
_cbor_builder_append(res, ctx);
149
}
150
151
void cbor_builder_uint16_callback(void *context, uint16_t value) {
152
struct _cbor_decoder_context *ctx = context;
153
cbor_item_t *res = cbor_new_int16();
154
CHECK_RES(ctx, res);
155
cbor_mark_uint(res);
156
cbor_set_uint16(res, value);
157
_cbor_builder_append(res, ctx);
158
}
159
160
void cbor_builder_uint32_callback(void *context, uint32_t value) {
161
struct _cbor_decoder_context *ctx = context;
162
cbor_item_t *res = cbor_new_int32();
163
CHECK_RES(ctx, res);
164
cbor_mark_uint(res);
165
cbor_set_uint32(res, value);
166
_cbor_builder_append(res, ctx);
167
}
168
169
void cbor_builder_uint64_callback(void *context, uint64_t value) {
170
struct _cbor_decoder_context *ctx = context;
171
cbor_item_t *res = cbor_new_int64();
172
CHECK_RES(ctx, res);
173
cbor_mark_uint(res);
174
cbor_set_uint64(res, value);
175
_cbor_builder_append(res, ctx);
176
}
177
178
void cbor_builder_negint8_callback(void *context, uint8_t value) {
179
struct _cbor_decoder_context *ctx = context;
180
cbor_item_t *res = cbor_new_int8();
181
CHECK_RES(ctx, res);
182
cbor_mark_negint(res);
183
cbor_set_uint8(res, value);
184
_cbor_builder_append(res, ctx);
185
}
186
187
void cbor_builder_negint16_callback(void *context, uint16_t value) {
188
struct _cbor_decoder_context *ctx = context;
189
cbor_item_t *res = cbor_new_int16();
190
CHECK_RES(ctx, res);
191
cbor_mark_negint(res);
192
cbor_set_uint16(res, value);
193
_cbor_builder_append(res, ctx);
194
}
195
196
void cbor_builder_negint32_callback(void *context, uint32_t value) {
197
struct _cbor_decoder_context *ctx = context;
198
cbor_item_t *res = cbor_new_int32();
199
CHECK_RES(ctx, res);
200
cbor_mark_negint(res);
201
cbor_set_uint32(res, value);
202
_cbor_builder_append(res, ctx);
203
}
204
205
void cbor_builder_negint64_callback(void *context, uint64_t value) {
206
struct _cbor_decoder_context *ctx = context;
207
cbor_item_t *res = cbor_new_int64();
208
CHECK_RES(ctx, res);
209
cbor_mark_negint(res);
210
cbor_set_uint64(res, value);
211
_cbor_builder_append(res, ctx);
212
}
213
214
void cbor_builder_byte_string_callback(void *context, cbor_data data,
215
uint64_t length) {
216
struct _cbor_decoder_context *ctx = context;
217
CHECK_LENGTH(ctx, length);
218
unsigned char *new_handle = _cbor_malloc(length);
219
if (new_handle == NULL) {
220
ctx->creation_failed = true;
221
return;
222
}
223
224
memcpy(new_handle, data, length);
225
cbor_item_t *new_chunk = cbor_new_definite_bytestring();
226
227
if (new_chunk == NULL) {
228
_cbor_free(new_handle);
229
ctx->creation_failed = true;
230
return;
231
}
232
233
cbor_bytestring_set_handle(new_chunk, new_handle, length);
234
235
// If an indef bytestring is on the stack, extend it (if it were closed, it
236
// would have been popped). Handle any syntax errors upstream.
237
if (ctx->stack->size > 0 && cbor_isa_bytestring(ctx->stack->top->item) &&
238
cbor_bytestring_is_indefinite(ctx->stack->top->item)) {
239
if (!cbor_bytestring_add_chunk(ctx->stack->top->item, new_chunk)) {
240
ctx->creation_failed = true;
241
}
242
cbor_decref(&new_chunk);
243
} else {
244
_cbor_builder_append(new_chunk, ctx);
245
}
246
}
247
248
void cbor_builder_byte_string_start_callback(void *context) {
249
struct _cbor_decoder_context *ctx = context;
250
cbor_item_t *res = cbor_new_indefinite_bytestring();
251
CHECK_RES(ctx, res);
252
PUSH_CTX_STACK(ctx, res, 0);
253
}
254
255
void cbor_builder_string_callback(void *context, cbor_data data,
256
uint64_t length) {
257
struct _cbor_decoder_context *ctx = context;
258
CHECK_LENGTH(ctx, length);
259
260
unsigned char *new_handle = _cbor_malloc(length);
261
if (new_handle == NULL) {
262
ctx->creation_failed = true;
263
return;
264
}
265
266
memcpy(new_handle, data, length);
267
cbor_item_t *new_chunk = cbor_new_definite_string();
268
if (new_chunk == NULL) {
269
_cbor_free(new_handle);
270
ctx->creation_failed = true;
271
return;
272
}
273
cbor_string_set_handle(new_chunk, new_handle, length);
274
275
// If an indef string is on the stack, extend it (if it were closed, it would
276
// have been popped). Handle any syntax errors upstream.
277
if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item) &&
278
cbor_string_is_indefinite(ctx->stack->top->item)) {
279
if (!cbor_string_add_chunk(ctx->stack->top->item, new_chunk)) {
280
ctx->creation_failed = true;
281
}
282
cbor_decref(&new_chunk);
283
} else {
284
_cbor_builder_append(new_chunk, ctx);
285
}
286
}
287
288
void cbor_builder_string_start_callback(void *context) {
289
struct _cbor_decoder_context *ctx = context;
290
cbor_item_t *res = cbor_new_indefinite_string();
291
CHECK_RES(ctx, res);
292
PUSH_CTX_STACK(ctx, res, 0);
293
}
294
295
void cbor_builder_array_start_callback(void *context, uint64_t size) {
296
struct _cbor_decoder_context *ctx = context;
297
CHECK_LENGTH(ctx, size);
298
cbor_item_t *res = cbor_new_definite_array(size);
299
CHECK_RES(ctx, res);
300
if (size > 0) {
301
PUSH_CTX_STACK(ctx, res, size);
302
} else {
303
_cbor_builder_append(res, ctx);
304
}
305
}
306
307
void cbor_builder_indef_array_start_callback(void *context) {
308
struct _cbor_decoder_context *ctx = context;
309
cbor_item_t *res = cbor_new_indefinite_array();
310
CHECK_RES(ctx, res);
311
PUSH_CTX_STACK(ctx, res, 0);
312
}
313
314
void cbor_builder_indef_map_start_callback(void *context) {
315
struct _cbor_decoder_context *ctx = context;
316
cbor_item_t *res = cbor_new_indefinite_map();
317
CHECK_RES(ctx, res);
318
PUSH_CTX_STACK(ctx, res, 0);
319
}
320
321
void cbor_builder_map_start_callback(void *context, uint64_t size) {
322
struct _cbor_decoder_context *ctx = context;
323
CHECK_LENGTH(ctx, size);
324
cbor_item_t *res = cbor_new_definite_map(size);
325
CHECK_RES(ctx, res);
326
if (size > 0) {
327
PUSH_CTX_STACK(ctx, res, size * 2);
328
} else {
329
_cbor_builder_append(res, ctx);
330
}
331
}
332
333
/**
334
* Is the (partially constructed) item indefinite?
335
*/
336
bool _cbor_is_indefinite(cbor_item_t *item) {
337
switch (item->type) {
338
case CBOR_TYPE_BYTESTRING:
339
return cbor_bytestring_is_indefinite(item);
340
case CBOR_TYPE_STRING:
341
return cbor_string_is_indefinite(item);
342
case CBOR_TYPE_ARRAY:
343
return cbor_array_is_indefinite(item);
344
case CBOR_TYPE_MAP:
345
return cbor_map_is_indefinite(item);
346
default:
347
// Should never happen since a non-nested item cannot be on top of the
348
// stack.
349
return false;
350
}
351
}
352
353
void cbor_builder_indef_break_callback(void *context) {
354
struct _cbor_decoder_context *ctx = context;
355
/* There must be an item to break out of*/
356
if (ctx->stack->size > 0) {
357
cbor_item_t *item = ctx->stack->top->item;
358
if (_cbor_is_indefinite(
359
item) && /* Only indefinite items can be terminated by 0xFF */
360
/* Special case: we cannot append up if an indefinite map is incomplete
361
(we are expecting a value). */
362
(item->type != CBOR_TYPE_MAP || ctx->stack->top->subitems % 2 == 0)) {
363
_cbor_stack_pop(ctx->stack);
364
_cbor_builder_append(item, ctx);
365
return;
366
}
367
}
368
369
ctx->syntax_error = true;
370
}
371
372
void cbor_builder_float2_callback(void *context, float value) {
373
struct _cbor_decoder_context *ctx = context;
374
cbor_item_t *res = cbor_new_float2();
375
CHECK_RES(ctx, res);
376
cbor_set_float2(res, value);
377
_cbor_builder_append(res, ctx);
378
}
379
380
void cbor_builder_float4_callback(void *context, float value) {
381
struct _cbor_decoder_context *ctx = context;
382
cbor_item_t *res = cbor_new_float4();
383
CHECK_RES(ctx, res);
384
cbor_set_float4(res, value);
385
_cbor_builder_append(res, ctx);
386
}
387
388
void cbor_builder_float8_callback(void *context, double value) {
389
struct _cbor_decoder_context *ctx = context;
390
cbor_item_t *res = cbor_new_float8();
391
CHECK_RES(ctx, res);
392
cbor_set_float8(res, value);
393
_cbor_builder_append(res, ctx);
394
}
395
396
void cbor_builder_null_callback(void *context) {
397
struct _cbor_decoder_context *ctx = context;
398
cbor_item_t *res = cbor_new_null();
399
CHECK_RES(ctx, res);
400
_cbor_builder_append(res, ctx);
401
}
402
403
void cbor_builder_undefined_callback(void *context) {
404
struct _cbor_decoder_context *ctx = context;
405
cbor_item_t *res = cbor_new_undef();
406
CHECK_RES(ctx, res);
407
_cbor_builder_append(res, ctx);
408
}
409
410
void cbor_builder_boolean_callback(void *context, bool value) {
411
struct _cbor_decoder_context *ctx = context;
412
cbor_item_t *res = cbor_build_bool(value);
413
CHECK_RES(ctx, res);
414
_cbor_builder_append(res, ctx);
415
}
416
417
void cbor_builder_tag_callback(void *context, uint64_t value) {
418
struct _cbor_decoder_context *ctx = context;
419
cbor_item_t *res = cbor_new_tag(value);
420
CHECK_RES(ctx, res);
421
PUSH_CTX_STACK(ctx, res, 1);
422
}
423
424