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 // Specifically, it returns n * 2.
19 func EncodedLen(n
int) int { return n
* 2 }
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.
25 func 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]
34 // ErrLength results from decoding an odd length slice.
35 var ErrLength
= errors
.New("encoding/hex: odd length hex string")
37 // InvalidByteError values describe errors resulting from an invalid byte in a hex string.
38 type InvalidByteError
byte
40 func (e InvalidByteError
) Error() string {
41 return fmt
.Sprintf("encoding/hex: invalid byte: %#U", rune(e
))
44 // DecodedLen returns the length of a decoding of x source bytes.
45 // Specifically, it returns x / 2.
46 func DecodedLen(x
int) int { return x
/ 2 }
48 // Decode decodes src into DecodedLen(len(src)) bytes,
49 // returning the actual number of bytes written to dst.
51 // Decode expects that src contain only hexadecimal
52 // characters and that src should have an even length.
53 func Decode(dst
, src
[]byte) (int, error
) {
58 for i
:= 0; i
< len(src
)/2; i
++ {
59 a
, ok
:= fromHexChar(src
[i
*2])
61 return 0, InvalidByteError(src
[i
*2])
63 b
, ok
:= fromHexChar(src
[i
*2+1])
65 return 0, InvalidByteError(src
[i
*2+1])
70 return len(src
) / 2, nil
73 // fromHexChar converts a hex character into its value and a success flag.
74 func fromHexChar(c
byte) (byte, bool) {
76 case '0' <= c
&& c
<= '9':
78 case 'a' <= c
&& c
<= 'f':
79 return c
- 'a' + 10, true
80 case 'A' <= c
&& c
<= 'F':
81 return c
- 'A' + 10, true
87 // EncodeToString returns the hexadecimal encoding of src.
88 func EncodeToString(src
[]byte) string {
89 dst
:= make([]byte, EncodedLen(len(src
)))
94 // DecodeString returns the bytes represented by the hexadecimal string s.
95 func DecodeString(s
string) ([]byte, error
) {
97 dst
:= make([]byte, DecodedLen(len(src
)))
98 _
, err
:= Decode(dst
, src
)
105 // Dump returns a string that contains a hex dump of the given data. The format
106 // of the hex dump matches the output of `hexdump -C` on the command line.
107 func Dump(data
[]byte) string {
109 dumper
:= Dumper(&buf
)
115 // Dumper returns a WriteCloser that writes a hex dump of all written data to
116 // w. The format of the dump matches the output of `hexdump -C` on the command
118 func Dumper(w io
.Writer
) io
.WriteCloser
{
126 used
int // number of bytes in the current line
127 n
uint // number of bytes, total
130 func toChar(b
byte) byte {
131 if b
< 32 || b
> 126 {
137 func (h
*dumper
) Write(data
[]byte) (n
int, err error
) {
138 // Output lines look like:
139 // 00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=|
140 // ^ offset ^ extra space ^ ASCII of line.
141 for i
:= range data
{
143 // At the beginning of a line we print the current
145 h
.buf
[0] = byte(h
.n
>> 24)
146 h
.buf
[1] = byte(h
.n
>> 16)
147 h
.buf
[2] = byte(h
.n
>> 8)
149 Encode(h
.buf
[4:], h
.buf
[:4])
152 _
, err
= h
.w
.Write(h
.buf
[4:])
157 Encode(h
.buf
[:], data
[i
:i
+1])
161 // There's an additional space after the 8th byte.
164 } else if h
.used
== 15 {
165 // At the end of the line there's an extra space and
166 // the bar for the right column.
171 _
, err
= h
.w
.Write(h
.buf
[:l
])
176 h
.rightChars
[h
.used
] = toChar(data
[i
])
180 h
.rightChars
[16] = '|'
181 h
.rightChars
[17] = '\n'
182 _
, err
= h
.w
.Write(h
.rightChars
[:])
192 func (h
*dumper
) Close() (err error
) {
193 // See the comments in Write() for the details of this format.
207 } else if h
.used
== 15 {
210 _
, err
= h
.w
.Write(h
.buf
[:l
])
216 h
.rightChars
[nBytes
] = '|'
217 h
.rightChars
[nBytes
+1] = '\n'
218 _
, err
= h
.w
.Write(h
.rightChars
[:nBytes
+2])