kaitai-struct-visualizer 0.7 → 0.11

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.
@@ -1,263 +1,234 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'benchmark'
2
4
 
3
5
  require 'kaitai/struct/visualizer/version'
4
6
  require 'kaitai/struct/visualizer/node'
5
7
  require 'kaitai/struct/visualizer/hex_viewer'
8
+ require 'kaitai/struct/visualizer/ks_error_matcher'
6
9
 
7
10
  module Kaitai::Struct::Visualizer
8
- class Tree
9
- def initialize(ui, st)
10
- @ui = ui
11
- @st = st
12
- @root = Node.new(self, st, 0)
13
- @root.id = '[root]'
11
+ class Tree
12
+ def initialize(ui, st)
13
+ @ui = ui
14
+ @st = st
15
+ @root = Node.new(self, st, 0)
16
+ @root.id = '[root]'
14
17
 
15
- @cur_io = nil
16
- @hv = HexViewer.new(ui, nil, self)
17
- @hv_hidden = false
18
+ @cur_io = nil
19
+ @hv = HexViewer.new(ui, nil, self)
20
+ @hv_hidden = false
18
21
 
19
- recalc_sizes
22
+ recalc_sizes
20
23
 
21
- @cur_line = 0
22
- @cur_shift = 0
23
- @do_exit = false
24
+ @cur_line = 0
25
+ @cur_shift = 0
26
+ @do_exit = false
24
27
 
25
- @ui.on_resize = proc {
26
- recalc_sizes
27
- redraw
28
- @hv.redraw
29
- }
30
- end
28
+ @ui.on_resize = proc { |redraw_needed|
29
+ recalc_sizes
30
+ redraw if redraw_needed
31
+ @hv.redraw if redraw_needed
32
+ }
33
+ end
31
34
 
32
- def recalc_sizes
33
- @max_scr_ln = @ui.rows - 3
34
- @hv.shift_x = @ui.cols - HexViewer.line_width - 1
35
- end
35
+ def recalc_sizes
36
+ @max_scr_ln = @ui.rows - 3
37
+ @hv.shift_x = @ui.cols - HexViewer.line_width - 1
38
+ end
36
39
 
37
- def run
38
- c = nil
39
- loop {
40
- t = redraw
40
+ def run
41
+ loop do
42
+ t = redraw
41
43
 
42
- if @cur_node.nil? and not @cur_line.nil?
43
- # gone beyond the end of the tree
44
- @cur_line = @root.height - 1
45
- clamp_cursor
46
- redraw
47
- end
44
+ if @cur_node.nil? && !@cur_line.nil?
45
+ # gone beyond the end of the tree
46
+ @cur_line = @root.height - 1
47
+ clamp_cursor
48
+ redraw
49
+ end
48
50
 
49
- raise '@cur_line is undetermined' if @cur_line.nil?
50
- raise '@cur_node is undetermined' if @cur_node.nil?
51
+ raise '@cur_line is undetermined' if @cur_line.nil?
52
+ raise '@cur_node is undetermined' if @cur_node.nil?
51
53
 
52
- thv = Benchmark.realtime {
53
- unless @hv_hidden
54
- hv_update_io
54
+ thv = Benchmark.realtime do
55
+ unless @hv_hidden
56
+ hv_update_io
55
57
 
56
- unless @cur_node.pos1.nil?
57
- if (@hv.addr < @cur_node.pos1) or (@hv.addr >= @cur_node.pos2)
58
+ if !@cur_node.pos1.nil? && ((@hv.addr < @cur_node.pos1) || (@hv.addr >= @cur_node.pos2))
58
59
  @hv.addr = @cur_node.pos1
59
60
  @hv.ensure_visible
60
61
  end
61
- end
62
62
 
63
- @hv.redraw
64
- regs = highlight_regions(4)
65
- @hv.highlight(regs)
63
+ @hv.redraw
64
+ regs = highlight_regions(4)
65
+ @hv.highlight(regs)
66
+ end
66
67
  end
67
- }
68
68
 
69
- @ui.goto(0, @max_scr_ln + 1)
70
- printf "all: %d, tree: %d, tree_draw: %d, hexview: %d, ln: %d, ", (t + thv) * 1e6, t * 1e6, @draw_time * 1e6, thv * 1e6, @ln
71
- puts "highlight = #{@cur_node.pos1}..#{@cur_node.pos2}"
72
- #puts "keypress: #{c.inspect}"
73
-
74
- begin
75
- process_keypress
76
- rescue EOFError => e
77
- @ui.message_box_exception(e)
78
- rescue Kaitai::Struct::Stream::UnexpectedDataError => e
79
- @ui.message_box_exception(e)
80
- end
69
+ @ui.goto(0, @max_scr_ln + 1)
70
+ printf 'all: %d, tree: %d, tree_draw: %d, hexview: %d, ln: %d, ', (t + thv) * 1e6, t * 1e6, @draw_time * 1e6, thv * 1e6, @ln
71
+ puts "highlight = #{@cur_node.pos1}..#{@cur_node.pos2}"
72
+ # puts "keypress: #{c.inspect}"
81
73
 
82
- return if @do_exit
74
+ begin
75
+ process_keypress
76
+ rescue Kaitai::Struct::Visualizer::KSErrorMatcher => e
77
+ @ui.message_box_exception(e)
78
+ end
83
79
 
84
- clamp_cursor
85
- }
86
- end
80
+ return if @do_exit
87
81
 
