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 "android/base/files/Stream.h"
16
17 #include <assert.h>
18 #include <string.h>
19
20 namespace android {
21 namespace base {
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(StringView str)106 void Stream::putString(StringView str) {
107 this->putBe32(str.size());
108 this->write(str.data(), str.size());
109 }
110
putString(const char * str)111 void Stream::putString(const char* str) {
112 putString(StringView(str));
113 }
114
putString(const char * str,size_t len)115 void Stream::putString(const char* str, size_t len) {
116 putString(StringView(str, len));
117 }
118
getString()119 std::string Stream::getString() {
120 std::string result;
121 size_t len = this->getBe32();
122 if (len > 0) {
123 result.resize(len);
124 if (this->read(&result[0], len) != static_cast<ssize_t>(len)) {
125 result.clear();
126 }
127 }
128 #ifdef _WIN32
129 else {
130 // std::string in GCC's STL still uses copy on write implementation
131 // with a single shared buffer for an empty string. Its dtor has
132 // a check for that shared buffer, and it deallocates memory only if
133 // the current string's instance address != shared empty string address
134 // Unfortunately, in Windows DLLs each DLL has its own copy of this
135 // empty string (that's just the way Windows DLLs work), so if this
136 // code creates an empty string and passes it over into another module,
137 // that module's std::string::~string() will compare address with its
138 // empty string object, find that they are different and will try to
139 // free() a static object.
140 // To mitigate it we make sure the string allocates something, so it
141 // isn't empty internally and dtor is OK to delete the storage.
142 result.reserve(1);
143 }
144 #endif
145 return result;
146 }
147
putPackedNum(uint64_t num)148 void Stream::putPackedNum(uint64_t num) {
149 do {
150 auto byte = uint8_t(num & 0x7f);
151 num >>= 7;
152 if (num) {
153 byte |= 0x80;
154 }
155 putByte(byte);
156 } while (num != 0);
157 }
158
getPackedNum()159 uint64_t Stream::getPackedNum() {
160 uint64_t res = 0;
161 uint8_t byte;
162 int i = 0;
163 do {
164 byte = getByte();
165 res |= uint64_t(byte & 0x7f) << (i++ * 7);
166 } while (byte & 0x80 && i < 10);
167 return res;
168 }
169
putPackedSignedNum(int64_t num)170 void Stream::putPackedSignedNum(int64_t num) {
171 if (num >= 0) {
172 assert((uint64_t(num) & (1ULL << 63)) == 0);
173 putPackedNum(uint64_t(num) << 1);
174 } else {
175 assert((uint64_t(-num) & (1ULL << 63)) == 0);
176 putPackedNum((uint64_t(-num) << 1) | 1);
177 }
178 }
179
getPackedSignedNum()180 int64_t Stream::getPackedSignedNum() {
181 auto num = getPackedNum();
182 auto sign = num & 1;
183 return sign ? -int64_t(num >> 1) : (num >> 1);
184 }
185
186 } // namespace base
187 } // namespace android
188