Added if, while and break statements to support more complex parsing logic.

This commit is contained in:
lcdr 2015-09-30 18:00:42 +02:00
parent 3e10476cd6
commit 86dfe01355
8 changed files with 62 additions and 37 deletions

View File

@ -15,7 +15,7 @@ Index 3 ($+7DC480):
[bit] - ???
Index 4 ($+8A3A40):
[EVAL:creation]
if creation:
[bit] - flag
[u64] - ???, could be "co" from xml data
[bit] - flag

View File

@ -1,6 +1,6 @@
Component 1 - ControllablePhysics (tested using LOT 1)
Index 1 ($+845770):
[EVAL:creation]
if creation:
[bit] - flag
[u32] - ???
[bit] - ???
@ -50,5 +50,5 @@ Index 1 ($+845770):
[float] - ???
[float] - ???
[float] - ???
[EVAL:not creation]
if not creation:
[bit] - flag?

View File

@ -1,6 +1,6 @@
Component 7 - Destructible (tested using LOT 1)
Index 1 ($+939820):
[EVAL:creation]
if creation:
[bit] - flag, expect == False
[u32] - count for following structs
[u32] - ???
@ -16,7 +16,7 @@ Index 1 ($+939820):
[bit] - ???
trigger=[bit] - ???, seems to trigger [s64] below?
[bit] - ???
[EVAL:trigger]
if trigger:
[s64] - ???
[u32] - ???
[bit] - flag, expect == False
@ -34,12 +34,12 @@ Index 1 ($+939820):
[bit] - ???
trigger=[bit] - ???, seems to trigger [s64] below?
[bit] - ???
[EVAL:trigger]
if trigger:
[s64] - ???
[u32] - ???
Index 2 ($+92BBD0):
[EVAL:creation]
if creation:
[bit] - flag
[u32] - ???, assert == 0
[u32] - ???, assert == 0
@ -67,10 +67,10 @@ Index 2 ($+92BBD0):
[u32] - count
[s32] - faction id
trigger=[bit] - flag
[EVAL:creation]
if creation:
[bit] - flag, assert == False
[bit] - flag, assert == False
[EVAL:trigger]
if trigger:
[bit] - ???, assert == False
[bit] - flag
[u32] - ???

View File

@ -1,6 +1,6 @@
Component 2 - Render (tested using LOT 1)
Index 1 ($+840310):
[EVAL:creation]
if creation:
[u32] - number of BehaviorEffects? (see BehaviorEffect table in cdclient), if this is -1 the client logs "Bad FX Unserialize", expect != -1
[u8] - length
[u8] - effectID string

View File

@ -1,6 +1,6 @@
Component 5 - Script (tested using LOT 3495)
Index 1 ($+87CDF0):
[EVAL:creation]
if creation:
[bit] - flag
[u32] - size of following struct
[u8] - compressed data, x bytes according to prev struct

View File

@ -1,6 +1,6 @@
Component 3 - SimplePhysics (tested using LOT 7701)
Index 1 ($+7E4B00):
[EVAL:creation]
if creation:
[bit] - ???
[float] - ???
[bit] - flag

View File

@ -1,6 +1,6 @@
Component 9 - Skill (tested using LOT 1)
Index 1 ($+806270):
[EVAL:creation]
if creation:
[bit] - flag
[u32] - count for following structs
[u32] - ???

View File

