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