From cef7ef60d0a79c288d6535d8ab99665c33c7c42e Mon Sep 17 00:00:00 2001 From: Harald Welte Date: Sun, 22 Jan 2017 19:04:08 +0100 Subject: Add python tools that (partially) parse the QXDM database --- tools/qxdm-db-tool.py | 38 ++++++++++++ tools/qxdm_db.py | 160 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 198 insertions(+) create mode 100755 tools/qxdm-db-tool.py create mode 100644 tools/qxdm_db.py diff --git a/tools/qxdm-db-tool.py b/tools/qxdm-db-tool.py new file mode 100755 index 0000000..4f50d1e --- /dev/null +++ b/tools/qxdm-db-tool.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# +# Code to parse the ASCII Database files of QXDM +# (C) 2017 by Harald Welte +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +from optparse import OptionParser +from qxdm_db import QxdmDb + +parser = OptionParser() +parser.add_option("-d", "--database-dir", dest="db_dir", + help="QXDM Database directory to use") + +(options, args) = parser.parse_args() + +if not options.db_dir: + print "You have to specify the database directory" + exit(2) + +db = QxdmDb(options.db_dir) + +db.export_valstr_events() +db.export_valstr_event_descs() +db.export_valstr_logitems() +db.export_valstr_msgs() diff --git a/tools/qxdm_db.py b/tools/qxdm_db.py new file mode 100644 index 0000000..126cfbc --- /dev/null +++ b/tools/qxdm_db.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +# +# Code to parse the ASCII Database files of QXDM +# (C) 2017 by Harald Welte +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +import csv + +def export_value_str(name, vals, flavor='osmocom'): + if flavor == 'osmocom': + print("const struct value_string %s[] = {" % name); + elif flavor == 'wireshark': + print("const value_string %s[] = {" % name); + for v in sorted(vals.iterkeys(), key=int): + print("\t{ %d, \"%s\" }," % (int(v), vals[v])); + print("\t{ 0, NULL }") + print("};"); + +class QxdmDb(object): + file_fields = { + 'Enum': ['id', 'name', 'entries_id', 'unknown'], + 'EnumEntry': ['enum_id', 'value', 'name', 'unknown'], + 'EventID': ['value', 'name', 'category_id', 'description_id'], + 'EventCategory': ['value', 'name', 'unknown', 'unknown2'], + 'Struct': ['id', 'index', 'unknown', 'field_id', 'unknown2', 'unknown3', 'unknown4'], + 'Field': ['id', 'name', 'bits', 'unknown1', 'unknown2', + 'unknown3', 'unknown4', 'unknown5'], + 'Description': ['id', 'text'], + 'LogItem': ['id', 'name', 'category_id', 'unknown'], + 'LogCategory': ['id', 'name', 'unknown', 'parent_id'], + 'MessageLevel': ['id', 'level', 'name', 'category_id'], + 'MessageCategory': ['id', 'name', 'unknown', 'parent_id'], + } + _csvdicts= {} + + descs = {} + enums = {} + events = {} + event_cats = {} + logitems = {} + log_cats = {} + msgs = {} + msg_cats = {} + + @staticmethod + def read_into_dict(fname, fieldnames=None): + csvfile = open(fname, 'rb') + r = csv.DictReader(csvfile, fieldnames=fieldnames, delimiter='^') + return r + + def gen_descs(self): + for d in self._csvdicts['Description']: + self.descs[int(d['id'], base=0)] = d['text'] + + def gen_enums(self): + for e in self._csvdicts['Enum']: + self.enums[int(e['id'], base=0)] = {'name': e['name'], 'entries': {}} + for ee in self._csvdicts['EnumEntry']: + self.enums[int(ee['enum_id'], base=0)]['entries'][int(ee['value'],base=0)] = ee['name'] + + def gen_events(self): + for c in self._csvdicts['EventCategory']: + self.event_cats[int(c['value'],base=0)] = {'name': c['name'], 'events': []} + + for e in self._csvdicts['EventID']: + val_int = int(e['value'], base=0) + self.events[val_int] = {'name': e['name']} + if e['description_id'] != '-1': + self.events[val_int]['description'] = self.descs[int(e['description_id'], base=0)] + cats = e['category_id'].split(',') + for c in cats: + cat_int = int(c, base=0) + if cat_int in self.event_cats: + self.event_cats[cat_int]['events'].append(self.events[val_int]) + + def gen_logitems(self): + for c in self._csvdicts['LogCategory']: + self.log_cats[int(c['id'],base=0)] = {'name': c['name'], 'items': []} + + for l in self._csvdicts['LogItem']: + val_int = int(l['id'], base=0) + self.logitems[val_int] = {'name': l['name']} + + cats = l['category_id'].split(',') + for c in cats: + cat_int = int(c, base=0) + if cat_int in self.log_cats: + self.log_cats[cat_int]['items'].append(self.logitems[val_int]) + + def gen_msglevels(self): + def strip_suffix(s): + slash = s.rfind('/') + if slash == -1: + return s + else: + return s[:slash] + for c in self._csvdicts['MessageCategory']: + self.msg_cats[int(c['id'],base=0)] = {'name': c['name'], 'msgs': []} + + for l in self._csvdicts['MessageLevel']: + val_int = int(l['id'], base=0) + level_int = int(l['level'], base=0) + if not val_int in self.msgs: + self.msgs[val_int] = {'levels':{}, 'name': strip_suffix(l['name'])} + self.msgs[val_int]['levels'][level_int] = {'name': l['name']} + + cats = l['category_id'].split(',') + for c in cats: + cat_int = int(c, base=0) + if cat_int in self.msg_cats: + self.msg_cats[cat_int]['msgs'].append(self.msgs[val_int]['levels'][level_int]) + + + def __init__(self, dir_to_db): + for f in self.file_fields: + fname = '%s/%s.txt' % (dir_to_db, f) + self._csvdicts[f] = self.read_into_dict(fname, self.file_fields[f]) + self.gen_descs() + self.gen_enums() + self.gen_events() + self.gen_logitems() + self.gen_msglevels() + + def export_valstr_events(self): + def f(v): + return v['name'] + vals = dict(zip(self.events, map(f, self.events.values()))) + export_value_str('diag_event_vals', vals) + + def export_valstr_event_descs(self): + vals = {} + for e in self.events: + if 'description' in self.events[e]: + vals[e] = self.events[e]['description'] + export_value_str('diag_event_descs', vals) + + def export_valstr_logitems(self): + def f(v): + return v['name'] + vals = dict(zip(self.logitems, map(f, self.logitems.values()))) + export_value_str('diag_log_item_vals', vals) + + def export_valstr_msgs(self): + def f(v): + return v['name'] + vals = dict(zip(self.msgs, map(f, self.msgs.values()))) + export_value_str('diag_msg_vals', vals) -- cgit v1.2.3