Something went wrong. Try again.
Reads and writes the Ogg container format in Zig: pages, packets, grouping and chaining, with a page layer that allocates nothing.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us>// SPDX-License-Identifier: MIT
//! The one check an Ogg page carries.//!//! Each page holds a 32-bit CRC over the whole of itself -- the header with the//! checksum field replaced by zeroes, followed by the body (RFC 3533,//! Section 6, field 7). It is what makes a page "a self-contained entity such//! that the page decode mechanism can recognize, verify, and handle single//! pages at a time", which is in turn what makes resynchronising after//! corruption possible at all.
const std = @import("std");
/// The page checksum: 32 bits, generator polynomial 0x04c11db7, initial value/// zero, neither input nor output reflected, and no final xor. RFC 3533 gives/// only the polynomial; the Xiph framing document spells out the rest as/// "direct algorithm, initial val and final XOR = 0".////// These parameters are not one of the CRC-32s the standard library names, and/// the near misses are worth spelling out, because reaching for one of them is/// the obvious mistake: the polynomial is the familiar one, but every/// catalogued variant using it either reflects input and output/// (CRC-32/ISO-HDLC, which is gzip's and what `std.hash.crc.Crc32` means),/// starts from all ones (CRC-32/BZIP2, CRC-32/MPEG-2), or xors the result/// (CRC-32/CKSUM). Ogg does none of those.////// Note that the bit order runs the other way from the rest of the format:/// every multi-byte field in a page header is little-endian, while the/// checksum over them is computed most significant bit first.pub const Crc32 = std.hash.crc.Crc(u32, .{ .polynomial = 0x04c11db7, .initial = 0x00000000, .reflect_input = false, .reflect_output = false, .xor_output = 0x00000000,});
/// Convenience for the common case of one contiguous run of bytes.pub fn checksum(bytes: []const u8) u32 { var c: Crc32 = .init(); c.update(bytes); return c.final();}
test "the checksum of no bytes at all is zero" { // Which follows from an initial value of zero and no final xor, and is // worth pinning because it is what distinguishes these parameters from // every catalogued CRC-32 sharing the polynomial. try std.testing.expectEqual(@as(u32, 0), checksum(""));}
test "a page libogg framed" { // The first page of src/tests/data/tone.oga, byte for byte, with the four // checksum bytes zeroed as the algorithm requires. The value it has to // come to is the one ffmpeg's Ogg muxer wrote into those bytes, so this // checks the parameters above against an implementation that was not ours. const page = [_]u8{ 0x4f, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x03, 0x45, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x33, 0x7f, 0x46, 0x4c, 0x41, 0x43, 0x01, 0x00, 0x00, 0x01, 0x66, 0x4c, 0x61, 0x43, 0x00, 0x00, 0x00, 0x22, 0x04, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x15, 0x01, 0xf4, 0x00, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }; try std.testing.expectEqual(@as(u32, 0x05d0cddd), checksum(&page));}
test "the checksum is computed over the bytes in the order they appear" { // `update` may be called more than once, which is how a page's header and // its body are covered without copying them into one buffer. var split: Crc32 = .init(); split.update("Ogg"); split.update("S"); try std.testing.expectEqual(checksum("OggS"), split.final());}