====== std.buffer — Byte-Puffer ====== → [[lyx_-_programmiersprache:units|Zurück zur Unit-Übersicht]] 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'' 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]]. ===== 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 [[lyx_-_programmiersprache:units:base64|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 ===== * [[lyx_-_programmiersprache:units:base64|std.base64]] — die eigentliche Base64-Kodierung * [[lyx_-_programmiersprache:units:alloc|std.alloc]] — Puffer beschaffen und freigeben * [[lyx_-_programmiersprache:units:pack|std.pack]] — Zahlen und Strings strukturiert in Puffer schreiben * [[lyx_-_programmiersprache:units:string|std.string]] — Funktionen für nullterminierte Zeichenketten