====== std.gzip ====== Der **gzip-Container** nach RFC 1952 — der Rahmen um DEFLATE, den ''[[lyx_-_programmiersprache:units:zlib|std.zlib]]'' liefert. Erzeugte Dateien lassen sich mit ''gunzip'' auspacken, und von ''gzip'' erzeugte Dateien liest diese Unit. Der Aufwand steckt nicht im Komprimieren, sondern in drei Kleinigkeiten des Formats: * **Die optionalen Kopffelder.** Nach dem Flag-Byte können ''FEXTRA'' (Länge + Daten), ''FNAME'' und ''FCOMMENT'' (nullterminiert) und ''FHCRC'' folgen. Wer sie nicht überspringt, setzt den DEFLATE-Strom an der falschen Stelle an — und merkt es erst, wenn der Trailer nicht passt. * **Der Trailer wird geprüft, nicht nur gelesen.** Eine mitgeführte, aber ungeprüfte Prüfsumme ist schlimmer als gar keine: Sie erweckt den Eindruck, der Inhalt sei abgesichert. Geprüft werden CRC-32 **und** ISIZE — und ''FHCRC'' obendrein, obwohl der RFC dort auch bloßes Überspringen erlaubt. * **Mehrere aneinandergehängte Member** sind zulässig (''cat a.gz b.gz''). Sie werden nacheinander ausgepackt und aneinandergehängt — so verhält sich ''gzip -d'' auch. **Autor:** Andreas Röne\\ **Copyright:** 2024-2026 Andreas Röne → [[lyx_-_programmiersprache:units:zlib|std.zlib]] · [[lyx_-_programmiersprache:units:brotli|std.brotli]] · [[lyx_-_programmiersprache:units:zstd|std.zstd]] · [[lyx_-_programmiersprache:units|Standard Library]] ---- ===== Funktionen ===== ^ Signatur ^ Beschreibung ^ | ''GzipCompressBound(srcLen: int64): int64'' | Obergrenze der Ausgabegröße — so viel muss der Zielpuffer fassen | | ''GzipCompress(src, srcLen, dst, dstMax): int64'' | Packt als ein gzip-Member; liefert die geschriebenen Bytes oder ''GZIP_OVERFLOW'' | | ''GzipDecompress(src, srcLen, dst, dstMax): int64'' | Packt aus; liefert die geschriebenen Bytes, ''GZIP_ERR'' oder ''GZIP_OVERFLOW'' | ^ Konstante ^ Wert ^ Bedeutung ^ | ''GZIP_OK'' | ''0'' | Erfolg | | ''GZIP_ERR'' | ''-1'' | Kein gzip, verstümmelt oder Prüfsumme falsch | | ''GZIP_OVERFLOW'' | ''-2'' | Ausgabepuffer zu klein | import std.io; import std.gzip; fn main(): int64 { var src: pchar := "Hallo Welt Hallo Welt Hallo Welt"c; var bound: int64 := GzipCompressBound(32); var dst: int64 := alloc(bound); var n: int64 := GzipCompress(src as int64, 32, dst, bound); PrintLn(IntToStr(n)); // geschriebene Bytes var back: int64 := alloc(256); var m: int64 := GzipDecompress(dst, n, back, 256); PrintLn(IntToStr(m)); // 32 — wieder die Ausgangslänge return 0; } ---- ===== Was der Container schreibt ===== ''GzipCompress'' schreibt den schlanken Kopf **ohne optionale Felder**: kein Dateiname, kein Kommentar, **kein Zeitstempel**. Nach RFC 1952 §2.3.1.2 genügt einem konformen Kompressor, ''ID1'', ''ID2'', ''CM'', ''CRC32'' und ''ISIZE'' richtig zu setzen und die übrigen Felder auf Vorgabewerten zu lassen. ''MTIME = 0'' heißt im RFC ausdrücklich „kein Zeitstempel vorhanden". Das ist eine bewusste Entscheidung: Ein echter Zeitstempel wäre eine verdeckte Abhängigkeit von der Uhr und machte die Ausgabe **unreproduzierbar** — dieselbe Eingabe ergäbe bei jedem Lauf eine andere Datei. Beim Auspacken werden alle optionalen Felder dagegen gelesen bzw. übersprungen. Ein gesetztes **reserviertes** Flag-Bit führt zu ''GZIP_ERR'': Es könnte ein neues Feld ankündigen, das alles Folgende verschiebt — dann wäre stilles Weiterdekodieren Raten. Anders als ''[[lyx_-_programmiersprache:units:brotli|std.brotli]]'' und ''[[lyx_-_programmiersprache:units:zstd|std.zstd]]'', die nur den Store-Modus schreiben, komprimiert ''GzipCompress'' **wirklich** — über ''DeflateCompressLZ77'' aus ''std.zlib''. 4096 Byte mit vierstelligem Muster ergeben 65 Byte Ausgabe; sehr kurze, unregelmäßige Eingaben können durch Kopf und Trailer (18 Byte) dennoch wachsen. ''FDICT'' gibt es in gzip nicht und ist entsprechend nicht vorgesehen. > **''dstMax'' muss mindestens ''GzipCompressBound(srcLen)'' sein — nicht bloß groß genug für das Ergebnis.** Die Prüfung steht vor dem Komprimieren und vergleicht gegen die Obergrenze: > > GzipCompress(src, 4096, dst, 256) // -> GZIP_OVERFLOW (-2), obwohl 65 Byte gereicht hätten > > Den Zielpuffer also immer mit ''GzipCompressBound'' bemessen (''srcLen + srcLen/8 + 128'') und nach dem Aufruf auf die zurückgegebene Länge zuschneiden. ---- Letzte Aktualisierung: 2026-08-11