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 "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/malformated 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 /* Move the result before free */
104 cbor_item_t *result_item = context.root;
105 return result_item;
106
107 error:
108 result->error.position = result->read;
109 // debug_print("Failed with decoder error %d at %d\n", result->error.code,
110 // result->error.position); cbor_describe(stack.top->item, stdout);
111 /* Free the stack */
112 while (stack.size > 0) {
113 cbor_decref(&stack.top->item);
114 _cbor_stack_pop(&stack);
115 }
116 return NULL;
117 }
118
_cbor_copy_int(cbor_item_t * item,bool negative)119 static cbor_item_t *_cbor_copy_int(cbor_item_t *item, bool negative) {
120 cbor_item_t *res;
121 switch (cbor_int_get_width(item)) {
122 case CBOR_INT_8:
123 res = cbor_build_uint8(cbor_get_uint8(item));
124 break;
125 case CBOR_INT_16:
126 res = cbor_build_uint16(cbor_get_uint16(item));
127 break;
128 case CBOR_INT_32:
129 res = cbor_build_uint32(cbor_get_uint32(item));
130 break;
131 case CBOR_INT_64:
132 res = cbor_build_uint64(cbor_get_uint64(item));
133 break;
134 default:
135 return NULL;
136 }
137
138 if (negative) cbor_mark_negint(res);
139
140 return res;
141 }
142
_cbor_copy_float_ctrl(cbor_item_t * item)143 static cbor_item_t *_cbor_copy_float_ctrl(cbor_item_t *item) {
144 switch (cbor_float_get_width(item)) {
145 case CBOR_FLOAT_0:
146 return cbor_build_ctrl(cbor_ctrl_value(item));
147 case CBOR_FLOAT_16:
148 return cbor_build_float2(cbor_float_get_float2(item));
149 case CBOR_FLOAT_32:
150 return cbor_build_float4(cbor_float_get_float4(item));
151 case CBOR_FLOAT_64:
152 return cbor_build_float8(cbor_float_get_float8(item));
153 }
154
155 return NULL;
156 }
157
cbor_copy(cbor_item_t * item)158 cbor_item_t *cbor_copy(cbor_item_t *item) {
159 switch (cbor_typeof(item)) {
160 case CBOR_TYPE_UINT:
161 return _cbor_copy_int(item, false);
162 case CBOR_TYPE_NEGINT:
163 return _cbor_copy_int(item, true);
164 case CBOR_TYPE_BYTESTRING:
165 if (cbor_bytestring_is_definite(item)) {
166 return cbor_build_bytestring(cbor_bytestring_handle(item),
167 cbor_bytestring_length(item));
168 } else {
169 cbor_item_t *res = cbor_new_indefinite_bytestring();
170 for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++)
171 cbor_bytestring_add_chunk(
172 res,
173 cbor_move(cbor_copy(cbor_bytestring_chunks_handle(item)[i])));
174 return res;
175 }
176 case CBOR_TYPE_STRING:
177 if (cbor_string_is_definite(item)) {
178 return cbor_build_stringn((const char *)cbor_string_handle(item),
179 cbor_string_length(item));
180 } else {
181 cbor_item_t *res = cbor_new_indefinite_string();
182 for (size_t i = 0; i < cbor_string_chunk_count(item); i++)
183 cbor_string_add_chunk(
184 res, cbor_move(cbor_copy(cbor_string_chunks_handle(item)[i])));
185 return res;
186 }
187 case CBOR_TYPE_ARRAY: {
188 cbor_item_t *res;
189 if (cbor_array_is_definite(item))
190 res = cbor_new_definite_array(cbor_array_size(item));
191 else
192 res = cbor_new_indefinite_array();
193
194 for (size_t i = 0; i < cbor_array_size(item); i++)
195 cbor_array_push(
196 res, cbor_move(cbor_copy(cbor_move(cbor_array_get(item, i)))));
197 return res;
198 }
199 case CBOR_TYPE_MAP: {
200 cbor_item_t *res;
201 if (cbor_map_is_definite(item))
202 res = cbor_new_definite_map(cbor_map_size(item));
203 else
204 res = cbor_new_indefinite_map();
205
206 struct cbor_pair *it = cbor_map_handle(item);
207 for (size_t i = 0; i < cbor_map_size(item); i++)
208 cbor_map_add(res, (struct cbor_pair){
209 .key = cbor_move(cbor_copy(it[i].key)),
210 .value = cbor_move(cbor_copy(it[i].value))});
211 return res;
212 }
213 case CBOR_TYPE_TAG:
214 return cbor_build_tag(
215 cbor_tag_value(item),
216 cbor_move(cbor_copy(cbor_move(cbor_tag_item(item)))));
217 case CBOR_TYPE_FLOAT_CTRL:
218 return _cbor_copy_float_ctrl(item);
219 }
220
221 return NULL;
222 }
223
224 #if CBOR_PRETTY_PRINTER
225
226 #include <inttypes.h>
227 #include <locale.h>
228 #include <stdlib.h>
229 #include <wchar.h>
230
231 #define __STDC_FORMAT_MACROS
232
_pow(int b,int ex)233 static int _pow(int b, int ex) {
234 if (ex == 0) return 1;
235 int res = b;
236 while (--ex > 0) res *= b;
237 return res;
238 }
239
_cbor_nested_describe(cbor_item_t * item,FILE * out,int indent)240 static void _cbor_nested_describe(cbor_item_t *item, FILE *out, int indent) {
241 setlocale(LC_ALL, "");
242 switch (cbor_typeof(item)) {
243 case CBOR_TYPE_UINT: {
244 fprintf(out, "%*s[CBOR_TYPE_UINT] ", indent, " ");
245 fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
246 fprintf(out, "Value: %" PRIu64 "\n", cbor_get_int(item));
247 break;
248 };
249 case CBOR_TYPE_NEGINT: {
250 fprintf(out, "%*s[CBOR_TYPE_NEGINT] ", indent, " ");
251 fprintf(out, "Width: %dB, ", _pow(2, cbor_int_get_width(item)));
252 fprintf(out, "Value: -%" PRIu64 " -1\n", cbor_get_int(item));
253 break;
254 };
255 case CBOR_TYPE_BYTESTRING: {
256 fprintf(out, "%*s[CBOR_TYPE_BYTESTRING] ", indent, " ");
257 if (cbor_bytestring_is_indefinite(item)) {
258 fprintf(out, "Indefinite, with %zu chunks:\n",
259 cbor_bytestring_chunk_count(item));
260 for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++)
261 _cbor_nested_describe(cbor_bytestring_chunks_handle(item)[i], out,
262 indent + 4);
263 } else {
264 fprintf(out, "Definite, length %zuB\n", cbor_bytestring_length(item));
265 }
266 break;
267 };
268 case CBOR_TYPE_STRING: {
269 fprintf(out, "%*s[CBOR_TYPE_STRING] ", indent, " ");
270 if (cbor_string_is_indefinite(item)) {
271 fprintf(out, "Indefinite, with %zu chunks:\n",
272 cbor_string_chunk_count(item));
273 for (size_t i = 0; i < cbor_string_chunk_count(item); i++)
274 _cbor_nested_describe(cbor_string_chunks_handle(item)[i], out,
275 indent + 4);
276 } else {
277 fprintf(out, "Definite, length %zuB, %zu codepoints\n",
278 cbor_string_length(item), cbor_string_codepoint_count(item));
279 /* Careful - this doesn't support multibyte characters! */
280 /* Printing those is out of the scope of this demo :) */
281 /* libICU is your friend */
282 fprintf(out, "%*s", indent + 4, " ");
283 /* XXX: no null at the end -> confused vprintf */
284 fwrite(cbor_string_handle(item), (int)cbor_string_length(item), 1, out);
285 fprintf(out, "\n");
286 }
287 break;
288 };
289 case CBOR_TYPE_ARRAY: {
290 fprintf(out, "%*s[CBOR_TYPE_ARRAY] ", indent, " ");
291 if (cbor_array_is_definite(item)) {
292 fprintf(out, "Definite, size: %zu\n", cbor_array_size(item));
293 } else {
294 fprintf(out, "Indefinite, size: %zu\n", cbor_array_size(item));
295 }
296
297 for (size_t i = 0; i < cbor_array_size(item); i++)
298 _cbor_nested_describe(cbor_array_handle(item)[i], out, indent + 4);
299 break;
300 };
301 case CBOR_TYPE_MAP: {
302 fprintf(out, "%*s[CBOR_TYPE_MAP] ", indent, " ");
303 if (cbor_map_is_definite(item)) {
304 fprintf(out, "Definite, size: %zu\n", cbor_map_size(item));
305 } else {
306 fprintf(out, "Indefinite, size: %zu\n", cbor_map_size(item));
307 }
308
309 for (size_t i = 0; i < cbor_map_size(item); i++) {
310 _cbor_nested_describe(cbor_map_handle(item)[i].key, out, indent + 4);
311 _cbor_nested_describe(cbor_map_handle(item)[i].value, out, indent + 4);
312 }
313 break;
314 };
315 case CBOR_TYPE_TAG: {
316 fprintf(out, "%*s[CBOR_TYPE_TAG] ", indent, " ");
317 fprintf(out, "Value: %" PRIu64 "\n", cbor_tag_value(item));
318 _cbor_nested_describe(cbor_move(cbor_tag_item(item)), out, indent + 4);
319 break;
320 };
321 case CBOR_TYPE_FLOAT_CTRL: {
322 fprintf(out, "%*s[CBOR_TYPE_FLOAT_CTRL] ", indent, " ");
323 if (cbor_float_ctrl_is_ctrl(item)) {
324 if (cbor_is_bool(item))
325 fprintf(out, "Bool: %s\n", cbor_get_bool(item) ? "true" : "false");
326 else if (cbor_is_undef(item))
327 fprintf(out, "Undefined\n");
328 else if (cbor_is_null(item))
329 fprintf(out, "Null\n");
330 else
331 fprintf(out, "Simple value %d\n", cbor_ctrl_value(item));
332 } else {
333 fprintf(out, "Width: %dB, ", _pow(2, cbor_float_get_width(item)));
334 fprintf(out, "value: %lf\n", cbor_float_get_float(item));
335 }
336 break;
337 };
338 }
339 }
340
cbor_describe(cbor_item_t * item,FILE * out)341 void cbor_describe(cbor_item_t *item, FILE *out) {
342 _cbor_nested_describe(item, out, 0);
343 }
344
345 #endif
346