📝 Added entire config directory for backup purposes

This commit is contained in:
z3rOR0ne 2022-11-03 00:09:22 -07:00
parent 4b38e59bb6
commit 9b946e2d14
11091 changed files with 1440953 additions and 0 deletions

View file

@ -0,0 +1,52 @@
## Purpose
The purpose of this library is to implement LZ4 compression/decompression,
as documented at the official LZ4 repository:
https://github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md
The files in this directory are developed as a separate project at:
https://github.com/gorhill/lz4-wasm
## Files
### `lz4-block-codec-any.js`
The purpose is to instanciate a WebAssembly- or pure javascript-based
LZ4 block codec.
If the choosen implementation is not specified, there will be an attempt to
create a WebAssembly-based instance. If for whatever reason this fails, a
pure javascript-based instance will be created.
The script for either instance are dynamically loaded and only when needed,
such that no resources are wasted by keeping in memory code which won't be
used.
### `lz4-block-codec-wasm.js`
This contains the code to instanciate WebAssembly-based LZ4 block codec. Note
that the WebAssembly module is loaded using a `same-origin` fetch, hence
ensuring that no code outside the package is loaded.
### `lz4-block-codec-js.js`
This contains the code to instanciate pure javascript-based LZ4 block codec.
This is used as a fallback implementation should WebAssembly not be available
for whatever reason.
### `lz4-block-codec.wasm`
This is the WebAssembly module, loaded by `lz4-block-codec-wasm.js` using a
`same-origin` fetch.
### `lz4-block-codec.wat`
The WebAssembly source code used to generate the WebAssembly module `lz4-block-codec.wasm`.
wat2wasm ./lz4-block-codec.wat -o ./lz4-block-codec.wasm
wasm-opt ./lz4-block-codec.wasm -O4 -o ./lz4-block-codec.wasm
You can get `wat2wasm` at <https://github.com/WebAssembly/wabt>, and `wasm-opt` at <https://github.com/WebAssembly/binaryen>.

View file

@ -0,0 +1,151 @@
/*******************************************************************************
lz4-block-codec-any.js
A wrapper to instanciate a wasm- and/or js-based LZ4 block
encoder/decoder.
Copyright (C) 2018 Raymond Hill
BSD-2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Home: https://github.com/gorhill/lz4-wasm
I used the same license as the one picked by creator of LZ4 out of respect
for his creation, see https://lz4.github.io/lz4/
*/
'use strict';
/******************************************************************************/
(function(context) { // >>>> Start of private namespace
/******************************************************************************/
const wd = (function() {
let url = document.currentScript.src;
let match = /[^\/]+$/.exec(url);
return match !== null ?
url.slice(0, match.index) :
'';
})();
const removeScript = function(script) {
if ( !script ) { return; }
if ( script.parentNode === null ) { return; }
script.parentNode.removeChild(script);
};
const createInstanceWASM = function() {
if ( context.LZ4BlockWASM instanceof Function ) {
const instance = new context.LZ4BlockWASM();
return instance.init().then(ok => ok ? instance : null);
}
if ( context.LZ4BlockWASM === null ) {
return Promise.resolve(null);
}
return new Promise(resolve => {
const script = document.createElement('script');
script.src = wd + 'lz4-block-codec-wasm.js';
script.addEventListener('load', ( ) => {
if ( context.LZ4BlockWASM instanceof Function === false ) {
context.LZ4BlockWASM = null;
resolve(null);
return;
}
const instance = new context.LZ4BlockWASM();
instance.init().then(ok => { resolve(ok ? instance : null); });
});
script.addEventListener('error', ( ) => {
context.LZ4BlockWASM = null;
resolve(null);
});
document.head.appendChild(script);
removeScript(script);
});
};
const createInstanceJS = function() {
if ( context.LZ4BlockJS instanceof Function ) {
const instance = new context.LZ4BlockJS();
return instance.init().then(ok => ok ? instance : null);
}
if ( context.LZ4BlockJS === null ) {
return Promise.resolve(null);
}
return new Promise(resolve => {
const script = document.createElement('script');
script.src = wd + 'lz4-block-codec-js.js';
script.addEventListener('load', ( ) => {
if ( context.LZ4BlockJS instanceof Function === false ) {
context.LZ4BlockJS = null;
resolve(null);
return;
}
const instance = new context.LZ4BlockJS();
instance.init().then(ok => { resolve(ok ? instance : null); });
});
script.addEventListener('error', ( ) => {
context.LZ4BlockJS = null;
resolve(null);
});
document.head.appendChild(script);
removeScript(script);
});
};
/******************************************************************************/
context.lz4BlockCodec = {
createInstance: function(flavor) {
let instantiator;
if ( flavor === 'wasm' ) {
instantiator = createInstanceWASM;
} else if ( flavor === 'js' ) {
instantiator = createInstanceJS;
} else {
instantiator = createInstanceWASM || createInstanceJS;
}
return (instantiator)().then(instance => {
if ( instance ) { return instance; }
if ( flavor === undefined ) {
return createInstanceJS();
}
return null;
});
},
reset: function() {
context.LZ4BlockWASM = undefined;
context.LZ4BlockJS = undefined;
}
};
/******************************************************************************/
})(this || self); // <<<< End of private namespace
/******************************************************************************/

