vox-core
Version:
Runtime de aplicaciones multiplataforma
112 lines (106 loc) • 4.13 kB
JavaScript
/* *Very* simple de/compression utility, based on simple_c and simple_d from
* rngcod13.zip at http://www.compressconsult.com/rangecoder/
* Really just a demonstration/test of the rangecoder.
*/
if (typeof define !== 'function') { var define = require('amdefine')(module); }
define(['./RangeCoder','./Stream','./Util'],function(RangeCoder,Stream,Util){
var MAX_BLOCK_SIZE = 1<<17;
var Simple = Object.create(null);
Simple.MAGIC = 'smpl';
Simple.compressFile = Util.compressFileHelper(Simple.MAGIC, function(input, output, size, props, finalByte) {
var encoder = new RangeCoder(output);
encoder.encodeStart(finalByte, 1);
// read a block
var block = Util.makeU8Buffer(MAX_BLOCK_SIZE);
var counts = [];
var blockLength = 0, sawEOF = false;
var readBlock = function() {
var pos = 0;
// initialize counts
for (pos=0; pos < 256; pos++) {
counts[pos] = 0;
}
if (sawEOF) {
blockLength = 0;
return;
}
for (pos=0; pos < MAX_BLOCK_SIZE; ) {
var c = input.readByte();
if (c===Stream.EOF) {
sawEOF = true;
break;
}
block[pos++] = c;
counts[c]++;
// bail if some count reaches maximum
if (counts[c]===0xFFFF) {
break;
}
}
blockLength = pos;
};
while (true) {
var i;
readBlock();
if (sawEOF && blockLength===0) {
break;
}
// indicate that there's another block comin'
encoder.encodeBit(true);
// write all the statistics
for (i=0; i<256; i++) {
encoder.encodeShort(counts[i]);
}
// convert counts to cumulative counts
counts[256] = blockLength;
for (i=256; i; i--) {
counts[i-1] = counts[i] - counts[i-1];
}
// encode the symbols using the probability table.
for (i=0; i<blockLength; i++) {
var ch = block[i];
encoder.encodeFreq(counts[ch+1]-counts[ch], counts[ch],
counts[256]);
}
}
// write a stop bit
encoder.encodeBit(false);
// done!
encoder.encodeFinish();
}, true);
Simple.decompressFile = Util.decompressFileHelper(Simple.MAGIC, function(input, output, size) {
var decoder = new RangeCoder(input);
decoder.decodeStart(true/*we already read the 'free' byte*/);
while (decoder.decodeBit()) {
var i, counts = [];
// read all the statistics
for (i=0; i<256; i++) {
counts[i] = decoder.decodeShort();
}
// compute cumulative stats & total block size
var blocksize = 0;
for (i=0; i<256; i++) {
var tmp = counts[i];
counts[i] = blocksize;
blocksize += tmp;
}
counts[256] = blocksize;
for (i=0; i<blocksize; i++) {
var cf = decoder.decodeCulFreq(blocksize);
// inefficient way to look up the symbol.
var symbol;
for (symbol=0; symbol<256; symbol++)
// careful, there are length-0 ranges
// (where counts[symbol]===counts[symbol+1])
if (counts[symbol]<=cf && cf < counts[symbol+1])
break;
var ch = symbol;
decoder.decodeUpdate(counts[symbol+1] - counts[symbol],
counts[symbol], blocksize);
output.writeByte(symbol);
}
}
decoder.decodeFinish();
});
return Simple;
});