Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Display binary #702

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/setup-go@v3
with:
go-version: "1.20.4"
go-version: "1.20.5"
- uses: actions/checkout@v3
- uses: golangci/golangci-lint-action@v3
with:
Expand Down Expand Up @@ -47,7 +47,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: "1.20.4"
go-version: "1.20.5"
- name: Test
env:
GOARCH: ${{ matrix.goarch }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-go@v3
with:
go-version: "1.20.4"
go-version: "1.20.5"
- uses: goreleaser/goreleaser-action@v2
with:
distribution: goreleaser
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# bump: docker-golang /FROM golang:([\d.]+)/ docker:golang|^1
FROM golang:1.20.4-bullseye AS base
FROM golang:1.20.5-bullseye AS base

# expect is used to test cli
RUN \
Expand Down
8 changes: 4 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ require (
// bump: gomod-golang-x-crypto /golang\.org\/x\/crypto v(.*)/ https://github.com/golang/crypto.git|^0
// bump: gomod-golang-x-crypto command go get -d golang.org/x/crypto@v$LATEST && go mod tidy
// bump: gomod-golang-x-crypto link "Tags" https://github.com/golang/crypto/tags
golang.org/x/crypto v0.9.0
golang.org/x/crypto v0.10.0

// has no tags
// go get -d golang.org/x/exp@master && go mod tidy
Expand All @@ -61,12 +61,12 @@ require (
// bump: gomod-golang-x-net /golang\.org\/x\/net v(.*)/ https://github.com/golang/net.git|^0
// bump: gomod-golang-x-net command go get -d golang.org/x/net@v$LATEST && go mod tidy
// bump: gomod-golang-x-net link "Tags" https://github.com/golang/net/tags
golang.org/x/net v0.10.0
golang.org/x/net v0.11.0

// bump: gomod-golang/text /golang\.org\/x\/text v(.*)/ https://github.com/golang/text.git|^0
// bump: gomod-golang/text command go get -d golang.org/x/text@v$LATEST && go mod tidy
// bump: gomod-golang/text link "Source diff $CURRENT..$LATEST" https://github.com/golang/text/compare/v$CURRENT..v$LATEST
golang.org/x/text v0.9.0
golang.org/x/text v0.10.0

// bump: gomod-gopkg.in/yaml.v3 /gopkg\.in\/yaml\.v3 v(.*)/ https://github.com/go-yaml/yaml.git|^3
// bump: gomod-gopkg.in/yaml.v3 command go get -d gopkg.in/yaml.v3@v$LATEST && go mod tidy
Expand All @@ -78,6 +78,6 @@ require (
github.com/itchyny/timefmt-go v0.1.5 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/sys v0.9.0 // indirect
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
)
16 changes: 8 additions & 8 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,18 @@ github.com/wader/gojq v0.12.1-0.20230529153812-b7e613069119 h1:9GNJxrBtaN5wHFGap
github.com/wader/gojq v0.12.1-0.20230529153812-b7e613069119/go.mod h1:jQY39j9tgky+JYcJrKNz5OYTe/sPDAw7FvVj13JGqVk=
github.com/wader/readline v0.0.0-20230307172220-bcb7158e7448 h1:AzpBtmgdXa3uznrb3esNeEoaLqtNEwckRmaUH0qWD6w=
github.com/wader/readline v0.0.0-20230307172220-bcb7158e7448/go.mod h1:Zgz8IJWvJoe7NK23CCPpC109XMCqJCpUhpHcnnA4XaM=
golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201 h1:BEABXpNXLEz0WxtA+6CQIz2xkg80e+1zrhWyMcq8VzE=
golang.org/x/exp v0.0.0-20230131160201-f062dba9d201/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/sys v0.0.0-20220627191245-f75cf1eec38b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
Expand Down
108 changes: 76 additions & 32 deletions pkg/interp/dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"github.com/wader/fq/internal/binwriter"
"github.com/wader/fq/internal/bitioex"
"github.com/wader/fq/internal/columnwriter"
"github.com/wader/fq/internal/hexpairwriter"
"github.com/wader/fq/internal/mathex"
"github.com/wader/fq/pkg/bitio"
"github.com/wader/fq/pkg/decode"
Expand Down Expand Up @@ -72,6 +73,7 @@ func dumpEx(v *decode.Value, ctx *dumpCtx, depth int, rootV *decode.Value, rootD
cprint := func(c int, a ...any) {
fmt.Fprint(cw.Columns[c], a...)
}
// cfmt: column i fmt.fprintf
cfmt := func(c int, format string, a ...any) {
fmt.Fprintf(cw.Columns[c], format, a...)
}
Expand Down Expand Up @@ -118,7 +120,9 @@ func dumpEx(v *decode.Value, ctx *dumpCtx, depth int, rootV *decode.Value, rootD

// show address bar on root, nested root and format change
if depth == 0 || v.IsRoot || v.Format != nil {
// write header: 00 01 02 03 04
cfmt(colHex, "%s", deco.DumpHeader.F(ctx.hexHeader))
// write header: 012345
cfmt(colASCII, "%s", deco.DumpHeader.F(ctx.asciiHeader))

if willDisplayData {
Expand Down Expand Up @@ -188,6 +192,10 @@ func dumpEx(v *decode.Value, ctx *dumpCtx, depth int, rootV *decode.Value, rootD

cprint(colField, "\n")

// --------------------------------------------------
// Error handling
// --------------------------------------------------

if valueErr != nil {
var printErrs func(depth int, err error)
printErrs = func(depth int, err error) {
Expand Down Expand Up @@ -223,24 +231,33 @@ func dumpEx(v *decode.Value, ctx *dumpCtx, depth int, rootV *decode.Value, rootD
printErrs(depth, valueErr)
}

// --------------------------------------------------
// For a given field, compute various helper variables
// --------------------------------------------------

rootBitLen, err := bitioex.Len(rootV.RootReader)
if err != nil {
return err
}

bufferLastBit := rootBitLen - 1
startBit := innerRange.Start
stopBit := innerRange.Stop() - 1
sizeBits := innerRange.Len
lastDisplayBit := stopBit
startBit := innerRange.Start // field's start bit index (for entire file)
stopBit := innerRange.Stop() - 1 // field's end bit index (for entire file); inclusive
sizeBits := innerRange.Len // field's bit length (1, 8, 16, 32, ...)

if opts.DisplayBytes > 0 && sizeBits > int64(opts.DisplayBytes)*8 {
lastDisplayBit = startBit + (int64(opts.DisplayBytes)*8 - 1)
if lastDisplayBit%(int64(opts.LineBytes)*8) != 0 {
lastDisplayBit += (int64(opts.LineBytes) * 8) - lastDisplayBit%(int64(opts.LineBytes)*8) - 1
// determine lastDisplayBit:
// sometimes the field's bit length overflows the max width of a line;
// cut off the overflow in such cases.
lastDisplayBit := stopBit
displayBits := int64(opts.DisplayBytes) * 8
lineBits := int64(opts.LineBytes) * 8
if opts.DisplayBytes > 0 && sizeBits > displayBits {
lastDisplayBit = startBit + (displayBits - 1)
if lastDisplayBit%lineBits != 0 {
lastDisplayBit += lineBits - lastDisplayBit%lineBits - 1
}

if lastDisplayBit > stopBit || stopBit-lastDisplayBit <= int64(opts.LineBytes)*8 {
if lastDisplayBit > stopBit || stopBit-lastDisplayBit <= lineBits {
lastDisplayBit = stopBit
}
}
Expand Down Expand Up @@ -270,12 +287,17 @@ func dumpEx(v *decode.Value, ctx *dumpCtx, depth int, rootV *decode.Value, rootD
startLineByte := startLine * int64(opts.LineBytes)
lastDisplayLine := lastDisplayByte / int64(opts.LineBytes)

// --------------------------------------------------
// Ouput Data
// --------------------------------------------------

// has length and is not compound or a collapsed struct/array (max depth)
if willDisplayData {
// write: 0x00012 (example address)
cfmt(colAddr, "%s%s\n",
rootIndent, deco.DumpAddr.F(mathex.PadFormatInt(startLineByte, opts.Addrbase, true, addrWidth)))

vBR, err := bitioex.Range(rootV.RootReader, startByte*4, displaySizeBits)
vBR1, err := bitioex.Range(rootV.RootReader, startByte*8, displaySizeBits)
if err != nil {
return err
}
Expand All @@ -286,29 +308,38 @@ func dumpEx(v *decode.Value, ctx *dumpCtx, depth int, rootV *decode.Value, rootD
}

addrLines := lastDisplayLine - startLine + 1
// hexpairFn := func(b byte) string { return deco.ByteColor(b).Wrap(hexpairwriter.Pair(b)) }
hexpairFn := func(b byte) string { return deco.ByteColor(b).Wrap(hexpairwriter.Pair(b)) }
binFn := func(b byte) string { return deco.ByteColor(b).Wrap(string("01"[int(b)])) }
asciiFn := func(b byte) string { return deco.ByteColor(b).Wrap(asciiwriter.SafeASCII(b)) }

hexBR, err := bitio.CloneReadSeeker(vBR2)
if err != nil {
return err
}
// if _, err := bitioex.CopyBitsBuffer(
// hexpairwriter.New(cw.Columns[colHex], opts.LineBytes, int(startLineByteOffset), hexpairFn),
// hexBR,
// buf); err != nil {
// return err
// }

if _, err := bitio.CopyBuffer(
binwriter.New(cw.Columns[colHex], opts.LineBytes*8, int(startLineBitOffset), binFn),
hexBR,
buf); err != nil {
return err
switch opts.Base {
case 16:
// write: 89 50 4e 47 0d 0a 1a 0a
hexBR, err := bitio.CloneReadSeeker(vBR1)
if err != nil {
return err
}
if _, err := bitioex.CopyBitsBuffer(
hexpairwriter.New(cw.Columns[colHex], opts.LineBytes, int(startLineByteOffset), hexpairFn),
hexBR,
buf); err != nil {
return err
}
case 2:
// write: 100010010101000
hexBR, err := bitio.CloneReadSeeker(vBR2)
if err != nil {
return err
}
if _, err := bitio.CopyBuffer(
binwriter.New(cw.Columns[colHex], opts.LineBytes*8, int(startLineBitOffset), binFn),
hexBR,
buf); err != nil {
return err
}
}

asciiBR, err := bitio.CloneReadSeeker(vBR)
// write: .PNG....
asciiBR, err := bitio.CloneReadSeeker(vBR1)
if err != nil {
return err
}
Expand Down Expand Up @@ -383,7 +414,13 @@ func dump(v *decode.Value, w io.Writer, opts *Options) error {
}

addrColumnWidth := maxAddrIndentWidth
hexColumnWidth := opts.LineBytes * 8
var hexColumnWidth int
switch opts.Base {
case 16:
hexColumnWidth = opts.LineBytes*3 - 1
case 2:
hexColumnWidth = opts.LineBytes * 8
}
asciiColumnWidth := opts.LineBytes
treeColumnWidth := -1
// TODO: set with and truncate/wrap properly
Expand All @@ -406,11 +443,18 @@ func dump(v *decode.Value, w io.Writer, opts *Options) error {

var hexHeader string
var asciiHeader string
var spaceLength int
switch opts.Base {
case 16:
spaceLength = 1
case 2:
spaceLength = 8 - 2 // TODO: adapt for wider screens
}
for i := 0; i < opts.LineBytes; i++ {
s := mathex.PadFormatInt(int64(i), opts.Addrbase, false, 2)
hexHeader += s
if i < opts.LineBytes-1 {
hexHeader += " "
if spaceLength > 1 || i < opts.LineBytes-1 {
hexHeader += strings.Repeat(" ", spaceLength)
}
asciiHeader += s[len(s)-1:]
}
Expand Down
1 change: 1 addition & 0 deletions pkg/interp/interp.go
Original file line number Diff line number Diff line change
Expand Up @@ -1044,6 +1044,7 @@ type Options struct {
BitsFormat string
LineBytes int
DisplayBytes int
Base int
Addrbase int
Sizebase int
SkipGaps bool
Expand Down
24 changes: 22 additions & 2 deletions pkg/interp/options.jq
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ def _opt_options:
argdecode: "array_string_pair",
argjson: "array_string_pair",
array_truncate: "number",
base: "number",
bits_format: "string",
byte_colors: "csv_ranges_array",
color: "boolean",
Expand Down Expand Up @@ -528,12 +529,31 @@ def options($opts):
+ [$opts]
)
| add
| ( if .width != 0 then [_intdiv(_intdiv(.width; 8); 2) * 2, 4] | max
else 16
| ( if .width != 0 then
if .base == 2 then
# set input data bits to ~44.4% of width
.5 * (8 / (8 + 1)) * .width | floor
else
# set input data hex to ~37.5% of width
.5 * (3 / (3 + 1)) * .width | floor
end
else
16 * 3
end
) as $input_data_width
| ( if .base == 2 then
# 100010010101000
# show at least 1 byte
[_intdiv($input_data_width; 8), 1] | max
else
# 89 50 4e 47 0d 0a 1a 0a
# show an even amount of bytes; and at least 4
[_intdiv(_intdiv($input_data_width; 3); 2) * 2, 4] | max
end
) as $display_bytes
# default if not set
| .display_bytes |= (. // $display_bytes)
| .line_bytes |= (. // $display_bytes)
| .base |= (. // 16)
);
def options: options({});