View file

@ -0,0 +1,297 @@
/*******************************************************************************
lz4-block-codec-js.js
A javascript wrapper around a pure javascript implementation of
LZ4 block format codec.
Copyright (C) 2018 Raymond Hill
BSD-2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Home: https://github.com/gorhill/lz4-wasm
I used the same license as the one picked by creator of LZ4 out of respect
for his creation, see https://lz4.github.io/lz4/
*/
'use strict';
/******************************************************************************/
(function(context) { // >>>> Start of private namespace
/******************************************************************************/
const growOutputBuffer = function(instance, size) {
if (
instance.outputBuffer === undefined ||
instance.outputBuffer.byteLength < size
) {
instance.outputBuffer = new ArrayBuffer(size + 0xFFFF & 0x7FFF0000);
}
return instance.outputBuffer;
};
const encodeBound = function(size) {
return size > 0x7E000000 ?
0 :
size + (size / 255 | 0) + 16;
};
const encodeBlock = function(instance, iBuf, oOffset) {
let iLen = iBuf.byteLength;
if ( iLen >= 0x7E000000 ) { throw new RangeError(); }
// "The last match must start at least 12 bytes before end of block"
let lastMatchPos = iLen - 12;
// "The last 5 bytes are always literals"
let lastLiteralPos = iLen - 5;
if ( instance.hashTable === undefined ) {
instance.hashTable = new Int32Array(65536);
}
instance.hashTable.fill(-65536);
if ( iBuf instanceof ArrayBuffer ) {
iBuf = new Uint8Array(iBuf);
}
let oLen = oOffset + encodeBound(iLen);
let oBuf = new Uint8Array(growOutputBuffer(instance, oLen), 0, oLen);
let iPos = 0;
let oPos = oOffset;
let anchorPos = 0;
// sequence-finding loop
for (;;) {
let refPos;
let mOffset;
let sequence = iBuf[iPos] << 8 | iBuf[iPos+1] << 16 | iBuf[iPos+2] << 24;
// match-finding loop
while ( iPos <= lastMatchPos ) {
sequence = sequence >>> 8 | iBuf[iPos+3] << 24;
let hash = (sequence * 0x9E37 & 0xFFFF) + (sequence * 0x79B1 >>> 16) & 0xFFFF;
refPos = instance.hashTable[hash];
instance.hashTable[hash] = iPos;
mOffset = iPos - refPos;
if (
mOffset < 65536 &&
iBuf[refPos+0] === ((sequence ) & 0xFF) &&
iBuf[refPos+1] === ((sequence >>> 8) & 0xFF) &&
iBuf[refPos+2] === ((sequence >>> 16) & 0xFF) &&
iBuf[refPos+3] === ((sequence >>> 24) & 0xFF)
) {
break;
}
iPos += 1;
}
// no match found
if ( iPos > lastMatchPos ) { break; }
// match found
let lLen = iPos - anchorPos;
let mLen = iPos;
iPos += 4; refPos += 4;
while ( iPos < lastLiteralPos && iBuf[iPos] === iBuf[refPos] ) {
iPos += 1; refPos += 1;
}
mLen = iPos - mLen;
let token = mLen < 19 ? mLen - 4 : 15;
// write token, length of literals if needed
if ( lLen >= 15 ) {
oBuf[oPos++] = 0xF0 | token;
let l = lLen - 15;
while ( l >= 255 ) {
oBuf[oPos++] = 255;
l -= 255;
}
oBuf[oPos++] = l;
} else {
oBuf[oPos++] = (lLen << 4) | token;
}
// write literals
while ( lLen-- ) {
oBuf[oPos++] = iBuf[anchorPos++];
}
if ( mLen === 0 ) { break; }
// write offset of match
oBuf[oPos+0] = mOffset;
oBuf[oPos+1] = mOffset >>> 8;
oPos += 2;
// write length of match if needed
if ( mLen >= 19 ) {
let l = mLen - 19;
while ( l >= 255 ) {
oBuf[oPos++] = 255;
l -= 255;
}
oBuf[oPos++] = l;
}
anchorPos = iPos;
}
// last sequence is literals only
let lLen = iLen - anchorPos;
if ( lLen >= 15 ) {
oBuf[oPos++] = 0xF0;
let l = lLen - 15;
while ( l >= 255 ) {
oBuf[oPos++] = 255;
l -= 255;
}
oBuf[oPos++] = l;
} else {
oBuf[oPos++] = lLen << 4;
}
while ( lLen-- ) {
oBuf[oPos++] = iBuf[anchorPos++];
}
return new Uint8Array(oBuf.buffer, 0, oPos);
};
const decodeBlock = function(instance, iBuf, iOffset, oLen) {
let iLen = iBuf.byteLength;
let oBuf = new Uint8Array(growOutputBuffer(instance, oLen), 0, oLen);
let iPos = iOffset, oPos = 0;
while ( iPos < iLen ) {
let token = iBuf[iPos++];
// literals
let clen = token >>> 4;
// length of literals
if ( clen !== 0 ) {
if ( clen === 15 ) {
let l;
for (;;) {
l = iBuf[iPos++];
if ( l !== 255 ) { break; }
clen += 255;
}
clen += l;
}
// copy literals
let end = iPos + clen;
while ( iPos < end ) {
oBuf[oPos++] = iBuf[iPos++];
}
if ( iPos === iLen ) { break; }
}
// match
let mOffset = iBuf[iPos+0] | (iBuf[iPos+1] << 8);
if ( mOffset === 0 || mOffset > oPos ) { return; }
iPos += 2;
// length of match
clen = (token & 0x0F) + 4;
if ( clen === 19 ) {
let l;
for (;;) {
l = iBuf[iPos++];
if ( l !== 255 ) { break; }
clen += 255;
}
clen += l;
}
// copy match
let mPos = oPos - mOffset;
let end = oPos + clen;
while ( oPos < end ) {
oBuf[oPos++] = oBuf[mPos++];
}
}
return oBuf;
};
/******************************************************************************/
context.LZ4BlockJS = function() {
this.hashTable = undefined;
this.outputBuffer = undefined;
};
context.LZ4BlockJS.prototype = {
flavor: 'js',
init: function() {
return Promise.resolve(true);
},
reset: function() {
this.hashTable = undefined;
this.outputBuffer = undefined;
},
bytesInUse: function() {
let bytesInUse = 0;
if ( this.hashTable !== undefined ) {
bytesInUse += this.hashTable.byteLength;
}
if ( this.outputBuffer !== undefined ) {
bytesInUse += this.outputBuffer.byteLength;
}
return bytesInUse;
},
encodeBlock: function(input, outputOffset) {
if ( input instanceof ArrayBuffer ) {
input = new Uint8Array(input);
} else if ( input instanceof Uint8Array === false ) {
throw new TypeError();
}
return encodeBlock(this, input, outputOffset);
},
decodeBlock: function(input, inputOffset, outputSize) {
if ( input instanceof ArrayBuffer ) {
input = new Uint8Array(input);
} else if ( input instanceof Uint8Array === false ) {
throw new TypeError();
}
return decodeBlock(this, input, inputOffset, outputSize);
}
};
/******************************************************************************/
})(this || self); // <<<< End of private namespace
/******************************************************************************/

