blob: d21ff23e5fc175a7555d570ffb89306c35eac8ac [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
25#define _BSD_SOURCE
26#include "cbor.h"
27#include "cborconstants_p.h"
28#include "compilersupport_p.h"
29
30#include <assert.h>
Thiago Macieira2312efd2015-05-06 16:07:48 -070031#include <stdlib.h>
Thiago Macieira54a0e102015-05-05 21:25:06 -070032#include <string.h>
33
Thiago Macieira4a99af92015-05-12 10:41:45 +090034#ifndef CBOR_PARSER_MAX_RECURSIONS
35# define CBOR_PARSER_MAX_RECURSIONS 1024
36#endif
37
Thiago Macieira54a0e102015-05-05 21:25:06 -070038/**
39 * \typedef CborValue
40 * This type contains one value parsed from the CBOR stream.
41 *
42 * To get the actual type, use cbor_value_get_type(). Then extract the value
43 * using one of the corresponding functions: cbor_value_get_boolean(), cbor_value_get_int64(),
44 * cbor_value_get_int(), cbor_value_copy_string(), cbor_value_get_array(), cbor_value_get_map(),
45 * cbor_value_get_double(), cbor_value_get_float().
46 *
47 * In C++ and C11 modes, you can additionally use the cbor_value_get_integer()
48 * and cbor_value_get_floating_point() generic functions.
49 *
50 * \omit
51 * Implementation details: the CborValue contains these fields:
52 * \list
53 * \li ptr: pointer to the actual data
54 * \li flags: flags from the decoder
Thiago Macieira2312efd2015-05-06 16:07:48 -070055 * \li extra: partially decoded integer value (0, 1 or 2 bytes)
Thiago Macieira54a0e102015-05-05 21:25:06 -070056 * \li remaining: remaining items in this collection after this item or UINT32_MAX if length is unknown
57 * \endlist
58 * \endomit
59 */
60
Thiago Macieira5752ce52015-06-16 12:10:03 -070061static inline uint16_t get16(const uint8_t *ptr)
Thiago Macieira54a0e102015-05-05 21:25:06 -070062{
63 uint16_t result;
64 memcpy(&result, ptr, sizeof(result));
Thiago Macieira5934a9f2015-06-16 11:55:28 -070065 return cbor_ntohs(result);
Thiago Macieira54a0e102015-05-05 21:25:06 -070066}
67
Thiago Macieira5752ce52015-06-16 12:10:03 -070068static inline uint32_t get32(const uint8_t *ptr)
Thiago Macieira54a0e102015-05-05 21:25:06 -070069{
70 uint32_t result;
71 memcpy(&result, ptr, sizeof(result));
Thiago Macieira5934a9f2015-06-16 11:55:28 -070072 return cbor_ntohl(result);
Thiago Macieira54a0e102015-05-05 21:25:06 -070073}
74
Thiago Macieira5752ce52015-06-16 12:10:03 -070075static inline uint64_t get64(const uint8_t *ptr)
Thiago Macieira54a0e102015-05-05 21:25:06 -070076{
77 uint64_t result;
78 memcpy(&result, ptr, sizeof(result));
Thiago Macieira5934a9f2015-06-16 11:55:28 -070079 return cbor_ntohll(result);
Thiago Macieira54a0e102015-05-05 21:25:06 -070080}
81
Thiago Macieiraf5cb94b2015-06-16 16:10:49 -070082static CborError extract_number(const CborParser *parser, const uint8_t **ptr, uint64_t *len)
Thiago Macieira2312efd2015-05-06 16:07:48 -070083{
84 uint8_t additional_information = **ptr & SmallValueMask;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070085 ++*ptr;
Thiago Macieira2312efd2015-05-06 16:07:48 -070086 if (additional_information < Value8Bit) {
87 *len = additional_information;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070088 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -070089 }
90 if (unlikely(additional_information > Value64Bit))
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070091 return CborErrorIllegalNumber;
Thiago Macieira2312efd2015-05-06 16:07:48 -070092
93 size_t bytesNeeded = 1 << (additional_information - Value8Bit);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070094 if (unlikely(*ptr + bytesNeeded > parser->end)) {
95 return CborErrorUnexpectedEOF;
Thiago Macieira2312efd2015-05-06 16:07:48 -070096 } else if (bytesNeeded == 1) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070097 *len = (uint8_t)(*ptr)[0];
Thiago Macieira2312efd2015-05-06 16:07:48 -070098 } else if (bytesNeeded == 2) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070099 *len = get16(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700100 } else if (bytesNeeded == 4) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700101 *len = get32(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700102 } else {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700103 *len = get64(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700104 }
105 *ptr += bytesNeeded;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700106 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700107}
108
Thiago Macieiraf5cb94b2015-06-16 16:10:49 -0700109static CborError extract_length(const CborParser *parser, const uint8_t **ptr, size_t *len)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700110{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700111 uint64_t v;
112 CborError err = extract_number(parser, ptr, &v);
113 if (err)
114 return err;
115
116 *len = v;
117 if (v != *len)
118 return CborErrorDataTooLarge;
119 return CborNoError;
120}
121
122static bool is_fixed_type(uint8_t type)
123{
124 return type != CborTextStringType && type != CborByteStringType && type != CborArrayType &&
125 type != CborMapType;
126}
127
128static CborError preparse_value(CborValue *it)
129{
130 const CborParser *parser = it->parser;
Thiago Macieira11e913f2015-05-07 13:01:18 -0700131 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700132
Thiago Macieira54a0e102015-05-05 21:25:06 -0700133 // are we at the end?
Thiago Macieira54a0e102015-05-05 21:25:06 -0700134 if (it->ptr == parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700135 return CborErrorUnexpectedEOF;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700136
137 uint8_t descriptor = *it->ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700138 uint8_t type = descriptor & MajorTypeMask;
Thiago Macieira851c4812015-05-08 15:23:20 -0700139 it->type = type;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700140 it->flags = 0;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700141 it->extra = (descriptor &= SmallValueMask);
142
Thiago Macieira56d99832015-05-07 14:34:27 -0700143 if (descriptor > Value64Bit) {
144 if (unlikely(descriptor != IndefiniteLength))
Thiago Macieira3f76f632015-05-12 10:10:09 +0900145 return type == CborSimpleType ? CborErrorUnknownType : CborErrorIllegalNumber;
Thiago Macieira56d99832015-05-07 14:34:27 -0700146 if (likely(!is_fixed_type(type))) {
147 // special case
148 it->flags |= CborIteratorFlag_UnknownLength;
149 it->type = type;
150 return CborNoError;
151 }
152 return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700153 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700154
Thiago Macieirac70169f2015-05-06 07:49:44 -0700155 size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit));
156 if (it->ptr + 1 + bytesNeeded > parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700157 return CborErrorUnexpectedEOF;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700158
Thiago Macieira851c4812015-05-08 15:23:20 -0700159 uint8_t majortype = type >> MajorTypeShift;
160 if (majortype == NegativeIntegerType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700161 it->flags |= CborIteratorFlag_NegativeInteger;
Thiago Macieira851c4812015-05-08 15:23:20 -0700162 it->type = CborIntegerType;
163 } else if (majortype == SimpleTypesType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700164 switch (descriptor) {
165 case FalseValue:
166 it->extra = false;
Thiago Macieira851c4812015-05-08 15:23:20 -0700167 it->type = CborBooleanType;
Thiago Macieira991dd922015-05-07 11:57:59 -0700168 break;
169
Thiago Macieira851c4812015-05-08 15:23:20 -0700170 case SinglePrecisionFloat:
171 case DoublePrecisionFloat:
172 it->flags |= CborIteratorFlag_IntegerValueTooLarge;
173 // fall through
Thiago Macieira54a0e102015-05-05 21:25:06 -0700174 case TrueValue:
175 case NullValue:
176 case UndefinedValue:
177 case HalfPrecisionFloat:
Thiago Macieira851c4812015-05-08 15:23:20 -0700178 it->type = *it->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700179 break;
180
181 case SimpleTypeInNextByte:
Thiago Macieira851c4812015-05-08 15:23:20 -0700182 it->extra = (uint8_t)it->ptr[1];
Thiago Macieira54a0e102015-05-05 21:25:06 -0700183#ifndef CBOR_PARSER_NO_STRICT_CHECKS
Thiago Macieira851c4812015-05-08 15:23:20 -0700184 if (unlikely(it->extra < 32)) {
185 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700186 return CborErrorIllegalSimpleType;
Thiago Macieira851c4812015-05-08 15:23:20 -0700187 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700188#endif
Thiago Macieira991dd922015-05-07 11:57:59 -0700189 break;
190
Thiago Macieira54a0e102015-05-05 21:25:06 -0700191 case 28:
192 case 29:
193 case 30:
Thiago Macieira54a0e102015-05-05 21:25:06 -0700194 case Break:
Thiago Macieira851c4812015-05-08 15:23:20 -0700195 assert(false); // these conditions can't be reached
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700196 return CborErrorUnexpectedBreak;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700197 }
Thiago Macieira851c4812015-05-08 15:23:20 -0700198 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700199 }
200
201 // try to decode up to 16 bits
202 if (descriptor < Value8Bit)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700203 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700204
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700205 if (descriptor == Value8Bit)
206 it->extra = (uint8_t)it->ptr[1];
207 else if (descriptor == Value16Bit)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700208 it->extra = get16(it->ptr + 1);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700209 else
210 it->flags |= CborIteratorFlag_IntegerValueTooLarge; // Value32Bit or Value64Bit
211 return CborNoError;
212}
Thiago Macieira54a0e102015-05-05 21:25:06 -0700213
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700214static CborError preparse_next_value(CborValue *it)
215{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700216 if (it->remaining != UINT32_MAX) {
Thiago Macieira11e913f2015-05-07 13:01:18 -0700217 // don't decrement the item count if the current item is tag: they don't count
218 if (it->type != CborTagType && !--it->remaining) {
219 it->type = CborInvalidType;
Thiago Macieira56d99832015-05-07 14:34:27 -0700220 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700221 }
Thiago Macieira5752ce52015-06-16 12:10:03 -0700222 } else if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (uint8_t)BreakByte) {
Thiago Macieira56d99832015-05-07 14:34:27 -0700223 // end of map or array
224 ++it->ptr;
225 it->type = CborInvalidType;
226 it->remaining = 0;
227 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700228 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700229
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700230 return preparse_value(it);
231}
232
233static CborError advance_internal(CborValue *it)
234{
235 uint64_t length;
236 CborError err = extract_number(it->parser, &it->ptr, &length);
237 assert(err == CborNoError);
238
Thiago Macieira56d99832015-05-07 14:34:27 -0700239 if (it->type == CborByteStringType || it->type == CborTextStringType) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700240 assert(length == (size_t)length);
Thiago Macieira56d99832015-05-07 14:34:27 -0700241 assert((it->flags & CborIteratorFlag_UnknownLength) == 0);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700242 it->ptr += length;
243 }
244
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700245 return preparse_next_value(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700246}
247
Thiago Macieira2312efd2015-05-06 16:07:48 -0700248/** \internal
249 *
250 * Decodes the CBOR integer value when it is larger than the 16 bits available
251 * in value->extra. This function requires that value->flags have the
252 * CborIteratorFlag_IntegerValueTooLarge flag set.
253 *
254 * This function is also used to extract single- and double-precision floating
255 * point values (SinglePrecisionFloat == Value32Bit and DoublePrecisionFloat ==
256 * Value64Bit).
257 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700258uint64_t _cbor_value_decode_int64_internal(const CborValue *value)
259{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700260 assert(value->flags & CborIteratorFlag_IntegerValueTooLarge ||
261 value->type == CborFloatType || value->type == CborDoubleType);
Thiago Macieira851c4812015-05-08 15:23:20 -0700262
263 // since the additional information can only be Value32Bit or Value64Bit,
264 // we just need to test for the one bit those two options differ
265 assert((*value->ptr & SmallValueMask) == Value32Bit || (*value->ptr & SmallValueMask) == Value64Bit);
266 if ((*value->ptr & 1) == (Value32Bit & 1))
Thiago Macieira54a0e102015-05-05 21:25:06 -0700267 return get32(value->ptr + 1);
268
269 assert((*value->ptr & SmallValueMask) == Value64Bit);
270 return get64(value->ptr + 1);
271}
272
273/**
274 * Initializes the CBOR parser for parsing \a size bytes beginning at \a
275 * buffer. Parsing will use flags set in \a flags. The iterator to the first
276 * element is returned in \a it.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700277 *
278 * The \a parser structure needs to remain valid throughout the decoding
279 * process. It is not thread-safe to share one CborParser among multiple
280 * threads iterating at the same time, but the object can be copied so multiple
281 * threads can iterate.
282 *
283 * ### Write how to determine the end pointer
284 * ### Write how to do limited-buffer windowed decoding
Thiago Macieira54a0e102015-05-05 21:25:06 -0700285 */
Thiago Macieira5752ce52015-06-16 12:10:03 -0700286CborError cbor_parser_init(const uint8_t *buffer, size_t size, int flags, CborParser *parser, CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700287{
288 memset(parser, 0, sizeof(*parser));
289 parser->end = buffer + size;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700290 parser->flags = flags;
291 it->parser = parser;
292 it->ptr = buffer;
293 it->remaining = 1; // there's one type altogether, usually an array or map
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700294 return preparse_value(it);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700295}
296
297/**
298 * Advances the CBOR value \a it by one fixed-size position. Fixed-size types
299 * are: integers, tags, simple types (including boolean, null and undefined
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700300 * values) and floating point types.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700301 *
302 * \sa cbor_value_at_end(), cbor_value_advance(), cbor_value_begin_recurse(), cbor_value_end_recurse()
303 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700304CborError cbor_value_advance_fixed(CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700305{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700306 assert(it->type != CborInvalidType);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700307 assert(is_fixed_type(it->type));
308 if (!it->remaining)
309 return CborErrorAdvancePastEOF;
310 return advance_internal(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700311}
312
Thiago Macieira4a99af92015-05-12 10:41:45 +0900313static CborError advance_recursive(CborValue *it, int nestingLevel)
314{
315 if (is_fixed_type(it->type))
316 return advance_internal(it);
317
318 if (!cbor_value_is_container(it)) {
319 size_t len = SIZE_MAX;
320 return cbor_value_copy_string(it, NULL, &len, it);
321 }
322
323 // map or array
324 if (nestingLevel == CBOR_PARSER_MAX_RECURSIONS)
325 return CborErrorNestingTooDeep;
326
327 CborError err;
328 CborValue recursed;
329 err = cbor_value_enter_container(it, &recursed);
330 if (err)
331 return err;
332 while (!cbor_value_at_end(&recursed)) {
333 err = advance_recursive(&recursed, nestingLevel + 1);
334 if (err)
335 return err;
336 }
337 return cbor_value_leave_container(it, &recursed);
338}
339
340
Thiago Macieira2312efd2015-05-06 16:07:48 -0700341/**
342 * Advances the CBOR value \a it by one element, skipping over containers.
343 * Unlike cbor_value_advance_fixed(), this function can be called on a CBOR
344 * value of any type. However, if the type is a container (map or array) or a
345 * string with a chunked payload, this function will not run in constant time
346 * and will recurse into itself (it will run on O(n) time for the number of
347 * elements or chunks and will use O(n) memory for the number of nested
348 * containers).
349 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700350 * \sa cbor_value_at_end(), cbor_value_advance_fixed(), cbor_value_begin_recurse(), cbor_value_end_recurse()
351 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700352CborError cbor_value_advance(CborValue *it)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700353{
354 assert(it->type != CborInvalidType);
355 if (!it->remaining)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700356 return CborErrorAdvancePastEOF;
Thiago Macieira4a99af92015-05-12 10:41:45 +0900357 return advance_recursive(it, 0);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700358}
359
360/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700361 * Advances the CBOR value \a it until it no longer points to a tag. If \a it is
362 * already not pointing to a tag, then this function returns it unchanged.
363 *
364 * \sa cbor_value_advance_fixed(), cbor_value_advance()
365 */
366CborError cbor_value_skip_tag(CborValue *it)
367{
368 while (cbor_value_is_tag(it)) {
369 CborError err = cbor_value_advance_fixed(it);
370 if (err)
371 return err;
372 }
373 return CborNoError;
374}
375
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700376/**
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700377 * \fn bool cbor_value_is_container(const CborValue *it)
378 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700379 * Returns true if the \a it value is a container and requires recursion in
380 * order to decode (maps and arrays), false otherwise.
381 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700382
Thiago Macieira2312efd2015-05-06 16:07:48 -0700383/**
384 * Creates a CborValue iterator pointing to the first element of the container
385 * represented by \a it and saves it in \a recursed. The \a it container object
386 * needs to be kept and passed again to cbor_value_leave_container() in order
387 * to continue iterating past this container.
388 *
389 * \sa cbor_value_is_container(), cbor_value_leave_container(), cbor_value_advance()
390 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700391CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700392{
Thiago Macieira56d99832015-05-07 14:34:27 -0700393 CborError err;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700394 assert(cbor_value_is_container(it));
Thiago Macieira54a0e102015-05-05 21:25:06 -0700395 *recursed = *it;
Thiago Macieira56d99832015-05-07 14:34:27 -0700396
Thiago Macieira54a0e102015-05-05 21:25:06 -0700397 if (it->flags & CborIteratorFlag_UnknownLength) {
398 recursed->remaining = UINT32_MAX;
Thiago Macieira56d99832015-05-07 14:34:27 -0700399 ++recursed->ptr;
400 err = preparse_value(recursed);
401 if (err != CborErrorUnexpectedBreak)
402 return err;
403 // actually, break was expected here
404 // it's just an empty container
405 ++recursed->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700406 } else {
Thiago Macieira56d99832015-05-07 14:34:27 -0700407 uint64_t len;
408 err = extract_number(recursed->parser, &recursed->ptr, &len);
409 assert(err == CborNoError);
Thiago Macieira56d99832015-05-07 14:34:27 -0700410
Thiago Macieira54a0e102015-05-05 21:25:06 -0700411 recursed->remaining = len;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900412 if (recursed->remaining != len || len == UINT32_MAX) {
413 // back track the pointer to indicate where the error occurred
414 recursed->ptr = it->ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700415 return CborErrorDataTooLarge;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900416 }
Thiago Macieirace16f052015-05-07 23:14:25 -0700417 if (recursed->type == CborMapType) {
418 // maps have keys and values, so we need to multiply by 2
Thiago Macieira3f76f632015-05-12 10:10:09 +0900419 if (recursed->remaining > UINT32_MAX / 2) {
420 // back track the pointer to indicate where the error occurred
421 recursed->ptr = it->ptr;
Thiago Macieirace16f052015-05-07 23:14:25 -0700422 return CborErrorDataTooLarge;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900423 }
Thiago Macieirace16f052015-05-07 23:14:25 -0700424 recursed->remaining *= 2;
425 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700426 if (len != 0)
427 return preparse_value(recursed);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700428 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700429
430 // the case of the empty container
431 recursed->type = CborInvalidType;
432 recursed->remaining = 0;
433 return CborNoError;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700434}
435
Thiago Macieira2312efd2015-05-06 16:07:48 -0700436/**
437 * Updates \a it to point to the next element after the container. The \a
Thiago Macieira56d99832015-05-07 14:34:27 -0700438 * recursed object needs to point to the element obtained either by advancing
439 * the last element of the container (via cbor_value_advance(),
440 * cbor_value_advance_fixed(), a nested cbor_value_leave_container(), or the \c
441 * next pointer from cbor_value_copy_string() or cbor_value_dup_string()).
Thiago Macieira2312efd2015-05-06 16:07:48 -0700442 *
443 * \sa cbor_value_enter_container(), cbor_value_at_end()
444 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700445CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700446{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700447 assert(cbor_value_is_container(it));
Thiago Macieira56d99832015-05-07 14:34:27 -0700448 assert(recursed->type == CborInvalidType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700449 it->ptr = recursed->ptr;
Thiago Macieira56d99832015-05-07 14:34:27 -0700450 return preparse_next_value(it);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700451}
452
Thiago Macieira2312efd2015-05-06 16:07:48 -0700453/**
454 * Calculates the length of the string in \a value and stores the result in \a
455 * len. This function is different from cbor_value_get_string_length() in that
456 * it calculates the length even for strings sent in chunks. For that reason,
457 * this function may not run in constant time (it will run in O(n) time on the
458 * number of chunks).
459 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700460 * \note On 32-bit platforms, this function will return error condition of \ref
461 * CborErrorDataTooLarge if the stream indicates a length that is too big to
462 * fit in 32-bit.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700463 *
464 * \sa cbor_value_get_string_length(), cbor_value_copy_string(), cbor_value_is_length_known()
465 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700466CborError cbor_value_calculate_string_length(const CborValue *value, size_t *len)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700467{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900468 *len = SIZE_MAX;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700469 return cbor_value_copy_string(value, NULL, len, NULL);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700470}
471
Thiago Macieira2312efd2015-05-06 16:07:48 -0700472/**
473 * Allocates memory for the string pointed by \a value and copies it into this
474 * buffer. The pointer to the buffer is stored in \a buffer and the number of
475 * bytes copied is stored in \a len (those variables must not be NULL).
476 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700477 * If \c malloc returns a NULL pointer, this function will return error
478 * condition \ref CborErrorOutOfMemory.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700479 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700480 * On success, \c{*buffer} will contain a valid pointer that must be freed by
481 * calling \c{free()}. This is the case even for zero-length strings.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700482 *
483 * The \a next pointer, if not null, will be updated to point to the next item
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700484 * after this string. If \a value points to the last item, then \a next will be
485 * invalid.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700486 *
487 * \note This function does not perform UTF-8 validation on the incoming text
488 * string.
489 *
490 * \sa cbor_value_copy_string()
491 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700492CborError cbor_value_dup_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700493{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700494 assert(buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700495 assert(buflen);
Thiago Macieira851c4812015-05-08 15:23:20 -0700496 CborError err = cbor_value_copy_string(value, NULL, buflen, NULL);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700497 if (err)
498 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700499
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700500 ++*buflen;
501 *buffer = malloc(*buflen);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700502 if (!*buffer) {
Thiago Macieirac70169f2015-05-06 07:49:44 -0700503 // out of memory
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700504 return CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700505 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700506 err = cbor_value_copy_string(value, *buffer, buflen, next);
507 if (err) {
Thiago Macieira2312efd2015-05-06 16:07:48 -0700508 free(*buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700509 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700510 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700511 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700512}
513
Thiago Macieira9ae05812015-05-11 15:09:09 +0900514// We return uintptr_t so that we can pass memcpy directly as the iteration
515// function. The choice is to optimize for memcpy, which is used in the base
516// parser API (cbor_value_copy_string), while memcmp is used in convenience API
517// only.
Thiago Macieira5752ce52015-06-16 12:10:03 -0700518typedef uintptr_t (*IterateFunction)(char *, const uint8_t *, size_t);
Thiago Macieira9ae05812015-05-11 15:09:09 +0900519
Thiago Macieira5752ce52015-06-16 12:10:03 -0700520static uintptr_t iterate_noop(char *dest, const uint8_t *src, size_t len)
Thiago Macieira9ae05812015-05-11 15:09:09 +0900521{
522 (void)dest;
523 (void)src;
524 (void)len;
525 return true;
526}
527
Thiago Macieira5752ce52015-06-16 12:10:03 -0700528static uintptr_t iterate_memcmp(char *s1, const uint8_t *s2, size_t len)
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700529{
Thiago Macieira5752ce52015-06-16 12:10:03 -0700530 return memcmp(s1, (const char *)s2, len) == 0;
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700531}
532
Thiago Macieira9ae05812015-05-11 15:09:09 +0900533static CborError iterate_string_chunks(const CborValue *value, char *buffer, size_t *buflen,
534 bool *result, CborValue *next, IterateFunction func)
535{
536 assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value));
537
538 size_t total;
539 CborError err;
Thiago Macieira5752ce52015-06-16 12:10:03 -0700540 const uint8_t *ptr = value->ptr;
Thiago Macieira9ae05812015-05-11 15:09:09 +0900541 if (cbor_value_is_length_known(value)) {
542 // easy case: fixed length
543 err = extract_length(value->parser, &ptr, &total);
544 if (err)
545 return err;
546 if (ptr + total > value->parser->end)
547 return CborErrorUnexpectedEOF;
548 if (total <= *buflen)
549 *result = func(buffer, ptr, total);
550 else
551 *result = false;
552 ptr += total;
553 } else {
554 // chunked
555 ++ptr;
556 total = 0;
557 *result = true;
558 while (true) {
559 size_t chunkLen;
560 size_t newTotal;
561
562 if (ptr == value->parser->end)
563 return CborErrorUnexpectedEOF;
564
Thiago Macieira5752ce52015-06-16 12:10:03 -0700565 if (*ptr == (uint8_t)BreakByte) {
Thiago Macieira9ae05812015-05-11 15:09:09 +0900566 ++ptr;
567 break;
568 }
569
570 // is this the right type?
571 if ((*ptr & MajorTypeMask) != value->type)
572 return CborErrorIllegalType;
573
574 err = extract_length(value->parser, &ptr, &chunkLen);
575 if (err)
576 return err;
577
Thiago Macieira1de31a42015-06-16 16:01:16 -0700578 if (unlikely(add_check_overflow(total, chunkLen, &newTotal)))
Thiago Macieira9ae05812015-05-11 15:09:09 +0900579 return CborErrorDataTooLarge;
580
581 if (ptr + chunkLen > value->parser->end)
582 return CborErrorUnexpectedEOF;
583
584 if (*result && *buflen >= newTotal)
585 *result = func(buffer + total, ptr, chunkLen);
586 else
587 *result = false;
588
589 ptr += chunkLen;
590 total = newTotal;
591 }
592 }
593
594 // is there enough room for the ending NUL byte?
595 if (*result && *buflen > total)
Thiago Macieira5752ce52015-06-16 12:10:03 -0700596 *result = func(buffer + total, (const uint8_t *)"", 1);
Thiago Macieira9ae05812015-05-11 15:09:09 +0900597 *buflen = total;
598
599 if (next) {
600 *next = *value;
601 next->ptr = ptr;
602 return preparse_next_value(next);
603 }
604 return CborNoError;
605}
606
Thiago Macieira2312efd2015-05-06 16:07:48 -0700607/**
608 * Copies the string pointed by \a value into the buffer provided at \a buffer
609 * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
610 * copy anything and will only update the \a next value.
611 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700612 * If the provided buffer length was too small, this function returns an error
613 * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
614 * of the string in order to preallocate a buffer, use
Thiago Macieira2312efd2015-05-06 16:07:48 -0700615 * cbor_value_calculate_string_length().
616 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700617 * On success, this function sets the number of bytes copied to \c{*buflen}. If
618 * the buffer is large enough, this function will insert a null byte after the
619 * last copied byte, to facilitate manipulation of text strings. That byte is
620 * not included in the returned value of \c{*buflen}.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700621 *
622 * The \a next pointer, if not null, will be updated to point to the next item
623 * after this string. If \a value points to the last item, then \a next will be
624 * invalid.
625 *
626 * \note This function does not perform UTF-8 validation on the incoming text
627 * string.
628 *
629 * \sa cbor_value_dup_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
630 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700631CborError cbor_value_copy_string(const CborValue *value, char *buffer,
632 size_t *buflen, CborValue *next)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700633{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900634 bool copied_all;
635 CborError err = iterate_string_chunks(value, buffer, buflen, &copied_all, next,
636 buffer ? (IterateFunction)memcpy : iterate_noop);
637 return err ? err :
638 copied_all ? CborNoError : CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700639}
640
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700641/**
642 * Compares the entry \a value with the string \a string and store the result
643 * in \a result. If the value is different from \a string or if it is not a
644 * text string, \a result will contain \c false.
645 *
646 * The entry at \a value may be a tagged string. If \a is not a string or a
647 * tagged string, the comparison result will be false.
648 */
649CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result)
650{
651 CborValue copy = *value;
652 CborError err = cbor_value_skip_tag(&copy);
653 if (err)
654 return err;
655 if (!cbor_value_is_text_string(&copy)) {
656 *result = false;
657 return CborNoError;
658 }
659
660 size_t len = strlen(string);
661 return iterate_string_chunks(&copy, CONST_CAST(char *, string), &len, result, NULL, iterate_memcmp);
662}
663
664/**
Thiago Macieira7b623c22015-05-11 15:52:14 +0900665 * Attempts to find the value in map \a map that corresponds to the text string
666 * entry \a string. If the item is found, it is stored in \a result. If no item
667 * is found matching the key, then \a result will contain an element of type
668 * \ref CborInvalidType.
669 *
670 * \note This function may be expensive to execute.
671 */
672CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element)
673{
674 assert(cbor_value_is_map(map));
675 size_t len = strlen(string);
676 CborError err = cbor_value_enter_container(map, element);
677 if (err)
678 goto error;
679
680 while (!cbor_value_at_end(element)) {
681 // find the non-tag so we can compare
682 err = cbor_value_skip_tag(element);
683 if (err)
684 goto error;
685 if (cbor_value_is_text_string(element)) {
686 bool equals;
687 size_t dummyLen = len;
688 err = iterate_string_chunks(element, CONST_CAST(char *, string), &dummyLen,
689 &equals, element, iterate_memcmp);
690 if (err)
691 goto error;
692 if (equals)
693 return preparse_value(element);
694 } else {
695 // skip this key
696 err = cbor_value_advance(element);
697 if (err)
698 goto error;
699 }
700
701 // skip this value
702 err = cbor_value_skip_tag(element);
703 if (err)
704 goto error;
705 err = cbor_value_advance(element);
706 if (err)
707 goto error;
708 }
709
710 // not found
711 element->type = CborInvalidType;
712 return CborNoError;
713
714error:
715 element->type = CborInvalidType;
716 return err;
717}
718
719/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700720 * Extracts a half-precision floating point from \a value and stores it in \a
721 * result.
722 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700723CborError cbor_value_get_half_float(const CborValue *value, void *result)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700724{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700725 assert(value->type == CborHalfFloatType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700726
727 // size has been computed already
728 uint16_t v = get16(value->ptr + 1);
729 memcpy(result, &v, sizeof(v));
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700730 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700731}