From ba21977ca9df94f18b365dd5bb06cbbe43d41d52 Mon Sep 17 00:00:00 2001 From: Yossi Date: Tue, 24 Feb 2009 00:16:00 -0800 Subject: Changed parse-brlyt output to match write-brlyt input --- ethyl.py | 23 ++++- parse-brlyt.py | 312 +++++++++++++++++++++++++++++++-------------------------- 2 files changed, 187 insertions(+), 148 deletions(-) diff --git a/ethyl.py b/ethyl.py index 0d283b4..ad128b1 100644 --- a/ethyl.py +++ b/ethyl.py @@ -122,9 +122,10 @@ for (dname, definition) in formats.items(): else: df.append((typ, name, default)) formats[dname] = df, etc, etcn - + # Dumb pretty printer def my_repr(b, start=''): + '''scrap this shit and implement new one eventually''' special = lambda x: type(x) not in (int, str, unicode) if type(b) == dict: if len(filter(special, b.values())) == 0: @@ -135,16 +136,16 @@ def my_repr(b, start=''): rep += ', ' else: f = True - rep += '%s: %s' % (str(a), my_repr(b[a])) + rep += '"%s": %s' % (str(a), my_repr(b[a])) rep += ' }' else: rep = '{\n' for a in sorted(b.keys()): c = b[a] if type(c) in (dict, list): - rep += '%s:\n%s\n' % (str(a), my_repr(c, ' ')) + rep += '"%s":\n%s,\n' % (str(a), my_repr(c, ' ')) else: - rep += '%s: %s\n' % ( str(a), my_repr(c)) + rep += '"%s": %s,\n' % ( str(a), my_repr(c)) rep += '}' elif type(b) in (int, long): rep = hex(b) @@ -158,8 +159,10 @@ def my_repr(b, start=''): else: rep = repr(b) return re.sub(re.compile('^', re.M), start, rep) + def pr_dict(*args): print my_repr(*args) + types = { 'u8': 'B', 'u16': 'H', @@ -176,6 +179,7 @@ types = { 'bool': 'c', 'char': 'c', } + def parse_var(pos, typ, chunk): if not types.has_key(typ): raise Exception('What\'s a %s?' % typ) @@ -189,15 +193,18 @@ def nullterm(str_plus): return str_plus[:z] else: return str_plus + def unnullterm(var, size): if len(var) > size: raise Exception('unnullterm: "%s" too long' % var) return var.ljust(size, '\0') + def untv(name): #assert '\0' not in name lex = len(name) + 16 lex -= lex % 16 return name.ljust(lex, '\0') + def parse_data(chunk, definition, prefix=None, start=0): df, etc, etcn = formats[definition] #print df, repr(definition) @@ -244,10 +251,12 @@ def parse_data(chunk, definition, prefix=None, start=0): ret = ret['_'] return (ret, pos) if etcn else ret + def unparse_var(typ, var): if not types.has_key(typ): raise Exception('What\'s a %s?' % typ) return struct.pack('>' + types[typ], var) + def unparse_data(vars, definition, prefix=None): df, etc, etcn = formats[definition] ret = '' @@ -288,6 +297,7 @@ def unparse_data(vars, definition, prefix=None): for v in var: ret += unparse_var(typ, v) return ret + def iff_to_chunks(z): pos = 0 chunks = [] @@ -300,6 +310,7 @@ def iff_to_chunks(z): pos += length chunks.append((cc, data)) return chunks + def bit_extract(num, start, end=None): if end is None: end = start @@ -307,12 +318,14 @@ def bit_extract(num, start, end=None): ret = (num & mask) >> (31 - end) return ret + def bit_place(num, start, end=None): # Just for sanity if end is None: end = start assert num <= 2**(end - start) return num << (31 - end) + def get_array(chunk, startpos, array_size, item_size, item_type=None): ar = [] pos = startpos @@ -321,6 +334,7 @@ def get_array(chunk, startpos, array_size, item_size, item_type=None): ar.append(get_opt(chunk, pos, True, item_size, item_type)[0]) pos += item_size return ar, pos + def get_opt(chunk, startpos, enabled, size, item_type=None): if not enabled: return None, startpos @@ -356,5 +370,6 @@ def put_opt(var, flags, bit, size, item_type=None): else: raise Exception('unhandled') return ret, flags + def i2f(int): return struct.unpack('>f', struct.pack('>I', int))[0] \ No newline at end of file diff --git a/parse-brlyt.py b/parse-brlyt.py index 44a0da0..4001901 100644 --- a/parse-brlyt.py +++ b/parse-brlyt.py @@ -1,157 +1,181 @@ import sys, struct, re from ethyl import * -if len(sys.argv) != 2: - print 'Usage: python parse-brlyt.py something.brlyt' - sys.exit(1) +def main(): + if len(sys.argv) != 2: + print 'Usage: python parse-brlyt.py something.brlyt' + sys.exit(1) + f = open(sys.argv[1], 'rb') + rlyt = f.read() + f.close() -f = open(sys.argv[1], 'rb') -rlyt = f.read() -f.close() + assert rlyt[0:8] == 'RLYT\xfe\xff\x00\x08' + offs, nel = struct.unpack('>hh', rlyt[0xc:0x10]) + ch = iff_to_chunks(rlyt[offs:]) -assert rlyt[0:8] == 'RLYT\xfe\xff\x00\x08' -offs, nel = struct.unpack('>hh', rlyt[0xc:0x10]) -ch = iff_to_chunks(rlyt[offs:]) + assert len(ch) == nel -assert len(ch) == nel + indentlevel = 0 + for typ, chunk in ch: + print ' ' * indentlevel + open_paren(typ), #+ ' ' + hex(len(chunk)) + vars = None + if typ in ('pic1', 'pan1', 'bnd1', 'wnd1', 'txt1'): + vars, pos = parse_data(chunk, 'pane') + assert chunk[:pos] == unparse_data(vars, 'pane') # for testing + if typ == 'txt1': + vars2, pos = parse_data(chunk[pos:], 'text', '~text') + os = vars2['~text.name_offs'] - 8 + txt = chunk[os:os + vars2['~text.len2']] + vars2['~text.text'] = unicode(txt, 'utf_16_be').rstrip('\x00') + vars2['~text.material'] = materials[vars2['~text.mat_off']] + vars.update(vars2) + #print vars['~text.cnt2'], len(vars2['~text.text']), len(txt), repr(txt) + elif typ == 'pic1': + vars2, pos = parse_data(chunk, 'pic', prefix='~pic', start=pos) + vars2['~pic.material'] = materials[vars2['~pic.mat_off']] + vars2['~pic.texcoords'] = [] + for n in xrange(vars2['~pic.num_texcoords']): + vars2['~pic.texcoords'].append(struct.unpack('>ffffffff', chunk[pos:pos+0x20])) + pos += 0x20 + assert pos == len(chunk) + vars.update(vars2) + elif typ == 'lyt1': + vars = parse_data(chunk, 'lytheader') + elif typ == 'grp1': + vars, pos = parse_data(chunk, 'group') + vars['subs'] = [] + for n in xrange(vars['numsubs']): + vars['subs'].append(nullterm(chunk[pos:pos+16])) + pos += 16 + elif typ in ('txl1', 'fnl1'): + things = {'txl1': 'textures', 'fnl1': 'files'}[typ] + vars, pos = parse_data(chunk, 'numoffs') + vars[things] = [] + pos += vars['offs'] + bpos = pos + del vars['offs'] # unneeded + for n in xrange(vars['num']): + offset, unk = struct.unpack('>II', chunk[pos:pos+8]) + name = nullterm(chunk[offset + bpos:]) + vars[things].append({'name': name, 'unk': unk}) + pos += 8 + if typ == 'txl1': + textures = vars['textures'] + elif typ == 'mat1': + vars, pos = parse_data(chunk, 'numoffs') + vars['materials'] = [] + pos += vars['offs'] + bpos = pos + del vars['offs'] + materials = [] + for n in xrange(vars['num']): + offset, = struct.unpack('>I', chunk[pos:pos+4]) + mat, mpos = parse_data(chunk, 'material', start = offset - 8) + #vars['materials'].append(mat) + flags = mat['flags'] + materials.append(mat['name']) + assert mpos == 0x40 + offset - 8 + + + #print hex(struct.unpack('>I', chunk[mpos:mpos+4])[0]) + + # I believe material is: + # 0x40, followed by + # 4 * flags[28-31], followed by + + + mat['texref'], mpos = get_array(chunk, mpos, bit_extract(flags, 28, 31), 4, 'texref') + + for a in mat['texref']: + a['tex'] = textures[a['tex_offs']]['name'] + + # 0x14 * flags[24-27], followed by + + mat['ua2'], mpos = get_array(chunk, mpos, bit_extract(flags, 24, 27), 0x14, 'ua2') + + # 4*flags[20-23], followed by + + mat['ua3'], mpos = get_array(chunk, mpos, bit_extract(flags, 20, 23), 4, '4b') + + # Changing ua3 things + # 1st --> disappears. + # 2nd --> no visible effect. + # 3rd --> disappears. + # 4th --> no visible effect. + + # 4 * flags[6] + + mat['ua4'], mpos = get_opt(chunk, mpos, bit_extract(flags, 6), 4, '4b') + + # 4 * flags[4] + + mat['ua5'], mpos = get_opt(chunk, mpos, bit_extract(flags, 4), 4, '4b') + + # 4 * flags[19] + + mat['ua6'], mpos = get_opt(chunk, mpos, bit_extract(flags, 19), 4, '4b') + + # 0x14 * flags[17-18] + + mat['ua7'], mpos = get_array(chunk, mpos, bit_extract(flags, 17, 18), 0x14, 'ua7') + + # 4 * flags[14-16] + + mat['ua8'], mpos = get_array(chunk, mpos, bit_extract(flags, 14, 16), 4, '4b') + + # 0x10 * flags[9-13] + + mat['ua9'], mpos = get_array(chunk, mpos, bit_extract(flags, 9, 13), 0x10, '10b') + + # 4 * flags[8], these are bytes btw + + mat['uaa'], mpos = get_opt(chunk, mpos, bit_extract(flags, 8), 4, '4b') + + # 4 * flags[7] + + mat['uab'], mpos = get_opt(chunk, mpos, bit_extract(flags, 7), 4, '4b') -indent = 0 -for typ, chunk in ch: - print ' ' * indent + typ + ' ' + hex(len(chunk)) - vars = None - if typ in ('pic1', 'pan1', 'bnd1', 'wnd1', 'txt1'): - vars, pos = parse_data(chunk, 'pane') - assert chunk[:pos] == unparse_data(vars, 'pane') # for testing - if typ == 'txt1': - vars2, pos = parse_data(chunk[pos:], 'text', '~text') - os = vars2['~text.name_offs'] - 8 - txt = chunk[os:os + vars2['~text.len2']] - vars2['~text.text'] = unicode(txt, 'utf_16_be').rstrip('\x00') - vars2['~text.material'] = materials[vars2['~text.mat_off']] - vars.update(vars2) - #print vars['~text.cnt2'], len(vars2['~text.text']), len(txt), repr(txt) - elif typ == 'pic1': - vars2, pos = parse_data(chunk, 'pic', prefix='~pic', start=pos) - vars2['~pic.material'] = materials[vars2['~pic.mat_off']] - vars2['~pic.texcoords'] = [] - for n in xrange(vars2['~pic.num_texcoords']): - vars2['~pic.texcoords'].append(struct.unpack('>ffffffff', chunk[pos:pos+0x20])) - pos += 0x20 - assert pos == len(chunk) - vars.update(vars2) - elif typ == 'lyt1': - vars = parse_data(chunk, 'lytheader') - elif typ == 'grp1': - vars, pos = parse_data(chunk, 'group') - vars['subs'] = [] - for n in xrange(vars['numsubs']): - vars['subs'].append(nullterm(chunk[pos:pos+16])) - pos += 16 - elif typ in ('txl1', 'fnl1'): - things = {'txl1': 'textures', 'fnl1': 'files'}[typ] - vars, pos = parse_data(chunk, 'numoffs') - vars[things] = [] - pos += vars['offs'] - bpos = pos - del vars['offs'] # unneeded - for n in xrange(vars['num']): - offset, unk = struct.unpack('>II', chunk[pos:pos+8]) - name = nullterm(chunk[offset + bpos:]) - vars[things].append({'name': name, 'unk': unk}) - pos += 8 - if typ == 'txl1': - textures = vars['textures'] - elif typ == 'mat1': - vars, pos = parse_data(chunk, 'numoffs') - vars['materials'] = [] - pos += vars['offs'] - bpos = pos - del vars['offs'] - materials = [] - for n in xrange(vars['num']): - offset, = struct.unpack('>I', chunk[pos:pos+4]) - mat, mpos = parse_data(chunk, 'material', start = offset - 8) - #vars['materials'].append(mat) - flags = mat['flags'] - materials.append(mat['name']) - assert mpos == 0x40 + offset - 8 - - - #print hex(struct.unpack('>I', chunk[mpos:mpos+4])[0]) - - # I believe material is: - # 0x40, followed by - # 4 * flags[28-31], followed by - - - mat['texref'], mpos = get_array(chunk, mpos, bit_extract(flags, 28, 31), 4, 'texref') - - for a in mat['texref']: - a['tex'] = textures[a['tex_offs']]['name'] - - # 0x14 * flags[24-27], followed by - - mat['ua2'], mpos = get_array(chunk, mpos, bit_extract(flags, 24, 27), 0x14, 'ua2') - - # 4*flags[20-23], followed by - - mat['ua3'], mpos = get_array(chunk, mpos, bit_extract(flags, 20, 23), 4, '4b') - - # Changing ua3 things - # 1st --> disappears. - # 2nd --> no visible effect. - # 3rd --> disappears. - # 4th --> no visible effect. - - # 4 * flags[6] - - mat['ua4'], mpos = get_opt(chunk, mpos, bit_extract(flags, 6), 4, '4b') - - # 4 * flags[4] - - mat['ua5'], mpos = get_opt(chunk, mpos, bit_extract(flags, 4), 4, '4b') - - # 4 * flags[19] - - mat['ua6'], mpos = get_opt(chunk, mpos, bit_extract(flags, 19), 4, '4b') - - # 0x14 * flags[17-18] - - mat['ua7'], mpos = get_array(chunk, mpos, bit_extract(flags, 17, 18), 0x14, 'ua7') - - # 4 * flags[14-16] - - mat['ua8'], mpos = get_array(chunk, mpos, bit_extract(flags, 14, 16), 4, '4b') - - # 0x10 * flags[9-13] - - mat['ua9'], mpos = get_array(chunk, mpos, bit_extract(flags, 9, 13), 0x10, '10b') - - # 4 * flags[8], these are bytes btw - - mat['uaa'], mpos = get_opt(chunk, mpos, bit_extract(flags, 8), 4, '4b') - - # 4 * flags[7] - - mat['uab'], mpos = get_opt(chunk, mpos, bit_extract(flags, 7), 4, '4b') + if n < vars['num'] - 1: + next_offset, = struct.unpack('>I', chunk[pos+4:pos+8]) + if next_offset - 8 != mpos: + mat['~_insane'] = next_offset - 8 - mpos # Extra shit we didn't parse :( + + mat['unk_bit_5'] = bit_extract(flags, 5) + mat['unk_bits_0_3'] = bit_extract(flags, 0, 3) # Overwritten by stuff - if n < vars['num'] - 1: - next_offset, = struct.unpack('>I', chunk[pos+4:pos+8]) - if next_offset - 8 != mpos: - mat['~_insane'] = next_offset - 8 - mpos # Extra shit we didn't parse :( + vars['materials'].append(mat) + pos += 4 + elif typ in ('grs1', 'pas1'): + indentlevel += 1 + elif typ in ('gre1', 'pae1'): + indentlevel -= 1 + else: + print 'Unhandled type %s' % typ + print repr(chunk) - mat['unk_bit_5'] = bit_extract(flags, 5) - mat['unk_bits_0_3'] = bit_extract(flags, 0, 3) # Overwritten by stuff + if vars: pr_dict(vars, ' ' * indentlevel + ' ') + print close_paren(typ, indentlevel) + #print hex(len(ch)) - vars['materials'].append(mat) - pos += 4 - elif typ in ('grs1', 'pas1'): - indent += 1 +def open_paren(typ): + if typ in ('grs1', 'pas1'): + return "'" + typ + "'" elif typ in ('gre1', 'pae1'): - indent -= 1 + return "'" + typ + "'" else: - print 'Unhandled type %s' % typ - print repr(chunk) - if vars: pr_dict(vars, ' ' * indent + ' ') -#print hex(len(ch)) + return "('" + typ + "',\n" + +def close_paren(typ, indentlevel): + if typ in ('grs1', 'pas1'): + indentlevel -= 1 + return ',' + elif typ in ('gre1', 'pae1'): + indentlevel += 1 + return ',' + return ' ' * indentlevel + ") ," + +if __name__ == "__main__": + print '[' + main() + print ']\n' \ No newline at end of file -- cgit v1.3.1