1
2
3
4
5
6 package hex
7
8 import (
9 "bytes"
10 "io"
11 "os"
12 "strconv"
13 )
14
15 const hextable = "0123456789abcdef"
16
17
18 func EncodedLen(n int) int { return n * 2 }
19
20
21
22
23
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]
28 }
29
30 return len(src) * 2
31 }
32
33
34 type OddLengthInputError struct{}
35
36 func (OddLengthInputError) String() string { return "odd length hex string" }
37
38
39 type InvalidHexCharError byte
40
41 func (e InvalidHexCharError) String() string {
42 return "invalid hex char: " + strconv.Itoa(int(e))
43 }
44
45 func DecodedLen(x int) int { return x / 2 }
46
47
48
49
50
51
52 func Decode(dst, src []byte) (int, os.Error) {
53 if len(src)%2 == 1 {
54 return 0, OddLengthInputError{}
55 }
56
57 for i := 0; i < len(src)/2; i++ {
58 a, ok := fromHexChar(src[i*2])
59 if !ok {
60 return 0, InvalidHexCharError(src[i*2])
61 }
62 b, ok := fromHexChar(src[i*2+1])
63 if !ok {
64 return 0, InvalidHexCharError(src[i*2+1])
65 }
66 dst[i] = (a << 4) | b
67 }
68
69 return len(src) / 2, nil
70 }
71
72
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
87 func EncodeToString(src []byte) string {
88 dst := make([]byte, EncodedLen(len(src)))
89 Encode(dst, src)
90 return string(dst)
91 }
92
93
94 func DecodeString(s string) ([]byte, os.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
105
106 func Dump(data []byte) string {
107 buf := bytes.NewBuffer(nil)
108 dumper := Dumper(buf)
109 dumper.Write(data)
110 dumper.Close()
111 return string(buf.Bytes())
112 }
113
114
115
116
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
126 n uint
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 os.Error) {
137
138
139
140 for i := range data {
141 if h.used == 0 {
142
143
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 }
153 Encode(h.buf[:], data[i:i+1])
154 h.buf[2] = ' '
155 l := 3
156 if h.used == 7 {
157
158 h.buf[3] = ' '
159 l = 4
160 } else if h.used == 15 {
161
162
163 h.buf[3] = ' '
164 h.buf[4] = '|'
165 l = 5
166 }
167 _, err = h.w.Write(h.buf[:l])
168 if err != nil {
169 return
170 }
171 n++
172 h.rightChars[h.used] = toChar(data[i])
173 h.used++
174 h.n++
175 if h.used == 16 {
176 h.rightChars[16] = '|'
177 h.rightChars[17] = '\n'
178 _, err = h.w.Write(h.rightChars[:])
179 if err != nil {
180 return
181 }
182 h.used = 0
183 }
184 }
185 return
186 }
187
188 func (h *dumper) Close() (err os.Error) {
189
190 if h.used == 0 {
191 return
192 }
193 h.buf[0] = ' '
194 h.buf[1] = ' '
195 h.buf[2] = ' '
196 h.buf[3] = ' '
197 h.buf[4] = '|'
198 nBytes := h.used
199 for h.used < 16 {
200 l := 3
201 if h.used == 7 {
202 l = 4
203 } else if h.used == 15 {
204 l = 5
205 }
206 _, err = h.w.Write(h.buf[:l])
207 if err != nil {
208 return
209 }
210 h.used++
211 }
212 h.rightChars[nBytes] = '|'
213 h.rightChars[nBytes+1] = '\n'
214 _, err = h.w.Write(h.rightChars[:nBytes+2])
215 return
216 }