hex.mx raw

   1  // Copyright 2009 The Go Authors. All rights reserved.
   2  // Use of this source code is governed by a BSD-style
   3  // license that can be found in the LICENSE file.
   4  
   5  // Package hex implements hexadecimal encoding and decoding.
   6  package hex
   7  
   8  import (
   9  	"errors"
  10  	"fmt"
  11  	"io"
  12  	"slices"
  13  	"bytes"
  14  )
  15  
  16  const (
  17  	hextable        = "0123456789abcdef"
  18  	reverseHexTable = "" +
  19  		"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  20  		"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  21  		"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  22  		"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xff\xff\xff\xff\xff\xff" +
  23  		"\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  24  		"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  25  		"\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  26  		"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  27  		"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  28  		"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  29  		"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  30  		"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  31  		"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  32  		"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  33  		"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
  34  		"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
  35  )
  36  
  37  // EncodedLen returns the length of an encoding of n source bytes.
  38  // Specifically, it returns n * 2.
  39  func EncodedLen(n int) int { return n * 2 }
  40  
  41  // Encode encodes src into [EncodedLen](len(src))
  42  // bytes of dst. As a convenience, it returns the number
  43  // of bytes written to dst, but this value is always [EncodedLen](len(src)).
  44  // Encode implements hexadecimal encoding.
  45  func Encode(dst, src []byte) int {
  46  	j := 0
  47  	for _, v := range src {
  48  		dst[j] = hextable[v>>4]
  49  		dst[j+1] = hextable[v&0x0f]
  50  		j += 2
  51  	}
  52  	return len(src) * 2
  53  }
  54  
  55  // AppendEncode appends the hexadecimally encoded src to dst
  56  // and returns the extended buffer.
  57  func AppendEncode(dst, src []byte) []byte {
  58  	n := EncodedLen(len(src))
  59  	dst = slices.Grow(dst, n)
  60  	Encode(dst[len(dst):][:n], src)
  61  	return dst[:len(dst)+n]
  62  }
  63  
  64  // ErrLength reports an attempt to decode an odd-length input
  65  // using [Decode] or [DecodeString].
  66  // The stream-based Decoder returns [io.ErrUnexpectedEOF] instead of ErrLength.
  67  var ErrLength = errors.New("encoding/hex: odd length hex string")
  68  
  69  // InvalidByteError values describe errors resulting from an invalid byte in a hex string.
  70  type InvalidByteError byte
  71  
  72  func (e InvalidByteError) Error() string {
  73  	return fmt.Sprintf("encoding/hex: invalid byte: %#U", rune(e))
  74  }
  75  
  76  // DecodedLen returns the length of a decoding of x source bytes.
  77  // Specifically, it returns x / 2.
  78  func DecodedLen(x int) int { return x / 2 }
  79  
  80  // Decode decodes src into [DecodedLen](len(src)) bytes,
  81  // returning the actual number of bytes written to dst.
  82  //
  83  // Decode expects that src contains only hexadecimal
  84  // characters and that src has even length.
  85  // If the input is malformed, Decode returns the number
  86  // of bytes decoded before the error.
  87  func Decode(dst, src []byte) (int, error) {
  88  	i, j := 0, 1
  89  	for ; j < len(src); j += 2 {
  90  		p := src[j-1]
  91  		q := src[j]
  92  
  93  		a := reverseHexTable[p]
  94  		b := reverseHexTable[q]
  95  		if a > 0x0f {
  96  			return i, InvalidByteError(p)
  97  		}
  98  		if b > 0x0f {
  99  			return i, InvalidByteError(q)
 100  		}
 101  		dst[i] = (a << 4) | b
 102  		i++
 103  	}
 104  	if len(src)%2 == 1 {
 105  		// Check for invalid char before reporting bad length,
 106  		// since the invalid char (if present) is an earlier problem.
 107  		if reverseHexTable[src[j-1]] > 0x0f {
 108  			return i, InvalidByteError(src[j-1])
 109  		}
 110  		return i, ErrLength
 111  	}
 112  	return i, nil
 113  }
 114  
 115  // AppendDecode appends the hexadecimally decoded src to dst
 116  // and returns the extended buffer.
 117  // If the input is malformed, it returns the partially decoded src and an error.
 118  func AppendDecode(dst, src []byte) ([]byte, error) {
 119  	n := DecodedLen(len(src))
 120  	dst = slices.Grow(dst, n)
 121  	n, err := Decode(dst[len(dst):][:n], src)
 122  	return dst[:len(dst)+n], err
 123  }
 124  
 125  // EncodeToString returns the hexadecimal encoding of src.
 126  func EncodeToString(src []byte) []byte {
 127  	dst := []byte{:EncodedLen(len(src))}
 128  	Encode(dst, src)
 129  	return []byte(dst)
 130  }
 131  
 132  // DecodeString returns the bytes represented by the hexadecimal string s.
 133  //
 134  // DecodeString expects that src contains only hexadecimal
 135  // characters and that src has even length.
 136  // If the input is malformed, DecodeString returns
 137  // the bytes decoded before the error.
 138  func DecodeString(s []byte) ([]byte, error) {
 139  	dst := []byte{:DecodedLen(len(s))}
 140  	n, err := Decode(dst, []byte(s))
 141  	return dst[:n], err
 142  }
 143  
 144  // Dump returns a string that contains a hex dump of the given data. The format
 145  // of the hex dump matches the output of `hexdump -C` on the command line.
 146  func Dump(data []byte) []byte {
 147  	if len(data) == 0 {
 148  		return ""
 149  	}
 150  
 151  	var buf bytes.Buffer
 152  	// Dumper will write 79 bytes per complete 16 byte chunk, and at least
 153  	// 64 bytes for whatever remains. Round the allocation up, since only a
 154  	// maximum of 15 bytes will be wasted.
 155  	buf.Grow((1 + ((len(data) - 1) / 16)) * 79)
 156  
 157  	dumper := Dumper(&buf)
 158  	dumper.Write(data)
 159  	dumper.Close()
 160  	return buf.String()
 161  }
 162  
 163  // bufferSize is the number of hexadecimal characters to buffer in encoder and decoder.
 164  const bufferSize = 1024
 165  
 166  type encoder struct {
 167  	w   io.Writer
 168  	err error
 169  	out [bufferSize]byte // output buffer
 170  }
 171  
 172  // NewEncoder returns an [io.Writer] that writes lowercase hexadecimal characters to w.
 173  func NewEncoder(w io.Writer) io.Writer {
 174  	return &encoder{w: w}
 175  }
 176  
 177  func (e *encoder) Write(p []byte) (n int, err error) {
 178  	for len(p) > 0 && e.err == nil {
 179  		chunkSize := bufferSize / 2
 180  		if len(p) < chunkSize {
 181  			chunkSize = len(p)
 182  		}
 183  
 184  		var written int
 185  		encoded := Encode(e.out[:], p[:chunkSize])
 186  		written, e.err = e.w.Write(e.out[:encoded])
 187  		n += written / 2
 188  		p = p[chunkSize:]
 189  	}
 190  	return n, e.err
 191  }
 192  
 193  type decoder struct {
 194  	r   io.Reader
 195  	err error
 196  	in  []byte           // input buffer (encoded form)
 197  	arr [bufferSize]byte // backing array for in
 198  }
 199  
 200  // NewDecoder returns an [io.Reader] that decodes hexadecimal characters from r.
 201  // NewDecoder expects that r contain only an even number of hexadecimal characters.
 202  func NewDecoder(r io.Reader) io.Reader {
 203  	return &decoder{r: r}
 204  }
 205  
 206  func (d *decoder) Read(p []byte) (n int, err error) {
 207  	// Fill internal buffer with sufficient bytes to decode
 208  	if len(d.in) < 2 && d.err == nil {
 209  		var numCopy, numRead int
 210  		numCopy = copy(d.arr[:], d.in) // Copies either 0 or 1 bytes
 211  		numRead, d.err = d.r.Read(d.arr[numCopy:])
 212  		d.in = d.arr[:numCopy+numRead]
 213  		if d.err == io.EOF && len(d.in)%2 != 0 {
 214  
 215  			if a := reverseHexTable[d.in[len(d.in)-1]]; a > 0x0f {
 216  				d.err = InvalidByteError(d.in[len(d.in)-1])
 217  			} else {
 218  				d.err = io.ErrUnexpectedEOF
 219  			}
 220  		}
 221  	}
 222  
 223  	// Decode internal buffer into output buffer
 224  	if numAvail := len(d.in) / 2; len(p) > numAvail {
 225  		p = p[:numAvail]
 226  	}
 227  	numDec, err := Decode(p, d.in[:len(p)*2])
 228  	d.in = d.in[2*numDec:]
 229  	if err != nil {
 230  		d.in, d.err = nil, err // Decode error; discard input remainder
 231  	}
 232  
 233  	if len(d.in) < 2 {
 234  		return numDec, d.err // Only expose errors when buffer fully consumed
 235  	}
 236  	return numDec, nil
 237  }
 238  
 239  // Dumper returns a [io.WriteCloser] that writes a hex dump of all written data to
 240  // w. The format of the dump matches the output of `hexdump -C` on the command
 241  // line.
 242  func Dumper(w io.Writer) io.WriteCloser {
 243  	return &dumper{w: w}
 244  }
 245  
 246  type dumper struct {
 247  	w          io.Writer
 248  	rightChars [18]byte
 249  	buf        [14]byte
 250  	used       int  // number of bytes in the current line
 251  	n          uint // number of bytes, total
 252  	closed     bool
 253  }
 254  
 255  func toChar(b byte) byte {
 256  	if b < 32 || b > 126 {
 257  		return '.'
 258  	}
 259  	return b
 260  }
 261  
 262  func (h *dumper) Write(data []byte) (n int, err error) {
 263  	if h.closed {
 264  		return 0, errors.New("encoding/hex: dumper closed")
 265  	}
 266  
 267  	// Output lines look like:
 268  	// 00000010  2e 2f 30 31 32 33 34 35  36 37 38 39 3a 3b 3c 3d  |./0123456789:;<=|
 269  	// ^ offset                          ^ extra space              ^ ASCII of line.
 270  	for i := range data {
 271  		if h.used == 0 {
 272  			// At the beginning of a line we print the current
 273  			// offset in hex.
 274  			h.buf[0] = byte(h.n >> 24)
 275  			h.buf[1] = byte(h.n >> 16)
 276  			h.buf[2] = byte(h.n >> 8)
 277  			h.buf[3] = byte(h.n)
 278  			Encode(h.buf[4:], h.buf[:4])
 279  			h.buf[12] = ' '
 280  			h.buf[13] = ' '
 281  			_, err = h.w.Write(h.buf[4:])
 282  			if err != nil {
 283  				return
 284  			}
 285  		}
 286  		Encode(h.buf[:], data[i:i+1])
 287  		h.buf[2] = ' '
 288  		l := 3
 289  		if h.used == 7 {
 290  			// There's an additional space after the 8th byte.
 291  			h.buf[3] = ' '
 292  			l = 4
 293  		} else if h.used == 15 {
 294  			// At the end of the line there's an extra space and
 295  			// the bar for the right column.
 296  			h.buf[3] = ' '
 297  			h.buf[4] = '|'
 298  			l = 5
 299  		}
 300  		_, err = h.w.Write(h.buf[:l])
 301  		if err != nil {
 302  			return
 303  		}
 304  		n++
 305  		h.rightChars[h.used] = toChar(data[i])
 306  		h.used++
 307  		h.n++
 308  		if h.used == 16 {
 309  			h.rightChars[16] = '|'
 310  			h.rightChars[17] = '\n'
 311  			_, err = h.w.Write(h.rightChars[:])
 312  			if err != nil {
 313  				return
 314  			}
 315  			h.used = 0
 316  		}
 317  	}
 318  	return
 319  }
 320  
 321  func (h *dumper) Close() (err error) {
 322  	// See the comments in Write() for the details of this format.
 323  	if h.closed {
 324  		return
 325  	}
 326  	h.closed = true
 327  	if h.used == 0 {
 328  		return
 329  	}
 330  	h.buf[0] = ' '
 331  	h.buf[1] = ' '
 332  	h.buf[2] = ' '
 333  	h.buf[3] = ' '
 334  	h.buf[4] = '|'
 335  	nBytes := h.used
 336  	for h.used < 16 {
 337  		l := 3
 338  		if h.used == 7 {
 339  			l = 4
 340  		} else if h.used == 15 {
 341  			l = 5
 342  		}
 343  		_, err = h.w.Write(h.buf[:l])
 344  		if err != nil {
 345  			return
 346  		}
 347  		h.used++
 348  	}
 349  	h.rightChars[nBytes] = '|'
 350  	h.rightChars[nBytes+1] = '\n'
 351  	_, err = h.w.Write(h.rightChars[:nBytes+2])
 352  	return
 353  }
 354