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  }