|
| 1 | +from typing import IO |
| 2 | +from struct import unpack |
| 3 | + |
| 4 | + |
| 5 | +def read_str(fh: IO[bytes]): |
| 6 | + (n,) = unpack("<I", fh.read(4)) |
| 7 | + return fh.read(n).decode("latin1") |
| 8 | + |
| 9 | + |
| 10 | +def read_wstr(fh: IO[bytes]): |
| 11 | + (n,) = unpack("<I", fh.read(4)) |
| 12 | + return bytes([0xFF - b for b in fh.read(n * 2)]).decode("UTF-16-LE") |
| 13 | + |
| 14 | + |
| 15 | +def read_int(fh: IO[bytes]) -> int: |
| 16 | + (n,) = unpack("<I", fh.read(4)) |
| 17 | + return n |
| 18 | + |
| 19 | + |
| 20 | +def read_entry(fh: IO[bytes], sig=b""): |
| 21 | + if not sig: |
| 22 | + sig = fh.read(4) |
| 23 | + assert sig == b" LBL", f"sig = {sig}" |
| 24 | + flag = read_int(fh) |
| 25 | + key = read_str(fh) |
| 26 | + kind = fh.read(4) |
| 27 | + value = read_wstr(fh) |
| 28 | + if kind == b"WRTS": |
| 29 | + extra = read_str(fh) |
| 30 | + else: |
| 31 | + assert kind == b" RTS" |
| 32 | + extra = None |
| 33 | + |
| 34 | + return key, value, flag, extra |
| 35 | + |
| 36 | + |
| 37 | +def read_head(fh: IO[bytes]) -> bytes: |
| 38 | + def fx( |
| 39 | + identifier: int, |
| 40 | + version: int, |
| 41 | + labels: int, |
| 42 | + extra_values: int, |
| 43 | + flags: int, |
| 44 | + language: int, |
| 45 | + ): |
| 46 | + return dict(locals()) |
| 47 | + |
| 48 | + return fx(*unpack("<IIIIII", fh.read(6 * 4))) |
| 49 | + |
| 50 | + |
| 51 | +def read_entries(fh: IO[bytes]): |
| 52 | + b = fh.read(4) |
| 53 | + while b == b" LBL": |
| 54 | + key, value, flag, extra = read_entry(fh, b) |
| 55 | + yield key, value, flag, extra |
| 56 | + b = fh.read(4) |
| 57 | + |
| 58 | + |
| 59 | +def parse(fh: IO[bytes]): |
| 60 | + head: tuple[int] = unpack("<IIIIII", fh.read(6 * 4)) |
| 61 | + strings = tuple(read_entries(fh)) |
| 62 | + return head, strings |
| 63 | + |
| 64 | + |
| 65 | +def parse_file(csf_file=""): |
| 66 | + with open(csf_file, "br") as rh: |
| 67 | + return parse(rh) |
0 commit comments