View file

@ -0,0 +1,195 @@
/*******************************************************************************
lz4-block-codec-wasm.js
A javascript wrapper around a WebAssembly implementation of
LZ4 block format codec.
Copyright (C) 2018 Raymond Hill
BSD-2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Home: https://github.com/gorhill/lz4-wasm
I used the same license as the one picked by creator of LZ4 out of respect
for his creation, see https://lz4.github.io/lz4/
*/
/* global WebAssembly */
'use strict';
/******************************************************************************/
(function(context) { // >>>> Start of private namespace
/******************************************************************************/
const wd = (function() {
let url = document.currentScript.src;
let match = /[^\/]+$/.exec(url);
return match !== null ?
url.slice(0, match.index) :
'';
})();
const growMemoryTo = function(wasmInstance, byteLength) {
let lz4api = wasmInstance.exports;
let neededByteLength = lz4api.getLinearMemoryOffset() + byteLength;
let pageCountBefore = lz4api.memory.buffer.byteLength >>> 16;
let pageCountAfter = (neededByteLength + 65535) >>> 16;
if ( pageCountAfter > pageCountBefore ) {
lz4api.memory.grow(pageCountAfter - pageCountBefore);
}
return lz4api.memory.buffer;
};
const encodeBlock = function(wasmInstance, inputArray, outputOffset) {
let lz4api = wasmInstance.exports;
let mem0 = lz4api.getLinearMemoryOffset();
let hashTableSize = 65536 * 4;
let inputSize = inputArray.byteLength;
if ( inputSize >= 0x7E000000 ) { throw new RangeError(); }
let memSize =
hashTableSize +
inputSize +
outputOffset + lz4api.lz4BlockEncodeBound(inputSize);
let memBuffer = growMemoryTo(wasmInstance, memSize);
let hashTable = new Int32Array(memBuffer, mem0, 65536);
hashTable.fill(-65536, 0, 65536);
let inputMem = new Uint8Array(memBuffer, mem0 + hashTableSize, inputSize);
inputMem.set(inputArray);
let outputSize = lz4api.lz4BlockEncode(
mem0 + hashTableSize,
inputSize,
mem0 + hashTableSize + inputSize + outputOffset
);
if ( outputSize === 0 ) { return; }
let outputArray = new Uint8Array(
memBuffer,
mem0 + hashTableSize + inputSize,
outputOffset + outputSize
);
return outputArray;
};
const decodeBlock = function(wasmInstance, inputArray, inputOffset, outputSize) {
let inputSize = inputArray.byteLength;
let lz4api = wasmInstance.exports;
let mem0 = lz4api.getLinearMemoryOffset();
let memSize = inputSize + outputSize;
let memBuffer = growMemoryTo(wasmInstance, memSize);
let inputArea = new Uint8Array(memBuffer, mem0, inputSize);
inputArea.set(inputArray);
outputSize = lz4api.lz4BlockDecode(
mem0 + inputOffset,
inputSize - inputOffset,
mem0 + inputSize
);
if ( outputSize === 0 ) { return; }
return new Uint8Array(memBuffer, mem0 + inputSize, outputSize);
};
/******************************************************************************/
context.LZ4BlockWASM = function() {
this.lz4wasmInstance = undefined;
};
context.LZ4BlockWASM.prototype = {
flavor: 'wasm',
init: function() {
if (
typeof WebAssembly !== 'object' ||
typeof WebAssembly.instantiateStreaming !== 'function'
) {
this.lz4wasmInstance = null;
}
if ( this.lz4wasmInstance === null ) {
return Promise.resolve(false);
}
if ( this.lz4wasmInstance instanceof WebAssembly.Instance ) {
return Promise.resolve(true);
}
if ( this.lz4wasmInstance === undefined ) {
this.lz4wasmInstance = fetch(
wd + 'lz4-block-codec.wasm',
{ mode: 'same-origin' }
).then(
WebAssembly.instantiateStreaming
).then(result => {
this.lz4wasmInstance = result && result.instance || null;
}).catch(reason => {
this.lz4wasmInstance = null;
console.info(reason);
}).then(( ) =>
this.lz4wasmInstance !== null
);
}
return this.lz4wasmInstance;
},
reset: function() {
this.lz4wasmInstance = undefined;
},
bytesInUse: function() {
return this.lz4wasmInstance instanceof WebAssembly.Instance ?
this.lz4wasmInstance.exports.memory.buffer.byteLength :
0;
},
encodeBlock: function(input, outputOffset) {
if ( this.lz4wasmInstance instanceof WebAssembly.Instance === false ) {
throw new Error('LZ4BlockWASM: not initialized');
}
if ( input instanceof ArrayBuffer ) {
input = new Uint8Array(input);
} else if ( input instanceof Uint8Array === false ) {
throw new TypeError();
}
return encodeBlock(this.lz4wasmInstance, input, outputOffset);
},
decodeBlock: function(input, inputOffset, outputSize) {
if ( this.lz4wasmInstance instanceof WebAssembly.Instance === false ) {
throw new Error('LZ4BlockWASM: not initialized');
}
if ( input instanceof ArrayBuffer ) {
input = new Uint8Array(input);
} else if ( input instanceof Uint8Array === false ) {
throw new TypeError();
}
return decodeBlock(this.lz4wasmInstance, input, inputOffset, outputSize);
}
};
/******************************************************************************/
})(this || self); // <<<< End of private namespace
/******************************************************************************/

