PR tree-optimization/82929
[official-gcc.git] / libgo / go / encoding / hex / hex.go
blob2768f1bac69927c5ba6d59c05ce250861c8228a7
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.
6 package hex
8 import (
9 "bytes"
10 "errors"
11 "fmt"
12 "io"
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]
31 return len(src) * 2
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) {
54 if len(src)%2 == 1 {
55 return 0, ErrLength
58 for i := 0; i < len(src)/2; i++ {
59 a, ok := fromHexChar(src[i*2])
60 if !ok {
61 return 0, InvalidByteError(src[i*2])
63 b, ok := fromHexChar(src[i*2+1])
64 if !ok {
65 return 0, InvalidByteError(src[i*2+1])
67 dst[i] = (a << 4) | b
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) {
75 switch {
76 case '0' <= c && c <= '9':
77 return c - '0', true
78 case 'a' <= c && c <= 'f':
79 return c - 'a' + 10, true
80 case 'A' <= c && c <= 'F':
81 return c - 'A' + 10, true
84 return 0, false
87 // EncodeToString returns the hexadecimal encoding of src.
88 func EncodeToString(src []byte) string {
89 dst := make([]byte, EncodedLen(len(src)))
90 Encode(dst, src)
91 return string(dst)
94 // DecodeString returns the bytes represented by the hexadecimal string s.
95 func DecodeString(s string) ([]byte, error) {
96 src := []byte(s)
97 dst := make([]byte, DecodedLen(len(src)))
98 _, err := Decode(dst, src)
99 if err != nil {
100 return nil, err
102 return dst, nil
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 {
108 var buf bytes.Buffer
109 dumper := Dumper(&buf)
110 dumper.Write(data)
111 dumper.Close()
112 return buf.String()
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
117 // line.
118 func Dumper(w io.Writer) io.WriteCloser {
119 return &dumper{w: w}
122 type dumper struct {
123 w io.Writer
124 rightChars [18]byte
125 buf [14]byte
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 {
132 return '.'
134 return b
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 {
142 if h.used == 0 {
143 // At the beginning of a line we print the current
144 // offset in hex.
145 h.buf[0] = byte(h.n >> 24)
146 h.buf[1] = byte(h.n >> 16)
147 h.buf[2] = byte(h.n >> 8)
148 h.buf[3] = byte(h.n)
149 Encode(h.buf[4:], h.buf[:4])
150 h.buf[12] = ' '
151 h.buf[13] = ' '
152 _, err = h.w.Write(h.buf[4:])
153 if err != nil {
154 return
157 Encode(h.buf[:], data[i:i+1])
158 h.buf[2] = ' '
159 l := 3
160 if h.used == 7 {
161 // There's an additional space after the 8th byte.
162 h.buf[3] = ' '
163 l = 4
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.
167 h.buf[3] = ' '
168 h.buf[4] = '|'
169 l = 5
171 _, err = h.w.Write(h.buf[:l])
172 if err != nil {
173 return
176 h.rightChars[h.used] = toChar(data[i])
177 h.used++
178 h.n++
179 if h.used == 16 {
180 h.rightChars[16] = '|'
181 h.rightChars[17] = '\n'
182 _, err = h.w.Write(h.rightChars[:])
183 if err != nil {
184 return
186 h.used = 0
189 return
192 func (h *dumper) Close() (err error) {
193 // See the comments in Write() for the details of this format.
194 if h.used == 0 {
195 return
197 h.buf[0] = ' '
198 h.buf[1] = ' '
199 h.buf[2] = ' '
200 h.buf[3] = ' '
201 h.buf[4] = '|'
202 nBytes := h.used
203 for h.used < 16 {
204 l := 3
205 if h.used == 7 {
206 l = 4
207 } else if h.used == 15 {
208 l = 5
210 _, err = h.w.Write(h.buf[:l])
211 if err != nil {
212 return
214 h.used++
216 h.rightChars[nBytes] = '|'
217 h.rightChars[nBytes+1] = '\n'
218 _, err = h.w.Write(h.rightChars[:nBytes+2])
219 return