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,257 +1,198 @@
1
- # coding: utf-8
2
- require 'Win32API'
1
+ # frozen_string_literal: true
2
+
3
+ require 'fiddle'
3
4
  require 'readline'
4
5
 
5
6
  module Kaitai
7
+ class ConsoleWindows
8
+ attr_reader :cols, :rows
6
9
 
7
- class ConsoleWindows
8
- attr_reader :cols
9
- attr_reader :rows
10
-
11
- GET_STD_HANDLE = Win32API.new('kernel32', 'GetStdHandle', 'L', 'L')
12
- GET_CONSOLE_SCREEN_BUFFER_INFO = Win32API.new('kernel32', 'GetConsoleScreenBufferInfo', 'LP', 'L')
13
-
14
- FILL_CONSOLE_OUTPUT_ATTRIBUTE = Win32API.new('kernel32', 'FillConsoleOutputAttribute', 'LILLP', 'I')
15
- FILL_CONSOLE_OUTPUT_CHARACTER = Win32API.new('kernel32', 'FillConsoleOutputCharacter', 'LILLP', 'I')
16
- SET_CONSOLE_CURSOR_POSITION = Win32API.new('kernel32', 'SetConsoleCursorPosition', 'LI', 'I')
17
- SET_CONSOLE_TEXT_ATTRIBUTE = Win32API.new('kernel32', 'SetConsoleTextAttribute', 'LL', 'I')
18
-
19
- WRITE_CONSOLE = Win32API.new("kernel32", "WriteConsole", ['l', 'p', 'l', 'p', 'p'], 'l')
20
-
21
- GETCH = Win32API.new("msvcrt", "_getch", [], 'I')
22
-
23
- def initialize
24
- @stdin_handle = GET_STD_HANDLE.call(-10)
25
- @stdout_handle = GET_STD_HANDLE.call(-11)
26
- @fg_color = 7
27
- @bg_color = 0
28
-
29
- # typedef struct _CONSOLE_SCREEN_BUFFER_INFO {
30
- # COORD dwSize;
31
- # COORD dwCursorPosition;
32
- # WORD wAttributes;
33
- # SMALL_RECT srWindow;
34
- # COORD dwMaximumWindowSize;
35
- # } CONSOLE_SCREEN_BUFFER_INFO;
36
-
37
- # 4 + 4 + 2 + 4 * 2 + 4 = 22
38
-
39
- csbi = 'X' * 22
40
-
41
- GET_CONSOLE_SCREEN_BUFFER_INFO.call(@stdout_handle, csbi)
42
- @buf_cols, @buf_rows,
43
- cur_x, cur_y, cur_attr,
44
- win_left, win_top, win_right, win_bottom,
45
- max_win_x, max_win_y = csbi.unpack('vvvvvvvvvvv')
46
-
47
- # Getting size of actual visible portion of Windows console
48
- # http://stackoverflow.com/a/12642749/487064
49
- @cols = win_right - win_left + 1
50
- @rows = win_bottom - win_top + 1
51
- end
10
+ kernel32 = Fiddle.dlopen('kernel32')
52
11
 
53
- def on_resize=(handler)
54
- @on_resize = handler
55
- end
12
+ dword = Fiddle::TYPE_LONG
13
+ word = Fiddle::TYPE_SHORT
14
+ ptr = Fiddle::TYPE_VOIDP
15
+ handle = Fiddle::TYPE_VOIDP
56
16
 
57
- def puts(s)
58
- Kernel::puts s
59
- # num_written = 'XXXX'
60
- # reserved = 'XXXX'
61
- # WRITE_CONSOLE.call(@stdout_handle, s, s.length, num_written, reserved)
62
- end
63
-
64
- def clear
65
- con_size = @buf_cols * @buf_rows
66
- num_written = 'XXXX'
67
- FILL_CONSOLE_OUTPUT_CHARACTER.call(
68
- @stdout_handle,
69
- 0x20, # ' '
70
- con_size,
71
- 0, # [0, 0] coords
72
- num_written
73
- )
74
- FILL_CONSOLE_OUTPUT_ATTRIBUTE.call(
75
- @stdout_handle,
76
- current_color_code,
77
- con_size,
78
- 0, # [0, 0] coords
79
- num_written
80
- )
81
- goto(0, 0)
82
- end
17
+ GET_STD_HANDLE = Fiddle::Function.new(kernel32['GetStdHandle'], [dword], handle)
18
+ GET_CONSOLE_SCREEN_BUFFER_INFO = Fiddle::Function.new(kernel32['GetConsoleScreenBufferInfo'], [handle, ptr], dword)
83
19
 
