github.com/cristalhq/base64@v0.1.2/base64.go (about)

     1  // based on https://github.com/powturbo/Turbo-Base64
     2  package base64
     3  
     4  import (
     5  	"errors"
     6  	"unsafe"
     7  )
     8  
     9  var ErrWrongData = errors.New("wrong base64 data")
    10  
    11  type Encoding struct {
    12  	lutSe  [64]byte
    13  	lutXe  [4096]uint32
    14  	lutXd0 [256]uint32
    15  	lutXd1 [256]uint32
    16  	lutXd2 [256]uint32
    17  	lutXd3 [256]uint32
    18  	pad    bool
    19  }
    20  
    21  func (e *Encoding) EncodedLen(n int) int {
    22  	if !e.pad {
    23  		return (n*8 + 5) / 6
    24  	}
    25  	return (n + 2) / 3 * 4
    26  }
    27  
    28  func (e *Encoding) Encode(dst []byte, src []byte) {
    29  	if len(src) == 0 {
    30  		return
    31  	}
    32  	e.encode(dst, src, uintptr(e.EncodedLen(len(src))))
    33  }
    34  
    35  func (e *Encoding) EncodeToBytes(src []byte) []byte {
    36  	if len(src) == 0 {
    37  		return []byte{}
    38  	}
    39  	length := e.EncodedLen(len(src))
    40  	result := make([]byte, length)
    41  	e.encode(result, src, uintptr(length))
    42  	return result
    43  }
    44  
    45  func (e *Encoding) EncodeToString(src []byte) string {
    46  	return b2s(e.EncodeToBytes(src))
    47  }
    48  
    49  func (e *Encoding) EncodeString(src string) []byte {
    50  	return e.EncodeToBytes(s2b(src))
    51  }
    52  
    53  func (e *Encoding) EncodeStringToString(src string) string {
    54  	return b2s(e.EncodeToBytes(s2b(src)))
    55  }
    56  
    57  func (e *Encoding) DecodedLen(n int) int {
    58  	sf := 0
    59  	if n > 4 {
    60  		sf++
    61  	}
    62  	if !e.pad {
    63  		return n*6/8 + sf
    64  	}
    65  	return n/4*3 + sf
    66  }
    67  
    68  func (e *Encoding) Decode(dst []byte, src []byte) (int, error) {
    69  	if len(src) == 0 {
    70  		return 0, nil
    71  	}
    72  	n := e.decode(dst, src)
    73  	if n == 0 {
    74  		return 0, ErrWrongData
    75  	}
    76  	return n, nil
    77  }
    78  
    79  func (e *Encoding) DecodeToBytes(src []byte) ([]byte, error) {
    80  	if len(src) == 0 {
    81  		return []byte{}, nil
    82  	}
    83  	length := e.DecodedLen(len(src))
    84  	if length == 0 {
    85  		return nil, ErrWrongData
    86  	}
    87  	result := make([]byte, length)
    88  	n := e.decode(result, src)
    89  	if n == 0 {
    90  		return nil, ErrWrongData
    91  	}
    92  	(*sliceHeader)(unsafe.Pointer(&result)).len = n
    93  	return result, nil
    94  }
    95  
    96  func (e *Encoding) DecodeToString(src []byte) (string, error) {
    97  	result, err := e.DecodeToBytes(src)
    98  	if err != nil {
    99  		return "", err
   100  	}
   101  	return b2s(result), nil
   102  }
   103  
   104  func (e *Encoding) DecodeString(src string) ([]byte, error) {
   105  	return e.DecodeToBytes(s2b(src))
   106  }
   107  
   108  func (e *Encoding) DecodeStringToString(src string) (string, error) {
   109  	result, err := e.DecodeToBytes(s2b(src))
   110  	if err != nil {
   111  		return "", err
   112  	}
   113  	return b2s(result), nil
   114  }
   115  
   116  func NewEncoding(lutSe [64]byte, pad bool) *Encoding {
   117  	lutXe, lutXd0, lutXd1, lutXd2, lutXd3 := makeLuts(lutSe)
   118  	return &Encoding{
   119  		lutSe:  lutSe,
   120  		lutXe:  lutXe,
   121  		lutXd0: lutXd0,
   122  		lutXd1: lutXd1,
   123  		lutXd2: lutXd2,
   124  		lutXd3: lutXd3,
   125  		pad:    pad,
   126  	}
   127  }
   128  
   129  var (
   130  	StdEncoding    = NewEncoding(stdLutSe, true)
   131  	RawStdEncoding = NewEncoding(stdLutSe, false)
   132  	URLEncoding    = NewEncoding(urlLutSe, true)
   133  	RawURLEncoding = NewEncoding(urlLutSe, false)
   134  )