xref: /freebsd/contrib/libcbor/src/cbor/streaming.c (revision abd87254)
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 "streaming.h"
9 #include "internal/loaders.h"
10 
claim_bytes(size_t required,size_t provided,struct cbor_decoder_result * result)11 static bool claim_bytes(size_t required, size_t provided,
12                         struct cbor_decoder_result *result) {
13   if (required > (provided - result->read)) {
14     result->required = required + result->read;
15     result->read = 0;
16     result->status = CBOR_DECODER_NEDATA;
17     return false;
18   } else {
19     result->read += required;
20     result->required = 0;
21     return true;
22   }
23 }
24 
25 // Use implicit capture as an exception to avoid the super long parameter list
26 #define CLAIM_BYTES_AND_INVOKE(callback_name, length, source_extra_offset) \
27   do {                                                                     \
28     if (claim_bytes(length, source_size, &result)) {                       \
29       callbacks->callback_name(context, source + 1 + source_extra_offset,  \
30                                length);                                    \
31     }                                                                      \
32   } while (0)
33 
34 #define READ_CLAIM_INVOKE(callback_name, length_reader, length_bytes) \
35   do {                                                                \
36     if (claim_bytes(length_bytes, source_size, &result)) {            \
37       uint64_t length = length_reader(source + 1);                    \
38       CLAIM_BYTES_AND_INVOKE(callback_name, length, length_bytes);    \
39     }                                                                 \
40     return result;                                                    \
41   } while (0)
42 
cbor_stream_decode(cbor_data source,size_t source_size,const struct cbor_callbacks * callbacks,void * context)43 struct cbor_decoder_result cbor_stream_decode(
44     cbor_data source, size_t source_size,
45     const struct cbor_callbacks *callbacks, void *context) {
46   // Attempt to claim the initial MTB byte
47   struct cbor_decoder_result result = {.status = CBOR_DECODER_FINISHED};
48   if (!claim_bytes(1, source_size, &result)) {
49     return result;
50   }
51 
52   switch (*source) {
53     case 0x00: /* Fallthrough */
54     case 0x01: /* Fallthrough */
55     case 0x02: /* Fallthrough */
56     case 0x03: /* Fallthrough */
57     case 0x04: /* Fallthrough */
58     case 0x05: /* Fallthrough */
59     case 0x06: /* Fallthrough */
60     case 0x07: /* Fallthrough */
61     case 0x08: /* Fallthrough */
62     case 0x09: /* Fallthrough */
63     case 0x0A: /* Fallthrough */
64     case 0x0B: /* Fallthrough */
65     case 0x0C: /* Fallthrough */
66     case 0x0D: /* Fallthrough */
67     case 0x0E: /* Fallthrough */
68     case 0x0F: /* Fallthrough */
69     case 0x10: /* Fallthrough */
70     case 0x11: /* Fallthrough */
71     case 0x12: /* Fallthrough */
72     case 0x13: /* Fallthrough */
73     case 0x14: /* Fallthrough */
74     case 0x15: /* Fallthrough */
75     case 0x16: /* Fallthrough */
76     case 0x17:
77       /* Embedded one byte unsigned integer */
78       {
79         callbacks->uint8(context, _cbor_load_uint8(source));
80         return result;
81       }
82     case 0x18:
83       /* One byte unsigned integer */
84       {
85         if (claim_bytes(1, source_size, &result)) {
86           callbacks->uint8(context, _cbor_load_uint8(source + 1));
87         }
88         return result;
89       }
90     case 0x19:
91       /* Two bytes unsigned integer */
92       {
93         if (claim_bytes(2, source_size, &result)) {
94           callbacks->uint16(context, _cbor_load_uint16(source + 1));
95         }
96         return result;
97       }
98     case 0x1A:
99       /* Four bytes unsigned integer */
100       {
101         if (claim_bytes(4, source_size, &result)) {
102           callbacks->uint32(context, _cbor_load_uint32(source + 1));
103         }
104         return result;
105       }
106     case 0x1B:
107       /* Eight bytes unsigned integer */
108       {
109         if (claim_bytes(8, source_size, &result)) {
110           callbacks->uint64(context, _cbor_load_uint64(source + 1));
111         }
112         return result;
113       }
114     case 0x1C: /* Fallthrough */
115     case 0x1D: /* Fallthrough */
116     case 0x1E: /* Fallthrough */
117     case 0x1F:
118       /* Reserved */
119       { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
120     case 0x20: /* Fallthrough */
121     case 0x21: /* Fallthrough */
122     case 0x22: /* Fallthrough */
123     case 0x23: /* Fallthrough */
124     case 0x24: /* Fallthrough */
125     case 0x25: /* Fallthrough */
126     case 0x26: /* Fallthrough */
127     case 0x27: /* Fallthrough */
128     case 0x28: /* Fallthrough */
129     case 0x29: /* Fallthrough */
130     case 0x2A: /* Fallthrough */
131     case 0x2B: /* Fallthrough */
132     case 0x2C: /* Fallthrough */
133     case 0x2D: /* Fallthrough */
134     case 0x2E: /* Fallthrough */
135     case 0x2F: /* Fallthrough */
136     case 0x30: /* Fallthrough */
137     case 0x31: /* Fallthrough */
138     case 0x32: /* Fallthrough */
139     case 0x33: /* Fallthrough */
140     case 0x34: /* Fallthrough */
141     case 0x35: /* Fallthrough */
142     case 0x36: /* Fallthrough */
143     case 0x37:
144       /* Embedded one byte negative integer */
145       {
146         callbacks->negint8(context,
147                            _cbor_load_uint8(source) - 0x20); /* 0x20 offset */
148         return result;
149       }
150     case 0x38:
151       /* One byte negative integer */
152       {
153         if (claim_bytes(1, source_size, &result)) {
154           callbacks->negint8(context, _cbor_load_uint8(source + 1));
155         }
156         return result;
157       }
158     case 0x39:
159       /* Two bytes negative integer */
160       {
161         if (claim_bytes(2, source_size, &result)) {
162           callbacks->negint16(context, _cbor_load_uint16(source + 1));
163         }
164         return result;
165       }
166     case 0x3A:
167       /* Four bytes negative integer */
168       {
169         if (claim_bytes(4, source_size, &result)) {
170           callbacks->negint32(context, _cbor_load_uint32(source + 1));
171         }
172         return result;
173       }
174     case 0x3B:
175       /* Eight bytes negative integer */
176       {
177         if (claim_bytes(8, source_size, &result)) {
178           callbacks->negint64(context, _cbor_load_uint64(source + 1));
179         }
180         return result;
181       }
182     case 0x3C: /* Fallthrough */
183     case 0x3D: /* Fallthrough */
184     case 0x3E: /* Fallthrough */
185     case 0x3F:
186       /* Reserved */
187       { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
188     case 0x40: /* Fallthrough */
189     case 0x41: /* Fallthrough */
190     case 0x42: /* Fallthrough */
191     case 0x43: /* Fallthrough */
192     case 0x44: /* Fallthrough */
193     case 0x45: /* Fallthrough */
194     case 0x46: /* Fallthrough */
195     case 0x47: /* Fallthrough */
196     case 0x48: /* Fallthrough */
197     case 0x49: /* Fallthrough */
198     case 0x4A: /* Fallthrough */
199     case 0x4B: /* Fallthrough */
200     case 0x4C: /* Fallthrough */
201     case 0x4D: /* Fallthrough */
202     case 0x4E: /* Fallthrough */
203     case 0x4F: /* Fallthrough */
204     case 0x50: /* Fallthrough */
205     case 0x51: /* Fallthrough */
206     case 0x52: /* Fallthrough */
207     case 0x53: /* Fallthrough */
208     case 0x54: /* Fallthrough */
209     case 0x55: /* Fallthrough */
210     case 0x56: /* Fallthrough */
211     case 0x57:
212       /* Embedded length byte string */
213       {
214         uint64_t length = _cbor_load_uint8(source) - 0x40; /* 0x40 offset */
215         CLAIM_BYTES_AND_INVOKE(byte_string, length, 0);
216         return result;
217       }
218     case 0x58:
219       /* One byte length byte string */
220       READ_CLAIM_INVOKE(byte_string, _cbor_load_uint8, 1);
221     case 0x59:
222       /* Two bytes length byte string */
223       READ_CLAIM_INVOKE(byte_string, _cbor_load_uint16, 2);
224     case 0x5A:
225       /* Four bytes length byte string */
226       READ_CLAIM_INVOKE(byte_string, _cbor_load_uint32, 4);
227     case 0x5B:
228       /* Eight bytes length byte string */
229       READ_CLAIM_INVOKE(byte_string, _cbor_load_uint64, 8);
230     case 0x5C: /* Fallthrough */
231     case 0x5D: /* Fallthrough */
232     case 0x5E:
233       /* Reserved */
234       { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
235     case 0x5F:
236       /* Indefinite byte string */
237       {
238         callbacks->byte_string_start(context);
239         return result;
240       }
241     case 0x60: /* Fallthrough */
242     case 0x61: /* Fallthrough */
243     case 0x62: /* Fallthrough */
244     case 0x63: /* Fallthrough */
245     case 0x64: /* Fallthrough */
246     case 0x65: /* Fallthrough */
247     case 0x66: /* Fallthrough */
248     case 0x67: /* Fallthrough */
249     case 0x68: /* Fallthrough */
250     case 0x69: /* Fallthrough */
251     case 0x6A: /* Fallthrough */
252     case 0x6B: /* Fallthrough */
253     case 0x6C: /* Fallthrough */
254     case 0x6D: /* Fallthrough */
255     case 0x6E: /* Fallthrough */
256     case 0x6F: /* Fallthrough */
257     case 0x70: /* Fallthrough */
258     case 0x71: /* Fallthrough */
259     case 0x72: /* Fallthrough */
260     case 0x73: /* Fallthrough */
261     case 0x74: /* Fallthrough */
262     case 0x75: /* Fallthrough */
263     case 0x76: /* Fallthrough */
264     case 0x77:
265       /* Embedded one byte length string */
266       {
267         uint64_t length = _cbor_load_uint8(source) - 0x60; /* 0x60 offset */
268         CLAIM_BYTES_AND_INVOKE(string, length, 0);
269         return result;
270       }
271     case 0x78:
272       /* One byte length string */
273       READ_CLAIM_INVOKE(string, _cbor_load_uint8, 1);
274     case 0x79:
275       /* Two bytes length string */
276       READ_CLAIM_INVOKE(string, _cbor_load_uint16, 2);
277     case 0x7A:
278       /* Four bytes length string */
279       READ_CLAIM_INVOKE(string, _cbor_load_uint32, 4);
280     case 0x7B:
281       /* Eight bytes length string */
282       READ_CLAIM_INVOKE(string, _cbor_load_uint64, 8);
283     case 0x7C: /* Fallthrough */
284     case 0x7D: /* Fallthrough */
285     case 0x7E:
286       /* Reserved */
287       { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
288     case 0x7F:
289       /* Indefinite length string */
290       {
291         callbacks->string_start(context);
292         return result;
293       }
294     case 0x80: /* Fallthrough */
295     case 0x81: /* Fallthrough */
296     case 0x82: /* Fallthrough */
297     case 0x83: /* Fallthrough */
298     case 0x84: /* Fallthrough */
299     case 0x85: /* Fallthrough */
300     case 0x86: /* Fallthrough */
301     case 0x87: /* Fallthrough */
302     case 0x88: /* Fallthrough */
303     case 0x89: /* Fallthrough */
304     case 0x8A: /* Fallthrough */
305     case 0x8B: /* Fallthrough */
306     case 0x8C: /* Fallthrough */
307     case 0x8D: /* Fallthrough */
308     case 0x8E: /* Fallthrough */
309     case 0x8F: /* Fallthrough */
310     case 0x90: /* Fallthrough */
311     case 0x91: /* Fallthrough */
312     case 0x92: /* Fallthrough */
313     case 0x93: /* Fallthrough */
314     case 0x94: /* Fallthrough */
315     case 0x95: /* Fallthrough */
316     case 0x96: /* Fallthrough */
317     case 0x97:
318       /* Embedded one byte length array */
319       {
320         callbacks->array_start(
321             context, _cbor_load_uint8(source) - 0x80); /* 0x40 offset */
322         return result;
323       }
324     case 0x98:
325       /* One byte length array */
326       {
327         if (claim_bytes(1, source_size, &result)) {
328           callbacks->array_start(context, _cbor_load_uint8(source + 1));
329         }
330         return result;
331       }
332     case 0x99:
333       /* Two bytes length array */
334       {
335         if (claim_bytes(2, source_size, &result)) {
336           callbacks->array_start(context, _cbor_load_uint16(source + 1));
337         }
338         return result;
339       }
340     case 0x9A:
341       /* Four bytes length array */
342       {
343         if (claim_bytes(4, source_size, &result)) {
344           callbacks->array_start(context, _cbor_load_uint32(source + 1));
345         }
346         return result;
347       }
348     case 0x9B:
349       /* Eight bytes length array */
350       {
351         if (claim_bytes(8, source_size, &result)) {
352           callbacks->array_start(context, _cbor_load_uint64(source + 1));
353         }
354         return result;
355       }
356     case 0x9C: /* Fallthrough */
357     case 0x9D: /* Fallthrough */
358     case 0x9E:
359       /* Reserved */
360       { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
361     case 0x9F:
362       /* Indefinite length array */
363       {
364         callbacks->indef_array_start(context);
365         return result;
366       }
367     case 0xA0: /* Fallthrough */
368     case 0xA1: /* Fallthrough */
369     case 0xA2: /* Fallthrough */
370     case 0xA3: /* Fallthrough */
371     case 0xA4: /* Fallthrough */
372     case 0xA5: /* Fallthrough */
373     case 0xA6: /* Fallthrough */
374     case 0xA7: /* Fallthrough */
375     case 0xA8: /* Fallthrough */
376     case 0xA9: /* Fallthrough */
377     case 0xAA: /* Fallthrough */
378     case 0xAB: /* Fallthrough */
379     case 0xAC: /* Fallthrough */
380     case 0xAD: /* Fallthrough */
381     case 0xAE: /* Fallthrough */
382     case 0xAF: /* Fallthrough */
383     case 0xB0: /* Fallthrough */
384     case 0xB1: /* Fallthrough */
385     case 0xB2: /* Fallthrough */
386     case 0xB3: /* Fallthrough */
387     case 0xB4: /* Fallthrough */
388     case 0xB5: /* Fallthrough */
389     case 0xB6: /* Fallthrough */
390     case 0xB7:
391       /* Embedded one byte length map */
392       {
393         callbacks->map_start(context,
394                              _cbor_load_uint8(source) - 0xA0); /* 0xA0 offset */
395         return result;
396       }
397     case 0xB8:
398       /* One byte length map */
399       {
400         if (claim_bytes(1, source_size, &result)) {
401           callbacks->map_start(context, _cbor_load_uint8(source + 1));
402         }
403         return result;
404       }
405     case 0xB9:
406       /* Two bytes length map */
407       {
408         if (claim_bytes(2, source_size, &result)) {
409           callbacks->map_start(context, _cbor_load_uint16(source + 1));
410         }
411         return result;
412       }
413     case 0xBA:
414       /* Four bytes length map */
415       {
416         if (claim_bytes(4, source_size, &result)) {
417           callbacks->map_start(context, _cbor_load_uint32(source + 1));
418         }
419         return result;
420       }
421     case 0xBB:
422       /* Eight bytes length map */
423       {
424         if (claim_bytes(8, source_size, &result)) {
425           callbacks->map_start(context, _cbor_load_uint64(source + 1));
426         }
427         return result;
428       }
429     case 0xBC: /* Fallthrough */
430     case 0xBD: /* Fallthrough */
431     case 0xBE:
432       /* Reserved */
433       { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
434     case 0xBF:
435       /* Indefinite length map */
436       {
437         callbacks->indef_map_start(context);
438         return result;
439       }
440       /* See https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml for tag
441        * assignment. All well-formed tags are processed regardless of validity
442        * since maintaining the known mapping would be impractical.
443        *
444        * Moreover, even tags in the reserved "standard" range are not assigned
445        * but may get assigned in the future (see e.g.
446        * https://github.com/PJK/libcbor/issues/307), so processing all tags
447        * improves forward compatibility.
448        */
449     case 0xC0: /* Fallthrough */
450     case 0xC1: /* Fallthrough */
451     case 0xC2: /* Fallthrough */
452     case 0xC3: /* Fallthrough */
453     case 0xC4: /* Fallthrough */
454     case 0xC5: /* Fallthrough */
455     case 0xC6: /* Fallthrough */
456     case 0xC7: /* Fallthrough */
457     case 0xC8: /* Fallthrough */
458     case 0xC9: /* Fallthrough */
459     case 0xCA: /* Fallthrough */
460     case 0xCB: /* Fallthrough */
461     case 0xCC: /* Fallthrough */
462     case 0xCD: /* Fallthrough */
463     case 0xCE: /* Fallthrough */
464     case 0xCF: /* Fallthrough */
465     case 0xD0: /* Fallthrough */
466     case 0xD1: /* Fallthrough */
467     case 0xD2: /* Fallthrough */
468     case 0xD3: /* Fallthrough */
469     case 0xD4: /* Fallthrough */
470     case 0xD5: /* Fallthrough */
471     case 0xD6: /* Fallthrough */
472     case 0xD7: /* Fallthrough */
473     {
474       callbacks->tag(context, (uint64_t)(_cbor_load_uint8(source) -
475                                          0xC0)); /* 0xC0 offset */
476       return result;
477     }
478     case 0xD8: /* 1B tag */
479     {
480       if (claim_bytes(1, source_size, &result)) {
481         callbacks->tag(context, _cbor_load_uint8(source + 1));
482       }
483       return result;
484     }
485     case 0xD9: /* 2B tag */
486     {
487       if (claim_bytes(2, source_size, &result)) {
488         callbacks->tag(context, _cbor_load_uint16(source + 1));
489       }
490       return result;
491     }
492     case 0xDA: /* 4B tag */
493     {
494       if (claim_bytes(4, source_size, &result)) {
495         callbacks->tag(context, _cbor_load_uint32(source + 1));
496       }
497       return result;
498     }
499     case 0xDB: /* 8B tag */
500     {
501       if (claim_bytes(8, source_size, &result)) {
502         callbacks->tag(context, _cbor_load_uint64(source + 1));
503       }
504       return result;
505     }
506     case 0xDC: /* Fallthrough */
507     case 0xDD: /* Fallthrough */
508     case 0xDE: /* Fallthrough */
509     case 0xDF: /* Reserved */
510     {
511       return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR};
512     }
513     case 0xE0: /* Fallthrough */
514     case 0xE1: /* Fallthrough */
515     case 0xE2: /* Fallthrough */
516     case 0xE3: /* Fallthrough */
517     case 0xE4: /* Fallthrough */
518     case 0xE5: /* Fallthrough */
519     case 0xE6: /* Fallthrough */
520     case 0xE7: /* Fallthrough */
521     case 0xE8: /* Fallthrough */
522     case 0xE9: /* Fallthrough */
523     case 0xEA: /* Fallthrough */
524     case 0xEB: /* Fallthrough */
525     case 0xEC: /* Fallthrough */
526     case 0xED: /* Fallthrough */
527     case 0xEE: /* Fallthrough */
528     case 0xEF: /* Fallthrough */
529     case 0xF0: /* Fallthrough */
530     case 0xF1: /* Fallthrough */
531     case 0xF2: /* Fallthrough */
532     case 0xF3: /* Simple value - unassigned */
533     {
534       return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR};
535     }
536     case 0xF4:
537       /* False */
538       {
539         callbacks->boolean(context, false);
540         return result;
541       }
542     case 0xF5:
543       /* True */
544       {
545         callbacks->boolean(context, true);
546         return result;
547       }
548     case 0xF6:
549       /* Null */
550       {
551         callbacks->null(context);
552         return result;
553       }
554     case 0xF7:
555       /* Undefined */
556       {
557         callbacks->undefined(context);
558         return result;
559       }
560     case 0xF8:
561       /* 1B simple value, unassigned */
562       { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
563     case 0xF9:
564       /* 2B float */
565       {
566         if (claim_bytes(2, source_size, &result)) {
567           callbacks->float2(context, _cbor_load_half(source + 1));
568         }
569         return result;
570       }
571     case 0xFA:
572       /* 4B float */
573       {
574         if (claim_bytes(4, source_size, &result)) {
575           callbacks->float4(context, _cbor_load_float(source + 1));
576         }
577         return result;
578       }
579     case 0xFB:
580       /* 8B float */
581       {
582         if (claim_bytes(8, source_size, &result)) {
583           callbacks->float8(context, _cbor_load_double(source + 1));
584         }
585         return result;
586       }
587     case 0xFC: /* Fallthrough */
588     case 0xFD: /* Fallthrough */
589     case 0xFE:
590       /* Reserved */
591       { return (struct cbor_decoder_result){.status = CBOR_DECODER_ERROR}; }
592     case 0xFF:
593       /* Break */
594       callbacks->indef_break(context);
595       // Never happens, the switch statement is exhaustive on the 1B range; make
596       // compiler happy
597     default:
598       return result;
599   }
600 }
601