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,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
|
data/spec/mixin_spec.rb
ADDED
@@ -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
|