1 /*
2  * Copyright (c) 2014-2019 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 #include <string.h>
10 #include "../arrays.h"
11 #include "../bytestrings.h"
12 #include "../floats_ctrls.h"
13 #include "../ints.h"
14 #include "../maps.h"
15 #include "../strings.h"
16 #include "../tags.h"
17 #include "unicode.h"
18 
_cbor_builder_append(cbor_item_t * item,struct _cbor_decoder_context * ctx)19 void _cbor_builder_append(cbor_item_t *item,
20                           struct _cbor_decoder_context *ctx) {
21   if (ctx->stack->size == 0) {
22     /* Top level item */
23     ctx->root = item;
24   } else {
25     /* Part of a bigger structure */
26     switch (ctx->stack->top->item->type) {
27       case CBOR_TYPE_ARRAY: {
28         if (cbor_array_is_definite(ctx->stack->top->item)) {
29           /*
30            * We don't need an explicit check for whether the item still belongs
31            * into this array because if there are extra items, they will cause a
32            * syntax error when decoded.
33            */
34           assert(ctx->stack->top->subitems > 0);
35           cbor_array_push(ctx->stack->top->item, item);
36           ctx->stack->top->subitems--;
37           if (ctx->stack->top->subitems == 0) {
38             cbor_item_t *item = ctx->stack->top->item;
39             _cbor_stack_pop(ctx->stack);
40             _cbor_builder_append(item, ctx);
41           }
42           cbor_decref(&item);
43         } else {
44           /* Indefinite array, don't bother with subitems */
45           cbor_array_push(ctx->stack->top->item, item);
46           cbor_decref(&item);
47         }
48         break;
49       }
50       case CBOR_TYPE_MAP: {
51         /* We use 0 and 1 subitems to distinguish between keys and values in
52          * indefinite items */
53         if (ctx->stack->top->subitems % 2) {
54           /* Odd record, this is a value */
55           _cbor_map_add_value(ctx->stack->top->item, cbor_move(item));
56         } else {
57           /* Even record, this is a key */
58           _cbor_map_add_key(ctx->stack->top->item, cbor_move(item));
59         }
60         if (cbor_map_is_definite(ctx->stack->top->item)) {
61           ctx->stack->top->subitems--;
62           if (ctx->stack->top->subitems == 0) {
63             cbor_item_t *item = ctx->stack->top->item;
64             _cbor_stack_pop(ctx->stack);
65             _cbor_builder_append(item, ctx);
66           }
67         } else {
68           ctx->stack->top->subitems ^=
69               1; /* Flip the indicator for indefinite items */
70         }
71         break;
72       }
73       case CBOR_TYPE_TAG: {
74         assert(ctx->stack->top->subitems == 1);
75         cbor_tag_set_item(ctx->stack->top->item, item);
76         cbor_decref(&item); /* Give up on our reference */
77         cbor_item_t *item = ctx->stack->top->item;
78         _cbor_stack_pop(ctx->stack);
79         _cbor_builder_append(item, ctx);
80         break;
81       }
82       default: {
83         cbor_decref(&item);
84         ctx->syntax_error = true;
85       }
86     }
87   }
88 }
89 
90 // TODO: refactor this to take the parameter name, this is way too magical
91 #define CHECK_RES                  \
92   do {                             \
93     if (res == NULL) {             \
94       ctx->creation_failed = true; \
95       return;                      \
96     }                              \
97   } while (0)
98 
cbor_builder_uint8_callback(void * context,uint8_t value)99 void cbor_builder_uint8_callback(void *context, uint8_t value) {
100   struct _cbor_decoder_context *ctx = context;
101   cbor_item_t *res = cbor_new_int8();
102   CHECK_RES;
103   cbor_mark_uint(res);
104   cbor_set_uint8(res, value);
105   _cbor_builder_append(res, ctx);
106 }
107 
cbor_builder_uint16_callback(void * context,uint16_t value)108 void cbor_builder_uint16_callback(void *context, uint16_t value) {
109   struct _cbor_decoder_context *ctx = context;
110   cbor_item_t *res = cbor_new_int16();
111   CHECK_RES;
112   cbor_mark_uint(res);
113   cbor_set_uint16(res, value);
114   _cbor_builder_append(res, ctx);
115 }
116 
cbor_builder_uint32_callback(void * context,uint32_t value)117 void cbor_builder_uint32_callback(void *context, uint32_t value) {
118   struct _cbor_decoder_context *ctx = context;
119   cbor_item_t *res = cbor_new_int32();
120   CHECK_RES;
121   cbor_mark_uint(res);
122   cbor_set_uint32(res, value);
123   _cbor_builder_append(res, ctx);
124 }
125 
cbor_builder_uint64_callback(void * context,uint64_t value)126 void cbor_builder_uint64_callback(void *context, uint64_t value) {
127   struct _cbor_decoder_context *ctx = context;
128   cbor_item_t *res = cbor_new_int64();
129   CHECK_RES;
130   cbor_mark_uint(res);
131   cbor_set_uint64(res, value);
132   _cbor_builder_append(res, ctx);
133 }
134 
cbor_builder_negint8_callback(void * context,uint8_t value)135 void cbor_builder_negint8_callback(void *context, uint8_t value) {
136   struct _cbor_decoder_context *ctx = context;
137   cbor_item_t *res = cbor_new_int8();
138   CHECK_RES;
139   cbor_mark_negint(res);
140   cbor_set_uint8(res, value);
141   _cbor_builder_append(res, ctx);
142 }
143 
cbor_builder_negint16_callback(void * context,uint16_t value)144 void cbor_builder_negint16_callback(void *context, uint16_t value) {
145   struct _cbor_decoder_context *ctx = context;
146   cbor_item_t *res = cbor_new_int16();
147   cbor_mark_negint(res);
148   cbor_set_uint16(res, value);
149   _cbor_builder_append(res, ctx);
150 }
151 
cbor_builder_negint32_callback(void * context,uint32_t value)152 void cbor_builder_negint32_callback(void *context, uint32_t value) {
153   struct _cbor_decoder_context *ctx = context;
154   cbor_item_t *res = cbor_new_int32();
155   CHECK_RES;
156   cbor_mark_negint(res);
157   cbor_set_uint32(res, value);
158   _cbor_builder_append(res, ctx);
159 }
160 
cbor_builder_negint64_callback(void * context,uint64_t value)161 void cbor_builder_negint64_callback(void *context, uint64_t value) {
162   struct _cbor_decoder_context *ctx = context;
163   cbor_item_t *res = cbor_new_int64();
164   CHECK_RES;
165   cbor_mark_negint(res);
166   cbor_set_uint64(res, value);
167   _cbor_builder_append(res, ctx);
168 }
169 
cbor_builder_byte_string_callback(void * context,cbor_data data,size_t length)170 void cbor_builder_byte_string_callback(void *context, cbor_data data,
171                                        size_t length) {
172   struct _cbor_decoder_context *ctx = context;
173   unsigned char *new_handle = _CBOR_MALLOC(length);
174   if (new_handle == NULL) {
175     ctx->creation_failed = true;
176     return;
177   }
178 
179   memcpy(new_handle, data, length);
180   cbor_item_t *res = cbor_new_definite_bytestring();
181 
182   if (res == NULL) {
183     _CBOR_FREE(new_handle);
184     ctx->creation_failed = true;
185     return;
186   }
187 
188   cbor_bytestring_set_handle(res, new_handle, length);
189 
190   if (ctx->stack->size > 0 && cbor_isa_bytestring(ctx->stack->top->item)) {
191     if (cbor_bytestring_is_indefinite(ctx->stack->top->item)) {
192       cbor_bytestring_add_chunk(ctx->stack->top->item, cbor_move(res));
193     } else {
194       cbor_decref(&res);
195       ctx->syntax_error = true;
196     }
197   } else {
198     _cbor_builder_append(res, ctx);
199   }
200 }
201 
cbor_builder_byte_string_start_callback(void * context)202 void cbor_builder_byte_string_start_callback(void *context) {
203   struct _cbor_decoder_context *ctx = context;
204   cbor_item_t *res = cbor_new_indefinite_bytestring();
205   CHECK_RES;
206   _cbor_stack_push(ctx->stack, res, 0);
207 }
208 
cbor_builder_string_callback(void * context,cbor_data data,size_t length)209 void cbor_builder_string_callback(void *context, cbor_data data,
210                                   size_t length) {
211   struct _cbor_decoder_context *ctx = context;
212   struct _cbor_unicode_status unicode_status;
213 
214   size_t codepoint_count =
215       _cbor_unicode_codepoint_count(data, length, &unicode_status);
216 
217   if (unicode_status.status == _CBOR_UNICODE_BADCP) {
218     ctx->syntax_error = true;
219     return;
220   }
221 
222   unsigned char *new_handle = _CBOR_MALLOC(length);
223 
224   if (new_handle == NULL) {
225     ctx->creation_failed = true;
226     return;
227   }
228 
229   memcpy(new_handle, data, length);
230   cbor_item_t *res = cbor_new_definite_string();
231   cbor_string_set_handle(res, new_handle, length);
232   res->metadata.string_metadata.codepoint_count = codepoint_count;
233 
234   /* Careful here: order matters */
235   if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item)) {
236     if (cbor_string_is_indefinite(ctx->stack->top->item)) {
237       cbor_string_add_chunk(ctx->stack->top->item, cbor_move(res));
238     } else {
239       cbor_decref(&res);
240       ctx->syntax_error = true;
241     }
242   } else {
243     _cbor_builder_append(res, ctx);
244   }
245 }
246 
cbor_builder_string_start_callback(void * context)247 void cbor_builder_string_start_callback(void *context) {
248   struct _cbor_decoder_context *ctx = context;
249   cbor_item_t *res = cbor_new_indefinite_string();
250   CHECK_RES;
251   _cbor_stack_push(ctx->stack, res, 0);
252 }
253 
cbor_builder_array_start_callback(void * context,size_t size)254 void cbor_builder_array_start_callback(void *context, size_t size) {
255   struct _cbor_decoder_context *ctx = context;
256   cbor_item_t *res = cbor_new_definite_array(size);
257   CHECK_RES;
258   if (size > 0) {
259     _cbor_stack_push(ctx->stack, res, size);
260   } else {
261     _cbor_builder_append(res, ctx);
262   }
263 }
264 
cbor_builder_indef_array_start_callback(void * context)265 void cbor_builder_indef_array_start_callback(void *context) {
266   struct _cbor_decoder_context *ctx = context;
267   cbor_item_t *res = cbor_new_indefinite_array();
268   CHECK_RES;
269   _cbor_stack_push(ctx->stack, res, 0);
270 }
271 
cbor_builder_indef_map_start_callback(void * context)272 void cbor_builder_indef_map_start_callback(void *context) {
273   struct _cbor_decoder_context *ctx = context;
274   cbor_item_t *res = cbor_new_indefinite_map();
275   CHECK_RES;
276   _cbor_stack_push(ctx->stack, res, 0);
277 }
278 
cbor_builder_map_start_callback(void * context,size_t size)279 void cbor_builder_map_start_callback(void *context, size_t size) {
280   struct _cbor_decoder_context *ctx = context;
281   cbor_item_t *res = cbor_new_definite_map(size);
282   CHECK_RES;
283   if (size > 0) {
284     _cbor_stack_push(ctx->stack, res, size * 2);
285   } else {
286     _cbor_builder_append(res, ctx);
287   }
288 }
289 
290 /**
291  * Is the (partially constructed) item indefinite?
292  */
_cbor_is_indefinite(cbor_item_t * item)293 bool _cbor_is_indefinite(cbor_item_t *item) {
294   switch (item->type) {
295     case CBOR_TYPE_BYTESTRING:
296       return item->metadata.bytestring_metadata.type ==
297              _CBOR_METADATA_INDEFINITE;
298     case CBOR_TYPE_STRING:
299       return item->metadata.string_metadata.type == _CBOR_METADATA_INDEFINITE;
300     case CBOR_TYPE_ARRAY:
301       return item->metadata.array_metadata.type == _CBOR_METADATA_INDEFINITE;
302     case CBOR_TYPE_MAP:
303       return item->metadata.map_metadata.type == _CBOR_METADATA_INDEFINITE;
304     default:
305       return false;
306   }
307 }
308 
cbor_builder_indef_break_callback(void * context)309 void cbor_builder_indef_break_callback(void *context) {
310   struct _cbor_decoder_context *ctx = context;
311   /* There must be an item to break out of*/
312   if (ctx->stack->size > 0) {
313     cbor_item_t *item = ctx->stack->top->item;
314     if (_cbor_is_indefinite(
315             item) && /* Only indefinite items can be terminated by 0xFF */
316         /* Special case: we cannot append up if an indefinite map is incomplete
317            (we are expecting a value). */
318         (item->type != CBOR_TYPE_MAP || ctx->stack->top->subitems % 2 == 0)) {
319       _cbor_stack_pop(ctx->stack);
320       _cbor_builder_append(item, ctx);
321       return;
322     }
323   }
324 
325   ctx->syntax_error = true;
326 }
327 
cbor_builder_float2_callback(void * context,float value)328 void cbor_builder_float2_callback(void *context, float value) {
329   struct _cbor_decoder_context *ctx = context;
330   cbor_item_t *res = cbor_new_float2();
331   cbor_set_float2(res, value);
332   _cbor_builder_append(res, ctx);
333 }
334 
cbor_builder_float4_callback(void * context,float value)335 void cbor_builder_float4_callback(void *context, float value) {
336   struct _cbor_decoder_context *ctx = context;
337   cbor_item_t *res = cbor_new_float4();
338   CHECK_RES;
339   cbor_set_float4(res, value);
340   _cbor_builder_append(res, ctx);
341 }
342 
cbor_builder_float8_callback(void * context,double value)343 void cbor_builder_float8_callback(void *context, double value) {
344   struct _cbor_decoder_context *ctx = context;
345   cbor_item_t *res = cbor_new_float8();
346   CHECK_RES;
347   cbor_set_float8(res, value);
348   _cbor_builder_append(res, ctx);
349 }
350 
cbor_builder_null_callback(void * context)351 void cbor_builder_null_callback(void *context) {
352   struct _cbor_decoder_context *ctx = context;
353   cbor_item_t *res = cbor_new_null();
354   CHECK_RES;
355   _cbor_builder_append(res, ctx);
356 }
357 
cbor_builder_undefined_callback(void * context)358 void cbor_builder_undefined_callback(void *context) {
359   struct _cbor_decoder_context *ctx = context;
360   cbor_item_t *res = cbor_new_undef();
361   CHECK_RES;
362   _cbor_builder_append(res, ctx);
363 }
364 
cbor_builder_boolean_callback(void * context,bool value)365 void cbor_builder_boolean_callback(void *context, bool value) {
366   struct _cbor_decoder_context *ctx = context;
367   cbor_item_t *res = cbor_build_bool(value);
368   CHECK_RES;
369   _cbor_builder_append(res, ctx);
370 }
371 
cbor_builder_tag_callback(void * context,uint64_t value)372 void cbor_builder_tag_callback(void *context, uint64_t value) {
373   struct _cbor_decoder_context *ctx = context;
374   cbor_item_t *res = cbor_new_tag(value);
375   CHECK_RES;
376   _cbor_stack_push(ctx->stack, res, 1);
377 }
378