base64x.go 5.2 KB

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