std.brotli — Brotli-Kompression und -Dekompression
std.brotli implementiert Brotli nach RFC 7932 vollständig in Lyx — keine externen Abhängigkeiten. Der Dekompressionspfad ist vollständig; der Kompressor arbeitet im Store-Modus (gültige RFC-7932-Streams, keine LZ77-Reduktion).
→ Standard Library · std.zlib · Archiv-Übersicht
Wann Brotli? Brotli ist der Standard-Content-Encoding für HTTP/2 und HTTP/3 — alle modernen Browser unterstützen Content-Encoding: br. Für Text und Web-Assets erzielt Brotli typisch 15–25 % bessere Kompressionsraten als gzip/DEFLATE. std.brotli ist primär für das Dekomprimieren von Brotli-Streams sinnvoll (z.B. HTTP-Responses von CDNs oder APIs). Für das Erzeugen komprimierter Inhalte eignet sich der Store-Kompressor als Platzhalter; echte LZ77-Kompression folgt in einer späteren Version.
Konstanten
| Konstante | Wert | Bedeutung |
|---|---|---|
BROTLI_OK | 0 | Kein Fehler |
BROTLI_ERR | -1 | Allgemeiner Fehler (korrupter Stream, ungültige Parameter) |
BROTLI_OVERFLOW | -2 | Ausgabepuffer zu klein |
Funktionen
| Funktion | Rückgabe | Beschreibung |
|---|---|---|
BrotliDecompress(src, srcLen, dst, dstMax) | int64 Bytes oder BROTLI_ERR | Dekomprimiert einen Brotli-Stream vollständig |
BrotliCompress(src, srcLen, dst, dstMax) | int64 Bytes oder BROTLI_ERR / BROTLI_OVERFLOW | Erzeugt einen gültigen Brotli-Stream (Store-Modus) |
Beide Funktionen arbeiten ohne interne Allokation des Ausgabepuffers — der Aufrufer stellt dst und dstMax bereit.
BrotliDecompress
Dekomprimiert einen vollständigen Brotli-Stream (RFC 7932). Unterstützt alle Kompressionsmodi (stored, LZ77, Huffman-Codes, Kontext-Maps, Block-Types). Schiebefenster bis 16 MB (WBITS 10–24).
import std.brotli;
import std.alloc;
import std.io;
fn BrotliBeispiel(komprimiert: int64, kompLen: int64): void {
// Ausgabepuffer: Brotli-Streams haben kein eingebettetes Größenfeld.
// Wenn die unkomprimierte Größe unbekannt ist, großzügig schätzen.
var dstMax: int64 := kompLen * 10;
var dst: int64 := alloc(dstMax + 1);
var n: int64 := BrotliDecompress(komprimiert, kompLen, dst, dstMax);
if n == BROTLI_ERR then {
PrintLn("Dekomprimierung fehlgeschlagen"c);
free(dst, dstMax + 1);
return;
}
poke8(dst + n, 0);
Print("Dekomprimiert: "c); PrintLn(IntToStr(n)c);
free(dst, dstMax + 1);
}
Bekannte Einschränkung: Static-Dictionary-Transforms (RFC 7932 §8) werden nicht unterstützt. Diese Transforms sind in der Praxis sehr selten — Standard-HTTP-Responses und übliche Brotli-Werkzeuge erzeugen sie nicht.
BrotliCompress
Erzeugt einen RFC-7932-konformen Brotli-Stream im Store-Modus: Alle Daten werden unkomprimiert eingebettet. Der Output ist ein gültiger Brotli-Stream und kann von jedem RFC-7932-Dekompressionsprogramm gelesen werden — er ist aber nicht kleiner als die Eingabe.
Puffergröße: Worst-Case-Overhead berechnet sich als:
benötigt = srcLen + ceil(srcLen / 16 MB) × 5 + 2
Für Eingaben ≤ 16 MB genügt dstMax = srcLen + 7.
import std.brotli;
import std.alloc;
fn BrotliStoreRoundtrip(): void {
var original: pchar := "Hallo Brotli!"c;
var srcLen: int64 := 13;
// Komprimieren (Store-Modus)
var cBuf: int64 := alloc(srcLen + 7);
var cLen: int64 := BrotliCompress(original as int64, srcLen, cBuf, srcLen + 7);
if cLen == BROTLI_ERR then { PrintLn("Komprimierung fehlgeschlagen"c); return; }
if cLen == BROTLI_OVERFLOW then { PrintLn("Puffer zu klein"c); return; }
Print("Komprimiert: "c); PrintLn(IntToStr(cLen)c);
// Dekomprimieren
var dBuf: int64 := alloc(srcLen + 1);
var dLen: int64 := BrotliDecompress(cBuf, cLen, dBuf, srcLen + 1);
poke8(dBuf + dLen, 0);
PrintLn(dBuf as pchar); // → "Hallo Brotli!"
free(cBuf, srcLen + 7);
free(dBuf, srcLen + 1);
}
Ausgabepuffer-Größe schätzen
Brotli-Streams enthalten keine eingebettete unkomprimierte Größe. Für die Dekompression gibt es drei Strategien:
1. Größe bekannt (z.B. aus HTTP Content-Length + separatem Header):
var dst: int64 := alloc(bekannteGroesse + 1);
BrotliDecompress(src, srcLen, dst, bekannteGroesse);
2. Konservativer Faktor (unbekannte Größe):
// Brotli-Kompressionsraten selten > 10:1 für reale Daten
var dstMax: int64 := srcLen * 10;
if dstMax < 65536 then { dstMax := 65536; }
var dst: int64 := alloc(dstMax + 1);
var n: int64 := BrotliDecompress(src, srcLen, dst, dstMax);
if n == BROTLI_ERR then {
// Puffer war möglicherweise zu klein — größer versuchen
}
3. HTTP-Response (empfohlen): Den Content-Length-Header des dekomprimierten Inhalts aus dem HTTP-Response lesen, falls der Server ihn mitsendet.
Vergleich mit std.zlib
| Merkmal | std.brotli | std.zlib |
|---|---|---|
| Standard | RFC 7932 | RFC 1950 / 1951 |
| HTTP-Encoding | br | gzip / deflate |
| Kompressionsrate (Text) | besser (15–25 % vs. gzip) | gut |
| Kompressor | Store-Modus (kein LZ77) | vollständig (LZ77 + Huffman) |
| Dekompressionstempo | vergleichbar | vergleichbar |
| Browser-Support | alle modernen Browser | universell |
| Einsatz in std.zip | nein | ja (Methode 8) |
Für serverseitig erzeugte komprimierte HTTP-Responses (z.B. in einem Lyx-HTTP-Server) ist std.zlib mit dem GZIP-Modus aktuell die bessere Wahl, solange der std.brotli-Kompressor im Store-Modus bleibt.
Speicherverwaltung
Beide Funktionen allokieren keinen Ausgabepuffer — der Aufrufer ist vollständig verantwortlich:
| Puffer | Wer allokiert | Wer gibt frei |
|---|---|---|
src (Eingabe) | Aufrufer | Aufrufer |
dst (Ausgabe) | Aufrufer (mindestens dstMax Bytes) | Aufrufer |
| Interne Arbeitspuffer | BrotliDecompress / BrotliCompress | automatisch beim Return |
Letzte Aktualisierung: 2026-06-13
