// Copyright 2011 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 base32 implements base32 encoding as specified by RFC 4648.
package base32import ()/* * Encodings */// An Encoding is a radix 32 encoding/decoding scheme, defined by a// 32-character alphabet. The most common is the "base32" encoding// introduced for SASL GSSAPI and standardized in RFC 4648.// The alternate "base32hex" encoding is used in DNSSEC.typeEncodingstruct { encode string decodeMap [256]byte padChar rune}// Alphabet returns the Base32 alphabet usedfunc ( *Encoding) () string {return .encode}const (StdPaddingrune = '='NoPaddingrune = -1)const encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"const encodeHex = "0123456789ABCDEFGHIJKLMNOPQRSTUV"// NewEncoding returns a new Encoding defined by the given alphabet,// which must be a 32-byte string.func ( string) *Encoding { := new(Encoding) .padChar = StdPadding .encode = for := 0; < len(.decodeMap); ++ { .decodeMap[] = 0xFF }for := 0; < len(); ++ { .decodeMap[[]] = byte() }return}// NewEncoding returns a new case insensitive Encoding defined by the// given alphabet, which must be a 32-byte string.func ( string) *Encoding { := new(Encoding) .padChar = StdPadding .encode = for := 0; < len(.decodeMap); ++ { .decodeMap[] = 0xFF }for := 0; < len(); ++ { .decodeMap[asciiToLower([])] = byte() .decodeMap[asciiToUpper([])] = byte() }return}func asciiToLower( byte) byte {if >= 'A' && <= 'Z' {return + 32 }return}func asciiToUpper( byte) byte {if >= 'a' && <= 'z' {return - 32 }return}// WithPadding creates a new encoding identical to enc except// with a specified padding character, or NoPadding to disable padding.func ( Encoding) ( rune) *Encoding { .padChar = return &}// StdEncoding is the standard base32 encoding, as defined in// RFC 4648.varStdEncoding = NewEncodingCI(encodeStd)// HexEncoding is the “Extended Hex Alphabet” defined in RFC 4648.// It is typically used in DNS.varHexEncoding = NewEncodingCI(encodeHex)varRawStdEncoding = NewEncodingCI(encodeStd).WithPadding(NoPadding)varRawHexEncoding = NewEncodingCI(encodeHex).WithPadding(NoPadding)/* * Encoder */// Encode encodes src using the encoding enc, writing// EncodedLen(len(src)) bytes to dst.//// The encoding pads the output to a multiple of 8 bytes,// so Encode is not appropriate for use on individual blocks// of a large data stream. Use NewEncoder() instead.func ( *Encoding) (, []byte) {iflen() == 0 {return }// Unpack 8x 5-bit source blocks into a 5 byte // destination quantumforlen() > 4 { [7] = .encode[[4]&0x1F] [6] = .encode[([4]>>5)|([3]<<3)&0x1F] [5] = .encode[([3]>>2)&0x1F] [4] = .encode[([3]>>7)|([2]<<1)&0x1F] [3] = .encode[(([2]>>4)|([1]<<4))&0x1F] [2] = .encode[([1]>>1)&0x1F] [1] = .encode[(([1]>>6)|([0]<<2))&0x1F] [0] = .encode[[0]>>3] = [5:] = [8:] }varbyteswitchlen() {case4: [6] = .encode[([3]<<3)&0x1F] [5] = .encode[([3]>>2)&0x1F] = [3] >> 7fallthroughcase3: [4] = .encode[|([2]<<1)&0x1F] = ([2] >> 4) & 0x1Ffallthroughcase2: [3] = .encode[|([1]<<4)&0x1F] [2] = .encode[([1]>>1)&0x1F] = ([1] >> 6) & 0x1Ffallthroughcase1: [1] = .encode[|([0]<<2)&0x1F] [0] = .encode[[0]>>3]case0:return }if .padChar != NoPadding { [7] = byte(.padChar)iflen() < 4 { [6] = byte(.padChar) [5] = byte(.padChar)iflen() < 3 { [4] = byte(.padChar)iflen() < 2 { [3] = byte(.padChar) [2] = byte(.padChar) } } } }}// EncodeToString returns the base32 encoding of src.func ( *Encoding) ( []byte) string { := make([]byte, .EncodedLen(len())) .Encode(, )returnstring()}type encoder struct { err error enc *Encoding w io.Writer buf [5]byte// buffered data waiting to be encoded nbuf int// number of bytes in buf out [1024]byte// output buffer}func ( *encoder) ( []byte) ( int, error) {if .err != nil {return0, .err }// Leading fringe.if .nbuf > 0 {varintfor = 0; < len() && .nbuf < 5; ++ { .buf[.nbuf] = [] .nbuf++ } += = [:]if .nbuf < 5 {return } .enc.Encode(.out[0:], .buf[0:])if _, .err = .w.Write(.out[0:8]); .err != nil {return , .err } .nbuf = 0 }// Large interior chunks.forlen() >= 5 { := len(.out) / 8 * 5if > len() { = len() -= % 5 } .enc.Encode(.out[0:], [0:])if _, .err = .w.Write(.out[0 : /5*8]); .err != nil {return , .err } += = [:] }// Trailing fringe. //lint:ignore S1001 fixed-length 5-byte slicefor := 0; < len(); ++ { .buf[] = [] } .nbuf = len() += len()return}// Close flushes any pending output from the encoder.// It is an error to call Write after calling Close.func ( *encoder) () error {// If there's anything left in the buffer, flush it outif .err == nil && .nbuf > 0 { .enc.Encode(.out[0:], .buf[0:.nbuf]) .nbuf = 0 _, .err = .w.Write(.out[0:8]) }return .err}// NewEncoder returns a new base32 stream encoder. Data written to// the returned writer will be encoded using enc and then written to w.// Base32 encodings operate in 5-byte blocks; when finished// writing, the caller must Close the returned encoder to flush any// partially written blocks.func ( *Encoding, io.Writer) io.WriteCloser {return &encoder{enc: , w: }}// EncodedLen returns the length in bytes of the base32 encoding// of an input buffer of length n.func ( *Encoding) ( int) int {if .padChar == NoPadding {return (*8 + 4) / 5// minimum # chars at 5 bits per char }return ( + 4) / 5 * 8}/* * Decoder */typeCorruptInputErrorint64func ( CorruptInputError) () string {return"illegal base32 data at input byte " + strconv.FormatInt(int64(), 10)}// decode is like Decode but returns an additional 'end' value, which// indicates if end-of-message padding was encountered and thus any// additional data is an error. This method assumes that src has been// stripped of all supported whitespace ('\r' and '\n').func ( *Encoding) (, []byte) ( int, bool, error) { := len()forlen() > 0 && ! {// Decode quantum using the base32 alphabetvar [8]byte := 8for := 0; < 8; {iflen() == 0 {if .padChar != NoPadding {return , false, CorruptInputError( - len() - ) } = break } := [0] = [1:]if == byte(.padChar) && >= 2 && len() < 8 {if .padChar == NoPadding {return , false, CorruptInputError() }// We've reached the end and there's paddingiflen()+ < 8-1 {// not enough paddingreturn , false, CorruptInputError() }for := 0; < 8-1-; ++ {iflen() > && [] != byte(.padChar) {// incorrect paddingreturn , false, CorruptInputError( - len() + - 1) } } , = , true// 7, 5 and 2 are not valid padding lengths, and so 1, 3 and 6 are not // valid dlen values. See RFC 4648 Section 6 "Base 32 Encoding" listing // the five valid padding lengths, and Section 9 "Illustrations and // Examples" for an illustration for how the 1st, 3rd and 6th base32 // src bytes do not yield enough information to decode a dst byte.if == 1 || == 3 || == 6 {return , false, CorruptInputError( - len() - 1) }break } [] = .decodeMap[]if [] == 0xFF {return , false, CorruptInputError( - len() - 1) } ++ }// Pack 8x 5-bit source blocks into 5 byte destination // quantumswitch {case8: [4] = [6]<<5 | [7]fallthroughcase7: [3] = [4]<<7 | [5]<<2 | [6]>>3fallthroughcase5: [2] = [3]<<4 | [4]>>1fallthroughcase4: [1] = [1]<<6 | [2]<<1 | [3]>>4fallthroughcase2: [0] = [0]<<3 | [1]>>2 }iflen() > 5 { = [5:] }switch {case2: += 1case4: += 2case5: += 3case7: += 4case8: += 5 } }return , , nil}// Decode decodes src using the encoding enc. It writes at most// DecodedLen(len(src)) bytes to dst and returns the number of bytes// written. If src contains invalid base32 data, it will return the// number of bytes successfully written and CorruptInputError.// New line characters (\r and \n) are ignored.func ( *Encoding) (, []byte) ( int, error) {// FIXME: if dst is the same as s use decodeInPlace := make([]byte, 0, len())for , := range {if != '\r' && != '\n' { = append(, ) } } , _, = .decode(, )return}func ( *Encoding) ( []byte) ( int, error) { := 0for , := range {if == '\n' || == '\r' {continue } [] = ++ } , _, = .decode(, [:])return}// DecodeString returns the bytes represented by the base32 string s.func ( *Encoding) ( string) ([]byte, error) { := []byte() , := .decodeInPlace()if != nil {returnnil, }return [:], nil}type decoder struct { err error enc *Encoding r io.Reader end bool// saw end of message buf [1024]byte// leftover input nbuf int out []byte// leftover decoded output outbuf [1024 / 8 * 5]byte}func ( *decoder) ( []byte) ( int, error) {if .err != nil {return0, .err }// Use leftover decoded output from last read.iflen(.out) > 0 { = copy(, .out) .out = .out[:]return , nil }// Read a chunk. := len() / 5 * 8if < 8 { = 8 }if > len(.buf) { = len(.buf) } , .err = io.ReadAtLeast(.r, .buf[.nbuf:], 8-.nbuf) .nbuf += if .nbuf < 8 {return0, .err }// Decode chunk into p, or d.out and then p if p is too small. := .nbuf / 8 * 8 := .nbuf / 8 * 5if > len() { , .end, .err = .enc.decode(.outbuf[0:], .buf[0:]) .out = .outbuf[0:] = copy(, .out) .out = .out[:] } else { , .end, .err = .enc.decode(, .buf[0:]) } .nbuf -= for := 0; < .nbuf; ++ { .buf[] = .buf[+] }if .err == nil { .err = }return , .err}type newlineFilteringReader struct { wrapped io.Reader}func ( *newlineFilteringReader) ( []byte) (int, error) { , := .wrapped.Read()for > 0 { := 0for , := range [0:] {if != '\r' && != '\n' {if != { [] = } ++ } }if > 0 {return , }// Previous buffer entirely whitespace, read again , = .wrapped.Read() }return , }// NewDecoder constructs a new base32 stream decoder.func ( *Encoding, io.Reader) io.Reader {return &decoder{enc: , r: &newlineFilteringReader{}}}// DecodedLen returns the maximum length in bytes of the decoded data// corresponding to n bytes of base32-encoded data.func ( *Encoding) ( int) int {if .padChar == NoPadding {return (*5 + 7) / 8 }return / 8 * 5}
The pages are generated with Goldsv0.8.2. (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 @zigo_101 (reachable from the left QR code) to get the latest news of Golds.