hexdump 0.1.0 → 0.2.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.
- data/ChangeLog.md +14 -0
- data/README.md +78 -44
- data/benchmarks/hexdump.rb +11 -1
- data/gemspec.yml +5 -3
- data/lib/hexdump/dumper.rb +441 -0
- data/lib/hexdump/hexdump.rb +22 -70
- data/spec/dumper_spec.rb +260 -0
- data/spec/hexdump_spec.rb +7 -149
- metadata +9 -8
data/ChangeLog.md
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
### 0.2.1 / 2011-06-11
|
2
|
+
|
3
|
+
* Fixed a major bug in {Hexdump::Dumper#dump}, where the line buffers
|
4
|
+
were not being cleared.
|
5
|
+
|
6
|
+
### 0.2.0 / 2011-06-11
|
7
|
+
|
8
|
+
* Added {Hexdump::Dumper}.
|
9
|
+
* Added support for hexdumping 1, 2, 4, 8 byte words.
|
10
|
+
* Added support for hexdumping Little and Big Endian words.
|
11
|
+
* Optimized the hexdump algorithm to not use Arrays, use a lookup table
|
12
|
+
of printable characters and cache formatted numbers.
|
13
|
+
* Opted into [test.rubygems.org](http://test.rubygems.org/).
|
14
|
+
|
1
15
|
### 0.1.0 / 2011-03-05
|
2
16
|
|
3
17
|
* Initial release:
|
data/README.md
CHANGED
@@ -15,53 +15,11 @@ Simple and Fast hexdumping for Ruby.
|
|
15
15
|
* Can send the hexdump output to any Object supporting the `<<` method.
|
16
16
|
* Can yield each line of hexdump, instead of printing the output.
|
17
17
|
* Supports printing ASCII, hexadecimal, decimal, octal and binary bytes.
|
18
|
+
* Supports hexdumping 1, 2, 4, 8 byte words.
|
19
|
+
* Supports hexdumping Little and Big Endian words.
|
18
20
|
* Makes {String}, {StringIO}, {IO}, {File} objects hexdumpable.
|
19
21
|
* Fast-ish.
|
20
22
|
|
21
|
-
## Benchmarks
|
22
|
-
|
23
|
-
Benchmarks show {Hexdump.dump} processing 2.4M of data.
|
24
|
-
|
25
|
-
### Ruby 1.9.2-p180
|
26
|
-
|
27
|
-
user system total real
|
28
|
-
hexdump (block) 7.740000 0.030000 7.770000 ( 8.138029)
|
29
|
-
hexdump 9.590000 0.050000 9.640000 ( 10.178203)
|
30
|
-
hexdump width=256 (block) 7.280000 0.020000 7.300000 ( 7.534507)
|
31
|
-
hexdump width=256 8.130000 0.030000 8.160000 ( 8.342448)
|
32
|
-
hexdump ascii=true (block) 7.740000 0.030000 7.770000 ( 7.958550)
|
33
|
-
hexdump ascii=true 9.550000 0.050000 9.600000 ( 9.803758)
|
34
|
-
|
35
|
-
### Ruby 1.8.7-p334
|
36
|
-
|
37
|
-
user system total real
|
38
|
-
hexdump (block) 10.520000 0.010000 10.530000 ( 10.692901)
|
39
|
-
hexdump 11.580000 0.010000 11.590000 ( 11.873978)
|
40
|
-
hexdump width=256 (block) 9.960000 0.110000 10.070000 ( 11.592033)
|
41
|
-
hexdump width=256 10.660000 0.010000 10.670000 ( 10.987417)
|
42
|
-
hexdump ascii=true (block) 10.620000 0.010000 10.630000 ( 10.899925)
|
43
|
-
hexdump ascii=true 11.590000 0.030000 11.620000 ( 12.765259)
|
44
|
-
|
45
|
-
### Jruby 1.5.6
|
46
|
-
|
47
|
-
user system total real
|
48
|
-
hexdump (block) 6.690000 0.000000 6.690000 ( 6.517000)
|
49
|
-
hexdump 8.234000 0.000000 8.234000 ( 8.234000)
|
50
|
-
hexdump width=256 (block) 4.488000 0.000000 4.488000 ( 4.488000)
|
51
|
-
hexdump width=256 5.462000 0.000000 5.462000 ( 5.462000)
|
52
|
-
hexdump ascii=true (block) 4.456000 0.000000 4.456000 ( 4.456000)
|
53
|
-
hexdump ascii=true 5.039000 0.000000 5.039000 ( 5.039000)
|
54
|
-
|
55
|
-
### Rubinius 1.2.3
|
56
|
-
|
57
|
-
user system total real
|
58
|
-
hexdump (block) 10.013478 0.018997 10.032475 ( 11.148450)
|
59
|
-
hexdump 13.153001 0.015997 13.168998 ( 13.740888)
|
60
|
-
hexdump width=256 (block) 8.845656 0.008999 8.854655 ( 9.022673)
|
61
|
-
hexdump width=256 9.894496 0.008999 9.903495 ( 10.121070)
|
62
|
-
hexdump ascii=true (block) 9.576544 0.021996 9.598540 ( 9.810846)
|
63
|
-
hexdump ascii=true 13.088011 0.015998 13.104009 ( 13.390532)
|
64
|
-
|
65
23
|
## Examples
|
66
24
|
|
67
25
|
require 'hexdump'
|
@@ -74,6 +32,10 @@ Benchmarks show {Hexdump.dump} processing 2.4M of data.
|
|
74
32
|
data.hexdump
|
75
33
|
# 00000000 68 65 6c 6c 6f 00 |hello.|
|
76
34
|
|
35
|
+
File.open('dump.txt','w') do |file|
|
36
|
+
data.hexdump(:output => file)
|
37
|
+
end
|
38
|
+
|
77
39
|
# iterate over the hexdump lines
|
78
40
|
data.hexdump do |index,hex,printable|
|
79
41
|
index # => 0
|
@@ -102,10 +64,82 @@ Benchmarks show {Hexdump.dump} processing 2.4M of data.
|
|
102
64
|
Hexdump.dump(data, :base => :binary)
|
103
65
|
# 00000000 01101000 01100101 01101100 01101100 01101111 00000000 |hello.|
|
104
66
|
|
67
|
+
("ABC" * 10).hexdump(:word_size => 2)
|
68
|
+
# 00000000 4241 4143 4342 4241 4143 4342 4241 4143 |䉁䅃䍂䉁䅃䍂䉁䅃|
|
69
|
+
# 00000010 4342 4241 4143 4342 4241 4143 4342 |䍂䉁䅃䍂䉁䅃䍂|
|
70
|
+
|
105
71
|
## Install
|
106
72
|
|
107
73
|
$ gem install hexdump
|
108
74
|
|
75
|
+
## Benchmarks
|
76
|
+
|
77
|
+
Benchmarks show {Hexdump.dump} processing 2.4M of data.
|
78
|
+
|
79
|
+
### Ruby 1.9.2-p180
|
80
|
+
|
81
|
+
user system total real
|
82
|
+
hexdump (block) 3.010000 0.010000 3.020000 ( 3.529396)
|
83
|
+
hexdump 5.430000 0.030000 5.460000 ( 6.216174)
|
84
|
+
hexdump width=256 (block) 3.010000 0.020000 3.030000 ( 3.308961)
|
85
|
+
hexdump width=256 4.700000 0.040000 4.740000 ( 5.520189)
|
86
|
+
hexdump ascii=true (block) 3.050000 0.010000 3.060000 ( 3.501436)
|
87
|
+
hexdump ascii=true 5.450000 0.040000 5.490000 ( 6.352144)
|
88
|
+
hexdump word_size=2 (block) 7.420000 0.050000 7.470000 ( 9.174734)
|
89
|
+
hexdump word_size=2 9.500000 0.070000 9.570000 ( 11.228204)
|
90
|
+
hexdump word_size=4 (block) 4.110000 0.030000 4.140000 ( 4.849785)
|
91
|
+
hexdump word_size=4 5.380000 0.060000 5.440000 ( 6.209022)
|
92
|
+
hexdump word_size=8 (block) 3.350000 0.070000 3.420000 ( 4.147304)
|
93
|
+
hexdump word_size=8 4.430000 0.040000 4.470000 ( 5.930758)
|
94
|
+
|
95
|
+
### Ruby 1.8.7-p334
|
96
|
+
|
97
|
+
user system total real
|
98
|
+
hexdump (block) 8.470000 0.020000 8.490000 ( 9.585524)
|
99
|
+
hexdump 11.080000 0.050000 11.130000 ( 12.542401)
|
100
|
+
hexdump width=256 (block) 8.360000 0.030000 8.390000 ( 9.431877)
|
101
|
+
hexdump width=256 10.310000 0.050000 10.360000 ( 12.278973)
|
102
|
+
hexdump ascii=true (block) 8.550000 0.030000 8.580000 ( 10.502437)
|
103
|
+
hexdump ascii=true 11.140000 0.040000 11.180000 ( 12.752712)
|
104
|
+
hexdump word_size=2 (block) 12.680000 0.060000 12.740000 ( 14.657269)
|
105
|
+
hexdump word_size=2 13.560000 0.080000 13.640000 ( 16.368675)
|
106
|
+
hexdump word_size=4 (block) 8.500000 0.040000 8.540000 ( 9.687623)
|
107
|
+
hexdump word_size=4 9.340000 0.040000 9.380000 ( 10.657158)
|
108
|
+
hexdump word_size=8 (block) 7.520000 0.040000 7.560000 ( 8.565246)
|
109
|
+
hexdump word_size=8 8.240000 0.040000 8.280000 ( 9.475693)
|
110
|
+
|
111
|
+
### JRuby 1.6.0
|
112
|
+
|
113
|
+
user system total real
|
114
|
+
hexdump (block) 6.742000 0.000000 6.742000 ( 6.495000)
|
115
|
+
hexdump 7.498000 0.000000 7.498000 ( 7.498000)
|
116
|
+
hexdump width=256 (block) 4.601000 0.000000 4.601000 ( 4.601000)
|
117
|
+
hexdump width=256 5.569000 0.000000 5.569000 ( 5.569000)
|
118
|
+
hexdump ascii=true (block) 5.198000 0.000000 5.198000 ( 5.198000)
|
119
|
+
hexdump ascii=true 5.799000 0.000000 5.799000 ( 5.798000)
|
120
|
+
hexdump word_size=2 (block) 8.440000 0.000000 8.440000 ( 8.440000)
|
121
|
+
hexdump word_size=2 8.698000 0.000000 8.698000 ( 8.698000)
|
122
|
+
hexdump word_size=4 (block) 5.603000 0.000000 5.603000 ( 5.602000)
|
123
|
+
hexdump word_size=4 5.999000 0.000000 5.999000 ( 5.999000)
|
124
|
+
hexdump word_size=8 (block) 7.975000 0.000000 7.975000 ( 7.975000)
|
125
|
+
hexdump word_size=8 5.255000 0.000000 5.255000 ( 5.255000)
|
126
|
+
|
127
|
+
### Rubinius 1.2.4
|
128
|
+
|
129
|
+
user system total real
|
130
|
+
hexdump (block) 5.064230 0.029996 5.094226 ( 6.236865)
|
131
|
+
hexdump 7.401875 0.039993 7.441868 ( 10.154394)
|
132
|
+
hexdump width=256 (block) 4.149369 0.054992 4.204361 ( 6.518306)
|
133
|
+
hexdump width=256 4.960246 0.089986 5.050232 ( 8.647516)
|
134
|
+
hexdump ascii=true (block) 4.458322 0.026996 4.485318 ( 5.570982)
|
135
|
+
hexdump ascii=true 6.961941 0.056992 7.018933 ( 9.895088)
|
136
|
+
hexdump word_size=2 (block) 8.856653 0.078988 8.935641 ( 11.226360)
|
137
|
+
hexdump word_size=2 10.489405 0.083988 10.573393 ( 12.980509)
|
138
|
+
hexdump word_size=4 (block) 4.848263 0.047992 4.896255 ( 6.526478)
|
139
|
+
hexdump word_size=4 6.649989 0.053992 6.703981 ( 8.245247)
|
140
|
+
hexdump word_size=8 (block) 5.638143 0.047993 5.686136 ( 12.530454)
|
141
|
+
hexdump word_size=8 7.598844 0.066990 7.665834 ( 16.881667)
|
142
|
+
|
109
143
|
## Copyright
|
110
144
|
|
111
145
|
Copyright (c) 2011 Hal Brodigan
|
data/benchmarks/hexdump.rb
CHANGED
@@ -8,7 +8,7 @@ require 'benchmark'
|
|
8
8
|
DATA = ((0..255).map { |b| b.chr }.join) * 10000
|
9
9
|
OUTPUT = Class.new { def <<(data); end }.new
|
10
10
|
|
11
|
-
Benchmark.bm(
|
11
|
+
Benchmark.bm(27) do |b|
|
12
12
|
b.report('hexdump (block)') do
|
13
13
|
Hexdump.dump(DATA) { |index,hex,print| }
|
14
14
|
end
|
@@ -32,4 +32,14 @@ Benchmark.bm(26) do |b|
|
|
32
32
|
b.report('hexdump ascii=true') do
|
33
33
|
Hexdump.dump(DATA, :ascci => true, :output => OUTPUT)
|
34
34
|
end
|
35
|
+
|
36
|
+
[2, 4, 8].each do |word_size|
|
37
|
+
b.report("hexdump word_size=#{word_size} (block)") do
|
38
|
+
Hexdump.dump(DATA, :word_size => word_size) { |index,hex,print| }
|
39
|
+
end
|
40
|
+
|
41
|
+
b.report("hexdump word_size=#{word_size}") do
|
42
|
+
Hexdump.dump(DATA, :word_size => word_size, :output => OUTPUT)
|
43
|
+
end
|
44
|
+
end
|
35
45
|
end
|
data/gemspec.yml
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
name: hexdump
|
2
|
-
version: 0.1
|
3
|
-
summary:
|
2
|
+
version: 0.2.1
|
3
|
+
summary: Hexdump Strings and IO objects.
|
4
4
|
description: Simple and Fast hexdumping for Ruby.
|
5
5
|
license: MIT
|
6
|
-
authors:
|
6
|
+
authors: Postmodern
|
7
7
|
email: postmodern.mod3@gmail.com
|
8
8
|
homepage: http://github.com/postmodern/hexdump
|
9
9
|
has_yard: true
|
10
10
|
|
11
|
+
required_ruby_version: ">= 1.8.7"
|
12
|
+
|
11
13
|
development_dependencies:
|
12
14
|
ore-tasks: ~> 0.4
|
13
15
|
rspec: ~> 2.4
|
@@ -0,0 +1,441 @@
|
|
1
|
+
module Hexdump
|
2
|
+
#
|
3
|
+
# Handles the parsing of data and formatting of the hexdump.
|
4
|
+
#
|
5
|
+
# @since 0.2.0
|
6
|
+
#
|
7
|
+
class Dumper
|
8
|
+
|
9
|
+
# Widths for formatted numbers
|
10
|
+
WIDTHS = {
|
11
|
+
:hexadecimal => proc { |word_size| word_size * 2 },
|
12
|
+
:decimal => {
|
13
|
+
1 => 3,
|
14
|
+
2 => 5,
|
15
|
+
4 => 10,
|
16
|
+
8 => 20
|
17
|
+
},
|
18
|
+
:octal => {
|
19
|
+
1 => 3,
|
20
|
+
2 => 6,
|
21
|
+
4 => 11,
|
22
|
+
8 => 22
|
23
|
+
},
|
24
|
+
:binary => proc { |word_size| word_size * 8 }
|
25
|
+
}
|
26
|
+
|
27
|
+
# Format Strings for the various bases
|
28
|
+
FORMATS = {
|
29
|
+
:hexadecimal => proc { |width| "%.#{width}x" },
|
30
|
+
:decimal => proc { |width| "%#{width}.d" },
|
31
|
+
:octal => proc { |width| "%.#{width}o" },
|
32
|
+
:binary => proc { |width| "%.#{width}b" }
|
33
|
+
}
|
34
|
+
|
35
|
+
# Character to represent unprintable characters
|
36
|
+
UNPRINTABLE = '.'
|
37
|
+
|
38
|
+
# ASCII printable bytes and characters
|
39
|
+
PRINTABLE = {
|
40
|
+
0x20 => " ",
|
41
|
+
0x21 => "!",
|
42
|
+
0x22 => "\"",
|
43
|
+
0x23 => "#",
|
44
|
+
0x24 => "$",
|
45
|
+
0x25 => "%",
|
46
|
+
0x26 => "&",
|
47
|
+
0x27 => "'",
|
48
|
+
0x28 => "(",
|
49
|
+
0x29 => ")",
|
50
|
+
0x2a => "*",
|
51
|
+
0x2b => "+",
|
52
|
+
0x2c => ",",
|
53
|
+
0x2d => "-",
|
54
|
+
0x2e => ".",
|
55
|
+
0x2f => "/",
|
56
|
+
0x30 => "0",
|
57
|
+
0x31 => "1",
|
58
|
+
0x32 => "2",
|
59
|
+
0x33 => "3",
|
60
|
+
0x34 => "4",
|
61
|
+
0x35 => "5",
|
62
|
+
0x36 => "6",
|
63
|
+
0x37 => "7",
|
64
|
+
0x38 => "8",
|
65
|
+
0x39 => "9",
|
66
|
+
0x3a => ":",
|
67
|
+
0x3b => ";",
|
68
|
+
0x3c => "<",
|
69
|
+
0x3d => "=",
|
70
|
+
0x3e => ">",
|
71
|
+
0x3f => "?",
|
72
|
+
0x40 => "@",
|
73
|
+
0x41 => "A",
|
74
|
+
0x42 => "B",
|
75
|
+
0x43 => "C",
|
76
|
+
0x44 => "D",
|
77
|
+
0x45 => "E",
|
78
|
+
0x46 => "F",
|
79
|
+
0x47 => "G",
|
80
|
+
0x48 => "H",
|
81
|
+
0x49 => "I",
|
82
|
+
0x4a => "J",
|
83
|
+
0x4b => "K",
|
84
|
+
0x4c => "L",
|
85
|
+
0x4d => "M",
|
86
|
+
0x4e => "N",
|
87
|
+
0x4f => "O",
|
88
|
+
0x50 => "P",
|
89
|
+
0x51 => "Q",
|
90
|
+
0x52 => "R",
|
91
|
+
0x53 => "S",
|
92
|
+
0x54 => "T",
|
93
|
+
0x55 => "U",
|
94
|
+
0x56 => "V",
|
95
|
+
0x57 => "W",
|
96
|
+
0x58 => "X",
|
97
|
+
0x59 => "Y",
|
98
|
+
0x5a => "Z",
|
99
|
+
0x5b => "[",
|
100
|
+
0x5c => "\\",
|
101
|
+
0x5d => "]",
|
102
|
+
0x5e => "^",
|
103
|
+
0x5f => "_",
|
104
|
+
0x60 => "`",
|
105
|
+
0x61 => "a",
|
106
|
+
0x62 => "b",
|
107
|
+
0x63 => "c",
|
108
|
+
0x64 => "d",
|
109
|
+
0x65 => "e",
|
110
|
+
0x66 => "f",
|
111
|
+
0x67 => "g",
|
112
|
+
0x68 => "h",
|
113
|
+
0x69 => "i",
|
114
|
+
0x6a => "j",
|
115
|
+
0x6b => "k",
|
116
|
+
0x6c => "l",
|
117
|
+
0x6d => "m",
|
118
|
+
0x6e => "n",
|
119
|
+
0x6f => "o",
|
120
|
+
0x70 => "p",
|
121
|
+
0x71 => "q",
|
122
|
+
0x72 => "r",
|
123
|
+
0x73 => "s",
|
124
|
+
0x74 => "t",
|
125
|
+
0x75 => "u",
|
126
|
+
0x76 => "v",
|
127
|
+
0x77 => "w",
|
128
|
+
0x78 => "x",
|
129
|
+
0x79 => "y",
|
130
|
+
0x7a => "z",
|
131
|
+
0x7b => "{",
|
132
|
+
0x7c => "|",
|
133
|
+
0x7d => "}",
|
134
|
+
0x7e => "~"
|
135
|
+
}
|
136
|
+
|
137
|
+
PRINTABLE.default = UNPRINTABLE
|
138
|
+
|
139
|
+
# The base to dump words as.
|
140
|
+
attr_reader :base
|
141
|
+
|
142
|
+
# The size of the words parse from the data.
|
143
|
+
attr_reader :word_size
|
144
|
+
|
145
|
+
# The endianness of the words parsed from the data.
|
146
|
+
attr_reader :endian
|
147
|
+
|
148
|
+
# The width in words of each hexdump line.
|
149
|
+
attr_reader :width
|
150
|
+
|
151
|
+
# Whether to display ASCII characters alongside numeric values.
|
152
|
+
attr_reader :ascii
|
153
|
+
|
154
|
+
#
|
155
|
+
# Creates a new Hexdump dumper.
|
156
|
+
#
|
157
|
+
# @param [Hash] options
|
158
|
+
# Additional options.
|
159
|
+
#
|
160
|
+
# @option options [Integer] :width (16)
|
161
|
+
# The number of bytes to dump for each line.
|
162
|
+
#
|
163
|
+
# @option options [Integer] :word_size (1)
|
164
|
+
# The number of bytes within a word.
|
165
|
+
#
|
166
|
+
# @option options [Symbol, Integer] :base (:hexadecimal)
|
167
|
+
# The base to print bytes in. Supported bases include, `:hexadecimal`,
|
168
|
+
# `:hex`, `16, `:decimal`, `:dec`, `10, `:octal`, `:oct`, `8`,
|
169
|
+
# `:binary`, `:bin` and `2`.
|
170
|
+
#
|
171
|
+
# @option options [Boolean] :ascii (false)
|
172
|
+
# Print ascii characters when possible.
|
173
|
+
#
|
174
|
+
# @raise [ArgumentError]
|
175
|
+
# The values for `:base` or `:endian` were unknown.
|
176
|
+
#
|
177
|
+
# @since 0.2.0
|
178
|
+
#
|
179
|
+
def initialize(options={})
|
180
|
+
@base = case options[:base]
|
181
|
+
when :hexadecimal, :hex, 16
|
182
|
+
:hexadecimal
|
183
|
+
when :decimal, :dec, 10
|
184
|
+
:decimal
|
185
|
+
when :octal, :oct, 8
|
186
|
+
:octal
|
187
|
+
when :binary, :bin, 2
|
188
|
+
:binary
|
189
|
+
when nil
|
190
|
+
:hexadecimal
|
191
|
+
else
|
192
|
+
raise(ArgumentError,"unknown base #{options[:base].inspect}")
|
193
|
+
end
|
194
|
+
|
195
|
+
@word_size = options.fetch(:word_size,1)
|
196
|
+
@endian = case options[:endian]
|
197
|
+
when 'little', :little
|
198
|
+
:little
|
199
|
+
when 'big', :big
|
200
|
+
:big
|
201
|
+
when nil
|
202
|
+
:little
|
203
|
+
else
|
204
|
+
raise(ArgumentError,"unknown endian: #{options[:endian].inspect}")
|
205
|
+
end
|
206
|
+
|
207
|
+
@width = (options.fetch(:width,16) / @word_size)
|
208
|
+
@ascii = options.fetch(:ascii,false)
|
209
|
+
|
210
|
+
@format_width = (WIDTHS[@base][@word_size] || 1)
|
211
|
+
@format = FORMATS[@base][@format_width]
|
212
|
+
|
213
|
+
if @word_size == 1
|
214
|
+
@format_cache = Hash.new do |hash,key|
|
215
|
+
hash[key] = sprintf(@format,key)
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
#
|
221
|
+
# Iterates over every word within the data.
|
222
|
+
#
|
223
|
+
# @param [#each_byte] data
|
224
|
+
# The data containing bytes.
|
225
|
+
#
|
226
|
+
# @yield [word]
|
227
|
+
# The given block will be passed each word within the data.
|
228
|
+
#
|
229
|
+
# @yieldparam [Integer]
|
230
|
+
# An unpacked word from the data.
|
231
|
+
#
|
232
|
+
# @return [Enumerator]
|
233
|
+
# If no block is given, an Enumerator will be returned.
|
234
|
+
#
|
235
|
+
# @raise [ArgumentError]
|
236
|
+
# The given data does not define the `#each_byte` method.
|
237
|
+
#
|
238
|
+
# @since 0.2.0
|
239
|
+
#
|
240
|
+
def each_word(data,&block)
|
241
|
+
return enum_for(:each_word,data) unless block
|
242
|
+
|
243
|
+
unless data.respond_to?(:each_byte)
|
244
|
+
raise(ArgumentError,"the data to hexdump must define #each_byte")
|
245
|
+
end
|
246
|
+
|
247
|
+
if @word_size > 1
|
248
|
+
word = 0
|
249
|
+
count = 0
|
250
|
+
|
251
|
+
init_shift = if @endian == :big
|
252
|
+
((@word_size - 1) * 8)
|
253
|
+
else
|
254
|
+
0
|
255
|
+
end
|
256
|
+
shift = init_shift
|
257
|
+
|
258
|
+
data.each_byte do |b|
|
259
|
+
word |= (b << shift)
|
260
|
+
|
261
|
+
if @endian == :big
|
262
|
+
shift -= 8
|
263
|
+
else
|
264
|
+
shift += 8
|
265
|
+
end
|
266
|
+
|
267
|
+
count += 1
|
268
|
+
|
269
|
+
if count >= @word_size
|
270
|
+
yield word
|
271
|
+
|
272
|
+
word = 0
|
273
|
+
count = 0
|
274
|
+
shift = init_shift
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
# yield the remaining word
|
279
|
+
yield word if count > 0
|
280
|
+
else
|
281
|
+
data.each_byte(&block)
|
282
|
+
end
|
283
|
+
end
|
284
|
+
|
285
|
+
#
|
286
|
+
# Iterates over the hexdump.
|
287
|
+
#
|
288
|
+
# @param [#each_byte] data
|
289
|
+
# The data to be hexdumped.
|
290
|
+
#
|
291
|
+
# @yield [index,numeric,printable]
|
292
|
+
# The given block will be passed the hexdump break-down of each
|
293
|
+
# segment.
|
294
|
+
#
|
295
|
+
# @yieldparam [Integer] index
|
296
|
+
# The index of the hexdumped segment.
|
297
|
+
#
|
298
|
+
# @yieldparam [Array<String>] numeric
|
299
|
+
# The numeric representation of the segment.
|
300
|
+
#
|
301
|
+
# @yieldparam [Array<String>] printable
|
302
|
+
# The printable representation of the segment.
|
303
|
+
#
|
304
|
+
# @return [Enumerator]
|
305
|
+
# If no block is given, an Enumerator will be returned.
|
306
|
+
#
|
307
|
+
# @since 0.2.0
|
308
|
+
#
|
309
|
+
def each(data)
|
310
|
+
return enum_for(:each,data) unless block_given?
|
311
|
+
|
312
|
+
index = 0
|
313
|
+
count = 0
|
314
|
+
|
315
|
+
numeric = []
|
316
|
+
printable = []
|
317
|
+
|
318
|
+
each_word(data) do |word|
|
319
|
+
numeric << format_numeric(word)
|
320
|
+
printable << format_printable(word)
|
321
|
+
|
322
|
+
count += 1
|
323
|
+
|
324
|
+
if count >= @width
|
325
|
+
yield(index,numeric,printable)
|
326
|
+
|
327
|
+
numeric.clear
|
328
|
+
printable.clear
|
329
|
+
|
330
|
+
index += (@width * @word_size)
|
331
|
+
count = 0
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
if count > 0
|
336
|
+
# yield the remaining data
|
337
|
+
yield(index,numeric,printable)
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
#
|
342
|
+
# Dumps the hexdump.
|
343
|
+
#
|
344
|
+
# @param [#each_byte] data
|
345
|
+
# The data to be hexdumped.
|
346
|
+
#
|
347
|
+
# @param [#<<] output
|
348
|
+
# The output to dump the hexdump to.
|
349
|
+
#
|
350
|
+
# @return [nil]
|
351
|
+
#
|
352
|
+
# @raise [ArgumentError]
|
353
|
+
# The output value does not support the `#<<` method.
|
354
|
+
#
|
355
|
+
# @since 0.2.0
|
356
|
+
#
|
357
|
+
def dump(data,output=STDOUT)
|
358
|
+
unless output.respond_to?(:<<)
|
359
|
+
raise(ArgumentError,"output must support the #<< method")
|
360
|
+
end
|
361
|
+
|
362
|
+
bytes_segment_width = ((@width * @format_width) + @width)
|
363
|
+
line_format = "%.8x %-#{bytes_segment_width}s |%s|\n"
|
364
|
+
|
365
|
+
index = 0
|
366
|
+
count = 0
|
367
|
+
|
368
|
+
numeric = ''
|
369
|
+
printable = ''
|
370
|
+
|
371
|
+
each_word(data) do |word|
|
372
|
+
numeric << format_numeric(word) << ' '
|
373
|
+
printable << format_printable(word)
|
374
|
+
|
375
|
+
count += 1
|
376
|
+
|
377
|
+
if count >= @width
|
378
|
+
output << sprintf(line_format,index,numeric,printable)
|
379
|
+
|
380
|
+
numeric = ''
|
381
|
+
printable = ''
|
382
|
+
|
383
|
+
index += (@width * @word_size)
|
384
|
+
count = 0
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
if count > 0
|
389
|
+
# output the remaining line
|
390
|
+
output << sprintf(line_format,index,numeric,printable)
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
protected
|
395
|
+
|
396
|
+
#
|
397
|
+
# Converts the word into a numeric String.
|
398
|
+
#
|
399
|
+
# @param [Integer] word
|
400
|
+
# The word to convert.
|
401
|
+
#
|
402
|
+
# @return [String]
|
403
|
+
# The numeric representation of the word.
|
404
|
+
#
|
405
|
+
# @since 0.2.0
|
406
|
+
#
|
407
|
+
def format_numeric(word)
|
408
|
+
if @word_size == 1
|
409
|
+
if (@ascii && (word >= 0x20 && word <= 0x7e))
|
410
|
+
PRINTABLE[word]
|
411
|
+
else
|
412
|
+
@format_cache[word]
|
413
|
+
end
|
414
|
+
else
|
415
|
+
sprintf(@format,word)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
|
419
|
+
#
|
420
|
+
# Converts a word into a printable String.
|
421
|
+
#
|
422
|
+
# @param [Integer] word
|
423
|
+
# The word to convert.
|
424
|
+
#
|
425
|
+
# @return [String]
|
426
|
+
# The printable representation of the word.
|
427
|
+
#
|
428
|
+
# @since 0.2.0
|
429
|
+
#
|
430
|
+
def format_printable(word)
|
431
|
+
if @word_size == 1
|
432
|
+
PRINTABLE[word]
|
433
|
+
elsif (RUBY_VERSION > '1.9.' && (word >= -2 && word <= 0x7fffffff))
|
434
|
+
word.chr(Encoding::UTF_8)
|
435
|
+
else
|
436
|
+
UNPRINTABLE
|
437
|
+
end
|
438
|
+
end
|
439
|
+
|
440
|
+
end
|
441
|
+
end
|
data/lib/hexdump/hexdump.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'hexdump/dumper'
|
2
|
+
|
1
3
|
#
|
2
4
|
# Provides the {Hexdump.dump} method and can add hexdumping to other classes
|
3
5
|
# by including the {Hexdump} module.
|
@@ -28,6 +30,9 @@ module Hexdump
|
|
28
30
|
# @option options [Integer] :width (16)
|
29
31
|
# The number of bytes to dump for each line.
|
30
32
|
#
|
33
|
+
# @option options [Integer] :word_size (1)
|
34
|
+
# The number of bytes within a word.
|
35
|
+
#
|
31
36
|
# @option options [Symbol, Integer] :base (:hexadecimal)
|
32
37
|
# The base to print bytes in. Supported bases include, `:hexadecimal`,
|
33
38
|
# `:hex`, `16, `:decimal`, `:dec`, `10, `:octal`, `:oct`, `8`,
|
@@ -39,89 +44,36 @@ module Hexdump
|
|
39
44
|
# @option options [#<<] :output (STDOUT)
|
40
45
|
# The output to print the hexdump to.
|
41
46
|
#
|
42
|
-
# @yield [index,
|
43
|
-
# The given block will be passed the hexdump break-down of each
|
47
|
+
# @yield [index,numeric,printable]
|
48
|
+
# The given block will be passed the hexdump break-down of each
|
49
|
+
# segment.
|
44
50
|
#
|
45
51
|
# @yieldparam [Integer] index
|
46
52
|
# The index of the hexdumped segment.
|
47
53
|
#
|
48
|
-
# @yieldparam [Array<String>]
|
49
|
-
# The
|
54
|
+
# @yieldparam [Array<String>] numeric
|
55
|
+
# The numeric representation of the segment.
|
50
56
|
#
|
51
|
-
# @yieldparam [Array<String>]
|
52
|
-
# The
|
57
|
+
# @yieldparam [Array<String>] printable
|
58
|
+
# The printable representation of the segment.
|
53
59
|
#
|
54
60
|
# @return [nil]
|
55
61
|
#
|
56
62
|
# @raise [ArgumentError]
|
57
|
-
# The given data does not define the `#each_byte` method,
|
58
|
-
# the `:output` value does not support the `#<<` method
|
63
|
+
# The given data does not define the `#each_byte` method,
|
64
|
+
# the `:output` value does not support the `#<<` method or
|
65
|
+
# the `:base` value was unknown.
|
59
66
|
#
|
60
|
-
def Hexdump.dump(data,options={})
|
61
|
-
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
output = options.fetch(:output,STDOUT)
|
66
|
-
|
67
|
-
unless output.respond_to?(:<<)
|
68
|
-
raise(ArgumentError,":output must support the #<< method")
|
69
|
-
end
|
70
|
-
|
71
|
-
width = options.fetch(:width,16)
|
72
|
-
base = options.fetch(:base,:hexadecimal)
|
73
|
-
ascii = options.fetch(:ascii,false)
|
74
|
-
byte_width, byte_format = case base
|
75
|
-
when :hexadecimal, :hex, 16
|
76
|
-
[2, "%.2x"]
|
77
|
-
when :decimal, :dec, 10
|
78
|
-
[3, "%3.d"]
|
79
|
-
when :octal, :oct, 8
|
80
|
-
[4, "0%.3o"]
|
81
|
-
when :binary, :bin, 2
|
82
|
-
[8, "%.8b"]
|
83
|
-
end
|
84
|
-
|
85
|
-
hex_byte = lambda { |byte|
|
86
|
-
if (ascii && (byte >= 0x20 && byte <= 0x7e))
|
87
|
-
byte.chr
|
88
|
-
else
|
89
|
-
byte_format % byte
|
90
|
-
end
|
91
|
-
}
|
92
|
-
|
93
|
-
print_byte = lambda { |byte|
|
94
|
-
if (byte >= 0x20 && byte <= 0x7e)
|
95
|
-
byte.chr
|
96
|
-
else
|
97
|
-
'.'
|
98
|
-
end
|
99
|
-
}
|
100
|
-
|
101
|
-
index = 0
|
102
|
-
|
103
|
-
hex_segment_width = ((width * byte_width) + (width - 1))
|
104
|
-
line_format = "%.8x %-#{hex_segment_width}s |%s|\n"
|
105
|
-
|
106
|
-
data.each_byte.each_slice(width) do |bytes|
|
107
|
-
hex_segment = bytes.map(&hex_byte)
|
108
|
-
print_segment = bytes.map(&print_byte)
|
109
|
-
|
110
|
-
if block_given?
|
111
|
-
yield(index,hex_segment,print_segment)
|
112
|
-
else
|
113
|
-
output << sprintf(
|
114
|
-
line_format,
|
115
|
-
index,
|
116
|
-
hex_segment.join(' '),
|
117
|
-
print_segment.join
|
118
|
-
)
|
119
|
-
end
|
67
|
+
def Hexdump.dump(data,options={},&block)
|
68
|
+
output = (options.delete(:output) || STDOUT)
|
69
|
+
dumper = Dumper.new(options)
|
120
70
|
|
121
|
-
|
71
|
+
if block
|
72
|
+
dumper.each(data,&block)
|
73
|
+
else
|
74
|
+
dumper.dump(data,output)
|
122
75
|
end
|
123
76
|
|
124
|
-
# flush the hexdump buffer
|
125
77
|
return nil
|
126
78
|
end
|
127
79
|
|
data/spec/dumper_spec.rb
ADDED
@@ -0,0 +1,260 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
require 'hexdump/dumper'
|
4
|
+
|
5
|
+
describe Hexdump::Dumper do
|
6
|
+
let(:bytes) { [104, 101, 108, 108, 111] }
|
7
|
+
let(:hex_chars) { ['68', '65', '6c', '6c', '6f'] }
|
8
|
+
let(:decimal_chars) { ['104', '101', '108', '108', '111'] }
|
9
|
+
let(:octal_chars) { ['150', '145', '154', '154', '157'] }
|
10
|
+
let(:binary_chars) { ['01101000', '01100101', '01101100', '01101100', '01101111'] }
|
11
|
+
let(:print_chars) { ['h', 'e', 'l', 'l', 'o'] }
|
12
|
+
let(:data) { print_chars.join }
|
13
|
+
|
14
|
+
it "should only accept known :base values" do
|
15
|
+
lambda {
|
16
|
+
described_class.new(data, :base => :foo)
|
17
|
+
}.should raise_error(ArgumentError)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should only accept known :endian values" do
|
21
|
+
lambda {
|
22
|
+
described_class.new(data, :endian => :foo)
|
23
|
+
}.should raise_error(ArgumentError)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "each_word" do
|
27
|
+
let(:data) { 'ABAB' }
|
28
|
+
let(:bytes) { [0x41, 0x42, 0x41, 0x42] }
|
29
|
+
let(:shorts_le) { [0x4241, 0x4241] }
|
30
|
+
let(:shorts_be) { [0x4142, 0x4142] }
|
31
|
+
let(:custom_words) { [0x414241, 0x42] }
|
32
|
+
|
33
|
+
it "should check if the data defines '#each_byte'" do
|
34
|
+
lambda {
|
35
|
+
subject.each_word(Object.new).to_a
|
36
|
+
}.should raise_error(ArgumentError)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should iterate over each byte by default" do
|
40
|
+
subject.each_word(data).to_a.should == bytes
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should allow iterating over custom word-sizes" do
|
44
|
+
dumper = described_class.new(:word_size => 3)
|
45
|
+
|
46
|
+
dumper.each_word(data).to_a.should == custom_words
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should iterate over little-endian words by default" do
|
50
|
+
dumper = described_class.new(:word_size => 2)
|
51
|
+
|
52
|
+
dumper.each_word(data).to_a.should == shorts_le
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should iterate over big-endian words" do
|
56
|
+
dumper = described_class.new(:word_size => 2, :endian => :big)
|
57
|
+
|
58
|
+
dumper.each_word(data).to_a.should == shorts_be
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe "#each" do
|
63
|
+
it "should yield the parts of each hexdump line to the given block" do
|
64
|
+
lines = []
|
65
|
+
|
66
|
+
subject.each(data) do |index,hex,print|
|
67
|
+
lines << [index, hex, print]
|
68
|
+
end
|
69
|
+
|
70
|
+
lines.length.should == 1
|
71
|
+
lines[0][0].should == 0
|
72
|
+
lines[0][1].should == hex_chars
|
73
|
+
lines[0][2].should == print_chars
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should provide the index within the data for each line" do
|
77
|
+
dumper = described_class.new(:width => 10)
|
78
|
+
indices = []
|
79
|
+
|
80
|
+
dumper.each('A' * 100) do |index,hex,print|
|
81
|
+
indices << index
|
82
|
+
end
|
83
|
+
|
84
|
+
indices.should == [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should allow configuring the width, in bytes, of each line" do
|
88
|
+
dumper = described_class.new(:width => 10)
|
89
|
+
widths = []
|
90
|
+
|
91
|
+
dumper.each('A' * 100) do |index,hex,print|
|
92
|
+
widths << hex.length
|
93
|
+
end
|
94
|
+
|
95
|
+
widths.should == ([10] * 10)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should hexdump the remaining bytes" do
|
99
|
+
dumper = described_class.new(:width => 10)
|
100
|
+
chars = (['B'] * 4)
|
101
|
+
string = chars.join
|
102
|
+
leading = ('A' * 100)
|
103
|
+
remainder = nil
|
104
|
+
|
105
|
+
dumper.each(leading + string) do |index,hex,print|
|
106
|
+
remainder = print
|
107
|
+
end
|
108
|
+
|
109
|
+
remainder.should == chars
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should provide the hexadecimal characters for each line" do
|
113
|
+
dumper = described_class.new(:width => 10)
|
114
|
+
chars = []
|
115
|
+
|
116
|
+
dumper.each(data * 100) do |index,hex,print|
|
117
|
+
chars += hex
|
118
|
+
end
|
119
|
+
|
120
|
+
chars.should == (hex_chars * 100)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should allow printing ASCII characters in place of hex characters" do
|
124
|
+
dumper = described_class.new(:ascii => true)
|
125
|
+
chars = []
|
126
|
+
|
127
|
+
dumper.each(data) do |index,hex,print|
|
128
|
+
chars += hex
|
129
|
+
end
|
130
|
+
|
131
|
+
chars.should == print_chars
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should provide the print characters for each line" do
|
135
|
+
dumper = described_class.new(:width => 10)
|
136
|
+
chars = []
|
137
|
+
|
138
|
+
dumper.each(data * 100) do |index,hex,print|
|
139
|
+
chars += print
|
140
|
+
end
|
141
|
+
|
142
|
+
chars.should == (print_chars * 100)
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should map unprintable characters to '.'" do
|
146
|
+
unprintable = ((0x00..0x1f).map(&:chr) + (0x7f..0xff).map(&:chr)).join
|
147
|
+
chars = []
|
148
|
+
|
149
|
+
subject.each(unprintable) do |index,hex,print|
|
150
|
+
chars += print
|
151
|
+
end
|
152
|
+
|
153
|
+
chars.should == (['.'] * unprintable.length)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should support dumping bytes in decimal format" do
|
157
|
+
dumper = described_class.new(:base => :decimal)
|
158
|
+
chars = []
|
159
|
+
|
160
|
+
dumper.each(data) do |index,hex,print|
|
161
|
+
chars += hex
|
162
|
+
end
|
163
|
+
|
164
|
+
chars.should == decimal_chars
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should support dumping bytes in octal format" do
|
168
|
+
dumper = described_class.new(:base => :octal)
|
169
|
+
chars = []
|
170
|
+
|
171
|
+
dumper.each(data) do |index,hex,print|
|
172
|
+
chars += hex
|
173
|
+
end
|
174
|
+
|
175
|
+
chars.should == octal_chars
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should support dumping bytes in binary format" do
|
179
|
+
dumper = described_class.new(:base => :binary)
|
180
|
+
chars = []
|
181
|
+
|
182
|
+
dumper.each(data) do |index,hex,print|
|
183
|
+
chars += hex
|
184
|
+
end
|
185
|
+
|
186
|
+
chars.should == binary_chars
|
187
|
+
end
|
188
|
+
|
189
|
+
context ":word_size" do
|
190
|
+
let(:options) { {:word_size => 2, :endian => :little} }
|
191
|
+
|
192
|
+
let(:hex_words) { ['6568', '6c6c', '006f'] }
|
193
|
+
let(:decimal_words) { ['25960', '27756', ' 111'] }
|
194
|
+
let(:octal_words) { ['062550', '066154', '000157'] }
|
195
|
+
let(:binary_words) { ['0110010101101000', '0110110001101100', '0000000001101111'] }
|
196
|
+
|
197
|
+
it "should dump words in hexadecimal" do
|
198
|
+
dumper = described_class.new(options)
|
199
|
+
words = []
|
200
|
+
|
201
|
+
dumper.each(data) do |index,hex,print|
|
202
|
+
words += hex
|
203
|
+
end
|
204
|
+
|
205
|
+
words.should == hex_words
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should dump words in decimal" do
|
209
|
+
dumper = described_class.new(options.merge(:base => :decimal))
|
210
|
+
words = []
|
211
|
+
|
212
|
+
dumper.each(data) do |index,dec,print|
|
213
|
+
words += dec
|
214
|
+
end
|
215
|
+
|
216
|
+
words.should == decimal_words
|
217
|
+
end
|
218
|
+
|
219
|
+
it "should dump words in octal" do
|
220
|
+
dumper = described_class.new(options.merge(:base => :octal))
|
221
|
+
words = []
|
222
|
+
|
223
|
+
dumper.each(data) do |index,oct,print|
|
224
|
+
words += oct
|
225
|
+
end
|
226
|
+
|
227
|
+
words.should == octal_words
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should dump words in binary" do
|
231
|
+
dumper = described_class.new(options.merge(:base => :binary))
|
232
|
+
words = []
|
233
|
+
|
234
|
+
dumper.each(data) do |index,bin,print|
|
235
|
+
words += bin
|
236
|
+
end
|
237
|
+
|
238
|
+
words.should == binary_words
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
describe "#dump" do
|
244
|
+
it "should check if the :output supports the '#<<' method" do
|
245
|
+
lambda {
|
246
|
+
subject.dump(data,Object.new)
|
247
|
+
}.should raise_error(ArgumentError)
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should append each line of the hexdump to the output" do
|
251
|
+
lines = []
|
252
|
+
|
253
|
+
subject.dump(data,lines)
|
254
|
+
|
255
|
+
lines.length.should == 1
|
256
|
+
lines[0].should include(hex_chars.join(' '))
|
257
|
+
lines[0].should include(print_chars.join)
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
data/spec/hexdump_spec.rb
CHANGED
@@ -1,159 +1,17 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
|
2
3
|
require 'hexdump'
|
3
4
|
|
4
5
|
describe Hexdump do
|
5
|
-
let(:bytes) { [104, 101, 108, 108, 111] }
|
6
|
-
let(:hex_chars) { ['68', '65', '6c', '6c', '6f'] }
|
7
|
-
let(:decimal_chars) { ['104', '101', '108', '108', '111'] }
|
8
|
-
let(:octal_chars) { ['0150', '0145', '0154', '0154', '0157'] }
|
9
|
-
let(:binary_chars) { ['01101000', '01100101', '01101100', '01101100', '01101111'] }
|
10
|
-
let(:print_chars) { ['h', 'e', 'l', 'l', 'o'] }
|
11
|
-
let(:data) { print_chars.join }
|
12
|
-
|
13
|
-
describe "dump" do
|
14
|
-
it "should check if the data defines '#each_byte'" do
|
15
|
-
lambda {
|
16
|
-
subject.dump(Object.new)
|
17
|
-
}.should raise_error(ArgumentError)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "should check if the :output supports the '#<<' method" do
|
21
|
-
lambda {
|
22
|
-
subject.dump(data, :output => Object.new)
|
23
|
-
}.should raise_error(ArgumentError)
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should append each line of the hexdump to the output" do
|
27
|
-
lines = []
|
28
|
-
subject.dump(data, :output => lines)
|
29
|
-
|
30
|
-
lines.length.should == 1
|
31
|
-
lines[0].should include(hex_chars.join(' '))
|
32
|
-
lines[0].should include(print_chars.join)
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should yield the parts of each hexdump line to the given block" do
|
36
|
-
lines = []
|
37
|
-
|
38
|
-
subject.dump(data) do |index,hex,print|
|
39
|
-
lines << [index, hex, print]
|
40
|
-
end
|
41
|
-
|
42
|
-
lines.length.should == 1
|
43
|
-
lines[0][0].should == 0
|
44
|
-
lines[0][1].should == hex_chars
|
45
|
-
lines[0][2].should == print_chars
|
46
|
-
end
|
47
|
-
|
48
|
-
it "should provide the index within the data for each line" do
|
49
|
-
indices = []
|
50
|
-
|
51
|
-
subject.dump('A' * 100, :width => 10) do |index,hex,print|
|
52
|
-
indices << index
|
53
|
-
end
|
54
|
-
|
55
|
-
indices.should == [0, 10, 20, 30, 40, 50, 60, 70, 80, 90]
|
56
|
-
end
|
57
|
-
|
58
|
-
it "should allow configuring the width, in bytes, of each line" do
|
59
|
-
widths = []
|
60
|
-
|
61
|
-
subject.dump('A' * 100, :width => 10) do |index,hex,print|
|
62
|
-
widths << hex.length
|
63
|
-
end
|
64
|
-
|
65
|
-
widths.should == ([10] * 10)
|
66
|
-
end
|
67
|
-
|
68
|
-
it "should hexdump the remaining bytes" do
|
69
|
-
chars = (['B'] * 4)
|
70
|
-
string = chars.join
|
71
|
-
leading = ('A' * 100)
|
72
|
-
remainder = nil
|
73
|
-
|
74
|
-
subject.dump(leading + string, :width => 10) do |index,hex,print|
|
75
|
-
remainder = print
|
76
|
-
end
|
77
|
-
|
78
|
-
remainder.should == chars
|
79
|
-
end
|
80
|
-
|
81
|
-
it "should provide the hexadecimal characters for each line" do
|
82
|
-
chars = []
|
83
|
-
|
84
|
-
subject.dump(data * 100, :width => 10) do |index,hex,print|
|
85
|
-
chars += hex
|
86
|
-
end
|
87
|
-
|
88
|
-
chars.should == (hex_chars * 100)
|
89
|
-
end
|
90
|
-
|
91
|
-
it "should allow printing ASCII characters in place of hex characters" do
|
92
|
-
chars = []
|
93
|
-
|
94
|
-
subject.dump(data, :ascii => true) do |index,hex,print|
|
95
|
-
chars += hex
|
96
|
-
end
|
97
|
-
|
98
|
-
chars.should == print_chars
|
99
|
-
end
|
100
|
-
|
101
|
-
it "should provide the print characters for each line" do
|
102
|
-
chars = []
|
103
|
-
|
104
|
-
subject.dump(data * 100, :width => 10) do |index,hex,print|
|
105
|
-
chars += print
|
106
|
-
end
|
107
|
-
|
108
|
-
chars.should == (print_chars * 100)
|
109
|
-
end
|
110
|
-
|
111
|
-
it "should map unprintable characters to '.'" do
|
112
|
-
unprintable = ((0x00..0x1f).map(&:chr) + (0x7f..0xff).map(&:chr)).join
|
113
|
-
chars = []
|
114
|
-
|
115
|
-
subject.dump(unprintable) do |index,hex,print|
|
116
|
-
chars += print
|
117
|
-
end
|
118
|
-
|
119
|
-
chars.should == (['.'] * unprintable.length)
|
120
|
-
end
|
121
|
-
|
122
|
-
it "should support dumping bytes in decimal format" do
|
123
|
-
chars = []
|
124
|
-
|
125
|
-
subject.dump(data, :base => :decimal) do |index,hex,print|
|
126
|
-
chars += hex
|
127
|
-
end
|
128
|
-
|
129
|
-
chars.should == decimal_chars
|
130
|
-
end
|
131
|
-
|
132
|
-
it "should support dumping bytes in octal format" do
|
133
|
-
chars = []
|
134
|
-
|
135
|
-
subject.dump(data, :base => :octal) do |index,hex,print|
|
136
|
-
chars += hex
|
137
|
-
end
|
138
|
-
|
139
|
-
chars.should == octal_chars
|
140
|
-
end
|
141
|
-
|
142
|
-
it "should support dumping bytes in binary format" do
|
143
|
-
chars = []
|
144
|
-
|
145
|
-
subject.dump(data, :base => :binary) do |index,hex,print|
|
146
|
-
chars += hex
|
147
|
-
end
|
148
|
-
|
149
|
-
chars.should == binary_chars
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
6
|
describe "#hexdump" do
|
7
|
+
let(:bytes) { [104, 101, 108, 108, 111] }
|
8
|
+
let(:hex_chars) { ['68', '65', '6c', '6c', '6f'] }
|
9
|
+
|
154
10
|
subject do
|
155
11
|
obj = Object.new.extend(Hexdump)
|
156
|
-
|
12
|
+
|
13
|
+
stub = obj.stub!(:each_byte)
|
14
|
+
bytes.each { |b| stub = stub.and_yield(b) }
|
157
15
|
|
158
16
|
obj
|
159
17
|
end
|
metadata
CHANGED
@@ -2,16 +2,15 @@
|
|
2
2
|
name: hexdump
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.1
|
5
|
+
version: 0.2.1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
|
-
-
|
8
|
+
- Postmodern
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
14
|
-
default_executable:
|
13
|
+
date: 2011-06-11 00:00:00 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: ore-tasks
|
@@ -70,16 +69,17 @@ files:
|
|
70
69
|
- gemspec.yml
|
71
70
|
- hexdump.gemspec
|
72
71
|
- lib/hexdump.rb
|
72
|
+
- lib/hexdump/dumper.rb
|
73
73
|
- lib/hexdump/extensions.rb
|
74
74
|
- lib/hexdump/extensions/file.rb
|
75
75
|
- lib/hexdump/extensions/io.rb
|
76
76
|
- lib/hexdump/extensions/string.rb
|
77
77
|
- lib/hexdump/extensions/string_io.rb
|
78
78
|
- lib/hexdump/hexdump.rb
|
79
|
+
- spec/dumper_spec.rb
|
79
80
|
- spec/extensions_spec.rb
|
80
81
|
- spec/hexdump_spec.rb
|
81
82
|
- spec/spec_helper.rb
|
82
|
-
has_rdoc: yard
|
83
83
|
homepage: http://github.com/postmodern/hexdump
|
84
84
|
licenses:
|
85
85
|
- MIT
|
@@ -93,7 +93,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
96
|
+
version: 1.8.7
|
97
97
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
98
|
none: false
|
99
99
|
requirements:
|
@@ -103,10 +103,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
103
103
|
requirements: []
|
104
104
|
|
105
105
|
rubyforge_project: hexdump
|
106
|
-
rubygems_version: 1.
|
106
|
+
rubygems_version: 1.8.1
|
107
107
|
signing_key:
|
108
108
|
specification_version: 3
|
109
|
-
summary:
|
109
|
+
summary: Hexdump Strings and IO objects.
|
110
110
|
test_files:
|
111
|
+
- spec/dumper_spec.rb
|
111
112
|
- spec/hexdump_spec.rb
|
112
113
|
- spec/extensions_spec.rb
|