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