blob: d6af5f148ed0d339e24ea5b124263949283f9faa [file] [log] [blame]
/**
* @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;