base64x.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. package base64x
  2. import (
  3. `encoding/base64`
  4. )
  5. // An Encoding is a radix 64 encoding/decoding scheme, defined by a
  6. // 64-character alphabet. The most common encoding is the "base64"
  7. // encoding defined in RFC 4648 and used in MIME (RFC 2045) and PEM
  8. // (RFC 1421). RFC 4648 also defines an alternate encoding, which is
  9. // the standard encoding with - and _ substituted for + and /.
  10. type Encoding int
  11. const (
  12. _MODE_URL = 1 << 0
  13. _MODE_RAW = 1 << 1
  14. _MODE_AVX2 = 1 << 2
  15. _MODE_JSON = 1 << 3
  16. )
  17. // StdEncoding is the standard base64 encoding, as defined in
  18. // RFC 4648.
  19. const StdEncoding Encoding = 0
  20. // URLEncoding is the alternate base64 encoding defined in RFC 4648.
  21. // It is typically used in URLs and file names.
  22. const URLEncoding Encoding = _MODE_URL
  23. // RawStdEncoding is the standard raw, unpadded base64 encoding,
  24. // as defined in RFC 4648 section 3.2.
  25. //
  26. // This is the same as StdEncoding but omits padding characters.
  27. const RawStdEncoding Encoding = _MODE_RAW
  28. // RawURLEncoding is the unpadded alternate base64 encoding defined in RFC 4648.
  29. // It is typically used in URLs and file names.
  30. //
  31. // This is the same as URLEncoding but omits padding characters.
  32. const RawURLEncoding Encoding = _MODE_RAW | _MODE_URL
  33. // JSONStdEncoding is the StdEncoding and encoded as JSON string as RFC 8259.
  34. const JSONStdEncoding Encoding = _MODE_JSON;
  35. var (
  36. archFlags = 0
  37. )
  38. /** Encoder Functions **/
  39. // Encode encodes src using the specified encoding, writing
  40. // EncodedLen(len(src)) bytes to out.
  41. //
  42. // The encoding pads the output to a multiple of 4 bytes,
  43. // so Encode is not appropriate for use on individual blocks
  44. // of a large data stream.
  45. //
  46. // If out is not large enough to contain the encoded result,
  47. // it will panic.
  48. func (self Encoding) Encode(out []byte, src []byte) {
  49. if len(src) != 0 {
  50. if buf := out[:0:len(out)]; self.EncodedLen(len(src)) <= len(out) {
  51. self.EncodeUnsafe(&buf, src)
  52. } else {
  53. panic("encoder output buffer is too small")
  54. }
  55. }
  56. }
  57. // EncodeUnsafe behaves like Encode, except it does NOT check if
  58. // out is large enough to contain the encoded result.
  59. //
  60. // It will also update the length of out.
  61. func (self Encoding) EncodeUnsafe(out *[]byte, src []byte) {
  62. b64encode(out, &src, int(self) | archFlags)
  63. }
  64. // EncodeToString returns the base64 encoding of src.
  65. func (self Encoding) EncodeToString(src []byte) string {
  66. nbs := len(src)
  67. ret := make([]byte, 0, self.EncodedLen(nbs))
  68. /* encode in native code */
  69. self.EncodeUnsafe(&ret, src)
  70. return mem2str(ret)
  71. }
  72. // EncodedLen returns the length in bytes of the base64 encoding
  73. // of an input buffer of length n.
  74. func (self Encoding) EncodedLen(n int) int {
  75. if (self & _MODE_RAW) == 0 {
  76. return (n + 2) / 3 * 4
  77. } else {
  78. return (n * 8 + 5) / 6
  79. }
  80. }
  81. /** Decoder Functions **/
  82. // Decode decodes src using the encoding enc. It writes at most
  83. // DecodedLen(len(src)) bytes to out and returns the number of bytes
  84. // written. If src contains invalid base64 data, it will return the
  85. // number of bytes successfully written and base64.CorruptInputError.
  86. //
  87. // New line characters (\r and \n) are ignored.
  88. //
  89. // If out is not large enough to contain the encoded result,
  90. // it will panic.
  91. func (self Encoding) Decode(out []byte, src []byte) (int, error) {
  92. if len(src) == 0 {
  93. return 0, nil
  94. } else if buf := out[:0:len(out)]; self.DecodedLen(len(src)) <= len(out) {
  95. return self.DecodeUnsafe(&buf, src)
  96. } else {
  97. panic("decoder output buffer is too small")
  98. }
  99. }
  100. // DecodeUnsafe behaves like Decode, except it does NOT check if
  101. // out is large enough to contain the decoded result.
  102. //
  103. // It will also update the length of out.
  104. func (self Encoding) DecodeUnsafe(out *[]byte, src []byte) (int, error) {
  105. if n := b64decode(out, mem2addr(src), len(src), int(self) | archFlags); n >= 0 {
  106. return n, nil
  107. } else {
  108. return 0, base64.CorruptInputError(-n - 1)
  109. }
  110. }
  111. // DecodeString returns the bytes represented by the base64 string s.
  112. func (self Encoding) DecodeString(s string) ([]byte, error) {
  113. src := str2mem(s)
  114. ret := make([]byte, 0, self.DecodedLen(len(s)))
  115. /* decode into the allocated buffer */
  116. if _, err := self.DecodeUnsafe(&ret, src); err != nil {
  117. return nil, err
  118. } else {
  119. return ret, nil
  120. }
  121. }
  122. // DecodedLen returns the maximum length in bytes of the decoded data
  123. // corresponding to n bytes of base64-encoded data.
  124. func (self Encoding) DecodedLen(n int) int {
  125. if (self & _MODE_RAW) == 0 {
  126. return n / 4 * 3
  127. } else {
  128. return n * 6 / 8
  129. }
  130. }