1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2021 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 | #ifndef CBORINTERNAL_P_H |
26 | #define CBORINTERNAL_P_H |
27 | |
28 | #include "compilersupport_p.h" |
29 | |
30 | #ifndef CBOR_NO_FLOATING_POINT |
31 | # include <float.h> |
32 | # include <math.h> |
33 | #else |
34 | # ifndef CBOR_NO_HALF_FLOAT_TYPE |
35 | # define CBOR_NO_HALF_FLOAT_TYPE 1 |
36 | # endif |
37 | #endif |
38 | |
39 | #ifndef CBOR_NO_HALF_FLOAT_TYPE |
40 | # if defined(__F16C__) || defined(__AVX2__) |
41 | # include <immintrin.h> |
42 | static inline unsigned short encode_half(float val) |
43 | { |
44 | __m128i m = _mm_cvtps_ph(_mm_set_ss(val), _MM_FROUND_CUR_DIRECTION); |
45 | return _mm_extract_epi16(m, 0); |
46 | } |
47 | static inline float decode_half(unsigned short half) |
48 | { |
49 | __m128i m = _mm_cvtsi32_si128(half); |
50 | return _mm_cvtss_f32(_mm_cvtph_ps(m)); |
51 | } |
52 | # else |
53 | /* software implementation of float-to-fp16 conversions */ |
54 | static inline unsigned short encode_half(double val) |
55 | { |
56 | uint64_t v; |
57 | int sign, exp, mant; |
58 | memcpy(dest: &v, src: &val, n: sizeof(v)); |
59 | sign = v >> 63 << 15; |
60 | exp = (v >> 52) & 0x7ff; |
61 | mant = v << 12 >> 12 >> (53-11); /* keep only the 11 most significant bits of the mantissa */ |
62 | exp -= 1023; |
63 | if (exp == 1024) { |
64 | /* infinity or NaN */ |
65 | exp = 16; |
66 | mant >>= 1; |
67 | } else if (exp >= 16) { |
68 | /* overflow, as largest number */ |
69 | exp = 15; |
70 | mant = 1023; |
71 | } else if (exp >= -14) { |
72 | /* regular normal */ |
73 | } else if (exp >= -24) { |
74 | /* subnormal */ |
75 | mant |= 1024; |
76 | mant >>= -(exp + 14); |
77 | exp = -15; |
78 | } else { |
79 | /* underflow, make zero */ |
80 | return 0; |
81 | } |
82 | |
83 | /* safe cast here as bit operations above guarantee not to overflow */ |
84 | return (unsigned short)(sign | ((exp + 15) << 10) | mant); |
85 | } |
86 | |
87 | /* this function was copied & adapted from RFC 7049 Appendix D */ |
88 | static inline double decode_half(unsigned short half) |
89 | { |
90 | int exp = (half >> 10) & 0x1f; |
91 | int mant = half & 0x3ff; |
92 | double val; |
93 | if (exp == 0) val = ldexp(x: mant, exp: -24); |
94 | else if (exp != 31) val = ldexp(x: mant + 1024, exp: exp - 25); |
95 | else val = mant == 0 ? INFINITY : NAN; |
96 | return half & 0x8000 ? -val : val; |
97 | } |
98 | # endif |
99 | #endif /* CBOR_NO_HALF_FLOAT_TYPE */ |
100 | |
101 | #ifndef CBOR_INTERNAL_API |
102 | # define CBOR_INTERNAL_API |
103 | #endif |
104 | |
105 | #ifndef CBOR_PARSER_MAX_RECURSIONS |
106 | # define CBOR_PARSER_MAX_RECURSIONS 1024 |
107 | #endif |
108 | |
109 | #ifndef CBOR_ENCODER_WRITER_CONTROL |
110 | # define CBOR_ENCODER_WRITER_CONTROL 0 |
111 | #endif |
112 | #ifndef CBOR_PARSER_READER_CONTROL |
113 | # define CBOR_PARSER_READER_CONTROL 0 |
114 | #endif |
115 | |
116 | /* |
117 | * CBOR Major types |
118 | * Encoded in the high 3 bits of the descriptor byte |
119 | * See http://tools.ietf.org/html/rfc7049#section-2.1 |
120 | */ |
121 | typedef enum CborMajorTypes { |
122 | UnsignedIntegerType = 0U, |
123 | NegativeIntegerType = 1U, |
124 | ByteStringType = 2U, |
125 | TextStringType = 3U, |
126 | ArrayType = 4U, |
127 | MapType = 5U, /* a.k.a. object */ |
128 | TagType = 6U, |
129 | SimpleTypesType = 7U |
130 | } CborMajorTypes; |
131 | |
132 | /* |
133 | * CBOR simple and floating point types |
134 | * Encoded in the low 8 bits of the descriptor byte when the |
135 | * Major Type is 7. |
136 | */ |
137 | typedef enum CborSimpleTypes { |
138 | FalseValue = 20, |
139 | TrueValue = 21, |
140 | NullValue = 22, |
141 | UndefinedValue = 23, |
142 | SimpleTypeInNextByte = 24, /* not really a simple type */ |
143 | HalfPrecisionFloat = 25, /* ditto */ |
144 | SinglePrecisionFloat = 26, /* ditto */ |
145 | DoublePrecisionFloat = 27, /* ditto */ |
146 | Break = 31 |
147 | } CborSimpleTypes; |
148 | |
149 | enum { |
150 | SmallValueBitLength = 5U, |
151 | SmallValueMask = (1U << SmallValueBitLength) - 1, /* 31 */ |
152 | Value8Bit = 24U, |
153 | Value16Bit = 25U, |
154 | Value32Bit = 26U, |
155 | Value64Bit = 27U, |
156 | IndefiniteLength = 31U, |
157 | |
158 | MajorTypeShift = SmallValueBitLength, |
159 | MajorTypeMask = (int) (~0U << MajorTypeShift), |
160 | |
161 | BreakByte = (unsigned)Break | (SimpleTypesType << MajorTypeShift) |
162 | }; |
163 | |
164 | static inline void copy_current_position(CborValue *dst, const CborValue *src) |
165 | { |
166 | /* This "if" is here for pedantry only: the two branches should perform |
167 | * the same memory operation. */ |
168 | if (src->parser->flags & CborParserFlag_ExternalSource) |
169 | dst->source.token = src->source.token; |
170 | else |
171 | dst->source.ptr = src->source.ptr; |
172 | } |
173 | |
174 | static inline bool can_read_bytes(const CborValue *it, size_t n) |
175 | { |
176 | if (CBOR_PARSER_READER_CONTROL >= 0) { |
177 | if (it->parser->flags & CborParserFlag_ExternalSource || CBOR_PARSER_READER_CONTROL != 0) { |
178 | #ifdef CBOR_PARSER_CAN_READ_BYTES_FUNCTION |
179 | return CBOR_PARSER_CAN_READ_BYTES_FUNCTION(it->source.token, n); |
180 | #else |
181 | return it->parser->source.ops->can_read_bytes(it->source.token, n); |
182 | #endif |
183 | } |
184 | } |
185 | |
186 | /* Convert the pointer subtraction to size_t since end >= ptr |
187 | * (this prevents issues with (ptrdiff_t)n becoming negative). |
188 | */ |
189 | return (size_t)(it->parser->source.end - it->source.ptr) >= n; |
190 | } |
191 | |
192 | static inline void advance_bytes(CborValue *it, size_t n) |
193 | { |
194 | if (CBOR_PARSER_READER_CONTROL >= 0) { |
195 | if (it->parser->flags & CborParserFlag_ExternalSource || CBOR_PARSER_READER_CONTROL != 0) { |
196 | #ifdef CBOR_PARSER_ADVANCE_BYTES_FUNCTION |
197 | CBOR_PARSER_ADVANCE_BYTES_FUNCTION(it->source.token, n); |
198 | #else |
199 | it->parser->source.ops->advance_bytes(it->source.token, n); |
200 | #endif |
201 | return; |
202 | } |
203 | } |
204 | |
205 | it->source.ptr += n; |
206 | } |
207 | |
208 | static inline CborError transfer_string(CborValue *it, const void **ptr, size_t offset, size_t len) |
209 | { |
210 | if (CBOR_PARSER_READER_CONTROL >= 0) { |
211 | if (it->parser->flags & CborParserFlag_ExternalSource || CBOR_PARSER_READER_CONTROL != 0) { |
212 | #ifdef CBOR_PARSER_TRANSFER_STRING_FUNCTION |
213 | return CBOR_PARSER_TRANSFER_STRING_FUNCTION(it->source.token, ptr, offset, len); |
214 | #else |
215 | return it->parser->source.ops->transfer_string(it->source.token, ptr, offset, len); |
216 | #endif |
217 | } |
218 | } |
219 | |
220 | it->source.ptr += offset; |
221 | if (can_read_bytes(it, n: len)) { |
222 | *CONST_CAST(const void **, ptr) = it->source.ptr; |
223 | it->source.ptr += len; |
224 | return CborNoError; |
225 | } |
226 | return CborErrorUnexpectedEOF; |
227 | } |
228 | |
229 | static inline void *read_bytes_unchecked(const CborValue *it, void *dst, size_t offset, size_t n) |
230 | { |
231 | if (CBOR_PARSER_READER_CONTROL >= 0) { |
232 | if (it->parser->flags & CborParserFlag_ExternalSource || CBOR_PARSER_READER_CONTROL != 0) { |
233 | #ifdef CBOR_PARSER_READ_BYTES_FUNCTION |
234 | return CBOR_PARSER_READ_BYTES_FUNCTION(it->source.token, dst, offset, n); |
235 | #else |
236 | return it->parser->source.ops->read_bytes(it->source.token, dst, offset, n); |
237 | #endif |
238 | } |
239 | } |
240 | |
241 | return memcpy(dest: dst, src: it->source.ptr + offset, n: n); |
242 | } |
243 | |
244 | #ifdef __GNUC__ |
245 | __attribute__((warn_unused_result)) |
246 | #endif |
247 | static inline void *read_bytes(const CborValue *it, void *dst, size_t offset, size_t n) |
248 | { |
249 | if (can_read_bytes(it, n: offset + n)) |
250 | return read_bytes_unchecked(it, dst, offset, n); |
251 | return NULL; |
252 | } |
253 | |
254 | static inline uint16_t read_uint8(const CborValue *it, size_t offset) |
255 | { |
256 | uint8_t result; |
257 | read_bytes_unchecked(it, dst: &result, offset, n: sizeof(result)); |
258 | return result; |
259 | } |
260 | |
261 | static inline uint16_t read_uint16(const CborValue *it, size_t offset) |
262 | { |
263 | uint16_t result; |
264 | read_bytes_unchecked(it, dst: &result, offset, n: sizeof(result)); |
265 | return cbor_ntohs(result); |
266 | } |
267 | |
268 | static inline uint32_t read_uint32(const CborValue *it, size_t offset) |
269 | { |
270 | uint32_t result; |
271 | read_bytes_unchecked(it, dst: &result, offset, n: sizeof(result)); |
272 | return cbor_ntohl(result); |
273 | } |
274 | |
275 | static inline uint64_t read_uint64(const CborValue *it, size_t offset) |
276 | { |
277 | uint64_t result; |
278 | read_bytes_unchecked(it, dst: &result, offset, n: sizeof(result)); |
279 | return cbor_ntohll(result); |
280 | } |
281 | |
282 | static inline CborError (const CborValue *it, uint64_t *value, size_t *bytesUsed) |
283 | { |
284 | uint8_t descriptor; |
285 | size_t bytesNeeded = 0; |
286 | |
287 | /* We've already verified that there's at least one byte to be read */ |
288 | read_bytes_unchecked(it, dst: &descriptor, offset: 0, n: 1); |
289 | descriptor &= SmallValueMask; |
290 | if (descriptor < Value8Bit) { |
291 | *value = descriptor; |
292 | } else if (unlikely(descriptor > Value64Bit)) { |
293 | return CborErrorIllegalNumber; |
294 | } else { |
295 | bytesNeeded = (size_t)(1 << (descriptor - Value8Bit)); |
296 | if (!can_read_bytes(it, n: 1 + bytesNeeded)) |
297 | return CborErrorUnexpectedEOF; |
298 | if (descriptor <= Value16Bit) { |
299 | if (descriptor == Value16Bit) |
300 | *value = read_uint16(it, offset: 1); |
301 | else |
302 | *value = read_uint8(it, offset: 1); |
303 | } else { |
304 | if (descriptor == Value32Bit) |
305 | *value = read_uint32(it, offset: 1); |
306 | else |
307 | *value = read_uint64(it, offset: 1); |
308 | } |
309 | } |
310 | |
311 | if (bytesUsed) |
312 | *bytesUsed = bytesNeeded; |
313 | return CborNoError; |
314 | } |
315 | |
316 | #endif /* CBORINTERNAL_P_H */ |
317 | |