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