UNPKG

shaka-player

Version:
301 lines (256 loc) 7.94 kB
/** * @license * Copyright 2016 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('goog.asserts'); goog.require('shaka.util.Error'); goog.require('shaka.util.StringUtils'); /** * Creates a DataViewReader, which abstracts a DataView object. * * @param {!DataView} dataView The DataView. * @param {shaka.util.DataViewReader.Endianness} endianness The endianness. * * @struct * @constructor * @export */ 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} * @export */ shaka.util.DataViewReader.Endianness = { BIG_ENDIAN: 0, LITTLE_ENDIAN: 1, }; /** @return {!DataView} The underlying DataView instance. */ shaka.util.DataViewReader.prototype.getDataView = function() { return this.dataView_; }; /** * @return {boolean} True if the reader has more data, false otherwise. * @export */ shaka.util.DataViewReader.prototype.hasMoreData = function() { return this.position_ < this.dataView_.byteLength; }; /** * Gets the current byte position. * @return {number} * @export */ shaka.util.DataViewReader.prototype.getPosition = function() { return this.position_; }; /** * Gets the byte length of the DataView. * @return {number} * @export */ 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 {shaka.util.Error} when reading past the end of the data view. * @export */ shaka.util.DataViewReader.prototype.readUint8 = function() { try { let value = this.dataView_.getUint8(this.position_); this.position_ += 1; return value; } catch (exception) { this.throwOutOfBounds_(); } }; /** * Reads an unsigned 16 bit integer, and advances the reader. * @return {number} The integer. * @throws {shaka.util.Error} when reading past the end of the data view. * @export */ shaka.util.DataViewReader.prototype.readUint16 = function() { try { let value = this.dataView_.getUint16(this.position_, this.littleEndian_); this.position_ += 2; return value; } catch (exception) { this.throwOutOfBounds_(); } }; /** * Reads an unsigned 32 bit integer, and advances the reader. * @return {number} The integer. * @throws {shaka.util.Error} when reading past the end of the data view. * @export */ shaka.util.DataViewReader.prototype.readUint32 = function() { try { let value = this.dataView_.getUint32(this.position_, this.littleEndian_); this.position_ += 4; return value; } catch (exception) { this.throwOutOfBounds_(); } }; /** * Reads a signed 32 bit integer, and advances the reader. * @return {number} The integer. * @throws {shaka.util.Error} when reading past the end of the data view. * @export */ shaka.util.DataViewReader.prototype.readInt32 = function() { try { let value = this.dataView_.getInt32(this.position_, this.littleEndian_); this.position_ += 4; return value; } catch (exception) { this.throwOutOfBounds_(); } }; /** * Reads an unsigned 64 bit integer, and advances the reader. * @return {number} The integer. * @throws {shaka.util.Error} when reading past the end of the data view or * when reading an integer too large to store accurately in JavaScript. * @export */ shaka.util.DataViewReader.prototype.readUint64 = function() { /** @type {number} */ let low; /** @type {number} */ let high; try { 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); } } catch (exception) { this.throwOutOfBounds_(); } if (high > 0x1FFFFF) { throw new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.MEDIA, shaka.util.Error.Code.JS_INTEGER_OVERFLOW); } 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 {shaka.util.Error} when reading past the end of the data view. * @export */ shaka.util.DataViewReader.prototype.readBytes = function(bytes) { goog.asserts.assert(bytes >= 0, 'Bad call to DataViewReader.readBytes'); if (this.position_ + bytes > this.dataView_.byteLength) { this.throwOutOfBounds_(); } let value = new Uint8Array( this.dataView_.buffer, this.dataView_.byteOffset + this.position_, bytes); this.position_ += bytes; return value; }; /** * Skips the specified number of bytes. * @param {number} bytes The number of bytes to skip. * @throws {shaka.util.Error} when skipping past the end of the data view. * @export */ shaka.util.DataViewReader.prototype.skip = function(bytes) { goog.asserts.assert(bytes >= 0, 'Bad call to DataViewReader.skip'); if (this.position_ + bytes > this.dataView_.byteLength) { this.throwOutOfBounds_(); } this.position_ += bytes; }; /** * Rewinds the specified number of bytes. * @param {number} bytes The number of bytes to rewind. * @throws {shaka.util.Error} when rewinding past the beginning of the data * view. * @export */ shaka.util.DataViewReader.prototype.rewind = function(bytes) { goog.asserts.assert(bytes >= 0, 'Bad call to DataViewReader.rewind'); if (this.position_ < bytes) { this.throwOutOfBounds_(); } this.position_ -= bytes; }; /** * Seeks to a specified position. * @param {number} position The desired byte position within the DataView. * @throws {shaka.util.Error} when seeking outside the range of the data view. * @export */ shaka.util.DataViewReader.prototype.seek = function(position) { goog.asserts.assert(position >= 0, 'Bad call to DataViewReader.seek'); if (position < 0 || position > this.dataView_.byteLength) { this.throwOutOfBounds_(); } this.position_ = position; }; /** * Keeps reading until it reaches a byte that equals to zero. The text is * assumed to be UTF-8. * @return {string} * @export */ shaka.util.DataViewReader.prototype.readTerminatedString = function() { let start = this.position_; while (this.hasMoreData()) { let value = this.dataView_.getUint8(this.position_); if (value == 0) break; this.position_ += 1; } let ret = new Uint8Array( this.dataView_.buffer, this.dataView_.byteOffset + start, this.position_ - start); // Skip string termination. this.position_ += 1; return shaka.util.StringUtils.fromUTF8(ret); }; /** * @throws {shaka.util.Error} * @private */ shaka.util.DataViewReader.prototype.throwOutOfBounds_ = function() { throw new shaka.util.Error( shaka.util.Error.Severity.CRITICAL, shaka.util.Error.Category.MEDIA, shaka.util.Error.Code.BUFFER_READ_OUT_OF_BOUNDS); };