Last active
January 3, 2023 22:30
-
-
Save vipertechofficial/2dde2e4b7574580deccdbc94d513728f to your computer and use it in GitHub Desktop.
AWESOME - Get your base64 a bit of futurism --> BASE 92 !!!
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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 <[email protected]> | |
* 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; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
https://codepen.io/vipertechofficial/pen/JjBXJPR
DEMO : LZ-UTF8 (Compression algorithms) + inlined ELement92.js --> awesome gain of performance (weight consumption)