"""Minimal WDC5 reader for dense modern WoW DB2 tables.""" from __future__ import annotations import copy import struct class WdcError(Exception): pass def _bits_le(data: bytes, bit_offset: int, bit_count: int) -> int: if bit_count == 0: return 0 start = bit_offset // 8 shift = bit_offset & 7 count = (shift + bit_count + 7) // 8 value = int.from_bytes(data[start:start + count], "little") >> shift return value & ((1 << bit_count) - 1) class WDC5: HEADER_OFFSET = 0x88 def __init__(self, data: bytes): self.data = data if data[:4] != b"WDC5" or len(data) < self.HEADER_OFFSET + 68: raise WdcError("not a supported WDC5 table") o = self.HEADER_OFFSET (self.record_count, self.field_count, self.record_size, self.string_table_size, self.table_hash, self.layout_hash, self.min_id, self.max_id, self.locale) = struct.unpack_from("<9I", data, o) self.flags, self.id_index = struct.unpack_from("= self.record_count: raise WdcError("WDC5 relationship record index is out of bounds") self.relationship_by_index[record_index] = foreign_id self.rows[self.row_ids[record_index]]["parent_id"] = foreign_id for i in range(self.copy_table_count): new_id, source_id = struct.unpack_from(" additional: raise WdcError("palette index out of bounds") return struct.unpack_from(" poff + additional: raise WdcError("palette-array index out of bounds") return struct.unpack_from("<%dI" % width, self.pallet, base) raise WdcError("unsupported WDC5 storage type %d" % kind) def string(self, row, field: int) -> str: relative = row["values"][field] start = row["record_offset"] + relative if start < self.strings_offset or start >= self.strings_offset + self.section_string_size: return "" end = self.data.find(b"\0", start, self.strings_offset + self.section_string_size) if end < 0: end = self.strings_offset + self.section_string_size return self.data[start:end].decode("utf-8", errors="replace") @staticmethod def as_float(value: int) -> float: return struct.unpack("