hexdump 0.3.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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,23 @@
1
+ require 'spec_helper'
2
+ require 'hexdump'
3
+
4
+ describe Hexdump do
5
+ let(:data) { ("A" * 32) + ("B" * 32) + ("C" * 32) }
6
+ let(:hexdump) { Hexdump::Hexdump.new.dump(data) }
7
+
8
+ describe ".hexdump" do
9
+ it "must write the hexdump lines of the given data to the output" do
10
+ expect {
11
+ subject.hexdump(data)
12
+ }.to output(hexdump).to_stdout
13
+ end
14
+ end
15
+
16
+ describe ".dump" do
17
+ it "must write the hexdump lines of the given data to the output" do
18
+ expect {
19
+ subject.dump(data)
20
+ }.to output(hexdump).to_stdout
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ require 'hexdump/mixin'
3
+
4
+ describe Hexdump::Mixin do
5
+ class TestMixin
6
+
7
+ include Hexdump::Mixin
8
+
9
+ def initialize(data)
10
+ @data = data
11
+ end
12
+
13
+ def each_byte(&block)
14
+ @data.each_byte(&block)
15
+ end
16
+
17
+ end
18
+
19
+ let(:data) { ("A" * 32) + ("B" * 32) + ("C" * 32) }
20
+ let(:hexdump) { Hexdump::Hexdump.new.dump(data) }
21
+
22
+ subject { TestMixin.new(data) }
23
+
24
+ describe "#hexdump" do
25
+ it "must write the hexdump lines of the object to $stdout" do
26
+ expect {
27
+ subject.hexdump
28
+ }.to output(hexdump).to_stdout
29
+ end
30
+ end
31
+
32
+ describe "#to_hexdump" do
33
+ it "must return the hexdump lines of the object" do
34
+ expect(subject.to_hexdump).to eq(hexdump)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,239 @@
1
+ require 'spec_helper'
2
+ require 'hexdump/numeric/binary'
3
+ require 'hexdump/type'
4
+
5
+ describe Hexdump::Numeric::Binary do
6
+ describe "#initialize" do
7
+ subject { described_class.new(type) }
8
+
9
+ context "when given a Type::Int type" do
10
+ context "and size is 1" do
11
+ let(:type) { Hexdump::Type::Int8.new }
12
+
13
+ it "must set #width to 8 + 1" do
14
+ expect(subject.width).to eq(8 + 1)
15
+ end
16
+ end
17
+
18
+ context "and size is 2" do
19
+ let(:type) { Hexdump::Type::Int16.new }
20
+
21
+ it "must set #width to 16 + 1" do
22
+ expect(subject.width).to eq(16 + 1)
23
+ end
24
+ end
25
+
26
+ context "and size is 4" do
27
+ let(:type) { Hexdump::Type::Int32.new }
28
+
29
+ it "must set #width to 32 + 1" do
30
+ expect(subject.width).to eq(32 + 1)
31
+ end
32
+ end
33
+
34
+ context "and size is 8" do
35
+ let(:type) { Hexdump::Type::Int64.new }
36
+
37
+ it "must set #width to 64 + 1" do
38
+ expect(subject.width).to eq(64 + 1)
39
+ end
40
+ end
41
+
42
+ context "but the type has an unsupported size" do
43
+ class UnsupportedIntType < Hexdump::Type::Int
44
+
45
+ def initialize
46
+ super(size: 3)
47
+ end
48
+
49
+ end
50
+
51
+ let(:type) { UnsupportedIntType.new }
52
+
53
+ it do
54
+ expect { described_class.new(type) }.to raise_error(NotImplementedError)
55
+ end
56
+ end
57
+ end
58
+
59
+ context "when given a Type::UInt type" do
60
+ context "and size is 1" do
61
+ let(:type) { Hexdump::Type::UInt8.new }
62
+
63
+ it "must set #width to 8" do
64
+ expect(subject.width).to eq(8)
65
+ end
66
+ end
67
+
68
+ context "and size is 2" do
69
+ let(:type) { Hexdump::Type::UInt16.new }
70
+
71
+ it "must set #width to 16" do
72
+ expect(subject.width).to eq(16)
73
+ end
74
+ end
75
+
76
+ context "and size is 4" do
77
+ let(:type) { Hexdump::Type::UInt32.new }
78
+
79
+ it "must set #width to 32" do
80
+ expect(subject.width).to eq(32)
81
+ end
82
+ end
83
+
84
+ context "and size is 8" do
85
+ let(:type) { Hexdump::Type::UInt64.new }
86
+
87
+ it "must set #width to 64" do
88
+ expect(subject.width).to eq(64)
89
+ end
90
+ end
91
+
92
+ context "but the type has an unsupported size" do
93
+ class UnsupportedUIntType < Hexdump::Type::UInt
94
+
95
+ def initialize
96
+ super(size: 3)
97
+ end
98
+
99
+ end
100
+
101
+ let(:type) { UnsupportedUIntType.new }
102
+
103
+ it do
104
+ expect { described_class.new(type) }.to raise_error(NotImplementedError)
105
+ end
106
+ end
107
+ end
108
+
109
+ context "when given a Type::Float type" do
110
+ let(:type) { Hexdump::Type::Float32.new }
111
+
112
+ it do
113
+ expect {
114
+ described_class.new(type)
115
+ }.to raise_error(Hexdump::Numeric::IncompatibleTypeError,"cannot format floating-point numbers in binary")
116
+ end
117
+ end
118
+
119
+ context "when given a non-Type object" do
120
+ let(:type) { Object.new }
121
+
122
+ it do
123
+ expect { described_class.new(type) }.to raise_error(TypeError)
124
+ end
125
+ end
126
+ end
127
+
128
+ describe "#%" do
129
+ subject { described_class.new(type) }
130
+
131
+ context "when the given type has size 1" do
132
+ let(:type) { Hexdump::Type::UInt8.new }
133
+
134
+ let(:value) { 0xf }
135
+ let(:binary) { '00001111' }
136
+
137
+ it "must return a binary string of length 8" do
138
+ expect(subject % value).to eq(binary)
139
+ end
140
+
141
+ context "and is signed" do
142
+ let(:type) { Hexdump::Type::Int8.new }
143
+
144
+ context "and the value is positive" do
145
+ it "must return a binary string of length 8 prefixed with a ' '" do
146
+ expect(subject % value).to eq(" #{binary}")
147
+ end
148
+ end
149
+
150
+ context "and the value is negative" do
151
+ it "must return a binary string of length 8 prefixed with a '-'" do
152
+ expect(subject % -value).to eq("-#{binary}")
153
+ end
154
+ end
155
+ end
156
+ end
157
+
158
+ context "when the given type has size 2" do
159
+ let(:type) { Hexdump::Type::UInt16.new }
160
+
161
+ let(:value) { 0xff }
162
+ let(:binary) { '0000000011111111' }
163
+
164
+ it "must return a binary string of length 16" do
165
+ expect(subject % value).to eq(binary)
166
+ end
167
+
168
+ context "and is signed" do
169
+ let(:type) { Hexdump::Type::Int16.new }
170
+
171
+ context "and the value is positive" do
172
+ it "must return a binary string of length 16 prefixed with a ' '" do
173
+ expect(subject % value).to eq(" #{binary}")
174
+ end
175
+ end
176
+
177
+ context "and the value is negative" do
178
+ it "must return a binary string of length 16 prefixed with a '-'" do
179
+ expect(subject % -value).to eq("-#{binary}")
180
+ end
181
+ end
182
+ end
183
+ end
184
+
185
+ context "when the given type has size 4" do
186
+ let(:type) { Hexdump::Type::UInt32.new }
187
+
188
+ let(:value) { 0xffff }
189
+ let(:binary) { '00000000000000001111111111111111' }
190
+
191
+ it "must return a binary string of length 32" do
192
+ expect(subject % value).to eq(binary)
193
+ end
194
+
195
+ context "and is signed" do
196
+ let(:type) { Hexdump::Type::Int32.new }
197
+
198
+ context "and the value is positive" do
199
+ it "must return a binary string of length 32 prefixed with a ' '" do
200
+ expect(subject % value).to eq(" #{binary}")
201
+ end
202
+ end
203
+
204
+ context "and the value is negative" do
205
+ it "must return a binary string of length 32 prefixed with a '-'" do
206
+ expect(subject % -value).to eq("-#{binary}")
207
+ end
208
+ end
209
+ end
210
+ end
211
+
212
+ context "when the given type has size 8" do
213
+ let(:type) { Hexdump::Type::UInt64.new }
214
+
215
+ let(:value) { 0xffffffff }
216
+ let(:binary) { '0000000000000000000000000000000011111111111111111111111111111111' }
217
+
218
+ it "must return a binary string of length 64" do
219
+ expect(subject % value).to eq(binary)
220
+ end
221
+
222
+ context "and is signed" do
223
+ let(:type) { Hexdump::Type::Int64.new }
224
+
225
+ context "and the value is positive" do
226
+ it "must return a binary string of length 64 prefixed with a ' '" do
227
+ expect(subject % value).to eq(" #{binary}")
228
+ end
229
+ end
230
+
231
+ context "and the value is negative" do
232
+ it "must return a binary string of length 64 prefixed with a '-'" do
233
+ expect(subject % -value).to eq("-#{binary}")
234
+ end
235
+ end
236
+ end
237
+ end
238
+ end
239
+ end
@@ -0,0 +1,210 @@
1
+ require 'spec_helper'
2
+ require 'hexdump/numeric/char_or_int'
3
+ require 'hexdump/numeric/hexadecimal'
4
+ require 'hexdump/type'
5
+
6
+ describe Hexdump::Numeric::CharOrInt do
7
+ let(:type) { Hexdump::Type::UInt8.new }
8
+ let(:base) { Hexdump::Numeric::Hexadecimal.new(type) }
9
+
10
+ subject { described_class.new(base) }
11
+
12
+ describe "#initialize" do
13
+ it "must set #base" do
14
+ expect(subject.base).to eq(base)
15
+ end
16
+
17
+ it "must default #encoding to nil" do
18
+ expect(subject.encoding).to be(nil)
19
+ end
20
+
21
+ it "must initialize the format string" do
22
+ expect(subject.to_s).to eq("%#{base.width}s")
23
+ end
24
+
25
+ context "when given an encoding" do
26
+ let(:encoding) { Encoding::UTF_8 }
27
+
28
+ subject { described_class.new(base,encoding) }
29
+
30
+ it "must set #encoding" do
31
+ expect(subject.encoding).to eq(encoding)
32
+ end
33
+ end
34
+ end
35
+
36
+ describe "#width" do
37
+ it "return the base's #width" do
38
+ expect(subject.width).to eq(base.width)
39
+ end
40
+ end
41
+
42
+ describe "#%" do
43
+ (0x20..0x7e).each do |byte|
44
+ context "when given #{byte.to_s(16)}" do
45
+ it "must return ' #{byte.chr}'" do
46
+ expect(subject % byte).to eq(" #{byte.chr}")
47
+ end
48
+ end
49
+ end
50
+
51
+ context "when given 0x00" do
52
+ it "must return '\\0'" do
53
+ expect(subject % 0x00).to eq("\\0")
54
+ end
55
+ end
56
+
57
+ context "when given 0x07" do
58
+ it "must return '\\a'" do
59
+ expect(subject % 0x07).to eq("\\a")
60
+ end
61
+ end
62
+
63
+ context "when given 0x08" do
64
+ it "must return '\\b'" do
65
+ expect(subject % 0x08).to eq("\\b")
66
+ end
67
+ end
68
+
69
+ context "when given 0x09" do
70
+ it "must return '\\t'" do
71
+ expect(subject % 0x09).to eq("\\t")
72
+ end
73
+ end
74
+
75
+ context "when given 0x0a" do
76
+ it "must return '\\n'" do
77
+ expect(subject % 0x0a).to eq("\\n")
78
+ end
79
+ end
80
+
81
+ context "when given 0x0b" do
82
+ it "must return '\\v'" do
83
+ expect(subject % 0x0b).to eq("\\v")
84
+ end
85
+ end
86
+
87
+ context "when given 0x0c" do
88
+ it "must return '\\f'" do
89
+ expect(subject % 0x0c).to eq("\\f")
90
+ end
91
+ end
92
+
93
+ context "when given 0x0d" do
94
+ it "must return '\\r'" do
95
+ expect(subject % 0x0d).to eq("\\r")
96
+ end
97
+ end
98
+
99
+ context "when given a byte that does not map to a printable character" do
100
+ it "must return the formatted byte" do
101
+ expect(subject % 0xff).to eq("ff")
102
+ end
103
+ end
104
+
105
+ context "when the numeric base has a width > 2" do
106
+ let(:type) { Hexdump::Type::UInt16.new }
107
+ let(:width) { base.width }
108
+
109
+ it "must left-pad printable characters with width-1 additional spaces" do
110
+ left_pad = ' ' * (width - 1)
111
+
112
+ expect(subject % 0x41).to eq("#{left_pad}A")
113
+ end
114
+
115
+ it "must left-pad escaped characters with width-2 additional spaces" do
116
+ left_pad = ' ' * (width - 2)
117
+
118
+ expect(subject % 0x00).to eq("#{left_pad}\\0")
119
+ end
120
+
121
+ it "must not left-pad numerically formatted values with spaces" do
122
+ expect(subject % 0xff).to eq("00ff")
123
+ end
124
+ end
125
+
126
+ context "when initialized with an encoding" do
127
+ let(:encoding) { Encoding::UTF_8 }
128
+
129
+ subject { described_class.new(base,encoding) }
130
+
131
+ context "when given 0x00" do
132
+ it "must return '\\0'" do
133
+ expect(subject % 0x00).to eq("\\0")
134
+ end
135
+ end
136
+
137
+ context "when given 0x07" do
138
+ it "must return '\\a'" do
139
+ expect(subject % 0x07).to eq("\\a")
140
+ end
141
+ end
142
+
143
+ context "when given 0x08" do
144
+ it "must return '\\b'" do
145
+ expect(subject % 0x08).to eq("\\b")
146
+ end
147
+ end
148
+
149
+ context "when given 0x09" do
150
+ it "must return '\\t'" do
151
+ expect(subject % 0x09).to eq("\\t")
152
+ end
153
+ end
154
+
155
+ context "when given 0x0a" do
156
+ it "must return '\\n'" do
157
+ expect(subject % 0x0a).to eq("\\n")
158
+ end
159
+ end
160
+
161
+ context "when given 0x0b" do
162
+ it "must return '\\v'" do
163
+ expect(subject % 0x0b).to eq("\\v")
164
+ end
165
+ end
166
+
167
+ context "when given 0x0c" do
168
+ it "must return '\\f'" do
169
+ expect(subject % 0x0c).to eq("\\f")
170
+ end
171
+ end
172
+
173
+ context "when given 0x0d" do
174
+ it "must return '\\r'" do
175
+ expect(subject % 0x0d).to eq("\\r")
176
+ end
177
+ end
178
+
179
+ context "when given a byte that does map to a printable character" do
180
+ it "must return the formatted character" do
181
+ expect(subject % 0x2603).to eq(" ☃")
182
+ end
183
+ end
184
+
185
+ context "when given a byte that does not map to a printable character" do
186
+ let(:byte) { 888 }
187
+
188
+ it "must return the numeric formatted value" do
189
+ expect(subject % byte).to eq(base % byte)
190
+ end
191
+ end
192
+
193
+ context "when given a byte that does not map any character" do
194
+ let(:byte) { 0xd800 }
195
+
196
+ it "must return the numeric formatted value" do
197
+ expect(subject % byte).to eq(base % byte)
198
+ end
199
+ end
200
+
201
+ context "when given a negative value" do
202
+ let(:byte) { -1 }
203
+
204
+ it "must return the numeric formatted value" do
205
+ expect(subject % byte).to eq(base % byte)
206
+ end
207
+ end
208
+ end
209
+ end
210
+ end