diff --git a/build/conformance.textproto b/build/conformance.textproto index fc791eb5d..f7820ff30 100644 --- a/build/conformance.textproto +++ b/build/conformance.textproto @@ -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: { diff --git a/demo/main.js b/demo/main.js index c4cb9a7b7..fa61d844b 100644 --- a/demo/main.js +++ b/demo/main.js @@ -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; diff --git a/lib/cast/cast_utils.js b/lib/cast/cast_utils.js index bc14573b1..697082fd3 100644 --- a/lib/cast/cast_utils.js +++ b/lib/cast/cast_utils.js @@ -187,7 +187,7 @@ shaka.cast.CastUtils = class { * @private */ static makeUint8Array_(obj) { - return new Uint8Array(obj['entries']); + return new Uint8Array(/** @type {!Array.} */ (obj['entries'])); } }; diff --git a/lib/dash/content_protection.js b/lib/dash/content_protection.js index aab0eae58..c9bcd538d 100644 --- a/lib/dash/content_protection.js +++ b/lib/dash/content_protection.js @@ -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, diff --git a/lib/hls/hls_parser.js b/lib/hls/hls_parser.js index 56a37b6a1..0bd1a03f6 100644 --- a/lib/hls/hls_parser.js +++ b/lib/hls/hls_parser.js @@ -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}, diff --git a/lib/media/closed_caption_parser.js b/lib/media/closed_caption_parser.js index 1d8a9d031..f0ee31a31 100644 --- a/lib/media/closed_caption_parser.js +++ b/lib/media/closed_caption_parser.js @@ -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) { diff --git a/lib/media/drm_engine.js b/lib/media/drm_engine.js index 7e35fb957..2626af7f8 100644 --- a/lib/media/drm_engine.js +++ b/lib/media/drm_engine.js @@ -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); }); diff --git a/lib/media/transmuxer.js b/lib/media/transmuxer.js index e09cc70c8..434630289 100644 --- a/lib/media/transmuxer.js +++ b/lib/media/transmuxer.js @@ -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)); } diff --git a/lib/polyfill/patchedmediakeys_apple.js b/lib/polyfill/patchedmediakeys_apple.js index 4f530cf8a..13676ca3e 100644 --- a/lib/polyfill/patchedmediakeys_apple.js +++ b/lib/polyfill/patchedmediakeys_apple.js @@ -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); } diff --git a/lib/polyfill/patchedmediakeys_ms.js b/lib/polyfill/patchedmediakeys_ms.js index 6f48e4fbf..b7fcea6a4 100644 --- a/lib/polyfill/patchedmediakeys_ms.js +++ b/lib/polyfill/patchedmediakeys_ms.js @@ -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); } diff --git a/lib/polyfill/patchedmediakeys_webkit.js b/lib/polyfill/patchedmediakeys_webkit.js index 9c71f07f6..45b69f2cf 100644 --- a/lib/polyfill/patchedmediakeys_webkit.js +++ b/lib/polyfill/patchedmediakeys_webkit.js @@ -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; } diff --git a/lib/text/text_engine.js b/lib/text/text_engine.js index ee56faa23..f03af7f0b 100644 --- a/lib/text/text_engine.js +++ b/lib/text/text_engine.js @@ -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_; diff --git a/lib/util/buffer_utils.js b/lib/util/buffer_utils.js index 523b74ee3..9b1162578 100644 --- a/lib/util/buffer_utils.js +++ b/lib/util/buffer_utils.js @@ -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))); } }; diff --git a/lib/util/data_view_reader.js b/lib/util/data_view_reader.js index beb207fae..31d501a92 100644 --- a/lib/util/data_view_reader.js +++ b/lib/util/data_view_reader.js @@ -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); diff --git a/lib/util/ebml_parser.js b/lib/util/ebml_parser.js index b307f8c47..75955dc41 100644 --- a/lib/util/ebml_parser.js +++ b/lib/util/ebml_parser.js @@ -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); } diff --git a/lib/util/fairplay_utils.js b/lib/util/fairplay_utils.js index afd243563..19313a6f0 100644 --- a/lib/util/fairplay_utils.js +++ b/lib/util/fairplay_utils.js @@ -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; } diff --git a/lib/util/string_utils.js b/lib/util/string_utils.js index c6fde34aa..048683645 100644 --- a/lib/util/string_utils.js +++ b/lib/util/string_utils.js @@ -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); diff --git a/test/util/buffer_utils_unit.js b/test/util/buffer_utils_unit.js index a5ef3f65b..d1cd4c33f 100644 --- a/test/util/buffer_utils_unit.js +++ b/test/util/buffer_utils_unit.js @@ -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); + }); + }); });