11
\$\begingroup\$

The task of this challenge is as following:

Write a program that reads a file of reasonable size (let's say <16 MB) from stdin or anywhere else (however you like, but must not be hardcoded), and put's the compressed output onto stdout. The output must be a valid gzip compressed file and if the compressed file runs through gunzip, it should yield exactly the same file as before.

Rules

  • The programming language used must be known before this competition started
  • The score of your program is the number of characters of the source code or the assembled program (whatever is shorter)
  • You're not allowed to use any kind of existing compression libraries.
  • Have fun!
\$\endgroup\$
  • 2
    \$\begingroup\$ Is the use of built-in libraries allowed? \$\endgroup\$ – hallvabo Jan 28 '11 at 14:43
  • \$\begingroup\$ @hallvabo: Nope. Forgot this. Thx \$\endgroup\$ – FUZxxl Jan 28 '11 at 15:08
  • 2
    \$\begingroup\$ Probably the best way to do this is just to pad the input with the "the following block is uncompressed" markers at the start of every block. \$\endgroup\$ – Anon. Jan 28 '11 at 16:05
  • \$\begingroup\$ gzip is a programming language. Not a Turing complete one though. \$\endgroup\$ – Alexandru Jan 28 '11 at 16:13
  • 1
    \$\begingroup\$ This is pretty much identical to the Guns and Zips problem. Why anyone would post their answers here rather than at codegolf.com is beyond me, unless they want to solve it in a language not supported by codegolf.com (e.g., GolfScript). \$\endgroup\$ – Chris Jester-Young Jan 29 '11 at 2:20
10
\$\begingroup\$

C# (534 characters)

using System.IO;using B=System.Byte;class X{static void Main(string[]a){var f=File.ReadAllBytes(a[0]);int l=f.Length,i=0,j;var p=new uint[256];for(uint k=0,r=0;k<256;r=++k){for(j=0;j<8;j++)r=r>>1^(r&1)*0xedb88320;p[k]=r;}uint c=~(uint)0,n=c;using(var o=File.Open(a[0]+".gz",FileMode.Create)){o.Write(new B[]{31,139,8,0,0,0,0,0,4,11},0,10);for(;i<l;i++){o.Write(new B[]{(B)(i<l-1?0:1),1,0,254,255,f[i]},0,6);c=p[(c^f[i])&0xFF]^c>>8;}c^=n;o.Write(new[]{(B)c,(B)(c>>8),(B)(c>>16),(B)(c>>24),(B)l,(B)(l>>8),(B)(l>>16),(B)(l>>24)},0,8);}}}

Much more readable:

using System.IO;
using B = System.Byte;
class X
{
    static void Main(string[] a)
    {
        // Read file contents
        var f = File.ReadAllBytes(a[0]);
        int l = f.Length, i = 0, j;

        // Initialise table for CRC hashsum
        var p = new uint[256];
        for (uint k = 0, r = 0; k < 256; r = ++k)
        {
            for (j = 0; j < 8; j++)
                r = r >> 1 ^ (r & 1) * 0xedb88320;
            p[k] = r;
        }

        uint c = ~(uint) 0, n = c;

        // Write the output file
        using (var o = File.Open(a[0] + ".gz", FileMode.Create))
        {
            // gzip header
            o.Write(new B[] { 31, 139, 8, 0, 0, 0, 0, 0, 4, 11 }, 0, 10);
            for (; i < l; i++)
            {
                // deflate block header plus one byte of payload
                o.Write(new B[] { (B) (i < l - 1 ? 0 : 1), 1, 0, 254, 255, f[i] }, 0, 6);
                // Compute CRC checksum
                c = p[(c ^ f[i]) & 0xFF] ^ c >> 8;
            }
            c ^= n;
            o.Write(new[] {
                // CRC checksum
                (B) c, (B) (c >> 8), (B) (c >> 16), (B) (c >> 24),
                // original file size
                (B) l, (B) (l >> 8), (B) (l >> 16), (B) (l >> 24)
            }, 0, 8);
        }
    }
}

Comments:

  • Expects path to file as first command-line argument.

  • Output file is input file + .gz.

  • I am not using any libraries to do the gzip, deflate or CRC32. It’s all in there.

  • This “compressor” increases the filesize by a factor of 6. But it’s in valid gzip format!

  • Tested using GNU gunzip and WinRAR.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.