hexdump 0.3.0 → 1.0.1

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.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +5 -6
  3. data/.gitignore +1 -0
  4. data/.yardopts +1 -1
  5. data/ChangeLog.md +79 -6
  6. data/Gemfile +3 -0
  7. data/LICENSE.txt +1 -1
  8. data/README.md +500 -137
  9. data/benchmark.rb +29 -22
  10. data/gemspec.yml +2 -1
  11. data/hexdump.gemspec +1 -4
  12. data/lib/hexdump/chars.rb +46 -0
  13. data/lib/hexdump/core_ext/file.rb +68 -6
  14. data/lib/hexdump/core_ext/io.rb +2 -2
  15. data/lib/hexdump/core_ext/kernel.rb +5 -0
  16. data/lib/hexdump/core_ext/string.rb +2 -2
  17. data/lib/hexdump/core_ext/string_io.rb +2 -2
  18. data/lib/hexdump/core_ext.rb +5 -4
  19. data/lib/hexdump/format_string.rb +43 -0
  20. data/lib/hexdump/hexdump.rb +766 -75
  21. data/lib/hexdump/mixin.rb +192 -0
  22. data/lib/hexdump/module_methods.rb +132 -0
  23. data/lib/hexdump/numeric/binary.rb +55 -0
  24. data/lib/hexdump/numeric/char_or_int.rb +95 -0
  25. data/lib/hexdump/numeric/decimal.rb +56 -0
  26. data/lib/hexdump/numeric/exceptions.rb +11 -0
  27. data/lib/hexdump/numeric/hexadecimal.rb +59 -0
  28. data/lib/hexdump/numeric/octal.rb +55 -0
  29. data/lib/hexdump/numeric.rb +5 -0
  30. data/lib/hexdump/reader.rb +313 -0
  31. data/lib/hexdump/theme/ansi.rb +82 -0
  32. data/lib/hexdump/theme/rule.rb +159 -0
  33. data/lib/hexdump/theme.rb +61 -0
  34. data/lib/hexdump/type.rb +233 -0
  35. data/lib/hexdump/types.rb +108 -0
  36. data/lib/hexdump/version.rb +1 -1
  37. data/lib/hexdump.rb +14 -3
  38. data/spec/chars_spec.rb +76 -0
  39. data/spec/core_ext_spec.rb +10 -6
  40. data/spec/format_string_spec.rb +22 -0
  41. data/spec/hexdump_class_spec.rb +1708 -0
  42. data/spec/hexdump_module_spec.rb +23 -0
  43. data/spec/mixin_spec.rb +37 -0
  44. data/spec/numeric/binary_spec.rb +239 -0
  45. data/spec/numeric/char_or_int_spec.rb +210 -0
  46. data/spec/numeric/decimal_spec.rb +317 -0
  47. data/spec/numeric/hexadecimal_spec.rb +320 -0
  48. data/spec/numeric/octal_spec.rb +239 -0
  49. data/spec/reader_spec.rb +866 -0
  50. data/spec/spec_helper.rb +2 -0
  51. data/spec/theme/ansi_spec.rb +242 -0
  52. data/spec/theme/rule_spec.rb +199 -0
  53. data/spec/theme_spec.rb +94 -0
  54. data/spec/type_spec.rb +317 -0
  55. data/spec/types_spec.rb +904 -0
  56. metadata +42 -12
  57. data/.gemtest +0 -0
  58. data/lib/hexdump/dumper.rb +0 -419
  59. data/lib/hexdump/extensions.rb +0 -2
  60. data/spec/dumper_spec.rb +0 -329
  61. data/spec/hexdump_spec.rb +0 -30
