Skip to content

Instantly share code, notes, and snippets.

@vipertechofficial
Last active January 3, 2023 22:30
Show Gist options
  • Save vipertechofficial/2dde2e4b7574580deccdbc94d513728f to your computer and use it in GitHub Desktop.
Save vipertechofficial/2dde2e4b7574580deccdbc94d513728f to your computer and use it in GitHub Desktop.
AWESOME - Get your base64 a bit of futurism --> BASE 92 !!!
/*
* The MIT License (MIT)
*
* Copyright (c) 2023 Affolter Matias
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
var Elemental92 = function(data){
if (!(this instanceof Elemental92)) {
return new Elemental92(data);
}
if(data instanceof Uint8Array || data instanceof Uint8ClampedArray) {
this.storage_input_ = data;
}else if(typeof data == "string") {
this.storage_input_ = Elemental92.UTF8.toByteArray(data);
}else if("buffer" in data || data instanceof ArrayBuffer) {
this.storage_input_ = new Uint8Array(data instanceof ArrayBuffer ? data : data.buffer);
}else if(data instanceof Object){
this.storage_input_ = Cbor(data).run();
}
this.storage_input_length_ = ( this.storage_input_.length | 0 ) >>> 0;
this.TILD_CHAR_CODE_ = Elemental92.config.TILD_CHAR_CODE;
this.BACKSLASH_CHAR_ = Elemental92.config.BACKSLASH_CHAR;
this.SLASH_CHAR_ = Elemental92.config.SLASH_CHAR;
this.CHUNCK_LENGTH_ = Elemental92.config.CHUNCK_LENGTH;
this.ENCODE_MAPPING_ = Elemental92.config.ENCODE_MAPPING;
this.DECODE_MAPPING_ = Elemental92.config.DECODE_MAPPING;
return this;
};
// https://github.com/Benzinga/lz4js
var xxhash = {
prime1: 0x9e3779b1,
prime2: 0x85ebca77,
prime3: 0xc2b2ae3d,
prime4: 0x27d4eb2f,
prime5: 0x165667b1,
util: {
hashU32(a) {
a = a | 0;
a = a + 2127912214 + (a << 12) | 0;
a = a ^ -949894596 ^ a >>> 19;
a = a + 374761393 + (a << 5) | 0;
a = a + -744332180 ^ a << 9;
a = a + -42973499 + (a << 3) | 0;
return a ^ -1252372727 ^ a >>> 16 | 0;
},
readU64(b, n) {
var x = 0;
x |= b[n++] << 0;
x |= b[n++] << 8;
x |= b[n++] << 16;
x |= b[n++] << 24;
x |= b[n++] << 32;
x |= b[n++] << 40;
x |= b[n++] << 48;
x |= b[n++] << 56;
return x;
},
readU32(b, n) {
var x = 0;
x |= b[n++] << 0;
x |= b[n++] << 8;
x |= b[n++] << 16;
x |= b[n++] << 24;
return x;
},
writeU32(b, n, x) {
b[n++] = (x >> 0) & 0xff;
b[n++] = (x >> 8) & 0xff;
b[n++] = (x >> 16) & 0xff;
b[n++] = (x >> 24) & 0xff;
},
imul(a, b) {
var ah = a >>> 16;
var al = a & 65535;
var bh = b >>> 16;
var bl = b & 65535;
return al * bl + (ah * bl + al * bh << 16) | 0;
}
},
rotl32 (x, r) {
x = x | 0;
r = r | 0;
return x >>> (32 - r | 0) | x << r | 0;
},
rotmul32 (h, r, m) {
h = h | 0;
r = r | 0;
m = m | 0;
return this.util.imul((h >>> (32 - r | 0) | h << r), m) | 0;
},
shiftxor32 (h, s) {
h = h | 0;
s = s | 0;
return h >>> s ^ h | 0;
},
xxhapply (h, src, m0, s, m1) {
return this.rotmul32(this.util.imul(src, m0) + h, s, m1);
},
xxh1 (h, src, index) {
return this.rotmul32((h + this.util.imul(src[index], this.prime5)), 11, this.prime1);
},
xxh4 (h, src, index) {
return this.xxhapply(h, this.util.readU32(src, index), this.prime3, 17, this.prime4);
},
xxh16 (h, src, index) {
return [
this.xxhapply(h[0], this.util.readU32(src, index + 0), this.prime2, 13, this.prime1),
this.xxhapply(h[1], this.util.readU32(src, index + 4), this.prime2, 13, this.prime1),
this.xxhapply(h[2], this.util.readU32(src, index + 8), this.prime2, 13, this.prime1),
this.xxhapply(h[3], this.util.readU32(src, index + 12), this.prime2, 13, this.prime1)
];
},
xxh32 (seed, src, index, len) {
var h, l;
l = len;
if (len >= 16) {
h = [
seed + this.prime1 + this.prime2,
seed + this.prime2,
seed,
seed - this.prime1
];
while (len >= 16) {
h = this.xxh16(h, src, index);
index += 16;
len -= 16;
}
h = this.rotl32(h[0], 1) + this.rotl32(h[1], 7) + this.rotl32(h[2], 12) + this.rotl32(h[3], 18) + l;
} else {
h = (seed + this.prime5 + len) >>> 0;
}
while (len >= 4) {
h = this.xxh4(h, src, index);
index += 4;
len -= 4;
}
while (len > 0) {
h = this.xxh1(h, src, index);
index++;
len--;
}
h = this.shiftxor32(this.util.imul(this.shiftxor32(this.util.imul(this.shiftxor32(h, 15), this.prime2), 13), this.prime3), 16);
return h >>> 0;
}
};
// https://github.com/Benzinga/lz4js
var lz4 = {
xxhash: xxhash,
util: xxhash.util,
// Utility functions/primitives
minMatch: 4,
minLength: 13,
searchLimit: 5,
skipTrigger: 6,
hashSize: 1 << 16,
// Token constants.
mlBits: 4,
mlMask: (1 << this.mlBits) - 1,
runBits: 4,
runMask: (1 << this.runBits) - 1,
makeBuffer(size) { // Makes a byte buffer. On older browsers, may return a plain array.
try {
return new Uint8Array(size);
} catch (error) {
var buf = new Array(size);
for (var i = 0; i < size; i++) {
buf[i] = 0;
}
return buf;
}
},
makeHashTable() { // Makes our hashtable. On older browsers, may return a plain array.
try {
return new Uint32Array(this.hashSize);
} catch (error) {
var hashTable = new Array(this.hashSize);
for (var i = 0; i < this.hashSize; i++) {
hashTable[i] = 0;
}
return hashTable;
}
},
// Shared buffers
blockBuf: this.makeBuffer(5 << 20),
hashTable: this.makeHashTable(),
// Frame constants.
magicNum: 0x184D2204,
// Frame descriptor flags.
fdContentChksum: 0x4,
fdContentSize: 0x8,
fdBlockChksum: 0x10,
// fdBlockIndep: 0x20,
fdVersion: 0x40,
fdVersionMask: 0xC0,
// Block sizes.
bsUncompressed: 0x80000000,
bsDefault: 7,
bsShift: 4,
bsMask: 7,
bsMap: {
4: 0x10000,
5: 0x40000,
6: 0x100000,
7: 0x400000
},
clearHashTable(table) { // Clear hashtable.
for (var i = 0; i < this.hashSize; i++) {
this.hashTable[i] = 0;
}
},
sliceArray(array, start, end) {
if (typeof array.buffer !== undefined) {
if (Uint8Array.prototype.slice) {
return array.slice(start, end);
} else {
// Uint8Array#slice polyfill.
var len = array.length;
// Calculate start.
start = start | 0;
start = (start < 0) ? Math.max(len + start, 0) : Math.min(start, len);
// Calculate end.
end = (end === undefined) ? len : end | 0;
end = (end < 0) ? Math.max(len + end, 0) : Math.min(end, len);
// Copy into new array.
var arraySlice = new Uint8Array(end - start);
for (var i = start, n = 0; i < end;) {
arraySlice[n++] = array[i++];
}
return arraySlice;
}
} else {
// Assume normal array.
return array.slice(start, end);
}
},
// Implementation
compressBound (n) {
return (n + (n / 255) + 16) | 0;
},
decompressBound (src) {
var sIndex = 0;
// Read magic number
if (this.util.readU32(src, sIndex) !== this.magicNum) {
throw new Error('invalid magic number');
}
sIndex += 4;
// Read descriptor
var descriptor = src[sIndex++];
// Check version
if ((descriptor & this.fdVersionMask) !== this.fdVersion) {
throw new Error('incompatible descriptor version ' + (descriptor & this.fdVersionMask));
}
// Read flags
var useBlockSum = (descriptor & this.fdBlockChksum) !== 0;
var useContentSize = (descriptor & this.fdContentSize) !== 0;
// Read block size
var bsIdx = (src[sIndex++] >> this.bsShift) & this.bsMask;
if (bsMap[bsIdx] === undefined) {
throw new Error('invalid block size ' + bsIdx);
}
var maxBlockSize = this.bsMap[bsIdx];
// Get content size
if (useContentSize) {
return this.util.readU64(src, sIndex);
}
// Checksum
sIndex++;
// Read blocks.
var maxSize = 0;
while (true) {
var blockSize = this.util.readU32(src, sIndex);
sIndex += 4;
if (blockSize & this.bsUncompressed) {
blockSize &= ~this.bsUncompressed;
maxSize += blockSize;
} else if (blockSize > 0) {
maxSize += maxBlockSize;
}
if (blockSize === 0) {
return maxSize;
}
if (useBlockSum) {
sIndex += 4;
}
sIndex += blockSize;
}
},
// Decompresses a block of Lz4.
decompressBlock (src, dst, sIndex, sLength, dIndex) {
var mLength, mOffset, sEnd, n, i;
var hasCopyWithin = dst.copyWithin !== undefined && dst.fill !== undefined;
// Setup initial state.
sEnd = sIndex + sLength;
// Consume entire input block.
while (sIndex < sEnd) {
var token = src[sIndex++];
// Copy literals.
var literalCount = (token >> 4);
if (literalCount > 0) {
// Parse length.
if (literalCount === 0xf) {
while (true) {
literalCount += src[sIndex];
if (src[sIndex++] !== 0xff) {
break;
}
}
}
// Copy literals
for (n = sIndex + literalCount; sIndex < n;) {
dst[dIndex++] = src[sIndex++];
}
}
if (sIndex >= sEnd) {
break;
}
// Copy match.
mLength = (token & 0xf);
// Parse offset.
mOffset = src[sIndex++] | (src[sIndex++] << 8);
// Parse length.
if (mLength === 0xf) {
while (true) {
mLength += src[sIndex];
if (src[sIndex++] !== 0xff) {
break;
}
}
}
mLength += this.minMatch;
// Copy match
// prefer to use typedarray.copyWithin for larger matches
// NOTE: copyWithin doesn't work as required by LZ4 for overlapping sequences
// e.g. mOffset=1, mLength=30 (repeach char 30 times)
// we special case the repeat char w/ array.fill
if (hasCopyWithin && mOffset === 1) {
dst.fill(dst[dIndex - 1] | 0, dIndex, dIndex + mLength);
dIndex += mLength;
} else if (hasCopyWithin && mOffset > mLength && mLength > 31) {
dst.copyWithin(dIndex, dIndex - mOffset, dIndex - mOffset + mLength);
dIndex += mLength;
} else {
for (i = dIndex - mOffset, n = i + mLength; i < n;) {
dst[dIndex++] = dst[i++] | 0;
}
}
}
return dIndex;
},
// Compresses a block with Lz4.
compressBlock (src, dst, sIndex, sLength, hashTable) {
var mIndex, mAnchor, mLength, mOffset, mStep;
var literalCount, dIndex, sEnd, n;
// Setup initial state.
dIndex = 0;
sEnd = sLength + sIndex;
mAnchor = sIndex;
// Process only if block is large enough.
if (sLength >= this.minLength) {
var searchMatchCount = (1 << this.skipTrigger) + 3;
// Consume until last n literals (Lz4 spec limitation.)
while (sIndex + this.minMatch < sEnd - this.searchLimit) {
var seq = this.util.readU32(src, sIndex);
var hash = this.util.hashU32(seq) >>> 0;
// Crush hash to 16 bits.
hash = ((hash >> 16) ^ hash) >>> 0 & 0xffff;
// Look for a match in the hashtable. NOTE: remove one; see below.
mIndex = hashTable[hash] - 1;
// Put pos in hash table. NOTE: add one so that zero = invalid.
hashTable[hash] = sIndex + 1;
// Determine if there is a match (within range.)
if (mIndex < 0 || ((sIndex - mIndex) >>> 16) > 0 || this.util.readU32(src, mIndex) !== seq) {
mStep = searchMatchCount++ >> this.skipTrigger;
sIndex += mStep;
continue;
}
searchMatchCount = (1 << this.skipTrigger) + 3;
// Calculate literal count and offset.
literalCount = sIndex - mAnchor;
mOffset = sIndex - mIndex;
// We've already matched one word, so get that out of the way.
sIndex += this.minMatch;
mIndex += this.minMatch;
// Determine match length.
// N.B.: mLength does not include minMatch, Lz4 adds it back
// in decoding.
mLength = sIndex;
while (sIndex < sEnd - this.searchLimit && src[sIndex] === src[mIndex]) {
sIndex++;
mIndex++;
}
mLength = sIndex - mLength;
// Write token + literal count.
var token = mLength < this.mlMask ? mLength : this.mlMask;
if (literalCount >= this.runMask) {
dst[dIndex++] = (this.runMask << this.mlBits) + token;
for (n = literalCount - this.runMask; n >= 0xff; n -= 0xff) {
dst[dIndex++] = 0xff;
}
dst[dIndex++] = n;
} else {
dst[dIndex++] = (literalCount << this.mlBits) + token;
}
// Write literals.
for (var i = 0; i < literalCount; i++) {
dst[dIndex++] = src[mAnchor + i];
}
// Write offset.
dst[dIndex++] = mOffset;
dst[dIndex++] = (mOffset >> 8);
// Write match length.
if (mLength >= this.mlMask) {
for (n = mLength - this.mlMask; n >= 0xff; n -= 0xff) {
dst[dIndex++] = 0xff;
}
dst[dIndex++] = n;
}
// Move the anchor.
mAnchor = sIndex;
}
}
// Nothing was encoded.
if (mAnchor === 0) {
return 0;
}
// Write remaining literals.
// Write literal token+count.
literalCount = sEnd - mAnchor;
if (literalCount >= this.runMask) {
dst[dIndex++] = (this.runMask << this.mlBits);
for (n = literalCount - this.runMask; n >= 0xff; n -= 0xff) {
dst[dIndex++] = 0xff;
}
dst[dIndex++] = n;
} else {
dst[dIndex++] = (literalCount << this.mlBits);
}
// Write literals.
sIndex = mAnchor;
while (sIndex < sEnd) {
dst[dIndex++] = src[sIndex++];
}
return dIndex;
},
// Decompresses a frame of Lz4 data.
decompressFrame (src, dst) {
var useBlockSum, useContentSum, useContentSize, descriptor;
var sIndex = 0;
var dIndex = 0;
// Read magic number
if (this.util.readU32(src, sIndex) !== this.magicNum) {
throw new Error('invalid magic number');
}
sIndex += 4;
// Read descriptor
descriptor = src[sIndex++];
// Check version
if ((descriptor & this.fdVersionMask) !== this.fdVersion) {
throw new Error('incompatible descriptor version');
}
// Read flags
useBlockSum = (descriptor & this.fdBlockChksum) !== 0;
useContentSum = (descriptor & this.fdContentChksum) !== 0;
useContentSize = (descriptor & this.fdContentSize) !== 0;
// Read block size
var bsIdx = (src[sIndex++] >> this.bsShift) & this.bsMask;
if (this.bsMap[bsIdx] === undefined) {
throw new Error('invalid block size');
}
if (useContentSize) {
// TODO: read content size
sIndex += 8;
}
sIndex++;
// Read blocks.
while (true) {
var compSize;
compSize = this.util.readU32(src, sIndex);
sIndex += 4;
if (compSize === 0) {
break;
}
if (useBlockSum) {
// TODO: read block checksum
sIndex += 4;
}
// Check if block is compressed
if ((compSize & this.bsUncompressed) !== 0) {
// Mask off the 'uncompressed' bit
compSize &= ~this.bsUncompressed;
// Copy uncompressed data into destination buffer.
for (var j = 0; j < compSize; j++) {
dst[dIndex++] = src[sIndex++];
}
} else {
// Decompress into blockBuf
dIndex = this.decompressBlock(src, dst, sIndex, compSize, dIndex);
sIndex += compSize;
}
}
if (useContentSum) {
// TODO: read content checksum
sIndex += 4;
}
return dIndex;
},
compressFrame (src, dst) { // Compresses data to an Lz4 frame.
var dIndex = 0;
// Write magic number.
this.util.writeU32(dst, dIndex, this.magicNum);
dIndex += 4;
// Descriptor flags.
dst[dIndex++] = this.fdVersion;
dst[dIndex++] = this.bsDefault << this.bsShift;
// Descriptor checksum.
dst[dIndex] = this.xxhash.hash(0, dst, 4, dIndex - 4) >> 8;
dIndex++;
// Write blocks.
var maxBlockSize = this.bsMap[this.bsDefault];
var remaining = src.length;
var sIndex = 0;
// Clear the hashtable.
this.clearHashTable(this.hashTable);
// Split input into blocks and write.
while (remaining > 0) {
var compSize = 0;
var blockSize = remaining > maxBlockSize ? maxBlockSize : remaining;
compSize = this.compressBlock(src, this.blockBuf, sIndex, blockSize, this.hashTable);
if (compSize > blockSize || compSize === 0) {
// Output uncompressed.
this.util.writeU32(dst, dIndex, 0x80000000 | blockSize);
dIndex += 4;
for (var z = sIndex + blockSize; sIndex < z;) {
dst[dIndex++] = src[sIndex++];
}
remaining -= blockSize;
} else {
// Output compressed.
this.util.writeU32(dst, dIndex, compSize);
dIndex += 4;
for (var j = 0; j < compSize;) {
dst[dIndex++] = this.blockBuf[j++];
}
sIndex += blockSize;
remaining -= blockSize;
}
}
// Write blank end block.
this.util.writeU32(dst, dIndex, 0);
dIndex += 4;
return dIndex;
},
// Decompresses a buffer containing an Lz4 frame. maxSize is optional; if not
// provided, a maximum size will be determined by examining the data. The
// buffer returned will always be perfectly-sized.
decompress (src, maxSize) {
var dst, size;
if (maxSize === undefined) {
maxSize = this.decompressBound(src);
}
dst = this.makeBuffer(maxSize);
size = this.decompressFrame(src, dst);
if (size !== maxSize) {
dst = this.sliceArray(dst, 0, size);
}
return dst;
},
// Compresses a buffer to an Lz4 frame. maxSize is optional; if not provided,
// a buffer will be created based on the theoretical worst output size for a
// given input size. The buffer returned will always be perfectly-sized.
compress (src, maxSize) {
var dst, size;
if (maxSize === undefined) {
maxSize = this.compressBound(src.length);
}
dst = this.makeBuffer(maxSize);
size = this.compressFrame(src, dst);
if (size !== maxSize) {
dst = this.sliceArray(dst, 0, size);
}
return dst;
}
};
Elemental92.LZ4 = lz4;
Elemental92.XXHASH = xxhash;
/*
* The MIT License (MIT)
*
* Copyright (c) 2014-2016 Patrick Gansterer <paroga@paroga.com>
* Copyright (c) 2023 Affolter Matias
*
*/
var Cbor = function(data){
if (!(this instanceof Cbor)) {
return new Cbor(data);
}
if(data instanceof ArrayBuffer) {
this.storage_ = data;
this.from_buffer_ = true;
}else if("buffer" in data) {
this.storage_ = data.buffer;
this.from_buffer_ = true;
}else {
this.storage_ = data;
this.from_buffer_ = false;
}
this.data_ = new ArrayBuffer(this._DATA_CHUNCK_SIZE);
this.dataView_ = new DataView(this.data);
this.lastLength_ = 0;
this.offset_ = 0;
return this;
};
Cbor.prototype._POW_2_24 = 5.960464477539063e-8;
Cbor.prototype._POW_2_32 = 4294967296;
Cbor.prototype._POW_2_53 = 9007199254740992;
Cbor.prototype._DATA_CHUNCK_SIZE = 256;
Object.defineProperty(Cbor.prototype, 'storage', {
get: function() { return this.storage_; }
});
Object.defineProperty(Cbor.prototype, 'isFromBuffer', {
get: function() { return this.from_buffer_; }
});
Object.defineProperty(Cbor.prototype, 'isFromObject', {
get: function() { return !this.from_buffer_; }
});
Object.defineProperty(Cbor.prototype, 'data', {
get: function() { return this.data_; }
});
Object.defineProperty(Cbor.prototype, 'dataView', {
get: function() { return this.dataView_; }
});
Object.defineProperty(Cbor.prototype, 'lastLength', {
get: function() { return this.lastLength_; }
});
Object.defineProperty(Cbor.prototype, 'offset', {
get: function() { return this.offset_; }
});
Cbor.prototype.prepareWrite = function (length) {
var newByteLength = this.data.byteLength;
var requiredLength = this.offset + length;
while (newByteLength < requiredLength){
newByteLength <<= 1;
}
if (newByteLength !== this.data.byteLength) {
var oldDataView = this.dataView;
this.data = new ArrayBuffer(newByteLength);
this.dataView = new DataView(this.data);
var uint32count = (this.offset + 3) >> 2;
for (var i = 0; i < uint32count; ++i)
this.dataView.setUint32(i << 2, oldDataView.getUint32(i << 2));
}
this.lastLength = length;
return this.dataView;
}
Cbor.prototype.commitWrite = function () {
this.offset += this.lastLength;
};
Cbor.prototype.writeFloat64 = function (value) {
this.commitWrite(this.prepareWrite(8).setFloat64(this.offset, value));
};
Cbor.prototype.writeUint8 = function (value) {
this.commitWrite(this.prepareWrite(1).setUint8(this.offset, value));
};
Cbor.prototype.writeUint8Array = function (value) {
this.prepareWrite(value.length);
for (var i = 0; i < value.length; ++i)
this.dataView.setUint8(this.offset + i, value[i]);
this.commitWrite();
};
Cbor.prototype.writeUint16 = function (value) {
this.commitWrite(this.prepareWrite(2).setUint16(this.offset, value));
};
Cbor.prototype.writeUint32 = function (value) {
this.commitWrite(this.prepareWrite(4).setUint32(this.offset, value));
};
Cbor.prototype.writeUint64 = function (value) {
var low = value % this._POW_2_32;
var high = (value - low) / this._POW_2_32;
var dataView = this.prepareWrite(8);
dataView.setUint32(this.offset, high);
dataView.setUint32(this.offset + 4, low);
this.commitWrite();
};
Cbor.prototype.writeTypeAndLength = function (type, length) {
if (length < 24) {
this.writeUint8(type << 5 | length);
} else if (length < 0x100) {
this.writeUint8(type << 5 | 24);
this.writeUint8(length);
} else if (length < 0x10000) {
this.writeUint8(type << 5 | 25);
this.writeUint16(length);
} else if (length < 0x100000000) {
this.writeUint8(type << 5 | 26);
this.writeUint32(length);
} else {
this.writeUint8(type << 5 | 27);
this.writeUint64(length);
}
};
Cbor.prototype.encodeItem = function (value) {
var i = 0;
if (value === false)
return this.writeUint8(0xf4);
if (value === true)
return this.writeUint8(0xf5);
if (value === null)
return this.writeUint8(0xf6);
if (value === undefined)
return this.writeUint8(0xf7);
switch (typeof value) {
case "number":
if (Math.floor(value) === value) {
if (0 <= value && value <= this._POW_2_53)
return this.writeTypeAndLength(0, value);
if (-this._POW_2_53 <= value && value < 0)
return this.writeTypeAndLength(1, -(value + 1));
}
this.writeUint8(0xfb);
return this.writeFloat64(value);
case "string":
var utf8data = [];
for (i = 0; i < value.length; ++i) {
var charCode = value.charCodeAt(i);
if (charCode < 0x80) {
utf8data.push(charCode);
} else if (charCode < 0x800) {
utf8data.push(0xc0 | charCode >> 6);
utf8data.push(0x80 | charCode & 0x3f);
} else if (charCode < 0xd800) {
utf8data.push(0xe0 | charCode >> 12);
utf8data.push(0x80 | (charCode >> 6) & 0x3f);
utf8data.push(0x80 | charCode & 0x3f);
} else {
charCode = (charCode & 0x3ff) << 10;
charCode |= value.charCodeAt(++i) & 0x3ff;
charCode += 0x10000;
utf8data.push(0xf0 | charCode >> 18);
utf8data.push(0x80 | (charCode >> 12) & 0x3f);
utf8data.push(0x80 | (charCode >> 6) & 0x3f);
utf8data.push(0x80 | charCode & 0x3f);
}
}
this.writeTypeAndLength(3, utf8data.length);
return this.writeUint8Array(utf8data);
default:
var length;
if (Array.isArray(value)) {
length = value.length;
this.writeTypeAndLength(4, length);
for (i = 0; i < length; ++i)
this.encodeItem(value[i]);
} else if (value instanceof Uint8Array) {
this.writeTypeAndLength(2, value.length);
this.writeUint8Array(value);
} else {
var keys = Object.keys(value);
length = keys.length;
this.writeTypeAndLength(5, length);
for (i = 0; i < length; ++i) {
var key = keys[i];
this.encodeItem(key);
this.encodeItem(value[key]);
}
}
}
};
Cbor.prototype.encode = function () {
if(this.isFromBuffer) {
return this.storage;
}else {
this.encodeItem(this.storage);
if ("slice" in this.data){
return this.data.slice(0, this.offset);
}
var ret = new ArrayBuffer(this.offset);
var retView = new DataView(ret);
for (var i = 0; i < this.offset; ++i){
retView.setUint8(i, this.dataView.getUint8(i));
}
return ret;
}
};
Cbor.prototype.commitRead = function (length, value) {
this.offset += length;
return value;
};
Cbor.prototype.readArrayBuffer = function (length) {
return this.commitRead(length, new Uint8Array(this.data, this.offset, length));
};
Cbor.prototype.readFloat16 = function () {
var tempArrayBuffer = new ArrayBuffer(4);
var tempDataView = new DataView(tempArrayBuffer);
var value = this.readUint16();
var sign = value & 0x8000;
var exponent = value & 0x7c00;
var fraction = value & 0x03ff;
if (exponent === 0x7c00)
exponent = 0xff << 10;
else if (exponent !== 0)
exponent += (127 - 15) << 10;
else if (fraction !== 0)
return (sign ? -1 : 1) * fraction * this._POW_2_24;
tempDataView.setUint32(0, sign << 16 | exponent << 13 | fraction << 13);
return tempDataView.getFloat32(0);
};
Cbor.prototype.readFloat32 = function() {return this.commitRead(4, this.dataView.getFloat32(this.offset));};
Cbor.prototype.readFloat64 = function() {return this.commitRead(4, this.dataView.getFloat64(this.offset));};
Cbor.prototype.readUint8 = function() {return this.commitRead(4, this.dataView.getUint8(this.offset));};
Cbor.prototype.readUint16 = function() {return this.commitRead(4, this.dataView.getUint16(this.offset));};
Cbor.prototype.readUint32 = function() {return this.commitRead(4, this.dataView.getUint32(this.offset));};
Cbor.prototype.readUint64 = function() {return this.commitRead(4, this.readUint32() * this._POW_2_32 + this.readUint32());};
Cbor.prototype.readBreak = function() {
if (this.dataView.getUint8(this.offset) !== 0xff)
return false;
this.offset += 1;
return true;
};
Cbor.prototype.readLength = function(additionalInformation) {
if (additionalInformation < 24)
return additionalInformation;
if (additionalInformation === 24)
return this.readUint8();
if (additionalInformation === 25)
return this.readUint16();
if (additionalInformation === 26)
return this.readUint32();
if (additionalInformation === 27)
return this.readUint64();
if (additionalInformation === 31)
return -1;
throw "Invalid length encoding";
};
Cbor.prototype.readIndefiniteStringLength = function(majorType) {
var initialByte = this.readUint8();
if (initialByte === 0xff)
return -1;
var length = this.readLength(initialByte & 0x1f);
if (length < 0 || (initialByte >> 5) !== majorType)
throw "Invalid indefinite length element";
return length;
};
Cbor.prototype.appendUtf16Data = function(utf16data, length) {
for (var i = 0; i < length; ++i) {
var value = this.readUint8();
if (value & 0x80) {
if (value < 0xe0) {
value = (value & 0x1f) << 6
| (this.readUint8() & 0x3f);
length -= 1;
} else if (value < 0xf0) {
value = (value & 0x0f) << 12
| (this.readUint8() & 0x3f) << 6
| (this.readUint8() & 0x3f);
length -= 2;
} else {
value = (value & 0x0f) << 18
| (this.readUint8() & 0x3f) << 12
| (this.readUint8() & 0x3f) << 6
| (this.readUint8() & 0x3f);
length -= 3;
}
}
if (value < 0x10000) {
utf16data.push(value);
} else {
value -= 0x10000;
utf16data.push(0xd800 | (value >> 10));
utf16data.push(0xdc00 | (value & 0x3ff));
}
}
};
Cbor.prototype.decodeItem = function(tagger, simpleValue) {
var initialByte = this.readUint8();
var majorType = initialByte >> 5;
var additionalInformation = initialByte & 0x1f;
var i;
var length;
if (majorType === 7) {
switch (additionalInformation) {
case 25:
return this.readFloat16();
case 26:
return this.readFloat32();
case 27:
return this.readFloat64();
}
}
length = this.readLength(additionalInformation);
if (length < 0 && (majorType < 2 || 6 < majorType))
throw "Invalid length";
switch (majorType) {
case 0:
return length;
case 1:
return -1 - length;
case 2:
if (length < 0) {
var elements = [];
var fullArrayLength = 0;
while ((length = this.readIndefiniteStringLength(majorType)) >= 0) {
fullArrayLength += length;
elements.push(this.readArrayBuffer(length));
}
var fullArray = new Uint8Array(fullArrayLength);
var fullArrayOffset = 0;
for (i = 0; i < elements.length; ++i) {
fullArray.set(elements[i], fullArrayOffset);
fullArrayOffset += elements[i].length;
}
return fullArray;
}
return this.readArrayBuffer(length);
case 3:
var utf16data = [];
if (length < 0) {
while ((length = this.readIndefiniteStringLength(majorType)) >= 0)
this.appendUtf16Data(utf16data, length);
} else
this.appendUtf16Data(utf16data, length);
return String.fromCharCode.apply(null, utf16data);
case 4:
var retArray;
if (length < 0) {
retArray = [];
while (!this.readBreak())
retArray.push(this.decodeItem());
} else {
retArray = new Array(length);
for (i = 0; i < length; ++i)
retArray[i] = this.decodeItem();
}
return retArray;
case 5:
var retObject = {};
for (i = 0; i < length || length < 0 && !this.readBreak(); ++i) {
var key = this.decodeItem();
retObject[key] = this.decodeItem();
}
return retObject;
case 6:
return tagger(this.decodeItem(), length);
case 7:
switch (length) {
case 20:
return false;
case 21:
return true;
case 22:
return null;
case 23:
return undefined;
default:
return simpleValue(length);
}
}
};
Cbor.prototype.decode = function (tagger, simpleValue) {
if(this.isFromObject) {
return this.storage;
}else {
this.dataView = new DataView(this.storage);
this.offset = 0;
if (typeof tagger !== "function") {
tagger = function(value) { return value; };
}
if (typeof simpleValue !== "function") {
simpleValue = function() { return undefined; };
}
var ret = this.decodeItem(tagger, simpleValue);
if (this.offset !== this.storage.byteLength) {
throw "Remaining bytes";
}
return ret;
}
};
Cbor.prototype.run = function () {
if (this.isFromObject) {
return this.encode();
} else {
return this.decode();
}
};
Elemental92.CBOR = Cbor;
Elemental92.config = {};
Elemental92.config.TILD_CHAR_CODE = 126;
Elemental92.config.BACKSLASH_CHAR = String.fromCharCode(92);
Elemental92.config.SLASH_CHAR = String.fromCharCode(47);
Elemental92.config.CHUNCK_LENGTH = 256;
Elemental92.config.ENCODE_MAPPING = Uint8Array.of(
33, 35, 36, 37, 38, 39, 40, 41, 42, 43,
44, 45, 46, 47, 48, 49, 50, 51, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
64, 65, 66, 67, 68, 69, 70, 71, 72, 73,
74, 75, 76, 77, 78, 79, 80, 81, 82, 83,
84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
94, 95, 97, 98, 99, 100, 101, 102, 103, 104,
105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
125, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0
);
Elemental92.config.DECODE_MAPPING = Uint8Array.of(
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 0, 255, 1, 2, 3, 4, 5,
6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
36, 37, 38, 39, 40, 41, 42, 43, 44, 45,
46, 47, 48, 49, 50, 51, 52, 53, 54, 55,
56, 57, 58, 59, 60, 61, 255, 62, 63, 64,
65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
85, 86, 87, 88, 89, 90, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 255, 255, 255, 255, 255
);
Object.defineProperty(Elemental92.prototype, 'getCharCodeAt', {
get: function() { return function(i){i = i|0; return this.storage_input_[i|0]; }}
});
Object.defineProperty(Elemental92.prototype, 'getDecodedCharCodeAt', {
get: function() { return function(i){i = i|0; return this.DECODE_MAPPING_[this.storage_input_[i|0]]; }}
});
Object.defineProperty(Elemental92.prototype, 'decodeChar', {
get: function() { return function(i){i = i|0; return this.DECODE_MAPPING_[i|0];}}
});
Object.defineProperty(Elemental92.prototype, 'encodeChar', {
get: function() { return function(i){i = i|0; return this.ENCODE_MAPPING_[i|0];}}
});
Object.defineProperty(Elemental92.prototype, 'inputLength', {
get: function() { return this.storage_input_length_|0; }
});
Object.defineProperty(Elemental92.prototype, 'BACKSLASH_CHAR', {
get: function() { return this.BACKSLASH_CHAR_; }
});
Object.defineProperty(Elemental92.prototype, 'SLASH_CHAR', {
get: function() { return this.SLASH_CHAR_; }
});
Object.defineProperty(Elemental92.prototype, 'CHUNCK_LENGTH', {
get: function() { return this.CHUNCK_LENGTH_; }
});
Object.defineProperty(Elemental92.prototype, 'TILD_CHAR_CODE', {
get: function() { return this.TILD_CHAR_CODE_; }
});
Elemental92.utils = {};
Elemental92.utils.onlyCharPrintable = function (string) {
// remove non-printable and other non-valid JSON chars
return string.replace(/[\u0000-\u0019]+/g,"");
}
Elemental92.utils.onlyCharParsable = function (string) {
// This function is required because JSON is weird with some char
string = string.replace(/\\n/g, "\\n")
.replace(/\\'/g, "\\'")
.replace(/\\"/g, '\\"')
.replace(/\\&/g, "\\&")
.replace(/\\r/g, "\\r")
.replace(/\\t/g, "\\t")
.replace(/\\b/g, "\\b")
.replace(/\\f/g, "\\f");
return string;
}
Elemental92.utils.normalizeEncode = function (string) {
return encodeURIComponent(string);
}
Elemental92.utils.normalizeDecode = function (string) {
return decodeURIComponent(string);
}
Elemental92.utils.escape = function (string, description, author) {
string = string.replaceAll(Elemental92.config.BACKSLASH_CHAR, " ");
string = string.replaceAll(Elemental92.config.SLASH_CHAR, "~");
string = string.replaceAll("$", "¡");
string = string.replaceAll("'", "§");
var json_object = {"Elemental92.js": string};
json_object.description = description;
json_object.author = author;
return JSON.stringify(json_object);
}
Elemental92.utils.unescape = function (string) {
string = JSON.parse(string)["Elemental92.js"];
string = string.replaceAll("§", "'");
string = string.replaceAll("¡", "$");
string = string.replaceAll("~", Elemental92.config.SLASH_CHAR);
string = string.replaceAll(" ", Elemental92.config.BACKSLASH_CHAR);
return string;
}
Elemental92.utils.fromByteArray = function (array_buffer) {
var uint8a = "buffer" in array_buffer ? new Uint8Array(array_buffer.buffer): new Uint8Array(array_buffer)
var i = 0, str = "", rl = uint8a.length|0;
for(; (i|0) < (rl|0); i = (i+Elemental92.config.CHUNCK_LENGTH|0)>>>0){
str = str.concat(String.fromCharCode.apply(null, uint8a.subarray(i|0, Math.min(i+Elemental92.config.CHUNCK_LENGTH|0, rl|0)|0)));
}
return unescape(str);
}
Elemental92.utils.toByteArray = function (str) {
str = escape(str);
var i = 0; var rl = str.length|0; var a = new Uint8Array(rl|0);
for(;(i+3|0) < (rl|0); i = (i+4|0)>>>0){
a.set(Uint8Array.of(
str.charCodeAt(i|0),
str.charCodeAt(i+1|0),
str.charCodeAt(i+2|0),
str.charCodeAt(i+3|0)),
i|0);
}
for(;(i|0) < (rl|0);i = (i+1|0)>>>0){ a[i|0] = str.charCodeAt(i|0); }
return a;
}
Elemental92.prototype.encode = function(desired_output) {
desired_output = desired_output || "String";
var string_output = Boolean(desired_output == "String");
var i = 0, j = 0; // i for raw, j for encoded
var size = (this.inputLength * 8 | 0) % 13 | 0; // for the malloc
var workspace = 0; // bits holding bin
var wssize = 0; // number of good bits in workspace
var tmp = 0;
var c = 0;
if ((this.inputLength|0) == 0) {
return string_output ? "~": Uint8Array.of(this.TILD_CHAR_CODE);
}
// precalculate how much space we need to malloc
if ((size|0) == 0) {
size = 2 * ((this.inputLength * 8) / 13 | 0) | 0;
} else if ((size|0) < 7) {
size = 2 * ((this.inputLength * 8) / 13 | 0) + 1 | 0;
} else {
size = 2 * ((this.inputLength * 8) / 13 | 0) + 2 | 0;
}
// do the malloc
var results = new Uint8Array(size|0);
for (; (i|0) < (this.inputLength|0); i = (i+1|0)>>>0) {
workspace = workspace << 8 | this.getCharCodeAt(i|0);
wssize = wssize+8|0;
if ((wssize|0) >= 13) {
tmp = (workspace >> (wssize - 13 | 0)) & 8191;
c = this.encodeChar(tmp / 91 | 0) & 0xFF;
if ((c|0) == 0) {
// do something, illegal character
return null;
}
results[j|0] = c & 0xFF;
j = (j+1|0) >>> 0;
c = this.encodeChar(tmp % 91 | 0) & 0xFF;
if ((c|0) == 0) {
// do something, illegal character;
return null;
}
results[j|0] = c & 0xFF;
j = (j+1|0) >>> 0;
wssize = wssize - 13 | 0;
}
}
// encode a last byte
if (0 < (wssize|0) && (wssize|0) < 7) {
tmp = (workspace << (6 - wssize | 0)) & 63; // pad the right side
c = this.encodeChar(tmp|0) & 0xFF;
if ((c|0) == 0) {
// do something, illegal character
return null;
}
results[j|0] = c & 0xFF;
} else if (7 <= (wssize|0)) {
tmp = (workspace << (13 - wssize | 0)) & 8191; // pad the right side
c = this.encodeChar(tmp / 91 | 0);
if ((c|0) == 0) {
// do something, illegal character
return null;
}
results[j|0] = c & 0xFF;
j = (j+1|0) >>> 0;
c = this.encodeChar(tmp % 91 | 0) & 0xFF;
if ((c|0) == 0) {
// do something, illegal character
return null;
}
results[j|0] = c & 0xFF;
}
return string_output ? Elemental92.utils.fromByteArray(results.subarray(0, results.length|0)) : results.slice(0, results.length|0);
};
Elemental92.prototype.decode = function(desired_output) {
desired_output = desired_output || "String";
var string_output = Boolean(desired_output == "String");
var i = 0, j = 0, b1 = 0, b2 = 0;
var workspace = 0;
var wssize = 0
// calculate size
var size = ((this.inputLength / 2 * 13) + (this.inputLength % 2 * 6)) / 8 | 0;
var res = new Uint8Array(size);
// handle small cases first
if ((this.getCharCodeAt(0) - this.TILD_CHAR_CODE | 0) == 0 || (this.inputLength|0) == 0){
return string_output ? "~": Uint8Array.of(this.TILD_CHAR_CODE);
}
// this case does not fit the specs
if ((this.inputLength|0) < 2) {
return string_output ? "": new Uint8Array(0);
}
// handle pairs of chars
workspace = 0;
wssize = 0;
j = 0;
for (i = 0; (i + 1 | 0) < (this.inputLength|0); i = (i+2|0)>>>0) {
b1 = this.getDecodedCharCodeAt(i | 0);
b2 = this.getDecodedCharCodeAt(i + 1 | 0);
workspace = (workspace << 13) | (b1 * 91 + b2 | 0);
wssize = wssize + 13 | 0;
while ((wssize|0) >= 8)
{
res[j|0] = (workspace >> (wssize - 8)) & 0xFF;
j = j+1|0;
wssize = wssize - 8 | 0;
}
}
// handle single char
if ((this.inputLength % 2 | 0) == 1) {
workspace = (workspace << 6) | this.getDecodedCharCodeAt(this.inputLength - 1 | 0);
wssize = wssize+6|0;
while ((wssize|0) >= 8)
{
res[j|0] = (workspace >> (wssize - 8)) & 0xFF;
j = j+1|0;
wssize = wssize - 8 | 0;
}
}
return string_output ? Elemental92.utils.fromByteArray(res.subarray(0, res.length|0)): res.slice(0, res.length|0);
};
Elemental92.BASE64 = {};
Elemental92.BASE64.ERROR_CODE = 255;
Elemental92.BASE64.CODES = Uint8Array.of(255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 0, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51);
Elemental92.BASE64.CHAR_CODES = Uint8Array.of(65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47);
Elemental92.BASE64.CODE_LENGTH = Elemental92.BASE64.CODES.length | 0;
Elemental92.BASE64._getCodesBufferResults = function(buffer) {return Uint8Array.of( (buffer >> 16) & 0xFF, (buffer >> 8) & 0xFF, buffer & 0xFF)};
Elemental92.BASE64._getCodesBufferResultsBy4 = function(buffer_1, buffer_2, buffer_3, buffer_4 ) {
return Uint8Array.of(
(buffer_1 >> 16) & 0xFF, (buffer_1 >> 8) & 0xFF, buffer_1 & 0xFF,
(buffer_2 >> 16) & 0xFF, (buffer_2 >> 8) & 0xFF, buffer_2 & 0xFF,
(buffer_3 >> 16) & 0xFF, (buffer_3 >> 8) & 0xFF, buffer_3 & 0xFF,
(buffer_4 >> 16) & 0xFF, (buffer_4 >> 8) & 0xFF, buffer_4 & 0xFF
);
};
Elemental92.BASE64._getCode = function(char_code) {
var self = Elemental92.BASE64;
char_code = (char_code | 0) & 0xFF;
if (((char_code|0)>>>0) >= ((self.CODE_LENGTH |0)>>>0)) {throw new Error("Unable to parse base64 string.");}
const code = (self.CODES[char_code] | 0) >>> 0;
if (((code|0)>>>0) == ((self.ERROR_CODE |0)>>>0)) {throw new Error("Unable to parse base64 string.");}
return (code | 0) & 0xFF;
};
Elemental92.BASE64._getCodesBuffer = function(str_char_codes) {
var self = Elemental92.BASE64;
return (self._getCode(str_char_codes[0]) << 18 | self._getCode(str_char_codes[1]) << 12 | self._getCode(str_char_codes[2]) << 6 | self._getCode(str_char_codes[3]) | 0) >>> 0;
};
Elemental92.BASE64.toByteArray = function (str) {
var self = Elemental92.BASE64;
if ((str.length % 4 | 0) > 0) {
throw new Error("Unable to parse base64 string.");
}
const index = str.indexOf("=") | 0;
if ((index|0) > -1 && (index|0) < (str.length - 2 | 0)) {
throw new Error("Unable to parse base64 string.");
}
let str_char_code = Uint8Array.from(str.split("").map(function(s){ return s.charCodeAt(0)}));
let missingOctets = str.endsWith("==") ? 2 : str.endsWith("=") ? 1 : 0,
n = str.length | 0,
result = new Uint8Array(3 * (n / 4) | 0);
let str_char_code_splitted = new Uint8Array(16);
let i = 0, j = 0;
for (;(i+16|0) < (n|0); i = (i+16|0)>>>0, j = (j+12|0)>>>0) { // Single Operation Multiple Data (SIMD) up to 3x faster
str_char_code_splitted.set(str_char_code.subarray(i, i+16|0));
result.set(self._getCodesBufferResultsBy4(
self._getCodesBuffer(str_char_code_splitted.subarray(0, 4)),
self._getCodesBuffer(str_char_code_splitted.subarray(4, 8)),
self._getCodesBuffer(str_char_code_splitted.subarray(8, 12)),
self._getCodesBuffer(str_char_code_splitted.subarray(12, 16))
), j);
}
for (;(i|0) < (n|0); i = (i+4|0)>>>0, j = (j+3|0)>>>0) { // Single Operation Single Data (normal)
result.set(self._getCodesBufferResults(self._getCodesBuffer(str_char_code.subarray(i|0, i+4|0))), j|0);
}
return result.slice(0, result.length - missingOctets | 0);
}
Elemental92.BASE64.fromByteArray = function (bytes) {
var self = Elemental92.BASE64;
let i = 2, j = 0;
let l = bytes.length | 0;
let k = l % 3 | 0;
let n = Math.floor(l / 3) * 4 + (k && k + 1) | 0;
let N = Math.ceil(l / 3) * 4 | 0;
let result = new Uint8Array(N|0);
for (i = 2, j = 0; (i|0) < (l|0); i = (i+3|0)>>>0, j = (j+4|0)>>>0) {
result[j|0] = self.CHAR_CODES[bytes[i - 2 | 0] >> 2] & 0xFF;
result[j+1|0] = self.CHAR_CODES[((bytes[i - 2 | 0] & 0x03) << 4) | (bytes[i - 1 | 0] >> 4)] & 0xFF;
result[j+2|0] = self.CHAR_CODES[((bytes[i - 1 | 0] & 0x0F) << 2) | (bytes[i] >> 6)] & 0xFF;
result[j+3|0] = self.CHAR_CODES[bytes[i|0] & 0x3F] & 0xFF;
}
if ((i|0) == (l + 1 | 0)) { // 1 octet yet to write
result[j] = self.CHAR_CODES[bytes[i - 2 | 0] >> 2] & 0xFF;
result[j+1|0] = self.CHAR_CODES[(bytes[i - 2 | 0] & 0x03) << 4] & 0xFF;
result[j+2|0] = "=".charCodeAt(0) & 0xFF;
result[j+3|0] = "=".charCodeAt(0) & 0xFF;
j = (j+4|0)>>>0;
}
if ((i|0) == (l|0)) {
result[j|0] = self.CHAR_CODES[bytes[i - 2 | 0] >> 2] & 0xFF;
result[j+1|0] = self.CHAR_CODES[((bytes[i - 2 | 0] & 0x03) << 4) | (bytes[i - 1 | 0] >> 4)] & 0xFF;
result[j+2|0] = self.CHAR_CODES[(bytes[i - 1 | 0] & 0x0F) << 2] & 0xFF;
result[j+3|0] = "=".charCodeAt(0) & 0xFF;
}
let s = "";
let rl = result.length|0;
for(i = 0; (i|0) < (rl|0); i = (i+Elemental92.config.CHUNCK_LENGTH|0)>>>0){
s = s.concat(String.fromCharCode.apply(null, result.subarray(i|0, Math.min(i+Elemental92.config.CHUNCK_LENGTH|0, rl))));
}
return s;
}
/*
* The MIT License (MIT)
* Copyright © 2017 Nicolas Froidure (https://github.com/nfroidure/utf-8)
* Copyright © 2022 Affolter Matias
*/
var UTF8 = function(){
if (!(this instanceof UTF8)) {
return new UTF8();
}
};
UTF8.prototype._BYTE_MASKS_CHAR_LENGTH = Uint8Array.of(0b0, 0b1111111, 0b11000000, 0b11100000, 0b11110000);
UTF8.prototype._BYTE_MASKS_CHAR_CODE = Uint32Array.of(0, 128, 2048, 65536, 2097152);
UTF8.prototype._getCharLength = function(byte) {
if (this._BYTE_MASKS_CHAR_LENGTH[4] == (byte & this._BYTE_MASKS_CHAR_LENGTH[4])) {
return 4;
} else if (this._BYTE_MASKS_CHAR_LENGTH[3] == (byte & this._BYTE_MASKS_CHAR_LENGTH[3])) {
return 3;
} else if (this._BYTE_MASKS_CHAR_LENGTH[2] == (byte & this._BYTE_MASKS_CHAR_LENGTH[2])) {
return 2;
} else if (byte == (byte & this._BYTE_MASKS_CHAR_LENGTH[1])) {
return 1;
}else {
return 0;
}
};
UTF8.prototype._getBytesForCharCode = function (cc){
if (cc < this._BYTE_MASKS_CHAR_CODE[1]) {
return 1;
} else if (cc < this._BYTE_MASKS_CHAR_CODE[2]) {
return 2;
} else if (cc < this._BYTE_MASKS_CHAR_CODE[3]) {
return 3;
} else if (cc < this._BYTE_MASKS_CHAR_CODE[4]) {
return 4;
}else {
throw new Error('CharCode ' + cc + ' cannot be encoded with UTF8.');
}
};
UTF8.prototype._setBytesFromCharCode = function (charCode, bytes, byteOffset, neededBytes) {
charCode = charCode | 0;
bytes = bytes || [];
byteOffset = byteOffset | 0;
neededBytes = neededBytes || this._getBytesForCharCode(charCode);
// Setting the charCode as it to bytes if the byte length is 1
if (1 == neededBytes) {
bytes[byteOffset] = charCode;
} else {
// Computing the first byte
bytes[byteOffset++] =
(parseInt('1111'.slice(0, neededBytes), 2) << (8 - neededBytes)) +
(charCode >>> (--neededBytes * 6));
// Computing next bytes
for (; neededBytes > 0; ) {
bytes[byteOffset++] = ((charCode >>> (--neededBytes * 6)) & 0x3f) | 0x80;
}
}
return bytes;
};
UTF8.prototype.toByteArray = function(string, bytes, byteOffset, byteLength, strict) {
string = encodeURIComponent(string) || '';
bytes = bytes || [];
byteOffset = byteOffset | 0;
byteLength =
'number' === typeof byteLength ? byteLength : bytes.byteLength || Infinity;
for (var i = 0, j = string.length; i < j; i++) {
var neededBytes = this._getBytesForCharCode(string[i].codePointAt(0));
if (strict && byteOffset + neededBytes > byteLength) {
throw new Error(
'Not enought bytes to encode the char "' +
string[i] +
'" at the offset "' +
byteOffset +
'".'
);
}else {
this._setBytesFromCharCode(
string[i].codePointAt(0),
bytes,
byteOffset,
neededBytes,
strict
);
byteOffset += neededBytes;
}
}
return bytes;
};
UTF8.prototype._getCharCode = function(bytes, byteOffset, charLength) {
var charCode = 0,
mask = '';
byteOffset = byteOffset || 0;
// validate that the array has at least one byte in it
if (bytes.length - byteOffset <= 0) {
throw new Error('No more characters remaining in array.');
}
// Retrieve charLength if not given
charLength = charLength || this._getCharLength(bytes[byteOffset]);
if (charLength == 0) {
throw new Error(
bytes[byteOffset].toString(2) +
' is not a significative' +
' byte (offset:' +
byteOffset +
').'
);
}
// Return byte value if charlength is 1
if (1 === charLength) {
return bytes[byteOffset];
}
// validate that the array has enough bytes to make up this character
if (bytes.length - byteOffset < charLength) {
throw new Error(
'Expected at least ' + charLength + ' bytes remaining in array.'
);
}
// Test UTF8 integrity
mask = '00000000'.slice(0, charLength) + 1 + '00000000'.slice(charLength + 1);
if (bytes[byteOffset] & parseInt(mask, 2)) {
throw Error(
'Index ' +
byteOffset +
': A ' +
charLength +
' bytes' +
' encoded char' +
' cannot encode the ' +
(charLength + 1) +
'th rank bit to 1.'
);
}
// Reading the first byte
mask = '0000'.slice(0, charLength + 1) + '11111111'.slice(charLength + 1);
charCode += (bytes[byteOffset] & parseInt(mask, 2)) << (--charLength * 6);
// Reading the next bytes
while (charLength) {
if (
0x80 !== (bytes[byteOffset + 1] & 0x80) ||
0x40 === (bytes[byteOffset + 1] & 0x40)
) {
throw Error(
'Index ' +
(byteOffset + 1) +
': Next bytes of encoded char' +
' must begin with a "10" bit sequence.'
);
}
charCode += (bytes[++byteOffset] & 0x3f) << (--charLength * 6);
}
return charCode;
};
UTF8.prototype.fromByteArray = function (bytes, byteOffset, byteLength, strict) {
var charLength,
chars = [];
byteOffset = byteOffset | 0;
byteLength =
'number' === typeof byteLength
? byteLength
: bytes.byteLength || bytes.length;
for (; byteOffset < byteLength; byteOffset++) {
charLength = this._getCharLength(bytes[byteOffset]);
if (byteOffset + charLength > byteLength) {
if (strict) {
throw Error(
'Index ' +
byteOffset +
': Found a ' +
charLength +
' bytes encoded char declaration but only ' +
(byteLength - byteOffset) +
' bytes are available.'
);
}
} else {
chars.push(
String.fromCodePoint(this._getCharCode(bytes, byteOffset, charLength, strict))
);
}
byteOffset += charLength - 1;
}
return decodeURIComponent(chars.join(''));
};
UTF8.prototype.isNotUTF8 = function (bytes, byteOffset, byteLength) {
try {
this.fromByteArray(bytes, byteOffset, byteLength, true);
} catch (e) {
return true;
}
return false;
}
Elemental92.UTF8 = new UTF8();
Elemental92.UTF16 = {};
Elemental92.UTF16.ENCODER = new TextEncoder("utf-16");
Elemental92.UTF16.DECODER = new TextDecoder("utf-16");
Elemental92.UTF16.fromByteArray = function (arr) {
return Elemental92.UTF16.DECODER.decode(arr);
};
Elemental92.UTF16.toByteArray = function (str) {
return Elemental92.UTF16.ENCODER.encode(str);
};
Elemental92.DOShrink = function (it) {
return Elemental92.utils.escape(
new Elemental92(
Elemental92.LZ4.compress(
Elemental92.CBOR({
data: it
}).run()
)
).encode("String")
);
};
Elemental92.DOExpand = function (it, within_input) {
return Elemental92.CBOR(
Elemental92.LZ4.decompress(
new Elemental92(
Elemental92.utils.unescape(it, within_input)
).decode("ArrayBuffer")
)
).run().data
};
window.Elemental92 = Elemental92;
export default Elemental92;
@vipertechofficial
Copy link
Author

https://codepen.io/vipertechofficial/pen/JjBXJPR

DEMO : LZ-UTF8 (Compression algorithms) + inlined ELement92.js --> awesome gain of performance (weight consumption)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment