Duffer Derek
import window from 'global/window';
// const log2 = Math.log2 ? Math.log2 : (x) => (Math.log(x) / Math.log(2));
const repeat = function(str, len) {
let acc = '';
while (len--) {
acc += str;
}
return acc;
};
// count the number of bits it would take to represent a number
// we used to do this with log2 but BigInt does not support builtin math
// Math.ceil(log2(x));
export const countBits = (x) => x.toString(2).length;
// count the number of whole bytes it would take to represent a number
export const countBytes = (x) => Math.ceil(countBits(x) / 8);
export const padStart = (b, len, str = ' ') => (repeat(str, len) + b.toString()).slice(-len);
export const isArrayBufferView = (obj) => {
if (ArrayBuffer.isView === 'function') {
return ArrayBuffer.isView(obj);
}
return obj && obj.buffer instanceof ArrayBuffer;
};
export const isTypedArray = (obj) => isArrayBufferView(obj);
export const toUint8 = function(bytes) {
if (bytes instanceof Uint8Array) {
return bytes;
}
if (!Array.isArray(bytes) && !isTypedArray(bytes) && !(bytes instanceof ArrayBuffer)) {
// any non-number or NaN leads to empty uint8array
// eslint-disable-next-line
if (typeof bytes !== 'number' || (typeof bytes === 'number' && bytes !== bytes)) {
bytes = 0;
} else {
bytes = [bytes];
}
}
return new Uint8Array(
bytes && bytes.buffer || bytes,
bytes && bytes.byteOffset || 0,
bytes && bytes.byteLength || 0
);
};
export const toHexString = function(bytes) {
bytes = toUint8(bytes);
let str = '';
for (let i = 0; i < bytes.length; i++) {
str += padStart(bytes[i].toString(16), 2, '0');
}
return str;
};
export const toBinaryString = function(bytes) {
bytes = toUint8(bytes);
let str = '';
for (let i = 0; i < bytes.length; i++) {
str += padStart(bytes[i].toString(2), 8, '0');
}
return str;
};
const BigInt = window.BigInt || Number;
const BYTE_TABLE = [
BigInt('0x1'),
BigInt('0x100'),
BigInt('0x10000'),
BigInt('0x1000000'),
BigInt('0x100000000'),
BigInt('0x10000000000'),
BigInt('0x1000000000000'),
BigInt('0x100000000000000'),
BigInt('0x10000000000000000')
];
export const ENDIANNESS = (function() {
const a = new Uint16Array([0xFFCC]);
const b = new Uint8Array(a.buffer, a.byteOffset, a.byteLength);
if (b[0] === 0xFF) {
return 'big';
}
if (b[0] === 0xCC) {
return 'little';
}
return 'unknown';
})();
export const IS_BIG_ENDIAN = ENDIANNESS === 'big';
export const IS_LITTLE_ENDIAN = ENDIANNESS === 'little';
export const bytesToNumber = function(bytes, {signed = false, le = false} = {}) {
bytes = toUint8(bytes);
const fn = le ? 'reduce' : 'reduceRight';
const obj = bytes[fn] ? bytes[fn] : Array.prototype[fn];
let number = obj.call(bytes, function(total, byte, i) {
const exponent = le ? i : Math.abs(i + 1 - bytes.length);
return total + (BigInt(byte) * BYTE_TABLE[exponent]);
}, BigInt(0));
if (signed) {
const max = BYTE_TABLE[bytes.length] / BigInt(2) - BigInt(1);
number = BigInt(number);
if (number > max) {
number -= max;
number -= max;
number -= BigInt(2);
}
}
return Number(number);
};
export const numberToBytes = function(number, {le = false} = {}) {
// eslint-disable-next-line
if ((typeof number !== 'bigint' && typeof number !== 'number') || (typeof number === 'number' && number !== number)) {
number = 0;
}
number = BigInt(number);
const byteCount = countBytes(number);
const bytes = new Uint8Array(new ArrayBuffer(byteCount));
for (let i = 0; i < byteCount; i++) {
const byteIndex = le ? i : Math.abs(i + 1 - bytes.length);
bytes[byteIndex] = Number((number / BYTE_TABLE[i]) & BigInt(0xFF));
if (number < 0) {
bytes[byteIndex] = Math.abs(~bytes[byteIndex]);
bytes[byteIndex] -= i === 0 ? 1 : 2;
}
}
return bytes;
};
export const bytesToString = (bytes) => {
if (!bytes) {
return '';
}
// TODO: should toUint8 handle cases where we only have 8 bytes
// but report more since this is a Uint16+ Array?
bytes = Array.prototype.slice.call(bytes);
const string = String.fromCharCode.apply(null, toUint8(bytes));
try {
return decodeURIComponent(escape(string));
} catch (e) {
// if decodeURIComponent/escape fails, we are dealing with partial
// or full non string data. Just return the potentially garbled string.
}
return string;
};
export const stringToBytes = (string, stringIsBytes) => {
if (typeof string !== 'string' && string && typeof string.toString === 'function') {
string = string.toString();
}
if (typeof string !== 'string') {
return new Uint8Array();
}
// If the string already is bytes, we don't have to do this
// otherwise we do this so that we split multi length characters
// into individual bytes
if (!stringIsBytes) {
string = unescape(encodeURIComponent(string));
}
const view = new Uint8Array(string.length);
for (let i = 0; i < string.length; i++) {
view[i] = string.charCodeAt(i);
}
return view;
};
export const concatTypedArrays = (...buffers) => {
buffers = buffers.filter((b) => b && (b.byteLength || b.length) && typeof b !== 'string');
if (buffers.length <= 1) {
// for 0 length we will return empty uint8
// for 1 length we return the first uint8
return toUint8(buffers[0]);
}
const totalLen = buffers.reduce((total, buf, i) => total + (buf.byteLength || buf.length), 0);
const tempBuffer = new Uint8Array(totalLen);
let offset = 0;
buffers.forEach(function(buf) {
buf = toUint8(buf);
tempBuffer.set(buf, offset);
offset += buf.byteLength;
});
return tempBuffer;
};
/**
* Check if the bytes "b" are contained within bytes "a".
*
* @param {Uint8Array|Array} a
* Bytes to check in
*
* @param {Uint8Array|Array} b
* Bytes to check for
*
* @param {Object} options
* options
*
* @param {Array|Uint8Array} [offset=0]
* offset to use when looking at bytes in a
*
* @param {Array|Uint8Array} [mask=[]]
* mask to use on bytes before comparison.
*
* @return {boolean}
* If all bytes in b are inside of a, taking into account
* bit masks.
*/
export const bytesMatch = (a, b, {offset = 0, mask = []} = {}) => {
a = toUint8(a);
b = toUint8(b);
// ie 11 does not support uint8 every
const fn = b.every ? b.every : Array.prototype.every;
return b.length &&
a.length - offset >= b.length &&
// ie 11 doesn't support every on uin8
fn.call(b, (bByte, i) => {
const aByte = (mask[i] ? (mask[i] & a[offset + i]) : a[offset + i]);
return bByte === aByte;
});
};
export const sliceBytes = function(src, start, end) {
if (Uint8Array.prototype.slice) {
return Uint8Array.prototype.slice.call(src, start, end);
}
return new Uint8Array(Array.prototype.slice.call(src, start, end));
};
export const reverseBytes = function(src) {
if (src.reverse) {
return src.reverse();
}
return Array.prototype.reverse.call(src);
};
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists