Skip to content

Commit 16e16a9

Browse files
committed
binfmt: add HexDump
Add a function that formats a []byte slice as a hex-encoded, wrapped string and displays the contained ASCII characters (like hexdump).
1 parent 56cdd34 commit 16e16a9

File tree

3 files changed

+150
-0
lines changed

3 files changed

+150
-0
lines changed

internal/binfmt/hexdump.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package binfmt
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"io"
7+
"strconv"
8+
)
9+
10+
// HexDump returns a string representation of the data in a hex dump format.
11+
// The width is the number of bytes per line.
12+
func HexDump(data []byte, width int, includeOffsets bool) string {
13+
var buf bytes.Buffer
14+
FHexDump(&buf, data, width, includeOffsets)
15+
return buf.String()
16+
}
17+
18+
// FHexDump writes a hex dump of the data to w.
19+
func FHexDump(w io.Writer, data []byte, width int, includeOffsets bool) {
20+
offsetFormatWidth := len(fmt.Sprintf("%x", max(1, len(data)-1)))
21+
offsetFormatStr := "%0" + strconv.Itoa(offsetFormatWidth) + "x"
22+
for i := 0; i < len(data); i += width {
23+
if includeOffsets {
24+
fmt.Fprintf(w, offsetFormatStr+": ", i)
25+
}
26+
for j := 0; j < width; j++ {
27+
if j%4 == 0 {
28+
fmt.Fprint(w, " ")
29+
}
30+
if i+j >= len(data) {
31+
fmt.Fprintf(w, " ")
32+
} else {
33+
fmt.Fprintf(w, "%02x", data[i+j])
34+
}
35+
}
36+
37+
fmt.Fprint(w, " | ")
38+
for j := 0; j < width; j++ {
39+
if i+j >= len(data) {
40+
break
41+
}
42+
if j%4 == 0 {
43+
fmt.Fprint(w, " ")
44+
}
45+
if data[i+j] < 32 || data[i+j] > 126 {
46+
fmt.Fprint(w, ".")
47+
} else {
48+
fmt.Fprintf(w, "%c", data[i+j])
49+
}
50+
}
51+
fmt.Fprintln(w)
52+
}
53+
}

