Source: util/data_view_reader.js

/**
 * @license
 * Copyright 2015 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

goog.provide('shaka.util.DataViewReader');

goog.require('shaka.asserts');



/**
 * Creates a DataViewReader, which abstracts a DataView object.
 *
 * @param {!DataView} dataView The DataView.
 * @param {shaka.util.DataViewReader.Endianness} endianness The endianness.
 * @constructor
 */
shaka.util.DataViewReader = function(dataView, endianness) {
  /** @private {!DataView} */
  this.dataView_ = dataView;

  /** @private {boolean} */
  this.littleEndian_ =
      endianness == shaka.util.DataViewReader.Endianness.LITTLE_ENDIAN;

  /** @private {number} */
  this.position_ = 0;
};


/**
 * Endianness.
 * @enum {number}
 */
shaka.util.DataViewReader.Endianness = {
  BIG_ENDIAN: 0,
  LITTLE_ENDIAN: 1
};


/**
 * @return {boolean} True if the reader has more data, false otherwise.
 */
shaka.util.DataViewReader.prototype.hasMoreData = function() {
  return this.position_ < this.dataView_.byteLength;
};


/**
 * Gets the current byte position.
 * @return {number}
 */
shaka.util.DataViewReader.prototype.getPosition = function() {
  return this.position_;
};


/**
 * Gets the byte length of the DataView.
 * @return {number}
 */
shaka.util.DataViewReader.prototype.getLength = function() {
  return this.dataView_.byteLength;
};


/**
 * Reads an unsigned 8 bit integer, and advances the reader.
 * @return {number} The integer.
 * @throws {RangeError} when reading past the end of the data view.
 */
shaka.util.DataViewReader.prototype.readUint8 = function() {
  var value = this.dataView_.getUint8(this.position_);
  this.position_ += 1;
  return value;
};


/**
 * Reads an unsigned 16 bit integer, and advances the reader.
 * @return {number} The integer.
 * @throws {RangeError} when reading past the end of the data view.
 */
shaka.util.DataViewReader.prototype.readUint16 = function() {
  var value = this.dataView_.getUint16(this.position_, this.littleEndian_);
  this.position_ += 2;
  return value;
};


/**
 * Reads an unsigned 32 bit integer, and advances the reader.
 * @return {number} The integer.
 * @throws {RangeError} when reading past the end of the data view.
 */
shaka.util.DataViewReader.prototype.readUint32 = function() {
  var value = this.dataView_.getUint32(this.position_, this.littleEndian_);
  this.position_ += 4;
  return value;
};


/**
 * Reads an unsigned 64 bit integer, and advances the reader.
 * @return {number} The integer.
 * @throws {RangeError} when reading past the end of the data view or when
 *     reading an integer too large to store accurately in JavaScript.
 */
shaka.util.DataViewReader.prototype.readUint64 = function() {
  var low, high;

  if (this.littleEndian_) {
    low = this.dataView_.getUint32(this.position_, true);
    high = this.dataView_.getUint32(this.position_ + 4, true);
  } else {
    high = this.dataView_.getUint32(this.position_, false);
    low = this.dataView_.getUint32(this.position_ + 4, false);
  }

  if (high > 0x1FFFFF) {
    throw new RangeError('DataViewReader: Overflow reading 64-bit value.');
  }

  this.position_ += 8;

  // NOTE: This is subtle, but in JavaScript you can't shift left by 32 and get
  // the full range of 53-bit values possible.  You must multiply by 2^32.
  return (high * Math.pow(2, 32)) + low;
};


/**
 * Reads the specified number of raw bytes.
 * @param {number} bytes The number of bytes to read.
 * @return {!Uint8Array}
 * @throws {RangeError} when reading past the end of the data view.
 */
shaka.util.DataViewReader.prototype.readBytes = function(bytes) {
  shaka.asserts.assert(bytes > 0);
  if (this.position_ + bytes > this.dataView_.byteLength) {
    throw new RangeError('DataViewReader: Read past end of DataView.');
  }
  var value = new Uint8Array(this.dataView_.buffer, this.position_, bytes);
  this.position_ += bytes;
  return value;
};


/**
 * Skips the specified number of bytes.
 * @param {number} bytes The number of bytes to skip.
 * @throws {RangeError} when skipping past the end of the data view.
 */
shaka.util.DataViewReader.prototype.skip = function(bytes) {
  shaka.asserts.assert(bytes >= 0);
  if (this.position_ + bytes > this.dataView_.byteLength) {
    throw new RangeError('DataViewReader: Skip past end of DataView.');
  }
  this.position_ += bytes;
};