"""Bounded AVI metadata reader for native TC260 AIGC labels. TC260-PG-20257A stores the label in an AVI ``LIST/INFO`` chunk whose child chunk ID is ``AIGC`` and whose value is the normative JSON object. The walker seeks over media chunks and reads only bounded metadata values. """ from __future__ import annotations from typing import TYPE_CHECKING, BinaryIO if TYPE_CHECKING: from pathlib import Path from remove_ai_watermarks.metadata import MAX_TC260_VALUE_BYTES, parse_tc260_aigc_json def _info_payloads( stream: BinaryIO, start: int, end: int, ) -> tuple[bytes, ...]: found: list[bytes] = [] position = start while position + 8 <= end: stream.seek(position) chunk_id = stream.read(4) size_raw = stream.read(4) if len(chunk_id) != 4 or len(size_raw) != 4: break size = int.from_bytes(size_raw, "little") payload_start = position + 8 payload_end = payload_start + size if payload_end > end: break if chunk_id == b"AIGC" and size <= MAX_TC260_VALUE_BYTES: value = stream.read(size) if len(value) == size and parse_tc260_aigc_json(value) is not None: found.append(value.rstrip(b"\x00 ")) position = payload_end + (size & 1) return tuple(found) def tc260_aigc_payloads(path: str | Path) -> tuple[bytes, ...]: """Read validated TC260 values from an AVI ``LIST/INFO/AIGC`` chunk.""" found: list[bytes] = [] try: with open(path, "rb") as stream: header = stream.read(12) if len(header) != 12 or header[:4] != b"RIFF" or header[8:12] != b"AVI ": return () stream.seek(0, 2) file_size = stream.tell() declared_end = min(8 + int.from_bytes(header[4:8], "little"), file_size) position = 12 while position + 8 <= declared_end: stream.seek(position) chunk_id = stream.read(4) size_raw = stream.read(4) if len(chunk_id) != 4 or len(size_raw) != 4: break size = int.from_bytes(size_raw, "little") payload_start = position + 8 payload_end = payload_start + size if payload_end > declared_end: break if chunk_id == b"LIST" and size >= 4: list_type = stream.read(4) if list_type == b"INFO": found.extend(_info_payloads(stream, payload_start + 4, payload_end)) position = payload_end + (size & 1) except OSError: return () return tuple(found)