mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-14 15:56:38 +03:00
Disallow using new Uint8Array with BufferSource.
Using "new Uint8Array" with a TypedArray creates a copy of the buffer; this is unnecessarily expensive for large buffers. This adds a rule to disallow using it in favor of a new utility that correctly creates a new "view" on the same buffer. Note it is fine to pass an ArrayBuffer to "new Uint8Array" and it won't copy; but there there are many cases where the type is BufferSource, so it could be a TypedArray. Unfortunately, there are many other cases where we explicitly pass an ArrayBuffer; but the compiler rules don't allow us to whitelist this case (since ArrayBuffer is part of BufferSource). Change-Id: I58696a85a9cbcc188c0b16919c9eeb63e56edca1
This commit is contained in:
@@ -106,6 +106,31 @@ requirement: {
|
||||
error_message: 'Use expect.toBe for primitives'
|
||||
}
|
||||
|
||||
requirement: {
|
||||
type: BANNED_CODE_PATTERN
|
||||
value: '/** @param {BufferSource} a */'
|
||||
'function template(a) { new Uint8Array(a) }'
|
||||
value: '/** @param {BufferSource} a */'
|
||||
'function template(a) { new Int8Array(a) }'
|
||||
value: '/** @param {BufferSource} a */'
|
||||
'function template(a) { new Uint8ClampedArray(a) }'
|
||||
value: '/** @param {BufferSource} a */'
|
||||
'function template(a) { new Unt16Array(a) }'
|
||||
value: '/** @param {BufferSource} a */'
|
||||
'function template(a) { new Int16Array(a) }'
|
||||
value: '/** @param {BufferSource} a */'
|
||||
'function template(a) { new Uint32Array(a) }'
|
||||
value: '/** @param {BufferSource} a */'
|
||||
'function template(a) { new Int32Array(a) }'
|
||||
value: '/** @param {BufferSource} a */'
|
||||
'function template(a) { new Float32Array(a) }'
|
||||
value: '/** @param {BufferSource} a */'
|
||||
'function template(a) { new Float64Array(a) }'
|
||||
error_message: 'Use shaka.util.BufferUtils.view* instead.'
|
||||
whitelist_regexp: 'lib/util/buffer_utils.js'
|
||||
whitelist_regexp: 'lib/util/uint8array_utils.js'
|
||||
whitelist_regexp: 'test/'
|
||||
}
|
||||
|
||||
# Disallow console logging.
|
||||
requirement: {
|
||||
|
||||
+1
-1
@@ -903,7 +903,7 @@ shakaDemo.Main = class {
|
||||
// Fetch the certificate, and apply it to the configuration.
|
||||
const certificate = await this.requestCertificate_(
|
||||
asset.certificateUri, netEngine);
|
||||
const certArray = new Uint8Array(certificate);
|
||||
const certArray = shaka.util.BufferUtils.toUint8(certificate);
|
||||
for (const drmSystem of asset.licenseServers.keys()) {
|
||||
config.drm.advanced[drmSystem] = config.drm.advanced[drmSystem] || {};
|
||||
config.drm.advanced[drmSystem].serverCertificate = certArray;
|
||||
|
||||
@@ -187,7 +187,7 @@ shaka.cast.CastUtils = class {
|
||||
* @private
|
||||
*/
|
||||
static makeUint8Array_(obj) {
|
||||
return new Uint8Array(obj['entries']);
|
||||
return new Uint8Array(/** @type {!Array.<number>} */ (obj['entries']));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -216,10 +216,8 @@ shaka.dash.ContentProtection = class {
|
||||
return [];
|
||||
}
|
||||
|
||||
const buffer = shaka.util.BufferUtils.unsafeGetArrayBuffer(view);
|
||||
const recordValue = new Uint8Array(
|
||||
buffer, view.byteOffset + byteOffset, byteLength);
|
||||
|
||||
const recordValue = shaka.util.BufferUtils.toUint8(
|
||||
view, byteOffset, byteLength);
|
||||
records.push({
|
||||
type: type,
|
||||
value: recordValue,
|
||||
@@ -232,7 +230,7 @@ shaka.dash.ContentProtection = class {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an ArrayBuffer for PlayReady Objects. The data
|
||||
* Parses a buffer for PlayReady Objects. The data
|
||||
* should contain a 32-bit integer indicating the length of
|
||||
* the PRO in bytes. Following that, a 16-bit integer for
|
||||
* the number of PlayReady Object Records in the PRO. Lastly,
|
||||
|
||||
@@ -2163,7 +2163,7 @@ shaka.hls.HlsParser = class {
|
||||
const parsedData = shaka.net.DataUriPlugin.parseRaw(uri);
|
||||
|
||||
// The data encoded in the URI is a PSSH box to be used as init data.
|
||||
const pssh = new Uint8Array(parsedData.data);
|
||||
const pssh = shaka.util.BufferUtils.toUint8(parsedData.data);
|
||||
const drmInfo = shaka.util.ManifestParserUtils.createDrmInfo(
|
||||
'com.widevine.alpha', [
|
||||
{initDataType: 'cenc', initData: pssh},
|
||||
|
||||
@@ -19,6 +19,8 @@ goog.provide('shaka.media.IClosedCaptionParser');
|
||||
goog.provide('shaka.media.MuxJSClosedCaptionParser');
|
||||
goog.provide('shaka.media.NoopCaptionParser');
|
||||
|
||||
goog.require('shaka.util.BufferUtils');
|
||||
|
||||
|
||||
/**
|
||||
* The IClosedCaptionParser defines the interface to provide all operations for
|
||||
@@ -78,7 +80,7 @@ shaka.media.MuxJSClosedCaptionParser = class {
|
||||
init(data) {
|
||||
const probe = muxjs.mp4.probe;
|
||||
// Caption parser for Dash
|
||||
const initBytes = new Uint8Array(data);
|
||||
const initBytes = shaka.util.BufferUtils.toUint8(data);
|
||||
this.videoTrackIds_ = probe.videoTrackIds(initBytes);
|
||||
this.timescales_ = probe.timescale(initBytes);
|
||||
this.muxCaptionParser_.init();
|
||||
@@ -88,7 +90,7 @@ shaka.media.MuxJSClosedCaptionParser = class {
|
||||
* @override
|
||||
*/
|
||||
parseFrom(data, onCaptions) {
|
||||
const segmentBytes = new Uint8Array(data);
|
||||
const segmentBytes = shaka.util.BufferUtils.toUint8(data);
|
||||
const dashParsed = this.muxCaptionParser_.parse(
|
||||
segmentBytes, this.videoTrackIds_, this.timescales_);
|
||||
if (dashParsed && dashParsed.captions) {
|
||||
|
||||
@@ -411,8 +411,8 @@ shaka.media.DrmEngine = class {
|
||||
!this.offlineSessionIds_.length) {
|
||||
// Explicit init data for any one stream or an offline session is
|
||||
// sufficient to suppress 'encrypted' events for all streams.
|
||||
const cb = (e) =>
|
||||
this.newInitData(e.initDataType, new Uint8Array(e.initData));
|
||||
const cb = (e) => this.newInitData(
|
||||
e.initDataType, shaka.util.BufferUtils.toUint8(e.initData));
|
||||
this.eventManager_.listen(this.video_, 'encrypted', cb);
|
||||
}
|
||||
}
|
||||
@@ -890,7 +890,8 @@ shaka.media.DrmEngine = class {
|
||||
// Suggestion: https://bit.ly/2JYcNTu
|
||||
// Format: https://www.w3.org/TR/eme-initdata-keyids/
|
||||
const initDataStr = JSON.stringify({'kids': keyIds});
|
||||
const initData = new Uint8Array(StringUtils.toUTF8(initDataStr));
|
||||
const initData =
|
||||
shaka.util.BufferUtils.toUint8(StringUtils.toUTF8(initDataStr));
|
||||
const initDatas = [{initData: initData, initDataType: 'keyids'}];
|
||||
|
||||
return {
|
||||
@@ -1313,7 +1314,8 @@ shaka.media.DrmEngine = class {
|
||||
hasExpiredKeys = true;
|
||||
}
|
||||
|
||||
const keyIdHex = shaka.util.Uint8ArrayUtils.toHex(new Uint8Array(keyId));
|
||||
const keyIdHex = shaka.util.Uint8ArrayUtils.toHex(
|
||||
shaka.util.BufferUtils.toUint8(keyId));
|
||||
|
||||
this.keyStatusByKeyId_.set(keyIdHex, status);
|
||||
});
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
goog.provide('shaka.media.Transmuxer');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('shaka.util.BufferUtils');
|
||||
goog.require('shaka.util.Error');
|
||||
goog.require('shaka.util.IDestroyable');
|
||||
goog.require('shaka.util.ManifestParserUtils');
|
||||
@@ -160,7 +161,7 @@ shaka.media.Transmuxer = class {
|
||||
this.transmuxedData_ = [];
|
||||
this.captions_ = [];
|
||||
|
||||
const dataArray = new Uint8Array(data);
|
||||
const dataArray = shaka.util.BufferUtils.toUint8(data);
|
||||
this.muxTransmuxer_.push(dataArray);
|
||||
this.muxTransmuxer_.flush();
|
||||
|
||||
@@ -190,11 +191,8 @@ shaka.media.Transmuxer = class {
|
||||
*/
|
||||
onTransmuxed_(segment) {
|
||||
this.captions_ = segment.captions;
|
||||
const segmentWithInit = new Uint8Array(segment.data.byteLength +
|
||||
segment.initSegment.byteLength);
|
||||
segmentWithInit.set(segment.initSegment, 0);
|
||||
segmentWithInit.set(segment.data, segment.initSegment.byteLength);
|
||||
this.transmuxedData_.push(segmentWithInit);
|
||||
this.transmuxedData_.push(
|
||||
shaka.util.Uint8ArrayUtils.concat(segment.initSegment, segment.data));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -335,9 +335,6 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeys = class {
|
||||
|
||||
/** @private {!shaka.util.EventManager} */
|
||||
this.eventManager_ = new shaka.util.EventManager();
|
||||
|
||||
/** @type {Uint8Array} */
|
||||
this.certificate = null;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
@@ -361,11 +358,7 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeys = class {
|
||||
/** @override */
|
||||
setServerCertificate(serverCertificate) {
|
||||
shaka.log.debug('PatchedMediaKeysApple.MediaKeys.setServerCertificate');
|
||||
|
||||
this.certificate =
|
||||
serverCertificate ? new Uint8Array(serverCertificate) : null;
|
||||
|
||||
return Promise.resolve(true);
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -475,7 +468,7 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession =
|
||||
// It also only accepts Uint8Array, not ArrayBuffer, so explicitly
|
||||
// make initData into a Uint8Array.
|
||||
const session = this.nativeMediaKeys_.createSession(
|
||||
'video/mp4', new Uint8Array(initData));
|
||||
'video/mp4', shaka.util.BufferUtils.toUint8(initData));
|
||||
this.nativeMediaKeySession_ = session;
|
||||
this.sessionId = session.sessionId || '';
|
||||
|
||||
@@ -515,7 +508,8 @@ shaka.polyfill.PatchedMediaKeysApple.MediaKeySession =
|
||||
|
||||
try {
|
||||
// Pass through to the native session.
|
||||
this.nativeMediaKeySession_.update(new Uint8Array(response));
|
||||
this.nativeMediaKeySession_.update(
|
||||
shaka.util.BufferUtils.toUint8(response));
|
||||
} catch (exception) {
|
||||
this.updatePromise_.reject(exception);
|
||||
}
|
||||
|
||||
@@ -498,8 +498,8 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession =
|
||||
|
||||
// NOTE: IE11 takes either Uint8Array or ArrayBuffer, but Edge 12 only
|
||||
// accepts Uint8Array.
|
||||
this.nativeMediaKeySession_ = this.nativeMediaKeys_
|
||||
.createSession('video/mp4', new Uint8Array(initData), null);
|
||||
this.nativeMediaKeySession_ = this.nativeMediaKeys_.createSession(
|
||||
'video/mp4', shaka.util.BufferUtils.toUint8(initData), null);
|
||||
|
||||
// Attach session event handlers here.
|
||||
this.eventManager_.listen(this.nativeMediaKeySession_, 'mskeymessage',
|
||||
@@ -538,7 +538,8 @@ shaka.polyfill.PatchedMediaKeysMs.MediaKeySession =
|
||||
// Pass through to the native session.
|
||||
// NOTE: IE11 takes either Uint8Array or ArrayBuffer, but Edge 12 only
|
||||
// accepts Uint8Array.
|
||||
this.nativeMediaKeySession_.update(new Uint8Array(response));
|
||||
this.nativeMediaKeySession_.update(
|
||||
shaka.util.BufferUtils.toUint8(response));
|
||||
} catch (exception) {
|
||||
this.updatePromise_.reject(exception);
|
||||
}
|
||||
|
||||
@@ -676,19 +676,22 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession =
|
||||
if (this.type_ == 'persistent-license') {
|
||||
const StringUtils = shaka.util.StringUtils;
|
||||
if (!offlineSessionId) {
|
||||
goog.asserts.assert(initData, 'expecting init data');
|
||||
// Persisting the initial license.
|
||||
// Prefix the init data with a tag to indicate persistence.
|
||||
const prefix = StringUtils.toUTF8('PERSISTENT|');
|
||||
const result =
|
||||
new Uint8Array(prefix.byteLength + initData.byteLength);
|
||||
result.set(new Uint8Array(prefix), 0);
|
||||
result.set(new Uint8Array(initData), prefix.byteLength);
|
||||
result.set(shaka.util.BufferUtils.toUint8(prefix), 0);
|
||||
result.set(
|
||||
shaka.util.BufferUtils.toUint8(initData),
|
||||
prefix.byteLength);
|
||||
mangledInitData = result;
|
||||
} else {
|
||||
// Loading a stored license.
|
||||
// Prefix the init data (which is really a session ID) with a tag
|
||||
// to indicate that we are loading a persisted session.
|
||||
mangledInitData = new Uint8Array(
|
||||
mangledInitData = shaka.util.BufferUtils.toUint8(
|
||||
StringUtils.toUTF8('LOAD_SESSION|' + offlineSessionId));
|
||||
}
|
||||
} else {
|
||||
@@ -697,11 +700,11 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession =
|
||||
'expected temporary session');
|
||||
goog.asserts.assert(!offlineSessionId,
|
||||
'unexpected offline session ID');
|
||||
mangledInitData = new Uint8Array(initData);
|
||||
goog.asserts.assert(initData, 'expecting init data');
|
||||
mangledInitData = shaka.util.BufferUtils.toUint8(initData);
|
||||
}
|
||||
|
||||
goog.asserts.assert(mangledInitData,
|
||||
'init data not set!');
|
||||
goog.asserts.assert(mangledInitData, 'init data not set!');
|
||||
} catch (exception) {
|
||||
return Promise.reject(exception);
|
||||
}
|
||||
@@ -750,7 +753,7 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession =
|
||||
*
|
||||
* @param {!shaka.util.PublicPromise} promise The promise associated with
|
||||
* this call.
|
||||
* @param {?BufferSource} response
|
||||
* @param {BufferSource} response
|
||||
* @private
|
||||
*/
|
||||
update_(promise, response) {
|
||||
@@ -787,7 +790,7 @@ shaka.polyfill.PatchedMediaKeysWebkit.MediaKeySession =
|
||||
keyId = Uint8ArrayUtils.fromBase64(jwkSet.keys[0].kid);
|
||||
} else {
|
||||
// The key ID is not required.
|
||||
key = new Uint8Array(response);
|
||||
key = shaka.util.BufferUtils.toUint8(response);
|
||||
keyId = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ goog.provide('shaka.text.TextEngine');
|
||||
|
||||
goog.require('goog.asserts');
|
||||
goog.require('shaka.text.Cue');
|
||||
goog.require('shaka.util.BufferUtils');
|
||||
goog.require('shaka.util.Error');
|
||||
goog.require('shaka.util.IDestroyable');
|
||||
goog.require('shaka.util.MimeUtils');
|
||||
@@ -162,7 +163,8 @@ shaka.text.TextEngine = class {
|
||||
|
||||
// Parse the buffer and extract the first cue start time.
|
||||
try {
|
||||
const firstCue = this.parser_.parseFirstCue(new Uint8Array(buffer), time);
|
||||
const firstCue = this.parser_.parseFirstCue(
|
||||
shaka.util.BufferUtils.toUint8(buffer), time);
|
||||
return firstCue.startTime;
|
||||
} catch (exception) {
|
||||
// This could be a failure from the parser itself (init segment required)
|
||||
@@ -194,7 +196,7 @@ shaka.text.TextEngine = class {
|
||||
}
|
||||
|
||||
if (startTime == null || endTime == null) {
|
||||
this.parser_.parseInit(new Uint8Array(buffer));
|
||||
this.parser_.parseInit(shaka.util.BufferUtils.toUint8(buffer));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -206,7 +208,8 @@ shaka.text.TextEngine = class {
|
||||
};
|
||||
|
||||
// Parse the buffer and add the new cues.
|
||||
const allCues = this.parser_.parseMedia(new Uint8Array(buffer), time);
|
||||
const allCues = this.parser_.parseMedia(
|
||||
shaka.util.BufferUtils.toUint8(buffer), time);
|
||||
const cuesToAppend = allCues.filter((cue) => {
|
||||
return cue.startTime >= this.appendWindowStart_ &&
|
||||
cue.startTime < this.appendWindowEnd_;
|
||||
|
||||
@@ -54,8 +54,8 @@ shaka.util.BufferUtils = class {
|
||||
return true;
|
||||
}
|
||||
|
||||
const uint8A = new Uint8Array(arr1);
|
||||
const uint8B = new Uint8Array(arr2);
|
||||
const uint8A = shaka.util.BufferUtils.toUint8(arr1);
|
||||
const uint8B = shaka.util.BufferUtils.toUint8(arr2);
|
||||
for (const i of shaka.util.Iterables.range(arr1.byteLength)) {
|
||||
if (uint8A[i] != uint8B[i]) {
|
||||
return false;
|
||||
@@ -108,14 +108,42 @@ shaka.util.BufferUtils = class {
|
||||
/**
|
||||
* Creates a DataView over the given buffer.
|
||||
* @param {BufferSource} buffer
|
||||
* @param {number=} offset
|
||||
* @param {number=} length
|
||||
* @return {!DataView}
|
||||
* @export
|
||||
*/
|
||||
static toDataView(buffer) {
|
||||
if (buffer instanceof ArrayBuffer) {
|
||||
return new DataView(buffer);
|
||||
} else {
|
||||
return new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
||||
}
|
||||
static toDataView(buffer, offset = 0, length = Infinity) {
|
||||
return shaka.util.BufferUtils.view_(buffer, offset, length, DataView);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new Uint8Array view on the same buffer.
|
||||
* @param {BufferSource} data
|
||||
* @param {number=} offset The offset from the beginning of this data's view
|
||||
* to start the new view at.
|
||||
* @param {number=} length The length of the new view.
|
||||
* @return {!Uint8Array}
|
||||
* @export
|
||||
*/
|
||||
static toUint8(data, offset = 0, length = Infinity) {
|
||||
return shaka.util.BufferUtils.view_(data, offset, length, Uint8Array);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BufferSource} data
|
||||
* @param {number} offset
|
||||
* @param {number} length
|
||||
* @param {function(new:T, ArrayBuffer, number, number)} Type
|
||||
* @return {!T}
|
||||
* @template T
|
||||
* @private
|
||||
*/
|
||||
static view_(data, offset, length, Type) {
|
||||
const buffer = shaka.util.BufferUtils.unsafeGetArrayBuffer(data);
|
||||
return new Type(
|
||||
buffer,
|
||||
(data.byteOffset || 0) + Math.min(offset, data.byteLength),
|
||||
Math.max(0, Math.min(data.byteLength - offset, length)));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -198,11 +198,8 @@ shaka.util.DataViewReader = class {
|
||||
throw this.outOfBounds_();
|
||||
}
|
||||
|
||||
const value = new Uint8Array(
|
||||
shaka.util.BufferUtils.unsafeGetArrayBuffer(this.dataView_),
|
||||
this.dataView_.byteOffset + this.position_,
|
||||
bytes);
|
||||
|
||||
const value =
|
||||
shaka.util.BufferUtils.toUint8(this.dataView_, this.position_, bytes);
|
||||
this.position_ += bytes;
|
||||
return value;
|
||||
}
|
||||
@@ -270,10 +267,8 @@ shaka.util.DataViewReader = class {
|
||||
this.position_ += 1;
|
||||
}
|
||||
|
||||
const ret = new Uint8Array(
|
||||
shaka.util.BufferUtils.unsafeGetArrayBuffer(this.dataView_),
|
||||
this.dataView_.byteOffset + start,
|
||||
this.position_ - start);
|
||||
const ret = shaka.util.BufferUtils.toUint8(
|
||||
this.dataView_, start, this.position_ - start);
|
||||
// Skip string termination.
|
||||
this.position_ += 1;
|
||||
return shaka.util.StringUtils.fromUTF8(ret);
|
||||
|
||||
+5
-11
@@ -81,10 +81,8 @@ shaka.util.EbmlParser = class {
|
||||
size :
|
||||
this.dataView_.byteLength - this.reader_.getPosition();
|
||||
|
||||
const dataView = new DataView(
|
||||
shaka.util.BufferUtils.unsafeGetArrayBuffer(this.dataView_),
|
||||
this.dataView_.byteOffset + this.reader_.getPosition(),
|
||||
elementSize);
|
||||
const dataView = shaka.util.BufferUtils.toDataView(
|
||||
this.dataView_, this.reader_.getPosition(), elementSize);
|
||||
|
||||
this.reader_.skip(elementSize);
|
||||
|
||||
@@ -130,6 +128,7 @@ shaka.util.EbmlParser = class {
|
||||
* @private
|
||||
*/
|
||||
parseVint_() {
|
||||
const position = this.reader_.getPosition();
|
||||
const firstByte = this.reader_.readUint8();
|
||||
if (firstByte == 0) {
|
||||
throw new shaka.util.Error(
|
||||
@@ -142,13 +141,8 @@ shaka.util.EbmlParser = class {
|
||||
const index = Math.floor(Math.log2(firstByte));
|
||||
const numBytes = 8 - index;
|
||||
goog.asserts.assert(numBytes <= 8 && numBytes >= 1, 'Incorrect log2 value');
|
||||
|
||||
const vint = new Uint8Array(numBytes);
|
||||
for (const i of shaka.util.Iterables.range(numBytes)) {
|
||||
vint[i] = i == 0 ? firstByte : this.reader_.readUint8();
|
||||
}
|
||||
|
||||
return vint;
|
||||
this.reader_.skip(numBytes - 1);
|
||||
return shaka.util.BufferUtils.toUint8(this.dataView_, position, numBytes);
|
||||
}
|
||||
|
||||
|
||||
|
||||
+10
-10
@@ -35,7 +35,7 @@ shaka.util.FairPlayUtils = class {
|
||||
* @export
|
||||
*/
|
||||
static defaultGetContentId(initData) {
|
||||
const uint8 = new Uint8Array(initData);
|
||||
const uint8 = shaka.util.BufferUtils.toUint8(initData);
|
||||
const dataview = shaka.util.BufferUtils.toDataView(uint8);
|
||||
// The first part is a 4 byte little-endian int, which is the length of
|
||||
// the second part.
|
||||
@@ -86,25 +86,25 @@ shaka.util.FairPlayUtils = class {
|
||||
// composed of several parts. First, the raw init data we already got.
|
||||
// Second, a 4-byte LE length followed by the content ID in UTF-16-LE.
|
||||
// Third, a 4-byte LE length followed by the certificate.
|
||||
/** @type {!Uint8Array} */
|
||||
/** @type {BufferSource} */
|
||||
let contentIdArray;
|
||||
if (typeof contentId == 'string') {
|
||||
contentIdArray = new Uint8Array(
|
||||
shaka.util.StringUtils.toUTF16(contentId, /* littleEndian= */ true));
|
||||
contentIdArray =
|
||||
shaka.util.StringUtils.toUTF16(contentId, /* littleEndian= */ true);
|
||||
} else {
|
||||
contentIdArray = new Uint8Array(contentId);
|
||||
contentIdArray = contentId;
|
||||
}
|
||||
|
||||
const rebuiltInitData = new Uint8Array(
|
||||
8 + initData.byteLength + contentIdArray.byteLength + cert.byteLength);
|
||||
|
||||
let offset = 0;
|
||||
/** @param {!Uint8Array} array */
|
||||
/** @param {BufferSource} array */
|
||||
const append = (array) => {
|
||||
rebuiltInitData.set(array, offset);
|
||||
rebuiltInitData.set(shaka.util.BufferUtils.toUint8(array), offset);
|
||||
offset += array.byteLength;
|
||||
};
|
||||
/** @param {!Uint8Array} array */
|
||||
/** @param {BufferSource} array */
|
||||
const appendWithLength = (array) => {
|
||||
const view = shaka.util.BufferUtils.toDataView(rebuiltInitData);
|
||||
const value = array.byteLength;
|
||||
@@ -113,9 +113,9 @@ shaka.util.FairPlayUtils = class {
|
||||
append(array);
|
||||
};
|
||||
|
||||
append(new Uint8Array(initData));
|
||||
append(initData);
|
||||
appendWithLength(contentIdArray);
|
||||
appendWithLength(new Uint8Array(cert));
|
||||
appendWithLength(cert);
|
||||
|
||||
return rebuiltInitData;
|
||||
}
|
||||
|
||||
@@ -43,7 +43,7 @@ shaka.util.StringUtils = class {
|
||||
return '';
|
||||
}
|
||||
|
||||
let uint8 = new Uint8Array(data);
|
||||
let uint8 = shaka.util.BufferUtils.toUint8(data);
|
||||
// If present, strip off the UTF-8 BOM.
|
||||
if (uint8[0] == 0xef && uint8[1] == 0xbb && uint8[2] == 0xbf) {
|
||||
uint8 = uint8.subarray(3);
|
||||
@@ -116,8 +116,11 @@ shaka.util.StringUtils = class {
|
||||
*/
|
||||
static fromBytesAutoDetect(data) {
|
||||
const StringUtils = shaka.util.StringUtils;
|
||||
if (!data) {
|
||||
return '';
|
||||
}
|
||||
|
||||
const uint8 = new Uint8Array(data);
|
||||
const uint8 = shaka.util.BufferUtils.toUint8(data);
|
||||
if (uint8[0] == 0xef && uint8[1] == 0xbb && uint8[2] == 0xbf) {
|
||||
return StringUtils.fromUTF8(uint8);
|
||||
} else if (uint8[0] == 0xfe && uint8[1] == 0xff) {
|
||||
@@ -212,6 +215,7 @@ shaka.util.StringUtils = class {
|
||||
// Check the browser for what chunk sizes it supports. Cache the result
|
||||
// in an impl method to avoid checking several times.
|
||||
if (!shaka.util.StringUtils.fromCharCodeImpl_) {
|
||||
/** @param {number} size @return {boolean} */
|
||||
const supportsChunkSize = (size) => {
|
||||
try {
|
||||
const buffer = new Uint8Array(size);
|
||||
|
||||
@@ -43,8 +43,7 @@ describe('BufferUtils', () => {
|
||||
expect(BufferUtils.equal(a, c)).toBe(false);
|
||||
});
|
||||
|
||||
// TODO(modmaker): Fix comparisons of different types.
|
||||
xit('compares different types', () => {
|
||||
it('compares different types', () => {
|
||||
const a = new Uint8Array([0, 1, 2, 3]);
|
||||
const b = new DataView(new ArrayBuffer(4));
|
||||
b.setUint16(0, 0x0001, false);
|
||||
@@ -86,4 +85,86 @@ describe('BufferUtils', () => {
|
||||
expect(BufferUtils.equal(a.buffer, d.buffer)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('toUint8', () => {
|
||||
it('allows passing ArrayBuffer', () => {
|
||||
const buffer = new ArrayBuffer(10);
|
||||
const value = BufferUtils.toUint8(buffer);
|
||||
expect(value.buffer).toBe(buffer);
|
||||
expect(value.byteOffset).toBe(0);
|
||||
expect(value.byteLength).toBe(buffer.byteLength);
|
||||
});
|
||||
|
||||
it('allows passing Uint8Array', () => {
|
||||
const buffer = new Uint8Array(10);
|
||||
const value = BufferUtils.toUint8(buffer);
|
||||
expect(value).not.toBe(buffer);
|
||||
expect(value.buffer).toBe(buffer.buffer);
|
||||
expect(value.byteOffset).toBe(0);
|
||||
expect(value.byteLength).toBe(buffer.byteLength);
|
||||
});
|
||||
|
||||
it('allows passing partial Uint8Array', () => {
|
||||
const buffer = new ArrayBuffer(10);
|
||||
const view = new Uint8Array(buffer, 4, 4);
|
||||
const value = BufferUtils.toUint8(view);
|
||||
expect(value).not.toBe(view);
|
||||
expect(value.buffer).toBe(buffer);
|
||||
expect(value.byteOffset).toBe(4);
|
||||
expect(value.byteLength).toBe(4);
|
||||
});
|
||||
|
||||
it('allows setting offset/length with ArrayBuffer', () => {
|
||||
const buffer = new ArrayBuffer(10);
|
||||
const value = BufferUtils.toUint8(buffer, 3, 5);
|
||||
expect(value.buffer).toBe(buffer);
|
||||
expect(value.byteOffset).toBe(3);
|
||||
expect(value.byteLength).toBe(5);
|
||||
});
|
||||
|
||||
it('allows setting offset/length with Uint8Array', () => {
|
||||
const buffer = new Uint8Array(10);
|
||||
const value = BufferUtils.toUint8(buffer, 3, 5);
|
||||
expect(value).not.toBe(buffer);
|
||||
expect(value.buffer).toBe(buffer.buffer);
|
||||
expect(value.byteOffset).toBe(3);
|
||||
expect(value.byteLength).toBe(5);
|
||||
});
|
||||
|
||||
it('allows setting offset/length with partial Uint8Array', () => {
|
||||
const buffer = new ArrayBuffer(20);
|
||||
const view = new Uint8Array(buffer, 5, 10);
|
||||
const value = BufferUtils.toUint8(view, 3, 5);
|
||||
expect(value).not.toBe(view);
|
||||
expect(value.buffer).toBe(buffer);
|
||||
expect(value.byteOffset).toBe(8);
|
||||
expect(value.byteLength).toBe(5);
|
||||
});
|
||||
|
||||
it('clamps offset to buffer', () => {
|
||||
const buffer = new ArrayBuffer(10);
|
||||
const value = BufferUtils.toUint8(buffer, 12);
|
||||
expect(value.buffer).toBe(buffer);
|
||||
expect(value.byteOffset).toBe(10);
|
||||
expect(value.byteLength).toBe(0);
|
||||
});
|
||||
|
||||
it('clamps offset to view', () => {
|
||||
const buffer = new ArrayBuffer(20);
|
||||
const view = new Uint8Array(buffer, 5, 10);
|
||||
const value = BufferUtils.toUint8(view, 12);
|
||||
expect(value.buffer).toBe(buffer);
|
||||
expect(value.byteOffset).toBe(15);
|
||||
expect(value.byteLength).toBe(0);
|
||||
});
|
||||
|
||||
it('clamps length to view', () => {
|
||||
const buffer = new ArrayBuffer(20);
|
||||
const view = new Uint8Array(buffer, 5, 10);
|
||||
const value = BufferUtils.toUint8(view, 4, 20);
|
||||
expect(value.buffer).toBe(buffer);
|
||||
expect(value.byteOffset).toBe(9);
|
||||
expect(value.byteLength).toBe(6);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user