@@ -0,0 +1,233 @@
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 [1, 2, 4, 8] size
23
+ # The type's size in bytes.
24
+ #
25
+ # @param [:little, :big, nil] endian
26
+ # The endianness of the type. `nil` indicates the type has no endianness.
27
+ #
28
+ # @param [Boolean] signed
29
+ # Indicates whether the type is signed or unsigned.
30
+ #
31
+ # @raise [ArgumentError]
32
+ # Invalid `endian:` or `size:` values.
33
+ #
34
+ def initialize(size: , endian: nil, signed: )
35
+ @endian = endian
36
+ @size = size
37
+ @signed = signed
38
+ end
39
+
40
+ #
41
+ # Whether the type is signed.
42
+ #
43
+ # @return [Boolean]
44
+ #
45
+ def signed?
46
+ @signed
47
+ end
48
+
49
+ #
50
+ # Whether the type is unsigned.
51
+ #
52
+ # @return [Boolean]
53
+ #
54
+ def unsigned?
55
+ !@signed
56
+ end
57
+
58
+ # The native endian-ness.
59
+ NATIVE_ENDIAN = if [0x1].pack('I') == [0x1].pack('N')
60
+ :big
61
+ else
62
+ :little
63
+ end
64
+
65
+ #
66
+ # Represents a signed integer type.
67
+ #
68
+ class Int < self
69
+
70
+ #
71
+ # Initializes the int type.
72
+ #
73
+ # @param [:little, :big] endian (NATIVE_ENDIAN)
74
+ # The endian-ness of the int type.
75
+ #
76
+ def initialize(endian: NATIVE_ENDIAN, **kwargs)
77
+ super(signed: true, endian: endian, **kwargs)
78
+ end
79
+
80
+ end
81
+
82
+ class Int8 < Int
83
+
84
+ #
85
+ # @see Int#initialize
86
+ #
87
+ def initialize(**kwargs)
88
+ super(size: 1, endian: nil, **kwargs)
89
+ end
90
+
91
+ end
92
+
93
+ class Int16 < Int
94
+
95
+ #
96
+ # @see Int#initialize
97
+ #
98
+ def initialize(**kwargs)
99
+ super(size: 2, **kwargs)
100
+ end
101
+
102
+ end
103
+
104
+ class Int32 < Int
105
+
106
+ #
107
+ # @see Int#initialize
108
+ #
109
+ def initialize(**kwargs)
110
+ super(size: 4, **kwargs)
111
+ end
112
+
113
+ end
114
+
115
+ class Int64 < Int
116
+
117
+ #
118
+ # @see Int#initialize
119
+ #
120
+ def initialize(**kwargs)
121
+ super(size: 8, **kwargs)
122
+ end
123
+
124
+ end
125
+
126
+ #
127
+ # Represents a unsigned integer type.
128
+ #
129
+ class UInt < self
130
+
131
+ #
132
+ # Initializes the uint type.
133
+ #
134
+ # @param [:little, :big] endian (NATIVE_ENDIAN)
135
+ # The endian-ness of the uint type.
136
+ #
137
+ def initialize(endian: NATIVE_ENDIAN, **kwargs)
138
+ super(signed: false, endian: endian, **kwargs)
139
+ end
140
+
141
+ end
142
+
143
+ class UInt8 < UInt
144
+
145
+ #
146
+ # @see UInt#initialize
147
+ #
148
+ def initialize(**kwargs)
149
+ super(size: 1, endian: nil, **kwargs)
150
+ end
151
+
152
+ end
153
+
154
+ class UInt16 < UInt
155
+
156
+ #
157
+ # @see UInt#initialize
158
+ #
159
+ def initialize(**kwargs)
160
+ super(size: 2, **kwargs)
161
+ end
162
+
163
+ end
164
+
165
+ class UInt32 < UInt
166
+
167
+ #
168
+ # @see UInt#initialize
169
+ #
170
+ def initialize(**kwargs)
171
+ super(size: 4, **kwargs)
172
+ end
173
+
174
+ end
175
+
176
+ class UInt64 < UInt
177
+
178
+ #
179
+ # @see UInt#initialize
180
+ #
181
+ def initialize(**kwargs)
182
+ super(size: 8, **kwargs)
183
+ end
184
+
185
+ end
186
+
187
+ #
188
+ # Represents a single-byte character.
189
+ #
190
+ class Char < Int8
191
+ end
192
+
193
+ #
194
+ # Represents a single-byte unsigned character.
195
+ #
196
+ class UChar < UInt8
197
+ end
198
+
199
+ #
200
+ # Represents a floating point type.
201
+ #
202
+ class Float < self
203
+
204
+ #
205
+ # Initializes the float type.
206
+ #
207
+ # @param [:little, :big] endian (NATIVE_ENDIAN)
208
+ # The endian-ness of the float type.
209
+ #
210
+ def initialize(endian: NATIVE_ENDIAN, **kwargs)
211
+ super(signed: true, endian: endian, **kwargs)
212
+ end
213
+
214
+ end
215
+
216
+ class Float32 < Float
217
+
218
+ def initialize(**kwargs)
219
+ super(size: 4, **kwargs)
220
+ end
221
+
222
+ end
223
+
224
+ class Float64 < Float
225
+
226
+ def initialize(**kwargs)
227
+ super(size: 8, **kwargs)
228
+ end
229
+
230
+ end
231
+
232
+ end
233
+ end
@@ -0,0 +1,108 @@
1
+ require_relative 'type'
2
+
3
+ module Hexdump
4
+ #
5
+ # @api private
6
+ #
7
+ # @since 1.0.0
8
+ #
9
+ TYPES = {
10
+ char: Type::Char.new,
11
+ uchar: Type::UChar.new,
12
+
13
+ int8: Type::Int8.new,
14
+ uint8: Type::UInt8.new,
15
+
16
+ int16: Type::Int16.new,
17
+ int16_le: Type::Int16.new(endian: :little),
18
+ int16_be: Type::Int16.new(endian: :big),
19
+ int16_ne: Type::Int16.new(endian: :big),
20
+
21
+ uint16: Type::UInt16.new,
22
+ uint16_le: Type::UInt16.new(endian: :little),
23
+ uint16_be: Type::UInt16.new(endian: :big),
24
+ uint16_ne: Type::UInt16.new(endian: :big),
25
+
26
+ int32: Type::Int32.new,
27
+ int32_le: Type::Int32.new(endian: :little),
28
+ int32_be: Type::Int32.new(endian: :big),
29
+ int32_ne: Type::Int32.new(endian: :big),
30
+
31
+ uint32: Type::UInt32.new,
32
+ uint32_le: Type::UInt32.new(endian: :little),
33
+ uint32_be: Type::UInt32.new(endian: :big),
34
+ uint32_ne: Type::UInt32.new(endian: :big),
35
+
36
+ int64: Type::Int64.new,
37
+ int64_le: Type::Int64.new(endian: :little),
38
+ int64_be: Type::Int64.new(endian: :big),
39
+ int64_ne: Type::Int64.new(endian: :big),
40
+
41
+ uint64: Type::UInt64.new,
42
+ uint64_le: Type::UInt64.new(endian: :little),
43
+ uint64_be: Type::UInt64.new(endian: :big),
44
+ uint64_ne: Type::UInt64.new(endian: :big),
45
+
46
+ float32: Type::Float32.new,
47
+ float32_le: Type::Float32.new(endian: :little),
48
+ float32_be: Type::Float32.new(endian: :big),
49
+ float32_ne: Type::Float32.new(endian: :big),
50
+
51
+ float64: Type::Float64.new,
52
+ float64_le: Type::Float64.new(endian: :little),
53
+ float64_be: Type::Float64.new(endian: :big),
54
+ float64_ne: Type::Float64.new(endian: :big),
55
+ }
56
+
57
+ TYPES[:byte] = TYPES[:uint8]
58
+
59
+ TYPES[:short] = TYPES[:int16]
60
+ TYPES[:short_le] = TYPES[:int16_le]
61
+ TYPES[:short_be] = TYPES[:int16_be]
62
+ TYPES[:short_ne] = TYPES[:int16_ne]
63
+
64
+ TYPES[:ushort] = TYPES[:uint16]
65
+ TYPES[:ushort_le] = TYPES[:uint16_le]
66
+ TYPES[:ushort_be] = TYPES[:uint16_be]
67
+ TYPES[:ushort_ne] = TYPES[:uint16_ne]
68
+
69
+ TYPES[:int] = TYPES[:int32]
70
+ TYPES[:int_le] = TYPES[:int32_le]
71
+ TYPES[:int_be] = TYPES[:int32_be]
72
+ TYPES[:int_ne] = TYPES[:int32_ne]
73
+
74
+ TYPES[:uint] = TYPES[:uint32]
75
+ TYPES[:uint_le] = TYPES[:uint32_le]
76
+ TYPES[:uint_be] = TYPES[:uint32_be]
77
+ TYPES[:uint_ne] = TYPES[:uint32_ne]
78
+
79
+ TYPES[:long] = TYPES[:int64]
80
+ TYPES[:long_le] = TYPES[:int64_le]
81
+ TYPES[:long_be] = TYPES[:int64_be]
82
+ TYPES[:long_ne] = TYPES[:int64_ne]
83
+
84
+ TYPES[:ulong] = TYPES[:uint64]
85
+ TYPES[:ulong_le] = TYPES[:uint64_le]
86
+ TYPES[:ulong_be] = TYPES[:uint64_be]
87
+ TYPES[:ulong_ne] = TYPES[:uint64_ne]
88
+
89
+ TYPES[:long_long] = TYPES[:int64]
90
+ TYPES[:long_long_le] = TYPES[:int64_le]
91
+ TYPES[:long_long_be] = TYPES[:int64_be]
92
+ TYPES[:long_long_ne] = TYPES[:int64_ne]
93
+
94
+ TYPES[:ulong_long] = TYPES[:uint64]
95
+ TYPES[:ulong_long_le] = TYPES[:uint64_le]
96
+ TYPES[:ulong_long_be] = TYPES[:uint64_be]
97
+ TYPES[:ulong_long_ne] = TYPES[:uint64_ne]
98
+
99
+ TYPES[:float] = TYPES[:float32]
100
+ TYPES[:float_le] = TYPES[:float32_le]
101
+ TYPES[:float_be] = TYPES[:float32_be]
102
+ TYPES[:float_ne] = TYPES[:float32_ne]
103
+
104
+ TYPES[:double] = TYPES[:float64]
105
+ TYPES[:double_le] = TYPES[:float64_le]
106
+ TYPES[:double_be] = TYPES[:float64_be]
107
+ TYPES[:double_ne] = TYPES[:float64_ne]
108
+ end
@@ -1,4 +1,4 @@
1
1
  module Hexdump
