1 /*
2 * Copyright (c) 2014-2020 Pavel Kalvoda <[email protected]>
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 #define CHECK_RES(ctx, res) \
91 do { \
92 if (res == NULL) { \
93 ctx->creation_failed = true; \
94 return; \
95 } \
96 } while (0)
97
98 #define PUSH_CTX_STACK(ctx, res, subitems) \
99 do { \
100 if (_cbor_stack_push(ctx->stack, res, subitems) == NULL) { \
101 cbor_decref(&res); \
102 ctx->creation_failed = true; \
103 } \
104 } while (0)
105
cbor_builder_uint8_callback(void * context,uint8_t value)106 void cbor_builder_uint8_callback(void *context, uint8_t value) {
107 struct _cbor_decoder_context *ctx = context;
108 cbor_item_t *res = cbor_new_int8();
109 CHECK_RES(ctx, res);
110 cbor_mark_uint(res);
111 cbor_set_uint8(res, value);
112 _cbor_builder_append(res, ctx);
113 }
114
cbor_builder_uint16_callback(void * context,uint16_t value)115 void cbor_builder_uint16_callback(void *context, uint16_t value) {
116 struct _cbor_decoder_context *ctx = context;
117 cbor_item_t *res = cbor_new_int16();
118 CHECK_RES(ctx, res);
119 cbor_mark_uint(res);
120 cbor_set_uint16(res, value);
121 _cbor_builder_append(res, ctx);
122 }
123
cbor_builder_uint32_callback(void * context,uint32_t value)124 void cbor_builder_uint32_callback(void *context, uint32_t value) {
125 struct _cbor_decoder_context *ctx = context;
126 cbor_item_t *res = cbor_new_int32();
127 CHECK_RES(ctx, res);
128 cbor_mark_uint(res);
129 cbor_set_uint32(res, value);
130 _cbor_builder_append(res, ctx);
131 }
132
cbor_builder_uint64_callback(void * context,uint64_t value)133 void cbor_builder_uint64_callback(void *context, uint64_t value) {
134 struct _cbor_decoder_context *ctx = context;
135 cbor_item_t *res = cbor_new_int64();
136 CHECK_RES(ctx, res);
137 cbor_mark_uint(res);
138 cbor_set_uint64(res, value);
139 _cbor_builder_append(res, ctx);
140 }
141
cbor_builder_negint8_callback(void * context,uint8_t value)142 void cbor_builder_negint8_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_negint(res);
147 cbor_set_uint8(res, value);
148 _cbor_builder_append(res, ctx);
149 }
150
cbor_builder_negint16_callback(void * context,uint16_t value)151 void cbor_builder_negint16_callback(void *context, uint16_t value) {
152 struct _cbor_decoder_context *ctx = context;
153 cbor_item_t *res = cbor_new_int16();
154 cbor_mark_negint(res);
155 cbor_set_uint16(res, value);
156 _cbor_builder_append(res, ctx);
157 }
158
cbor_builder_negint32_callback(void * context,uint32_t value)159 void cbor_builder_negint32_callback(void *context, uint32_t value) {
160 struct _cbor_decoder_context *ctx = context;
161 cbor_item_t *res = cbor_new_int32();
162 CHECK_RES(ctx, res);
163 cbor_mark_negint(res);
164 cbor_set_uint32(res, value);
165 _cbor_builder_append(res, ctx);
166 }
167
cbor_builder_negint64_callback(void * context,uint64_t value)168 void cbor_builder_negint64_callback(void *context, uint64_t value) {
169 struct _cbor_decoder_context *ctx = context;
170 cbor_item_t *res = cbor_new_int64();
171 CHECK_RES(ctx, res);
172 cbor_mark_negint(res);
173 cbor_set_uint64(res, value);
174 _cbor_builder_append(res, ctx);
175 }
176
cbor_builder_byte_string_callback(void * context,cbor_data data,size_t length)177 void cbor_builder_byte_string_callback(void *context, cbor_data data,
178 size_t length) {
179 struct _cbor_decoder_context *ctx = context;
180 unsigned char *new_handle = _CBOR_MALLOC(length);
181 if (new_handle == NULL) {
182 ctx->creation_failed = true;
183 return;
184 }
185
186 memcpy(new_handle, data, length);
187 cbor_item_t *res = cbor_new_definite_bytestring();
188
189 if (res == NULL) {
190 _CBOR_FREE(new_handle);
191 ctx->creation_failed = true;
192 return;
193 }
194
195 cbor_bytestring_set_handle(res, new_handle, length);
196
197 if (ctx->stack->size > 0 && cbor_isa_bytestring(ctx->stack->top->item)) {
198 if (cbor_bytestring_is_indefinite(ctx->stack->top->item)) {
199 cbor_bytestring_add_chunk(ctx->stack->top->item, cbor_move(res));
200 } else {
201 cbor_decref(&res);
202 ctx->syntax_error = true;
203 }
204 } else {
205 _cbor_builder_append(res, ctx);
206 }
207 }
208
cbor_builder_byte_string_start_callback(void * context)209 void cbor_builder_byte_string_start_callback(void *context) {
210 struct _cbor_decoder_context *ctx = context;
211 cbor_item_t *res = cbor_new_indefinite_bytestring();
212 CHECK_RES(ctx, res);
213 PUSH_CTX_STACK(ctx, res, 0);
214 }
215
cbor_builder_string_callback(void * context,cbor_data data,size_t length)216 void cbor_builder_string_callback(void *context, cbor_data data,
217 size_t length) {
218 struct _cbor_decoder_context *ctx = context;
219 struct _cbor_unicode_status unicode_status;
220
221 size_t codepoint_count =
222 _cbor_unicode_codepoint_count(data, length, &unicode_status);
223
224 if (unicode_status.status == _CBOR_UNICODE_BADCP) {
225 ctx->syntax_error = true;
226 return;
227 }
228
229 unsigned char *new_handle = _CBOR_MALLOC(length);
230
231 if (new_handle == NULL) {
232 ctx->creation_failed = true;
233 return;
234 }
235
236 memcpy(new_handle, data, length);
237 cbor_item_t *res = cbor_new_definite_string();
238 if (res == NULL) {
239 _CBOR_FREE(new_handle);
240 ctx->creation_failed = true;
241 return;
242 }
243 cbor_string_set_handle(res, new_handle, length);
244 res->metadata.string_metadata.codepoint_count = codepoint_count;
245
246 /* Careful here: order matters */
247 if (ctx->stack->size > 0 && cbor_isa_string(ctx->stack->top->item)) {
248 if (cbor_string_is_indefinite(ctx->stack->top->item)) {
249 cbor_string_add_chunk(ctx->stack->top->item, cbor_move(res));
250 } else {
251 cbor_decref(&res);
252 ctx->syntax_error = true;
253 }
254 } else {
255 _cbor_builder_append(res, ctx);
256 }
257 }
258
cbor_builder_string_start_callback(void * context)259 void cbor_builder_string_start_callback(void *context) {
260 struct _cbor_decoder_context *ctx = context;
261 cbor_item_t *res = cbor_new_indefinite_string();
262 CHECK_RES(ctx, res);
263 PUSH_CTX_STACK(ctx, res, 0);
264 }
265
cbor_builder_array_start_callback(void * context,size_t size)266 void cbor_builder_array_start_callback(void *context, size_t size) {
267 struct _cbor_decoder_context *ctx = context;
268 cbor_item_t *res = cbor_new_definite_array(size);
269 CHECK_RES(ctx, res);
270 if (size > 0) {
271 PUSH_CTX_STACK(ctx, res, size);
272 } else {
273 _cbor_builder_append(res, ctx);
274 }
275 }
276
cbor_builder_indef_array_start_callback(void * context)277 void cbor_builder_indef_array_start_callback(void *context) {
278 struct _cbor_decoder_context *ctx = context;
279 cbor_item_t *res = cbor_new_indefinite_array();
280 CHECK_RES(ctx, res);
281 PUSH_CTX_STACK(ctx, res, 0);
282 }
283
cbor_builder_indef_map_start_callback(void * context)284 void cbor_builder_indef_map_start_callback(void *context) {
285 struct _cbor_decoder_context *ctx = context;
286 cbor_item_t *res = cbor_new_indefinite_map();
287 CHECK_RES(ctx, res);
288 PUSH_CTX_STACK(ctx, res, 0);
289 }
290
cbor_builder_map_start_callback(void * context,size_t size)291 void cbor_builder_map_start_callback(void *context, size_t size) {
292 struct _cbor_decoder_context *ctx = context;
293 cbor_item_t *res = cbor_new_definite_map(size);
294 CHECK_RES(ctx, res);
295 if (size > 0) {
296 PUSH_CTX_STACK(ctx, res, size * 2);
297 } else {
298 _cbor_builder_append(res, ctx);
299 }
300 }
301
302 /**
303 * Is the (partially constructed) item indefinite?
304 */
_cbor_is_indefinite(cbor_item_t * item)305 bool _cbor_is_indefinite(cbor_item_t *item) {
306 switch (item->type) {
307 case CBOR_TYPE_BYTESTRING:
308 return item->metadata.bytestring_metadata.type ==
309 _CBOR_METADATA_INDEFINITE;
310 case CBOR_TYPE_STRING:
311 return item->metadata.string_metadata.type == _CBOR_METADATA_INDEFINITE;
312 case CBOR_TYPE_ARRAY:
313 return item->metadata.array_metadata.type == _CBOR_METADATA_INDEFINITE;
314 case CBOR_TYPE_MAP:
315 return item->metadata.map_metadata.type == _CBOR_METADATA_INDEFINITE;
316 default:
317 return false;
318 }
319 }
320
cbor_builder_indef_break_callback(void * context)321 void cbor_builder_indef_break_callback(void *context) {
322 struct _cbor_decoder_context *ctx = context;
323 /* There must be an item to break out of*/
324 if (ctx->stack->size > 0) {
325 cbor_item_t *item = ctx->stack->top->item;
326 if (_cbor_is_indefinite(
327 item) && /* Only indefinite items can be terminated by 0xFF */
328 /* Special case: we cannot append up if an indefinite map is incomplete
329 (we are expecting a value). */
330 (item->type != CBOR_TYPE_MAP || ctx->stack->top->subitems % 2 == 0)) {
331 _cbor_stack_pop(ctx->stack);
332 _cbor_builder_append(item, ctx);
333 return;
334 }
335 }
336
337 ctx->syntax_error = true;
338 }
339
cbor_builder_float2_callback(void * context,float value)340 void cbor_builder_float2_callback(void *context, float value) {
341 struct _cbor_decoder_context *ctx = context;
342 cbor_item_t *res = cbor_new_float2();
343 cbor_set_float2(res, value);
344 _cbor_builder_append(res, ctx);
345 }
346
cbor_builder_float4_callback(void * context,float value)347 void cbor_builder_float4_callback(void *context, float value) {
348 struct _cbor_decoder_context *ctx = context;
349 cbor_item_t *res = cbor_new_float4();
350 CHECK_RES(ctx, res);
351 cbor_set_float4(res, value);
352 _cbor_builder_append(res, ctx);
353 }
354
cbor_builder_float8_callback(void * context,double value)355 void cbor_builder_float8_callback(void *context, double value) {
356 struct _cbor_decoder_context *ctx = context;
357 cbor_item_t *res = cbor_new_float8();
358 CHECK_RES(ctx, res);
359 cbor_set_float8(res, value);
360 _cbor_builder_append(res, ctx);
361 }
362
cbor_builder_null_callback(void * context)363 void cbor_builder_null_callback(void *context) {
364 struct _cbor_decoder_context *ctx = context;
365 cbor_item_t *res = cbor_new_null();
366 CHECK_RES(ctx, res);
367 _cbor_builder_append(res, ctx);
368 }
369
cbor_builder_undefined_callback(void * context)370 void cbor_builder_undefined_callback(void *context) {
371 struct _cbor_decoder_context *ctx = context;
372 cbor_item_t *res = cbor_new_undef();
373 CHECK_RES(ctx, res);
374 _cbor_builder_append(res, ctx);
375 }
376
cbor_builder_boolean_callback(void * context,bool value)377 void cbor_builder_boolean_callback(void *context, bool value) {
378 struct _cbor_decoder_context *ctx = context;
379 cbor_item_t *res = cbor_build_bool(value);
380 CHECK_RES(ctx, res);
381 _cbor_builder_append(res, ctx);
382 }
383
cbor_builder_tag_callback(void * context,uint64_t value)384 void cbor_builder_tag_callback(void *context, uint64_t value) {
385 struct _cbor_decoder_context *ctx = context;
386 cbor_item_t *res = cbor_new_tag(value);
387 CHECK_RES(ctx, res);
388 PUSH_CTX_STACK(ctx, res, 1);
389 }
390