blob: 0cf4099d3f3ae4cfc40bd2e826b21004c7164d31 [file] [log] [blame]
Thiago Macieira54a0e102015-05-05 21:25:06 -07001/****************************************************************************
2**
3** Copyright (C) 2015 Intel Corporation
4**
5** Permission is hereby granted, free of charge, to any person obtaining a copy
6** of this software and associated documentation files (the "Software"), to deal
7** in the Software without restriction, including without limitation the rights
8** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9** copies of the Software, and to permit persons to whom the Software is
10** furnished to do so, subject to the following conditions:
11**
12** The above copyright notice and this permission notice shall be included in
13** all copies or substantial portions of the Software.
14**
15** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21** THE SOFTWARE.
22**
23****************************************************************************/
24
Thiago Macieiraed5b57c2015-07-07 16:38:27 -070025#define _BSD_SOURCE 1
Thiago Macieira54a0e102015-05-05 21:25:06 -070026#include "cbor.h"
27#include "cborconstants_p.h"
28#include "compilersupport_p.h"
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 Macieira8f3fb782015-06-16 16:27:01 -070034#include "assert_p.h" /* Always include last */
35
Thiago Macieira4a99af92015-05-12 10:41:45 +090036#ifndef CBOR_PARSER_MAX_RECURSIONS
37# define CBOR_PARSER_MAX_RECURSIONS 1024
38#endif
39
Thiago Macieira54a0e102015-05-05 21:25:06 -070040/**
41 * \typedef CborValue
42 * This type contains one value parsed from the CBOR stream.
43 *
44 * To get the actual type, use cbor_value_get_type(). Then extract the value
45 * using one of the corresponding functions: cbor_value_get_boolean(), cbor_value_get_int64(),
46 * cbor_value_get_int(), cbor_value_copy_string(), cbor_value_get_array(), cbor_value_get_map(),
47 * cbor_value_get_double(), cbor_value_get_float().
48 *
49 * In C++ and C11 modes, you can additionally use the cbor_value_get_integer()
50 * and cbor_value_get_floating_point() generic functions.
51 *
52 * \omit
53 * Implementation details: the CborValue contains these fields:
54 * \list
55 * \li ptr: pointer to the actual data
56 * \li flags: flags from the decoder
Thiago Macieira2312efd2015-05-06 16:07:48 -070057 * \li extra: partially decoded integer value (0, 1 or 2 bytes)
Thiago Macieira54a0e102015-05-05 21:25:06 -070058 * \li remaining: remaining items in this collection after this item or UINT32_MAX if length is unknown
59 * \endlist
60 * \endomit
61 */
62
Thiago Macieira5752ce52015-06-16 12:10:03 -070063static inline uint16_t get16(const uint8_t *ptr)
Thiago Macieira54a0e102015-05-05 21:25:06 -070064{
65 uint16_t result;
66 memcpy(&result, ptr, sizeof(result));
Thiago Macieira5934a9f2015-06-16 11:55:28 -070067 return cbor_ntohs(result);
Thiago Macieira54a0e102015-05-05 21:25:06 -070068}
69
Thiago Macieira5752ce52015-06-16 12:10:03 -070070static inline uint32_t get32(const uint8_t *ptr)
Thiago Macieira54a0e102015-05-05 21:25:06 -070071{
72 uint32_t result;
73 memcpy(&result, ptr, sizeof(result));
Thiago Macieira5934a9f2015-06-16 11:55:28 -070074 return cbor_ntohl(result);
Thiago Macieira54a0e102015-05-05 21:25:06 -070075}
76
Thiago Macieira5752ce52015-06-16 12:10:03 -070077static inline uint64_t get64(const uint8_t *ptr)
Thiago Macieira54a0e102015-05-05 21:25:06 -070078{
79 uint64_t result;
80 memcpy(&result, ptr, sizeof(result));
Thiago Macieira5934a9f2015-06-16 11:55:28 -070081 return cbor_ntohll(result);
Thiago Macieira54a0e102015-05-05 21:25:06 -070082}
83
Thiago Macieiraf5cb94b2015-06-16 16:10:49 -070084static CborError extract_number(const CborParser *parser, const uint8_t **ptr, uint64_t *len)
Thiago Macieira2312efd2015-05-06 16:07:48 -070085{
86 uint8_t additional_information = **ptr & SmallValueMask;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070087 ++*ptr;
Thiago Macieira2312efd2015-05-06 16:07:48 -070088 if (additional_information < Value8Bit) {
89 *len = additional_information;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070090 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -070091 }
92 if (unlikely(additional_information > Value64Bit))
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070093 return CborErrorIllegalNumber;
Thiago Macieira2312efd2015-05-06 16:07:48 -070094
95 size_t bytesNeeded = 1 << (additional_information - Value8Bit);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070096 if (unlikely(*ptr + bytesNeeded > parser->end)) {
97 return CborErrorUnexpectedEOF;
Thiago Macieira2312efd2015-05-06 16:07:48 -070098 } else if (bytesNeeded == 1) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070099 *len = (uint8_t)(*ptr)[0];
Thiago Macieira2312efd2015-05-06 16:07:48 -0700100 } else if (bytesNeeded == 2) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700101 *len = get16(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700102 } else if (bytesNeeded == 4) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700103 *len = get32(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700104 } else {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700105 *len = get64(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700106 }
107 *ptr += bytesNeeded;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700108 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700109}
110
Thiago Macieiraf5cb94b2015-06-16 16:10:49 -0700111static CborError extract_length(const CborParser *parser, const uint8_t **ptr, size_t *len)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700112{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700113 uint64_t v;
114 CborError err = extract_number(parser, ptr, &v);
115 if (err)
116 return err;
117
118 *len = v;
119 if (v != *len)
120 return CborErrorDataTooLarge;
121 return CborNoError;
122}
123
124static bool is_fixed_type(uint8_t type)
125{
126 return type != CborTextStringType && type != CborByteStringType && type != CborArrayType &&
127 type != CborMapType;
128}
129
130static CborError preparse_value(CborValue *it)
131{
132 const CborParser *parser = it->parser;
Thiago Macieira11e913f2015-05-07 13:01:18 -0700133 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700134
Thiago Macieira54a0e102015-05-05 21:25:06 -0700135 // are we at the end?
Thiago Macieira54a0e102015-05-05 21:25:06 -0700136 if (it->ptr == parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700137 return CborErrorUnexpectedEOF;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700138
139 uint8_t descriptor = *it->ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700140 uint8_t type = descriptor & MajorTypeMask;
Thiago Macieira851c4812015-05-08 15:23:20 -0700141 it->type = type;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700142 it->flags = 0;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700143 it->extra = (descriptor &= SmallValueMask);
144
Thiago Macieira56d99832015-05-07 14:34:27 -0700145 if (descriptor > Value64Bit) {
146 if (unlikely(descriptor != IndefiniteLength))
Thiago Macieira3f76f632015-05-12 10:10:09 +0900147 return type == CborSimpleType ? CborErrorUnknownType : CborErrorIllegalNumber;
Thiago Macieira56d99832015-05-07 14:34:27 -0700148 if (likely(!is_fixed_type(type))) {
149 // special case
150 it->flags |= CborIteratorFlag_UnknownLength;
151 it->type = type;
152 return CborNoError;
153 }
154 return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700155 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700156
Thiago Macieirac70169f2015-05-06 07:49:44 -0700157 size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit));
158 if (it->ptr + 1 + bytesNeeded > parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700159 return CborErrorUnexpectedEOF;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700160
Thiago Macieira851c4812015-05-08 15:23:20 -0700161 uint8_t majortype = type >> MajorTypeShift;
162 if (majortype == NegativeIntegerType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700163 it->flags |= CborIteratorFlag_NegativeInteger;
Thiago Macieira851c4812015-05-08 15:23:20 -0700164 it->type = CborIntegerType;
165 } else if (majortype == SimpleTypesType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700166 switch (descriptor) {
167 case FalseValue:
168 it->extra = false;
Thiago Macieira851c4812015-05-08 15:23:20 -0700169 it->type = CborBooleanType;
Thiago Macieira991dd922015-05-07 11:57:59 -0700170 break;
171
Thiago Macieira851c4812015-05-08 15:23:20 -0700172 case SinglePrecisionFloat:
173 case DoublePrecisionFloat:
174 it->flags |= CborIteratorFlag_IntegerValueTooLarge;
175 // fall through
Thiago Macieira54a0e102015-05-05 21:25:06 -0700176 case TrueValue:
177 case NullValue:
178 case UndefinedValue:
179 case HalfPrecisionFloat:
Thiago Macieira851c4812015-05-08 15:23:20 -0700180 it->type = *it->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700181 break;
182
183 case SimpleTypeInNextByte:
Thiago Macieira851c4812015-05-08 15:23:20 -0700184 it->extra = (uint8_t)it->ptr[1];
Thiago Macieira54a0e102015-05-05 21:25:06 -0700185#ifndef CBOR_PARSER_NO_STRICT_CHECKS
Thiago Macieira851c4812015-05-08 15:23:20 -0700186 if (unlikely(it->extra < 32)) {
187 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700188 return CborErrorIllegalSimpleType;
Thiago Macieira851c4812015-05-08 15:23:20 -0700189 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700190#endif
Thiago Macieira991dd922015-05-07 11:57:59 -0700191 break;
192
Thiago Macieira54a0e102015-05-05 21:25:06 -0700193 case 28:
194 case 29:
195 case 30:
Thiago Macieira54a0e102015-05-05 21:25:06 -0700196 case Break:
Thiago Macieira851c4812015-05-08 15:23:20 -0700197 assert(false); // these conditions can't be reached
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700198 return CborErrorUnexpectedBreak;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700199 }
Thiago Macieira851c4812015-05-08 15:23:20 -0700200 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700201 }
202
203 // try to decode up to 16 bits
204 if (descriptor < Value8Bit)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700205 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700206
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700207 if (descriptor == Value8Bit)
208 it->extra = (uint8_t)it->ptr[1];
209 else if (descriptor == Value16Bit)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700210 it->extra = get16(it->ptr + 1);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700211 else
212 it->flags |= CborIteratorFlag_IntegerValueTooLarge; // Value32Bit or Value64Bit
213 return CborNoError;
214}
Thiago Macieira54a0e102015-05-05 21:25:06 -0700215
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700216static CborError preparse_next_value(CborValue *it)
217{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700218 if (it->remaining != UINT32_MAX) {
Thiago Macieira11e913f2015-05-07 13:01:18 -0700219 // don't decrement the item count if the current item is tag: they don't count
220 if (it->type != CborTagType && !--it->remaining) {
221 it->type = CborInvalidType;
Thiago Macieira56d99832015-05-07 14:34:27 -0700222 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700223 }
Thiago Macieira5752ce52015-06-16 12:10:03 -0700224 } else if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (uint8_t)BreakByte) {
Thiago Macieira56d99832015-05-07 14:34:27 -0700225 // end of map or array
226 ++it->ptr;
227 it->type = CborInvalidType;
228 it->remaining = 0;
229 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700230 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700231
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700232 return preparse_value(it);
233}
234
235static CborError advance_internal(CborValue *it)
236{
237 uint64_t length;
238 CborError err = extract_number(it->parser, &it->ptr, &length);
239 assert(err == CborNoError);
240
Thiago Macieira56d99832015-05-07 14:34:27 -0700241 if (it->type == CborByteStringType || it->type == CborTextStringType) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700242 assert(length == (size_t)length);
Thiago Macieira56d99832015-05-07 14:34:27 -0700243 assert((it->flags & CborIteratorFlag_UnknownLength) == 0);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700244 it->ptr += length;
245 }
246
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700247 return preparse_next_value(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700248}
249
Thiago Macieira2312efd2015-05-06 16:07:48 -0700250/** \internal
251 *
252 * Decodes the CBOR integer value when it is larger than the 16 bits available
253 * in value->extra. This function requires that value->flags have the
254 * CborIteratorFlag_IntegerValueTooLarge flag set.
255 *
256 * This function is also used to extract single- and double-precision floating
257 * point values (SinglePrecisionFloat == Value32Bit and DoublePrecisionFloat ==
258 * Value64Bit).
259 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700260uint64_t _cbor_value_decode_int64_internal(const CborValue *value)
261{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700262 assert(value->flags & CborIteratorFlag_IntegerValueTooLarge ||
263 value->type == CborFloatType || value->type == CborDoubleType);
Thiago Macieira851c4812015-05-08 15:23:20 -0700264
265 // since the additional information can only be Value32Bit or Value64Bit,
266 // we just need to test for the one bit those two options differ
267 assert((*value->ptr & SmallValueMask) == Value32Bit || (*value->ptr & SmallValueMask) == Value64Bit);
268 if ((*value->ptr & 1) == (Value32Bit & 1))
Thiago Macieira54a0e102015-05-05 21:25:06 -0700269 return get32(value->ptr + 1);
270
271 assert((*value->ptr & SmallValueMask) == Value64Bit);
272 return get64(value->ptr + 1);
273}
274
275/**
276 * Initializes the CBOR parser for parsing \a size bytes beginning at \a
277 * buffer. Parsing will use flags set in \a flags. The iterator to the first
278 * element is returned in \a it.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700279 *
280 * The \a parser structure needs to remain valid throughout the decoding
281 * process. It is not thread-safe to share one CborParser among multiple
282 * threads iterating at the same time, but the object can be copied so multiple
283 * threads can iterate.
284 *
285 * ### Write how to determine the end pointer
286 * ### Write how to do limited-buffer windowed decoding
Thiago Macieira54a0e102015-05-05 21:25:06 -0700287 */
Thiago Macieira5752ce52015-06-16 12:10:03 -0700288CborError cbor_parser_init(const uint8_t *buffer, size_t size, int flags, CborParser *parser, CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700289{
290 memset(parser, 0, sizeof(*parser));
291 parser->end = buffer + size;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700292 parser->flags = flags;
293 it->parser = parser;
294 it->ptr = buffer;
295 it->remaining = 1; // there's one type altogether, usually an array or map
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700296 return preparse_value(it);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700297}
298
299/**
300 * Advances the CBOR value \a it by one fixed-size position. Fixed-size types
301 * are: integers, tags, simple types (including boolean, null and undefined
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700302 * values) and floating point types.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700303 *
304 * \sa cbor_value_at_end(), cbor_value_advance(), cbor_value_begin_recurse(), cbor_value_end_recurse()
305 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700306CborError cbor_value_advance_fixed(CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700307{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700308 assert(it->type != CborInvalidType);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700309 assert(is_fixed_type(it->type));
310 if (!it->remaining)
311 return CborErrorAdvancePastEOF;
312 return advance_internal(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700313}
314
Thiago Macieira4a99af92015-05-12 10:41:45 +0900315static CborError advance_recursive(CborValue *it, int nestingLevel)
316{
317 if (is_fixed_type(it->type))
318 return advance_internal(it);
319
320 if (!cbor_value_is_container(it)) {
321 size_t len = SIZE_MAX;
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700322 return _cbor_value_copy_string(it, NULL, &len, it);
Thiago Macieira4a99af92015-05-12 10:41:45 +0900323 }
324
325 // map or array
326 if (nestingLevel == CBOR_PARSER_MAX_RECURSIONS)
327 return CborErrorNestingTooDeep;
328
329 CborError err;
330 CborValue recursed;
331 err = cbor_value_enter_container(it, &recursed);
332 if (err)
333 return err;
334 while (!cbor_value_at_end(&recursed)) {
335 err = advance_recursive(&recursed, nestingLevel + 1);
336 if (err)
337 return err;
338 }
339 return cbor_value_leave_container(it, &recursed);
340}
341
342
Thiago Macieira2312efd2015-05-06 16:07:48 -0700343/**
344 * Advances the CBOR value \a it by one element, skipping over containers.
345 * Unlike cbor_value_advance_fixed(), this function can be called on a CBOR
346 * value of any type. However, if the type is a container (map or array) or a
347 * string with a chunked payload, this function will not run in constant time
348 * and will recurse into itself (it will run on O(n) time for the number of
349 * elements or chunks and will use O(n) memory for the number of nested
350 * containers).
351 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700352 * \sa cbor_value_at_end(), cbor_value_advance_fixed(), cbor_value_begin_recurse(), cbor_value_end_recurse()
353 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700354CborError cbor_value_advance(CborValue *it)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700355{
356 assert(it->type != CborInvalidType);
357 if (!it->remaining)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700358 return CborErrorAdvancePastEOF;
Thiago Macieira4a99af92015-05-12 10:41:45 +0900359 return advance_recursive(it, 0);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700360}
361
362/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700363 * Advances the CBOR value \a it until it no longer points to a tag. If \a it is
364 * already not pointing to a tag, then this function returns it unchanged.
365 *
366 * \sa cbor_value_advance_fixed(), cbor_value_advance()
367 */
368CborError cbor_value_skip_tag(CborValue *it)
369{
370 while (cbor_value_is_tag(it)) {
371 CborError err = cbor_value_advance_fixed(it);
372 if (err)
373 return err;
374 }
375 return CborNoError;
376}
377
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700378/**
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700379 * \fn bool cbor_value_is_container(const CborValue *it)
380 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700381 * Returns true if the \a it value is a container and requires recursion in
382 * order to decode (maps and arrays), false otherwise.
383 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700384
Thiago Macieira2312efd2015-05-06 16:07:48 -0700385/**
386 * Creates a CborValue iterator pointing to the first element of the container
387 * represented by \a it and saves it in \a recursed. The \a it container object
388 * needs to be kept and passed again to cbor_value_leave_container() in order
389 * to continue iterating past this container.
390 *
391 * \sa cbor_value_is_container(), cbor_value_leave_container(), cbor_value_advance()
392 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700393CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700394{
Thiago Macieira56d99832015-05-07 14:34:27 -0700395 CborError err;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700396 assert(cbor_value_is_container(it));
Thiago Macieira54a0e102015-05-05 21:25:06 -0700397 *recursed = *it;
Thiago Macieira56d99832015-05-07 14:34:27 -0700398
Thiago Macieira54a0e102015-05-05 21:25:06 -0700399 if (it->flags & CborIteratorFlag_UnknownLength) {
400 recursed->remaining = UINT32_MAX;
Thiago Macieira56d99832015-05-07 14:34:27 -0700401 ++recursed->ptr;
402 err = preparse_value(recursed);
403 if (err != CborErrorUnexpectedBreak)
404 return err;
405 // actually, break was expected here
406 // it's just an empty container
407 ++recursed->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700408 } else {
Thiago Macieira56d99832015-05-07 14:34:27 -0700409 uint64_t len;
410 err = extract_number(recursed->parser, &recursed->ptr, &len);
411 assert(err == CborNoError);
Thiago Macieira56d99832015-05-07 14:34:27 -0700412
Thiago Macieira54a0e102015-05-05 21:25:06 -0700413 recursed->remaining = len;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900414 if (recursed->remaining != len || len == UINT32_MAX) {
415 // back track the pointer to indicate where the error occurred
416 recursed->ptr = it->ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700417 return CborErrorDataTooLarge;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900418 }
Thiago Macieirace16f052015-05-07 23:14:25 -0700419 if (recursed->type == CborMapType) {
420 // maps have keys and values, so we need to multiply by 2
Thiago Macieira3f76f632015-05-12 10:10:09 +0900421 if (recursed->remaining > UINT32_MAX / 2) {
422 // back track the pointer to indicate where the error occurred
423 recursed->ptr = it->ptr;
Thiago Macieirace16f052015-05-07 23:14:25 -0700424 return CborErrorDataTooLarge;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900425 }
Thiago Macieirace16f052015-05-07 23:14:25 -0700426 recursed->remaining *= 2;
427 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700428 if (len != 0)
429 return preparse_value(recursed);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700430 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700431
432 // the case of the empty container
433 recursed->type = CborInvalidType;
434 recursed->remaining = 0;
435 return CborNoError;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700436}
437
Thiago Macieira2312efd2015-05-06 16:07:48 -0700438/**
439 * Updates \a it to point to the next element after the container. The \a
Thiago Macieira56d99832015-05-07 14:34:27 -0700440 * recursed object needs to point to the element obtained either by advancing
441 * the last element of the container (via cbor_value_advance(),
442 * cbor_value_advance_fixed(), a nested cbor_value_leave_container(), or the \c
443 * next pointer from cbor_value_copy_string() or cbor_value_dup_string()).
Thiago Macieira2312efd2015-05-06 16:07:48 -0700444 *
445 * \sa cbor_value_enter_container(), cbor_value_at_end()
446 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700447CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700448{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700449 assert(cbor_value_is_container(it));
Thiago Macieira56d99832015-05-07 14:34:27 -0700450 assert(recursed->type == CborInvalidType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700451 it->ptr = recursed->ptr;
Thiago Macieira56d99832015-05-07 14:34:27 -0700452 return preparse_next_value(it);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700453}
454
Thiago Macieira2312efd2015-05-06 16:07:48 -0700455/**
456 * Calculates the length of the string in \a value and stores the result in \a
457 * len. This function is different from cbor_value_get_string_length() in that
458 * it calculates the length even for strings sent in chunks. For that reason,
459 * this function may not run in constant time (it will run in O(n) time on the
460 * number of chunks).
461 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700462 * \note On 32-bit platforms, this function will return error condition of \ref
463 * CborErrorDataTooLarge if the stream indicates a length that is too big to
464 * fit in 32-bit.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700465 *
466 * \sa cbor_value_get_string_length(), cbor_value_copy_string(), cbor_value_is_length_known()
467 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700468CborError cbor_value_calculate_string_length(const CborValue *value, size_t *len)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700469{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900470 *len = SIZE_MAX;
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700471 return _cbor_value_copy_string(value, NULL, len, NULL);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700472}
473
Thiago Macieira2312efd2015-05-06 16:07:48 -0700474/**
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700475 * \fn CborError cbor_value_dup_text_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next)
476 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700477 * Allocates memory for the string pointed by \a value and copies it into this
478 * buffer. The pointer to the buffer is stored in \a buffer and the number of
479 * bytes copied is stored in \a len (those variables must not be NULL).
480 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700481 * If \c malloc returns a NULL pointer, this function will return error
482 * condition \ref CborErrorOutOfMemory.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700483 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700484 * On success, \c{*buffer} will contain a valid pointer that must be freed by
485 * calling \c{free()}. This is the case even for zero-length strings.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700486 *
487 * The \a next pointer, if not null, will be updated to point to the next item
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700488 * after this string. If \a value points to the last item, then \a next will be
489 * invalid.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700490 *
491 * \note This function does not perform UTF-8 validation on the incoming text
492 * string.
493 *
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700494 * \sa cbor_value_copy_text_string(), cbor_value_dup_byte_string()
Thiago Macieira2312efd2015-05-06 16:07:48 -0700495 */
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700496
497/**
498 * \fn CborError cbor_value_dup_byte_string(const CborValue *value, uint8_t **buffer, size_t *buflen, CborValue *next)
499 *
500 * Allocates memory for the string pointed by \a value and copies it into this
501 * buffer. The pointer to the buffer is stored in \a buffer and the number of
502 * bytes copied is stored in \a len (those variables must not be NULL).
503 *
504 * If \c malloc returns a NULL pointer, this function will return error
505 * condition \ref CborErrorOutOfMemory.
506 *
507 * On success, \c{*buffer} will contain a valid pointer that must be freed by
508 * calling \c{free()}. This is the case even for zero-length strings.
509 *
510 * The \a next pointer, if not null, will be updated to point to the next item
511 * after this string. If \a value points to the last item, then \a next will be
512 * invalid.
513 *
514 * \sa cbor_value_copy_byte_string(), cbor_value_dup_text_string()
515 */
516CborError _cbor_value_dup_string(const CborValue *value, void **buffer, size_t *buflen, CborValue *next)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700517{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700518 assert(buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700519 assert(buflen);
Thiago Macieirafc870932015-06-19 15:01:35 -0700520 *buflen = SIZE_MAX;
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700521 CborError err = _cbor_value_copy_string(value, NULL, buflen, NULL);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700522 if (err)
523 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700524
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700525 ++*buflen;
526 *buffer = malloc(*buflen);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700527 if (!*buffer) {
Thiago Macieirac70169f2015-05-06 07:49:44 -0700528 // out of memory
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700529 return CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700530 }
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700531 err = _cbor_value_copy_string(value, *buffer, buflen, next);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700532 if (err) {
Thiago Macieira2312efd2015-05-06 16:07:48 -0700533 free(*buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700534 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700535 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700536 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700537}
538
Thiago Macieira9ae05812015-05-11 15:09:09 +0900539// We return uintptr_t so that we can pass memcpy directly as the iteration
540// function. The choice is to optimize for memcpy, which is used in the base
541// parser API (cbor_value_copy_string), while memcmp is used in convenience API
542// only.
Thiago Macieira5752ce52015-06-16 12:10:03 -0700543typedef uintptr_t (*IterateFunction)(char *, const uint8_t *, size_t);
Thiago Macieira9ae05812015-05-11 15:09:09 +0900544
Thiago Macieira5752ce52015-06-16 12:10:03 -0700545static uintptr_t iterate_noop(char *dest, const uint8_t *src, size_t len)
Thiago Macieira9ae05812015-05-11 15:09:09 +0900546{
547 (void)dest;
548 (void)src;
549 (void)len;
550 return true;
551}
552
Thiago Macieira5752ce52015-06-16 12:10:03 -0700553static uintptr_t iterate_memcmp(char *s1, const uint8_t *s2, size_t len)
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700554{
Thiago Macieira5752ce52015-06-16 12:10:03 -0700555 return memcmp(s1, (const char *)s2, len) == 0;
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700556}
557
Thiago Macieira9ae05812015-05-11 15:09:09 +0900558static CborError iterate_string_chunks(const CborValue *value, char *buffer, size_t *buflen,
559 bool *result, CborValue *next, IterateFunction func)
560{
561 assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value));
562
563 size_t total;
564 CborError err;
Thiago Macieira5752ce52015-06-16 12:10:03 -0700565 const uint8_t *ptr = value->ptr;
Thiago Macieira9ae05812015-05-11 15:09:09 +0900566 if (cbor_value_is_length_known(value)) {
567 // easy case: fixed length
568 err = extract_length(value->parser, &ptr, &total);
569 if (err)
570 return err;
571 if (ptr + total > value->parser->end)
572 return CborErrorUnexpectedEOF;
573 if (total <= *buflen)
574 *result = func(buffer, ptr, total);
575 else
576 *result = false;
577 ptr += total;
578 } else {
579 // chunked
580 ++ptr;
581 total = 0;
582 *result = true;
583 while (true) {
584 size_t chunkLen;
585 size_t newTotal;
586
587 if (ptr == value->parser->end)
588 return CborErrorUnexpectedEOF;
589
Thiago Macieira5752ce52015-06-16 12:10:03 -0700590 if (*ptr == (uint8_t)BreakByte) {
Thiago Macieira9ae05812015-05-11 15:09:09 +0900591 ++ptr;
592 break;
593 }
594
595 // is this the right type?
596 if ((*ptr & MajorTypeMask) != value->type)
597 return CborErrorIllegalType;
598
599 err = extract_length(value->parser, &ptr, &chunkLen);
600 if (err)
601 return err;
602
Thiago Macieira1de31a42015-06-16 16:01:16 -0700603 if (unlikely(add_check_overflow(total, chunkLen, &newTotal)))
Thiago Macieira9ae05812015-05-11 15:09:09 +0900604 return CborErrorDataTooLarge;
605
606 if (ptr + chunkLen > value->parser->end)
607 return CborErrorUnexpectedEOF;
608
609 if (*result && *buflen >= newTotal)
610 *result = func(buffer + total, ptr, chunkLen);
611 else
612 *result = false;
613
614 ptr += chunkLen;
615 total = newTotal;
616 }
617 }
618
619 // is there enough room for the ending NUL byte?
620 if (*result && *buflen > total)
Thiago Macieira5752ce52015-06-16 12:10:03 -0700621 *result = func(buffer + total, (const uint8_t *)"", 1);
Thiago Macieira9ae05812015-05-11 15:09:09 +0900622 *buflen = total;
623
624 if (next) {
625 *next = *value;
626 next->ptr = ptr;
627 return preparse_next_value(next);
628 }
629 return CborNoError;
630}
631
Thiago Macieira2312efd2015-05-06 16:07:48 -0700632/**
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700633 * \fn CborError cbor_value_copy_text_string(const CborValue *value, char *buffer, size_t *buflen, CborValue *next)
634 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700635 * Copies the string pointed by \a value into the buffer provided at \a buffer
636 * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
637 * copy anything and will only update the \a next value.
638 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700639 * If the provided buffer length was too small, this function returns an error
640 * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
641 * of the string in order to preallocate a buffer, use
Thiago Macieira2312efd2015-05-06 16:07:48 -0700642 * cbor_value_calculate_string_length().
643 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700644 * On success, this function sets the number of bytes copied to \c{*buflen}. If
645 * the buffer is large enough, this function will insert a null byte after the
646 * last copied byte, to facilitate manipulation of text strings. That byte is
647 * not included in the returned value of \c{*buflen}.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700648 *
649 * The \a next pointer, if not null, will be updated to point to the next item
650 * after this string. If \a value points to the last item, then \a next will be
651 * invalid.
652 *
653 * \note This function does not perform UTF-8 validation on the incoming text
654 * string.
655 *
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700656 * \sa cbor_value_dup_text_string(), cbor_value_copy_byte_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
Thiago Macieira2312efd2015-05-06 16:07:48 -0700657 */
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700658
659/**
660 * \fn CborError cbor_value_copy_byte_string(const CborValue *value, uint8_t *buffer, size_t *buflen, CborValue *next)
661 *
662 * Copies the string pointed by \a value into the buffer provided at \a buffer
663 * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
664 * copy anything and will only update the \a next value.
665 *
666 * If the provided buffer length was too small, this function returns an error
667 * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
668 * of the string in order to preallocate a buffer, use
669 * cbor_value_calculate_string_length().
670 *
671 * On success, this function sets the number of bytes copied to \c{*buflen}. If
672 * the buffer is large enough, this function will insert a null byte after the
673 * last copied byte, to facilitate manipulation of null-terminated strings.
674 * That byte is not included in the returned value of \c{*buflen}.
675 *
676 * The \a next pointer, if not null, will be updated to point to the next item
677 * after this string. If \a value points to the last item, then \a next will be
678 * invalid.
679 *
680 * \sa cbor_value_dup_text_string(), cbor_value_copy_text_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
681 */
682
683CborError _cbor_value_copy_string(const CborValue *value, void *buffer,
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700684 size_t *buflen, CborValue *next)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700685{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900686 bool copied_all;
Thiago Macieiraed5b57c2015-07-07 16:38:27 -0700687 CborError err = iterate_string_chunks(value, (char*)buffer, buflen, &copied_all, next,
Thiago Macieira9ae05812015-05-11 15:09:09 +0900688 buffer ? (IterateFunction)memcpy : iterate_noop);
689 return err ? err :
690 copied_all ? CborNoError : CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700691}
692
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700693/**
694 * Compares the entry \a value with the string \a string and store the result
695 * in \a result. If the value is different from \a string or if it is not a
696 * text string, \a result will contain \c false.
697 *
698 * The entry at \a value may be a tagged string. If \a is not a string or a
699 * tagged string, the comparison result will be false.
700 */
701CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result)
702{
703 CborValue copy = *value;
704 CborError err = cbor_value_skip_tag(&copy);
705 if (err)
706 return err;
707 if (!cbor_value_is_text_string(&copy)) {
708 *result = false;
709 return CborNoError;
710 }
711
712 size_t len = strlen(string);
713 return iterate_string_chunks(&copy, CONST_CAST(char *, string), &len, result, NULL, iterate_memcmp);
714}
715
716/**
Thiago Macieira7b623c22015-05-11 15:52:14 +0900717 * Attempts to find the value in map \a map that corresponds to the text string
718 * entry \a string. If the item is found, it is stored in \a result. If no item
719 * is found matching the key, then \a result will contain an element of type
720 * \ref CborInvalidType.
721 *
722 * \note This function may be expensive to execute.
723 */
724CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element)
725{
726 assert(cbor_value_is_map(map));
727 size_t len = strlen(string);
728 CborError err = cbor_value_enter_container(map, element);
729 if (err)
730 goto error;
731
732 while (!cbor_value_at_end(element)) {
733 // find the non-tag so we can compare
734 err = cbor_value_skip_tag(element);
735 if (err)
736 goto error;
737 if (cbor_value_is_text_string(element)) {
738 bool equals;
739 size_t dummyLen = len;
740 err = iterate_string_chunks(element, CONST_CAST(char *, string), &dummyLen,
741 &equals, element, iterate_memcmp);
742 if (err)
743 goto error;
744 if (equals)
745 return preparse_value(element);
746 } else {
747 // skip this key
748 err = cbor_value_advance(element);
749 if (err)
750 goto error;
751 }
752
753 // skip this value
754 err = cbor_value_skip_tag(element);
755 if (err)
756 goto error;
757 err = cbor_value_advance(element);
758 if (err)
759 goto error;
760 }
761
762 // not found
763 element->type = CborInvalidType;
764 return CborNoError;
765
766error:
767 element->type = CborInvalidType;
768 return err;
769}
770
771/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700772 * Extracts a half-precision floating point from \a value and stores it in \a
773 * result.
774 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700775CborError cbor_value_get_half_float(const CborValue *value, void *result)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700776{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700777 assert(value->type == CborHalfFloatType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700778
779 // size has been computed already
780 uint16_t v = get16(value->ptr + 1);
781 memcpy(result, &v, sizeof(v));
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700782 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700783}