libcbor 0.12.0
libcbor is a C library for parsing and generating CBOR, the general-purpose schema-less binary data format.
Loading...
Searching...
No Matches
builder_callbacks.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014-2020 Pavel Kalvoda <me@pavelkalvoda.com>
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.
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: {
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;
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
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;
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;
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
142void 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
151void cbor_builder_uint16_callback(void* context, uint16_t value) {
152 struct _cbor_decoder_context* ctx = context;
154 CHECK_RES(ctx, res);
155 cbor_mark_uint(res);
156 cbor_set_uint16(res, value);
157 _cbor_builder_append(res, ctx);
158}
159
160void cbor_builder_uint32_callback(void* context, uint32_t value) {
161 struct _cbor_decoder_context* ctx = context;
163 CHECK_RES(ctx, res);
164 cbor_mark_uint(res);
165 cbor_set_uint32(res, value);
166 _cbor_builder_append(res, ctx);
167}
168
169void cbor_builder_uint64_callback(void* context, uint64_t value) {
170 struct _cbor_decoder_context* ctx = context;
172 CHECK_RES(ctx, res);
173 cbor_mark_uint(res);
174 cbor_set_uint64(res, value);
175 _cbor_builder_append(res, ctx);
176}
177
178void 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
187void cbor_builder_negint16_callback(void* context, uint16_t value) {
188 struct _cbor_decoder_context* ctx = context;
190 CHECK_RES(ctx, res);
191 cbor_mark_negint(res);
192 cbor_set_uint16(res, value);
193 _cbor_builder_append(res, ctx);
194}
195
196void cbor_builder_negint32_callback(void* context, uint32_t value) {
197 struct _cbor_decoder_context* ctx = context;
199 CHECK_RES(ctx, res);
200 cbor_mark_negint(res);
201 cbor_set_uint32(res, value);
202 _cbor_builder_append(res, ctx);
203}
204
205void cbor_builder_negint64_callback(void* context, uint64_t value) {
206 struct _cbor_decoder_context* ctx = context;
208 CHECK_RES(ctx, res);
209 cbor_mark_negint(res);
210 cbor_set_uint64(res, value);
211 _cbor_builder_append(res, ctx);
212}
213
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);
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) &&
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
249 struct _cbor_decoder_context* ctx = context;
251 CHECK_RES(ctx, res);
252 PUSH_CTX_STACK(ctx, res, 0);
253}
254
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);
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) &&
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
289 struct _cbor_decoder_context* ctx = context;
291 CHECK_RES(ctx, res);
292 PUSH_CTX_STACK(ctx, res, 0);
293}
294
295void cbor_builder_array_start_callback(void* context, uint64_t size) {
296 struct _cbor_decoder_context* ctx = context;
297 CHECK_LENGTH(ctx, 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
308 struct _cbor_decoder_context* ctx = context;
310 CHECK_RES(ctx, res);
311 PUSH_CTX_STACK(ctx, res, 0);
312}
313
315 struct _cbor_decoder_context* ctx = context;
317 CHECK_RES(ctx, res);
318 PUSH_CTX_STACK(ctx, res, 0);
319}
320
321void cbor_builder_map_start_callback(void* context, uint64_t size) {
322 struct _cbor_decoder_context* ctx = context;
323 CHECK_LENGTH(ctx, 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
337 switch (item->type) {
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
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;
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)) {
364 _cbor_builder_append(item, ctx);
365 return;
366 }
367 }
368
369 ctx->syntax_error = true;
370}
371
372void cbor_builder_float2_callback(void* context, float value) {
373 struct _cbor_decoder_context* ctx = context;
375 CHECK_RES(ctx, res);
376 cbor_set_float2(res, value);
377 _cbor_builder_append(res, ctx);
378}
379
380void cbor_builder_float4_callback(void* context, float value) {
381 struct _cbor_decoder_context* ctx = context;
383 CHECK_RES(ctx, res);
384 cbor_set_float4(res, value);
385 _cbor_builder_append(res, ctx);
386}
387
388void cbor_builder_float8_callback(void* context, double value) {
389 struct _cbor_decoder_context* ctx = context;
391 CHECK_RES(ctx, res);
392 cbor_set_float8(res, value);
393 _cbor_builder_append(res, ctx);
394}
395
396void 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
404 struct _cbor_decoder_context* ctx = context;
406 CHECK_RES(ctx, res);
407 _cbor_builder_append(res, ctx);
408}
409
410void 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
417void 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}
_cbor_malloc_t _cbor_malloc
Definition allocators.c:10
_cbor_free_t _cbor_free
Definition allocators.c:12
bool cbor_array_is_indefinite(const cbor_item_t *item)
Is the array indefinite?
Definition arrays.c:87
bool cbor_array_push(cbor_item_t *array, cbor_item_t *pushee)
Append to the end.
Definition arrays.c:44
bool cbor_array_is_definite(const cbor_item_t *item)
Is the array definite?
Definition arrays.c:82
cbor_item_t * cbor_new_definite_array(size_t size)
Create new definite array.
Definition arrays.c:97
cbor_item_t * cbor_new_indefinite_array(void)
Create new indefinite array.
Definition arrays.c:118
void cbor_builder_byte_string_callback(void *context, cbor_data data, uint64_t length)
void cbor_builder_uint64_callback(void *context, uint64_t value)
void cbor_builder_boolean_callback(void *context, bool value)
bool _cbor_is_indefinite(cbor_item_t *item)
Is the (partially constructed) item indefinite?
void cbor_builder_byte_string_start_callback(void *context)
void cbor_builder_array_start_callback(void *context, uint64_t size)
void cbor_builder_string_start_callback(void *context)
void cbor_builder_indef_map_start_callback(void *context)
void cbor_builder_negint16_callback(void *context, uint16_t value)
void cbor_builder_undefined_callback(void *context)
void cbor_builder_negint32_callback(void *context, uint32_t value)
void cbor_builder_null_callback(void *context)
void cbor_builder_map_start_callback(void *context, uint64_t size)
void cbor_builder_uint32_callback(void *context, uint32_t value)
#define CHECK_LENGTH(ctx, length)
#define CHECK_RES(ctx, res)
void cbor_builder_indef_array_start_callback(void *context)
#define PUSH_CTX_STACK(ctx, res, subitems)
void cbor_builder_uint16_callback(void *context, uint16_t value)
void cbor_builder_negint8_callback(void *context, uint8_t value)
void cbor_builder_string_callback(void *context, cbor_data data, uint64_t length)
void cbor_builder_tag_callback(void *context, uint64_t value)
void cbor_builder_uint8_callback(void *context, uint8_t value)
void cbor_builder_float4_callback(void *context, float value)
void cbor_builder_negint64_callback(void *context, uint64_t value)
void _cbor_builder_append(cbor_item_t *item, struct _cbor_decoder_context *ctx)
Internal helper: Append item to the top of the stack while handling errors.
void cbor_builder_float8_callback(void *context, double value)
void cbor_builder_float2_callback(void *context, float value)
void cbor_builder_indef_break_callback(void *context)
bool cbor_bytestring_is_indefinite(const cbor_item_t *item)
Is the byte string indefinite?
Definition bytestrings.c:27
cbor_item_t * cbor_new_definite_bytestring(void)
Creates a new definite byte string.
Definition bytestrings.c:31
bool cbor_bytestring_add_chunk(cbor_item_t *item, cbor_item_t *chunk)
Appends a chunk to the bytestring.
Definition bytestrings.c:92
cbor_item_t * cbor_new_indefinite_bytestring(void)
Creates a new indefinite byte string.
Definition bytestrings.c:42
void cbor_bytestring_set_handle(cbor_item_t *item, cbor_mutable_data data, size_t length)
Set the handle to the binary data.
Definition bytestrings.c:71
bool cbor_isa_string(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition common.c:34
bool cbor_isa_bytestring(const cbor_item_t *item)
Does the item have the appropriate major type?
Definition common.c:30
void cbor_decref(cbor_item_t **item_ref)
Decreases the item's reference count by one, deallocating the item if needed.
Definition common.c:83
#define CBOR_ASSERT(e)
Definition common.h:73
const unsigned char * cbor_data
Definition data.h:20
@ CBOR_TYPE_MAP
5 - maps
Definition data.h:35
@ CBOR_TYPE_TAG
6 - tags
Definition data.h:37
@ CBOR_TYPE_BYTESTRING
2 - byte strings
Definition data.h:29
@ CBOR_TYPE_STRING
3 - strings
Definition data.h:31
@ CBOR_TYPE_ARRAY
4 - arrays
Definition data.h:33
cbor_item_t * cbor_new_undef(void)
Constructs new undef ctrl item.
cbor_item_t * cbor_new_float2(void)
Constructs a new float item.
cbor_item_t * cbor_new_float8(void)
Constructs a new float item.
void cbor_set_float4(cbor_item_t *item, float value)
Assigns a float value.
void cbor_set_float8(cbor_item_t *item, double value)
Assigns a float value.
cbor_item_t * cbor_build_bool(bool value)
Constructs new boolean ctrl item.
cbor_item_t * cbor_new_null(void)
Constructs new null ctrl item.
void cbor_set_float2(cbor_item_t *item, float value)
Assigns a float value.
cbor_item_t * cbor_new_float4(void)
Constructs a new float item.
void cbor_set_uint16(cbor_item_t *item, uint16_t value)
Assigns the integer value.
Definition ints.c:63
cbor_item_t * cbor_new_int32(void)
Allocates new integer with 4B width.
Definition ints.c:111
void cbor_set_uint32(cbor_item_t *item, uint32_t value)
Assigns the integer value.
Definition ints.c:69
cbor_item_t * cbor_new_int8(void)
Allocates new integer with 1B width.
Definition ints.c:91
void cbor_set_uint8(cbor_item_t *item, uint8_t value)
Assigns the integer value.
Definition ints.c:57
void cbor_mark_negint(cbor_item_t *item)
Marks the integer item as a negative integer.
Definition ints.c:86
cbor_item_t * cbor_new_int64(void)
Allocates new integer with 8B width.
Definition ints.c:121
cbor_item_t * cbor_new_int16(void)
Allocates new integer with 2B width.
Definition ints.c:101
void cbor_mark_uint(cbor_item_t *item)
Marks the integer item as a positive integer.
Definition ints.c:81
void cbor_set_uint64(cbor_item_t *item, uint64_t value)
Assigns the integer value.
Definition ints.c:75
bool cbor_map_is_definite(const cbor_item_t *item)
Is this map definite?
Definition maps.c:113
bool _cbor_map_add_key(cbor_item_t *item, cbor_item_t *key)
Add a key to the map.
Definition maps.c:52
cbor_item_t * cbor_new_indefinite_map(void)
Create a new indefinite map.
Definition maps.c:37
bool cbor_map_is_indefinite(const cbor_item_t *item)
Is this map indefinite?
Definition maps.c:118
bool _cbor_map_add_value(cbor_item_t *item, cbor_item_t *value)
Add a value to the map.
Definition maps.c:95
cbor_item_t * cbor_new_definite_map(size_t size)
Create a new definite map.
Definition maps.c:21
void _cbor_stack_pop(struct _cbor_stack *stack)
Definition stack.c:14
cbor_item_t * cbor_new_definite_string(void)
Creates a new definite string.
Definition strings.c:13
void cbor_string_set_handle(cbor_item_t *item, cbor_mutable_data data, size_t length)
Set the handle to the underlying string.
Definition strings.c:65
bool cbor_string_add_chunk(cbor_item_t *item, cbor_item_t *chunk)
Appends a chunk to the string.
Definition strings.c:95
cbor_item_t * cbor_new_indefinite_string(void)
Creates a new indefinite string.
Definition strings.c:25
bool cbor_string_is_indefinite(const cbor_item_t *item)
Is the string indefinite?
Definition strings.c:142
High-level decoding context.
bool creation_failed
Callback creating the last item has failed.
bool syntax_error
Stack expectation mismatch.
struct _cbor_stack * stack
cbor_item_t * item
Item under construction.
Definition stack.h:22
size_t subitems
How many outstanding subitems are expected.
Definition stack.h:31
struct _cbor_stack_record * top
Definition stack.h:36
size_t size
Definition stack.h:37
The item handle.
Definition data.h:171
cbor_type type
Major type discriminator.
Definition data.h:177
void cbor_tag_set_item(cbor_item_t *tag, cbor_item_t *tagged_item)
Assign a tag to an item.
Definition tags.c:33
cbor_item_t * cbor_new_tag(uint64_t value)
Create a new tag.
Definition tags.c:10