...

Source file src/encoding/hex/hex.go

Documentation: encoding/hex

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

View as plain text