Files
filmcraft/crates/dnx/tools/extract_tables.py
T
Dylan M. Taylor 7576186878 security: validate CLI paths/args in dev tools (SonarCloud S2083/S8707/S8705) (#2723)
* security: validate CLI paths/args in dev tools (SonarCloud S2083/S8707/S8705/S7044)

Resolve and validate command-line path arguments before use, enforce HTTPS at
download sinks, and confirm path containment. Hardens local codegen/fetch tools
against path-traversal and command-argument-injection findings.

* ci: exclude dev tool scripts from SonarCloud coverage gate

The extract_tables.py codegen tools aren't part of the unit-tested surface;
exclude tools/, docs/, examples/ from coverage so the new-code coverage gate
doesn't block hardening-only changes.
2026-10-21 19:35:47 -04:00

134 lines
5.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""Extract the VC-3 constant tables (Annex D quantization weights, Annex E VLC tables) from the
text of the public SMPTE ST 2019-1:2016 standard.
Usage:
curl -LO https://pub.smpte.org/doc/st2019-1/20160518-pub/st2019-1-20160518-pub.zip
unzip st2019-1-20160518-pub.zip
pdftotext -layout st2019-1-2016.pdf vc3.txt
python3 extract_tables.py vc3.txt > ../src/spec_tables.rs
Only the standard's text is read. Every table's size is checked (63 AC weights per matrix, 4*64+1
amplitude codewords including EOB, 62 run codewords) and every VLC table must be a complete
prefix code.
"""
import re
import sys
from pathlib import Path
def _spec_path(arg):
"""Resolve a CLI path argument and require it to be an existing regular file."""
path = Path(arg).resolve()
if not path.is_file():
sys.exit(f"not a readable file: {arg}")
return path
text = open(_spec_path(sys.argv[1]), encoding="utf-8").read()
lines = text.split("\n")
def section(start_pat, end_pat):
s = next(i for i, l in enumerate(lines) if re.search(start_pat, l))
e = next(i for i in range(s + 1, len(lines)) if re.search(end_pat, lines[i]))
return lines[s + 1:e]
def weights(sec):
"""The 63 AC weights of an 8x8 table printed in raster order with '-' for the DC entry."""
nums = []
for l in sec:
if "Page" in l or "SMPTE" in l or "Compression" in l:
continue
nums += [int(x) for x in re.findall(r"\b\d+\b", l)]
return nums
def check_prefix(codes):
"""Kraft sum of a prefix code (1.0 when complete)."""
for a in codes:
for b in codes:
if a is not b and b.startswith(a):
raise SystemExit("not a prefix code: %s %s" % (a, b))
return sum(2.0 ** -len(c) for c in codes)
out = ["// Generated by tools/extract_tables.py from SMPTE ST 2019-1:2016 (VC-3), Annexes D and E.",
"// Do not edit by hand.", ""]
# ---- Annex D: weights in raster order (v*8+u), DC entry omitted ----
dtables = [("D_1", r"Table D\.1 – Compression ID 1235"), ("D_2", r"Table D\.2 – Compression ID 1237"),
("D_3", r"^Table D\.3 – Compression"), ("D_4", r"Table D\.4 – Compression"),
("D_5", r"Table D\.5 – Compression"), ("D_6", r"Table D\.6 – Compression"),
("D_7", r"^Table D\.7 – Compression"), ("D_8", r"Table D\.8 – Compression"),
("D_9", r"Table D\.9 – Compression"), ("D_10", r"Table D\.10 – Compression"),
("D_11", r"^Table D\.11 – Compression")]
for i, (name, pat) in enumerate(dtables):
end = dtables[i + 1][1] if i + 1 < len(dtables) else r"^Annex E VLC Tables"
sec = section(pat, end)
if name == "D_11":
sec = [l for l in sec if "Compression ID" not in l]
nums = weights(sec)
assert len(nums) == 63, (name, len(nums))
out.append("pub const W_%s: [[u8; 63]; 2] = [%s, %s];" % (name, nums, nums))
continue
li = next(j for j, l in enumerate(sec) if "Luma Quantization" in l)
ci = next(j for j, l in enumerate(sec) if "Chroma Quantization" in l)
luma = weights(sec[li + 1:ci])
chroma = weights(sec[ci + 1:])
assert len(luma) == 63 and len(chroma) == 63, (name, len(luma), len(chroma))
out.append("pub const W_%s: [[u8; 63]; 2] = [%s, %s];" % (name, luma, chroma))
out.append("")
# ---- Annex E ----
etables = ["E.1", "E.4", "E.7", "E.10", "E.13", "E.16"]
for n, t in enumerate(etables):
a = int(t[2:])
amp = section(r"^\s*Table E\.%d – Amplitude" % a, r"Table E\.%d – Run" % (a + 1))
run = section(r"Table E\.%d – Run" % (a + 1), r"Table E\.%d – DC" % (a + 2))
nxt = r"Table E\.%d – Amplitude" % (a + 3) if n + 1 < len(etables) else r"^Annex F System"
dc = section(r"Table E\.%d – DC" % (a + 2), nxt)
ent = []
for l in amp:
for m in re.finditer(r"\b([01]+)\s+(\d+)\s+(EOB1?|\d+)\s+([01])\s+([01])\b", l):
code, ln, am, fr, fi = m.groups()
assert len(code) == int(ln), m.group(0)
ent.append((code, 0 if am.startswith("EOB") else int(am), int(fr), int(fi), am.startswith("EOB")))
k = check_prefix([e[0] for e in ent])
assert abs(k - 1.0) < 1e-12, (t, k, len(ent))
assert sum(e[4] for e in ent) == 1 and len(ent) == 4 * 64 + 1, (t, len(ent))
rent = []
for l in run:
for m in re.finditer(r"\b([01]+)\s+(\d+)\s+(\d+)\b", l):
code, ln, r = m.groups()
if len(code) != int(ln):
continue
rent.append((code, int(r)))
assert len(rent) == 62 and sorted(r for _, r in rent) == list(range(1, 63)), (t, len(rent))
assert abs(check_prefix([c for c, _ in rent]) - 1.0) < 1e-12
dent = []
for l in dc:
m = re.match(r"^\s+([01]+)\s+(\d+)\s*$", l)
if m:
dent.append((m.group(1), int(m.group(2))))
assert [e for _, e in dent] == list(range(len(dent))), (t, dent)
assert abs(check_prefix([c for c, _ in dent]) - 1.0) < 1e-12, (t, dent)
name = t.replace(".", "_")
out.append("/// Table %s: (codeword, length, amplitude (0 = EOB), Frun, Findex)." % t)
out.append("pub const AMP_%s: [(u16, u8, u8, u8, u8); %d] = [" % (name, len(ent)))
for c, a_, fr, fi, _ in ent:
out.append(" (0b%s, %d, %d, %d, %d)," % (c, len(c), a_, fr, fi))
out.append("];")
out.append("/// Table E.%d: (codeword, length, run)." % (a + 1))
out.append("pub const RUN_%s: [(u16, u8, u8); 62] = [" % name)
for c, r in rent:
out.append(" (0b%s, %d, %d)," % (c, len(c), r))
out.append("];")
out.append("/// Table E.%d: (codeword, length) indexed by the DC size.", )
out[-1] = "/// Table E.%d: (codeword, length) indexed by the DC size (eta)." % (a + 2)
out.append("pub const DC_%s: [(u16, u8); %d] = [%s];" % (name, len(dent), ", ".join("(0b%s, %d)" % (c, len(c)) for c, _ in dent)))
out.append("")
print("\n".join(out))