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