88
- def process_keypress
89
- c = @ui.read_char_mapped
90
- case c
91
- when :up_arrow
92
- @cur_line -= 1
93
- @cur_node = nil
94
- when :down_arrow
95
- @cur_line += 1
96
- @cur_node = nil
97
- when :left_arrow
98
- if @cur_node.open?
99
- @cur_node.close
100
- else
101
- par = @cur_node.parent
102
- if par
103
- @cur_line = nil
104
- @cur_node = par
105
- end
82
+ clamp_cursor
106
83
  end
107
- when :right_arrow
108
- if @cur_node.openable?
84
+ end
85
+
86
+ def process_keypress
87
+ c = @ui.read_char_mapped
88
+ case c
89
+ when :up_arrow
90
+ @cur_line -= 1
91
+ @cur_node = nil
92
+ when :down_arrow
93
+ @cur_line += 1
94
+ @cur_node = nil
95
+ when :left_arrow
109
96
  if @cur_node.open?
110
- @cur_line += 1
111
- @cur_node = nil
97
+ @cur_node.close
112
98
  else
113
- @cur_node.open
99
+ par = @cur_node.parent
100
+ if par
101
+ @cur_line = nil
102
+ @cur_node = par
103
+ end
114
104
  end
115
- end
116
- when :home
117
- @cur_line = @cur_shift = 0
118
- @cur_node = nil
119
- when :end
120
- @cur_line = @root.height - 1
121
- @cur_node = nil
122
- when :pg_up
123
- @cur_line -= 20
124
- @cur_node = nil
125
- when :pg_dn
126
- @cur_line += 20
127
- @cur_node = nil
128
- when :enter
129
- if @cur_node.hex?
130
- @ui.clear
131
- hv = HexViewer.new(@ui, @cur_node.value)
132
- hv.redraw
133
- hv.run
105
+ when :right_arrow
106
+ if @cur_node.openable?
107
+ if @cur_node.open?
108
+ @cur_line += 1
109
+ @cur_node = nil
110
+ else
111
+ @cur_node.open
112
+ end
113
+ end
114
+ when :home
115
+ @cur_line = @cur_shift = 0
116
+ @cur_node = nil
117
+ when :end
118
+ @cur_line = @root.height - 1
119
+ @cur_node = nil
120
+ when :pg_up
121
+ @cur_line -= 20
122
+ @cur_node = nil
123
+ when :pg_dn
124
+ @cur_line += 20
125
+ @cur_node = nil
126
+ when :enter
127
+ if @cur_node.hex?
128
+ @ui.clear
129
+ hv = HexViewer.new(@ui, @cur_node.value)
130
+ hv.redraw
131
+ hv.run
132
+ @ui.clear
133
+ redraw
134
+ else
135
+ @cur_node.toggle
136
+ end
137
+ when :tab
138
+ @hv.run
139
+ when 'H'
140
+ @hv_hidden = !@hv_hidden
134
141
  @ui.clear
