1
2
3
4
5
6
7
8
9
10
11
12 """Graphical view of protocol data and a decode of it"""
13
14 import sys
15 import re
16 import traceback
17 import wx
18 import StringIO
19 import struct
20
21 import common
22 import prototypes
23
24 import hexeditor
25
27 "List control showing the various events"
28
29 - def __init__(self, parent, id=-1, events=[]):
30 self.events=events
31 wx.ListCtrl.__init__(self, parent, id, style=wx.LC_REPORT|wx.LC_VIRTUAL)
32 self.InsertColumn(0, "Time")
33 self.InsertColumn(1, "Size")
34 self.InsertColumn(2, "Class")
35 self.InsertColumn(3, "Description")
36
37 self.SetColumnWidth(0, 100)
38 self.SetColumnWidth(1, 50)
39 self.SetColumnWidth(2, 200)
40 self.SetColumnWidth(3, 1000)
41
42 self.SetItemCount(len(events))
43
45 self.DeleteAllItems()
46 self.events=events
47 self.SetItemCount(len(events))
48
49 - def OnGetItemText(self, index, col):
50 curtime, curdesc, curclass, curdata=self.events[index]
51 if col==0:
52 return curtime
53 if col==1:
54 if len(curdata):
55 return "%5d" % (len(curdata),)
56 return ""
57 if col==2:
58 return curclass
59 if col==3:
60 return curdesc
61 assert False
62
65
66
67
69 """A top level frame for analysing protocol data"""
70 _pane_widths=[-2, -3, -4]
71 _pos_pane_index=0
72 _sel_pane_index=1
73 _val_pane_index=2
74
75 - def __init__(self, parent=None, id=-1, title="BitPim Protocol Analyser", data=None):
76 """Start the show
77
78 @param data: data to show. If None, then it will be obtained from the clipboard
79 """
80 wx.Frame.__init__(self, parent, id, title, size=(800,750),
81 style=wx.DEFAULT_FRAME_STYLE)
82
83 self.CreateStatusBar(len(self._pane_widths))
84 self.SetStatusWidths(self._pane_widths)
85
86 topsplit=wx.SplitterWindow(self, -1, style=wx.SP_3D|wx.SP_LIVE_UPDATE)
87
88 self.list=Eventlist(topsplit, 12)
89
90 botsplit=wx.SplitterWindow(topsplit, -1, style=wx.SP_3D|wx.SP_LIVE_UPDATE)
91 topsplit.SplitHorizontally(self.list, botsplit, 300)
92
93 self.tree=wx.TreeCtrl(botsplit, 23, style=wx.TR_DEFAULT_STYLE)
94 self.hex=hexeditor.HexEditor(botsplit,
95 _set_pos=self.set_pos,
96 _set_sel=self.set_sel,
97 _set_val=self.set_val)
98 botsplit.SplitHorizontally(self.tree, self.hex, 200)
99
100 if data is None:
101 data=self.getclipboarddata()
102
103 self.newdata(data)
104
105 wx.EVT_LIST_ITEM_SELECTED(self, self.list.GetId(), self.OnListBoxItem)
106 wx.EVT_LIST_ITEM_ACTIVATED(self, self.list.GetId(), self.OnListBoxItem)
107
108 wx.EVT_TREE_SEL_CHANGED(self, self.tree.GetId(), self.OnTreeSelection)
109
110 self.Show()
111
113 "We have new data - the old data is tossed"
114 self.parsedata(data)
115 self.list.newdata(self.packets)
116
118 "The user selected an event in the listbox"
119 index=evt.m_itemIndex
120 curtime, curdesc, curclass, curdata=self.packets[index]
121 self.errorinfo=""
122 self.hex.SetData("")
123 self.hex.highlightrange(-1,-1)
124 if len(curdata):
125 self.hex.SetData(curdata)
126
127 else:
128 self.hex.SetData(curdesc)
129
130
131 self.tree.DeleteAllItems()
132 if len(curclass):
133 b=prototypes.buffer(curdata)
134 try:
135 klass=common.getfullname(curclass)
136 except Exception,e:
137 self.errorme("Finding class",e)
138 wx.TipWindow(self.tree,self.errorinfo)
139 return
140 try:
141 obj=klass()
142 except Exception,e:
143 self.errorme("Instantiating object",e)
144 wx.TipWindow(self.tree,self.errorinfo)
145 return
146
147 try:
148 obj.readfrombuffer(b, autolog=False)
149 except Exception,e:
150 self.errorme("Reading from buffer",e)
151
152
153 root=self.tree.AddRoot(curclass)
154 try:
155 self.tree.SetPyData(root, obj.packetspan())
156 except:
157 self.errorme("Object did not construct correctly")
158
159 self.addtreeitems(obj, root)
160 if len(self.errorinfo):
161 wx.TipWindow(self.tree,self.errorinfo)
162
164 "Add fields from obj to parent node"
165 try:
166 for name,field,desc in obj.containerelements():
167 if desc is None:
168 desc=""
169 else:
170 desc=" - "+desc
171 iscontainer=False
172 try:
173 iscontainer=field.iscontainer()
174 except:
175 pass
176
177 s=field.__class__.__name__+" "+name
178 if iscontainer:
179 c=field.__class__
180 s+=": <%s.%s>" % (c.__module__, c.__name__)
181 else:
182 try:
183 v=field.getvalue()
184 except Exception,e:
185 v="<Exception: "+e.__str__()+">"
186 s+=": "
187 if isinstance(v, int) and not isinstance(v, type(True)):
188 s+="%d 0x%x" % (v,v)
189 else:
190 s+=`v`
191 if len(desc):
192 s+=desc
193 node=self.tree.AppendItem(parent, s)
194 try:
195 self.tree.SetPyData(node, field.packetspan())
196 except:
197 pass
198 if iscontainer:
199 self.addtreeitems(field, node)
200 except Exception,e:
201 str="<Exception: "+e.__str__()+">"
202 self.tree.AppendItem(parent,str)
203
213
214
215 - def errorme(self, desc, exception=None):
216 "Put exception information into the hex pane and output traceback to console"
217 if exception is not None:
218 x=StringIO.StringIO()
219 print >>x,exception.__str__(),
220 self.errorinfo+=x.getvalue()+" : "
221 print >>sys.stderr, common.formatexception()
222 self.errorinfo+=desc+"\n"
223
225 """Gets text data on clipboard"""
226 do=wx.TextDataObject()
227 wx.TheClipboard.Open()
228 success=wx.TheClipboard.GetData(do)
229 wx.TheClipboard.Close()
230 if not success:
231 wx.MessageBox("Whatever is in the clipboard isn't text", "No way Dude")
232 return ""
233 return do.GetText()
234
235 patevent=re.compile(r"^(\d?\d:\d\d:\d\d\.\d\d\d)(.*)")
236 patdataevent=re.compile(r"^(\d?\d:\d\d:\d\d\.\d\d\d)(.*)(Data - \d+ bytes.*)")
237 patdatarow=re.compile(r"^([0-9A-Fa-f]{8})(.*)")
238 patclass=re.compile(r"^<#!\s+(.*)\s+!#>")
239
241 """Fills in our internal data structures based on contents of data"""
242
243
244 data=data.replace("\r", "\n")
245 lastlen=0
246 while lastlen!=len(data):
247 lastlen=len(data)
248 data=data.replace("\n\n", "\n")
249
250 self.packets=[]
251
252 curtime=curdesc=curclass=curdata=""
253
254 indata=False
255
256 for line in data.split('\n'):
257
258 if len(line.strip())==0:
259 continue
260 mo=self.patclass.match(line)
261 if mo is not None:
262
263 curclass=mo.group(1)
264 indata=True
265 continue
266
267 if indata:
268 mo=self.patdatarow.match(line)
269 if mo is not None:
270
271 pos=int(mo.group(1), 16)
272 assert pos==len(curdata)
273 for i in range(9, min(len(line), 9+16*3), 3):
274 s=line[i:i+2]
275 if len(s)!=2 or s==" ":
276
277 continue
278 b=int(s,16)
279 curdata+=chr(b)
280 continue
281
282 indata=False
283 self.packets.append( (curtime, curdesc, curclass, curdata) )
284 curtime=curdesc=curclass=curdata=""
285
286
287 mo=self.patdataevent.match(line)
288 if mo is not None:
289 self.packets.append( (curtime, curdesc, curclass, curdata) )
290 curtime=curdesc=curclass=curdata=""
291 curtime=mo.group(1)
292 curdesc=mo.group(2)+mo.group(3)
293 indata=True
294 continue
295
296 mo=self.patevent.match(line)
297 if mo is not None:
298 self.packets.append( (curtime, curdesc, curclass, curdata) )
299 curtime=curdesc=curclass=curdata=""
300 curtime=mo.group(1)
301 curdesc=mo.group(2)
302 indata=True
303 continue
304
305 if len(curdesc):
306 curdesc+="\n"
307 curdesc+=line
308
309
310 self.packets.append( (curtime, curdesc, curclass, curdata) )
311
312
313
314 self.packets=filter(lambda item: reduce(lambda x,y: x+y, map(len, item)), self.packets)
315
317 """Display the current buffer offset in the format of
318 Pos: 0x12=18
319 """
320 if pos is None:
321 s=''
322 else:
323 s='Pos: 0x%X=%d'%(pos, pos)
324 self.SetStatusText(s, self._pos_pane_index)
325 - def set_sel(self, sel_start, sel_end):
326 if sel_start is None or sel_start==-1 or\
327 sel_end is None or sel_end==-1:
328 s=''
329 else:
330 sel_len=sel_end-sel_start
331 sel_end-=1
332 s='Sel: 0x%X=%d to 0x%X=%d (0x%X=%d bytes)'%(
333 sel_start, sel_start, sel_end, sel_end,
334 sel_len, sel_len)
335 self.SetStatusText(s, self._sel_pane_index)
337 if v:
338
339 s='Val: 0x%02X=%d'%(ord(v[0]), ord(v[0]))
340 if len(v)>1:
341
342 u_s=struct.unpack('<H', v[:struct.calcsize('<H')])[0]
343 s+=' 0x%04X=%d'%(u_s, u_s)
344 if len(v)>3:
345
346 u_i=struct.unpack('<I', v[:struct.calcsize('<I')])[0]
347 s+=' 0x%08X=%d'%(u_i, u_i)
348 else:
349 s=''
350 self.SetStatusText(s, self._val_pane_index)
351
352 if __name__=='__main__':
353 app=wx.PySimpleApp()
354
355 data=None
356 if len(sys.argv)==2:
357
358 data=common.opentextfile(sys.argv[1]).read()
359 frame=Analyser(data=data)
360 app.MainLoop()
361