// Copyright 2009 The Go Authors. All rights reserved.// Use of this source code is governed by a BSD-style// license that can be found in the LICENSE file.
// Package hex implements hexadecimal encoding and decoding.
package heximport ()const ( hextable = "0123456789abcdef" reverseHexTable = "" +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xff\xff\xff\xff\xff\xff" +"\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff")// EncodedLen returns the length of an encoding of n source bytes.// Specifically, it returns n * 2.func ( int) int { return * 2 }// Encode encodes src into [EncodedLen](len(src))// bytes of dst. As a convenience, it returns the number// of bytes written to dst, but this value is always [EncodedLen](len(src)).// Encode implements hexadecimal encoding.func (, []byte) int { := 0for , := range { [] = hextable[>>4] [+1] = hextable[&0x0f] += 2 }returnlen() * 2}// AppendEncode appends the hexadecimally encoded src to dst// and returns the extended buffer.func (, []byte) []byte { := EncodedLen(len()) = slices.Grow(, )Encode([len():][:], )return [:len()+]}// ErrLength reports an attempt to decode an odd-length input// using [Decode] or [DecodeString].// The stream-based Decoder returns [io.ErrUnexpectedEOF] instead of ErrLength.varErrLength = errors.New("encoding/hex: odd length hex string")// InvalidByteError values describe errors resulting from an invalid byte in a hex string.typeInvalidByteErrorbytefunc ( InvalidByteError) () string {returnfmt.Sprintf("encoding/hex: invalid byte: %#U", rune())}// DecodedLen returns the length of a decoding of x source bytes.// Specifically, it returns x / 2.func ( int) int { return / 2 }// Decode decodes src into [DecodedLen](len(src)) bytes,// returning the actual number of bytes written to dst.//// Decode expects that src contains only hexadecimal// characters and that src has even length.// If the input is malformed, Decode returns the number// of bytes decoded before the error.func (, []byte) (int, error) { , := 0, 1for ; < len(); += 2 { := [-1] := [] := reverseHexTable[] := reverseHexTable[]if > 0x0f {return , InvalidByteError() }if > 0x0f {return , InvalidByteError() } [] = ( << 4) | ++ }iflen()%2 == 1 {// Check for invalid char before reporting bad length, // since the invalid char (if present) is an earlier problem.ifreverseHexTable[[-1]] > 0x0f {return , InvalidByteError([-1]) }return , ErrLength }return , nil}// AppendDecode appends the hexadecimally decoded src to dst// and returns the extended buffer.// If the input is malformed, it returns the partially decoded src and an error.func (, []byte) ([]byte, error) { := DecodedLen(len()) = slices.Grow(, ) , := Decode([len():][:], )return [:len()+], }// EncodeToString returns the hexadecimal encoding of src.func ( []byte) string { := make([]byte, EncodedLen(len()))Encode(, )returnstring()}// DecodeString returns the bytes represented by the hexadecimal string s.//// DecodeString expects that src contains only hexadecimal// characters and that src has even length.// If the input is malformed, DecodeString returns// the bytes decoded before the error.func ( string) ([]byte, error) { := make([]byte, DecodedLen(len())) , := Decode(, []byte())return [:], }// Dump returns a string that contains a hex dump of the given data. The format// of the hex dump matches the output of `hexdump -C` on the command line.func ( []byte) string {iflen() == 0 {return"" }varstrings.Builder// Dumper will write 79 bytes per complete 16 byte chunk, and at least // 64 bytes for whatever remains. Round the allocation up, since only a // maximum of 15 bytes will be wasted. .Grow((1 + ((len() - 1) / 16)) * 79) := Dumper(&) .Write() .Close()return .String()}// bufferSize is the number of hexadecimal characters to buffer in encoder and decoder.const bufferSize = 1024type encoder struct { w io.Writer err error out [bufferSize]byte// output buffer}// NewEncoder returns an [io.Writer] that writes lowercase hexadecimal characters to w.func ( io.Writer) io.Writer {return &encoder{w: }}func ( *encoder) ( []byte) ( int, error) {forlen() > 0 && .err == nil { := bufferSize / 2iflen() < { = len() }varint := Encode(.out[:], [:]) , .err = .w.Write(.out[:]) += / 2 = [:] }return , .err}type decoder struct { r io.Reader err error in []byte// input buffer (encoded form) arr [bufferSize]byte// backing array for in}// NewDecoder returns an [io.Reader] that decodes hexadecimal characters from r.// NewDecoder expects that r contain only an even number of hexadecimal characters.func ( io.Reader) io.Reader {return &decoder{r: }}func ( *decoder) ( []byte) ( int, error) {// Fill internal buffer with sufficient bytes to decodeiflen(.in) < 2 && .err == nil {var , int = copy(.arr[:], .in) // Copies either 0 or 1 bytes , .err = .r.Read(.arr[:]) .in = .arr[:+]if .err == io.EOF && len(.in)%2 != 0 {if := reverseHexTable[.in[len(.in)-1]]; > 0x0f { .err = InvalidByteError(.in[len(.in)-1]) } else { .err = io.ErrUnexpectedEOF } } }// Decode internal buffer into output bufferif := len(.in) / 2; len() > { = [:] } , := Decode(, .in[:len()*2]) .in = .in[2*:]if != nil { .in, .err = nil, // Decode error; discard input remainder }iflen(.in) < 2 {return , .err// Only expose errors when buffer fully consumed }return , nil}// Dumper returns a [io.WriteCloser] that writes a hex dump of all written data to// w. The format of the dump matches the output of `hexdump -C` on the command// line.func ( io.Writer) io.WriteCloser {return &dumper{w: }}type dumper struct { w io.Writer rightChars [18]byte buf [14]byte used int// number of bytes in the current line n uint// number of bytes, total closed bool}func toChar( byte) byte {if < 32 || > 126 {return'.' }return}func ( *dumper) ( []byte) ( int, error) {if .closed {return0, errors.New("encoding/hex: dumper closed") }// Output lines look like: // 00000010 2e 2f 30 31 32 33 34 35 36 37 38 39 3a 3b 3c 3d |./0123456789:;<=| // ^ offset ^ extra space ^ ASCII of line.for := range {if .used == 0 {// At the beginning of a line we print the current // offset in hex. .buf[0] = byte(.n >> 24) .buf[1] = byte(.n >> 16) .buf[2] = byte(.n >> 8) .buf[3] = byte(.n)Encode(.buf[4:], .buf[:4]) .buf[12] = ' ' .buf[13] = ' ' _, = .w.Write(.buf[4:])if != nil {return } }Encode(.buf[:], [:+1]) .buf[2] = ' ' := 3if .used == 7 {// There's an additional space after the 8th byte. .buf[3] = ' ' = 4 } elseif .used == 15 {// At the end of the line there's an extra space and // the bar for the right column. .buf[3] = ' ' .buf[4] = '|' = 5 } _, = .w.Write(.buf[:])if != nil {return } ++ .rightChars[.used] = toChar([]) .used++ .n++if .used == 16 { .rightChars[16] = '|' .rightChars[17] = '\n' _, = .w.Write(.rightChars[:])if != nil {return } .used = 0 } }return}func ( *dumper) () ( error) {// See the comments in Write() for the details of this format.if .closed {return } .closed = trueif .used == 0 {return } .buf[0] = ' ' .buf[1] = ' ' .buf[2] = ' ' .buf[3] = ' ' .buf[4] = '|' := .usedfor .used < 16 { := 3if .used == 7 { = 4 } elseif .used == 15 { = 5 } _, = .w.Write(.buf[:])if != nil {return } .used++ } .rightChars[] = '|' .rightChars[+1] = '\n' _, = .w.Write(.rightChars[:+2])return}
The pages are generated with Goldsv0.6.9-preview. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds.