bitbucket.org/ai69/amoy@v0.2.3/base36.go (about)

     1  package amoy
     2  
     3  // Migrate from https://github.com/martinlindhe/base36/blob/master/base36.go
     4  
     5  import (
     6  	"math/big"
     7  	"strings"
     8  )
     9  
    10  var (
    11  	bigRadix   = big.NewInt(36)
    12  	bigZero    = big.NewInt(0)
    13  	base36     = []byte("0123456789abcdefghijklmnopqrstuvwxyz")
    14  	uint8Index = []uint64{
    15  		0,
    16  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    17  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    18  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    19  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    20  		0, 0, 0, 0, 0, 0, 0, 0, 1, 2,
    21  		3, 4, 5, 6, 7, 8, 9, 0, 0, 0,
    22  		0, 0, 0, 0, 10, 11, 12, 13, 14,
    23  		15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
    24  		25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
    25  		35, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13,
    26  		14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
    27  		24, 25, 26, 27, 28, 29, 30, 31, 32, 33,
    28  		34, 35, 0, 0, 0, 0, 0, 0, 0, 0,
    29  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    30  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    31  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    32  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    33  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    34  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    35  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    36  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    37  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    38  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    39  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    40  		0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
    41  		0, 0, 0, 0, 0, // 256
    42  	}
    43  	pow36Index = []uint64{
    44  		1, 36, 1296, 46656, 1679616, 60466176,
    45  		2176782336, 78364164096, 2821109907456,
    46  		101559956668416, 3656158440062976,
    47  		131621703842267136, 4738381338321616896,
    48  		9223372036854775808,
    49  	}
    50  )
    51  
    52  // EncodeBytesAsBase36Bytes encodes a byte slice to base36.
    53  func EncodeBytesAsBase36Bytes(b []byte) []byte {
    54  	x := new(big.Int)
    55  	x.SetBytes(b)
    56  
    57  	answer := make([]byte, 0, len(b)*136/100)
    58  	for x.Cmp(bigZero) > 0 {
    59  		mod := new(big.Int)
    60  		x.DivMod(x, bigRadix, mod)
    61  		answer = append(answer, base36[mod.Int64()])
    62  	}
    63  
    64  	// leading zero bytes
    65  	for _, i := range b {
    66  		if i != 0 {
    67  			break
    68  		}
    69  		answer = append(answer, base36[0])
    70  	}
    71  
    72  	// reverse
    73  	alen := len(answer)
    74  	for i := 0; i < alen/2; i++ {
    75  		answer[i], answer[alen-1-i] = answer[alen-1-i], answer[i]
    76  	}
    77  
    78  	return answer
    79  }
    80  
    81  // EncodeBytesAsBase36 encodes a byte slice to base36 string.
    82  func EncodeBytesAsBase36(b []byte) string {
    83  	return string(EncodeBytesAsBase36Bytes(b))
    84  }
    85  
    86  // DecodeBase36ToBytes decodes a base36 string to a byte slice, using alphabet.
    87  func DecodeBase36ToBytes(b string) []byte {
    88  	alphabet := string(base36)
    89  	answer := big.NewInt(0)
    90  	j := big.NewInt(1)
    91  
    92  	for i := len(b) - 1; i >= 0; i-- {
    93  		tmp := strings.IndexAny(alphabet, string(b[i]))
    94  		if tmp == -1 {
    95  			return []byte("")
    96  		}
    97  		idx := big.NewInt(int64(tmp))
    98  		tmp1 := big.NewInt(0)
    99  		tmp1.Mul(j, idx)
   100  
   101  		answer.Add(answer, tmp1)
   102  		j.Mul(j, bigRadix)
   103  	}
   104  
   105  	tmpval := answer.Bytes()
   106  
   107  	var numZeros int
   108  	for numZeros = 0; numZeros < len(b); numZeros++ {
   109  		if b[numZeros] != alphabet[0] {
   110  			break
   111  		}
   112  	}
   113  	flen := numZeros + len(tmpval)
   114  	val := make([]byte, flen, flen)
   115  	copy(val[numZeros:], tmpval)
   116  
   117  	return val
   118  }