Base64 nach RFC 4648: Binärdaten als druckbare ASCII-Zeichen. Je drei Eingabebytes werden zu vier Zeichen, das Ergebnis ist rund ein Drittel größer als die Eingabe. Die Unit kann das Standardalphabet und die URL-sichere Variante, dazu Padding-Helfer, HTTP-Basic-Auth und Data-URLs.
→ Standard Library · std.string · std.alloc
Alle Beispiele dieser Seite sind mit lyxc 1.0.21A übersetzt und ausgeführt; die gezeigten Ausgaben sind echte Programmausgaben und mit Pythons base64 gegengeprüft.
Decodeist derzeit nicht abgesichert — für Daten aus fremder Quelle ungeeignet. Zwei Befunde, beide nachgemessen:
*max_output_lenwird nicht ausgewertet. Der Dekoder schreibt so viele Bytes, wie die Eingabe hergibt; ein zu kleiner Zielpuffer führt zum Überlauf in benachbarten Speicher (#1406).
* Ungültige Zeichen werden nicht erkannt. Die Umkehrtabelle markiert sie mit-1, gelesen wird vorzeichenlos — die Prüfungv < 0greift nie, undDecodeliefert Datenmüll statt-1(#1407).
Bis das behoben ist: Eingaben mitIsValidvorprüfen, die Zielpuffergröße ausDecodedLenberechnen und großzügig bemessen.
Keine Funktion dieser Unit legt einen Ausgabepuffer an — jede schreibt in einen Puffer, den der Aufrufer stellt, und hängt ein Nullbyte an. Die Rückgabe ist die Zahl geschriebener Zeichen ohne dieses Nullbyte.
| Für | Größe |
|---|---|
Encode / EncodeBytes | EncodedLen(len) + 1 |
EncodeUrlSafe | EncodedLen(len) + 1 (das Ergebnis ist kürzer, weil kein Padding) |
Decode / DecodeUrlSafe | DecodedLen(len) + 1 |
EncodeBasicAuth | 6 + EncodedLen(user + pass + 1) + 1 |
EncodeDataUrl | 13 + mime + EncodedLen(len) + 1 |
EncodedLenundDecodedLenrechnen ohne Nullbyte.EncodedLen(6)ergibt 8 — der Puffer muss 9 Byte fassen.DecodedLenliefert die obere Schranke (len / 4 × 3); mit Padding sind es ein oder zwei Byte weniger.
Zwei Funktionen legen intern Puffer fester Größe an: EncodeBasicAuth rechnet mit 512 Byte für benutzer:passwort und 1024 Byte für das Ergebnis, EncodeDataUrl mit 4096 Byte für die kodierten Daten. Längere Eingaben laufen über diese internen Grenzen hinaus.
| Signatur | Beschreibung |
|---|---|
Encode(input: pchar, output: pchar): int64 | Kodiert bis zum Nullbyte. Für Binärdaten ungeeignet — ein Nullbyte im Eingang beendet die Kodierung. |
EncodeBytes(input: pchar, input_len: int64, output: pchar): int64 | Kodiert genau input_len Bytes; der Weg für Binärdaten. |
EncodeUrlSafe(input: pchar, output: pchar): int64 | Alphabet mit - und _ statt + und /, ohne Padding. Kodiert ebenfalls bis zum Nullbyte. |
EncodedLen(input_len: int64): int64 | (len + 2) / 3 × 4 — die Länge mit Padding. |
import std.base64;
import std.alloc;
import std.string;
fn main(): int64 {
var buf: int64 := alloc(256);
var out: pchar := buf as pchar;
// RFC-4648-Testvektoren
PrintLn(StrConcat("'' -> ", IntToStr(Encode(""c, out))));
Encode("f"c, out); PrintLn(StrConcat("f -> ", out));
Encode("fo"c, out); PrintLn(StrConcat("fo -> ", out));
Encode("foo"c, out); PrintLn(StrConcat("foo -> ", out));
Encode("foob"c, out); PrintLn(StrConcat("foob -> ", out));
Encode("fooba"c, out); PrintLn(StrConcat("fooba -> ", out));
Encode("foobar"c, out); PrintLn(StrConcat("foobar -> ", out));
// Rueckweg
var back: int64 := alloc(256);
var n: int64 := Decode("Zm9vYmFy"c, back as pchar, 256);
poke8(back + n, 0);
PrintLn(StrConcat(StrConcat("Zm9vYmFy -> ", back as pchar), StrConcat(" (", StrConcat(IntToStr(n), " Byte)"))));
// URL-sichere Variante
EncodeUrlSafe("\xfb\xff\xbf"c, out);
PrintLn(StrConcat("URL-safe (fb ff bf) -> ", out));
Encode("\xfb\xff\xbf"c, out);
PrintLn(StrConcat("Standard (fb ff bf) -> ", out));
return 0;
}
'' -> 0
f -> Zg==
fo -> Zm8=
foo -> Zm9v
foob -> Zm9vYg==
fooba -> Zm9vYmE=
foobar -> Zm9vYmFy
Zm9vYmFy -> foobar (6 Byte)
URL-safe (fb ff bf) -> -_-_
Standard (fb ff bf) -> +/+/
Alle sieben Testvektoren aus RFC 4648 §10 stimmen, ebenso die Alphabet-Umschaltung an den Bytes fb ff bf.
| Signatur | Beschreibung |
|---|---|
Decode(input: pchar, output: pchar, max_output_len: int64): int64 | Dekodiert Standard-Base64. Rückgabe: Zahl der Bytes. Das Ergebnis wird nicht nullterminiert und max_output_len nicht geprüft. |
DecodeUrlSafe(input: pchar, output: pchar, max_output_len: int64): int64 | Dasselbe mit dem URL-sicheren Alphabet. |
DecodedLen(input_len: int64): int64 | len / 4 × 3 — obere Schranke der Bytezahl. |
Der Dekoder arbeitet in Vierergruppen und hält an, sobald weniger als vier Zeichen übrig sind. Eine Eingabe, deren Länge kein Vielfaches von 4 ist, liefert also die Bytes der vollständigen Gruppen und ignoriert den Rest — ohne Fehler. Padding (=) beendet die Verarbeitung sauber.
Der Standard-Dekoder verschluckt URL-sichere Eingaben.Decode("-_-_")liefert drei Bytes statt einer Fehlermeldung — andere Bytes alsDecodeUrlSafe. Wer nicht weiß, welche Variante ankommt, prüft das Alphabet selbst: enthält die Eingabe-oder_, ist es die URL-sichere Form;+oder/die Standardform.
| Signatur | Beschreibung |
|---|---|
IsValidChar(c: int64): bool | Ein Zeichen des Standardalphabets oder =. Kennt - und _ nicht. |
IsValid(input: pchar): bool | Länge ist Vielfaches von 4, alle Zeichen zulässig. Leerer Text gilt als gültig. |
HasValidPadding(input: pchar): bool | Liefert immer true — siehe Kasten. |
import std.base64;
import std.alloc;
import std.string;
fn J(b: bool): pchar { if (b) { return "true"; } return "false"; }
fn main(): int64 {
var out: int64 := alloc(256);
PrintLn(StrConcat("Decode('***='): ", IntToStr(Decode("***="c, out as pchar, 256))));
PrintLn(StrConcat("Decode('-_-_'): ", IntToStr(Decode("-_-_"c, out as pchar, 256))));
PrintLn(StrConcat("DecodeUrlSafe('-_-_'): ", IntToStr(DecodeUrlSafe("-_-_"c, out as pchar, 256))));
PrintLn(StrConcat("IsValid('Zm9vYmFy'): ", J(IsValid("Zm9vYmFy"c))));
PrintLn(StrConcat("IsValid('Zm9v Ymfy'): ", J(IsValid("Zm9v Ymfy"c))));
PrintLn(StrConcat("IsValid('abc'): ", J(IsValid("abc"c))));
PrintLn(StrConcat("IsValid('-_-_'): ", J(IsValid("-_-_"c))));
PrintLn(StrConcat("HasValidPadding('a=b='): ", J(HasValidPadding("a=b="c))));
return 0;
}
Decode('***='): 2
Decode('-_-_'): 3
DecodeUrlSafe('-_-_'): 3
IsValid('Zm9vYmFy'): true
IsValid('Zm9v Ymfy'): false
IsValid('abc'): false
IsValid('-_-_'): false
HasValidPadding('a=b='): true
HasValidPaddingprüft nichts. Alle Verzweigungen der Funktion enden mittrue, das abschließendereturn falseist unerreichbar."a=b="und"===="gelten damit als gültig, obwohl=nur am Ende stehen darf (#1409).IsValidendet mit dieser Prüfung und erbt den Fehler — es prüft faktisch nur Länge und Zeichenvorrat.
Für URL-sicheres Base64 gibt es keine Prüffunktion:IsValidmeldet dortfalse, weil-und_nicht im Standardalphabet stehen.
| Signatur | Beschreibung |
|---|---|
StripPadding(input: pchar, output: pchar): int64 | Entfernt alle =-Zeichen, auch mitten im Text. |
AddPadding(input: pchar, output: pchar): int64 | Füllt auf ein Vielfaches von 4 auf. -1, wenn die Länge modulo 4 gleich 1 ist — dieser Fall ist in Base64 nicht darstellbar. |
Typischer Einsatz: JSON Web Tokens und OAuth-Parameter tragen URL-sicheres Base64 ohne Padding. Vor dem Dekodieren mit einem Standard-Dekoder ergänzt AddPadding die fehlenden Zeichen.
StripPadding('Zm9vYg=='): 6 -> Zm9vYg
AddPadding('Zm9vYg'): 8 -> Zm9vYg==
AddPadding('Zm9vYgX'): 8
| Signatur | Beschreibung |
|---|---|
EncodeBasicAuth(username: pchar, password: pchar, output: pchar): int64 | Erzeugt den vollständigen Header-Wert einschließlich Basic -Präfix. |
DecodeBasicAuth(auth_header: pchar, username: pchar, password: pchar): int64 | Zerlegt ihn wieder; 1 bei Erfolg, 0 bei fehlendem Präfix, ungültiger Kodierung oder fehlendem Doppelpunkt. |
EncodeDataUrl(mime_type: pchar, data: pchar, output: pchar): int64 | Baut data:<mime>;base64,<daten>. Kodiert bis zum Nullbyte — für Binärdaten ungeeignet. |
import std.base64;
import std.alloc;
import std.string;
fn main(): int64 {
// HTTP Basic Auth
var hdr: int64 := alloc(512);
var n: int64 := EncodeBasicAuth("aladdin"c, "opensesame"c, hdr as pchar);
PrintLn(StrConcat(StrConcat("Header (", IntToStr(n)), StrConcat(" Zeichen): ", hdr as pchar)));
var user: int64 := alloc(128);
var pass: int64 := alloc(128);
var ok: int64 := DecodeBasicAuth(hdr as pchar, user as pchar, pass as pchar);
PrintLn(StrConcat(StrConcat("zurueck: ok=", IntToStr(ok)),
StrConcat(" Benutzer=", StrConcat(user as pchar, StrConcat(" Passwort=", pass as pchar)))));
// Ein Header ohne "Basic "-Praefix wird abgewiesen
PrintLn(StrConcat("DecodeBasicAuth('Bearer xyz'): ", IntToStr(DecodeBasicAuth("Bearer xyz"c, user as pchar, pass as pchar))));
// Data-URL
var url: int64 := alloc(512);
var m: int64 := EncodeDataUrl("text/plain"c, "Hallo Lyx"c, url as pchar);
PrintLn(StrConcat("Data-URL: ", url as pchar));
return 0;
}
Header (30 Zeichen): Basic YWxhZGRpbjpvcGVuc2VzYW1l
zurueck: ok=1 Benutzer=aladdin Passwort=opensesame
DecodeBasicAuth('Bearer xyz'): 0
Data-URL: data:text/plain;base64,SGFsbG8gTHl4
Beide Werte stimmen mit dem Beispiel aus RFC 7617 überein.
DecodeBasicAuthprüft nur das Präfix, nicht die Länge der Zielpuffer. Benutzername und Passwort werden ungeprüft in die übergebenen Puffer geschrieben; der interne Dekodierpuffer fasst 512 Byte. Für Header aus dem Netz gilt derselbe Vorbehalt wie fürDecode.
| Konstante | Wert | Bedeutung |
|---|---|---|
ENCODE_STD | 0 | Standardalphabet (+, /, mit Padding) |
ENCODE_URL_SAFE | 1 | URL-sicher (-, _, ohne Padding) |
Beide sind Kennzahlen für eigene Fallunterscheidungen — keine Funktion dieser Unit nimmt sie als Parameter entgegen. Die Variante wählt man über den Funktionsnamen (Encode gegen EncodeUrlSafe).
Decode selbst terminieren. Die Kodierfunktionen hängen ein Nullbyte an, der Dekoder nicht — er liefert Binärdaten. Für die Textausgabe poke8(puffer + n, 0).Encode hört beim ersten Nullbyte auf. Für Binärdaten immer EncodeBytes mit ausdrücklicher Länge nehmen; dasselbe gilt sinngemäß für EncodeUrlSafe und EncodeDataUrl, die beide keine Längenvariante haben.DecodedLen ist eine obere Schranke, kein exaktes Ergebnis — der Rückgabewert von Decode ist maßgeblich.std.base64 erzeugt eine durchgehende Zeile und überliest beim Dekodieren keine Umbrüche — ein \n in der Eingabe ist ein ungültiges Zeichen und wird derzeit als Wert 255 verrechnet.Decode und DecodeUrlSafe legen ihre 128-Byte-Umkehrtabelle bei jedem Aufruf neu an und geben sie nie frei — 1000 Aufrufe kosten 128 000 Byte (#1408).EncodeBasicAuth (512 / 1024 Byte) und EncodeDataUrl (4096 Byte) begrenzen die Eingabelänge, ohne das zu melden.Weiterführend: std.string · std.crypto · std.net.http · Standard Library
Quelle: std/base64.lyx (498 Zeilen) · Autor: Andreas Röne · Copyright: 2024–2025 Andreas Röne
Letzte Aktualisierung: 2026-08-13 — Seite gegen std/base64.lyx neu geschrieben. Der Abschnitt „Externe Funktionen„ mit libc_malloc ist entfallen: Die Bindung wurde mit #1310 entfernt, die Unit nutzt std.alloc. Neu: drei lauffähige Beispiele mit echter Ausgabe (RFC-4648-Testvektoren gegen Python geprüft), Puffergrößen-Tabelle, Fallstricke — und die vier belegten Defekte #1406 (max_output_len ignoriert), #1407 (ungültige Zeichen unerkannt), #1408 (Speicherleck je Aufruf), #1409 (HasValidPadding immer true). Geprüft mit lyxc 1.0.21A.