[hexxy] add --reverse option and --plain

This commit is contained in:
mizi 2024-01-25 13:38:27 -09:00
parent f45df01756
commit 6d4d21c621
2 changed files with 195 additions and 7 deletions

117
hexxy.go
View file

@ -2,6 +2,7 @@ package main
import ( import (
"bufio" "bufio"
"encoding/hex"
"errors" "errors"
"fmt" "fmt"
"io" "io"
@ -16,6 +17,10 @@ import (
var opts struct { var opts struct {
NoColor bool `short:"N" long:"no-color" description:"do not print output with color"` NoColor bool `short:"N" long:"no-color" description:"do not print output with color"`
OffsetFormat string `short:"t" long:"radix" default:"x" choice:"d" choice:"o" choice:"x" description:"Print offset in [d|o|x] format"` OffsetFormat string `short:"t" long:"radix" default:"x" choice:"d" choice:"o" choice:"x" description:"Print offset in [d|o|x] format"`
Reverse bool `short:"r" long:"reverse" description:"re-assemble hexdump output back into binary"`
Plain bool `short:"p" long:"plain" description:"plain output without ascii table and offset row [often used with hexxy -r]"`
ForceColor bool `short:"F" long:"force-color" description:"color is automatically disabled if output is a pipe, this option forces color output"`
Separator string `short:"s" long:"separator" default:"|" description:"separator character for the ascii character table"`
Verbose bool `short:"v" long:"verbose" description:"print debugging information and verbose output"` Verbose bool `short:"v" long:"verbose" description:"print debugging information and verbose output"`
} }
@ -81,6 +86,7 @@ func printOffset(offset uint64) string {
} }
func printSeparator(writer io.Writer, newline bool) { func printSeparator(writer io.Writer, newline bool) {
// WHY???
if newline { if newline {
fmt.Fprintln(writer, Separator) fmt.Fprintln(writer, Separator)
} else { } else {
@ -158,27 +164,97 @@ func Hexdump(file *os.File, color *Color) error {
return nil return nil
} }
func HexdumpPlain(file *os.File) error {
// stdout := bufio.NewWriter(os.Stdout)
// stderr := os.Stderr
// defer stdout.Flush()
src, err := io.ReadAll(file)
if err != nil {
return err
}
dst := make([]byte, hex.EncodedLen(len(src)))
hex.Encode(dst, src)
fmt.Printf("%s\n", dst)
// reader := bufio.NewReaderSize(file, 10*1024*1024)
// for {
// b, err := reader.ReadByte()
// if errors.Is(err, io.EOF) {
// break
// }
// if err != nil {
// fmt.Fprintf(stderr, "Failed to read %v: %v\n", file.Name(), err)
// return err
// }
// stdout.WriteString(fmt.Sprintf("%02x", string(b)))
// }
return nil
}
func plain2Binary(file *os.File) error {
return reverse(os.Stdout, os.Stdin)
// contents, err := io.ReadAll(file)
// if err != nil {
// return err
// }
// fmt.Println(len(contents))
// fmt.Printf("Binary byte representation: %08b\n", contents)
// _, err = hex.Decode(contents, dst)
// if err != nil {
// return err
// }
// os.Stdout.Write(dst)
// dest := make([]byte, hex.EncodedLen(len(contents)))
// hex.Decode(dest, contents)
// fmt.Printf("%s\n", dest)
// return nil
}
func getOffsetFormat() error { func getOffsetFormat() error {
var prefix string var prefix string
var suffix string var suffix string
var sep string
// turn off color if output is a pipe
// idk if I like this though since I often
// use hexxy asdf | head -n 10 but I also want to work on --reverse option
// stat, _ := os.Stdout.Stat()
// if stat.Mode()&os.ModeCharDevice == 0 && !opts.ForceColor {
// opts.NoColor = true
// }
if !opts.NoColor { if !opts.NoColor {
prefix = GREY prefix = GREY
suffix = CLR suffix = CLR
sep = "│"
} else { } else {
prefix = "" prefix = ""
suffix = "" suffix = ""
sep = "|"
} }
Separator = prefix + "│" + suffix if opts.Separator != "" {
sep = opts.Separator
}
Separator = prefix + sep + suffix
switch opts.OffsetFormat { switch opts.OffsetFormat {
case "d": case "d":
OffsetFormat = prefix + "%08d " + suffix OffsetFormat = prefix + "%08d " + suffix
case "o": case "o":
OffsetFormat = prefix + "%08o " + suffix OffsetFormat = prefix + "%08o " + suffix
case "x": case "x":
OffsetFormat = prefix + "%08x " + suffix OffsetFormat = prefix + "%08x " + suffix
default: default:
return fmt.Errorf("Offset format must be [d|o|x]") return fmt.Errorf("Offset format must be [d|o|x]")
} }
@ -188,6 +264,10 @@ func getOffsetFormat() error {
func Hexxy(args []string) error { func Hexxy(args []string) error {
color := &Color{} color := &Color{}
if opts.Reverse {
return plain2Binary(os.Stdin)
}
if opts.NoColor { if opts.NoColor {
color.disable = true color.disable = true
} }
@ -197,7 +277,11 @@ func Hexxy(args []string) error {
} }
if len(args) < 1 && stdinOpen() { if len(args) < 1 && stdinOpen() {
return Hexdump(os.Stdin, color) if opts.Plain {
return HexdumpPlain(os.Stdin)
} else {
return Hexdump(os.Stdin, color)
}
} }
for _, f := range args { for _, f := range args {
@ -207,8 +291,14 @@ func Hexxy(args []string) error {
} }
defer file.Close() defer file.Close()
if err := Hexdump(file, color); err != nil { if opts.Plain {
return err if err := HexdumpPlain(file); err != nil {
return err
}
} else {
if err := Hexdump(file, color); err != nil {
return err
}
} }
} }
@ -228,6 +318,19 @@ func main() {
Debug = log.Printf Debug = log.Printf
} }
if opts.Reverse {
// f, err := os.Open(args[0])
// if err != nil {
// panic(err)
// }
// defer f.Close()
err = plain2Binary(os.Stdin)
if err != nil {
log.Fatal(err)
}
os.Exit(0)
}
err = getOffsetFormat() err = getOffsetFormat()
if err != nil { if err != nil {
log.Fatal(err) log.Fatal(err)

85
reverse.go Normal file
View file

@ -0,0 +1,85 @@
package main
import (
"bufio"
"fmt"
"io"
"os"
"strconv"
"strings"
)
// func reverse(w io.Writer, path string) error {
func reverse(w io.Writer, f *os.File) error {
// f, err := os.Open(path)
// if err != nil {
// return err
// }
// defer f.Close()
s := bufio.NewScanner(f)
star := false
var prev uint64
var data []byte
var zero [16]byte
for s.Scan() {
line := s.Text()
if line == "*" {
star = true
continue
}
if len(line) < len("00000000") {
return fmt.Errorf("invalid line %q, missing address prefix", line)
}
part := line[:len("00000000")]
line = line[len("00000000"):]
addr, err := strconv.ParseUint(part, 16, 32)
if err != nil {
return err
}
if star {
for i := prev + 16; i < addr; i += 16 {
data = append(data, zero[:]...)
}
star = false
}
prev = addr
pos := strings.IndexByte(line, '|')
if pos != -1 {
line = line[:pos]
}
for len(line) > 0 {
line = strings.TrimSpace(line)
pos := strings.IndexByte(line, ' ')
if pos == -1 {
pos = len(line)
}
part := line[:pos]
line = line[pos:]
b, err := strconv.ParseUint(part, 16, 8)
if err != nil {
return err
}
data = append(data, byte(b))
}
}
if err := s.Err(); err != nil {
return err
}
if _, err := w.Write(data); err != nil {
return err
}
return nil
}