base64.mx raw

   1  package helpers
   2  
   3  const b64encode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
   4  
   5  // Base64Encode encodes bytes to standard base64.
   6  func Base64Encode(data []byte) string {
   7  	n := len(data)
   8  	out := []byte{:0:(n+2)/3*4}
   9  	for i := 0; i < n; i += 3 {
  10  		var b0, b1, b2 byte
  11  		b0 = data[i]
  12  		if i+1 < n {
  13  			b1 = data[i+1]
  14  		}
  15  		if i+2 < n {
  16  			b2 = data[i+2]
  17  		}
  18  		out = append(out, b64encode[(b0>>2)&0x3f])
  19  		out = append(out, b64encode[((b0<<4)|(b1>>4))&0x3f])
  20  		if i+1 < n {
  21  			out = append(out, b64encode[((b1<<2)|(b2>>6))&0x3f])
  22  		} else {
  23  			out = append(out, '=')
  24  		}
  25  		if i+2 < n {
  26  			out = append(out, b64encode[b2&0x3f])
  27  		} else {
  28  			out = append(out, '=')
  29  		}
  30  	}
  31  	return string(out)
  32  }
  33  
  34  // Base64Decode decodes standard base64. Returns nil on invalid input.
  35  func Base64Decode(s string) []byte {
  36  	// Strip padding.
  37  	n := len(s)
  38  	pad := 0
  39  	for n > 0 && s[n-1] == '=' {
  40  		pad++
  41  		n--
  42  	}
  43  	out := []byte{:0:n*3/4}
  44  	var acc uint32
  45  	var bits int
  46  	for i := 0; i < n; i++ {
  47  		v := b64val(s[i])
  48  		if v < 0 {
  49  			return nil
  50  		}
  51  		acc = (acc << 6) | uint32(v)
  52  		bits += 6
  53  		if bits >= 8 {
  54  			bits -= 8
  55  			out = append(out, byte(acc>>uint(bits)))
  56  		}
  57  	}
  58  	_ = pad
  59  	return out
  60  }
  61  
  62  func b64val(c byte) int {
  63  	switch {
  64  	case c >= 'A' && c <= 'Z':
  65  		return int(c - 'A')
  66  	case c >= 'a' && c <= 'z':
  67  		return int(c-'a') + 26
  68  	case c >= '0' && c <= '9':
  69  		return int(c-'0') + 52
  70  	case c == '+':
  71  		return 62
  72  	case c == '/':
  73  		return 63
  74  	default:
  75  		return -1
  76  	}
  77  }
  78