blob: ab3cae1ec184ec4828377866d8d0a41dc53f0359 [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"
Thiago Macieira4e9626c2015-09-21 14:57:17 -070029#include "extract_number_p.h"
Thiago Macieira54a0e102015-05-05 21:25:06 -070030
31#include <assert.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 Macieira8f3fb782015-06-16 16:27:01 -070035#include "assert_p.h" /* Always include last */
36
Thiago Macieira4a99af92015-05-12 10:41:45 +090037#ifndef CBOR_PARSER_MAX_RECURSIONS
38# define CBOR_PARSER_MAX_RECURSIONS 1024
39#endif
40
Thiago Macieira54a0e102015-05-05 21:25:06 -070041/**
42 * \typedef CborValue
43 * This type contains one value parsed from the CBOR stream.
44 *
45 * To get the actual type, use cbor_value_get_type(). Then extract the value
46 * using one of the corresponding functions: cbor_value_get_boolean(), cbor_value_get_int64(),
47 * cbor_value_get_int(), cbor_value_copy_string(), cbor_value_get_array(), cbor_value_get_map(),
48 * cbor_value_get_double(), cbor_value_get_float().
49 *
50 * In C++ and C11 modes, you can additionally use the cbor_value_get_integer()
51 * and cbor_value_get_floating_point() generic functions.
52 *
53 * \omit
54 * Implementation details: the CborValue contains these fields:
55 * \list
56 * \li ptr: pointer to the actual data
57 * \li flags: flags from the decoder
Thiago Macieira2312efd2015-05-06 16:07:48 -070058 * \li extra: partially decoded integer value (0, 1 or 2 bytes)
Thiago Macieira54a0e102015-05-05 21:25:06 -070059 * \li remaining: remaining items in this collection after this item or UINT32_MAX if length is unknown
60 * \endlist
61 * \endomit
62 */
63
Thiago Macieiraf5cb94b2015-06-16 16:10:49 -070064static CborError extract_length(const CborParser *parser, const uint8_t **ptr, size_t *len)
Thiago Macieira54a0e102015-05-05 21:25:06 -070065{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070066 uint64_t v;
Thiago Macieira4e9626c2015-09-21 14:57:17 -070067 CborError err = extract_number(ptr, parser->end, &v);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070068 if (err)
69 return err;
70
71 *len = v;
72 if (v != *len)
73 return CborErrorDataTooLarge;
74 return CborNoError;
75}
76
77static bool is_fixed_type(uint8_t type)
78{
79 return type != CborTextStringType && type != CborByteStringType && type != CborArrayType &&
80 type != CborMapType;
81}
82
83static CborError preparse_value(CborValue *it)
84{
85 const CborParser *parser = it->parser;
Thiago Macieira11e913f2015-05-07 13:01:18 -070086 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070087
Thiago Macieira54a0e102015-05-05 21:25:06 -070088 // are we at the end?
Thiago Macieira54a0e102015-05-05 21:25:06 -070089 if (it->ptr == parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070090 return CborErrorUnexpectedEOF;
Thiago Macieira54a0e102015-05-05 21:25:06 -070091
92 uint8_t descriptor = *it->ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070093 uint8_t type = descriptor & MajorTypeMask;
Thiago Macieira851c4812015-05-08 15:23:20 -070094 it->type = type;
Thiago Macieira54a0e102015-05-05 21:25:06 -070095 it->flags = 0;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070096 it->extra = (descriptor &= SmallValueMask);
97
Thiago Macieira56d99832015-05-07 14:34:27 -070098 if (descriptor > Value64Bit) {
99 if (unlikely(descriptor != IndefiniteLength))
Thiago Macieira3f76f632015-05-12 10:10:09 +0900100 return type == CborSimpleType ? CborErrorUnknownType : CborErrorIllegalNumber;
Thiago Macieira56d99832015-05-07 14:34:27 -0700101 if (likely(!is_fixed_type(type))) {
102 // special case
103 it->flags |= CborIteratorFlag_UnknownLength;
104 it->type = type;
105 return CborNoError;
106 }
107 return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700108 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700109
Thiago Macieirac70169f2015-05-06 07:49:44 -0700110 size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit));
Thiago Macieira63abed92015-10-28 17:01:14 -0700111 if (bytesNeeded + 1 > (size_t)(parser->end - it->ptr))
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700112 return CborErrorUnexpectedEOF;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700113
Thiago Macieira851c4812015-05-08 15:23:20 -0700114 uint8_t majortype = type >> MajorTypeShift;
115 if (majortype == NegativeIntegerType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700116 it->flags |= CborIteratorFlag_NegativeInteger;
Thiago Macieira851c4812015-05-08 15:23:20 -0700117 it->type = CborIntegerType;
118 } else if (majortype == SimpleTypesType) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700119 switch (descriptor) {
120 case FalseValue:
121 it->extra = false;
Thiago Macieira851c4812015-05-08 15:23:20 -0700122 it->type = CborBooleanType;
Thiago Macieira991dd922015-05-07 11:57:59 -0700123 break;
124
Thiago Macieira851c4812015-05-08 15:23:20 -0700125 case SinglePrecisionFloat:
126 case DoublePrecisionFloat:
127 it->flags |= CborIteratorFlag_IntegerValueTooLarge;
128 // fall through
Thiago Macieira54a0e102015-05-05 21:25:06 -0700129 case TrueValue:
130 case NullValue:
131 case UndefinedValue:
132 case HalfPrecisionFloat:
Thiago Macieira851c4812015-05-08 15:23:20 -0700133 it->type = *it->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700134 break;
135
136 case SimpleTypeInNextByte:
Thiago Macieira851c4812015-05-08 15:23:20 -0700137 it->extra = (uint8_t)it->ptr[1];
Thiago Macieira54a0e102015-05-05 21:25:06 -0700138#ifndef CBOR_PARSER_NO_STRICT_CHECKS
Thiago Macieira851c4812015-05-08 15:23:20 -0700139 if (unlikely(it->extra < 32)) {
140 it->type = CborInvalidType;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700141 return CborErrorIllegalSimpleType;
Thiago Macieira851c4812015-05-08 15:23:20 -0700142 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700143#endif
Thiago Macieira991dd922015-05-07 11:57:59 -0700144 break;
145
Thiago Macieira54a0e102015-05-05 21:25:06 -0700146 case 28:
147 case 29:
148 case 30:
Thiago Macieira54a0e102015-05-05 21:25:06 -0700149 case Break:
Thiago Macieira851c4812015-05-08 15:23:20 -0700150 assert(false); // these conditions can't be reached
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700151 return CborErrorUnexpectedBreak;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700152 }
Thiago Macieira851c4812015-05-08 15:23:20 -0700153 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700154 }
155
156 // try to decode up to 16 bits
157 if (descriptor < Value8Bit)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700158 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700159
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700160 if (descriptor == Value8Bit)
161 it->extra = (uint8_t)it->ptr[1];
162 else if (descriptor == Value16Bit)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700163 it->extra = get16(it->ptr + 1);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700164 else
165 it->flags |= CborIteratorFlag_IntegerValueTooLarge; // Value32Bit or Value64Bit
166 return CborNoError;
167}
Thiago Macieira54a0e102015-05-05 21:25:06 -0700168
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700169static CborError preparse_next_value(CborValue *it)
170{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700171 if (it->remaining != UINT32_MAX) {
Thiago Macieira11e913f2015-05-07 13:01:18 -0700172 // don't decrement the item count if the current item is tag: they don't count
173 if (it->type != CborTagType && !--it->remaining) {
174 it->type = CborInvalidType;
Thiago Macieira56d99832015-05-07 14:34:27 -0700175 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700176 }
Thiago Macieira5752ce52015-06-16 12:10:03 -0700177 } else if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (uint8_t)BreakByte) {
Thiago Macieira56d99832015-05-07 14:34:27 -0700178 // end of map or array
179 ++it->ptr;
180 it->type = CborInvalidType;
181 it->remaining = 0;
182 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700183 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700184
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700185 return preparse_value(it);
186}
187
188static CborError advance_internal(CborValue *it)
189{
190 uint64_t length;
Thiago Macieira4e9626c2015-09-21 14:57:17 -0700191 CborError err = extract_number(&it->ptr, it->parser->end, &length);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700192 assert(err == CborNoError);
193
Thiago Macieira56d99832015-05-07 14:34:27 -0700194 if (it->type == CborByteStringType || it->type == CborTextStringType) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700195 assert(length == (size_t)length);
Thiago Macieira56d99832015-05-07 14:34:27 -0700196 assert((it->flags & CborIteratorFlag_UnknownLength) == 0);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700197 it->ptr += length;
198 }
199
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700200 return preparse_next_value(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700201}
202
Thiago Macieira2312efd2015-05-06 16:07:48 -0700203/** \internal
204 *
205 * Decodes the CBOR integer value when it is larger than the 16 bits available
206 * in value->extra. This function requires that value->flags have the
207 * CborIteratorFlag_IntegerValueTooLarge flag set.
208 *
209 * This function is also used to extract single- and double-precision floating
210 * point values (SinglePrecisionFloat == Value32Bit and DoublePrecisionFloat ==
211 * Value64Bit).
212 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700213uint64_t _cbor_value_decode_int64_internal(const CborValue *value)
214{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700215 assert(value->flags & CborIteratorFlag_IntegerValueTooLarge ||
216 value->type == CborFloatType || value->type == CborDoubleType);
Thiago Macieira851c4812015-05-08 15:23:20 -0700217
218 // since the additional information can only be Value32Bit or Value64Bit,
219 // we just need to test for the one bit those two options differ
220 assert((*value->ptr & SmallValueMask) == Value32Bit || (*value->ptr & SmallValueMask) == Value64Bit);
221 if ((*value->ptr & 1) == (Value32Bit & 1))
Thiago Macieira54a0e102015-05-05 21:25:06 -0700222 return get32(value->ptr + 1);
223
224 assert((*value->ptr & SmallValueMask) == Value64Bit);
225 return get64(value->ptr + 1);
226}
227
228/**
229 * Initializes the CBOR parser for parsing \a size bytes beginning at \a
230 * buffer. Parsing will use flags set in \a flags. The iterator to the first
231 * element is returned in \a it.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700232 *
233 * The \a parser structure needs to remain valid throughout the decoding
234 * process. It is not thread-safe to share one CborParser among multiple
235 * threads iterating at the same time, but the object can be copied so multiple
236 * threads can iterate.
237 *
238 * ### Write how to determine the end pointer
239 * ### Write how to do limited-buffer windowed decoding
Thiago Macieira54a0e102015-05-05 21:25:06 -0700240 */
Thiago Macieira5752ce52015-06-16 12:10:03 -0700241CborError cbor_parser_init(const uint8_t *buffer, size_t size, int flags, CborParser *parser, CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700242{
243 memset(parser, 0, sizeof(*parser));
244 parser->end = buffer + size;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700245 parser->flags = flags;
246 it->parser = parser;
247 it->ptr = buffer;
248 it->remaining = 1; // there's one type altogether, usually an array or map
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700249 return preparse_value(it);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700250}
251
252/**
253 * Advances the CBOR value \a it by one fixed-size position. Fixed-size types
254 * are: integers, tags, simple types (including boolean, null and undefined
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700255 * values) and floating point types.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700256 *
257 * \sa cbor_value_at_end(), cbor_value_advance(), cbor_value_begin_recurse(), cbor_value_end_recurse()
258 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700259CborError cbor_value_advance_fixed(CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700260{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700261 assert(it->type != CborInvalidType);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700262 assert(is_fixed_type(it->type));
263 if (!it->remaining)
264 return CborErrorAdvancePastEOF;
265 return advance_internal(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700266}
267
Thiago Macieira4a99af92015-05-12 10:41:45 +0900268static CborError advance_recursive(CborValue *it, int nestingLevel)
269{
270 if (is_fixed_type(it->type))
271 return advance_internal(it);
272
273 if (!cbor_value_is_container(it)) {
274 size_t len = SIZE_MAX;
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700275 return _cbor_value_copy_string(it, NULL, &len, it);
Thiago Macieira4a99af92015-05-12 10:41:45 +0900276 }
277
278 // map or array
279 if (nestingLevel == CBOR_PARSER_MAX_RECURSIONS)
280 return CborErrorNestingTooDeep;
281
282 CborError err;
283 CborValue recursed;
284 err = cbor_value_enter_container(it, &recursed);
285 if (err)
286 return err;
287 while (!cbor_value_at_end(&recursed)) {
288 err = advance_recursive(&recursed, nestingLevel + 1);
289 if (err)
290 return err;
291 }
292 return cbor_value_leave_container(it, &recursed);
293}
294
295
Thiago Macieira2312efd2015-05-06 16:07:48 -0700296/**
297 * Advances the CBOR value \a it by one element, skipping over containers.
298 * Unlike cbor_value_advance_fixed(), this function can be called on a CBOR
299 * value of any type. However, if the type is a container (map or array) or a
300 * string with a chunked payload, this function will not run in constant time
301 * and will recurse into itself (it will run on O(n) time for the number of
302 * elements or chunks and will use O(n) memory for the number of nested
303 * containers).
304 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700305 * \sa cbor_value_at_end(), cbor_value_advance_fixed(), cbor_value_begin_recurse(), cbor_value_end_recurse()
306 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700307CborError cbor_value_advance(CborValue *it)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700308{
309 assert(it->type != CborInvalidType);
310 if (!it->remaining)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700311 return CborErrorAdvancePastEOF;
Thiago Macieira4a99af92015-05-12 10:41:45 +0900312 return advance_recursive(it, 0);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700313}
314
315/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700316 * Advances the CBOR value \a it until it no longer points to a tag. If \a it is
317 * already not pointing to a tag, then this function returns it unchanged.
318 *
319 * \sa cbor_value_advance_fixed(), cbor_value_advance()
320 */
321CborError cbor_value_skip_tag(CborValue *it)
322{
323 while (cbor_value_is_tag(it)) {
324 CborError err = cbor_value_advance_fixed(it);
325 if (err)
326 return err;
327 }
328 return CborNoError;
329}
330
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700331/**
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700332 * \fn bool cbor_value_is_container(const CborValue *it)
333 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700334 * Returns true if the \a it value is a container and requires recursion in
335 * order to decode (maps and arrays), false otherwise.
336 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700337
Thiago Macieira2312efd2015-05-06 16:07:48 -0700338/**
339 * Creates a CborValue iterator pointing to the first element of the container
340 * represented by \a it and saves it in \a recursed. The \a it container object
341 * needs to be kept and passed again to cbor_value_leave_container() in order
342 * to continue iterating past this container.
343 *
344 * \sa cbor_value_is_container(), cbor_value_leave_container(), cbor_value_advance()
345 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700346CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700347{
Thiago Macieira56d99832015-05-07 14:34:27 -0700348 CborError err;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700349 assert(cbor_value_is_container(it));
Thiago Macieira54a0e102015-05-05 21:25:06 -0700350 *recursed = *it;
Thiago Macieira56d99832015-05-07 14:34:27 -0700351
Thiago Macieira54a0e102015-05-05 21:25:06 -0700352 if (it->flags & CborIteratorFlag_UnknownLength) {
353 recursed->remaining = UINT32_MAX;
Thiago Macieira56d99832015-05-07 14:34:27 -0700354 ++recursed->ptr;
355 err = preparse_value(recursed);
356 if (err != CborErrorUnexpectedBreak)
357 return err;
358 // actually, break was expected here
359 // it's just an empty container
360 ++recursed->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700361 } else {
Thiago Macieira56d99832015-05-07 14:34:27 -0700362 uint64_t len;
Thiago Macieira4e9626c2015-09-21 14:57:17 -0700363 err = extract_number(&recursed->ptr, recursed->parser->end, &len);
Thiago Macieira56d99832015-05-07 14:34:27 -0700364 assert(err == CborNoError);
Thiago Macieira56d99832015-05-07 14:34:27 -0700365
Thiago Macieira54a0e102015-05-05 21:25:06 -0700366 recursed->remaining = len;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900367 if (recursed->remaining != len || len == UINT32_MAX) {
368 // back track the pointer to indicate where the error occurred
369 recursed->ptr = it->ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700370 return CborErrorDataTooLarge;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900371 }
Thiago Macieirace16f052015-05-07 23:14:25 -0700372 if (recursed->type == CborMapType) {
373 // maps have keys and values, so we need to multiply by 2
Thiago Macieira3f76f632015-05-12 10:10:09 +0900374 if (recursed->remaining > UINT32_MAX / 2) {
375 // back track the pointer to indicate where the error occurred
376 recursed->ptr = it->ptr;
Thiago Macieirace16f052015-05-07 23:14:25 -0700377 return CborErrorDataTooLarge;
Thiago Macieira3f76f632015-05-12 10:10:09 +0900378 }
Thiago Macieirace16f052015-05-07 23:14:25 -0700379 recursed->remaining *= 2;
380 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700381 if (len != 0)
382 return preparse_value(recursed);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700383 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700384
385 // the case of the empty container
386 recursed->type = CborInvalidType;
387 recursed->remaining = 0;
388 return CborNoError;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700389}
390
Thiago Macieira2312efd2015-05-06 16:07:48 -0700391/**
392 * Updates \a it to point to the next element after the container. The \a
Thiago Macieira56d99832015-05-07 14:34:27 -0700393 * recursed object needs to point to the element obtained either by advancing
394 * the last element of the container (via cbor_value_advance(),
395 * cbor_value_advance_fixed(), a nested cbor_value_leave_container(), or the \c
396 * next pointer from cbor_value_copy_string() or cbor_value_dup_string()).
Thiago Macieira2312efd2015-05-06 16:07:48 -0700397 *
398 * \sa cbor_value_enter_container(), cbor_value_at_end()
399 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700400CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700401{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700402 assert(cbor_value_is_container(it));
Thiago Macieira56d99832015-05-07 14:34:27 -0700403 assert(recursed->type == CborInvalidType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700404 it->ptr = recursed->ptr;
Thiago Macieira56d99832015-05-07 14:34:27 -0700405 return preparse_next_value(it);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700406}
407
Thiago Macieira2312efd2015-05-06 16:07:48 -0700408/**
409 * Calculates the length of the string in \a value and stores the result in \a
410 * len. This function is different from cbor_value_get_string_length() in that
411 * it calculates the length even for strings sent in chunks. For that reason,
412 * this function may not run in constant time (it will run in O(n) time on the
413 * number of chunks).
414 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700415 * \note On 32-bit platforms, this function will return error condition of \ref
416 * CborErrorDataTooLarge if the stream indicates a length that is too big to
417 * fit in 32-bit.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700418 *
419 * \sa cbor_value_get_string_length(), cbor_value_copy_string(), cbor_value_is_length_known()
420 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700421CborError cbor_value_calculate_string_length(const CborValue *value, size_t *len)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700422{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900423 *len = SIZE_MAX;
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700424 return _cbor_value_copy_string(value, NULL, len, NULL);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700425}
426
Thiago Macieira2312efd2015-05-06 16:07:48 -0700427/**
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700428 * \fn CborError cbor_value_dup_text_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next)
429 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700430 * Allocates memory for the string pointed by \a value and copies it into this
431 * buffer. The pointer to the buffer is stored in \a buffer and the number of
432 * bytes copied is stored in \a len (those variables must not be NULL).
433 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700434 * If \c malloc returns a NULL pointer, this function will return error
435 * condition \ref CborErrorOutOfMemory.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700436 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700437 * On success, \c{*buffer} will contain a valid pointer that must be freed by
438 * calling \c{free()}. This is the case even for zero-length strings.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700439 *
440 * The \a next pointer, if not null, will be updated to point to the next item
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700441 * after this string. If \a value points to the last item, then \a next will be
442 * invalid.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700443 *
444 * \note This function does not perform UTF-8 validation on the incoming text
445 * string.
446 *
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700447 * \sa cbor_value_copy_text_string(), cbor_value_dup_byte_string()
Thiago Macieira2312efd2015-05-06 16:07:48 -0700448 */
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700449
450/**
451 * \fn CborError cbor_value_dup_byte_string(const CborValue *value, uint8_t **buffer, size_t *buflen, CborValue *next)
452 *
453 * Allocates memory for the string pointed by \a value and copies it into this
454 * buffer. The pointer to the buffer is stored in \a buffer and the number of
455 * bytes copied is stored in \a len (those variables must not be NULL).
456 *
457 * If \c malloc returns a NULL pointer, this function will return error
458 * condition \ref CborErrorOutOfMemory.
459 *
460 * On success, \c{*buffer} will contain a valid pointer that must be freed by
461 * calling \c{free()}. This is the case even for zero-length strings.
462 *
463 * The \a next pointer, if not null, will be updated to point to the next item
464 * after this string. If \a value points to the last item, then \a next will be
465 * invalid.
466 *
467 * \sa cbor_value_copy_byte_string(), cbor_value_dup_text_string()
468 */
469CborError _cbor_value_dup_string(const CborValue *value, void **buffer, size_t *buflen, CborValue *next)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700470{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700471 assert(buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700472 assert(buflen);
Thiago Macieirafc870932015-06-19 15:01:35 -0700473 *buflen = SIZE_MAX;
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700474 CborError err = _cbor_value_copy_string(value, NULL, buflen, NULL);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700475 if (err)
476 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700477
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700478 ++*buflen;
479 *buffer = malloc(*buflen);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700480 if (!*buffer) {
Thiago Macieirac70169f2015-05-06 07:49:44 -0700481 // out of memory
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700482 return CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700483 }
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700484 err = _cbor_value_copy_string(value, *buffer, buflen, next);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700485 if (err) {
Thiago Macieira2312efd2015-05-06 16:07:48 -0700486 free(*buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700487 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700488 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700489 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700490}
491
Thiago Macieira9ae05812015-05-11 15:09:09 +0900492// We return uintptr_t so that we can pass memcpy directly as the iteration
493// function. The choice is to optimize for memcpy, which is used in the base
494// parser API (cbor_value_copy_string), while memcmp is used in convenience API
495// only.
Thiago Macieira5752ce52015-06-16 12:10:03 -0700496typedef uintptr_t (*IterateFunction)(char *, const uint8_t *, size_t);
Thiago Macieira9ae05812015-05-11 15:09:09 +0900497
Thiago Macieira5752ce52015-06-16 12:10:03 -0700498static uintptr_t iterate_noop(char *dest, const uint8_t *src, size_t len)
Thiago Macieira9ae05812015-05-11 15:09:09 +0900499{
500 (void)dest;
501 (void)src;
502 (void)len;
503 return true;
504}
505
Thiago Macieira5752ce52015-06-16 12:10:03 -0700506static uintptr_t iterate_memcmp(char *s1, const uint8_t *s2, size_t len)
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700507{
Thiago Macieira5752ce52015-06-16 12:10:03 -0700508 return memcmp(s1, (const char *)s2, len) == 0;
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700509}
510
Thiago Macieira9ae05812015-05-11 15:09:09 +0900511static CborError iterate_string_chunks(const CborValue *value, char *buffer, size_t *buflen,
512 bool *result, CborValue *next, IterateFunction func)
513{
514 assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value));
515
516 size_t total;
517 CborError err;
Thiago Macieira5752ce52015-06-16 12:10:03 -0700518 const uint8_t *ptr = value->ptr;
Thiago Macieira9ae05812015-05-11 15:09:09 +0900519 if (cbor_value_is_length_known(value)) {
520 // easy case: fixed length
521 err = extract_length(value->parser, &ptr, &total);
522 if (err)
523 return err;
Thiago Macieira63abed92015-10-28 17:01:14 -0700524 if (total > (size_t)(value->parser->end - ptr))
Thiago Macieira9ae05812015-05-11 15:09:09 +0900525 return CborErrorUnexpectedEOF;
526 if (total <= *buflen)
527 *result = func(buffer, ptr, total);
528 else
529 *result = false;
530 ptr += total;
531 } else {
532 // chunked
533 ++ptr;
534 total = 0;
535 *result = true;
536 while (true) {
537 size_t chunkLen;
538 size_t newTotal;
539
540 if (ptr == value->parser->end)
541 return CborErrorUnexpectedEOF;
542
Thiago Macieira5752ce52015-06-16 12:10:03 -0700543 if (*ptr == (uint8_t)BreakByte) {
Thiago Macieira9ae05812015-05-11 15:09:09 +0900544 ++ptr;
545 break;
546 }
547
548 // is this the right type?
549 if ((*ptr & MajorTypeMask) != value->type)
550 return CborErrorIllegalType;
551
552 err = extract_length(value->parser, &ptr, &chunkLen);
553 if (err)
554 return err;
555
Thiago Macieira1de31a42015-06-16 16:01:16 -0700556 if (unlikely(add_check_overflow(total, chunkLen, &newTotal)))
Thiago Macieira9ae05812015-05-11 15:09:09 +0900557 return CborErrorDataTooLarge;
558
Thiago Macieira63abed92015-10-28 17:01:14 -0700559 if (chunkLen > (size_t)(value->parser->end - ptr))
Thiago Macieira9ae05812015-05-11 15:09:09 +0900560 return CborErrorUnexpectedEOF;
561
562 if (*result && *buflen >= newTotal)
563 *result = func(buffer + total, ptr, chunkLen);
564 else
565 *result = false;
566
567 ptr += chunkLen;
568 total = newTotal;
569 }
570 }
571
572 // is there enough room for the ending NUL byte?
573 if (*result && *buflen > total)
Thiago Macieira5752ce52015-06-16 12:10:03 -0700574 *result = func(buffer + total, (const uint8_t *)"", 1);
Thiago Macieira9ae05812015-05-11 15:09:09 +0900575 *buflen = total;
576
577 if (next) {
578 *next = *value;
579 next->ptr = ptr;
580 return preparse_next_value(next);
581 }
582 return CborNoError;
583}
584
Thiago Macieira2312efd2015-05-06 16:07:48 -0700585/**
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700586 * \fn CborError cbor_value_copy_text_string(const CborValue *value, char *buffer, size_t *buflen, CborValue *next)
587 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700588 * Copies the string pointed by \a value into the buffer provided at \a buffer
589 * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
590 * copy anything and will only update the \a next value.
591 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700592 * If the provided buffer length was too small, this function returns an error
593 * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
594 * of the string in order to preallocate a buffer, use
Thiago Macieira2312efd2015-05-06 16:07:48 -0700595 * cbor_value_calculate_string_length().
596 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700597 * On success, this function sets the number of bytes copied to \c{*buflen}. If
598 * the buffer is large enough, this function will insert a null byte after the
599 * last copied byte, to facilitate manipulation of text strings. That byte is
600 * not included in the returned value of \c{*buflen}.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700601 *
602 * The \a next pointer, if not null, will be updated to point to the next item
603 * after this string. If \a value points to the last item, then \a next will be
604 * invalid.
605 *
606 * \note This function does not perform UTF-8 validation on the incoming text
607 * string.
608 *
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700609 * \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 -0700610 */
Thiago Macieiraff130bc2015-06-19 15:15:33 -0700611
612/**
613 * \fn CborError cbor_value_copy_byte_string(const CborValue *value, uint8_t *buffer, size_t *buflen, CborValue *next)
614 *
615 * Copies the string pointed by \a value into the buffer provided at \a buffer
616 * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
617 * copy anything and will only update the \a next value.
618 *
619 * If the provided buffer length was too small, this function returns an error
620 * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
621 * of the string in order to preallocate a buffer, use
622 * cbor_value_calculate_string_length().
623 *
624 * On success, this function sets the number of bytes copied to \c{*buflen}. If
625 * the buffer is large enough, this function will insert a null byte after the
626 * last copied byte, to facilitate manipulation of null-terminated strings.
627 * That byte is not included in the returned value of \c{*buflen}.
628 *
629 * The \a next pointer, if not null, will be updated to point to the next item
630 * after this string. If \a value points to the last item, then \a next will be
631 * invalid.
632 *
633 * \sa cbor_value_dup_text_string(), cbor_value_copy_text_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
634 */
635
636CborError _cbor_value_copy_string(const CborValue *value, void *buffer,
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700637 size_t *buflen, CborValue *next)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700638{
Thiago Macieira9ae05812015-05-11 15:09:09 +0900639 bool copied_all;
Thiago Macieiraed5b57c2015-07-07 16:38:27 -0700640 CborError err = iterate_string_chunks(value, (char*)buffer, buflen, &copied_all, next,
Thiago Macieira9ae05812015-05-11 15:09:09 +0900641 buffer ? (IterateFunction)memcpy : iterate_noop);
642 return err ? err :
643 copied_all ? CborNoError : CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700644}
645
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700646/**
647 * Compares the entry \a value with the string \a string and store the result
648 * in \a result. If the value is different from \a string or if it is not a
649 * text string, \a result will contain \c false.
650 *
651 * The entry at \a value may be a tagged string. If \a is not a string or a
652 * tagged string, the comparison result will be false.
653 */
654CborError cbor_value_text_string_equals(const CborValue *value, const char *string, bool *result)
655{
656 CborValue copy = *value;
657 CborError err = cbor_value_skip_tag(&copy);
658 if (err)
659 return err;
660 if (!cbor_value_is_text_string(&copy)) {
661 *result = false;
662 return CborNoError;
663 }
664
665 size_t len = strlen(string);
666 return iterate_string_chunks(&copy, CONST_CAST(char *, string), &len, result, NULL, iterate_memcmp);
667}
668
669/**
Thiago Macieira7b623c22015-05-11 15:52:14 +0900670 * Attempts to find the value in map \a map that corresponds to the text string
671 * entry \a string. If the item is found, it is stored in \a result. If no item
672 * is found matching the key, then \a result will contain an element of type
673 * \ref CborInvalidType.
674 *
675 * \note This function may be expensive to execute.
676 */
677CborError cbor_value_map_find_value(const CborValue *map, const char *string, CborValue *element)
678{
679 assert(cbor_value_is_map(map));
680 size_t len = strlen(string);
681 CborError err = cbor_value_enter_container(map, element);
682 if (err)
683 goto error;
684
685 while (!cbor_value_at_end(element)) {
686 // find the non-tag so we can compare
687 err = cbor_value_skip_tag(element);
688 if (err)
689 goto error;
690 if (cbor_value_is_text_string(element)) {
691 bool equals;
692 size_t dummyLen = len;
693 err = iterate_string_chunks(element, CONST_CAST(char *, string), &dummyLen,
694 &equals, element, iterate_memcmp);
695 if (err)
696 goto error;
697 if (equals)
698 return preparse_value(element);
699 } else {
700 // skip this key
701 err = cbor_value_advance(element);
702 if (err)
703 goto error;
704 }
705
706 // skip this value
707 err = cbor_value_skip_tag(element);
708 if (err)
709 goto error;
710 err = cbor_value_advance(element);
711 if (err)
712 goto error;
713 }
714
715 // not found
716 element->type = CborInvalidType;
717 return CborNoError;
718
719error:
720 element->type = CborInvalidType;
721 return err;
722}
723
724/**
Thiago Macieirac4a73c62015-05-09 18:14:11 -0700725 * Extracts a half-precision floating point from \a value and stores it in \a
726 * result.
727 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700728CborError cbor_value_get_half_float(const CborValue *value, void *result)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700729{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700730 assert(value->type == CborHalfFloatType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700731
732 // size has been computed already
733 uint16_t v = get16(value->ptr + 1);
734 memcpy(result, &v, sizeof(v));
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700735 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700736}