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