hexdump 0.3.0 → 1.0.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.
- checksums.yaml +4 -4
- data/ChangeLog.md +68 -2
- data/Gemfile +1 -0
- data/README.md +486 -135
- data/benchmark.rb +29 -22
- data/lib/hexdump/chars.rb +46 -0
- data/lib/hexdump/core_ext/file.rb +68 -6
- data/lib/hexdump/core_ext/io.rb +2 -2
- data/lib/hexdump/core_ext/kernel.rb +7 -0
- data/lib/hexdump/core_ext/string.rb +2 -2
- data/lib/hexdump/core_ext/string_io.rb +2 -2
- data/lib/hexdump/core_ext.rb +1 -0
- data/lib/hexdump/format_string.rb +43 -0
- data/lib/hexdump/hexdump.rb +768 -75
- data/lib/hexdump/mixin.rb +198 -0
- data/lib/hexdump/module_methods.rb +132 -0
- data/lib/hexdump/numeric/binary.rb +55 -0
- data/lib/hexdump/numeric/char_or_int.rb +90 -0
- data/lib/hexdump/numeric/decimal.rb +56 -0
- data/lib/hexdump/numeric/exceptions.rb +11 -0
- data/lib/hexdump/numeric/hexadecimal.rb +59 -0
- data/lib/hexdump/numeric/octal.rb +55 -0
- data/lib/hexdump/numeric.rb +5 -0
- data/lib/hexdump/reader.rb +314 -0
- data/lib/hexdump/theme/ansi.rb +81 -0
- data/lib/hexdump/theme/rule.rb +159 -0
- data/lib/hexdump/theme.rb +61 -0
- data/lib/hexdump/type.rb +232 -0
- data/lib/hexdump/types.rb +108 -0
- data/lib/hexdump/version.rb +1 -1
- data/lib/hexdump.rb +12 -1
- data/spec/chars_spec.rb +76 -0
- data/spec/core_ext_spec.rb +10 -6
- data/spec/hexdump_class_spec.rb +1708 -0
- data/spec/hexdump_module_spec.rb +23 -0
- data/spec/mixin_spec.rb +37 -0
- data/spec/numeric/binary_spec.rb +239 -0
- data/spec/numeric/char_or_int_spec.rb +210 -0
- data/spec/numeric/decimal_spec.rb +317 -0
- data/spec/numeric/hexadecimal_spec.rb +320 -0
- data/spec/numeric/octal_spec.rb +239 -0
- data/spec/reader_spec.rb +863 -0
- data/spec/theme/ansi_spec.rb +242 -0
- data/spec/theme/rule_spec.rb +199 -0
- data/spec/theme_spec.rb +94 -0
- data/spec/type_spec.rb +317 -0
- data/spec/types_spec.rb +904 -0
- metadata +39 -10
- data/.gemtest +0 -0
- data/lib/hexdump/dumper.rb +0 -419
- data/spec/dumper_spec.rb +0 -329
- data/spec/hexdump_spec.rb +0 -30
@@ -0,0 +1,81 @@
|
|
1
|
+
module Hexdump
|
2
|
+
class Theme
|
3
|
+
#
|
4
|
+
# Represents an ANSI control sequence.
|
5
|
+
#
|
6
|
+
# @api private
|
7
|
+
#
|
8
|
+
# @since 1.0.0
|
9
|
+
#
|
10
|
+
class ANSI
|
11
|
+
# ANSI reset control sequence
|
12
|
+
RESET = "\e[0m"
|
13
|
+
|
14
|
+
PARAMETERS = {
|
15
|
+
reset: RESET,
|
16
|
+
|
17
|
+
bold: "\e[1m",
|
18
|
+
faint: "\e[2m",
|
19
|
+
italic: "\e[3m",
|
20
|
+
underline: "\e[4m",
|
21
|
+
invert: "\e[7m",
|
22
|
+
strike: "\e[9m",
|
23
|
+
black: "\e[30m",
|
24
|
+
red: "\e[31m",
|
25
|
+
green: "\e[32m",
|
26
|
+
yellow: "\e[33m",
|
27
|
+
blue: "\e[34m",
|
28
|
+
magenta: "\e[35m",
|
29
|
+
cyan: "\e[36m",
|
30
|
+
white: "\e[37m",
|
31
|
+
|
32
|
+
on_black: "\e[40m",
|
33
|
+
on_red: "\e[41m",
|
34
|
+
on_green: "\e[42m",
|
35
|
+
on_yellow: "\e[43m",
|
36
|
+
on_blue: "\e[44m",
|
37
|
+
on_magenta: "\e[45m",
|
38
|
+
on_cyan: "\e[46m",
|
39
|
+
on_white: "\e[47m"
|
40
|
+
}
|
41
|
+
|
42
|
+
# The style name(s).
|
43
|
+
#
|
44
|
+
# @return [Symbol, Array<Symbol>] style
|
45
|
+
attr_reader :parameters
|
46
|
+
|
47
|
+
# The ANSI string.
|
48
|
+
#
|
49
|
+
# @return [String]
|
50
|
+
attr_reader :string
|
51
|
+
|
52
|
+
#
|
53
|
+
# Initializes an ANSI control sequence.
|
54
|
+
#
|
55
|
+
# @param [Symbol, Array<Symbol>] style
|
56
|
+
#
|
57
|
+
def initialize(parameters)
|
58
|
+
@parameters = parameters
|
59
|
+
|
60
|
+
@string = String.new
|
61
|
+
|
62
|
+
Array(parameters).each do |name|
|
63
|
+
@string << PARAMETERS.fetch(name) do
|
64
|
+
raise(ArgumentError,"unknown ANSI parameter: #{name}")
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Returns the ANSI string.
|
71
|
+
#
|
72
|
+
# @return [String]
|
73
|
+
#
|
74
|
+
def to_s
|
75
|
+
@string
|
76
|
+
end
|
77
|
+
|
78
|
+
alias to_str to_s
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'hexdump/theme/ansi'
|
2
|
+
|
3
|
+
require 'strscan'
|
4
|
+
|
5
|
+
module Hexdump
|
6
|
+
class Theme
|
7
|
+
#
|
8
|
+
# Represents a color highlighting rule.
|
9
|
+
#
|
10
|
+
# @api private
|
11
|
+
#
|
12
|
+
# @since 1.0.0
|
13
|
+
#
|
14
|
+
class Rule
|
15
|
+
|
16
|
+
# The default style to apply to strings.
|
17
|
+
#
|
18
|
+
# @return [ANSI, nil]
|
19
|
+
attr_reader :style
|
20
|
+
|
21
|
+
# Highlighting rules for exact strings.
|
22
|
+
#
|
23
|
+
# @return [Hash{String => ANSI}]
|
24
|
+
attr_reader :highlight_strings
|
25
|
+
|
26
|
+
# Highlighting rules for matching substrings.
|
27
|
+
#
|
28
|
+
# @return [Hash{String => ANSI}]
|
29
|
+
attr_reader :highlight_regexps
|
30
|
+
|
31
|
+
#
|
32
|
+
# Initializes the color.
|
33
|
+
#
|
34
|
+
# @param [Symbol, Array<Symbol>] style
|
35
|
+
# The default style name(s). See {ANSI::PARAMETERS}.
|
36
|
+
#
|
37
|
+
# @param [Hash{String,Regexp => Symbol,Array<Symbol>}, nil] highlights
|
38
|
+
# Optional highlighting rules.
|
39
|
+
#
|
40
|
+
def initialize(style: nil, highlights: nil)
|
41
|
+
@reset = ANSI::RESET
|
42
|
+
|
43
|
+
@style = if style
|
44
|
+
ANSI.new(style)
|
45
|
+
end
|
46
|
+
|
47
|
+
@highlight_strings = {}
|
48
|
+
@highlight_regexps = {}
|
49
|
+
|
50
|
+
if highlights
|
51
|
+
highlights.each do |pattern,style|
|
52
|
+
highlight(pattern,style)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# The highlighting rules.
|
59
|
+
#
|
60
|
+
# @return [Hash{String,Regexp => ANSI}]
|
61
|
+
# The combination of {#highlight_strings} and {#highlight_regexps}.
|
62
|
+
#
|
63
|
+
def highlights
|
64
|
+
@highlight_strings.merge(@highlight_regexps)
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Adds a highlighting rule.
|
69
|
+
#
|
70
|
+
# @param [String, Regexp] pattern
|
71
|
+
# The exact String to highlight or regular expression to highlight.
|
72
|
+
#
|
73
|
+
# @param [Symbol, Array<Symbol>] style
|
74
|
+
# The style name(s). See {ANSI::PARAMETERS}.
|
75
|
+
#
|
76
|
+
# @raise [ArgumentError]
|
77
|
+
# The given pattern was not a String or Regexp.
|
78
|
+
#
|
79
|
+
# @example
|
80
|
+
# hexdump.style.numeric.highlight('00', :faint)
|
81
|
+
#
|
82
|
+
# @example
|
83
|
+
# hexdump.style.index.highlight(/00$/, [:white, :bold])
|
84
|
+
#
|
85
|
+
# @api public
|
86
|
+
#
|
87
|
+
def highlight(pattern,style)
|
88
|
+
ansi = ANSI.new(style)
|
89
|
+
|
90
|
+
case pattern
|
91
|
+
when String
|
92
|
+
@highlight_strings[pattern] = ansi
|
93
|
+
when Regexp
|
94
|
+
@highlight_regexps[pattern] = ansi
|
95
|
+
else
|
96
|
+
raise(ArgumentError,"pattern must be a String or Regexp: #{pattern.inspect}")
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
#
|
101
|
+
# Applies coloring/highlighting to a string.
|
102
|
+
#
|
103
|
+
# @param [String] string
|
104
|
+
# The string to color/highlight.
|
105
|
+
#
|
106
|
+
# @return [String]
|
107
|
+
# The colored the string.
|
108
|
+
#
|
109
|
+
def apply(string)
|
110
|
+
if (!@highlight_strings.empty? || !@highlight_regexps.empty?)
|
111
|
+
apply_highlight(string)
|
112
|
+
elsif @style
|
113
|
+
"#{@style}#{string}#{@reset}"
|
114
|
+
else
|
115
|
+
string
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
private
|
120
|
+
|
121
|
+
def apply_highlight(string)
|
122
|
+
if (ansi = @highlight_strings[string])
|
123
|
+
# highlight the whole string
|
124
|
+
"#{ansi}#{string}#{@reset}"
|
125
|
+
else
|
126
|
+
scanner = StringScanner.new(string)
|
127
|
+
new_string = String.new
|
128
|
+
|
129
|
+
until scanner.eos?
|
130
|
+
matched = false
|
131
|
+
|
132
|
+
@highlight_regexps.each do |regexp,ansi|
|
133
|
+
if (match = scanner.scan(regexp))
|
134
|
+
# highlight the match
|
135
|
+
new_string << "#{ansi}#{match}#{@reset}"
|
136
|
+
new_string << "#{@style}" unless scanner.eos?
|
137
|
+
matched = true
|
138
|
+
break
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
unless matched
|
143
|
+
# next char
|
144
|
+
new_string << scanner.getch
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
if @style
|
149
|
+
new_string.prepend(@style) unless new_string.start_with?("\e")
|
150
|
+
new_string << @reset unless new_string.end_with?(@reset)
|
151
|
+
end
|
152
|
+
|
153
|
+
new_string
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'hexdump/theme/rule'
|
2
|
+
|
3
|
+
module Hexdump
|
4
|
+
#
|
5
|
+
# Represents a hexdump theme (styling + highlighting).
|
6
|
+
#
|
7
|
+
# @api semipublic
|
8
|
+
#
|
9
|
+
# @since 1.0.0
|
10
|
+
#
|
11
|
+
class Theme
|
12
|
+
|
13
|
+
# The index styling/highlights.
|
14
|
+
#
|
15
|
+
# @return [Rule, nil]
|
16
|
+
#
|
17
|
+
# @api public
|
18
|
+
attr_reader :index
|
19
|
+
|
20
|
+
# The numeric styling/highlights.
|
21
|
+
#
|
22
|
+
# @return [Rule, nil]
|
23
|
+
#
|
24
|
+
# @api public
|
25
|
+
attr_reader :numeric
|
26
|
+
|
27
|
+
# The chars styling/highlights.
|
28
|
+
#
|
29
|
+
# @return [Rule, nil]
|
30
|
+
#
|
31
|
+
# @api public
|
32
|
+
attr_reader :chars
|
33
|
+
|
34
|
+
#
|
35
|
+
# Initializes the theme.
|
36
|
+
#
|
37
|
+
# @param [Hash{:index,:numeric,:chars => Symbol,Array<Symbol>,nil}] style
|
38
|
+
# The default style of the index, numeric, and/or chars columns.
|
39
|
+
#
|
40
|
+
# @param [Hash{:index,:numeric,:chars => Hash{String,Regexp => Symbol,Array<Symbol>},nil}] highlights
|
41
|
+
# The highlighting rules for the index, numeric, and/or chars columns.
|
42
|
+
#
|
43
|
+
def initialize(style: {}, highlights: {})
|
44
|
+
@index = Rule.new(
|
45
|
+
style: style[:index],
|
46
|
+
highlights: highlights[:index]
|
47
|
+
)
|
48
|
+
|
49
|
+
@numeric = Rule.new(
|
50
|
+
style: style[:numeric],
|
51
|
+
highlights: highlights[:numeric]
|
52
|
+
)
|
53
|
+
|
54
|
+
@chars = Rule.new(
|
55
|
+
style: style[:chars],
|
56
|
+
highlights: highlights[:chars]
|
57
|
+
)
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
data/lib/hexdump/type.rb
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
module Hexdump
|
2
|
+
#
|
3
|
+
# @api private
|
4
|
+
#
|
5
|
+
# @since 1.0.0
|
6
|
+
#
|
7
|
+
class Type
|
8
|
+
|
9
|
+
# The endian-ness of the type.
|
10
|
+
#
|
11
|
+
# @return [:little, :big, nil]
|
12
|
+
attr_reader :endian
|
13
|
+
|
14
|
+
# The size in bytes of the type.
|
15
|
+
#
|
16
|
+
# @return [1, 2, 4, 8]
|
17
|
+
attr_reader :size
|
18
|
+
|
19
|
+
#
|
20
|
+
# Initializes the type.
|
21
|
+
#
|
22
|
+
# @param [Symbol] name
|
23
|
+
#
|
24
|
+
# @param [:little, :big, nil] endian
|
25
|
+
#
|
26
|
+
# @param [1, 2, 4, 8] size
|
27
|
+
#
|
28
|
+
# @param [Boolean] signed
|
29
|
+
#
|
30
|
+
# @raise [ArgumentError]
|
31
|
+
# Invalid `endian:` or `size:` values.
|
32
|
+
#
|
33
|
+
def initialize(size: , endian: nil, signed: )
|
34
|
+
@endian = endian
|
35
|
+
@size = size
|
36
|
+
@signed = signed
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Whether the type is signed.
|
41
|
+
#
|
42
|
+
# @return [Boolean]
|
43
|
+
#
|
44
|
+
def signed?
|
45
|
+
@signed
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Whether the type is unsigned.
|
50
|
+
#
|
51
|
+
# @return [Boolean]
|
52
|
+
#
|
53
|
+
def unsigned?
|
54
|
+
!@signed
|
55
|
+
end
|
56
|
+
|
57
|
+
# The native endian-ness.
|
58
|
+
NATIVE_ENDIAN = if [0x1].pack('I') == [0x1].pack('N')
|
59
|
+
:big
|
60
|
+
else
|
61
|
+
:little
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Represents a signed integer type.
|
66
|
+
#
|
67
|
+
class Int < self
|
68
|
+
|
69
|
+
#
|
70
|
+
# Initializes the int type.
|
71
|
+
#
|
72
|
+
# @param [:little, :big] endian (NATIVE_ENDIAN)
|
73
|
+
# The endian-ness of the int type.
|
74
|
+
#
|
75
|
+
def initialize(endian: NATIVE_ENDIAN, **kwargs)
|
76
|
+
super(signed: true, endian: endian, **kwargs)
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
class Int8 < Int
|
82
|
+
|
83
|
+
#
|
84
|
+
# @see Int#initialize
|
85
|
+
#
|
86
|
+
def initialize(**kwargs)
|
87
|
+
super(size: 1, endian: nil, **kwargs)
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
class Int16 < Int
|
93
|
+
|
94
|
+
#
|
95
|
+
# @see Int#initialize
|
96
|
+
#
|
97
|
+
def initialize(**kwargs)
|
98
|
+
super(size: 2, **kwargs)
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
class Int32 < Int
|
104
|
+
|
105
|
+
#
|
106
|
+
# @see Int#initialize
|
107
|
+
#
|
108
|
+
def initialize(**kwargs)
|
109
|
+
super(size: 4, **kwargs)
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
class Int64 < Int
|
115
|
+
|
116
|
+
#
|
117
|
+
# @see Int#initialize
|
118
|
+
#
|
119
|
+
def initialize(**kwargs)
|
120
|
+
super(size: 8, **kwargs)
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
#
|
126
|
+
# Represents a unsigned integer type.
|
127
|
+
#
|
128
|
+
class UInt < self
|
129
|
+
|
130
|
+
#
|
131
|
+
# Initializes the uint type.
|
132
|
+
#
|
133
|
+
# @param [:little, :big] endian (NATIVE_ENDIAN)
|
134
|
+
# The endian-ness of the uint type.
|
135
|
+
#
|
136
|
+
def initialize(endian: NATIVE_ENDIAN, **kwargs)
|
137
|
+
super(signed: false, endian: endian, **kwargs)
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
|
142
|
+
class UInt8 < UInt
|
143
|
+
|
144
|
+
#
|
145
|
+
# @see UInt#initialize
|
146
|
+
#
|
147
|
+
def initialize(**kwargs)
|
148
|
+
super(size: 1, endian: nil, **kwargs)
|
149
|
+
end
|
150
|
+
|
151
|
+
end
|
152
|
+
|
153
|
+
class UInt16 < UInt
|
154
|
+
|
155
|
+
#
|
156
|
+
# @see UInt#initialize
|
157
|
+
#
|
158
|
+
def initialize(**kwargs)
|
159
|
+
super(size: 2, **kwargs)
|
160
|
+
end
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
class UInt32 < UInt
|
165
|
+
|
166
|
+
#
|
167
|
+
# @see UInt#initialize
|
168
|
+
#
|
169
|
+
def initialize(**kwargs)
|
170
|
+
super(size: 4, **kwargs)
|
171
|
+
end
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
class UInt64 < UInt
|
176
|
+
|
177
|
+
#
|
178
|
+
# @see UInt#initialize
|
179
|
+
#
|
180
|
+
def initialize(**kwargs)
|
181
|
+
super(size: 8, **kwargs)
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
#
|
187
|
+
# Represents a single-byte character.
|
188
|
+
#
|
189
|
+
class Char < Int8
|
190
|
+
end
|
191
|
+
|
192
|
+
#
|
193
|
+
# Represents a single-byte unsigned character.
|
194
|
+
#
|
195
|
+
class UChar < UInt8
|
196
|
+
end
|
197
|
+
|
198
|
+
#
|
199
|
+
# Represents a floating point type.
|
200
|
+
#
|
201
|
+
class Float < self
|
202
|
+
|
203
|
+
#
|
204
|
+
# Initializes the float type.
|
205
|
+
#
|
206
|
+
# @param [:little, :big] endian (NATIVE_ENDIAN)
|
207
|
+
# The endian-ness of the float type.
|
208
|
+
#
|
209
|
+
def initialize(endian: NATIVE_ENDIAN, **kwargs)
|
210
|
+
super(signed: true, endian: endian, **kwargs)
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
214
|
+
|
215
|
+
class Float32 < Float
|
216
|
+
|
217
|
+
def initialize(**kwargs)
|
218
|
+
super(size: 4, **kwargs)
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
|
223
|
+
class Float64 < Float
|
224
|
+
|
225
|
+
def initialize(**kwargs)
|
226
|
+
super(size: 8, **kwargs)
|
227
|
+
end
|
228
|
+
|
229
|
+
end
|
230
|
+
|
231
|
+
end
|
232
|
+
end
|