kaitai-struct-visualizer 0.5 → 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,293 +1,302 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'kaitai/struct/visualizer/version'
2
4
 
3
5
  module Kaitai::Struct::Visualizer
4
- class HexViewer
5
- def initialize(ui, buf, shift_x = 0, tree = nil)
6
- @ui = ui
7
- @buf = buf
8
- @shift_x = shift_x
9
- @tree = tree
10
-
11
- @embedded = not(tree.nil?)
12
- @max_scr_ln = @ui.rows - 3
13
-
14
- @addr = 0
15
- @scroll_y = 0
16
- reset_cur
17
- raise if @cur_x.nil?
18
- end
6
+ class HexViewer
7
+ attr_accessor :shift_x
19
8
 
20
- def buf=(buf)
21
- @buf = buf
22
- end
9
+ def initialize(ui, buf, tree = nil)
10
+ @ui = ui
11
+ @buf = buf
12
+ @shift_x = 0
13
+ @tree = tree
23
14
 
24
- def addr; @addr; end
25
- def addr=(a)
26
- @addr = a
27
- reset_cur
28
- end
15
+ @embedded = !tree.nil?
16
+ @max_scr_ln = @ui.rows - 3
29
17
 
30
- def reset_cur
31
- @cur_y = addr_to_row(@addr)
32
- @cur_x = addr_to_col(@addr)
33
- end
18
+ @addr = 0
19
+ @scroll_y = 0
20
+ reset_cur
21
+ raise if @cur_x.nil?
22
+ end
34
23
 
35
- def highlight(regions)
36
- highlight_hide
37
- @hl_regions = regions
38
- highlight_show
39
- end
24
+ attr_writer :buf
40
25
 
41
- def ensure_visible
42
- scr_y = row_to_scr(@cur_y)
43
- if scr_y < 0
44
- @scroll_y = @cur_y
45
- redraw
46
- highlight_show
47
- elsif scr_y > @max_scr_ln
48
- @scroll_y = @cur_y - @max_scr_ln
49
- redraw
26
+ attr_reader :addr
27
+
28
+ def addr=(a)
29
+ @addr = a
30
+ reset_cur
31
+ end
32
+
33
+ def reset_cur
34
+ @cur_y = addr_to_row(@addr)
35
+ @cur_x = addr_to_col(@addr)
36
+ end
37
+
38
+ def highlight(regions)
39
+ highlight_hide
40
+ @hl_regions = regions
50
41
  highlight_show
51
42
  end
52
- end
53
43
 