84
- ##
85
- # Put the cursor up to screen position (x, y). First line is 0,
86
- # first column is 0.
87
- def goto(x, y)
88
- coord = [x, y].pack('vv').unpack('V')[0]
89
- SET_CONSOLE_CURSOR_POSITION.call(@stdout_handle, coord)
90
- end
20
+ FILL_CONSOLE_OUTPUT_ATTRIBUTE = Fiddle::Function.new(kernel32['FillConsoleOutputAttribute'], [handle, word, dword, dword, ptr], dword)
21
+ FILL_CONSOLE_OUTPUT_CHARACTER = Fiddle::Function.new(kernel32['FillConsoleOutputCharacter'], [handle, word, dword, dword, ptr], dword)
22
+ SET_CONSOLE_CURSOR_POSITION = Fiddle::Function.new(kernel32['SetConsoleCursorPosition'], [handle, dword], dword)
23
+ SET_CONSOLE_TEXT_ATTRIBUTE = Fiddle::Function.new(kernel32['SetConsoleTextAttribute'], [handle, dword], dword)
91
24
 
92
- COLORS = {
93
- :black => 0,
94
- :blue => 1,
95
- :green => 2,
96
- :aqua => 3,
97
- :red => 4,
98
- :purple => 5,
99
- :yellow => 6,
100
- :white => 7,
101
- :gray => 8,
102
- :light_blue => 9,
103
- :light_green => 0xa,
104
- :light_aqua => 0xb,
105
- :light_red => 0xc,
106
- :light_purple => 0xd,
107
- :light_yellow => 0xe,
108
- :bright_white => 0xf,
109
- }
110
-
111
- def fg_color=(col)
112
- code = COLORS[col]
113
- raise "Invalid color: #{col}" unless code
114
- @fg_color = code
115
- update_colors
116
- end
25
+ GETCH = Fiddle::Function.new(Fiddle.dlopen('msvcrt')['_getch'], [], word)
117
26
 
118
- def bg_color=(col)
119
- code = COLORS[col]
120
- raise "Invalid color: #{col}" unless code
121
- @bg_color = code
122
- update_colors
123
- end
27
+ def initialize
28
+ @stdin_handle = GET_STD_HANDLE.call(-10)
29
+ @stdout_handle = GET_STD_HANDLE.call(-11)
30
+ @fg_color = 7
31
+ @bg_color = 0
124
32
 
125
- def reset_colors
126
- @fg_color = 7
127
- @bg_color = 0
128
- update_colors
129
- end
33
+ # typedef struct _CONSOLE_SCREEN_BUFFER_INFO {
34
+ # COORD dwSize;
35
+ # COORD dwCursorPosition;
36
+ # WORD wAttributes;
37
+ # SMALL_RECT srWindow;
38
+ # COORD dwMaximumWindowSize;
39
+ # } CONSOLE_SCREEN_BUFFER_INFO;
40
+
41
+ # 4 + 4 + 2 + 4 * 2 + 4 = 22
130
42
 
131
- ZERO_ESCAPE = 0.chr
132
- E0_ESCAPE = 0xe0.chr
133
-
134
- # Reads keypresses from the user including 2 and 3 escape character sequences.
135
- def read_char
136
- input = GETCH.call.chr
137
- if input == E0_ESCAPE || input == ZERO_ESCAPE
138
- input << GETCH.call.chr
43
+ load_term_size
139
44
  end
140
- return input
141
- end
142
45
 
143
- def read_char_mapped
144
- c = read_char
145
- c2 = KEY_MAP[c]
146
- c2 ? c2 : c
147
- end
46
+ def load_term_size
47
+ csbi = 'X' * 22
148
48
 
