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> 29 T min(T x, T y) { 30 return x < y ? x : y; 31 } 32 33 template <typename T> 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|. 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|. 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 74 InputStreamBuffer::InputStreamBuffer(const void* data, size_t size) 75 : InputStreamBuffer(data, static_cast<const uint8_t*>(data) + size) {} 76 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 83 bool InputStreamBuffer::Done() { 84 return pos_ >= end_ && !Advance(); 85 } 86 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 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 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 131 bool InputStreamBuffer::Advance() { 132 return false; 133 } 134 135 NestedInputStreamBuffer::NestedInputStreamBuffer(InputStreamBuffer* delegate, 136 size_t size) 137 : InputStreamBuffer(delegate->pos_, ClampEnd(delegate, size)), 138 delegate_(delegate), 139 remaining_(size) {} 140 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 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 162 OutputStreamBuffer::OutputStreamBuffer(void* data, size_t size) 163 : OutputStreamBuffer(data, static_cast<uint8_t*>(data) + size) {} 164 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 170 bool OutputStreamBuffer::Done() { 171 return pos_ >= end_ && !Advance(); 172 } 173 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 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 204 bool OutputStreamBuffer::Advance() { 205 return false; 206 } 207 208 CountingOutputStreamBuffer::CountingOutputStreamBuffer() 209 : OutputStreamBuffer(scratch_space_, kScratchSpaceSize) {} 210 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 220 BlobOutputStreamBuffer::BlobOutputStreamBuffer(Blob* blob) 221 : OutputStreamBuffer(blob->data(), blob->size()), blob_(blob) {} 222 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 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 242 ProtoReader::ProtoReader(InputStreamBuffer* stream_buffer) 243 : stream_buffer_(stream_buffer) {} 244 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 281 bool ProtoReader::ReadVarint(uint64_t* value) { 282 NVRAM_CHECK(wire_type() == WireType::kVarint); 283 return DecodeVarint(stream_buffer_, value); 284 } 285 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 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 302 ProtoWriter::ProtoWriter(OutputStreamBuffer* stream_buffer) 303 : stream_buffer_(stream_buffer) {} 304 305 bool ProtoWriter::WriteVarint(uint64_t value) { 306 return WriteWireTag(WireType::kVarint) && 307 EncodeVarint(stream_buffer_, value); 308 } 309 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 316 bool ProtoWriter::WriteLengthHeader(size_t size) { 317 return WriteWireTag(WireType::kLengthDelimited) && 318 EncodeVarint(stream_buffer_, size); 319 } 320 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