script: add print-riff-chunks.go
diff --git a/script/print-riff-chunks.go b/script/print-riff-chunks.go new file mode 100644 index 0000000..bf1bc3e --- /dev/null +++ b/script/print-riff-chunks.go
@@ -0,0 +1,105 @@ +// Copyright 2026 The Wuffs Authors. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// https://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// SPDX-License-Identifier: Apache-2.0 OR MIT + +//go:build ignore +// +build ignore + +package main + +// print-riff-chunks.go prints a RIFF's chunks' position and type. +// +// ANI, AVI, WAV and WEBP files are all RIFF files. +// +// Usage: go run print-riff-chunks.go foo.webp + +import ( + "flag" + "fmt" + "os" +) + +func main() { + if err := main1(); err != nil { + os.Stderr.WriteString(err.Error() + "\n") + os.Exit(1) + } +} + +func main1() error { + flag.Parse() + args := flag.Args() + if len(args) != 1 { + return fmt.Errorf("usage: progname filename.riff") + } + src, err := os.ReadFile(args[0]) + if err != nil { + return err + } + + pos := 0 + if len(src) < 12 { + return posError(pos, len(src)) + } else if len(src) > 0x7FFF_FFFF { + return fmt.Errorf("RIFF file is too large") + } + chunkLen := int64(u32le(src[pos+4 : pos+8])) + if int64(len(src)-8) < chunkLen { + return posError(0, len(src)) + } + fmt.Printf("pos = 0x%08X = %10d (+8) len = 0x%08X = %10d RIFF/%s\n", + 0, 0, chunkLen, chunkLen, clean(src[8:12])) + pos = 12 + + for pos < len(src) { + if pos > (len(src) - 8) { + return posError(pos, len(src)) + } + + n := int64(u32le(src[pos+4 : pos+8])) + fmt.Printf("pos = 0x%08X = %10d (+8) len = 0x%08X = %10d %s\n", + pos, pos, n, n, clean(src[pos:pos+4])) + pos += 8 + if (n & 1) != 0 { + n++ + } + + if int64(len(src)-pos) < n { + return posError(pos, len(src)) + } + pos += int(n) + } + + fmt.Printf("pos = 0x%08X = %10d ~~~~\n", + pos, pos) + return nil +} + +func posError(pos int, lenSrc int) error { + return fmt.Errorf("bad RIFF, pos = 0x%08X = %10d, len(src) = 0x%08X = %10d", + pos, pos, lenSrc, lenSrc) +} + +func clean(b []byte) string { + a := [4]byte{} + for i, c := range b[:4] { + if (c < '!') || ('~' < c) { + c = '.' + } + a[i] = c + } + return string(a[:4]) +} + +func u32le(b []byte) uint32 { + return (uint32(b[0]) << 0) | + (uint32(b[1]) << 8) | + (uint32(b[2]) << 16) | + (uint32(b[3]) << 24) +}