blob: 84dc5b6d7852d79a8c81ea35d2acb6278004a841 [file] [log] [blame]
Yi Jinc23fad22017-09-15 17:24:59 -07001/*
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
17#include <android/util/EncodedBuffer.h>
18
19#include <stdlib.h>
20
21namespace android {
22namespace util {
23
24const size_t BUFFER_SIZE = 8 * 1024; // 8 KB
25
26EncodedBuffer::Pointer::Pointer() : Pointer(BUFFER_SIZE)
27{
28}
29
30EncodedBuffer::Pointer::Pointer(size_t chunkSize)
31 :mIndex(0),
32 mOffset(0)
33{
34 mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
35}
36
37size_t
38EncodedBuffer::Pointer::pos() const
39{
40 return mIndex * mChunkSize + mOffset;
41}
42
43size_t
44EncodedBuffer::Pointer::index() const
45{
46 return mIndex;
47}
48
49size_t
50EncodedBuffer::Pointer::offset() const
51{
52 return mOffset;
53}
54
55void
56EncodedBuffer::Pointer::move(size_t amt)
57{
58 size_t newOffset = mOffset + amt;
59 mIndex += newOffset / mChunkSize;
60 mOffset = newOffset % mChunkSize;
61}
62
63void
64EncodedBuffer::Pointer::rewind()
65{
66 mIndex = 0;
67 mOffset = 0;
68}
69
70EncodedBuffer::Pointer
71EncodedBuffer::Pointer::copy() const
72{
73 Pointer p = Pointer(mChunkSize);
74 p.mIndex = mIndex;
75 p.mOffset = mOffset;
76 return p;
77}
78
79// ===========================================================
80EncodedBuffer::EncodedBuffer() : EncodedBuffer(0)
81{
82}
83
84EncodedBuffer::EncodedBuffer(size_t chunkSize)
85 :mBuffers()
86{
87 mChunkSize = chunkSize == 0 ? BUFFER_SIZE : chunkSize;
88 mWp = Pointer(mChunkSize);
89}
90
91EncodedBuffer::~EncodedBuffer()
92{
93 for (size_t i=0; i<mBuffers.size(); i++) {
94 uint8_t* buf = mBuffers[i];
95 free(buf);
96 }
97}
98
99inline uint8_t*
100EncodedBuffer::at(const Pointer& p) const
101{
102 return mBuffers[p.index()] + p.offset();
103}
104
105/******************************** Write APIs ************************************************/
106size_t
107EncodedBuffer::size() const
108{
109 return mWp.pos();
110}
111
112EncodedBuffer::Pointer*
113EncodedBuffer::wp()
114{
115 return &mWp;
116}
117
118uint8_t*
119EncodedBuffer::writeBuffer()
120{
121 // This prevents write pointer move too fast than allocating the buffer.
122 if (mWp.index() > mBuffers.size()) return NULL;
123 uint8_t* buf = NULL;
124 if (mWp.index() == mBuffers.size()) {
125 buf = (uint8_t*)malloc(mChunkSize);
126
127 if (buf == NULL) return NULL; // This indicates NO_MEMORY
128
129 mBuffers.push_back(buf);
130 }
131 return at(mWp);
132}
133
134size_t
135EncodedBuffer::currentToWrite()
136{
137 return mChunkSize - mWp.offset();
138}
139
140size_t
141EncodedBuffer::writeRawVarint(uint32_t val)
142{
143 size_t size = 0;
144 while (true) {
145 size++;
146 if ((val & ~0x7F) == 0) {
147 *writeBuffer() = (uint8_t) val;
148 mWp.move();
149 return size;
150 } else {
151 *writeBuffer() = (uint8_t)((val & 0x7F) | 0x80);
152 mWp.move();
153 val >>= 7;
154 }
155 }
156}
157
158size_t
159EncodedBuffer::writeHeader(uint32_t fieldId, uint8_t wireType)
160{
161 return writeRawVarint((fieldId << 3) | wireType);
162}
163
164/********************************* Read APIs ************************************************/
165EncodedBuffer::iterator
166EncodedBuffer::begin() const
167{
168 return EncodedBuffer::iterator(*this);
169}
170
171EncodedBuffer::iterator::iterator(const EncodedBuffer& buffer)
172 :mData(buffer),
173 mRp(buffer.mChunkSize)
174{
175}
176
177size_t
178EncodedBuffer::iterator::size() const
179{
180 return mData.size();
181}
182
183size_t
184EncodedBuffer::iterator::bytesRead() const
185{
186 return mRp.pos();
187}
188
189EncodedBuffer::Pointer*
190EncodedBuffer::iterator::rp()
191{
192 return &mRp;
193}
194
195uint8_t const*
196EncodedBuffer::iterator::readBuffer()
197{
198 return hasNext() ? const_cast<uint8_t const*>(mData.at(mRp)) : NULL;
199}
200
201size_t
202EncodedBuffer::iterator::currentToRead()
203{
204 return (mData.mWp.index() > mRp.index()) ?
205 mData.mChunkSize - mRp.offset() :
206 mData.mWp.offset() - mRp.offset();
207}
208
209bool
210EncodedBuffer::iterator::hasNext()
211{
212 return mRp.pos() < mData.mWp.pos();
213}
214
215uint8_t
216EncodedBuffer::iterator::next()
217{
218 uint8_t res = *(mData.at(mRp));
219 mRp.move();
220 return res;
221}
222
223uint32_t
224EncodedBuffer::iterator::readRawVarint()
225{
226 uint32_t val = 0, shift = 0;
227 while (true) {
228 uint8_t byte = next();
229 val += (byte & 0x7F) << shift;
230 if ((byte & 0x80) == 0) break;
231 shift += 7;
232 }
233 return val;
234}
235
236} // util
237} // android