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_MSG_FORMATTING_H_
19 #define TEEUI_MSG_FORMATTING_H_
20
21 #include <algorithm>
22 #include <stddef.h>
23 #include <stdint.h>
24 #include <tuple>
25 #include <type_traits>
26 #include <utility>
27
28 #include <teeui/utils.h>
29
30 namespace teeui {
31 namespace msg {
32
33 template <typename... fields> class Message {};
34
35 template <size_t... idx, typename... T>
tuple_move_helper(std::index_sequence<idx...>,std::tuple<T...> && t)36 std::tuple<std::remove_reference_t<T>&&...> tuple_move_helper(std::index_sequence<idx...>,
37 std::tuple<T...>&& t) {
38 return {std::move(std::get<idx>(t))...};
39 }
40
41 template <typename... T>
tuple_move(std::tuple<T...> && t)42 std::tuple<std::remove_reference_t<T>&&...> tuple_move(std::tuple<T...>&& t) {
43 return tuple_move_helper(std::make_index_sequence<sizeof...(T)>(), std::move(t));
44 }
45
46 template <typename... T>
tuple_move(std::tuple<T...> & t)47 std::tuple<std::remove_reference_t<T>&&...> tuple_move(std::tuple<T...>& t) {
48 return tuple_move_helper(std::make_index_sequence<sizeof...(T)>(), std::move(t));
49 }
50
51 void zero(volatile uint8_t* begin, const volatile uint8_t* end);
52
53 template <typename T> class StreamState {
54 public:
55 static_assert(
56 sizeof(T) == 1,
57 "StreamState must be instantiated with 1 byte sized type, e.g., uint8_t or const uint8_t.");
58 using ptr_t = T*;
59 template <size_t size>
StreamState(T (& buffer)[size])60 StreamState(T (&buffer)[size]) : begin_(&buffer[0]), end_(&buffer[size]), pos_(begin_) {}
StreamState(T * buffer,size_t size)61 StreamState(T* buffer, size_t size) : begin_(buffer), end_(buffer + size), pos_(begin_) {}
StreamState()62 StreamState() : begin_(nullptr), end_(nullptr), pos_(nullptr) {}
63 StreamState& operator+=(size_t offset) {
64 auto good_ = pos_ != nullptr && pos_ + offset <= end_;
65 if (good_) {
66 pos_ += offset;
67 } else {
68 pos_ = nullptr;
69 }
70 return *this;
71 }
72
73 operator bool() const { return pos_ != nullptr; }
pos()74 ptr_t pos() const { return pos_; };
75
76 template <typename U = T>
insertFieldSize(typename std::enable_if<!std::is_const<U>::value,uint32_t>::type size)77 bool insertFieldSize(typename std::enable_if<!std::is_const<U>::value, uint32_t>::type size) {
78 // offset to the nearest n * 8 + 4 boundary from beginning of the buffer! (not memory).
79 uintptr_t pos = pos_ - begin_;
80 auto offset = (((pos + 11UL) & ~7UL) - 4UL) - pos;
81 if (*this += offset + sizeof(size)) {
82 // zero out the gaps
83 zero(pos_ - offset - sizeof(size), pos_ - sizeof(size));
84 *reinterpret_cast<uint32_t*>(pos_ - sizeof(size)) = size;
85 return true;
86 }
87 return false;
88 }
89
90 template <typename U = T>
extractFieldSize()91 typename std::enable_if<std::is_const<U>::value, uint32_t>::type extractFieldSize() {
92 // offset to the nearest n * 8 + 4 boundary from beginning of the buffer! (not memory).
93 uintptr_t pos = pos_ - begin_;
94 auto offset = (((pos + 11UL) & ~7UL) - 4UL) - pos;
95 if (*this += offset + sizeof(uint32_t)) {
96 return *reinterpret_cast<const uint32_t*>(pos_ - sizeof(uint32_t));
97 }
98 return 0;
99 }
100
bad()101 void bad() { pos_ = nullptr; };
102
103 private:
104 ptr_t begin_;
105 ptr_t end_;
106 ptr_t pos_;
107 };
108
109 using WriteStream = StreamState<uint8_t>;
110 using ReadStream = StreamState<const uint8_t>;
111
zero(const volatile uint8_t *,const volatile uint8_t *)112 inline void zero(const volatile uint8_t*, const volatile uint8_t*) {}
113 //// This odd alignment function aligns the stream position to a 4byte and never 8byte boundary
114 //// It is to accommodate the 4 byte size field which is then followed by 8byte aligned data.
115 // template <typename T>
116 // StreamState<T> unalign(StreamState<T> s) {
117 // auto result = s;
118 // auto offset = (((uintptr_t(s.pos_) + 11UL) & ~7UL) - 4UL) - uintptr_t(s.pos_);
119 // result += offset;
120 // // zero out the gaps when writing
121 // if (result) zero(s.pos_, result.pos_);
122 // return result;
123 //}
124
125 WriteStream write(WriteStream out, const uint8_t* buffer, uint32_t size);
126
write(WriteStream out,const uint8_t (& v)[size])127 template <uint32_t size> WriteStream write(WriteStream out, const uint8_t (&v)[size]) {
128 return write(out, v, size);
129 }
130
131 std::tuple<ReadStream, ReadStream::ptr_t, uint32_t> read(ReadStream in);
132
readSimpleType(ReadStream in)133 template <typename T> std::tuple<ReadStream, T> readSimpleType(ReadStream in) {
134 auto [in_, pos, size] = read(in);
135 T result = {};
136 if (in_ && size == sizeof(T))
137 result = *reinterpret_cast<const T*>(pos);
138 else
139 in_.bad();
140 return {in_, result};
141 }
142
write(Message<>,WriteStream out)143 inline WriteStream write(Message<>, WriteStream out) {
144 return out;
145 }
146
147 template <typename Head, typename... Tail>
write(Message<Head,Tail...>,WriteStream out,const Head & head,const Tail &...tail)148 WriteStream write(Message<Head, Tail...>, WriteStream out, const Head& head, const Tail&... tail) {
149 out = write(out, head);
150 return write(Message<Tail...>(), out, tail...);
151 }
152
read(Message<Msg...>,ReadStream in)153 template <typename... Msg> std::tuple<ReadStream, Msg...> read(Message<Msg...>, ReadStream in) {
154 return {in, [&in]() -> Msg {
155 Msg result;
156 std::tie(in, result) = read(Message<Msg>(), in);
157 return result;
158 }()...};
159 }
160
161 template <typename T> struct msg2tuple {};
162
163 template <typename... T> struct msg2tuple<Message<T...>> { using type = std::tuple<T...>; };
164
165 template <typename T> using msg2tuple_t = typename msg2tuple<T>::type;
166
167 template <size_t first_idx, size_t... idx, typename HEAD, typename... T>
168 std::tuple<T&&...> tuple_tail(std::index_sequence<first_idx, idx...>, std::tuple<HEAD, T...>&& t) {
169 return {std::move(std::get<idx>(t))...};
170 }
171
172 template <size_t first_idx, size_t... idx, typename HEAD, typename... T>
173 std::tuple<const T&...> tuple_tail(std::index_sequence<first_idx, idx...>,
174 const std::tuple<HEAD, T...>& t) {
175 return {std::get<idx>(t)...};
176 }
177
178 template <typename HEAD, typename... Tail>
179 std::tuple<Tail&&...> tuple_tail(std::tuple<HEAD, Tail...>&& t) {
180 return tuple_tail(std::make_index_sequence<sizeof...(Tail) + 1>(), std::move(t));
181 }
182
183 template <typename HEAD, typename... Tail>
184 std::tuple<const Tail&...> tuple_tail(const std::tuple<HEAD, Tail...>& t) {
185 return tuple_tail(std::make_index_sequence<sizeof...(Tail) + 1>(), t);
186 }
187
188 } // namespace msg
189
190 using msg::Message;
191 using msg::msg2tuple;
192 using msg::msg2tuple_t;
193 using msg::read;
194 using msg::readSimpleType;
195 using msg::ReadStream;
196 using msg::tuple_tail;
197 using msg::write;
198 using msg::WriteStream;
199
200 } // namespace teeui
201
202 #endif // TEEUI_MSG_FORMATTING_H_
203