tor-browser

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

BitReader.cpp (4879B)


      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 // Derived from Stagefright's ABitReader.
      6 
      7 #include "BitReader.h"
      8 
      9 #include "nsStringFwd.h"
     10 
     11 namespace mozilla {
     12 
     13 BitReader::BitReader(const mozilla::MediaByteBuffer* aBuffer)
     14    : BitReader(aBuffer->Elements(), aBuffer->Length() * 8) {}
     15 
     16 BitReader::BitReader(const mozilla::MediaByteBuffer* aBuffer, size_t aBits)
     17    : BitReader(aBuffer->Elements(), aBits) {}
     18 
     19 BitReader::BitReader(const uint8_t* aBuffer, size_t aBits)
     20    : mData(aBuffer),
     21      mOriginalBitSize(aBits),
     22      mTotalBitsLeft(aBits),
     23      mSize((aBits + 7) / 8),
     24      mReservoir(0),
     25      mNumBitsLeft(0) {}
     26 
     27 BitReader::~BitReader() = default;
     28 
     29 uint32_t BitReader::ReadBits(size_t aNum) {
     30  MOZ_ASSERT(aNum <= 32);
     31  if (mTotalBitsLeft < aNum) {
     32 #ifdef DEBUG
     33    nsAutoCString msg;
     34    msg.AppendFmt("Reading past end of buffer, totalBitsLeft={}, num={}",
     35                  mTotalBitsLeft, aNum);
     36    NS_WARNING(msg.get());
     37 #endif
     38    return 0;
     39  }
     40  uint32_t result = 0;
     41  while (aNum > 0) {
     42    if (mNumBitsLeft == 0) {
     43      FillReservoir();
     44    }
     45 
     46    size_t m = aNum;
     47    if (m > mNumBitsLeft) {
     48      m = mNumBitsLeft;
     49    }
     50 
     51    if (m == 32) {
     52      result = mReservoir;
     53      mReservoir = 0;
     54    } else {
     55      result = (result << m) | (mReservoir >> (32 - m));
     56      mReservoir <<= m;
     57    }
     58    mNumBitsLeft -= m;
     59    mTotalBitsLeft -= m;
     60 
     61    aNum -= m;
     62  }
     63 
     64  return result;
     65 }
     66 
     67 // Read unsigned integer Exp-Golomb-coded.
     68 uint32_t BitReader::ReadUE() {
     69  uint32_t i = 0;
     70 
     71  while (ReadBit() == 0 && i < 32) {
     72    i++;
     73  }
     74  if (i == 32) {
     75    // This can happen if the data is invalid, or if it's
     76    // short, since ReadBit() will return 0 when it runs
     77    // off the end of the buffer.
     78    NS_WARNING("Invalid H.264 data");
     79    return 0;
     80  }
     81  uint32_t r = ReadBits(i);
     82  r += (uint32_t(1) << i) - 1;
     83 
     84  return r;
     85 }
     86 
     87 // Read signed integer Exp-Golomb-coded.
     88 int32_t BitReader::ReadSE() {
     89  int32_t r = ReadUE();
     90  if (r & 1) {
     91    return (r + 1) / 2;
     92  } else {
     93    return -r / 2;
     94  }
     95 }
     96 
     97 uint64_t BitReader::ReadU64() {
     98  uint64_t hi = ReadU32();
     99  uint32_t lo = ReadU32();
    100  return (hi << 32) | lo;
    101 }
    102 
    103 CheckedUint64 BitReader::ReadULEB128() {
    104  // See https://en.wikipedia.org/wiki/LEB128#Decode_unsigned_integer
    105  CheckedUint64 value = 0;
    106  for (size_t i = 0; i < sizeof(uint64_t) * 8 / 7; i++) {
    107    bool more = ReadBit();
    108    value += static_cast<uint64_t>(ReadBits(7)) << (i * 7);
    109    if (!more) {
    110      break;
    111    }
    112  }
    113  return value;
    114 }
    115 
    116 uint64_t BitReader::ReadUTF8() {
    117  int64_t val = ReadBits(8);
    118  uint32_t top = (val & 0x80) >> 1;
    119 
    120  if ((val & 0xc0) == 0x80 || val >= 0xFE) {
    121    // error.
    122    return -1;
    123  }
    124  while (val & top) {
    125    int tmp = ReadBits(8) - 128;
    126    if (tmp >> 6) {
    127      // error.
    128      return -1;
    129    }
    130    val = (val << 6) + tmp;
    131    top <<= 5;
    132  }
    133  val &= (top << 1) - 1;
    134  return val;
    135 }
    136 
    137 size_t BitReader::BitCount() const { return mOriginalBitSize - mTotalBitsLeft; }
    138 
    139 size_t BitReader::BitsLeft() const { return mTotalBitsLeft; }
    140 
    141 void BitReader::FillReservoir() {
    142  if (mSize == 0) {
    143    NS_ASSERTION(false, "Attempting to fill reservoir from past end of data");
    144    return;
    145  }
    146 
    147  mReservoir = 0;
    148  size_t i;
    149  for (i = 0; mSize > 0 && i < 4; i++) {
    150    mReservoir = (mReservoir << 8) | *mData;
    151    mData++;
    152    mSize--;
    153  }
    154 
    155  mNumBitsLeft = 8 * i;
    156  mReservoir <<= 32 - mNumBitsLeft;
    157 }
    158 
    159 /* static */
    160 uint32_t BitReader::GetBitLength(const mozilla::MediaByteBuffer* aNAL) {
    161  size_t size = aNAL->Length();
    162 
    163  while (size > 0 && aNAL->ElementAt(size - 1) == 0) {
    164    size--;
    165  }
    166 
    167  if (!size) {
    168    return 0;
    169  }
    170 
    171  if (size > UINT32_MAX / 8) {
    172    // We can't represent it, we'll use as much as we can.
    173    return UINT32_MAX;
    174  }
    175 
    176  uint8_t v = aNAL->ElementAt(size - 1);
    177  size *= 8;
    178 
    179  // Remove the stop bit and following trailing zeros.
    180  if (v) {
    181    // Count the consecutive zero bits (trailing) on the right by binary search.
    182    // Adapted from Matt Whitlock algorithm to only bother with 8 bits integers.
    183    uint32_t c;
    184    if (v & 1) {
    185      // Special case for odd v (assumed to happen half of the time).
    186      c = 0;
    187    } else {
    188      c = 1;
    189      if ((v & 0xf) == 0) {
    190        v >>= 4;
    191        c += 4;
    192      }
    193      if ((v & 0x3) == 0) {
    194        v >>= 2;
    195        c += 2;
    196      }
    197      c -= v & 0x1;
    198    }
    199    size -= c + 1;
    200  }
    201  return size;
    202 }
    203 
    204 size_t BitReader::AdvanceBits(size_t aNum) {
    205  const size_t advanceBits = std::min(aNum, BitsLeft());
    206  size_t temp = advanceBits;
    207  while (temp > 0) {
    208    uint32_t readBits = temp > 32 ? 32 : temp;
    209    // TODO : return error if reading less bits than expectation in bug 1972401.
    210    (void)ReadBits(readBits);
    211    temp -= readBits;
    212  }
    213  return advanceBits;
    214 }
    215 
    216 }  // namespace mozilla