blob: 03bb55422e1a9879c7310101fee3463d9fbb58a3 [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
35/**
36 * \typedef CborValue
37 * This type contains one value parsed from the CBOR stream.
38 *
39 * To get the actual type, use cbor_value_get_type(). Then extract the value
40 * using one of the corresponding functions: cbor_value_get_boolean(), cbor_value_get_int64(),
41 * cbor_value_get_int(), cbor_value_copy_string(), cbor_value_get_array(), cbor_value_get_map(),
42 * cbor_value_get_double(), cbor_value_get_float().
43 *
44 * In C++ and C11 modes, you can additionally use the cbor_value_get_integer()
45 * and cbor_value_get_floating_point() generic functions.
46 *
47 * \omit
48 * Implementation details: the CborValue contains these fields:
49 * \list
50 * \li ptr: pointer to the actual data
51 * \li flags: flags from the decoder
Thiago Macieira2312efd2015-05-06 16:07:48 -070052 * \li extra: partially decoded integer value (0, 1 or 2 bytes)
Thiago Macieira54a0e102015-05-05 21:25:06 -070053 * \li remaining: remaining items in this collection after this item or UINT32_MAX if length is unknown
54 * \endlist
55 * \endomit
56 */
57
Thiago Macieira54a0e102015-05-05 21:25:06 -070058static inline uint16_t get16(const char *ptr)
59{
60 uint16_t result;
61 memcpy(&result, ptr, sizeof(result));
62 return be16toh(result);
63}
64
65static inline uint32_t get32(const char *ptr)
66{
67 uint32_t result;
68 memcpy(&result, ptr, sizeof(result));
69 return be32toh(result);
70}
71
72static inline uint64_t get64(const char *ptr)
73{
74 uint64_t result;
75 memcpy(&result, ptr, sizeof(result));
76 return be64toh(result);
77}
78
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070079static inline CborError extract_number(const CborParser *parser, const char **ptr, uint64_t *len)
Thiago Macieira2312efd2015-05-06 16:07:48 -070080{
81 uint8_t additional_information = **ptr & SmallValueMask;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070082 ++*ptr;
Thiago Macieira2312efd2015-05-06 16:07:48 -070083 if (additional_information < Value8Bit) {
84 *len = additional_information;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070085 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -070086 }
87 if (unlikely(additional_information > Value64Bit))
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070088 return CborErrorIllegalNumber;
Thiago Macieira2312efd2015-05-06 16:07:48 -070089
90 size_t bytesNeeded = 1 << (additional_information - Value8Bit);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070091 if (unlikely(*ptr + bytesNeeded > parser->end)) {
92 return CborErrorUnexpectedEOF;
Thiago Macieira2312efd2015-05-06 16:07:48 -070093 } else if (bytesNeeded == 1) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070094 *len = (uint8_t)(*ptr)[0];
Thiago Macieira2312efd2015-05-06 16:07:48 -070095 } else if (bytesNeeded == 2) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070096 *len = get16(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -070097 } else if (bytesNeeded == 4) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070098 *len = get32(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -070099 } else {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700100 *len = get64(*ptr);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700101 }
102 *ptr += bytesNeeded;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700103 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700104}
105
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700106static inline CborError extract_length(const CborParser *parser, const char **ptr, size_t *len)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700107{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700108 uint64_t v;
109 CborError err = extract_number(parser, ptr, &v);
110 if (err)
111 return err;
112
113 *len = v;
114 if (v != *len)
115 return CborErrorDataTooLarge;
116 return CborNoError;
117}
118
119static bool is_fixed_type(uint8_t type)
120{
121 return type != CborTextStringType && type != CborByteStringType && type != CborArrayType &&
122 type != CborMapType;
123}
124
125static CborError preparse_value(CborValue *it)
126{
127 const CborParser *parser = it->parser;
Thiago Macieira11e913f2015-05-07 13:01:18 -0700128 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700129
Thiago Macieira54a0e102015-05-05 21:25:06 -0700130 // are we at the end?
Thiago Macieira54a0e102015-05-05 21:25:06 -0700131 if (it->ptr == parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700132 return CborErrorUnexpectedEOF;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700133
134 uint8_t descriptor = *it->ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700135 uint8_t type = descriptor & MajorTypeMask;
Thiago Macieira851c4812015-05-08 15:23:20 -0700136 it->type = type;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700137 it->flags = 0;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700138 it->extra = (descriptor &= SmallValueMask);
139
Thiago Macieira56d99832015-05-07 14:34:27 -0700140 if (descriptor > Value64Bit) {
141 if (unlikely(descriptor != IndefiniteLength))
Thiago Macieira3f76f632015-05-12 10:10:09 +0900142 return type == CborSimpleType ? CborErrorUnknownType : CborErrorIllegalNumber;
Thiago Macieira56d99832015-05-07 14:34:27 -0700143 if (likely(!is_fixed_type(type))) {
144 // special case
145 it->flags |= CborIteratorFlag_UnknownLength;
146 it->type = type;
147 return CborNoError;
148 }
149 return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700150 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700151
Thiago Macieirac70169f2015-05-06 07:49:44 -0700152 size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit));
153 if (it->ptr + 1 + bytesNeeded > parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700154 return CborErrorUnexpectedEOF;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700155
Thiago Macieira851c4812015-05-08 15:23:20 -0700156 uint8_t majortype = type >> MajorTypeShift;
157 if (majortype == NegativeIntegerType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700158 it->flags |= CborIteratorFlag_NegativeInteger;
Thiago Macieira851c4812015-05-08 15:23:20 -0700159 it->type = CborIntegerType;
160 } else if (majortype == SimpleTypesType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700161 switch (descriptor) {
162 case FalseValue:
163 it->extra = false;
Thiago Macieira851c4812015-05-08 15:23:20 -0700164 it->type = CborBooleanType;
Thiago Macieira991dd922015-05-07 11:57:59 -0700165 break;
166
Thiago Macieira851c4812015-05-08 15:23:20 -0700167 case SinglePrecisionFloat:
168 case DoublePrecisionFloat:
169 it->flags |= CborIteratorFlag_IntegerValueTooLarge;
170 // fall through
Thiago Macieira54a0e102015-05-05 21:25:06 -0700171 case TrueValue:
172 case NullValue:
173 case UndefinedValue:
174 case HalfPrecisionFloat:
Thiago Macieira851c4812015-05-08 15:23:20 -0700175 it->type = *it->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700176 break;
177
178 case SimpleTypeInNextByte:
Thiago Macieira851c4812015-05-08 15:23:20 -0700179 it->extra = (uint8_t)it->ptr[1];
Thiago Macieira54a0e102015-05-05 21:25:06 -0700180#ifndef CBOR_PARSER_NO_STRICT_CHECKS
Thiago Macieira851c4812015-05-08 15:23:20 -0700181 if (unlikely(it->extra < 32)) {
182 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700183 return CborErrorIllegalSimpleType;
Thiago Macieira851c4812015-05-08 15:23:20 -0700184 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700185#endif
Thiago Macieira991dd922015-05-07 11:57:59 -0700186 break;
187
Thiago Macieira54a0e102015-05-05 21:25:06 -0700188 case 28:
189 case 29:
190 case 30:
Thiago Macieira54a0e102015-05-05 21:25:06 -0700191 case Break:
Thiago Macieira851c4812015-05-08 15:23:20 -0700192 assert(false); // these conditions can't be reached
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700193 return CborErrorUnexpectedBreak;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700194 }
Thiago Macieira851c4812015-05-08 15:23:20 -0700195 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700196 }
197
198 // try to decode up to 16 bits
199 if (descriptor < Value8Bit)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700200 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700201
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700202 if (descriptor == Value8Bit)
203 it->extra = (uint8_t)it->ptr[1];
204 else if (descriptor == Value16Bit)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700205 it->extra = get16(it->ptr + 1);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700206 else
207 it->flags |= CborIteratorFlag_IntegerValueTooLarge; // Value32Bit or Value64Bit
208 return CborNoError;
209}
Thiago Macieira54a0e102015-05-05 21:25:06 -0700210
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700211static CborError preparse_next_value(CborValue *it)
212{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700213 if (it->remaining != UINT32_MAX) {
Thiago Macieira11e913f2015-05-07 13:01:18 -0700214 // don't decrement the item count if the current item is tag: they don't count
215 if (it->type != CborTagType && !--it->remaining) {
216 it->type = CborInvalidType;
Thiago Macieira56d99832015-05-07 14:34:27 -0700217 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700218 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700219 } else if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (char)BreakByte) {
220 // end of map or array
221 ++it->ptr;
222 it->type = CborInvalidType;
223 it->remaining = 0;
224 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700225 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700226
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700227 return preparse_value(it);
228}
229
230static CborError advance_internal(CborValue *it)
231{
232 uint64_t length;
233 CborError err = extract_number(it->parser, &it->ptr, &length);
234 assert(err == CborNoError);
235
Thiago Macieira56d99832015-05-07 14:34:27 -0700236 if (it->type == CborByteStringType || it->type == CborTextStringType) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700237 assert(length == (size_t)length);
Thiago Macieira56d99832015-05-07 14:34:27 -0700238 assert((it->flags & CborIteratorFlag_UnknownLength) == 0);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700239 it->ptr += length;
240 }
241
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700242 return preparse_next_value(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700243}
244
Thiago Macieira2312efd2015-05-06 16:07:48 -0700245/** \internal
246 *
247 * Decodes the CBOR integer value when it is larger than the 16 bits available
248 * in value->extra. This function requires that value->flags have the
249 * CborIteratorFlag_IntegerValueTooLarge flag set.
250 *
251 * This function is also used to extract single- and double-precision floating
252 * point values (SinglePrecisionFloat == Value32Bit and DoublePrecisionFloat ==
253 * Value64Bit).
254 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700255uint64_t _cbor_value_decode_int64_internal(const CborValue *value)
256{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700257 assert(value->flags & CborIteratorFlag_IntegerValueTooLarge ||
258 value->type == CborFloatType || value->type == CborDoubleType);
Thiago Macieira851c4812015-05-08 15:23:20 -0700259
260 // since the additional information can only be Value32Bit or Value64Bit,
261 // we just need to test for the one bit those two options differ
262 assert((*value->ptr & SmallValueMask) == Value32Bit || (*value->ptr & SmallValueMask) == Value64Bit);
263 if ((*value->ptr & 1) == (Value32Bit & 1))
Thiago Macieira54a0e102015-05-05 21:25:06 -0700264 return get32(value->ptr + 1);
265
266 assert((*value->ptr & SmallValueMask) == Value64Bit);
267 return get64(value->ptr + 1);
268}
269
270/**
271 * Initializes the CBOR parser for parsing \a size bytes beginning at \a
272 * buffer. Parsing will use flags set in \a flags. The iterator to the first
273 * element is returned in \a it.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700274 *
275 * The \a parser structure needs to remain valid throughout the decoding
276 * process. It is not thread-safe to share one CborParser among multiple
277 * threads iterating at the same time, but the object can be copied so multiple
278 * threads can iterate.
279 *
280 * ### Write how to determine the end pointer
281 * ### Write how to do limited-buffer windowed decoding
Thiago Macieira54a0e102015-05-05 21:25:06 -0700282 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700283CborError cbor_parser_init(const char *buffer, size_t size, int flags, CborParser *parser, CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700284{
285 memset(parser, 0, sizeof(*parser));
286 parser->end = buffer + size;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700287 parser->flags = flags;
288 it->parser = parser;
289 it->ptr = buffer;
290 it->remaining = 1; // there's one type altogether, usually an array or map
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700291 return preparse_value(it);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700292}
293
294/**
295 * Advances the CBOR value \a it by one fixed-size position. Fixed-size types
296 * are: integers, tags, simple types (including boolean, null and undefined
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700297 * values) and floating point types.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700298 *
299 * \sa cbor_value_at_end(), cbor_value_advance(), cbor_value_begin_recurse(), cbor_value_end_recurse()
300 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700301CborError cbor_value_advance_fixed(CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700302{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700303 assert(it->type != CborInvalidType);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700304 assert(is_fixed_type(it->type));
305 if (!it->remaining)
306 return CborErrorAdvancePastEOF;
307 return advance_internal(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700308}
309
Thiago Macieira2312efd2015-05-06 16:07:48 -0700310/**
311 * Advances the CBOR value \a it by one element, skipping over containers.
312 * Unlike cbor_value_advance_fixed(), this function can be called on a CBOR
313 * value of any type. However, if the type is a container (map or array) or a
314 * string with a chunked payload, this function will not run in constant time
315 * and will recurse into itself (it will run on O(n) time for the number of
316 * elements or chunks and will use O(n) memory for the number of nested
317 * containers).
318 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700319 * \sa cbor_value_at_end(), cbor_value_advance_fixed(), cbor_value_begin_recurse(), cbor_value_end_recurse()
320 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700321CborError cbor_value_advance(CborValue *it)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700322{
323 assert(it->type != CborInvalidType);
324 if (!it->remaining)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700325 return CborErrorAdvancePastEOF;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700326 if (is_fixed_type(it->type))
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700327 return advance_internal(it);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700328
Thiago Macieira9ae05812015-05-11 15:09:09 +0900329 if (!cbor_value_is_container(it)) {
330 size_t len = SIZE_MAX;
331 return cbor_value_copy_string(it, NULL, &len, it);
332 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700333
334 // map or array
335 CborError err;
336 CborValue recursed;
337 err = cbor_value_enter_container(it, &recursed);
338 if (err)
339 return err;
340 while (!cbor_value_at_end(&recursed)) {
341 err = cbor_value_advance(&recursed);
342 if (err)
343 return err;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700344 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700345 return cbor_value_leave_container(it, &recursed);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700346}
347
348/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700349 * Advances the CBOR value \a it until it no longer points to a tag. If \a it is
350 * already not pointing to a tag, then this function returns it unchanged.
351 *
352 * \sa cbor_value_advance_fixed(), cbor_value_advance()
353 */
354CborError cbor_value_skip_tag(CborValue *it)
355{
356 while (cbor_value_is_tag(it)) {
357 CborError err = cbor_value_advance_fixed(it);
358 if (err)
359 return err;
360 }
361 return CborNoError;
362}
363
364
365/**
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700366 * \fn bool cbor_value_is_container(const CborValue *it)
367 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700368 * Returns true if the \a it value is a container and requires recursion in
369 * order to decode (maps and arrays), false otherwise.
370 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700371
Thiago Macieira2312efd2015-05-06 16:07:48 -0700372/**
373 * Creates a CborValue iterator pointing to the first element of the container
374 * represented by \a it and saves it in \a recursed. The \a it container object
375 * needs to be kept and passed again to cbor_value_leave_container() in order
376 * to continue iterating past this container.
377 *
378 * \sa cbor_value_is_container(), cbor_value_leave_container(), cbor_value_advance()
379 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700380CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700381{
Thiago Macieira56d99832015-05-07 14:34:27 -0700382 CborError err;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700383 assert(cbor_value_is_container(it));
Thiago Macieira54a0e102015-05-05 21:25:06 -0700384 *recursed = *it;
Thiago Macieira56d99832015-05-07 14:34:27 -0700385
Thiago Macieira54a0e102015-05-05 21:25:06 -0700386 if (it->flags & CborIteratorFlag_UnknownLength) {
387 recursed->remaining = UINT32_MAX;
Thiago Macieira56d99832015-05-07 14:34:27 -0700388 ++recursed->ptr;
389 err = preparse_value(recursed);
390 if (err != CborErrorUnexpectedBreak)
391 return err;
392 // actually, break was expected here
393 // it's just an empty container
394 ++recursed->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700395 } else {
Thiago Macieira56d99832015-05-07 14:34:27 -0700396 uint64_t len;
397 err = extract_number(recursed->parser, &recursed->ptr, &len);
398 assert(err == CborNoError);
Thiago Macieira56d99832015-05-07 14:34:27 -0700399
Thiago Macieira54a0e102015-05-05 21:25:06 -0700400 recursed->remaining = len;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900401 if (recursed->remaining != len || len == UINT32_MAX) {
402 // back track the pointer to indicate where the error occurred
403 recursed->ptr = it->ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700404 return CborErrorDataTooLarge;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900405 }
Thiago Macieirace16f052015-05-07 23:14:25 -0700406 if (recursed->type == CborMapType) {
407 // maps have keys and values, so we need to multiply by 2
Thiago Macieira3f76f632015-05-12 10:10:09 +0900408 if (recursed->remaining > UINT32_MAX / 2) {
409 // back track the pointer to indicate where the error occurred
410 recursed->ptr = it->ptr;
Thiago Macieirace16f052015-05-07 23:14:25 -0700411 return CborErrorDataTooLarge;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900412 }
Thiago Macieirace16f052015-05-07 23:14:25 -0700413 recursed->remaining *= 2;
414 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700415 if (len != 0)
416 return preparse_value(recursed);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700417 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700418
419 // the case of the empty container
420 recursed->type = CborInvalidType;
421 recursed->remaining = 0;
422 return CborNoError;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700423}
424
Thiago Macieira2312efd2015-05-06 16:07:48 -0700425/**
426 * Updates \a it to point to the next element after the container. The \a
Thiago Macieira56d99832015-05-07 14:34:27 -0700427 * recursed object needs to point to the element obtained either by advancing
428 * the last element of the container (via cbor_value_advance(),
429 * cbor_value_advance_fixed(), a nested cbor_value_leave_container(), or the \c
430 * next pointer from cbor_value_copy_string() or cbor_value_dup_string()).
Thiago Macieira2312efd2015-05-06 16:07:48 -0700431 *
432 * \sa cbor_value_enter_container(), cbor_value_at_end()
433 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700434CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700435{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700436 assert(cbor_value_is_container(it));
Thiago Macieira56d99832015-05-07 14:34:27 -0700437 assert(recursed->type == CborInvalidType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700438 it->ptr = recursed->ptr;
Thiago Macieira56d99832015-05-07 14:34:27 -0700439 return preparse_next_value(it);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700440}
441
Thiago Macieira2312efd2015-05-06 16:07:48 -0700442/**
443 * Calculates the length of the string in \a value and stores the result in \a
444 * len. This function is different from cbor_value_get_string_length() in that
445 * it calculates the length even for strings sent in chunks. For that reason,
446 * this function may not run in constant time (it will run in O(n) time on the
447 * number of chunks).
448 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700449 * \note On 32-bit platforms, this function will return error condition of \ref
450 * CborErrorDataTooLarge if the stream indicates a length that is too big to
451 * fit in 32-bit.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700452 *
453 * \sa cbor_value_get_string_length(), cbor_value_copy_string(), cbor_value_is_length_known()
454 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700455CborError cbor_value_calculate_string_length(const CborValue *value, size_t *len)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700456{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900457 *len = SIZE_MAX;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700458 return cbor_value_copy_string(value, NULL, len, NULL);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700459}
460
Thiago Macieira2312efd2015-05-06 16:07:48 -0700461/**
462 * Allocates memory for the string pointed by \a value and copies it into this
463 * buffer. The pointer to the buffer is stored in \a buffer and the number of
464 * bytes copied is stored in \a len (those variables must not be NULL).
465 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700466 * If \c malloc returns a NULL pointer, this function will return error
467 * condition \ref CborErrorOutOfMemory.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700468 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700469 * On success, \c{*buffer} will contain a valid pointer that must be freed by
470 * calling \c{free()}. This is the case even for zero-length strings.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700471 *
472 * The \a next pointer, if not null, will be updated to point to the next item
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700473 * after this string. If \a value points to the last item, then \a next will be
474 * invalid.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700475 *
476 * \note This function does not perform UTF-8 validation on the incoming text
477 * string.
478 *
479 * \sa cbor_value_copy_string()
480 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700481CborError cbor_value_dup_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700482{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700483 assert(buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700484 assert(buflen);
Thiago Macieira851c4812015-05-08 15:23:20 -0700485 CborError err = cbor_value_copy_string(value, NULL, buflen, NULL);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700486 if (err)
487 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700488
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700489 ++*buflen;
490 *buffer = malloc(*buflen);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700491 if (!*buffer) {
Thiago Macieirac70169f2015-05-06 07:49:44 -0700492 // out of memory
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700493 return CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700494 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700495 err = cbor_value_copy_string(value, *buffer, buflen, next);
496 if (err) {
Thiago Macieira2312efd2015-05-06 16:07:48 -0700497 free(*buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700498 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700499 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700500 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700501}
502
Thiago Macieira9ae05812015-05-11 15:09:09 +0900503// We return uintptr_t so that we can pass memcpy directly as the iteration
504// function. The choice is to optimize for memcpy, which is used in the base
505// parser API (cbor_value_copy_string), while memcmp is used in convenience API
506// only.
507typedef uintptr_t (*IterateFunction)(char *, const char *, size_t);
508
509static uintptr_t iterate_noop(char *dest, const char *src, size_t len)
510{
511 (void)dest;
512 (void)src;
513 (void)len;
514 return true;
515}
516
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700517static uintptr_t iterate_memcmp(char *s1, const char *s2, size_t len)
518{
519 return memcmp(s1, s2, len) == 0;
520}
521
Thiago Macieira9ae05812015-05-11 15:09:09 +0900522static CborError iterate_string_chunks(const CborValue *value, char *buffer, size_t *buflen,
523 bool *result, CborValue *next, IterateFunction func)
524{
525 assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value));
526
527 size_t total;
528 CborError err;
529 const char *ptr = value->ptr;
530 if (cbor_value_is_length_known(value)) {
531 // easy case: fixed length
532 err = extract_length(value->parser, &ptr, &total);
533 if (err)
534 return err;
535 if (ptr + total > value->parser->end)
536 return CborErrorUnexpectedEOF;
537 if (total <= *buflen)
538 *result = func(buffer, ptr, total);
539 else
540 *result = false;
541 ptr += total;
542 } else {
543 // chunked
544 ++ptr;
545 total = 0;
546 *result = true;
547 while (true) {
548 size_t chunkLen;
549 size_t newTotal;
550
551 if (ptr == value->parser->end)
552 return CborErrorUnexpectedEOF;
553
554 if (*ptr == (char)BreakByte) {
555 ++ptr;
556 break;
557 }
558
559 // is this the right type?
560 if ((*ptr & MajorTypeMask) != value->type)
561 return CborErrorIllegalType;
562
563 err = extract_length(value->parser, &ptr, &chunkLen);
564 if (err)
565 return err;
566
567 if (unlikely(!add_check_overflow(total, chunkLen, &newTotal)))
568 return CborErrorDataTooLarge;
569
570 if (ptr + chunkLen > value->parser->end)
571 return CborErrorUnexpectedEOF;
572
573 if (*result && *buflen >= newTotal)
574 *result = func(buffer + total, ptr, chunkLen);
575 else
576 *result = false;
577
578 ptr += chunkLen;
579 total = newTotal;
580 }
581 }
582
583 // is there enough room for the ending NUL byte?
584 if (*result && *buflen > total)
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700585 *result = func(buffer + total, "", 1);
Thiago Macieira9ae05812015-05-11 15:09:09 +0900586 *buflen = total;
587
588 if (next) {
589 *next = *value;
590 next->ptr = ptr;
591 return preparse_next_value(next);
592 }
593 return CborNoError;
594}
595
Thiago Macieira2312efd2015-05-06 16:07:48 -0700596/**
597 * Copies the string pointed by \a value into the buffer provided at \a buffer
598 * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
599 * copy anything and will only update the \a next value.
600 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700601 * If the provided buffer length was too small, this function returns an error
602 * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
603 * of the string in order to preallocate a buffer, use
Thiago Macieira2312efd2015-05-06 16:07:48 -0700604 * cbor_value_calculate_string_length().
605 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700606 * On success, this function sets the number of bytes copied to \c{*buflen}. If
607 * the buffer is large enough, this function will insert a null byte after the
608 * last copied byte, to facilitate manipulation of text strings. That byte is
609 * not included in the returned value of \c{*buflen}.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700610 *
611 * The \a next pointer, if not null, will be updated to point to the next item
612 * after this string. If \a value points to the last item, then \a next will be
613 * invalid.
614 *
615 * \note This function does not perform UTF-8 validation on the incoming text
616 * string.
617 *
618 * \sa cbor_value_dup_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
619 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700620CborError cbor_value_copy_string(const CborValue *value, char *buffer,
621 size_t *buflen, CborValue *next)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700622{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900623 bool copied_all;
624 CborError err = iterate_string_chunks(value, buffer, buflen, &copied_all, next,
625 buffer ? (IterateFunction)memcpy : iterate_noop);
626 return err ? err :
627 copied_all ? CborNoError : CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700628}
629
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700630/**
631 * Compares the entry \a value with the string \a string and store the result
632 * in \a result. If the value is different from \a string or if it is not a
633 * text string, \a result will contain \c false.
634 *
635 * The entry at \a value may be a tagged string. If \a is not a string or a
636 * tagged string, the comparison result will be false.
637 */
638CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result)
639{
640 CborValue copy = *value;
641 CborError err = cbor_value_skip_tag(&copy);
642 if (err)
643 return err;
644 if (!cbor_value_is_text_string(&copy)) {
645 *result = false;
646 return CborNoError;
647 }
648
649 size_t len = strlen(string);
650 return iterate_string_chunks(&copy, CONST_CAST(char *, string), &len, result, NULL, iterate_memcmp);
651}
652
653/**
Thiago Macieira7b623c22015-05-11 15:52:14 +0900654 * Attempts to find the value in map \a map that corresponds to the text string
655 * entry \a string. If the item is found, it is stored in \a result. If no item
656 * is found matching the key, then \a result will contain an element of type
657 * \ref CborInvalidType.
658 *
659 * \note This function may be expensive to execute.
660 */
661CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element)
662{
663 assert(cbor_value_is_map(map));
664 size_t len = strlen(string);
665 CborError err = cbor_value_enter_container(map, element);
666 if (err)
667 goto error;
668
669 while (!cbor_value_at_end(element)) {
670 // find the non-tag so we can compare
671 err = cbor_value_skip_tag(element);
672 if (err)
673 goto error;
674 if (cbor_value_is_text_string(element)) {
675 bool equals;
676 size_t dummyLen = len;
677 err = iterate_string_chunks(element, CONST_CAST(char *, string), &dummyLen,
678 &equals, element, iterate_memcmp);
679 if (err)
680 goto error;
681 if (equals)
682 return preparse_value(element);
683 } else {
684 // skip this key
685 err = cbor_value_advance(element);
686 if (err)
687 goto error;
688 }
689
690 // skip this value
691 err = cbor_value_skip_tag(element);
692 if (err)
693 goto error;
694 err = cbor_value_advance(element);
695 if (err)
696 goto error;
697 }
698
699 // not found
700 element->type = CborInvalidType;
701 return CborNoError;
702
703error:
704 element->type = CborInvalidType;
705 return err;
706}
707
708/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700709 * Extracts a half-precision floating point from \a value and stores it in \a
710 * result.
711 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700712CborError cbor_value_get_half_float(const CborValue *value, void *result)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700713{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700714 assert(value->type == CborHalfFloatType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700715
716 // size has been computed already
717 uint16_t v = get16(value->ptr + 1);
718 memcpy(result, &v, sizeof(v));
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700719 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700720}