...
Run Format

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		"bytes"
    10		"errors"
    11		"fmt"
    12		"io"
    13	)
    14	
    15	var hextable = [16]byte{
    16		'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    17		'a', 'b', 'c', 'd', 'e', 'f',
    18	}
    19	
    20	// EncodedLen returns the length of an encoding of n source bytes.
    21	// Specifically, it returns n * 2.
    22	func EncodedLen(n int) int { return n * 2 }
    23	
    24	// Encode encodes src into EncodedLen(len(src))
    25	// bytes of dst. As a convenience, it returns the number
    26	// of bytes written to dst, but this value is always EncodedLen(len(src)).
    27	// Encode implements hexadecimal encoding.
    28	func Encode(dst, src []byte) int {
    29		for i, v := range src {
    30			dst[i*2] = hextable[v>>4]
    31			dst[i*2+1] = hextable[v&0x0f]
    32		}
    33	
    34		return len(src) * 2
    35	}
    36	
    37	// ErrLength results from decoding an odd length slice.
    38	var ErrLength = errors.New("encoding/hex: odd length hex string")
    39	
    40	// InvalidByteError values describe errors resulting from an invalid byte in a hex string.
    41	type InvalidByteError byte
    42	
    43	func (e InvalidByteError) Error() string {
    44		return fmt.Sprintf("encoding/hex: invalid byte: %#U", rune(e))
    45	}
    46	
    47	// DecodedLen returns the length of a decoding of x source bytes.
    48	// Specifically, it returns x / 2.
    49	func DecodedLen(x int) int { return x / 2 }
    50	
    51	// Decode decodes src into DecodedLen(len(src)) bytes,
    52	// returning the actual number of bytes written to dst.
    53	//
    54	// Decode expects that src contain only hexadecimal
    55	// characters and that src should have an even length.
    56	func Decode(dst, src []byte) (int, error) {
    57		if len(src)%2 == 1 {
    58			return 0, ErrLength
    59		}
    60	
    61		for i := 0; i < len(src)/2; i++ {
    62			a, ok := fromHexChar(src[i*2])
    63			if !ok {
    64				return 0, InvalidByteError(src[i*2])
    65			}
    66			b, ok := fromHexChar(src[i*2+1])
    67			if !ok {
    68				return 0, InvalidByteError(src[i*2+1])
    69			}
    70			dst[i] = (a << 4) | b
    71		}
    72	
    73		return len(src) / 2, nil
    74	}
    75	
    76	// fromHexChar converts a hex character into its value and a success flag.
    77	func fromHexChar(c byte) (byte, bool) {
    78		switch {
    79		case '0' <= c && c <= '9':
    80			return c - '0', true
    81		case 'a' <= c && c <= 'f':
    82			return c - 'a' + 10, true
    83		case 'A' <= c && c <= 'F':
    84			return c - 'A' + 10, true
    85		}
    86	
    87		return 0, false
    88	}
    89	
    90	// EncodeToString returns the hexadecimal encoding of src.
    91	func EncodeToString(src []byte) string {
    92		dst := make([]byte, EncodedLen(len(src)))
    93		Encode(dst, src)
    94		return string(dst)
    95	}
    96	
    97	// DecodeString returns the bytes represented by the hexadecimal string s.
    98	func DecodeString(s string) ([]byte, error) {
    99		src := []byte(s)
   100		dst := make([]byte, DecodedLen(len(src)))
   101		_, err := Decode(dst, src)
   102		if err != nil {
   103			return nil, err
   104		}
   105		return dst, nil
   106	}
   107	
   108	// Dump returns a string that contains a hex dump of the given data. The format
   109	// of the hex dump matches the output of `hexdump -C` on the command line.
   110	func Dump(data []byte) string {
   111		var buf bytes.Buffer
   112		dumper := Dumper(&buf)
   113		dumper.Write(data)
   114		dumper.Close()
   115		return buf.String()
   116	}
   117	
   118	// Dumper returns a WriteCloser that writes a hex dump of all written data to
   119	// w. The format of the dump matches the output of `hexdump -C` on the command
   120	// line.
   121	func Dumper(w io.Writer) io.WriteCloser {
   122		return &dumper{w: w}
   123	}
   124	
   125	type dumper struct {
   126		w          io.Writer
   127		rightChars [18]byte
   128		buf        [14]byte
   129		used       int  // number of bytes in the current line
   130		n          uint // number of bytes, total
   131	}
   132	
   133	func toChar(b byte) byte {
   134		if b < 32 || b > 126 {
   135			return '.'
   136		}
   137		return b
   138	}
   139	
   140	func (h *dumper) Write(data []byte) (n int, err error) {
   141		// Output lines look like:
   142		// 00000010  2e 2f 30 31 32 33 34 35  36 37 38 39 3a 3b 3c 3d  |./0123456789:;<=|
   143		// ^ offset                          ^ extra space              ^ ASCII of line.
   144		for i := range data {
   145			if h.used == 0 {
   146				// At the beginning of a line we print the current
   147				// offset in hex.
   148				h.buf[0] = byte(h.n >> 24)
   149				h.buf[1] = byte(h.n >> 16)
   150				h.buf[2] = byte(h.n >> 8)
   151				h.buf[3] = byte(h.n)
   152				Encode(h.buf[4:], h.buf[:4])
   153				h.buf[12] = ' '
   154				h.buf[13] = ' '
   155				_, err = h.w.Write(h.buf[4:])
   156				if err != nil {
   157					return
   158				}
   159			}
   160			Encode(h.buf[:], data[i:i+1])
   161			h.buf[2] = ' '
   162			l := 3
   163			if h.used == 7 {
   164				// There's an additional space after the 8th byte.
   165				h.buf[3] = ' '
   166				l = 4
   167			} else if h.used == 15 {
   168				// At the end of the line there's an extra space and
   169				// the bar for the right column.
   170				h.buf[3] = ' '
   171				h.buf[4] = '|'
   172				l = 5
   173			}
   174			_, err = h.w.Write(h.buf[:l])
   175			if err != nil {
   176				return
   177			}
   178			n++
   179			h.rightChars[h.used] = toChar(data[i])
   180			h.used++
   181			h.n++
   182			if h.used == 16 {
   183				h.rightChars[16] = '|'
   184				h.rightChars[17] = '\n'
   185				_, err = h.w.Write(h.rightChars[:])
   186				if err != nil {
   187					return
   188				}
   189				h.used = 0
   190			}
   191		}
   192		return
   193	}
   194	
   195	func (h *dumper) Close() (err error) {
   196		// See the comments in Write() for the details of this format.
   197		if h.used == 0 {
   198			return
   199		}
   200		h.buf[0] = ' '
   201		h.buf[1] = ' '
   202		h.buf[2] = ' '
   203		h.buf[3] = ' '
   204		h.buf[4] = '|'
   205		nBytes := h.used
   206		for h.used < 16 {
   207			l := 3
   208			if h.used == 7 {
   209				l = 4
   210			} else if h.used == 15 {
   211				l = 5
   212			}
   213			_, err = h.w.Write(h.buf[:l])
   214			if err != nil {
   215				return
   216			}
   217			h.used++
   218		}
   219		h.rightChars[nBytes] = '|'
   220		h.rightChars[nBytes+1] = '\n'
   221		_, err = h.w.Write(h.rightChars[:nBytes+2])
   222		return
   223	}
   224	

View as plain text