135
142
  redraw
136
- else
137
- @cur_node.toggle
143
+ when 'q'
144
+ @do_exit = true
138
145
  end
139
- when :tab
140
- @hv.run
141
- when 'H'
142
- @hv_hidden = !@hv_hidden
143
- @ui.clear
144
- redraw
145
- when 'q'
146
- @do_exit = true
147
146
  end
148
- end
149
147
 
150
- def clamp_cursor
151
- if @cur_line
152
- @cur_line = 0 if @cur_line < 0
148
+ def clamp_cursor
149
+ return unless @cur_line
153
150
 
154
- if @cur_line - @cur_shift < 0
155
- @cur_shift = @cur_line
156
- end
157
- if @cur_line - @cur_shift > @max_scr_ln
158
- @cur_shift = @cur_line - @max_scr_ln
151
+ @cur_line = 0 if @cur_line.negative?
152
+
153
+ @cur_shift = @cur_line if (@cur_line - @cur_shift).negative?
154
+ @cur_shift = @cur_line - @max_scr_ln if (@cur_line - @cur_shift) > @max_scr_ln
155
+ end
156
+
157
+ def redraw
158
+ @draw_time = 0
159
+ Benchmark.realtime do
160
+ @ui.clear
161
+ @ln = 0
162
+ draw_rec(@root)
159
163
  end
160
164
  end
161
- end
162
165
 
163
- def redraw
164
- @draw_time = 0
165
- Benchmark.realtime {
166
- @ui.clear
167
- @ln = 0
168
- draw_rec(@root)
169
- }
170
- end
166
+ def draw_rec(n)
167
+ scr_ln = @ln - @cur_shift
168
+ return if @cur_node && (scr_ln > @max_scr_ln)
169
+
170
+ if @ln == @cur_line
171
+ # Seeking cur_node by cur_line
172
+ @cur_node = n
173
+ @ui.bg_color = :white
174
+ @ui.fg_color = :black
175
+ elsif @cur_node == n
176
+ # Seeking cur_line by cur_node
177
+ @cur_line = @ln
178
+ @ui.bg_color = :white
179
+ @ui.fg_color = :black
180
+ end
171
181
 
172
- def draw_rec(n)
173
- scr_ln = @ln - @cur_shift
174
- return if @cur_node and scr_ln > @max_scr_ln
175
-
176
- if @ln == @cur_line
177
- # Seeking cur_node by cur_line
178
- @cur_node = n
179
- @ui.bg_color = :gray
180
- @ui.fg_color = :black
181
- elsif @cur_node == n
182
- # Seeking cur_line by cur_node
183
- @cur_line = @ln
184
- @ui.bg_color = :gray
185
- @ui.fg_color = :black
186
- end
182
+ @draw_time += Benchmark.realtime do
183
+ # n.draw(@ui) if scr_ln >= 0
184
+ n.draw(@ui) if (scr_ln >= 0) && (scr_ln <= @max_scr_ln)
185
+ end
187
186
 
188
- @draw_time += Benchmark.realtime {
189
- # n.draw(@ui) if scr_ln >= 0
190
- n.draw(@ui) if scr_ln >= 0 and scr_ln <= @max_scr_ln
191
- }
187
+ @ui.reset_colors if @ln == @cur_line
188
+ @ln += 1
192
189
 
