emonti-hexwrench 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,62 @@
1
+
2
+ # This class was automatically generated from XRC source. It is not
3
+ # recommended that this file is edited directly; instead, inherit from
4
+ # this class and extend its behaviour there.
5
+ #
6
+ # Source file: ui/gui.xrc
7
+ # Generated at: Sun Feb 15 15:08:37 -0600 2009
8
+
9
+ class Hexwrench::EditorFrameBase < Wx::Frame
10
+
11
+ attr_reader :top_menu_bar, :mitem_open, :mitem_new, :mitem_save,
12
+ :mitem_quit, :mitem_copy, :mitem_cut, :mitem_paste,
13
+ :mitem_select_all, :mitem_select_range,
14
+ :mitem_adv_search, :mitem_data_inspector,
15
+ :mitem_strings, :util_bar, :util_jump, :util_search,
16
+ :util_search_kind, :util_ins_chk, :status_bar
17
+
18
+ def initialize(parent = nil)
19
+ super()
20
+ xml = Wx::XmlResource.get
21
+ xml.flags = 2 # Wx::XRC_NO_SUBCLASSING
22
+ xml.init_all_handlers
23
+ xml.load(File.dirname(__FILE__) + "/ui/gui.xrc")
24
+ xml.load_frame_subclass(self, parent, "editor_frame")
25
+
26
+ finder = lambda do | x |
27
+ int_id = Wx::xrcid(x)
28
+ begin
29
+ Wx::Window.find_window_by_id(int_id, self) || int_id
30
+ # Temporary hack to work around regression in 1.9.2; remove
31
+ # begin/rescue clause in later versions
32
+ rescue RuntimeError
33
+ int_id
34
+ end
35
+ end
36
+
37
+ @top_menu_bar = finder.call("top_menu_bar")
38
+ @mitem_open = finder.call("mitem_open")
39
+ @mitem_new = finder.call("mitem_new")
40
+ @mitem_save = finder.call("mitem_save")
41
+ @mitem_quit = finder.call("mitem_quit")
42
+ @mitem_copy = finder.call("mitem_copy")
43
+ @mitem_cut = finder.call("mitem_cut")
44
+ @mitem_paste = finder.call("mitem_paste")
45
+ @mitem_select_all = finder.call("mitem_select_all")
46
+ @mitem_select_range = finder.call("mitem_select_range")
47
+ @mitem_adv_search = finder.call("mitem_adv_search")
48
+ @mitem_data_inspector = finder.call("mitem_data_inspector")
49
+ @mitem_strings = finder.call("mitem_strings")
50
+ @util_bar = finder.call("util_bar")
51
+ @util_jump = finder.call("util_jump")
52
+ @util_search = finder.call("util_search")
53
+ @util_search_kind = finder.call("util_search_kind")
54
+ @util_ins_chk = finder.call("util_ins_chk")
55
+ @status_bar = finder.call("status_bar")
56
+ if self.class.method_defined? "on_init"
57
+ self.on_init()
58
+ end
59
+ end
60
+ end
61
+
62
+
@@ -0,0 +1,72 @@
1
+ # experimental "Wx::Grid" version of the strings window
2
+
3
+ require 'rbkb/extends'
4
+
5
+ module Hexwrench
6
+ class StringsFrame < Wx::Frame
7
+ def initialize(parent, data, strings_opts=nil)
8
+ super(parent, :title => "Strings")
9
+ @grid = Wx::Grid.new(self)
10
+
11
+ @data = data
12
+ @strings_opts =(strings_opts || {})
13
+ @strings_opts[:font] ||=
14
+ Wx::Font.new(10, Wx::MODERN, Wx::NORMAL, Wx::NORMAL)
15
+
16
+ make_grid()
17
+ end
18
+
19
+ def make_grid()
20
+ tbl = StringsTableBase.new(@data, @strings_opts)
21
+ @grid.set_table(tbl, Wx::Grid::GridSelectRows)
22
+ @grid.set_row_label_size(0)
23
+ @grid.enable_grid_lines(false)
24
+ @grid.disable_drag_row_size()
25
+ @grid.disable_drag_grid_size()
26
+ @grid.set_label_font(@strings_opts[:font])
27
+ end
28
+ end
29
+
30
+ class StringsTableBase < Wx::GridTableBase
31
+ def initialize(data, strings_opts=nil)
32
+ super()
33
+ strings_opts ||= {}
34
+ @font = strings_opts[:font]
35
+ @font ||= Wx::Font.new(10, Wx::MODERN, Wx::NORMAL, Wx::NORMAL)
36
+ @cell_attr = Wx::GridCellAttr.new( Wx::BLACK, Wx::WHITE, @font,
37
+ Wx::ALIGN_LEFT, Wx::ALIGN_CENTRE)
38
+ @cell_attr.set_read_only(true)
39
+ @strings = data.strings(strings_opts)
40
+ end
41
+
42
+ def get_number_cols
43
+ 4
44
+ end
45
+
46
+ def get_number_rows
47
+ @strings.size
48
+ end
49
+
50
+ def get_col_label_value(col)
51
+ ["start", "end", "kind", "string"][col]
52
+ end
53
+
54
+ def get_row_label_value(row)
55
+ ""
56
+ end
57
+
58
+ def get_value(row, col)
59
+ val=@strings[row][col].to_s
60
+ return (col > 2)? val.inspect : val
61
+ end
62
+
63
+ def is_empty_cell(row, col)
64
+ (r=@strings[row]).nil? or r[col].nil?
65
+ end
66
+
67
+ def get_attr(*args)
68
+ @cell_attr.clone
69
+ end
70
+
71
+ end
72
+ end
@@ -0,0 +1,105 @@
1
+ ### DEPRECATED by stringsvlist.rb
2
+
3
+ require 'rbkb/extends'
4
+
5
+ module Hexwrench
6
+ class StringsFrame < Wx::Frame
7
+ attr_reader :strings_list
8
+ def initialize(parent, editor, strings_opts=nil)
9
+ unless @editor = editor
10
+ Kernel.raise "#{self.class}.new() requires an editor window parameter"
11
+ end
12
+
13
+ super(parent, :title => "Strings")
14
+
15
+ @strings_list = StringsList.new(self, @editor, strings_opts)
16
+ @strings_list.evt_window_destroy do |evt|
17
+ self.destroy() rescue (ObjectPreviouslyDeleted)
18
+ evt.skip(true)
19
+ end
20
+
21
+ evt_list_item_selected(@strings_list) do |evt|
22
+ s_off, e_off, kind, str = evt.item.data
23
+ if @editor.select_range(s_off..e_off-1)
24
+ @editor.set_area_ascii
25
+ @editor.scroll_to_idx(s_off)
26
+ @editor.refresh
27
+ end
28
+ end
29
+
30
+
31
+ # Fire our strings operation only on switching (via activation)
32
+ # we do this because strings is a costly operation
33
+ evt_activate do |evt|
34
+ if @data_changed
35
+ @data_changed=false
36
+ @strings_list.do_strings
37
+ end
38
+ end
39
+ end
40
+
41
+ def notify_data_change
42
+ @data_changed=true
43
+ end
44
+
45
+ def do_strings
46
+ @strings_list.do_strings
47
+ end
48
+ end
49
+
50
+ class StringsList < Wx::ListCtrl
51
+ attr_reader :strings_opts
52
+
53
+ def initialize(parent, editor, strings_opts=nil)
54
+ unless @editor = editor
55
+ Kernel.raise "#{self.class}.new() requires an editor window parameter"
56
+ end
57
+
58
+ super(parent, :style => Wx::LC_REPORT|Wx::LC_SINGLE_SEL|Wx::LC_HRULES|Wx::LC_VRULES)
59
+ insert_column(0, "start")
60
+ insert_column(1, "len")
61
+ insert_column(2, "kind")
62
+ insert_column(3, "string")
63
+
64
+ @strings_opts = (strings_opts || {})
65
+ @strings_opts[:encoding] ||= :both
66
+
67
+ @font = Wx::Font.new(10, Wx::MODERN, Wx::NORMAL, Wx::NORMAL)
68
+ set_font(@font)
69
+ end
70
+
71
+ GAUGE_STYLE = Wx::PD_CAN_ABORT |
72
+ Wx::PD_REMAINING_TIME |
73
+ Wx::PD_ESTIMATED_TIME |
74
+ Wx::PD_ELAPSED_TIME
75
+
76
+ def do_strings
77
+ gauge =
78
+ Wx::ProgressDialog.new("", "Generating Strings",
79
+ @editor.data.size, self, GAUGE_STYLE)
80
+
81
+ self.hide
82
+ delete_all_items
83
+ i=0
84
+ @editor.data.strings(@strings_opts) do |startoff, endoff, stype, str|
85
+ unless gauge.update(endoff)
86
+ # the "abort" button was pressed
87
+ destroy
88
+ return nil
89
+ end
90
+ d_str = ((stype == :unicode)? str.gsub(/(.)\x00/){$1} : str).inspect
91
+ insert_item(i, startoff.to_s)
92
+ set_item i, 1, (endoff-startoff).to_s
93
+ set_item i, 2, stype.to_s
94
+ set_item i, 3, d_str
95
+ set_item_data(i, [startoff, endoff, stype])
96
+ i+=1
97
+ end
98
+
99
+ 0.upto(3) {|c| set_column_width c, Wx::LIST_AUTOSIZE } if i > 0
100
+ self.show
101
+ gauge.destroy()
102
+ return i
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,123 @@
1
+
2
+ require 'rbkb/extends.rb'
3
+
4
+ module Hexwrench
5
+ class StringsFrame < Wx::Frame
6
+ attr_reader :strings_list
7
+
8
+ def initialize(parent, editor, strings_opts=nil)
9
+ unless @editor = editor
10
+ Kernel.raise "#{self.class}.new() requires an editor window parameter"
11
+ end
12
+
13
+ @strings_opts = (strings_opts || {})
14
+ @strings_opts[:min] ||= 5
15
+
16
+ super(parent, :title => "Strings")
17
+
18
+ # Fire our strings operation only on switching windows (via activation)
19
+ # we do this because finding strings (to a lesser extent) and
20
+ # populating the window (to a larger extent) may be a costly operation
21
+ evt_idle do |evt|
22
+ if @data_changed and active?
23
+ @data_changed=false
24
+ do_strings
25
+ end
26
+ end
27
+
28
+ do_strings
29
+ end
30
+
31
+ def notify_data_change
32
+ @data_changed=true
33
+ end
34
+
35
+ def do_strings
36
+ if @strings_list.nil?
37
+ @strings_list = StringsList.new(self, @editor) unless @strings_list
38
+
39
+ evt_list_item_selected(@strings_list) do |evt|
40
+ s_off, e_off, kind, str = @strings_list.strings[evt.get_index]
41
+ if @editor.select_range(s_off..e_off-1)
42
+ @editor.set_area_ascii
43
+ @editor.scroll_to_idx(s_off)
44
+ @editor.refresh
45
+ end
46
+ end
47
+ else
48
+ @strings_list.refresh_strings()
49
+ end
50
+ end
51
+ end
52
+
53
+ class StringsList < Wx::ListCtrl
54
+ attr_accessor :strings_opts, :strings, :editor
55
+
56
+ def initialize(parent, editor, strings_opts=nil)
57
+ @strings_opts ||= {}
58
+ @editor = editor
59
+
60
+ super(parent, :style => Wx::LC_REPORT|Wx::LC_SINGLE_SEL|Wx::LC_HRULES|Wx::LC_VRULES|Wx::LC_VIRTUAL)
61
+
62
+ @font = Wx::Font.new(10, Wx::MODERN, Wx::NORMAL, Wx::NORMAL)
63
+ set_font(@font)
64
+
65
+ @dc = Wx::WindowDC.new(self)
66
+ @labels = ["start idx", "end idx", "kind", "string"]
67
+ @labels.each_index {|i| insert_column(i, @labels[i]) }
68
+
69
+ refresh_strings()
70
+
71
+ @attr = Wx::ListItemAttr.new
72
+ @attr.set_background_colour(Wx::WHITE)
73
+ end
74
+
75
+ def refresh_strings()
76
+ @strings = []
77
+ colwids = @labels.map {|l| @dc.get_text_extent("@@#{l}@@", @font)[0]}
78
+ @editor.data.strings(@strings_opts) do |*mtch|
79
+ @strings << mtch[0..2]
80
+
81
+ # calculate column widths during loop so we don't have to autosize
82
+ # later. (autosize can be slow on large lists)
83
+ 0.upto(2) do |i|
84
+ owid = colwids[i]
85
+ nwid = @dc.get_text_extent("@#{mtch[i]}@", @font)[0]
86
+ colwids[i] = nwid if nwid > owid
87
+ end
88
+ swid=colwids[3]
89
+ nswid=@dc.get_text_extent("@#{get_string(mtch)}@", @font)[0]
90
+ colwids[3] = nswid if nswid > swid
91
+ end
92
+ colwids.each_index {|i| set_column_width(i, colwids[i])}
93
+ set_item_count(@strings.size)
94
+ end
95
+
96
+ def get_string(match)
97
+ dat = @editor.data[(match[0]..match[1]-1)]
98
+ if match[2] == :unicode
99
+ dat.gsub(/(.)\x00/){$1}
100
+ else
101
+ dat
102
+ end.inspect
103
+ end
104
+
105
+ def create_strings(data)
106
+ end
107
+
108
+ def on_get_item_text(row, col)
109
+ if r = @strings[row]
110
+ if col == 3
111
+ get_string(r)
112
+ else
113
+ r[col].to_s
114
+ end
115
+ end
116
+ end
117
+
118
+ def on_get_item_attr(item)
119
+ @attr
120
+ end
121
+ end
122
+ end
123
+
@@ -0,0 +1,93 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <resource version="2.3.0.1" xmlns="http://www.wxwidgets.org/wxxrc">
3
+ <object class="wxFrame" name="editor_frame" subclass="EditorFrameBase">
4
+ <style>wxCAPTION|wxRESIZE_BORDER|wxSYSTEM_MENU|wxMINIMIZE_BOX|wxMAXIMIZE_BOX|wxCLOSE_BOX</style>
5
+ <size>400,300</size>
6
+ <title>Hexwrench</title>
7
+ <object class="wxMenuBar" name="top_menu_bar">
8
+ <object class="wxMenu">
9
+ <label>&amp;File</label>
10
+ <object class="wxMenuItem" name="mitem_open">
11
+ <label>Open</label>
12
+ </object>
13
+ <object class="wxMenuItem" name="mitem_new">
14
+ <label>New</label>
15
+ </object>
16
+ <object class="wxMenuItem" name="mitem_save">
17
+ <label>Save</label>
18
+ </object>
19
+ <object class="wxMenuItem" name="mitem_quit">
20
+ <label>Quit</label>
21
+ </object>
22
+ </object>
23
+ <object class="wxMenu">
24
+ <label>&amp;Edit</label>
25
+ <object class="wxMenuItem" name="mitem_copy">
26
+ <label>Copy</label>
27
+ </object>
28
+ <object class="wxMenuItem" name="mitem_cut">
29
+ <label>Cut</label>
30
+ </object>
31
+ <object class="wxMenuItem" name="mitem_paste">
32
+ <label>Paste</label>
33
+ </object>
34
+ <object class="wxMenuItem" name="mitem_select_all">
35
+ <label>Select All</label>
36
+ </object>
37
+ <object class="wxMenuItem" name="mitem_select_range">
38
+ <label>Select Range</label>
39
+ </object>
40
+ <object class="separator">
41
+ </object>
42
+ <object class="wxMenuItem" name="mitem_adv_search">
43
+ <label>Advanced Search</label>
44
+ </object>
45
+ </object>
46
+ <object class="wxMenu">
47
+ <label>&amp;Tools</label>
48
+ <object class="wxMenuItem" name="mitem_data_inspector">
49
+ <label>Data Inspector</label>
50
+ </object>
51
+ <object class="wxMenuItem" name="mitem_strings">
52
+ <label>Strings</label>
53
+ </object>
54
+ </object>
55
+ </object>
56
+ <object class="wxToolBar" name="util_bar">
57
+ <style>wxTB_FLAT|wxTB_HORIZONTAL</style>
58
+ <object class="wxTextCtrl" name="util_jump">
59
+ <style>wxTE_PROCESS_ENTER</style>
60
+ <value>jump to addr.</value>
61
+ </object>
62
+ <object class="separator">
63
+ </object>
64
+ <object class="wxTextCtrl" name="util_search">
65
+ <style>wxTE_PROCESS_ENTER</style>
66
+ <value>search</value>
67
+ </object>
68
+ <object class="wxChoice" name="util_search_kind">
69
+ <size>70,-1</size>
70
+ <font>
71
+ <size>10</size>
72
+ <family>modern</family>
73
+ </font>
74
+ <content>
75
+ <item>ASCII</item>
76
+ <item>Hex</item>
77
+ </content>
78
+ <selection>0</selection>
79
+ </object>
80
+ <object class="separator">
81
+ </object>
82
+ <object class="wxCheckBox" name="util_ins_chk">
83
+ <label>INS</label>
84
+ <checked>1</checked>
85
+ </object>
86
+ </object>
87
+ <object class="wxStatusBar" name="status_bar">
88
+ <style>wxST_SIZEGRIP|wxNO_BORDER</style>
89
+ <fields>2</fields>
90
+ <widths></widths>
91
+ </object>
92
+ </object>
93
+ </resource>
data/lib/hexwrench.rb ADDED
@@ -0,0 +1,14 @@
1
+ begin
2
+ require 'rubygems'
3
+ rescue LoadError
4
+ end
5
+
6
+ module Hexwrench
7
+ VERSION = "0.2.0"
8
+ end
9
+ require 'wx'
10
+ require 'hexwrench/edit_window'
11
+ require 'hexwrench/gui.rb' # gui.rb provides EditFrame's layout from XRC
12
+ require 'hexwrench/edit_frame'
13
+ require 'hexwrench/data_inspector'
14
+ require 'hexwrench/stringsvlist'
@@ -0,0 +1,13 @@
1
+ # a byte-value heat colorizer based on colorbindump
2
+
3
+ raw_palette = [[0x30, 0x30, 0x30] ] +
4
+ (1..31).map {|x| [96,96,96]} +
5
+ (32..127).map {|x| [128,196,128]} +
6
+ (128..255).map {|x| [96,96,96]}
7
+
8
+ @palette = raw_palette.map {|p| Wx::Brush.new(Wx::Colour.new(*p[0..2]))}
9
+ editor.post_paint_proc = lambda {|this,dc,idx,c,hX,aX,y|
10
+ brush = [@palette[c], Wx::TRANSPARENT_BRUSH]
11
+ this.colorize_byte_bg(brush, dc, hX,aX,y)
12
+ }
13
+ editor.refresh
data/tasks/ann.rake ADDED
@@ -0,0 +1,80 @@
1
+
2
+ begin
3
+ require 'bones/smtp_tls'
4
+ rescue LoadError
5
+ require 'net/smtp'
6
+ end
7
+ require 'time'
8
+
9
+ namespace :ann do
10
+
11
+ # A prerequisites task that all other tasks depend upon
12
+ task :prereqs
13
+
14
+ file PROJ.ann.file do
15
+ ann = PROJ.ann
16
+ puts "Generating #{ann.file}"
17
+ File.open(ann.file,'w') do |fd|
18
+ fd.puts("#{PROJ.name} version #{PROJ.version}")
19
+ fd.puts(" by #{Array(PROJ.authors).first}") if PROJ.authors
20
+ fd.puts(" #{PROJ.url}") if PROJ.url.valid?
21
+ fd.puts(" (the \"#{PROJ.release_name}\" release)") if PROJ.release_name
22
+ fd.puts
23
+ fd.puts("== DESCRIPTION")
24
+ fd.puts
25
+ fd.puts(PROJ.description)
26
+ fd.puts
27
+ fd.puts(PROJ.changes.sub(%r/^.*$/, '== CHANGES'))
28
+ fd.puts
29
+ ann.paragraphs.each do |p|
30
+ fd.puts "== #{p.upcase}"
31
+ fd.puts
32
+ fd.puts paragraphs_of(PROJ.readme_file, p).join("\n\n")
33
+ fd.puts
34
+ end
35
+ fd.puts ann.text if ann.text
36
+ end
37
+ end
38
+
39
+ desc "Create an announcement file"
40
+ task :announcement => ['ann:prereqs', PROJ.ann.file]
41
+
42
+ desc "Send an email announcement"
43
+ task :email => ['ann:prereqs', PROJ.ann.file] do
44
+ ann = PROJ.ann
45
+ from = ann.email[:from] || Array(PROJ.authors).first || PROJ.email
46
+ to = Array(ann.email[:to])
47
+
48
+ ### build a mail header for RFC 822
49
+ rfc822msg = "From: #{from}\n"
50
+ rfc822msg << "To: #{to.join(',')}\n"
51
+ rfc822msg << "Subject: [ANN] #{PROJ.name} #{PROJ.version}"
52
+ rfc822msg << " (#{PROJ.release_name})" if PROJ.release_name
53
+ rfc822msg << "\n"
54
+ rfc822msg << "Date: #{Time.new.rfc822}\n"
55
+ rfc822msg << "Message-Id: "
56
+ rfc822msg << "<#{"%.8f" % Time.now.to_f}@#{ann.email[:domain]}>\n\n"
57
+ rfc822msg << File.read(ann.file)
58
+
59
+ params = [:server, :port, :domain, :acct, :passwd, :authtype].map do |key|
60
+ ann.email[key]
61
+ end
62
+
63
+ params[3] = PROJ.email if params[3].nil?
64
+
65
+ if params[4].nil?
66
+ STDOUT.write "Please enter your e-mail password (#{params[3]}): "
67
+ params[4] = STDIN.gets.chomp
68
+ end
69
+
70
+ ### send email
71
+ Net::SMTP.start(*params) {|smtp| smtp.sendmail(rfc822msg, from, to)}
72
+ end
73
+ end # namespace :ann
74
+
75
+ desc 'Alias to ann:announcement'
76
+ task :ann => 'ann:announcement'
77
+
78
+ CLOBBER << PROJ.ann.file
79
+
80
+ # EOF
data/tasks/bones.rake ADDED
@@ -0,0 +1,20 @@
1
+
2
+ if HAVE_BONES
3
+
4
+ namespace :bones do
5
+
6
+ desc 'Show the PROJ open struct'
7
+ task :debug do |t|
8
+ atr = if t.application.top_level_tasks.length == 2
9
+ t.application.top_level_tasks.pop
10
+ end
11
+
12
+ if atr then Bones::Debug.show_attr(PROJ, atr)
13
+ else Bones::Debug.show PROJ end
14
+ end
15
+
16
+ end # namespace :bones
17
+
18
+ end # HAVE_BONES
19
+
20
+ # EOF