Source file src/encoding/hex/hex.go

     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  	"strings"
    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) string {
   127  	dst := make([]byte, EncodedLen(len(src)))
   128  	Encode(dst, src)
   129  	return string(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 string) ([]byte, error) {
   139  	src := []byte(s)
   140  	// We can use the source slice itself as the destination
   141  	// because the decode loop increments by one and then the 'seen' byte is not used anymore.
   142  	n, err := Decode(src, src)
   143  	return src[:n], err
   144  }
   145  
   146  // Dump returns a string that contains a hex dump of the given data. The format
   147  // of the hex dump matches the output of `hexdump -C` on the command line.
   148  func Dump(data []byte) string {
   149  	if len(data) == 0 {
   150  		return ""
   151  	}
   152  
   153  	var buf strings.Builder
   154  	// Dumper will write 79 bytes per complete 16 byte chunk, and at least
   155  	// 64 bytes for whatever remains. Round the allocation up, since only a
   156  	// maximum of 15 bytes will be wasted.
   157  	buf.Grow((1 + ((len(data) - 1) / 16)) * 79)
   158  
   159  	dumper := Dumper(&buf)
   160  	dumper.Write(data)
   161  	dumper.Close()
   162  	return buf.String()
   163  }
   164  
   165  // bufferSize is the number of hexadecimal characters to buffer in encoder and decoder.
   166  const bufferSize = 1024
   167  
   168  type encoder struct {
   169  	w   io.Writer
   170  	err error
   171  	out [bufferSize]byte // output buffer
   172  }
   173  
   174  // NewEncoder returns an [io.Writer] that writes lowercase hexadecimal characters to w.
   175  func NewEncoder(w io.Writer) io.Writer {
   176  	return &encoder{w: w}
   177  }
   178  
   179  func (e *encoder) Write(p []byte) (n int, err error) {
   180  	for len(p) > 0 && e.err == nil {
   181  		chunkSize := bufferSize / 2
   182  		if len(p) < chunkSize {
   183  			chunkSize = len(p)
   184  		}
   185  
   186  		var written int
   187  		encoded := Encode(e.out[:], p[:chunkSize])
   188  		written, e.err = e.w.Write(e.out[:encoded])
   189  		n += written / 2
   190  		p = p[chunkSize:]
   191  	}
   192  	return n, e.err
   193  }
   194  
   195  type decoder struct {
   196  	r   io.Reader
   197  	err error
   198  	in  []byte           // input buffer (encoded form)
   199  	arr [bufferSize]byte // backing array for in
   200  }
   201  
   202  // NewDecoder returns an [io.Reader] that decodes hexadecimal characters from r.
   203  // NewDecoder expects that r contain only an even number of hexadecimal characters.
   204  func NewDecoder(r io.Reader) io.Reader {
   205  	return &decoder{r: r}
   206  }
   207  
   208  func (d *decoder) Read(p []byte) (n int, err error) {
   209  	// Fill internal buffer with sufficient bytes to decode
   210  	if len(d.in) < 2 && d.err == nil {
   211  		var numCopy, numRead int
   212  		numCopy = copy(d.arr[:], d.in) // Copies either 0 or 1 bytes
   213  		numRead, d.err = d.r.Read(d.arr[numCopy:])
   214  		d.in = d.arr[:numCopy+numRead]
   215  		if d.err == io.EOF && len(d.in)%2 != 0 {
   216  
   217  			if a := reverseHexTable[d.in[len(d.in)-1]]; a > 0x0f {
   218  				d.err = InvalidByteError(d.in[len(d.in)-1])
   219  			} else {
   220  				d.err = io.ErrUnexpectedEOF
   221  			}
   222  		}
   223  	}
   224  
   225  	// Decode internal buffer into output buffer
   226  	if numAvail := len(d.in) / 2; len(p) > numAvail {
   227  		p = p[:numAvail]
   228  	}
   229  	numDec, err := Decode(p, d.in[:len(p)*2])
   230  	d.in = d.in[2*numDec:]
   231  	if err != nil {
   232  		d.in, d.err = nil, err // Decode error; discard input remainder
   233  	}
   234  
   235  	if len(d.in) < 2 {
   236  		return numDec, d.err // Only expose errors when buffer fully consumed
   237  	}
   238  	return numDec, nil
   239  }
   240  
   241  // Dumper returns a [io.WriteCloser] that writes a hex dump of all written data to
   242  // w. The format of the dump matches the output of `hexdump -C` on the command
   243  // line.
   244  func Dumper(w io.Writer) io.WriteCloser {
   245  	return &dumper{w: w}
   246  }
   247  
   248  type dumper struct {
   249  	w          io.Writer
   250  	rightChars [18]byte
   251  	buf        [14]byte
   252  	used       int  // number of bytes in the current line
   253  	n          uint // number of bytes, total
   254  	closed     bool
   255  }
   256  
   257  func toChar(b byte) byte {
   258  	if b < 32 || b > 126 {
   259  		return '.'
   260  	}
   261  	return b
   262  }
   263  
   264  func (h *dumper) Write(data []byte) (n int, err error) {
   265  	if h.closed {
   266  		return 0, errors.New("encoding/hex: dumper closed")
   267  	}
   268  
   269  	// Output lines look like:
   270  	// 00000010  2e 2f 30 31 32 33 34 35  36 37 38 39 3a 3b 3c 3d  |./0123456789:;<=|
   271  	// ^ offset                          ^ extra space              ^ ASCII of line.
   272  	for i := range data {
   273  		if h.used == 0 {
   274  			// At the beginning of a line we print the current
   275  			// offset in hex.
   276  			h.buf[0] = byte(h.n >> 24)
   277  			h.buf[1] = byte(h.n >> 16)
   278  			h.buf[2] = byte(h.n >> 8)
   279  			h.buf[3] = byte(h.n)
   280  			Encode(h.buf[4:], h.buf[:4])
   281  			h.buf[12] = ' '
   282  			h.buf[13] = ' '
   283  			_, err = h.w.Write(h.buf[4:])
   284  			if err != nil {
   285  				return
   286  			}
   287  		}
   288  		Encode(h.buf[:], data[i:i+1])
   289  		h.buf[2] = ' '
   290  		l := 3
   291  		if h.used == 7 {
   292  			// There's an additional space after the 8th byte.
   293  			h.buf[3] = ' '
   294  			l = 4
   295  		} else if h.used == 15 {
   296  			// At the end of the line there's an extra space and
   297  			// the bar for the right column.
   298  			h.buf[3] = ' '
   299  			h.buf[4] = '|'
   300  			l = 5
   301  		}
   302  		_, err = h.w.Write(h.buf[:l])
   303  		if err != nil {
   304  			return
   305  		}
   306  		n++
   307  		h.rightChars[h.used] = toChar(data[i])
   308  		h.used++
   309  		h.n++
   310  		if h.used == 16 {
   311  			h.rightChars[16] = '|'
   312  			h.rightChars[17] = '\n'
   313  			_, err = h.w.Write(h.rightChars[:])
   314  			if err != nil {
   315  				return
   316  			}
   317  			h.used = 0
   318  		}
   319  	}
   320  	return
   321  }
   322  
   323  func (h *dumper) Close() (err error) {
   324  	// See the comments in Write() for the details of this format.
   325  	if h.closed {
   326  		return
   327  	}
   328  	h.closed = true
   329  	if h.used == 0 {
   330  		return
   331  	}
   332  	h.buf[0] = ' '
   333  	h.buf[1] = ' '
   334  	h.buf[2] = ' '
   335  	h.buf[3] = ' '
   336  	h.buf[4] = '|'
   337  	nBytes := h.used
   338  	for h.used < 16 {
   339  		l := 3
   340  		if h.used == 7 {
   341  			l = 4
   342  		} else if h.used == 15 {
   343  			l = 5
   344  		}
   345  		_, err = h.w.Write(h.buf[:l])
   346  		if err != nil {
   347  			return
   348  		}
   349  		h.used++
   350  	}
   351  	h.rightChars[nBytes] = '|'
   352  	h.rightChars[nBytes+1] = '\n'
   353  	_, err = h.w.Write(h.rightChars[:nBytes+2])
   354  	return
   355  }
   356  

View as plain text