Inhaltsverzeichnis

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