Softanza
StartFrançais
Softanza
I/O, formats, extensibility, media

Files & formats

Safety first: XXE closed by construction; deliberate subsets (flat HTML, zip only, UTF-8, a 64 MB cap).

1 Strong · 6 Solid · 4 Partial · 1 Emerging

Measured against: lxml · libarchive · Folders: base/file(opens in a new tab) · base/archive(opens in a new tab) · base/html(opens in a new tab) · For programmers: this area's reference

the shapes a document takes: a tree for JSON, rows for CSV, nested boxes for XML
the shapes a document takes: a tree for JSON, rows for CSV, nested boxes for XML. drawn on 2026-10-01 by the site's script tools/areas-figurative.ring, run inside the library at commit 0e72e2e2c · the source(opens in a new tab)

Rethought from first principles

What Softanza kept from what works, and what it rethought, as the library wrote it down in its design documents and narrations.

The Softanza wayYou reach a file by what you intend to do with it, and each format is parsed once, in the engine, by a parser whose refusals are part of its safety.

Kept from the best practice

  • XML canonical form is checked byte for byte against libxml2 across ten test vectors, kept as permanent tests. An independent reference judges the code, not its own word. source(opens in a new tab)
  • Reading returns the value, not the raw text: & comes back as &. Callers never decode by hand, so nothing is shown raw or escaped twice. source(opens in a new tab)
  • One class per format, not per source. JSON, CSV, HTML and XML each take text; a file is a source, not a kind, so loading and saving are conveniences. source(opens in a new tab)

Rethought

  • Files are opened by intention, not by mode: FileRead, FileAppend, FileCreate, FileOverwrite, FileUpdate. Each intention can also read, as an open notebook can. source(opens in a new tab)
  • The XML parser refuses any DOCTYPE or ENTITY declaration before parsing. File-reading and memory-bomb attacks are closed by construction, not by a setting someone may forget. source(opens in a new tab)
  • XML paths come in three forms only, matched by local name. A partial XPath would invite queries that silently fail, and prefixes are only local nicknames. source(opens in a new tab)
  • An object-store key is not a file path. Each stored file is named by the SHA-256 of its key, so path traversal cannot be expressed and case-distinct keys stay distinct. source(opens in a new tab)

A competent, safety-first formats module -- engine-backed file I/O, directories (with the Windows non-ASCII listing bug defeated), CSV, JSON, and a namespace-aware XML parser -- whose one genuine standout is XML security: XXE is closed by construction, the parser refusing <!DOCTYPE> and <!ENTITY> outright, which lxml and most XML libraries get wrong by default. Everything else is a deliberate subset: no XPath/XSLT/validation, a flat HTML index, zip-only archives via Haro's minizip, UTF-8 only, and whole-file reads with a 64 MB cap.

What a crafter does with it, and what stands out

  • XXE closed by construction: the parser refuses <!DOCTYPE> and <!ENTITY>, a posture lxml defaults to wrong
  • The Windows non-ASCII directory listing bug defeated (wide-W API to UTF-8)
  • One strict namespace-aware XML parser shared with XML digital signatures (SAML), with exclusive C14N
  • CSV eval() on list-looking cells removed; byte-scan number test ~156x faster than regex-per-cell

What is owed

  • Migrate the stzJson constructor to the fixed UTF-8 parser (shipped but unwired)
  • Streaming and large-file reads past the 64 MB cap; iterparse-style XML/JSON
  • A real archive layer (tar, gzip/zlib); charset detection and non-UTF-8 decoding
  • Multiline CSV, richer HTML (slice 3), XPath, a pathlib-style path surface

The Softanza way, run

What Softanza does differently in this area, shown by code taken from its narrations and guards, and run for this page.

Any document carrying a DOCTYPE or an ENTITY declaration is refused before parsing begins.

Softanza
? StzXmlIsValid("<!DOCTYPE d [<!ENTITY e SYSTEM 'file:///etc/passwd'>]><d/>")
? StzXmlIsValid("<!ENTITY xxe SYSTEM 'file:///etc/passwd'><d/>")
Output
0
0

run on 2026-10-01 21:18 inside the library at commit 0e72e2e2c; taken from base/doc/narrations/stz-xml-the-parser-that-says-no.md(opens in a new tab)

Three path forms, matched by local name, read a document that has a namespace without ever naming it.

