base64x.go 5.1 KB

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