"""Lector mínimo de DB2 WDC3/WDC4 (formato de wowdev.wiki). Solo lo necesario para sacar columnas enteras: registros normales, bitpacked, common data y pallet (indexed). No implementa strings ni arrays de pallet, que no hacen falta para el mapeo item -> displayId. """ import struct FIELD_COMPRESSION_NONE = 0 FIELD_COMPRESSION_BITPACKED = 1 FIELD_COMPRESSION_COMMON_DATA = 2 FIELD_COMPRESSION_BITPACKED_INDEXED = 3 FIELD_COMPRESSION_BITPACKED_INDEXED_ARRAY = 4 FIELD_COMPRESSION_BITPACKED_SIGNED = 5 def _bits(data, bit_offset, bit_size): """Lee bit_size bits a partir de bit_offset (little-endian).""" byte = bit_offset // 8 shift = bit_offset % 8 nbytes = (shift + bit_size + 7) // 8 chunk = data[byte:byte + nbytes] if len(chunk) < nbytes: chunk = chunk + b'\x00' * (nbytes - len(chunk)) val = int.from_bytes(chunk, 'little') return (val >> shift) & ((1 << bit_size) - 1) class DB2: def __init__(self, path): self.d = d = open(path, 'rb').read() self.magic = d[:4].decode() if self.magic not in ('WDC3', 'WDC4'): raise ValueError(f'formato no soportado: {self.magic}') (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, self.flags, self.id_index, self.total_field_count, self.bitpacked_data_offset, self.lookup_column_count, self.field_storage_info_size, self.common_data_size, self.pallet_data_size, self.section_count) = struct.unpack_from('