193
- @ui.reset_colors if @ln == @cur_line
194
- @ln += 1
195
- if n.open?
196
- n.children.each { |ch|
190
+ return unless n.open?
191
+
192
+ n.children.each do |ch|
197
193
  draw_rec(ch)
198
194
  break if scr_ln > @max_scr_ln
199
- }
195
+ end
200
196
  end
201
- end
202
197
 
203
- def do_exit
204
- @do_exit = true
205
- end
198
+ def do_exit
199
+ @do_exit = true
200
+ end
201
+
202
+ def hv_update_io
203
+ io = @cur_node.io
204
+ return unless io != @cur_io
206
205
 
207
- def hv_update_io
208
- io = @cur_node.io
209
- if io != @cur_io
210
206
  @cur_io = io
211
207
  io.seek(0)
212
208
  buf = io.read_bytes_full
213
209
  @hv.buf = buf
214
210
 
215
- # @hv.redraw
211
+ # @hv.redraw
216
212
  end
217
- end
218
213
 
219
- def highlight_regions(max_levels)
220
- node = @cur_node
221
- r = []
222
- max_levels.times { |i|
223
- return r if node.nil?
224
- r << [node.pos1, node.pos2]
225
- node = node.parent
226
- }
227
- r
228
- end
214
+ def highlight_regions(max_levels)
215
+ node = @cur_node
216
+ r = []
217
+ max_levels.times do |_i|
218
+ return r if node.nil?
229
219
 
230
- def tree_width
231
- if @hv_hidden
232
- @ui.cols
233
- else
234
- @hv.shift_x
220
+ r << [node.pos1, node.pos2]
221
+ node = node.parent
222
+ end
223
+ r
235
224
  end
236
- end
237
225
 
238
- def self.explore_object(obj, level)
239
- root = Node.new(obj, level)
240
- if obj.is_a?(Fixnum) or obj.is_a?(String)
241
- # do nothing else
242
- elsif obj.is_a?(Array)
243
- root = Node.new(obj, level)
244
- obj.each_with_index { |el, i|
245
- n = explore_object(el, level + 1)
246
- n.id = i
247
- root.add(n)
248
- }
249
- else
250
- root = Node.new(obj, level)
251
- obj.instance_variables.each { |k|
252
- k = k.to_s
253
- next if k =~ /^@_/
254
- el = obj.instance_eval(k)
255
- n = explore_object(el, level + 1)
256
- n.id = k
257
- root.add(n)
258
- }
226
+ def tree_width
227
+ if @hv_hidden
228
+ @ui.cols
229
+ else
230
+ @hv.shift_x
231
+ end
259
232
  end
260
- root
261
233
  end
262
234
  end
263
- end
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Kaitai
2
4
  module Struct
3
5
  module Visualizer
4
- VERSION = '0.7'
6
+ VERSION = '0.11'
5
7
  end
6
8
  end
7
9
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'kaitai/struct/visualizer/version'
2
4
  require 'kaitai/tui'
3
5
  require 'kaitai/struct/visualizer/parser'
@@ -8,17 +10,17 @@ require 'zlib'
8
10
  require 'stringio'
9
11
 
10
12
  module Kaitai::Struct::Visualizer
11
- class Visualizer < Parser
12
- def run
13
- load_exc = load
13
+ class Visualizer < Parser
14
+ def run
15
+ load_exc = load
14
16
 
15
- @ui = Kaitai::TUI.new
16
- @tree = Tree.new(@ui, @data)
17
+ @ui = Kaitai::TUI.new
18
+ @tree = Tree.new(@ui, @data)
17
19
 
18
- @tree.redraw
19
- @ui.message_box_exception(load_exc) if load_exc
20
+ @tree.redraw
21
+ @ui.message_box_exception(load_exc) if load_exc
20
22
 
21
- @tree.run
23
+ @tree.run
24
+ end
22
25
  end
23
26
  end
