1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #define LOG_TAG "libprotoutil"
17
18 #include <stdlib.h>
19
20 #include <android/util/EncodedBuffer.h>
21 #include <android/util/protobuf.h>
22 #include <cutils/log.h>
23
24 namespace android {
25 namespace util {
26
27 const size_t BUFFER_SIZE = 8 * 1024; // 8 KB
28
Pointer()29 EncodedBuffer::Pointer::Pointer() : Pointer(BUFFER_SIZE)
30 {
31 }
32
Pointer(size_t chunkSize)33 EncodedBuffer::Pointer::Pointer(size_t chunkSize)
34 :mIndex(0),
35 mOffset(0)
36 {
37 mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
38 }
39
40 size_t
pos() const41 EncodedBuffer::Pointer::pos() const
42 {
43 return mIndex * mChunkSize + mOffset;
44 }
45
46 size_t
index() const47 EncodedBuffer::Pointer::index() const
48 {
49 return mIndex;
50 }
51
52 size_t
offset() const53 EncodedBuffer::Pointer::offset() const
54 {
55 return mOffset;
56 }
57
58 EncodedBuffer::Pointer*
move(size_t amt)59 EncodedBuffer::Pointer::move(size_t amt)
60 {
61 size_t newOffset = mOffset + amt;
62 mIndex += newOffset / mChunkSize;
63 mOffset = newOffset % mChunkSize;
64 return this;
65 }
66
67 EncodedBuffer::Pointer*
rewind()68 EncodedBuffer::Pointer::rewind()
69 {
70 mIndex = 0;
71 mOffset = 0;
72 return this;
73 }
74
75 EncodedBuffer::Pointer
copy() const76 EncodedBuffer::Pointer::copy() const
77 {
78 Pointer p = Pointer(mChunkSize);
79 p.mIndex = mIndex;
80 p.mOffset = mOffset;
81 return p;
82 }
83
84 // ===========================================================
EncodedBuffer()85 EncodedBuffer::EncodedBuffer() : EncodedBuffer(0)
86 {
87 }
88
EncodedBuffer(size_t chunkSize)89 EncodedBuffer::EncodedBuffer(size_t chunkSize)
90 :mBuffers()
91 {
92 mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
93 mWp = Pointer(mChunkSize);
94 mEp = Pointer(mChunkSize);
95 }
96
~EncodedBuffer()97 EncodedBuffer::~EncodedBuffer()
98 {
99 for (size_t i=0; i<mBuffers.size(); i++) {
100 uint8_t* buf = mBuffers[i];
101 free(buf);
102 }
103 }
104
105 inline uint8_t*
at(const Pointer & p) const106 EncodedBuffer::at(const Pointer& p) const
107 {
108 return mBuffers[p.index()] + p.offset();
109 }
110
111 void
clear()112 EncodedBuffer::clear()
113 {
114 mWp.rewind();
115 mEp.rewind();
116 }
117
118 /******************************** Write APIs ************************************************/
119 size_t
size() const120 EncodedBuffer::size() const
121 {
122 return mWp.pos();
123 }
124
125 EncodedBuffer::Pointer*
wp()126 EncodedBuffer::wp()
127 {
128 return &mWp;
129 }
130
131 uint8_t*
writeBuffer()132 EncodedBuffer::writeBuffer()
133 {
134 // This prevents write pointer move too fast than allocating the buffer.
135 if (mWp.index() > mBuffers.size()) return NULL;
136 uint8_t* buf = NULL;
137 if (mWp.index() == mBuffers.size()) {
138 buf = (uint8_t*)malloc(mChunkSize);
139
140 if (buf == NULL) return NULL; // This indicates NO_MEMORY
141
142 mBuffers.push_back(buf);
143 }
144 return at(mWp);
145 }
146
147 size_t
currentToWrite()148 EncodedBuffer::currentToWrite()
149 {
150 return mChunkSize - mWp.offset();
151 }
152
153 void
writeRawByte(uint8_t val)154 EncodedBuffer::writeRawByte(uint8_t val)
155 {
156 *writeBuffer() = val;
157 mWp.move();
158 }
159
160 size_t
writeRawVarint64(uint64_t val)161 EncodedBuffer::writeRawVarint64(uint64_t val)
162 {
163 size_t size = 0;
164 while (true) {
165 size++;
166 if ((val & ~0x7F) == 0) {
167 writeRawByte((uint8_t) val);
168 return size;
169 } else {
170 writeRawByte((uint8_t)((val & 0x7F) | 0x80));
171 val >>= 7;
172 }
173 }
174 }
175
176 size_t
writeRawVarint32(uint32_t val)177 EncodedBuffer::writeRawVarint32(uint32_t val)
178 {
179 uint64_t v =(uint64_t)val;
180 return writeRawVarint64(v);
181 }
182
183 void
writeRawFixed32(uint32_t val)184 EncodedBuffer::writeRawFixed32(uint32_t val)
185 {
186 writeRawByte((uint8_t) val);
187 writeRawByte((uint8_t) (val>>8));
188 writeRawByte((uint8_t) (val>>16));
189 writeRawByte((uint8_t) (val>>24));
190 }
191
192 void
writeRawFixed64(uint64_t val)193 EncodedBuffer::writeRawFixed64(uint64_t val)
194 {
195 writeRawByte((uint8_t) val);
196 writeRawByte((uint8_t) (val>>8));
197 writeRawByte((uint8_t) (val>>16));
198 writeRawByte((uint8_t) (val>>24));
199 writeRawByte((uint8_t) (val>>32));
200 writeRawByte((uint8_t) (val>>40));
201 writeRawByte((uint8_t) (val>>48));
202 writeRawByte((uint8_t) (val>>56));
203 }
204
205 size_t
writeHeader(uint32_t fieldId,uint8_t wireType)206 EncodedBuffer::writeHeader(uint32_t fieldId, uint8_t wireType)
207 {
208 return writeRawVarint32((fieldId << FIELD_ID_SHIFT) | wireType);
209 }
210
211 /******************************** Edit APIs ************************************************/
212 EncodedBuffer::Pointer*
ep()213 EncodedBuffer::ep()
214 {
215 return &mEp;
216 }
217
218 uint8_t
readRawByte()219 EncodedBuffer::readRawByte()
220 {
221 uint8_t val = *at(mEp);
222 mEp.move();
223 return val;
224 }
225
226 uint64_t
readRawVarint()227 EncodedBuffer::readRawVarint()
228 {
229 uint64_t val = 0, shift = 0;
230 size_t start = mEp.pos();
231 while (true) {
232 uint8_t byte = readRawByte();
233 val |= (UINT64_C(0x7F) & byte) << shift;
234 if ((byte & 0x80) == 0) break;
235 shift += 7;
236 }
237 return val;
238 }
239
240 uint32_t
readRawFixed32()241 EncodedBuffer::readRawFixed32()
242 {
243 uint32_t val = 0;
244 for (auto i=0; i<32; i+=8) {
245 val += (uint32_t)readRawByte() << i;
246 }
247 return val;
248 }
249
250 uint64_t
readRawFixed64()251 EncodedBuffer::readRawFixed64()
252 {
253 uint64_t val = 0;
254 for (auto i=0; i<64; i+=8) {
255 val += (uint64_t)readRawByte() << i;
256 }
257 return val;
258 }
259
260 void
editRawFixed32(size_t pos,uint32_t val)261 EncodedBuffer::editRawFixed32(size_t pos, uint32_t val)
262 {
263 size_t oldPos = mEp.pos();
264 mEp.rewind()->move(pos);
265 for (auto i=0; i<32; i+=8) {
266 *at(mEp) = (uint8_t) (val >> i);
267 mEp.move();
268 }
269 mEp.rewind()->move(oldPos);
270 }
271
272 void
copy(size_t srcPos,size_t size)273 EncodedBuffer::copy(size_t srcPos, size_t size)
274 {
275 if (size == 0) return;
276 Pointer cp(mChunkSize);
277 cp.move(srcPos);
278
279 while (cp.pos() < srcPos + size) {
280 writeRawByte(*at(cp));
281 cp.move();
282 }
283 }
284
285 /********************************* Read APIs ************************************************/
286 EncodedBuffer::iterator
begin() const287 EncodedBuffer::begin() const
288 {
289 return EncodedBuffer::iterator(*this);
290 }
291
iterator(const EncodedBuffer & buffer)292 EncodedBuffer::iterator::iterator(const EncodedBuffer& buffer)
293 :mData(buffer),
294 mRp(buffer.mChunkSize)
295 {
296 }
297
298 size_t
size() const299 EncodedBuffer::iterator::size() const
300 {
301 return mData.size();
302 }
303
304 size_t
bytesRead() const305 EncodedBuffer::iterator::bytesRead() const
306 {
307 return mRp.pos();
308 }
309
310 EncodedBuffer::Pointer*
rp()311 EncodedBuffer::iterator::rp()
312 {
313 return &mRp;
314 }
315
316 uint8_t const*
readBuffer()317 EncodedBuffer::iterator::readBuffer()
318 {
319 return hasNext() ? const_cast<uint8_t const*>(mData.at(mRp)) : NULL;
320 }
321
322 size_t
currentToRead()323 EncodedBuffer::iterator::currentToRead()
324 {
325 return (mData.mWp.index() > mRp.index()) ?
326 mData.mChunkSize - mRp.offset() :
327 mData.mWp.offset() - mRp.offset();
328 }
329
330 bool
hasNext()331 EncodedBuffer::iterator::hasNext()
332 {
333 return mRp.pos() < mData.mWp.pos();
334 }
335
336 uint8_t
next()337 EncodedBuffer::iterator::next()
338 {
339 uint8_t res = *(mData.at(mRp));
340 mRp.move();
341 return res;
342 }
343
344 uint64_t
readRawVarint()345 EncodedBuffer::iterator::readRawVarint()
346 {
347 uint64_t val = 0, shift = 0;
348 while (true) {
349 uint8_t byte = next();
350 val |= (INT64_C(0x7F) & byte) << shift;
351 if ((byte & 0x80) == 0) break;
352 shift += 7;
353 }
354 return val;
355 }
356
357 } // util
358 } // android
359