View file

@ -0,0 +1,745 @@
;;
;; lz4-block-codec.wat: a WebAssembly implementation of LZ4 block format codec
;; Copyright (C) 2018 Raymond Hill
;;
;; BSD-2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
;;
;; Redistribution and use in source and binary forms, with or without
;; modification, are permitted provided that the following conditions are
;; met:
;;
;; 1. Redistributions of source code must retain the above copyright
;; notice, this list of conditions and the following disclaimer.
;;
;; 2. Redistributions in binary form must reproduce the above
;; copyright notice, this list of conditions and the following disclaimer
;; in the documentation and/or other materials provided with the
;; distribution.
;;
;; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
;; "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
;; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
;; A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
;; OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
;; SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
;; LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
;; OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
;;
;; Home: https://github.com/gorhill/lz4-wasm
;;
;; I used the same license as the one picked by creator of LZ4 out of respect
;; for his creation, see https://lz4.github.io/lz4/
;;
(module
;;
;; module start
;;
;; (func $log (import "imports" "log") (param i32 i32 i32))
(memory (export "memory") 1)
;;
;; Public functions
;;
;;
;; Return an offset to the first byte of usable linear memory.
;; Might be useful in the future to reserve memory space for whatever purpose,
;; like config variables, etc.
;;
(func $getLinearMemoryOffset (export "getLinearMemoryOffset")
(result i32)
i32.const 0
)
;;
;; unsigned int lz4BlockEncodeBound()
;;
;; Return the maximum size of the output buffer holding the compressed data.
;;
;; Reference implementation:
;; https://github.com/lz4/lz4/blob/dev/lib/lz4.h#L156
;;
(func (export "lz4BlockEncodeBound")
(param $ilen i32)
(result i32)
get_local $ilen
i32.const 0x7E000000
i32.gt_u
if
i32.const 0
return
end
get_local $ilen
get_local $ilen
i32.const 255
i32.div_u
i32.add
i32.const 16
i32.add
)
;;
;; unsigned int lz4BlockEncode(
;; unsigned int inPtr,
;; unsigned int ilen,
;; unsigned int outPtr
;; )
;;
;; https://github.com/lz4/lz4/blob/dev/lib/lz4.c#L651
;;
;; The implementation below is modified from the reference one.
;;
;; - There is no skip adjustement for repeated failure to find a match.
;;
;; - All configurable values are hard-coded to match the generic version
;; of the compressor.
;;
;; Note the size of the input block is NOT encoded in the output buffer, it
;; is for the caller to figure how they will save that information on
;; their side. At this point it is probably a trivial amount of work to
;; implement the LZ4 frame format, which encode the content size, but this
;; is for another day.
;;
(func $lz4BlockEncode (export "lz4BlockEncode")
(param $inPtr i32) ;; pointer to start of input buffer
(param $ilen i32) ;; size of input buffer
(param $outPtr i32) ;; pointer to start of output buffer
(result i32)
(local $hashPtrBeg i32) ;; start of hash buffer
(local $hashPtr i32) ;; current hash entry
(local $anchorPtr i32) ;; anchor position in input
(local $inPtrEnd1 i32) ;; point in input at which match-finding must cease
(local $inPtrEnd2 i32) ;; point in input at which match-length finding must cease
(local $inPtrEnd i32) ;; point to end of input
(local $outPtrBeg i32) ;; start of output buffer
(local $refPtr i32) ;; start of match in input
(local $seq32 i32) ;; 4-byte value from current input position
(local $llen i32) ;; length of found literals
(local $moffset i32) ;; offset to found match from current input position
(local $mlen i32) ;; length of found match
get_local $ilen ;; empty input = empty output
i32.const 0x7E000000 ;; max input size: 0x7E000000
i32.gt_u
if
i32.const 0
return
end
get_local $ilen ;; "blocks < 13 bytes cannot be compressed"
i32.const 13
i32.lt_u
if
i32.const 0
return
end
call $getLinearMemoryOffset ;; hash table is at start of usable memory
set_local $hashPtrBeg
get_local $inPtr
tee_local $anchorPtr
get_local $ilen
i32.add
tee_local $inPtrEnd
i32.const -5 ;; "The last 5 bytes are always literals."
i32.add
tee_local $inPtrEnd2
i32.const -7 ;; "The last match must start at least 12 bytes before end of block"
i32.add
set_local $inPtrEnd1
get_local $outPtr
set_local $outPtrBeg
;;
;; sequence processing loop
;;
block $noMoreSequence loop $nextSequence
get_local $inPtr
get_local $inPtrEnd1
i32.ge_u ;; 5 or less bytes left?
br_if $noMoreSequence
get_local $inPtr ;; first sequence of 3 bytes before match-finding loop
i32.load8_u
i32.const 8
i32.shl
get_local $inPtr
i32.load8_u offset=1
i32.const 16
i32.shl
i32.or
get_local $inPtr
i32.load8_u offset=2
i32.const 24
i32.shl
i32.or
set_local $seq32
;;
;; match-finding loop
;;
loop $findMatch block $noMatchFound
get_local $inPtr
get_local $inPtrEnd2
i32.gt_u ;; less than 12 bytes left?
br_if $noMoreSequence
get_local $seq32 ;; update last byte of current sequence
i32.const 8
i32.shr_u
get_local $inPtr
i32.load8_u offset=3
i32.const 24
i32.shl
i32.or
tee_local $seq32
i32.const 0x9E3779B1 ;; compute 16-bit hash
i32.mul
i32.const 16
i32.shr_u ;; hash value is at top of stack
i32.const 2 ;; lookup refPtr at hash entry
i32.shl
get_local $hashPtrBeg
i32.add
tee_local $hashPtr
i32.load
set_local $refPtr
get_local $hashPtr ;; update hash entry with inPtr
get_local $inPtr
i32.store
get_local $inPtr
get_local $refPtr
i32.sub
tee_local $moffset ;; remember match offset, we will need it in case of match
i32.const 0xFFFF
i32.gt_s ;; match offset > 65535 = unusable match
br_if $noMatchFound
;;
;; confirm match: different sequences can yield same hash
;; compare-branch each byte to potentially save memory read ops
;;
get_local $seq32 ;; byte 0
i32.const 0xFF
i32.and
get_local $refPtr
i32.load8_u
i32.ne ;; refPtr[0] !== inPtr[0]
br_if $noMatchFound
get_local $seq32 ;; byte 1
i32.const 8
i32.shr_u
i32.const 0xFF
i32.and
get_local $refPtr
i32.load8_u offset=1
i32.ne
br_if $noMatchFound ;; refPtr[1] !== inPtr[1]
get_local $seq32 ;; byte 2
i32.const 16
i32.shr_u
i32.const 0xFF
i32.and
get_local $refPtr
i32.load8_u offset=2
i32.ne ;; refPtr[2] !== inPtr[2]
br_if $noMatchFound
get_local $seq32 ;; byte 3
i32.const 24
i32.shr_u
i32.const 0xFF
i32.and
get_local $refPtr
i32.load8_u offset=3
i32.ne ;; refPtr[3] !== inPtr[3]
br_if $noMatchFound
;;
;; a valid match has been found at this point
;;
get_local $inPtr ;; compute length of literals
get_local $anchorPtr
i32.sub
set_local $llen
get_local $inPtr ;; find match length
i32.const 4 ;; skip over confirmed 4-byte match
i32.add
set_local $inPtr
get_local $refPtr
i32.const 4
i32.add
tee_local $mlen ;; remember refPtr to later compute match length
set_local $refPtr
block $endOfMatch loop ;; scan input buffer until match ends
get_local $inPtr
get_local $inPtrEnd2
i32.ge_u
br_if $endOfMatch
get_local $inPtr
i32.load8_u
get_local $refPtr
i32.load8_u
i32.ne
br_if $endOfMatch
get_local $inPtr
i32.const 1
i32.add
set_local $inPtr
get_local $refPtr
i32.const 1
i32.add
set_local $refPtr
br 0
end end $endOfMatch
;; encode token
get_local $outPtr ;; output token
get_local $llen
get_local $refPtr
get_local $mlen
i32.sub
tee_local $mlen
call $writeToken
get_local $outPtr
i32.const 1
i32.add
set_local $outPtr
get_local $llen ;; encode/write length of literals if needed
i32.const 15
i32.ge_s
if
get_local $outPtr
get_local $llen
call $writeLength
set_local $outPtr
end
;; copy literals
get_local $outPtr
get_local $anchorPtr
get_local $llen
call $copy
get_local $outPtr
get_local $llen
i32.add
set_local $outPtr
;; encode match offset
get_local $outPtr
get_local $moffset
i32.store8
get_local $outPtr
get_local $moffset
i32.const 8
i32.shr_u
i32.store8 offset=1
get_local $outPtr
i32.const 2
i32.add
set_local $outPtr
get_local $mlen ;; encode/write length of match if needed
i32.const 15
i32.ge_s
if
get_local $outPtr
get_local $mlen
call $writeLength
set_local $outPtr
end
get_local $inPtr ;; advance anchor to current position
set_local $anchorPtr
br $nextSequence
end $noMatchFound
get_local $inPtr ;; no match found: advance to next byte
i32.const 1
i32.add
set_local $inPtr
br $findMatch end ;; match offset > 65535 = unusable match
end end $noMoreSequence
;;
;; generate last (match-less) sequence if compression succeeded
;;
get_local $outPtr
get_local $outPtrBeg
i32.eq
if
i32.const 0
return
end
get_local $outPtr
get_local $inPtrEnd
get_local $anchorPtr
i32.sub
tee_local $llen
i32.const 0
call $writeToken
get_local $outPtr
i32.const 1
i32.add
set_local $outPtr
get_local $llen
i32.const 15
i32.ge_u
if
get_local $outPtr
get_local $llen
call $writeLength
set_local $outPtr
end
get_local $outPtr
get_local $anchorPtr
get_local $llen
call $copy
get_local $outPtr ;; return number of written bytes
get_local $llen
i32.add
get_local $outPtrBeg
i32.sub
)
;;
;; unsigned int lz4BlockDecode(
;; unsigned int inPtr,
;; unsigned int ilen
;; unsigned int outPtr
;; )
;;
;; Reference:
;; https://github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md
;;
(func (export "lz4BlockDecode")
(param $inPtr0 i32) ;; start of input buffer
(param $ilen i32) ;; length of input buffer
(param $outPtr0 i32) ;; start of output buffer
(result i32)
(local $inPtr i32) ;; current position in input buffer
(local $inPtrEnd i32) ;; end of input buffer
(local $outPtr i32) ;; current position in output buffer
(local $matchPtr i32) ;; position of current match
(local $token i32) ;; sequence token
(local $clen i32) ;; number of bytes to copy
(local $_ i32) ;; general purpose variable
get_local $ilen ;; if ( ilen == 0 ) { return 0; }
i32.eqz
if
i32.const 0
return
end
get_local $inPtr0
tee_local $inPtr ;; current position in input buffer
get_local $ilen
i32.add
set_local $inPtrEnd
get_local $outPtr0 ;; start of output buffer
set_local $outPtr ;; current position in output buffer
block $noMoreSequence loop ;; iterate through all sequences
get_local $inPtr
get_local $inPtrEnd
i32.ge_u
br_if $noMoreSequence ;; break when nothing left to read in input buffer
get_local $inPtr ;; read token -- consume one byte
i32.load8_u
get_local $inPtr
i32.const 1
i32.add
set_local $inPtr
tee_local $token ;; extract length of literals from token
i32.const 4
i32.shr_u
tee_local $clen ;; consume extra length bytes if present
i32.eqz
if else
get_local $clen
i32.const 15
i32.eq
if loop
get_local $inPtr
i32.load8_u
get_local $inPtr
i32.const 1
i32.add
set_local $inPtr
tee_local $_
get_local $clen
i32.add
set_local $clen
get_local $_
i32.const 255
i32.eq
br_if 0
end end
get_local $outPtr ;; copy literals to ouput buffer
get_local $inPtr
get_local $clen
call $copy
get_local $outPtr ;; advance output buffer pointer past copy
get_local $clen
i32.add
set_local $outPtr
get_local $clen ;; advance input buffer pointer past literals
get_local $inPtr
i32.add
tee_local $inPtr
get_local $inPtrEnd ;; exit if this is the last sequence
i32.eq
br_if $noMoreSequence
end
get_local $outPtr ;; read match offset
get_local $inPtr
i32.load8_u
get_local $inPtr
i32.load8_u offset=1
i32.const 8
i32.shl
i32.or
i32.sub
tee_local $matchPtr
get_local $outPtr ;; match position can't be outside input buffer bounds
i32.eq
br_if $noMoreSequence
get_local $matchPtr
get_local $inPtrEnd
i32.lt_u
br_if $noMoreSequence
get_local $inPtr ;; advance input pointer past match offset bytes
i32.const 2
i32.add
set_local $inPtr
get_local $token ;; extract length of match from token
i32.const 15
i32.and
i32.const 4
i32.add
tee_local $clen
i32.const 19 ;; consume extra length bytes if present
i32.eq
if loop
get_local $inPtr
i32.load8_u
get_local $inPtr
i32.const 1
i32.add
set_local $inPtr
tee_local $_
get_local $clen
i32.add
set_local $clen
get_local $_
i32.const 255
i32.eq
br_if 0
end end
get_local $outPtr ;; copy match to ouput buffer
get_local $matchPtr
get_local $clen
call $copy
get_local $clen ;; advance output buffer pointer past copy
get_local $outPtr
i32.add
set_local $outPtr
br 0
end end $noMoreSequence
get_local $outPtr ;; return number of written bytes
get_local $outPtr0
i32.sub
)
;;
;; Private functions
;;
;;
;; Encode a sequence token
;;
;; Reference documentation:
;; https://github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md
;;
(func $writeToken
(param $outPtr i32)
(param $llen i32)
(param $mlen i32)
get_local $outPtr
get_local $llen
i32.const 15
get_local $llen
i32.const 15
i32.lt_u
select
i32.const 4
i32.shl
get_local $mlen
i32.const 15
get_local $mlen
i32.const 15
i32.lt_u
select
i32.or
i32.store8
)
;;
;; Encode and output length bytes. The return value is the pointer following
;; the last byte written.
;;
;; Reference documentation:
;; https://github.com/lz4/lz4/blob/dev/doc/lz4_Block_format.md
;;
(func $writeLength
(param $outPtr i32)
(param $len i32)
(result i32)
get_local $len
i32.const 15
i32.sub
set_local $len
loop
get_local $outPtr
get_local $len
i32.const 255
get_local $len
i32.const 255
i32.lt_u
select
i32.store8
get_local $outPtr
i32.const 1
i32.add
set_local $outPtr
get_local $len
i32.const 255
i32.sub
tee_local $len
i32.const 0
i32.ge_s
br_if 0
end
get_local $outPtr
)
;;
;; Copy n bytes from source to destination.
;;
;; It is overlap-safe only from left-to-right -- which is only what is
;; required in the current module.
;;
(func $copy
(param $dst i32)
(param $src i32)
(param $len i32)
block $lessThan8 loop
get_local $len
i32.const 8
i32.lt_u
br_if $lessThan8
get_local $dst
get_local $src
i32.load8_u
i32.store8
get_local $dst
get_local $src
i32.load8_u offset=1
i32.store8 offset=1
get_local $dst
get_local $src
i32.load8_u offset=2
i32.store8 offset=2
get_local $dst
get_local $src
i32.load8_u offset=3
i32.store8 offset=3
get_local $dst
get_local $src
i32.load8_u offset=4
i32.store8 offset=4
get_local $dst
get_local $src
i32.load8_u offset=5
i32.store8 offset=5
get_local $dst
get_local $src
i32.load8_u offset=6
i32.store8 offset=6
get_local $dst
get_local $src
i32.load8_u offset=7
i32.store8 offset=7
get_local $dst
i32.const 8
i32.add
set_local $dst
get_local $src
i32.const 8
i32.add
set_local $src
get_local $len
i32.const -8
i32.add
set_local $len
br 0
end end $lessThan8
get_local $len
i32.const 4
i32.ge_u
if
get_local $dst
get_local $src
i32.load8_u
i32.store8
get_local $dst
get_local $src
i32.load8_u offset=1
i32.store8 offset=1
get_local $dst
get_local $src
i32.load8_u offset=2
i32.store8 offset=2
get_local $dst
get_local $src
i32.load8_u offset=3
i32.store8 offset=3
get_local $dst
i32.const 4
i32.add
set_local $dst
get_local $src
i32.const 4
i32.add
set_local $src
get_local $len
i32.const -4
i32.add
set_local $len
end
get_local $len
i32.const 2
i32.ge_u
if
get_local $dst
get_local $src
i32.load8_u
i32.store8
get_local $dst
get_local $src
i32.load8_u offset=1
i32.store8 offset=1
get_local $dst
i32.const 2
i32.add
set_local $dst
get_local $src
i32.const 2
i32.add
set_local $src
get_local $len
i32.const -2
i32.add
set_local $len
end
get_local $len
i32.eqz
if else
get_local $dst
get_local $src
i32.load8_u
i32.store8
end
)
;;
;; module end
;;
)