forked from 1b-agent/opencadstudio-upstream
Bug: The DGN compound-file reader walked FAT chains with a fixed 1,000,000-iteration guard - a step budget, not a byte budget. A self-referential FAT entry (fat[s] = s) burns the whole budget reading the same sector: 4.1 GB per call at 4 KiB sectors. Directory, mini stream and miniFAT chains are alive simultaneously (about 12 GB peak) -> allocator abort while merely selecting the file in the attach dialog. Separately, models() inflated every model directory's streams (512 MB each) with no total, and directory entries can all point at one shared payload - 1.2 GB retained from a 4.3 MB file. Reproduce: 1. Craft a ~1.5 KB CFB (sector shift 9) whose directory start sector's FAT entry points at itself (zeroed FAT sector). 2. ATTACH and pick the file (any listing path parses the CFB). 3. Before: the directory chain grows to 4,000,000 entries from a 1536-byte file, then abort. 4. After: every chain is bounded by the file's own sector count - instant, memory at most the file size. 5. For the models path: a file with 300 model dirs sharing a 4 MB payload inflated to 1,258,291,200 bytes before; now it stops at the file-scaled budget (max(file x 64, 256 MiB)). Fix: chain bounds itself by file bytes / sector size: a chain can only read in-file sectors, and after that many steps it must have repeated one - the walk is deterministic, so a repeat is a cycle that yields nothing new. That is the strongest bound the format allows and it never truncates a legitimate chain (each sector is read at most once). The mini-stream loop uses the same argument over mini.len() / 64. models() checks a file-scaled total budget before inflating each dir; later dirs are dropped (earlier ones still load, name/table discovery degrades gracefully). Tests: the hostile 1.5 KB file keeps all bytes <= file size; the 300-model file stays within budget.