2
2
  # hexdump version
3
- VERSION = '0.3.0'
3
+ VERSION = '1.0.1'
4
4
  end
data/lib/hexdump.rb CHANGED
@@ -1,3 +1,14 @@
1
- require 'hexdump/hexdump'
2
- require 'hexdump/core_ext'
3
- require 'hexdump/version'
1
+ require_relative 'hexdump/module_methods'
2
+ require_relative 'hexdump/core_ext'
3
+ require_relative 'hexdump/version'
4
+
5
+ module Hexdump
6
+ extend ModuleMethods
7
+
8
+ #
9
+ # @see hexdump
10
+ #
11
+ def self.dump(data,**kwargs)
12
+ hexdump(data,**kwargs)
13
+ end
14
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+ require 'hexdump/chars'
3
+
4
+ describe Hexdump::Chars do
5
+ describe "#initialize" do
6
+ it "must default #encoding to nil" do
7
+ expect(subject.encoding).to be(nil)
8
+ end
9
+
10
+ context "when given nil" do
11
+ subject { described_class.new(nil) }
12
+
13
+ it "must set #encoding to nil" do
14
+ expect(subject.encoding).to be(nil)
15
+ end
16
+ end
17
+
18
+ context "when given an Encoding object" do
19
+ let(:encoding) { Encoding::UTF_8 }
20
+
21
+ subject { described_class.new(encoding) }
22
+
23
+ it "must set #encoding to the Encoding object" do
24
+ expect(subject.encoding).to be(encoding)
25
+ end
26
+ end
27
+ end
28
+
29
+ describe "#scrub" do
30
+ context "when the string only contains printable ASCII characters" do
31
+ let(:string) { "hello" }
32
+
33
+ it "must return the string unchanged" do
34
+ expect(subject.scrub(string)).to eq(string)
35
+ end
36
+ end
37
+
38
+ context "when the string contains unprintable ASCII characters" do
39
+ let(:ascii) { (0..255).map(&:chr).join }
40
+
41
+ it "must replace non-printable ASCII characters with a '.'" do
42
+ expect(subject.scrub(ascii)).to eq(ascii.gsub(/[^\x20-\x7e]/,'.'))
43
+ end
44
+ end
45
+
46
+ context "#encoding is set" do
47
+ let(:encoding) { Encoding::UTF_8 }
48
+ let(:string) { "hello" }
49
+
50
+ subject { described_class.new(encoding) }
51
+
52
+ it "must convert the string to the #encoding" do
53
+ expect((subject.scrub(string)).encoding).to eq(encoding)
54
+ end
55
+
56
+ context "when the string contains an invalid byte-sequence" do
57
+ let(:invalid_bytes) { "\x80\x81" }
58
+ let(:string) { "A#{invalid_bytes}B" }
59
+
60
+ it "must replace any invalid byte sequencnes with a '.'" do
61
+ expect(subject.scrub(string)).to eq("A..B")
62
+ end
63
+ end
64
+
65
+ context "when the string contains unprintable characters" do
66
+ let(:codepoint) { 888 }
67
+ let(:char) { codepoint.chr(encoding) }
68
+ let(:string) { "A#{char}B" }
69
+
70
+ it "must replace unprintable characters with a '.'" do
71
+ expect(subject.scrub(string)).to eq("A.B")
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
@@ -2,19 +2,23 @@ require 'spec_helper'
2
2
  require 'hexdump/core_ext'
