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 CONFIRMATIONUI_1_0_DEFAULT_CBOR_H_
19 #define CONFIRMATIONUI_1_0_DEFAULT_CBOR_H_
20
21 #include <stddef.h>
22 #include <stdint.h>
23 #include <type_traits>
24
25 namespace android {
26 namespace hardware {
27 namespace confirmationui {
28 namespace support {
29
30 template <typename In, typename Out>
copy(In begin,In end,Out out)31 Out copy(In begin, In end, Out out) {
32 while (begin != end) {
33 *out++ = *begin++;
34 }
35 return out;
36 }
37
38 enum class Type : uint8_t {
39 NUMBER = 0,
40 NEGATIVE = 1,
41 BYTE_STRING = 2,
42 TEXT_STRING = 3,
43 ARRAY = 4,
44 MAP = 5,
45 TAG = 6,
46 FLOAT = 7,
47 };
48
49 enum class Error : uint32_t {
50 OK = 0,
51 OUT_OF_DATA = 1,
52 MALFORMED = 2,
53 MALFORMED_UTF8 = 3,
54 };
55
56 template <typename Key, typename Value>
57 struct MapElement {
58 const Key& key_;
59 const Value& value_;
MapElementMapElement60 MapElement(const Key& key, const Value& value) : key_(key), value_(value) {}
61 };
62
63 template <typename... Elems>
64 struct Array;
65
66 template <typename Head, typename... Tail>
67 struct Array<Head, Tail...> {
68 const Head& head_;
69 Array<Tail...> tail_;
70 Array(const Head& head, const Tail&... tail) : head_(head), tail_(tail...) {}
71 constexpr size_t size() const { return sizeof...(Tail) + 1; };
72 };
73
74 template <>
75 struct Array<> {};
76
77 struct TextStr {};
78 struct ByteStr {};
79
80 template <typename T, typename Variant>
81 struct StringBuffer {
82 const T* data_;
83 size_t size_;
84 StringBuffer(const T* data, size_t size) : data_(data), size_(size) {
85 static_assert(sizeof(T) == 1, "elements too large");
86 }
87 const T* data() const { return data_; }
88 size_t size() const { return size_; }
89 };
90
91 /**
92 * Takes a char array turns it into a StringBuffer of TextStr type. The length of the resulting
93 * StringBuffer is size - 1, effectively stripping the 0 character from the region being considered.
94 * If the terminating 0 shall not be stripped use text_keep_last.
95 */
96 template <size_t size>
97 StringBuffer<char, TextStr> text(const char (&str)[size]) {
98 if (size > 0) return StringBuffer<char, TextStr>(str, size - 1);
99 return StringBuffer<char, TextStr>(str, size);
100 }
101
102 /**
103 * As opposed to text(const char (&str)[size] this function does not strips the last character.
104 */
105 template <size_t size>
106 StringBuffer<char, TextStr> text_keep_last(const char (&str)[size]) {
107 return StringBuffer<char, TextStr>(str, size);
108 }
109
110 template <typename T>
111 auto getData(const T& v) -> decltype(v.data()) {
112 return v.data();
113 }
114
115 template <typename T>
116 auto getData(const T& v) -> decltype(v.c_str()) {
117 return v.c_str();
118 }
119
120 template <typename T>
121 auto text(const T& str) -> StringBuffer<std::decay_t<decltype(*getData(str))>, TextStr> {
122 return StringBuffer<std::decay_t<decltype(*getData(str))>, TextStr>(getData(str), str.size());
123 }
124
125 inline StringBuffer<char, TextStr> text(const char* str, size_t size) {
126 return StringBuffer<char, TextStr>(str, size);
127 }
128
129 template <typename T, size_t size>
130 StringBuffer<T, ByteStr> bytes(const T (&str)[size]) {
131 return StringBuffer<T, ByteStr>(str, size);
132 }
133
134 template <typename T>
135 StringBuffer<T, ByteStr> bytes(const T* str, size_t size) {
136 return StringBuffer<T, ByteStr>(str, size);
137 }
138
139 template <typename T>
140 auto bytes(const T& str) -> StringBuffer<std::decay_t<decltype(*getData(str))>, ByteStr> {
141 return StringBuffer<std::decay_t<decltype(*getData(str))>, ByteStr>(getData(str), str.size());
142 }
143
144 template <typename... Elems>
145 struct Map;
146
147 template <typename HeadKey, typename HeadValue, typename... Tail>
148 struct Map<MapElement<HeadKey, HeadValue>, Tail...> {
149 const MapElement<HeadKey, HeadValue>& head_;
150 Map<Tail...> tail_;
151 Map(const MapElement<HeadKey, HeadValue>& head, const Tail&... tail)
152 : head_(head), tail_(tail...) {}
153 constexpr size_t size() const { return sizeof...(Tail) + 1; };
154 };
155
156 template <>
157 struct Map<> {};
158
159 template <typename... Keys, typename... Values>
160 Map<MapElement<Keys, Values>...> map(const MapElement<Keys, Values>&... elements) {
161 return Map<MapElement<Keys, Values>...>(elements...);
162 }
163
164 template <typename... Elements>
165 Array<Elements...> arr(const Elements&... elements) {
166 return Array<Elements...>(elements...);
167 }
168
169 template <typename Key, typename Value>
170 MapElement<Key, Value> pair(const Key& k, const Value& v) {
171 return MapElement<Key, Value>(k, v);
172 }
173
174 template <size_t size>
175 struct getUnsignedType;
176
177 template <>
178 struct getUnsignedType<sizeof(uint8_t)> {
179 typedef uint8_t type;
180 };
181 template <>
182 struct getUnsignedType<sizeof(uint16_t)> {
183 typedef uint16_t type;
184 };
185 template <>
186 struct getUnsignedType<sizeof(uint32_t)> {
187 typedef uint32_t type;
188 };
189 template <>
190 struct getUnsignedType<sizeof(uint64_t)> {
191 typedef uint64_t type;
192 };
193
194 template <size_t size>
195 using Unsigned = typename getUnsignedType<size>::type;
196
197 class WriteState {
198 public:
199 WriteState() : data_(nullptr), size_(0), error_(Error::OK) {}
200 WriteState(uint8_t* buffer, size_t size) : data_(buffer), size_(size), error_(Error::OK) {}
201 WriteState(uint8_t* buffer, size_t size, Error error)
202 : data_(buffer), size_(size), error_(error) {}
203 template <size_t size>
204 WriteState(uint8_t (&buffer)[size]) : data_(buffer), size_(size), error_(Error::OK) {}
205
206 WriteState& operator++() {
207 if (size_) {
208 ++data_;
209 --size_;
210 } else {
211 error_ = Error::OUT_OF_DATA;
212 }
213 return *this;
214 }
215 WriteState& operator+=(size_t offset) {
216 if (offset > size_) {
217 error_ = Error::OUT_OF_DATA;
218 } else {
219 data_ += offset;
220 size_ -= offset;
221 }
222 return *this;
223 }
224 operator bool() const { return error_ == Error::OK; }
225
226 uint8_t* data_;
227 size_t size_;
228 Error error_;
229 };
230
231 WriteState writeHeader(WriteState wState, Type type, const uint64_t value);
232 bool checkUTF8Copy(const char* begin, const char* const end, uint8_t* out);
233
234 template <typename T>
235 WriteState writeNumber(WriteState wState, const T& v) {
236 if (!wState) return wState;
237 if (v >= 0) {
238 return writeHeader(wState, Type::NUMBER, v);
239 } else {
240 return writeHeader(wState, Type::NEGATIVE, UINT64_C(-1) - v);
241 }
242 }
243
244 inline WriteState write(const WriteState& wState, const uint8_t& v) {
245 return writeNumber(wState, v);
246 }
247 inline WriteState write(const WriteState& wState, const int8_t& v) {
248 return writeNumber(wState, v);
249 }
250 inline WriteState write(const WriteState& wState, const uint16_t& v) {
251 return writeNumber(wState, v);
252 }
253 inline WriteState write(const WriteState& wState, const int16_t& v) {
254 return writeNumber(wState, v);
255 }
256 inline WriteState write(const WriteState& wState, const uint32_t& v) {
257 return writeNumber(wState, v);
258 }
259 inline WriteState write(const WriteState& wState, const int32_t& v) {
260 return writeNumber(wState, v);
261 }
262 inline WriteState write(const WriteState& wState, const uint64_t& v) {
263 return writeNumber(wState, v);
264 }
265 inline WriteState write(const WriteState& wState, const int64_t& v) {
266 return writeNumber(wState, v);
267 }
268
269 template <typename T>
270 WriteState write(WriteState wState, const StringBuffer<T, TextStr>& v) {
271 wState = writeHeader(wState, Type::TEXT_STRING, v.size());
272 uint8_t* buffer = wState.data_;
273 wState += v.size();
274 if (!wState) return wState;
275 if (!checkUTF8Copy(v.data(), v.data() + v.size(), buffer)) {
276 wState.error_ = Error::MALFORMED_UTF8;
277 }
278 return wState;
279 }
280
281 template <typename T>
282 WriteState write(WriteState wState, const StringBuffer<T, ByteStr>& v) {
283 wState = writeHeader(wState, Type::BYTE_STRING, v.size());
284 uint8_t* buffer = wState.data_;
285 wState += v.size();
286 if (!wState) return wState;
287 static_assert(sizeof(*v.data()) == 1, "elements too large");
288 copy(v.data(), v.data() + v.size(), buffer);
289 return wState;
290 }
291
292 template <template <typename...> class Arr>
293 WriteState writeArrayHelper(WriteState wState, const Arr<>&) {
294 return wState;
295 }
296
297 template <template <typename...> class Arr, typename Head, typename... Tail>
298 WriteState writeArrayHelper(WriteState wState, const Arr<Head, Tail...>& arr) {
299 wState = write(wState, arr.head_);
300 return writeArrayHelper(wState, arr.tail_);
301 }
302
303 template <typename... Elems>
304 WriteState write(WriteState wState, const Map<Elems...>& map) {
305 if (!wState) return wState;
306 wState = writeHeader(wState, Type::MAP, map.size());
307 return writeArrayHelper(wState, map);
308 }
309
310 template <typename... Elems>
311 WriteState write(WriteState wState, const Array<Elems...>& arr) {
312 if (!wState) return wState;
313 wState = writeHeader(wState, Type::ARRAY, arr.size());
314 return writeArrayHelper(wState, arr);
315 }
316
317 template <typename Key, typename Value>
318 WriteState write(WriteState wState, const MapElement<Key, Value>& element) {
319 if (!wState) return wState;
320 wState = write(wState, element.key_);
321 return write(wState, element.value_);
322 }
323
324 template <typename Head, typename... Tail>
325 WriteState write(WriteState wState, const Head& head, const Tail&... tail) {
326 wState = write(wState, head);
327 return write(wState, tail...);
328 }
329
330 } // namespace support
331 } // namespace confirmationui
332 } // namespace hardware
333 } // namespace android
334
335 #endif // CONFIRMATIONUI_1_0_DEFAULT_CBOR_H_
336