blob: 6fca60f6986ae77f8015edd3dc2133471edcceb0 [file] [log] [blame]
Thiago Macieiraaddf8042017-02-26 11:37:06 -08001/****************************************************************************
2**
3** Copyright (C) 2017 Intel Corporation
4**
5** Permission is hereby granted, free of charge, to any person obtaining a copy
6** of this software and associated documentation files (the "Software"), to deal
7** in the Software without restriction, including without limitation the rights
8** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9** copies of the Software, and to permit persons to whom the Software is
10** furnished to do so, subject to the following conditions:
11**
12** The above copyright notice and this permission notice shall be included in
13** all copies or substantial portions of the Software.
14**
15** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21** THE SOFTWARE.
22**
23****************************************************************************/
24
25#define _BSD_SOURCE 1
26#define _DEFAULT_SOURCE 1
27#ifndef __STDC_LIMIT_MACROS
28# define __STDC_LIMIT_MACROS 1
29#endif
30
31#include "cbor.h"
32#include "cborinternal_p.h"
33#include "compilersupport_p.h"
Thiago Macieira17d42a12017-02-26 14:42:37 -080034#include "utf8_p.h"
Thiago Macieiraaddf8042017-02-26 11:37:06 -080035
36#include <string.h>
37
38#ifndef CBOR_NO_FLOATING_POINT
39# include <float.h>
40# include <math.h>
41#endif
42
43
44#ifndef CBOR_PARSER_MAX_RECURSIONS
45# define CBOR_PARSER_MAX_RECURSIONS 1024
46#endif
47
48/**
49 * \addtogroup CborParsing
50 * @{
51 */
52
53/**
54 * \enum CborValidationFlags
55 * The CborValidationFlags enum contains flags that control the validation of a
56 * CBOR stream.
57 *
58 * \value CborValidateBasic Validates only the syntax correctedness of the stream.
59 * \value CborValidateCanonical Validates that the stream is in canonical format, according to
60 * RFC 7049 section 3.9.
61 * \value CborValidateStrictMode Performs strict validation, according to RFC 7049 section 3.10.
62 * \value CborValidateStrictest Attempt to perform the strictest validation we know of.
63 *
64 * \value CborValidateShortestIntegrals (Canonical) Validate that integral numbers and lengths are
65 * enconded in their shortest form possible.
66 * \value CborValidateShortestFloatingPoint (Canonical) Validate that floating-point numbers are encoded
67 * in their shortest form possible.
68 * \value CborValidateShortestNumbers (Canonical) Validate both integrals and floating-point numbers
69 * are in their shortest form possible.
70 * \value CborValidateNoIndeterminateLength (Canonical) Validate that no string, array or map uses
71 * indeterminate length encoding.
72 * \value CborValidateMapIsSorted (Canonical & Strict mode) Validate that map keys appear in
73 * sorted order.
74 * \value CborValidateMapKeysAreUnique (Strict mode) Validate that map keys are unique.
75 * \value CborValidateTagUse (Strict mode) Validate that known tags are used with the
76 * correct types. This does not validate that the content of
77 * those types is syntactically correct.
78 * \value CborValidateUtf8 (Strict mode) Validate that text strings are appropriately
79 * encoded in UTF-8.
80 * \value CborValidateMapKeysAreString Validate that all map keys are text strings.
81 * \value CborValidateNoUndefined Validate that no elements of type "undefined" are present.
82 * \value CborValidateNoTags Validate that no tags are used.
83 * \value CborValidateFiniteFloatingPoint Validate that all floating point numbers are finite (no NaN or
84 * infinities are allowed).
85 * \value CborValidateCompleteData Validate that the stream is complete and there is no more data
86 * in the buffer.
87 * \value CborValidateNoUnknownSimpleTypesSA Validate that all Standards Action simple types are registered
88 * with IANA.
89 * \value CborValidateNoUnknownSimpleTypes Validate that all simple types used are registered with IANA.
90 * \value CborValidateNoUnknownTagsSA Validate that all Standard Actions tags are registered with IANA.
91 * \value CborValidateNoUnknownTagsSR Validate that all Standard Actions and Specification Required tags
92 * are registered with IANA (see below for limitations).
93 * \value CborValidateNoUnkonwnTags Validate that all tags are registered with IANA
94 * (see below for limitations).
95 *
96 * \par Simple type registry
97 * The CBOR specification requires that registration for use of the first 19
98 * simple types must be done by way of Standards Action. The rest of the simple
99 * types only require a specification. The official list can be obtained from
100 * https://www.iana.org/assignments/cbor-simple-values/cbor-simple-values.xhtml.
101 *
102 * \par
103 * There are no registered simple types recognized by this release of TinyCBOR
104 * (beyond those defined by RFC 7049).
105 *
106 * \par Tag registry
107 * The CBOR specification requires that registration for use of the first 23
108 * tags must be done by way of Standards Action. The next up to tag 255 only
109 * require a specification. Finally, all other tags can be registered on a
110 * first-come-first-serve basis. The official list can be ontained from
111 * https://www.iana.org/assignments/cbor-tags/cbor-tags.xhtml.
112 *
113 * \par
114 * Given the variability of this list, TinyCBOR cannot recognize all tags
115 * registered with IANA. Instead, the implementation only recognizes tags
116 * that are backed by an RFC.
117 *
118 * \par
119 * These are the tags known to the current TinyCBOR release:
Thiago Macieira0342d722017-02-26 13:12:50 -0800120<table>
121 <tr>
122 <th>Tag</th>
123 <th>Data Item</th>
124 <th>Semantics</th>
125 </tr>
126 <tr>
127 <td>0</td>
128 <td>UTF-8 text string</td>
129 <td>Standard date/time string</td>
130 </td>
131 <tr>
132 <td>1</td>
133 <td>integer</td>
134 <td>Epoch-based date/time</td>
135 </td>
136 <tr>
137 <td>2</td>
138 <td>byte string</td>
139 <td>Positive bignum</td>
140 </td>
141 <tr>
142 <td>3</td>
143 <td>byte string</td>
144 <td>Negative bignum</td>
145 </td>
146 <tr>
147 <td>4</td>
148 <td>array</td>
149 <td>Decimal fraction</td>
150 </td>
151 <tr>
152 <td>5</td>
153 <td>array</td>
154 <td>Bigfloat</td>
155 </td>
156 <tr>
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700157 <td>16</td>
158 <td>array</td>
159 <td>COSE Single Recipient Encrypted Data Object (RFC 8152)</td>
160 </td>
161 <tr>
162 <td>17</td>
163 <td>array</td>
164 <td>COSE Mac w/o Recipients Object (RFC 8152)</td>
165 </td>
166 <tr>
167 <td>18</td>
168 <td>array</td>
169 <td>COSE Single Signer Data Object (RFC 8162)</td>
170 </td>
171 <tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800172 <td>21</td>
173 <td>byte string, array, map</td>
174 <td>Expected conversion to base64url encoding</td>
175 </td>
176 <tr>
177 <td>22</td>
178 <td>byte string, array, map</td>
179 <td>Expected conversion to base64 encoding</td>
180 </td>
181 <tr>
182 <td>23</td>
183 <td>byte string, array, map</td>
184 <td>Expected conversion to base16 encoding</td>
185 </td>
186 <tr>
187 <td>24</td>
188 <td>byte string</td>
189 <td>Encoded CBOR data item</td>
190 </td>
191 <tr>
192 <td>32</td>
193 <td>UTF-8 text string</td>
194 <td>URI</td>
195 </td>
196 <tr>
197 <td>33</td>
198 <td>UTF-8 text string</td>
199 <td>base64url</td>
200 </td>
201 <tr>
202 <td>34</td>
203 <td>UTF-8 text string</td>
204 <td>base64</td>
205 </td>
206 <tr>
207 <td>35</td>
208 <td>UTF-8 text string</td>
209 <td>Regular expression</td>
210 </td>
211 <tr>
212 <td>36</td>
213 <td>UTF-8 text string</td>
214 <td>MIME message</td>
215 </td>
216 <tr>
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700217 <td>96</td>
218 <td>array</td>
219 <td>COSE Encrypted Data Object (RFC 8152)</td>
220 </td>
221 <tr>
222 <td>97</td>
223 <td>array</td>
224 <td>COSE MACed Data Object (RFC 8152)</td>
225 </td>
226 <tr>
227 <td>98</td>
228 <td>array</td>
229 <td>COSE Signed Data Object (RFC 8152)</td>
230 </td>
231 <tr>
Thiago Macieira0342d722017-02-26 13:12:50 -0800232 <td>55799</td>
233 <td>any</td>
234 <td>Self-describe CBOR</td>
235 </td>
236</table>
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800237 */
238
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100239struct KnownTagData { uint32_t tag; uint32_t types; };
Thiago Macieira0342d722017-02-26 13:12:50 -0800240static const struct KnownTagData knownTagData[] = {
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100241 { 0, (uint8_t)CborTextStringType },
242 { 1, (uint8_t)(CborIntegerType+1) },
243 { 2, (uint8_t)CborByteStringType },
244 { 3, (uint8_t)CborByteStringType },
245 { 4, (uint8_t)CborArrayType },
246 { 5, (uint8_t)CborArrayType },
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700247 { 16, (uint8_t)CborArrayType },
248 { 17, (uint8_t)CborArrayType },
249 { 18, (uint8_t)CborArrayType },
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100250 { 21, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
251 { 22, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
252 { 23, (uint8_t)CborByteStringType | ((uint8_t)CborArrayType << 8) | ((uint8_t)CborMapType << 16) },
253 { 24, (uint8_t)CborByteStringType },
254 { 32, (uint8_t)CborTextStringType },
255 { 33, (uint8_t)CborTextStringType },
256 { 34, (uint8_t)CborTextStringType },
257 { 35, (uint8_t)CborTextStringType },
258 { 36, (uint8_t)CborTextStringType },
Thiago Macieira2fe481c2017-09-28 23:50:05 -0700259 { 96, (uint8_t)CborArrayType },
260 { 97, (uint8_t)CborArrayType },
261 { 98, (uint8_t)CborArrayType },
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100262 { 55799, 0U }
Thiago Macieira0342d722017-02-26 13:12:50 -0800263};
264
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800265static CborError validate_value(CborValue *it, int flags, int recursionLeft);
266
Thiago Macieira17d42a12017-02-26 14:42:37 -0800267static inline CborError validate_utf8_string(const void *ptr, size_t n)
268{
269 const uint8_t *buffer = (const uint8_t *)ptr;
270 const uint8_t * const end = buffer + n;
271 while (buffer < end) {
272 uint32_t uc = get_utf8(&buffer, end);
273 if (uc == ~0U)
274 return CborErrorInvalidUtf8TextString;
275 }
276 return CborNoError;
277}
278
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800279static inline CborError validate_simple_type(uint8_t simple_type, int flags)
280{
281 /* At current time, all known simple types are those from RFC 7049,
282 * which are parsed by the parser into different CBOR types.
283 * That means that if we've got here, the type is unknown */
284 if (simple_type < 32)
285 return (flags & CborValidateNoUnknownSimpleTypesSA) ? CborErrorUnknownSimpleType : CborNoError;
286 return (flags & CborValidateNoUnknownSimpleTypes) == CborValidateNoUnknownSimpleTypes ?
287 CborErrorUnknownSimpleType : CborNoError;
288}
289
Thiago Macieira63d143b2017-02-26 17:43:50 -0800290static inline CborError validate_number(const CborValue *it, CborType type, int flags)
291{
292 CborError err = CborNoError;
293 const uint8_t *ptr = it->ptr;
294 uint64_t value;
295
296 if ((flags & CborValidateShortestIntegrals) == 0)
297 return err;
298 if (type >= CborHalfFloatType && type <= CborDoubleType)
299 return err; /* checked elsewhere */
300
301 err = _cbor_value_extract_number(&ptr, it->parser->end, &value);
302 if (err)
303 return err;
304
305 size_t bytesUsed = (size_t)(ptr - it->ptr - 1);
306 size_t bytesNeeded = 0;
307 if (value >= Value8Bit)
308 ++bytesNeeded;
309 if (value > 0xffU)
310 ++bytesNeeded;
311 if (value > 0xffffU)
312 bytesNeeded += 2;
313 if (value > 0xffffffffU)
314 bytesNeeded += 4;
315 if (bytesNeeded < bytesUsed)
316 return CborErrorOverlongEncoding;
317 return CborNoError;
318}
319
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800320static inline CborError validate_tag(CborValue *it, CborTag tag, int flags, int recursionLeft)
321{
322 CborType type = cbor_value_get_type(it);
Thiago Macieira0342d722017-02-26 13:12:50 -0800323 const size_t knownTagCount = sizeof(knownTagData) / sizeof(knownTagData[0]);
324 const struct KnownTagData *tagData = knownTagData;
325 const struct KnownTagData * const knownTagDataEnd = knownTagData + knownTagCount;
326
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800327 if (!recursionLeft)
328 return CborErrorNestingTooDeep;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800329 if (flags & CborValidateNoTags)
330 return CborErrorExcludedType;
Thiago Macieira0342d722017-02-26 13:12:50 -0800331
332 /* find the tag data, if any */
333 for ( ; tagData != knownTagDataEnd; ++tagData) {
334 if (tagData->tag < tag)
335 continue;
336 if (tagData->tag > tag)
337 tagData = NULL;
338 break;
339 }
340 if (tagData == knownTagDataEnd)
341 tagData = NULL;
342
343 if (flags & CborValidateNoUnknownTags && !tagData) {
344 /* tag not found */
345 if (flags & CborValidateNoUnknownTagsSA && tag < 24)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800346 return CborErrorUnknownTag;
Thiago Macieira0342d722017-02-26 13:12:50 -0800347 if ((flags & CborValidateNoUnknownTagsSR) == CborValidateNoUnknownTagsSR && tag < 256)
348 return CborErrorUnknownTag;
349 if ((flags & CborValidateNoUnknownTags) == CborValidateNoUnknownTags)
350 return CborErrorUnknownTag;
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800351 }
352
Thiago Macieirac85bcf52017-03-06 09:04:40 +0100353 if (flags & CborValidateTagUse && tagData && tagData->types) {
354 uint32_t allowedTypes = tagData->types;
355
356 /* correct Integer so it's not zero */
357 if (type == CborIntegerType)
358 ++type;
359
360 while (allowedTypes) {
361 if ((uint8_t)(allowedTypes & 0xff) == type)
362 break;
363 allowedTypes >>= 8;
364 }
365 if (!allowedTypes)
366 return CborErrorInappropriateTagForType;
367 }
368
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800369 return validate_value(it, flags, recursionLeft);
370}
371
372#ifndef CBOR_NO_FLOATING_POINT
373static inline CborError validate_floating_point(CborValue *it, CborType type, int flags)
374{
375 CborError err;
376 double val;
377 float valf;
378 uint16_t valf16;
379
380 if (type != CborDoubleType) {
381 if (type == CborFloatType) {
382 err = cbor_value_get_float(it, &valf);
383 val = valf;
384 } else {
385# ifdef CBOR_NO_HALF_FLOAT_TYPE
386 (void)val16;
387 return CborErrorUnsupportedType;
388# else
389 err = cbor_value_get_half_float(it, &valf16);
390 val = decode_half(valf16);
391# endif
392 }
393 } else {
394 err = cbor_value_get_double(it, &val);
395 }
396 cbor_assert(err == CborNoError); /* can't fail */
397
398 int r = fpclassify(val);
399 if (r == FP_NAN || r == FP_INFINITE) {
400 if (flags & CborValidateFiniteFloatingPoint)
401 return CborErrorExcludedValue;
402 if (flags & CborValidateShortestFloatingPoint) {
403 if (type == CborDoubleType)
404 return CborErrorOverlongEncoding;
405# ifndef CBOR_NO_HALF_FLOAT_TYPE
406 if (type == CborFloatType)
407 return CborErrorOverlongEncoding;
408 if (r == FP_NAN && valf16 != 0x7e00)
409 return CborErrorImproperValue;
410 if (r == FP_INFINITE && valf16 != 0x7c00 && valf16 != 0xfc00)
411 return CborErrorImproperValue;
412# endif
413 }
414 }
415
416 if (flags & CborValidateShortestFloatingPoint && type > CborHalfFloatType) {
417 if (type == CborDoubleType) {
418 valf = (float)val;
419 if ((double)valf == val)
420 return CborErrorOverlongEncoding;
421 }
422# ifndef CBOR_NO_HALF_FLOAT_TYPE
423 if (type == CborFloatType) {
424 valf16 = encode_half(valf);
425 if (valf == decode_half(valf16))
426 return CborErrorOverlongEncoding;
427 }
428# endif
429 }
430
431 return CborNoError;
432}
433#endif
434
435static CborError validate_container(CborValue *it, int containerType, int flags, int recursionLeft)
436{
437 CborError err;
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800438 const uint8_t *previous = NULL;
439 const uint8_t *previous_end;
440
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800441 if (!recursionLeft)
442 return CborErrorNestingTooDeep;
443
444 while (!cbor_value_at_end(it)) {
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800445 const uint8_t *current;
446
447 if (containerType == CborMapType) {
448 current = it->ptr;
449 if (flags & CborValidateMapKeysAreString) {
450 CborType type = cbor_value_get_type(it);
451 if (type == CborTagType) {
452 /* skip the tags */
453 CborValue copy = *it;
454 err = cbor_value_skip_tag(&copy);
455 if (err)
456 return err;
457 type = cbor_value_get_type(&copy);
458 }
459 if (type != CborTextStringType)
460 return CborErrorMapKeyNotString;
461 }
462 }
463
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800464 err = validate_value(it, flags, recursionLeft);
465 if (err)
466 return err;
467
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800468 if (containerType != CborMapType)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800469 continue;
470
Thiago Macieirad9a8d832017-02-26 18:37:55 -0800471 if (flags & CborValidateMapIsSorted) {
472 if (previous) {
473 uint64_t len1, len2;
474 const uint8_t *ptr;
475
476 /* extract the two lengths */
477 ptr = previous;
478 _cbor_value_extract_number(&ptr, it->parser->end, &len1);
479 ptr = current;
480 _cbor_value_extract_number(&ptr, it->parser->end, &len2);
481
482 if (len1 > len2)
483 return CborErrorMapNotSorted;
484 if (len1 == len2) {
485 size_t bytelen1 = (size_t)(previous_end - previous);
486 size_t bytelen2 = (size_t)(it->ptr - current);
487 int r = memcmp(previous, current, bytelen1 <= bytelen2 ? bytelen1 : bytelen2);
488
489 if (r == 0 && bytelen1 != bytelen2)
490 r = bytelen1 < bytelen2 ? -1 : +1;
491 if (r > 0)
492 return CborErrorMapNotSorted;
493 if (r == 0 && (flags & CborValidateMapKeysAreUnique) == CborValidateMapKeysAreUnique)
494 return CborErrorMapKeysNotUnique;
495 }
496 }
497
498 previous = current;
499 previous_end = it->ptr;
500 }
501
502 /* map: that was the key, so get the value */
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800503 err = validate_value(it, flags, recursionLeft);
504 if (err)
505 return err;
506 }
507 return CborNoError;
508}
509
510static CborError validate_value(CborValue *it, int flags, int recursionLeft)
511{
512 CborError err;
Thiago Macieira63d143b2017-02-26 17:43:50 -0800513 CborType type = cbor_value_get_type(it);
514
515 if (cbor_value_is_length_known(it)) {
516 err = validate_number(it, type, flags);
517 if (err)
518 return err;
519 } else {
520 if (flags & CborValidateNoIndeterminateLength)
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800521 return CborErrorUnknownLength;
522 }
523
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800524 switch (type) {
525 case CborArrayType:
526 case CborMapType: {
527 /* recursive type */
528 CborValue recursed;
529 err = cbor_value_enter_container(it, &recursed);
530 if (!err)
531 err = validate_container(&recursed, type, flags, recursionLeft - 1);
532 if (err) {
533 it->ptr = recursed.ptr;
534 return err;
535 }
536 err = cbor_value_leave_container(it, &recursed);
537 if (err)
538 return err;
539 return CborNoError;
540 }
541
542 case CborIntegerType: {
543 uint64_t val;
544 err = cbor_value_get_raw_integer(it, &val);
545 cbor_assert(err == CborNoError); /* can't fail */
546
547 break;
548 }
549
550 case CborByteStringType:
551 case CborTextStringType: {
552 size_t n = 0;
553 const void *ptr;
554
Thiago Macieira63d143b2017-02-26 17:43:50 -0800555 err = _cbor_value_prepare_string_iteration(it);
556 if (err)
557 return err;
558
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800559 while (1) {
Thiago Macieira63d143b2017-02-26 17:43:50 -0800560 err = validate_number(it, type, flags);
561 if (err)
562 return err;
563
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800564 err = _cbor_value_get_string_chunk(it, &ptr, &n, it);
565 if (err)
566 return err;
567 if (!ptr)
568 break;
Thiago Macieira17d42a12017-02-26 14:42:37 -0800569
570 if (type == CborTextStringType && flags & CborValidateUtf8) {
571 err = validate_utf8_string(ptr, n);
572 if (err)
573 return err;
574 }
Thiago Macieiraaddf8042017-02-26 11:37:06 -0800575 }
576
577 return CborNoError;
578 }
579
580 case CborTagType: {
581 CborTag tag;
582 err = cbor_value_get_tag(it, &tag);
583 cbor_assert(err == CborNoError); /* can't fail */
584
585 err = cbor_value_advance_fixed(it);
586 if (err)
587 return err;
588 err = validate_tag(it, tag, flags, recursionLeft - 1);
589 if (err)
590 return err;
591
592 return CborNoError;
593 }
594
595 case CborSimpleType: {
596 uint8_t simple_type;
597 err = cbor_value_get_simple_type(it, &simple_type);
598 cbor_assert(err == CborNoError); /* can't fail */
599 err = validate_simple_type(simple_type, flags);
600 if (err)
601 return err;
602 break;
603 }
604
605 case CborNullType:
606 case CborBooleanType:
607 break;
608
609 case CborUndefinedType:
610 if (flags & CborValidateNoUndefined)
611 return CborErrorExcludedType;
612 break;
613
614 case CborHalfFloatType:
615 case CborFloatType:
616 case CborDoubleType: {
617#ifdef CBOR_NO_FLOATING_POINT
618 return CborErrorUnsupportedType;
619#else
620 err = validate_floating_point(it, type, flags);
621 if (err)
622 return err;
623 break;
624 }
625#endif /* !CBOR_NO_FLOATING_POINT */
626
627 case CborInvalidType:
628 return CborErrorUnknownType;
629 }
630
631 err = cbor_value_advance_fixed(it);
632 return err;
633}
634
635/**
636 * Performs a full validation controlled by the \a flags options of the CBOR
637 * stream pointed by \a it and returns the error it found. If no error was
638 * found, it returns CborNoError and the application can iterate over the items
639 * with certainty that no other errors will appear during parsing.
640 *
641 * If \a flags is CborValidateBasic, the result should be the same as
642 * cbor_value_validate_basic().
643 *
644 * This function has the same timing and memory requirements as
645 * cbor_value_advance() and cbor_value_validate_basic().
646 *
647 * \sa CborValidationFlags, cbor_value_validate_basic(), cbor_value_advance()
648 */
649CborError cbor_value_validate(const CborValue *it, int flags)
650{
651 CborValue value = *it;
652 CborError err = validate_value(&value, flags, CBOR_PARSER_MAX_RECURSIONS);
653 if (err)
654 return err;
655 if (flags & CborValidateCompleteData && it->ptr != it->parser->end)
656 return CborErrorGarbageAtEnd;
657 return CborNoError;
658}
659
660/**
661 * @}
662 */