1 // Copyright 2015 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "aemu/base/files/Stream.h"
16
17 #include <assert.h>
18 #include <string.h>
19
20 namespace gfxstream {
21 namespace guest {
22
putByte(uint8_t value)23 void Stream::putByte(uint8_t value) {
24 write(&value, 1U);
25 }
26
getByte()27 uint8_t Stream::getByte() {
28 uint8_t value[1] = { 0 };
29 read(value, 1U);
30 return value[0];
31 }
32
putBe16(uint16_t value)33 void Stream::putBe16(uint16_t value) {
34 uint8_t b[2] = { (uint8_t)(value >> 8), (uint8_t)value };
35 write(b, 2U);
36 }
37
getBe16()38 uint16_t Stream::getBe16() {
39 uint8_t b[2] = { 0, 0 };
40 read(b, 2U);
41 return ((uint16_t)b[0] << 8) | (uint16_t)b[1];
42 }
43
putBe32(uint32_t value)44 void Stream::putBe32(uint32_t value) {
45 uint8_t b[4] = {
46 (uint8_t)(value >> 24),
47 (uint8_t)(value >> 16),
48 (uint8_t)(value >> 8),
49 (uint8_t)value };
50 write(b, 4U);
51 }
52
getBe32()53 uint32_t Stream::getBe32() {
54 uint8_t b[4] = { 0, 0, 0, 0 };
55 read(b, 4U);
56 return ((uint32_t)b[0] << 24) |
57 ((uint32_t)b[1] << 16) |
58 ((uint32_t)b[2] << 8) |
59 (uint32_t)b[3];
60 }
61
putBe64(uint64_t value)62 void Stream::putBe64(uint64_t value) {
63 uint8_t b[8] = {
64 (uint8_t)(value >> 56),
65 (uint8_t)(value >> 48),
66 (uint8_t)(value >> 40),
67 (uint8_t)(value >> 32),
68 (uint8_t)(value >> 24),
69 (uint8_t)(value >> 16),
70 (uint8_t)(value >> 8),
71 (uint8_t)value };
72 write(b, 8U);
73 }
74
getBe64()75 uint64_t Stream::getBe64() {
76 uint8_t b[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
77 read(b, 8U);
78 return ((uint64_t)b[0] << 56) |
79 ((uint64_t)b[1] << 48) |
80 ((uint64_t)b[2] << 40) |
81 ((uint64_t)b[3] << 32) |
82 ((uint64_t)b[4] << 24) |
83 ((uint64_t)b[5] << 16) |
84 ((uint64_t)b[6] << 8) |
85 (uint64_t)b[7];
86 }
87
putFloat(float v)88 void Stream::putFloat(float v) {
89 union {
90 float f;
91 uint8_t bytes[sizeof(float)];
92 } u;
93 u.f = v;
94 this->write(u.bytes, sizeof(u.bytes));
95 }
96
getFloat()97 float Stream::getFloat() {
98 union {
99 float f;
100 uint8_t bytes[sizeof(float)];
101 } u;
102 this->read(u.bytes, sizeof(u.bytes));
103 return u.f;
104 }
105
putString(const char * str)106 void Stream::putString(const char* str) {
107 if (str) {
108 putString(str, strlen(str));
109 } else {
110 putString("", 0);
111 }
112 }
113
putString(const std::string & str)114 void Stream::putString(const std::string& str) {
115 putString(str.data(), str.size());
116 }
117
putString(const char * str,size_t len)118 void Stream::putString(const char* str, size_t len) {
119 if (str) {
120 this->putBe32(len);
121 this->write(str, len);
122 }
123 }
124
getString()125 std::string Stream::getString() {
126 std::string result;
127 size_t len = this->getBe32();
128 if (len > 0) {
129 result.resize(len);
130 if (this->read(&result[0], len) != static_cast<ssize_t>(len)) {
131 result.clear();
132 }
133 }
134 #ifdef _WIN32
135 else {
136 // std::string in GCC's STL still uses copy on write implementation
137 // with a single shared buffer for an empty string. Its dtor has
138 // a check for that shared buffer, and it deallocates memory only if
139 // the current string's instance address != shared empty string address
140 // Unfortunately, in Windows DLLs each DLL has its own copy of this
141 // empty string (that's just the way Windows DLLs work), so if this
142 // code creates an empty string and passes it over into another module,
143 // that module's std::string::~string() will compare address with its
144 // empty string object, find that they are different and will try to
145 // free() a static object.
146 // To mitigate it we make sure the string allocates something, so it
147 // isn't empty internally and dtor is OK to delete the storage.
148 result.reserve(1);
149 }
150 #endif
151 return result;
152 }
153
putPackedNum(uint64_t num)154 void Stream::putPackedNum(uint64_t num) {
155 do {
156 auto byte = uint8_t(num & 0x7f);
157 num >>= 7;
158 if (num) {
159 byte |= 0x80;
160 }
161 putByte(byte);
162 } while (num != 0);
163 }
164
getPackedNum()165 uint64_t Stream::getPackedNum() {
166 uint64_t res = 0;
167 uint8_t byte;
168 int i = 0;
169 do {
170 byte = getByte();
171 res |= uint64_t(byte & 0x7f) << (i++ * 7);
172 } while (byte & 0x80 && i < 10);
173 return res;
174 }
175
putPackedSignedNum(int64_t num)176 void Stream::putPackedSignedNum(int64_t num) {
177 if (num >= 0) {
178 assert((uint64_t(num) & (1ULL << 63)) == 0);
179 putPackedNum(uint64_t(num) << 1);
180 } else {
181 assert((uint64_t(-num) & (1ULL << 63)) == 0);
182 putPackedNum((uint64_t(-num) << 1) | 1);
183 }
184 }
185
getPackedSignedNum()186 int64_t Stream::getPackedSignedNum() {
187 auto num = getPackedNum();
188 auto sign = num & 1;
189 return sign ? -int64_t(num >> 1) : (num >> 1);
190 }
191
192 // Static big-endian conversions
193
194 // the |v| pointer is unlikely to be aligned---use memcpy throughout
195
toByte(uint8_t *)196 void Stream::toByte(uint8_t*) { } // no conversion
197
toBe16(uint8_t * v)198 void Stream::toBe16(uint8_t* v) {
199 uint16_t value;
200 memcpy(&value, v, sizeof(uint16_t));
201 uint8_t b[2] = { (uint8_t)(value >> 8), (uint8_t)value };
202 memcpy(v, b, sizeof(uint16_t));
203 }
204
toBe32(uint8_t * v)205 void Stream::toBe32(uint8_t* v) {
206 uint32_t value;
207 memcpy(&value, v, sizeof(uint32_t));
208 uint8_t b[4] = {
209 (uint8_t)(value >> 24),
210 (uint8_t)(value >> 16),
211 (uint8_t)(value >> 8),
212 (uint8_t)value };
213 memcpy(v, b, sizeof(uint32_t));
214 }
215
toBe64(uint8_t * v)216 void Stream::toBe64(uint8_t* v) {
217 uint64_t value;
218 memcpy(&value, v, sizeof(uint64_t));
219 uint8_t b[8] = {
220 (uint8_t)(value >> 56),
221 (uint8_t)(value >> 48),
222 (uint8_t)(value >> 40),
223 (uint8_t)(value >> 32),
224 (uint8_t)(value >> 24),
225 (uint8_t)(value >> 16),
226 (uint8_t)(value >> 8),
227 (uint8_t)value };
228 memcpy(v, b, sizeof(uint64_t));
229 }
230
fromByte(uint8_t *)231 void Stream::fromByte(uint8_t*) { } // no conversion
232
fromBe16(uint8_t * v)233 void Stream::fromBe16(uint8_t* v) {
234 uint8_t b[2];
235 memcpy(b, v, sizeof(uint16_t));
236 uint16_t value = ((uint16_t)b[0] << 8) | (uint16_t)b[1];
237 memcpy(v, &value, sizeof(uint16_t));
238 }
239
fromBe32(uint8_t * v)240 void Stream::fromBe32(uint8_t* v) {
241 uint8_t b[4];
242 memcpy(b, v, sizeof(uint32_t));
243 uint32_t value =
244 ((uint32_t)b[0] << 24) |
245 ((uint32_t)b[1] << 16) |
246 ((uint32_t)b[2] << 8) |
247 (uint32_t)b[3];
248 memcpy(v, &value, sizeof(uint32_t));
249 }
250
fromBe64(uint8_t * v)251 void Stream::fromBe64(uint8_t* v) {
252 uint8_t b[8];
253 memcpy(b, v, sizeof(uint64_t));
254 uint64_t value =
255 ((uint64_t)b[0] << 56) |
256 ((uint64_t)b[1] << 48) |
257 ((uint64_t)b[2] << 40) |
258 ((uint64_t)b[3] << 32) |
259 ((uint64_t)b[4] << 24) |
260 ((uint64_t)b[5] << 16) |
261 ((uint64_t)b[6] << 8) |
262 (uint64_t)b[7];
263 memcpy(v, &value, sizeof(uint64_t));
264 }
265
266 } // namespace base
267 } // namespace android
268