Softanza
cXml = '<library xmlns="urn:lib" name="City Library">' +
       '<book isbn="1"><title>Dune</title><year>1965</year></book>' +
       '<book isbn="2"><title>Ubik</title><year>1969</year></book>' +
       '</library>'
? StzXmlRoot(cXml)
? StzXmlGet(cXml, "library/book/title")
? StzXmlGet(cXml, "library/book[2]/title")
? StzXmlGet(cXml, "//year")
Output
library
Dune
Ubik
1965

run on 2026-10-01 21:18 inside the library at commit 0e72e2e2c; taken from base/doc/narrations/stz-xml-the-parser-that-says-no.md(opens in a new tab)

Two keys that differ only by case stay two objects, even on a case-insensitive disk, because each stored file is named by a hash of its key.

Softanza
oB = StzFileBlobStoreQ("uploads")
oB.Save("Photo.JPG", "the original")
oB.Save("photo.jpg", "a different picture")
? oB.NumberOfBlobs()                 # --> 2
? oB.Fetch("Photo.JPG")              # --> the original
? oB.Fetch("photo.jpg")              # --> a different picture
Output
2
the original
a different picture

run on 2026-10-01 21:18 inside the library at commit 0e72e2e2c; taken from base/doc/narrations/stz-service-virtualization-code-first-subscribe-later.md(opens in a new tab)

The articles of this area (4)

The lanes, one by one

Lanes and their notes are quoted as they were read at the source, on Read from the source on 2026-09-16, from a read-only main worktree.

XML security -- XXE closed by construction
Strong
xml.zig refuses any document containing <!DOCTYPE> or <!ENTITY>, a hard failure; guarded: a file:///etc/passwd entity doc returns FALSE, SAML docs parse.xml.zig; XXE guard under test/file
File I/O
Solid
read/write/append/copy/delete/stat engine-backed with a pathIsUsable screen; 64 MB read cap, no streaming, no mmap/seek, Move is copy+delete.file.zig, stzFile
Directory operations
Solid
list/walk/create/delete/count via stz_dir_*; non-ASCII listing fixed with the wide-W API (guarded: Arabic/CJK/Hebrew/emoji names, listed count == engine count).stz_dir_*, stzFolder; non-ASCII guard under test/file
CSV
Solid
csv.zig RFC-4180 quoting, header auto-detect, exact round-trip inference; eval() on cells removed, byte-scan number test ~156x faster; no multiline fields.csv.zig, stzCSV
JSON
Solid
json.zig parse/serialize/pretty; the UTF-8 trap fixed in StzJsonToList, but the stzJson class constructor still calls the old pure-Haro parser; no JSONPath.json.zig, StzJsonToList, JsonFilterFeatures
XML parsing & query
Solid
Strict namespace-aware parser shared with xmldsig.zig/SAML, exclusive C14N, a small local-name path grammar; no XPath, XSLT or DTD/XSD validation.xml.zig, xmldsig.zig, stzXml
File watching
Solid
fswatch.zig snapshots (mtime, size) and diffs to ADD/MOD/DEL; stzFolderWatcher Watch/Drain/Stop; polling-based, no native OS events.fswatch.zig, stzFolderWatcher
HTML parsing & query
Partial
html_dom.zig tokenizer + flat element index with tag/#id/.class selectors, double-decode fix, O(n^2) Find fix; no real DOM tree, no combinators, read-only.html_dom.zig, stzHtml; test/html
Archives & compression
Partial
stzZipFile read/write backed by Haro's native ziplib (minizip), not the engine; compressor.zig only crc32/adler32/RLE; zip only, no tar/gzip/7z.stzZipFile, compressor.zig
Path manipulation
Partial
Engine stz_path_extension/basename/dirname only (both / and \); no join, normalize, relative-to or glob, no path object.stz_path_extension, stz_path_basename, stz_path_dirname
Streaming & large files
Partial
Whole-file read only with a hard 64 MB cap; the one large-file path is JsonFilterFeatures (GeoJSON in-engine); no streaming, iterparse or mmap.JsonFilterFeatures
Encoding / charset
Emerging
None for text: codec.zig is Base64 only, everything UTF-8 by design; no charset detection, no non-UTF-8 decoding (Windows-1252, Shift-JIS).codec.zig