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