blob: 315f9ea842fa21620f8d20965b3f3f3f9478935e [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>
31#include <endian.h>
Thiago Macieira2312efd2015-05-06 16:07:48 -070032#include <stdlib.h>
Thiago Macieira54a0e102015-05-05 21:25:06 -070033#include <string.h>
34
Thiago Macieira4a99af92015-05-12 10:41:45 +090035#ifndef CBOR_PARSER_MAX_RECURSIONS
36# define CBOR_PARSER_MAX_RECURSIONS 1024
37#endif
38
Thiago Macieira54a0e102015-05-05 21:25:06 -070039/**
40 * \typedef CborValue
41 * This type contains one value parsed from the CBOR stream.
42 *
43 * To get the actual type, use cbor_value_get_type(). Then extract the value
44 * using one of the corresponding functions: cbor_value_get_boolean(), cbor_value_get_int64(),
45 * cbor_value_get_int(), cbor_value_copy_string(), cbor_value_get_array(), cbor_value_get_map(),
46 * cbor_value_get_double(), cbor_value_get_float().
47 *
48 * In C++ and C11 modes, you can additionally use the cbor_value_get_integer()
49 * and cbor_value_get_floating_point() generic functions.
50 *
51 * \omit
52 * Implementation details: the CborValue contains these fields:
53 * \list
54 * \li ptr: pointer to the actual data
55 * \li flags: flags from the decoder
Thiago Macieira2312efd2015-05-06 16:07:48 -070056 * \li extra: partially decoded integer value (0, 1 or 2 bytes)
Thiago Macieira54a0e102015-05-05 21:25:06 -070057 * \li remaining: remaining items in this collection after this item or UINT32_MAX if length is unknown
58 * \endlist
59 * \endomit
60 */
61
Thiago Macieira54a0e102015-05-05 21:25:06 -070062static inline uint16_t get16(const char *ptr)
63{
64 uint16_t result;
65 memcpy(&result, ptr, sizeof(result));
66 return be16toh(result);
67}
68
69static inline uint32_t get32(const char *ptr)
70{
71 uint32_t result;
72 memcpy(&result, ptr, sizeof(result));
73 return be32toh(result);
74}
75
76static inline uint64_t get64(const char *ptr)
77{
78 uint64_t result;
79 memcpy(&result, ptr, sizeof(result));
80 return be64toh(result);
81}
82
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070083static inline CborError extract_number(const CborParser *parser, const char **ptr, uint64_t *len)
Thiago Macieira2312efd2015-05-06 16:07:48 -070084{
85 uint8_t additional_information = **ptr & SmallValueMask;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070086 ++*ptr;
Thiago Macieira2312efd2015-05-06 16:07:48 -070087 if (additional_information < Value8Bit) {
88 *len = additional_information;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070089 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -070090 }
91 if (unlikely(additional_information > Value64Bit))
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070092 return CborErrorIllegalNumber;
Thiago Macieira2312efd2015-05-06 16:07:48 -070093
94 size_t bytesNeeded = 1 << (additional_information - Value8Bit);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070095 if (unlikely(*ptr + bytesNeeded > parser->end)) {
96 return CborErrorUnexpectedEOF;
Thiago Macieira2312efd2015-05-06 16:07:48 -070097 } else if (bytesNeeded == 1) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070098 *len = (uint8_t)(*ptr)[0];
Thiago Macieira2312efd2015-05-06 16:07:48 -070099 } else if (bytesNeeded == 2) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700100 *len = get16(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700101 } else if (bytesNeeded == 4) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700102 *len = get32(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700103 } else {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700104 *len = get64(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700105 }
106 *ptr += bytesNeeded;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700107 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700108}
109
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700110static inline CborError extract_length(const CborParser *parser, const char **ptr, size_t *len)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700111{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700112 uint64_t v;
113 CborError err = extract_number(parser, ptr, &v);
114 if (err)
115 return err;
116
117 *len = v;
118 if (v != *len)
119 return CborErrorDataTooLarge;
120 return CborNoError;
121}
122
123static bool is_fixed_type(uint8_t type)
124{
125 return type != CborTextStringType && type != CborByteStringType && type != CborArrayType &&
126 type != CborMapType;
127}
128
129static CborError preparse_value(CborValue *it)
130{
131 const CborParser *parser = it->parser;
Thiago Macieira11e913f2015-05-07 13:01:18 -0700132 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700133
Thiago Macieira54a0e102015-05-05 21:25:06 -0700134 // are we at the end?
Thiago Macieira54a0e102015-05-05 21:25:06 -0700135 if (it->ptr == parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700136 return CborErrorUnexpectedEOF;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700137
138 uint8_t descriptor = *it->ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700139 uint8_t type = descriptor & MajorTypeMask;
Thiago Macieira851c4812015-05-08 15:23:20 -0700140 it->type = type;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700141 it->flags = 0;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700142 it->extra = (descriptor &= SmallValueMask);
143
Thiago Macieira56d99832015-05-07 14:34:27 -0700144 if (descriptor > Value64Bit) {
145 if (unlikely(descriptor != IndefiniteLength))
Thiago Macieira3f76f632015-05-12 10:10:09 +0900146 return type == CborSimpleType ? CborErrorUnknownType : CborErrorIllegalNumber;
Thiago Macieira56d99832015-05-07 14:34:27 -0700147 if (likely(!is_fixed_type(type))) {
148 // special case
149 it->flags |= CborIteratorFlag_UnknownLength;
150 it->type = type;
151 return CborNoError;
152 }
153 return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700154 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700155
Thiago Macieirac70169f2015-05-06 07:49:44 -0700156 size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit));
157 if (it->ptr + 1 + bytesNeeded > parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700158 return CborErrorUnexpectedEOF;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700159
Thiago Macieira851c4812015-05-08 15:23:20 -0700160 uint8_t majortype = type >> MajorTypeShift;
161 if (majortype == NegativeIntegerType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700162 it->flags |= CborIteratorFlag_NegativeInteger;
Thiago Macieira851c4812015-05-08 15:23:20 -0700163 it->type = CborIntegerType;
164 } else if (majortype == SimpleTypesType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700165 switch (descriptor) {
166 case FalseValue:
167 it->extra = false;
Thiago Macieira851c4812015-05-08 15:23:20 -0700168 it->type = CborBooleanType;
Thiago Macieira991dd922015-05-07 11:57:59 -0700169 break;
170
Thiago Macieira851c4812015-05-08 15:23:20 -0700171 case SinglePrecisionFloat:
172 case DoublePrecisionFloat:
173 it->flags |= CborIteratorFlag_IntegerValueTooLarge;
174 // fall through
Thiago Macieira54a0e102015-05-05 21:25:06 -0700175 case TrueValue:
176 case NullValue:
177 case UndefinedValue:
178 case HalfPrecisionFloat:
Thiago Macieira851c4812015-05-08 15:23:20 -0700179 it->type = *it->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700180 break;
181
182 case SimpleTypeInNextByte:
Thiago Macieira851c4812015-05-08 15:23:20 -0700183 it->extra = (uint8_t)it->ptr[1];
Thiago Macieira54a0e102015-05-05 21:25:06 -0700184#ifndef CBOR_PARSER_NO_STRICT_CHECKS
Thiago Macieira851c4812015-05-08 15:23:20 -0700185 if (unlikely(it->extra < 32)) {
186 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700187 return CborErrorIllegalSimpleType;
Thiago Macieira851c4812015-05-08 15:23:20 -0700188 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700189#endif
Thiago Macieira991dd922015-05-07 11:57:59 -0700190 break;
191
Thiago Macieira54a0e102015-05-05 21:25:06 -0700192 case 28:
193 case 29:
194 case 30:
Thiago Macieira54a0e102015-05-05 21:25:06 -0700195 case Break:
Thiago Macieira851c4812015-05-08 15:23:20 -0700196 assert(false); // these conditions can't be reached
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700197 return CborErrorUnexpectedBreak;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700198 }
Thiago Macieira851c4812015-05-08 15:23:20 -0700199 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700200 }
201
202 // try to decode up to 16 bits
203 if (descriptor < Value8Bit)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700204 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700205
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700206 if (descriptor == Value8Bit)
207 it->extra = (uint8_t)it->ptr[1];
208 else if (descriptor == Value16Bit)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700209 it->extra = get16(it->ptr + 1);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700210 else
211 it->flags |= CborIteratorFlag_IntegerValueTooLarge; // Value32Bit or Value64Bit
212 return CborNoError;
213}
Thiago Macieira54a0e102015-05-05 21:25:06 -0700214
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700215static CborError preparse_next_value(CborValue *it)
216{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700217 if (it->remaining != UINT32_MAX) {
Thiago Macieira11e913f2015-05-07 13:01:18 -0700218 // don't decrement the item count if the current item is tag: they don't count
219 if (it->type != CborTagType && !--it->remaining) {
220 it->type = CborInvalidType;
Thiago Macieira56d99832015-05-07 14:34:27 -0700221 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700222 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700223 } else if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (char)BreakByte) {
224 // end of map or array
225 ++it->ptr;
226 it->type = CborInvalidType;
227 it->remaining = 0;
228 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700229 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700230
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700231 return preparse_value(it);
232}
233
234static CborError advance_internal(CborValue *it)
235{
236 uint64_t length;
237 CborError err = extract_number(it->parser, &it->ptr, &length);
238 assert(err == CborNoError);
239
Thiago Macieira56d99832015-05-07 14:34:27 -0700240 if (it->type == CborByteStringType || it->type == CborTextStringType) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700241 assert(length == (size_t)length);
Thiago Macieira56d99832015-05-07 14:34:27 -0700242 assert((it->flags & CborIteratorFlag_UnknownLength) == 0);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700243 it->ptr += length;
244 }
245
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700246 return preparse_next_value(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700247}
248
Thiago Macieira2312efd2015-05-06 16:07:48 -0700249/** \internal
250 *
251 * Decodes the CBOR integer value when it is larger than the 16 bits available
252 * in value->extra. This function requires that value->flags have the
253 * CborIteratorFlag_IntegerValueTooLarge flag set.
254 *
255 * This function is also used to extract single- and double-precision floating
256 * point values (SinglePrecisionFloat == Value32Bit and DoublePrecisionFloat ==
257 * Value64Bit).
258 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700259uint64_t _cbor_value_decode_int64_internal(const CborValue *value)
260{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700261 assert(value->flags & CborIteratorFlag_IntegerValueTooLarge ||
262 value->type == CborFloatType || value->type == CborDoubleType);
Thiago Macieira851c4812015-05-08 15:23:20 -0700263
264 // since the additional information can only be Value32Bit or Value64Bit,
265 // we just need to test for the one bit those two options differ
266 assert((*value->ptr & SmallValueMask) == Value32Bit || (*value->ptr & SmallValueMask) == Value64Bit);
267 if ((*value->ptr & 1) == (Value32Bit & 1))
Thiago Macieira54a0e102015-05-05 21:25:06 -0700268 return get32(value->ptr + 1);
269
270 assert((*value->ptr & SmallValueMask) == Value64Bit);
271 return get64(value->ptr + 1);
272}
273
274/**
275 * Initializes the CBOR parser for parsing \a size bytes beginning at \a
276 * buffer. Parsing will use flags set in \a flags. The iterator to the first
277 * element is returned in \a it.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700278 *
279 * The \a parser structure needs to remain valid throughout the decoding
280 * process. It is not thread-safe to share one CborParser among multiple
281 * threads iterating at the same time, but the object can be copied so multiple
282 * threads can iterate.
283 *
284 * ### Write how to determine the end pointer
285 * ### Write how to do limited-buffer windowed decoding
Thiago Macieira54a0e102015-05-05 21:25:06 -0700286 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700287CborError cbor_parser_init(const char *buffer, size_t size, int flags, CborParser *parser, CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700288{
289 memset(parser, 0, sizeof(*parser));
290 parser->end = buffer + size;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700291 parser->flags = flags;
292 it->parser = parser;
293 it->ptr = buffer;
294 it->remaining = 1; // there's one type altogether, usually an array or map
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700295 return preparse_value(it);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700296}
297
298/**
299 * Advances the CBOR value \a it by one fixed-size position. Fixed-size types
300 * are: integers, tags, simple types (including boolean, null and undefined
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700301 * values) and floating point types.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700302 *
303 * \sa cbor_value_at_end(), cbor_value_advance(), cbor_value_begin_recurse(), cbor_value_end_recurse()
304 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700305CborError cbor_value_advance_fixed(CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700306{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700307 assert(it->type != CborInvalidType);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700308 assert(is_fixed_type(it->type));
309 if (!it->remaining)
310 return CborErrorAdvancePastEOF;
311 return advance_internal(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700312}
313
Thiago Macieira4a99af92015-05-12 10:41:45 +0900314static CborError advance_recursive(CborValue *it, int nestingLevel)
315{
316 if (is_fixed_type(it->type))
317 return advance_internal(it);
318
319 if (!cbor_value_is_container(it)) {
320 size_t len = SIZE_MAX;
321 return cbor_value_copy_string(it, NULL, &len, it);
322 }
323
324 // map or array
325 if (nestingLevel == CBOR_PARSER_MAX_RECURSIONS)
326 return CborErrorNestingTooDeep;
327
328 CborError err;
329 CborValue recursed;
330 err = cbor_value_enter_container(it, &recursed);
331 if (err)
332 return err;
333 while (!cbor_value_at_end(&recursed)) {
334 err = advance_recursive(&recursed, nestingLevel + 1);
335 if (err)
336 return err;
337 }
338 return cbor_value_leave_container(it, &recursed);
339}
340
341
Thiago Macieira2312efd2015-05-06 16:07:48 -0700342/**
343 * Advances the CBOR value \a it by one element, skipping over containers.
344 * Unlike cbor_value_advance_fixed(), this function can be called on a CBOR
345 * value of any type. However, if the type is a container (map or array) or a
346 * string with a chunked payload, this function will not run in constant time
347 * and will recurse into itself (it will run on O(n) time for the number of
348 * elements or chunks and will use O(n) memory for the number of nested
349 * containers).
350 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700351 * \sa cbor_value_at_end(), cbor_value_advance_fixed(), cbor_value_begin_recurse(), cbor_value_end_recurse()
352 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700353CborError cbor_value_advance(CborValue *it)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700354{
355 assert(it->type != CborInvalidType);
356 if (!it->remaining)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700357 return CborErrorAdvancePastEOF;
Thiago Macieira4a99af92015-05-12 10:41:45 +0900358 return advance_recursive(it, 0);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700359}
360
361/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700362 * Advances the CBOR value \a it until it no longer points to a tag. If \a it is
363 * already not pointing to a tag, then this function returns it unchanged.
364 *
365 * \sa cbor_value_advance_fixed(), cbor_value_advance()
366 */
367CborError cbor_value_skip_tag(CborValue *it)
368{
369 while (cbor_value_is_tag(it)) {
370 CborError err = cbor_value_advance_fixed(it);
371 if (err)
372 return err;
373 }
374 return CborNoError;
375}
376
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700377/**
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700378 * \fn bool cbor_value_is_container(const CborValue *it)
379 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700380 * Returns true if the \a it value is a container and requires recursion in
381 * order to decode (maps and arrays), false otherwise.
382 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700383
Thiago Macieira2312efd2015-05-06 16:07:48 -0700384/**
385 * Creates a CborValue iterator pointing to the first element of the container
386 * represented by \a it and saves it in \a recursed. The \a it container object
387 * needs to be kept and passed again to cbor_value_leave_container() in order
388 * to continue iterating past this container.
389 *
390 * \sa cbor_value_is_container(), cbor_value_leave_container(), cbor_value_advance()
391 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700392CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700393{
Thiago Macieira56d99832015-05-07 14:34:27 -0700394 CborError err;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700395 assert(cbor_value_is_container(it));
Thiago Macieira54a0e102015-05-05 21:25:06 -0700396 *recursed = *it;
Thiago Macieira56d99832015-05-07 14:34:27 -0700397
Thiago Macieira54a0e102015-05-05 21:25:06 -0700398 if (it->flags & CborIteratorFlag_UnknownLength) {
399 recursed->remaining = UINT32_MAX;
Thiago Macieira56d99832015-05-07 14:34:27 -0700400 ++recursed->ptr;
401 err = preparse_value(recursed);
402 if (err != CborErrorUnexpectedBreak)
403 return err;
404 // actually, break was expected here
405 // it's just an empty container
406 ++recursed->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700407 } else {
Thiago Macieira56d99832015-05-07 14:34:27 -0700408 uint64_t len;
409 err = extract_number(recursed->parser, &recursed->ptr, &len);
410 assert(err == CborNoError);
Thiago Macieira56d99832015-05-07 14:34:27 -0700411
Thiago Macieira54a0e102015-05-05 21:25:06 -0700412 recursed->remaining = len;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900413 if (recursed->remaining != len || len == UINT32_MAX) {
414 // back track the pointer to indicate where the error occurred
415 recursed->ptr = it->ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700416 return CborErrorDataTooLarge;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900417 }
Thiago Macieirace16f052015-05-07 23:14:25 -0700418 if (recursed->type == CborMapType) {
419 // maps have keys and values, so we need to multiply by 2
Thiago Macieira3f76f632015-05-12 10:10:09 +0900420 if (recursed->remaining > UINT32_MAX / 2) {
421 // back track the pointer to indicate where the error occurred
422 recursed->ptr = it->ptr;
Thiago Macieirace16f052015-05-07 23:14:25 -0700423 return CborErrorDataTooLarge;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900424 }
Thiago Macieirace16f052015-05-07 23:14:25 -0700425 recursed->remaining *= 2;
426 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700427 if (len != 0)
428 return preparse_value(recursed);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700429 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700430
431 // the case of the empty container
432 recursed->type = CborInvalidType;
433 recursed->remaining = 0;
434 return CborNoError;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700435}
436
Thiago Macieira2312efd2015-05-06 16:07:48 -0700437/**
438 * Updates \a it to point to the next element after the container. The \a
Thiago Macieira56d99832015-05-07 14:34:27 -0700439 * recursed object needs to point to the element obtained either by advancing
440 * the last element of the container (via cbor_value_advance(),
441 * cbor_value_advance_fixed(), a nested cbor_value_leave_container(), or the \c
442 * next pointer from cbor_value_copy_string() or cbor_value_dup_string()).
Thiago Macieira2312efd2015-05-06 16:07:48 -0700443 *
444 * \sa cbor_value_enter_container(), cbor_value_at_end()
445 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700446CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700447{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700448 assert(cbor_value_is_container(it));
Thiago Macieira56d99832015-05-07 14:34:27 -0700449 assert(recursed->type == CborInvalidType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700450 it->ptr = recursed->ptr;
Thiago Macieira56d99832015-05-07 14:34:27 -0700451 return preparse_next_value(it);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700452}
453
Thiago Macieira2312efd2015-05-06 16:07:48 -0700454/**
455 * Calculates the length of the string in \a value and stores the result in \a
456 * len. This function is different from cbor_value_get_string_length() in that
457 * it calculates the length even for strings sent in chunks. For that reason,
458 * this function may not run in constant time (it will run in O(n) time on the
459 * number of chunks).
460 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700461 * \note On 32-bit platforms, this function will return error condition of \ref
462 * CborErrorDataTooLarge if the stream indicates a length that is too big to
463 * fit in 32-bit.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700464 *
465 * \sa cbor_value_get_string_length(), cbor_value_copy_string(), cbor_value_is_length_known()
466 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700467CborError cbor_value_calculate_string_length(const CborValue *value, size_t *len)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700468{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900469 *len = SIZE_MAX;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700470 return cbor_value_copy_string(value, NULL, len, NULL);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700471}
472
Thiago Macieira2312efd2015-05-06 16:07:48 -0700473/**
474 * Allocates memory for the string pointed by \a value and copies it into this
475 * buffer. The pointer to the buffer is stored in \a buffer and the number of
476 * bytes copied is stored in \a len (those variables must not be NULL).
477 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700478 * If \c malloc returns a NULL pointer, this function will return error
479 * condition \ref CborErrorOutOfMemory.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700480 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700481 * On success, \c{*buffer} will contain a valid pointer that must be freed by
482 * calling \c{free()}. This is the case even for zero-length strings.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700483 *
484 * The \a next pointer, if not null, will be updated to point to the next item
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700485 * after this string. If \a value points to the last item, then \a next will be
486 * invalid.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700487 *
488 * \note This function does not perform UTF-8 validation on the incoming text
489 * string.
490 *
491 * \sa cbor_value_copy_string()
492 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700493CborError cbor_value_dup_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700494{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700495 assert(buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700496 assert(buflen);
Thiago Macieira851c4812015-05-08 15:23:20 -0700497 CborError err = cbor_value_copy_string(value, NULL, buflen, NULL);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700498 if (err)
499 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700500
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700501 ++*buflen;
502 *buffer = malloc(*buflen);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700503 if (!*buffer) {
Thiago Macieirac70169f2015-05-06 07:49:44 -0700504 // out of memory
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700505 return CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700506 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700507 err = cbor_value_copy_string(value, *buffer, buflen, next);
508 if (err) {
Thiago Macieira2312efd2015-05-06 16:07:48 -0700509 free(*buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700510 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700511 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700512 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700513}
514
Thiago Macieira9ae05812015-05-11 15:09:09 +0900515// We return uintptr_t so that we can pass memcpy directly as the iteration
516// function. The choice is to optimize for memcpy, which is used in the base
517// parser API (cbor_value_copy_string), while memcmp is used in convenience API
518// only.
519typedef uintptr_t (*IterateFunction)(char *, const char *, size_t);
520
521static uintptr_t iterate_noop(char *dest, const char *src, size_t len)
522{
523 (void)dest;
524 (void)src;
525 (void)len;
526 return true;
527}
528
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700529static uintptr_t iterate_memcmp(char *s1, const char *s2, size_t len)
530{
531 return memcmp(s1, s2, len) == 0;
532}
533
Thiago Macieira9ae05812015-05-11 15:09:09 +0900534static CborError iterate_string_chunks(const CborValue *value, char *buffer, size_t *buflen,
535 bool *result, CborValue *next, IterateFunction func)
536{
537 assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value));
538
539 size_t total;
540 CborError err;
541 const char *ptr = value->ptr;
542 if (cbor_value_is_length_known(value)) {
543 // easy case: fixed length
544 err = extract_length(value->parser, &ptr, &total);
545 if (err)
546 return err;
547 if (ptr + total > value->parser->end)
548 return CborErrorUnexpectedEOF;
549 if (total <= *buflen)
550 *result = func(buffer, ptr, total);
551 else
552 *result = false;
553 ptr += total;
554 } else {
555 // chunked
556 ++ptr;
557 total = 0;
558 *result = true;
559 while (true) {
560 size_t chunkLen;
561 size_t newTotal;
562
563 if (ptr == value->parser->end)
564 return CborErrorUnexpectedEOF;
565
566 if (*ptr == (char)BreakByte) {
567 ++ptr;
568 break;
569 }
570
571 // is this the right type?
572 if ((*ptr & MajorTypeMask) != value->type)
573 return CborErrorIllegalType;
574
575 err = extract_length(value->parser, &ptr, &chunkLen);
576 if (err)
577 return err;
578
579 if (unlikely(!add_check_overflow(total, chunkLen, &newTotal)))
580 return CborErrorDataTooLarge;
581
582 if (ptr + chunkLen > value->parser->end)
583 return CborErrorUnexpectedEOF;
584
585 if (*result && *buflen >= newTotal)
586 *result = func(buffer + total, ptr, chunkLen);
587 else
588 *result = false;
589
590 ptr += chunkLen;
591 total = newTotal;
592 }
593 }
594
595 // is there enough room for the ending NUL byte?
596 if (*result && *buflen > total)
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700597 *result = func(buffer + total, "", 1);
Thiago Macieira9ae05812015-05-11 15:09:09 +0900598 *buflen = total;
599
600 if (next) {
601 *next = *value;
602 next->ptr = ptr;
603 return preparse_next_value(next);
604 }
605 return CborNoError;
606}
607
Thiago Macieira2312efd2015-05-06 16:07:48 -0700608/**
609 * Copies the string pointed by \a value into the buffer provided at \a buffer
610 * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
611 * copy anything and will only update the \a next value.
612 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700613 * If the provided buffer length was too small, this function returns an error
614 * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
615 * of the string in order to preallocate a buffer, use
Thiago Macieira2312efd2015-05-06 16:07:48 -0700616 * cbor_value_calculate_string_length().
617 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700618 * On success, this function sets the number of bytes copied to \c{*buflen}. If
619 * the buffer is large enough, this function will insert a null byte after the
620 * last copied byte, to facilitate manipulation of text strings. That byte is
621 * not included in the returned value of \c{*buflen}.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700622 *
623 * The \a next pointer, if not null, will be updated to point to the next item
624 * after this string. If \a value points to the last item, then \a next will be
625 * invalid.
626 *
627 * \note This function does not perform UTF-8 validation on the incoming text
628 * string.
629 *
630 * \sa cbor_value_dup_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
631 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700632CborError cbor_value_copy_string(const CborValue *value, char *buffer,
633 size_t *buflen, CborValue *next)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700634{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900635 bool copied_all;
636 CborError err = iterate_string_chunks(value, buffer, buflen, &copied_all, next,
637 buffer ? (IterateFunction)memcpy : iterate_noop);
638 return err ? err :
639 copied_all ? CborNoError : CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700640}
641
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700642/**
643 * Compares the entry \a value with the string \a string and store the result
644 * in \a result. If the value is different from \a string or if it is not a
645 * text string, \a result will contain \c false.
646 *
647 * The entry at \a value may be a tagged string. If \a is not a string or a
648 * tagged string, the comparison result will be false.
649 */
650CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result)
651{
652 CborValue copy = *value;
653 CborError err = cbor_value_skip_tag(&copy);
654 if (err)
655 return err;
656 if (!cbor_value_is_text_string(&copy)) {
657 *result = false;
658 return CborNoError;
659 }
660
661 size_t len = strlen(string);
662 return iterate_string_chunks(&copy, CONST_CAST(char *, string), &len, result, NULL, iterate_memcmp);
663}
664
665/**
Thiago Macieira7b623c22015-05-11 15:52:14 +0900666 * Attempts to find the value in map \a map that corresponds to the text string
667 * entry \a string. If the item is found, it is stored in \a result. If no item
668 * is found matching the key, then \a result will contain an element of type
669 * \ref CborInvalidType.
670 *
671 * \note This function may be expensive to execute.
672 */
673CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element)
674{
675 assert(cbor_value_is_map(map));
676 size_t len = strlen(string);
677 CborError err = cbor_value_enter_container(map, element);
678 if (err)
679 goto error;
680
681 while (!cbor_value_at_end(element)) {
682 // find the non-tag so we can compare
683 err = cbor_value_skip_tag(element);
684 if (err)
685 goto error;
686 if (cbor_value_is_text_string(element)) {
687 bool equals;
688 size_t dummyLen = len;
689 err = iterate_string_chunks(element, CONST_CAST(char *, string), &dummyLen,
690 &equals, element, iterate_memcmp);
691 if (err)
692 goto error;
693 if (equals)
694 return preparse_value(element);
695 } else {
696 // skip this key
697 err = cbor_value_advance(element);
698 if (err)
699 goto error;
700 }
701
702 // skip this value
703 err = cbor_value_skip_tag(element);
704 if (err)
705 goto error;
706 err = cbor_value_advance(element);
707 if (err)
708 goto error;
709 }
710
711 // not found
712 element->type = CborInvalidType;
713 return CborNoError;
714
715error:
716 element->type = CborInvalidType;
717 return err;
718}
719
720/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700721 * Extracts a half-precision floating point from \a value and stores it in \a
722 * result.
723 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700724CborError cbor_value_get_half_float(const CborValue *value, void *result)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700725{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700726 assert(value->type == CborHalfFloatType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700727
728 // size has been computed already
729 uint16_t v = get16(value->ptr + 1);
730 memcpy(result, &v, sizeof(v));
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700731 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700732}