xref: /freebsd/contrib/libcbor/src/cbor/internal/builder_callbacks.c (revision 6580f5c38dd5b01aeeaed16b370f1a12423437f0)
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.
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