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 if (!_cbor_map_add_value(ctx->stack->top->item, item)) {
72 ctx->creation_failed = true;
73 cbor_decref(&item);
74 break;
75 }
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 struct _cbor_unicode_status unicode_status;
260 uint64_t codepoint_count =
261 _cbor_unicode_codepoint_count(data, length, &unicode_status);
262
263 if (unicode_status.status != _CBOR_UNICODE_OK) {
264 ctx->syntax_error = true;
265 return;
266 }
267 CBOR_ASSERT(codepoint_count <= length);
268
269 unsigned char *new_handle = _cbor_malloc(length);
270
271 if (new_handle == NULL) {
272 ctx->creation_failed = true;
273 return;
274 }
275
276 memcpy(new_handle, data, length);
277 cbor_item_t *new_chunk = cbor_new_definite_string();
278 if (new_chunk == NULL) {
279 _cbor_free(new_handle);
280 ctx->creation_failed = true;
281 return;
282 }
283 cbor_string_set_handle(new_chunk, new_handle, length);
284 new_chunk->metadata.string_metadata.codepoint_count = codepoint_count;
285
286 // If an indef string is on the stack, extend it (if it were closed, it would
287 // have been popped). Handle any syntax errors upstream.
288 if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item) &&
289 cbor_string_is_indefinite(ctx->stack->top->item)) {
290 if (!cbor_string_add_chunk(ctx->stack->top->item, new_chunk)) {
291 ctx->creation_failed = true;
292 }
293 cbor_decref(&new_chunk);
294 } else {
295 _cbor_builder_append(new_chunk, ctx);
296 }
297 }
298
cbor_builder_string_start_callback(void * context)299 void cbor_builder_string_start_callback(void *context) {
300 struct _cbor_decoder_context *ctx = context;
301 cbor_item_t *res = cbor_new_indefinite_string();
302 CHECK_RES(ctx, res);
303 PUSH_CTX_STACK(ctx, res, 0);
304 }
305
cbor_builder_array_start_callback(void * context,uint64_t size)306 void cbor_builder_array_start_callback(void *context, uint64_t size) {
307 struct _cbor_decoder_context *ctx = context;
308 CHECK_LENGTH(ctx, size);
309 cbor_item_t *res = cbor_new_definite_array(size);
310 CHECK_RES(ctx, res);
311 if (size > 0) {
312 PUSH_CTX_STACK(ctx, res, size);
313 } else {
314 _cbor_builder_append(res, ctx);
315 }
316 }
317
cbor_builder_indef_array_start_callback(void * context)318 void cbor_builder_indef_array_start_callback(void *context) {
319 struct _cbor_decoder_context *ctx = context;
320 cbor_item_t *res = cbor_new_indefinite_array();
321 CHECK_RES(ctx, res);
322 PUSH_CTX_STACK(ctx, res, 0);
323 }
324
cbor_builder_indef_map_start_callback(void * context)325 void cbor_builder_indef_map_start_callback(void *context) {
326 struct _cbor_decoder_context *ctx = context;
327 cbor_item_t *res = cbor_new_indefinite_map();
328 CHECK_RES(ctx, res);
329 PUSH_CTX_STACK(ctx, res, 0);
330 }
331
cbor_builder_map_start_callback(void * context,uint64_t size)332 void cbor_builder_map_start_callback(void *context, uint64_t size) {
333 struct _cbor_decoder_context *ctx = context;
334 CHECK_LENGTH(ctx, size);
335 cbor_item_t *res = cbor_new_definite_map(size);
336 CHECK_RES(ctx, res);
337 if (size > 0) {
338 PUSH_CTX_STACK(ctx, res, size * 2);
339 } else {
340 _cbor_builder_append(res, ctx);
341 }
342 }
343
344 /**
345 * Is the (partially constructed) item indefinite?
346 */
_cbor_is_indefinite(cbor_item_t * item)347 bool _cbor_is_indefinite(cbor_item_t *item) {
348 switch (item->type) {
349 case CBOR_TYPE_BYTESTRING:
350 return cbor_bytestring_is_indefinite(item);
351 case CBOR_TYPE_STRING:
352 return cbor_string_is_indefinite(item);
353 case CBOR_TYPE_ARRAY:
354 return cbor_array_is_indefinite(item);
355 case CBOR_TYPE_MAP:
356 return cbor_map_is_indefinite(item);
357 default:
358 return false;
359 }
360 }
361
cbor_builder_indef_break_callback(void * context)362 void cbor_builder_indef_break_callback(void *context) {
363 struct _cbor_decoder_context *ctx = context;
364 /* There must be an item to break out of*/
365 if (ctx->stack->size > 0) {
366 cbor_item_t *item = ctx->stack->top->item;
367 if (_cbor_is_indefinite(
368 item) && /* Only indefinite items can be terminated by 0xFF */
369 /* Special case: we cannot append up if an indefinite map is incomplete
370 (we are expecting a value). */
371 (item->type != CBOR_TYPE_MAP || ctx->stack->top->subitems % 2 == 0)) {
372 _cbor_stack_pop(ctx->stack);
373 _cbor_builder_append(item, ctx);
374 return;
375 }
376 }
377
378 ctx->syntax_error = true;
379 }
380
cbor_builder_float2_callback(void * context,float value)381 void cbor_builder_float2_callback(void *context, float value) {
382 struct _cbor_decoder_context *ctx = context;
383 cbor_item_t *res = cbor_new_float2();
384 CHECK_RES(ctx, res);
385 cbor_set_float2(res, value);
386 _cbor_builder_append(res, ctx);
387 }
388
cbor_builder_float4_callback(void * context,float value)389 void cbor_builder_float4_callback(void *context, float value) {
390 struct _cbor_decoder_context *ctx = context;
391 cbor_item_t *res = cbor_new_float4();
392 CHECK_RES(ctx, res);
393 cbor_set_float4(res, value);
394 _cbor_builder_append(res, ctx);
395 }
396
cbor_builder_float8_callback(void * context,double value)397 void cbor_builder_float8_callback(void *context, double value) {
398 struct _cbor_decoder_context *ctx = context;
399 cbor_item_t *res = cbor_new_float8();
400 CHECK_RES(ctx, res);
401 cbor_set_float8(res, value);
402 _cbor_builder_append(res, ctx);
403 }
404
cbor_builder_null_callback(void * context)405 void cbor_builder_null_callback(void *context) {
406 struct _cbor_decoder_context *ctx = context;
407 cbor_item_t *res = cbor_new_null();
408 CHECK_RES(ctx, res);
409 _cbor_builder_append(res, ctx);
410 }
411
cbor_builder_undefined_callback(void * context)412 void cbor_builder_undefined_callback(void *context) {
413 struct _cbor_decoder_context *ctx = context;
414 cbor_item_t *res = cbor_new_undef();
415 CHECK_RES(ctx, res);
416 _cbor_builder_append(res, ctx);
417 }
418
cbor_builder_boolean_callback(void * context,bool value)419 void cbor_builder_boolean_callback(void *context, bool value) {
420 struct _cbor_decoder_context *ctx = context;
421 cbor_item_t *res = cbor_build_bool(value);
422 CHECK_RES(ctx, res);
423 _cbor_builder_append(res, ctx);
424 }
425
cbor_builder_tag_callback(void * context,uint64_t value)426 void cbor_builder_tag_callback(void *context, uint64_t value) {
427 struct _cbor_decoder_context *ctx = context;
428 cbor_item_t *res = cbor_new_tag(value);
429 CHECK_RES(ctx, res);
430 PUSH_CTX_STACK(ctx, res, 1);
431 }
432