Napisz użycie kompresujące dla plików gzip

11

Zadanie tego wyzwania jest następujące:

Napisz program, który odczyta plik o rozsądnej wielkości (powiedzmy <16 MB) ze standardowego wejścia lub gdziekolwiek indziej (jak chcesz, ale nie musi być zakodowany na stałe) i umieść skompresowane wyjście na standardowe wyjście. Dane wyjściowe muszą być prawidłowym skompresowanym plikiem gzip, a jeśli skompresowany plik działa przez gunzip, powinien dać dokładnie taki sam plik jak poprzednio.

Zasady

  • Używany język programowania musi być znany przed rozpoczęciem konkursu
  • Wynik twojego programu to liczba znaków kodu źródłowego lub skompilowanego programu (cokolwiek jest krótsze)
  • Nie wolno używać żadnych istniejących bibliotek kompresji.
  • Baw się dobrze!
FUZxxl
źródło
2
Czy dozwolone jest korzystanie z wbudowanych bibliotek?
hallvabo
@hallvabo: Nie. Zapomniałem o tym Thx
FUZxxl
2
Prawdopodobnie najlepszym sposobem na to jest po prostu wypełnienie wejścia znacznikami „następujący blok jest nieskompresowany” na początku każdego bloku.
Anon.
gzip to język programowania. Nie jest to jednak kompletny Turing.
Alexandru
1
Jest to prawie identyczne z problemem Guns and Zips . Dlaczego ktoś zamieszcza tutaj swoje odpowiedzi, a nie na codegolf.com, jest poza mną, chyba że chce rozwiązać je w języku nieobsługiwanym przez codegolf.com (np. GolfScript).
Chris Jester-Young

Odpowiedzi:

10

C # (534 znaków)

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

Znacznie bardziej czytelny:

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

Komentarze:

  • Oczekuje ścieżki do pliku jako pierwszego argumentu wiersza polecenia.

  • Plik wyjściowy to plik wejściowy + .gz.

  • Nie używam żadnych bibliotek do gzip, deflate lub CRC32. Wszystko tam jest.

  • Ten „kompresor” zwiększa rozmiar pliku sześciokrotnie. Ale jest w prawidłowym formacie gzip!

  • Testowane przy użyciu GNU gunzip i WinRAR.

Timwi
źródło