54
- def run
55
- c = nil
56
- loop {
57
- @ui.goto(0, @max_scr_ln + 1)
58
- printf "%08x (%d, %d)", @addr, @cur_x, @cur_y
59
-
60
- @ui.goto(col_to_col_char(@cur_x), row_to_scr(@cur_y))
61
- c = @ui.read_char_mapped
62
- case c
63
- when :tab
64
- return if @embedded
65
- when :left_arrow
66
- if @addr > 0
67
- @addr -= 1
68
- @cur_x -= 1
69
- if @cur_x < 0
70
- @cur_y -= 1
71
- @cur_x = PER_LINE - 1
44
+ def ensure_visible
45
+ scr_y = row_to_scr(@cur_y)
46
+ if scr_y.negative?
47
+ @scroll_y = @cur_y
48
+ redraw
49
+ highlight_show
50
+ elsif scr_y > @max_scr_ln
51
+ @scroll_y = @cur_y - @max_scr_ln
52
+ redraw
53
+ highlight_show
54
+ end
55
+ end
56
+
57
+ def run
58
+ c = nil
59
+ loop do
60
+ @ui.goto(0, @max_scr_ln + 1)
61
+ printf '%08x (%d, %d)', @addr, @cur_x, @cur_y
62
+
63
+ @ui.goto(col_to_col_char(@cur_x), row_to_scr(@cur_y))
64
+ c = @ui.read_char_mapped
65
+ case c
66
+ when :tab
67
+ return if @embedded
68
+ when :left_arrow
69
+ if @addr.positive?
70
+ @addr -= 1
71
+ @cur_x -= 1
72
+ if @cur_x.negative?
73
+ @cur_y -= 1
74
+ @cur_x = PER_LINE - 1
75
+ end
72
76
  end
73
- end
74
- when :right_arrow
75
- if @addr < @buf.size
76
- @addr += 1
77
- @cur_x += 1
78
- if @cur_x >= PER_LINE
79
- @cur_y += 1
77
+ when :right_arrow
78
+ if @addr < @buf.size
79
+ @addr += 1
80
+ @cur_x += 1
81
+ if @cur_x >= PER_LINE
82
+ @cur_y += 1
83
+ @cur_x = 0
84
+ end
85
+ end
86
+ when :up_arrow
87
+ @addr -= PER_LINE
88
+ @cur_y -= 1
89
+ clamp_cursor
90
+ when :down_arrow
91
+ @addr += PER_LINE
92
+ @cur_y += 1
93
+ clamp_cursor
94
+ when :pg_dn
95
+ @addr += PER_LINE * PAGE_ROWS
96
+ @cur_y += PAGE_ROWS
97
+ clamp_cursor
98
+ when :pg_up
99
+ @addr -= PER_LINE * PAGE_ROWS
100
+ @cur_y -= PAGE_ROWS
101
+ clamp_cursor
102
+ when :home
103
+ if @cur_x.zero?
104
+ @addr = 0
105
+ @cur_y = 0
106
+ else
107
+ @addr -= @cur_x
80
108
  @cur_x = 0
81
109
  end
110
+ clamp_cursor
111
+ when :end
112
+ if @cur_x == PER_LINE - 1
113
+ @addr = @buf.size - 1
114
+ reset_cur
115
+ else
116
+ @addr = @addr - @cur_x + PER_LINE - 1
117
+ @cur_x = PER_LINE - 1
118
+ end
119
+ clamp_cursor
120
+ when 'w'
121
+ fn = @ui.input_str('Write buffer to file', 'Filename')
122
+ File.open(fn, 'w') do |out|
123
+ out.write(@buf)
124
+ end
125
+ @ui.clear
126
+ redraw
127
+ when 'q'
128
+ @tree&.do_exit
129
+ return
82
130
  end
83
- when :up_arrow
84
- @addr -= PER_LINE
85
- @cur_y -= 1
86
- clamp_cursor
87
- when :down_arrow
88
- @addr += PER_LINE
89
- @cur_y += 1
90
- clamp_cursor
91
- when :pg_dn
92
- @addr += PER_LINE * PAGE_ROWS
93
- @cur_y += PAGE_ROWS
94
- clamp_cursor
95
- when :pg_up
96
- @addr -= PER_LINE * PAGE_ROWS
97
- @cur_y -= PAGE_ROWS
98
- clamp_cursor
99
- when :home
100
- if @cur_x == 0
101
- @addr = 0
102
- @cur_y = 0
103
- else
104
- @addr -= @cur_x
105
- @cur_x = 0
106
- end
107
- clamp_cursor
108
- when :end
109
- if @cur_x == PER_LINE - 1
110
- @addr = @buf.size - 1
111
- reset_cur
112
- else
113
- @addr = @addr - @cur_x + PER_LINE - 1
114
- @cur_x = PER_LINE - 1
115
- end
116
- clamp_cursor
117
- when 'w'
118
- fn = @ui.input_str('Write buffer to file', 'Filename')
119
- File.open(fn, 'w') { |out|
120
- out.write(@buf)
121
- }
122
- @ui.clear
123
- redraw
124
- when 'q'
125
- @tree.do_exit if @tree
126
- return
127
- end
128
131
 
129
- ensure_visible
130
- }
131
- end
132
+ ensure_visible
133
+ end
134
+ end
132
135
 
