mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-14 15:56:38 +03:00
8796415d87
All other enum keys are quoted, and these should be, too. Change-Id: If1776d9611b1102d65bab6584b19aced82b4ba81
282 lines
6.3 KiB
JavaScript
282 lines
6.3 KiB
JavaScript
/** @license
|
|
* Copyright 2016 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
goog.provide('shaka.util.DataViewReader');
|
|
|
|
goog.require('goog.asserts');
|
|
goog.require('shaka.util.BufferUtils');
|
|
goog.require('shaka.util.Error');
|
|
goog.require('shaka.util.StringUtils');
|
|
|
|
|
|
/**
|
|
* @summary DataViewReader abstracts a DataView object.
|
|
* @export
|
|
*/
|
|
shaka.util.DataViewReader = class {
|
|
/**
|
|
* @param {BufferSource} data
|
|
* @param {shaka.util.DataViewReader.Endianness} endianness The endianness.
|
|
*/
|
|
constructor(data, endianness) {
|
|
/** @private {!DataView} */
|
|
this.dataView_ = shaka.util.BufferUtils.toDataView(data);
|
|
|
|
/** @private {boolean} */
|
|
this.littleEndian_ =
|
|
endianness == shaka.util.DataViewReader.Endianness.LITTLE_ENDIAN;
|
|
|
|
/** @private {number} */
|
|
this.position_ = 0;
|
|
}
|
|
|
|
|
|
/** @return {!DataView} The underlying DataView instance. */
|
|
getDataView() {
|
|
return this.dataView_;
|
|
}
|
|
|
|
|
|
/**
|
|
* @return {boolean} True if the reader has more data, false otherwise.
|
|
* @export
|
|
*/
|
|
hasMoreData() {
|
|
return this.position_ < this.dataView_.byteLength;
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets the current byte position.
|
|
* @return {number}
|
|
* @export
|
|
*/
|
|
getPosition() {
|
|
return this.position_;
|
|
}
|
|
|
|
|
|
/**
|
|
* Gets the byte length of the DataView.
|
|
* @return {number}
|
|
* @export
|
|
*/
|
|
getLength() {
|
|
return this.dataView_.byteLength;
|
|
}
|
|
|
|
|
|
/**
|
|
* Reads an unsigned 8 bit integer, and advances the reader.
|
|
* @return {number} The integer.
|
|
* @export
|
|
*/
|
|
readUint8() {
|
|
try {
|
|
const value = this.dataView_.getUint8(this.position_);
|
|
this.position_ += 1;
|
|
return value;
|
|
} catch (exception) {
|
|
throw this.outOfBounds_();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Reads an unsigned 16 bit integer, and advances the reader.
|
|
* @return {number} The integer.
|
|
* @export
|
|
*/
|
|
readUint16() {
|
|
try {
|
|
const value =
|
|
this.dataView_.getUint16(this.position_, this.littleEndian_);
|
|
this.position_ += 2;
|
|
return value;
|
|
} catch (exception) {
|
|
throw this.outOfBounds_();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Reads an unsigned 32 bit integer, and advances the reader.
|
|
* @return {number} The integer.
|
|
* @export
|
|
*/
|
|
readUint32() {
|
|
try {
|
|
const value =
|
|
this.dataView_.getUint32(this.position_, this.littleEndian_);
|
|
this.position_ += 4;
|
|
return value;
|
|
} catch (exception) {
|
|
throw this.outOfBounds_();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Reads a signed 32 bit integer, and advances the reader.
|
|
* @return {number} The integer.
|
|
* @export
|
|
*/
|
|
readInt32() {
|
|
try {
|
|
const value = this.dataView_.getInt32(this.position_, this.littleEndian_);
|
|
this.position_ += 4;
|
|
return value;
|
|
} catch (exception) {
|
|
throw this.outOfBounds_();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Reads an unsigned 64 bit integer, and advances the reader.
|
|
* @return {number} The integer.
|
|
* @export
|
|
*/
|
|
readUint64() {
|
|
/** @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) {
|
|
throw this.outOfBounds_();
|
|
}
|
|
|
|
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}
|
|
* @export
|
|
*/
|
|
readBytes(bytes) {
|
|
goog.asserts.assert(bytes >= 0, 'Bad call to DataViewReader.readBytes');
|
|
if (this.position_ + bytes > this.dataView_.byteLength) {
|
|
throw this.outOfBounds_();
|
|
}
|
|
|
|
const value =
|
|
shaka.util.BufferUtils.toUint8(this.dataView_, this.position_, bytes);
|
|
this.position_ += bytes;
|
|
return value;
|
|
}
|
|
|
|
|
|
/**
|
|
* Skips the specified number of bytes.
|
|
* @param {number} bytes The number of bytes to skip.
|
|
* @export
|
|
*/
|
|
skip(bytes) {
|
|
goog.asserts.assert(bytes >= 0, 'Bad call to DataViewReader.skip');
|
|
if (this.position_ + bytes > this.dataView_.byteLength) {
|
|
throw this.outOfBounds_();
|
|
}
|
|
this.position_ += bytes;
|
|
}
|
|
|
|
|
|
/**
|
|
* Rewinds the specified number of bytes.
|
|
* @param {number} bytes The number of bytes to rewind.
|
|
* @export
|
|
*/
|
|
rewind(bytes) {
|
|
goog.asserts.assert(bytes >= 0, 'Bad call to DataViewReader.rewind');
|
|
if (this.position_ < bytes) {
|
|
throw this.outOfBounds_();
|
|
}
|
|
this.position_ -= bytes;
|
|
}
|
|
|
|
|
|
/**
|
|
* Seeks to a specified position.
|
|
* @param {number} position The desired byte position within the DataView.
|
|
* @export
|
|
*/
|
|
seek(position) {
|
|
goog.asserts.assert(position >= 0, 'Bad call to DataViewReader.seek');
|
|
if (position < 0 || position > this.dataView_.byteLength) {
|
|
throw this.outOfBounds_();
|
|
}
|
|
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
|
|
*/
|
|
readTerminatedString() {
|
|
const start = this.position_;
|
|
while (this.hasMoreData()) {
|
|
const value = this.dataView_.getUint8(this.position_);
|
|
if (value == 0) {
|
|
break;
|
|
}
|
|
this.position_ += 1;
|
|
}
|
|
|
|
const ret = shaka.util.BufferUtils.toUint8(
|
|
this.dataView_, start, this.position_ - start);
|
|
// Skip string termination.
|
|
this.position_ += 1;
|
|
return shaka.util.StringUtils.fromUTF8(ret);
|
|
}
|
|
|
|
|
|
/**
|
|
* @return {!shaka.util.Error}
|
|
* @private
|
|
*/
|
|
outOfBounds_() {
|
|
return new shaka.util.Error(
|
|
shaka.util.Error.Severity.CRITICAL,
|
|
shaka.util.Error.Category.MEDIA,
|
|
shaka.util.Error.Code.BUFFER_READ_OUT_OF_BOUNDS);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Endianness.
|
|
* @enum {number}
|
|
* @export
|
|
*/
|
|
shaka.util.DataViewReader.Endianness = {
|
|
'BIG_ENDIAN': 0,
|
|
'LITTLE_ENDIAN': 1,
|
|
};
|