nxxd 1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +52 -0
- data/README.md +106 -0
- data/bin/nxxd +219 -0
- data/lib/nxxd/nvim.rb +116 -0
- data/lib/nxxd/version.rb +12 -0
- data/lib/nxxd.rb +201 -0
- data/nxxd.gemspec +37 -0
- metadata +51 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 5235dca5d1f46e13930f0d67076555a589a8966f4e83abf933a805ca722abbfe
|
4
|
+
data.tar.gz: 16ee0e67f7b9b8d765639470d7aff99c8e4aa71a5668493808589fcd42089ccd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b9b88cd360d0af386401df8eada33e03718790136ce709d4f5d74ea4f54311d2a22df54e7f6d157d6a8ed53a5d073ccf1958f40f582aa8d2cae3b4d7f74dc175
|
7
|
+
data.tar.gz: 3e6a4f1b49aeef9867e80b0b900b99951a6b37d53d4b8f1ee82d37f9d58f773355f2a72d651e5df734022d942d7673d0c7af76f384f5a8cd564eb69ff2b2dadc
|
data/LICENSE
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# BSD-2-clause license, extended by language use conditions
|
2
|
+
|
3
|
+
Copyright (C) 2025, Bertram Scharpf <software@bertram-scharpf.de>.
|
4
|
+
All rights reserved.
|
5
|
+
|
6
|
+
Redistribution and use in source and binary forms, with or without
|
7
|
+
modification, are permitted provided that the following conditions are
|
8
|
+
met:
|
9
|
+
|
10
|
+
* Redistributions of source code must retain the above copyright
|
11
|
+
notice, this list of conditions and the following disclaimer.
|
12
|
+
|
13
|
+
* Redistributions in binary form must reproduce the above copyright
|
14
|
+
notice, this list of conditions and the following disclaimer in
|
15
|
+
the documentation and/or other materials provided with the
|
16
|
+
distribution.
|
17
|
+
|
18
|
+
* Redistributions must not contain any clauses about anticipated
|
19
|
+
harassment or discrimination, nor must they be held in a so-called
|
20
|
+
"inclusive language". As far as German language is used, the
|
21
|
+
conditions mentioned below additionally apply.
|
22
|
+
|
23
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
24
|
+
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
25
|
+
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
26
|
+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
27
|
+
OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
28
|
+
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
29
|
+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
30
|
+
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
31
|
+
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
32
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
33
|
+
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
34
|
+
|
35
|
+
|
36
|
+
## Use of the German Language
|
37
|
+
|
38
|
+
Beim Gebrauch deutscher Sprache sind Weiterentwicklungen und
|
39
|
+
-verbreitungen nur gestattet unter Einhaltung sowie abermaligen
|
40
|
+
Einforderns folgender zusätzlicher Bedingungen:
|
41
|
+
|
42
|
+
* Keine Verwendung von sogenannter „geschlechtergerechter Sprache“,
|
43
|
+
also Anfügen von weiblichen Endungen mit Binnen-I, Sternchen,
|
44
|
+
Doppelpunkt, Unterstrich oder ähnlichem, oder Konstruktionen, die
|
45
|
+
den Sachverhalt falsch wiedergeben („Radfahrende“, „Studierende“).
|
46
|
+
|
47
|
+
* Keine Verwendung der „reformierten Rechtschreibung“ von 1996,
|
48
|
+
insbesondere Doppel-S am Silbenende, „plazieren“ mit T, sowie
|
49
|
+
Großschreibung von Wendungen wie „des weiteren“.
|
50
|
+
|
51
|
+
|
52
|
+
<!-- vim:set ft=markdown : -->
|
data/README.md
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
# Nxxd Hex Dump tool
|
2
|
+
|
3
|
+
Yet another Xxd reimplementation.
|
4
|
+
|
5
|
+
The original Xxd is part of the Vim editor (<https://www.vim.org>).
|
6
|
+
This one is written in plain Ruby.
|
7
|
+
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
```bash
|
12
|
+
sudo gem install nxxd
|
13
|
+
```
|
14
|
+
|
15
|
+
|
16
|
+
## Command line execution
|
17
|
+
|
18
|
+
Plain output:
|
19
|
+
|
20
|
+
```bash
|
21
|
+
echo hello | grep --color=yes -nH ll | nxxd
|
22
|
+
dd if=/dev/urandom bs=16 count=4 status=none | nxxd
|
23
|
+
```
|
24
|
+
|
25
|
+
The filename will be added as a comment, unless you explicitly ask to refrain
|
26
|
+
from that.
|
27
|
+
|
28
|
+
```bash
|
29
|
+
nxxd /bin/sleep 2>/dev/null | head
|
30
|
+
nxxd -p /bin/sleep 2>/dev/null | head
|
31
|
+
```
|
32
|
+
|
33
|
+
Repeated lines will be squeezed by default.
|
34
|
+
|
35
|
+
```bash
|
36
|
+
dd if=/dev/zero bs=16 count=4 status=none | nxxd
|
37
|
+
dd if=/dev/zero bs=16 count=4 status=none | nxxd -a
|
38
|
+
dd if=/dev/zero bs=16 count=4 status=none | nxxd -f
|
39
|
+
ruby -e 'print "xyz="*16' | nxxd
|
40
|
+
```
|
41
|
+
|
42
|
+
Reverse operation.
|
43
|
+
|
44
|
+
```bash
|
45
|
+
echo '42617a696e6761210a' | nxxd -r
|
46
|
+
echo hello | grep --color=yes -nH ll | nxxd | nxxd -r
|
47
|
+
```
|
48
|
+
|
49
|
+
C source code output.
|
50
|
+
|
51
|
+
```bash
|
52
|
+
nxxd -i someimage.png
|
53
|
+
```
|
54
|
+
|
55
|
+
Get help.
|
56
|
+
|
57
|
+
```bash
|
58
|
+
nxxd -h
|
59
|
+
```
|
60
|
+
|
61
|
+
|
62
|
+
## Ruby classes and methods
|
63
|
+
|
64
|
+
Here's an example:
|
65
|
+
|
66
|
+
```ruby
|
67
|
+
require "nxxd"
|
68
|
+
|
69
|
+
data = " !\"\#$%&'()*+,-./0123456789:;<=>?"
|
70
|
+
Nxxd::Dump.new.run data do |l| puts l end
|
71
|
+
```
|
72
|
+
|
73
|
+
Reverse operation allows free address jumping.
|
74
|
+
Both string and file output can be done.
|
75
|
+
|
76
|
+
```ruby
|
77
|
+
require "nxxd"
|
78
|
+
|
79
|
+
x = <<~EOT
|
80
|
+
0004: 204d 696c 6b79 2047 7265 656e 0a Milky Green
|
81
|
+
0000: 436f 6465 Code
|
82
|
+
EOT
|
83
|
+
|
84
|
+
s = Nxxd::Dump.reverse x
|
85
|
+
puts s.encoding, s.length, s.inspect
|
86
|
+
|
87
|
+
File.open "status", "w" do |f|
|
88
|
+
Nxxd::Dump.reverse x, f
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
92
|
+
|
93
|
+
## Colorization
|
94
|
+
|
95
|
+
There is no and there will be no color support. Pipe the output to your
|
96
|
+
favourite editor and use the syntax highlighting there.
|
97
|
+
|
98
|
+
If you are using Vim/Neovim, you might like the more elaborate syntax
|
99
|
+
highlighting included in this package [xxd.vim](./vim/syntax/xxd.vim).
|
100
|
+
|
101
|
+
|
102
|
+
## Copyright
|
103
|
+
|
104
|
+
* (C) 2025 Bertram Scharpf <software@bertram-scharpf.de>
|
105
|
+
* License: [BSD-2-Clause+](./LICENSE)
|
106
|
+
|
data/bin/nxxd
ADDED
@@ -0,0 +1,219 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#
|
4
|
+
# nxxd -- Hex dump tool
|
5
|
+
#
|
6
|
+
|
7
|
+
require "nxxd"
|
8
|
+
require "nxxd/version"
|
9
|
+
|
10
|
+
|
11
|
+
module Nxxd
|
12
|
+
|
13
|
+
class Application
|
14
|
+
|
15
|
+
NAME = "nxxd"
|
16
|
+
|
17
|
+
OPTIONS = {
|
18
|
+
"r" => [ :reverse, true, "Reverse operation, pack"],
|
19
|
+
"o" => [ :output, :NAME, "Output file (- = stdout)"],
|
20
|
+
"output" => "o",
|
21
|
+
"f" => [ :full, true, "Full output (no squeeze)"],
|
22
|
+
"full" => "f",
|
23
|
+
"a" => [ :full, false, "Abbreviate (squeeze duplicate lines)"],
|
24
|
+
"p" => [ :plain, true, "Plain output (no comments, no C variables)"],
|
25
|
+
"u" => [ :upper, true, "Upper case A-F"],
|
26
|
+
"upper" => "u",
|
27
|
+
"l" => [ :line_size, :NUM, "Line size"],
|
28
|
+
"line" => "l",
|
29
|
+
"d" => [ :addr_len, :NUM, "Address length"],
|
30
|
+
"addrs" => "d",
|
31
|
+
"i" => [ :cnums, true, "C-style number literals"],
|
32
|
+
"include" => "i",
|
33
|
+
"C" => [ :capitals, true, "Capitalize C variable names with -i"],
|
34
|
+
"capitalize" => "C",
|
35
|
+
"h" => [ :help, :help, "Print this help message"],
|
36
|
+
"help" => "h",
|
37
|
+
"v" => [ :version, :version, "Version information"],
|
38
|
+
"version" => "v",
|
39
|
+
}
|
40
|
+
|
41
|
+
OPT_ENV = "NXXD"
|
42
|
+
|
43
|
+
class Options
|
44
|
+
|
45
|
+
attr_reader :opts, :args
|
46
|
+
|
47
|
+
def initialize params
|
48
|
+
@opts, @args = {}, []
|
49
|
+
env = ENV[ OPT_ENV]
|
50
|
+
if env then
|
51
|
+
@params = env.split
|
52
|
+
until @params.empty? do
|
53
|
+
p = @params.shift
|
54
|
+
case p
|
55
|
+
when /^--/ then $'.empty? or set $'
|
56
|
+
when /^-/ then set_short $'
|
57
|
+
else set p
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
@params = params
|
62
|
+
until @params.empty? do
|
63
|
+
p = @params.shift
|
64
|
+
case p
|
65
|
+
when /^--/ then $'.empty? and break ; set $'
|
66
|
+
when /^-/ then set_short $'
|
67
|
+
else @args.push p
|
68
|
+
end
|
69
|
+
end
|
70
|
+
@args.concat @params
|
71
|
+
@params = nil
|
72
|
+
rescue StandardError
|
73
|
+
$stderr.puts $!
|
74
|
+
exit 1
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def set_short cont
|
80
|
+
@cont = cont
|
81
|
+
until @cont.empty? do
|
82
|
+
c = @cont.slice! 0
|
83
|
+
set c
|
84
|
+
end
|
85
|
+
ensure
|
86
|
+
@cont = nil
|
87
|
+
end
|
88
|
+
|
89
|
+
def set o
|
90
|
+
opt = loop do
|
91
|
+
d = OPTIONS[ o]
|
92
|
+
raise "Unknown option: #{o}" unless d
|
93
|
+
break d if Array === d
|
94
|
+
o = d
|
95
|
+
end
|
96
|
+
key, t, = opt
|
97
|
+
if Symbol === t then
|
98
|
+
type = type_repr t
|
99
|
+
if type then
|
100
|
+
arg = @cont.slice! 0..nil if @cont
|
101
|
+
arg = @params.shift if not arg or arg.empty?
|
102
|
+
arg = Integer arg if %i(NUM INT).include? type
|
103
|
+
else
|
104
|
+
send t
|
105
|
+
exit 0
|
106
|
+
end
|
107
|
+
else
|
108
|
+
arg = t
|
109
|
+
end
|
110
|
+
@opts[ key] = arg
|
111
|
+
end
|
112
|
+
|
113
|
+
def version
|
114
|
+
puts "#{NAME} -- #{VERSION}"
|
115
|
+
puts AUTHOR
|
116
|
+
puts "License: #{LICENSE}"
|
117
|
+
end
|
118
|
+
|
119
|
+
def help
|
120
|
+
version
|
121
|
+
puts
|
122
|
+
puts "Usage: #$0 [options] [ inputfile+ [ outputfile ] ]"
|
123
|
+
puts
|
124
|
+
OPTIONS.each { |opt,defn|
|
125
|
+
case defn
|
126
|
+
when String then
|
127
|
+
text = "= #{opt_repr defn}"
|
128
|
+
else
|
129
|
+
_, arg, text = *defn
|
130
|
+
type = type_repr arg if Symbol === arg
|
131
|
+
end
|
132
|
+
puts " %-10s %-10s %s" % [(opt_repr opt), type, text]
|
133
|
+
}
|
134
|
+
end
|
135
|
+
|
136
|
+
def type_repr type
|
137
|
+
type if type =~ /\A[A-Z_]+\z/
|
138
|
+
end
|
139
|
+
|
140
|
+
def opt_repr o
|
141
|
+
o.length == 1 ? "-#{o}" : "--#{o}"
|
142
|
+
end
|
143
|
+
|
144
|
+
end
|
145
|
+
|
146
|
+
def initialize params
|
147
|
+
o = Options.new params
|
148
|
+
@opts, @args = o.opts, o.args
|
149
|
+
@inputs = []
|
150
|
+
@inputs.push @args.shift
|
151
|
+
@output = (@opts.delete :output) || @args.pop
|
152
|
+
@inputs.push @args.shift until @args.empty?
|
153
|
+
end
|
154
|
+
|
155
|
+
def run
|
156
|
+
open_output do |o|
|
157
|
+
if @opts[ :reverse] then
|
158
|
+
open_inputs do |f|
|
159
|
+
Dump.reverse f, o
|
160
|
+
end
|
161
|
+
else
|
162
|
+
cls = (@opts.delete :cnums) ? DumpNums : Dump
|
163
|
+
open_inputs do |f|
|
164
|
+
d = cls.new **@opts
|
165
|
+
d.run f do |l| o.puts l end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
rescue ArgumentError
|
170
|
+
$stderr.puts "Incompatible Options: #@opts"
|
171
|
+
1
|
172
|
+
rescue Errno::EPIPE
|
173
|
+
$stderr.puts "Broken pipe. Stop."
|
174
|
+
rescue Errno::ESPIPE
|
175
|
+
$stderr.puts "Seek not possible. Specify an output file."
|
176
|
+
2
|
177
|
+
rescue Interrupt
|
178
|
+
$stderr.puts "Interrupted."
|
179
|
+
1
|
180
|
+
rescue
|
181
|
+
$stderr.puts "Error: #$! (#{$!.class})"
|
182
|
+
1
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
def open_inputs
|
188
|
+
plain = @opts.delete :plain
|
189
|
+
@inputs.each do |i|
|
190
|
+
i = nil if i == "-"
|
191
|
+
@opts[ :input] = i unless plain
|
192
|
+
if i then
|
193
|
+
File.open i, "r" do |f|
|
194
|
+
yield f
|
195
|
+
end
|
196
|
+
else
|
197
|
+
yield $stdin
|
198
|
+
end
|
199
|
+
ensure
|
200
|
+
@opts.delete :input
|
201
|
+
end
|
202
|
+
nil
|
203
|
+
end
|
204
|
+
|
205
|
+
def open_output
|
206
|
+
o = @output unless @output == "-"
|
207
|
+
if o then
|
208
|
+
File.open o, "w" do |o| yield o end
|
209
|
+
else
|
210
|
+
yield $stdout
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
end
|
215
|
+
|
216
|
+
exit (Application.new $*).run.to_i
|
217
|
+
|
218
|
+
end
|
219
|
+
|
data/lib/nxxd/nvim.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
#
|
2
|
+
# nxxd/nvim.rb -- Neovim commands
|
3
|
+
#
|
4
|
+
|
5
|
+
require "nxxd"
|
6
|
+
|
7
|
+
(Neovim::Client === $vim rescue false) or
|
8
|
+
raise "This file must be required from inside Neovim using the 'nvim' Rubygem."
|
9
|
+
|
10
|
+
|
11
|
+
[
|
12
|
+
"command -nargs=? -bang -complete=file -bar HexDump call rubyeval('Nxxd::Nvim.dump<bang> %q|<args>|')",
|
13
|
+
"command -nargs=? -range=% -bang -complete=file -bar HexPack call rubyeval('Nxxd::Nvim.pack<bang> %q|<args>|, <line1>..<line2>')",
|
14
|
+
].each { |c| $vim.command c }
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
module Kernel
|
19
|
+
class <<self
|
20
|
+
def popen_outerr a
|
21
|
+
ro, wo = IO.pipe
|
22
|
+
re, we = IO.pipe
|
23
|
+
fork do
|
24
|
+
ro.close
|
25
|
+
re.close
|
26
|
+
STDOUT.reopen wo
|
27
|
+
STDERR.reopen we
|
28
|
+
exec a
|
29
|
+
end
|
30
|
+
wo.close
|
31
|
+
we.close
|
32
|
+
yield ro, re
|
33
|
+
Process.waitpid
|
34
|
+
ensure
|
35
|
+
ro.close
|
36
|
+
re.close
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
module Nxxd
|
43
|
+
|
44
|
+
module Nvim
|
45
|
+
|
46
|
+
class <<self
|
47
|
+
|
48
|
+
def dump a
|
49
|
+
a ||= $vim.get_name 0
|
50
|
+
File.open a do |f|
|
51
|
+
dump_file a, f
|
52
|
+
end
|
53
|
+
$vim.get_current_buf.set_var "origfile", a
|
54
|
+
end
|
55
|
+
|
56
|
+
def dump! a
|
57
|
+
Kernel.popen_outerr a do |ro,re|
|
58
|
+
dump_file a, ro
|
59
|
+
e = re.read.lines.map { |x| x.chomp! ; "# #{x}" }
|
60
|
+
$vim.put e, "l", false, true
|
61
|
+
end
|
62
|
+
$?.success? or $vim.put [ "### Exit code: #{$?.exitstatus}"], "l", false, true
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def dump_file a, f
|
68
|
+
$vim.command "enew"
|
69
|
+
$vim.set_option filetype: "xxd", buftype: "nofile"
|
70
|
+
$vim.get_current_buf.set_name "[hex: #{a}]"
|
71
|
+
(Dump.new input: a).run f do |l|
|
72
|
+
$vim.put [l], "l", false, true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
public
|
77
|
+
|
78
|
+
def pack a, range
|
79
|
+
pack_check a, range do |d|
|
80
|
+
raise "File exists. Overwrite with '!'." if File.exist? d
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def pack! a, range
|
85
|
+
pack_check a, range do || end
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def pack_check a, range
|
91
|
+
b = $vim.get_current_buf
|
92
|
+
a = a.notempty?
|
93
|
+
a ||= b.get_var "origfile" rescue nil
|
94
|
+
a or raise "No file name given."
|
95
|
+
yield a
|
96
|
+
File.open a, "w" do |f|
|
97
|
+
r = Range.new b, range
|
98
|
+
Nxxd::Dump.reverse r, f
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
class Range
|
105
|
+
def initialize buf, range
|
106
|
+
@buf, @range = buf, range
|
107
|
+
end
|
108
|
+
def each_line &block
|
109
|
+
@buf.each @range, &block
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
data/lib/nxxd/version.rb
ADDED
data/lib/nxxd.rb
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
#
|
2
|
+
# nxxd.rb -- Hex Dump Tool
|
3
|
+
#
|
4
|
+
|
5
|
+
|
6
|
+
module Nxxd
|
7
|
+
|
8
|
+
module ReadChunks
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def read_chunks input
|
13
|
+
case input
|
14
|
+
when String then
|
15
|
+
i = 0
|
16
|
+
while i < input.bytesize do
|
17
|
+
b = input.byteslice i, @line_size
|
18
|
+
yield b
|
19
|
+
i += @line_size
|
20
|
+
end
|
21
|
+
else
|
22
|
+
loop do
|
23
|
+
b = input.read @line_size
|
24
|
+
break unless b
|
25
|
+
yield b
|
26
|
+
break if b.length < @line_size
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
class Dump
|
34
|
+
|
35
|
+
include ReadChunks
|
36
|
+
|
37
|
+
LINE_SIZE = 16
|
38
|
+
ADDR_FMT = "%%0%dx:"
|
39
|
+
|
40
|
+
def initialize full: nil, upper: false, line_size: nil, addr_len: nil, input: nil
|
41
|
+
@full = full
|
42
|
+
@input = input
|
43
|
+
@line_size = line_size||LINE_SIZE
|
44
|
+
@addr_fmt = ADDR_FMT % (addr_len||8)
|
45
|
+
@nib_fmt = "%02x"
|
46
|
+
if upper then
|
47
|
+
@addr_fmt.upcase!
|
48
|
+
@nib_fmt.upcase!
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def run input
|
53
|
+
addr = 0
|
54
|
+
prev, repeat = nil, false
|
55
|
+
yield "# #@input" if @input
|
56
|
+
read_chunks input do |b|
|
57
|
+
if b == prev and not @full then
|
58
|
+
unless repeat then
|
59
|
+
yield "*"
|
60
|
+
repeat = true
|
61
|
+
end
|
62
|
+
else
|
63
|
+
r = @addr_fmt % addr
|
64
|
+
r << " "
|
65
|
+
h = b.unpack "C*"
|
66
|
+
sp = false
|
67
|
+
@line_size.times {
|
68
|
+
x = h.shift
|
69
|
+
r << (x ? @nib_fmt % x : " ")
|
70
|
+
r << " " if sp
|
71
|
+
sp = !sp
|
72
|
+
}
|
73
|
+
r << " " << (b.gsub /[^ -~]/, ".")
|
74
|
+
yield r
|
75
|
+
prev, repeat = b, false
|
76
|
+
end
|
77
|
+
addr += b.size
|
78
|
+
end
|
79
|
+
yield @addr_fmt % addr
|
80
|
+
nil
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
class <<self
|
85
|
+
|
86
|
+
def reverse input, output = nil
|
87
|
+
output ||= ""
|
88
|
+
o = String === output ? (WriteChunksString.new output) : output
|
89
|
+
o.set_encoding Encoding::ASCII_8BIT
|
90
|
+
r, repeat = nil, false
|
91
|
+
input.each_line { |l|
|
92
|
+
l.chomp!
|
93
|
+
case l
|
94
|
+
when /^\s*(?:#|$)/ then nil
|
95
|
+
when /^\*/ then repeat = true
|
96
|
+
when /^(?:(\h+):)?\s*((?:\h\h ?)*)/ then
|
97
|
+
addr, nibs = $~.captures
|
98
|
+
if addr then
|
99
|
+
addr = $1.to_i 0x10
|
100
|
+
if repeat then
|
101
|
+
loop do
|
102
|
+
s = addr - o.tell
|
103
|
+
break if s <= 0
|
104
|
+
o.write s >= r.length ? r : r[ 0, s]
|
105
|
+
end
|
106
|
+
repeat = false
|
107
|
+
else
|
108
|
+
end
|
109
|
+
o.seek addr
|
110
|
+
end
|
111
|
+
r = (nibs.scan /\h\h/).map { |x| x.to_i 0x10 }.pack "C*"
|
112
|
+
o.write r
|
113
|
+
else
|
114
|
+
raise "Uninterpretable hex dump: #{l.chomp}"
|
115
|
+
end
|
116
|
+
}
|
117
|
+
output
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
class DumpNums
|
125
|
+
|
126
|
+
include ReadChunks
|
127
|
+
|
128
|
+
LINE_SIZE = 12
|
129
|
+
|
130
|
+
def initialize upper: false, line_size: nil, capitals: nil, input: nil
|
131
|
+
@line_size = line_size||LINE_SIZE
|
132
|
+
@nib_fmt = "%#04x"
|
133
|
+
@nib_fmt.upcase! if upper
|
134
|
+
if input then
|
135
|
+
@varname = input.dup
|
136
|
+
@varname.insert 0, "__" if @varname =~ /\A\d/
|
137
|
+
@varname.gsub! /[^a-zA-Z0-9]/, "_"
|
138
|
+
@varname.upcase! if capitals
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def run input, &block
|
143
|
+
if @varname then
|
144
|
+
yield "unsigned char #@varname[] = {"
|
145
|
+
len = run_plain input, &block
|
146
|
+
yield "};"
|
147
|
+
yield "unsigned int #@varname\_len = %d;" % len
|
148
|
+
else
|
149
|
+
run_plain input, &block
|
150
|
+
end
|
151
|
+
nil
|
152
|
+
end
|
153
|
+
|
154
|
+
private
|
155
|
+
|
156
|
+
def run_plain input
|
157
|
+
prev, len = nil, 0
|
158
|
+
read_chunks input do |b|
|
159
|
+
if prev then
|
160
|
+
prev << ","
|
161
|
+
yield prev
|
162
|
+
end
|
163
|
+
prev = " " + ((b.unpack "C*").map { |x| @nib_fmt % x }.join ", ")
|
164
|
+
len += b.bytesize
|
165
|
+
end
|
166
|
+
yield prev if prev
|
167
|
+
len
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
class WriteChunksString
|
173
|
+
def initialize str
|
174
|
+
@str = str
|
175
|
+
end
|
176
|
+
def set_encoding enc
|
177
|
+
@str.force_encoding enc
|
178
|
+
end
|
179
|
+
def tell ; @pos || @str.length ; end
|
180
|
+
def seek pos
|
181
|
+
s = pos - @str.length
|
182
|
+
if s >= 0 then
|
183
|
+
s.times { @str << "\0".b }
|
184
|
+
else
|
185
|
+
@pos = pos
|
186
|
+
end
|
187
|
+
end
|
188
|
+
def write b
|
189
|
+
if @pos then
|
190
|
+
l = b.length
|
191
|
+
@str[ @pos, l] = b
|
192
|
+
@pos += l
|
193
|
+
@pos = nil if @pos >= @str.length
|
194
|
+
else
|
195
|
+
@str << b
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
data/nxxd.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#
|
2
|
+
# nxxd.gemspec -- Gem Specification
|
3
|
+
#
|
4
|
+
|
5
|
+
require "./lib/nxxd/version"
|
6
|
+
|
7
|
+
|
8
|
+
Gem::Specification.new do |s|
|
9
|
+
s.name = "nxxd"
|
10
|
+
s.version = Nxxd::VERSION
|
11
|
+
s.platform = Gem::Platform::RUBY
|
12
|
+
s.required_ruby_version = ">= 3.1"
|
13
|
+
s.summary = "Hex Dump Tool"
|
14
|
+
s.description = <<~EOT
|
15
|
+
Yet another Xxd reimplementation.
|
16
|
+
EOT
|
17
|
+
s.license = "LicenseRef-LICENSE"
|
18
|
+
|
19
|
+
s.authors,
|
20
|
+
s.email = (<<~EOT.scan /(\S.*\S)\s*<(.*)>/).transpose
|
21
|
+
Bertram Scharpf <software@bertram-scharpf.de>
|
22
|
+
EOT
|
23
|
+
|
24
|
+
s.homepage = "https://github.com/BertramScharpf/ruby-nxxd"
|
25
|
+
|
26
|
+
s.requirements = "Just Ruby"
|
27
|
+
|
28
|
+
s.require_paths = %w(lib)
|
29
|
+
s.files = Dir[ "lib/**/*.rb", "bin/*", ] +
|
30
|
+
%w(LICENSE README.md nxxd.gemspec)
|
31
|
+
s.bindir = "bin"
|
32
|
+
s.extensions = %w()
|
33
|
+
s.executables = %w(nxxd)
|
34
|
+
s.extra_rdoc_files = %w()
|
35
|
+
|
36
|
+
end
|
37
|
+
|
metadata
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: nxxd
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.0'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Bertram Scharpf
|
8
|
+
bindir: bin
|
9
|
+
cert_chain: []
|
10
|
+
date: 2025-01-30 00:00:00.000000000 Z
|
11
|
+
dependencies: []
|
12
|
+
description: 'Yet another Xxd reimplementation.
|
13
|
+
|
14
|
+
'
|
15
|
+
email:
|
16
|
+
- software@bertram-scharpf.de
|
17
|
+
executables:
|
18
|
+
- nxxd
|
19
|
+
extensions: []
|
20
|
+
extra_rdoc_files: []
|
21
|
+
files:
|
22
|
+
- LICENSE
|
23
|
+
- README.md
|
24
|
+
- bin/nxxd
|
25
|
+
- lib/nxxd.rb
|
26
|
+
- lib/nxxd/nvim.rb
|
27
|
+
- lib/nxxd/version.rb
|
28
|
+
- nxxd.gemspec
|
29
|
+
homepage: https://github.com/BertramScharpf/ruby-nxxd
|
30
|
+
licenses:
|
31
|
+
- LicenseRef-LICENSE
|
32
|
+
metadata: {}
|
33
|
+
rdoc_options: []
|
34
|
+
require_paths:
|
35
|
+
- lib
|
36
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.1'
|
41
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
requirements:
|
47
|
+
- Just Ruby
|
48
|
+
rubygems_version: 3.6.2
|
49
|
+
specification_version: 4
|
50
|
+
summary: Hex Dump Tool
|
51
|
+
test_files: []
|