1 /*
2 *
3 * Copyright 2017, The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #ifndef TEEUI_CBOR_H_
19 #define TEEUI_CBOR_H_
20
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <type_traits>
24
25 namespace teeui {
26 namespace cbor {
27
copy(In begin,In end,Out out)28 template <typename In, typename Out> Out copy(In begin, In end, Out out) {
29 while (begin != end) {
30 *out++ = *begin++;
31 }
32 return out;
33 }
34
35 enum class Type : uint8_t {
36 NUMBER = 0,
37 NEGATIVE = 1,
38 BYTE_STRING = 2,
39 TEXT_STRING = 3,
40 ARRAY = 4,
41 MAP = 5,
42 TAG = 6,
43 FLOAT = 7,
44 };
45
46 enum class Error : uint32_t {
47 OK = 0,
48 OUT_OF_DATA = 1,
49 MALFORMED = 2,
50 MALFORMED_UTF8 = 3,
51 };
52
53 template <typename Key, typename Value> struct MapElement {
54 const Key& key_;
55 const Value& value_;
MapElementMapElement56 MapElement(const Key& key, const Value& value) : key_(key), value_(value) {}
57 };
58
59 template <typename... Elems> struct Array;
60
61 template <typename Head, typename... Tail> struct Array<Head, Tail...> {
62 const Head& head_;
63 Array<Tail...> tail_;
64 Array(const Head& head, const Tail&... tail) : head_(head), tail_(tail...) {}
65 constexpr size_t size() const { return sizeof...(Tail) + 1; };
66 };
67
68 template <> struct Array<> {};
69
70 struct TextStr {};
71 struct ByteStr {};
72
73 template <typename T, typename Variant> struct StringBuffer {
74 const T* data_;
75 size_t size_;
76 StringBuffer(const T* data, size_t size) : data_(data), size_(size) {
77 static_assert(sizeof(T) == 1, "elements too large");
78 }
79 const T* data() const { return data_; }
80 size_t size() const { return size_; }
81 };
82
83 /**
84 * Takes a char array turns it into a StringBuffer of TextStr type. The length of the resulting
85 * StringBuffer is size - 1, effectively stripping the 0 character from the region being considered.
86 * If the terminating 0 shall not be stripped use text_keep_last.
87 */
88 template <size_t size> StringBuffer<char, TextStr> text(const char (&str)[size]) {
89 if (size > 0) return StringBuffer<char, TextStr>(str, size - 1);
90 return StringBuffer<char, TextStr>(str, size);
91 }
92
93 /**
94 * As opposed to text(const char (&str)[size] this function does not strips the last character.
95 */
96 template <size_t size> StringBuffer<char, TextStr> text_keep_last(const char (&str)[size]) {
97 return StringBuffer<char, TextStr>(str, size);
98 }
99
100 template <typename T> auto getData(const T& v) -> decltype(v.data()) {
101 return v.data();
102 }
103
104 template <typename T> auto getData(const T& v) -> decltype(v.c_str()) {
105 return v.c_str();
106 }
107
108 template <typename T>
109 auto text(const T& str) -> StringBuffer<std::decay_t<decltype(*getData(str))>, TextStr> {
110 return StringBuffer<std::decay_t<decltype(*getData(str))>, TextStr>(getData(str), str.size());
111 }
112
113 inline StringBuffer<char, TextStr> text(const char* str, size_t size) {
114 return StringBuffer<char, TextStr>(str, size);
115 }
116
117 template <typename T, size_t size> StringBuffer<T, ByteStr> bytes(const T (&str)[size]) {
118 return StringBuffer<T, ByteStr>(str, size);
119 }
120
121 template <typename T> StringBuffer<T, ByteStr> bytes(const T* str, size_t size) {
122 return StringBuffer<T, ByteStr>(str, size);
123 }
124
125 template <typename T>
126 auto bytes(const T& str) -> StringBuffer<std::decay_t<decltype(*getData(str))>, ByteStr> {
127 return StringBuffer<std::decay_t<decltype(*getData(str))>, ByteStr>(getData(str), str.size());
128 }
129
130 template <typename... Elems> struct Map;
131
132 template <typename HeadKey, typename HeadValue, typename... Tail>
133 struct Map<MapElement<HeadKey, HeadValue>, Tail...> {
134 const MapElement<HeadKey, HeadValue>& head_;
135 Map<Tail...> tail_;
136 Map(const MapElement<HeadKey, HeadValue>& head, const Tail&... tail)
137 : head_(head), tail_(tail...) {}
138 constexpr size_t size() const { return sizeof...(Tail) + 1; };
139 };
140
141 template <> struct Map<> {};
142
143 template <typename... Keys, typename... Values>
144 Map<MapElement<Keys, Values>...> map(const MapElement<Keys, Values>&... elements) {
145 return Map<MapElement<Keys, Values>...>(elements...);
146 }
147
148 template <typename... Elements> Array<Elements...> arr(const Elements&... elements) {
149 return Array<Elements...>(elements...);
150 }
151
152 template <typename Key, typename Value> MapElement<Key, Value> pair(const Key& k, const Value& v) {
153 return MapElement<Key, Value>(k, v);
154 }
155
156 template <size_t size> struct getUnsignedType;
157
158 template <> struct getUnsignedType<sizeof(uint8_t)> { using type = uint8_t; };
159 template <> struct getUnsignedType<sizeof(uint16_t)> { using type = uint16_t; };
160 template <> struct getUnsignedType<sizeof(uint32_t)> { using type = uint32_t; };
161 template <> struct getUnsignedType<sizeof(uint64_t)> { using type = uint64_t; };
162
163 template <size_t size> using Unsigned = typename getUnsignedType<size>::type;
164
165 class WriteState {
166 public:
167 WriteState() : data_(nullptr), size_(0), error_(Error::OK) {}
168 WriteState(uint8_t* buffer, size_t size) : data_(buffer), size_(size), error_(Error::OK) {}
169 WriteState(uint8_t* buffer, size_t size, Error error)
170 : data_(buffer), size_(size), error_(error) {}
171 template <size_t size>
172 WriteState(uint8_t (&buffer)[size]) : data_(buffer), size_(size), error_(Error::OK) {}
173
174 WriteState& operator++() {
175 if (size_) {
176 ++data_;
177 --size_;
178 } else {
179 error_ = Error::OUT_OF_DATA;
180 }
181 return *this;
182 }
183 WriteState& operator+=(size_t offset) {
184 if (offset > size_) {
185 error_ = Error::OUT_OF_DATA;
186 } else {
187 data_ += offset;
188 size_ -= offset;
189 }
190 return *this;
191 }
192 operator bool() const { return error_ == Error::OK; }
193
194 uint8_t* data_;
195 size_t size_;
196 Error error_;
197 };
198
199 WriteState writeHeader(WriteState wState, Type type, const uint64_t value);
200 bool checkUTF8Copy(const char* begin, const char* const end, uint8_t* out);
201
202 template <typename T> WriteState writeNumber(WriteState wState, const T& v) {
203 if (!wState) return wState;
204 if (v >= 0) {
205 return writeHeader(wState, Type::NUMBER, v);
206 } else {
207 return writeHeader(wState, Type::NEGATIVE, UINT64_C(-1) - v);
208 }
209 }
210
211 inline WriteState write(const WriteState& wState, const uint8_t& v) {
212 return writeNumber(wState, v);
213 }
214 inline WriteState write(const WriteState& wState, const int8_t& v) {
215 return writeNumber(wState, v);
216 }
217 inline WriteState write(const WriteState& wState, const uint16_t& v) {
218 return writeNumber(wState, v);
219 }
220 inline WriteState write(const WriteState& wState, const int16_t& v) {
221 return writeNumber(wState, v);
222 }
223 inline WriteState write(const WriteState& wState, const uint32_t& v) {
224 return writeNumber(wState, v);
225 }
226 inline WriteState write(const WriteState& wState, const int32_t& v) {
227 return writeNumber(wState, v);
228 }
229 inline WriteState write(const WriteState& wState, const uint64_t& v) {
230 return writeNumber(wState, v);
231 }
232 inline WriteState write(const WriteState& wState, const int64_t& v) {
233 return writeNumber(wState, v);
234 }
235
236 template <typename T> WriteState write(WriteState wState, const StringBuffer<T, TextStr>& v) {
237 wState = writeHeader(wState, Type::TEXT_STRING, v.size());
238 uint8_t* buffer = wState.data_;
239 wState += v.size();
240 if (!wState) return wState;
241 if (!checkUTF8Copy(v.data(), v.data() + v.size(), buffer)) {
242 wState.error_ = Error::MALFORMED_UTF8;
243 }
244 return wState;
245 }
246
247 template <typename T> WriteState write(WriteState wState, const StringBuffer<T, ByteStr>& v) {
248 wState = writeHeader(wState, Type::BYTE_STRING, v.size());
249 uint8_t* buffer = wState.data_;
250 wState += v.size();
251 if (!wState) return wState;
252 static_assert(sizeof(*v.data()) == 1, "elements too large");
253 copy(v.data(), v.data() + v.size(), buffer);
254 return wState;
255 }
256
257 template <template <typename...> class Arr>
258 WriteState writeArrayHelper(WriteState wState, const Arr<>&) {
259 return wState;
260 }
261
262 template <template <typename...> class Arr, typename Head, typename... Tail>
263 WriteState writeArrayHelper(WriteState wState, const Arr<Head, Tail...>& arr) {
264 wState = write(wState, arr.head_);
265 return writeArrayHelper(wState, arr.tail_);
266 }
267
268 template <typename... Elems> WriteState write(WriteState wState, const Map<Elems...>& map) {
269 if (!wState) return wState;
270 wState = writeHeader(wState, Type::MAP, map.size());
271 return writeArrayHelper(wState, map);
272 }
273
274 template <typename... Elems> WriteState write(WriteState wState, const Array<Elems...>& arr) {
275 if (!wState) return wState;
276 wState = writeHeader(wState, Type::ARRAY, arr.size());
277 return writeArrayHelper(wState, arr);
278 }
279
280 template <typename Key, typename Value>
281 WriteState write(WriteState wState, const MapElement<Key, Value>& element) {
282 if (!wState) return wState;
283 wState = write(wState, element.key_);
284 return write(wState, element.value_);
285 }
286
287 template <typename Head, typename... Tail>
288 WriteState write(WriteState wState, const Head& head, const Tail&... tail) {
289 wState = write(wState, head);
290 return write(wState, tail...);
291 }
292
293 } // namespace cbor
294 } // namespace teeui
295
296 #endif // TEEUI_CBOR_H_
297