internal/binfmt/hexdump_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package binfmt
2+
3+
import (
4+
"fmt"
5+
"os"
6+
"testing"
7+
8+
"github.com/cockroachdb/datadriven"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
func TestHexFmt(t *testing.T) {
13+
var width, offset, length int
14+
datadriven.RunTest(t, "testdata/hexdump", func(t *testing.T, d *datadriven.TestData) string {
15+
width = 16
16+
d.ScanArgs(t, "pos", &offset, &length)
17+
d.MaybeScanArgs(t, "width", &width)
18+
switch d.Cmd {
19+
case "read-file":
20+
path := d.CmdArgs[0].String()
21+
data, err := os.ReadFile(path)
22+
require.NoError(t, err)
23+
return HexDump(data[offset:offset+length], width, d.HasArg("include-offsets"))
24+
case "sequential":
25+
var size int
26+
d.ScanArgs(t, "size", &size)
27+
data := make([]byte, size)
28+
for i := 0; i < size; i++ {
29+
data[i] = byte(i)
30+
}
31+
return HexDump(data, width, d.HasArg("include-offsets"))
32+
default:
33+
return fmt.Sprintf("unknown command: %s", d.Cmd)
34+
}
35+
})
36+
}

internal/binfmt/testdata/hexdump

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
sequential size=512 include-offsets width=16 pos=(0,512)
2+
----
3+
000: 00010203 04050607 08090a0b 0c0d0e0f | .... .... .... ....
4+
010: 10111213 14151617 18191a1b 1c1d1e1f | .... .... .... ....
5+
020: 20212223 24252627 28292a2b 2c2d2e2f | !"# $%&' ()*+ ,-./
6+
030: 30313233 34353637 38393a3b 3c3d3e3f | 0123 4567 89:; <=>?
7+
040: 40414243 44454647 48494a4b 4c4d4e4f | @ABC DEFG HIJK LMNO
8+
050: 50515253 54555657 58595a5b 5c5d5e5f | PQRS TUVW XYZ[ \]^_
9+
060: 60616263 64656667 68696a6b 6c6d6e6f | `abc defg hijk lmno
10+
070: 70717273 74757677 78797a7b 7c7d7e7f | pqrs tuvw xyz{ |}~.
11+
080: 80818283 84858687 88898a8b 8c8d8e8f | .... .... .... ....
12+
090: 90919293 94959697 98999a9b 9c9d9e9f | .... .... .... ....
13+
0a0: a0a1a2a3 a4a5a6a7 a8a9aaab acadaeaf | .... .... .... ....
14+
0b0: b0b1b2b3 b4b5b6b7 b8b9babb bcbdbebf | .... .... .... ....
15+
0c0: c0c1c2c3 c4c5c6c7 c8c9cacb cccdcecf | .... .... .... ....
16+
0d0: d0d1d2d3 d4d5d6d7 d8d9dadb dcdddedf | .... .... .... ....
17+
0e0: e0e1e2e3 e4e5e6e7 e8e9eaeb ecedeeef | .... .... .... ....
18+
0f0: f0f1f2f3 f4f5f6f7 f8f9fafb fcfdfeff | .... .... .... ....
19+
100: 00010203 04050607 08090a0b 0c0d0e0f | .... .... .... ....
20+
110: 10111213 14151617 18191a1b 1c1d1e1f | .... .... .... ....
21+
120: 20212223 24252627 28292a2b 2c2d2e2f | !"# $%&' ()*+ ,-./
22+
130: 30313233 34353637 38393a3b 3c3d3e3f | 0123 4567 89:; <=>?
23+
140: 40414243 44454647 48494a4b 4c4d4e4f | @ABC DEFG HIJK LMNO
24+
150: 50515253 54555657 58595a5b 5c5d5e5f | PQRS TUVW XYZ[ \]^_
25+
160: 60616263 64656667 68696a6b 6c6d6e6f | `abc defg hijk lmno
26+
170: 70717273 74757677 78797a7b 7c7d7e7f | pqrs tuvw xyz{ |}~.
27+
180: 80818283 84858687 88898a8b 8c8d8e8f | .... .... .... ....
28+
190: 90919293 94959697 98999a9b 9c9d9e9f | .... .... .... ....
29+
1a0: a0a1a2a3 a4a5a6a7 a8a9aaab acadaeaf | .... .... .... ....
30+
1b0: b0b1b2b3 b4b5b6b7 b8b9babb bcbdbebf | .... .... .... ....
31+
1c0: c0c1c2c3 c4c5c6c7 c8c9cacb cccdcecf | .... .... .... ....
32+
1d0: d0d1d2d3 d4d5d6d7 d8d9dadb dcdddedf | .... .... .... ....
33+
1e0: e0e1e2e3 e4e5e6e7 e8e9eaeb ecedeeef | .... .... .... ....
34+
1f0: f0f1f2f3 f4f5f6f7 f8f9fafb fcfdfeff | .... .... .... ....
35+
36+
read-file ../../testdata/db-stage-4/000004.sst pos=(10,200) include-offsets
37+
----
38+
00: 00000000 0209057a 010c0000 00000000 | .... ...z .... ....
39+
10: 74687265 65000b04 666f6f01 0d000000 | thre e... foo. ....
40+
20: 00000066 6f757200 00000001 00000000 | ...f our. .... ....
41+
30: 49ac4e14 00090267 11ffffff ffffffff | I.N. ...g .... ....
42+
40: 00390000 00000100 00000074 8d30d700 | .9.. .... ...t .0..
43+
50: 23017065 62626c65 2e726177 2e706f69 | #.pe bble .raw .poi
44+
60: 6e742d74 6f6d6273 746f6e65 2e6b6579 | nt-t ombs tone .key
45+
70: 2e73697a 65030024 04726f63 6b736462 | .siz e..$ .roc ksdb
46+
80: 2e626c6f 636b2e62 61736564 2e746162 | .blo ck.b ased .tab
47+
90: 6c652e69 6e646578 2e747970 65000000 | le.i ndex .typ e...
48+
a0: 001a1001 70726566 69782e66 696c7465 | .... pref ix.f ilte
49+
b0: 72696e67 301a1301 77686f6c 652e6b65 | ring 0... whol e.ke
50+
c0: 792e6669 6c746572 | y.fi lter
51+
52+
read-file ../../testdata/db-stage-4/MANIFEST-000006 pos=(0,256) include-offsets width=32
53+
----
54+
00: 9ef1d093 22000101 1a6c6576 656c6462 2e427974 65776973 65436f6d 70617261 | .... "... .lev eldb .Byt ewis eCom para
55+
20: 746f7202 02030704 001cf77b d52d0001 02050306 040e6700 04c5050b 62617200 | tor. .... ...{ .-.. .... ..g. .... bar.
56+
40: 0e000000 0000000b 666f6f01 0d000000 0000000c 0e060585 a6b8ab06 01000000 | .... .... foo. .... .... .... .... ....
57+
60: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | .... .... .... .... .... .... .... ....
58+
80: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | .... .... .... .... .... .... .... ....
59+
a0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | .... .... .... .... .... .... .... ....
60+
c0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | .... .... .... .... .... .... .... ....
61+
e0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 | .... .... .... .... .... .... .... ....

0 commit comments

Comments
 (0)