base64.mx raw

   1  package helpers
   2  
   3  const b64encode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
   4  
   5  // Base64Encode encodes bytes to standard base64. The output size is known
   6  // from the input size, so it is presized and written through a cursor: push
   7  // does not grow, and the padding concat returned a full slice that the next
   8  // push could not extend.
   9  func Base64Encode(data []byte) (s string) {
  10  	n := len(data)
  11  	out := []byte{:(n + 2) / 3 * 4}
  12  	j := 0
  13  	for i := 0; i < n; i += 3 {
  14  		var b0, b1, b2 byte
  15  		b0 = data[i]
  16  		if i+1 < n {
  17  			b1 = data[i+1]
  18  		}
  19  		if i+2 < n {
  20  			b2 = data[i+2]
  21  		}
  22  		out[j] = b64encode[(b0>>2)&0x3f]
  23  		j++
  24  		out[j] = b64encode[((b0<<4)|(b1>>4))&0x3f]
  25  		j++
  26  		if i+1 < n {
  27  			out[j] = b64encode[((b1<<2)|(b2>>6))&0x3f]
  28  		} else {
  29  			out[j] = '='
  30  		}
  31  		j++
  32  		if i+2 < n {
  33  			out[j] = b64encode[b2&0x3f]
  34  		} else {
  35  			out[j] = '='
  36  		}
  37  		j++
  38  	}
  39  	return string(out)
  40  }
  41  
  42  // Base64Decode decodes standard base64. Returns nil on invalid input.
  43  func Base64Decode(s string) (buf []byte) {
  44  	// Strip padding.
  45  	n := len(s)
  46  	pad := 0
  47  	for n > 0 && s[n-1] == '=' {
  48  		pad++
  49  		n--
  50  	}
  51  	out := []byte{:n * 3 / 4}
  52  	j := 0
  53  	var acc uint32
  54  	var bits int32
  55  	for i := 0; i < n; i++ {
  56  		v := b64val(s[i])
  57  		if v < 0 {
  58  			return nil
  59  		}
  60  		acc = (acc << 6) | uint32(v)
  61  		bits += 6
  62  		if bits >= 8 {
  63  			bits -= 8
  64  			out[j] = byte(acc >> uint32(bits))
  65  			j++
  66  		}
  67  	}
  68  	_ = pad
  69  	return out[:j]
  70  }
  71  
  72  func b64val(c byte) (n int32) {
  73  	switch {
  74  	case c >= 'A' && c <= 'Z':
  75  		return int32(c - 'A')
  76  	case c >= 'a' && c <= 'z':
  77  		return int32(c-'a') + 26
  78  	case c >= '0' && c <= '9':
  79  		return int32(c-'0') + 52
  80  	case c == '+':
  81  		return 62
  82  	case c == '/':
  83  		return 63
  84  	default:
  85  		return -1
  86  	}
  87  }
  88