24
- end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'kaitai/struct/visualizer/version'
2
4
  require 'kaitai/struct/visualizer/visualizer'
3
5
  require 'kaitai/struct/visualizer/ksy_compiler'
data/lib/kaitai/tui.rb CHANGED
@@ -1,113 +1,100 @@
1
- # coding: utf-8
1
+ # frozen_string_literal: true
2
+
2
3
  require 'forwardable'
3
4
 
4
5
  module Kaitai
5
-
6
- class TUI
7
- extend Forwardable
8
- def_delegators :@console, :rows, :cols, :goto, :clear, :fg_color=, :bg_color=, :reset_colors, :read_char_mapped
9
-
10
- attr_reader :highlight_colors
11
-
12
- def initialize
13
- if TUI::is_windows?
14
- require 'kaitai/console_windows'
15
- @console = ConsoleWindows.new
16
- @highlight_colors = [
17
- :white,
18
- :aqua,
19
- :blue,
20
- :green,
21
- :white,
22
- ]
23
- else
24
- require 'kaitai/console_ansi'
25
- @console = ConsoleANSI.new
26
- @highlight_colors = [
27
- :gray14,
28
- :gray11,
29
- :gray8,
30
- :gray5,
31
- :gray2,
32
- ]
6
+ class TUI
7
+ extend Forwardable
8
+ def_delegators :@console, :rows, :cols, :goto, :clear, :fg_color=, :bg_color=, :reset_colors, :read_char_mapped
9
+
10
+ attr_reader :highlight_colors
11
+
12
+ def initialize
13
+ if TUI.windows?
14
+ require 'kaitai/console_windows'
15
+ @console = ConsoleWindows.new
16
+ @highlight_colors = %i[bright_white bright_cyan cyan gray]
17
+ else
18
+ require 'kaitai/console_ansi'
19
+ @console = ConsoleANSI.new
20
+ @highlight_colors = %i[bright_white bright_cyan cyan gray]
21
+ end
33
22
  end
34
- end
35
23
 
36
- def on_resize=(handler)
37
- @console.on_resize = handler
38
- end
24
+ def on_resize=(handler)
25
+ @console.on_resize = handler
26
+ end
39
27
 
40
- def message_box_exception(e)
41
- message_box("Error while parsing", e.message)
42
- end
28
+ def message_box_exception(e)
29
+ message_box('Error while parsing', e.message)
30
+ end
43
31
 
44
- SINGLE_CHARSET = '┌┐└┘─│'
45
- HEAVY_CHARSET = '┏┓┗┛━┃'
46
- DOUBLE_CHARSET = '╔╗╚╝═║'
47
-
48
- CHAR_TL = 0
49
- CHAR_TR = 1
50
- CHAR_BL = 2
51
- CHAR_BR = 3
52
- CHAR_H = 4
53
- CHAR_V = 5
54
-
55
- def message_box(header, msg)
56
- top_y = @console.rows / 2 - 5
57
- draw_rectangle(10, top_y, @console.cols - 20, 10)
58
- @console.goto(@console.cols / 2 - (header.length / 2) - 1, top_y)
59
- print ' ', header, ' '
60
- @console.goto(11, top_y + 1)
61
- puts msg
62
- draw_button(@console.cols / 2 - 10, top_y + 8, 10, 'OK')
63
- loop {
64
- c = @console.read_char_mapped
65
- return if c == :enter
66
- }
67
- end
32
+ SINGLE_CHARSET = '┌┐└┘─│'
33
+ HEAVY_CHARSET = '┏┓┗┛━┃'
34
+ DOUBLE_CHARSET = '╔╗╚╝═║'
35
+
36
+ CHAR_TL = 0
37
+ CHAR_TR = 1
38
+ CHAR_BL = 2
39
+ CHAR_BR = 3
40
+ CHAR_H = 4
41
+ CHAR_V = 5
42
+
43
+ def message_box(header, msg)
44
+ top_y = @console.rows / 2 - 5
45
+ draw_rectangle(10, top_y, @console.cols - 20, 10)
46
+ @console.goto(@console.cols / 2 - (header.length / 2) - 1, top_y)
47
+ print ' ', header, ' '
48
+ @console.goto(11, top_y + 1)
49
+ puts msg
50
+ draw_button(@console.cols / 2 - 10, top_y + 8, 10, 'OK')
51
+ loop do
52
+ c = @console.read_char_mapped
53
+ return if c == :enter
54
+ end
55
+ end
68
56
 
