blob: cfef347342223e2d3d775b33b11d8bc09a28fe5e [file] [log] [blame]
Mattias Nisslercdab1232016-01-25 18:40:25 +01001/*
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
Mattias Nisslera715cb12016-02-09 13:54:46 +010017#include <nvram/messages/io.h>
Mattias Nisslercdab1232016-01-25 18:40:25 +010018
19extern "C" {
20#include <string.h>
21}
22
Mattias Nisslera715cb12016-02-09 13:54:46 +010023#include <nvram/messages/compiler.h>
Mattias Nisslercdab1232016-01-25 18:40:25 +010024
25namespace nvram {
26namespace {
27
28template <typename T>
29T min(T x, T y) {
30 return x < y ? x : y;
31}
32
33template <typename T>
34T 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|.
39bool 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|.
52bool 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
Mattias Nisslercdab1232016-01-25 18:40:25 +010074InputStreamBuffer::InputStreamBuffer(const void* data, size_t size)
75 : InputStreamBuffer(data, static_cast<const uint8_t*>(data) + size) {}
76
77InputStreamBuffer::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
Mattias Nisslercdab1232016-01-25 18:40:25 +010083bool InputStreamBuffer::Done() {
84 return pos_ >= end_ && !Advance();
85}
86
87bool 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
105bool 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
117bool 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
131bool InputStreamBuffer::Advance() {
132 return false;
133}
134
135NestedInputStreamBuffer::NestedInputStreamBuffer(InputStreamBuffer* delegate,
136 size_t size)
Mattias Nissler42455ff2016-03-01 21:58:11 +0100137 : InputStreamBuffer(delegate->pos_, ClampEnd(delegate, size)),
Mattias Nisslercdab1232016-01-25 18:40:25 +0100138 delegate_(delegate),
139 remaining_(size) {}
140
Mattias Nisslercdab1232016-01-25 18:40:25 +0100141bool 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_;
Mattias Nissler42455ff2016-03-01 21:58:11 +0100149 end_ = ClampEnd(delegate_, remaining_);
Mattias Nisslercdab1232016-01-25 18:40:25 +0100150 return status;
151}
152
Mattias Nissler42455ff2016-03-01 21:58:11 +0100153// static
154const 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
Mattias Nisslercdab1232016-01-25 18:40:25 +0100162OutputStreamBuffer::OutputStreamBuffer(void* data, size_t size)
163 : OutputStreamBuffer(data, static_cast<uint8_t*>(data) + size) {}
164
165OutputStreamBuffer::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
Mattias Nisslercdab1232016-01-25 18:40:25 +0100170bool OutputStreamBuffer::Done() {
171 return pos_ >= end_ && !Advance();
172}
173
174bool 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
192bool 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
204bool OutputStreamBuffer::Advance() {
205 return false;
206}
207
208CountingOutputStreamBuffer::CountingOutputStreamBuffer()
209 : OutputStreamBuffer(scratch_space_, kScratchSpaceSize) {}
210
Mattias Nisslercdab1232016-01-25 18:40:25 +0100211bool CountingOutputStreamBuffer::Advance() {
212 bytes_written_ += pos_ - scratch_space_;
213 pos_ = scratch_space_;
214 end_ = scratch_space_ + kScratchSpaceSize;
215 return true;
216}
217
218uint8_t CountingOutputStreamBuffer::scratch_space_[kScratchSpaceSize];
219
220BlobOutputStreamBuffer::BlobOutputStreamBuffer(Blob* blob)
221 : OutputStreamBuffer(blob->data(), blob->size()), blob_(blob) {}
222
Mattias Nisslercdab1232016-01-25 18:40:25 +0100223bool 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
233bool BlobOutputStreamBuffer::Truncate() {
Mattias Nissler42455ff2016-03-01 21:58:11 +0100234 if (!blob_->Resize(pos_ - blob_->data())) {
235 return false;
236 }
237 end_ = blob_->data() + blob_->size();
238 pos_ = end_;
239 return true;
Mattias Nisslercdab1232016-01-25 18:40:25 +0100240}
241
242ProtoReader::ProtoReader(InputStreamBuffer* stream_buffer)
243 : stream_buffer_(stream_buffer) {}
244
245bool 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
281bool ProtoReader::ReadVarint(uint64_t* value) {
282 NVRAM_CHECK(wire_type() == WireType::kVarint);
283 return DecodeVarint(stream_buffer_, value);
284}
285
286bool ProtoReader::ReadLengthDelimited(void* data, size_t size) {
287 NVRAM_CHECK(wire_type() == WireType::kLengthDelimited);
288 return stream_buffer_->Read(data, size);
289}
290
291bool 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
302ProtoWriter::ProtoWriter(OutputStreamBuffer* stream_buffer)
303 : stream_buffer_(stream_buffer) {}
304
305bool ProtoWriter::WriteVarint(uint64_t value) {
306 return WriteWireTag(WireType::kVarint) &&
307 EncodeVarint(stream_buffer_, value);
308}
309
310bool 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
316bool ProtoWriter::WriteLengthHeader(size_t size) {
317 return WriteWireTag(WireType::kLengthDelimited) &&
318 EncodeVarint(stream_buffer_, size);
319}
320
321bool 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