std.buffer — Byte-Puffer
Operationen auf rohen Speicherbereichen: kopieren, füllen, umkehren, vergleichen, suchen, in Hex umwandeln und zurück. Die Unit allokiert nichts — jeder Puffer kommt vom Aufrufer, jede Funktion bekommt die Länge mitgeteilt.
Genau daraus folgt ihre wichtigste Eigenschaft: sie ist binärsicher. Nullbytes mitten in den Daten beenden nichts, Werte über 127 werden unverändert durchgereicht.
Einsatzbereiche: Protokollrahmen, Binärformate, Zwischenschicht für Netzwerk- und Krypto-Units.
Autor: Andreas Röne
Copyright: 2024–2025 Andreas Röne
Quelle: std/buffer.lyx
<WRAP info> Diese Unit ist vollständig geprüft und arbeitet fehlerfrei — einschließlich des Hex-Rundlaufs über alle Bytewerte von 0 bis 255 und der Suche in Daten mit eingebetteten Nullbytes. Zu beachten sind lediglich die Aufrufkonventionen unter Worauf zu achten ist. </WRAP>
Import
import std.buffer;
Konstanten
| Name | Wert | Bedeutung |
|---|---|---|
DEFAULT_BUFFER_CAPACITY | 256 | Vorschlag für eine Anfangsgröße |
MIN_BUFFER_CAPACITY | 16 | Vorschlag für die kleinste sinnvolle Größe |
GROWTH_FACTOR | 2 | Faktor, mit dem BufferCalculateCapacity vergrößert |
Die ersten beiden sind reine Empfehlungen — keine Funktion der Unit verwendet sie.
Funktionen
Vergleichen und Suchen
| Signatur | Beschreibung |
|---|---|
BufferEquals(buf1: pchar, len1: int64, buf2: pchar, len2: int64): bool | Byteweiser Vergleich; unterschiedliche Längen ergeben sofort false |
BufferFind(haystack: pchar, hlen: int64, needle: pchar, nlen: int64): int64 | Position des ersten Vorkommens, sonst -1 |
BufferFind liefert auch dann -1, wenn die Nadel leer ist (nlen == 0) oder länger als der Heuhaufen — nicht 0, wie es manche Textsuchen tun.
Verändern
| Signatur | Beschreibung |
|---|---|
BufferCopy(dest: pchar, src: pchar, len: int64): int64 | Kopiert len Bytes, liefert len |
BufferFill(buf: pchar, len: int64, byte: int64): void | Füllt len Bytes mit einem Wert |
BufferReverse(buf: pchar, len: int64): void | Dreht die Bytefolge an Ort und Stelle um |
BufferAppendString(buf: pchar, buf_len: int64, str: pchar, max_out: int64): int64 | Hängt einen nullterminierten String an; liefert die neue Länge oder -1, wenn der Platz nicht reicht |
BufferToString(buf: pchar, len: int64, output: pchar): int64 | Kopiert len Bytes nach output und terminiert dort mit einem Nullbyte |
BufferCopy setzt voraus, dass sich Quelle und Ziel nicht überlappen — es wird von vorn nach hinten kopiert.
Hex
| Signatur | Beschreibung |
|---|---|
ByteToHex(byte: int64, output: pchar): int64 | Schreibt zwei Großbuchstaben-Hexziffern, liefert 2. Terminiert nicht |
BufferToHex(input: pchar, len: int64, output: pchar): int64 | Wandelt len Bytes in 2·len Hexzeichen und terminiert |
HexToBuffer(input: pchar, output: pchar): int64 | Liest einen nullterminierten Hexstring; liefert die Bytezahl oder -1 |
HexToBuffer akzeptiert Groß- und Kleinschreibung und meldet -1 bei ungerader Länge oder Zeichen außerhalb von 0–9/A–F/a–f. Ein leerer String ergibt 0.
Kapazität und Größenrechner
| Signatur | Beschreibung |
|---|---|
BufferCalculateCapacity(current, needed: int64): int64 | Reicht current, bleibt es dabei; sonst wird verdoppelt, mindestens aber auf needed |
Base64EncodedLen(input_len: int64): int64 | Zeichenzahl einer Base64-Kodierung mit Auffüllzeichen |
Base64DecodedLen(input_len: int64): int64 | Obergrenze der Bytezahl beim Dekodieren |
Die beiden Base64-Rechner geben nur Größen zurück; die Kodierung selbst liegt in std.base64, das mit EncodedLen eine namensgleiche Funktion mitbringt. Beide liefern dieselben Werte — geprüft für Eingabelängen 1 bis 8 gegen die tatsächliche Ausgabe von EncodeBytes.
Beispiel
import std.buffer;
import std.alloc;
fn main(): int64 {
// Binaerdaten mit Nullbytes und Werten ueber 127
var bin: int64 := alloc(8);
poke8(bin, 0); poke8(bin+1, 15); poke8(bin+2, 16); poke8(bin+3, 127);
poke8(bin+4, 128); poke8(bin+5, 200); poke8(bin+6, 254); poke8(bin+7, 255);
// Als Hex ausgeben
var hex: int64 := alloc(32);
var n: int64 := BufferToHex(bin as pchar, 8, hex as pchar);
PrintLn("BufferToHex: ", IntToStr(n), " Zeichen -> ", hex as pchar);
// und wieder zurueck
var zurueck: int64 := alloc(16);
var m: int64 := HexToBuffer(hex as pchar, zurueck as pchar);
PrintLn("HexToBuffer: ", IntToStr(m), " Bytes, identisch? ",
IntToStr(BufferEquals(bin as pchar, 8, zurueck as pchar, 8) as int64));
// Suchen und Vergleichen arbeiten laengenbasiert, Nullbytes stoeren nicht
var muster: int64 := alloc(4);
poke8(muster, 128); poke8(muster+1, 200);
PrintLn("Find(Muster 128 200) = ", IntToStr(BufferFind(bin as pchar, 8, muster as pchar, 2)));
// Textpuffer zusammensetzen
var buf: int64 := alloc(64);
var len: int64 := BufferCopy(buf as pchar, "Hallo" as pchar, 5);
len := BufferAppendString(buf as pchar, len, " Welt" as pchar, 64);
PrintLn("nach Append: ", IntToStr(len), " Bytes");
var text: int64 := alloc(64);
BufferToString(buf as pchar, len, text as pchar);
PrintLn("als String: '", text as pchar, "'");
// Wachstum planen
PrintLn("CalculateCapacity(256, 300) = ", IntToStr(BufferCalculateCapacity(256, 300)));
PrintLn("CalculateCapacity(256, 5000) = ", IntToStr(BufferCalculateCapacity(256, 5000)));
return 0;
}
Ausgabe:
BufferToHex: 16 Zeichen -> 000F107F80C8FEFF
HexToBuffer: 8 Bytes, identisch? 1
Find(Muster 128 200) = 4
nach Append: 10 Bytes
als String: 'Hallo Welt'
CalculateCapacity(256, 300) = 512
CalculateCapacity(256, 5000) = 5000
Der Hex-Rundlauf umfasst hier bewusst das Nullbyte, die Grenzwerte 127/128 und 255 — alle acht Bytes kommen unverändert zurück.
Worauf zu achten ist
Keine Grenzprüfung
Keine Funktion kennt die Größe der übergebenen Puffer. BufferCopy(dest, src, 1000) schreibt tausend Bytes, gleich wie groß dest ist; BufferToHex braucht 2·len + 1 Bytes im Ziel, BufferToString len + 1. Diese Größen rechnet der Aufrufer aus.
Einzige Ausnahme ist BufferAppendString: dort begrenzt max_out das Ziel.
BufferAppendString terminiert nicht
Die Funktion hängt nur die Zeichen an und gibt die neue Länge zurück. Ein Nullbyte setzt sie nicht — dafür ist BufferToString da:
var len: int64 := BufferCopy(buf as pchar, "Hallo" as pchar, 5);
len := BufferAppendString(buf as pchar, len, " Welt" as pchar, 64);
BufferToString(buf as pchar, len, text as pchar); // erst hier entsteht ein String
Die Platzprüfung lautet buf_len + str_len >= max_out — ein Byte bleibt also für die spätere Nullterminierung frei. Bei max_out = 13 und einem Ergebnis von genau 13 Bytes kommt deshalb -1 zurück.
ByteToHex hinterlässt keinen String
Es schreibt genau zwei Zeichen an den Anfang des Puffers. Was dahinter steht, bleibt stehen:
Puffer vorher 'XXX', ByteToHex(255, puffer) -> 'FFX'
Für einen einzelnen Bytewert als Zeichenkette also selbst terminieren, oder BufferToHex mit len = 1 verwenden.
Überlappende Bereiche
BufferCopy kopiert vorwärts. Überlappen sich Quelle und Ziel so, dass das Ziel hinter der Quelle liegt, werden bereits kopierte Bytes erneut gelesen. Für Verschiebungen innerhalb eines Puffers zuerst in einen Zwischenpuffer kopieren.
Hex ist immer Großschreibung
BufferToHex und ByteToHex geben A–F aus. HexToBuffer liest beide Schreibweisen.
Verwandte Units
- std.base64 — die eigentliche Base64-Kodierung
- std.alloc — Puffer beschaffen und freigeben
- std.pack — Zahlen und Strings strukturiert in Puffer schreiben
- std.string — Funktionen für nullterminierte Zeichenketten
