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