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