Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /**
- fpaq0 - Stationary order 0 file arithmetic compressor.
- (C) 2004, Matt Mahoney under GPL, http://www.gnu.org/licenses/gpl.txt
- Translated to the D language by leonardo maffi, Feb 8 2008.
- Modified by ,
- Copyright: GPL
- */
- // To compile: dmd -O -release -inline fpaq0D.d
- // or: gdc -O3 -frelease fpaq0.d -o fpaq0D
- module fpaq0;
- import std.c.stdio: FILE, getc, putc, ftell, fopen, fclose, EOF;
- import std.c.time: clock, CLOCKS_PER_SEC;
- import std.stdio: writefln;
- import std.string: toStringz;
- import core.memory;
- @system
- /**********************************************
- A Predictor estimates the probability that the next bit of uncompressed data is 1.
- */
- struct Predictor {
- int cxt = 1; // Context: last 0-8 bits with a leading 1
- int[2][512] ct; // 0 and 1 counts in context cxt
- /**
- returns P(1) as a 12 bit number (0-4095).
- Assume a stationary order 0 stream of 9-bit symbols.
- */
- nothrow pure const int p() {
- return 4096 * (ct[cxt][1] + 1) / (ct[cxt][0] + ct[cxt][1] + 2);
- }
- /// trains the predictor with the actual bit (0 or 1).
- nothrow pure void update(int y) {
- ct[cxt][y]++;
- if (ct[cxt][y] > 65534) {
- ct[cxt][0] >>= 1;
- ct[cxt][1] >>= 1;
- }
- cxt += cxt + y;
- if (cxt >= 512)
- cxt = 1;
- }
- }
- nothrow void compress(FILE* fin, FILE* fout) {
- Predictor predictor;
- uint x1, x2 = 0xffffffff; // Range, initially [0, 1), scaled by 2^32
- uint x; // Last 4 input bytes of archive.
- uint y;
- uint xmid;
- for ( ; ; ) {
- int c = getc(fin);
- if (c == EOF)
- break;
- //e.encode(0);
- y = 0;
- xmid = x1 + ((x2 - x1) >> 12) * predictor.p();
- assert(xmid >= x1 && xmid < x2);
- if (y)
- x2 = xmid;
- else
- x1 = xmid + 1;
- predictor.update(y);
- while (((x1 ^ x2) & 0xff000000) == 0) {
- putc(x2 >> 24, fout);
- x1 <<= 8;
- x2 = (x2 << 8) + 255;
- }
- for(int i = 7; i >= 0; --i){
- //e.encode((c >> i) & 1);
- y = (c >> i) & 1;
- xmid = x1 + ((x2 - x1) >> 12) * predictor.p();
- assert(xmid >= x1 && xmid < x2);
- if (y)
- x2 = xmid;
- else
- x1 = xmid + 1;
- predictor.update(y);
- while (((x1 ^ x2) & 0xff000000) == 0) {
- putc(x2 >> 24, fout);
- x1 <<= 8;
- x2 = (x2 << 8) + 255;
- }
- }
- }
- //e.encode(1)
- y = 1;
- xmid = x1 + ((x2 - x1) >> 12) * predictor.p();
- assert(xmid >= x1 && xmid < x2);
- if (y)
- x2 = xmid;
- else
- x1 = xmid + 1;
- predictor.update(y);
- while (((x1 ^ x2) & 0xff000000) == 0) {
- putc(x2 >> 24, fout);
- x1 <<= 8;
- x2 = (x2 << 8) + 255;
- }
- // e.flush();
- while (((x1 ^ x2) & 0xff000000) == 0) {
- putc(x2 >> 24, fout);
- x1 <<= 8;
- x2 = (x2 << 8) + 255;
- }
- putc(x2 >> 24, fout); // First unequal byte.
- }
- nothrow void decompress(FILE* fin, FILE* fout) {
- Predictor predictor;
- uint x1, x2 = 0xffffffff; // Range, initially [0, 1), scaled by 2^32
- uint x; // Last 4 input bytes of archive.
- int c;
- uint xmid;
- int y;
- // Initialize x to the first 4 bytes of the archive
- foreach(i; 0 .. 4) {
- c = getc(fin);
- if (c == EOF)
- c = 0;
- x = (x << 8) + (c & 0xff);
- }
- // pre-encode for while
- xmid = x1 + ((x2 - x1) >> 12) * predictor.p();
- assert(xmid >= x1 && xmid < x2);
- y = 0;
- if (x <= xmid) {
- y = 1;
- x2 = xmid;
- }
- else
- x1 = xmid + 1;
- predictor.update(y);
- while (((x1 ^ x2) & 0xff000000) == 0) {
- x1 <<= 8;
- x2 = (x2 << 8) + 255;
- int c2 = getc(fin);
- if (c2 == EOF)
- c2 = 0;
- x = (x << 8) + c2;
- }
- while (!y) { //acho que isto vai dar problema
- c = 1;
- while (c < 256) {
- xmid = x1 + ((x2 - x1) >> 12) * predictor.p();
- assert(xmid >= x1 && xmid < x2);
- y = 0;
- if (x <= xmid) {
- y = 1;
- x2 = xmid;
- }
- else
- x1 = xmid + 1;
- predictor.update(y);
- while (((x1 ^ x2) & 0xff000000) == 0) {
- x1 <<= 8;
- x2 = (x2 << 8) + 255;
- int c2 = getc(fin);
- if (c2 == EOF)
- c2 = 0;
- x = (x << 8) + c2;
- }
- c += c + y;
- }
- putc(c - 256, fout);
- // second round, for while definition
- xmid = x1 + ((x2 - x1) >> 12) * predictor.p();
- assert(xmid >= x1 && xmid < x2);
- y = 0;
- if (x <= xmid) {
- y = 1;
- x2 = xmid;
- }
- else
- x1 = xmid + 1;
- predictor.update(y);
- while (((x1 ^ x2) & 0xff000000) == 0) {
- x1 <<= 8;
- x2 = (x2 << 8) + 255;
- int c2 = getc(fin);
- if (c2 == EOF)
- c2 = 0;
- x = (x << 8) + c2;
- }
- }
- }
- int main(string[] args) {
- // Chech arguments: fpaq0 c/d input output
- if (args.length != 4 || (args[1] != "c" && args[1] != "d")) {
- writefln("To compress: fpaq0 c input output");
- writefln("To decompress: fpaq0 d input output");
- return 1;
- }
- auto start = clock(); // Start timer
- // Open files
- FILE* fin = fopen(args[2].toStringz(), "rb".ptr);
- if (!fin) {
- writefln(args[2]);
- return 1;
- }
- FILE* fout = fopen(args[3].toStringz(), "wb".ptr);
- if (!fout) {
- writefln(args[3]);
- return 1;
- }
- GC.disable;
- if (args[1] == "c")
- compress(fin, fout);
- else
- decompress(fin, fout);
- // Print results
- double stop = (clock() - start) / cast(double)CLOCKS_PER_SEC;
- writefln("%s (%d bytes) -> %s (%d bytes) in %1.2f s",
- args[2], ftell(fin), args[3], ftell(fout), stop);
- fclose(fin);
- fclose(fout);
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement