blob: 14583f2e1ae3b5ed2bfd501e216886cf53e8ec02 [file] [log] [blame]
Thiago Macieira54a0e102015-05-05 21:25:06 -07001/****************************************************************************
2**
3** Copyright (C) 2015 Intel Corporation
4**
5** Permission is hereby granted, free of charge, to any person obtaining a copy
6** of this software and associated documentation files (the "Software"), to deal
7** in the Software without restriction, including without limitation the rights
8** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9** copies of the Software, and to permit persons to whom the Software is
10** furnished to do so, subject to the following conditions:
11**
12** The above copyright notice and this permission notice shall be included in
13** all copies or substantial portions of the Software.
14**
15** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21** THE SOFTWARE.
22**
23****************************************************************************/
24
25#define _BSD_SOURCE
26#include "cbor.h"
27#include "cborconstants_p.h"
28#include "compilersupport_p.h"
29
30#include <assert.h>
31#include <endian.h>
Thiago Macieira2312efd2015-05-06 16:07:48 -070032#include <stdlib.h>
Thiago Macieira54a0e102015-05-05 21:25:06 -070033#include <string.h>
34
Thiago Macieirac70169f2015-05-06 07:49:44 -070035#if defined(__GNUC__) && !defined(__INTEL_COMPILER) && !defined(__clang__) && \
36 (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)
37# pragma GCC optimize("-ffunction-sections")
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 Macieira54a0e102015-05-05 21:25:06 -070063static inline uint16_t get16(const char *ptr)
64{
65 uint16_t result;
66 memcpy(&result, ptr, sizeof(result));
67 return be16toh(result);
68}
69
70static inline uint32_t get32(const char *ptr)
71{
72 uint32_t result;
73 memcpy(&result, ptr, sizeof(result));
74 return be32toh(result);
75}
76
77static inline uint64_t get64(const char *ptr)
78{
79 uint64_t result;
80 memcpy(&result, ptr, sizeof(result));
81 return be64toh(result);
82}
83
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -070084static inline CborError extract_number(const CborParser *parser, const char **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 Macieiraa43a4ef2015-05-06 20:25:18 -0700111static inline CborError extract_length(const CborParser *parser, const char **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 Macieira54a0e102015-05-05 21:25:06 -0700141 it->flags = 0;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700142 it->extra = (descriptor &= SmallValueMask);
143
Thiago Macieira56d99832015-05-07 14:34:27 -0700144 if (descriptor > Value64Bit) {
145 if (unlikely(descriptor != IndefiniteLength))
146 return CborErrorIllegalNumber;
147 if (likely(!is_fixed_type(type))) {
148 // special case
149 it->flags |= CborIteratorFlag_UnknownLength;
150 it->type = type;
151 return CborNoError;
152 }
153 return type == CborSimpleType ? CborErrorUnexpectedBreak : CborErrorIllegalNumber;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700154 }
Thiago Macieira54a0e102015-05-05 21:25:06 -0700155
Thiago Macieirac70169f2015-05-06 07:49:44 -0700156 size_t bytesNeeded = descriptor < Value8Bit ? 0 : (1 << (descriptor - Value8Bit));
157 if (it->ptr + 1 + bytesNeeded > parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700158 return CborErrorUnexpectedEOF;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700159
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700160 switch ((CborMajorTypes)(type >> MajorTypeShift)) {
Thiago Macieira54a0e102015-05-05 21:25:06 -0700161 case NegativeIntegerType:
162 it->flags |= CborIteratorFlag_NegativeInteger;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700163 type = CborIntegerType;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700164 // fall through
165 case UnsignedIntegerType:
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700166 case ByteStringType:
167 case TextStringType:
168 case ArrayType:
169 case MapType:
Thiago Macieira54a0e102015-05-05 21:25:06 -0700170 case TagType:
171 break;
172
173 case SimpleTypesType:
174 switch (descriptor) {
175 case FalseValue:
176 it->extra = false;
Thiago Macieira991dd922015-05-07 11:57:59 -0700177 type = CborBooleanType;
178 break;
179
Thiago Macieira54a0e102015-05-05 21:25:06 -0700180 case TrueValue:
181 case NullValue:
182 case UndefinedValue:
183 case HalfPrecisionFloat:
184 case SinglePrecisionFloat:
185 case DoublePrecisionFloat:
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700186 type = *it->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700187 break;
188
189 case SimpleTypeInNextByte:
Thiago Macieira54a0e102015-05-05 21:25:06 -0700190#ifndef CBOR_PARSER_NO_STRICT_CHECKS
Thiago Macieira991dd922015-05-07 11:57:59 -0700191 if ((unsigned char)it->ptr[1] < 32)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700192 return CborErrorIllegalSimpleType;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700193#endif
Thiago Macieira991dd922015-05-07 11:57:59 -0700194 break;
195
Thiago Macieira54a0e102015-05-05 21:25:06 -0700196 case 28:
197 case 29:
198 case 30:
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700199 return CborErrorUnknownType;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700200
201 case Break:
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700202 return CborErrorUnexpectedBreak;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700203 }
204 break;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700205 }
206
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700207 // no further errors possible
208 it->type = type;
209
Thiago Macieira54a0e102015-05-05 21:25:06 -0700210 // try to decode up to 16 bits
211 if (descriptor < Value8Bit)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700212 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700213
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700214 if (descriptor == Value8Bit)
215 it->extra = (uint8_t)it->ptr[1];
216 else if (descriptor == Value16Bit)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700217 it->extra = get16(it->ptr + 1);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700218 else
219 it->flags |= CborIteratorFlag_IntegerValueTooLarge; // Value32Bit or Value64Bit
220 return CborNoError;
221}
Thiago Macieira54a0e102015-05-05 21:25:06 -0700222
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700223static CborError preparse_next_value(CborValue *it)
224{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700225 if (it->remaining != UINT32_MAX) {
Thiago Macieira11e913f2015-05-07 13:01:18 -0700226 // don't decrement the item count if the current item is tag: they don't count
227 if (it->type != CborTagType && !--it->remaining) {
228 it->type = CborInvalidType;
Thiago Macieira56d99832015-05-07 14:34:27 -0700229 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700230 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700231 } else if (it->remaining == UINT32_MAX && it->ptr != it->parser->end && *it->ptr == (char)BreakByte) {
232 // end of map or array
233 ++it->ptr;
234 it->type = CborInvalidType;
235 it->remaining = 0;
236 return CborNoError;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700237 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700238
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700239 return preparse_value(it);
240}
241
242static CborError advance_internal(CborValue *it)
243{
244 uint64_t length;
245 CborError err = extract_number(it->parser, &it->ptr, &length);
246 assert(err == CborNoError);
Thiago Macieira56d99832015-05-07 14:34:27 -0700247// assert(it->type != CborArrayType && it->type != CborMapType);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700248
Thiago Macieira56d99832015-05-07 14:34:27 -0700249 if (it->type == CborByteStringType || it->type == CborTextStringType) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700250 assert(length == (size_t)length);
Thiago Macieira56d99832015-05-07 14:34:27 -0700251 assert((it->flags & CborIteratorFlag_UnknownLength) == 0);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700252 it->ptr += length;
253 }
254
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700255 return preparse_next_value(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700256}
257
Thiago Macieira2312efd2015-05-06 16:07:48 -0700258/** \internal
259 *
260 * Decodes the CBOR integer value when it is larger than the 16 bits available
261 * in value->extra. This function requires that value->flags have the
262 * CborIteratorFlag_IntegerValueTooLarge flag set.
263 *
264 * This function is also used to extract single- and double-precision floating
265 * point values (SinglePrecisionFloat == Value32Bit and DoublePrecisionFloat ==
266 * Value64Bit).
267 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700268uint64_t _cbor_value_decode_int64_internal(const CborValue *value)
269{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700270 assert(value->flags & CborIteratorFlag_IntegerValueTooLarge ||
271 value->type == CborFloatType || value->type == CborDoubleType);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700272 if ((*value->ptr & SmallValueMask) == Value32Bit)
273 return get32(value->ptr + 1);
274
275 assert((*value->ptr & SmallValueMask) == Value64Bit);
276 return get64(value->ptr + 1);
277}
278
279/**
280 * Initializes the CBOR parser for parsing \a size bytes beginning at \a
281 * buffer. Parsing will use flags set in \a flags. The iterator to the first
282 * element is returned in \a it.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700283 *
284 * The \a parser structure needs to remain valid throughout the decoding
285 * process. It is not thread-safe to share one CborParser among multiple
286 * threads iterating at the same time, but the object can be copied so multiple
287 * threads can iterate.
288 *
289 * ### Write how to determine the end pointer
290 * ### Write how to do limited-buffer windowed decoding
Thiago Macieira54a0e102015-05-05 21:25:06 -0700291 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700292CborError cbor_parser_init(const char *buffer, size_t size, int flags, CborParser *parser, CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700293{
294 memset(parser, 0, sizeof(*parser));
295 parser->end = buffer + size;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700296 parser->flags = flags;
297 it->parser = parser;
298 it->ptr = buffer;
299 it->remaining = 1; // there's one type altogether, usually an array or map
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700300 return preparse_value(it);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700301}
302
303/**
304 * Advances the CBOR value \a it by one fixed-size position. Fixed-size types
305 * are: integers, tags, simple types (including boolean, null and undefined
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700306 * values) and floating point types.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700307 *
308 * \sa cbor_value_at_end(), cbor_value_advance(), cbor_value_begin_recurse(), cbor_value_end_recurse()
309 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700310CborError cbor_value_advance_fixed(CborValue *it)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700311{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700312 assert(it->type != CborInvalidType);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700313 assert(is_fixed_type(it->type));
314 if (!it->remaining)
315 return CborErrorAdvancePastEOF;
316 return advance_internal(it);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700317}
318
Thiago Macieira2312efd2015-05-06 16:07:48 -0700319/**
320 * Advances the CBOR value \a it by one element, skipping over containers.
321 * Unlike cbor_value_advance_fixed(), this function can be called on a CBOR
322 * value of any type. However, if the type is a container (map or array) or a
323 * string with a chunked payload, this function will not run in constant time
324 * and will recurse into itself (it will run on O(n) time for the number of
325 * elements or chunks and will use O(n) memory for the number of nested
326 * containers).
327 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700328 * \sa cbor_value_at_end(), cbor_value_advance_fixed(), cbor_value_begin_recurse(), cbor_value_end_recurse()
329 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700330CborError cbor_value_advance(CborValue *it)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700331{
332 assert(it->type != CborInvalidType);
333 if (!it->remaining)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700334 return CborErrorAdvancePastEOF;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700335 if (is_fixed_type(it->type))
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700336 return advance_internal(it);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700337
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700338 if (!cbor_value_is_container(it))
339 return cbor_value_copy_string(it, NULL, 0, it);
340
341 // map or array
342 CborError err;
343 CborValue recursed;
344 err = cbor_value_enter_container(it, &recursed);
345 if (err)
346 return err;
347 while (!cbor_value_at_end(&recursed)) {
348 err = cbor_value_advance(&recursed);
349 if (err)
350 return err;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700351 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700352 return cbor_value_leave_container(it, &recursed);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700353}
354
355/**
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700356 * \fn bool cbor_value_is_container(const CborValue *it)
357 *
Thiago Macieira2312efd2015-05-06 16:07:48 -0700358 * Returns true if the \a it value is a container and requires recursion in
359 * order to decode (maps and arrays), false otherwise.
360 */
Thiago Macieira54a0e102015-05-05 21:25:06 -0700361
Thiago Macieira2312efd2015-05-06 16:07:48 -0700362/**
363 * Creates a CborValue iterator pointing to the first element of the container
364 * represented by \a it and saves it in \a recursed. The \a it container object
365 * needs to be kept and passed again to cbor_value_leave_container() in order
366 * to continue iterating past this container.
367 *
368 * \sa cbor_value_is_container(), cbor_value_leave_container(), cbor_value_advance()
369 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700370CborError cbor_value_enter_container(const CborValue *it, CborValue *recursed)
Thiago Macieira54a0e102015-05-05 21:25:06 -0700371{
Thiago Macieira56d99832015-05-07 14:34:27 -0700372 CborError err;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700373 assert(cbor_value_is_container(it));
Thiago Macieira54a0e102015-05-05 21:25:06 -0700374 *recursed = *it;
Thiago Macieira56d99832015-05-07 14:34:27 -0700375
Thiago Macieira54a0e102015-05-05 21:25:06 -0700376 if (it->flags & CborIteratorFlag_UnknownLength) {
377 recursed->remaining = UINT32_MAX;
Thiago Macieira56d99832015-05-07 14:34:27 -0700378 ++recursed->ptr;
379 err = preparse_value(recursed);
380 if (err != CborErrorUnexpectedBreak)
381 return err;
382 // actually, break was expected here
383 // it's just an empty container
384 ++recursed->ptr;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700385 } else {
Thiago Macieira56d99832015-05-07 14:34:27 -0700386 uint64_t len;
387 err = extract_number(recursed->parser, &recursed->ptr, &len);
388 assert(err == CborNoError);
389 (void)err;
390
Thiago Macieira54a0e102015-05-05 21:25:06 -0700391 recursed->remaining = len;
392 if (recursed->remaining != len || len == UINT32_MAX)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700393 return CborErrorDataTooLarge;
Thiago Macieirace16f052015-05-07 23:14:25 -0700394 if (recursed->type == CborMapType) {
395 // maps have keys and values, so we need to multiply by 2
396 if (recursed->remaining > UINT32_MAX / 2)
397 return CborErrorDataTooLarge;
398 recursed->remaining *= 2;
399 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700400 if (len != 0)
401 return preparse_value(recursed);
Thiago Macieira54a0e102015-05-05 21:25:06 -0700402 }
Thiago Macieira56d99832015-05-07 14:34:27 -0700403
404 // the case of the empty container
405 recursed->type = CborInvalidType;
406 recursed->remaining = 0;
407 return CborNoError;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700408}
409
Thiago Macieira2312efd2015-05-06 16:07:48 -0700410/**
411 * Updates \a it to point to the next element after the container. The \a
Thiago Macieira56d99832015-05-07 14:34:27 -0700412 * recursed object needs to point to the element obtained either by advancing
413 * the last element of the container (via cbor_value_advance(),
414 * cbor_value_advance_fixed(), a nested cbor_value_leave_container(), or the \c
415 * next pointer from cbor_value_copy_string() or cbor_value_dup_string()).
Thiago Macieira2312efd2015-05-06 16:07:48 -0700416 *
417 * \sa cbor_value_enter_container(), cbor_value_at_end()
418 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700419CborError cbor_value_leave_container(CborValue *it, const CborValue *recursed)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700420{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700421 assert(cbor_value_is_container(it));
Thiago Macieira56d99832015-05-07 14:34:27 -0700422 assert(recursed->type == CborInvalidType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700423 it->ptr = recursed->ptr;
Thiago Macieira56d99832015-05-07 14:34:27 -0700424 return preparse_next_value(it);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700425}
426
Thiago Macieira2312efd2015-05-06 16:07:48 -0700427/**
428 * Calculates the length of the string in \a value and stores the result in \a
429 * len. This function is different from cbor_value_get_string_length() in that
430 * it calculates the length even for strings sent in chunks. For that reason,
431 * this function may not run in constant time (it will run in O(n) time on the
432 * number of chunks).
433 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700434 * \note On 32-bit platforms, this function will return error condition of \ref
435 * CborErrorDataTooLarge if the stream indicates a length that is too big to
436 * fit in 32-bit.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700437 *
438 * \sa cbor_value_get_string_length(), cbor_value_copy_string(), cbor_value_is_length_known()
439 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700440CborError cbor_value_calculate_string_length(const CborValue *value, size_t *len)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700441{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700442 return cbor_value_copy_string(value, NULL, len, NULL);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700443}
444
Thiago Macieira2312efd2015-05-06 16:07:48 -0700445/**
446 * Allocates memory for the string pointed by \a value and copies it into this
447 * buffer. The pointer to the buffer is stored in \a buffer and the number of
448 * bytes copied is stored in \a len (those variables must not be NULL).
449 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700450 * If \c malloc returns a NULL pointer, this function will return error
451 * condition \ref CborErrorOutOfMemory.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700452 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700453 * On success, \c{*buffer} will contain a valid pointer that must be freed by
454 * calling \c{free()}. This is the case even for zero-length strings.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700455 *
456 * The \a next pointer, if not null, will be updated to point to the next item
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700457 * after this string. If \a value points to the last item, then \a next will be
458 * invalid.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700459 *
460 * \note This function does not perform UTF-8 validation on the incoming text
461 * string.
462 *
463 * \sa cbor_value_copy_string()
464 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700465CborError cbor_value_dup_string(const CborValue *value, char **buffer, size_t *buflen, CborValue *next)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700466{
Thiago Macieira2312efd2015-05-06 16:07:48 -0700467 assert(buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700468 assert(buflen);
469 CborError err = cbor_value_calculate_string_length(value, buflen);
470 if (err)
471 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700472
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700473 ++*buflen;
474 *buffer = malloc(*buflen);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700475 if (!*buffer) {
Thiago Macieirac70169f2015-05-06 07:49:44 -0700476 // out of memory
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700477 return CborErrorOutOfMemory;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700478 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700479 err = cbor_value_copy_string(value, *buffer, buflen, next);
480 if (err) {
Thiago Macieira2312efd2015-05-06 16:07:48 -0700481 free(*buffer);
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700482 return err;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700483 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700484 return CborNoError;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700485}
486
487/**
488 * Copies the string pointed by \a value into the buffer provided at \a buffer
489 * of \a buflen bytes. If \a buffer is a NULL pointer, this function will not
490 * copy anything and will only update the \a next value.
491 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700492 * If the provided buffer length was too small, this function returns an error
493 * condition of \ref CborErrorOutOfMemory. If you need to calculate the length
494 * of the string in order to preallocate a buffer, use
Thiago Macieira2312efd2015-05-06 16:07:48 -0700495 * cbor_value_calculate_string_length().
496 *
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700497 * On success, this function sets the number of bytes copied to \c{*buflen}. If
498 * the buffer is large enough, this function will insert a null byte after the
499 * last copied byte, to facilitate manipulation of text strings. That byte is
500 * not included in the returned value of \c{*buflen}.
Thiago Macieira2312efd2015-05-06 16:07:48 -0700501 *
502 * The \a next pointer, if not null, will be updated to point to the next item
503 * after this string. If \a value points to the last item, then \a next will be
504 * invalid.
505 *
506 * \note This function does not perform UTF-8 validation on the incoming text
507 * string.
508 *
509 * \sa cbor_value_dup_string(), cbor_value_get_string_length(), cbor_value_calculate_string_length()
510 */
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700511CborError cbor_value_copy_string(const CborValue *value, char *buffer,
512 size_t *buflen, CborValue *next)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700513{
514 assert(cbor_value_is_byte_string(value) || cbor_value_is_text_string(value));
515
516 size_t total;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700517 CborError err;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700518 const char *ptr = value->ptr;
519 if (cbor_value_is_length_known(value)) {
520 // easy case: fixed length
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700521 err = extract_length(value->parser, &ptr, &total);
522 if (err)
523 return err;
Thiago Macieira7aca88d2015-05-07 22:26:13 -0700524 if (ptr + total > value->parser->end)
525 return CborErrorUnexpectedEOF;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700526 if (buffer) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700527 if (*buflen < total)
528 return CborErrorOutOfMemory;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700529 memcpy(buffer, ptr, total);
530 ptr += total;
531 }
532 } else {
533 // chunked
534 ++ptr;
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700535 total = 0;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700536 while (true) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700537 size_t chunkLen;
538 size_t newTotal;
539
Thiago Macieira2312efd2015-05-06 16:07:48 -0700540 if (ptr == value->parser->end)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700541 return CborErrorUnexpectedEOF;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700542
543 if (*ptr == (char)BreakByte) {
544 ++ptr;
545 break;
546 }
547
548 // is this the right type?
549 if ((*ptr & MajorTypeMask) != value->type)
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700550 return CborErrorIllegalType;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700551
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700552 err = extract_length(value->parser, &ptr, &chunkLen);
553 if (err)
554 return err;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700555
Thiago Macieira2312efd2015-05-06 16:07:48 -0700556 if (unlikely(!add_check_overflow(total, chunkLen, &newTotal)))
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700557 return CborErrorDataTooLarge;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700558
Thiago Macieira7aca88d2015-05-07 22:26:13 -0700559 if (ptr + chunkLen > value->parser->end)
560 return CborErrorUnexpectedEOF;
561
Thiago Macieira2312efd2015-05-06 16:07:48 -0700562 if (buffer) {
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700563 if (*buflen < newTotal)
564 return CborErrorOutOfMemory;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700565 memcpy(buffer + total, ptr, chunkLen);
566 }
567 ptr += chunkLen;
568 total = newTotal;
569 }
570 }
571
572 // is there enough room for the ending NUL byte?
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700573 if (buffer && *buflen > total)
Thiago Macieira2312efd2015-05-06 16:07:48 -0700574 buffer[total] = '\0';
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700575 *buflen = total;
Thiago Macieira2312efd2015-05-06 16:07:48 -0700576
577 if (next) {
578 *next = *value;
579 next->ptr = ptr;
Thiago Macieira7aca88d2015-05-07 22:26:13 -0700580 return preparse_next_value(next);
Thiago Macieira2312efd2015-05-06 16:07:48 -0700581 }
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700582 return CborNoError;
Thiago Macieirac70169f2015-05-06 07:49:44 -0700583}
584
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700585CborError cbor_value_get_half_float(const CborValue *value, void *result)
Thiago Macieirac70169f2015-05-06 07:49:44 -0700586{
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700587 assert(value->type == CborHalfFloatType);
Thiago Macieirac70169f2015-05-06 07:49:44 -0700588
589 // size has been computed already
590 uint16_t v = get16(value->ptr + 1);
591 memcpy(result, &v, sizeof(v));
Thiago Macieiraa43a4ef2015-05-06 20:25:18 -0700592 return CborNoError;
Thiago Macieira54a0e102015-05-05 21:25:06 -0700593}