[ create a new paste ] login | about

Link: http://codepad.org/phpLP7cx    [ raw code | fork ]

D, pasted on Apr 14:
import core.stdc.stdio;
import core.stdc.stdlib;
import core.stdc.string;
import core.stdc.time;
import std.string: toStringz;

struct Predictor
{
    int cxt = 1;
    int ct[512][2];

    pure int p() const
    {
        return 4096 * (ct[cxt][1] + 1) / (ct[cxt][0] + ct[cxt][1] + 2);
    }

    void update(int y)
    {
        if (++ct[cxt][y] > 65534)
        {
            ct[cxt][0] >>= 1;
            ct[cxt][1] >>= 1;
        }
        if ((cxt += cxt + y) >= 512)
            cxt = 1;
    }
}

enum Mode
{
    COMPRESS = 0,
    DECOMPRESS
}

struct Encoder
{
private:

    Predictor predictor;
    Mode mode = void;
    FILE* archive = void;
    uint x1, x2 = 0xffffffff;
    uint x;

public:

    this(Mode m, FILE* f)
    {
        mode = m;
        archive = f;

        if (mode == Mode.DECOMPRESS)
        {
            foreach (i; 0 .. 4)
            {
                int c = getc(archive);
                if (c == EOF) c = '\0';
                x = (x << 8) + (c&0xff);
            }
        }
    }

    void encode(int y)
    {
        const uint 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, archive);
            x1 <<= 8;
            x2 = (x2 << 8) + 255;
        }
    }

    int decode()
    {
        const uint xmid = x1 + ((x2-x1) >> 12) * predictor.p();
        assert(xmid >= x1 && xmid < x2);

        int 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 c = getc(archive);
            if (c == EOF) c = 0;
            x = (x << 8) + c;
        }

        return y;
    }

    void flush()
    {
        if (mode == Mode.COMPRESS)
        {
            while (((x1 ^ x2)&0xff000000) == 0)
            {
                putc(x2 >> 24, archive);
                x1 <<= 8;
                x2 = (x2 << 8) + 255;
            }
            putc(x2 >> 24, archive);
        }
    }
}

int main(string[] args)
{
    if (args.length != 4 || (args[1][0] != 'c' && args[1][0] != 'd'))
    {
        printf(
            "To compress:   fpaq0 c input output\n"
            "To decompress: fpaq0 d input output\n"
        );
        return 1;
    }

    clock_t start = clock();

    FILE* fin = fopen(args[2].toStringz(), "rb");
    if  (!fin)
    {
        perror(args[2].toStringz());
        return 1;
    }

    FILE *fout = fopen(args[3].toStringz(), "wb");
    if  (!fout)
    {
        perror(args[3].toStringz());
        return 1;
    }

    if (args[1][0] == 'c')
    {
        int c;
        Encoder e = Encoder(Mode.COMPRESS, fout);
        while ((c = getc(fin)) != EOF)
        {
            e.encode(0);
            for (int i = 7; i >= 0; --i)
                e.encode((c >> i)&1);
        }
        e.encode(1);
        e.flush();
    }
    else
    {
        Encoder e = Encoder(Mode.DECOMPRESS, fin);
        while (!e.decode())
        {
            int c = 1;
            while (c < 256)
                c += c + e.decode();
            putc(c - 256, fout);
        }
    }

    printf(
        "%s (%ld bytes) -> %s (%ld bytes) in %1.2f s.\n",
        args[2].toStringz(), ftell(fin), args[3].toStringz(), ftell(fout),
        (cast(double)clock() - start) / CLOCKS_PER_SEC
    );
    return 0;
}


Create a new paste based on this one


Comments: