mirror of
https://github.com/storytold/filmcraft.git
synced 2026-10-24 10:10:05 -06:00
* 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.
95 lines
3.7 KiB
Python
95 lines
3.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Extract the VP8 constant tables from the text of RFC 6386 ("VP8 Data Format and Decoding Guide").
|
|
|
|
Usage:
|
|
curl -L -o rfc6386.txt https://www.rfc-editor.org/rfc/rfc6386.txt
|
|
python3 extract_tables.py rfc6386.txt > ../src/spec_tables.rs
|
|
|
|
Only sections 1-19 (the format description) are read: the text is cut at section 20 ("Attachment
|
|
One: Reference Decoder Source Code"), so nothing comes from the reference decoder. Every table is
|
|
emitted flat (row-major, as printed) with its element count checked against the declared dimensions.
|
|
"""
|
|
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()
|
|
cut = text.find("\n20. Attachment One")
|
|
if cut < 0:
|
|
sys.exit("section 20 not found")
|
|
text = text[:cut]
|
|
# page breaks: footer / header lines and form feeds
|
|
text = "\n".join(l for l in text.split("\n") if not l.startswith("Bankoski") and not l.startswith("RFC 6386 ") and "\f" not in l)
|
|
|
|
|
|
def table(name, count, occurrence=-1):
|
|
"""Integers of the table `name ... = { ... }` (by default the last definition in the text)."""
|
|
found = []
|
|
# a definition: `name [dim] [dim] ... = {` (uses of the table never have `= {` after the brackets)
|
|
for m in re.finditer(r"\b%s\s*(?:\[[^\]\n]*\]\s*)+=\s*\{" % re.escape(name), text):
|
|
brace = m.end() - 1
|
|
depth = 0
|
|
i = brace
|
|
while True:
|
|
ch = text[i]
|
|
if ch == "{":
|
|
depth += 1
|
|
elif ch == "}":
|
|
depth -= 1
|
|
if depth == 0:
|
|
break
|
|
i += 1
|
|
body = re.sub(r"/\*.*?\*/", "", text[brace:i], flags=re.S)
|
|
body = re.sub(r"//[^\n]*", "", body)
|
|
found.append([int(v) for v in re.findall(r"-?\d+", body)])
|
|
if not found:
|
|
sys.exit("table %s not found" % name)
|
|
vals = found[occurrence]
|
|
if len(vals) != count:
|
|
sys.exit("table %s: %d values, expected %d" % (name, len(vals), count))
|
|
return vals
|
|
|
|
|
|
TABLES = [
|
|
# (spec name, rust name, rust type, count)
|
|
("coeff_update_probs", "COEFF_UPDATE_PROBS", "u8", 4 * 8 * 3 * 11),
|
|
("default_coeff_probs", "DEFAULT_COEFF_PROBS", "u8", 4 * 8 * 3 * 11),
|
|
("kf_bmode_prob", "KF_BMODE_PROBS", "u8", 10 * 10 * 9),
|
|
("dc_qlookup", "DC_QLOOKUP", "u16", 128),
|
|
("ac_qlookup", "AC_QLOOKUP", "u16", 128),
|
|
("vp8_mode_contexts", "MODE_CONTEXTS", "u8", 6 * 4),
|
|
("sub_mv_ref_prob", "SUB_MV_REF_PROBS", "u8", 5 * 3),
|
|
("vp8_mv_update_probs", "MV_UPDATE_PROBS", "u8", 2 * 19),
|
|
("default_mv_context", "DEFAULT_MV_PROBS", "u8", 2 * 19),
|
|
("bmode_prob", "BMODE_PROBS", "u8", 9),
|
|
("coeff_bands", "COEFF_BANDS", "u8", 16),
|
|
("kf_ymode_prob", "KF_YMODE_PROBS", "u8", 4),
|
|
("kf_uv_mode_prob", "KF_UV_MODE_PROBS", "u8", 3),
|
|
("ymode_prob", "YMODE_PROBS", "u8", 4),
|
|
("uv_mode_prob", "UV_MODE_PROBS", "u8", 3),
|
|
("mvpartition_probs", "MVPARTITION_PROBS", "u8", 3),
|
|
("BilinearFilters", "BILINEAR_FILTERS", "i32", 8 * 6),
|
|
("filters", "SIXTAP_FILTERS", "i32", 8 * 6),
|
|
]
|
|
|
|
print("// Generated by tools/extract_tables.py from the text of RFC 6386 (sections 1-19). Do not edit.")
|
|
print("// Every table is flat, row-major, in the order the specification prints it.")
|
|
print()
|
|
for spec, rust, ty, count in TABLES:
|
|
vals = table(spec, count)
|
|
print("/// `%s` (RFC 6386), %d entries." % (spec, count))
|
|
print("pub const %s: [%s; %d] = [" % (rust, ty, count))
|
|
for i in range(0, count, 16):
|
|
print(" " + ", ".join(str(v) for v in vals[i:i + 16]) + ",")
|
|
print("];")
|
|
print()
|