/*
* @copyright 2022 Tridium, Inc. All Rights Reserved.
* @author Sai Komaravolu
*/
/*eslint-env browser */
/**
* Defines {@link baja.Blob}
* @module baja/obj/Blob
*/
define([
'bajaScript/sys',
'bajaScript/baja/obj/Simple',
'bajaScript/baja/obj/byteUtil',
'lex!' ], function (
baja,
Simple,
byteUtil,
lexjs) {
'use strict';
/**
* A `baja:Blob` of Bajascript is a wrapper class for raw byte array objects.
*
* @since Niagara 4.14
* @class
* @alias baja.Blob
* @extends baja.Simple
*/
class Blob extends Simple {
/**
* When creating a `Blob` use make() instead of new Object.
* Constructor should be considered private.
*
* @param {Uint8Array} byteArr array of bytes
*/
constructor(byteArr = new Uint8Array()) {
super();
if (!(byteArr && byteArr instanceof Uint8Array)) {
throw new Error(lexjs.$getSync({ module: 'baja', key: 'blob.arrayInput.message', def: 'array input is required.' }));
}
this.$byteArr = byteArr;
}
/**
* Returns the Blob as an encoded string.
*
* @returns {String} encoded string
*/
encodeToString() {
return byteUtil.byteArrayToBase64String(this.$byteArr);
}
/**
* Converts the input string to a Blob.
*
* @param {string} base64String
* @returns {baja.Blob}
*/
decodeFromString(base64String = '') {
if (base64String.length === 0) {
return Blob.DEFAULT;
}
return Blob.make(byteUtil.base64StringToByteArray(base64String));
}
/**
* Makes a `Blob`.
*
* @param {Uint8Array} byteArr array of bytes
* @returns {baja.Blob}
* @example
*
* // blob can be created with a byte array.
* let blob = baja.Blob.make(new Uint8Array([ 1, 2, 3, 4, 5, 6 ]));
*
* // DEFAULT blob can be created with no parameters.
* let blob = baja.Blob.make();
*
* // blob can be created as a DEFAULT.
* let blob = baja.Blob.DEFAULT;
*/
make(byteArr = new Uint8Array()) {
return Blob.make(byteArr);
}
/**
* @returns {Number} Byte length of the Blob
*/
length() {
return this.$byteArr.length;
}
/**
* @param {Number} index position of the bytes in the Blob
* @returns {Number|undefined} Number if a byte is available at given index else undefined.
*/
byteAt(index) {
return this.$byteArr.at(index);
}
/**
* @returns {Uint8Array} array of the Blob bytes
*/
getBytes() {
//Return a copy of the byte array to avoid instance modification.
return this.$byteArr.slice();
}
/**
* Returns the blob's byte array with the index position as the pivot.
* In case of an empty array, bytes are copied into it and index position is not considered.
*
* @param {Array} arrayToCopy
* @param index
* @returns {Uint8Array}
*/
copyBytes(arrayToCopy, index) {
arrayToCopy.splice(index, 0, ...Array.from(this.$byteArr));
return new Uint8Array(arrayToCopy);
}
/**
* Checks for equality of bytes in the Blob and input.
*
* @param {Array} byteArr
* @returns {boolean}
*/
bytesEqual(byteArr) {
if (byteArr.length !== this.$byteArr.length) {
return false;
}
for (let i = 0; i < this.$byteArr.length - 1; i++) {
if (byteArr[i] !== this.$byteArr[i]) {
return false;
}
}
return true;
}
/**
* @param {Uint8Array} byteArr
* @returns {baja.Blob}
*/
static make(byteArr = new Uint8Array()) {
return new Blob(byteArr);
}
/**
* Makes a Blob from an input hex string.
*
* @param {String} hexString
* @returns {baja.Blob}
* @example
*
* let blob = baja.Blob.make('00123a');
*/
static makeBlobFromHexString(hexString) {
// If user enters an empty string, return a default Blob without invoking the Blob.DEFAULT.decodeFromString()
if (hexString.trim().length === 0) {
return Blob.DEFAULT;
}
// Check if input string is a Hex and return Blob from decoded Hex String.
if (isHex(hexString)) {
let base64String = hexStringToBase64String(hexString);
return Blob.DEFAULT.decodeFromString(base64String);
}
// Throw an error if input is not a Hex String.
throw new Error(lexjs.$getSync({ module: 'baja', key: 'blob.notAHexString.message', def: '{0} is not a hexadecimal.', args: [ hexString ] }));
}
/**
* @returns {baja.Blob}
*/
static get DEFAULT() {
return DEFAULT;
}
}
/**
* Converts Hex string to a Base64 array.
*
* @private
* @param {String} hexString
* @returns {String}
*/
const hexStringToBase64String = (hexString) => {
// hex string cannot have odd length, prepending a '0' if it's odd.
hexString = (hexString.length % 2 === 0 ? hexString : '0' + hexString);
return btoa(String.fromCharCode.apply(null,
hexString.replace(/([A-Fa-f\d]{2})/g, "0x$1;") // 00123a => [ 0x00;0x12;0x3a]
.replace(/;$/, "").split(";")) // removes end ; and splits them
);
};
/**
* Validates if input string is Hexadecimal.
*
* @private
* @param {String} str
* @returns {boolean}
*/
const isHex = (str) => {
return !str.match(/[^A-Fa-f\d]/);
};
const DEFAULT = Blob.make();
return Blob;
});