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 "cbor.h"
9 #include "cbor/internal/builder_callbacks.h"
10 #include "cbor/internal/loaders.h"
11
cbor_load(cbor_data source,size_t source_size,struct cbor_load_result * result)12 cbor_item_t *cbor_load(cbor_data source, size_t source_size,
13 struct cbor_load_result *result) {
14 /* Context stack */
15 static struct cbor_callbacks callbacks = {
16 .uint8 = &cbor_builder_uint8_callback,
17 .uint16 = &cbor_builder_uint16_callback,
18 .uint32 = &cbor_builder_uint32_callback,
19 .uint64 = &cbor_builder_uint64_callback,
20
21 .negint8 = &cbor_builder_negint8_callback,
22 .negint16 = &cbor_builder_negint16_callback,
23 .negint32 = &cbor_builder_negint32_callback,
24 .negint64 = &cbor_builder_negint64_callback,
25
26 .byte_string = &cbor_builder_byte_string_callback,
27 .byte_string_start = &cbor_builder_byte_string_start_callback,
28
29 .string = &cbor_builder_string_callback,
30 .string_start = &cbor_builder_string_start_callback,
31
32 .array_start = &cbor_builder_array_start_callback,
33 .indef_array_start = &cbor_builder_indef_array_start_callback,
34
35 .map_start = &cbor_builder_map_start_callback,
36 .indef_map_start = &cbor_builder_indef_map_start_callback,
37
38 .tag = &cbor_builder_tag_callback,
39
40 .null = &cbor_builder_null_callback,
41 .undefined = &cbor_builder_undefined_callback,
42 .boolean = &cbor_builder_boolean_callback,
43 .float2 = &cbor_builder_float2_callback,
44 .float4 = &cbor_builder_float4_callback,
45 .float8 = &cbor_builder_float8_callback,
46 .indef_break = &cbor_builder_indef_break_callback};
47
48 if (source_size == 0) {
49 result->error.code = CBOR_ERR_NODATA;
50 return NULL;
51 }
52 struct _cbor_stack stack = _cbor_stack_init();
53
54 /* Target for callbacks */
55 struct _cbor_decoder_context context = (struct _cbor_decoder_context){
56 .stack = &stack, .creation_failed = false, .syntax_error = false};
57 struct cbor_decoder_result decode_result;
58 *result =
59 (struct cbor_load_result){.read = 0, .error = {.code = CBOR_ERR_NONE}};
60
61 do {
62 if (source_size > result->read) { /* Check for overflows */
63 decode_result =
64 cbor_stream_decode(source + result->read, source_size - result->read,
65 &callbacks, &context);
66 } else {
67 result->error = (struct cbor_error){.code = CBOR_ERR_NOTENOUGHDATA,
68 .position = result->read};
69 goto error;
70 }
71
72 switch (decode_result.status) {
73 case CBOR_DECODER_FINISHED:
74 /* Everything OK */
75 {
76 result->read += decode_result.read;
77 break;
78 }
79 case CBOR_DECODER_NEDATA:
80 /* Data length doesn't match MTB expectation */
81 {
82 result->error.code = CBOR_ERR_NOTENOUGHDATA;
83 goto error;
84 }
85 case CBOR_DECODER_ERROR:
86 /* Reserved/malformed item */
87 {
88 result->error.code = CBOR_ERR_MALFORMATED;
89 goto error;
90 }
91 }
92
93 if (context.creation_failed) {
94 /* Most likely unsuccessful allocation - our callback has failed */
95 result->error.code = CBOR_ERR_MEMERROR;
96 goto error;
97 } else if (context.syntax_error) {
98 result->error.code = CBOR_ERR_SYNTAXERROR;
99 goto error;
100 }
101 } while (stack.size > 0);
102
103 return context.root;
104
105 error:
106 result->error.position = result->read;
107 // debug_print("Failed with decoder error %d at %d\n", result->error.code,
108 // result->error.position); cbor_describe(stack.top->item, stdout);
109 /* Free the stack */
110 while (stack.size > 0) {
111 cbor_decref(&stack.top->item);
112 _cbor_stack_pop(&stack);
113 }
114 return NULL;
115 }
116
_cbor_copy_int(cbor_item_t * item,bool negative)117 static cbor_item_t *_cbor_copy_int(cbor_item_t *item, bool negative) {
118 cbor_item_t *res;
119 switch (cbor_int_get_width(item)) {
120 case CBOR_INT_8:
121 res = cbor_build_uint8(cbor_get_uint8(item));
122 break;
123 case CBOR_INT_16:
124 res = cbor_build_uint16(cbor_get_uint16(item));
125 break;
126 case CBOR_INT_32:
127 res = cbor_build_uint32(cbor_get_uint32(item));
128 break;
129 case CBOR_INT_64:
130 res = cbor_build_uint64(cbor_get_uint64(item));
131 break;
132 }
133
134 if (negative) cbor_mark_negint(res);
135
136 return res;
137 }
138
_cbor_copy_float_ctrl(cbor_item_t * item)139 static cbor_item_t *_cbor_copy_float_ctrl(cbor_item_t *item) {
140 // cppcheck-suppress missingReturn
141 switch (cbor_float_get_width(item)) {
142 case CBOR_FLOAT_0:
143 return cbor_build_ctrl(cbor_ctrl_value(item));
144 case CBOR_FLOAT_16:
145 return cbor_build_float2(cbor_float_get_float2(item));
146 case CBOR_FLOAT_32:
147 return cbor_build_float4(cbor_float_get_float4(item));
148 case CBOR_FLOAT_64:
149 return cbor_build_float8(cbor_float_get_float8(item));
150 }
151 }
152
cbor_copy(cbor_item_t * item)153 cbor_item_t *cbor_copy(cbor_item_t *item) {
154 // cppcheck-suppress missingReturn
155 switch (cbor_typeof(item)) {
156 case CBOR_TYPE_UINT:
157 return _cbor_copy_int(item, false);
158 case CBOR_TYPE_NEGINT:
159 return _cbor_copy_int(item, true);
160 case CBOR_TYPE_BYTESTRING:
161 if (cbor_bytestring_is_definite(item)) {
162 return cbor_build_bytestring(cbor_bytestring_handle(item),
163 cbor_bytestring_length(item));
164 } else {
165 cbor_item_t *res = cbor_new_indefinite_bytestring();
166 if (res == NULL) {
167 return NULL;
168 }
169
170 for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {
171 cbor_item_t *chunk_copy =
172 cbor_copy(cbor_bytestring_chunks_handle(item)[i]);
173 if (chunk_copy == NULL) {
174 cbor_decref(&res);
175 return NULL;
176 }
177 if (!cbor_bytestring_add_chunk(res, chunk_copy)) {
178 cbor_decref(&chunk_copy);
179 cbor_decref(&res);
180 return NULL;
181 }
182 cbor_decref(&chunk_copy);
183 }
184 return res;
185 }
186 case CBOR_TYPE_STRING:
187 if (cbor_string_is_definite(item)) {
188 return cbor_build_stringn((const char *)cbor_string_handle(item),
189 cbor_string_length(item));
190 } else {
191 cbor_item_t *res = cbor_new_indefinite_string();
192 if (res == NULL) {
193 return NULL;
194 }
195
196 for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {
197 cbor_item_t *chunk_copy =
198 cbor_copy(cbor_string_chunks_handle(item)[i]);
199 if (chunk_copy == NULL) {
200 cbor_decref(&res);
201 return NULL;
202 }
203 if (!cbor_string_add_chunk(res, chunk_copy)) {
204 cbor_decref(&chunk_copy);
205 cbor_decref(&res);
206 return NULL;
207 }
208 cbor_decref(&chunk_copy);
209 }
210 return res;
211 }
212 case CBOR_TYPE_ARRAY: {
213 cbor_item_t *res;
214 if (cbor_array_is_definite(item)) {
215 res = cbor_new_definite_array(cbor_array_size(item));
216 } else {
217 res = cbor_new_indefinite_array();
218 }
219 if (res == NULL) {
220 return NULL;
221 }
222
223 for (size_t i = 0; i < cbor_array_size(item); i++) {
224 cbor_item_t *entry_copy = cbor_copy(cbor_move(cbor_array_get(item, i)));
225 if (entry_copy == NULL) {
226 cbor_decref(&res);
227 return NULL;
228 }
229 if (!cbor_array_push(res, entry_copy)) {
230 cbor_decref(&entry_copy);
231 cbor_decref(&res);
232 return NULL;
233 }
234 cbor_decref(&entry_copy);
235 }
236 return res;
237 }
238 case CBOR_TYPE_MAP: {
239 cbor_item_t *res;
240 if (cbor_map_is_definite(item)) {
241 res = cbor_new_definite_map(cbor_map_size(item));
242 } else {
243 res = cbor_new_indefinite_map();
244 }
245 if (res == NULL) {
246 return NULL;
247 }
248
249 struct cbor_pair *it = cbor_map_handle(item);
250 for (size_t i = 0; i < cbor_map_size(item); i++) {
251 cbor_item_t *key_copy = cbor_copy(it[i].key);
252 if (key_copy == NULL) {
253 cbor_decref(&res);
254 return NULL;
255 }
256 cbor_item_t *value_copy = cbor_copy(it[i].value);
257 if (value_copy == NULL) {
258 cbor_decref(&res);
259 cbor_decref(&key_copy);
260 return NULL;
261 }
262 if (!cbor_map_add(res, (struct cbor_pair){.key = key_copy,
263 .value = value_copy})) {
264 cbor_decref(&res);
265 cbor_decref(&key_copy);
266 cbor_decref(&value_copy);
267 return NULL;
268 }
269 cbor_decref(&key_copy);
270 cbor_decref(&value_copy);
271 }
272 return res;
273 }
274 case CBOR_TYPE_TAG: {
275 cbor_item_t *item_copy = cbor_copy(cbor_move(cbor_tag_item(item)));
276 if (item_copy == NULL) {
277 return NULL;
278 }
279 cbor_item_t *tag = cbor_build_tag(cbor_tag_value(item), item_copy);
280 cbor_decref(&item_copy);
281 return tag;
282 }
283 case CBOR_TYPE_FLOAT_CTRL:
284 return _cbor_copy_float_ctrl(item);
285 }
286 }
287
288 #if CBOR_PRETTY_PRINTER
289
290 #include <inttypes.h>
291 #include <locale.h>
292 #include <stdlib.h>
293 #include <wchar.h>
294
295 #define __STDC_FORMAT_MACROS
296
_pow(int b,int ex)297 static int _pow(int b, int ex) {
298 if (ex == 0) return 1;
299 int res = b;
300 while (--ex > 0) res *= b;
301 return res;
302 }
303
_cbor_nested_describe(cbor_item_t * item,FILE * out,int indent)304 static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
305 setlocale(LC_ALL, "");
306 switch (cbor_typeof(item)) {
307 case CBOR_TYPE_UINT: {
308 fprintf(out, "%*s[CBOR_TYPE_UINT] ", indent, " ");
309 fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
310 fprintf(out, "Value: %" PRIu64 "\n", cbor_get_int(item));
311 break;
312 }
313 case CBOR_TYPE_NEGINT: {
314 fprintf(out, "%*s[CBOR_TYPE_NEGINT] ", indent, " ");
315 fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
316 fprintf(out, "Value: -%" PRIu64 " -1\n", cbor_get_int(item));
317 break;
318 }
319 case CBOR_TYPE_BYTESTRING: {
320 fprintf(out, "%*s[CBOR_TYPE_BYTESTRING] ", indent, " ");
321 if (cbor_bytestring_is_indefinite(item)) {
322 fprintf(out, "Indefinite, with %zu chunks:\n",
323 cbor_bytestring_chunk_count(item));
324 for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++)
325 _cbor_nested_describe(cbor_bytestring_chunks_handle(item)[i], out,
326 indent + 4);
327 } else {
328 fprintf(out, "Definite, length %zuB\n", cbor_bytestring_length(item));
329 }
330 break;
331 }
332 case CBOR_TYPE_STRING: {
333 fprintf(out, "%*s[CBOR_TYPE_STRING] ", indent, " ");
334 if (cbor_string_is_indefinite(item)) {
335 fprintf(out, "Indefinite, with %zu chunks:\n",
336 cbor_string_chunk_count(item));
337 for (size_t i = 0; i < cbor_string_chunk_count(item); i++)
338 _cbor_nested_describe(cbor_string_chunks_handle(item)[i], out,
339 indent + 4);
340 } else {
341 fprintf(out, "Definite, length %zuB, %zu codepoints\n",
342 cbor_string_length(item), cbor_string_codepoint_count(item));
343 /* Careful - this doesn't support multibyte characters! */
344 /* Printing those is out of the scope of this demo :) */
345 /* libICU is your friend */
346 fprintf(out, "%*s", indent + 4, " ");
347 /* XXX: no null at the end -> confused vprintf */
348 fwrite(cbor_string_handle(item), (int)cbor_string_length(item), 1, out);
349 fprintf(out, "\n");
350 }
351 break;
352 }
353 case CBOR_TYPE_ARRAY: {
354 fprintf(out, "%*s[CBOR_TYPE_ARRAY] ", indent, " ");
355 if (cbor_array_is_definite(item)) {
356 fprintf(out, "Definite, size: %zu\n", cbor_array_size(item));
357 } else {
358 fprintf(out, "Indefinite, size: %zu\n", cbor_array_size(item));
359 }
360
361 for (size_t i = 0; i < cbor_array_size(item); i++)
362 _cbor_nested_describe(cbor_array_handle(item)[i], out, indent + 4);
363 break;
364 }
365 case CBOR_TYPE_MAP: {
366 fprintf(out, "%*s[CBOR_TYPE_MAP] ", indent, " ");
367 if (cbor_map_is_definite(item)) {
368 fprintf(out, "Definite, size: %zu\n", cbor_map_size(item));
369 } else {
370 fprintf(out, "Indefinite, size: %zu\n", cbor_map_size(item));
371 }
372
373 for (size_t i = 0; i < cbor_map_size(item); i++) {
374 _cbor_nested_describe(cbor_map_handle(item)[i].key, out, indent + 4);
375 _cbor_nested_describe(cbor_map_handle(item)[i].value, out, indent + 4);
376 }
377 break;
378 }
379 case CBOR_TYPE_TAG: {
380 fprintf(out, "%*s[CBOR_TYPE_TAG] ", indent, " ");
381 fprintf(out, "Value: %" PRIu64 "\n", cbor_tag_value(item));
382 _cbor_nested_describe(cbor_move(cbor_tag_item(item)), out, indent + 4);
383 break;
384 }
385 case CBOR_TYPE_FLOAT_CTRL: {
386 fprintf(out, "%*s[CBOR_TYPE_FLOAT_CTRL] ", indent, " ");
387 if (cbor_float_ctrl_is_ctrl(item)) {
388 if (cbor_is_bool(item))
389 fprintf(out, "Bool: %s\n", cbor_get_bool(item) ? "true" : "false");
390 else if (cbor_is_undef(item))
391 fprintf(out, "Undefined\n");
392 else if (cbor_is_null(item))
393 fprintf(out, "Null\n");
394 else
395 fprintf(out, "Simple value %d\n", cbor_ctrl_value(item));
396 } else {
397 fprintf(out, "Width: %dB, ", _pow(2, cbor_float_get_width(item)));
398 fprintf(out, "value: %lf\n", cbor_float_get_float(item));
399 }
400 break;
401 }
402 }
403 }
404
cbor_describe(cbor_item_t * item,FILE * out)405 void cbor_describe(cbor_item_t *item, FILE *out) {
406 _cbor_nested_describe(item, out, 0);
407 }
408
409 #endif
410