Home | History | Annotate | Download | only in messages
      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