Tulis utilitas kompresi untuk file gzip

11

Tugas tantangan ini adalah sebagai berikut:

Tulis sebuah program yang membaca file dengan ukuran yang masuk akal (misalkan <16 MB) dari stdin atau di tempat lain (sesuka Anda, tetapi jangan di-hardcode), dan masukkan output terkompresi ke stdout. Outputnya harus berupa file terkompresi gzip yang valid dan jika file terkompresi berjalan melalui gunzip, itu harus menghasilkan file yang sama persis seperti sebelumnya.

Aturan

  • Bahasa pemrograman yang digunakan harus diketahui sebelum kompetisi ini dimulai
  • Nilai program Anda adalah jumlah karakter kode sumber atau program rakitan (apa pun yang lebih pendek)
  • Anda tidak diizinkan menggunakan perpustakaan kompresi apa pun yang ada.
  • Selamat bersenang-senang!
FUZxxl
sumber
2
Apakah penggunaan perpustakaan bawaan diizinkan?
hallvabo
@hallvabo: Tidak. Lupa ini. Thx
FUZxxl
2
Mungkin cara terbaik untuk melakukan ini adalah hanya menempelkan input dengan spidol "blok berikut ini tidak terkompresi" di awal setiap blok.
Anon.
gzip adalah bahasa pemrograman. Bukan Turing yang lengkap sekalipun.
Alexandru
1
Ini cukup identik dengan masalah Guns and Zip . Mengapa ada orang yang memposting jawaban mereka di sini daripada di codegolf.com adalah di luar saya, kecuali mereka ingin menyelesaikannya dalam bahasa yang tidak didukung oleh codegolf.com (misalnya, GolfScript).
Chris Jester-Young

Jawaban:

10

C # (534 karakter)

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);}}}

Jauh lebih mudah dibaca:

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);
        }
    }
}

Komentar:

  • Mengharapkan path ke file sebagai argumen baris perintah pertama.

  • File output adalah file input + .gz.

  • Saya tidak menggunakan perpustakaan apa pun untuk melakukan gzip, deflate atau CRC32. Semuanya ada di sana.

  • "Kompresor" ini meningkatkan ukuran file dengan faktor 6. Tapi itu dalam format gzip yang valid!

  • Diuji menggunakan GNU gunzip dan WinRAR.

Timwi
sumber