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