std.iso — ISO 9660-Images lesen und schreiben

std.iso liest und schreibt ISO 9660-Images (Level 1) ohne externe Abhängigkeiten. Der Reader traversiert den vollständigen Verzeichnisbaum per BFS und gibt vollständige Pfade zurück (subdir/DATEI.TXT). Der Writer erzeugt ein gültiges bootfähiges ISO-Image mit flachem Root-Verzeichnis.

Archiv-Übersicht · std.zip · std.tar · Guide: ISO-Abbilder · Standard Library

Alle Beispiele dieser Seite sind mit lyxc 1.0.21A übersetzt und ausgeführt; die gezeigten Ausgaben sind echte Programmausgaben.

Image-Layout (festes Schema):

Sektor  0–15  System Area (leer)
Sektor    16  PVD — Primary Volume Descriptor  (Volume-ID: "LYXISO")
Sektor    17  VDST — Volume Descriptor Set Terminator
Sektor 18–19  Path Table (L-Type + M-Type)
Sektor    20  Root-Verzeichnis
Sektor   21+  Dateidaten

Einschränkungen:

  • Sektorgröße: 2048 Bytes (ISO 9660 Standard)
  • Max. 4096 Dateieinträge, max. 256 Verzeichnisse (Lesen)
  • Writer: nur flaches Root-Verzeichnis — keine Unterverzeichnisse
  • Dateinamen (Writer): max. 36 Zeichen, nur A–Z 0–9 _ . — ungültige Zeichen werden zu _, Kleinbuchstaben zu Großbuchstaben
  • Kein Joliet, kein Rock Ridge, kein El Torito Boot-Record

Konstanten

Konstante Wert Bedeutung
ISO_SECTOR 2048 Sektorgröße in Bytes
ISO_MAX_ENTRIES 4096 Maximale Dateieinträge pro Image
ISO_MAX_DIRS 256 Maximale Verzeichnisse (BFS-Queue beim Lesen)
ISO_MAX_PATH 512 Maximale Pfadlänge in Bytes
ISO_ERR_OK 0 Kein Fehler
ISO_ERR_NOTISO 1 Keine gültige ISO 9660-Datei (PVD-Signatur fehlt)
ISO_ERR_IO 2 I/O-Fehler beim Lesen oder Schreiben
ISO_ERR_CORRUPT 3 Image beschädigt
ISO_ERR_FULL 4 ISO_MAX_ENTRIES erreicht
ISO_ERR_NAMETOOLONG 5 Dateiname > 36 Zeichen oder leer

Lesen (IsoReader)

