Line data Source code
1 : /**
2 : Copyright (c) 2016-2022 Roman Katuntsev <sbkarr@stappler.org>
3 : Copyright (c) 2023 Stappler LLC <admin@stappler.dev>
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 : #ifndef STAPPLER_DATA_SPDATACBOR_H_
25 : #define STAPPLER_DATA_SPDATACBOR_H_
26 :
27 : #include "SPBytesView.h"
28 : #include "SPHalfFloat.h"
29 :
30 : namespace STAPPLER_VERSIONIZED stappler::data::cbor {
31 :
32 : enum class MajorType : uint8_t {
33 : Unsigned = 0,
34 : Negative = 1,
35 : ByteString = 2,
36 : CharString = 3,
37 : Array = 4,
38 : Map = 5,
39 : Tag = 6,
40 : Simple = 7
41 : };
42 :
43 : enum class SimpleValue : uint8_t {
44 : False = 20,
45 : True = 21,
46 : Null = 22,
47 : Undefined = 23,
48 : };
49 :
50 : enum class Flags : uint8_t {
51 : Null = 0,
52 : Interrupt = 0xFF,
53 :
54 : MajorTypeShift = 5, // bitshift for major type id
55 :
56 : MajorTypeMask = 7, // mask for major type id
57 : MajorTypeMaskEncoded = 7 << 5, // mask for major type id
58 :
59 : AdditionalInfoMask = 31, // mask for additional info
60 :
61 : MaxAdditionalNumber = 24,
62 : AdditionalNumber8Bit = 24,
63 : AdditionalNumber16Bit = 25,
64 : AdditionalNumber32Bit = 26,
65 : AdditionalNumber64Bit = 27,
66 :
67 : Simple8Bit = 24,
68 : AdditionalFloat16Bit = 25,
69 : AdditionalFloat32Bit = 26,
70 : AdditionalFloat64Bit = 27,
71 :
72 : Unassigned1 = 28,
73 : Unassigned2 = 29,
74 : Unassigned3 = 30,
75 :
76 : UndefinedLength = 31,
77 : };
78 :
79 : enum class MajorTypeEncoded : uint8_t {
80 : Unsigned = toInt(MajorType::Unsigned) << toInt(Flags::MajorTypeShift),
81 : Negative = toInt(MajorType::Negative) << toInt(Flags::MajorTypeShift),
82 : ByteString = toInt(MajorType::ByteString) << toInt(Flags::MajorTypeShift),
83 : CharString = toInt(MajorType::CharString) << toInt(Flags::MajorTypeShift),
84 : Array = toInt(MajorType::Array) << toInt(Flags::MajorTypeShift),
85 : Map = toInt(MajorType::Map) << toInt(Flags::MajorTypeShift),
86 : Tag = toInt(MajorType::Tag) << toInt(Flags::MajorTypeShift),
87 : Simple = toInt(MajorType::Simple) << toInt(Flags::MajorTypeShift)
88 : };
89 :
90 : enum class Tag : uint16_t {
91 : DateTime = 0, // string - Standard date/time string
92 : EpochTime = 1, // multiple - Epoch-based date/time
93 : PositiveBignum = 2, // byte string
94 : NegativeBignum = 3, // byte string
95 : DecimalFraction = 4, // array - Decimal fraction;
96 : BigFloat = 5, // array
97 : /* 6-20 - Unassigned */
98 : ExpectedBase64Url = 21, // multiple - Expected conversion to base64url encoding;
99 : ExpectedBase64 = 22, // multiple - Expected conversion to base64 encoding;
100 : ExpectedBase16 = 23, // multiple - Expected conversion to base16 encoding;
101 : EmbeddedCbor = 24, // byte string - Encoded CBOR data item;
102 :
103 : StringReference = 25, // unsigned integer - reference the nth previously seen string
104 : // [http://cbor.schmorp.de/stringref][Marc_A._Lehmann]
105 :
106 : SerializedPerl = 26, // array - Serialised Perl object with classname and constructor arguments
107 : // [http://cbor.schmorp.de/perl-object][Marc_A._Lehmann]
108 :
109 : SerializedObject = 27, // array - Serialised language-independent object with type name and constructor arguments
110 : // [http://cbor.schmorp.de/generic-object][Marc_A._Lehmann]
111 :
112 : SharedValue = 28, // multiple - mark value as (potentially) shared
113 : // [http://cbor.schmorp.de/value-sharing][Marc_A._Lehmann]
114 :
115 : ValueReference = 29, // unsigned integer - reference nth marked value
116 : // [http://cbor.schmorp.de/value-sharing][Marc_A._Lehmann]
117 :
118 : RationalNumber = 30, // array - Rational number
119 : // [http://peteroupc.github.io/CBOR/rational.html][Peter_Occil]
120 :
121 : /* 31 - Unassigned */
122 : HintHintUri = 32, // UTF-8 string;
123 : HintBase64Url = 33, // UTF-8 string;
124 : HintBase64 = 34, // UTF-8 string;
125 : HintRegularExpression = 35, // UTF-8 string;
126 : HintMimeMessage = 36, // UTF-8 string;
127 :
128 : BinaryUuid = 37, // byte string - Binary UUID [RFC4122] section 4.1.2;
129 : // [https://github.com/lucas-clemente/cbor-specs/blob/master/uuid.md][Lucas_Clemente]
130 :
131 : LanguageTaggedString = 38, // byte string - [http://peteroupc.github.io/CBOR/langtags.html][Peter_Occil]
132 : Identifier = 39, // multiple - [https://github.com/lucas-clemente/cbor-specs/blob/master/id.md][Lucas_Clemente]
133 :
134 : /* 40-255 - Unassigned */
135 :
136 : StringMark = 256, // multiple - mark value as having string references
137 : // [http://cbor.schmorp.de/stringref][Marc_A._Lehmann]
138 :
139 : BinaryMimeMessage = 257, // byte string - Binary MIME message
140 : // [http://peteroupc.github.io/CBOR/binarymime.html][Peter_Occil]
141 :
142 : /* 258-263 - Unassigned */
143 : DecimalFractionFixed = 264, // array - Decimal fraction with arbitrary exponent
144 : // [http://peteroupc.github.io/CBOR/bigfrac.html][Peter_Occil]
145 :
146 : BigFloatFixed = 265, // array - Bigfloat with arbitrary exponent
147 : // [http://peteroupc.github.io/CBOR/bigfrac.html][Peter_Occil]
148 :
149 : /* 266-22097 - Unassigned */
150 : HintIndirection = 22098, // multiple - hint that indicates an additional level of indirection
151 : // [http://cbor.schmorp.de/indirection][Marc_A._Lehmann]
152 :
153 : /* 22099-55798 - Unassigned */
154 :
155 : CborMagick = 55799, // multiple - Self-describe CBOR;
156 : /* 55800-18446744073709551615 - Unassigned */
157 : };
158 :
159 : constexpr MajorTypeEncoded operator << (MajorType t, Flags f) {
160 : return MajorTypeEncoded(toInt(t) << toInt(f));
161 : }
162 :
163 : constexpr bool operator == (uint8_t v, MajorTypeEncoded enc) {
164 : return (v & toInt(Flags::MajorTypeMaskEncoded)) == toInt(enc);
165 : }
166 :
167 : constexpr bool operator == (uint8_t v, MajorType t) {
168 : return (v & toInt(Flags::MajorTypeMaskEncoded)) == (t << Flags::MajorTypeShift);
169 : }
170 :
171 : constexpr bool operator == (uint8_t v, Flags f) {
172 : return (v & toInt(Flags::AdditionalInfoMask)) == (toInt(f));
173 : }
174 :
175 : constexpr MajorType type(uint8_t v) {
176 : switch (MajorTypeEncoded(v & 0b11100000)) {
177 : case MajorTypeEncoded::Unsigned: return MajorType::Unsigned; break;
178 : case MajorTypeEncoded::Negative: return MajorType::Negative; break;
179 : case MajorTypeEncoded::ByteString: return MajorType::ByteString; break;
180 : case MajorTypeEncoded::CharString: return MajorType::CharString; break;
181 : case MajorTypeEncoded::Array: return MajorType::Array; break;
182 : case MajorTypeEncoded::Map: return MajorType::Map; break;
183 : case MajorTypeEncoded::Tag: return MajorType::Tag; break;
184 : case MajorTypeEncoded::Simple: return MajorType::Simple; break;
185 : }
186 : return MajorType::Unsigned;
187 : }
188 :
189 : constexpr uint8_t data(uint8_t v) {
190 : return v & toInt(Flags::AdditionalInfoMask);
191 : }
192 :
193 : constexpr Flags flags(uint8_t v) {
194 : return Flags(v & toInt(Flags::AdditionalInfoMask));
195 : }
196 :
197 : // writer: some class with implementation of:
198 : // emplace(uint8_t byte)
199 : // emplace(uint8_t *bytes, size_t nbytes)
200 :
201 : template <class Writer>
202 16600 : inline void _writeId(Writer &w) {
203 : // write CBOR id ( 0xd9d9f7 )
204 16600 : w.emplace(0xd9);
205 16600 : w.emplace(0xd9);
206 16600 : w.emplace(0xf7);
207 16600 : }
208 :
209 : template <class Writer, class T>
210 4959661 : inline void _writeNumeric(Writer &w, T value, MajorTypeEncoded m, Flags f) {
211 4959661 : value = byteorder::HostToNetwork(value);
212 4959661 : w.emplace(toInt(m) | toInt(f));
213 4959661 : w.emplace((uint8_t *)&value, sizeof(T));
214 4959661 : }
215 :
216 : template <class Writer>
217 22549456 : inline void _writeInt(Writer &w, uint64_t value, MajorTypeEncoded type) {
218 22549456 : if (value < toInt(Flags::MaxAdditionalNumber)) {
219 19335379 : w.emplace(toInt(type) | (uint8_t)value);
220 3214077 : } else if (value <= maxOf<uint8_t>()) {
221 1539684 : w.emplace(toInt(type) | toInt(Flags::AdditionalNumber8Bit));
222 1539684 : w.emplace((uint8_t)value);
223 1674393 : } else if (value <= maxOf<uint16_t>()) {
224 1177843 : _writeNumeric(w, (uint16_t)value, type, Flags::AdditionalNumber16Bit);
225 496550 : } else if (value <= maxOf<uint32_t>()) {
226 496325 : _writeNumeric(w, (uint32_t)value, type, Flags::AdditionalNumber32Bit);
227 225 : } else if (value <= maxOf<uint64_t>()) {
228 225 : _writeNumeric(w, (uint64_t)value, type, Flags::AdditionalNumber64Bit);
229 : }
230 22549456 : }
231 :
232 : template <class Writer>
233 0 : inline void _writeFloatNaN(Writer &w) {
234 0 : _writeNumeric(w, halffloat::nan(), MajorTypeEncoded::Simple, Flags::AdditionalFloat16Bit); // write nan from IEEE 754
235 0 : }
236 :
237 : template <class Writer>
238 0 : inline void _writeFloatPositiveInf(Writer &w) {
239 0 : _writeNumeric(w, halffloat::posinf(), MajorTypeEncoded::Simple, Flags::AdditionalFloat16Bit); // write +inf from IEEE 754
240 0 : }
241 :
242 : template <class Writer>
243 0 : inline void _writeFloatNegativeInf(Writer &w) {
244 0 : _writeNumeric(w, halffloat::neginf(), MajorTypeEncoded::Simple, Flags::AdditionalFloat16Bit); // write -inf from IEEE 754
245 0 : }
246 :
247 : template <class Writer>
248 857168 : inline void _writeFloat16(Writer &w, uint16_t value) {
249 857168 : _writeNumeric(w, value, MajorTypeEncoded::Simple, Flags::AdditionalFloat16Bit);
250 857168 : }
251 :
252 : template <class Writer>
253 2428100 : inline void _writeFloat32(Writer &w, float value) {
254 2428100 : _writeNumeric(w, value, MajorTypeEncoded::Simple, Flags::AdditionalFloat32Bit);
255 2428100 : }
256 :
257 : template <class Writer>
258 0 : inline void _writeFloat64(Writer &w, double value) {
259 0 : _writeNumeric(w, value, MajorTypeEncoded::Simple, Flags::AdditionalFloat64Bit);
260 0 : }
261 :
262 : template <class Writer>
263 497700 : inline void _writeArrayStart(Writer &w, size_t len) {
264 497700 : _writeInt(w, len, MajorTypeEncoded::Array);
265 497700 : }
266 :
267 : template <class Writer>
268 1377209 : inline void _writeMapStart(Writer &w, size_t len) {
269 1377209 : _writeInt(w, len, MajorTypeEncoded::Map);
270 1377209 : }
271 :
272 : template <class Writer>
273 3825 : inline void _writeNull(Writer &w, nullptr_t = nullptr) {
274 3825 : w.emplace(toInt(MajorTypeEncoded::Simple) | toInt(SimpleValue::Null));
275 3825 : }
276 :
277 : template <class Writer>
278 921250 : inline void _writeBool(Writer &w, bool value) {
279 921250 : w.emplace(toInt(MajorTypeEncoded::Simple) | toInt(value ? SimpleValue::True : SimpleValue::False));
280 921250 : }
281 :
282 : template <class Writer>
283 6755000 : inline void _writeInt(Writer &w, int64_t value) {
284 6755000 : if (value == 0) {
285 330575 : w.emplace(toInt(MajorTypeEncoded::Unsigned));
286 : } else {
287 6424425 : if (value > 0) {
288 6418975 : _writeInt(w, (uint64_t)value, MajorTypeEncoded::Unsigned);
289 : } else {
290 5450 : _writeInt(w, (uint64_t)std::abs(value + 1), MajorTypeEncoded::Negative);
291 : }
292 : }
293 6755000 : }
294 :
295 : template <class Writer>
296 3285268 : inline void _writeFloat(Writer &w, double value) {
297 : // calculate optimal size to store value
298 : // some code from https://github.com/cabo/cn-cbor/blob/master/src/cn-encoder.c
299 3285268 : float fvalue = value;
300 3285268 : if (isnan(value)) { // NaN -- we always write a half NaN
301 0 : _writeFloatNaN(w);
302 3285268 : } else if (value == NumericLimits<double>::infinity()) {
303 0 : _writeFloatPositiveInf(w);
304 3285268 : } else if (value == - NumericLimits<double>::infinity()) {
305 0 : _writeFloatNegativeInf(w);
306 3285268 : } else if (fvalue == value) { // 32 bits is enough and we aren't NaN
307 : union {
308 : float f;
309 : uint32_t u;
310 : } u32;
311 :
312 3285268 : u32.f = fvalue;
313 3285268 : if ((u32.u & 0x1FFF) == 0) { // worth trying half
314 857168 : int s16 = (u32.u >> 16) & 0x8000;
315 857168 : int exp = (u32.u >> 23) & 0xff;
316 857168 : int mant = u32.u & 0x7fffff;
317 857168 : if (exp == 0 && mant == 0) {
318 : ; // 0.0, -0.0
319 857168 : } else if (exp >= 113 && exp <= 142) { // normalized
320 857168 : s16 += ((exp - 112) << 10) + (mant >> 13);
321 0 : } else if (exp >= 103 && exp < 113) { // denorm, exp16 = 0
322 0 : if (mant & ((1 << (126 - exp)) - 1)) {
323 0 : _writeFloat32(w, fvalue);
324 0 : return;
325 : }
326 0 : s16 += ((mant + 0x800000) >> (126 - exp));
327 0 : } else if (exp == 255 && mant == 0) { // Inf
328 0 : s16 += 0x7c00;
329 : } else {
330 0 : _writeFloat32(w, fvalue);
331 0 : return;
332 : }
333 :
334 857168 : _writeFloat16(w, s16);
335 : } else {
336 2428100 : _writeFloat32(w, fvalue);
337 : }
338 : } else {
339 0 : _writeFloat64(w, value);
340 : }
341 : }
342 :
343 : template <class Writer>
344 13824029 : inline void _writeString(Writer &w, const StringView &str) {
345 13824029 : auto size = str.size();
346 13824029 : _writeInt(w, size, MajorTypeEncoded::CharString);
347 13824029 : w.emplace((uint8_t *)str.data(), size);
348 13824029 : }
349 :
350 : template <class Writer>
351 426093 : inline void _writeBytes(Writer &w, const BytesViewTemplate<Endian::Network> &data) {
352 426093 : auto size = data.size();
353 426093 : _writeInt(w, size, MajorTypeEncoded::ByteString);
354 426093 : w.emplace(data.data(), size);
355 426093 : }
356 :
357 : template <class Writer>
358 6471200 : inline void _writeNumber(Writer &w, float n) {
359 6471200 : if (n == roundf(n)) {
360 3613350 : _writeInt(w, int64_t(n));
361 : } else {
362 2857850 : _writeFloat(w, n);
363 : }
364 6471200 : };
365 :
366 56074458 : inline uint64_t _readIntValue(BytesViewTemplate<Endian::Network> &r, uint8_t type) {
367 56074458 : if (type < toInt(Flags::MaxAdditionalNumber)) {
368 53323111 : return type;
369 2751345 : } else if (type == toInt(Flags::AdditionalNumber8Bit)) {
370 1719790 : return r.readUnsigned();
371 1031574 : } else if (type == toInt(Flags::AdditionalNumber16Bit)) {
372 790228 : return r.readUnsigned16();
373 241348 : } else if (type == toInt(Flags::AdditionalNumber32Bit)) {
374 240475 : return r.readUnsigned32();
375 875 : } else if (type == toInt(Flags::AdditionalNumber64Bit)) {
376 775 : return r.readUnsigned64();
377 : } else {
378 100 : return 0;
379 : }
380 : }
381 :
382 19435932 : inline int64_t _readInt(BytesViewTemplate<Endian::Network> &r) {
383 19435932 : uint8_t type = r.readUnsigned();
384 19435932 : MajorTypeEncoded majorType = (MajorTypeEncoded)(type & toInt(Flags::MajorTypeMaskEncoded));;
385 19435932 : type = type & toInt(Flags::AdditionalInfoMask);
386 :
387 19435932 : switch(majorType) {
388 19435932 : case MajorTypeEncoded::Unsigned: return _readIntValue(r, type); break;
389 0 : case MajorTypeEncoded::Negative: return (-1 - _readIntValue(r, type)); break;
390 : default: break;
391 : }
392 : return 0;
393 : }
394 :
395 49319739 : inline double _readNumber(BytesViewTemplate<Endian::Network> &r) {
396 49319739 : uint8_t type = r.readUnsigned();
397 49319739 : MajorTypeEncoded majorType = (MajorTypeEncoded)(type & toInt(Flags::MajorTypeMaskEncoded));;
398 49319739 : type = type & toInt(Flags::AdditionalInfoMask);
399 :
400 49319739 : switch(majorType) {
401 27462952 : case MajorTypeEncoded::Unsigned:
402 27462952 : return _readIntValue(r, type);
403 : break;
404 15990 : case MajorTypeEncoded::Negative:
405 15990 : return (-1 - static_cast<int64_t>(_readIntValue(r, type)));
406 : break;
407 21840797 : case MajorTypeEncoded::Simple:
408 21840797 : if (type == toInt(Flags::AdditionalFloat16Bit)) {
409 3288149 : return r.readFloat16();
410 18552648 : } else if (type == toInt(Flags::AdditionalFloat32Bit)) {
411 18552648 : return r.readFloat32();
412 0 : } else if (type == toInt(Flags::AdditionalFloat64Bit)) {
413 0 : return r.readFloat64();
414 : }
415 : break;
416 : default: break;
417 : }
418 : return 0.0;
419 : }
420 :
421 : }
422 :
423 : #endif /* STAPPLER_DATA_SPDATACBOR_H_ */
|