blob: f62727bdb9fd60f10f09d21abc0607289e566c58 [file] [log] [blame]
Thiago Macieira54a0e102015-05-05 21:25:06 -07001/****************************************************************************
2**
3** Copyright (C) 2015 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
Thiago Macieiraed5b57c2015-07-07 16:38:27 -070025#define _BSD_SOURCE 1
Thiago Macieira54a0e102015-05-05 21:25:06 -070026#include "cbor.h"
27#include "cborconstants_p.h"
28#include "compilersupport_p.h"
Thiago Macieira4e9626c2015-09-21 14:57:17 -070029#include "extract_number_p.h"
Thiago Macieira54a0e102015-05-05 21:25:06 -070030
31#include <assert.h>
Thiago Macieira54a0e102015-05-05 21:25:06 -070032#include <string.h>
33
Thiago Macieira8f3fb782015-06-16 16:27:01 -070034#include "assert_p.h" /* Always include last */
35
Thiago Macieira4a99af92015-05-12 10:41:45 +090036#ifndef CBOR_PARSER_MAX_RECURSIONS
37# define CBOR_PARSER_MAX_RECURSIONS 1024
38#endif
39
Thiago Macieira54a0e102015-05-05 21:25:06 -070040/**
41 * \typedef CborValue
42 * This type contains one value parsed from the CBOR stream.
43 *
44 * To get the actual type, use cbor_value_get_type(). Then extract the value
45 * using one of the corresponding functions: cbor_value_get_boolean(), cbor_value_get_int64(),
46 * cbor_value_get_int(), cbor_value_copy_string(), cbor_value_get_array(), cbor_value_get_map(),
47 * cbor_value_get_double(), cbor_value_get_float().
48 *
49 * In C++ and C11 modes, you can additionally use the cbor_value_get_integer()
50 * and cbor_value_get_floating_point() generic functions.
51 *
52 * \omit
53 * Implementation details: the CborValue contains these fields:
54 * \list
55 * \li ptr: pointer to the actual data
56 * \li flags: flags from the decoder
Thiago Macieira2312efd2015-05-06 16:07:48 -070057 * \li extra: partially decoded integer value (0, 1 or 2 bytes)
Thiago Macieira54a0e102015-05-05 21:25:06 -070058 * \li remaining: remaining items in this collection after this item or UINT32_MAX if length is unknown
59 * \endlist
60 * \endomit
61 */
62
Thiago Macieiraf5cb94b2015-06-16 16:10:49 -070063static CborError extract_length(const CborParser *parser, const uint8_t **ptr, size_t *len)
Thiago Macieira54a0e102015-05-05 21:25:06 -070064{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070065 uint64_t v;
Thiago Macieira4e9626c2015-09-21 14:57:17 -070066 CborError err = extract_number(ptr, parser->end, &v);
Mike Colagrosso629d5b72016-02-24 15:12:34 -070067 if (err) {
68 *len = 0;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070069 return err;
Mike Colagrosso629d5b72016-02-24 15:12:34 -070070 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070071
72 *len = v;
73 if (v != *len)
74 return CborErrorDataTooLarge;
75 return CborNoError;
76}
77
78static bool is_fixed_type(uint8_t type)
79{
80 return type != CborTextStringType && type != CborByteStringType && type != CborArrayType &&
81 type != CborMapType;
82}
83
84static CborError preparse_value(CborValue *it)
85{
86 const CborParser *parser = it->parser;
Thiago Macieira11e913f2015-05-07 13:01:18 -070087 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070088
Thiago Macieiradbc01292016-06-06 17:02:25 -070089 /* are we at the end? */
Thiago Macieira54a0e102015-05-05 21:25:06 -070090 if (it->ptr == parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070091 return CborErrorUnexpectedEOF;
Thiago Macieira54a0e102015-05-05 21:25:06 -070092
93 uint8_t descriptor = *it->ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070094 uint8_t type = descriptor & MajorTypeMask;
Thiago Macieira851c4812015-05-08 15:23:20 -070095 it->type = type;
Thiago Macieira54a0e102015-05-05 21:25:06 -070096 it->flags = 0;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070097 it->extra = (descriptor &= SmallValueMask);
98
Thiago Macieira56d99832015-05-07 14:34:27 -070099 if (descriptor > Value64Bit) {
100 if (unlikely(descriptor != IndefiniteLength))
Thiago Macieira3f76f632015-05-12 10:10:09 +0900101 return type == CborSimpleType ? CborErrorUnknownType : CborErrorIllegalNumber;
Thiago Macieira56d99832015-05-07 14:34:27 -0700102 if (likely(!is_fixed_type(type))) {
Thiago Macieiradbc01292016-06-06 17:02:25 -0700103 /* special case */
Thiago Macieira56d99832015-05-07 14:34:27 -0700104 it->flags |= CborIteratorFlag_UnknownLength;
105 it->type = type;
106 return CborNoError;
107 }
108 return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700109 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700110
Thiago Macieirac70169f2015-05-06 07:49:44 -0700111 size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit));
Thiago Macieira63abed92015-10-28 17:01:14 -0700112 if (bytesNeeded + 1 > (size_t)(parser->end - it->ptr))
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700113 return CborErrorUnexpectedEOF;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700114
Thiago Macieira851c4812015-05-08 15:23:20 -0700115 uint8_t majortype = type >> MajorTypeShift;
116 if (majortype == NegativeIntegerType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700117 it->flags |= CborIteratorFlag_NegativeInteger;
Thiago Macieira851c4812015-05-08 15:23:20 -0700118 it->type = CborIntegerType;
119 } else if (majortype == SimpleTypesType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700120 switch (descriptor) {
121 case FalseValue:
122 it->extra = false;
Thiago Macieira851c4812015-05-08 15:23:20 -0700123 it->type = CborBooleanType;
Thiago Macieira991dd922015-05-07 11:57:59 -0700124 break;
125
Thiago Macieira851c4812015-05-08 15:23:20 -0700126 case SinglePrecisionFloat:
127 case DoublePrecisionFloat:
128 it->flags |= CborIteratorFlag_IntegerValueTooLarge;
Thiago Macieiradbc01292016-06-06 17:02:25 -0700129 /* fall through */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700130 case TrueValue:
131 case NullValue:
132 case UndefinedValue:
133 case HalfPrecisionFloat:
Thiago Macieira851c4812015-05-08 15:23:20 -0700134 it->type = *it->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700135 break;
136
137 case SimpleTypeInNextByte:
Thiago Macieira851c4812015-05-08 15:23:20 -0700138 it->extra = (uint8_t)it->ptr[1];
Thiago Macieira54a0e102015-05-05 21:25:06 -0700139#ifndef CBOR_PARSER_NO_STRICT_CHECKS
Thiago Macieira851c4812015-05-08 15:23:20 -0700140 if (unlikely(it->extra < 32)) {
141 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700142 return CborErrorIllegalSimpleType;
Thiago Macieira851c4812015-05-08 15:23:20 -0700143 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700144#endif
Thiago Macieira991dd922015-05-07 11:57:59 -0700145 break;
146
Thiago Macieira54a0e102015-05-05 21:25:06 -0700147 case 28:
148 case 29:
149 case 30:
Thiago Macieira54a0e102015-05-05 21:25:06 -0700150 case Break:
Thiago Macieiradbc01292016-06-06 17:02:25 -0700151 assert(false); /* these conditions can't be reached */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700152 return CborErrorUnexpectedBreak;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700153 }
Thiago Macieira851c4812015-05-08 15:23:20 -0700154 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700155 }
156
Thiago Macieiradbc01292016-06-06 17:02:25 -0700157 /* try to decode up to 16 bits */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700158 if (descriptor < Value8Bit)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700159 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700160
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700161 if (descriptor == Value8Bit)
162 it->extra = (uint8_t)it->ptr[1];
163 else if (descriptor == Value16Bit)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700164 it->extra = get16(it->ptr + 1);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700165 else
Thiago Macieiradbc01292016-06-06 17:02:25 -0700166 it->flags |= CborIteratorFlag_IntegerValueTooLarge; /* Value32Bit or Value64Bit */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700167 return CborNoError;
168}
Thiago Macieira54a0e102015-05-05 21:25:06 -0700169
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700170static CborError preparse_next_value(CborValue *it)
171{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700172 if (it->remaining != UINT32_MAX) {
Thiago Macieiradbc01292016-06-06 17:02:25 -0700173 /* don't decrement the item count if the current item is tag: they don't count */
Thiago Macieira11e913f2015-05-07 13:01:18 -0700174 if (it->type != CborTagType && !--it->remaining) {
175 it->type = CborInvalidType;
Thiago Macieira56d99832015-05-07 14:34:27 -0700176 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700177 }
Thiago Macieira5752ce52015-06-16 12:10:03 -0700178 } else if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (uint8_t)BreakByte) {
Thiago Macieiradbc01292016-06-06 17:02:25 -0700179 /* end of map or array */
Thiago Macieira56d99832015-05-07 14:34:27 -0700180 ++it->ptr;
181 it->type = CborInvalidType;
182 it->remaining = 0;
183 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700184 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700185
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700186 return preparse_value(it);
187}
188
189static CborError advance_internal(CborValue *it)
190{
191 uint64_t length;
Thiago Macieira4e9626c2015-09-21 14:57:17 -0700192 CborError err = extract_number(&it->ptr, it->parser->end, &length);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700193 assert(err == CborNoError);
194
Thiago Macieira56d99832015-05-07 14:34:27 -0700195 if (it->type == CborByteStringType || it->type == CborTextStringType) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700196 assert(length == (size_t)length);
Thiago Macieira56d99832015-05-07 14:34:27 -0700197 assert((it->flags & CborIteratorFlag_UnknownLength) == 0);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700198 it->ptr += length;
199 }
200
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700201 return preparse_next_value(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700202}
203
Thiago Macieira2312efd2015-05-06 16:07:48 -0700204/** \internal
205 *
206 * Decodes the CBOR integer value when it is larger than the 16 bits available
207 * in value->extra. This function requires that value->flags have the
208 * CborIteratorFlag_IntegerValueTooLarge flag set.
209 *
210 * This function is also used to extract single- and double-precision floating
211 * point values (SinglePrecisionFloat == Value32Bit and DoublePrecisionFloat ==
212 * Value64Bit).
213 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700214uint64_t _cbor_value_decode_int64_internal(const CborValue *value)
215{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700216 assert(value->flags & CborIteratorFlag_IntegerValueTooLarge ||
217 value->type == CborFloatType || value->type == CborDoubleType);
Thiago Macieira851c4812015-05-08 15:23:20 -0700218
Thiago Macieiradbc01292016-06-06 17:02:25 -0700219 /* since the additional information can only be Value32Bit or Value64Bit,
220 * we just need to test for the one bit those two options differ */
Thiago Macieira851c4812015-05-08 15:23:20 -0700221 assert((*value->ptr & SmallValueMask) == Value32Bit || (*value->ptr & SmallValueMask) == Value64Bit);
222 if ((*value->ptr & 1) == (Value32Bit & 1))
Thiago Macieira54a0e102015-05-05 21:25:06 -0700223 return get32(value->ptr + 1);
224
225 assert((*value->ptr & SmallValueMask) == Value64Bit);
226 return get64(value->ptr + 1);
227}
228
229/**
230 * Initializes the CBOR parser for parsing \a size bytes beginning at \a
231 * buffer. Parsing will use flags set in \a flags. The iterator to the first
232 * element is returned in \a it.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700233 *
234 * The \a parser structure needs to remain valid throughout the decoding
235 * process. It is not thread-safe to share one CborParser among multiple
236 * threads iterating at the same time, but the object can be copied so multiple
237 * threads can iterate.
238 *
239 * ### Write how to determine the end pointer
240 * ### Write how to do limited-buffer windowed decoding
Thiago Macieira54a0e102015-05-05 21:25:06 -0700241 */
Thiago Macieira5752ce52015-06-16 12:10:03 -0700242CborError cbor_parser_init(const uint8_t *buffer, size_t size, int flags, CborParser *parser, CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700243{
244 memset(parser, 0, sizeof(*parser));
245 parser->end = buffer + size;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700246 parser->flags = flags;
247 it->parser = parser;
248 it->ptr = buffer;
Thiago Macieiradbc01292016-06-06 17:02:25 -0700249 it->remaining = 1; /* there's one type altogether, usually an array or map */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700250 return preparse_value(it);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700251}
252
253/**
254 * Advances the CBOR value \a it by one fixed-size position. Fixed-size types
255 * are: integers, tags, simple types (including boolean, null and undefined
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700256 * values) and floating point types.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700257 *
258 * \sa cbor_value_at_end(), cbor_value_advance(), cbor_value_begin_recurse(), cbor_value_end_recurse()
259 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700260CborError cbor_value_advance_fixed(CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700261{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700262 assert(it->type != CborInvalidType);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700263 assert(is_fixed_type(it->type));
264 if (!it->remaining)
265 return CborErrorAdvancePastEOF;
266 return advance_internal(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700267}
268
Thiago Macieira4a99af92015-05-12 10:41:45 +0900269static CborError advance_recursive(CborValue *it, int nestingLevel)
270{
271 if (is_fixed_type(it->type))
272 return advance_internal(it);
273
274 if (!cbor_value_is_container(it)) {
275 size_t len = SIZE_MAX;
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700276 return _cbor_value_copy_string(it, NULL, &len, it);
Thiago Macieira4a99af92015-05-12 10:41:45 +0900277 }
278
Thiago Macieiradbc01292016-06-06 17:02:25 -0700279 /* map or array */
Thiago Macieira4a99af92015-05-12 10:41:45 +0900280 if (nestingLevel == CBOR_PARSER_MAX_RECURSIONS)
281 return CborErrorNestingTooDeep;
282
283 CborError err;
284 CborValue recursed;
285 err = cbor_value_enter_container(it, &recursed);
286 if (err)
287 return err;
288 while (!cbor_value_at_end(&recursed)) {
289 err = advance_recursive(&recursed, nestingLevel + 1);
290 if (err)
291 return err;
292 }
293 return cbor_value_leave_container(it, &recursed);
294}
295
296
Thiago Macieira2312efd2015-05-06 16:07:48 -0700297/**
298 * Advances the CBOR value \a it by one element, skipping over containers.
299 * Unlike cbor_value_advance_fixed(), this function can be called on a CBOR
300 * value of any type. However, if the type is a container (map or array) or a
301 * string with a chunked payload, this function will not run in constant time
302 * and will recurse into itself (it will run on O(n) time for the number of
303 * elements or chunks and will use O(n) memory for the number of nested
304 * containers).
305 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700306 * \sa cbor_value_at_end(), cbor_value_advance_fixed(), cbor_value_begin_recurse(), cbor_value_end_recurse()
307 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700308CborError cbor_value_advance(CborValue *it)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700309{
310 assert(it->type != CborInvalidType);
311 if (!it->remaining)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700312 return CborErrorAdvancePastEOF;
Thiago Macieira4a99af92015-05-12 10:41:45 +0900313 return advance_recursive(it, 0);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700314}
315
316/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700317 * Advances the CBOR value \a it until it no longer points to a tag. If \a it is
318 * already not pointing to a tag, then this function returns it unchanged.
319 *
320 * \sa cbor_value_advance_fixed(), cbor_value_advance()
321 */
322CborError cbor_value_skip_tag(CborValue *it)
323{
324 while (cbor_value_is_tag(it)) {
325 CborError err = cbor_value_advance_fixed(it);
326 if (err)
327 return err;
328 }
329 return CborNoError;
330}
331
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700332/**
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700333 * \fn bool cbor_value_is_container(const CborValue *it)
334 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700335 * Returns true if the \a it value is a container and requires recursion in
336 * order to decode (maps and arrays), false otherwise.
337 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700338
Thiago Macieira2312efd2015-05-06 16:07:48 -0700339/**
340 * Creates a CborValue iterator pointing to the first element of the container
341 * represented by \a it and saves it in \a recursed. The \a it container object
342 * needs to be kept and passed again to cbor_value_leave_container() in order
343 * to continue iterating past this container.
344 *
345 * \sa cbor_value_is_container(), cbor_value_leave_container(), cbor_value_advance()
346 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700347CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700348{
Thiago Macieira56d99832015-05-07 14:34:27 -0700349 CborError err;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700350 assert(cbor_value_is_container(it));
Thiago Macieira54a0e102015-05-05 21:25:06 -0700351 *recursed = *it;
Thiago Macieira56d99832015-05-07 14:34:27 -0700352
Thiago Macieira54a0e102015-05-05 21:25:06 -0700353 if (it->flags & CborIteratorFlag_UnknownLength) {
354 recursed->remaining = UINT32_MAX;
Thiago Macieira56d99832015-05-07 14:34:27 -0700355 ++recursed->ptr;
356 err = preparse_value(recursed);
357 if (err != CborErrorUnexpectedBreak)
358 return err;
Thiago Macieiradbc01292016-06-06 17:02:25 -0700359 /* actually, break was expected here
360 * it's just an empty container */
Thiago Macieira56d99832015-05-07 14:34:27 -0700361 ++recursed->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700362 } else {
Thiago Macieira56d99832015-05-07 14:34:27 -0700363 uint64_t len;
Thiago Macieira4e9626c2015-09-21 14:57:17 -0700364 err = extract_number(&recursed->ptr, recursed->parser->end, &len);
Thiago Macieira56d99832015-05-07 14:34:27 -0700365 assert(err == CborNoError);
Thiago Macieira56d99832015-05-07 14:34:27 -0700366
Thiago Macieirae12dfd02016-06-07 16:29:25 -0700367 recursed->remaining = (uint32_t)len;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900368 if (recursed->remaining != len || len == UINT32_MAX) {
Thiago Macieiradbc01292016-06-06 17:02:25 -0700369 /* back track the pointer to indicate where the error occurred */
Thiago Macieira3f76f632015-05-12 10:10:09 +0900370 recursed->ptr = it->ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700371 return CborErrorDataTooLarge;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900372 }
Thiago Macieirace16f052015-05-07 23:14:25 -0700373 if (recursed->type == CborMapType) {
Thiago Macieiradbc01292016-06-06 17:02:25 -0700374 /* maps have keys and values, so we need to multiply by 2 */
Thiago Macieira3f76f632015-05-12 10:10:09 +0900375 if (recursed->remaining > UINT32_MAX / 2) {
Thiago Macieiradbc01292016-06-06 17:02:25 -0700376 /* back track the pointer to indicate where the error occurred */
Thiago Macieira3f76f632015-05-12 10:10:09 +0900377 recursed->ptr = it->ptr;
Thiago Macieirace16f052015-05-07 23:14:25 -0700378 return CborErrorDataTooLarge;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900379 }
Thiago Macieirace16f052015-05-07 23:14:25 -0700380 recursed->remaining *= 2;
381 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700382 if (len != 0)
383 return preparse_value(recursed);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700384 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700385
Thiago Macieiradbc01292016-06-06 17:02:25 -0700386 /* the case of the empty container */
Thiago Macieira56d99832015-05-07 14:34:27 -0700387 recursed->type = CborInvalidType;
388 recursed->remaining = 0;
389 return CborNoError;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700390}
391
Thiago Macieira2312efd2015-05-06 16:07:48 -0700392/**
393 * Updates \a it to point to the next element after the container. The \a
Thiago Macieira56d99832015-05-07 14:34:27 -0700394 * recursed object needs to point to the element obtained either by advancing
395 * the last element of the container (via cbor_value_advance(),
396 * cbor_value_advance_fixed(), a nested cbor_value_leave_container(), or the \c
397 * next pointer from cbor_value_copy_string() or cbor_value_dup_string()).
Thiago Macieira2312efd2015-05-06 16:07:48 -0700398 *
399 * \sa cbor_value_enter_container(), cbor_value_at_end()
400 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700401CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700402{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700403 assert(cbor_value_is_container(it));
Thiago Macieira56d99832015-05-07 14:34:27 -0700404 assert(recursed->type == CborInvalidType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700405 it->ptr = recursed->ptr;
Thiago Macieira56d99832015-05-07 14:34:27 -0700406 return preparse_next_value(it);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700407}
408
Thiago Macieira2312efd2015-05-06 16:07:48 -0700409/**
410 * Calculates the length of the string in \a value and stores the result in \a
411 * len. This function is different from cbor_value_get_string_length() in that
412 * it calculates the length even for strings sent in chunks. For that reason,
413 * this function may not run in constant time (it will run in O(n) time on the
414 * number of chunks).
415 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700416 * \note On 32-bit platforms, this function will return error condition of \ref
417 * CborErrorDataTooLarge if the stream indicates a length that is too big to
418 * fit in 32-bit.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700419 *
420 * \sa cbor_value_get_string_length(), cbor_value_copy_string(), cbor_value_is_length_known()
421 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700422CborError cbor_value_calculate_string_length(const CborValue *value, size_t *len)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700423{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900424 *len = SIZE_MAX;
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700425 return _cbor_value_copy_string(value, NULL, len, NULL);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700426}
427
Thiago Macieiradbc01292016-06-06 17:02:25 -0700428/* We return uintptr_t so that we can pass memcpy directly as the iteration
429 * function. The choice is to optimize for memcpy, which is used in the base
430 * parser API (cbor_value_copy_string), while memcmp is used in convenience API
431 * only. */
Thiago Macieira5752ce52015-06-16 12:10:03 -0700432typedef uintptr_t (*IterateFunction)(char *, const uint8_t *, size_t);
Thiago Macieira9ae05812015-05-11 15:09:09 +0900433
Thiago Macieira5752ce52015-06-16 12:10:03 -0700434static uintptr_t iterate_noop(char *dest, const uint8_t *src, size_t len)
Thiago Macieira9ae05812015-05-11 15:09:09 +0900435{
436 (void)dest;
437 (void)src;
438 (void)len;
439 return true;
440}
441
Thiago Macieira5752ce52015-06-16 12:10:03 -0700442static uintptr_t iterate_memcmp(char *s1, const uint8_t *s2, size_t len)
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700443{
Thiago Macieira5752ce52015-06-16 12:10:03 -0700444 return memcmp(s1, (const char *)s2, len) == 0;
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700445}
446
Thiago Macieira9ae05812015-05-11 15:09:09 +0900447static CborError iterate_string_chunks(const CborValue *value, char *buffer, size_t *buflen,
448 bool *result, CborValue *next, IterateFunction func)
449{
450 assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value));
451
452 size_t total;
453 CborError err;
Thiago Macieira5752ce52015-06-16 12:10:03 -0700454 const uint8_t *ptr = value->ptr;
Thiago Macieira9ae05812015-05-11 15:09:09 +0900455 if (cbor_value_is_length_known(value)) {
Thiago Macieiradbc01292016-06-06 17:02:25 -0700456 /* easy case: fixed length */
Thiago Macieira9ae05812015-05-11 15:09:09 +0900457 err = extract_length(value->parser, &ptr, &total);
458 if (err)
459 return err;
Thiago Macieira63abed92015-10-28 17:01:14 -0700460 if (total > (size_t)(value->parser->end - ptr))
Thiago Macieira9ae05812015-05-11 15:09:09 +0900461 return CborErrorUnexpectedEOF;
462 if (total <= *buflen)
Thiago Macieirae12dfd02016-06-07 16:29:25 -0700463 *result = !!func(buffer, ptr, total);
Thiago Macieira9ae05812015-05-11 15:09:09 +0900464 else
465 *result = false;
466 ptr += total;
467 } else {
Thiago Macieiradbc01292016-06-06 17:02:25 -0700468 /* chunked */
Thiago Macieira9ae05812015-05-11 15:09:09 +0900469 ++ptr;
470 total = 0;
471 *result = true;
472 while (true) {
473 size_t chunkLen;
474 size_t newTotal;
475
476 if (ptr == value->parser->end)
477 return CborErrorUnexpectedEOF;
478
Thiago Macieira5752ce52015-06-16 12:10:03 -0700479 if (*ptr == (uint8_t)BreakByte) {
Thiago Macieira9ae05812015-05-11 15:09:09 +0900480 ++ptr;
481 break;
482 }
483
Thiago Macieiradbc01292016-06-06 17:02:25 -0700484 /* is this the right type? */
Thiago Macieira9ae05812015-05-11 15:09:09 +0900485 if ((*ptr & MajorTypeMask) != value->type)
486 return CborErrorIllegalType;
487
488 err = extract_length(value->parser, &ptr, &chunkLen);
489 if (err)
490 return err;
491
Thiago Macieira1de31a42015-06-16 16:01:16 -0700492 if (unlikely(add_check_overflow(total, chunkLen, &newTotal)))
Thiago Macieira9ae05812015-05-11 15:09:09 +0900493 return CborErrorDataTooLarge;
494
Thiago Macieira63abed92015-10-28 17:01:14 -0700495 if (chunkLen > (size_t)(value->parser->end - ptr))
Thiago Macieira9ae05812015-05-11 15:09:09 +0900496 return CborErrorUnexpectedEOF;
497
498 if (*result && *buflen >= newTotal)
Thiago Macieirae12dfd02016-06-07 16:29:25 -0700499 *result = !!func(buffer + total, ptr, chunkLen);
Thiago Macieira9ae05812015-05-11 15:09:09 +0900500 else
501 *result = false;
502
503 ptr += chunkLen;
504 total = newTotal;
505 }
506 }
507
Thiago Macieiradbc01292016-06-06 17:02:25 -0700508 /* is there enough room for the ending NUL byte? */
Thiago Macieira9ae05812015-05-11 15:09:09 +0900509 if (*result && *buflen > total)
Thiago Macieirae12dfd02016-06-07 16:29:25 -0700510 *result = !!func(buffer + total, (const uint8_t *)"", 1);
Thiago Macieira9ae05812015-05-11 15:09:09 +0900511 *buflen = total;
512
513 if (next) {
514 *next = *value;
515 next->ptr = ptr;
516 return preparse_next_value(next);
517 }
518 return CborNoError;
519}
520
Thiago Macieira2312efd2015-05-06 16:07:48 -0700521/**
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700522 * \fn CborError cbor_value_copy_text_string(const CborValue *value, char *buffer, size_t *buflen, CborValue *next)
523 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700524 * Copies the string pointed by \a value into the buffer provided at \a buffer
525 * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
526 * copy anything and will only update the \a next value.
527 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700528 * If the provided buffer length was too small, this function returns an error
529 * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
530 * of the string in order to preallocate a buffer, use
Thiago Macieira2312efd2015-05-06 16:07:48 -0700531 * cbor_value_calculate_string_length().
532 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700533 * On success, this function sets the number of bytes copied to \c{*buflen}. If
534 * the buffer is large enough, this function will insert a null byte after the
535 * last copied byte, to facilitate manipulation of text strings. That byte is
536 * not included in the returned value of \c{*buflen}.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700537 *
538 * The \a next pointer, if not null, will be updated to point to the next item
539 * after this string. If \a value points to the last item, then \a next will be
540 * invalid.
541 *
542 * \note This function does not perform UTF-8 validation on the incoming text
543 * string.
544 *
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700545 * \sa cbor_value_dup_text_string(), cbor_value_copy_byte_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
Thiago Macieira2312efd2015-05-06 16:07:48 -0700546 */
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700547
548/**
549 * \fn CborError cbor_value_copy_byte_string(const CborValue *value, uint8_t *buffer, size_t *buflen, CborValue *next)
550 *
551 * Copies the string pointed by \a value into the buffer provided at \a buffer
552 * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
553 * copy anything and will only update the \a next value.
554 *
555 * If the provided buffer length was too small, this function returns an error
556 * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
557 * of the string in order to preallocate a buffer, use
558 * cbor_value_calculate_string_length().
559 *
560 * On success, this function sets the number of bytes copied to \c{*buflen}. If
561 * the buffer is large enough, this function will insert a null byte after the
562 * last copied byte, to facilitate manipulation of null-terminated strings.
563 * That byte is not included in the returned value of \c{*buflen}.
564 *
565 * The \a next pointer, if not null, will be updated to point to the next item
566 * after this string. If \a value points to the last item, then \a next will be
567 * invalid.
568 *
569 * \sa cbor_value_dup_text_string(), cbor_value_copy_text_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
570 */
571
572CborError _cbor_value_copy_string(const CborValue *value, void *buffer,
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700573 size_t *buflen, CborValue *next)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700574{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900575 bool copied_all;
Thiago Macieiraed5b57c2015-07-07 16:38:27 -0700576 CborError err = iterate_string_chunks(value, (char*)buffer, buflen, &copied_all, next,
Thiago Macieira9ae05812015-05-11 15:09:09 +0900577 buffer ? (IterateFunction)memcpy : iterate_noop);
578 return err ? err :
579 copied_all ? CborNoError : CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700580}
581
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700582/**
583 * Compares the entry \a value with the string \a string and store the result
584 * in \a result. If the value is different from \a string or if it is not a
585 * text string, \a result will contain \c false.
586 *
587 * The entry at \a value may be a tagged string. If \a is not a string or a
588 * tagged string, the comparison result will be false.
589 */
590CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result)
591{
592 CborValue copy = *value;
593 CborError err = cbor_value_skip_tag(&copy);
594 if (err)
595 return err;
596 if (!cbor_value_is_text_string(&copy)) {
597 *result = false;
598 return CborNoError;
599 }
600
601 size_t len = strlen(string);
602 return iterate_string_chunks(&copy, CONST_CAST(char *, string), &len, result, NULL, iterate_memcmp);
603}
604
605/**
Thiago Macieira7b623c22015-05-11 15:52:14 +0900606 * Attempts to find the value in map \a map that corresponds to the text string
607 * entry \a string. If the item is found, it is stored in \a result. If no item
608 * is found matching the key, then \a result will contain an element of type
609 * \ref CborInvalidType.
610 *
611 * \note This function may be expensive to execute.
612 */
613CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element)
614{
615 assert(cbor_value_is_map(map));
616 size_t len = strlen(string);
617 CborError err = cbor_value_enter_container(map, element);
618 if (err)
619 goto error;
620
621 while (!cbor_value_at_end(element)) {
Thiago Macieiradbc01292016-06-06 17:02:25 -0700622 /* find the non-tag so we can compare */
Thiago Macieira7b623c22015-05-11 15:52:14 +0900623 err = cbor_value_skip_tag(element);
624 if (err)
625 goto error;
626 if (cbor_value_is_text_string(element)) {
627 bool equals;
628 size_t dummyLen = len;
629 err = iterate_string_chunks(element, CONST_CAST(char *, string), &dummyLen,
630 &equals, element, iterate_memcmp);
631 if (err)
632 goto error;
633 if (equals)
634 return preparse_value(element);
635 } else {
Thiago Macieiradbc01292016-06-06 17:02:25 -0700636 /* skip this key */
Thiago Macieira7b623c22015-05-11 15:52:14 +0900637 err = cbor_value_advance(element);
638 if (err)
639 goto error;
640 }
641
Thiago Macieiradbc01292016-06-06 17:02:25 -0700642 /* skip this value */
Thiago Macieira7b623c22015-05-11 15:52:14 +0900643 err = cbor_value_skip_tag(element);
644 if (err)
645 goto error;
646 err = cbor_value_advance(element);
647 if (err)
648 goto error;
649 }
650
Thiago Macieiradbc01292016-06-06 17:02:25 -0700651 /* not found */
Thiago Macieira7b623c22015-05-11 15:52:14 +0900652 element->type = CborInvalidType;
653 return CborNoError;
654
655error:
656 element->type = CborInvalidType;
657 return err;
658}
659
660/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700661 * Extracts a half-precision floating point from \a value and stores it in \a
662 * result.
663 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700664CborError cbor_value_get_half_float(const CborValue *value, void *result)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700665{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700666 assert(value->type == CborHalfFloatType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700667
Thiago Macieiradbc01292016-06-06 17:02:25 -0700668 /* size has been computed already */
Thiago Macieirac70169f2015-05-06 07:49:44 -0700669 uint16_t v = get16(value->ptr + 1);
670 memcpy(result, &v, sizeof(v));
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700671 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700672}