42 lines
1.7 KiB
Python
42 lines
1.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Validate a complete MTHD archive before including private HD art in a mac bundle."""
|
|
import pathlib
|
|
import struct
|
|
import sys
|
|
|
|
|
|
def verify(path):
|
|
data = pathlib.Path(path).read_bytes()
|
|
if len(data) < 12 or data[:4] != b'MTHD':
|
|
raise ValueError('invalid MTHD header')
|
|
version, count = struct.unpack_from('<II', data, 4)
|
|
if version != 1 or not 0 < count <= 100000:
|
|
raise ValueError('invalid archive version/count')
|
|
index, entries, names = 12, [], set()
|
|
for _ in range(count):
|
|
if index + 2 > len(data): raise ValueError('truncated index')
|
|
size, = struct.unpack_from('<H', data, index)
|
|
index += 2
|
|
if not 0 < size <= 4096 or index + size + 8 > len(data): raise ValueError('invalid entry')
|
|
name = data[index:index+size].decode('latin1')
|
|
index += size
|
|
offset, length = struct.unpack_from('<II', data, index)
|
|
index += 8
|
|
if name in names or not length or offset + length > len(data): raise ValueError('invalid payload range')
|
|
names.add(name)
|
|
entries.append((name, offset, length))
|
|
for name, offset, length in entries:
|
|
image = data[offset:offset+length]
|
|
if offset < index or length < 33 or image[:8] != b'\x89PNG\r\n\x1a\n' or image[12:16] != b'IHDR':
|
|
raise ValueError('invalid PNG: ' + name)
|
|
w, h = struct.unpack_from('>II', image, 16)
|
|
if not 0 < w <= 4096 or not 0 < h <= 4096: raise ValueError('invalid dimensions: ' + name)
|
|
return count
|
|
|
|
|
|
if __name__ == '__main__':
|
|
try:
|
|
print(f'HD UI archive valid: {verify(sys.argv[1])} textures')
|
|
except (ValueError, OSError, IndexError, struct.error) as error:
|
|
sys.exit(str(error))
|