149
- KEY_MAP = {
150
- "\b" => :backspace,
151
- "\t" => :tab,
152
- "\r" => :enter,
153
-
154
- # Regular AT keyboard arrows
155
- E0_ESCAPE + "H" => :up_arrow,
156
- E0_ESCAPE + "P" => :down_arrow,
157
- E0_ESCAPE + "K" => :left_arrow,
158
- E0_ESCAPE + "M" => :right_arrow,
159
- E0_ESCAPE + "I" => :pg_up,
160
- E0_ESCAPE + "Q" => :pg_dn,
161
- E0_ESCAPE + "G" => :home,
162
- E0_ESCAPE + "O" => :end,
163
-
164
- # Keypad
165
- ZERO_ESCAPE + "H" => :up_arrow,
166
- ZERO_ESCAPE + "P" => :down_arrow,
167
- ZERO_ESCAPE + "K" => :left_arrow,
168
- ZERO_ESCAPE + "M" => :right_arrow,
169
- ZERO_ESCAPE + "I" => :pg_up,
170
- ZERO_ESCAPE + "Q" => :pg_dn,
171
- ZERO_ESCAPE + "G" => :home,
172
- ZERO_ESCAPE + "O" => :end,
173
- }
174
-
175
- def message_box_exception(e)
176
- message_box("Error while parsing", e.message)
177
- end
49
+ GET_CONSOLE_SCREEN_BUFFER_INFO.call(@stdout_handle, csbi)
50
+ @buf_cols, @buf_rows,
51
+ _cur_x, _cur_y, _cur_attr,
52
+ win_left, win_top, win_right, win_bottom,
53
+ _max_win_x, _max_win_y = csbi.unpack('vvvvvvvvvvv')
178
54
 
179
- SINGLE_CHARSET = '┌┐└┘─│'
180
- HEAVY_CHARSET = '┏┓┗┛━┃'
181
- DOUBLE_CHARSET = '╔╗╚╝═║'
182
-
183
- CHAR_TL = 0
184
- CHAR_TR = 1
185
- CHAR_BL = 2
186
- CHAR_BR = 3
187
- CHAR_H = 4
188
- CHAR_V = 5
189
-
190
- def message_box(header, msg)
191
- top_y = @rows / 2 - 5
192
- draw_rectangle(10, top_y, @cols - 20, 10)
193
- goto(@cols / 2 - (header.length / 2) - 1, top_y)
194
- print ' ', header, ' '
195
- goto(11, top_y + 1)
196
- puts msg
197
- draw_button(@cols / 2 - 10, top_y + 8, 10, 'OK')
198
- loop {
199
- c = read_char_mapped
200
- return if c == :enter
201
- }
202
- end
55
+ # Getting size of actual visible portion of Windows console
56
+ # http://stackoverflow.com/a/12642749/487064
57
+ @cols = win_right - win_left + 1
58
+ @rows = win_bottom - win_top + 1
59
+ end
203
60
 
204
- def input_str(header, msg)
205
- top_y = @rows / 2 - 5
206
- draw_rectangle(10, top_y, @cols - 20, 10)
207
- goto(@cols / 2 - (header.length / 2) - 1, top_y)
208
- print ' ', header, ' '
61
+ attr_writer :on_resize
62
+
63
+ def clear
64
+ con_size = @buf_cols * @buf_rows
65
+ num_written = +'XXXX'
66
+ FILL_CONSOLE_OUTPUT_CHARACTER.call(
67
+ @stdout_handle,
68
+ 0x20, # ' '
69
+ con_size,
70
+ 0, # [0, 0] coords
71
+ num_written
72
+ )
73
+ FILL_CONSOLE_OUTPUT_ATTRIBUTE.call(
74
+ @stdout_handle,
75
+ current_color_code,
76
+ con_size,
77
+ 0, # [0, 0] coords
78
+ num_written
79
+ )
80
+ goto(0, 0)
81
+ end
209
82
 
210
- goto(11, top_y + 1)
211
- Readline.readline('', false)
212
- end
83
+ # Put the cursor up to screen position (x, y). First line is 0, first column is 0.
84
+ def goto(x, y)
85
+ coord = [x, y].pack('vv').unpack1('V')
86
+ SET_CONSOLE_CURSOR_POSITION.call(@stdout_handle, coord)
87
+ end
213
88
 
214
- def draw_rectangle(x, y, w, h, charset = DOUBLE_CHARSET)
215
- goto(x, y)
216
- print charset[CHAR_TL]
217
- print charset[CHAR_H] * (w - 2)
218
- print charset[CHAR_TR]
219
-
220
- ((y + 1)..(y + h - 1)).each { |i|
221
- goto(x, i)
222
- print charset[CHAR_V]
223
- print ' ' * (w - 2)
224
- print charset[CHAR_V]
225
- }
226
-
227
- goto(x, y + h)
228
- print charset[CHAR_BL]
229
- print charset[CHAR_H] * (w - 2)
230
- print charset[CHAR_BR]
231
- end
89
+ COLORS = {
90
+ black: 0,
91
+ blue: 1,
92
+ green: 2,
93
+ cyan: 3,
94
+ red: 4,
95
+ magenta: 5,
96
+ yellow: 6,
97
+ white: 7,
98
+ gray: 8,
99
+ bright_blue: 9,
100
+ bright_green: 10,
101
+ bright_cyan: 11,
102
+ bright_red: 12,
103
+ bright_magenta: 13,
104
+ bright_yellow: 14,
105
+ bright_white: 15
106
+ }.freeze
107
+
108
+ def fg_color=(col)
109
+ code = COLORS[col]
110
+ raise "Invalid color: #{col}" unless code
111
+
112
+ @fg_color = code
113
+ update_colors
114
+ end
232
115
 
