xref: /netbsd/external/mit/libcbor/dist/src/cbor.c (revision 4ab93bc7)
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