Funktion Rückgabe Beschreibung
IsoOpen(path) int64 Handle oder 0 Öffnet ISO-Image, traversiert vollständigen Verzeichnisbaum (BFS)
IsoClose(handle) void Gibt Handle und alle Ressourcen frei
IsoCount(handle) int64 Anzahl der Dateieinträge (keine Verzeichnisse)
IsoName(handle, idx) int64 pchar Vollständiger Pfad des idx-ten Eintrags (interner Puffer — nicht free'n)
IsoSize(handle, idx) int64 Dateigröße in Bytes
IsoRead(handle, idx, outBuf, maxLen) int64 Bytes oder -1 Liest Dateiinhalt in outBuf
IsoFind(handle, name) int64 Index oder -1 Sucht Eintrag nach exaktem Pfad. Der Index folgt der Reihenfolge im Abbild, nicht der Anlegereihenfolge — die Verzeichniseinträge stehen nach ISO 9660 sortiert, DATEN.BIN also vor README.TXT

Der Reader gibt vollständige Pfade zurück, inklusive Verzeichnisnamen: BOOT/GRUB/GRUB.CFG oder DATA/LOG.TXT. Verzeichniseinträge selbst erscheinen nicht in der Liste — nur reguläre Dateien.

import std.iso;
import std.alloc;
import std.string;

fn main(): int64 {
    var w: int64 := IsoWriterNew();
    IsoWriterAdd(w, "README.TXT"c, "ISO 9660 aus Lyx"c as int64, 16);
    IsoWriterAdd(w, "DATEN.BIN"c, "0123456789"c as int64, 10);
    var rc: int64 := IsoWriterSave(w, "/tmp/lyx_test.iso"c);
    IsoWriterFree(w);
    PrintLn(StrConcat("Save rc (0 = ok): ", IntToStr(rc)));

    var h: int64 := IsoOpen("/tmp/lyx_test.iso"c);
    if (h == 0) { PrintLn("IsoOpen fehlgeschlagen"); return 1; }
    PrintLn(StrConcat("Eintraege: ", IntToStr(IsoCount(h))));
    var i: int64 := 0;
    while (i < IsoCount(h)) {
        PrintLn(StrConcat(StrConcat("  ", IsoName(h, i) as pchar),
                StrConcat("  ", IntToStr(IsoSize(h, i)))));
        i := i + 1;
    }
    var idx: int64 := IsoFind(h, "README.TXT"c);
    PrintLn(StrConcat("Find(README.TXT): ", IntToStr(idx)));
    if (idx >= 0) {
        var buf: int64 := alloc(256);
        var n: int64 := IsoRead(h, idx, buf, 256);
        poke8(buf + n, 0);
        PrintLn(StrConcat("Inhalt: ", buf as pchar));
    }
    IsoClose(h);
    return 0;
}

Save rc (0 = ok): 0
Eintraege: 2
  DATEN.BIN  10
  README.TXT  16
Find(README.TXT): 1
Inhalt: ISO 9660 aus Lyx

Das Abbild ist 47 104 Byte groß (23 Sektoren à 2048 Byte) und wird von 7z gelesen:

$ 7z l /tmp/lyx_test.iso
                    .....           16           16  README.TXT
                    .....           10           10  DATEN.BIN


Schreiben (IsoWriter)

Funktion Rückgabe Beschreibung
IsoWriterNew() int64 Writer-Handle Erstellt neuen leeren Writer
IsoWriterAdd(w, name, data, dataLen) int64 Fehlercode Fügt Datei hinzu; Name wird automatisch normalisiert
IsoWriterSave(w, path) int64 Fehlercode Schreibt vollständiges ISO 9660-Image
IsoWriterFree(w) void Gibt Writer frei (nicht die data-Puffer — diese gehören dem Aufrufer)

IsoWriterAdd normalisiert den Dateinamen automatisch: Kleinbuchstaben → Großbuchstaben, ungültige Zeichen → _. Das Version-Suffix ;1 wird beim Schreiben angehängt. Beim Lesen entfernt der Reader es automatisch — IsoName gibt Namen ohne ;1 zurück.

Hinweis zu data-Puffern: IsoWriterAdd kopiert die Daten nicht — es speichert nur den Zeiger. Die Puffer müssen bis zum Aufruf von IsoWriterSave gültig bleiben. IsoWriterFree gibt nur die Name-Strings frei, nicht die data-Zeiger.


Dateinamen-Normalisierung

ISO 9660 Level 1 kennt nur einen kleinen Zeichenvorrat: AZ, 09, _ und den Punkt. IsoWriterAdd nimmt den Namen unverändert entgegen — normalisiert wird erst beim Schreiben:

Übergeben Im Abbild
README.TXT README.TXT
readme.txt README.TXT
boot-config.cfg BOOT_CONFIG.CFG
mein datei.bin MEIN_DATEI.BIN
EinLangerName.txt EINLANGERNAME.TXT
unterordner/a.txt UNTERORDNER_A.TXT

Nachgemessen mit lyxc 1.0.21A: Kleinbuchstaben werden großgeschrieben, jedes andere unzulässige Zeichen wird zu _.

 
Der Schrägstrich ist keine Ausnahme. unterordner/a.txt erzeugt kein Unterverzeichnis, sondern eine Datei namens UNTERORDNER_A.TXT im Wurzelverzeichnis. Der Writer legt ausschließlich flache Abbilder an; wer eine Verzeichnisstruktur braucht, kommt mit dieser Unit nicht weiter. Der Reader dagegen kennt Unterverzeichnisse und liefert vollständige Pfade.

Die 8.3-Regel von Level 1 wird beim Schreiben ebenfalls nicht erzwungen: EINLANGERNAME.TXT (13 Zeichen vor dem Punkt) landet unverändert im Abbild. Lesegeräte, die streng nach Level 1 arbeiten, könnten den Namen abweisen.

Speicherverwaltung

Handle Freigabe
IsoOpen → Reader-Handle IsoClose(handle)
IsoWriterNew → Writer-Handle IsoWriterFree(w)
IsoName → interner Puffer nicht free'n — gehört dem Handle
outBuf in IsoRead Aufrufer allokiert, Aufrufer gibt frei
data-Zeiger in IsoWriterAdd Aufrufer verwaltet — bis IsoWriterSave gültig halten

Letzte Aktualisierung: 2026-08-13 — Beispiele lauffähig gemacht, ausgeführt und mit 7z gegengelesen (lyxc 1.0.21A); Namens-Normalisierung nachgemessen — der Schrägstrich erzeugt kein Unterverzeichnis, die 8.3-Regel wird beim Schreiben nicht erzwungen.

Codebeispiele geprüft: gegen lyxc 1.2.5C übersetzt (Prüflauf 2026-09-08 über die gesamte Doku: 574 Vollprogramme, 0 echte Fehler; zusätzlich 5159 Aufrufe gegen die pub fn-Signaturen in aurum/std gehalten, 0 Abweichungen).

Letzte Aktualisierung: 2026-08-30 — Beispielausgabe gegen lyxc 1.1.14A nachgezogen: die Einträge kommen sortiert zurück (DATEN.BIN vor README.TXT), IsoFind(README.TXT) liefert deshalb 1 statt 0.