aboutsummaryrefslogtreecommitdiff
path: root/ethyl.py
diff options
context:
space:
mode:
Diffstat (limited to 'ethyl.py')
-rw-r--r--ethyl.py143
1 files changed, 142 insertions, 1 deletions
diff --git a/ethyl.py b/ethyl.py
index 8db217e..2d0d205 100644
--- a/ethyl.py
+++ b/ethyl.py
@@ -1,3 +1,4 @@
+import sys, struct, re
formats = {
'pane': '''
u8 flags_1 // 8
@@ -61,4 +62,144 @@ formats = {
u32 c
''',
-} \ No newline at end of file
+}
+
+for (dname, definition) in formats.items():
+ definition = re.sub(re.compile('//.*$', re.M), '', definition)
+ definition = definition.strip()
+ definition = re.sub('\n[\n ]+', '\n', definition)
+ df = [[j.strip() for j in i.strip().split()] for i in definition.split('\n')]
+ df = []
+ etc = etcn = False
+ for i in definition.split('\n'):
+ i = i.strip()
+ if i[:3] == 'etc':
+ etc = True
+ if i == 'etc!':
+ etcn = True
+ continue
+ typ, name = [j.strip() for j in i.split()]
+ m = re.match('^([^\[]+)\[([a-zA-Z0-9]+)\]$', name)
+ if m:
+ name = m.group(1)
+ size = eval(m.group(2))
+ df.append((typ, (name, size)))
+ else:
+ df.append((typ, name))
+ formats[dname] = df, etc, etcn
+
+
+
+def pr_dict(data, start=''):
+ for a in sorted(data.keys()):
+ b = data[a]
+ print '%s%s: %s' % (start, str(a), hex(b) if type(b) in (int, long) else repr(b))
+types = {
+ 'u8': 'B',
+ 'u16': 'H',
+ 'u32': 'I',
+ 'u64': 'Q',
+ 's8': 'b',
+ 's16': 'h',
+ 's32': 'i',
+ 's64': 'q',
+ 'float': 'f',
+ 'f32': 'f',
+ 'double': 'd',
+ 'f64': 'd',
+ 'bool': 'c',
+ 'char': 'c',
+}
+def parse_var(pos, typ, chunk):
+ if not types.has_key(typ):
+ raise Exception('What\'s a %s?' % typ)
+ fmt = '>' + types[typ]
+ size = struct.calcsize(fmt)
+
+ return (pos + size), struct.unpack(fmt, chunk[pos:pos + size])[0]
+def nullterm(str_plus):
+ z = str_plus.find('\0')
+ if z != -1:
+ return str_plus[:z]
+ else:
+ return str_plus
+def parse_data(chunk, definition, prefix=None, start=0):
+ df, etc, etcn = formats[definition]
+ #print df, repr(definition)
+ #print df
+
+ pos = start
+ ret = {}
+ for typ, name in df:
+ try:
+ name, size = name
+ except:
+ pos, var = parse_var(pos, typ, chunk)
+ else:
+ if typ == 'char':
+ var = chunk[pos:pos+size].rstrip(chr(0))
+ pos += size
+ else:
+ var = []
+ for n in xrange(size):
+ pos, varn = parse_var(pos, typ, chunk)
+ var.append(varn)
+ if ret.has_key(name):
+ try:
+ ret[name].append(var)
+ except AttributeError:
+ ret[name] = [ret[name], var]
+ else:
+ ret[name] = var
+ #print hex(pos)
+ if pos > len(chunk):
+ raise Exception('too much!')
+ if pos < len(chunk):
+ if etc and not etcn:
+ ret['etc'] = repr(chunk[pos:])
+ elif not etc:
+ raise Exception('Incomplete handling...')
+ if prefix is not None:
+ ret2 = {}
+ for (k, v) in ret.items():
+ ret2[prefix + '.' + k] = v
+ ret = ret2
+ 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 = ''
+ for typ, name in df:
+ size = None
+ try:
+ name, size = name
+ except:
+ pass
+ if prefix is not None:
+ name = re.sub('^' + re.quote(prefix) + '\.', '', name)
+ var = vars[name]
+ if size is None:
+ ret += unparse_var(typ, var)
+ else:
+ if typ == 'char':
+ ret += var.ljust(size, '\0')
+ else:
+ assert len(var) == size
+ for v in var:
+ ret += unparse_var(typ, v)
+ return ret
+def iff_to_chunks(z):
+ pos = 0
+ chunks = []
+ while pos < len(z):
+ cc = z[pos:pos+4]
+ length, = struct.unpack('>I', z[pos+4:pos+8])
+ #print cc
+ #print hex(length)
+ data = z[pos+8:pos+length]
+ pos += length
+ chunks.append((cc, data))
+ return chunks \ No newline at end of file