233
- def draw_button(x, y, w, caption)
234
- goto(x, y)
235
- puts "[ #{caption} ]"
236
- end
116
+ def bg_color=(col)
117
+ code = COLORS[col]
118
+ raise "Invalid color: #{col}" unless code
237
119
 
238
- # Regexp borrowed from
239
- # http://stackoverflow.com/questions/170956/how-can-i-find-which-operating-system-my-ruby-program-is-running-on
240
- @@is_windows = (RUBY_PLATFORM =~ /cygwin|mswin|mingw|bccwin|wince|emx/) ? true : false
120
+ @bg_color = code
121
+ update_colors
122
+ end
241
123
 
242
- # Detects if current platform is Windows-based.
243
- def self.is_windows?
244
- @@is_windows
245
- end
124
+ def reset_colors
125
+ @fg_color = 7
126
+ @bg_color = 0
127
+ update_colors
128
+ end
246
129
 
247
- private
248
- def current_color_code
249
- (@bg_color << 4) | @fg_color
250
- end
251
-
252
- def update_colors
253
- SET_CONSOLE_TEXT_ATTRIBUTE.call(@stdout_handle, current_color_code)
254
- end
255
- end
130
+ ZERO_ESCAPE = 0.chr
131
+ E0_ESCAPE = 0xe0.chr
132
+
133
+ # Reads keypresses from the user including 2 and 3 escape character sequences.
134
+ def read_char
135
+ input = GETCH.call.chr
136
+ input << GETCH.call.chr if input == E0_ESCAPE || input == ZERO_ESCAPE
256
137
 
138
+ # https://github.com/kaitai-io/kaitai_struct_visualizer/issues/14
139
+ load_term_size
140
+ @on_resize&.call(false)
141
+
142
+ input
143
+ end
144
+
145
+ def read_char_mapped
146
+ c = read_char
147
+ c2 = KEY_MAP[c]
148
+ c2 || c
149
+ end
150
+
151
+ KEY_MAP = {
152
+ "\b" => :backspace,
153
+ "\t" => :tab,
154
+ "\r" => :enter,
155
+
156
+ # Regular AT keyboard arrows
157
+ "#{E0_ESCAPE}H" => :up_arrow,
158
+ "#{E0_ESCAPE}P" => :down_arrow,
159
+ "#{E0_ESCAPE}K" => :left_arrow,
160
+ "#{E0_ESCAPE}M" => :right_arrow,
161
+ "#{E0_ESCAPE}I" => :pg_up,
162
+ "#{E0_ESCAPE}Q" => :pg_dn,
163
+ "#{E0_ESCAPE}G" => :home,
164
+ "#{E0_ESCAPE}O" => :end,
165
+
166
+ # Keypad
167
+ "#{ZERO_ESCAPE}H" => :up_arrow,
168
+ "#{ZERO_ESCAPE}P" => :down_arrow,
169
+ "#{ZERO_ESCAPE}K" => :left_arrow,
170
+ "#{ZERO_ESCAPE}M" => :right_arrow,
171
+ "#{ZERO_ESCAPE}I" => :pg_up,
172
+ "#{ZERO_ESCAPE}Q" => :pg_dn,
173
+ "#{ZERO_ESCAPE}G" => :home,
174
+ "#{ZERO_ESCAPE}O" => :end
175
+ }.freeze
176
+
177
+ SINGLE_CHARSET = '┌┐└┘─│'
178
+ HEAVY_CHARSET = '┏┓┗┛━┃'
179
+ DOUBLE_CHARSET = '╔╗╚╝═║'
180
+
181
+ CHAR_TL = 0
182
+ CHAR_TR = 1
183
+ CHAR_BL = 2
184
+ CHAR_BR = 3
185
+ CHAR_H = 4
186
+ CHAR_V = 5
187
+
188
+ private
189
+
190
+ def current_color_code
191
+ (@bg_color << 4) | @fg_color
192
+ end
193
+
194
+ def update_colors
195
+ SET_CONSOLE_TEXT_ATTRIBUTE.call(@stdout_handle, current_color_code)
196
+ end
197
+ end
257
198
  end