3
3
 
4
4
  describe "Hexdump core_ext" do
5
- it "should include Hexdump into String" do
6
- expect(String).to include(Hexdump)
5
+ it "should include Hexdump::Mixin into String" do
6
+ expect(String).to include(Hexdump::Mixin)
7
7
  end
8
8
 
9
- it "should include Hexdump into StringIO" do
10
- expect(StringIO).to include(Hexdump)
9
+ it "should include Hexdump::Mixin into StringIO" do
10
+ expect(StringIO).to include(Hexdump::Mixin)
11
11
  end
12
12
 
13
- it "should include Hexdump into IO" do
14
- expect(IO).to include(Hexdump)
13
+ it "should include Hexdump::Mixin into IO" do
14
+ expect(IO).to include(Hexdump::Mixin)
15
15
  end
16
16
 
17
17
  it "should define File.hexdump" do
18
18
  expect(File).to respond_to(:hexdump)
19
19
  end
20
+
21
+ it "should include Hexdump::ModuleMethods into ::Kernel" do
22
+ expect(Kernel).to include(Hexdump::ModuleMethods)
23
+ end
20
24
  end
@@ -0,0 +1,22 @@
1
+ require 'spec_helper'
2
+ require 'hexdump/format_string'
3
+
4
+ describe Hexdump::FormatString do
5
+ let(:fmt) { "%x" }
6
+
7
+ subject { described_class.new(fmt) }
8
+
9
+ describe "#%" do
10
+ let(:value) { 255 }
11
+
12
+ it "must format the given value" do
13
+ expect(subject % value).to eq(fmt % value)
14
+ end
15
+ end
16
+
17
+ describe "#to_s" do
18
+ it "must return the format string" do
19
+ expect(subject.to_s).to eq(fmt)
20
+ end
21
+ end
22
+ end