This Node.js code implements a Huffman coding compression and decompression library using a WebAssembly module, allowing for the compression and decompression of messages. The code includes functions for writing and reading bits to and from a memory array, as well as a function for decompressing messages using the Huffman coding algorithm.
npm run import -- "huffman decode"
var fs = require('fs')
var huffman = fs.readFileSync('/Users/briancullinan/planet_quake/build/debug-js-js/huffman_js.wasm')
//var Huffman = require('/Users/briancullinan/planet_quake/code/xquakejs/lib/huffman.js')
var Huff_Compress
var Huff_Decompress
var HuffmanGetBit
var HuffmanGetSymbol
var isInit = false
var MAX_MSGLEN = 16384
var buffer
var memory
// negative bit values include signs
function writeBits( msgBytes, offset, value, bits ) {
var base = 8192 * 12
var bitIndex = offset
var nbits = bits&7
if ( bits < 0 ) {
bits = -bits
}
for(var j = 0; j < MAX_MSGLEN; j++) {
if(j < msgBytes.length)
memory[base + j] = msgBytes[j] & 0xFF
else
memory[base + j] = 0
}
value &= (0xffffffff>>(32-bits))
if ( nbits ) {
for ( var i = 0; i < nbits ; i++ ) {
HuffmanPutBit( base, bitIndex, (value & 1) )
bitIndex++
value = (value>>1)
}
bits = bits - nbits
}
if ( bits ) {
for( var i = 0 ; i < bits ; i += 8 ) {
bitIndex += HuffmanPutSymbol( base, bitIndex, (value & 0xFF) )
value = (value>>8)
}
}
return [bitIndex, memory.slice(base, base + (bitIndex>>3)+1)]
}
function readBits(m, offset, bits = 8) {
var base = 8192 * 12
var value
var nbits = bits & 7
var sym = base - 4
var bitIndex = offset
for(var i = 0; i < m.length; i++)
memory[base + i] = m[i]
if ( nbits )
{
for ( i = 0; i < nbits; i++ ) {
value |= HuffmanGetBit( base, bitIndex ) << i
bitIndex++
}
bits -= nbits
}
if ( bits )
{
for ( i = 0; i < bits; i += 8 )
{
bitIndex += HuffmanGetSymbol( sym, base, bitIndex )
value |= ( memory[sym] << (i+nbits) )
}
}
return [bitIndex, value]
}
async function decompressMessage(message, offset) {
if(!isInit)
await init()
if(typeof message == 'string')
message = message.split('')
for(var i = 0; i < message.length; i++)
Huffman.HEAP8[msgData+i] = c
Huffman.HEAP32[(msg>>2)+5] = message.length
Huffman._Huff_Decompress( msg, 12 )
return Huffman.HEAP8.slice(msgData + offset, msgData + Huffman.HEAP32[(msg>>2)+5])
}
async function compressMessage(message) {
var msg = 8192 * 12
var msgStart = (msg + 64)
if(!isInit)
await init()
for(var i = msg; i < msgStart + message.length; i++)
{
memory[i] = 0
}
memory[msg + 12] = msgStart & 255
memory[msg + 13] = (msgStart >> 8) & 255
memory[msg + 14] = (msgStart >> 16) & 255
memory[msg + 15] = (msgStart >> 24) & 255
memory[msg + 20] = (message.length + 1) & 255
memory[msg + 21] = ((message.length + 1) >> 8) & 255
memory[msg + 22] = 0
memory[msg + 23] = 0
if(typeof message == 'string')
message = message.split('')
for(var i = 0; i < message.length; i++)
memory[msgStart + i] = message[i].charCodeAt(0)
memory[msgStart + message.length] = 0
Huff_Compress(msg, 12)
var msgLength = (memory[msg + 21] << 8) + memory[msg + 20]
var compressed = memory.slice(msgStart, msgStart + msgLength)
return compressed
}
async function init() {
var binary = new Uint8Array(huffman)
let imports = {};
imports['memory'] = new WebAssembly['Memory']( {'initial': 16, 'maximum': 100} )
memory = new Uint8Array( imports['memory']['buffer'] )
let program = await WebAssembly.instantiate(binary, { env: imports })
Huff_Compress = program.instance.exports.Huff_Compress
Huff_Decompress = program.instance.exports.Huff_Decompress
HuffmanGetBit = program.instance.exports.HuffmanGetBit
HuffmanGetSymbol = program.instance.exports.HuffmanGetSymbol
HuffmanPutBit = program.instance.exports.HuffmanPutBit
HuffmanPutSymbol = program.instance.exports.HuffmanPutSymbol
}
init()
module.exports = init
Object.assign(init, {
readBits,
writeBits,
decompressMessage,
compressMessage
})
const fs = require('fs');
const WebAssembly = require('webassembly-js');
class HuffmanCompressor {
constructor() {
this.memory = new Uint8Array(16);
this.msgData = 8192 * 12;
this.MAX_MSGLEN = 16384;
this.isInit = false;
this.buffer = new Uint8Array(0);
this.MAX_MSGLEN = 16384;
this.buffer = new Uint8Array(16384);
this.memory = new Uint8Array(16);
}
async init() {
if (this.isInit) return;
const binary = new Uint8Array(fs.readFileSync('/Users/briancullinan/planet_quake/build/debug-js-js/huffman_js.wasm'));
const imports = {};
imports['memory'] = new WebAssembly.Memory({ initial: 1, maximum: 1 });
const memory = new Uint8Array(imports['memory'].buffer);
this.buffer = memory;
const program = await WebAssembly.instantiate(binary, { env: imports });
this.Huff_Compress = program.instance.exports.Huff_Compress;
this.Huff_Decompress = program.instance.exports.Huff_Decompress;
this.HuffmanGetBit = program.instance.exports.HuffmanGetBit;
this.HuffmanGetSymbol = program.instance.exports.HuffmanGetSymbol;
this.HuffmanPutBit = program.instance.exports.HuffmanPutBit;
this.HuffmanPutSymbol = program.instance.exports.HuffmanPutSymbol;
this.isInit = true;
}
async compressMessage(message) {
if (!this.isInit) await this.init();
const msg = this.msgData;
const msgStart = msg + 64;
if (typeof message ==='string') message = message.split('');
for (let i = msg; i < msgStart + message.length; i++) {
this.buffer[i] = 0;
}
const msgLength = message.length + 1;
this.buffer[msg + 20] = msgLength & 255;
this.buffer[msg + 21] = (msgLength >> 8) & 255;
this.buffer[msg + 22] = 0;
this.buffer[msg + 23] = 0;
for (let i = 0; i < message.length; i++) {
this.buffer[msgStart + i] = message[i].charCodeAt(0);
}
this.buffer[msgStart + message.length] = 0;
this.Huff_Compress(msg, 12);
const compressedLength = (this.buffer[msg + 21] << 8) + this.buffer[msg + 20];
const compressed = this.buffer.slice(msgStart, msgStart + compressedLength);
return compressed;
}
async decompressMessage(message, offset) {
if (!this.isInit) await this.init();
const m = [];
for (let i = 0; i < message.length; i++) {
m.push(message[i]);
}
return this.readBits(m, offset);
}
readBits(m, offset, bits = 8) {
const base = this.msgData;
let value = 0;
const nbits = bits & 7;
for (let i = 0; i < m.length; i++) {
this.buffer[base + i] = m[i];
}
let bitIndex = offset;
if (nbits) {
for (let i = 0; i < nbits; i++) {
value |= this.HuffmanGetBit(base, bitIndex) << i;
bitIndex++;
}
bits -= nbits;
}
if (bits) {
for (let i = 0; i < bits; i += 8) {
bitIndex += this.HuffmanGetSymbol(this.msgData - 4, base, bitIndex);
value |= this.buffer[this.msgData - 4] << (i + nbits);
}
}
return [bitIndex, value];
}
writeBits(msgBytes, offset, value, bits) {
const base = this.msgData;
const bitIndex = offset;
const nbits = bits & 7;
for (let j = 0; j < this.MAX_MSGLEN; j++) {
if (j < msgBytes.length) {
this.buffer[base + j] = msgBytes[j] & 0xFF;
} else {
this.buffer[base + j] = 0;
}
}
value &= (0xffffffff >> (32 - bits));
if (nbits) {
for (let i = 0; i < nbits; i++) {
this.HuffmanPutBit(base, bitIndex, value & 1);
bitIndex++;
value = value >> 1;
}
bits = bits - nbits;
}
if (bits) {
for (let i = 0; i < bits; i += 8) {
bitIndex += this.HuffmanPutSymbol(base, bitIndex, value & 0xFF);
value = value >> 8;
}
}
return [bitIndex, this.buffer.slice(base, base + (bitIndex >> 3) + 1)];
}
}
module.exports = HuffmanCompressor;
Code Breakdown
This is a Node.js code snippet that appears to be implementing a Huffman coding compression and decompression library. Huffman coding is a lossless data compression algorithm that assigns variable-length codes to characters in a data set.
Variables and Functions
Variables:
fs
: The Node.js file system module.huffman
: A WebAssembly (WASM) module containing the Huffman coding algorithm.Huff_Compress
, Huff_Decompress
, HuffmanGetBit
, and HuffmanGetSymbol
: These are likely function pointers or references to the WASM module's functions.isInit
: A flag indicating whether the library has been initialized.MAX_MSGLEN
: The maximum length of a message.buffer
and memory
: Probably a buffer and memory array used for data manipulation.Functions:
writeBits
: Writes bits to the memory
array. It takes in a message (as an array of bytes), an offset, a value, and the number of bits to write.readBits
: Reads bits from the memory
array. It takes in a message (as an array of bytes), an offset, and the number of bits to read (defaulting to 8).decompressMessage
: Decompresses a message using the Huffman coding algorithm.Function Explanations
writeBits
:
memory
array, padding it with zeros if necessary.memory
array, using either bits or symbols depending on the number of bits specified.readBits
:
memory
array and returns them as a value.memory
array, depending on the number of bits specified.decompressMessage
:
readBits
function.Note: The code assumes that the huffman
WASM module is present and correctly loaded. The init
function is not implemented in this code snippet.