69
- def input_str(header, msg)
70
- top_y = @console.rows / 2 - 5
71
- draw_rectangle(10, top_y, @console.cols - 20, 10)
72
- goto(@console.cols / 2 - (header.length / 2) - 1, top_y)
73
- print ' ', header, ' '
57
+ def input_str(header, _msg)
58
+ top_y = @console.rows / 2 - 5
59
+ draw_rectangle(10, top_y, @console.cols - 20, 10)
60
+ goto(@console.cols / 2 - (header.length / 2) - 1, top_y)
61
+ print ' ', header, ' '
74
62
 
75
- goto(11, top_y + 1)
76
- Readline.readline('', false)
77
- end
63
+ goto(11, top_y + 1)
64
+ Readline.readline('', false)
65
+ end
78
66
 
79
- def draw_rectangle(x, y, w, h, charset = DOUBLE_CHARSET)
80
- goto(x, y)
81
- print charset[CHAR_TL]
82
- print charset[CHAR_H] * (w - 2)
83
- print charset[CHAR_TR]
84
-
85
- ((y + 1)..(y + h - 1)).each { |i|
86
- goto(x, i)
87
- print charset[CHAR_V]
88
- print ' ' * (w - 2)
89
- print charset[CHAR_V]
90
- }
91
-
92
- goto(x, y + h)
93
- print charset[CHAR_BL]
94
- print charset[CHAR_H] * (w - 2)
95
- print charset[CHAR_BR]
96
- end
67
+ def draw_rectangle(x, y, w, h, charset = DOUBLE_CHARSET)
68
+ goto(x, y)
69
+ print charset[CHAR_TL]
70
+ print charset[CHAR_H] * (w - 2)
71
+ print charset[CHAR_TR]
72
+
73
+ ((y + 1)..(y + h - 1)).each do |i|
74
+ goto(x, i)
75
+ print charset[CHAR_V]
76
+ print ' ' * (w - 2)
77
+ print charset[CHAR_V]
78
+ end
79
+
80
+ goto(x, y + h)
81
+ print charset[CHAR_BL]
82
+ print charset[CHAR_H] * (w - 2)
83
+ print charset[CHAR_BR]
84
+ end
97
85
 
98
- def draw_button(x, y, w, caption)
99
- goto(x, y)
100
- puts "[ #{caption} ]"
101
- end
86
+ def draw_button(x, y, _w, caption)
87
+ goto(x, y)
88
+ puts "[ #{caption} ]"
89
+ end
102
90
 
103
- # Regexp borrowed from
104
- # http://stackoverflow.com/questions/170956/how-can-i-find-which-operating-system-my-ruby-program-is-running-on
105
- @@is_windows = (RUBY_PLATFORM =~ /cygwin|mswin|mingw|bccwin|wince|emx/) ? true : false
91
+ # Regexp borrowed from
92
+ # http://stackoverflow.com/questions/170956/how-can-i-find-which-operating-system-my-ruby-program-is-running-on
93
+ @@is_windows = (RUBY_PLATFORM =~ /cygwin|mswin|mingw|bccwin|wince|emx/) ? true : false
106
94
 
107
- # Detects if current platform is Windows-based.
108
- def self.is_windows?
109
- @@is_windows
95
+ # Detects whether the current platform is Windows-based.
96
+ def self.windows?
97
+ @@is_windows
98
+ end
110
99
  end
111
100
  end
112
-
113
- end