]> Cypherpunks.ru repositories - gostls13.git/blob - src/encoding/hex/hex.go
encoding: add AppendEncode and AppendDecode
[gostls13.git] / src / encoding / hex / hex.go
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         "strings"
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) string {
127         dst := make([]byte, EncodedLen(len(src)))
128         Encode(dst, src)
129         return string(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 string) ([]byte, error) {
139         src := []byte(s)
140         // We can use the source slice itself as the destination
141         // because the decode loop increments by one and then the 'seen' byte is not used anymore.
142         n, err := Decode(src, src)
143         return src[:n], err
144 }
145
146 // Dump returns a string that contains a hex dump of the given data. The format
147 // of the hex dump matches the output of `hexdump -C` on the command line.
148 func Dump(data []byte) string {
149         if len(data) == 0 {
150                 return ""
151         }
152
153         var buf strings.Builder
154         // Dumper will write 79 bytes per complete 16 byte chunk, and at least
155         // 64 bytes for whatever remains. Round the allocation up, since only a
156         // maximum of 15 bytes will be wasted.
157         buf.Grow((1 + ((len(data) - 1) / 16)) * 79)
158
159         dumper := Dumper(&buf)
160         dumper.Write(data)
161         dumper.Close()
162         return buf.String()
163 }
164
165 // bufferSize is the number of hexadecimal characters to buffer in encoder and decoder.
166 const bufferSize = 1024
167
168 type encoder struct {
169         w   io.Writer
170         err error
171         out [bufferSize]byte // output buffer
172 }
173
174 // NewEncoder returns an io.Writer that writes lowercase hexadecimal characters to w.
175 func NewEncoder(w io.Writer) io.Writer {
176         return &encoder{w: w}
177 }
178
179 func (e *encoder) Write(p []byte) (n int, err error) {
180         for len(p) > 0 && e.err == nil {
181                 chunkSize := bufferSize / 2
182                 if len(p) < chunkSize {
183                         chunkSize = len(p)
184                 }
185
186                 var written int
187                 encoded := Encode(e.out[:], p[:chunkSize])
188                 written, e.err = e.w.Write(e.out[:encoded])
189                 n += written / 2
190                 p = p[chunkSize:]
191         }
192         return n, e.err
193 }
194
195 type decoder struct {
196         r   io.Reader
197         err error
198         in  []byte           // input buffer (encoded form)
199         arr [bufferSize]byte // backing array for in
200 }
201
202 // NewDecoder returns an io.Reader that decodes hexadecimal characters from r.
203 // NewDecoder expects that r contain only an even number of hexadecimal characters.
204 func NewDecoder(r io.Reader) io.Reader {
205         return &decoder{r: r}
206 }
207
208 func (d *decoder) Read(p []byte) (n int, err error) {
209         // Fill internal buffer with sufficient bytes to decode
210         if len(d.in) < 2 && d.err == nil {
211                 var numCopy, numRead int
212                 numCopy = copy(d.arr[:], d.in) // Copies either 0 or 1 bytes
213                 numRead, d.err = d.r.Read(d.arr[numCopy:])
214                 d.in = d.arr[:numCopy+numRead]
215                 if d.err == io.EOF && len(d.in)%2 != 0 {
216
217                         if a := reverseHexTable[d.in[len(d.in)-1]]; a > 0x0f {
218                                 d.err = InvalidByteError(d.in[len(d.in)-1])
219                         } else {
220                                 d.err = io.ErrUnexpectedEOF
221                         }
222                 }
223         }
224
225         // Decode internal buffer into output buffer
226         if numAvail := len(d.in) / 2; len(p) > numAvail {
227                 p = p[:numAvail]
228         }
229         numDec, err := Decode(p, d.in[:len(p)*2])
230         d.in = d.in[2*numDec:]
231         if err != nil {
232                 d.in, d.err = nil, err // Decode error; discard input remainder
233         }
234
235         if len(d.in) < 2 {
236                 return numDec, d.err // Only expose errors when buffer fully consumed
237         }
238         return numDec, nil
239 }
240
241 // Dumper returns a WriteCloser that writes a hex dump of all written data to
242 // w. The format of the dump matches the output of `hexdump -C` on the command
243 // line.
244 func Dumper(w io.Writer) io.WriteCloser {
245         return &dumper{w: w}
246 }
247
248 type dumper struct {
249         w          io.Writer
250         rightChars [18]byte
251         buf        [14]byte
252         used       int  // number of bytes in the current line
253         n          uint // number of bytes, total
254         closed     bool
255 }
256
257 func toChar(b byte) byte {
258         if b < 32 || b > 126 {
259                 return '.'
260         }
261         return b
262 }
263
264 func (h *dumper) Write(data []byte) (n int, err error) {
265         if h.closed {
266                 return 0, errors.New("encoding/hex: dumper closed")
267         }
268
269         // Output lines look like:
270         // 00000010  2e 2f 30 31 32 33 34 35  36 37 38 39 3a 3b 3c 3d  |./0123456789:;<=|
271         // ^ offset                          ^ extra space              ^ ASCII of line.
272         for i := range data {
273                 if h.used == 0 {
274                         // At the beginning of a line we print the current
275                         // offset in hex.
276                         h.buf[0] = byte(h.n >> 24)
277                         h.buf[1] = byte(h.n >> 16)
278                         h.buf[2] = byte(h.n >> 8)
279                         h.buf[3] = byte(h.n)
280                         Encode(h.buf[4:], h.buf[:4])
281                         h.buf[12] = ' '
282                         h.buf[13] = ' '
283                         _, err = h.w.Write(h.buf[4:])
284                         if err != nil {
285                                 return
286                         }
287                 }
288                 Encode(h.buf[:], data[i:i+1])
289                 h.buf[2] = ' '
290                 l := 3
291                 if h.used == 7 {
292                         // There's an additional space after the 8th byte.
293                         h.buf[3] = ' '
294                         l = 4
295                 } else if h.used == 15 {
296                         // At the end of the line there's an extra space and
297                         // the bar for the right column.
298                         h.buf[3] = ' '
299                         h.buf[4] = '|'
300                         l = 5
301                 }
302                 _, err = h.w.Write(h.buf[:l])
303                 if err != nil {
304                         return
305                 }
306                 n++
307                 h.rightChars[h.used] = toChar(data[i])
308                 h.used++
309                 h.n++
310                 if h.used == 16 {
311                         h.rightChars[16] = '|'
312                         h.rightChars[17] = '\n'
313                         _, err = h.w.Write(h.rightChars[:])
314                         if err != nil {
315                                 return
316                         }
317                         h.used = 0
318                 }
319         }
320         return
321 }
322
323 func (h *dumper) Close() (err error) {
324         // See the comments in Write() for the details of this format.
325         if h.closed {
326                 return
327         }
328         h.closed = true
329         if h.used == 0 {
330                 return
331         }
332         h.buf[0] = ' '
333         h.buf[1] = ' '
334         h.buf[2] = ' '
335         h.buf[3] = ' '
336         h.buf[4] = '|'
337         nBytes := h.used
338         for h.used < 16 {
339                 l := 3
340                 if h.used == 7 {
341                         l = 4
342                 } else if h.used == 15 {
343                         l = 5
344                 }
345                 _, err = h.w.Write(h.buf[:l])
346                 if err != nil {
347                         return
348                 }
349                 h.used++
350         }
351         h.rightChars[nBytes] = '|'
352         h.rightChars[nBytes+1] = '\n'
353         _, err = h.w.Write(h.rightChars[:nBytes+2])
354         return
355 }