Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
hex.go354 linesDownload Raw Back to hex
1// Copyright 2009 The Go Authors. All rights reserved.2// Use of this source code is governed by a BSD-style3// license that can be found in the LICENSE file.4 5// Package hex implements hexadecimal encoding and decoding.6package hex7 8import (9	"errors"10	"fmt"11	"io"12	"slices"13	"strings"14)15 16const (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.39func 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 number43// of bytes written to dst, but this value is always [EncodedLen](len(src)).44// Encode implements hexadecimal encoding.45func Encode(dst, src []byte) int {46	j := 047	for _, v := range src {48		dst[j] = hextable[v>>4]49		dst[j+1] = hextable[v&0x0f]50		j += 251	}52	return len(src) * 253}54 55// AppendEncode appends the hexadecimally encoded src to dst56// and returns the extended buffer.57func 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 input65// using [Decode] or [DecodeString].66// The stream-based Decoder returns [io.ErrUnexpectedEOF] instead of ErrLength.67var ErrLength = errors.New("encoding/hex: odd length hex string")68 69// InvalidByteError values describe errors resulting from an invalid byte in a hex string.70type InvalidByteError byte71 72func (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.78func 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 hexadecimal84// characters and that src has even length.85// If the input is malformed, Decode returns the number86// of bytes decoded before the error.87func Decode(dst, src []byte) (int, error) {88	i, j := 0, 189	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) | b102		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, ErrLength111	}112	return i, nil113}114 115// AppendDecode appends the hexadecimally decoded src to dst116// and returns the extended buffer.117// If the input is malformed, it returns the partially decoded src and an error.118func 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], err123}124 125// EncodeToString returns the hexadecimal encoding of src.126func 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 hexadecimal135// characters and that src has even length.136// If the input is malformed, DecodeString returns137// the bytes decoded before the error.138func DecodeString(s string) ([]byte, error) {139	dst := make([]byte, DecodedLen(len(s)))140	n, err := Decode(dst, []byte(s))141	return dst[:n], err142}143 144// Dump returns a string that contains a hex dump of the given data. The format145// of the hex dump matches the output of `hexdump -C` on the command line.146func Dump(data []byte) string {147	if len(data) == 0 {148		return ""149	}150 151	var buf strings.Builder152	// Dumper will write 79 bytes per complete 16 byte chunk, and at least153	// 64 bytes for whatever remains. Round the allocation up, since only a154	// 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.164const bufferSize = 1024165 166type encoder struct {167	w   io.Writer168	err error169	out [bufferSize]byte // output buffer170}171 172// NewEncoder returns an [io.Writer] that writes lowercase hexadecimal characters to w.173func NewEncoder(w io.Writer) io.Writer {174	return &encoder{w: w}175}176 177func (e *encoder) Write(p []byte) (n int, err error) {178	for len(p) > 0 && e.err == nil {179		chunkSize := bufferSize / 2180		if len(p) < chunkSize {181			chunkSize = len(p)182		}183 184		var written int185		encoded := Encode(e.out[:], p[:chunkSize])186		written, e.err = e.w.Write(e.out[:encoded])187		n += written / 2188		p = p[chunkSize:]189	}190	return n, e.err191}192 193type decoder struct {194	r   io.Reader195	err error196	in  []byte           // input buffer (encoded form)197	arr [bufferSize]byte // backing array for in198}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.202func NewDecoder(r io.Reader) io.Reader {203	return &decoder{r: r}204}205 206func (d *decoder) Read(p []byte) (n int, err error) {207	// Fill internal buffer with sufficient bytes to decode208	if len(d.in) < 2 && d.err == nil {209		var numCopy, numRead int210		numCopy = copy(d.arr[:], d.in) // Copies either 0 or 1 bytes211		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.ErrUnexpectedEOF219			}220		}221	}222 223	// Decode internal buffer into output buffer224	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 remainder231	}232 233	if len(d.in) < 2 {234		return numDec, d.err // Only expose errors when buffer fully consumed235	}236	return numDec, nil237}238 239// Dumper returns a [io.WriteCloser] that writes a hex dump of all written data to240// w. The format of the dump matches the output of `hexdump -C` on the command241// line.242func Dumper(w io.Writer) io.WriteCloser {243	return &dumper{w: w}244}245 246type dumper struct {247	w          io.Writer248	rightChars [18]byte249	buf        [14]byte250	used       int  // number of bytes in the current line251	n          uint // number of bytes, total252	closed     bool253}254 255func toChar(b byte) byte {256	if b < 32 || b > 126 {257		return '.'258	}259	return b260}261 262func (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 current273			// 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				return284			}285		}286		Encode(h.buf[:], data[i:i+1])287		h.buf[2] = ' '288		l := 3289		if h.used == 7 {290			// There's an additional space after the 8th byte.291			h.buf[3] = ' '292			l = 4293		} else if h.used == 15 {294			// At the end of the line there's an extra space and295			// the bar for the right column.296			h.buf[3] = ' '297			h.buf[4] = '|'298			l = 5299		}300		_, err = h.w.Write(h.buf[:l])301		if err != nil {302			return303		}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				return314			}315			h.used = 0316		}317	}318	return319}320 321func (h *dumper) Close() (err error) {322	// See the comments in Write() for the details of this format.323	if h.closed {324		return325	}326	h.closed = true327	if h.used == 0 {328		return329	}330	h.buf[0] = ' '331	h.buf[1] = ' '332	h.buf[2] = ' '333	h.buf[3] = ' '334	h.buf[4] = '|'335	nBytes := h.used336	for h.used < 16 {337		l := 3338		if h.used == 7 {339			l = 4340		} else if h.used == 15 {341			l = 5342		}343		_, err = h.w.Write(h.buf[:l])344		if err != nil {345			return346		}347		h.used++348	}349	h.rightChars[nBytes] = '|'350	h.rightChars[nBytes+1] = '\n'351	_, err = h.w.Write(h.rightChars[:nBytes+2])352	return353}354 
codekingpro/portable-devtools · Team Ai