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