133
- def clamp_cursor
134
- if @addr < 0
135
- @addr = 0
136
- @cur_x = 0
137
- @cur_y = 0
138
- elsif @addr >= @buf.size
139
- @addr = @buf.size - 1
140
- reset_cur
136
+ def clamp_cursor
137
+ if @addr.negative?
138
+ @addr = 0
139
+ @cur_x = 0
140
+ @cur_y = 0
141
+ elsif @addr >= @buf.size
142
+ @addr = @buf.size - 1
143
+ reset_cur
144
+ end
141
145
  end
142
- end
143
146
 
144
- PER_LINE = 16
145
- PER_GROUP = 4
146
- PAGE_ROWS = 20
147
- FMT = "%08x: %-#{PER_LINE * 3}s| %-#{PER_LINE}s\n"
147
+ PER_LINE = 16
148
+ PER_GROUP = 4
149
+ PAGE_ROWS = 20
150
+ FMT = "%08x: %-#{PER_LINE * 3}s| %-#{PER_LINE}s\n"
148
151
 
149
- def self.line_width
150
- #8 + 2 + 3 * PER_LINE + 2 + PER_LINE
151
- 12 + 4 * PER_LINE
152
- end
152
+ def self.line_width
153
+ # 8 + 2 + 3 * PER_LINE + 2 + PER_LINE
154
+ 12 + 4 * PER_LINE
155
+ end
153
156
 
154
- def col_to_col_hex(c)
155
- #8 + 2 + 3 * c
156
- @shift_x + 10 + 3 * c
157
- end
157
+ def col_to_col_hex(c)
158
+ # 8 + 2 + 3 * c
159
+ @shift_x + 10 + 3 * c
160
+ end
158
161
 
159
- def col_to_col_char(c)
160
- #8 + 2 + 3 * PER_LINE + 2
161
- @shift_x + 12 + 3 * PER_LINE + c
162
- end
162
+ def col_to_col_char(c)
163
+ # 8 + 2 + 3 * PER_LINE + 2
164
+ @shift_x + 12 + 3 * PER_LINE + c
165
+ end
163
166
 
164
- def row_to_scr(r)
165
- r - @scroll_y
166
- end
167
+ def row_to_scr(r)
168
+ r - @scroll_y
169
+ end
167
170
 
168
- def redraw
169
- i = row_col_to_addr(@scroll_y, 0)
170
- row = 0
171
+ def redraw
172
+ i = row_col_to_addr(@scroll_y, 0)
173
+ row = 0
171
174
 
172
- while row <= @max_scr_ln do
173
- line = @buf[i, PER_LINE]
174
- return unless line
175
+ while row <= @max_scr_ln
176
+ line = @buf[i, PER_LINE]
177
+ return unless line
175
178
 
176
- @ui.goto(@shift_x, row)
179
+ @ui.goto(@shift_x, row)
177
180
 
178
- hex = line.bytes.map { |x| sprintf('%02x', x) }.join(' ')
179
- char = line.bytes.map { |x| byte_to_display_char(x) }.join
181
+ hex = line.bytes.map { |x| format('%02x', x) }.join(' ')
182
+ char = line.bytes.map { |x| byte_to_display_char(x) }.join
180
183
 
181
- printf FMT, i, hex, char
182
- i += PER_LINE
183
- row += 1
184
+ printf FMT, i, hex, char
185
+ i += PER_LINE
186
+ row += 1
187
+ end
184
188
  end
185
- end
186
189
 
187
- def each_highlight_region
188
- return if @hl_regions.nil?
189
- n = @hl_regions.size
190
- (n - 1).downto(0).each { |i|
191
- p1 = @hl_regions[i][0]
192
- p2 = @hl_regions[i][1]
193
- yield i, p1, p2 unless p1.nil?
194
- }
195
- end
190
+ def each_highlight_region
191
+ return if @hl_regions.nil?
196
192
 
