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