/* Package base36 provides a reasonably fast implementation of a binary base36 codec. */
package base36 // Simplified code based on https://godoc.org/github.com/mr-tron/base58 // which in turn is based on https://github.com/trezor/trezor-crypto/commit/89a7d7797b806fac import ( ) const UcAlphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" const LcAlphabet = "0123456789abcdefghijklmnopqrstuvwxyz" const maxDigitOrdinal = 'z' const maxDigitValueB36 = 35 var revAlphabet [maxDigitOrdinal + 1]byte func init() { for := range revAlphabet { revAlphabet[] = maxDigitValueB36 + 1 } for , := range UcAlphabet { revAlphabet[byte()] = byte() if > '9' { revAlphabet[byte()+32] = byte() } } } // EncodeToStringUc encodes the given byte-buffer as base36 using [0-9A-Z] as // the digit-alphabet func ( []byte) string { return encode(, UcAlphabet) } // EncodeToStringLc encodes the given byte-buffer as base36 using [0-9a-z] as // the digit-alphabet func ( []byte) string { return encode(, LcAlphabet) } func encode( []byte, string) string { := len() := 0 for < && [] == 0 { ++ } // It is crucial to make this as short as possible, especially for // the usual case of CIDs. = + // This is an integer simplification of // ceil(log(256)/log(36)) (-)*277/179 + 1 // Note: pools *DO NOT* help, the overhead of zeroing // kills any performance gain to be had := make([]byte, ) var , int var uint32 = - 1 for , := range [:] { = - 1 for = uint32(); > || != 0; -- { += uint32(([])) * 256 [] = byte( % 36) /= 36 } = } // Determine the additional "zero-gap" in the buffer (aside from zcnt) for = ; < && [] == 0; ++ { } // Now encode the values with actual alphabet in-place := [-:] = len() for = 0; < ; ++ { [] = [[]] } return string([:]) } // DecodeString takes a base36 encoded string and returns a slice of the decoded // bytes. func ( string) ([]byte, error) { if len() == 0 { return nil, fmt.Errorf("can not decode zero-length string") } := 0 for < len() && [] == '0' { ++ } // the 32bit algo stretches the result up to 2 times := make([]byte, 2*(((len())*179/277)+1)) // no more than 84 bytes when len(s) <= 64 := make([]uint32, (len()+3)/4) // no more than 16 bytes when len(s) <= 64 for , := range { if > maxDigitOrdinal || revAlphabet[] > maxDigitValueB36 { return nil, fmt.Errorf("invalid base36 character (%q)", ) } := uint64(revAlphabet[]) for := len() - 1; >= 0; -- { := uint64([])*36 + = ( >> 32) [] = uint32( & 0xFFFFFFFF) } } := (uint(len()%4) * 8) if == 0 { = 32 } -= 8 := 0 for := 0; < len(); ++ { for < 32 { // loop relies on uint overflow [] = byte([] >> ) -= 8 ++ } = 24 } // find the most significant byte post-decode, if any for := ; < ; ++ { if [] > 0 { return [- : : ], nil } } // it's all zeroes return [::], nil }