/** * @fileoverview Provides ByteString as a basic data type for protos. */ goog.module('protobuf.ByteString'); const base64 = goog.require('goog.crypt.base64'); const {arrayBufferSlice, cloneArrayBufferView, hashUint8Array, uint8ArrayEqual} = goog.require('protobuf.binary.typedArrays'); /** * Immutable sequence of bytes. * * Bytes can be obtained as an ArrayBuffer or a base64 encoded string. * @final */ class ByteString { /** * @param {?Uint8Array} bytes * @param {?string} base64 * @private */ constructor(bytes, base64) { /** @private {?Uint8Array}*/ this.bytes_ = bytes; /** @private {?string} */ this.base64_ = base64; /** @private {number} */ this.hashCode_ = 0; } /** * Constructs a ByteString instance from a base64 string. * @param {string} value * @return {!ByteString} */ static fromBase64String(value) { if (value == null) { throw new Error('value must not be null'); } return new ByteString(/* bytes */ null, value); } /** * Constructs a ByteString from an array buffer. * @param {!ArrayBuffer} bytes * @param {number=} start * @param {number=} end * @return {!ByteString} */ static fromArrayBuffer(bytes, start = 0, end = undefined) { return new ByteString( new Uint8Array(arrayBufferSlice(bytes, start, end)), /* base64 */ null); } /** * Constructs a ByteString from any ArrayBufferView (e.g. DataView, * TypedArray, Uint8Array, etc.). * @param {!ArrayBufferView} bytes * @return {!ByteString} */ static fromArrayBufferView(bytes) { return new ByteString(cloneArrayBufferView(bytes), /* base64 */ null); } /** * Constructs a ByteString from an Uint8Array. DON'T MODIFY the underlying * ArrayBuffer, since the ByteString directly uses it without making a copy. * * This method exists so that internal APIs can construct a ByteString without * paying the penalty of copying an ArrayBuffer when that ArrayBuffer is not * supposed to change. It is exposed to a limited number of internal classes * through bytestring_internal.js. * * @param {!Uint8Array} bytes * @return {!ByteString} * @package */ static fromUint8ArrayUnsafe(bytes) { return new ByteString(bytes, /* base64 */ null); } /** * Returns this ByteString as an ArrayBuffer. * @return {!ArrayBuffer} */ toArrayBuffer() { const bytes = this.ensureBytes_(); return arrayBufferSlice( bytes.buffer, bytes.byteOffset, bytes.byteOffset + bytes.byteLength); } /** * Returns this ByteString as an Uint8Array. DON'T MODIFY the returned array, * since the ByteString holds the reference to the same array. * * This method exists so that internal APIs can get contents of a ByteString * without paying the penalty of copying an ArrayBuffer. It is exposed to a * limited number of internal classes through bytestring_internal.js. * @return {!Uint8Array} * @package */ toUint8ArrayUnsafe() { return this.ensureBytes_(); } /** * Returns this ByteString as a base64 encoded string. * @return {string} */ toBase64String() { return this.ensureBase64String_(); } /** * Returns true for Bytestrings that contain identical values. * @param {*} other * @return {boolean} */ equals(other) { if (this === other) { return true; } if (!(other instanceof ByteString)) { return false; } const otherByteString = /** @type {!ByteString} */ (other); return uint8ArrayEqual(this.ensureBytes_(), otherByteString.ensureBytes_()); } /** * Returns a number (int32) that is suitable for using in hashed structures. * @return {number} */ hashCode() { if (this.hashCode_ == 0) { this.hashCode_ = hashUint8Array(this.ensureBytes_()); } return this.hashCode_; } /** * Returns true if the bytestring is empty. * @return {boolean} */ isEmpty() { if (this.bytes_ != null && this.bytes_.byteLength == 0) { return true; } if (this.base64_ != null && this.base64_.length == 0) { return true; } return false; } /** * @return {!Uint8Array} * @private */ ensureBytes_() { if (this.bytes_) { return this.bytes_; } return this.bytes_ = base64.decodeStringToUint8Array( /** @type {string} */ (this.base64_)); } /** * @return {string} * @private */ ensureBase64String_() { if (this.base64_ == null) { this.base64_ = base64.encodeByteArray(this.bytes_); } return this.base64_; } } /** @const {!ByteString} */ ByteString.EMPTY = new ByteString(new Uint8Array(0), null); exports = ByteString;