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.
_cbor_builder_append(cbor_item_t * item,struct _cbor_decoder_context * ctx)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
cbor_builder_uint8_callback(void * context,uint8_t value)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
cbor_builder_uint16_callback(void * context,uint16_t value)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
cbor_builder_uint32_callback(void * context,uint32_t value)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
cbor_builder_uint64_callback(void * context,uint64_t value)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
cbor_builder_negint8_callback(void * context,uint8_t value)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
cbor_builder_negint16_callback(void * context,uint16_t value)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
cbor_builder_negint32_callback(void * context,uint32_t value)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
cbor_builder_negint64_callback(void * context,uint64_t value)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
cbor_builder_byte_string_callback(void * context,cbor_data data,uint64_t length)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
cbor_builder_byte_string_start_callback(void * context)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
cbor_builder_string_callback(void * context,cbor_data data,uint64_t length)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
cbor_builder_string_start_callback(void * context)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
cbor_builder_array_start_callback(void * context,uint64_t size)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
cbor_builder_indef_array_start_callback(void * context)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
cbor_builder_indef_map_start_callback(void * context)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
cbor_builder_map_start_callback(void * context,uint64_t size)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 */
_cbor_is_indefinite(cbor_item_t * item)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
cbor_builder_indef_break_callback(void * context)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
cbor_builder_float2_callback(void * context,float value)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
cbor_builder_float4_callback(void * context,float value)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
cbor_builder_float8_callback(void * context,double value)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
cbor_builder_null_callback(void * context)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
cbor_builder_undefined_callback(void * context)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
cbor_builder_boolean_callback(void * context,bool value)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
cbor_builder_tag_callback(void * context,uint64_t value)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