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
data/benchmark.rb
CHANGED
@@ -5,43 +5,50 @@ $LOAD_PATH.unshift(File.expand_path('../lib',__FILE__))
|
|
5
5
|
require 'hexdump'
|
6
6
|
require 'benchmark'
|
7
7
|
|
8
|
-
|
9
|
-
|
8
|
+
class NullOutput
|
9
|
+
def <<(data)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
size_mb = 1
|
14
|
+
puts "Generating #{size_mb}Mb of random data ..."
|
15
|
+
data = Array.new(size_mb * 1024 * 1024) { rand(255).chr }.join
|
16
|
+
output = NullOutput.new
|
10
17
|
|
11
|
-
|
12
|
-
|
13
|
-
|
18
|
+
types = Hexdump::TYPES.values.uniq.map(&Hexdump::TYPES.method(:key))
|
19
|
+
|
20
|
+
Benchmark.bm(42) do |b|
|
21
|
+
b.report('Hexdump.hexdump(data)') do
|
22
|
+
Hexdump.hexdump(data, output: output)
|
14
23
|
end
|
15
24
|
|
16
|
-
b.report(
|
17
|
-
Hexdump.
|
25
|
+
b.report("Hexdump.hexdump(data, repeating: false)") do
|
26
|
+
Hexdump.hexdump(data, repeating: false, output: output)
|
18
27
|
end
|
19
28
|
|
20
|
-
b.report(
|
21
|
-
Hexdump.
|
29
|
+
b.report("Hexdump.hexdump(data, chars_column: false)") do
|
30
|
+
Hexdump.hexdump(data, chars_column: false, output: output)
|
22
31
|
end
|
23
32
|
|
24
|
-
|
25
|
-
|
26
|
-
Hexdump.dump(DATA, word_size: word_size, output: OUTPUT)
|
27
|
-
end
|
33
|
+
b.report('Hexdump.hexdump(data, columns: 256)') do
|
34
|
+
Hexdump.hexdump(data, columns: 256, output: output)
|
28
35
|
end
|
29
36
|
|
30
|
-
b.report('Hexdump.
|
31
|
-
Hexdump.
|
37
|
+
b.report('Hexdump.hexdump(data, group_columns: 4)') do
|
38
|
+
Hexdump.hexdump(data, group_columns: 4, output: output)
|
32
39
|
end
|
33
40
|
|
34
|
-
b.report('Hexdump.
|
35
|
-
Hexdump.
|
41
|
+
b.report('Hexdump.hexdump(data, group_chars: 4)') do
|
42
|
+
Hexdump.hexdump(data, group_chars: 4, output: output)
|
36
43
|
end
|
37
44
|
|
38
|
-
b.report('Hexdump.
|
39
|
-
Hexdump.
|
45
|
+
b.report('Hexdump.hexdump(data, encoding: :utf8)') do
|
46
|
+
Hexdump.hexdump(data, encoding: :utf8, output: output)
|
40
47
|
end
|
41
48
|
|
42
|
-
|
43
|
-
b.report("Hexdump.
|
44
|
-
Hexdump.
|
49
|
+
types.each do |type|
|
50
|
+
b.report("Hexdump.hexdump(data, type: #{type.inspect})") do
|
51
|
+
Hexdump.hexdump(data, type: type, output: output)
|
45
52
|
end
|
46
53
|
end
|
47
54
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Hexdump
|
2
|
+
#
|
3
|
+
# @api private
|
4
|
+
#
|
5
|
+
# @since 1.0.0
|
6
|
+
#
|
7
|
+
class Chars
|
8
|
+
|
9
|
+
# The encoding to convert the characters to.
|
10
|
+
#
|
11
|
+
# @return [Encoding, nil]
|
12
|
+
attr_reader :encoding
|
13
|
+
|
14
|
+
#
|
15
|
+
# Initializes the chars formatter.
|
16
|
+
#
|
17
|
+
# @param [Encoding, nil] encoding
|
18
|
+
# The encoding to convert characters to.
|
19
|
+
#
|
20
|
+
def initialize(encoding=nil)
|
21
|
+
@encoding = encoding
|
22
|
+
end
|
23
|
+
|
24
|
+
#
|
25
|
+
# Formats a string of characters.
|
26
|
+
#
|
27
|
+
# @param [String] chars
|
28
|
+
# The input string of raw characters.
|
29
|
+
#
|
30
|
+
# @return [String]
|
31
|
+
# The formatted string of raw characters.
|
32
|
+
#
|
33
|
+
def scrub(chars)
|
34
|
+
if @encoding
|
35
|
+
chars.force_encoding(@encoding)
|
36
|
+
chars.scrub!('.')
|
37
|
+
chars.gsub!(/[^[:print:]]/u,'.')
|
38
|
+
else
|
39
|
+
chars.tr!("^\x20-\x7e",'.')
|
40
|
+
end
|
41
|
+
|
42
|
+
chars
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require 'hexdump/
|
1
|
+
require 'hexdump/core_ext/io'
|
2
2
|
|
3
3
|
class File
|
4
4
|
|
@@ -8,14 +8,76 @@ class File
|
|
8
8
|
# @param [String] path
|
9
9
|
# The path of the file.
|
10
10
|
#
|
11
|
-
# @param [Hash]
|
12
|
-
# Additional
|
11
|
+
# @param [Hash{Symbol => Object}] kwargs
|
12
|
+
# Additional keyword arguments for {Format#initialize}.
|
13
13
|
#
|
14
|
-
# @
|
14
|
+
# @option kwargs [#print] :output ($stdout)
|
15
|
+
# The output to print the hexdump to.
|
15
16
|
#
|
16
|
-
|
17
|
+
# @option kwargs [:int8, :uint8, :char, :uchar, :byte, :int16, :int16_le, :int16_be, :int16_ne, :uint16, :uint16_le, :uint16_be, :uint16_ne, :short, :short_le, :short_be, :short_ne, :ushort, :ushort_le, :ushort_be, :ushort_ne, :int32, :int32_le, :int32_be, :int32_ne, :uint32, :uint32_le, :uint32_be, :uint32_ne, :int, :long, :long_le, :long_be, :long_ne, :uint, :ulong, :ulong_le, :ulong_be, :ulong_ne, :int64, :int64_le, :int64_be, :int64_ne, :uint64, :uint64_le, :uint64_be, :uint64_ne, :long_long, :long_long_le, :long_long_be, :long_long_ne, :ulong_long, :ulong_long_le, :ulong_long_be, :ulong_long_ne, :float, :float_le, :float_be, :float_ne, :double, :double_le, :double_be, :double_ne] :type (:byte)
|
18
|
+
# The type to decode the data as.
|
19
|
+
#
|
20
|
+
# @option kwargs [Integer, nil] :offset
|
21
|
+
# Controls whether to skip N number of bytes before starting to read data.
|
22
|
+
#
|
23
|
+
# @option kwargs [Integer, nil] :length
|
24
|
+
# Controls control many bytes to read.
|
25
|
+
#
|
26
|
+
# @option kwargs [Boolean] :zero_pad (false)
|
27
|
+
# Enables or disables zero padding of data, so that the remaining bytes
|
28
|
+
# can be decoded as a uint, int, or float.
|
29
|
+
#
|
30
|
+
# @option kwargs [Integer] :columns (16)
|
31
|
+
# The number of bytes to dump for each line.
|
32
|
+
#
|
33
|
+
# @option kwargs [Integer, nil] :group_columns
|
34
|
+
# Separate groups of columns with an additional space.
|
35
|
+
#
|
36
|
+
# @option kwargs [Integer, :type, nil] :group_chars
|
37
|
+
# Group chars into columns.
|
38
|
+
# If `:type`, then the chars will be grouped by the `type`'s size.
|
39
|
+
#
|
40
|
+
# @option kwargs [Boolean] :repeating
|
41
|
+
# Controls whether to omit repeating duplicate rows data with a `*`.
|
42
|
+
#
|
43
|
+
# @option kwargs [16, 10, 8, 2] :base (16)
|
44
|
+
# The base to print bytes in.
|
45
|
+
#
|
46
|
+
# @option kwargs [16, 10, 8, 2] :index_base (16)
|
47
|
+
# Control the base that the index is displayed in.
|
48
|
+
#
|
49
|
+
# @option kwargs [Integer, nil] :index_offset
|
50
|
+
# The offset to start the index at.
|
51
|
+
#
|
52
|
+
# @option kwargs [Boolean] :chars_column (true)
|
53
|
+
# Controls whether to display the characters column.
|
54
|
+
#
|
55
|
+
# @option kwargs [:ascii, :utf8, Encoding, nil] :encoding
|
56
|
+
# The encoding to display the characters in.
|
57
|
+
#
|
58
|
+
# @option kwargs [Boolean, Hash{:index,:numeric,:chars => Symbol,Array<Symbol>}] :style
|
59
|
+
# Enables theming of index, numeric, or chars columns.
|
60
|
+
#
|
61
|
+
# @option kwargs [Boolean, Hash{:index,:numeric,:chars => Hash{String,Regexp => Symbol,Array<Symbol>}}] :highlights
|
62
|
+
# Enables selective highlighting of index, numeric, or chars columns.
|
63
|
+
#
|
64
|
+
# @yield [hexdump]
|
65
|
+
# If a block is given, it will be passed the newly initialized hexdump
|
66
|
+
# instance.
|
67
|
+
#
|
68
|
+
# @yieldparam [Hexdump::Hexdump] hexdump
|
69
|
+
# The newly initialized hexdump instance.
|
70
|
+
#
|
71
|
+
# @see IO#hexdump
|
72
|
+
#
|
73
|
+
# @example
|
74
|
+
# File.hexdump("/bin/ls")
|
75
|
+
# # 00000000 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 |.ELF............|
|
76
|
+
# # ...
|
77
|
+
#
|
78
|
+
def self.hexdump(path,**kwargs,&block)
|
17
79
|
self.open(path,'rb') do |file|
|
18
|
-
|
80
|
+
file.hexdump(**kwargs,&block)
|
19
81
|
end
|
20
82
|
end
|
21
83
|
|
data/lib/hexdump/core_ext/io.rb
CHANGED
data/lib/hexdump/core_ext.rb
CHANGED
@@ -0,0 +1,43 @@
|
|
1
|
+
module Hexdump
|
2
|
+
#
|
3
|
+
# @api private
|
4
|
+
#
|
5
|
+
# @since 1.0.0
|
6
|
+
#
|
7
|
+
class FormatString
|
8
|
+
|
9
|
+
#
|
10
|
+
# Initializes the format string.
|
11
|
+
#
|
12
|
+
# @param [String] fmt
|
13
|
+
# The format string.
|
14
|
+
#
|
15
|
+
def initialize(fmt)
|
16
|
+
@fmt = fmt
|
17
|
+
end
|
18
|
+
|
19
|
+
#
|
20
|
+
# Formats the given value.
|
21
|
+
#
|
22
|
+
# @param [Integer, Float] value
|
23
|
+
# The given value.
|
24
|
+
#
|
25
|
+
# @return [String]
|
26
|
+
# The formatted value.
|
27
|
+
#
|
28
|
+
def %(value)
|
29
|
+
sprintf(@fmt,value)
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Converts the format string back into a String.
|
34
|
+
#
|
35
|
+
# @return [String]
|
36
|
+
# The raw format string.
|
37
|
+
#
|
38
|
+
def to_s
|
39
|
+
@fmt
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
data/lib/hexdump/hexdump.rb
CHANGED
@@ -1,86 +1,779 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
# include Hexdump
|
10
|
-
#
|
11
|
-
# def each_byte
|
12
|
-
# # ...
|
13
|
-
# end
|
14
|
-
#
|
15
|
-
# end
|
16
|
-
#
|
17
|
-
# data = AbstractData.new
|
18
|
-
# data.hexdump
|
19
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'hexdump/types'
|
4
|
+
require 'hexdump/reader'
|
5
|
+
require 'hexdump/numeric'
|
6
|
+
require 'hexdump/chars'
|
7
|
+
require 'hexdump/theme'
|
8
|
+
|
20
9
|
module Hexdump
|
21
10
|
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
# @param [#each_byte] data
|
25
|
-
# The data to be hexdumped.
|
26
|
-
#
|
27
|
-
# @param [Integer] width (16)
|
28
|
-
# The number of bytes to dump for each line.
|
29
|
-
#
|
30
|
-
# @param [Integer] endian (:little)
|
31
|
-
# The endianness that the bytes are organized in. Supported endianness
|
32
|
-
# include `:little` and `:big`.
|
33
|
-
#
|
34
|
-
# @param [Integer] word_size (1)
|
35
|
-
# The number of bytes within a word.
|
36
|
-
#
|
37
|
-
# @param [Symbol, Integer] base (:hexadecimal)
|
38
|
-
# The base to print bytes in. Supported bases include, `:hexadecimal`,
|
39
|
-
# `:hex`, `16, `:decimal`, `:dec`, `10, `:octal`, `:oct`, `8`,
|
40
|
-
# `:binary`, `:bin` and `2`.
|
41
|
-
#
|
42
|
-
# @param [Boolean] ascii (false)
|
43
|
-
# Print ascii characters when possible.
|
11
|
+
# Handles the parsing of data and formatting of the hexdump.
|
44
12
|
#
|
45
|
-
# @
|
46
|
-
# The output to print the hexdump to.
|
13
|
+
# @since 1.0.0
|
47
14
|
#
|
48
|
-
# @
|
49
|
-
# The given block will be passed the hexdump break-down of each
|
50
|
-
# segment.
|
15
|
+
# @api semipublic
|
51
16
|
#
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
17
|
+
class Hexdump
|
18
|
+
|
19
|
+
# Default number of columns
|
20
|
+
#
|
21
|
+
# @since 1.0.0
|
22
|
+
DEFAULT_COLUMNS = 16
|
23
|
+
|
24
|
+
# Numeric bases and their formatting classes.
|
25
|
+
BASES = {
|
26
|
+
16 => Numeric::Hexadecimal,
|
27
|
+
10 => Numeric::Decimal,
|
28
|
+
8 => Numeric::Octal,
|
29
|
+
2 => Numeric::Binary
|
30
|
+
}
|
31
|
+
|
32
|
+
# The reader object.
|
33
|
+
#
|
34
|
+
# @return [Reader]
|
35
|
+
attr_reader :reader
|
36
|
+
|
37
|
+
# The format of the index number.
|
38
|
+
#
|
39
|
+
# @return [Numeric::Hexadecimal,
|
40
|
+
# Numeric::Decimal,
|
41
|
+
# Numeric::Octal,
|
42
|
+
# Numeric::Binary]
|
43
|
+
attr_reader :index
|
44
|
+
|
45
|
+
# The numeric base format.
|
46
|
+
#
|
47
|
+
# @return [Numeric::Hexadecimal,
|
48
|
+
# Numeric::Decimal,
|
49
|
+
# Numeric::Octal,
|
50
|
+
# Numeric::Binary]
|
51
|
+
attr_reader :numeric
|
52
|
+
|
53
|
+
# The characters formatter.
|
54
|
+
#
|
55
|
+
# @return [Chars, nil]
|
56
|
+
attr_reader :chars
|
57
|
+
|
58
|
+
#
|
59
|
+
# Initializes a hexdump format.
|
60
|
+
#
|
61
|
+
# @param [:int8, :uint8, :char, :uchar, :byte, :int16, :int16_le, :int16_be, :int16_ne, :uint16, :uint16_le, :uint16_be, :uint16_ne, :short, :short_le, :short_be, :short_ne, :ushort, :ushort_le, :ushort_be, :ushort_ne, :int32, :int32_le, :int32_be, :int32_ne, :uint32, :uint32_le, :uint32_be, :uint32_ne, :int, :long, :long_le, :long_be, :long_ne, :uint, :ulong, :ulong_le, :ulong_be, :ulong_ne, :int64, :int64_le, :int64_be, :int64_ne, :uint64, :uint64_le, :uint64_be, :uint64_ne, :long_long, :long_long_le, :long_long_be, :long_long_ne, :ulong_long, :ulong_long_le, :ulong_long_be, :ulong_long_ne, :float, :float_le, :float_be, :float_ne, :double, :double_le, :double_be, :double_ne] type (:byte)
|
62
|
+
# The type to decode the data as.
|
63
|
+
#
|
64
|
+
# @param [Integer, nil] offset
|
65
|
+
# Controls whether to skip N number of bytes before starting to read data.
|
66
|
+
#
|
67
|
+
# @param [Integer, nil] length
|
68
|
+
# Controls control many bytes to read.
|
69
|
+
#
|
70
|
+
# @param [Boolean] zero_pad
|
71
|
+
# Enables or disables zero padding of data, so that the remaining bytes
|
72
|
+
# can be decoded as a uint, int, or float.
|
73
|
+
#
|
74
|
+
# @param [Boolean] repeating
|
75
|
+
# Controls whether to omit repeating duplicate rows data with a `*`.
|
76
|
+
#
|
77
|
+
# @param [Integer] columns
|
78
|
+
# The number of columns per hexdump line. Defaults to `16 / sizeof(type)`.
|
79
|
+
#
|
80
|
+
# @param [Integer, nil] group_columns
|
81
|
+
# Separate groups of columns with an additional space.
|
82
|
+
#
|
83
|
+
# @param [Integer, :type, nil] group_chars
|
84
|
+
# Group chars into columns.
|
85
|
+
# If `:type`, then the chars will be grouped by the `type`'s size.
|
86
|
+
#
|
87
|
+
# @param [16, 10, 8, 2] base
|
88
|
+
# The base to print bytes in. Defaults to 16, or to 10 if printing floats.
|
89
|
+
#
|
90
|
+
# @param [16, 10, 8, 2] index_base
|
91
|
+
# Control the base that the index is displayed in. Defaults to base 16.
|
92
|
+
#
|
93
|
+
# @param [Integer] index_offset
|
94
|
+
# The offset to start the index at.
|
95
|
+
#
|
96
|
+
# @param [Boolean] chars
|
97
|
+
# Controls whether to display the characters column.
|
98
|
+
#
|
99
|
+
# @param [:ascii, :utf8, Encoding, nil] encoding
|
100
|
+
# The encoding to display the characters in.
|
101
|
+
#
|
102
|
+
# @param [Boolean, Hash{:index,:numeric,:chars => Symbol,Array<Symbol>}] style
|
103
|
+
# Enables theming of index, numeric, or chars columns.
|
104
|
+
#
|
105
|
+
# @param [Boolean, Hash{:index,:numeric,:chars => Hash{String,Regexp => Symbol,Array<Symbol>}}] highlights
|
106
|
+
# Enables selective highlighting of index, numeric, or chars columns.
|
107
|
+
#
|
108
|
+
# @yield [self]
|
109
|
+
# If a block is given, it will be passed the newly initialized hexdump
|
110
|
+
# instance.
|
111
|
+
#
|
112
|
+
# @raise [ArgumentError]
|
113
|
+
# The values for `:base` or `:endian` were unknown.
|
114
|
+
#
|
115
|
+
# @example Initializing styling:
|
116
|
+
# Hexdump::Hexdump.new(style: {index: :white, numeric: :green, chars: :cyan})
|
117
|
+
#
|
118
|
+
# @example Initializing highlighting:
|
119
|
+
# Hexdump::Hexdump.new(
|
120
|
+
# highlights: {
|
121
|
+
# index: {/00$/ => [:white, :bold]},
|
122
|
+
# numeric: {
|
123
|
+
# /^[8-f][0-9a-f]$/ => :faint,
|
124
|
+
# /f/ => :cyan,
|
125
|
+
# '00' => [:black, :on_red]
|
126
|
+
# },
|
127
|
+
# chars: {/[^\.]+/ => :green}
|
128
|
+
# }
|
129
|
+
# )
|
130
|
+
#
|
131
|
+
# @example Initializing with a block:
|
132
|
+
# Hexdump::Hexdump.new do |hexdump|
|
133
|
+
# hexdump.type = :uint16
|
134
|
+
# # ...
|
135
|
+
#
|
136
|
+
# hexdump.theme do |theme|
|
137
|
+
# theme.index.highlight(/00$/, [:white, :bold])
|
138
|
+
# theme.numeric.highlight(/^[8-f][0-9a-f]$/, :faint)
|
139
|
+
# # ...
|
140
|
+
# end
|
141
|
+
# end
|
142
|
+
#
|
143
|
+
def initialize(type: :byte, offset: nil, length: nil, zero_pad: false, repeating: false, columns: nil, group_columns: nil, group_chars: nil, base: nil, index_base: 16, index_offset: nil, chars_column: true, encoding: nil, style: nil, highlights: nil)
|
144
|
+
# reader options
|
145
|
+
self.type = type
|
146
|
+
self.offset = offset
|
147
|
+
self.length = length
|
148
|
+
self.zero_pad = zero_pad
|
149
|
+
self.repeating = repeating
|
150
|
+
|
151
|
+
# numeric formatting options
|
152
|
+
self.base = base if base
|
153
|
+
self.columns = columns
|
154
|
+
self.group_columns = group_columns
|
155
|
+
|
156
|
+
# index options
|
157
|
+
self.index_base = index_base
|
158
|
+
self.index_offset = index_offset || offset
|
159
|
+
|
160
|
+
# chars formatting options
|
161
|
+
self.encoding = encoding
|
162
|
+
self.chars_column = chars_column
|
163
|
+
self.group_chars = group_chars
|
164
|
+
|
165
|
+
@theme = if (style.kind_of?(Hash) || highlights.kind_of?(Hash))
|
166
|
+
Theme.new(
|
167
|
+
style: style || {},
|
168
|
+
highlights: highlights || {}
|
169
|
+
)
|
170
|
+
end
|
171
|
+
|
172
|
+
yield self if block_given?
|
173
|
+
|
174
|
+
@reader = Reader.new(@type, offset: @offset,
|
175
|
+
length: @length,
|
176
|
+
zero_pad: @zero_pad)
|
177
|
+
|
178
|
+
# default the numeric base
|
179
|
+
@base ||= case @type
|
180
|
+
when Type::Float, Type::Char, Type::UChar then 10
|
181
|
+
else 16
|
182
|
+
end
|
183
|
+
|
184
|
+
# default the number of columns based on the type's size
|
185
|
+
@columns ||= (DEFAULT_COLUMNS / @type.size)
|
186
|
+
|
187
|
+
@index = BASES.fetch(@index_base).new(TYPES[:uint32])
|
188
|
+
@numeric = BASES.fetch(@base).new(@type)
|
70
189
|
|
71
|
-
|
72
|
-
|
190
|
+
case @type
|
191
|
+
when Type::Char, Type::UChar
|
192
|
+
# display characters inline for the :char and :uchar type, and disable
|
193
|
+
# the characters column
|
194
|
+
@numeric = Numeric::CharOrInt.new(@numeric,@encoding)
|
195
|
+
|
196
|
+
@chars = nil
|
197
|
+
@chars_column = false
|
198
|
+
else
|
199
|
+
@chars = Chars.new(@encoding) if @chars_column
|
200
|
+
end
|
73
201
|
end
|
74
202
|
|
75
|
-
|
76
|
-
|
203
|
+
#
|
204
|
+
# @group Reader Configuration
|
205
|
+
#
|
206
|
+
|
207
|
+
# The word type to decode the byte stream as.
|
208
|
+
#
|
209
|
+
# @return [Type]
|
210
|
+
#
|
211
|
+
# @api public
|
212
|
+
attr_reader :type
|
213
|
+
|
214
|
+
# The optional offset to start the index at.
|
215
|
+
#
|
216
|
+
# @return [Integer, nil]
|
217
|
+
#
|
218
|
+
# @api public
|
219
|
+
attr_accessor :offset
|
220
|
+
|
221
|
+
# The optional length of data to read.
|
222
|
+
#
|
223
|
+
# @return [Integer, nil]
|
224
|
+
#
|
225
|
+
# @api public
|
226
|
+
attr_accessor :length
|
227
|
+
|
228
|
+
# Controls whether to zero-pad the data so it aligns with the type's size.
|
229
|
+
#
|
230
|
+
# @return [Boolean]
|
231
|
+
#
|
232
|
+
# @api public
|
233
|
+
attr_accessor :zero_pad
|
234
|
+
|
235
|
+
alias zero_pad? zero_pad
|
236
|
+
|
237
|
+
# Controls whether repeating duplicate rows will be omitted with a `*`.
|
238
|
+
#
|
239
|
+
# @return [Boolean]
|
240
|
+
#
|
241
|
+
# @api public
|
242
|
+
attr_accessor :repeating
|
243
|
+
|
244
|
+
alias repeating? repeating
|
245
|
+
|
246
|
+
#
|
247
|
+
# Sets the hexdump type.
|
248
|
+
#
|
249
|
+
# @param [:int8, :uint8, :char, :uchar, :byte, :int16, :int16_le, :int16_be, :int16_ne, :uint16, :uint16_le, :uint16_be, :uint16_ne, :short, :short_le, :short_be, :short_ne, :ushort, :ushort_le, :ushort_be, :ushort_ne, :int32, :int32_le, :int32_be, :int32_ne, :uint32, :uint32_le, :uint32_be, :uint32_ne, :int, :long, :long_le, :long_be, :long_ne, :uint, :ulong, :ulong_le, :ulong_be, :ulong_ne, :int64, :int64_le, :int64_be, :int64_ne, :uint64, :uint64_le, :uint64_be, :uint64_ne, :long_long, :long_long_le, :long_long_be, :long_long_ne, :ulong_long, :ulong_long_le, :ulong_long_be, :ulong_long_ne, :float, :float_le, :float_be, :float_ne, :double, :double_le, :double_be, :double_ne] value
|
250
|
+
#
|
251
|
+
# @return [Type]
|
252
|
+
#
|
253
|
+
# @raise [ArgumentError]
|
254
|
+
#
|
255
|
+
# @api public
|
256
|
+
#
|
257
|
+
def type=(value)
|
258
|
+
@type = TYPES.fetch(value) do
|
259
|
+
raise(ArgumentError,"unsupported type: #{value.inspect}")
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
#
|
264
|
+
# @group Numeric Configuration
|
265
|
+
#
|
266
|
+
|
267
|
+
# The base to dump words as.
|
268
|
+
#
|
269
|
+
# @return [16, 10, 8, 2]
|
270
|
+
#
|
271
|
+
# @api public
|
272
|
+
attr_accessor :base
|
273
|
+
|
274
|
+
#
|
275
|
+
# Sets the numeric column base.
|
276
|
+
#
|
277
|
+
# @param [16, 10, 8, 2] value
|
278
|
+
#
|
279
|
+
# @return [16, 10, 8, 2]
|
280
|
+
#
|
281
|
+
# @raise [ArgumentError]
|
282
|
+
#
|
283
|
+
# @api public
|
284
|
+
#
|
285
|
+
def base=(value)
|
286
|
+
case value
|
287
|
+
when 16, 10, 8, 2
|
288
|
+
@base = value
|
289
|
+
else
|
290
|
+
raise(ArgumentError,"unsupported base: #{value.inspect}")
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
294
|
+
# The number of columns per hexdump line.
|
295
|
+
#
|
296
|
+
# @return [Integer]
|
297
|
+
#
|
298
|
+
# @api public
|
299
|
+
attr_accessor :columns
|
300
|
+
|
301
|
+
# The number of columns to group together.
|
302
|
+
#
|
303
|
+
# @return [Integer, nil]
|
304
|
+
#
|
305
|
+
# @api public
|
306
|
+
attr_accessor :group_columns
|
307
|
+
|
308
|
+
#
|
309
|
+
# @group Index Configuration
|
310
|
+
#
|
311
|
+
|
312
|
+
# The base to format the index column as.
|
313
|
+
#
|
314
|
+
# @return [16, 10, 8, 2]
|
315
|
+
#
|
316
|
+
# @api public
|
317
|
+
attr_reader :index_base
|
318
|
+
|
319
|
+
#
|
320
|
+
# Sets the index column base.
|
321
|
+
#
|
322
|
+
# @param [16, 10, 8, 2] value
|
323
|
+
#
|
324
|
+
# @return [16, 10, 8, 2]
|
325
|
+
#
|
326
|
+
# @raise [ArgumentError]
|
327
|
+
#
|
328
|
+
# @api public
|
329
|
+
#
|
330
|
+
def index_base=(value)
|
331
|
+
case value
|
332
|
+
when 16, 10, 8, 2
|
333
|
+
@index_base = value
|
334
|
+
else
|
335
|
+
raise(ArgumentError,"unsupported index base: #{value.inspect}")
|
336
|
+
end
|
337
|
+
end
|
338
|
+
|
339
|
+
# Starts the index at the given offset.
|
340
|
+
#
|
341
|
+
# @return [Integer, nil]
|
342
|
+
#
|
343
|
+
# @api public
|
344
|
+
attr_accessor :index_offset
|
345
|
+
|
346
|
+
#
|
347
|
+
# @group Characters Configuration
|
348
|
+
#
|
349
|
+
|
350
|
+
# The encoding to use when decoding characters.
|
351
|
+
#
|
352
|
+
# @return [Encoding, nil]
|
353
|
+
#
|
354
|
+
# @api public
|
355
|
+
attr_reader :encoding
|
356
|
+
|
357
|
+
#
|
358
|
+
# Sets the encoding.
|
359
|
+
#
|
360
|
+
# @param [:ascii, :utf8, Encoding, nil] value
|
361
|
+
#
|
362
|
+
# @return [Encoding, nil]
|
363
|
+
#
|
364
|
+
# @api public
|
365
|
+
#
|
366
|
+
def encoding=(value)
|
367
|
+
@encoding = case value
|
368
|
+
when :ascii then nil
|
369
|
+
when :utf8 then Encoding::UTF_8
|
370
|
+
when Encoding then value
|
371
|
+
when nil then nil
|
372
|
+
else
|
373
|
+
raise(ArgumentError,"encoding must be nil, :ascii, :utf8, or an Encoding object")
|
374
|
+
end
|
375
|
+
end
|
376
|
+
|
377
|
+
# Controls whether to display the characters column.
|
378
|
+
#
|
379
|
+
# @return [Boolean]
|
380
|
+
#
|
381
|
+
# @api public
|
382
|
+
attr_accessor :chars_column
|
383
|
+
|
384
|
+
alias chars_column? chars_column
|
385
|
+
|
386
|
+
# Groups the characters together into groups.
|
387
|
+
#
|
388
|
+
# @return [Integer, nil]
|
389
|
+
#
|
390
|
+
# @api public
|
391
|
+
attr_reader :group_chars
|
392
|
+
|
393
|
+
#
|
394
|
+
# Sets the character grouping.
|
395
|
+
#
|
396
|
+
# @param [Integer, :type] value
|
397
|
+
#
|
398
|
+
# @return [Integer, nil]
|
399
|
+
#
|
400
|
+
# @api public
|
401
|
+
#
|
402
|
+
def group_chars=(value)
|
403
|
+
@group_chars = case value
|
404
|
+
when Integer then value
|
405
|
+
when :type then @type.size
|
406
|
+
when nil then nil
|
407
|
+
else
|
408
|
+
raise(ArgumentError,"invalid group_chars value: #{value.inspect}")
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
#
|
413
|
+
# @group Theme Configuration
|
414
|
+
#
|
415
|
+
|
416
|
+
#
|
417
|
+
# Determines if hexdump styling/highlighting has been enabled.
|
418
|
+
#
|
419
|
+
# @return [Boolean]
|
420
|
+
#
|
421
|
+
# @api public
|
422
|
+
#
|
423
|
+
def theme?
|
424
|
+
!@theme.nil?
|
425
|
+
end
|
426
|
+
|
427
|
+
#
|
428
|
+
# The hexdump theme.
|
429
|
+
#
|
430
|
+
# @yield [theme]
|
431
|
+
# If a block is given, the theme will be auto-initialized and yielded.
|
432
|
+
#
|
433
|
+
# @yieldparam [Theme] theme
|
434
|
+
# The hexdump theme.
|
435
|
+
#
|
436
|
+
# @return [Theme, nil]
|
437
|
+
# The initialized hexdump theme.
|
438
|
+
#
|
439
|
+
# @api public
|
440
|
+
#
|
441
|
+
def theme(&block)
|
442
|
+
if block
|
443
|
+
@theme ||= Theme.new
|
444
|
+
@theme.tap(&block)
|
445
|
+
else
|
446
|
+
@theme
|
447
|
+
end
|
448
|
+
end
|
449
|
+
|
450
|
+
#
|
451
|
+
# @group Formatting Methods
|
452
|
+
#
|
453
|
+
|
454
|
+
#
|
455
|
+
# Enumerates over each slice of read values.
|
456
|
+
#
|
457
|
+
# @param [#each_byte] data
|
458
|
+
# The data to be hexdumped.
|
459
|
+
#
|
460
|
+
# @yield [slice]
|
461
|
+
# The given block will be passed the hexdump break-down of each
|
462
|
+
# row.
|
463
|
+
#
|
464
|
+
# @yieldparam [Array<(String, Integer)>, Array<(String, Float)>] slice
|
465
|
+
# The decoded values.
|
466
|
+
#
|
467
|
+
# @return [Enumerator]
|
468
|
+
# If no block is given, an Enumerator will be returned.
|
469
|
+
#
|
470
|
+
def each_slice(data,&block)
|
471
|
+
@reader.each(data).each_slice(@columns,&block)
|
472
|
+
end
|
473
|
+
|
474
|
+
#
|
475
|
+
# Enumerates each row of values read from the given data.
|
476
|
+
#
|
477
|
+
# @param [#each_byte] data
|
478
|
+
# The data to be hexdumped.
|
479
|
+
#
|
480
|
+
# @yield [index, values, chars]
|
481
|
+
# The given block will be passed the hexdump break-down of each
|
482
|
+
# row.
|
483
|
+
#
|
484
|
+
# @yieldparam [Integer, '*'] index
|
485
|
+
# The index of the hexdumped row.
|
486
|
+
# If the index is `'*'`, then it indicates the beginning of repeating
|
487
|
+
# rows of data.
|
488
|
+
#
|
489
|
+
# @yieldparam [Array<Integer>, Array<Float>] values
|
490
|
+
# The decoded values.
|
491
|
+
#
|
492
|
+
# @yieldparam [String] chars
|
493
|
+
# A raw characters that were read.
|
494
|
+
#
|
495
|
+
# @return [Integer, Enumerator]
|
496
|
+
# If a block is given, then the final number of bytes read is returned.
|
497
|
+
# If no block is given, an Enumerator will be returned.
|
498
|
+
#
|
499
|
+
def each_row(data,&block)
|
500
|
+
return enum_for(__method__,data) unless block_given?
|
501
|
+
|
502
|
+
index = @index_offset || 0
|
503
|
+
chars = nil
|
504
|
+
|
505
|
+
each_slice(data) do |slice|
|
506
|
+
numeric = []
|
507
|
+
chars = [] if @chars
|
508
|
+
|
509
|
+
next_index = index
|
510
|
+
|
511
|
+
slice.each do |(raw,value)|
|
512
|
+
numeric << value
|
513
|
+
chars << raw if @chars
|
514
|
+
|
515
|
+
next_index += raw.length
|
516
|
+
end
|
517
|
+
|
518
|
+
yield index, numeric, chars
|
519
|
+
index = next_index
|
520
|
+
end
|
521
|
+
|
522
|
+
return index
|
523
|
+
end
|
524
|
+
|
525
|
+
#
|
526
|
+
# Enumerates each non-repeating row of hexdumped data.
|
527
|
+
#
|
528
|
+
# @param [#each_byte] data
|
529
|
+
# The data to be hexdumped.
|
530
|
+
#
|
531
|
+
# @yield [index, numeric, chars]
|
532
|
+
# The given block will be passed the hexdump break-down of each
|
533
|
+
# row.
|
534
|
+
#
|
535
|
+
# @yieldparam [Integer, '*'] index
|
536
|
+
# The index of the hexdumped row.
|
537
|
+
# If the index is `'*'`, then it indicates the beginning of repeating
|
538
|
+
# rows of data.
|
539
|
+
#
|
540
|
+
# @yieldparam [Array<Integer>, Array<Float>, nil] values
|
541
|
+
# The decoded values.
|
542
|
+
#
|
543
|
+
# @yieldparam [String, nil] chars
|
544
|
+
# A raw characters that were read.
|
545
|
+
#
|
546
|
+
# @return [Integer, Enumerator]
|
547
|
+
# If a block is given, the final number of bytes read will be returned.
|
548
|
+
# If no block is given, an Enumerator will be returned.
|
549
|
+
#
|
550
|
+
def each_non_repeating_row(data)
|
551
|
+
return enum_for(__method__,data) unless block_given?
|
552
|
+
|
553
|
+
previous_row = nil
|
554
|
+
is_repeating = false
|
555
|
+
|
556
|
+
each_row(data) do |index,*row|
|
557
|
+
if row == previous_row
|
558
|
+
unless is_repeating
|
559
|
+
yield '*'
|
560
|
+
is_repeating = true
|
561
|
+
end
|
562
|
+
else
|
563
|
+
if is_repeating
|
564
|
+
previous_row = nil
|
565
|
+
is_repeating = false
|
566
|
+
end
|
567
|
+
|
568
|
+
yield index, *row
|
569
|
+
previous_row = row
|
570
|
+
end
|
571
|
+
end
|
572
|
+
end
|
573
|
+
|
574
|
+
#
|
575
|
+
# Enumerates each formatted row of hexdumped data.
|
576
|
+
#
|
577
|
+
# @param [#each_byte] data
|
578
|
+
# The data to be hexdumped.
|
579
|
+
#
|
580
|
+
# @param [Boolean] ansi
|
581
|
+
# Whether to enable styling/highlighting.
|
582
|
+
#
|
583
|
+
# @yield [index, numeric, chars]
|
584
|
+
# The given block will be passed the hexdump break-down of each
|
585
|
+
# row.
|
586
|
+
#
|
587
|
+
# @yieldparam [Integer, '*'] index
|
588
|
+
# The index of the hexdumped row.
|
589
|
+
# If the index is `'*'`, then it indicates the beginning of repeating
|
590
|
+
# rows of data.
|
591
|
+
#
|
592
|
+
# @yieldparam [Array<String>, nil] numeric
|
593
|
+
# The numeric representation of the row.
|
594
|
+
#
|
595
|
+
# @yieldparam [Array<String>, nil] chars
|
596
|
+
# The printable representation of the row.
|
597
|
+
#
|
598
|
+
# @return [String, Enumerator]
|
599
|
+
# If a block is given, the final number of bytes read will be returned.
|
600
|
+
# If no block is given, an Enumerator will be returned.
|
601
|
+
#
|
602
|
+
def each_formatted_row(data, ansi: theme?, **kwargs)
|
603
|
+
return enum_for(__method__,data, ansi: ansi) unless block_given?
|
604
|
+
|
605
|
+
format_index = lambda { |index|
|
606
|
+
formatted = @index % index
|
607
|
+
formatted = @theme.index.apply(formatted) if ansi
|
608
|
+
formatted
|
609
|
+
}
|
610
|
+
|
611
|
+
blank = ' ' * @numeric.width
|
612
|
+
|
613
|
+
format_numeric = lambda { |value|
|
614
|
+
if value
|
615
|
+
formatted = @numeric % value
|
616
|
+
formatted = @theme.numeric.apply(formatted) if ansi
|
617
|
+
formatted
|
618
|
+
else
|
619
|
+
blank
|
620
|
+
end
|
621
|
+
}
|
622
|
+
|
623
|
+
# cache the formatted numbers for 8bit and 16bit values
|
624
|
+
numeric_cache = if @type.size <= 2
|
625
|
+
Hash.new do |hash,value|
|
626
|
+
hash[value] = format_numeric.call(value)
|
627
|
+
end
|
628
|
+
else
|
629
|
+
format_numeric
|
630
|
+
end
|
631
|
+
|
632
|
+
if @chars
|
633
|
+
format_chars = lambda { |chars|
|
634
|
+
formatted = @chars.scrub(chars.join)
|
635
|
+
formatted = @theme.chars.apply(formatted) if ansi
|
636
|
+
formatted
|
637
|
+
}
|
638
|
+
end
|
639
|
+
|
640
|
+
enum = if @repeating then each_row(data)
|
641
|
+
else each_non_repeating_row(data)
|
642
|
+
end
|
643
|
+
|
644
|
+
index = enum.each do |index,numeric,chars=nil|
|
645
|
+
if index == '*'
|
646
|
+
yield index
|
647
|
+
else
|
648
|
+
formatted_index = format_index[index]
|
649
|
+
formatted_numbers = numeric.map { |value| numeric_cache[value] }
|
650
|
+
|
651
|
+
formatted_chars = if @chars
|
652
|
+
if @group_chars
|
653
|
+
chars.join.chars.each_slice(@group_chars).map(&format_chars)
|
654
|
+
else
|
655
|
+
format_chars.call(chars)
|
656
|
+
end
|
657
|
+
end
|
658
|
+
|
659
|
+
yield formatted_index, formatted_numbers, formatted_chars
|
660
|
+
end
|
661
|
+
end
|
662
|
+
|
663
|
+
return format_index[index]
|
664
|
+
end
|
665
|
+
|
666
|
+
#
|
667
|
+
# Enumerates over each line in the hexdump.
|
668
|
+
#
|
669
|
+
# @param [#each_byte] data
|
670
|
+
# The data to be hexdumped.
|
671
|
+
#
|
672
|
+
# @param [Hash{Symbol => Object}] kwargs
|
673
|
+
# Additional keyword arguments for {#each_formatted_row}.
|
674
|
+
#
|
675
|
+
# @yield [line]
|
676
|
+
# The given block will be passed each line from the hexdump.
|
677
|
+
#
|
678
|
+
# @yieldparam [String] line
|
679
|
+
# Each line from the hexdump output, terminated with a newline character.
|
680
|
+
#
|
681
|
+
# @return [Enumerator]
|
682
|
+
# If no block is given, an Enumerator object will be returned
|
683
|
+
#
|
684
|
+
# @return [nil]
|
685
|
+
#
|
686
|
+
def each_line(data,**kwargs)
|
687
|
+
return enum_for(__method__,data,**kwargs) unless block_given?
|
688
|
+
|
689
|
+
join_numeric = if @group_columns
|
690
|
+
lambda { |numeric|
|
691
|
+
numeric.each_slice(@group_columns).map { |numbers|
|
692
|
+
numbers.join(' ')
|
693
|
+
}.join(' ')
|
694
|
+
}
|
695
|
+
else
|
696
|
+
lambda { |numeric| numeric.join(' ') }
|
697
|
+
end
|
698
|
+
|
699
|
+
index = each_formatted_row(data,**kwargs) do |index,numeric,chars=nil|
|
700
|
+
if index == '*'
|
701
|
+
yield "#{index}#{$/}"
|
702
|
+
else
|
703
|
+
numeric_column = join_numeric.call(numeric)
|
704
|
+
|
705
|
+
if numeric.length < @columns
|
706
|
+
missing_columns = (@columns - numeric.length)
|
707
|
+
column_width = @numeric.width + 1
|
708
|
+
|
709
|
+
spaces = (missing_columns * column_width)
|
710
|
+
spaces += ((missing_columns / @group_columns) - 1) if @group_columns
|
711
|
+
|
712
|
+
numeric_column << ' ' * spaces
|
713
|
+
end
|
714
|
+
|
715
|
+
line = if @chars
|
716
|
+
if @group_chars
|
717
|
+
chars = chars.join('|')
|
718
|
+
end
|
719
|
+
|
720
|
+
"#{index} #{numeric_column} |#{chars}|#{$/}"
|
721
|
+
else
|
722
|
+
"#{index} #{numeric_column}#{$/}"
|
723
|
+
end
|
724
|
+
|
725
|
+
yield line
|
726
|
+
end
|
727
|
+
end
|
728
|
+
|
729
|
+
yield "#{index}#{$/}"
|
730
|
+
return nil
|
731
|
+
end
|
732
|
+
|
733
|
+
#
|
734
|
+
# Prints the hexdump.
|
735
|
+
#
|
736
|
+
# @param [#each_byte] data
|
737
|
+
# The data to be hexdumped.
|
738
|
+
#
|
739
|
+
# @param [#print] output
|
740
|
+
# The output to dump the hexdump to.
|
741
|
+
#
|
742
|
+
# @return [nil]
|
743
|
+
#
|
744
|
+
# @raise [ArgumentError]
|
745
|
+
# The output value does not support the `#<<` method.
|
746
|
+
#
|
747
|
+
def hexdump(data, output: $stdout)
|
748
|
+
unless output.respond_to?(:<<)
|
749
|
+
raise(ArgumentError,"output must support the #<< method")
|
750
|
+
end
|
751
|
+
|
752
|
+
ansi = theme? && $stdout.tty?
|
753
|
+
|
754
|
+
each_line(data, ansi: ansi) do |line|
|
755
|
+
output << line
|
756
|
+
end
|
757
|
+
end
|
758
|
+
|
759
|
+
#
|
760
|
+
# Outputs the hexdump to a String.
|
761
|
+
#
|
762
|
+
# @param [#each_byte] data
|
763
|
+
# The data to be hexdumped.
|
764
|
+
#
|
765
|
+
# @return [String]
|
766
|
+
# The output of the hexdump.
|
767
|
+
#
|
768
|
+
# @note
|
769
|
+
# **Caution:** this method appends each line of the hexdump to a String,
|
770
|
+
# and that String can grow quite large and consume a lot of memory.
|
771
|
+
#
|
772
|
+
def dump(data)
|
773
|
+
String.new.tap do |string|
|
774
|
+
hexdump(data, output: string)
|
775
|
+
end
|
776
|
+
end
|
77
777
|
|
78
|
-
#
|
79
|
-
# Hexdumps the object.
|
80
|
-
#
|
81
|
-
# @see Hexdump.dump
|
82
|
-
#
|
83
|
-
def hexdump(**options,&block)
|
84
|
-
Hexdump.dump(self,**options,&block)
|
85
778
|
end
|
86
779
|
end
|