blob: e39bce9304bf8a61201104d3e3e9fe051d34a736 [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>
32#include <string.h>
33
34/**
35 * \typedef CborValue
36 * This type contains one value parsed from the CBOR stream.
37 *
38 * To get the actual type, use cbor_value_get_type(). Then extract the value
39 * using one of the corresponding functions: cbor_value_get_boolean(), cbor_value_get_int64(),
40 * cbor_value_get_int(), cbor_value_copy_string(), cbor_value_get_array(), cbor_value_get_map(),
41 * cbor_value_get_double(), cbor_value_get_float().
42 *
43 * In C++ and C11 modes, you can additionally use the cbor_value_get_integer()
44 * and cbor_value_get_floating_point() generic functions.
45 *
46 * \omit
47 * Implementation details: the CborValue contains these fields:
48 * \list
49 * \li ptr: pointer to the actual data
50 * \li flags: flags from the decoder
51 * \li extra: partially decoded integer value
52 * \li remaining: remaining items in this collection after this item or UINT32_MAX if length is unknown
53 * \endlist
54 * \endomit
55 */
56
57static bool makeError(CborParser *parser, CborParserError error, uint64_t addend)
58{
59 (void)addend;
60 parser->error = error;
61 return false;
62}
63#ifdef CBOR_PARSER_NO_DETAILED_ERROR
64// This way, the compiler should eliminate all error settings by dead code elimination
65# define makeError(parser, err, addend) makeError(parser, (err) * 0 + CborErrorInternalError, addend)
66#endif
67
68static inline uint16_t get16(const char *ptr)
69{
70 uint16_t result;
71 memcpy(&result, ptr, sizeof(result));
72 return be16toh(result);
73}
74
75static inline uint32_t get32(const char *ptr)
76{
77 uint32_t result;
78 memcpy(&result, ptr, sizeof(result));
79 return be32toh(result);
80}
81
82static inline uint64_t get64(const char *ptr)
83{
84 uint64_t result;
85 memcpy(&result, ptr, sizeof(result));
86 return be64toh(result);
87}
88
89static void preparse_value(CborValue *it)
90{
91 // are we at the end?
92 CborParser *parser = it->parser;
93 if (it->ptr == parser->end)
94 goto error_eof;
95
96 uint8_t descriptor = *it->ptr;
97 it->type = descriptor & MajorTypeMask;
98 it->flags = 0;
99 descriptor &= SmallValueMask;
100 it->extra = descriptor;
101
102 switch ((CborMajorTypes)(it->type >> MajorTypeShift)) {
103 case NegativeIntegerType:
104 it->flags |= CborIteratorFlag_NegativeInteger;
105 // fall through
106 case UnsignedIntegerType:
107 case TagType:
108 break;
109
110 case SimpleTypesType:
111 switch (descriptor) {
112 case FalseValue:
113 it->extra = false;
114 // fall through
115 case TrueValue:
116 case NullValue:
117 case UndefinedValue:
118 case HalfPrecisionFloat:
119 case SinglePrecisionFloat:
120 case DoublePrecisionFloat:
121 it->type = descriptor;
122 break;
123
124 case SimpleTypeInNextByte:
125 if (it->ptr + 1 > parser->end)
126 goto error_eof;
127 it->extra = it->ptr[1];
128#ifndef CBOR_PARSER_NO_STRICT_CHECKS
129 if (it->extra < 32) {
130 makeError(parser, CborErrorIllegalSimpleType, it->extra);
131 goto error;
132 }
133#endif
134 case 28:
135 case 29:
136 case 30:
137 makeError(parser, CborErrorUnknownType, *it->ptr);
138 goto error;
139
140 case Break:
141 makeError(parser, CborErrorUnexpectedBreak, 0);
142 goto error;
143 }
144 break;
145
146 case ByteStringType:
147 case TextStringType:
148 case ArrayType:
149 case MapType:
150 if (descriptor == IndefiniteLength)
151 it->flags |= CborIteratorFlag_UnknownLength;
152 break;
153 }
154
155 // try to decode up to 16 bits
156 if (descriptor < Value8Bit)
157 return;
158 if (unlikely(descriptor > Value64Bit))
159 goto illegal_number_error;
160
161 size_t bytesNeeded = 1 << (descriptor - Value8Bit);
162 if (it->ptr + 1 + bytesNeeded > parser->end)
163 goto error_eof;
164 if (descriptor == Value8Bit) {
165 it->extra = it->ptr[1];
166 return;
167 }
168 if (descriptor == Value16Bit) {
169 it->extra = get16(it->ptr + 1);
170 return;
171 }
172 // Value32Bit or Value64Bit
173 it->flags |= CborIteratorFlag_IntegerValueTooLarge;
174 return;
175
176illegal_number_error:
177 makeError(parser, CborErrorIllegalNumber, it->ptr[1]);
178 goto error;
179
180error_eof:
181 makeError(parser, CborErrorUnexpectedEOF, 0);
182error:
183 it->type = CborInvalidType;
184 return;
185}
186
187uint64_t _cbor_value_decode_int64_internal(const CborValue *value)
188{
189 assert(value->flags & CborIteratorFlag_IntegerValueTooLarge);
190 if ((*value->ptr & SmallValueMask) == Value32Bit)
191 return get32(value->ptr + 1);
192
193 assert((*value->ptr & SmallValueMask) == Value64Bit);
194 return get64(value->ptr + 1);
195}
196
197/**
198 * Initializes the CBOR parser for parsing \a size bytes beginning at \a
199 * buffer. Parsing will use flags set in \a flags. The iterator to the first
200 * element is returned in \a it.
201 */
202void cbor_parser_init(const char *buffer, size_t size, int flags, CborParser *parser, CborValue *it)
203{
204 memset(parser, 0, sizeof(*parser));
205 parser->end = buffer + size;
206 parser->error = CborNoError;
207 parser->flags = flags;
208 it->parser = parser;
209 it->ptr = buffer;
210 it->remaining = 1; // there's one type altogether, usually an array or map
211 preparse_value(it);
212}
213
214static bool is_fixed_type(uint8_t type)
215{
216 return type == CborIntegerType || type == CborTagType || type == CborSimpleType;
217}
218
219static bool advance_internal(CborValue *it)
220{
221 unsigned size = 1 << (*it->ptr - Value8Bit);
222 if (it->ptr + size > it->parser->end)
223 return makeError(it->parser, CborErrorUnexpectedEOF, 0);
224
225 it->ptr += size;
226 if (it->remaining == UINT32_MAX && *it->ptr == (char)BreakByte) {
227 // end of map or array
228 // ### FIXME: was it a map or array?
229 it->remaining = 0;
230 return true;
231 }
232
233 if (it->remaining != UINT32_MAX)
234 --it->remaining;
235 preparse_value(it);
236 return true;
237}
238
239bool cbor_value_advance_fixed(CborValue *it)
240{
241 assert(is_fixed_type(it->type));
242 return it->remaining && advance_internal(it);
243}
244
245bool cbor_value_is_recursive(const CborValue *it)
246{
247 return it->type == CborArrayType || it->type == CborMapType;
248}
249
250bool cbor_value_begin_recurse(const CborValue *it, CborValue *recursed)
251{
252 assert(cbor_value_is_recursive(it));
253 *recursed = *it;
254 if (it->flags & CborIteratorFlag_UnknownLength) {
255 recursed->remaining = UINT32_MAX;
256 } else {
257 uint64_t len = _cbor_value_extract_int64_helper(it);
258 recursed->remaining = len;
259 if (recursed->remaining != len || len == UINT32_MAX)
260 return makeError(it->parser, CborErrorDataTooLarge, len);
261 }
262 if (!advance_internal(recursed))
263 return false;
264 return true;
265}