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