197
- def highlight_hide
198
- each_highlight_region { |i, p1, p2|
199
- highlight_draw(p1, p2)
200
- }
201
- end
193
+ n = @hl_regions.size
194
+ (n - 1).downto(0).each do |i|
195
+ p1 = @hl_regions[i][0]
196
+ p2 = @hl_regions[i][1]
197
+ yield i, p1, p2 unless p1.nil?
198
+ end
199
+ end
202
200
 
203
- def highlight_show
204
- each_highlight_region { |i, p1, p2|
205
- @ui.bg_color = @ui.highlight_colors[i]
206
- @ui.fg_color = :black
207
- highlight_draw(p1, p2)
208
- }
209
- @ui.reset_colors
210
- end
201
+ def highlight_hide
202
+ each_highlight_region do |_i, p1, p2|
203
+ highlight_draw(p1, p2)
204
+ end
205
+ end
211
206
 
212
- def highlight_draw(p1, p2)
213
- r = row_to_scr(addr_to_row(p1))
214
- return if r > @max_scr_ln
215
- if r < 0
216
- c = 0
217
- r = 0
218
- i = row_col_to_addr(@scroll_y, 0)
219
- return if i >= p2
220
- else
221
- c = addr_to_col(p1)
222
- i = p1
207
+ def highlight_show
208
+ each_highlight_region do |i, p1, p2|
209
+ @ui.bg_color = @ui.highlight_colors[i]
210
+ @ui.fg_color = :black
211
+ highlight_draw(p1, p2)
212
+ end
213
+ @ui.reset_colors
223
214
  end
224
215
 
225
- highlight_draw_hex(r, c, i, p2)
226
- highlight_draw_char(r, c, i, p2)
227
- end
216
+ def highlight_draw(p1, p2)
217
+ r = row_to_scr(addr_to_row(p1))
218
+ return if r > @max_scr_ln
228
219
 
229
- def highlight_draw_hex(r, c, i, p2)
230
- @ui.goto(col_to_col_hex(c), r)
231
- while i < p2
232
- v = byte_at(i)
233
- return if v.nil?
234
- printf('%02x ', v)
235
- c += 1
236
- if c >= PER_LINE
220
+ if r.negative?
237
221
  c = 0
238
- r += 1
239
- return if r > @max_scr_ln
240
- @ui.goto(col_to_col_hex(c), r)
222
+ r = 0
223
+ i = row_col_to_addr(@scroll_y, 0)
224
+ return if i >= p2
225
+ else
226
+ c = addr_to_col(p1)
227
+ i = p1
241
228
  end
242
- i += 1
229
+
230
+ highlight_draw_hex(r, c, i, p2)
231
+ highlight_draw_char(r, c, i, p2)
243
232
  end
244
- end
245
233
 
246
- def highlight_draw_char(r, c, i, p2)
247
- @ui.goto(col_to_col_char(c), r)
234
+ def highlight_draw_hex(r, c, i, p2)
235
+ @ui.goto(col_to_col_hex(c), r)
236
+ while i < p2
237
+ v = byte_at(i)
238
+ return if v.nil?
248
239
 
249
- while i < p2
250
- v = byte_at(i)
251
- return if v.nil?
252
- print byte_to_display_char(v)
253
- c += 1
254
- if c >= PER_LINE
255
- c = 0
256
- r += 1
257
- return if r > @max_scr_ln
258
- @ui.goto(col_to_col_char(c), r)
240
+ printf('%02x ', v)
241
+ c += 1
242
+ if c >= PER_LINE
243
+ c = 0
244
+ r += 1
245
+ return if r > @max_scr_ln
246
+
247
+ @ui.goto(col_to_col_hex(c), r)
248
+ end
249
+ i += 1
259
250
  end
260
- i += 1
261
251
  end
262
- end
263
252
 
