Blog/jokoak_euskaraz/stray/Stray_Euskara_Mod/locres.py
(Deskargatu)
import struct
MAGIC = bytes.fromhex('0e147475674a03fc4a15909dc3377f1b')
def read_fstring(data, off):
l = struct.unpack('<i', data[off:off+4])[0]
off += 4
if l == 0:
return '', off
if l < 0:
raw = data[off:off+(-l)*2]
s = raw.decode('utf-16-le', errors='replace')
return s.rstrip('\x00'), off + (-l)*2
s = data[off:off+l]
return s[:-1].decode('utf-8', errors='replace'), off + l
def parse(data):
assert data[:16] == MAGIC, 'not a locres v3 file'
off = 16
version = data[off]
off += 1
lut_off = struct.unpack('<q', data[off:off+8])[0]
off += 8
entries_count = struct.unpack('<I', data[off:off+4])[0]
off += 4
ns_count = struct.unpack('<I', data[off:off+4])[0]
off += 4
namespaces = []
for _ in range(ns_count):
ns_hash = struct.unpack('<I', data[off:off+4])[0]
off += 4
ns, off = read_fstring(data, off)
key_count = struct.unpack('<I', data[off:off+4])[0]
off += 4
keys = []
for _ in range(key_count):
key_hash = struct.unpack('<I', data[off:off+4])[0]
off += 4
key, off = read_fstring(data, off)
src_hash = struct.unpack('<I', data[off:off+4])[0]
off += 4
lut_index = struct.unpack('<i', data[off:off+4])[0]
off += 4
keys.append((key, key_hash, src_hash, lut_index))
namespaces.append((ns_hash, ns, keys))
end_of_entries = off
assert lut_off == end_of_entries or lut_off >= end_of_entries, (lut_off, end_of_entries)
off = lut_off
lut_count = struct.unpack('<I', data[off:off+4])[0]
off += 4
lut = []
for _ in range(lut_count):
s, off = read_fstring(data, off)
ref = struct.unpack('<i', data[off:off+4])[0]
off += 4
lut.append(s)
return {
'version': version,
'namespaces': namespaces,
'lut': lut,
'entries_count': entries_count,
}
def write_fstring_bytes(s):
if not s:
return b'\x00\x00\x00\x00'
try:
b = s.encode('ascii')
return struct.pack('<i', len(b) + 1) + b + b'\x00'
except UnicodeEncodeError:
b = s.encode('utf-16-le')
return struct.pack('<i', -(len(b)//2 + 1)) + b + b'\x00\x00'
def build(namespaces, lut, ns_hashes=None):
body = bytearray()
body += MAGIC
body += b'\x03' # version
body += b'\x00' * 8 # lut offset placeholder
body += struct.pack('<I', sum(len(ks) for _, ks in namespaces))
body += struct.pack('<I', len(namespaces))
for i, (ns, keys) in enumerate(namespaces):
ns_hash = (ns_hashes[i] if ns_hashes else 0)
body += struct.pack('<I', ns_hash)
body += write_fstring_bytes(ns)
body += struct.pack('<I', len(keys))
for key, key_hash, src_hash, lut_index in keys:
body += struct.pack('<I', key_hash)
body += write_fstring_bytes(key)
body += struct.pack('<I', src_hash)
body += struct.pack('<i', lut_index)
lut_body = bytearray()
lut_body += struct.pack('<I', len(lut))
for s in lut:
lut_body += write_fstring_bytes(s)
lut_body += struct.pack('<i', 1) # refcount
body += lut_body
lut_off = len(body) - len(lut_body)
body[17:25] = struct.pack('<q', lut_off)
return bytes(body)
if __name__ == '__main__':
import sys
for path in sys.argv[1:]:
data = open(path, 'rb').read()
r = parse(data)
print(path)
print(' version:', r['version'], 'entries:', r['entries_count'], 'lut:', len(r['lut']))
for ns_hash, ns, keys in r['namespaces']:
print(' ns:', repr(ns), 'keys:', len(keys))