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 #include <sys/mman.h>
20 
21 #include <android/util/EncodedBuffer.h>
22 #include <android/util/protobuf.h>
23 #include <cutils/log.h>
24 
25 namespace android {
26 namespace util {
27 
28 const size_t BUFFER_SIZE = 8 * 1024; // 8 KB
29 
Pointer()30 EncodedBuffer::Pointer::Pointer() : Pointer(BUFFER_SIZE)
31 {
32 }
33 
Pointer(size_t chunkSize)34 EncodedBuffer::Pointer::Pointer(size_t chunkSize)
35         :mIndex(0),
36          mOffset(0)
37 {
38     mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
39 }
40 
41 size_t
pos() const42 EncodedBuffer::Pointer::pos() const
43 {
44     return mIndex * mChunkSize + mOffset;
45 }
46 
47 size_t
index() const48 EncodedBuffer::Pointer::index() const
49 {
50     return mIndex;
51 }
52 
53 size_t
offset() const54 EncodedBuffer::Pointer::offset() const
55 {
56     return mOffset;
57 }
58 
59 EncodedBuffer::Pointer*
move(size_t amt)60 EncodedBuffer::Pointer::move(size_t amt)
61 {
62     size_t newOffset = mOffset + amt;
63     mIndex += newOffset / mChunkSize;
64     mOffset = newOffset % mChunkSize;
65     return this;
66 }
67 
68 EncodedBuffer::Pointer*
rewind()69 EncodedBuffer::Pointer::rewind()
70 {
71     mIndex = 0;
72     mOffset = 0;
73     return this;
74 }
75 
76 EncodedBuffer::Pointer
copy() const77 EncodedBuffer::Pointer::copy() const
78 {
79     Pointer p = Pointer(mChunkSize);
80     p.mIndex = mIndex;
81     p.mOffset = mOffset;
82     return p;
83 }
84 
85 // ===========================================================
EncodedBuffer()86 EncodedBuffer::EncodedBuffer() : EncodedBuffer(BUFFER_SIZE)
87 {
88 }
89 
EncodedBuffer(size_t chunkSize)90 EncodedBuffer::EncodedBuffer(size_t chunkSize)
91         :mBuffers()
92 {
93     // Align chunkSize to memory page size
94     chunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
95     mChunkSize = (chunkSize / PAGE_SIZE + ((chunkSize % PAGE_SIZE == 0) ? 0 : 1)) * PAGE_SIZE;
96     mWp = Pointer(mChunkSize);
97     mEp = Pointer(mChunkSize);
98 }
99 
~EncodedBuffer()100 EncodedBuffer::~EncodedBuffer()
101 {
102     for (size_t i=0; i<mBuffers.size(); i++) {
103         uint8_t* buf = mBuffers[i];
104         munmap(buf, mChunkSize);
105     }
106 }
107 
108 inline uint8_t*
at(const Pointer & p) const109 EncodedBuffer::at(const Pointer& p) const
110 {
111     return mBuffers[p.index()] + p.offset();
112 }
113 
114 void
clear()115 EncodedBuffer::clear()
116 {
117     mWp.rewind();
118     mEp.rewind();
119 }
120 
121 /******************************** Write APIs ************************************************/
122 size_t
size() const123 EncodedBuffer::size() const
124 {
125     return mWp.pos();
126 }
127 
128 EncodedBuffer::Pointer*
wp()129 EncodedBuffer::wp()
130 {
131     return &mWp;
132 }
133 
134 uint8_t*
writeBuffer()135 EncodedBuffer::writeBuffer()
136 {
137     // This prevents write pointer move too fast than allocating the buffer.
138     if (mWp.index() > mBuffers.size()) return NULL;
139     uint8_t* buf = NULL;
140     if (mWp.index() == mBuffers.size()) {
141         // Use mmap instead of malloc to ensure memory alignment i.e. no fragmentation so that
142         // the mem region can be immediately reused by the allocator after calling munmap()
143         buf = (uint8_t*)mmap(NULL, mChunkSize, PROT_READ | PROT_WRITE,
144                 MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
145 
146         if (buf == NULL) return NULL; // This indicates NO_MEMORY
147 
148         mBuffers.push_back(buf);
149     }
150     return at(mWp);
151 }
152 
153 size_t
currentToWrite()154 EncodedBuffer::currentToWrite()
155 {
156     return mChunkSize - mWp.offset();
157 }
158 
159 void
writeRawByte(uint8_t val)160 EncodedBuffer::writeRawByte(uint8_t val)
161 {
162     *writeBuffer() = val;
163     mWp.move();
164 }
165 
166 size_t
writeRawVarint64(uint64_t val)167 EncodedBuffer::writeRawVarint64(uint64_t val)
168 {
169     size_t size = 0;
170     while (true) {
171         size++;
172         if ((val & ~0x7F) == 0) {
173             writeRawByte((uint8_t) val);
174             return size;
175         } else {
176             writeRawByte((uint8_t)((val & 0x7F) | 0x80));
177             val >>= 7;
178         }
179     }
180 }
181 
182 size_t
writeRawVarint32(uint32_t val)183 EncodedBuffer::writeRawVarint32(uint32_t val)
184 {
185     uint64_t v =(uint64_t)val;
186     return writeRawVarint64(v);
187 }
188 
189 void
writeRawFixed32(uint32_t val)190 EncodedBuffer::writeRawFixed32(uint32_t val)
191 {
192     writeRawByte((uint8_t) val);
193     writeRawByte((uint8_t) (val>>8));
194     writeRawByte((uint8_t) (val>>16));
195     writeRawByte((uint8_t) (val>>24));
196 }
197 
198 void
writeRawFixed64(uint64_t val)199 EncodedBuffer::writeRawFixed64(uint64_t val)
200 {
201     writeRawByte((uint8_t) val);
202     writeRawByte((uint8_t) (val>>8));
203     writeRawByte((uint8_t) (val>>16));
204     writeRawByte((uint8_t) (val>>24));
205     writeRawByte((uint8_t) (val>>32));
206     writeRawByte((uint8_t) (val>>40));
207     writeRawByte((uint8_t) (val>>48));
208     writeRawByte((uint8_t) (val>>56));
209 }
210 
211 size_t
writeHeader(uint32_t fieldId,uint8_t wireType)212 EncodedBuffer::writeHeader(uint32_t fieldId, uint8_t wireType)
213 {
214     return writeRawVarint32((fieldId << FIELD_ID_SHIFT) | wireType);
215 }
216 
217 status_t
writeRaw(uint8_t const * buf,size_t size)218 EncodedBuffer::writeRaw(uint8_t const* buf, size_t size)
219 {
220     while (size > 0) {
221         uint8_t* target = writeBuffer();
222         if (target == NULL) {
223             return -ENOMEM;
224         }
225         size_t chunk = currentToWrite();
226         if (chunk > size) {
227             chunk = size;
228         }
229         memcpy(target, buf, chunk);
230         size -= chunk;
231         buf += chunk;
232         mWp.move(chunk);
233     }
234     return NO_ERROR;
235 }
236 
237 status_t
writeRaw(const sp<ProtoReader> & reader)238 EncodedBuffer::writeRaw(const sp<ProtoReader>& reader)
239 {
240     status_t err;
241     uint8_t const* buf;
242     while ((buf = reader->readBuffer()) != nullptr) {
243         size_t amt = reader->currentToRead();
244         err = writeRaw(buf, amt);
245         reader->move(amt);
246         if (err != NO_ERROR) {
247             return err;
248         }
249     }
250     return NO_ERROR;
251 }
252 
253 status_t
writeRaw(const sp<ProtoReader> & reader,size_t size)254 EncodedBuffer::writeRaw(const sp<ProtoReader>& reader, size_t size)
255 {
256     status_t err;
257     uint8_t const* buf;
258     while (size > 0 && (buf = reader->readBuffer()) != nullptr) {
259         size_t amt = reader->currentToRead();
260         if (size < amt) {
261             amt = size;
262         }
263         err = writeRaw(buf, amt);
264         reader->move(amt);
265         size -= amt;
266         if (err != NO_ERROR) {
267             return err;
268         }
269     }
270     return size == 0 ? NO_ERROR : NOT_ENOUGH_DATA;
271 }
272 
273 
274 /******************************** Edit APIs ************************************************/
275 EncodedBuffer::Pointer*
ep()276 EncodedBuffer::ep()
277 {
278     return &mEp;
279 }
280 
281 uint8_t
readRawByte()282 EncodedBuffer::readRawByte()
283 {
284     uint8_t val = *at(mEp);
285     mEp.move();
286     return val;
287 }
288 
289 uint64_t
readRawVarint()290 EncodedBuffer::readRawVarint()
291 {
292     uint64_t val = 0, shift = 0;
293     size_t start = mEp.pos();
294     while (true) {
295         uint8_t byte = readRawByte();
296         val |= (UINT64_C(0x7F) & byte) << shift;
297         if ((byte & 0x80) == 0) break;
298         shift += 7;
299     }
300     return val;
301 }
302 
303 uint32_t
readRawFixed32()304 EncodedBuffer::readRawFixed32()
305 {
306     uint32_t val = 0;
307     for (auto i=0; i<32; i+=8) {
308         val += (uint32_t)readRawByte() << i;
309     }
310     return val;
311 }
312 
313 uint64_t
readRawFixed64()314 EncodedBuffer::readRawFixed64()
315 {
316     uint64_t val = 0;
317     for (auto i=0; i<64; i+=8) {
318         val += (uint64_t)readRawByte() << i;
319     }
320     return val;
321 }
322 
323 void
editRawFixed32(size_t pos,uint32_t val)324 EncodedBuffer::editRawFixed32(size_t pos, uint32_t val)
325 {
326     size_t oldPos = mEp.pos();
327     mEp.rewind()->move(pos);
328     for (auto i=0; i<32; i+=8) {
329         *at(mEp) = (uint8_t) (val >> i);
330         mEp.move();
331     }
332     mEp.rewind()->move(oldPos);
333 }
334 
335 void
copy(size_t srcPos,size_t size)336 EncodedBuffer::copy(size_t srcPos, size_t size)
337 {
338     if (size == 0) return;
339     Pointer cp(mChunkSize);
340     cp.move(srcPos);
341 
342     while (cp.pos() < srcPos + size) {
343         writeRawByte(*at(cp));
344         cp.move();
345     }
346 }
347 
348 /********************************* Read APIs ************************************************/
349 sp<ProtoReader>
read()350 EncodedBuffer::read()
351 {
352     return new EncodedBuffer::Reader(this);
353 }
354 
Reader(const sp<EncodedBuffer> & buffer)355 EncodedBuffer::Reader::Reader(const sp<EncodedBuffer>& buffer)
356         :mData(buffer),
357          mRp(buffer->mChunkSize)
358 {
359 }
360 
~Reader()361 EncodedBuffer::Reader::~Reader() {
362 }
363 
364 ssize_t
size() const365 EncodedBuffer::Reader::size() const
366 {
367     return (ssize_t)mData->size();
368 }
369 
370 size_t
bytesRead() const371 EncodedBuffer::Reader::bytesRead() const
372 {
373     return mRp.pos();
374 }
375 
376 uint8_t const*
readBuffer()377 EncodedBuffer::Reader::readBuffer()
378 {
379     return hasNext() ? const_cast<uint8_t const*>(mData->at(mRp)) : NULL;
380 }
381 
382 size_t
currentToRead()383 EncodedBuffer::Reader::currentToRead()
384 {
385     return (mData->mWp.index() > mRp.index()) ?
386             mData->mChunkSize - mRp.offset() :
387             mData->mWp.offset() - mRp.offset();
388 }
389 
390 bool
hasNext()391 EncodedBuffer::Reader::hasNext()
392 {
393     return mRp.pos() < mData->mWp.pos();
394 }
395 
396 uint8_t
next()397 EncodedBuffer::Reader::next()
398 {
399     uint8_t res = *(mData->at(mRp));
400     mRp.move();
401     return res;
402 }
403 
404 uint64_t
readRawVarint()405 EncodedBuffer::Reader::readRawVarint()
406 {
407     uint64_t val = 0, shift = 0;
408     while (true) {
409         uint8_t byte = next();
410         val |= (INT64_C(0x7F) & byte) << shift;
411         if ((byte & 0x80) == 0) break;
412         shift += 7;
413     }
414     return val;
415 }
416 
417 void
move(size_t amt)418 EncodedBuffer::Reader::move(size_t amt)
419 {
420     mRp.move(amt);
421 }
422 
423 } // util
424 } // android
425