- Zig 100%
|
|
||
|---|---|---|
| src | marked InitError as public | |
| tests | added test files and updated root with public types | |
| .gitignore | initial commit with project boilerplate | |
| build.zig | removed unused lib artifact from build.zig | |
| build.zig.zon | initial commit with project boilerplate | |
| CHANGELOG.md | fixed date in CHANGELOG | |
| LICENSE | added LICENSE and README | |
| README.md | updated README to reflect 2.0 changes | |
riff
A zero-allocation, stream-oriented parser for structural multimedia containers. It provides a generic, un-opinionated engine to safely traverse and isolate chunk layouts across the RIFF/IFF file ecosystem without loading entire payloads into memory.
Features
- Zero Allocation: Operates entirely on stream cursors and user-provided stack/heap buffers.
- Format Agnostic: Treats layout symmetrically across Big-Endian and Little-Endian boundaries.
- Clean Domain Separation: Focuses exclusively on file structure layout; interpreting data schemas (like audio decoding or text metadata parsing) is completely deferred to your application logic.
Supported Container Formats
The library handles all structural variations of the classic Interchange File Format (IFF) architecture:
| Format / Profile | Endianness | Common Target Extensions |
|---|---|---|
| RIFF | Little-Endian | .wav, .avi, .webp |
| RIFX | Big-Endian | .wav (Big-Endian variant) |
| RF64 | Little-Endian | .wav (EBU standard for files > 4GB) |
| FORM | Big-Endian | .aif, .aiff, .iff |
| WAVE64 | Little-Endian | .w64 (Sony standard for files > 4GB) |
Installation
Add riff to your build.zig.zon dependencies:
.dependencies=.{.riff=.{.url="https://codeberg.org/audiophile/riff/archive/v2.0.0.tar.gz",// .hash = "...",},},Expose the module in your build.zig:
constriff=b.dependency("riff",.{.target=target,.optimize=optimize,});exe.root_module.addImport("riff",riff.module("riff"));Quick Start
The core workflow involves initializing a Demuxer on an active stream, iterating through top-level chunks, and cleanly spawning a sub-isolated List type when a nested collection container is encountered.
conststd=@import("std");constriff=@import("riff");pubfnmain(init:std.process.Init)!void{// Boilerplate to open a file and initialize/cleanup its readerconstio=init.io;constcwd=std.Io.Dir.cwd();constfile=trycwd.openFile(io,"filename.wav",.{});deferfile.close(io);varfile_buffer:[4096]u8=undefined;varreader=file.reader(io,&file_buffer);// Initialize the demuxer to read the chunks of the containervarbuffer:[4096]u8=undefined;vardemuxer=tryriff.Demuxer.init(&reader.interface,&buffer);// Iterate the chunks of the containerwhile(trydemuxer.next())|chunk|{// Print child chunkstd.debug.print("{f}\n",.{chunk.id});// Process chunkvarlimited:Reader.Limited=chunk.payload(reader,&.{});// TODO: Process chunk payload// Ensure chunk is fully consumed, leaving reader aligned to next chunk_=trylimited.interface.discardRemaining();tryreader.discardAll(chunk.padding);}}API Reference
Demuxer
The top-level stream coordinator. It reads the file header to establish the byte-ordering flavor and acts as a layout engine over the root chunks.
pub fn init(reader: *std.Io.Reader, buffer: []u8) !Demuxer
Initializes the parser from any activestd.Io.Readerinterface. Parses the root magic header (RIFF,FORM, etc.) to self-configure.pub fn next(self: *Demuxer) !?Chunk
Advances the stream cursor to the next valid chunk header. Returnsnullwhen the stream is exhausted.
License
This project is licensed under the MIT License.