tor-browser

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

BufferReader.h (9206B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #ifndef BUFFER_READER_H_
      6 #define BUFFER_READER_H_
      7 
      8 #include <string.h>
      9 
     10 #include "MediaData.h"
     11 #include "MediaSpan.h"
     12 #include "mozilla/EndianUtils.h"
     13 #include "mozilla/Logging.h"
     14 #include "mozilla/Result.h"
     15 #include "nsTArray.h"
     16 #include "nscore.h"
     17 
     18 namespace mozilla {
     19 
     20 extern mozilla::LazyLogModule gMP4MetadataLog;
     21 
     22 class MOZ_RAII BufferReader {
     23 public:
     24  BufferReader() : mPtr(nullptr), mRemaining(0), mLength(0) {}
     25  BufferReader(const uint8_t* aData, size_t aSize)
     26      : mPtr(aData), mRemaining(aSize), mLength(aSize) {}
     27  template <size_t S>
     28  explicit BufferReader(const AutoTArray<uint8_t, S>& aData)
     29      : mPtr(aData.Elements()),
     30        mRemaining(aData.Length()),
     31        mLength(aData.Length()) {}
     32  explicit BufferReader(const nsTArray<uint8_t>& aData)
     33      : mPtr(aData.Elements()),
     34        mRemaining(aData.Length()),
     35        mLength(aData.Length()) {}
     36  explicit BufferReader(const mozilla::MediaByteBuffer* aData)
     37      : mPtr(aData->Elements()),
     38        mRemaining(aData->Length()),
     39        mLength(aData->Length()) {}
     40  explicit BufferReader(const mozilla::MediaSpan& aData)
     41      : mPtr(aData.Elements()),
     42        mRemaining(aData.Length()),
     43        mLength(aData.Length()) {}
     44  explicit BufferReader(const Span<const uint8_t>& aData)
     45      : mPtr(aData.Elements()),
     46        mRemaining(aData.Length()),
     47        mLength(aData.Length()) {}
     48 
     49  void SetData(const nsTArray<uint8_t>& aData) {
     50    MOZ_ASSERT(!mPtr && !mRemaining);
     51    mPtr = aData.Elements();
     52    mRemaining = aData.Length();
     53    mLength = mRemaining;
     54  }
     55 
     56  ~BufferReader() = default;
     57 
     58  size_t Offset() const { return mLength - mRemaining; }
     59 
     60  size_t Remaining() const { return mRemaining; }
     61 
     62  mozilla::Result<uint8_t, nsresult> ReadU8() {
     63    auto ptr = Read(1);
     64    if (!ptr) {
     65      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
     66              ("%s: failure", __func__));
     67      return mozilla::Err(NS_ERROR_FAILURE);
     68    }
     69    return *ptr;
     70  }
     71 
     72  mozilla::Result<uint16_t, nsresult> ReadU16() {
     73    auto ptr = Read(2);
     74    if (!ptr) {
     75      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
     76              ("%s: failure", __func__));
     77      return mozilla::Err(NS_ERROR_FAILURE);
     78    }
     79    return mozilla::BigEndian::readUint16(ptr);
     80  }
     81 
     82  mozilla::Result<int16_t, nsresult> ReadLE16() {
     83    auto ptr = Read(2);
     84    if (!ptr) {
     85      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
     86              ("%s: failure", __func__));
     87      return mozilla::Err(NS_ERROR_FAILURE);
     88    }
     89    return mozilla::LittleEndian::readInt16(ptr);
     90  }
     91 
     92  mozilla::Result<uint32_t, nsresult> ReadU24() {
     93    auto ptr = Read(3);
     94    if (!ptr) {
     95      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
     96              ("%s: failure", __func__));
     97      return mozilla::Err(NS_ERROR_FAILURE);
     98    }
     99    return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
    100  }
    101 
    102  mozilla::Result<int32_t, nsresult> Read24() {
    103    return ReadU24().map([](uint32_t x) { return (int32_t)x; });
    104  }
    105 
    106  mozilla::Result<int32_t, nsresult> ReadLE24() {
    107    auto ptr = Read(3);
    108    if (!ptr) {
    109      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    110              ("%s: failure", __func__));
    111      return mozilla::Err(NS_ERROR_FAILURE);
    112    }
    113    int32_t result = int32_t(ptr[2] << 16 | ptr[1] << 8 | ptr[0]);
    114    if (result & 0x00800000u) {
    115      result -= 0x1000000;
    116    }
    117    return result;
    118  }
    119 
    120  mozilla::Result<uint32_t, nsresult> ReadU32() {
    121    auto ptr = Read(4);
    122    if (!ptr) {
    123      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    124              ("%s: failure", __func__));
    125      return mozilla::Err(NS_ERROR_FAILURE);
    126    }
    127    return mozilla::BigEndian::readUint32(ptr);
    128  }
    129 
    130  mozilla::Result<int32_t, nsresult> Read32() {
    131    auto ptr = Read(4);
    132    if (!ptr) {
    133      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    134              ("%s: failure", __func__));
    135      return mozilla::Err(NS_ERROR_FAILURE);
    136    }
    137    return mozilla::BigEndian::readInt32(ptr);
    138  }
    139 
    140  mozilla::Result<uint32_t, nsresult> ReadLEU32() {
    141    auto ptr = Read(4);
    142    if (!ptr) {
    143      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    144              ("%s: failure", __func__));
    145      return mozilla::Err(NS_ERROR_FAILURE);
    146    }
    147    return mozilla::LittleEndian::readUint32(ptr);
    148  }
    149 
    150  mozilla::Result<uint64_t, nsresult> ReadU64() {
    151    auto ptr = Read(8);
    152    if (!ptr) {
    153      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    154              ("%s: failure", __func__));
    155      return mozilla::Err(NS_ERROR_FAILURE);
    156    }
    157    return mozilla::BigEndian::readUint64(ptr);
    158  }
    159 
    160  mozilla::Result<int64_t, nsresult> Read64() {
    161    auto ptr = Read(8);
    162    if (!ptr) {
    163      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    164              ("%s: failure", __func__));
    165      return mozilla::Err(NS_ERROR_FAILURE);
    166    }
    167    return mozilla::BigEndian::readInt64(ptr);
    168  }
    169 
    170  const uint8_t* Read(size_t aCount) {
    171    if (aCount > mRemaining) {
    172      mPtr += mRemaining;
    173      mRemaining = 0;
    174      return nullptr;
    175    }
    176    mRemaining -= aCount;
    177 
    178    const uint8_t* result = mPtr;
    179    mPtr += aCount;
    180 
    181    return result;
    182  }
    183 
    184  const uint8_t* Rewind(size_t aCount) {
    185    MOZ_ASSERT(aCount <= Offset());
    186    size_t rewind = Offset();
    187    if (aCount < rewind) {
    188      rewind = aCount;
    189    }
    190    mRemaining += rewind;
    191    mPtr -= rewind;
    192    return mPtr;
    193  }
    194 
    195  mozilla::Result<uint8_t, nsresult> PeekU8() const {
    196    auto ptr = Peek(1);
    197    if (!ptr) {
    198      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    199              ("%s: failure", __func__));
    200      return mozilla::Err(NS_ERROR_FAILURE);
    201    }
    202    return *ptr;
    203  }
    204 
    205  mozilla::Result<uint16_t, nsresult> PeekU16() const {
    206    auto ptr = Peek(2);
    207    if (!ptr) {
    208      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    209              ("%s: failure", __func__));
    210      return mozilla::Err(NS_ERROR_FAILURE);
    211    }
    212    return mozilla::BigEndian::readUint16(ptr);
    213  }
    214 
    215  mozilla::Result<uint32_t, nsresult> PeekU24() const {
    216    auto ptr = Peek(3);
    217    if (!ptr) {
    218      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    219              ("%s: failure", __func__));
    220      return mozilla::Err(NS_ERROR_FAILURE);
    221    }
    222    return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
    223  }
    224 
    225  mozilla::Result<int32_t, nsresult> Peek24() const {
    226    return PeekU24().map([](uint32_t x) { return (int32_t)x; });
    227  }
    228 
    229  mozilla::Result<uint32_t, nsresult> PeekU32() {
    230    auto ptr = Peek(4);
    231    if (!ptr) {
    232      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    233              ("%s: failure", __func__));
    234      return mozilla::Err(NS_ERROR_FAILURE);
    235    }
    236    return mozilla::BigEndian::readUint32(ptr);
    237  }
    238 
    239  const uint8_t* Peek(size_t aCount) const {
    240    if (aCount > mRemaining) {
    241      return nullptr;
    242    }
    243    return mPtr;
    244  }
    245 
    246  const uint8_t* Seek(size_t aOffset) {
    247    if (aOffset >= mLength) {
    248      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    249              ("%s: failure, offset: %zu", __func__, aOffset));
    250      return nullptr;
    251    }
    252 
    253    mPtr = mPtr - Offset() + aOffset;
    254    mRemaining = mLength - aOffset;
    255    return mPtr;
    256  }
    257 
    258  const uint8_t* Reset() {
    259    mPtr -= Offset();
    260    mRemaining = mLength;
    261    return mPtr;
    262  }
    263 
    264  uint32_t Align() const { return 4 - ((intptr_t)mPtr & 3); }
    265 
    266  template <typename T>
    267  bool CanReadType() const {
    268    return mRemaining >= sizeof(T);
    269  }
    270 
    271  template <typename T>
    272  T ReadType() {
    273    auto ptr = Read(sizeof(T));
    274    if (!ptr) {
    275      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    276              ("%s: failure", __func__));
    277      return 0;
    278    }
    279    // handle unaligned accesses by memcpying
    280    T ret;
    281    memcpy(&ret, ptr, sizeof(T));
    282    return ret;
    283  }
    284 
    285  template <typename T>
    286  [[nodiscard]] bool ReadArray(nsTArray<T>& aDest, size_t aLength) {
    287    auto ptr = Read(aLength * sizeof(T));
    288    if (!ptr) {
    289      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    290              ("%s: failure", __func__));
    291      return false;
    292    }
    293 
    294    aDest.Clear();
    295    aDest.AppendElements(reinterpret_cast<const T*>(ptr), aLength);
    296    return true;
    297  }
    298 
    299  template <typename T>
    300  [[nodiscard]] bool ReadArray(FallibleTArray<T>& aDest, size_t aLength) {
    301    auto ptr = Read(aLength * sizeof(T));
    302    if (!ptr) {
    303      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    304              ("%s: failure", __func__));
    305      return false;
    306    }
    307 
    308    aDest.Clear();
    309    if (!aDest.SetCapacity(aLength, mozilla::fallible)) {
    310      return false;
    311    }
    312    MOZ_ALWAYS_TRUE(aDest.AppendElements(reinterpret_cast<const T*>(ptr),
    313                                         aLength, mozilla::fallible));
    314    return true;
    315  }
    316 
    317  template <typename T>
    318  mozilla::Result<Span<const T>, nsresult> ReadSpan(size_t aLength) {
    319    auto ptr = Read(aLength * sizeof(T));
    320    if (!ptr) {
    321      MOZ_LOG(gMP4MetadataLog, mozilla::LogLevel::Error,
    322              ("%s: failure", __func__));
    323      return mozilla::Err(NS_ERROR_FAILURE);
    324    }
    325    return Span(reinterpret_cast<const T*>(ptr), aLength);
    326  }
    327 
    328 private:
    329  const uint8_t* mPtr;
    330  size_t mRemaining;
    331  size_t mLength;
    332 };
    333 
    334 }  // namespace mozilla
    335 
    336 #endif