1 /*
2 * Copyright 2019 Google
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "Stream.h"
7
8 #include <assert.h>
9 #include <string.h>
10
11 namespace gfxstream {
12 namespace aemu {
13
putByte(uint8_t value)14 void Stream::putByte(uint8_t value) { write(&value, 1U); }
15
getByte()16 uint8_t Stream::getByte() {
17 uint8_t value[1] = {0};
18 read(value, 1U);
19 return value[0];
20 }
21
putBe16(uint16_t value)22 void Stream::putBe16(uint16_t value) {
23 uint8_t b[2] = {(uint8_t)(value >> 8), (uint8_t)value};
24 write(b, 2U);
25 }
26
getBe16()27 uint16_t Stream::getBe16() {
28 uint8_t b[2] = {0, 0};
29 read(b, 2U);
30 return ((uint16_t)b[0] << 8) | (uint16_t)b[1];
31 }
32
putBe32(uint32_t value)33 void Stream::putBe32(uint32_t value) {
34 uint8_t b[4] = {(uint8_t)(value >> 24), (uint8_t)(value >> 16), (uint8_t)(value >> 8),
35 (uint8_t)value};
36 write(b, 4U);
37 }
38
getBe32()39 uint32_t Stream::getBe32() {
40 uint8_t b[4] = {0, 0, 0, 0};
41 read(b, 4U);
42 return ((uint32_t)b[0] << 24) | ((uint32_t)b[1] << 16) | ((uint32_t)b[2] << 8) | (uint32_t)b[3];
43 }
44
putBe64(uint64_t value)45 void Stream::putBe64(uint64_t value) {
46 uint8_t b[8] = {(uint8_t)(value >> 56), (uint8_t)(value >> 48), (uint8_t)(value >> 40),
47 (uint8_t)(value >> 32), (uint8_t)(value >> 24), (uint8_t)(value >> 16),
48 (uint8_t)(value >> 8), (uint8_t)value};
49 write(b, 8U);
50 }
51
getBe64()52 uint64_t Stream::getBe64() {
53 uint8_t b[8] = {0, 0, 0, 0, 0, 0, 0, 0};
54 read(b, 8U);
55 return ((uint64_t)b[0] << 56) | ((uint64_t)b[1] << 48) | ((uint64_t)b[2] << 40) |
56 ((uint64_t)b[3] << 32) | ((uint64_t)b[4] << 24) | ((uint64_t)b[5] << 16) |
57 ((uint64_t)b[6] << 8) | (uint64_t)b[7];
58 }
59
putFloat(float v)60 void Stream::putFloat(float v) {
61 union {
62 float f;
63 uint8_t bytes[sizeof(float)];
64 } u;
65 u.f
66 = v;
67 this->write(u.bytes, sizeof(u.bytes));
68 }
69
getFloat()70 float Stream::getFloat() {
71 union {
72 float f;
73 uint8_t bytes[sizeof(float)];
74 } u;
75 this->read(u.bytes, sizeof(u.bytes));
76 return u.f;
77 }
78
putString(const char * str)79 void Stream::putString(const char* str) { putString(str, strlen(str)); }
80
putString(const char * str,size_t len)81 void Stream::putString(const char* str, size_t len) {
82 this->putBe32(len);
83 this->write(str, len);
84 }
85
putString(const std::string & str)86 void Stream::putString(const std::string& str) { putString(str.c_str()); }
87
getString()88 std::string Stream::getString() {
89 std::string result;
90 size_t len = this->getBe32();
91 if (len > 0) {
92 result.resize(len);
93 if (this->read(&result[0], len) != static_cast<ssize_t>(len)) {
94 result.clear();
95 }
96 }
97 #ifdef _WIN32
98 else {
99 // std::string in GCC's STL still uses copy on write implementation
100 // with a single shared buffer for an empty string. Its dtor has
101 // a check for that shared buffer, and it deallocates memory only if
102 // the current string's instance address != shared empty string address
103 // Unfortunately, in Windows DLLs each DLL has its own copy of this
104 // empty string (that's just the way Windows DLLs work), so if this
105 // code creates an empty string and passes it over into another module,
106 // that module's std::string::~string() will compare address with its
107 // empty string object, find that they are different and will try to
108 // free() a static object.
109 // To mitigate it we make sure the string allocates something, so it
110 // isn't empty internally and dtor is OK to delete the storage.
111 result.reserve(1);
112 }
113 #endif
114 return result;
115 }
116
putPackedNum(uint64_t num)117 void Stream::putPackedNum(uint64_t num) {
118 do {
119 auto byte = uint8_t(num & 0x7f);
120 num >>= 7;
121 if (num) {
122 byte |= 0x80;
123 }
124 putByte(byte);
125 } while (num != 0);
126 }
127
getPackedNum()128 uint64_t Stream::getPackedNum() {
129 uint64_t res = 0;
130 uint8_t byte;
131 int i = 0;
132 do {
133 byte = getByte();
134 res |= uint64_t(byte & 0x7f) << (i++ * 7);
135 } while (byte & 0x80 && i < 10);
136 return res;
137 }
138
putPackedSignedNum(int64_t num)139 void Stream::putPackedSignedNum(int64_t num) {
140 if (num >= 0) {
141 assert((uint64_t(num) & (1ULL << 63)) == 0);
142 putPackedNum(uint64_t(num) << 1);
143 } else {
144 assert((uint64_t(-num) & (1ULL << 63)) == 0);
145 putPackedNum((uint64_t(-num) << 1) | 1);
146 }
147 }
148
getPackedSignedNum()149 int64_t Stream::getPackedSignedNum() {
150 auto num = getPackedNum();
151 auto sign = num & 1;
152 return sign ? -int64_t(num >> 1) : (num >> 1);
153 }
154
155 // Static big-endian conversions
156
157 // the |v| pointer is unlikely to be aligned---use memcpy throughout
158
toByte(uint8_t *)159 void Stream::toByte(uint8_t*) {} // no conversion
160
toBe16(uint8_t * v)161 void Stream::toBe16(uint8_t* v) {
162 uint16_t value;
163 memcpy(&value, v, sizeof(uint16_t));
164 uint8_t b[2] = {(uint8_t)(value >> 8), (uint8_t)value};
165 memcpy(v, b, sizeof(uint16_t));
166 }
167
toBe32(uint8_t * v)168 void Stream::toBe32(uint8_t* v) {
169 uint32_t value;
170 memcpy(&value, v, sizeof(uint32_t));
171 uint8_t b[4] = {(uint8_t)(value >> 24), (uint8_t)(value >> 16), (uint8_t)(value >> 8),
172 (uint8_t)value};
173 memcpy(v, b, sizeof(uint32_t));
174 }
175
toBe64(uint8_t * v)176 void Stream::toBe64(uint8_t* v) {
177 uint64_t value;
178 memcpy(&value, v, sizeof(uint64_t));
179 uint8_t b[8] = {(uint8_t)(value >> 56), (uint8_t)(value >> 48), (uint8_t)(value >> 40),
180 (uint8_t)(value >> 32), (uint8_t)(value >> 24), (uint8_t)(value >> 16),
181 (uint8_t)(value >> 8), (uint8_t)value};
182 memcpy(v, b, sizeof(uint64_t));
183 }
184
fromByte(uint8_t *)185 void Stream::fromByte(uint8_t*) {} // no conversion
186
fromBe16(uint8_t * v)187 void Stream::fromBe16(uint8_t* v) {
188 uint8_t b[2];
189 memcpy(b, v, sizeof(uint16_t));
190 uint16_t value = ((uint16_t)b[0] << 8) | (uint16_t)b[1];
191 memcpy(v, &value, sizeof(uint16_t));
192 }
193
fromBe32(uint8_t * v)194 void Stream::fromBe32(uint8_t* v) {
195 uint8_t b[4];
196 memcpy(b, v, sizeof(uint32_t));
197 uint32_t value =
198 ((uint32_t)b[0] << 24) | ((uint32_t)b[1] << 16) | ((uint32_t)b[2] << 8) | (uint32_t)b[3];
199 memcpy(v, &value, sizeof(uint32_t));
200 }
201
fromBe64(uint8_t * v)202 void Stream::fromBe64(uint8_t* v) {
203 uint8_t b[8];
204 memcpy(b, v, sizeof(uint64_t));
205 uint64_t value = ((uint64_t)b[0] << 56) | ((uint64_t)b[1] << 48) | ((uint64_t)b[2] << 40) |
206 ((uint64_t)b[3] << 32) | ((uint64_t)b[4] << 24) | ((uint64_t)b[5] << 16) |
207 ((uint64_t)b[6] << 8) | (uint64_t)b[7];
208 memcpy(v, &value, sizeof(uint64_t));
209 }
210
saveStringArray(Stream * stream,const char * const * strings,uint32_t count)211 void saveStringArray(Stream* stream, const char* const* strings, uint32_t count) {
212 stream->putBe32(count);
213 for (uint32_t i = 0; i < count; ++i) {
214 stream->putString(strings[i]);
215 }
216 }
217
218 } // namespace aemu
219 } // namespace gfxstream
220