1 /*
2 * Copyright (C) 2016 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 <nvram/messages/io.h>
18
19 extern "C" {
20 #include <string.h>
21 }
22
23 #include <nvram/messages/compiler.h>
24
25 namespace nvram {
26 namespace {
27
28 template <typename T>
min(T x,T y)29 T min(T x, T y) {
30 return x < y ? x : y;
31 }
32
33 template <typename T>
max(T x,T y)34 T max(T x, T y) {
35 return x > y ? x : y;
36 }
37
38 // Encodes |value| in varint format and writes the result to |stream|.
EncodeVarint(OutputStreamBuffer * stream,uint64_t value)39 bool EncodeVarint(OutputStreamBuffer* stream, uint64_t value) {
40 do {
41 uint8_t byte = (value & 0x7f) | (((value >> 7) == 0) ? 0x00 : 0x80);
42 if (!stream->WriteByte(byte)) {
43 return false;
44 }
45 value >>= 7;
46 } while (value != 0);
47 return true;
48 }
49
50 // Read a varint-encoded number from stream, decode it and store the result in
51 // |value|.
DecodeVarint(InputStreamBuffer * stream_buffer,uint64_t * value)52 bool DecodeVarint(InputStreamBuffer* stream_buffer, uint64_t* value) {
53 // Maximum number of bytes required to encode an |uint64_t| as varint. Each
54 // byte in a varint has 7 payload bytes, so encoding 64 bits yields at most 10
55 // bytes.
56 static constexpr int kMaxVarintBytes = 10;
57
58 *value = 0;
59 for (int i = 0; i < kMaxVarintBytes; ++i) {
60 uint8_t byte = 0;
61 if (!stream_buffer->ReadByte(&byte)) {
62 return false;
63 }
64 *value |= static_cast<uint64_t>(byte & 0x7f) << (i * 7);
65 if ((byte & 0x80) == 0) {
66 return true;
67 }
68 }
69 return false;
70 }
71
72 } // namespace
73
InputStreamBuffer(const void * data,size_t size)74 InputStreamBuffer::InputStreamBuffer(const void* data, size_t size)
75 : InputStreamBuffer(data, static_cast<const uint8_t*>(data) + size) {}
76
InputStreamBuffer(const void * start,const void * end)77 InputStreamBuffer::InputStreamBuffer(const void* start, const void* end)
78 : pos_(static_cast<const uint8_t*>(start)),
79 end_(static_cast<const uint8_t*>(end)) {
80 NVRAM_CHECK(pos_ <= end_);
81 }
82
Done()83 bool InputStreamBuffer::Done() {
84 return pos_ >= end_ && !Advance();
85 }
86
Read(void * data,size_t size)87 bool InputStreamBuffer::Read(void* data, size_t size) {
88 uint8_t* buffer = static_cast<uint8_t*>(data);
89 NVRAM_CHECK(pos_ <= end_);
90 while (size > static_cast<size_t>(end_ - pos_)) {
91 memcpy(buffer, pos_, end_ - pos_);
92 buffer += end_ - pos_;
93 size -= end_ - pos_;
94 pos_ = end_;
95 if (!Advance()) {
96 return false;
97 }
98 NVRAM_CHECK(pos_ < end_);
99 }
100 memcpy(buffer, pos_, size);
101 pos_ += size;
102 return true;
103 }
104
ReadByte(uint8_t * byte)105 bool InputStreamBuffer::ReadByte(uint8_t* byte) {
106 if (pos_ >= end_) {
107 if (!Advance()) {
108 return false;
109 }
110 NVRAM_CHECK(pos_ < end_);
111 }
112 *byte = *pos_;
113 ++pos_;
114 return true;
115 }
116
Skip(size_t size)117 bool InputStreamBuffer::Skip(size_t size) {
118 NVRAM_CHECK(pos_ <= end_);
119 while (size > static_cast<size_t>(end_ - pos_)) {
120 size -= end_ - pos_;
121 pos_ = end_;
122 if (!Advance()) {
123 return false;
124 }
125 NVRAM_CHECK(pos_ < end_);
126 }
127 pos_ += size;
128 return true;
129 }
130
Advance()131 bool InputStreamBuffer::Advance() {
132 return false;
133 }
134
NestedInputStreamBuffer(InputStreamBuffer * delegate,size_t size)135 NestedInputStreamBuffer::NestedInputStreamBuffer(InputStreamBuffer* delegate,
136 size_t size)
137 : InputStreamBuffer(delegate->pos_, ClampEnd(delegate, size)),
138 delegate_(delegate),
139 remaining_(size) {}
140
Advance()141 bool NestedInputStreamBuffer::Advance() {
142 remaining_ -= end_ - delegate_->pos_;
143 if (remaining_ == 0) {
144 delegate_->pos_ = end_;
145 return false;
146 }
147 bool status = delegate_->Advance();
148 pos_ = delegate_->pos_;
149 end_ = ClampEnd(delegate_, remaining_);
150 return status;
151 }
152
153 // static
ClampEnd(InputStreamBuffer * delegate,size_t size)154 const uint8_t* NestedInputStreamBuffer::ClampEnd(InputStreamBuffer* delegate,
155 size_t size) {
156 NVRAM_CHECK(delegate->pos_ <= delegate->end_);
157 return size < static_cast<size_t>(delegate->end_ - delegate->pos_)
158 ? delegate->pos_ + size
159 : delegate->end_;
160 }
161
OutputStreamBuffer(void * data,size_t size)162 OutputStreamBuffer::OutputStreamBuffer(void* data, size_t size)
163 : OutputStreamBuffer(data, static_cast<uint8_t*>(data) + size) {}
164
OutputStreamBuffer(void * start,void * end)165 OutputStreamBuffer::OutputStreamBuffer(void* start, void* end)
166 : pos_(static_cast<uint8_t*>(start)), end_(static_cast<uint8_t*>(end)) {
167 NVRAM_CHECK(pos_ <= end_);
168 }
169
Done()170 bool OutputStreamBuffer::Done() {
171 return pos_ >= end_ && !Advance();
172 }
173
Write(const void * data,size_t size)174 bool OutputStreamBuffer::Write(const void* data, size_t size) {
175 const uint8_t* buffer = static_cast<const uint8_t*>(data);
176 NVRAM_CHECK(pos_ <= end_);
177 while (size > static_cast<size_t>(end_ - pos_)) {
178 memcpy(pos_, buffer, end_ - pos_);
179 buffer += end_ - pos_;
180 size -= end_ - pos_;
181 pos_ = end_;
182 if (!Advance()) {
183 return false;
184 }
185 NVRAM_CHECK(pos_ < end_);
186 }
187 memcpy(pos_, buffer, size);
188 pos_ += size;
189 return true;
190 }
191
WriteByte(uint8_t byte)192 bool OutputStreamBuffer::WriteByte(uint8_t byte) {
193 if (pos_ >= end_) {
194 if (!Advance()) {
195 return false;
196 }
197 NVRAM_CHECK(pos_ < end_);
198 }
199 *pos_ = byte;
200 ++pos_;
201 return true;
202 }
203
Advance()204 bool OutputStreamBuffer::Advance() {
205 return false;
206 }
207
CountingOutputStreamBuffer()208 CountingOutputStreamBuffer::CountingOutputStreamBuffer()
209 : OutputStreamBuffer(scratch_space_, kScratchSpaceSize) {}
210
Advance()211 bool CountingOutputStreamBuffer::Advance() {
212 bytes_written_ += pos_ - scratch_space_;
213 pos_ = scratch_space_;
214 end_ = scratch_space_ + kScratchSpaceSize;
215 return true;
216 }
217
218 uint8_t CountingOutputStreamBuffer::scratch_space_[kScratchSpaceSize];
219
BlobOutputStreamBuffer(Blob * blob)220 BlobOutputStreamBuffer::BlobOutputStreamBuffer(Blob* blob)
221 : OutputStreamBuffer(blob->data(), blob->size()), blob_(blob) {}
222
Advance()223 bool BlobOutputStreamBuffer::Advance() {
224 ptrdiff_t offset = pos_ - blob_->data();
225 if (!blob_->Resize(max<size_t>(blob_->size() * 2, 32))) {
226 return false;
227 }
228 pos_ = blob_->data() + offset;
229 end_ = blob_->data() + blob_->size();
230 return true;
231 }
232
Truncate()233 bool BlobOutputStreamBuffer::Truncate() {
234 if (!blob_->Resize(pos_ - blob_->data())) {
235 return false;
236 }
237 end_ = blob_->data() + blob_->size();
238 pos_ = end_;
239 return true;
240 }
241
ProtoReader(InputStreamBuffer * stream_buffer)242 ProtoReader::ProtoReader(InputStreamBuffer* stream_buffer)
243 : stream_buffer_(stream_buffer) {}
244
ReadWireTag()245 bool ProtoReader::ReadWireTag() {
246 uint64_t wire_tag;
247 if (!DecodeVarint(stream_buffer_, &wire_tag)) {
248 return false;
249 }
250
251 wire_type_ = wire_tag & 0x7;
252 field_number_ = wire_tag >> 3;
253 switch (wire_type()) {
254 case WireType::kLengthDelimited: {
255 uint64_t size;
256 if (!DecodeVarint(stream_buffer_, &size)) {
257 return false;
258 }
259 field_size_ = static_cast<size_t>(size);
260 if (static_cast<uint64_t>(field_size_) != size) {
261 return false;
262 }
263 break;
264 }
265 case WireType::kFixed64:
266 field_size_ = sizeof(uint64_t);
267 break;
268 case WireType::kFixed32:
269 field_size_ = sizeof(uint32_t);
270 break;
271 case WireType::kVarint:
272 case WireType::kStartGroup:
273 case WireType::kEndGroup:
274 field_size_ = 0;
275 break;
276 }
277
278 return true;
279 }
280
ReadVarint(uint64_t * value)281 bool ProtoReader::ReadVarint(uint64_t* value) {
282 NVRAM_CHECK(wire_type() == WireType::kVarint);
283 return DecodeVarint(stream_buffer_, value);
284 }
285
ReadLengthDelimited(void * data,size_t size)286 bool ProtoReader::ReadLengthDelimited(void* data, size_t size) {
287 NVRAM_CHECK(wire_type() == WireType::kLengthDelimited);
288 return stream_buffer_->Read(data, size);
289 }
290
SkipField()291 bool ProtoReader::SkipField() {
292 if (wire_type() == WireType::kVarint) {
293 uint64_t dummy;
294 return DecodeVarint(stream_buffer_, &dummy);
295 } else if (field_size_ > 0) {
296 return stream_buffer_->Skip(field_size_);
297 }
298
299 return true;
300 }
301
ProtoWriter(OutputStreamBuffer * stream_buffer)302 ProtoWriter::ProtoWriter(OutputStreamBuffer* stream_buffer)
303 : stream_buffer_(stream_buffer) {}
304
WriteVarint(uint64_t value)305 bool ProtoWriter::WriteVarint(uint64_t value) {
306 return WriteWireTag(WireType::kVarint) &&
307 EncodeVarint(stream_buffer_, value);
308 }
309
WriteLengthDelimited(const void * data,size_t size)310 bool ProtoWriter::WriteLengthDelimited(const void* data, size_t size) {
311 return WriteWireTag(WireType::kLengthDelimited) &&
312 EncodeVarint(stream_buffer_, size) &&
313 stream_buffer_->Write(data, size);
314 }
315
WriteLengthHeader(size_t size)316 bool ProtoWriter::WriteLengthHeader(size_t size) {
317 return WriteWireTag(WireType::kLengthDelimited) &&
318 EncodeVarint(stream_buffer_, size);
319 }
320
WriteWireTag(WireType wire_type)321 bool ProtoWriter::WriteWireTag(WireType wire_type) {
322 return EncodeVarint(stream_buffer_,
323 (field_number_ << 3) | static_cast<uint64_t>(wire_type));
324 }
325
326 } // namespace nvram
327