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
24namespace android {
25namespace util {
26
27const size_t BUFFER_SIZE = 8 * 1024; // 8 KB
28
29EncodedBuffer::Pointer::Pointer() : Pointer(BUFFER_SIZE)
30{
31}
32
33EncodedBuffer::Pointer::Pointer(size_t chunkSize)
34        :mIndex(0),
35         mOffset(0)
36{
37    mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
38}
39
40size_t
41EncodedBuffer::Pointer::pos() const
42{
43    return mIndex * mChunkSize + mOffset;
44}
45
46size_t
47EncodedBuffer::Pointer::index() const
48{
49    return mIndex;
50}
51
52size_t
53EncodedBuffer::Pointer::offset() const
54{
55    return mOffset;
56}
57
58EncodedBuffer::Pointer*
59EncodedBuffer::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
67EncodedBuffer::Pointer*
68EncodedBuffer::Pointer::rewind()
69{
70    mIndex = 0;
71    mOffset = 0;
72    return this;
73}
74
75EncodedBuffer::Pointer
76EncodedBuffer::Pointer::copy() const
77{
78    Pointer p = Pointer(mChunkSize);
79    p.mIndex = mIndex;
80    p.mOffset = mOffset;
81    return p;
82}
83
84// ===========================================================
85EncodedBuffer::EncodedBuffer() : EncodedBuffer(0)
86{
87}
88
89EncodedBuffer::EncodedBuffer(size_t chunkSize)
90        :mBuffers()
91{
92    mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
93    mWp = Pointer(mChunkSize);
94    mEp = Pointer(mChunkSize);
95}
96
97EncodedBuffer::~EncodedBuffer()
98{
99    for (size_t i=0; i<mBuffers.size(); i++) {
100        uint8_t* buf = mBuffers[i];
101        free(buf);
102    }
103}
104
105inline uint8_t*
106EncodedBuffer::at(const Pointer& p) const
107{
108    return mBuffers[p.index()] + p.offset();
109}
110
111void
112EncodedBuffer::clear()
113{
114    mWp.rewind();
115    mEp.rewind();
116}
117
118/******************************** Write APIs ************************************************/
119size_t
120EncodedBuffer::size() const
121{
122    return mWp.pos();
123}
124
125EncodedBuffer::Pointer*
126EncodedBuffer::wp()
127{
128    return &mWp;
129}
130
131uint8_t*
132EncodedBuffer::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
147size_t
148EncodedBuffer::currentToWrite()
149{
150    return mChunkSize - mWp.offset();
151}
152
153void
154EncodedBuffer::writeRawByte(uint8_t val)
155{
156    *writeBuffer() = val;
157    mWp.move();
158}
159
160size_t
161EncodedBuffer::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
176size_t
177EncodedBuffer::writeRawVarint32(uint32_t val)
178{
179    uint64_t v =(uint64_t)val;
180    return writeRawVarint64(v);
181}
182
183void
184EncodedBuffer::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
192void
193EncodedBuffer::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
205size_t
206EncodedBuffer::writeHeader(uint32_t fieldId, uint8_t wireType)
207{
208    return writeRawVarint32((fieldId << FIELD_ID_SHIFT) | wireType);
209}
210
211/******************************** Edit APIs ************************************************/
212EncodedBuffer::Pointer*
213EncodedBuffer::ep()
214{
215    return &mEp;
216}
217
218uint8_t
219EncodedBuffer::readRawByte()
220{
221    uint8_t val = *at(mEp);
222    mEp.move();
223    return val;
224}
225
226uint64_t
227EncodedBuffer::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
240uint32_t
241EncodedBuffer::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
250uint64_t
251EncodedBuffer::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
260void
261EncodedBuffer::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
272void
273EncodedBuffer::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 ************************************************/
286EncodedBuffer::iterator
287EncodedBuffer::begin() const
288{
289    return EncodedBuffer::iterator(*this);
290}
291
292EncodedBuffer::iterator::iterator(const EncodedBuffer& buffer)
293        :mData(buffer),
294         mRp(buffer.mChunkSize)
295{
296}
297
298size_t
299EncodedBuffer::iterator::size() const
300{
301    return mData.size();
302}
303
304size_t
305EncodedBuffer::iterator::bytesRead() const
306{
307    return mRp.pos();
308}
309
310EncodedBuffer::Pointer*
311EncodedBuffer::iterator::rp()
312{
313    return &mRp;
314}
315
316uint8_t const*
317EncodedBuffer::iterator::readBuffer()
318{
319    return hasNext() ? const_cast<uint8_t const*>(mData.at(mRp)) : NULL;
320}
321
322size_t
323EncodedBuffer::iterator::currentToRead()
324{
325    return (mData.mWp.index() > mRp.index()) ?
326            mData.mChunkSize - mRp.offset() :
327            mData.mWp.offset() - mRp.offset();
328}
329
330bool
331EncodedBuffer::iterator::hasNext()
332{
333    return mRp.pos() < mData.mWp.pos();
334}
335
336uint8_t
337EncodedBuffer::iterator::next()
338{
339    uint8_t res = *(mData.at(mRp));
340    mRp.move();
341    return res;
342}
343
344uint64_t
345EncodedBuffer::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