@ -11,21 +11,29 @@ VAR_CHARS = r"[^ \t\[\]]+"
BITSTREAM_TYPES = {"bit": c_bit, "float": c_float, "double": c_double, "s8": c_int8, "u8": c_uint8, "s16": c_int16, "u16": c_uint16, "s32": c_int32, "u32": c_uint32, "s64": c_int64, "u64": c_uint64}
TYPES_RE = "("+"|".join(BITSTREAM_TYPES.keys())+")"
DEFINITION_SYNTAX = re.compile(r"""^
(?P<indent>\t*) # Indentation
((?P<var_assign>"""+VAR_CHARS+r""")=)? # Assign this struct a variable so the value can be back-referenced later
\[(
(EVAL:(?P<eval>.+)) # Expression to be evaluated, evaluated value acts like struct value, usually used for variables
|
(?P<type>"""+TYPES_RE+r""") # Struct type
)\]
(\ -\ (?P<description>.*?) # Description for the struct
(,\ expect\ (?P<expect>(.+?)))? # Expect the value to be like this expression. Struct attribute 'unexpected' will be None if no expects, True if any expects are False, or False if all expects are True.
(,\ assert\ (?P<assert>(.+?)))? # Assert the value to be like this expression, will raise AssertionError if not True.
)?$
DEFINITION_SYNTAX = re.compile(r"""
^(?P<indent>\t*) # Indentation
(if\ (?P<if_condition>.+):
|
while\ (?P<while_condition>.+):
|
(?P<break>break)
|
((?P<var_assign>"""+VAR_CHARS+r""")=)? # Assign this struct a variable so the value can be back-referenced later
\[
(?P<type>"""+TYPES_RE+r""") # Struct type
\]
\ -\ (?P<description>.*?) # Description for the struct
(,\ expect\ (?P<expect>(.+?)))? # Expect the value to be like this expression. Struct attribute 'unexpected' will be None if no expects, True if any expects are False, or False if all expects are True.
(,\ assert\ (?P<assert>(.+?)))? # Assert the value to be like this expression, will raise AssertionError if not True.
)$
""", re.VERBOSE)
Definition = namedtuple("Definition", ("var_assign", "eval", "type", "description", "expects", "asserts"))
IfStatement = namedtuple("IfStatement", ("condition",))
WhileStatement = namedtuple("WhileStatement", ("condition",))
BreakStatement = namedtuple("BreakStatement", ())
StructDefinition = namedtuple("struct_token", ("var_assign", "type", "description", "expects", "asserts"))
Structure = namedtuple("Structure", ("level", "description", "value", "unexpected"))
class StructParser:
@ -95,12 +103,16 @@ class StructParser:
@staticmethod
def _to_def_tuple(def_):
if def_["eval"] is not None:
eval_ = compile(def_["eval"], "<eval>", "eval")
type_ = None
else:
eval_ = None
type_ = BITSTREAM_TYPES[def_["type"]]
if def_["if_condition"] is not None:
condition = compile(def_["if_condition"], "<if_condition>", "eval")
return IfStatement(condition)
if def_["while_condition"] is not None:
condition = compile(def_["while_condition"], "<while_condition>", "eval")
return WhileStatement(condition)
if def_["break"] is not None:
return BreakStatement()
type_ = BITSTREAM_TYPES[def_["type"]]
if def_["expect"] is not None:
expects = [compile("value "+i, "<expect>", "eval") for i in def_["expect"].split(" and ")]
@ -111,13 +123,24 @@ class StructParser:
else:
asserts = ()
return Definition(def_["var_assign"], eval_, type_, def_["description"], expects, asserts)
return StructDefinition(def_["var_assign"], type_, def_["description"], expects, asserts)
def _parse_struct_occurrences(self, stream, defs, stack_level=0, repeat_times=1):
for _ in range(repeat_times):
for def_, children in defs:
if def_.eval is not None:
value = self._eval(def_.eval)
if isinstance(def_, IfStatement):
if children and self._eval(def_.condition):
break_ = yield from self._parse_struct_occurrences(stream, children, stack_level+1)
if break_:
return True
elif isinstance(def_, WhileStatement):
if children:
while self._eval(def_.condition):
break_ = yield from self._parse_struct_occurrences(stream, children, stack_level+1)
if break_:
break
elif isinstance(def_, BreakStatement):
return True
else:
value = stream.read(def_.type)
@ -138,8 +161,10 @@ class StructParser:
self._variables[def_.var_assign] = value
yield Structure(stack_level, def_.description, value, unexpected)
if children:
yield from self._parse_struct_occurrences(stream, children, stack_level+1, value)
if children and value:
break_ = yield from self._parse_struct_occurrences(stream, children, stack_level+1, value)
if break_:
return True
def _eval(self, expression, value=None):
globals_ = {"__builtins__": {}, "value": value}