Module hexeditor
[hide private]
[frames] | no frames]

Source Code for Module hexeditor

   1  #!/usr/bin/env python 
   2  ### BITPIM 
   3  ### 
   4  ### Copyright (C) 2003-2004 Roger Binns <rogerb@rogerbinns.com> 
   5  ### 
   6  ### This program is free software; you can redistribute it and/or modify 
   7  ### it under the terms of the BitPim license as detailed in the LICENSE file. 
   8  ### 
   9  ### $Id: hexeditor.py 4377 2007-08-27 04:58:33Z djpham $ 
  10   
  11  """A hex editor widget""" 
  12   
  13  # system modules 
  14  from __future__ import with_statement 
  15  import string 
  16  import struct 
  17   
  18  # wx modules 
  19  import wx 
  20  from wx.lib import masked 
  21  from wx.lib import scrolledpanel as scrolled 
  22   
  23  # bitpim modules 
  24  import common 
  25  import guihelper 
  26   
  27  #------------------------------------------------------------------------------- 
28 -class DataStruct(object):
29 - def __init__(self, _name):
30 self.name=_name 31 self.fields=[]
32 - def set(self, dict):
33 self.name=dict.keys()[0] 34 self.fields=[] 35 for f in dict[self.name]: 36 if f['type']==DataItem.numeric_type: 37 item=NumericDataItem(f['name']) 38 elif f['type']==DataItem.string_type: 39 item=StringDataItem(f['name']) 40 else: 41 item=DataItem(f['name'], DataItem.struct_type) 42 item.set(f) 43 self.fields.append(item)
44 - def get(self):
45 l=[] 46 for f in self.fields: 47 l.append(f.get()) 48 return { self.name: l }
49 - def encode(self, data, buffer_offset=0):
50 # encode data to each & every fields and return the results 51 l=[] 52 start=0 53 data_len=len(data) 54 for f in self.fields: 55 s=f.encode(data, start) 56 start=f.start+f.len 57 l.append( { '[0x%04X=%d]%s'%(f.start+buffer_offset, 58 f.start+buffer_offset, f.name): `s` }) 59 if start>=data_len: 60 break 61 return l
62 63 #-------------------------------------------------------------------------------
64 -class DataItem(object):
65 """Represent a data item/component with in a record, which is a list of 66 these things. 67 """ 68 offset_from_start='From Start' 69 offset_from_prev='From Last Field' 70 string_type='string' 71 numeric_type='numeric' 72 struct_type='struct'
73 - def __init__(self, _name, _type=numeric_type):
74 self.name=_name 75 self.offset_type=self.offset_from_start 76 self.offset=0 77 self.size=1 78 self.start=self.len=None # start & length/size of actual data encoded 79 # numeric fields 80 self.unsigned=True 81 self.LE=True 82 # string fields 83 self.fixed=True 84 self.null_terminated=False 85 self.type=_type
86 - def _get_type(self):
87 return self._type
88 - def _set_type(self, _type):
89 if _type not in (self.numeric_type, self.string_type, self.struct_type): 90 raise TypeError 91 self._type=_type 92 if _type==self.numeric_type: 93 self.__class__=NumericDataItem 94 elif _type==self.string_type: 95 self.__class__=StringDataItem
96 type=property(fget=_get_type, fset=_set_type)
97 - def get(self):
98 return { 'name': self.name, 'offset_type': self.offset_type, 99 'offset': self.offset, 'type': self.type }
100 - def set(self, d):
101 self.name=d.get('name', '<None>') 102 self.offset_type=d.get('offset_type', None) 103 self.offset=d.get('offset', None) 104 self.type=d.get('type', None)
105 - def encode(self, s, start=None):
106 """Encode the value of this item based on the string s""" 107 raise NotImplementedError
108 109 #-------------------------------------------------------------------------------
110 -class NumericDataItem(DataItem):
111 _fmts={ # struct pack/unpack formats 112 True: { # unsigned 113 True: { # little endian 114 1: 'B', 2: '<H', 4: '<I' }, # size 115 False: { # big endian 116 1: 'B', 2: '>H', 4: '>I' } }, # size 117 False: { # signed 118 True: { # little endian 119 1: 'b', 2: '<h', 4: '<i' }, # size 120 False: { # big endian 121 1: 'b', 2: '>h', 4: '>i' } } } # size 122
123 - def __init__(self, name):
124 super(NumericDataItem, self).__init__(name, self.numeric_type)
125 - def get(self):
126 r=super(NumericDataItem, self).get() 127 r.update( 128 { 'unsigned': self.unsigned, 129 'little_endian': self.LE, 130 'size': self.size }) 131 return r
132 - def set(self, d):
133 super(NumericDataItem, self).set(d) 134 if d.get('type', None)!=self.numeric_type: 135 raise TypeError 136 self.unsigned=d.get('unsigned', True) 137 self.LE=d.get('little_endian', True) 138 self.size=d.get('size', 1)
139 - def encode(self, s, start=None):
140 fmt=self._fmts[self.unsigned][self.LE][self.size] 141 self.len=struct.calcsize(fmt) 142 if self.offset_type==self.offset_from_start: 143 self.start=self.offset 144 else: 145 if start is None: 146 raise ValueError 147 self.start=start+self.offset 148 return struct.unpack(fmt, s[self.start:self.start+self.len])[0]
149 150 #-------------------------------------------------------------------------------
151 -class StringDataItem(DataItem):
152 - def __init__(self, name):
153 super(StringDataItem, self).__init__(name, self.string_type)
154 - def get(self):
155 r=super(StringDataItem, self).get() 156 r.update({ 'fixed': self.fixed, 'size': self.size, 157 'null_terminated': self.null_terminated }) 158 return r
159 - def set(self, d):
160 super(StringDataItem, self).set(d) 161 if d.get('type', None)!=self.string_type: 162 raise TypeError 163 self.fixed=d.get('fixed', True) 164 self.size=d.get('size', 0) 165 self.null_terminated=d.get('null_terminated', False)
166 - def encode(self, s, start=None):
167 if self.offset_type==self.offset_from_start: 168 self.start=self.offset 169 else: 170 if start is None: 171 raise ValueError 172 self.start=start+self.offset 173 if self.fixed: 174 # fixed length string 175 if self.size==-1: 176 # take all available space 177 self.len=len(s)-self.offset 178 s0=s[self.start:] 179 else: 180 # fixed size 181 s0=s[self.start:self.start+self.size] 182 self.len=self.size 183 else: 184 # pascal style variable string 185 self.len=ord(s[self.start]) 186 s0=s[self.start+1:self.start+1+self.len] 187 if self.null_terminated: 188 i=s0.find('\x00') 189 if i==-1: 190 return s0 191 else: 192 self.len=i 193 return s0[:i] 194 else: 195 return s0
196 197 #-------------------------------------------------------------------------------
198 -class GeneralInfoSizer(wx.FlexGridSizer):
199 - def __init__(self, parent):
200 super(GeneralInfoSizer, self).__init__(-1, 2, 5, 5) 201 self.AddGrowableCol(1) 202 self.Add(wx.StaticText(parent, -1, 'Struct Name:'), 0, wx.EXPAND|wx.ALL, 5) 203 self._struct_name=wx.TextCtrl(parent, -1, '') 204 self.Add(self._struct_name, 0, wx.EXPAND|wx.ALL, 5) 205 self.Add(wx.StaticText(parent, -1, 'Field Name:'), 0, wx.EXPAND|wx.ALL, 5) 206 self._name=wx.TextCtrl(parent, -1, '') 207 self.Add(self._name, 0, wx.EXPAND|wx.ALL, 5) 208 self.Add(wx.StaticText(parent, -1, 'Type:'), 0, wx.EXPAND|wx.ALL, 5) 209 self._type=wx.ComboBox(parent, wx.NewId(), 210 choices=[DataItem.numeric_type, 211 DataItem.string_type], 212 value=DataItem.numeric_type, 213 style=wx.CB_DROPDOWN|wx.CB_READONLY) 214 self.Add(self._type, 0, wx.EXPAND|wx.ALL, 5) 215 self.Add(wx.StaticText(parent, -1, 'Offset Type:'), 0, wx.EXPAND|wx.ALL, 5) 216 self._offset_type=wx.ComboBox(parent, -1, 217 value=DataItem.offset_from_start, 218 choices=[DataItem.offset_from_start, 219 DataItem.offset_from_prev], 220 style=wx.CB_DROPDOWN|wx.CB_READONLY) 221 self.Add(self._offset_type, 0, wx.EXPAND|wx.ALL, 5) 222 self.Add(wx.StaticText(parent, -1, 'Offset Value:'), 0, wx.EXPAND|wx.ALL, 5) 223 self._offset=masked.NumCtrl(parent, wx.NewId(), 224 allowNegative=False, 225 min=0) 226 self.Add(self._offset, 0, wx.ALL, 5) 227 self._fields_group=(self._name, self._type, self._offset_type, 228 self._offset)
229 - def set(self, data):
230 if isinstance(data, DataStruct): 231 self._struct_name.SetValue(data.name) 232 elif isinstance(data, DataItem): 233 self._name.SetValue(data.name) 234 self._type.SetValue(data.type) 235 self._offset_type.SetValue(data.offset_type) 236 self._offset.SetValue(data.offset)
237 - def get(self, data):
238 data.name=self._name.GetValue() 239 data.type=self._type.GetValue() 240 data.offset_type=self._offset_type.GetValue() 241 data.offset=int(self._offset.GetValue()) 242 return data
243 - def show(self, show_struct=False, show_field=False):
244 self._struct_name.Enable(show_struct) 245 for w in self._fields_group: 246 w.Enable(show_field)
247 - def _get_struct_name(self):
248 return self._struct_name.GetValue()
249 struct_name=property(fget=_get_struct_name)
250 - def _get_type(self):
251 return self._type.GetValue()
252 type=property(fget=_get_type)
253 - def _get_type_id(self):
254 return self._type.GetId()
255 type_id=property(fget=_get_type_id)
256 257 #-------------------------------------------------------------------------------
258 -class NumericInfoSizer(wx.FlexGridSizer):
259 _sign_choices=['Unsigned', 'Signed'] 260 _endian_choices=['Little Endian', 'Big Endian'] 261 _size_choices=['1', '2', '4']
262 - def __init__(self, parent):
263 super(NumericInfoSizer, self).__init__(-1, 2, 5, 5) 264 self.AddGrowableCol(1) 265 self.Add(wx.StaticText(parent, -1, 'Signed:'), 0, wx.EXPAND|wx.ALL, 5) 266 self._sign=wx.ComboBox(parent, -1, value=self._sign_choices[0], 267 choices=self._sign_choices, 268 style=wx.CB_DROPDOWN|wx.CB_READONLY) 269 self.Add(self._sign, 0, wx.EXPAND|wx.ALL, 5) 270 self.Add(wx.StaticText(parent, -1, 'Endian:'), 0, wx.EXPAND|wx.ALL, 5) 271 self._endian=wx.ComboBox(parent, -1, value=self._endian_choices[0], 272 choices=self._endian_choices, 273 style=wx.CB_DROPDOWN|wx.CB_READONLY) 274 self.Add(self._endian, 0, wx.EXPAND|wx.ALL, 5) 275 self.Add(wx.StaticText(parent, -1, 'Size:'), 0, wx.EXPAND|wx.ALL, 5) 276 self._size=wx.ComboBox(parent, -1, value=self._size_choices[0], 277 choices=self._size_choices, 278 style=wx.CB_DROPDOWN|wx.CB_READONLY) 279 self.Add(self._size, 0, wx.EXPAND|wx.ALL, 5)
280 - def set(self, data):
281 if data.unsigned: 282 self._sign.SetValue(self._sign_choices[0]) 283 else: 284 self._sign.SetValue(self._sign_choices[1]) 285 if data.LE: 286 self._endian.SetValue(self._endian_choices[0]) 287 else: 288 self._endian.SetValue(self._endian_choices[1]) 289 self._size.SetValue(`data.size`)
290 - def get(self, data):
291 data.unsigned=self._sign.GetValue()==self._sign_choices[0] 292 data.LE=self._endian.GetValue()==self._endian_choices[0] 293 data.size=int(self._size.GetValue()) 294 return data
295 296 #-------------------------------------------------------------------------------
297 -class StringInfoSizer(wx.FlexGridSizer):
298 _fixed_choices=['Fixed', 'Pascal']
299 - def __init__(self, parent):
300 super(StringInfoSizer, self).__init__(-1, 2, 5, 5) 301 self.AddGrowableCol(1) 302 self.Add(wx.StaticText(parent, -1, 'Fixed/Pascal:'), 0, wx.EXPAND|wx.ALL, 5) 303 self._fixed=wx.ComboBox(parent, -1, value=self._fixed_choices[0], 304 choices=self._fixed_choices, 305 style=wx.CB_DROPDOWN|wx.CB_READONLY) 306 self.Add(self._fixed, 0, wx.EXPAND|wx.ALL, 5) 307 self.Add(wx.StaticText(parent, -1, 'Max Length:'), 0, wx.EXPAND|wx.ALL, 5) 308 self._max_len=masked.NumCtrl(parent, -1, value=1, min=-1) 309 self.Add(self._max_len, 0, wx.EXPAND|wx.ALL, 5) 310 self.Add(wx.StaticText(parent, -1, 'Null Terminated:'), 0, wx.EXPAND|wx.ALL, 5) 311 self._null_terminated=wx.CheckBox(parent, -1) 312 self.Add(self._null_terminated, 0, wx.EXPAND|wx.ALL, 5)
313 - def set(self, data):
314 if data.fixed: 315 self._fixed.SetValue(self._fixed_choices[0]) 316 else: 317 self._fixed.SetValue(self._fixed_choices[1]) 318 self._max_len.SetValue(`data.size`) 319 self._null_terminated.SetValue(data.null_terminated)
320 - def get(self, data):
321 data.fixed=self._fixed.GetValue()==self._fixed_choices[0] 322 data.size=int(self._max_len.GetValue()) 323 data.null_terminated=self._null_terminated.GetValue() 324 return data
325 326 #-------------------------------------------------------------------------------
327 -class TemplateDialog(wx.Dialog):
328 _type_choices=['Numeric', 'String'] 329 _struct_type='struct' 330 _field_type='field'
331 - def __init__(self, parent):
332 super(TemplateDialog, self).__init__(parent, -1, 333 'Hex Template Editor', 334 style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) 335 self._data=[] 336 self._item_tree=self._numeric_bs=self._string_bs=None 337 self._general_bs=None 338 self._tree_root=None 339 self._field_info=self._field_info_hbs=None 340 self._info_sizer={ NumericDataItem.numeric_type: self._numeric_bs, 341 StringDataItem.string_type: self._string_bs } 342 main_vbs=wx.BoxSizer(wx.VERTICAL) 343 hbs1=wx.BoxSizer(wx.HORIZONTAL) 344 hbs1.Add(self._create_tree_pane(), 1, wx.EXPAND|wx.ALL, 5) 345 hbs1.Add(self._create_info_pane(), 2, wx.EXPAND|wx.ALL, 5) 346 main_vbs.Add(hbs1, 1, wx.EXPAND|wx.ALL, 5) 347 main_vbs.Add(wx.StaticLine(self, -1, style=wx.LI_HORIZONTAL), 0, wx.EXPAND|wx.ALL, 5) 348 main_vbs.Add(self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.HELP), 0, wx.ALIGN_CENTRE|wx.ALL, 5) 349 self.SetSizer(main_vbs) 350 self.SetAutoLayout(True) 351 main_vbs.Fit(self)
352
353 - def _create_tree_pane(self):
354 vbs=wx.BoxSizer(wx.VERTICAL) 355 sw=scrolled.ScrolledPanel(self, -1) 356 self._item_tree=wx.TreeCtrl(sw, wx.NewId(), 357 style=wx.TR_DEFAULT_STYLE|wx.TR_HAS_BUTTONS) 358 wx.EVT_TREE_SEL_CHANGED(self, self._item_tree.GetId(), 359 self._OnTreeSel) 360 self._tree_root=self._item_tree.AddRoot('Data Templates') 361 sw_bs=wx.BoxSizer(wx.VERTICAL) 362 sw_bs.Add(self._item_tree, 1, wx.EXPAND|wx.ALL, 0) 363 sw.SetSizer(sw_bs) 364 sw.SetAutoLayout(True) 365 sw_bs.Fit(sw) 366 sw.SetupScrolling() 367 vbs.Add(sw, 1, wx.EXPAND|wx.ALL, 5) 368 hbs=wx.BoxSizer(wx.HORIZONTAL) 369 hbs.Add(wx.Button(self, wx.ID_ADD, 'Add'), 0, wx.EXPAND|wx.ALL, 5) 370 hbs.Add(wx.Button(self, wx.ID_DELETE, 'Delete'), 0, wx.EXPAND|wx.ALL, 5) 371 wx.EVT_BUTTON(self, wx.ID_ADD, self._OnAdd) 372 wx.EVT_BUTTON(self, wx.ID_DELETE, self._OnDelete) 373 vbs.Add(hbs, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5) 374 return vbs
375 - def _create_info_pane(self):
376 # main boxsize 377 vbs=wx.BoxSizer(wx.VERTICAL) 378 hbs=wx.BoxSizer(wx.HORIZONTAL) 379 # Type & offset 380 static_bs=wx.StaticBoxSizer(wx.StaticBox(self, -1, 'Field Type'), 381 wx.VERTICAL) 382 self._general_bs=GeneralInfoSizer(self) 383 wx.EVT_COMBOBOX(self, self._general_bs.type_id, self._OnTypeChanged) 384 static_bs.Add(self._general_bs, 0, wx.EXPAND|wx.ALL, 5) 385 hbs.Add(static_bs, 0, wx.ALL, 5) 386 # all info 387 self._field_info=wx.StaticBoxSizer(wx.StaticBox(self, -1, 'Field Info'), 388 wx.VERTICAL) 389 # numeric info box 390 self._numeric_bs=NumericInfoSizer(self) 391 self._field_info.Add(self._numeric_bs, 0, wx.EXPAND|wx.ALL, 5) 392 self._string_bs=StringInfoSizer(self) 393 self._field_info.Add(self._string_bs, 0, wx.EXPAND|wx.ALL, 5) 394 hbs.Add(self._field_info, 0, wx.ALL, 5) 395 vbs.Add(hbs, 1, wx.EXPAND|wx.ALL, 5) 396 hbs1=wx.BoxSizer(wx.HORIZONTAL) 397 hbs1.Add(wx.Button(self, wx.ID_SAVE, 'Set'), 0, wx.EXPAND|wx.ALL, 5) 398 hbs1.Add(wx.Button(self, wx.ID_REVERT, 'Revert'), 0, wx.EXPAND|wx.ALL, 5) 399 wx.EVT_BUTTON(self, wx.ID_SAVE, self._OnSave) 400 wx.EVT_BUTTON(self, wx.ID_REVERT, self._OnRevert) 401 vbs.Add(hbs1, 0, wx.ALIGN_CENTER_HORIZONTAL, 0) 402 self._field_info_hbs=hbs 403 return vbs
404 - def _show_field_info(self, _struct=False, field=False, 405 numeric_field=False, string_field=False):
406 # show/hide individual fields 407 self._general_bs.show(_struct, field) 408 self._field_info.Show(self._numeric_bs, numeric_field) 409 self._field_info.Show(self._string_bs, string_field) 410 self._field_info.Layout() 411 self._field_info_hbs.Layout()
412 - def _populate(self):
413 # clear the tree and repopulate 414 self._item_tree.DeleteChildren(self._tree_root) 415 for i,e in enumerate(self._data): 416 item=self._item_tree.AppendItem(self._tree_root, e.name) 417 self._item_tree.SetPyData(item, { 'type': self._struct_type, 418 'index': i }) 419 for i1,e1 in enumerate(e.fields): 420 field_item=self._item_tree.AppendItem(item, e1.name) 421 self._item_tree.SetPyData(field_item, { 'type': self._field_type, 422 'index': i, 423 'field_index': i1 }) 424 self.expand()
425 - def _populate_struct(self, _item_index):
426 self._general_bs.set(self._data[_item_index]) 427 self._show_field_info(True)
428 - def _populate_each(self, _struct_index, _item_index):
429 _struct=self._data[_struct_index] 430 _item=_struct.fields[_item_index] 431 self._general_bs.set(_item) 432 if _item.type==DataItem.numeric_type: 433 self._show_field_info(True, True, True) 434 self._numeric_bs.set(_item) 435 else: 436 self._show_field_info(True, True, False, True) 437 self._string_bs.set(_item)
438 - def _OnTypeChanged(self, _):
439 new_type=self._general_bs.type 440 self._show_field_info(True, True, new_type==DataItem.numeric_type, 441 new_type==DataItem.string_type)
442 - def _OnAdd(self, _):
443 sel_idx=self._item_tree.GetSelection() 444 if not sel_idx.IsOk(): 445 return 446 if sel_idx==self._tree_root: 447 # add a new structure 448 struct_item=DataStruct('New Struct') 449 self._data.append(struct_item) 450 else: 451 # add a new field to the existing structure 452 data_item=self._item_tree.GetPyData(sel_idx) 453 item=NumericDataItem('New Field') 454 self._data[data_item['index']].fields.append(item) 455 self._populate()
456 - def _OnDelete(self, _):
457 sel_idx=self._item_tree.GetSelection() 458 if not sel_idx.IsOk(): 459 return 460 node_data=self._item_tree.GetPyData(sel_idx) 461 if node_data is None: 462 return 463 if node_data['type']==self._field_type: 464 # del this field 465 del self._data[node_data['index']].fields[node_data['field_index']] 466 else: 467 # del this struct and its fields 468 del self._data[node_data['index']] 469 # and re-populate the tree 470 self._populate()
471 - def _OnSave(self, _):
472 sel_idx=self._item_tree.GetSelection() 473 if not sel_idx.IsOk(): 474 return 475 node_data=self._item_tree.GetPyData(sel_idx) 476 if node_data is None: 477 return 478 # update the struct name 479 self._data[node_data['index']].name=self._general_bs.struct_name 480 if node_data['type']==self._field_type: 481 data_item=self._data[node_data['index']].\ 482 fields[node_data['field_index']] 483 data_item=self._general_bs.get(data_item) 484 if data_item.type==DataItem.numeric_type: 485 data_item=self._numeric_bs.get(data_item) 486 else: 487 data_item=self._string_bs.get(data_item) 488 self._data[node_data['index']].fields[node_data['field_index']]=data_item 489 self._item_tree.SetItemText(self._item_tree.GetItemParent(sel_idx), 490 self._data[node_data['index']].name) 491 self._item_tree.SetItemText(sel_idx, data_item.name) 492 else: 493 self._item_tree.SetItemText(sel_idx, self._data[node_data['index']].name)
494
495 - def _OnRevert(self, _):
496 sel_idx=self._item_tree.GetSelection() 497 if not sel_idx.IsOk(): 498 return 499 node_data=self._item_tree.GetPyData(sel_idx) 500 if node_data is None: 501 self._show_field_info() 502 else: 503 self._populate_struct(node_data['index']) 504 if node_data['type']==self._field_type: 505 self._populate_each(node_data['index'], node_data['field_index'])
506
507 - def _OnTreeSel(self, evt):
508 sel_idx=evt.GetItem() 509 if not sel_idx.IsOk(): 510 # invalid selection 511 return 512 item_data=self._item_tree.GetPyData(sel_idx) 513 if item_data is None: 514 self._show_field_info() 515 else: 516 self._populate_struct(item_data['index']) 517 if item_data['type']==self._field_type: 518 self._populate_each(item_data['index'], item_data['field_index'])
519 - def expand(self):
520 # expand the tree 521 self._item_tree.Expand(self._tree_root) 522 (id, cookie)=self._item_tree.GetFirstChild(self._tree_root) 523 while id.IsOk(): 524 self._item_tree.Expand(id) 525 (id, cookie)=self._item_tree.GetNextChild(self._tree_root, cookie)
526 - def set(self, l):
527 self._data=l 528 self._populate()
529 - def get(self):
530 return self._data
531 532 #-------------------------------------------------------------------------------
533 -class HexEditor(wx.ScrolledWindow):
534 535 _addr_range=xrange(8) 536 _hex_range_start=10 537 _hex_range_start2=33 538 _hex_range=xrange(_hex_range_start, 58) 539 _ascii_range_start=60 540 _ascii_range=xrange(60, 76) 541
542 - def __init__(self, parent, id=-1, style=wx.WANTS_CHARS, 543 _set_pos=None, _set_sel=None, _set_val=None):
544 wx.ScrolledWindow.__init__(self, parent, id, style=style) 545 self.parent=parent 546 self.data="" 547 self.title="" 548 self.buffer=None 549 self.hasfocus=False 550 self.dragging=False 551 self.current_ofs=None 552 self._module=None 553 self._templates=[] 554 self._search_string=None 555 # ways of displaying status 556 self.set_pos=_set_pos or self._set_pos 557 self.set_val=_set_val or self._set_val 558 self.set_sel=_set_sel or self._set_sel 559 # some GUI setup 560 self.SetBackgroundColour("WHITE") 561 self.SetCursor(wx.StockCursor(wx.CURSOR_IBEAM)) 562 self.sethighlight(wx.NamedColour("BLACK"), wx.NamedColour("YELLOW")) 563 self.setnormal(wx.NamedColour("BLACK"), wx.NamedColour("WHITE")) 564 self.setfont(wx.TheFontList.FindOrCreateFont(10, wx.MODERN, wx.NORMAL, wx.NORMAL)) 565 self.OnSize(None) 566 self.highlightrange(None, None) 567 # other stuff 568 self._create_context_menu() 569 self._map_events()
570
571 - def _map_events(self):
572 wx.EVT_SCROLLWIN(self, self.OnScrollWin) 573 wx.EVT_PAINT(self, self.OnPaint) 574 wx.EVT_SIZE(self, self.OnSize) 575 wx.EVT_ERASE_BACKGROUND(self, self.OnEraseBackground) 576 wx.EVT_SET_FOCUS(self, self.OnGainFocus) 577 wx.EVT_KILL_FOCUS(self, self.OnLoseFocus) 578 wx.EVT_LEFT_DOWN(self, self.OnStartSelection) 579 wx.EVT_LEFT_UP(self, self.OnEndSelection) 580 wx.EVT_MOTION(self, self.OnMakeSelection) 581 wx.EVT_RIGHT_UP(self, self.OnRightClick)
582
583 - def _create_context_menu(self):
584 self._reload_menu_id=self._apply_menu_id=None 585 menu_items=( 586 ('File', (('Load', self.OnLoadFile), 587 ('Save As', self.OnSaveAs), 588 ('Save Selection As', self.OnSaveSelection), 589 ('Save Hexdump As', self.OnSaveHexdumpAs))), 590 ('Set Selection', (('Start', self.OnStartSelMenu), 591 ('End', self.OnEndSelMenu))), 592 ('Value', self.OnViewValue), 593 ('Search', (('Search', self.OnSearch), 594 ('Search Again', self.OnSearchAgain))), 595 ('Import Python Module', self.OnImportModule), 596 ('Reload Python Module', self.OnReloadModule, '_reload_menu_id'), 597 ('Apply Python Func', self.OnApplyFunc, '_apply_menu_id'), 598 ('Template', (('Load', self.OnTemplateLoad), 599 ('Save As', self.OnTemplateSaveAs), 600 ('Edit', self.OnTemplateEdit), 601 ('Apply', self.OnTemplateApply))) 602 ) 603 self._bgmenu=wx.Menu() 604 for menu_item in menu_items: 605 if isinstance(menu_item[1], tuple): 606 # submenu 607 sub_menu=wx.Menu() 608 for submenu_item in menu_item[1]: 609 id=wx.NewId() 610 sub_menu.Append(id, submenu_item[0]) 611 wx.EVT_MENU(self, id, submenu_item[1]) 612 self._bgmenu.AppendMenu(wx.NewId(), menu_item[0], sub_menu) 613 else: 614 # regular menu item 615 id=wx.NewId() 616 self._bgmenu.Append(id, menu_item[0]) 617 wx.EVT_MENU(self, id, menu_item[1]) 618 if len(menu_item)>2: 619 # need to save menu ID 620 setattr(self, menu_item[2], id)
621
622 - def SetData(self, data):
623 self.data=data 624 self.needsupdate=True 625 self.updatescrollbars() 626 self.Refresh()
627
628 - def SetTitle(self, title):
629 self.title=title
630
631 - def SetStatusDisplay(self, _set_pos=None, _set_sel=None, _set_val=None):
632 self.set_pos=_set_pos or self._set_pos 633 self.set_sel=_set_sel or self._set_sel 634 self.set_val=_set_val or self._set_val
635
636 - def OnEraseBackground(self, _):
637 pass
638 - def _set_pos(self, pos):
639 pass
640 - def _set_sel(self, sel_start, sel_end):
641 pass
642 - def _set_val(self, v):
643 pass
644
645 - def _to_char_line(self, x, y):
646 """Convert an x,y point to (char, line) 647 """ 648 return x/self.charwidth, y/self.charheight
649 - def _to_xy(self, char, line):
650 return char*self.charwidth, line*self.charheight
651 - def _to_buffer_offset(self, char, line):
652 if char in self._hex_range: 653 if char>self._hex_range_start2: 654 char-=1 655 if ((char-self._hex_range_start)%3)<2: 656 return line*16+(char-self._hex_range_start)/3 657 elif char in self._ascii_range: 658 return line*16+char-self._ascii_range_start
659 - def _set_and_move(self, evt):
660 c,l=self._to_char_line(evt.GetX(), evt.GetY()) 661 self.GetCaret().Move(self._to_xy(c, l)) 662 x0, y0=self.GetViewStart() 663 char_x=c+x0 664 line_y=l+y0 665 return self._to_buffer_offset(char_x, line_y)
666 _value_formats=( 667 ('unsigned char', 'B', struct.calcsize('B')), 668 ('signed char', 'b', struct.calcsize('b')), 669 ('LE unsigned short', '<H', struct.calcsize('<H')), 670 ('LE signed short', '<h', struct.calcsize('<h')), 671 ('BE unsigned short', '>H', struct.calcsize('>H')), 672 ('BE signed short', '>h', struct.calcsize('>h')), 673 ('LE unsigned int', '<I', struct.calcsize('<I')), 674 ('LE signed int', '<i', struct.calcsize('<i')), 675 ('BE unsigned int', '>I', struct.calcsize('>I')), 676 ('BE signed int', '>i', struct.calcsize('>i')), 677 )
678 - def _gen_values(self, _data, _ofs):
679 """ Generate the values of various number formats starting at the 680 current offset. 681 """ 682 n=_data[_ofs:] 683 len_n=len(n) 684 s='0x%X=%d'%(_ofs, _ofs) 685 res=[{ 'Data Offset': s}, {'':''} ] 686 for i,e in enumerate(self._value_formats): 687 if len_n<e[2]: 688 continue 689 v=struct.unpack(e[1], n[:e[2]])[0] 690 if i%2: 691 s='%d'%v 692 else: 693 fmt='0x%0'+str(e[2]*2)+'X=%d' 694 s=fmt%(v,v) 695 res.append({ e[0]: s }) 696 return res
697
698 - def _apply_template(self, template_name):
699 # if user specifies a block, encode that, 700 if self.highlightstart is None or self.highlightstart==-1 or \ 701 self.highlightend is None or self.highlightend==-1: 702 # no selection 703 _data=self.data[self.current_ofs:] 704 _ofs=self.current_ofs 705 else: 706 _data=self.data[self.highlightstart:self.highlightend] 707 _ofs=self.highlightstart 708 for f in self._templates: 709 if f.name==template_name: 710 l=[{ 'Template': f.name }, 711 { 'Data Offset': '0x%04X=%d'%(_ofs, _ofs) }] 712 return l+f.encode(_data, _ofs) 713 return []
714
715 - def _display_result(self, result):
716 """ Display the results from applying a Python routine over the data 717 """ 718 s='' 719 for d in result: 720 for k,e in d.items(): 721 s+=k+':\t'+e+'\n' 722 guihelper.MessageDialog(self, s, 'Results', style=wx.OK)
723
724 - def OnLoadFile(self, _):
725 with guihelper.WXDialogWrapper(wx.FileDialog(self, 'Select a file to load', 726 style=wx.OPEN|wx.FILE_MUST_EXIST), 727 True) as (dlg, retcode): 728 if retcode==wx.ID_OK: 729 self.SetData(file(dlg.GetPath(), 'rb').read())
730 - def OnSaveAs(self, _):
731 with guihelper.WXDialogWrapper(wx.FileDialog(self, 'Select a file to save', 732 style=wx.SAVE|wx.OVERWRITE_PROMPT), 733 True) as (dlg, retcode): 734 if retcode==wx.ID_OK: 735 file(dlg.GetPath(), 'wb').write(self.data)
736 - def hexdumpdata(self):
737 res="" 738 l=len(self.data) 739 if self.title: 740 res += self.title+": "+`l`+" bytes\n" 741 res += "<#! !#>\n" 742 pos=0 743 while pos<l: 744 text="%08X "%(pos) 745 line=self.data[pos:pos+16] 746 for i in range(len(line)): 747 text+="%02X "%(ord(line[i])) 748 text+=" "*(16-len(line)) 749 text+=" " 750 for i in range(len(line)): 751 c=line[i] 752 if (ord(c)>=32 and string.printable.find(c)>=0): 753 text+=c 754 else: 755 text+='.' 756 res+=text+"\n" 757 pos+=16 758 return res
759
760 - def OnSaveHexdumpAs(self, _):
761 with guihelper.WXDialogWrapper(wx.FileDialog(self, 'Select a file to save', 762 style=wx.SAVE|wx.OVERWRITE_PROMPT), 763 True) as (dlg, retcode): 764 if retcode==wx.ID_OK: 765 file(dlg.GetPath(), 'wb').write(self.hexdumpdata())
766 - def OnSaveSelection(self, _):
767 if self.highlightstart is None or self.highlightstart==-1 or \ 768 self.highlightend is None or self.highlightend==-1: 769 # no selection 770 return 771 with guihelper.WXDialogWrapper(wx.FileDialog(self, 'Select a file to save', 772 style=wx.SAVE|wx.OVERWRITE_PROMPT), 773 True) as (dlg, retcode): 774 if retcode==wx.ID_OK: 775 file(dlg.GetPath(), 'wb').write( 776 self.data[self.highlightstart:self.highlightend])
777
778 - def OnReloadModule(self, _):
779 try: 780 reload(self._module) 781 except: 782 self._module=None 783 guihelper.MessageDialog(self, 'Failed to reload module', 784 'Reload Module Error', 785 style=wx.OK|wx.ICON_ERROR)
786
787 - def OnApplyFunc(self, _):
788 choices=[x for x in dir(self._module) \ 789 if callable(getattr(self._module, x))] 790 with guihelper.WXDialogWrapper(wx.SingleChoiceDialog(self, 'Select a function to apply:', 791 'Apply Python Func', 792 choices), 793 True) as (dlg, retcode): 794 if retcode==wx.ID_OK: 795 try: 796 res=getattr(self._module, dlg.GetStringSelection())( 797 self, self.data, self.current_ofs) 798 self._display_result(res) 799 except: 800 guihelper.MessageDialog(self, 'Apply Func raised an exception', 801 'Apply Func Error', 802 style=wx.OK|wx.ICON_ERROR)
803
804 - def OnImportModule(self, _):
805 with guihelper.WXDialogWrapper(wx.TextEntryDialog(self, 'Enter the name of a Python Module:', 806 'Module Import'), 807 True) as (dlg, retcode): 808 if retcode==wx.ID_OK: 809 try: 810 self._module=common.importas(dlg.GetValue()) 811 except ImportError: 812 self._module=None 813 guihelper.MessageDialog(self, 'Failed to import module: '+dlg.GetValue(), 814 'Module Import Error', 815 style=wx.OK|wx.ICON_ERROR)
816
817 - def OnStartSelMenu(self, evt):
818 ofs=self.current_ofs 819 if ofs is not None: 820 self.highlightstart=ofs 821 self.needsupdate=True 822 self.Refresh() 823 self.set_sel(self.highlightstart, self.highlightend)
824
825 - def OnEndSelMenu(self, _):
826 ofs=self.current_ofs 827 if ofs is not None: 828 self.highlightend=ofs+1 829 self.needsupdate=True 830 self.Refresh() 831 self.set_sel(self.highlightstart, self.highlightend)
832
833 - def OnViewValue(self, _):
834 ofs=self.current_ofs 835 if ofs is not None: 836 self._display_result(self._gen_values(self.data, ofs))
837
838 - def OnStartSelection(self, evt):
839 self.highlightstart=self.highlightend=None 840 ofs=self._set_and_move(evt) 841 if ofs is not None: 842 self.highlightstart=ofs 843 self.dragging=True 844 self.set_val(self.data[ofs:]) 845 else: 846 self.set_val(None) 847 self.needsupdate=True 848 self.Refresh() 849 self.set_pos(ofs) 850 self.set_sel(self.highlightstart, self.highlightend)
851
852 - def OnMakeSelection(self, evt):
853 if not self.dragging: 854 return 855 ofs=self._set_and_move(evt) 856 if ofs is not None: 857 self.highlightend=ofs+1 858 self.needsupdate=True 859 self.Refresh() 860 self.set_pos(ofs) 861 self.set_sel(self.highlightstart, self.highlightend)
862 - def OnEndSelection(self, evt):
863 self.dragging=False 864 ofs=self._set_and_move(evt) 865 self.set_pos(ofs) 866 self.set_sel(self.highlightstart, self.highlightend)
867
868 - def OnRightClick(self, evt):
869 self.current_ofs=self._set_and_move(evt) 870 if self.current_ofs is None: 871 self.set_val(None) 872 else: 873 self.set_val(self.data[self.current_ofs:]) 874 self.set_pos(self.current_ofs) 875 self._bgmenu.Enable(self._apply_menu_id, self._module is not None) 876 self._bgmenu.Enable(self._reload_menu_id, self._module is not None) 877 self.PopupMenu(self._bgmenu, evt.GetPosition())
878
879 - def OnTemplateLoad(self, _):
880 with guihelper.WXDialogWrapper(wx.FileDialog(self, 'Select a file to load', 881 wildcard='*.tmpl', 882 style=wx.OPEN|wx.FILE_MUST_EXIST), 883 True) as (dlg, retcode): 884 if retcode==wx.ID_OK: 885 result={} 886 try: 887 execfile(dlg.GetPath()) 888 except UnicodeError: 889 common.unicode_execfile(dlg.GetPath()) 890 exist_keys={} 891 for i,e in enumerate(self._templates): 892 exist_keys[e.name]=i 893 for d in result['templates']: 894 data_struct=DataStruct('new struct') 895 data_struct.set(d) 896 if exist_keys.has_key(data_struct.name): 897 self._templates[exist_keys[data_struct.name]]=data_struct 898 else: 899 self._templates.append(data_struct)
900
901 - def OnTemplateSaveAs(self, _):
902 with guihelper.WXDialogWrapper(wx.FileDialog(self, 'Select a file to save', 903 wildcard='*.tmpl', 904 style=wx.SAVE|wx.OVERWRITE_PROMPT), 905 True) as (dlg, retcode): 906 if retcode==wx.ID_OK: 907 r=[x.get() for x in self._templates] 908 common.writeversionindexfile(dlg.GetPath(), 909 { 'templates': r }, 1)
910
911 - def OnTemplateApply(self, _):
912 if not self._templates: 913 # no templates to apply 914 return 915 choices=[x.name for x in self._templates] 916 with guihelper.WXDialogWrapper(wx.SingleChoiceDialog(self, 'Select a template to apply:', 917 'Apply Data Template', 918 choices), 919 True) as (dlg, retcode): 920 if retcode==wx.ID_OK: 921 try: 922 res=self._apply_template(dlg.GetStringSelection()) 923 self._display_result(res) 924 except: 925 guihelper.MessageDialog(self, 'Apply Template raised an exception', 926 'Apply Template Error', 927 style=wx.OK|wx.ICON_ERROR),
928
929 - def OnTemplateEdit(self, _):
930 dlg=TemplateDialog(self) 931 dlg.set(self._templates) 932 with guihelper.WXDialogWrapper(dlg, True) as (dlg, retcode): 933 if retcode==wx.ID_OK: 934 self._templates=dlg.get()
935
936 - def OnSearch(self, evt):
937 with guihelper.WXDialogWrapper(wx.TextEntryDialog(self, 'Enter data to search (1 0x23 045 ...):', 938 'Search Data'), 939 True) as (dlg, retcode): 940 if retcode==wx.ID_OK: 941 l=dlg.GetValue().split(' ') 942 s='' 943 for e in l: 944 if e[0:2]=='0x': 945 s+=chr(int(e, 16)) 946 elif e[0]=='0': 947 s+=chr(int(e, 8)) 948 else: 949 s+=chr(int(e)) 950 i=self.data[self.current_ofs:].find(s) 951 if i!=-1: 952 self._search_string=s 953 self.highlightstart=i+self.current_ofs 954 self.highlightend=self.highlightstart+len(s) 955 self.needsupdate=True 956 self.Refresh() 957 self.set_sel(self.highlightstart, self.highlightend) 958 else: 959 self._search_string=None
960
961 - def OnSearchAgain(self, evt):
962 if self._search_string is not None: 963 i=self.data[self.current_ofs:].find(self._search_string) 964 if i==-1: 965 return 966 self.highlightstart=i+self.current_ofs 967 self.highlightend=self.highlightstart+len(self._search_string) 968 self.needsupdate=True 969 self.Refresh() 970 self.set_sel(self.highlightstart, self.highlightend)
971
972 - def OnSize(self, evt):
973 # uncomment these lines to prevent going wider than is needed 974 # if self.width>self.widthinchars*self.charwidth: 975 # self.SetClientSize( (self.widthinchars*self.charwidth, self.height) ) 976 if evt is None: 977 self.width=(self.widthinchars+3)*self.charwidth 978 self.height=self.charheight*20 979 self.SetClientSize((self.width, self.height)) 980 self.SetCaret(wx.Caret(self, (self.charwidth, self.charheight))) 981 self.GetCaret().Show(True) 982 else: 983 self.width,self.height=self.GetClientSizeTuple() 984 self.needsupdate=True
985
986 - def OnGainFocus(self,_):
987 self.hasfocus=True 988 self.needsupdate=True 989 self.Refresh()
990
991 - def OnLoseFocus(self,_):
992 self.hasfocus=False 993 self.needsupdate=True 994 self.Refresh()
995
996 - def highlightrange(self, start, end):
997 self.needsupdate=True 998 self.highlightstart=start 999 self.highlightend=end 1000 self.Refresh() 1001 self.set_pos(None) 1002 self.set_sel(self.highlightstart, self.highlightend) 1003 self.set_val(None)
1004
1005 - def _ishighlighted(self, pos):
1006 return pos>=self.highlightstart and pos<self.highlightend
1007
1008 - def sethighlight(self, foreground, background):
1009 self.highlight=foreground,background
1010
1011 - def setnormal(self, foreground, background):
1012 self.normal=foreground,background
1013
1014 - def setfont(self, font):
1015 dc=wx.ClientDC(self) 1016 dc.SetFont(font) 1017 self.charwidth, self.charheight=dc.GetTextExtent("M") 1018 self.font=font 1019 self.updatescrollbars()
1020
1021 - def updatescrollbars(self):
1022 # how many lines are we? 1023 lines=len(self.data)/16 1024 if lines==0 or len(self.data)%16: 1025 lines+=1 1026 self.datalines=lines 1027 ## lines+=1 # status line 1028 # fixed width 1029 self.widthinchars=8+2+3*16+1+2+16 1030 self.SetScrollbars(self.charwidth, self.charheight, self.widthinchars, lines, self.GetViewStart()[0], self.GetViewStart()[1])
1031
1032 - def _setnormal(self,dc):
1033 dc.SetTextForeground(self.normal[0]) 1034 dc.SetTextBackground(self.normal[1])
1035
1036 - def _sethighlight(self,dc):
1037 dc.SetTextForeground(self.highlight[0]) 1038 dc.SetTextBackground(self.highlight[1])
1039
1040 - def _setstatus(self,dc):
1041 dc.SetTextForeground(self.normal[1]) 1042 dc.SetTextBackground(self.normal[0]) 1043 dc.SetBrush(wx.BLACK_BRUSH)
1044 1045
1046 - def OnDraw(self, dc):
1047 xd,yd=self.GetViewStart() 1048 st=0 # 0=normal, 1=highlight 1049 dc.BeginDrawing() 1050 dc.SetBackgroundMode(wx.SOLID) 1051 dc.SetFont(self.font) 1052 for line in range(yd, min(self.datalines, yd+self.height/self.charheight+1)): 1053 # address 1054 self._setnormal(dc) 1055 st=0 1056 dc.DrawText("%08X" % (line*16), 0, line*self.charheight) 1057 # bytes 1058 for i in range(16): 1059 pos=line*16+i 1060 if pos>=len(self.data): 1061 break 1062 hl=self._ishighlighted(pos) 1063 if hl!=st: 1064 if hl: 1065 st=1 1066 self._sethighlight(dc) 1067 else: 1068 st=0 1069 self._setnormal(dc) 1070 if hl: 1071 space="" 1072 if i<15: 1073 if self._ishighlighted(pos+1): 1074 space=" " 1075 if i==7: 1076 space=" " 1077 else: 1078 space="" 1079 c=self.data[pos] 1080 dc.DrawText("%02X%s" % (ord(c),space), (10+(3*i)+(i>=8))*self.charwidth, line*self.charheight) 1081 if not (ord(c)>=32 and string.printable.find(c)>=0): 1082 c='.' 1083 dc.DrawText(c, (10+(3*16)+2+i)*self.charwidth, line*self.charheight) 1084 1085 ## if self.hasfocus: 1086 ## self._setstatus(dc) 1087 ## w,h=self.GetClientSizeTuple() 1088 ## dc.DrawRectangle(0,h-self.charheight+yd*self.charheight,self.widthinchars*self.charwidth,self.charheight) 1089 ## dc.DrawText("A test of stuff "+`yd`, 0, h-self.charheight+yd*self.charheight) 1090 1091 dc.EndDrawing()
1092
1093 - def updatebuffer(self):
1094 if self.buffer is None or \ 1095 self.buffer.GetWidth()!=self.width or \ 1096 self.buffer.GetHeight()!=self.height: 1097 if self.buffer is not None: 1098 del self.buffer 1099 self.buffer=wx.EmptyBitmap(self.width, self.height) 1100 1101 mdc=wx.MemoryDC() 1102 mdc.SelectObject(self.buffer) 1103 mdc.SetBackground(wx.TheBrushList.FindOrCreateBrush(self.GetBackgroundColour(), wx.SOLID)) 1104 mdc.Clear() 1105 self.PrepareDC(mdc) 1106 self.OnDraw(mdc) 1107 mdc.SelectObject(wx.NullBitmap) 1108 del mdc
1109
1110 - def OnPaint(self, event):
1111 if self.needsupdate: 1112 self.needsupdate=False 1113 self.updatebuffer() 1114 dc=wx.PaintDC(self) 1115 dc.BeginDrawing() 1116 dc.DrawBitmap(self.buffer, 0, 0, False) 1117 dc.EndDrawing()
1118
1119 - def OnScrollWin(self, event):
1120 self.needsupdate=True 1121 self.Refresh() # clear whole widget 1122 event.Skip() # default event handlers now do scrolling etc
1123
1124 -class HexEditorDialog(wx.Dialog):
1125 _pane_widths=[-2, -3, -4] 1126 _pos_pane_index=0 1127 _sel_pane_index=1 1128 _val_pane_index=2
1129 - def __init__(self, parent, data='', title='BitPim Hex Editor', helpd_id=-1):
1130 super(HexEditorDialog, self).__init__(parent, -1, title, 1131 size=(500, 500), 1132 style=wx.DEFAULT_DIALOG_STYLE|\ 1133 wx.RESIZE_BORDER) 1134 self._status_bar=wx.StatusBar(self, -1) 1135 self._status_bar.SetFieldsCount(len(self._pane_widths)) 1136 self._status_bar.SetStatusWidths(self._pane_widths) 1137 vbs=wx.BoxSizer(wx.VERTICAL) 1138 self._hex_editor=HexEditor(self, _set_pos=self.set_pos, 1139 _set_val=self.set_val, 1140 _set_sel=self.set_sel) 1141 self._hex_editor.SetData(data) 1142 self._hex_editor.SetTitle(title) 1143 vbs.Add(self._hex_editor, 1, wx.EXPAND|wx.ALL, 5) 1144 vbs.Add(wx.StaticLine(self), 0, wx.EXPAND|wx.ALL, 5) 1145 ok_btn=wx.Button(self, wx.ID_OK, 'OK') 1146 vbs.Add(ok_btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5) 1147 vbs.Add(self._status_bar, 0, wx.EXPAND|wx.ALL, 0) 1148 self.SetSizer(vbs) 1149 self.SetAutoLayout(True) 1150 vbs.Fit(self)
1151 - def set_pos(self, pos):
1152 """Display the current buffer offset in the format of 1153 Pos: 0x12=18 1154 """ 1155 if pos is None: 1156 s='' 1157 else: 1158 s='Pos: 0x%X=%d'%(pos, pos) 1159 self._status_bar.SetStatusText(s, self._pos_pane_index)
1160 - def set_sel(self, sel_start, sel_end):
1161 if sel_start is None or sel_start==-1 or\ 1162 sel_end is None or sel_end ==-1: 1163 s='' 1164 else: 1165 sel_len=sel_end-sel_start 1166 sel_end-=1 1167 s='Sel: 0x%X=%d to 0x%X=%d (0x%X=%d bytes)'%( 1168 sel_start, sel_start, sel_end, sel_end, 1169 sel_len, sel_len) 1170 self._status_bar.SetStatusText(s, self._sel_pane_index)
1171 - def set_val(self, v):
1172 if v: 1173 # char 1174 s='Val: 0x%02X=%d'%(ord(v[0]), ord(v[0])) 1175 if len(v)>1: 1176 # short 1177 u_s=struct.unpack('<H', v[:struct.calcsize('<H')])[0] 1178 s+=' 0x%04X=%d'%(u_s, u_s) 1179 if len(v)>3: 1180 # int/long 1181 u_i=struct.unpack('<I', v[:struct.calcsize('<I')])[0] 1182 s+=' 0x%08X=%d'%(u_i, u_i) 1183 else: 1184 s='' 1185 self._status_bar.SetStatusText(s, self._val_pane_index)
1186
1187 - def set(self, data):
1188 self._hex_editor.SetData(data)
1189 1190 1191 if __name__=='__main__': 1192 import sys 1193 1194 if len(sys.argv)!=2: 1195 print 'Usage:',sys.argv[0],'<File Name>' 1196 sys.exit(1) 1197 app=wx.PySimpleApp() 1198 with guihelper.WXDialogWrapper(HexEditorDialog(None, file(sys.argv[1], 'rb').read(), 1199 sys.argv[1]), 1200 True): 1201 pass 1202 sys.exit(0) 1203