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.
5 // Package hex implements hexadecimal encoding and decoding.
15 const hextable
= "0123456789abcdef"
17 // EncodedLen returns the length of an encoding of n source bytes.
18 func EncodedLen(n
int) int { return n
* 2 }
20 // Encode encodes src into EncodedLen(len(src))
21 // bytes of dst. As a convenience, it returns the number
22 // of bytes written to dst, but this value is always EncodedLen(len(src)).
23 // Encode implements hexadecimal encoding.
24 func Encode(dst
, src
[]byte) int {
25 for i
, v
:= range src
{
26 dst
[i
*2] = hextable
[v
>>4]
27 dst
[i
*2+1] = hextable
[v
&0x0f]
33 // ErrLength results from decoding an odd length slice.
34 var ErrLength
= errors
.New("encoding/hex: odd length hex string")
36 // InvalidByteError values describe errors resulting from an invalid byte in a hex string.
37 type InvalidByteError
byte
39 func (e InvalidByteError
) Error() string {
40 return fmt
.Sprintf("encoding/hex: invalid byte: %#U", rune(e
))
43 func DecodedLen(x
int) int { return x
/ 2 }
45 // Decode decodes src into DecodedLen(len(src)) bytes, returning the actual
46 // number of bytes written to dst.
48 // If Decode encounters invalid input, it returns an error describing the failure.
49 func Decode(dst
, src
[]byte) (int, error
) {
54 for i
:= 0; i
< len(src
)/2; i
++ {
55 a
, ok
:= fromHexChar(src
[i
*2])
57 return 0, InvalidByteError(src
[i
*2])
59 b
, ok
:= fromHexChar(src
[i
*2+1])
61 return 0, InvalidByteError(src
[i
*2+1])
66 return len(src
) / 2, nil
69 // fromHexChar converts a hex character into its value and a success flag.
70 func fromHexChar(c
byte) (byte, bool) {
72 case '0' <= c
&& c
<= '9':
74 case 'a' <= c
&& c
<= 'f':
75 return c
- 'a' + 10, true
76 case 'A' <= c
&& c
<= 'F':
77 return c
- 'A' + 10, true
83 // EncodeToString returns the hexadecimal encoding of src.
84 func EncodeToString(src
[]byte) string {
85 dst
:= make([]byte, EncodedLen(len(src
)))
90 // DecodeString returns the bytes represented by the hexadecimal string s.
91 func DecodeString(s
string) ([]byte, error
) {
93 dst
:= make([]byte, DecodedLen(len(src
)))
94 _
, err
:= Decode(dst
, src
)
101 // Dump returns a string that contains a hex dump of the given data. The format
102 // of the hex dump matches the output of `hexdump -C` on the command line.
103 func Dump(data
[]byte) string {
105 dumper
:= Dumper(&buf
)
108 return string(buf
.Bytes())
111 // Dumper returns a WriteCloser that writes a hex dump of all written data to
112 // w. The format of the dump matches the output of `hexdump -C` on the command
114 func Dumper(w io
.Writer
) io
.WriteCloser
{
122 used
int // number of bytes in the current line
123 n
uint // number of bytes, total
126 func toChar(b
byte) byte {
127 if b
< 32 || b
> 126 {
133 func (h
*dumper
) Write(data
[]byte) (n
int, err error
) {
134 // Output lines look like:
135 // 00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=|
136 // ^ offset ^ extra space ^ ASCII of line.
137 for i
:= range data
{
139 // At the beginning of a line we print the current
141 h
.buf
[0] = byte(h
.n
>> 24)
142 h
.buf
[1] = byte(h
.n
>> 16)
143 h
.buf
[2] = byte(h
.n
>> 8)
145 Encode(h
.buf
[4:], h
.buf
[:4])
148 _
, err
= h
.w
.Write(h
.buf
[4:])
153 Encode(h
.buf
[:], data
[i
:i
+1])
157 // There's an additional space after the 8th byte.
160 } else if h
.used
== 15 {
161 // At the end of the line there's an extra space and
162 // the bar for the right column.
167 _
, err
= h
.w
.Write(h
.buf
[:l
])
172 h
.rightChars
[h
.used
] = toChar(data
[i
])
176 h
.rightChars
[16] = '|'
177 h
.rightChars
[17] = '\n'
178 _
, err
= h
.w
.Write(h
.rightChars
[:])
188 func (h
*dumper
) Close() (err error
) {
189 // See the comments in Write() for the details of this format.
203 } else if h
.used
== 15 {
206 _
, err
= h
.w
.Write(h
.buf
[:l
])
212 h
.rightChars
[nBytes
] = '|'
213 h
.rightChars
[nBytes
+1] = '\n'
214 _
, err
= h
.w
.Write(h
.rightChars
[:nBytes
+2])