tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

IOBuffers.h (3610B)


      1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
      2 /* This Source Code Form is subject to the terms of the Mozilla Public
      3 * License, v. 2.0. If a copy of the MPL was not distributed with this
      4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      5 
      6 #ifndef IOBuffers_h
      7 #define IOBuffers_h
      8 
      9 #include "mozilla/Assertions.h"
     10 #include "mozilla/CheckedInt.h"
     11 #include "mozilla/EndianUtils.h"
     12 #include "mozilla/EnumSet.h"
     13 #include "mozilla/Range.h"
     14 #include "nsString.h"
     15 #include "nsTArray.h"
     16 
     17 namespace mozilla {
     18 namespace loader {
     19 
     20 class OutputBuffer {
     21 public:
     22  OutputBuffer() {}
     23 
     24  uint8_t* write(size_t size) {
     25    auto buf = data.AppendElements(size);
     26    cursor_ += size;
     27    return buf;
     28  }
     29 
     30  void codeUint8(const uint8_t& val) { *write(sizeof val) = val; }
     31 
     32  template <typename T>
     33  void codeUint8(const EnumSet<T>& val) {
     34    // EnumSets are always represented as uint32_t values, so we need to
     35    // assert that the value actually fits in a uint8 before writing it.
     36    uint32_t value = val.serialize();
     37    codeUint8(CheckedUint8(value).value());
     38  }
     39 
     40  void codeUint16(const uint16_t& val) {
     41    LittleEndian::writeUint16(write(sizeof val), val);
     42  }
     43 
     44  void codeUint32(const uint32_t& val) {
     45    LittleEndian::writeUint32(write(sizeof val), val);
     46  }
     47 
     48  void codeString(const nsCString& str) {
     49    auto len = CheckedUint16(str.Length()).value();
     50 
     51    codeUint16(len);
     52    memcpy(write(len), str.BeginReading(), len);
     53  }
     54 
     55  size_t cursor() const { return cursor_; }
     56 
     57  uint8_t* Get() { return data.Elements(); }
     58 
     59  const uint8_t* Get() const { return data.Elements(); }
     60 
     61 private:
     62  nsTArray<uint8_t> data;
     63  size_t cursor_ = 0;
     64 };
     65 
     66 class InputBuffer {
     67 public:
     68  explicit InputBuffer(const Range<const uint8_t>& buffer) : data(buffer) {}
     69 
     70  // Since the other constructor stores `buffer` by reference, we must ensure
     71  // no implicit conversions occur (which would result in a reference to a
     72  // temporary being stored).
     73  template <typename T>
     74  explicit InputBuffer(T) = delete;
     75 
     76  const uint8_t* read(size_t size) {
     77    MOZ_ASSERT(checkCapacity(size));
     78 
     79    const auto* buf = &data[cursor_];
     80    cursor_ += size;
     81    return buf;
     82  }
     83 
     84  bool codeUint8(uint8_t& val) {
     85    if (checkCapacity(sizeof val)) {
     86      val = *read(sizeof val);
     87    }
     88    return !error_;
     89  }
     90 
     91  template <typename T>
     92  bool codeUint8(EnumSet<T>& val) {
     93    uint8_t value;
     94    if (codeUint8(value)) {
     95      val.deserialize(value);
     96    }
     97    return !error_;
     98  }
     99 
    100  bool codeUint16(uint16_t& val) {
    101    if (checkCapacity(sizeof val)) {
    102      val = LittleEndian::readUint16(read(sizeof val));
    103    }
    104    return !error_;
    105  }
    106 
    107  bool codeUint32(uint32_t& val) {
    108    if (checkCapacity(sizeof val)) {
    109      val = LittleEndian::readUint32(read(sizeof val));
    110    }
    111    return !error_;
    112  }
    113 
    114  bool codeString(nsCString& str) {
    115    uint16_t len;
    116    if (codeUint16(len)) {
    117      if (checkCapacity(len)) {
    118        str.SetLength(len);
    119        memcpy(str.BeginWriting(), read(len), len);
    120      }
    121    }
    122    return !error_;
    123  }
    124 
    125  bool error() { return error_; }
    126 
    127  bool finished() { return error_ || !remainingCapacity(); }
    128 
    129  size_t remainingCapacity() { return data.length() - cursor_; }
    130 
    131  size_t cursor() const { return cursor_; }
    132 
    133  const uint8_t* Get() const { return data.begin().get(); }
    134 
    135 private:
    136  bool checkCapacity(size_t size) {
    137    if (size > remainingCapacity()) {
    138      error_ = true;
    139    }
    140    return !error_;
    141  }
    142 
    143  bool error_ = false;
    144 
    145 public:
    146  const Range<const uint8_t>& data;
    147  size_t cursor_ = 0;
    148 };
    149 
    150 }  // namespace loader
    151 }  // namespace mozilla
    152 
    153 #endif  // IOBuffers_h