blob: f5de1f73aa24fd83191ffc23d648b1eb627d2031 [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 Macieira851c4812015-05-08 15:23:20 -070035#ifdef NDEBUG
36# undef assert
37# define assert(cond) do { if (!(cond)) unreachable(); } while (0)
38#endif
39
Thiago Macieirac70169f2015-05-06 07:49:44 -070040#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) && \
41 (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)
42# pragma GCC optimize("-ffunction-sections")
43#endif
44
Thiago Macieira54a0e102015-05-05 21:25:06 -070045/**
46 * \typedef CborValue
47 * This type contains one value parsed from the CBOR stream.
48 *
49 * To get the actual type, use cbor_value_get_type(). Then extract the value
50 * using one of the corresponding functions: cbor_value_get_boolean(), cbor_value_get_int64(),
51 * cbor_value_get_int(), cbor_value_copy_string(), cbor_value_get_array(), cbor_value_get_map(),
52 * cbor_value_get_double(), cbor_value_get_float().
53 *
54 * In C++ and C11 modes, you can additionally use the cbor_value_get_integer()
55 * and cbor_value_get_floating_point() generic functions.
56 *
57 * \omit
58 * Implementation details: the CborValue contains these fields:
59 * \list
60 * \li ptr: pointer to the actual data
61 * \li flags: flags from the decoder
Thiago Macieira2312efd2015-05-06 16:07:48 -070062 * \li extra: partially decoded integer value (0, 1 or 2 bytes)
Thiago Macieira54a0e102015-05-05 21:25:06 -070063 * \li remaining: remaining items in this collection after this item or UINT32_MAX if length is unknown
64 * \endlist
65 * \endomit
66 */
67
Thiago Macieira54a0e102015-05-05 21:25:06 -070068static inline uint16_t get16(const char *ptr)
69{
70 uint16_t result;
71 memcpy(&result, ptr, sizeof(result));
72 return be16toh(result);
73}
74
75static inline uint32_t get32(const char *ptr)
76{
77 uint32_t result;
78 memcpy(&result, ptr, sizeof(result));
79 return be32toh(result);
80}
81
82static inline uint64_t get64(const char *ptr)
83{
84 uint64_t result;
85 memcpy(&result, ptr, sizeof(result));
86 return be64toh(result);
87}
88
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070089static inline CborError extract_number(const CborParser *parser, const char **ptr, uint64_t *len)
Thiago Macieira2312efd2015-05-06 16:07:48 -070090{
91 uint8_t additional_information = **ptr & SmallValueMask;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070092 ++*ptr;
Thiago Macieira2312efd2015-05-06 16:07:48 -070093 if (additional_information < Value8Bit) {
94 *len = additional_information;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070095 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -070096 }
97 if (unlikely(additional_information > Value64Bit))
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070098 return CborErrorIllegalNumber;
Thiago Macieira2312efd2015-05-06 16:07:48 -070099
100 size_t bytesNeeded = 1 << (additional_information - Value8Bit);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700101 if (unlikely(*ptr + bytesNeeded > parser->end)) {
102 return CborErrorUnexpectedEOF;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700103 } else if (bytesNeeded == 1) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700104 *len = (uint8_t)(*ptr)[0];
Thiago Macieira2312efd2015-05-06 16:07:48 -0700105 } else if (bytesNeeded == 2) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700106 *len = get16(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700107 } else if (bytesNeeded == 4) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700108 *len = get32(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700109 } else {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700110 *len = get64(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700111 }
112 *ptr += bytesNeeded;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700113 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700114}
115
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700116static inline CborError extract_length(const CborParser *parser, const char **ptr, size_t *len)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700117{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700118 uint64_t v;
119 CborError err = extract_number(parser, ptr, &v);
120 if (err)
121 return err;
122
123 *len = v;
124 if (v != *len)
125 return CborErrorDataTooLarge;
126 return CborNoError;
127}
128
129static bool is_fixed_type(uint8_t type)
130{
131 return type != CborTextStringType && type != CborByteStringType && type != CborArrayType &&
132 type != CborMapType;
133}
134
135static CborError preparse_value(CborValue *it)
136{
137 const CborParser *parser = it->parser;
Thiago Macieira11e913f2015-05-07 13:01:18 -0700138 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700139
Thiago Macieira54a0e102015-05-05 21:25:06 -0700140 // are we at the end?
Thiago Macieira54a0e102015-05-05 21:25:06 -0700141 if (it->ptr == parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700142 return CborErrorUnexpectedEOF;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700143
144 uint8_t descriptor = *it->ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700145 uint8_t type = descriptor & MajorTypeMask;
Thiago Macieira851c4812015-05-08 15:23:20 -0700146 it->type = type;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700147 it->flags = 0;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700148 it->extra = (descriptor &= SmallValueMask);
149
Thiago Macieira56d99832015-05-07 14:34:27 -0700150 if (descriptor > Value64Bit) {
151 if (unlikely(descriptor != IndefiniteLength))
152 return CborErrorIllegalNumber;
153 if (likely(!is_fixed_type(type))) {
154 // special case
155 it->flags |= CborIteratorFlag_UnknownLength;
156 it->type = type;
157 return CborNoError;
158 }
159 return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700160 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700161
Thiago Macieirac70169f2015-05-06 07:49:44 -0700162 size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit));
163 if (it->ptr + 1 + bytesNeeded > parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700164 return CborErrorUnexpectedEOF;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700165
Thiago Macieira851c4812015-05-08 15:23:20 -0700166 uint8_t majortype = type >> MajorTypeShift;
167 if (majortype == NegativeIntegerType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700168 it->flags |= CborIteratorFlag_NegativeInteger;
Thiago Macieira851c4812015-05-08 15:23:20 -0700169 it->type = CborIntegerType;
170 } else if (majortype == SimpleTypesType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700171 switch (descriptor) {
172 case FalseValue:
173 it->extra = false;
Thiago Macieira851c4812015-05-08 15:23:20 -0700174 it->type = CborBooleanType;
Thiago Macieira991dd922015-05-07 11:57:59 -0700175 break;
176
Thiago Macieira851c4812015-05-08 15:23:20 -0700177 case SinglePrecisionFloat:
178 case DoublePrecisionFloat:
179 it->flags |= CborIteratorFlag_IntegerValueTooLarge;
180 // fall through
Thiago Macieira54a0e102015-05-05 21:25:06 -0700181 case TrueValue:
182 case NullValue:
183 case UndefinedValue:
184 case HalfPrecisionFloat:
Thiago Macieira851c4812015-05-08 15:23:20 -0700185 it->type = *it->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700186 break;
187
188 case SimpleTypeInNextByte:
Thiago Macieira851c4812015-05-08 15:23:20 -0700189 it->extra = (uint8_t)it->ptr[1];
Thiago Macieira54a0e102015-05-05 21:25:06 -0700190#ifndef CBOR_PARSER_NO_STRICT_CHECKS
Thiago Macieira851c4812015-05-08 15:23:20 -0700191 if (unlikely(it->extra < 32)) {
192 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700193 return CborErrorIllegalSimpleType;
Thiago Macieira851c4812015-05-08 15:23:20 -0700194 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700195#endif
Thiago Macieira991dd922015-05-07 11:57:59 -0700196 break;
197
Thiago Macieira54a0e102015-05-05 21:25:06 -0700198 case 28:
199 case 29:
200 case 30:
Thiago Macieira54a0e102015-05-05 21:25:06 -0700201 case Break:
Thiago Macieira851c4812015-05-08 15:23:20 -0700202 assert(false); // these conditions can't be reached
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700203 return CborErrorUnexpectedBreak;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700204 }
Thiago Macieira851c4812015-05-08 15:23:20 -0700205 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700206 }
207
208 // try to decode up to 16 bits
209 if (descriptor < Value8Bit)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700210 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700211
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700212 if (descriptor == Value8Bit)
213 it->extra = (uint8_t)it->ptr[1];
214 else if (descriptor == Value16Bit)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700215 it->extra = get16(it->ptr + 1);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700216 else
217 it->flags |= CborIteratorFlag_IntegerValueTooLarge; // Value32Bit or Value64Bit
218 return CborNoError;
219}
Thiago Macieira54a0e102015-05-05 21:25:06 -0700220
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700221static CborError preparse_next_value(CborValue *it)
222{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700223 if (it->remaining != UINT32_MAX) {
Thiago Macieira11e913f2015-05-07 13:01:18 -0700224 // don't decrement the item count if the current item is tag: they don't count
225 if (it->type != CborTagType && !--it->remaining) {
226 it->type = CborInvalidType;
Thiago Macieira56d99832015-05-07 14:34:27 -0700227 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700228 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700229 } else if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (char)BreakByte) {
230 // end of map or array
231 ++it->ptr;
232 it->type = CborInvalidType;
233 it->remaining = 0;
234 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700235 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700236
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700237 return preparse_value(it);
238}
239
240static CborError advance_internal(CborValue *it)
241{
242 uint64_t length;
243 CborError err = extract_number(it->parser, &it->ptr, &length);
244 assert(err == CborNoError);
245
Thiago Macieira56d99832015-05-07 14:34:27 -0700246 if (it->type == CborByteStringType || it->type == CborTextStringType) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700247 assert(length == (size_t)length);
Thiago Macieira56d99832015-05-07 14:34:27 -0700248 assert((it->flags & CborIteratorFlag_UnknownLength) == 0);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700249 it->ptr += length;
250 }
251
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700252 return preparse_next_value(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700253}
254
Thiago Macieira2312efd2015-05-06 16:07:48 -0700255/** \internal
256 *
257 * Decodes the CBOR integer value when it is larger than the 16 bits available
258 * in value->extra. This function requires that value->flags have the
259 * CborIteratorFlag_IntegerValueTooLarge flag set.
260 *
261 * This function is also used to extract single- and double-precision floating
262 * point values (SinglePrecisionFloat == Value32Bit and DoublePrecisionFloat ==
263 * Value64Bit).
264 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700265uint64_t _cbor_value_decode_int64_internal(const CborValue *value)
266{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700267 assert(value->flags & CborIteratorFlag_IntegerValueTooLarge ||
268 value->type == CborFloatType || value->type == CborDoubleType);
Thiago Macieira851c4812015-05-08 15:23:20 -0700269
270 // since the additional information can only be Value32Bit or Value64Bit,
271 // we just need to test for the one bit those two options differ
272 assert((*value->ptr & SmallValueMask) == Value32Bit || (*value->ptr & SmallValueMask) == Value64Bit);
273 if ((*value->ptr & 1) == (Value32Bit & 1))
Thiago Macieira54a0e102015-05-05 21:25:06 -0700274 return get32(value->ptr + 1);
275
276 assert((*value->ptr & SmallValueMask) == Value64Bit);
277 return get64(value->ptr + 1);
278}
279
280/**
281 * Initializes the CBOR parser for parsing \a size bytes beginning at \a
282 * buffer. Parsing will use flags set in \a flags. The iterator to the first
283 * element is returned in \a it.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700284 *
285 * The \a parser structure needs to remain valid throughout the decoding
286 * process. It is not thread-safe to share one CborParser among multiple
287 * threads iterating at the same time, but the object can be copied so multiple
288 * threads can iterate.
289 *
290 * ### Write how to determine the end pointer
291 * ### Write how to do limited-buffer windowed decoding
Thiago Macieira54a0e102015-05-05 21:25:06 -0700292 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700293CborError cbor_parser_init(const char *buffer, size_t size, int flags, CborParser *parser, CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700294{
295 memset(parser, 0, sizeof(*parser));
296 parser->end = buffer + size;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700297 parser->flags = flags;
298 it->parser = parser;
299 it->ptr = buffer;
300 it->remaining = 1; // there's one type altogether, usually an array or map
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700301 return preparse_value(it);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700302}
303
304/**
305 * Advances the CBOR value \a it by one fixed-size position. Fixed-size types
306 * are: integers, tags, simple types (including boolean, null and undefined
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700307 * values) and floating point types.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700308 *
309 * \sa cbor_value_at_end(), cbor_value_advance(), cbor_value_begin_recurse(), cbor_value_end_recurse()
310 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700311CborError cbor_value_advance_fixed(CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700312{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700313 assert(it->type != CborInvalidType);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700314 assert(is_fixed_type(it->type));
315 if (!it->remaining)
316 return CborErrorAdvancePastEOF;
317 return advance_internal(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700318}
319
Thiago Macieira2312efd2015-05-06 16:07:48 -0700320/**
321 * Advances the CBOR value \a it by one element, skipping over containers.
322 * Unlike cbor_value_advance_fixed(), this function can be called on a CBOR
323 * value of any type. However, if the type is a container (map or array) or a
324 * string with a chunked payload, this function will not run in constant time
325 * and will recurse into itself (it will run on O(n) time for the number of
326 * elements or chunks and will use O(n) memory for the number of nested
327 * containers).
328 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700329 * \sa cbor_value_at_end(), cbor_value_advance_fixed(), cbor_value_begin_recurse(), cbor_value_end_recurse()
330 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700331CborError cbor_value_advance(CborValue *it)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700332{
333 assert(it->type != CborInvalidType);
334 if (!it->remaining)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700335 return CborErrorAdvancePastEOF;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700336 if (is_fixed_type(it->type))
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700337 return advance_internal(it);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700338
Thiago Macieira9ae05812015-05-11 15:09:09 +0900339 if (!cbor_value_is_container(it)) {
340 size_t len = SIZE_MAX;
341 return cbor_value_copy_string(it, NULL, &len, it);
342 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700343
344 // map or array
345 CborError err;
346 CborValue recursed;
347 err = cbor_value_enter_container(it, &recursed);
348 if (err)
349 return err;
350 while (!cbor_value_at_end(&recursed)) {
351 err = cbor_value_advance(&recursed);
352 if (err)
353 return err;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700354 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700355 return cbor_value_leave_container(it, &recursed);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700356}
357
358/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700359 * Advances the CBOR value \a it until it no longer points to a tag. If \a it is
360 * already not pointing to a tag, then this function returns it unchanged.
361 *
362 * \sa cbor_value_advance_fixed(), cbor_value_advance()
363 */
364CborError cbor_value_skip_tag(CborValue *it)
365{
366 while (cbor_value_is_tag(it)) {
367 CborError err = cbor_value_advance_fixed(it);
368 if (err)
369 return err;
370 }
371 return CborNoError;
372}
373
374
375/**
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700376 * \fn bool cbor_value_is_container(const CborValue *it)
377 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700378 * Returns true if the \a it value is a container and requires recursion in
379 * order to decode (maps and arrays), false otherwise.
380 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700381
Thiago Macieira2312efd2015-05-06 16:07:48 -0700382/**
383 * Creates a CborValue iterator pointing to the first element of the container
384 * represented by \a it and saves it in \a recursed. The \a it container object
385 * needs to be kept and passed again to cbor_value_leave_container() in order
386 * to continue iterating past this container.
387 *
388 * \sa cbor_value_is_container(), cbor_value_leave_container(), cbor_value_advance()
389 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700390CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700391{
Thiago Macieira56d99832015-05-07 14:34:27 -0700392 CborError err;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700393 assert(cbor_value_is_container(it));
Thiago Macieira54a0e102015-05-05 21:25:06 -0700394 *recursed = *it;
Thiago Macieira56d99832015-05-07 14:34:27 -0700395
Thiago Macieira54a0e102015-05-05 21:25:06 -0700396 if (it->flags & CborIteratorFlag_UnknownLength) {
397 recursed->remaining = UINT32_MAX;
Thiago Macieira56d99832015-05-07 14:34:27 -0700398 ++recursed->ptr;
399 err = preparse_value(recursed);
400 if (err != CborErrorUnexpectedBreak)
401 return err;
402 // actually, break was expected here
403 // it's just an empty container
404 ++recursed->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700405 } else {
Thiago Macieira56d99832015-05-07 14:34:27 -0700406 uint64_t len;
407 err = extract_number(recursed->parser, &recursed->ptr, &len);
408 assert(err == CborNoError);
Thiago Macieira56d99832015-05-07 14:34:27 -0700409
Thiago Macieira54a0e102015-05-05 21:25:06 -0700410 recursed->remaining = len;
411 if (recursed->remaining != len || len == UINT32_MAX)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700412 return CborErrorDataTooLarge;
Thiago Macieirace16f052015-05-07 23:14:25 -0700413 if (recursed->type == CborMapType) {
414 // maps have keys and values, so we need to multiply by 2
415 if (recursed->remaining > UINT32_MAX / 2)
416 return CborErrorDataTooLarge;
417 recursed->remaining *= 2;
418 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700419 if (len != 0)
420 return preparse_value(recursed);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700421 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700422
423 // the case of the empty container
424 recursed->type = CborInvalidType;
425 recursed->remaining = 0;
426 return CborNoError;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700427}
428
Thiago Macieira2312efd2015-05-06 16:07:48 -0700429/**
430 * Updates \a it to point to the next element after the container. The \a
Thiago Macieira56d99832015-05-07 14:34:27 -0700431 * recursed object needs to point to the element obtained either by advancing
432 * the last element of the container (via cbor_value_advance(),
433 * cbor_value_advance_fixed(), a nested cbor_value_leave_container(), or the \c
434 * next pointer from cbor_value_copy_string() or cbor_value_dup_string()).
Thiago Macieira2312efd2015-05-06 16:07:48 -0700435 *
436 * \sa cbor_value_enter_container(), cbor_value_at_end()
437 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700438CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700439{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700440 assert(cbor_value_is_container(it));
Thiago Macieira56d99832015-05-07 14:34:27 -0700441 assert(recursed->type == CborInvalidType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700442 it->ptr = recursed->ptr;
Thiago Macieira56d99832015-05-07 14:34:27 -0700443 return preparse_next_value(it);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700444}
445
Thiago Macieira2312efd2015-05-06 16:07:48 -0700446/**
447 * Calculates the length of the string in \a value and stores the result in \a
448 * len. This function is different from cbor_value_get_string_length() in that
449 * it calculates the length even for strings sent in chunks. For that reason,
450 * this function may not run in constant time (it will run in O(n) time on the
451 * number of chunks).
452 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700453 * \note On 32-bit platforms, this function will return error condition of \ref
454 * CborErrorDataTooLarge if the stream indicates a length that is too big to
455 * fit in 32-bit.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700456 *
457 * \sa cbor_value_get_string_length(), cbor_value_copy_string(), cbor_value_is_length_known()
458 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700459CborError cbor_value_calculate_string_length(const CborValue *value, size_t *len)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700460{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900461 *len = SIZE_MAX;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700462 return cbor_value_copy_string(value, NULL, len, NULL);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700463}
464
Thiago Macieira2312efd2015-05-06 16:07:48 -0700465/**
466 * Allocates memory for the string pointed by \a value and copies it into this
467 * buffer. The pointer to the buffer is stored in \a buffer and the number of
468 * bytes copied is stored in \a len (those variables must not be NULL).
469 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700470 * If \c malloc returns a NULL pointer, this function will return error
471 * condition \ref CborErrorOutOfMemory.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700472 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700473 * On success, \c{*buffer} will contain a valid pointer that must be freed by
474 * calling \c{free()}. This is the case even for zero-length strings.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700475 *
476 * The \a next pointer, if not null, will be updated to point to the next item
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700477 * after this string. If \a value points to the last item, then \a next will be
478 * invalid.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700479 *
480 * \note This function does not perform UTF-8 validation on the incoming text
481 * string.
482 *
483 * \sa cbor_value_copy_string()
484 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700485CborError cbor_value_dup_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700486{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700487 assert(buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700488 assert(buflen);
Thiago Macieira851c4812015-05-08 15:23:20 -0700489 CborError err = cbor_value_copy_string(value, NULL, buflen, NULL);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700490 if (err)
491 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700492
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700493 ++*buflen;
494 *buffer = malloc(*buflen);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700495 if (!*buffer) {
Thiago Macieirac70169f2015-05-06 07:49:44 -0700496 // out of memory
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700497 return CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700498 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700499 err = cbor_value_copy_string(value, *buffer, buflen, next);
500 if (err) {
Thiago Macieira2312efd2015-05-06 16:07:48 -0700501 free(*buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700502 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700503 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700504 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700505}
506
Thiago Macieira9ae05812015-05-11 15:09:09 +0900507// We return uintptr_t so that we can pass memcpy directly as the iteration
508// function. The choice is to optimize for memcpy, which is used in the base
509// parser API (cbor_value_copy_string), while memcmp is used in convenience API
510// only.
511typedef uintptr_t (*IterateFunction)(char *, const char *, size_t);
512
513static uintptr_t iterate_noop(char *dest, const char *src, size_t len)
514{
515 (void)dest;
516 (void)src;
517 (void)len;
518 return true;
519}
520
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700521static uintptr_t iterate_memcmp(char *s1, const char *s2, size_t len)
522{
523 return memcmp(s1, s2, len) == 0;
524}
525
Thiago Macieira9ae05812015-05-11 15:09:09 +0900526static CborError iterate_string_chunks(const CborValue *value, char *buffer, size_t *buflen,
527 bool *result, CborValue *next, IterateFunction func)
528{
529 assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value));
530
531 size_t total;
532 CborError err;
533 const char *ptr = value->ptr;
534 if (cbor_value_is_length_known(value)) {
535 // easy case: fixed length
536 err = extract_length(value->parser, &ptr, &total);
537 if (err)
538 return err;
539 if (ptr + total > value->parser->end)
540 return CborErrorUnexpectedEOF;
541 if (total <= *buflen)
542 *result = func(buffer, ptr, total);
543 else
544 *result = false;
545 ptr += total;
546 } else {
547 // chunked
548 ++ptr;
549 total = 0;
550 *result = true;
551 while (true) {
552 size_t chunkLen;
553 size_t newTotal;
554
555 if (ptr == value->parser->end)
556 return CborErrorUnexpectedEOF;
557
558 if (*ptr == (char)BreakByte) {
559 ++ptr;
560 break;
561 }
562
563 // is this the right type?
564 if ((*ptr & MajorTypeMask) != value->type)
565 return CborErrorIllegalType;
566
567 err = extract_length(value->parser, &ptr, &chunkLen);
568 if (err)
569 return err;
570
571 if (unlikely(!add_check_overflow(total, chunkLen, &newTotal)))
572 return CborErrorDataTooLarge;
573
574 if (ptr + chunkLen > value->parser->end)
575 return CborErrorUnexpectedEOF;
576
577 if (*result && *buflen >= newTotal)
578 *result = func(buffer + total, ptr, chunkLen);
579 else
580 *result = false;
581
582 ptr += chunkLen;
583 total = newTotal;
584 }
585 }
586
587 // is there enough room for the ending NUL byte?
588 if (*result && *buflen > total)
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700589 *result = func(buffer + total, "", 1);
Thiago Macieira9ae05812015-05-11 15:09:09 +0900590 *buflen = total;
591
592 if (next) {
593 *next = *value;
594 next->ptr = ptr;
595 return preparse_next_value(next);
596 }
597 return CborNoError;
598}
599
Thiago Macieira2312efd2015-05-06 16:07:48 -0700600/**
601 * Copies the string pointed by \a value into the buffer provided at \a buffer
602 * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
603 * copy anything and will only update the \a next value.
604 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700605 * If the provided buffer length was too small, this function returns an error
606 * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
607 * of the string in order to preallocate a buffer, use
Thiago Macieira2312efd2015-05-06 16:07:48 -0700608 * cbor_value_calculate_string_length().
609 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700610 * On success, this function sets the number of bytes copied to \c{*buflen}. If
611 * the buffer is large enough, this function will insert a null byte after the
612 * last copied byte, to facilitate manipulation of text strings. That byte is
613 * not included in the returned value of \c{*buflen}.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700614 *
615 * The \a next pointer, if not null, will be updated to point to the next item
616 * after this string. If \a value points to the last item, then \a next will be
617 * invalid.
618 *
619 * \note This function does not perform UTF-8 validation on the incoming text
620 * string.
621 *
622 * \sa cbor_value_dup_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
623 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700624CborError cbor_value_copy_string(const CborValue *value, char *buffer,
625 size_t *buflen, CborValue *next)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700626{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900627 bool copied_all;
628 CborError err = iterate_string_chunks(value, buffer, buflen, &copied_all, next,
629 buffer ? (IterateFunction)memcpy : iterate_noop);
630 return err ? err :
631 copied_all ? CborNoError : CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700632}
633
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700634/**
635 * Compares the entry \a value with the string \a string and store the result
636 * in \a result. If the value is different from \a string or if it is not a
637 * text string, \a result will contain \c false.
638 *
639 * The entry at \a value may be a tagged string. If \a is not a string or a
640 * tagged string, the comparison result will be false.
641 */
642CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result)
643{
644 CborValue copy = *value;
645 CborError err = cbor_value_skip_tag(&copy);
646 if (err)
647 return err;
648 if (!cbor_value_is_text_string(&copy)) {
649 *result = false;
650 return CborNoError;
651 }
652
653 size_t len = strlen(string);
654 return iterate_string_chunks(&copy, CONST_CAST(char *, string), &len, result, NULL, iterate_memcmp);
655}
656
657/**
Thiago Macieira7b623c22015-05-11 15:52:14 +0900658 * Attempts to find the value in map \a map that corresponds to the text string
659 * entry \a string. If the item is found, it is stored in \a result. If no item
660 * is found matching the key, then \a result will contain an element of type
661 * \ref CborInvalidType.
662 *
663 * \note This function may be expensive to execute.
664 */
665CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element)
666{
667 assert(cbor_value_is_map(map));
668 size_t len = strlen(string);
669 CborError err = cbor_value_enter_container(map, element);
670 if (err)
671 goto error;
672
673 while (!cbor_value_at_end(element)) {
674 // find the non-tag so we can compare
675 err = cbor_value_skip_tag(element);
676 if (err)
677 goto error;
678 if (cbor_value_is_text_string(element)) {
679 bool equals;
680 size_t dummyLen = len;
681 err = iterate_string_chunks(element, CONST_CAST(char *, string), &dummyLen,
682 &equals, element, iterate_memcmp);
683 if (err)
684 goto error;
685 if (equals)
686 return preparse_value(element);
687 } else {
688 // skip this key
689 err = cbor_value_advance(element);
690 if (err)
691 goto error;
692 }
693
694 // skip this value
695 err = cbor_value_skip_tag(element);
696 if (err)
697 goto error;
698 err = cbor_value_advance(element);
699 if (err)
700 goto error;
701 }
702
703 // not found
704 element->type = CborInvalidType;
705 return CborNoError;
706
707error:
708 element->type = CborInvalidType;
709 return err;
710}
711
712/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700713 * Extracts a half-precision floating point from \a value and stores it in \a
714 * result.
715 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700716CborError cbor_value_get_half_float(const CborValue *value, void *result)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700717{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700718 assert(value->type == CborHalfFloatType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700719
720 // size has been computed already
721 uint16_t v = get16(value->ptr + 1);
722 memcpy(result, &v, sizeof(v));
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700723 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700724}