-
Notifications
You must be signed in to change notification settings - Fork 1
/
viewer_urwid.py
executable file
·187 lines (152 loc) · 5.07 KB
/
viewer_urwid.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#!/usr/bin/env python
import re
import os
import sys
import kshelp
import urwid
import kaitaistruct
filterLevel = 0
ktb = None
def callback_tree_modified(listBox, footer):
kaitaiNode = listBox.get_focus()[1]
fieldName = kaitaiNode.get_key()
range_ = None
tmp = kaitaiNode.get_parent()
if tmp:
range_ = kshelp.getFieldRange(tmp._ksobj, fieldName)
if not range_:
range_ = ''
footer.set_text(".%s %s" % (fieldName, str(range_)))
class KaitaiTreeWidget(urwid.TreeWidget):
global ktb
unexpanded_icon = urwid.AttrMap(urwid.TreeWidget.unexpanded_icon, 'dirmark')
expanded_icon = urwid.AttrMap(urwid.TreeWidget.expanded_icon, 'dirmark')
def __init__(self, node):
self.__super.__init__(node)
self._w = urwid.AttrWrap(self._w, None)
self._w.attr = 'body'
self._w.focus_attr = 'focus'
def get_display_text(self):
# default display will be "key: value"
return urwid.TreeWidget.get_display_text(self)
def selectable(self):
return True
class KaitaiNode(urwid.TreeNode):
# same as TreeNode constructor + ksobj
def __init__(self, value, ksobj, parent=None, key=None, depth=None):
self._ksobj = ksobj
urwid.TreeNode.__init__(self, value, parent=parent, key=key, depth=depth)
def load_widget(self):
return KaitaiTreeWidget(self)
class KaitaiParentNode(urwid.ParentNode):
# same as ParentNode constructor + ksobj
def __init__(self, value, ksobj, parent=None, key=None):
self._ksobj = ksobj
# depth is steps from root, count them
depth = 0
traveller = ksobj
while traveller._parent:
depth += 1
traveller = traveller._parent
# if a field description isn't provided, generate it from the ksobj
if value == None:
value = kshelp.objToStr(ksobj)
# parent constructor
urwid.ParentNode.__init__(
self,
value, # field description self._value
key=key, # field name self._key
parent=parent, # self._parent
depth=depth # self._depth
)
def load_widget(self):
return KaitaiTreeWidget(self)
# URWID asks us the names ("keys") of our children
def load_child_keys(self):
global filterLevel
result = []
kshelp.exercise(self._ksobj)
for fieldName in (
kshelp.getFieldNamesPrint(self._ksobj, filterLevel) +
kshelp.getFieldNamesDescend(self._ksobj, filterLevel)
):
childObj = getattr(self._ksobj, fieldName)
if isinstance(childObj, list):
for i in range(len(childObj)):
result.append('%s[%d]' % (fieldName, i))
else:
result.append(fieldName)
return result
# URWID asks us for nodes for each of the names ("keys") of our children
def load_child_node(self, key):
childObj = None
# is the key like "blah[5]"? then list
m = re.match(r'^(\w*)\[(\d+)\]$', key)
if m:
(fieldName, fieldIdx) = m.group(1,2)
childObj = getattr(self._ksobj, fieldName)[int(fieldIdx)]
else:
childObj = getattr(self._ksobj, key)
if isinstance(childObj, kaitaistruct.KaitaiStruct):
return KaitaiParentNode(None, childObj, parent=self, key=key)
else:
return KaitaiNode(kshelp.objToStr(childObj), childObj, parent=self, key=key, depth=self.get_depth()+1)
class KaitaiTreeBrowser:
palette = [
('body', 'light gray', 'black'),
('flagged', 'black', 'dark green', ('bold','underline')),
('focus', 'light gray', 'dark blue', 'standout'),
('flagged focus', 'yellow', 'dark cyan',
('bold','standout','underline')),
('head', 'yellow', 'black', 'standout'),
('foot', 'light gray', 'black'),
('key', 'light cyan', 'black','underline'),
('title', 'white', 'black', 'bold'),
('dirmark', 'black', 'dark cyan', 'bold'),
('flag', 'dark gray', 'light gray'),
('error', 'dark red', 'light gray'),
]
footer_text = [
('title', "Kaitai Data Browser"), " ",
('key', "UP"), ",", ('key', "DOWN"), ",",
('key', "PAGE UP"), ",", ('key', "PAGE DOWN"),
" ",
('key', "+"), ",",
('key', "-"), " ",
('key', "LEFT"), " ",
('key', "HOME"), " ",
('key', "END"), " ",
('key', "Q"),
]
def __init__(self, ksobj=None):
self.topnode = KaitaiParentNode(None, ksobj, key=kshelp.objToStr(ksobj))
self.walker = urwid.TreeWalker(self.topnode)
self.listbox = urwid.TreeListBox(self.walker)
self.listbox.offset_rows = 0
self.header = urwid.Text( "" )
self.footer = urwid.AttrWrap( urwid.Text( self.footer_text ),
'foot')
self.view = urwid.Frame(
urwid.AttrWrap( self.listbox, 'body' ),
header=urwid.AttrWrap(self.header, 'head' ),
footer=self.footer )
urwid.connect_signal(self.walker, "modified", callback_tree_modified, weak_args=[self.listbox, self.footer])
def main(self):
"""Run the program."""
self.loop = urwid.MainLoop(self.view, self.palette,
unhandled_input=self.unhandled_input)
self.loop.run()
def unhandled_input(self, k):
if k in ('q','Q'):
raise urwid.ExitMainLoop()
#------------------------------------------------------------------------------
# main
#------------------------------------------------------------------------------
if __name__ == '__main__':
assert len(sys.argv) == 3
(filterLevel, fpath) = (sys.argv[1], sys.argv[2])
filterLevel = int(filterLevel)
ksobj = kshelp.parseFpath(fpath)
ktb = KaitaiTreeBrowser(ksobj)
ktb.main()
#dumpDict(treeDict, 0)