/src/arduinojson/src/ArduinoJson/MsgPack/MsgPackExtension.hpp
Line | Count | Source |
1 | | #pragma once |
2 | | |
3 | | #include <ArduinoJson/Variant/Converter.hpp> |
4 | | |
5 | | ARDUINOJSON_BEGIN_PUBLIC_NAMESPACE |
6 | | |
7 | | class MsgPackExtension { |
8 | | public: |
9 | 0 | MsgPackExtension() : data_(nullptr), size_(0), type_(0) {} |
10 | | explicit MsgPackExtension(int8_t type, const void* data, size_t size) |
11 | 0 | : data_(data), size_(size), type_(type) {} |
12 | | |
13 | 0 | int8_t type() const { |
14 | 0 | return type_; |
15 | 0 | } |
16 | | |
17 | 0 | const void* data() const { |
18 | 0 | return data_; |
19 | 0 | } |
20 | | |
21 | 0 | size_t size() const { |
22 | 0 | return size_; |
23 | 0 | } |
24 | | |
25 | | private: |
26 | | const void* data_; |
27 | | size_t size_; |
28 | | int8_t type_; |
29 | | }; |
30 | | |
31 | | template <> |
32 | | struct Converter<MsgPackExtension> : private detail::VariantAttorney { |
33 | 0 | static bool toJson(MsgPackExtension src, JsonVariant dst) { |
34 | 0 | auto data = getData(dst); |
35 | 0 | if (!data) |
36 | 0 | return false; |
37 | 0 |
|
38 | 0 | auto resources = getResourceManager(dst); |
39 | 0 | detail::VariantImpl::clear(data, resources); |
40 | 0 |
|
41 | 0 | if (!src.data()) |
42 | 0 | return true; |
43 | 0 |
|
44 | 0 | uint8_t format, sizeBytes; |
45 | 0 | if (src.size() >= 0x10000) { |
46 | 0 | format = 0xc9; // ext 32 |
47 | 0 | sizeBytes = 4; |
48 | 0 | } else if (src.size() >= 0x100) { |
49 | 0 | format = 0xc8; // ext 16 |
50 | 0 | sizeBytes = 2; |
51 | 0 | } else if (src.size() == 16) { |
52 | 0 | format = 0xd8; // fixext 16 |
53 | 0 | sizeBytes = 0; |
54 | 0 | } else if (src.size() == 8) { |
55 | 0 | format = 0xd7; // fixext 8 |
56 | 0 | sizeBytes = 0; |
57 | 0 | } else if (src.size() == 4) { |
58 | 0 | format = 0xd6; // fixext 4 |
59 | 0 | sizeBytes = 0; |
60 | 0 | } else if (src.size() == 2) { |
61 | 0 | format = 0xd5; // fixext 2 |
62 | 0 | sizeBytes = 0; |
63 | 0 | } else if (src.size() == 1) { |
64 | 0 | format = 0xd4; // fixext 1 |
65 | 0 | sizeBytes = 0; |
66 | 0 | } else { |
67 | 0 | format = 0xc7; // ext 8 |
68 | 0 | sizeBytes = 1; |
69 | 0 | } |
70 | 0 |
|
71 | 0 | auto str = resources->createString(src.size() + 2 + sizeBytes); |
72 | 0 | if (!str) |
73 | 0 | return false; |
74 | 0 |
|
75 | 0 | resources->saveString(str); |
76 | 0 | auto ptr = reinterpret_cast<uint8_t*>(str->data); |
77 | 0 | *ptr++ = uint8_t(format); |
78 | 0 | for (uint8_t i = 0; i < sizeBytes; i++) |
79 | 0 | *ptr++ = uint8_t(src.size() >> (sizeBytes - i - 1) * 8 & 0xff); |
80 | 0 | *ptr++ = uint8_t(src.type()); |
81 | 0 | memcpy(ptr, src.data(), src.size()); |
82 | 0 | data->setRawString(str); |
83 | 0 | return true; |
84 | 0 | } |
85 | | |
86 | 0 | static MsgPackExtension fromJson(JsonVariantConst src) { |
87 | 0 | auto data = getData(src); |
88 | 0 | if (!data) |
89 | 0 | return {}; |
90 | 0 | auto rawstr = data->asRawString(); |
91 | 0 | if (rawstr.size() == 0) |
92 | 0 | return {}; |
93 | 0 | auto p = reinterpret_cast<const uint8_t*>(rawstr.c_str()); |
94 | 0 |
|
95 | 0 | size_t payloadSize = 0; |
96 | 0 | uint8_t headerSize = 0; |
97 | 0 |
|
98 | 0 | const uint8_t& code = p[0]; |
99 | 0 |
|
100 | 0 | if (code >= 0xd4 && code <= 0xd8) { // fixext 1 |
101 | 0 | headerSize = 2; |
102 | 0 | payloadSize = size_t(1) << (code - 0xd4); |
103 | 0 | } |
104 | 0 |
|
105 | 0 | if (code >= 0xc7 && code <= 0xc9) { |
106 | 0 | uint8_t sizeBytes = uint8_t(1 << (code - 0xc7)); |
107 | 0 | for (uint8_t i = 0; i < sizeBytes; i++) |
108 | 0 | payloadSize = (payloadSize << 8) | p[1 + i]; |
109 | 0 | headerSize = uint8_t(2 + sizeBytes); |
110 | 0 | } |
111 | 0 |
|
112 | 0 | if (rawstr.size() == headerSize + payloadSize) |
113 | 0 | return MsgPackExtension(int8_t(p[headerSize - 1]), p + headerSize, |
114 | 0 | payloadSize); |
115 | 0 |
|
116 | 0 | return {}; |
117 | 0 | } |
118 | | |
119 | 0 | static bool checkJson(JsonVariantConst src) { |
120 | 0 | return fromJson(src).data() != nullptr; |
121 | 0 | } |
122 | | }; |
123 | | |
124 | | ARDUINOJSON_END_PUBLIC_NAMESPACE |