264
- def byte_at(i)
265
- v = @buf[i]
266
- if v.nil?
267
- nil
268
- else
269
- v.ord
253
+ def highlight_draw_char(r, c, i, p2)
254
+ @ui.goto(col_to_col_char(c), r)
255
+
256
+ while i < p2
257
+ v = byte_at(i)
258
+ return if v.nil?
259
+
260
+ print byte_to_display_char(v)
261
+ c += 1
262
+ if c >= PER_LINE
263
+ c = 0
264
+ r += 1
265
+ return if r > @max_scr_ln
266
+
267
+ @ui.goto(col_to_col_char(c), r)
268
+ end
269
+ i += 1
270
+ end
271
+ end
272
+
273
+ def byte_at(i)
274
+ v = @buf[i]
275
+ if v.nil?
276
+ nil
277
+ else
278
+ v.ord
279
+ end
270
280
  end
271
- end
272
281
 
273
- def byte_to_display_char(x)
274
- if x < 0x20 or x >= 0x7f
275
- '.'
276
- else
277
- x.chr
282
+ def byte_to_display_char(x)
283
+ if (x < 0x20) || (x >= 0x7f)
284
+ '.'
285
+ else
286
+ x.chr
287
+ end
278
288
  end
279
- end
280
289
 
281
- def addr_to_row(addr)
282
- addr / PER_LINE
283
- end
290
+ def addr_to_row(addr)
291
+ addr / PER_LINE
292
+ end
284
293
 
285
- def addr_to_col(addr)
286
- addr % PER_LINE
287
- end
294
+ def addr_to_col(addr)
295
+ addr % PER_LINE
296
+ end
288
297
 
289
- def row_col_to_addr(row, col)
290
- row * PER_LINE + col
298
+ def row_col_to_addr(row, col)
299
+ row * PER_LINE + col
300
+ end
291
301
  end
292
302
  end
293
- end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kaitai/struct/struct'
4
+
5
+ module Kaitai::Struct::Visualizer
6
+ class KSErrorMatcher
7
+ def self.===(exc)
8
+ return true if exc.is_a?(EOFError)
9
+ return true if exc.is_a?(ArgumentError)
10
+ return true if exc.is_a?(NoMethodError)
11
+ return true if exc.is_a?(TypeError)
12
+
13
+ # Raised by the runtime library's seek() implementation for negative offsets, see
14
+ # https://github.com/kaitai-io/kaitai_struct_ruby_runtime/blob/0fa62e64949f68cb001b58b7b45e15580d154ac9/lib/kaitai/struct/struct.rb#L637
15
+ return true if exc.is_a?(Errno::EINVAL)
16
+
17
+ # KaitaiStructError is a common ancestor of all Validation*Error and
18
+ # UndecidedEndiannessError classes since 0.9. However, it doesn't exist in
19
+ # the runtime library before 0.9, so we first make sure it's defined
20
+ # before we access it (accessing an undefined item would result in a
21
+ # NameError).
22
+ return true if
23
+ defined?(Kaitai::Struct::KaitaiStructError) &&
24
+ exc.is_a?(Kaitai::Struct::KaitaiStructError)
25
+ # Since 0.9, UndecidedEndiannessError is a subclass of KaitaiStructError
26
+ # (which was already handled above), but in 0.8 it was derived directly
27
+ # from Exception (in which case it hasn't been handled yet). Also,
28
+ # switchable default endianness is a new feature in 0.8, so the
29
+ # UndecidedEndiannessError class doesn't exist in older runtimes at all.
30
+ return true if
31
+ defined?(Kaitai::Struct::Stream::UndecidedEndiannessError) &&
32
+ exc.is_a?(Kaitai::Struct::Stream::UndecidedEndiannessError)
33
+ # UnexpectedDataError is no longer thrown by KSC-generated code since 0.9 -
34
+ # it has been superseded by ValidationNotEqualError. It still exists
35
+ # even in the 0.10 runtime library, but it will be removed one day, so
36
+ # we'll also check if it's defined.
37
+ return true if
38
+ defined?(Kaitai::Struct::Stream::UnexpectedDataError) &&
39
+ exc.is_a?(Kaitai::Struct::Stream::UnexpectedDataError)
40
+
41
+ false
42
+ end
43
+ end
44
+ end