mirror of
https://github.com/blacktop/ipsw.git
synced 2026-05-08 12:22:26 +00:00
167 lines
3.7 KiB
Go
167 lines
3.7 KiB
Go
package utils
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"errors"
|
|
"io"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/fatih/color"
|
|
)
|
|
|
|
// CREDIT: https://pkg.go.dev/encoding/hex (edited to add vaddr and color)
|
|
|
|
var colorFaint = color.New(color.Faint, color.FgHiBlue).SprintFunc()
|
|
|
|
func colorZeros(dump string) string {
|
|
if len(dump) > 0 {
|
|
dubzerosMatch := regexp.MustCompile(`\s(00\s)+|\.`)
|
|
dump = dubzerosMatch.ReplaceAllStringFunc(dump, func(s string) string {
|
|
return colorFaint(s)
|
|
})
|
|
}
|
|
return dump
|
|
}
|
|
|
|
// HexDump returns a string that contains a hex dump of the given data. The format
|
|
// of the hex dump matches the output of `hexdump -C` on the command line.
|
|
func HexDump(data []byte, vaddr uint64) string {
|
|
if len(data) == 0 {
|
|
return ""
|
|
}
|
|
|
|
var buf strings.Builder
|
|
// Dumper will write 79 bytes per complete 16 byte chunk, and at least
|
|
// 64 bytes for whatever remains. Round the allocation up, since only a
|
|
// maximum of 15 bytes will be wasted.
|
|
buf.Grow((1 + ((len(data) - 1) / 16)) * 79)
|
|
|
|
dumper := Dumper(&buf, uint(vaddr))
|
|
dumper.Write(data)
|
|
dumper.Close()
|
|
return colorZeros(buf.String())
|
|
}
|
|
|
|
// Dumper returns a WriteCloser that writes a hex dump of all written data to
|
|
// w. The format of the dump matches the output of `hexdump -C` on the command
|
|
// line.
|
|
func Dumper(w io.Writer, vaddr uint) io.WriteCloser {
|
|
return &dumper{w: w, n: vaddr}
|
|
}
|
|
|
|
type dumper struct {
|
|
w io.Writer
|
|
rightChars [18]byte
|
|
buf [27]byte
|
|
used int // number of bytes in the current line
|
|
n uint // number of bytes, total
|
|
closed bool
|
|
}
|
|
|
|
func toChar(b byte) byte {
|
|
if b < 32 || b > 126 {
|
|
return '.'
|
|
}
|
|
return b
|
|
}
|
|
|
|
func (h *dumper) Write(data []byte) (n int, err error) {
|
|
if h.closed {
|
|
return 0, errors.New("encoding/hex: dumper closed")
|
|
}
|
|
|
|
// Output lines look like:
|
|
// 00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=|
|
|
// ^ offset ^ extra space ^ ASCII of line.
|
|
for i := range data {
|
|
if h.used == 0 {
|
|
// At the beginning of a line we print the current
|
|
// offset in hex.
|
|
h.buf[0] = byte(h.n >> 56)
|
|
h.buf[1] = byte(h.n >> 48)
|
|
h.buf[2] = byte(h.n >> 40)
|
|
h.buf[3] = byte(h.n >> 32)
|
|
h.buf[4] = byte(h.n >> 24)
|
|
h.buf[5] = byte(h.n >> 16)
|
|
h.buf[6] = byte(h.n >> 8)
|
|
h.buf[7] = byte(h.n)
|
|
hex.Encode(h.buf[8:], h.buf[:8])
|
|
h.buf[24] = ':'
|
|
h.buf[25] = ' '
|
|
h.buf[26] = ' '
|
|
color.New(color.Italic, color.Faint).Fprint(h.w, string(h.buf[8:25]))
|
|
_, err = h.w.Write(h.buf[25:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
}
|
|
hex.Encode(h.buf[:], data[i:i+1])
|
|
h.buf[2] = ' '
|
|
l := 3
|
|
if h.used == 7 {
|
|
// There's an additional space after the 8th byte.
|
|
h.buf[3] = ' '
|
|
l = 4
|
|
} else if h.used == 15 {
|
|
// At the end of the line there's an extra space and
|
|
// the bar for the right column.
|
|
h.buf[3] = ' '
|
|
h.buf[4] = '|'
|
|
l = 5
|
|
}
|
|
_, err = h.w.Write(h.buf[:l])
|
|
if err != nil {
|
|
return
|
|
}
|
|
n++
|
|
h.rightChars[h.used] = toChar(data[i])
|
|
h.used++
|
|
h.n++
|
|
if h.used == 16 {
|
|
h.rightChars[16] = '|'
|
|
h.rightChars[17] = '\n'
|
|
_, err = h.w.Write(h.rightChars[:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
h.used = 0
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func (h *dumper) Close() (err error) {
|
|
// See the comments in Write() for the details of this format.
|
|
if h.closed {
|
|
return
|
|
}
|
|
h.closed = true
|
|
if h.used == 0 {
|
|
return
|
|
}
|
|
h.buf[0] = ' '
|
|
h.buf[1] = ' '
|
|
h.buf[2] = ' '
|
|
h.buf[3] = ' '
|
|
h.buf[4] = '|'
|
|
nBytes := h.used
|
|
for h.used < 16 {
|
|
l := 3
|
|
if h.used == 7 {
|
|
l = 4
|
|
} else if h.used == 15 {
|
|
l = 5
|
|
}
|
|
_, err = h.w.Write(h.buf[:l])
|
|
if err != nil {
|
|
return
|
|
}
|
|
h.used++
|
|
}
|
|
h.rightChars[nBytes] = '|'
|
|
h.rightChars[nBytes+1] = '\n'
|
|
_, err = h.w.Write(h.rightChars[:nBytes+2])
|
|
return
|
|
}
|