summaryrefslogtreecommitdiff
path: root/optdump.py
diff options
context:
space:
mode:
authorAsh Wolf <ninji@wuffs.org>2022-10-19 21:16:13 +0100
committerAsh Wolf <ninji@wuffs.org>2022-10-19 21:16:13 +0100
commitd1f153d34b023d81768f6087f67dbfff714bafc9 (patch)
treea694d470a60655d0cda15a70791fbdb90a2398cf /optdump.py
parent775b6861666af36d317fb577cf489e2c6377f878 (diff)
downloadMWCC-d1f153d34b023d81768f6087f67dbfff714bafc9.tar.gz
MWCC-d1f153d34b023d81768f6087f67dbfff714bafc9.zip
let's commit all this before my VM blows up and nukes my work
Diffstat (limited to '')
-rw-r--r--optdump.py386
1 files changed, 386 insertions, 0 deletions
diff --git a/optdump.py b/optdump.py
new file mode 100644
index 0000000..b1bb42e
--- /dev/null
+++ b/optdump.py
@@ -0,0 +1,386 @@
+import json
+
+'''
+HOW TO GENERATE:
+
+
+'''
+
+def play_with_addr(ea):
+ if ea == 0:
+ return None
+
+ e = ida_name.get_name_expr(0, 0, ea, BADADDR)
+ e = e[13:-2]
+ return e
+
+class String:
+ name: str
+ value: str
+
+ @staticmethod
+ def from_ea(ea):
+ if ea == 0:
+ return None
+ else:
+ s = String()
+ s.name = get_name(ea)
+ v = get_bytes(ea, 1024)
+ v = v[:v.find(b'\0')]
+ s.value = v.decode('ascii')
+ return s
+
+ def encode(self):
+ if self.name.startswith('a'):
+ return self.value
+ else:
+ return dict(name=self.name, value=self.value)
+
+class Param:
+ name: str
+ flags: int
+ myname: String
+
+ @staticmethod
+ def from_ea(ea):
+ print('reading param %08x' % ea)
+ which = get_wide_byte(ea)
+ next_ea = get_wide_dword(ea + 6)
+ p = PARAM_CLASSES[which]()
+ p.populate_from_ea(ea)
+ return p, next_ea
+
+ def populate_from_ea(self, ea):
+ self.name = get_name(ea)
+ self.flags = get_wide_byte(ea + 1)
+ self.myname = String.from_ea(get_wide_dword(ea + 2))
+
+ def encode(self):
+ d = dict(_name=self.name, flags=self.flags)
+ if self.myname is not None:
+ d['myname'] = self.myname
+ return d
+
+ @staticmethod
+ def list_from_ea(ea):
+ lst = []
+ while ea != 0:
+ param, next_ea = Param.from_ea(ea)
+ lst.append(param)
+ ea = next_ea
+ return lst
+
+class FTypeCreatorParam(Param):
+ def populate_from_ea(self, ea):
+ super(FTypeCreatorParam, self).populate_from_ea(ea)
+ self.fc = play_with_addr(get_wide_dword(ea + 10))
+ self.iscreator = get_wide_byte(ea + 14)
+ def encode(self):
+ d = super(FTypeCreatorParam, self).encode()
+ d['_type'] = 'FTypeCreator'
+ d['fc'] = self.fc
+ d['iscreator'] = self.iscreator
+ return d
+
+class FilePathParam(Param):
+ def populate_from_ea(self, ea):
+ super(FilePathParam, self).populate_from_ea(ea)
+ self.fflags = get_wide_byte(ea + 10)
+ self.defaultstr = String.from_ea(get_wide_dword(ea + 11))
+ self.filename = play_with_addr(get_wide_dword(ea + 15))
+ self.maxlen = get_wide_dword(ea + 19)
+ def encode(self):
+ d = super(FilePathParam, self).encode()
+ d['_type'] = 'FilePath'
+ d['fflags'] = self.fflags
+ d['defaultstr'] = self.defaultstr
+ d['filename'] = self.filename
+ d['maxlen'] = self.maxlen
+ return d
+
+class NumberParam(Param):
+ def populate_from_ea(self, ea):
+ super(NumberParam, self).populate_from_ea(ea)
+ self.size = get_wide_byte(ea + 10)
+ self.fit = get_wide_byte(ea + 11)
+ self.lo = get_wide_dword(ea + 12)
+ self.hi = get_wide_dword(ea + 16)
+ self.num = play_with_addr(get_wide_dword(ea + 20))
+ def encode(self):
+ d = super(NumberParam, self).encode()
+ d['_type'] = 'Number'
+ d['size'] = self.size
+ d['fit'] = self.fit
+ d['lo'] = self.lo
+ d['hi'] = self.hi
+ d['num'] = self.num
+ return d
+
+class StringParam(Param):
+ def populate_from_ea(self, ea):
+ super(StringParam, self).populate_from_ea(ea)
+ self.maxlen = get_wide_word(ea + 10)
+ self.pstring = get_wide_byte(ea + 12)
+ self.str = play_with_addr(get_wide_dword(ea + 13))
+ def encode(self):
+ d = super(StringParam, self).encode()
+ d['_type'] = 'String'
+ d['maxlen'] = self.maxlen
+ d['pstring'] = self.pstring
+ d['str'] = self.str
+ return d
+
+class IdParam(StringParam):
+ def populate_from_ea(self, ea):
+ super(IdParam, self).populate_from_ea(ea)
+ def encode(self):
+ d = super(IdParam, self).encode()
+ d['_type'] = 'Id'
+ return d
+
+class SymParam(StringParam):
+ def populate_from_ea(self, ea):
+ super(SymParam, self).populate_from_ea(ea)
+ def encode(self):
+ d = super(SymParam, self).encode()
+ d['_type'] = 'Sym'
+ return d
+
+class OnOffParam(Param):
+ def populate_from_ea(self, ea):
+ super(OnOffParam, self).populate_from_ea(ea)
+ self.var = play_with_addr(get_wide_dword(ea + 10))
+ def encode(self):
+ d = super(OnOffParam, self).encode()
+ d['_type'] = 'OnOff'
+ d['var'] = self.var
+ return d
+
+class OffOnParam(Param):
+ def populate_from_ea(self, ea):
+ super(OffOnParam, self).populate_from_ea(ea)
+ self.var = play_with_addr(get_wide_dword(ea + 10))
+ def encode(self):
+ d = super(OffOnParam, self).encode()
+ d['_type'] = 'OffOn'
+ d['var'] = self.var
+ return d
+
+class MaskParam(Param):
+ def populate_from_ea(self, ea):
+ super(MaskParam, self).populate_from_ea(ea)
+ self.size = get_wide_byte(ea + 10)
+ self.ormask = get_wide_dword(ea + 11)
+ self.andmask = get_wide_dword(ea + 15)
+ self.num = play_with_addr(get_wide_dword(ea + 19))
+ def encode(self):
+ d = super(MaskParam, self).encode()
+ d['_type'] = 'Mask'
+ d['size'] = self.size
+ d['ormask'] = self.ormask
+ d['andmask'] = self.andmask
+ d['num'] = self.num
+ return d
+
+class ToggleParam(Param):
+ def populate_from_ea(self, ea):
+ super(ToggleParam, self).populate_from_ea(ea)
+ self.size = get_wide_byte(ea + 10)
+ self.mask = get_wide_dword(ea + 11)
+ self.num = play_with_addr(get_wide_dword(ea + 15))
+ def encode(self):
+ d = super(ToggleParam, self).encode()
+ d['_type'] = 'Toggle'
+ d['size'] = self.size
+ d['mask'] = self.mask
+ d['num'] = self.num
+ return d
+
+class SetParam(Param):
+ def populate_from_ea(self, ea):
+ super(SetParam, self).populate_from_ea(ea)
+ self.size = get_wide_byte(ea + 10)
+ self.value = get_wide_dword(ea + 11)
+ self.num = play_with_addr(get_wide_dword(ea + 15))
+ def encode(self):
+ d = super(SetParam, self).encode()
+ d['_type'] = 'Set'
+ d['size'] = self.size
+ d['value'] = self.value
+ d['num'] = self.num
+ return d
+
+class SetStringParam(Param):
+ def populate_from_ea(self, ea):
+ super(SetStringParam, self).populate_from_ea(ea)
+ self.value = get_wide_dword(ea + 10)
+ self.pstring = get_wide_byte(ea + 14)
+ self.var = play_with_addr(get_wide_dword(ea + 15))
+ def encode(self):
+ d = super(SetStringParam, self).encode()
+ d['_type'] = 'SetString'
+ d['value'] = self.value
+ d['pstring'] = self.pstring
+ d['var'] = self.var
+ return d
+
+class GenericParam(Param):
+ def populate_from_ea(self, ea):
+ super(GenericParam, self).populate_from_ea(ea)
+ self.parse = play_with_addr(get_wide_dword(ea + 10))
+ # self.var = play_with_addr(get_wide_dword(ea + 14))
+ var = get_wide_dword(ea + 14)
+ if get_name(var).startswith('a'):
+ self.var = String.from_ea(var)
+ else:
+ self.var = var
+ self.help = String.from_ea(get_wide_dword(ea + 18))
+ def encode(self):
+ d = super(GenericParam, self).encode()
+ d['_type'] = 'Generic'
+ d['parse'] = self.parse
+ d['var'] = self.var
+ d['help'] = self.help
+ return d
+
+class IfArgParam(Param):
+ def populate_from_ea(self, ea):
+ super(IfArgParam, self).populate_from_ea(ea)
+ self.parg = Param.list_from_ea(get_wide_dword(ea + 10))
+ self.helpa = String.from_ea(get_wide_dword(ea + 14))
+ self.pnone = Param.list_from_ea(get_wide_dword(ea + 18))
+ self.helpn = String.from_ea(get_wide_dword(ea + 22))
+ def encode(self):
+ d = super(IfArgParam, self).encode()
+ d['_type'] = 'IfArg'
+ d['parg'] = self.parg
+ d['helpa'] = self.helpa
+ d['pnone'] = self.pnone
+ d['helpn'] = self.helpn
+ return d
+
+class SettingParam(Param):
+ def populate_from_ea(self, ea):
+ super(SettingParam, self).populate_from_ea(ea)
+ self.parse = play_with_addr(get_wide_dword(ea + 10))
+ self.valuename = String.from_ea(get_wide_dword(ea + 14))
+ def encode(self):
+ d = super(SettingParam, self).encode()
+ d['_type'] = 'Setting'
+ d['parse'] = self.parse
+ d['valuename'] = self.valuename
+ return d
+
+PARAM_CLASSES = [
+ Param,
+ FTypeCreatorParam,
+ FilePathParam,
+ NumberParam,
+ StringParam,
+ IdParam,
+ SymParam,
+ OnOffParam,
+ OffOnParam,
+ MaskParam,
+ ToggleParam,
+ SetParam,
+ SetStringParam,
+ GenericParam,
+ IfArgParam,
+ SettingParam
+]
+
+class Option:
+ name: str
+ names: String
+ avail: int
+ sub: 'OptionList'
+ conflicts: 'OptionList'
+ help: String
+
+ @staticmethod
+ def from_ea(ea):
+ if ea == 0:
+ return None
+ else:
+ o = Option()
+ o.name = get_name(ea)
+ o.names = String.from_ea(get_wide_dword(ea))
+ o.avail = get_wide_dword(ea + 4)
+ o.param = Param.list_from_ea(get_wide_dword(ea + 8))
+ o.sub = OptionList.from_ea(get_wide_dword(ea + 12))
+ o.conflicts = OptionList.from_ea(get_wide_dword(ea + 16), shallow=True)
+ o.help = String.from_ea(get_wide_dword(ea + 20))
+ return o
+
+ @staticmethod
+ def read_list(list_ea, shallow=False):
+ lst = []
+ while True:
+ ea = get_wide_dword(list_ea)
+ if ea == 0:
+ break
+ if shallow:
+ lst.append(get_name(ea))
+ else:
+ lst.append(Option.from_ea(ea))
+ list_ea += 4
+ return lst
+
+ def encode(self):
+ d = dict(_name=self.name, names=self.names, avail=self.avail, param=self.param, help=self.help)
+ if self.sub is not None:
+ d['sub'] = self.sub
+ if self.conflicts is not None:
+ d['conflicts'] = self.conflicts
+ return d
+
+class OptionList:
+ @staticmethod
+ def from_ea(ea, shallow=False):
+ if ea == 0:
+ return None
+ else:
+ ol = OptionList()
+ ol.name = get_name(ea)
+ ol.help = String.from_ea(get_wide_dword(ea))
+ ol.flags = get_wide_dword(ea + 4)
+ list_ea = get_wide_dword(ea + 8)
+ if list_ea != 0:
+ ol.list_name = get_name(list_ea)
+ ol.list = Option.read_list(list_ea, shallow)
+ return ol
+
+ def dump(self):
+ print(f'OptionList({self.name})')
+
+ def encode(self):
+ d = dict(_name=self.name, flags=self.flags, _list_name=self.list_name, list=self.list)
+ if self.help is not None:
+ d['help'] = self.help
+ return d
+
+def get_optlist_eas():
+ ea = get_name_ea_simple('_optLists')
+ lists = []
+ while True:
+ list_ea = get_wide_dword(ea)
+ if list_ea == 0:
+ break
+ # list_name = get_name(list_ea)
+ lists.append(list_ea)
+ ea += 4
+ return lists
+
+optlists = []
+for ea in get_optlist_eas():
+ optlists.append(OptionList.from_ea(ea))
+
+def enc(obj):
+ if hasattr(obj, 'encode'):
+ return obj.encode()
+ else:
+ raise TypeError
+
+with open('/Users/ash/src/mwcc/opts.json', 'w') as f:
+ json.dump(optlists, f, sort_keys=True, indent=4, default=enc)