react-native-quick-crypto 1.0.18 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (751) hide show
  1. package/QuickCrypto.podspec +12 -38
  2. package/README.md +2 -0
  3. package/android/CMakeLists.txt +3 -0
  4. package/cpp/utils/HybridUtils.cpp +39 -77
  5. package/deps/simdutf/.clang-format +4 -0
  6. package/deps/simdutf/.github/ISSUE_TEMPLATE/bug_report.md +62 -0
  7. package/deps/simdutf/.github/ISSUE_TEMPLATE/config.yml +1 -0
  8. package/deps/simdutf/.github/ISSUE_TEMPLATE/feature_request.md +35 -0
  9. package/deps/simdutf/.github/ISSUE_TEMPLATE/standard-issue-template.md +29 -0
  10. package/deps/simdutf/.github/pull_request_template.md +51 -0
  11. package/deps/simdutf/.github/workflows/aarch64.yml +39 -0
  12. package/deps/simdutf/.github/workflows/alpine.yml +27 -0
  13. package/deps/simdutf/.github/workflows/amalgamation_demos.yml +34 -0
  14. package/deps/simdutf/.github/workflows/armv7.yml +32 -0
  15. package/deps/simdutf/.github/workflows/atomic_fuzz.yml +25 -0
  16. package/deps/simdutf/.github/workflows/cifuzz.yml +37 -0
  17. package/deps/simdutf/.github/workflows/clangformat.yml +36 -0
  18. package/deps/simdutf/.github/workflows/debian-latestcxxstandards.yml +40 -0
  19. package/deps/simdutf/.github/workflows/debian.yml +33 -0
  20. package/deps/simdutf/.github/workflows/documentation.yml +36 -0
  21. package/deps/simdutf/.github/workflows/emscripten.yml +19 -0
  22. package/deps/simdutf/.github/workflows/loongarch64-gcc-14.2.yml +39 -0
  23. package/deps/simdutf/.github/workflows/macos-latest.yml +29 -0
  24. package/deps/simdutf/.github/workflows/msys2-clang.yml +48 -0
  25. package/deps/simdutf/.github/workflows/msys2.yml +50 -0
  26. package/deps/simdutf/.github/workflows/ppc64le.yml +29 -0
  27. package/deps/simdutf/.github/workflows/rvv-1024-clang-18.yml +35 -0
  28. package/deps/simdutf/.github/workflows/rvv-128-clang-17.yml +35 -0
  29. package/deps/simdutf/.github/workflows/rvv-256-gcc-14.yml +31 -0
  30. package/deps/simdutf/.github/workflows/s390x.yml +29 -0
  31. package/deps/simdutf/.github/workflows/selective-amalgamation.yml +29 -0
  32. package/deps/simdutf/.github/workflows/typos.yml +19 -0
  33. package/deps/simdutf/.github/workflows/ubuntu22-cxx20.yml +30 -0
  34. package/deps/simdutf/.github/workflows/ubuntu22.yml +32 -0
  35. package/deps/simdutf/.github/workflows/ubuntu22_gcc12.yml +27 -0
  36. package/deps/simdutf/.github/workflows/ubuntu22sani.yml +29 -0
  37. package/deps/simdutf/.github/workflows/ubuntu24-cxxstandards.yml +34 -0
  38. package/deps/simdutf/.github/workflows/ubuntu24-unsignedchar.yml +34 -0
  39. package/deps/simdutf/.github/workflows/ubuntu24.yml +32 -0
  40. package/deps/simdutf/.github/workflows/ubuntu24sani.yml +36 -0
  41. package/deps/simdutf/.github/workflows/ubuntu24sani_clang.yml +29 -0
  42. package/deps/simdutf/.github/workflows/vs17-arm-ci.yml +21 -0
  43. package/deps/simdutf/.github/workflows/vs17-ci-cxx20.yml +41 -0
  44. package/deps/simdutf/.github/workflows/vs17-ci.yml +41 -0
  45. package/deps/simdutf/.github/workflows/vs17-clang-ci.yml +41 -0
  46. package/deps/simdutf/.github/workflows/vs17-cxxstandards.yml +36 -0
  47. package/deps/simdutf/AI_USAGE_POLICY.md +56 -0
  48. package/deps/simdutf/AUTHORS +6 -0
  49. package/deps/simdutf/CMakeLists.txt +231 -0
  50. package/deps/simdutf/CONTRIBUTING.md +214 -0
  51. package/deps/simdutf/CONTRIBUTORS +1 -0
  52. package/deps/simdutf/Doxyfile +2584 -0
  53. package/deps/simdutf/LICENSE-APACHE +201 -0
  54. package/deps/simdutf/LICENSE-MIT +18 -0
  55. package/deps/simdutf/Makefile.crosscompile +54 -0
  56. package/deps/simdutf/README-RVV.md +16 -0
  57. package/deps/simdutf/README.md +2782 -0
  58. package/deps/simdutf/SECURITY.md +8 -0
  59. package/deps/simdutf/benchmarks/CMakeLists.txt +101 -0
  60. package/deps/simdutf/benchmarks/alignment.cpp +150 -0
  61. package/deps/simdutf/benchmarks/base64/CMakeLists.txt +30 -0
  62. package/deps/simdutf/benchmarks/base64/benchmark_base64.cpp +875 -0
  63. package/deps/simdutf/benchmarks/base64/libbase64_spaces.h +49 -0
  64. package/deps/simdutf/benchmarks/base64/node_base64.h +227 -0
  65. package/deps/simdutf/benchmarks/base64/openssl3_base64.h +334 -0
  66. package/deps/simdutf/benchmarks/benchmark.cpp +65 -0
  67. package/deps/simdutf/benchmarks/benchmark_to_well_formed_utf16.cpp +347 -0
  68. package/deps/simdutf/benchmarks/competition/.clang-format-ignore +5 -0
  69. package/deps/simdutf/benchmarks/competition/CppCon2018/utf_utils.cpp +1276 -0
  70. package/deps/simdutf/benchmarks/competition/CppCon2018/utf_utils.h +595 -0
  71. package/deps/simdutf/benchmarks/competition/README.md +7 -0
  72. package/deps/simdutf/benchmarks/competition/hoehrmann/hoehrmann.h +91 -0
  73. package/deps/simdutf/benchmarks/competition/inoue2008/inoue_utf8_to_utf16.h +444 -0
  74. package/deps/simdutf/benchmarks/competition/inoue2008/inoue_utf8_to_utf16_tables.h +13183 -0
  75. package/deps/simdutf/benchmarks/competition/inoue2008/script.py +73 -0
  76. package/deps/simdutf/benchmarks/competition/llvm/ConvertUTF.cpp +738 -0
  77. package/deps/simdutf/benchmarks/competition/llvm/ConvertUTF.h +293 -0
  78. package/deps/simdutf/benchmarks/competition/u8u16/COPYRIGHT +8 -0
  79. package/deps/simdutf/benchmarks/competition/u8u16/Makefile +44 -0
  80. package/deps/simdutf/benchmarks/competition/u8u16/OSL3.0.txt +169 -0
  81. package/deps/simdutf/benchmarks/competition/u8u16/Profiling/BOM_Profiler.h +148 -0
  82. package/deps/simdutf/benchmarks/competition/u8u16/Profiling/i386_timer.h +45 -0
  83. package/deps/simdutf/benchmarks/competition/u8u16/Profiling/ppc_timer.c +34 -0
  84. package/deps/simdutf/benchmarks/competition/u8u16/README +56 -0
  85. package/deps/simdutf/benchmarks/competition/u8u16/config/config_defs.h +43 -0
  86. package/deps/simdutf/benchmarks/competition/u8u16/config/g4_config.h +27 -0
  87. package/deps/simdutf/benchmarks/competition/u8u16/config/mmx_config.h +16 -0
  88. package/deps/simdutf/benchmarks/competition/u8u16/config/p4_config.h +18 -0
  89. package/deps/simdutf/benchmarks/competition/u8u16/config/p4_ideal_config.h +16 -0
  90. package/deps/simdutf/benchmarks/competition/u8u16/config/spu_config.h +28 -0
  91. package/deps/simdutf/benchmarks/competition/u8u16/config/ssse3_config.h +20 -0
  92. package/deps/simdutf/benchmarks/competition/u8u16/iconv_u8u16.c +2 -0
  93. package/deps/simdutf/benchmarks/competition/u8u16/lib/altivec_simd.h +440 -0
  94. package/deps/simdutf/benchmarks/competition/u8u16/lib/libgen/make_basic_ops.py +121 -0
  95. package/deps/simdutf/benchmarks/competition/u8u16/lib/libgen/make_half_operand_versions.py +158 -0
  96. package/deps/simdutf/benchmarks/competition/u8u16/lib/libgen/make_test.py +270 -0
  97. package/deps/simdutf/benchmarks/competition/u8u16/lib/mmx_simd.h +141 -0
  98. package/deps/simdutf/benchmarks/competition/u8u16/lib/mmx_simd_basic.h +216 -0
  99. package/deps/simdutf/benchmarks/competition/u8u16/lib/mmx_simd_built_in.h +119 -0
  100. package/deps/simdutf/benchmarks/competition/u8u16/lib/mmx_simd_modified.h +2430 -0
  101. package/deps/simdutf/benchmarks/competition/u8u16/lib/outline.txt +39 -0
  102. package/deps/simdutf/benchmarks/competition/u8u16/lib/spu_simd.h +421 -0
  103. package/deps/simdutf/benchmarks/competition/u8u16/lib/sse_simd.h +836 -0
  104. package/deps/simdutf/benchmarks/competition/u8u16/lib/stdint.h +222 -0
  105. package/deps/simdutf/benchmarks/competition/u8u16/libu8u16_BE.c +4 -0
  106. package/deps/simdutf/benchmarks/competition/u8u16/libu8u16_LE.c +5 -0
  107. package/deps/simdutf/benchmarks/competition/u8u16/proto/u8u16.py +390 -0
  108. package/deps/simdutf/benchmarks/competition/u8u16/src/Makefile +18 -0
  109. package/deps/simdutf/benchmarks/competition/u8u16/src/bytelex.h +448 -0
  110. package/deps/simdutf/benchmarks/competition/u8u16/src/charsets/ASCII_EBCDIC.h +284 -0
  111. package/deps/simdutf/benchmarks/competition/u8u16/src/libu8u16.c +1975 -0
  112. package/deps/simdutf/benchmarks/competition/u8u16/src/libu8u16.pdf +0 -0
  113. package/deps/simdutf/benchmarks/competition/u8u16/src/libu8u16.w +2263 -0
  114. package/deps/simdutf/benchmarks/competition/u8u16/src/multiliteral.h +239 -0
  115. package/deps/simdutf/benchmarks/competition/u8u16/src/u8u16.c +232 -0
  116. package/deps/simdutf/benchmarks/competition/u8u16/src/x8x16.c +194 -0
  117. package/deps/simdutf/benchmarks/competition/u8u16/src/xml_error.c +193 -0
  118. package/deps/simdutf/benchmarks/competition/u8u16/src/xml_error.h +167 -0
  119. package/deps/simdutf/benchmarks/competition/u8u16/src/xmldecl.c +288 -0
  120. package/deps/simdutf/benchmarks/competition/u8u16/src/xmldecl.h +117 -0
  121. package/deps/simdutf/benchmarks/competition/u8u16/u8u16_g4.c +2 -0
  122. package/deps/simdutf/benchmarks/competition/u8u16/u8u16_mmx.c +2 -0
  123. package/deps/simdutf/benchmarks/competition/u8u16/u8u16_p4.c +3 -0
  124. package/deps/simdutf/benchmarks/competition/u8u16/u8u16_p4_ideal.c +2 -0
  125. package/deps/simdutf/benchmarks/competition/u8u16/u8u16_spu.c +2 -0
  126. package/deps/simdutf/benchmarks/competition/u8u16/u8u16_ssse3.c +3 -0
  127. package/deps/simdutf/benchmarks/competition/u8u16/x8x16_p4.c +2 -0
  128. package/deps/simdutf/benchmarks/competition/utf8lut/LICENSE +23 -0
  129. package/deps/simdutf/benchmarks/competition/utf8lut/data/test_minimal.txt +44 -0
  130. package/deps/simdutf/benchmarks/competition/utf8lut/readme.md +106 -0
  131. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_clang_corr_tests.cmd +11 -0
  132. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_clang_corr_tests.sh +13 -0
  133. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_gcc_corr_tests.sh +13 -0
  134. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_gcc_example.sh +13 -0
  135. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_gcc_file_conv.sh +14 -0
  136. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_gcc_iconv_lib.sh +11 -0
  137. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_gcc_iconv_sample.sh +8 -0
  138. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_mingw_corr_tests.cmd +12 -0
  139. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_mingw_example.cmd +13 -0
  140. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_mingw_file_conv.cmd +14 -0
  141. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_mingw_iconv_lib.cmd +11 -0
  142. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_mingw_iconv_sample.cmd +8 -0
  143. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_msvc_corr_tests.cmd +11 -0
  144. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_msvc_example.cmd +12 -0
  145. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_msvc_file_conv.cmd +13 -0
  146. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_msvc_iconv_lib.cmd +10 -0
  147. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/build_msvc_iconv_sample.cmd +9 -0
  148. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/html_table.py +25 -0
  149. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/measure.py +94 -0
  150. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/resize.py +20 -0
  151. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/wipe_all.cmd +2 -0
  152. package/deps/simdutf/benchmarks/competition/utf8lut/scripts/wipe_interm.cmd +1 -0
  153. package/deps/simdutf/benchmarks/competition/utf8lut/src/base/CustomMemcpy.h +75 -0
  154. package/deps/simdutf/benchmarks/competition/utf8lut/src/base/PerfDefs.h +47 -0
  155. package/deps/simdutf/benchmarks/competition/utf8lut/src/base/Timing.cpp +17 -0
  156. package/deps/simdutf/benchmarks/competition/utf8lut/src/base/Timing.h +76 -0
  157. package/deps/simdutf/benchmarks/competition/utf8lut/src/buffer/AllProcessors.cpp +35 -0
  158. package/deps/simdutf/benchmarks/competition/utf8lut/src/buffer/BaseBufferProcessor.cpp +117 -0
  159. package/deps/simdutf/benchmarks/competition/utf8lut/src/buffer/BaseBufferProcessor.h +210 -0
  160. package/deps/simdutf/benchmarks/competition/utf8lut/src/buffer/BufferDecoder.h +158 -0
  161. package/deps/simdutf/benchmarks/competition/utf8lut/src/buffer/BufferEncoder.h +104 -0
  162. package/deps/simdutf/benchmarks/competition/utf8lut/src/buffer/ProcessorPlugins.h +334 -0
  163. package/deps/simdutf/benchmarks/competition/utf8lut/src/buffer/ProcessorSelector.h +186 -0
  164. package/deps/simdutf/benchmarks/competition/utf8lut/src/core/DecoderLut.cpp +140 -0
  165. package/deps/simdutf/benchmarks/competition/utf8lut/src/core/DecoderLut.h +42 -0
  166. package/deps/simdutf/benchmarks/competition/utf8lut/src/core/DecoderProcess.h +100 -0
  167. package/deps/simdutf/benchmarks/competition/utf8lut/src/core/Dfa.h +57 -0
  168. package/deps/simdutf/benchmarks/competition/utf8lut/src/core/EncoderLut.cpp +85 -0
  169. package/deps/simdutf/benchmarks/competition/utf8lut/src/core/EncoderLut.h +27 -0
  170. package/deps/simdutf/benchmarks/competition/utf8lut/src/core/EncoderProcess.h +126 -0
  171. package/deps/simdutf/benchmarks/competition/utf8lut/src/core/ProcessTrivial.h +108 -0
  172. package/deps/simdutf/benchmarks/competition/utf8lut/src/iconv/iconv.cpp +139 -0
  173. package/deps/simdutf/benchmarks/competition/utf8lut/src/iconv/iconv.h +74 -0
  174. package/deps/simdutf/benchmarks/competition/utf8lut/src/message/MessageConverter.cpp +65 -0
  175. package/deps/simdutf/benchmarks/competition/utf8lut/src/message/MessageConverter.h +91 -0
  176. package/deps/simdutf/benchmarks/competition/utf8lut/src/tests/CorrectnessTests.cpp +772 -0
  177. package/deps/simdutf/benchmarks/competition/utf8lut/src/tests/Example.cpp +12 -0
  178. package/deps/simdutf/benchmarks/competition/utf8lut/src/tests/FileConverter.cpp +486 -0
  179. package/deps/simdutf/benchmarks/competition/utf8lut/src/tests/iconv_sample.c +162 -0
  180. package/deps/simdutf/benchmarks/competition/utf8lut/src/utf8lut.h +15 -0
  181. package/deps/simdutf/benchmarks/competition/utf8sse4/fromutf8-sse.cpp +292 -0
  182. package/deps/simdutf/benchmarks/competition/utfcpp/LICENSE +23 -0
  183. package/deps/simdutf/benchmarks/competition/utfcpp/README.md +1503 -0
  184. package/deps/simdutf/benchmarks/competition/utfcpp/source/utf8/checked.h +335 -0
  185. package/deps/simdutf/benchmarks/competition/utfcpp/source/utf8/core.h +338 -0
  186. package/deps/simdutf/benchmarks/competition/utfcpp/source/utf8/cpp11.h +103 -0
  187. package/deps/simdutf/benchmarks/competition/utfcpp/source/utf8/cpp17.h +103 -0
  188. package/deps/simdutf/benchmarks/competition/utfcpp/source/utf8/unchecked.h +274 -0
  189. package/deps/simdutf/benchmarks/competition/utfcpp/source/utf8.h +34 -0
  190. package/deps/simdutf/benchmarks/dataset/README.md +155 -0
  191. package/deps/simdutf/benchmarks/dataset/emoji.txt +204 -0
  192. package/deps/simdutf/benchmarks/dataset/scripts/utf8type.py +40 -0
  193. package/deps/simdutf/benchmarks/dataset/wikipedia_mars/Makefile +80 -0
  194. package/deps/simdutf/benchmarks/dataset/wikipedia_mars/convert_to_utf6.py +20 -0
  195. package/deps/simdutf/benchmarks/find/CMakeLists.txt +6 -0
  196. package/deps/simdutf/benchmarks/find/findbenchmark.cpp +63 -0
  197. package/deps/simdutf/benchmarks/find/findbenchmarker.h +46 -0
  198. package/deps/simdutf/benchmarks/shortbench.cpp +555 -0
  199. package/deps/simdutf/benchmarks/src/CMakeLists.txt +52 -0
  200. package/deps/simdutf/benchmarks/src/apple_arm_events.h +1104 -0
  201. package/deps/simdutf/benchmarks/src/benchmark.cpp +3899 -0
  202. package/deps/simdutf/benchmarks/src/benchmark.h +317 -0
  203. package/deps/simdutf/benchmarks/src/benchmark_base.cpp +144 -0
  204. package/deps/simdutf/benchmarks/src/benchmark_base.h +98 -0
  205. package/deps/simdutf/benchmarks/src/cmdline.cpp +176 -0
  206. package/deps/simdutf/benchmarks/src/cmdline.h +35 -0
  207. package/deps/simdutf/benchmarks/src/event_counter.h +162 -0
  208. package/deps/simdutf/benchmarks/src/linux-perf-events.h +104 -0
  209. package/deps/simdutf/benchmarks/stream.cpp +209 -0
  210. package/deps/simdutf/benchmarks/threaded.cpp +123 -0
  211. package/deps/simdutf/cmake/CPM.cmake +1363 -0
  212. package/deps/simdutf/cmake/JoinPaths.cmake +23 -0
  213. package/deps/simdutf/cmake/add_cpp_test.cmake +68 -0
  214. package/deps/simdutf/cmake/simdutf-config.cmake.in +2 -0
  215. package/deps/simdutf/cmake/simdutf-flags.cmake +26 -0
  216. package/deps/simdutf/cmake/toolchains-ci/riscv64-linux-gnu.cmake +4 -0
  217. package/deps/simdutf/cmake/toolchains-dev/README.md +32 -0
  218. package/deps/simdutf/cmake/toolchains-dev/aarch64.cmake +14 -0
  219. package/deps/simdutf/cmake/toolchains-dev/loongarch64.cmake +22 -0
  220. package/deps/simdutf/cmake/toolchains-dev/powerpc64.cmake +16 -0
  221. package/deps/simdutf/cmake/toolchains-dev/powerpc64le.cmake +16 -0
  222. package/deps/simdutf/cmake/toolchains-dev/riscv64.cmake +16 -0
  223. package/deps/simdutf/cmake/toolchains-dev/rvv-spike.cmake +38 -0
  224. package/deps/simdutf/doc/avx512.png +0 -0
  225. package/deps/simdutf/doc/logo.png +0 -0
  226. package/deps/simdutf/doc/logo.svg +165 -0
  227. package/deps/simdutf/doc/node2023.png +0 -0
  228. package/deps/simdutf/doc/shortinput.md +78 -0
  229. package/deps/simdutf/doc/utf16utf8.png +0 -0
  230. package/deps/simdutf/doc/utf8utf16.png +0 -0
  231. package/deps/simdutf/doc/widelogo.png +0 -0
  232. package/deps/simdutf/doxygen.py +50 -0
  233. package/deps/simdutf/fuzz/.clang-format +9 -0
  234. package/deps/simdutf/fuzz/CMakeLists.txt +45 -0
  235. package/deps/simdutf/fuzz/README.md +168 -0
  236. package/deps/simdutf/fuzz/atomic_base64.cpp +448 -0
  237. package/deps/simdutf/fuzz/base64.cpp +278 -0
  238. package/deps/simdutf/fuzz/build.sh +83 -0
  239. package/deps/simdutf/fuzz/conversion.cpp +669 -0
  240. package/deps/simdutf/fuzz/helpers/.clang-format-ignore +1 -0
  241. package/deps/simdutf/fuzz/helpers/common.h +135 -0
  242. package/deps/simdutf/fuzz/helpers/nameof.hpp +1258 -0
  243. package/deps/simdutf/fuzz/main.cpp +72 -0
  244. package/deps/simdutf/fuzz/minimize_and_cleanse.sh +87 -0
  245. package/deps/simdutf/fuzz/misc.cpp +216 -0
  246. package/deps/simdutf/fuzz/random_fuzz.sh +154 -0
  247. package/deps/simdutf/fuzz/roundtrip.cpp +588 -0
  248. package/deps/simdutf/fuzz/safe_conversion.cpp +104 -0
  249. package/deps/simdutf/include/simdutf/avx512.h +79 -0
  250. package/deps/simdutf/include/simdutf/base64_implementation.h +158 -0
  251. package/deps/simdutf/include/simdutf/base64_tables.h +887 -0
  252. package/deps/simdutf/include/simdutf/common_defs.h +186 -0
  253. package/deps/simdutf/include/simdutf/compiler_check.h +50 -0
  254. package/deps/simdutf/include/simdutf/constexpr_ptr.h +138 -0
  255. package/deps/simdutf/include/simdutf/encoding_types.h +189 -0
  256. package/deps/simdutf/include/simdutf/error.h +126 -0
  257. package/deps/simdutf/include/simdutf/implementation.h +7081 -0
  258. package/deps/simdutf/include/simdutf/internal/isadetection.h +325 -0
  259. package/deps/simdutf/include/simdutf/portability.h +285 -0
  260. package/deps/simdutf/include/simdutf/scalar/ascii.h +86 -0
  261. package/deps/simdutf/include/simdutf/scalar/atomic_util.h +105 -0
  262. package/deps/simdutf/include/simdutf/scalar/base64.h +911 -0
  263. package/deps/simdutf/include/simdutf/scalar/latin1.h +26 -0
  264. package/deps/simdutf/include/simdutf/scalar/latin1_to_utf16/latin1_to_utf16.h +52 -0
  265. package/deps/simdutf/include/simdutf/scalar/latin1_to_utf32/latin1_to_utf32.h +27 -0
  266. package/deps/simdutf/include/simdutf/scalar/latin1_to_utf8/latin1_to_utf8.h +191 -0
  267. package/deps/simdutf/include/simdutf/scalar/swap_bytes.h +35 -0
  268. package/deps/simdutf/include/simdutf/scalar/utf16.h +226 -0
  269. package/deps/simdutf/include/simdutf/scalar/utf16_to_latin1/utf16_to_latin1.h +108 -0
  270. package/deps/simdutf/include/simdutf/scalar/utf16_to_latin1/valid_utf16_to_latin1.h +40 -0
  271. package/deps/simdutf/include/simdutf/scalar/utf16_to_utf32/utf16_to_utf32.h +86 -0
  272. package/deps/simdutf/include/simdutf/scalar/utf16_to_utf32/valid_utf16_to_utf32.h +44 -0
  273. package/deps/simdutf/include/simdutf/scalar/utf16_to_utf8/utf16_to_utf8.h +295 -0
  274. package/deps/simdutf/include/simdutf/scalar/utf16_to_utf8/valid_utf16_to_utf8.h +91 -0
  275. package/deps/simdutf/include/simdutf/scalar/utf32.h +82 -0
  276. package/deps/simdutf/include/simdutf/scalar/utf32_to_latin1/utf32_to_latin1.h +68 -0
  277. package/deps/simdutf/include/simdutf/scalar/utf32_to_latin1/valid_utf32_to_latin1.h +67 -0
  278. package/deps/simdutf/include/simdutf/scalar/utf32_to_utf16/utf32_to_utf16.h +84 -0
  279. package/deps/simdutf/include/simdutf/scalar/utf32_to_utf16/valid_utf32_to_utf16.h +44 -0
  280. package/deps/simdutf/include/simdutf/scalar/utf32_to_utf8/utf32_to_utf8.h +142 -0
  281. package/deps/simdutf/include/simdutf/scalar/utf32_to_utf8/valid_utf32_to_utf8.h +72 -0
  282. package/deps/simdutf/include/simdutf/scalar/utf8.h +326 -0
  283. package/deps/simdutf/include/simdutf/scalar/utf8_to_latin1/utf8_to_latin1.h +225 -0
  284. package/deps/simdutf/include/simdutf/scalar/utf8_to_latin1/valid_utf8_to_latin1.h +87 -0
  285. package/deps/simdutf/include/simdutf/scalar/utf8_to_utf16/utf8_to_utf16.h +342 -0
  286. package/deps/simdutf/include/simdutf/scalar/utf8_to_utf16/valid_utf8_to_utf16.h +106 -0
  287. package/deps/simdutf/include/simdutf/scalar/utf8_to_utf32/utf8_to_utf32.h +299 -0
  288. package/deps/simdutf/include/simdutf/scalar/utf8_to_utf32/valid_utf8_to_utf32.h +83 -0
  289. package/deps/simdutf/include/simdutf/simdutf_version.h +26 -0
  290. package/deps/simdutf/include/simdutf.h +26 -0
  291. package/deps/simdutf/include/simdutf_c.h +342 -0
  292. package/deps/simdutf/riscv/Dockerfile +16 -0
  293. package/deps/simdutf/riscv/README.md +24 -0
  294. package/deps/simdutf/riscv/remove-docker-station +8 -0
  295. package/deps/simdutf/riscv/run-docker-station +31 -0
  296. package/deps/simdutf/scripts/.flake8 +2 -0
  297. package/deps/simdutf/scripts/Makefile +2 -0
  298. package/deps/simdutf/scripts/README_ADD_FUNCTION.md +49 -0
  299. package/deps/simdutf/scripts/add_function.py +330 -0
  300. package/deps/simdutf/scripts/amalgamation_tests.py +156 -0
  301. package/deps/simdutf/scripts/base64/Makefile +2 -0
  302. package/deps/simdutf/scripts/base64/README.md +2 -0
  303. package/deps/simdutf/scripts/base64/avx512.py +76 -0
  304. package/deps/simdutf/scripts/base64/neon_decode.py +143 -0
  305. package/deps/simdutf/scripts/base64/neon_generate_lut.py +101 -0
  306. package/deps/simdutf/scripts/base64/sse.py +252 -0
  307. package/deps/simdutf/scripts/base64/sseregular.py +160 -0
  308. package/deps/simdutf/scripts/base64/sseurl.py +283 -0
  309. package/deps/simdutf/scripts/base64/table.py +59 -0
  310. package/deps/simdutf/scripts/base64bench_print.py +145 -0
  311. package/deps/simdutf/scripts/benchmark-all.py +119 -0
  312. package/deps/simdutf/scripts/benchmark_print.py +324 -0
  313. package/deps/simdutf/scripts/check_feature_macros.py +156 -0
  314. package/deps/simdutf/scripts/check_typos.sh +13 -0
  315. package/deps/simdutf/scripts/clang_format.sh +35 -0
  316. package/deps/simdutf/scripts/clang_format_docker.sh +38 -0
  317. package/deps/simdutf/scripts/common.py +24 -0
  318. package/deps/simdutf/scripts/compilation_benchmark.py +55 -0
  319. package/deps/simdutf/scripts/compile_many_variations.sh +64 -0
  320. package/deps/simdutf/scripts/create_latex_table.py +62 -0
  321. package/deps/simdutf/scripts/docker/Dockerfile +14 -0
  322. package/deps/simdutf/scripts/docker/Makefile +9 -0
  323. package/deps/simdutf/scripts/docker/README.md +30 -0
  324. package/deps/simdutf/scripts/docker/llvm.gpg +0 -0
  325. package/deps/simdutf/scripts/ppc64_convert_utf16_to_utf8.py +155 -0
  326. package/deps/simdutf/scripts/prepare_doxygen.sh +21 -0
  327. package/deps/simdutf/scripts/release.py +197 -0
  328. package/deps/simdutf/scripts/shortinputplots.py +97 -0
  329. package/deps/simdutf/scripts/sse_convert_utf16_to_utf8.py +422 -0
  330. package/deps/simdutf/scripts/sse_convert_utf32_to_utf16.py +105 -0
  331. package/deps/simdutf/scripts/sse_utf8_utf16_decode.py +186 -0
  332. package/deps/simdutf/scripts/sse_validate_utf16le_proof.py +137 -0
  333. package/deps/simdutf/scripts/sse_validate_utf16le_testcases.py +129 -0
  334. package/deps/simdutf/scripts/table.py +207 -0
  335. package/deps/simdutf/scripts/tests/new.txt +33 -0
  336. package/deps/simdutf/scripts/tests/old.txt +33 -0
  337. package/deps/simdutf/scripts/tests/results.txt +272 -0
  338. package/deps/simdutf/simdutf.pc.in +11 -0
  339. package/deps/simdutf/singleheader/.flake8 +2 -0
  340. package/deps/simdutf/singleheader/CMakeLists.txt +64 -0
  341. package/deps/simdutf/singleheader/README-dev.md +81 -0
  342. package/deps/simdutf/singleheader/README.md +19 -0
  343. package/deps/simdutf/singleheader/amalgamate.py +513 -0
  344. package/deps/simdutf/singleheader/amalgamation_demo.c +59 -0
  345. package/deps/simdutf/singleheader/amalgamation_demo.cpp +54 -0
  346. package/deps/simdutf/singleheader/test-features.py +262 -0
  347. package/deps/simdutf/src/CMakeLists.txt +78 -0
  348. package/deps/simdutf/src/arm64/arm_base64.cpp +791 -0
  349. package/deps/simdutf/src/arm64/arm_convert_latin1_to_utf16.cpp +24 -0
  350. package/deps/simdutf/src/arm64/arm_convert_latin1_to_utf32.cpp +24 -0
  351. package/deps/simdutf/src/arm64/arm_convert_latin1_to_utf8.cpp +70 -0
  352. package/deps/simdutf/src/arm64/arm_convert_utf16_to_latin1.cpp +61 -0
  353. package/deps/simdutf/src/arm64/arm_convert_utf16_to_utf32.cpp +185 -0
  354. package/deps/simdutf/src/arm64/arm_convert_utf16_to_utf8.cpp +780 -0
  355. package/deps/simdutf/src/arm64/arm_convert_utf32_to_latin1.cpp +60 -0
  356. package/deps/simdutf/src/arm64/arm_convert_utf32_to_utf16.cpp +208 -0
  357. package/deps/simdutf/src/arm64/arm_convert_utf32_to_utf8.cpp +505 -0
  358. package/deps/simdutf/src/arm64/arm_convert_utf8_to_latin1.cpp +69 -0
  359. package/deps/simdutf/src/arm64/arm_convert_utf8_to_utf16.cpp +313 -0
  360. package/deps/simdutf/src/arm64/arm_convert_utf8_to_utf32.cpp +179 -0
  361. package/deps/simdutf/src/arm64/arm_find.cpp +199 -0
  362. package/deps/simdutf/src/arm64/arm_utf16fix.cpp +185 -0
  363. package/deps/simdutf/src/arm64/arm_validate_utf16.cpp +165 -0
  364. package/deps/simdutf/src/arm64/arm_validate_utf32le.cpp +65 -0
  365. package/deps/simdutf/src/arm64/implementation.cpp +1442 -0
  366. package/deps/simdutf/src/encoding_types.cpp +67 -0
  367. package/deps/simdutf/src/error.cpp +3 -0
  368. package/deps/simdutf/src/fallback/implementation.cpp +589 -0
  369. package/deps/simdutf/src/generic/ascii_validation.h +50 -0
  370. package/deps/simdutf/src/generic/base64.h +233 -0
  371. package/deps/simdutf/src/generic/base64lengths.h +63 -0
  372. package/deps/simdutf/src/generic/buf_block_reader.h +109 -0
  373. package/deps/simdutf/src/generic/find.h +75 -0
  374. package/deps/simdutf/src/generic/utf16/change_endianness.h +24 -0
  375. package/deps/simdutf/src/generic/utf16/count_code_points_bytemask.h +58 -0
  376. package/deps/simdutf/src/generic/utf16/to_well_formed.h +93 -0
  377. package/deps/simdutf/src/generic/utf16/utf32_length_from_utf16.h +15 -0
  378. package/deps/simdutf/src/generic/utf16/utf8_length_from_utf16.h +35 -0
  379. package/deps/simdutf/src/generic/utf16/utf8_length_from_utf16_bytemask.h +199 -0
  380. package/deps/simdutf/src/generic/utf16.h +73 -0
  381. package/deps/simdutf/src/generic/utf32.h +136 -0
  382. package/deps/simdutf/src/generic/utf8/utf16_length_from_utf8_bytemask.h +53 -0
  383. package/deps/simdutf/src/generic/utf8.h +92 -0
  384. package/deps/simdutf/src/generic/utf8_to_latin1/utf8_to_latin1.h +316 -0
  385. package/deps/simdutf/src/generic/utf8_to_latin1/valid_utf8_to_latin1.h +78 -0
  386. package/deps/simdutf/src/generic/utf8_to_utf16/utf8_to_utf16.h +332 -0
  387. package/deps/simdutf/src/generic/utf8_to_utf16/valid_utf8_to_utf16.h +74 -0
  388. package/deps/simdutf/src/generic/utf8_to_utf32/utf8_to_utf32.h +318 -0
  389. package/deps/simdutf/src/generic/utf8_to_utf32/valid_utf8_to_utf32.h +42 -0
  390. package/deps/simdutf/src/generic/utf8_validation/utf8_lookup4_algorithm.h +223 -0
  391. package/deps/simdutf/src/generic/utf8_validation/utf8_validator.h +84 -0
  392. package/deps/simdutf/src/generic/validate_utf16.h +164 -0
  393. package/deps/simdutf/src/generic/validate_utf32.h +99 -0
  394. package/deps/simdutf/src/haswell/avx2_base64.cpp +837 -0
  395. package/deps/simdutf/src/haswell/avx2_convert_latin1_to_utf16.cpp +28 -0
  396. package/deps/simdutf/src/haswell/avx2_convert_latin1_to_utf32.cpp +20 -0
  397. package/deps/simdutf/src/haswell/avx2_convert_latin1_to_utf8.cpp +83 -0
  398. package/deps/simdutf/src/haswell/avx2_convert_utf16_to_latin1.cpp +83 -0
  399. package/deps/simdutf/src/haswell/avx2_convert_utf16_to_utf32.cpp +210 -0
  400. package/deps/simdutf/src/haswell/avx2_convert_utf16_to_utf8.cpp +602 -0
  401. package/deps/simdutf/src/haswell/avx2_convert_utf32_to_latin1.cpp +116 -0
  402. package/deps/simdutf/src/haswell/avx2_convert_utf32_to_utf16.cpp +164 -0
  403. package/deps/simdutf/src/haswell/avx2_convert_utf32_to_utf8.cpp +569 -0
  404. package/deps/simdutf/src/haswell/avx2_convert_utf8_to_latin1.cpp +60 -0
  405. package/deps/simdutf/src/haswell/avx2_convert_utf8_to_utf16.cpp +195 -0
  406. package/deps/simdutf/src/haswell/avx2_convert_utf8_to_utf32.cpp +135 -0
  407. package/deps/simdutf/src/haswell/avx2_utf16fix.cpp +173 -0
  408. package/deps/simdutf/src/haswell/avx2_validate_utf16.cpp +17 -0
  409. package/deps/simdutf/src/haswell/implementation.cpp +1447 -0
  410. package/deps/simdutf/src/icelake/icelake_ascii_validation.inl.cpp +19 -0
  411. package/deps/simdutf/src/icelake/icelake_base64.inl.cpp +630 -0
  412. package/deps/simdutf/src/icelake/icelake_common.inl.cpp +37 -0
  413. package/deps/simdutf/src/icelake/icelake_convert_latin1_to_utf16.inl.cpp +36 -0
  414. package/deps/simdutf/src/icelake/icelake_convert_latin1_to_utf32.inl.cpp +23 -0
  415. package/deps/simdutf/src/icelake/icelake_convert_latin1_to_utf8.inl.cpp +107 -0
  416. package/deps/simdutf/src/icelake/icelake_convert_utf16_to_latin1.inl.cpp +103 -0
  417. package/deps/simdutf/src/icelake/icelake_convert_utf16_to_utf32.inl.cpp +136 -0
  418. package/deps/simdutf/src/icelake/icelake_convert_utf16_to_utf8.inl.cpp +206 -0
  419. package/deps/simdutf/src/icelake/icelake_convert_utf32_to_latin1.inl.cpp +74 -0
  420. package/deps/simdutf/src/icelake/icelake_convert_utf32_to_utf16.inl.cpp +338 -0
  421. package/deps/simdutf/src/icelake/icelake_convert_utf32_to_utf8.inl.cpp +574 -0
  422. package/deps/simdutf/src/icelake/icelake_convert_utf8_to_latin1.inl.cpp +104 -0
  423. package/deps/simdutf/src/icelake/icelake_convert_utf8_to_utf16.inl.cpp +75 -0
  424. package/deps/simdutf/src/icelake/icelake_convert_valid_utf8_to_latin1.inl.cpp +69 -0
  425. package/deps/simdutf/src/icelake/icelake_find.inl.cpp +146 -0
  426. package/deps/simdutf/src/icelake/icelake_from_utf8.inl.cpp +266 -0
  427. package/deps/simdutf/src/icelake/icelake_from_valid_utf8.inl.cpp +136 -0
  428. package/deps/simdutf/src/icelake/icelake_macros.inl.cpp +143 -0
  429. package/deps/simdutf/src/icelake/icelake_utf16fix.cpp +138 -0
  430. package/deps/simdutf/src/icelake/icelake_utf32_validation.inl.cpp +63 -0
  431. package/deps/simdutf/src/icelake/icelake_utf8_common.inl.cpp +753 -0
  432. package/deps/simdutf/src/icelake/icelake_utf8_length_from_utf16.inl.cpp +269 -0
  433. package/deps/simdutf/src/icelake/icelake_utf8_validation.inl.cpp +116 -0
  434. package/deps/simdutf/src/icelake/implementation.cpp +1903 -0
  435. package/deps/simdutf/src/implementation.cpp +2526 -0
  436. package/deps/simdutf/src/lasx/implementation.cpp +1531 -0
  437. package/deps/simdutf/src/lasx/lasx_base64.cpp +695 -0
  438. package/deps/simdutf/src/lasx/lasx_convert_latin1_to_utf16.cpp +76 -0
  439. package/deps/simdutf/src/lasx/lasx_convert_latin1_to_utf32.cpp +55 -0
  440. package/deps/simdutf/src/lasx/lasx_convert_latin1_to_utf8.cpp +65 -0
  441. package/deps/simdutf/src/lasx/lasx_convert_utf16_to_latin1.cpp +64 -0
  442. package/deps/simdutf/src/lasx/lasx_convert_utf16_to_utf32.cpp +183 -0
  443. package/deps/simdutf/src/lasx/lasx_convert_utf16_to_utf8.cpp +550 -0
  444. package/deps/simdutf/src/lasx/lasx_convert_utf32_to_latin1.cpp +73 -0
  445. package/deps/simdutf/src/lasx/lasx_convert_utf32_to_utf16.cpp +218 -0
  446. package/deps/simdutf/src/lasx/lasx_convert_utf32_to_utf8.cpp +589 -0
  447. package/deps/simdutf/src/lasx/lasx_convert_utf8_to_latin1.cpp +72 -0
  448. package/deps/simdutf/src/lasx/lasx_convert_utf8_to_utf16.cpp +296 -0
  449. package/deps/simdutf/src/lasx/lasx_convert_utf8_to_utf32.cpp +190 -0
  450. package/deps/simdutf/src/lasx/lasx_find.cpp +64 -0
  451. package/deps/simdutf/src/lasx/lasx_validate_utf16.cpp +13 -0
  452. package/deps/simdutf/src/lasx/lasx_validate_utf32le.cpp +84 -0
  453. package/deps/simdutf/src/lsx/implementation.cpp +1417 -0
  454. package/deps/simdutf/src/lsx/lsx_base64.cpp +675 -0
  455. package/deps/simdutf/src/lsx/lsx_convert_latin1_to_utf16.cpp +39 -0
  456. package/deps/simdutf/src/lsx/lsx_convert_latin1_to_utf32.cpp +27 -0
  457. package/deps/simdutf/src/lsx/lsx_convert_latin1_to_utf8.cpp +56 -0
  458. package/deps/simdutf/src/lsx/lsx_convert_utf16_to_latin1.cpp +64 -0
  459. package/deps/simdutf/src/lsx/lsx_convert_utf16_to_utf32.cpp +133 -0
  460. package/deps/simdutf/src/lsx/lsx_convert_utf16_to_utf8.cpp +518 -0
  461. package/deps/simdutf/src/lsx/lsx_convert_utf32_to_latin1.cpp +66 -0
  462. package/deps/simdutf/src/lsx/lsx_convert_utf32_to_utf16.cpp +155 -0
  463. package/deps/simdutf/src/lsx/lsx_convert_utf32_to_utf8.cpp +459 -0
  464. package/deps/simdutf/src/lsx/lsx_convert_utf8_to_latin1.cpp +75 -0
  465. package/deps/simdutf/src/lsx/lsx_convert_utf8_to_utf16.cpp +291 -0
  466. package/deps/simdutf/src/lsx/lsx_convert_utf8_to_utf32.cpp +179 -0
  467. package/deps/simdutf/src/lsx/lsx_find.cpp +60 -0
  468. package/deps/simdutf/src/lsx/lsx_validate_utf16.cpp +13 -0
  469. package/deps/simdutf/src/lsx/lsx_validate_utf32le.cpp +68 -0
  470. package/deps/simdutf/src/ppc64/implementation.cpp +992 -0
  471. package/deps/simdutf/src/ppc64/ppc64_base64.cpp +480 -0
  472. package/deps/simdutf/src/ppc64/ppc64_base64_internal_tests.cpp +401 -0
  473. package/deps/simdutf/src/ppc64/ppc64_convert_latin1_to_utf16.cpp +12 -0
  474. package/deps/simdutf/src/ppc64/ppc64_convert_latin1_to_utf32.cpp +12 -0
  475. package/deps/simdutf/src/ppc64/ppc64_convert_latin1_to_utf8.cpp +149 -0
  476. package/deps/simdutf/src/ppc64/ppc64_convert_utf16_to_latin1.cpp +67 -0
  477. package/deps/simdutf/src/ppc64/ppc64_convert_utf16_to_utf32.cpp +87 -0
  478. package/deps/simdutf/src/ppc64/ppc64_convert_utf16_to_utf8.cpp +296 -0
  479. package/deps/simdutf/src/ppc64/ppc64_convert_utf32_to_latin1.cpp +57 -0
  480. package/deps/simdutf/src/ppc64/ppc64_convert_utf32_to_utf16.cpp +117 -0
  481. package/deps/simdutf/src/ppc64/ppc64_convert_utf32_to_utf8.cpp +166 -0
  482. package/deps/simdutf/src/ppc64/ppc64_convert_utf8_to_latin1.cpp +69 -0
  483. package/deps/simdutf/src/ppc64/ppc64_convert_utf8_to_utf16.cpp +211 -0
  484. package/deps/simdutf/src/ppc64/ppc64_convert_utf8_to_utf32.cpp +153 -0
  485. package/deps/simdutf/src/ppc64/ppc64_utf16_to_utf8_tables.h +1011 -0
  486. package/deps/simdutf/src/ppc64/ppc64_utf8_length_from_latin1.cpp +37 -0
  487. package/deps/simdutf/src/ppc64/ppc64_validate_utf16.cpp +19 -0
  488. package/deps/simdutf/src/ppc64/templates.cpp +91 -0
  489. package/deps/simdutf/src/rvv/implementation.cpp +138 -0
  490. package/deps/simdutf/src/rvv/rvv_find.cpp +27 -0
  491. package/deps/simdutf/src/rvv/rvv_helpers.inl.cpp +23 -0
  492. package/deps/simdutf/src/rvv/rvv_latin1_to.inl.cpp +71 -0
  493. package/deps/simdutf/src/rvv/rvv_length_from.inl.cpp +164 -0
  494. package/deps/simdutf/src/rvv/rvv_utf16_to.inl.cpp +399 -0
  495. package/deps/simdutf/src/rvv/rvv_utf16fix.cpp +110 -0
  496. package/deps/simdutf/src/rvv/rvv_utf32_to.inl.cpp +307 -0
  497. package/deps/simdutf/src/rvv/rvv_utf8_to.inl.cpp +435 -0
  498. package/deps/simdutf/src/rvv/rvv_validate.inl.cpp +275 -0
  499. package/deps/simdutf/src/simdutf/arm64/begin.h +2 -0
  500. package/deps/simdutf/src/simdutf/arm64/bitmanipulation.h +34 -0
  501. package/deps/simdutf/src/simdutf/arm64/end.h +2 -0
  502. package/deps/simdutf/src/simdutf/arm64/implementation.h +307 -0
  503. package/deps/simdutf/src/simdutf/arm64/intrinsics.h +10 -0
  504. package/deps/simdutf/src/simdutf/arm64/simd.h +547 -0
  505. package/deps/simdutf/src/simdutf/arm64/simd16-inl.h +403 -0
  506. package/deps/simdutf/src/simdutf/arm64/simd32-inl.h +129 -0
  507. package/deps/simdutf/src/simdutf/arm64/simd64-inl.h +28 -0
  508. package/deps/simdutf/src/simdutf/arm64.h +43 -0
  509. package/deps/simdutf/src/simdutf/fallback/begin.h +1 -0
  510. package/deps/simdutf/src/simdutf/fallback/bitmanipulation.h +13 -0
  511. package/deps/simdutf/src/simdutf/fallback/end.h +1 -0
  512. package/deps/simdutf/src/simdutf/fallback/implementation.h +331 -0
  513. package/deps/simdutf/src/simdutf/fallback.h +42 -0
  514. package/deps/simdutf/src/simdutf/haswell/begin.h +15 -0
  515. package/deps/simdutf/src/simdutf/haswell/bitmanipulation.h +35 -0
  516. package/deps/simdutf/src/simdutf/haswell/end.h +13 -0
  517. package/deps/simdutf/src/simdutf/haswell/implementation.h +338 -0
  518. package/deps/simdutf/src/simdutf/haswell/intrinsics.h +67 -0
  519. package/deps/simdutf/src/simdutf/haswell/simd.h +363 -0
  520. package/deps/simdutf/src/simdutf/haswell/simd16-inl.h +261 -0
  521. package/deps/simdutf/src/simdutf/haswell/simd32-inl.h +111 -0
  522. package/deps/simdutf/src/simdutf/haswell/simd64-inl.h +34 -0
  523. package/deps/simdutf/src/simdutf/haswell.h +63 -0
  524. package/deps/simdutf/src/simdutf/icelake/begin.h +14 -0
  525. package/deps/simdutf/src/simdutf/icelake/bitmanipulation.h +44 -0
  526. package/deps/simdutf/src/simdutf/icelake/end.h +12 -0
  527. package/deps/simdutf/src/simdutf/icelake/implementation.h +346 -0
  528. package/deps/simdutf/src/simdutf/icelake/intrinsics.h +138 -0
  529. package/deps/simdutf/src/simdutf/icelake/simd.h +17 -0
  530. package/deps/simdutf/src/simdutf/icelake/simd16-inl.h +90 -0
  531. package/deps/simdutf/src/simdutf/icelake/simd32-inl.h +47 -0
  532. package/deps/simdutf/src/simdutf/icelake.h +81 -0
  533. package/deps/simdutf/src/simdutf/lasx/begin.h +8 -0
  534. package/deps/simdutf/src/simdutf/lasx/bitmanipulation.h +25 -0
  535. package/deps/simdutf/src/simdutf/lasx/end.h +8 -0
  536. package/deps/simdutf/src/simdutf/lasx/implementation.h +310 -0
  537. package/deps/simdutf/src/simdutf/lasx/intrinsics.h +319 -0
  538. package/deps/simdutf/src/simdutf/lasx/simd.h +551 -0
  539. package/deps/simdutf/src/simdutf/lasx/simd16-inl.h +234 -0
  540. package/deps/simdutf/src/simdutf/lasx/simd32-inl.h +74 -0
  541. package/deps/simdutf/src/simdutf/lasx/simd64-inl.h +52 -0
  542. package/deps/simdutf/src/simdutf/lasx.h +49 -0
  543. package/deps/simdutf/src/simdutf/lsx/begin.h +2 -0
  544. package/deps/simdutf/src/simdutf/lsx/bitmanipulation.h +25 -0
  545. package/deps/simdutf/src/simdutf/lsx/end.h +2 -0
  546. package/deps/simdutf/src/simdutf/lsx/implementation.h +309 -0
  547. package/deps/simdutf/src/simdutf/lsx/intrinsics.h +196 -0
  548. package/deps/simdutf/src/simdutf/lsx/simd.h +421 -0
  549. package/deps/simdutf/src/simdutf/lsx/simd16-inl.h +242 -0
  550. package/deps/simdutf/src/simdutf/lsx/simd32-inl.h +69 -0
  551. package/deps/simdutf/src/simdutf/lsx/simd64-inl.h +50 -0
  552. package/deps/simdutf/src/simdutf/lsx.h +52 -0
  553. package/deps/simdutf/src/simdutf/ppc64/begin.h +1 -0
  554. package/deps/simdutf/src/simdutf/ppc64/bitmanipulation.h +29 -0
  555. package/deps/simdutf/src/simdutf/ppc64/end.h +1 -0
  556. package/deps/simdutf/src/simdutf/ppc64/implementation.h +348 -0
  557. package/deps/simdutf/src/simdutf/ppc64/intrinsics.h +19 -0
  558. package/deps/simdutf/src/simdutf/ppc64/simd.h +177 -0
  559. package/deps/simdutf/src/simdutf/ppc64/simd16-inl.h +327 -0
  560. package/deps/simdutf/src/simdutf/ppc64/simd32-inl.h +247 -0
  561. package/deps/simdutf/src/simdutf/ppc64/simd8-inl.h +618 -0
  562. package/deps/simdutf/src/simdutf/ppc64.h +40 -0
  563. package/deps/simdutf/src/simdutf/rvv/begin.h +7 -0
  564. package/deps/simdutf/src/simdutf/rvv/end.h +7 -0
  565. package/deps/simdutf/src/simdutf/rvv/implementation.h +321 -0
  566. package/deps/simdutf/src/simdutf/rvv/intrinsics.h +131 -0
  567. package/deps/simdutf/src/simdutf/rvv.h +41 -0
  568. package/deps/simdutf/src/simdutf/westmere/begin.h +8 -0
  569. package/deps/simdutf/src/simdutf/westmere/bitmanipulation.h +37 -0
  570. package/deps/simdutf/src/simdutf/westmere/end.h +8 -0
  571. package/deps/simdutf/src/simdutf/westmere/implementation.h +338 -0
  572. package/deps/simdutf/src/simdutf/westmere/intrinsics.h +38 -0
  573. package/deps/simdutf/src/simdutf/westmere/simd.h +379 -0
  574. package/deps/simdutf/src/simdutf/westmere/simd16-inl.h +242 -0
  575. package/deps/simdutf/src/simdutf/westmere/simd32-inl.h +151 -0
  576. package/deps/simdutf/src/simdutf/westmere/simd64-inl.h +33 -0
  577. package/deps/simdutf/src/simdutf/westmere.h +59 -0
  578. package/deps/simdutf/src/simdutf.cpp +152 -0
  579. package/deps/simdutf/src/simdutf_c.cpp +525 -0
  580. package/deps/simdutf/src/tables/utf16_to_utf8_tables.h +768 -0
  581. package/deps/simdutf/src/tables/utf32_to_utf16_tables.h +53 -0
  582. package/deps/simdutf/src/tables/utf8_to_utf16_tables.h +826 -0
  583. package/deps/simdutf/src/westmere/implementation.cpp +1479 -0
  584. package/deps/simdutf/src/westmere/internal/loader.cpp +7 -0
  585. package/deps/simdutf/src/westmere/internal/write_v_u16_11bits_to_utf8.cpp +66 -0
  586. package/deps/simdutf/src/westmere/sse_base64.cpp +672 -0
  587. package/deps/simdutf/src/westmere/sse_convert_latin1_to_utf16.cpp +21 -0
  588. package/deps/simdutf/src/westmere/sse_convert_latin1_to_utf32.cpp +31 -0
  589. package/deps/simdutf/src/westmere/sse_convert_latin1_to_utf8.cpp +71 -0
  590. package/deps/simdutf/src/westmere/sse_convert_utf16_to_latin1.cpp +70 -0
  591. package/deps/simdutf/src/westmere/sse_convert_utf16_to_utf32.cpp +206 -0
  592. package/deps/simdutf/src/westmere/sse_convert_utf16_to_utf8.cpp +504 -0
  593. package/deps/simdutf/src/westmere/sse_convert_utf32_to_latin1.cpp +82 -0
  594. package/deps/simdutf/src/westmere/sse_convert_utf32_to_utf16.cpp +209 -0
  595. package/deps/simdutf/src/westmere/sse_convert_utf32_to_utf8.cpp +589 -0
  596. package/deps/simdutf/src/westmere/sse_convert_utf8_to_latin1.cpp +58 -0
  597. package/deps/simdutf/src/westmere/sse_convert_utf8_to_utf16.cpp +197 -0
  598. package/deps/simdutf/src/westmere/sse_convert_utf8_to_utf32.cpp +141 -0
  599. package/deps/simdutf/src/westmere/sse_utf16fix.cpp +82 -0
  600. package/deps/simdutf/src/westmere/sse_validate_utf16.cpp +17 -0
  601. package/deps/simdutf/tests/CMakeLists.txt +483 -0
  602. package/deps/simdutf/tests/atomic_base64_tests.cpp +2845 -0
  603. package/deps/simdutf/tests/base64_tests.cpp +3617 -0
  604. package/deps/simdutf/tests/basic_fuzzer.cpp +805 -0
  605. package/deps/simdutf/tests/bele_tests.cpp +182 -0
  606. package/deps/simdutf/tests/constexpr_base64_tests.cpp +387 -0
  607. package/deps/simdutf/tests/convert_latin1_to_utf16be_tests.cpp +52 -0
  608. package/deps/simdutf/tests/convert_latin1_to_utf16le_tests.cpp +80 -0
  609. package/deps/simdutf/tests/convert_latin1_to_utf32_tests.cpp +66 -0
  610. package/deps/simdutf/tests/convert_latin1_to_utf8_tests.cpp +120 -0
  611. package/deps/simdutf/tests/convert_utf16_to_utf8_safe_tests.cpp +203 -0
  612. package/deps/simdutf/tests/convert_utf16_to_utf8_with_replacement_tests.cpp +276 -0
  613. package/deps/simdutf/tests/convert_utf16be_to_latin1_tests.cpp +109 -0
  614. package/deps/simdutf/tests/convert_utf16be_to_latin1_tests_with_errors.cpp +136 -0
  615. package/deps/simdutf/tests/convert_utf16be_to_utf32_tests.cpp +193 -0
  616. package/deps/simdutf/tests/convert_utf16be_to_utf32_with_errors_tests.cpp +381 -0
  617. package/deps/simdutf/tests/convert_utf16be_to_utf8_tests.cpp +259 -0
  618. package/deps/simdutf/tests/convert_utf16be_to_utf8_with_errors_tests.cpp +266 -0
  619. package/deps/simdutf/tests/convert_utf16le_to_latin1_tests.cpp +148 -0
  620. package/deps/simdutf/tests/convert_utf16le_to_latin1_tests_with_errors.cpp +176 -0
  621. package/deps/simdutf/tests/convert_utf16le_to_utf32_tests.cpp +213 -0
  622. package/deps/simdutf/tests/convert_utf16le_to_utf32_with_errors_tests.cpp +318 -0
  623. package/deps/simdutf/tests/convert_utf16le_to_utf8_tests.cpp +343 -0
  624. package/deps/simdutf/tests/convert_utf16le_to_utf8_with_errors_tests.cpp +271 -0
  625. package/deps/simdutf/tests/convert_utf32_to_latin1_tests.cpp +111 -0
  626. package/deps/simdutf/tests/convert_utf32_to_latin1_with_errors_tests.cpp +96 -0
  627. package/deps/simdutf/tests/convert_utf32_to_utf16be_tests.cpp +148 -0
  628. package/deps/simdutf/tests/convert_utf32_to_utf16be_with_errors_tests.cpp +192 -0
  629. package/deps/simdutf/tests/convert_utf32_to_utf16le_tests.cpp +166 -0
  630. package/deps/simdutf/tests/convert_utf32_to_utf16le_with_errors_tests.cpp +215 -0
  631. package/deps/simdutf/tests/convert_utf32_to_utf8_tests.cpp +181 -0
  632. package/deps/simdutf/tests/convert_utf32_to_utf8_with_errors_tests.cpp +261 -0
  633. package/deps/simdutf/tests/convert_utf8_to_latin1_tests.cpp +516 -0
  634. package/deps/simdutf/tests/convert_utf8_to_latin1_with_errors_tests.cpp +579 -0
  635. package/deps/simdutf/tests/convert_utf8_to_utf16be_tests.cpp +412 -0
  636. package/deps/simdutf/tests/convert_utf8_to_utf16be_with_errors_tests.cpp +480 -0
  637. package/deps/simdutf/tests/convert_utf8_to_utf16le_tests.cpp +671 -0
  638. package/deps/simdutf/tests/convert_utf8_to_utf16le_with_errors_tests.cpp +455 -0
  639. package/deps/simdutf/tests/convert_utf8_to_utf32_tests.cpp +1204 -0
  640. package/deps/simdutf/tests/convert_utf8_to_utf32_with_errors_tests.cpp +337 -0
  641. package/deps/simdutf/tests/convert_valid_utf16be_to_latin1_tests.cpp +37 -0
  642. package/deps/simdutf/tests/convert_valid_utf16be_to_utf32_tests.cpp +97 -0
  643. package/deps/simdutf/tests/convert_valid_utf16be_to_utf8_tests.cpp +126 -0
  644. package/deps/simdutf/tests/convert_valid_utf16le_to_latin1_tests.cpp +71 -0
  645. package/deps/simdutf/tests/convert_valid_utf16le_to_utf32_tests.cpp +122 -0
  646. package/deps/simdutf/tests/convert_valid_utf16le_to_utf8_tests.cpp +244 -0
  647. package/deps/simdutf/tests/convert_valid_utf32_to_latin1_tests.cpp +49 -0
  648. package/deps/simdutf/tests/convert_valid_utf32_to_utf16be_tests.cpp +92 -0
  649. package/deps/simdutf/tests/convert_valid_utf32_to_utf16le_tests.cpp +114 -0
  650. package/deps/simdutf/tests/convert_valid_utf32_to_utf8_tests.cpp +109 -0
  651. package/deps/simdutf/tests/convert_valid_utf8_to_latin1_tests.cpp +84 -0
  652. package/deps/simdutf/tests/convert_valid_utf8_to_utf16be_tests.cpp +124 -0
  653. package/deps/simdutf/tests/convert_valid_utf8_to_utf16le_tests.cpp +221 -0
  654. package/deps/simdutf/tests/convert_valid_utf8_to_utf32_tests.cpp +155 -0
  655. package/deps/simdutf/tests/count_utf16be.cpp +64 -0
  656. package/deps/simdutf/tests/count_utf16le.cpp +61 -0
  657. package/deps/simdutf/tests/count_utf8.cpp +87 -0
  658. package/deps/simdutf/tests/detect_encodings_tests.cpp +312 -0
  659. package/deps/simdutf/tests/embed/valid_utf8.txt +1 -0
  660. package/deps/simdutf/tests/embed_tests.cpp +22 -0
  661. package/deps/simdutf/tests/find_tests.cpp +77 -0
  662. package/deps/simdutf/tests/fixed_string_tests.cpp +153 -0
  663. package/deps/simdutf/tests/helpers/CMakeLists.txt +25 -0
  664. package/deps/simdutf/tests/helpers/compiletime_conversions.h +222 -0
  665. package/deps/simdutf/tests/helpers/fixed_string.h +267 -0
  666. package/deps/simdutf/tests/helpers/random_int.cpp +30 -0
  667. package/deps/simdutf/tests/helpers/random_int.h +39 -0
  668. package/deps/simdutf/tests/helpers/random_utf16.cpp +123 -0
  669. package/deps/simdutf/tests/helpers/random_utf16.h +52 -0
  670. package/deps/simdutf/tests/helpers/random_utf32.cpp +41 -0
  671. package/deps/simdutf/tests/helpers/random_utf32.h +40 -0
  672. package/deps/simdutf/tests/helpers/random_utf8.cpp +93 -0
  673. package/deps/simdutf/tests/helpers/random_utf8.h +36 -0
  674. package/deps/simdutf/tests/helpers/test.cpp +231 -0
  675. package/deps/simdutf/tests/helpers/test.h +193 -0
  676. package/deps/simdutf/tests/helpers/transcode_test_base.cpp +1257 -0
  677. package/deps/simdutf/tests/helpers/transcode_test_base.h +683 -0
  678. package/deps/simdutf/tests/helpers/utf16.h +27 -0
  679. package/deps/simdutf/tests/installation_tests/find/CMakeLists.txt +43 -0
  680. package/deps/simdutf/tests/installation_tests/from_fetch/CMakeLists.txt +47 -0
  681. package/deps/simdutf/tests/internal_tests.cpp +27 -0
  682. package/deps/simdutf/tests/null_safety_tests.cpp +94 -0
  683. package/deps/simdutf/tests/random_fuzzer.cpp +779 -0
  684. package/deps/simdutf/tests/readme_tests.cpp +274 -0
  685. package/deps/simdutf/tests/reference/CMakeLists.txt +23 -0
  686. package/deps/simdutf/tests/reference/decode_utf16.h +81 -0
  687. package/deps/simdutf/tests/reference/decode_utf32.h +47 -0
  688. package/deps/simdutf/tests/reference/encode_latin1.cpp +1 -0
  689. package/deps/simdutf/tests/reference/encode_latin1.h +32 -0
  690. package/deps/simdutf/tests/reference/encode_utf16.cpp +49 -0
  691. package/deps/simdutf/tests/reference/encode_utf16.h +20 -0
  692. package/deps/simdutf/tests/reference/encode_utf32.cpp +1 -0
  693. package/deps/simdutf/tests/reference/encode_utf32.h +36 -0
  694. package/deps/simdutf/tests/reference/encode_utf8.cpp +1 -0
  695. package/deps/simdutf/tests/reference/encode_utf8.h +40 -0
  696. package/deps/simdutf/tests/reference/validate_utf16.cpp +60 -0
  697. package/deps/simdutf/tests/reference/validate_utf16.h +14 -0
  698. package/deps/simdutf/tests/reference/validate_utf16_to_latin1.cpp +35 -0
  699. package/deps/simdutf/tests/reference/validate_utf16_to_latin1.h +13 -0
  700. package/deps/simdutf/tests/reference/validate_utf32.cpp +27 -0
  701. package/deps/simdutf/tests/reference/validate_utf32.h +12 -0
  702. package/deps/simdutf/tests/reference/validate_utf32_to_latin1.cpp +27 -0
  703. package/deps/simdutf/tests/reference/validate_utf32_to_latin1.h +12 -0
  704. package/deps/simdutf/tests/reference/validate_utf8.cpp +82 -0
  705. package/deps/simdutf/tests/reference/validate_utf8.h +11 -0
  706. package/deps/simdutf/tests/reference/validate_utf8_to_latin1.cpp +43 -0
  707. package/deps/simdutf/tests/reference/validate_utf8_to_latin1.h +12 -0
  708. package/deps/simdutf/tests/select_implementation.cpp +43 -0
  709. package/deps/simdutf/tests/simdutf_c_tests.cpp +244 -0
  710. package/deps/simdutf/tests/span_tests.cpp +401 -0
  711. package/deps/simdutf/tests/special_tests.cpp +559 -0
  712. package/deps/simdutf/tests/straight_c_test.c +187 -0
  713. package/deps/simdutf/tests/text_encoding_tests.cpp +77 -0
  714. package/deps/simdutf/tests/to_well_formed_utf16_tests.cpp +377 -0
  715. package/deps/simdutf/tests/utf8_length_from_utf16_tests.cpp +202 -0
  716. package/deps/simdutf/tests/validate_ascii_basic_tests.cpp +165 -0
  717. package/deps/simdutf/tests/validate_ascii_with_errors_tests.cpp +77 -0
  718. package/deps/simdutf/tests/validate_utf16be_basic_tests.cpp +175 -0
  719. package/deps/simdutf/tests/validate_utf16be_with_errors_tests.cpp +188 -0
  720. package/deps/simdutf/tests/validate_utf16le_basic_tests.cpp +268 -0
  721. package/deps/simdutf/tests/validate_utf16le_with_errors_tests.cpp +274 -0
  722. package/deps/simdutf/tests/validate_utf32_basic_tests.cpp +92 -0
  723. package/deps/simdutf/tests/validate_utf32_with_errors_tests.cpp +114 -0
  724. package/deps/simdutf/tests/validate_utf8_basic_tests.cpp +178 -0
  725. package/deps/simdutf/tests/validate_utf8_brute_force_tests.cpp +88 -0
  726. package/deps/simdutf/tests/validate_utf8_puzzler_tests.cpp +33 -0
  727. package/deps/simdutf/tests/validate_utf8_with_errors_tests.cpp +228 -0
  728. package/deps/simdutf/tools/CMakeLists.txt +85 -0
  729. package/deps/simdutf/tools/fastbase64.cpp +250 -0
  730. package/deps/simdutf/tools/sutf.cpp +556 -0
  731. package/deps/simdutf/tools/sutf.h +40 -0
  732. package/lib/commonjs/blake3.js +2 -1
  733. package/lib/commonjs/blake3.js.map +1 -1
  734. package/lib/commonjs/diffie-hellman.js +5 -4
  735. package/lib/commonjs/diffie-hellman.js.map +1 -1
  736. package/lib/commonjs/ecdh.js +5 -4
  737. package/lib/commonjs/ecdh.js.map +1 -1
  738. package/lib/module/blake3.js +2 -1
  739. package/lib/module/blake3.js.map +1 -1
  740. package/lib/module/diffie-hellman.js +5 -4
  741. package/lib/module/diffie-hellman.js.map +1 -1
  742. package/lib/module/ecdh.js +5 -4
  743. package/lib/module/ecdh.js.map +1 -1
  744. package/lib/tsconfig.tsbuildinfo +1 -1
  745. package/lib/typescript/blake3.d.ts.map +1 -1
  746. package/lib/typescript/diffie-hellman.d.ts.map +1 -1
  747. package/lib/typescript/ecdh.d.ts.map +1 -1
  748. package/package.json +2 -2
  749. package/src/blake3.ts +2 -1
  750. package/src/diffie-hellman.ts +5 -7
  751. package/src/ecdh.ts +5 -8
@@ -0,0 +1,3617 @@
1
+ #include "simdutf.h"
2
+
3
+ #include <algorithm>
4
+ #include <array>
5
+ #include <cmath>
6
+ #include <cstddef>
7
+ #include <iostream>
8
+ #include <tuple>
9
+ #include <vector>
10
+
11
+ #include <tests/helpers/random_int.h>
12
+ #include <tests/helpers/test.h>
13
+
14
+ // to limit the runtime of this test
15
+ #ifndef SIMDUTF_BASE64_TEST_MAXLEN
16
+ #error "SIMDUTF_BASE64_TEST_MAXLEN not set."
17
+ #endif
18
+ constexpr std::size_t max_len = SIMDUTF_BASE64_TEST_MAXLEN;
19
+
20
+ // Return the length of the prefix that contains count base64 characters.
21
+ // Thus, if count is 3, the function returns the length of the prefix
22
+ // that contains 3 base64 characters. Padding characters are counted.
23
+ size_t prefix_length_base64_index(size_t count, simdutf::base64_options options,
24
+ const char *input, size_t length) {
25
+ size_t i = 0;
26
+ while (i < length && simdutf::base64_ignorable(input[i], options)) {
27
+ i++;
28
+ }
29
+ if (count == 0) {
30
+ return i; // duh!
31
+ }
32
+ for (; i < length; i++) {
33
+ if (simdutf::base64_ignorable(input[i], options)) {
34
+ continue;
35
+ }
36
+ // We have a base64 character or a padding character.
37
+ count--;
38
+ if (count == 0) {
39
+ return i + 1;
40
+ }
41
+ }
42
+ return -1; // should never happen
43
+ }
44
+
45
+ template <typename char_type>
46
+ size_t length_without_empty_tail(
47
+ const std::vector<char_type> &input,
48
+ simdutf::base64_options options = simdutf::base64_options::base64_default) {
49
+ if (input.size() == 0) {
50
+ return 0;
51
+ }
52
+ size_t i = input.size();
53
+ while (i > 0 && simdutf::base64_ignorable(input[i - 1], options)) {
54
+ i--;
55
+ }
56
+ return i;
57
+ }
58
+
59
+ // We may disable base64url tests by commenting out this next line.
60
+ #define SIMDUTF_BASE64URL_TESTS 1
61
+
62
+ using random_generator = std::mt19937;
63
+ static random_generator::result_type seed = 42;
64
+
65
+ constexpr uint8_t to_base64_value[] = {
66
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255,
67
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
68
+ 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255,
69
+ 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
70
+ 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
71
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
72
+ 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33,
73
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
74
+ 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
75
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
76
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
77
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
78
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
79
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
80
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
81
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
82
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
83
+ 255};
84
+
85
+ constexpr uint8_t to_base64url_value[] = {
86
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 64, 64, 255, 64, 64, 255,
87
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
88
+ 255, 255, 64, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
89
+ 62, 255, 255, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
90
+ 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
91
+ 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
92
+ 25, 255, 255, 255, 255, 63, 255, 26, 27, 28, 29, 30, 31, 32, 33,
93
+ 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
94
+ 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
95
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
96
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
97
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
98
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
99
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
100
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
101
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
102
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
103
+ 255};
104
+
105
+ template <typename char_type> bool is_space(char_type c) {
106
+ const static std::array<char_type, 5> space = {' ', '\t', '\n', '\r', '\f'};
107
+ return std::find(space.begin(), space.end(), c) != space.end();
108
+ }
109
+
110
+ template <typename char_type> bool is_non_base64_space(char_type c) {
111
+ return uint8_t(c) >= 128 || to_base64_value[uint8_t(c)] == 255;
112
+ }
113
+
114
+ template <typename char_type> bool is_non_base64_url_space(char_type c) {
115
+ return uint8_t(c) >= 128 || to_base64url_value[uint8_t(c)] == 255;
116
+ }
117
+
118
+ template <typename char_type>
119
+ size_t add_space(std::vector<char_type> &v, std::mt19937 &gen) {
120
+ const static std::array<char_type, 5> space = {' ', '\t', '\n', '\r', '\f'};
121
+ std::uniform_int_distribution<int> index_dist(0, v.size());
122
+ size_t i = index_dist(gen);
123
+ std::uniform_int_distribution<int> char_dist(0, space.size() - 1);
124
+ v.insert(v.begin() + i, space[char_dist(gen)]);
125
+ return i;
126
+ }
127
+
128
+ // consider using add_simple_spaces for better performance.
129
+ template <typename char_type>
130
+ size_t add_simple_space(std::vector<char_type> &v, std::mt19937 &gen) {
131
+ std::uniform_int_distribution<int> index_dist(0, v.size());
132
+ size_t i = index_dist(gen);
133
+ v.insert(v.begin() + i, ' ');
134
+ return i;
135
+ }
136
+
137
+ template <typename char_type>
138
+ std::vector<char_type> add_simple_spaces(std::vector<char_type> &v,
139
+ std::mt19937 &gen,
140
+ size_t number_of_spaces) {
141
+ // If there are no spaces to add or the vector is empty, return
142
+ if (number_of_spaces == 0) {
143
+ return v;
144
+ }
145
+
146
+ // Generate unique random positions
147
+ std::vector<bool> positions(v.size() + number_of_spaces, false);
148
+ std::uniform_int_distribution<size_t> dist(0, positions.size() - 1);
149
+ for (size_t i = 0; i < number_of_spaces; ++i) {
150
+ size_t pos = dist(gen);
151
+ while (positions[pos]) {
152
+ pos = dist(gen);
153
+ }
154
+ positions[pos] = true;
155
+ }
156
+ std::vector<char_type> result;
157
+ result.resize(v.size() + number_of_spaces);
158
+ int pos = 0;
159
+ for (size_t i = 0; i < v.size() + number_of_spaces; ++i) {
160
+ if (positions[i]) {
161
+ result[i] = ' ';
162
+ } else {
163
+ result[i] = v[pos++];
164
+ }
165
+ }
166
+ return result;
167
+ }
168
+
169
+ std::string add_simple_spaces(const std::string &v, std::mt19937 &gen,
170
+ size_t number_of_spaces) {
171
+ // If there are no spaces to add or the vector is empty, return
172
+ if (number_of_spaces == 0) {
173
+ return v;
174
+ }
175
+
176
+ // Generate unique random positions
177
+ std::vector<bool> positions(v.size() + number_of_spaces, false);
178
+ std::uniform_int_distribution<size_t> dist(0, positions.size() - 1);
179
+ for (size_t i = 0; i < number_of_spaces; ++i) {
180
+ size_t pos = dist(gen);
181
+ while (positions[pos]) {
182
+ pos = dist(gen);
183
+ }
184
+ positions[pos] = true;
185
+ }
186
+ std::string result;
187
+ result.resize(v.size() + number_of_spaces);
188
+ int pos = 0;
189
+ for (size_t i = 0; i < v.size() + number_of_spaces; ++i) {
190
+ if (positions[i]) {
191
+ result[i] = ' ';
192
+ } else {
193
+ result[i] = v[pos++];
194
+ }
195
+ }
196
+ return result;
197
+ }
198
+
199
+ template <typename char_type>
200
+ size_t add_garbage(std::vector<char_type> &v, std::mt19937 &gen,
201
+ const uint8_t *table) {
202
+ auto equal_sign = std::find(v.begin(), v.end(), '=');
203
+ size_t len = v.size();
204
+ if (equal_sign != v.end()) {
205
+ len = std::distance(v.begin(), equal_sign);
206
+ }
207
+ std::uniform_int_distribution<int> index_dist(0, len);
208
+ size_t i = index_dist(gen);
209
+ std::uniform_int_distribution<int> char_dist(
210
+ 0, (1 << (sizeof(char_type) * 8)) - 1);
211
+ char_type c = char_dist(gen);
212
+ while ((uint8_t(c) == c && table[uint8_t(c)] != 255) || c == '=') {
213
+ c = char_dist(gen);
214
+ }
215
+ v.insert(v.begin() + i, c);
216
+ return i;
217
+ }
218
+
219
+ // https://github.com/tc39/test262/blob/f0dc15c6c7ec095ba3caf3acc0f8665394665841/test/built-ins/Uint8Array/fromBase64/last-chunk-invalid.js
220
+ TEST(tc39_illegal_padded_chunks) {
221
+ std::string test_cases[] = {
222
+ "=", "==", "===", "====", "=====", "A=",
223
+ "A==", "A===", "A====", "A=====", "AA====", "AA=====",
224
+ "AAA==", "AAA===", "AAA====", "AAA=====", "AAAA=", "AAAA==",
225
+ "AAAA===", "AAAA====", "AAAA=====", "AAAAA=", "AAAAA==", "AAAAA===",
226
+ "AAAAA====", "AAAAA====="};
227
+ std::mt19937 gen((std::mt19937::result_type)(seed));
228
+ for (const std::string &input : test_cases) {
229
+ std::vector<uint8_t> back(255);
230
+ size_t len = back.size();
231
+ for (auto option :
232
+ {simdutf::last_chunk_handling_options::strict,
233
+ simdutf::last_chunk_handling_options::loose,
234
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
235
+ auto r = simdutf::base64_to_binary_safe(
236
+ input.data(), input.size(), reinterpret_cast<char *>(back.data()),
237
+ len, simdutf::base64_default, option, true);
238
+ ASSERT_FALSE(r.error == simdutf::error_code::SUCCESS);
239
+ ASSERT_FALSE(r.error == simdutf::error_code::OUTPUT_BUFFER_TOO_SMALL);
240
+ }
241
+ }
242
+ }
243
+
244
+ // From Node.js tests:
245
+ TEST(issue_node_anything_goes) {
246
+
247
+ auto test =
248
+ [](const std::string &input, const std::string &expected,
249
+ simdutf::base64_options options =
250
+ simdutf::base64_options::base64_default_or_url_accept_garbage) {
251
+ size_t buflen = simdutf::maximal_binary_length_from_base64(
252
+ input.data(), input.size());
253
+ std::vector<char> back(buflen);
254
+ size_t written_len = buflen;
255
+ auto result = simdutf::base64_to_binary_safe(
256
+ input.data(), input.length(), back.data(), written_len,
257
+ simdutf::base64_default_or_url_accept_garbage);
258
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
259
+ ASSERT_EQUAL(written_len, expected.size());
260
+ ASSERT_TRUE(std::equal(back.begin(), back.begin() + written_len,
261
+ expected.begin()));
262
+ };
263
+ test("YQ", "a");
264
+ test("Y Q", "a");
265
+ test("Y Q ", "a");
266
+ test(" Y Q", "a");
267
+ test("Y Q==", "a");
268
+ test("YQ ==", "a");
269
+ test("YQ == junk", "a");
270
+ test("YWI", "ab");
271
+ test("YWI=", "ab");
272
+ test("YWJj", "abc");
273
+ test("YWJjZA", "abcd");
274
+ test("YWJjZA==", "abcd");
275
+ test("YW Jj ZA ==", "abcd");
276
+ test("YWJjZGU=", "abcde");
277
+ test("YWJjZGVm", "abcdef");
278
+ test("Y WJjZGVm", "abcdef");
279
+ test("YW JjZGVm", "abcdef");
280
+ test("YWJ jZGVm", "abcdef");
281
+ test("YWJj ZGVm", "abcdef");
282
+ test("Y W J j Z G V m", "abcdef");
283
+ test("Y W\n JjZ \nG Vm", "abcdef");
284
+ test("rMeTqoNvw-M_dQ", "\xac\xc7\x93\xaa\x83\x6f\xc3\xe3\x3f\x75");
285
+
286
+ const char *text =
287
+ "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "
288
+ "eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut "
289
+ "enim ad minim veniam, quis nostrud exercitation ullamco laboris "
290
+ "nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in "
291
+ "reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla "
292
+ "pariatur. Excepteur sint occaecat cupidatat non proident, sunt in "
293
+ "culpa qui officia deserunt mollit anim id est laborum.";
294
+
295
+ test("TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Npbmcg"
296
+ "ZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0"
297
+ "IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlz"
298
+ "IG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1"
299
+ "aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBp"
300
+ "biByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xv"
301
+ "cmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNh"
302
+ "dCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lh"
303
+ "IGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==",
304
+ text);
305
+
306
+ test("TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Npbmcg"
307
+ "ZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0"
308
+ "IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlz"
309
+ "IG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1"
310
+ "aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBp"
311
+ "biByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xv"
312
+ "cmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNh"
313
+ "dCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lh"
314
+ "IGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg",
315
+ text);
316
+
317
+ test("TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Npbmcg\n"
318
+ "ZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0\n"
319
+ "IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlz\n"
320
+ "IG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1\n"
321
+ "aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBp\n"
322
+ "biByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xv\n"
323
+ "cmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNh\n"
324
+ "dCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lh\n"
325
+ "IGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg==",
326
+ text);
327
+
328
+ test("TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2Npbmcg\n"
329
+ "ZWxpdCwgc2VkIGRvIGVpdXNtb2QgdGVtcG9yIGluY2lkaWR1bnQgdXQgbGFib3JlIGV0\n"
330
+ "IGRvbG9yZSBtYWduYSBhbGlxdWEuIFV0IGVuaW0gYWQgbWluaW0gdmVuaWFtLCBxdWlz\n"
331
+ "IG5vc3RydWQgZXhlcmNpdGF0aW9uIHVsbGFtY28gbGFib3JpcyBuaXNpIHV0IGFsaXF1\n"
332
+ "aXAgZXggZWEgY29tbW9kbyBjb25zZXF1YXQuIER1aXMgYXV0ZSBpcnVyZSBkb2xvciBp\n"
333
+ "biByZXByZWhlbmRlcml0IGluIHZvbHVwdGF0ZSB2ZWxpdCBlc3NlIGNpbGx1bSBkb2xv\n"
334
+ "cmUgZXUgZnVnaWF0IG51bGxhIHBhcmlhdHVyLiBFeGNlcHRldXIgc2ludCBvY2NhZWNh\n"
335
+ "dCBjdXBpZGF0YXQgbm9uIHByb2lkZW50LCBzdW50IGluIGN1bHBhIHF1aSBvZmZpY2lh\n"
336
+ "IGRlc2VydW50IG1vbGxpdCBhbmltIGlkIGVzdCBsYWJvcnVtLg",
337
+ text);
338
+ }
339
+
340
+ TEST(issue_dash) {
341
+ const std::string input = "Iw==";
342
+ std::vector<char> back(1);
343
+ size_t len = back.size();
344
+ auto r = simdutf::base64_to_binary_safe(input.data(), input.size(),
345
+ back.data(), len);
346
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
347
+ ASSERT_EQUAL(r.count, 4);
348
+ ASSERT_EQUAL(len, 1);
349
+ ASSERT_EQUAL(back[0], '#');
350
+ }
351
+
352
+ TEST(issue_dash_partial) {
353
+ const std::string input = "Iw==";
354
+ std::vector<char> back(1);
355
+ size_t len = back.size();
356
+ auto r = simdutf::base64_to_binary_safe(
357
+ input.data(), input.size(), back.data(), len, simdutf::base64_default,
358
+ simdutf::last_chunk_handling_options::stop_before_partial);
359
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
360
+ ASSERT_EQUAL(r.count, 4);
361
+ ASSERT_EQUAL(len, 1);
362
+ ASSERT_EQUAL(back[0], '#');
363
+ }
364
+
365
+ // https://github.com/tc39/test262
366
+ TEST(tc39_4a) {
367
+ std::pair<std::string, std::vector<uint8_t>> test_cases[] = {
368
+ {"ZXhhZg==", {101, 120, 97, 102}},
369
+ {"ZXhhZg", {101, 120, 97}},
370
+ {"ZXhhZh==", {101, 120, 97, 102}},
371
+ {"ZXhhZh", {101, 120, 97}},
372
+ {"ZXhhZg=", {101, 120, 97}}};
373
+ for (const auto tc : test_cases) {
374
+ const std::string &input = tc.first;
375
+ const std::vector<uint8_t> &expected = tc.second;
376
+ std::vector<uint8_t> back(expected.size(), 255);
377
+ size_t len = back.size();
378
+ auto r = simdutf::base64_to_binary_safe(
379
+ input.data(), input.size(), reinterpret_cast<char *>(back.data()), len,
380
+ simdutf::base64_default,
381
+ simdutf::last_chunk_handling_options::stop_before_partial, true);
382
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
383
+ ASSERT_EQUAL(len, expected.size());
384
+ ASSERT_EQUAL(back, expected);
385
+ }
386
+ }
387
+
388
+ // https://github.com/tc39/test262
389
+ TEST(tc39_4b) {
390
+ std::pair<std::string, std::vector<uint8_t>> test_cases[] = {
391
+ {"ZXhhZg==", {101, 120, 97, 102}},
392
+ {"ZXhhZg", {101, 120, 97}},
393
+ {"ZXhhZh==", {101, 120, 97, 102}},
394
+ {"ZXhhZh", {101, 120, 97}},
395
+ {"ZXhhZg=", {101, 120, 97}}};
396
+ for (const auto tc : test_cases) {
397
+ const std::string &input = tc.first;
398
+ const std::vector<uint8_t> &expected = tc.second;
399
+ std::vector<uint8_t> back(expected.size(), 255);
400
+ size_t len = back.size();
401
+ auto r = simdutf::base64_to_binary_safe(
402
+ input.data(), input.size(), reinterpret_cast<char *>(back.data()), len,
403
+ simdutf::base64_default,
404
+ simdutf::last_chunk_handling_options::stop_before_partial, true);
405
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
406
+ ASSERT_EQUAL(len, expected.size());
407
+ ASSERT_EQUAL(back, expected);
408
+ }
409
+ }
410
+
411
+ // https://github.com/tc39/test262
412
+ TEST(tc39_3a) {
413
+ const std::string input = "ZXhhZg===";
414
+ std::vector<uint8_t> back = {255, 255, 255, 255, 255};
415
+
416
+ size_t len = back.size();
417
+ auto r = simdutf::base64_to_binary_safe(
418
+ input.data(), input.size(), reinterpret_cast<char *>(back.data()), len,
419
+ simdutf::base64_default,
420
+ simdutf::last_chunk_handling_options::stop_before_partial, true);
421
+ ASSERT_TRUE(r.error != simdutf::error_code::SUCCESS);
422
+ }
423
+
424
+ // https://github.com/tc39/test262
425
+ TEST(tc39_3b) {
426
+ const std::string input = "ZXhhZg===";
427
+ std::vector<uint8_t> back = {255, 255, 255, 255, 255};
428
+
429
+ size_t len = back.size();
430
+ auto r = implementation.base64_to_binary(
431
+ input.data(), input.size(), reinterpret_cast<char *>(back.data()),
432
+ simdutf::base64_default,
433
+ simdutf::last_chunk_handling_options::stop_before_partial);
434
+ ASSERT_TRUE(r.error != simdutf::error_code::SUCCESS);
435
+ }
436
+
437
+ // https://github.com/tc39/test262
438
+ TEST(tc39_1a) {
439
+ const std::string input = "Zm9vYmE=";
440
+ std::vector<uint8_t> back = {255, 255, 255, 255, 255};
441
+ std::vector<uint8_t> expected = {102, 111, 111, 98, 97};
442
+
443
+ size_t len = back.size();
444
+ auto r = simdutf::base64_to_binary_safe(
445
+ input.data(), input.size(), reinterpret_cast<char *>(back.data()), len,
446
+ simdutf::base64_default,
447
+ simdutf::last_chunk_handling_options::stop_before_partial, true);
448
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
449
+ ASSERT_EQUAL(r.count, 8);
450
+ ASSERT_EQUAL(len, 5);
451
+ ASSERT_EQUAL(back, expected);
452
+ }
453
+
454
+ // https://github.com/tc39/test262
455
+ TEST(tc39_1b) {
456
+ const std::string input = "Zm9vYmE=";
457
+ std::vector<uint8_t> back = {255, 255, 255, 255, 255};
458
+ std::vector<uint8_t> expected = {102, 111, 111, 98, 97};
459
+
460
+ size_t len = back.size();
461
+ auto r = simdutf::base64_to_binary_safe(
462
+ input.data(), input.size(), reinterpret_cast<char *>(back.data()), len,
463
+ simdutf::base64_default,
464
+ simdutf::last_chunk_handling_options::stop_before_partial, true);
465
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
466
+ ASSERT_EQUAL(r.count, 8);
467
+ ASSERT_EQUAL(len, 5);
468
+ ASSERT_EQUAL(back, expected);
469
+ }
470
+
471
+ // https://github.com/tc39/test262
472
+ TEST(tc39_2) {
473
+ const std::string input = "Zm9vYmE";
474
+ std::vector<uint8_t> back = {255, 255, 255, 255, 255};
475
+ std::vector<uint8_t> expected = {102, 111, 111, 255, 255};
476
+
477
+ size_t len = back.size();
478
+ auto r = simdutf::base64_to_binary_safe(
479
+ input.data(), input.size(), reinterpret_cast<char *>(back.data()), len,
480
+ simdutf::base64_default,
481
+ simdutf::last_chunk_handling_options::stop_before_partial, true);
482
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
483
+ ASSERT_EQUAL(r.count, 4);
484
+ ASSERT_EQUAL(len, 3);
485
+ ASSERT_EQUAL(back, expected);
486
+ }
487
+
488
+ // https://github.com/tc39/test262/blob/f0dc15c6c7ec095ba3caf3acc0f8665394665841/test/built-ins/Uint8Array/fromBase64/last-chunk-invalid.js
489
+ TEST(tc39_illegal_padded_chunks_unsafe) {
490
+ std::string test_cases[] = {
491
+ "=", "==", "===", "====", "=====", "A=",
492
+ "A==", "A===", "A====", "A=====", "AA====", "AA=====",
493
+ "AAA==", "AAA===", "AAA====", "AAA=====", "AAAA=", "AAAA==",
494
+ "AAAA===", "AAAA====", "AAAA=====", "AAAAA=", "AAAAA==", "AAAAA===",
495
+ "AAAAA====", "AAAAA====="};
496
+ std::mt19937 gen((std::mt19937::result_type)(seed));
497
+ for (const std::string &input : test_cases) {
498
+ std::vector<uint8_t> back(255);
499
+ size_t len = back.size();
500
+ for (auto option :
501
+ {simdutf::last_chunk_handling_options::strict,
502
+ simdutf::last_chunk_handling_options::loose,
503
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
504
+ auto r = simdutf::base64_to_binary(input.data(), input.size(),
505
+ reinterpret_cast<char *>(back.data()),
506
+ simdutf::base64_default, option);
507
+ ASSERT_FALSE(r.error == simdutf::error_code::SUCCESS);
508
+ }
509
+ }
510
+ std::string base(128, 'A');
511
+ for (const std::string &input_orig : test_cases) {
512
+ std::string input = base + input_orig;
513
+
514
+ std::vector<uint8_t> back(255);
515
+ size_t len = back.size();
516
+ for (auto option :
517
+ {simdutf::last_chunk_handling_options::strict,
518
+ simdutf::last_chunk_handling_options::loose,
519
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
520
+ auto r = simdutf::base64_to_binary(input.data(), input.size(),
521
+ reinterpret_cast<char *>(back.data()),
522
+ simdutf::base64_default, option);
523
+ ASSERT_FALSE(r.error == simdutf::error_code::SUCCESS);
524
+ }
525
+ }
526
+ for (const std::string &input_orig : test_cases) {
527
+ std::string input = base + input_orig;
528
+ input = add_simple_spaces(input, gen, 5 + 2 * input.size());
529
+ std::vector<uint8_t> back(255);
530
+ size_t len = back.size();
531
+ for (auto option :
532
+ {simdutf::last_chunk_handling_options::strict,
533
+ simdutf::last_chunk_handling_options::loose,
534
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
535
+ auto r = simdutf::base64_to_binary(input.data(), input.size(),
536
+ reinterpret_cast<char *>(back.data()),
537
+ simdutf::base64_default, option);
538
+ ASSERT_FALSE(r.error == simdutf::error_code::SUCCESS);
539
+ }
540
+ }
541
+ }
542
+
543
+ auto verify_lines = [](const char *c, int N, int line_length) {
544
+ int current_line_length = 0; // Track the length of the current line
545
+ // Iterate through the string
546
+ for (int i = 0; i < N; ++i) {
547
+ if (c[i] == '\n') {
548
+ // Check if a non-final line has incorrect length
549
+ if (current_line_length != line_length) {
550
+ std::cerr << "A non-final line has incorrect length "
551
+ << current_line_length << " != " << line_length << "\n";
552
+ std::cerr << std::string(c, N) << "\n";
553
+ return false;
554
+ }
555
+ current_line_length = 0; // Reset for the next line
556
+ continue;
557
+ }
558
+
559
+ current_line_length++;
560
+ // Check if the current line exceeds the allowed length
561
+ if (current_line_length > line_length) {
562
+ std::cerr << "A line exceeds the allowed length " << current_line_length
563
+ << " > " << line_length << "\n";
564
+ std::cerr << std::string(c, N) << "\n";
565
+ return false;
566
+ }
567
+ }
568
+ return true;
569
+ };
570
+
571
+ TEST(with_lines_pauldreik) {
572
+ size_t line_length = 5;
573
+ size_t max_length = 2048;
574
+ std::vector<char> source(max_length, 'f');
575
+ std::vector<char> back(max_length);
576
+ std::vector<char> buffer;
577
+ for (auto selected_option : {simdutf::base64_options::base64_url,
578
+ simdutf::base64_options::base64_default}) {
579
+ for (size_t line_length = 5; line_length < 128; line_length += 7) {
580
+ for (size_t length = 1; length < 2048; length += 17) {
581
+ buffer.resize(simdutf::base64_length_from_binary_with_lines(
582
+ length, selected_option, line_length));
583
+ size_t size = implementation.binary_to_base64_with_lines(
584
+ source.data(), length, buffer.data(), line_length, selected_option);
585
+ auto r = implementation.base64_to_binary(buffer.data(), buffer.size(),
586
+ back.data(), selected_option);
587
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
588
+ ASSERT_TRUE(
589
+ std::equal(back.begin(), back.begin() + length, source.begin()));
590
+ ASSERT_EQUAL(size, buffer.size());
591
+ ASSERT_TRUE(verify_lines(buffer.data(), buffer.size(), line_length));
592
+ }
593
+ }
594
+ }
595
+ }
596
+
597
+ TEST(with_lines) {
598
+
599
+ for (size_t line_length : {4, 64, 76, 80, 128}) {
600
+ for (size_t len = 0; len < max_len; len += 17) {
601
+ std::vector<char> source(len, 0);
602
+ std::vector<char> buffer;
603
+ buffer.resize(simdutf::base64_length_from_binary_with_lines(
604
+ len, simdutf::base64_default, line_length));
605
+ std::mt19937 gen((std::mt19937::result_type)(seed));
606
+ std::uniform_int_distribution<int> byte_generator{0, 255};
607
+ for (size_t trial = 0; trial < 2; trial++) {
608
+ for (size_t i = 0; i < len; i++) {
609
+ source[i] = byte_generator(gen);
610
+ }
611
+ size_t size = implementation.binary_to_base64_with_lines(
612
+ source.data(), source.size(), buffer.data(), line_length);
613
+ ASSERT_EQUAL(size, buffer.size());
614
+ buffer.resize(size); // unnecessary
615
+ ASSERT_TRUE(verify_lines(buffer.data(), buffer.size(), line_length));
616
+ std::vector<char> back(simdutf::maximal_binary_length_from_base64(
617
+ buffer.data(), buffer.size()));
618
+ auto option = simdutf::last_chunk_handling_options::stop_before_partial;
619
+
620
+ simdutf::full_result r = implementation.base64_to_binary_details(
621
+ buffer.data(), buffer.size(), back.data(), simdutf::base64_default,
622
+ option);
623
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
624
+ const size_t expected_output_length = len;
625
+ const size_t expected_input_length = prefix_length_base64_index(
626
+ (expected_output_length + 2) / 3 * 4, simdutf::base64_default,
627
+ buffer.data(), buffer.size());
628
+ ASSERT_EQUAL(r.output_count, expected_output_length);
629
+ ASSERT_TRUE(std::equal(back.begin(),
630
+ back.begin() + expected_output_length,
631
+ source.begin()));
632
+ ASSERT_EQUAL(r.input_count, expected_input_length);
633
+ }
634
+ }
635
+ }
636
+ }
637
+
638
+ // stop-before-partial should behave like so:
639
+ // 1. if the last chunk is not a multiple of 4, we should stop before the last
640
+ // chunk
641
+ // 2. if the last chunk is a multiple of 4 (counting padding), we should
642
+ // decode it
643
+ // 3. If there is a padding character appearing in the last chunk where we have
644
+ // fewer than 2 base64 characters, we should return an error.
645
+ //
646
+ // https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64
647
+ //
648
+ TEST(partial_should_decode_up_to_last_chunk) {
649
+ for (size_t len = 0; len < max_len; len++) {
650
+ std::vector<char> source(len, 0);
651
+ std::vector<char> buffer;
652
+ buffer.resize(simdutf::base64_length_from_binary(len));
653
+ std::mt19937 gen((std::mt19937::result_type)(seed));
654
+ std::uniform_int_distribution<int> byte_generator{0, 255};
655
+ for (size_t trial = 0; trial < 10; trial++) {
656
+ for (size_t i = 0; i < len; i++) {
657
+ source[i] = byte_generator(gen);
658
+ }
659
+ buffer.resize(simdutf::base64_length_from_binary(len));
660
+ size_t size = implementation.binary_to_base64(
661
+ source.data(), source.size(), buffer.data());
662
+ ASSERT_EQUAL(size, buffer.size());
663
+ buffer.resize(size); // unnecessary
664
+ add_simple_spaces(buffer, gen, 5 + 2 * len);
665
+ std::vector<char> back(simdutf::maximal_binary_length_from_base64(
666
+ buffer.data(), buffer.size()));
667
+ auto option = simdutf::last_chunk_handling_options::stop_before_partial;
668
+
669
+ simdutf::full_result r = implementation.base64_to_binary_details(
670
+ buffer.data(), buffer.size(), back.data(), simdutf::base64_default,
671
+ option);
672
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
673
+ const size_t expected_output_length = len;
674
+ const size_t expected_input_length = prefix_length_base64_index(
675
+ (expected_output_length + 2) / 3 * 4, simdutf::base64_default,
676
+ buffer.data(), buffer.size());
677
+ ASSERT_EQUAL(r.output_count, expected_output_length);
678
+ ASSERT_TRUE(std::equal(
679
+ back.begin(), back.begin() + expected_output_length, source.begin()));
680
+ // If there is just zero one character in the last chunk, and there is a
681
+ // padding character, we should return an error.
682
+ if (buffer.size() > 0 && len > 0 && len % 3 != 0) {
683
+ // We have a last chunk that is not a multiple of 4.
684
+ // So there are padding characters.
685
+ size_t to_remove = 0;
686
+ // We want to leave just one character in the last chunk
687
+ // This should cause an error.
688
+ if (len % 3 == 1) {
689
+ // last chunk is 2
690
+ to_remove = 1;
691
+ } else if (len % 3 == 2) {
692
+ // last chunk is 3
693
+ to_remove = 2;
694
+ }
695
+ for (size_t i = buffer.size() - 1;; i--) {
696
+ if (simdutf::base64_valid(buffer[i], simdutf::base64_default)) {
697
+ buffer[i] = ' ';
698
+ to_remove--;
699
+ if (to_remove == 0) {
700
+ break;
701
+ }
702
+ }
703
+ }
704
+ r = implementation.base64_to_binary_details(
705
+ buffer.data(), buffer.size(), back.data(), simdutf::base64_default,
706
+ option);
707
+ ASSERT_EQUAL(r.error, simdutf::error_code::BASE64_INPUT_REMAINDER);
708
+ // Next, we empty the last chunk
709
+ for (size_t i = buffer.size() - 1;; i--) {
710
+ if (simdutf::base64_valid(buffer[i], simdutf::base64_default)) {
711
+ buffer[i] = ' ';
712
+ break;
713
+ }
714
+ }
715
+ r = implementation.base64_to_binary_details(
716
+ buffer.data(), buffer.size(), back.data(), simdutf::base64_default,
717
+ option);
718
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
719
+ }
720
+ }
721
+ }
722
+ }
723
+
724
+ TEST(partial_should_decode_four_wise_chunks) {
725
+ // 37 bytes = 4 * 3 + 1
726
+ const std::string input = "X8vzLrvHmZgncicZDnXdVZkktaYFDvi41fA2A";
727
+ std::vector<char> buffer;
728
+ buffer.resize(input.size() / 4 * 3);
729
+ auto option = simdutf::last_chunk_handling_options::stop_before_partial;
730
+ auto r = implementation.base64_to_binary_details(
731
+ input.data(), input.size(), buffer.data(), simdutf::base64_default,
732
+ option);
733
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
734
+ ASSERT_TRUE(r.input_count == 36);
735
+ ASSERT_TRUE(r.output_count == 27);
736
+ }
737
+
738
+ TEST(stop_before_partial_one_char) {
739
+ std::vector<char> base64(5463, 0x20);
740
+ base64.back() = 0x38; // this is the number 8 (a valid base64 character)
741
+ std::vector<char> back(0);
742
+ // with stop_before_partial, we should stop before the last character
743
+ // and not decode it. There should be no error.
744
+ // https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64
745
+ simdutf::result r = implementation.base64_to_binary(
746
+ base64.data(), base64.size(), back.data(), simdutf::base64_default,
747
+ simdutf::last_chunk_handling_options::stop_before_partial);
748
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
749
+ ASSERT_EQUAL(r.count, 0);
750
+ size_t buflen = back.size();
751
+ ASSERT_EQUAL(buflen, 0);
752
+ r = simdutf::base64_to_binary_safe(
753
+ base64.data(), base64.size(), back.data(), buflen,
754
+ simdutf::base64_default,
755
+ simdutf::last_chunk_handling_options::stop_before_partial);
756
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
757
+ ASSERT_EQUAL(buflen, 0);
758
+ back.resize(base64.size());
759
+ buflen = back.size();
760
+ r = simdutf::base64_to_binary_safe(
761
+ base64.data(), base64.size(), back.data(), buflen,
762
+ simdutf::base64_default,
763
+ simdutf::last_chunk_handling_options::stop_before_partial);
764
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
765
+ ASSERT_EQUAL(buflen, 0);
766
+ }
767
+
768
+ TEST(hybrid_decoding) {
769
+ std::vector<std::pair<std::string, std::vector<uint8_t>>> test_data = {
770
+ {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA__--_"
771
+ "--"
772
+ "_--__"
773
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
774
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
775
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
776
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
777
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
778
+ 0xff, 0xff, 0xbe, 0xff, 0xef, 0xbf, 0xfb, 0xef, 0xff, 0x00, 0x00, 0x00,
779
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
780
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
782
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
783
+ {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA__-+_"
784
+ "--"
785
+ "_--/"
786
+ "_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
787
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
788
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
789
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
790
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
791
+ 0xff, 0xff, 0xbe, 0xff, 0xef, 0xbf, 0xfb, 0xef, 0xff, 0x00, 0x00, 0x00,
792
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
793
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
794
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
795
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
796
+ {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA__-+_"
797
+ "--"
798
+ " / "
799
+ "--/_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
800
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
801
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
802
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
803
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
804
+ 0xff, 0xff, 0xbe, 0xff, 0xef, 0xbf, 0xfb, 0xef, 0xff, 0x00, 0x00, 0x00,
805
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
806
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
807
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
808
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
809
+ {"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA//-+/"
810
+ "--/--/"
811
+ "_AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
812
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
813
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
815
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
816
+ 0xff, 0xff, 0xbe, 0xff, 0xef, 0xbf, 0xfb, 0xef, 0xff, 0x00, 0x00, 0x00,
817
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
818
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
819
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
820
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
821
+
822
+ };
823
+ for (const auto &test : test_data) {
824
+ const std::string &base64 = test.first;
825
+ const std::vector<uint8_t> &expected = test.second;
826
+ std::vector<uint8_t> decoded(simdutf::maximal_binary_length_from_base64(
827
+ base64.data(), base64.size()));
828
+ auto r = implementation.base64_to_binary(
829
+ base64.data(), base64.size(), reinterpret_cast<char *>(decoded.data()),
830
+ simdutf::base64_default_or_url);
831
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
832
+ ASSERT_EQUAL(r.count, expected.size());
833
+ decoded.resize(r.count);
834
+ ASSERT_EQUAL(decoded, expected);
835
+ }
836
+ }
837
+
838
+ TEST(roundtrip_base64_with_spaces) {
839
+ for (size_t len = 0; len < max_len; len++) {
840
+ std::vector<char> source(len, 0);
841
+ std::vector<char> buffer;
842
+ buffer.resize(simdutf::base64_length_from_binary(len));
843
+ std::mt19937 gen((std::mt19937::result_type)(seed));
844
+ std::uniform_int_distribution<int> byte_generator{0, 255};
845
+ for (size_t trial = 0; trial < 10; trial++) {
846
+ for (size_t i = 0; i < len; i++) {
847
+ source[i] = 'a' + i % ('z' - 'a'); // byte_generator(gen);
848
+ }
849
+ size_t size = implementation.binary_to_base64(
850
+ source.data(), source.size(), buffer.data());
851
+ buffer.resize(size);
852
+ for (size_t i = 0; i < 5; i++) {
853
+ add_space(buffer, gen);
854
+ }
855
+ std::vector<char> back(simdutf::maximal_binary_length_from_base64(
856
+ buffer.data(), buffer.size()));
857
+ for (auto option :
858
+ {simdutf::last_chunk_handling_options::strict,
859
+ simdutf::last_chunk_handling_options::loose,
860
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
861
+ if (option ==
862
+ simdutf::last_chunk_handling_options::stop_before_partial &&
863
+ len % 3 != 0) {
864
+ continue;
865
+ }
866
+ simdutf::result r = implementation.base64_to_binary(
867
+ buffer.data(), buffer.size(), back.data(), simdutf::base64_default,
868
+ option);
869
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
870
+ ASSERT_EQUAL(r.count, len);
871
+ ASSERT_BYTES_EQUAL(source, back, len);
872
+ }
873
+ for (auto option :
874
+ {simdutf::last_chunk_handling_options::strict,
875
+ simdutf::last_chunk_handling_options::loose,
876
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
877
+ if (option ==
878
+ simdutf::last_chunk_handling_options::stop_before_partial &&
879
+ len % 3 != 0) {
880
+ continue;
881
+ }
882
+ size_t back_length = back.size();
883
+ auto r = simdutf::base64_to_binary_safe(
884
+ buffer.data(), buffer.size(), back.data(), back_length,
885
+ simdutf::base64_default, option);
886
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
887
+ ASSERT_EQUAL(back_length, len);
888
+
889
+ for (size_t i = r.count; i < buffer.size(); i++) {
890
+ ASSERT_TRUE(is_space(buffer[i]));
891
+ }
892
+ ASSERT_TRUE(std::equal(back.begin(), back.begin() + back_length,
893
+ source.begin()));
894
+ }
895
+ }
896
+ }
897
+ }
898
+
899
+ TEST(roundtrip_base64_with_garbage) {
900
+ for (size_t len = 0; len < max_len; len++) {
901
+ std::vector<char> source(len, 0);
902
+ std::vector<char> buffer;
903
+ buffer.resize(simdutf::base64_length_from_binary(len));
904
+ std::mt19937 gen((std::mt19937::result_type)(seed));
905
+ std::uniform_int_distribution<int> byte_generator{0, 255};
906
+ for (size_t trial = 0; trial < 10; trial++) {
907
+ for (size_t i = 0; i < len; i++) {
908
+ source[i] = byte_generator(gen);
909
+ }
910
+ size_t size = implementation.binary_to_base64(
911
+ source.data(), source.size(), buffer.data());
912
+ buffer.resize(size);
913
+ for (size_t i = 0; i < 5; i++) {
914
+ add_garbage(buffer, gen, to_base64_value);
915
+ }
916
+ std::vector<char> back(simdutf::maximal_binary_length_from_base64(
917
+ buffer.data(), buffer.size()));
918
+ for (auto option : {simdutf::last_chunk_handling_options::strict,
919
+ simdutf::last_chunk_handling_options::loose}) {
920
+ simdutf::result r = implementation.base64_to_binary(
921
+ buffer.data(), buffer.size(), back.data(),
922
+ simdutf::base64_default_accept_garbage, option);
923
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
924
+ ASSERT_EQUAL(r.count, len);
925
+ ASSERT_TRUE(
926
+ std::equal(back.begin(), back.begin() + len, source.begin()));
927
+ }
928
+ for (auto option :
929
+ {simdutf::last_chunk_handling_options::strict,
930
+ simdutf::last_chunk_handling_options::loose,
931
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
932
+ if (option ==
933
+ simdutf::last_chunk_handling_options::stop_before_partial &&
934
+ len % 3 != 0) {
935
+ continue;
936
+ }
937
+ size_t back_length = back.size();
938
+ auto r = simdutf::base64_to_binary_safe(
939
+ buffer.data(), buffer.size(), back.data(), back_length,
940
+ simdutf::base64_default_accept_garbage, option);
941
+
942
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
943
+ ASSERT_EQUAL(back_length, len);
944
+ for (size_t i = r.count; i < buffer.size(); i++) {
945
+ ASSERT_TRUE(!simdutf::base64_valid(
946
+ buffer[i], simdutf::base64_default_accept_garbage));
947
+ }
948
+ ASSERT_TRUE(std::equal(back.begin(), back.begin() + back_length,
949
+ source.begin()));
950
+ }
951
+ }
952
+ }
953
+ }
954
+
955
+ TEST(roundtrip_base64_url_with_garbage) {
956
+ for (size_t len = 0; len < max_len; len++) {
957
+ std::vector<char> source(len, 0);
958
+ std::vector<char> buffer;
959
+ buffer.resize(simdutf::base64_length_from_binary(len));
960
+ std::mt19937 gen((std::mt19937::result_type)(seed));
961
+ std::uniform_int_distribution<int> byte_generator{0, 255};
962
+ for (size_t trial = 0; trial < 10; trial++) {
963
+ for (size_t i = 0; i < len; i++) {
964
+ source[i] = byte_generator(gen);
965
+ }
966
+ size_t size = implementation.binary_to_base64(
967
+ source.data(), source.size(), buffer.data(), simdutf::base64_url);
968
+ buffer.resize(size);
969
+ for (size_t i = 0; i < 5; i++) {
970
+ add_garbage(buffer, gen, to_base64url_value);
971
+ }
972
+ std::vector<char> back(simdutf::maximal_binary_length_from_base64(
973
+ buffer.data(), buffer.size()));
974
+ for (auto option :
975
+ {simdutf::last_chunk_handling_options::strict,
976
+ simdutf::last_chunk_handling_options::loose,
977
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
978
+ if (option ==
979
+ simdutf::last_chunk_handling_options::stop_before_partial &&
980
+ len % 3 != 0) {
981
+ continue;
982
+ }
983
+ simdutf::result r = implementation.base64_to_binary(
984
+ buffer.data(), buffer.size(), back.data(),
985
+ simdutf::base64_url_accept_garbage, option);
986
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
987
+ ASSERT_EQUAL(r.count, len);
988
+ ASSERT_TRUE(
989
+ std::equal(back.begin(), back.begin() + len, source.begin()));
990
+ }
991
+ for (auto option :
992
+ {simdutf::last_chunk_handling_options::strict,
993
+ simdutf::last_chunk_handling_options::loose,
994
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
995
+ if (option ==
996
+ simdutf::last_chunk_handling_options::stop_before_partial &&
997
+ len % 3 != 0) {
998
+ continue;
999
+ }
1000
+ size_t back_length = back.size();
1001
+ auto r = simdutf::base64_to_binary_safe(
1002
+ buffer.data(), buffer.size(), back.data(), back_length,
1003
+ simdutf::base64_url_accept_garbage, option);
1004
+
1005
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
1006
+ ASSERT_EQUAL(back_length, len);
1007
+
1008
+ if (option ==
1009
+ simdutf::last_chunk_handling_options::stop_before_partial) {
1010
+ for (size_t i = r.count; i < buffer.size(); i++) {
1011
+ ASSERT_TRUE(is_non_base64_url_space(buffer[i]));
1012
+ }
1013
+ } else {
1014
+ ASSERT_EQUAL(r.count, buffer.size());
1015
+ }
1016
+ ASSERT_TRUE(std::equal(back.begin(), back.begin() + back_length,
1017
+ source.begin()));
1018
+ }
1019
+ }
1020
+ }
1021
+ }
1022
+
1023
+ TEST(roundtrip_base64_with_lots_of_spaces) {
1024
+ for (size_t len = 0; len < max_len; len++) {
1025
+ std::vector<char> source(len, 0);
1026
+ std::vector<char> buffer;
1027
+ buffer.resize(simdutf::base64_length_from_binary(len));
1028
+ std::mt19937 gen((std::mt19937::result_type)(seed));
1029
+ std::uniform_int_distribution<int> byte_generator{0, 255};
1030
+ for (size_t trial = 0; trial < 10; trial++) {
1031
+ for (size_t i = 0; i < len; i++) {
1032
+ source[i] = byte_generator(gen);
1033
+ }
1034
+ size_t size = implementation.binary_to_base64(
1035
+ source.data(), source.size(), buffer.data());
1036
+ buffer.resize(size);
1037
+ add_simple_spaces(buffer, gen, 5 + 2 * len);
1038
+ std::vector<char> back(simdutf::maximal_binary_length_from_base64(
1039
+ buffer.data(), buffer.size()));
1040
+ for (auto option :
1041
+ {simdutf::last_chunk_handling_options::strict,
1042
+ simdutf::last_chunk_handling_options::loose,
1043
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1044
+ if (option ==
1045
+ simdutf::last_chunk_handling_options::stop_before_partial &&
1046
+ len % 3 != 0) {
1047
+ continue;
1048
+ }
1049
+ simdutf::result r = implementation.base64_to_binary(
1050
+ buffer.data(), buffer.size(), back.data(), simdutf::base64_default,
1051
+ option);
1052
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
1053
+ ASSERT_EQUAL(r.count, len);
1054
+ ASSERT_TRUE(
1055
+ std::equal(back.begin(), back.begin() + len, source.begin()));
1056
+ }
1057
+ for (auto option :
1058
+ {simdutf::last_chunk_handling_options::strict,
1059
+ simdutf::last_chunk_handling_options::loose,
1060
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1061
+ if (option ==
1062
+ simdutf::last_chunk_handling_options::stop_before_partial &&
1063
+ len % 3 != 0) {
1064
+ continue;
1065
+ }
1066
+ size_t back_length = back.size();
1067
+ auto r = simdutf::base64_to_binary_safe(
1068
+ buffer.data(), buffer.size(), back.data(), back_length,
1069
+ simdutf::base64_default, option);
1070
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
1071
+ ASSERT_EQUAL(back_length, len);
1072
+
1073
+ if (option ==
1074
+ simdutf::last_chunk_handling_options::stop_before_partial) {
1075
+ for (size_t i = r.count; i < buffer.size(); i++) {
1076
+ ASSERT_TRUE(is_space(buffer[i]));
1077
+ }
1078
+ if (r.count > 0) {
1079
+ ASSERT_TRUE(!is_space(buffer[r.count - 1]));
1080
+ }
1081
+ } else {
1082
+ ASSERT_EQUAL(r.count, buffer.size());
1083
+ }
1084
+ ASSERT_TRUE(std::equal(back.begin(), back.begin() + back_length,
1085
+ source.begin()));
1086
+ }
1087
+ }
1088
+ }
1089
+ }
1090
+
1091
+ TEST(roundtrip_base64_with_lots_of_spaces_at_the_end) {
1092
+ std::vector<char> buffer;
1093
+ for (size_t len = 0; len < max_len; len += 10) {
1094
+ std::vector<char> source(len, 0);
1095
+ buffer.clear();
1096
+ buffer.resize(simdutf::base64_length_from_binary(len), '\0');
1097
+ std::mt19937 gen((std::mt19937::result_type)(seed));
1098
+ std::uniform_int_distribution<int> byte_generator{0, 255};
1099
+ for (size_t trial = 0; trial < 10; trial++) {
1100
+ for (size_t i = 0; i < len; i++) {
1101
+ source[i] = byte_generator(gen);
1102
+ }
1103
+ size_t size = implementation.binary_to_base64(
1104
+ source.data(), source.size(), buffer.data());
1105
+ buffer.resize(size);
1106
+ add_simple_spaces(buffer, gen, 5 + 2 * len);
1107
+ std::vector<char> back(simdutf::maximal_binary_length_from_base64(
1108
+ buffer.data(), buffer.size()));
1109
+ buffer.resize(buffer.size() + 65536, ' ');
1110
+ for (auto option :
1111
+ {simdutf::last_chunk_handling_options::strict,
1112
+ simdutf::last_chunk_handling_options::loose,
1113
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1114
+ if (option ==
1115
+ simdutf::last_chunk_handling_options::stop_before_partial &&
1116
+ len % 3 != 0) {
1117
+ continue;
1118
+ }
1119
+ size_t back_length = back.size();
1120
+ auto r = simdutf::base64_to_binary_safe(
1121
+ buffer.data(), buffer.size(), back.data(), back_length,
1122
+ simdutf::base64_default, option);
1123
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
1124
+ ASSERT_EQUAL(back_length, len);
1125
+ for (size_t i = r.count; i < buffer.size(); i++) {
1126
+ ASSERT_TRUE(is_space(buffer[i]));
1127
+ }
1128
+ ASSERT_TRUE(std::equal(back.begin(), back.begin() + back_length,
1129
+ source.begin()));
1130
+ }
1131
+ }
1132
+ }
1133
+ }
1134
+
1135
+ TEST(roundtrip_base64_with_lots_of_spaces_at_the_beginning) {
1136
+ std::vector<char> buffer;
1137
+ for (size_t len = 0; len < max_len; len += 10) {
1138
+ std::vector<char> source(len, 0);
1139
+ buffer.clear();
1140
+ buffer.resize(simdutf::base64_length_from_binary(len), '\0');
1141
+ std::mt19937 gen((std::mt19937::result_type)(seed));
1142
+ std::uniform_int_distribution<int> byte_generator{0, 255};
1143
+ for (size_t trial = 0; trial < 10; trial++) {
1144
+ for (size_t i = 0; i < len; i++) {
1145
+ source[i] = byte_generator(gen);
1146
+ }
1147
+ size_t size = implementation.binary_to_base64(
1148
+ source.data(), source.size(), buffer.data());
1149
+ buffer.resize(size);
1150
+ add_simple_spaces(buffer, gen, 5 + 2 * len);
1151
+ std::vector<char> back(simdutf::maximal_binary_length_from_base64(
1152
+ buffer.data(), buffer.size()));
1153
+ buffer.insert(buffer.begin(), 65536, ' ');
1154
+ for (auto option :
1155
+ {simdutf::last_chunk_handling_options::strict,
1156
+ simdutf::last_chunk_handling_options::loose,
1157
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1158
+ if (option ==
1159
+ simdutf::last_chunk_handling_options::stop_before_partial &&
1160
+ len % 3 != 0) {
1161
+ continue;
1162
+ }
1163
+ size_t back_length = back.size();
1164
+ auto r = simdutf::base64_to_binary_safe(
1165
+ buffer.data(), buffer.size(), back.data(), back_length,
1166
+ simdutf::base64_default, option);
1167
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
1168
+ ASSERT_EQUAL(back_length, len);
1169
+ for (size_t i = r.count; i < buffer.size(); i++) {
1170
+ ASSERT_TRUE(is_space(buffer[i]));
1171
+ }
1172
+
1173
+ ASSERT_TRUE(std::equal(back.begin(), back.begin() + back_length,
1174
+ source.begin()));
1175
+ }
1176
+ }
1177
+ }
1178
+ }
1179
+
1180
+ TEST(base64_decode_just_one_padding_partial_safe) {
1181
+ std::vector<std::tuple<std::string, simdutf::result, size_t>> test_cases = {
1182
+ {"uuuu uu=", {simdutf::error_code::SUCCESS, 4}, 3},
1183
+ // 5. If char is "=", then If chunkLength < 2, then Let error be a new
1184
+ // SyntaxError exception.
1185
+ {"uuuu u==",
1186
+ {simdutf::error_code::BASE64_INPUT_REMAINDER, 18},
1187
+ 3}, // error
1188
+ {"uuuu u=",
1189
+ {simdutf::error_code::BASE64_INPUT_REMAINDER, 18},
1190
+ 3}, // error
1191
+ {"uuuu ==",
1192
+ {simdutf::error_code::INVALID_BASE64_CHARACTER, 17},
1193
+ 3}, // error
1194
+ {"uuuu =",
1195
+ {simdutf::error_code::INVALID_BASE64_CHARACTER, 17},
1196
+ 3}, // error
1197
+ };
1198
+ std::vector<char> buffer(128);
1199
+ printf("\n");
1200
+ for (auto &p : test_cases) {
1201
+ auto input = std::get<0>(p);
1202
+ auto expected_result = std::get<1>(p);
1203
+ size_t expected_output = std::get<2>(p);
1204
+ printf("input: %s\n", input.c_str());
1205
+ for (auto option : {simdutf::base64_options::base64_default,
1206
+ simdutf::base64_options::base64_url}) {
1207
+ for (auto chunk_option :
1208
+ {simdutf::last_chunk_handling_options::stop_before_partial}) {
1209
+ for (size_t output = 3; output < buffer.size(); output++) {
1210
+ size_t written = output;
1211
+ auto result = simdutf::base64_to_binary_safe(
1212
+ input.data(), input.size(), buffer.data(), written, option,
1213
+ chunk_option);
1214
+ ASSERT_EQUAL(result.error, expected_result.error);
1215
+ ASSERT_EQUAL(written, expected_output);
1216
+ ASSERT_EQUAL(result.count, expected_result.count);
1217
+ }
1218
+ }
1219
+ }
1220
+ }
1221
+ }
1222
+
1223
+ // partial decoding will succeed and just decode the first 3 bytes, even if we
1224
+ // have ample output memory.
1225
+ TEST(base64_decode_just_one_padding_partial_generous) {
1226
+ std::vector<std::pair<std::string, simdutf::result>> test_cases = {
1227
+ {"uuuu uu=", {simdutf::error_code::SUCCESS, 3}},
1228
+ // 5. If char is "=", then If chunkLength < 2, then Let error be a new
1229
+ // SyntaxError exception.
1230
+ {"uuuu u==",
1231
+ {simdutf::error_code::BASE64_INPUT_REMAINDER, 18}}, // error
1232
+ {"uuuu u=",
1233
+ {simdutf::error_code::BASE64_INPUT_REMAINDER, 18}}, // error
1234
+ {"uuuu ==",
1235
+ {simdutf::error_code::INVALID_BASE64_CHARACTER, 17}}, // error
1236
+ {"uuuu =",
1237
+ {simdutf::error_code::INVALID_BASE64_CHARACTER, 17}}, // error
1238
+ };
1239
+ std::vector<char> buffer(6);
1240
+ for (auto &p : test_cases) {
1241
+ auto input = p.first;
1242
+ auto expected_result = p.second;
1243
+ for (auto option : {simdutf::base64_options::base64_default,
1244
+ simdutf::base64_options::base64_url}) {
1245
+ for (auto chunk_option :
1246
+ {simdutf::last_chunk_handling_options::stop_before_partial}) {
1247
+ auto result = implementation.base64_to_binary(
1248
+ input.data(), input.size(), buffer.data(), option, chunk_option);
1249
+ ASSERT_EQUAL(result.error, expected_result.error);
1250
+ ASSERT_EQUAL(result.count, expected_result.count);
1251
+ }
1252
+ }
1253
+ }
1254
+ }
1255
+
1256
+ // loose decoding will fail when there is a single leftover padding character.
1257
+ TEST(base64_decode_just_one_padding_loose) {
1258
+ std::vector<std::pair<std::string, simdutf::result>> test_cases = {
1259
+ {"uuuu =",
1260
+ {simdutf::error_code::INVALID_BASE64_CHARACTER, 17}}};
1261
+ std::vector<char> buffer(3);
1262
+ for (auto &p : test_cases) {
1263
+ auto input = p.first;
1264
+ auto expected_result = p.second;
1265
+ for (auto option : {simdutf::base64_options::base64_default,
1266
+ simdutf::base64_options::base64_url}) {
1267
+ for (auto chunk_option : {simdutf::last_chunk_handling_options::loose}) {
1268
+ auto result = implementation.base64_to_binary(
1269
+ input.data(), input.size(), buffer.data(), option, chunk_option);
1270
+ ASSERT_EQUAL(result.error, expected_result.error);
1271
+ ASSERT_EQUAL(result.count, expected_result.count);
1272
+ }
1273
+ }
1274
+ }
1275
+ }
1276
+
1277
+ // strict decoding will fail with a pointer to the last valid character.
1278
+ TEST(base64_decode_just_one_padding_strict) {
1279
+ std::vector<std::pair<std::string, simdutf::result>> test_cases = {
1280
+ {"uuuu =",
1281
+ {simdutf::error_code::INVALID_BASE64_CHARACTER, 17}}};
1282
+ std::vector<char> buffer(3);
1283
+ for (auto &p : test_cases) {
1284
+ auto input = p.first;
1285
+ auto expected_result = p.second;
1286
+ for (auto option : {simdutf::base64_options::base64_default,
1287
+ simdutf::base64_options::base64_url}) {
1288
+ for (auto chunk_option : {simdutf::last_chunk_handling_options::strict}) {
1289
+ auto result = implementation.base64_to_binary(
1290
+ input.data(), input.size(), buffer.data(), option, chunk_option);
1291
+ ASSERT_EQUAL(result.error, expected_result.error);
1292
+ ASSERT_EQUAL(result.count, expected_result.count);
1293
+ }
1294
+ }
1295
+ }
1296
+ }
1297
+
1298
+ // partial decoding will succeed and just decode the first 3 bytes.
1299
+ // https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64
1300
+ TEST(base64_decode_just_one_padding_partial) {
1301
+ std::vector<std::pair<std::string, simdutf::result>> test_cases = {
1302
+ {"uuuu uu=", {simdutf::error_code::SUCCESS, 3}},
1303
+ // 5. If char is "=", then If chunkLength < 2, then Let error be a new
1304
+ // SyntaxError exception.
1305
+ {"uuuu u==",
1306
+ {simdutf::error_code::BASE64_INPUT_REMAINDER, 18}}, // error
1307
+ {"uuuu u=",
1308
+ {simdutf::error_code::BASE64_INPUT_REMAINDER, 18}}, // error
1309
+ {"uuuu ==",
1310
+ {simdutf::error_code::INVALID_BASE64_CHARACTER, 17}}, // error
1311
+ {"uuuu =",
1312
+ {simdutf::error_code::INVALID_BASE64_CHARACTER, 17}}, // error
1313
+ };
1314
+ std::vector<char> buffer(3);
1315
+ for (auto &p : test_cases) {
1316
+ auto input = p.first;
1317
+ auto expected_result = p.second;
1318
+ for (auto option : {simdutf::base64_options::base64_default,
1319
+ simdutf::base64_options::base64_url}) {
1320
+ for (auto chunk_option :
1321
+ {simdutf::last_chunk_handling_options::stop_before_partial}) {
1322
+ auto result = implementation.base64_to_binary(
1323
+ input.data(), input.size(), buffer.data(), option, chunk_option);
1324
+
1325
+ ASSERT_EQUAL(result.error, expected_result.error);
1326
+ ASSERT_EQUAL(result.count, expected_result.count);
1327
+ }
1328
+ }
1329
+ }
1330
+ }
1331
+
1332
+ TEST(base64_decode_partial_cases) {
1333
+ std::vector<std::pair<std::string, simdutf::result>> test_cases = {
1334
+ {"ZXhhZg", {simdutf::error_code::SUCCESS, 4}},
1335
+ {"ZXhhZg "
1336
+ " ",
1337
+ {simdutf::error_code::SUCCESS, 4}},
1338
+ {" "
1339
+ "ZXhhZg",
1340
+ {simdutf::error_code::SUCCESS, 68}},
1341
+ };
1342
+ std::vector<char> buffer(3);
1343
+ for (auto &p : test_cases) {
1344
+ auto input = p.first;
1345
+ auto expected_result = p.second;
1346
+ size_t written = buffer.size();
1347
+ auto result = simdutf::base64_to_binary_safe(
1348
+ input.data(), input.size(), buffer.data(), written,
1349
+ simdutf::base64_default,
1350
+ simdutf::last_chunk_handling_options::stop_before_partial);
1351
+ ASSERT_EQUAL(result.error, expected_result.error);
1352
+ ASSERT_EQUAL(result.count, expected_result.count);
1353
+ }
1354
+ }
1355
+
1356
+ TEST(base64_decode_strict_cases) {
1357
+ std::vector<std::pair<std::string, uint64_t>> test_cases = {
1358
+ {"ZXhhZg==", simdutf::error_code::SUCCESS},
1359
+ {"YWE=", simdutf::error_code::SUCCESS},
1360
+ {"YWF=", simdutf::error_code::BASE64_EXTRA_BITS},
1361
+ {"ZXhhZh==", simdutf::error_code::BASE64_EXTRA_BITS},
1362
+ // {"ZXhhZg", simdutf::error_code::BASE64_INPUT_REMAINDER},
1363
+ // {"ZXhhZh", simdutf::error_code::BASE64_INPUT_REMAINDER},
1364
+ {"Z X h h Z h = =", simdutf::error_code::BASE64_EXTRA_BITS},
1365
+ //{"ZX h hZg", simdutf::error_code::BASE64_INPUT_REMAINDER},
1366
+ //{"ZXh hZ h", simdutf::error_code::BASE64_INPUT_REMAINDER},
1367
+ };
1368
+ std::vector<char> buffer(1024);
1369
+ for (auto &p : test_cases) {
1370
+ auto input = p.first;
1371
+ auto expected_error = p.second;
1372
+ simdutf::result result = implementation.base64_to_binary(
1373
+ input.data(), input.size(), buffer.data(), simdutf::base64_default,
1374
+ simdutf::last_chunk_handling_options::strict);
1375
+ ASSERT_EQUAL(result.error, expected_error);
1376
+ size_t written = buffer.size();
1377
+ result = simdutf::base64_to_binary_safe(
1378
+ input.data(), input.size(), buffer.data(), written,
1379
+ simdutf::base64_default, simdutf::last_chunk_handling_options::strict);
1380
+ ASSERT_EQUAL(result.error, expected_error);
1381
+ }
1382
+ }
1383
+
1384
+ TEST(base64_decode_strict_cases_length) {
1385
+ std::vector<std::pair<std::string, simdutf::result>> test_cases = {
1386
+ {"ddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd"
1387
+ "dd"
1388
+ "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddzzz=",
1389
+ {simdutf::error_code::BASE64_EXTRA_BITS, 131}},
1390
+ };
1391
+ std::vector<char> buffer(1024);
1392
+ for (auto &p : test_cases) {
1393
+ auto input = p.first;
1394
+ auto expected_result = p.second;
1395
+ simdutf::result result = implementation.base64_to_binary(
1396
+ input.data(), input.size(), buffer.data(), simdutf::base64_default,
1397
+ simdutf::last_chunk_handling_options::strict);
1398
+ ASSERT_EQUAL(result.error, expected_result.error);
1399
+ ASSERT_EQUAL(result.count, expected_result.count);
1400
+ size_t written = buffer.size();
1401
+ result = simdutf::base64_to_binary_safe(
1402
+ input.data(), input.size(), buffer.data(), written,
1403
+ simdutf::base64_default, simdutf::last_chunk_handling_options::strict);
1404
+ ASSERT_EQUAL(result.error, expected_result.error);
1405
+ ASSERT_EQUAL(result.count, expected_result.count);
1406
+ }
1407
+ }
1408
+
1409
+ // https://bugs.webkit.org/show_bug.cgi?id=290829
1410
+ TEST(issue_webkit_290829) {
1411
+ std::string data = "MjYyZg===";
1412
+ std::vector<char> output(5); // 5 is part of the issue
1413
+ std::vector<uint8_t> expected = {0x32, 0x36, 0x32};
1414
+
1415
+ for (auto option :
1416
+ {simdutf::last_chunk_handling_options::strict,
1417
+ simdutf::last_chunk_handling_options::loose,
1418
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1419
+ std::fill(output.begin(), output.end(), 0);
1420
+ const auto r1 =
1421
+ implementation.base64_to_binary(data.data(), data.size(), output.data(),
1422
+ simdutf::base64_default, option);
1423
+ ASSERT_EQUAL(r1.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
1424
+ ASSERT_EQUAL(r1.count, 6);
1425
+ }
1426
+
1427
+ for (auto option :
1428
+ {simdutf::last_chunk_handling_options::strict,
1429
+ simdutf::last_chunk_handling_options::loose,
1430
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1431
+ std::fill(output.begin(), output.end(), 0);
1432
+ size_t back_length = output.size();
1433
+ constexpr bool decode_up_to_bad_char = true;
1434
+ auto r = simdutf::base64_to_binary_safe(
1435
+ data.data(), data.size(), output.data(), back_length,
1436
+ simdutf::base64_default, option, decode_up_to_bad_char);
1437
+
1438
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
1439
+ ASSERT_EQUAL(r.count, 6);
1440
+ ASSERT_EQUAL(back_length, 3);
1441
+ ASSERT_BYTES_EQUAL(output, expected, 3);
1442
+ }
1443
+ }
1444
+
1445
+ // https://bugs.webkit.org/show_bug.cgi?id=290829
1446
+ TEST(issue_webkit_utf16_290829) {
1447
+ std::string data = "MjYyZg===";
1448
+ std::vector<char> output(5); // 5 is part of the issue
1449
+ std::vector<uint16_t> expected = {0x32, 0x36, 0x32};
1450
+
1451
+ for (auto option :
1452
+ {simdutf::last_chunk_handling_options::strict,
1453
+ simdutf::last_chunk_handling_options::loose,
1454
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1455
+ std::fill(output.begin(), output.end(), 0);
1456
+ const auto r1 =
1457
+ implementation.base64_to_binary(data.data(), data.size(), output.data(),
1458
+ simdutf::base64_default, option);
1459
+ ASSERT_EQUAL(r1.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
1460
+ ASSERT_EQUAL(r1.count, 6);
1461
+ }
1462
+
1463
+ for (auto option :
1464
+ {simdutf::last_chunk_handling_options::strict,
1465
+ simdutf::last_chunk_handling_options::loose,
1466
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1467
+ std::fill(output.begin(), output.end(), 0);
1468
+ size_t back_length = output.size();
1469
+ constexpr bool decode_up_to_bad_char = true;
1470
+ auto r = simdutf::base64_to_binary_safe(
1471
+ data.data(), data.size(), output.data(), back_length,
1472
+ simdutf::base64_default, option, decode_up_to_bad_char);
1473
+
1474
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
1475
+ ASSERT_EQUAL(r.count, 6);
1476
+ ASSERT_EQUAL(back_length, 3);
1477
+ ASSERT_BYTES_EQUAL(output, expected, 3);
1478
+ }
1479
+ }
1480
+
1481
+ // https://bugs.webkit.org/show_bug.cgi?id=290829
1482
+ TEST(issue_webkit_utf16_290829_bad_char) {
1483
+ std::string data(1024, 'A');
1484
+ std::vector<char> expected(1024 / 4 * 3, 0);
1485
+ std::vector<char> output(1024 / 4 * 3);
1486
+ for (size_t invalid = 0; invalid < data.size(); invalid++) {
1487
+ data[invalid] = '?'; // invalid
1488
+ for (auto option :
1489
+ {simdutf::last_chunk_handling_options::strict,
1490
+ simdutf::last_chunk_handling_options::loose,
1491
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1492
+ std::fill(output.begin(), output.end(), 255);
1493
+ size_t back_length = output.size();
1494
+ constexpr bool decode_up_to_bad_char = true;
1495
+ auto r = simdutf::base64_to_binary_safe(
1496
+ data.data(), data.size(), output.data(), back_length,
1497
+ simdutf::base64_default, option, decode_up_to_bad_char);
1498
+
1499
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
1500
+ ASSERT_EQUAL(r.count, invalid);
1501
+ size_t expected_length = invalid / 4 * 3;
1502
+ ASSERT_EQUAL(back_length, expected_length);
1503
+ ASSERT_BYTES_EQUAL(output, expected, expected_length);
1504
+ }
1505
+ data[invalid] = 'A'; // valid
1506
+ }
1507
+ }
1508
+
1509
+ TEST(issue_webkit_utf16_290829_example) {
1510
+ std::string data(1024, 'A');
1511
+ std::vector<char> expected(1024 / 4 * 3, 0);
1512
+ std::vector<char> output(1024 / 4 * 3);
1513
+ for (size_t invalid = 0; invalid < data.size(); invalid++) {
1514
+ data[invalid] = '?'; // invalid
1515
+ for (auto option :
1516
+ {simdutf::last_chunk_handling_options::strict,
1517
+ simdutf::last_chunk_handling_options::loose,
1518
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1519
+ std::fill(output.begin(), output.end(), 255);
1520
+ size_t back_length = output.size();
1521
+ constexpr bool decode_up_to_bad_char = true;
1522
+ auto r = simdutf::base64_to_binary_safe(
1523
+ data.data(), data.size(), output.data(), back_length,
1524
+ simdutf::base64_default, option, decode_up_to_bad_char);
1525
+
1526
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
1527
+ ASSERT_EQUAL(r.count, invalid);
1528
+ size_t expected_length = invalid / 4 * 3;
1529
+ ASSERT_EQUAL(back_length, expected_length);
1530
+ ASSERT_BYTES_EQUAL(output, expected, expected_length);
1531
+ }
1532
+ data[invalid] = 'A'; // valid
1533
+ }
1534
+ }
1535
+
1536
+ TEST(issue_single_bad16) {
1537
+ std::vector<char16_t> data = {0x3f};
1538
+ ASSERT_EQUAL(data.size(), 1);
1539
+ size_t outlen = implementation.maximal_binary_length_from_base64(data.data(),
1540
+ data.size());
1541
+ std::vector<char> out(outlen);
1542
+ const auto r = implementation.base64_to_binary(
1543
+ (const char *)data.data(), data.size(), out.data(),
1544
+ simdutf::base64_url_with_padding,
1545
+ simdutf::last_chunk_handling_options::strict);
1546
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
1547
+ ASSERT_EQUAL(r.count, 0);
1548
+ }
1549
+
1550
+ TEST(issue_615) {
1551
+ const std::vector<char> data{' ', '=', '='};
1552
+ std::vector<char> output(100);
1553
+ const auto r1 =
1554
+ implementation.base64_to_binary(data.data(), data.size(), output.data(),
1555
+ simdutf::base64_default, simdutf::strict);
1556
+ ASSERT_EQUAL(r1.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
1557
+ ASSERT_EQUAL(r1.count, 1);
1558
+ const auto r2 = implementation.base64_to_binary(
1559
+ data.data() + 1, data.size() - 1, output.data(), simdutf::base64_default,
1560
+ simdutf::strict);
1561
+ ASSERT_EQUAL(r2.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
1562
+ ASSERT_EQUAL(r2.count, 0);
1563
+ const auto r3 = implementation.base64_to_binary(
1564
+ data.data(), data.size(), output.data(), simdutf::base64_default,
1565
+ simdutf::stop_before_partial);
1566
+ ASSERT_EQUAL(r3.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
1567
+ ASSERT_EQUAL(r3.count, 1);
1568
+ const auto r4 = implementation.base64_to_binary(
1569
+ data.data() + 1, data.size() - 1, output.data(), simdutf::base64_default,
1570
+ simdutf::stop_before_partial);
1571
+ ASSERT_EQUAL(r4.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
1572
+ ASSERT_EQUAL(r4.count, 0);
1573
+ }
1574
+
1575
+ TEST(issue_kkk) {
1576
+ std::vector<char> data = {
1577
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1578
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1579
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1580
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1581
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1582
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1583
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1584
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x20, 0x20, 0x20, 0x20, 0x20,
1585
+ 0x20, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1586
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1587
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1588
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1589
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1590
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1591
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b,
1592
+ 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x4b, 0x20, 0x20, 0x20,
1593
+ 0x63};
1594
+ ASSERT_EQUAL(data.size(), 193);
1595
+ size_t outlen = implementation.maximal_binary_length_from_base64(data.data(),
1596
+ data.size());
1597
+ std::vector<char> out(outlen);
1598
+ const auto r = implementation.base64_to_binary(
1599
+ (const char *)data.data(), data.size(), out.data(),
1600
+ simdutf::base64_url_with_padding,
1601
+ simdutf::last_chunk_handling_options::strict);
1602
+ ASSERT_EQUAL(r.error, simdutf::error_code::BASE64_INPUT_REMAINDER);
1603
+ ASSERT_EQUAL(r.count, 193);
1604
+ }
1605
+
1606
+ TEST(issue_520) {
1607
+ std::vector<unsigned char> data{
1608
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 12, 32,
1609
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1610
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
1611
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 82,
1612
+ };
1613
+ std::vector<char> out(48);
1614
+
1615
+ const auto r =
1616
+ implementation.base64_to_binary((const char *)data.data(), data.size(),
1617
+ out.data(), simdutf::base64_default);
1618
+ ASSERT_EQUAL(r.error, simdutf::error_code::BASE64_INPUT_REMAINDER);
1619
+ ASSERT_EQUAL(r.count, 64);
1620
+ }
1621
+
1622
+ TEST(base64_decode_complete_input) {
1623
+ std::vector<unsigned char> input_data = {0x54, 0x57, 0x46,
1624
+ 0x75}; // "TWFu" Base64 for "Man"
1625
+ std::vector<char> expected_output = {'M', 'a', 'n'};
1626
+ std::vector<char> output_buffer(expected_output.size());
1627
+
1628
+ // Test with all last_chunk_handling_options
1629
+ for (auto option :
1630
+ {simdutf::last_chunk_handling_options::strict,
1631
+ simdutf::last_chunk_handling_options::loose,
1632
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1633
+ auto result = implementation.base64_to_binary(
1634
+ reinterpret_cast<const char *>(input_data.data()), input_data.size(),
1635
+ output_buffer.data(), simdutf::base64_default, option);
1636
+
1637
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
1638
+ ASSERT_EQUAL(result.count, expected_output.size());
1639
+ ASSERT_TRUE(
1640
+ (std::equal(output_buffer.begin(), output_buffer.begin() + result.count,
1641
+ expected_output.begin())));
1642
+ }
1643
+ }
1644
+
1645
+ // https://github.com/simdutf/simdutf/issues/824
1646
+ /*
1647
+ The TC39 base64 proposal step 10.a and 10.b together means that, when using
1648
+ stop-before-partial:
1649
+
1650
+ If in the middle of decoding a chunk, return the ending position of the previous
1651
+ chunk before skipping whitespace. If not in the middle of decoding a chunk,
1652
+ return the entire input length, including trailing whitespace.
1653
+ */
1654
+ TEST(issue_824) {
1655
+ struct read_write {
1656
+ size_t read;
1657
+ size_t written;
1658
+ };
1659
+ std::vector<std::tuple<std::string, read_write, std::vector<uint8_t>>>
1660
+ test_cases = {
1661
+ {" ", {2, 0}, {}}, // return the entire input length, including
1662
+ // trailing whitespace.
1663
+ {" A A G A / v 8 ",
1664
+ {8, 3},
1665
+ {0, 1, 128}} // return the ending position of the previous chunk
1666
+ // before skipping whitespace.
1667
+ };
1668
+
1669
+ std::vector<unsigned char> case1(5463, 0x20);
1670
+ case1.back() = 0x38;
1671
+ test_cases.emplace_back(std::string(case1.begin(), case1.end()),
1672
+ read_write{0, 0}, std::vector<uint8_t>{});
1673
+
1674
+ std::string long_input(1000, ' ');
1675
+ test_cases.emplace_back(long_input, read_write{1000, 0},
1676
+ std::vector<uint8_t>{});
1677
+ test_cases.emplace_back(long_input + " A A G A / v 8 ",
1678
+ read_write{1000 + 8, 3},
1679
+ std::vector<uint8_t>{0, 1, 128});
1680
+ // In https://tc39.es/proposal-arraybuffer-base64/spec/#sec-frombase64
1681
+ // the 'read' variable is only ever incremented when a full chunk is
1682
+ // successfully decoded. And we always return the 'read' variable,
1683
+ // except when we reach the end of the input with a chunkLength of zero.
1684
+ test_cases.emplace_back(long_input + "A", read_write{0, 0},
1685
+ std::vector<uint8_t>{});
1686
+ test_cases.emplace_back("AAAA" + long_input + "A", read_write{4, 3},
1687
+ std::vector<uint8_t>{0, 0, 0});
1688
+
1689
+ for (const std::tuple<std::string, read_write, std::vector<uint8_t>> &t :
1690
+ test_cases) {
1691
+ auto input_data = std::get<0>(t);
1692
+ auto read_write_info = std::get<1>(t);
1693
+ auto expected_output = std::get<2>(t);
1694
+ std::vector<uint8_t> output_buffer(
1695
+ implementation.maximal_binary_length_from_base64(input_data.data(),
1696
+ input_data.size()));
1697
+ size_t written = output_buffer.size();
1698
+ auto result = simdutf::base64_to_binary_safe(
1699
+ input_data.data(), input_data.size(),
1700
+ reinterpret_cast<char *>(output_buffer.data()), written,
1701
+ simdutf::base64_default,
1702
+ simdutf::last_chunk_handling_options::stop_before_partial, true);
1703
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
1704
+ ASSERT_EQUAL(result.count, read_write_info.read);
1705
+ ASSERT_EQUAL(written, expected_output.size());
1706
+ output_buffer.resize(written);
1707
+ ASSERT_TRUE(output_buffer == expected_output);
1708
+ }
1709
+ for (const std::tuple<std::string, read_write, std::vector<uint8_t>> &t :
1710
+ test_cases) {
1711
+ auto input_data = std::get<0>(t);
1712
+ auto read_write_info = std::get<1>(t);
1713
+ auto expected_output = std::get<2>(t);
1714
+ std::vector<uint8_t> output_buffer(expected_output.size());
1715
+ size_t written = output_buffer.size();
1716
+ auto result = simdutf::base64_to_binary_safe(
1717
+ input_data.data(), input_data.size(),
1718
+ reinterpret_cast<char *>(output_buffer.data()), written,
1719
+ simdutf::base64_default,
1720
+ simdutf::last_chunk_handling_options::stop_before_partial, true);
1721
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
1722
+ ASSERT_EQUAL(result.count, read_write_info.read);
1723
+ ASSERT_EQUAL(written, expected_output.size());
1724
+ output_buffer.resize(written);
1725
+ ASSERT_TRUE(output_buffer == expected_output);
1726
+ }
1727
+ }
1728
+
1729
+ TEST(issue_824_a) {
1730
+ std::vector<unsigned char> base64(5463, 0x20);
1731
+ base64.back() = 0x38;
1732
+ std::vector<char> outbuf(8224);
1733
+ std::size_t outlen = outbuf.size();
1734
+ const auto result = simdutf::base64_to_binary_safe(
1735
+ (const char *)base64.data(), base64.size(), outbuf.data(), outlen,
1736
+ simdutf::base64_default,
1737
+ simdutf::last_chunk_handling_options::stop_before_partial, false);
1738
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
1739
+ ASSERT_EQUAL(result.count, 0);
1740
+ ASSERT_EQUAL(outlen, 0);
1741
+ }
1742
+
1743
+ TEST(issue_06_05_2025_001) {
1744
+ const std::vector<unsigned char> base64{
1745
+ 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
1746
+ 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
1747
+ 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
1748
+ 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
1749
+ 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
1750
+ 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
1751
+ 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
1752
+ 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
1753
+ 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x0a, 0x0a,
1754
+ 0x0a, 0x6f, 0x6e, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f,
1755
+ 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71, 0x71,
1756
+ 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x0a,
1757
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x67, 0x0a,
1758
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x4b, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
1759
+ 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a, 0x0a,
1760
+ };
1761
+ std::vector<char> outbuf(28426);
1762
+ std::size_t outlen = outbuf.size();
1763
+ const auto result = simdutf::base64_to_binary_safe(
1764
+ (const char *)base64.data(), base64.size(), outbuf.data(), outlen,
1765
+ simdutf::base64_default,
1766
+ simdutf::last_chunk_handling_options::stop_before_partial, true);
1767
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
1768
+ ASSERT_EQUAL(result.count, base64.size());
1769
+ ASSERT_EQUAL(outlen, 111);
1770
+ };
1771
+
1772
+ // https://github.com/WebKit/WebKit/blob/18fad22e2078542316a576989676d31cfd08d777/JSTests/stress/uint8array-fromBase64.js#L135
1773
+ TEST(base64_decode_webkit_cases) {
1774
+
1775
+ struct read_write {
1776
+ size_t read;
1777
+ size_t written;
1778
+ };
1779
+ std::vector<std::tuple<std::string, read_write, std::vector<uint8_t>>>
1780
+ test_cases = {
1781
+ {"", {0, 0}, {}},
1782
+ {"AA==", {4, 1}, {0}},
1783
+ {"AQ==", {4, 1}, {1}},
1784
+ {"gA==", {4, 1}, {128}},
1785
+ {"/g==", {4, 1}, {254}},
1786
+ {"/w==", {4, 1}, {255}},
1787
+ {"AAE=", {4, 2}, {0, 1}},
1788
+ {"/v8=", {4, 2}, {254, 255}},
1789
+ {"AAGA/v8=", {8, 5}, {0, 1, 128, 254, 255}},
1790
+ {" ", {2, 0}, {}},
1791
+ {" A A = = ", {14, 1}, {0}},
1792
+ {" A Q = = ", {14, 1}, {1}},
1793
+ {" g A = = ", {14, 1}, {128}},
1794
+ {" / g = = ", {14, 1}, {254}},
1795
+ {" / w = = ", {14, 1}, {255}},
1796
+ {" A A E = ", {14, 2}, {0, 1}},
1797
+ {" / v 8 = ", {14, 2}, {254, 255}},
1798
+ {" A A G A / v 8 = ", {26, 5}, {0, 1, 128, 254, 255}}};
1799
+
1800
+ // Test with all last_chunk_handling_options
1801
+ for (auto option :
1802
+ {simdutf::last_chunk_handling_options::strict,
1803
+ simdutf::last_chunk_handling_options::loose,
1804
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1805
+ for (const std::tuple<std::string, read_write, std::vector<uint8_t>> &t :
1806
+ test_cases) {
1807
+ auto input_data = std::get<0>(t);
1808
+ auto expected_output = std::get<2>(t);
1809
+ std::vector<uint8_t> output_buffer(
1810
+ implementation.maximal_binary_length_from_base64(input_data.data(),
1811
+ input_data.size()));
1812
+ auto result = implementation.base64_to_binary(
1813
+ input_data.data(), input_data.size(),
1814
+ reinterpret_cast<char *>(output_buffer.data()),
1815
+ simdutf::base64_default, option);
1816
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
1817
+ ASSERT_EQUAL(result.count, expected_output.size());
1818
+ output_buffer.resize(result.count);
1819
+ ASSERT_TRUE(output_buffer == expected_output);
1820
+ }
1821
+ }
1822
+
1823
+ for (auto option :
1824
+ {simdutf::last_chunk_handling_options::strict,
1825
+ simdutf::last_chunk_handling_options::loose,
1826
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1827
+ for (const std::tuple<std::string, read_write, std::vector<uint8_t>> &t :
1828
+ test_cases) {
1829
+ auto input_data = std::get<0>(t);
1830
+ auto read_write_info = std::get<1>(t);
1831
+ auto expected_output = std::get<2>(t);
1832
+ std::vector<uint8_t> output_buffer(
1833
+ implementation.maximal_binary_length_from_base64(input_data.data(),
1834
+ input_data.size()));
1835
+ auto result = implementation.base64_to_binary_details(
1836
+ input_data.data(), input_data.size(),
1837
+ reinterpret_cast<char *>(output_buffer.data()),
1838
+ simdutf::base64_default, option);
1839
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
1840
+ ASSERT_EQUAL(result.output_count, expected_output.size());
1841
+ ASSERT_EQUAL(result.output_count, read_write_info.written);
1842
+ ASSERT_EQUAL(result.input_count, read_write_info.read);
1843
+ output_buffer.resize(result.output_count);
1844
+ ASSERT_TRUE(output_buffer == expected_output);
1845
+ }
1846
+ }
1847
+ // Test with all last_chunk_handling_options
1848
+ for (auto option : {simdutf::last_chunk_handling_options::strict,
1849
+ simdutf::last_chunk_handling_options::loose}) {
1850
+ for (const std::tuple<std::string, read_write, std::vector<uint8_t>> &t :
1851
+ test_cases) {
1852
+ auto input_data = std::get<0>(t);
1853
+ auto read_write_info = std::get<1>(t);
1854
+ auto expected_output = std::get<2>(t);
1855
+ std::vector<uint8_t> output_buffer(
1856
+ implementation.maximal_binary_length_from_base64(input_data.data(),
1857
+ input_data.size()));
1858
+ size_t written = output_buffer.size();
1859
+ auto result = simdutf::base64_to_binary_safe(
1860
+ input_data.data(), input_data.size(),
1861
+ reinterpret_cast<char *>(output_buffer.data()), written,
1862
+ simdutf::base64_default, option);
1863
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
1864
+ ASSERT_EQUAL(result.count, read_write_info.read);
1865
+ ASSERT_EQUAL(written, expected_output.size());
1866
+ output_buffer.resize(written);
1867
+ ASSERT_TRUE(output_buffer == expected_output);
1868
+ }
1869
+ }
1870
+ }
1871
+
1872
+ // https://github.com/WebKit/WebKit/blob/18fad22e2078542316a576989676d31cfd08d777/JSTests/stress/uint8array-fromBase64.js#L206
1873
+ TEST(base64_decode_webkit_more_cases) {
1874
+ std::vector<std::string> test_cases = {
1875
+ "AA", " A A ", "AQ", " A Q ", "gA",
1876
+ " g A ", "/g", " / g ", "/w", " / w ",
1877
+ "AAE", " A A E ", "/v8", " / v 8 "};
1878
+ for (auto option :
1879
+ {simdutf::last_chunk_handling_options::strict,
1880
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1881
+ for (const std::string &input_data : test_cases) {
1882
+ std::vector<uint8_t> output_buffer(
1883
+ implementation.maximal_binary_length_from_base64(input_data.data(),
1884
+ input_data.size()));
1885
+ auto result = implementation.base64_to_binary(
1886
+ input_data.data(), input_data.size(),
1887
+ reinterpret_cast<char *>(output_buffer.data()),
1888
+ simdutf::base64_default, option);
1889
+ if (option == simdutf::last_chunk_handling_options::strict) {
1890
+ ASSERT_EQUAL(result.error, simdutf::error_code::BASE64_INPUT_REMAINDER);
1891
+ } else {
1892
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
1893
+ ASSERT_EQUAL(result.count, 0);
1894
+ }
1895
+ }
1896
+ }
1897
+ for (auto option :
1898
+ {simdutf::last_chunk_handling_options::strict,
1899
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1900
+ for (const std::string &input_data : test_cases) {
1901
+ std::vector<uint8_t> output_buffer(
1902
+ implementation.maximal_binary_length_from_base64(input_data.data(),
1903
+ input_data.size()));
1904
+ size_t written = output_buffer.size();
1905
+ auto result = simdutf::base64_to_binary_safe(
1906
+ input_data.data(), input_data.size(),
1907
+ reinterpret_cast<char *>(output_buffer.data()), written,
1908
+ simdutf::base64_default, option);
1909
+ if (option == simdutf::last_chunk_handling_options::strict) {
1910
+ ASSERT_EQUAL(result.error, simdutf::error_code::BASE64_INPUT_REMAINDER);
1911
+ } else {
1912
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
1913
+ ASSERT_EQUAL(written, 0);
1914
+ }
1915
+ }
1916
+ }
1917
+ }
1918
+
1919
+ TEST(base64_decode_webkit_like_but_random_more_cases) {
1920
+ for (size_t len = 1; len <= max_len; len++) {
1921
+ for (size_t trial = 0; trial < 10; trial++) {
1922
+ std::vector<char> source(len, 0);
1923
+ std::vector<char> buffer;
1924
+ buffer.resize(simdutf::base64_length_from_binary(len));
1925
+ std::mt19937 gen((std::mt19937::result_type)(seed));
1926
+ std::uniform_int_distribution<int> byte_generator{0, 255};
1927
+ for (size_t i = 0; i < len; i++) {
1928
+ source[i] = byte_generator(gen);
1929
+ }
1930
+ simdutf_maybe_unused const size_t size = implementation.binary_to_base64(
1931
+ source.data(), source.size(), buffer.data());
1932
+ for (size_t removed = 1; !buffer.empty() && removed <= 2; removed++) {
1933
+ buffer.pop_back();
1934
+ for (auto option :
1935
+ {simdutf::last_chunk_handling_options::strict,
1936
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1937
+ std::vector<uint8_t> output_buffer(
1938
+ implementation.maximal_binary_length_from_base64(buffer.data(),
1939
+ buffer.size()));
1940
+ auto result = implementation.base64_to_binary(
1941
+ buffer.data(), buffer.size(),
1942
+ reinterpret_cast<char *>(output_buffer.data()),
1943
+ simdutf::base64_default, option);
1944
+ if (option == simdutf::last_chunk_handling_options::strict) {
1945
+ ASSERT_EQUAL(result.error,
1946
+ simdutf::error_code::BASE64_INPUT_REMAINDER);
1947
+ } else {
1948
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
1949
+ ASSERT_EQUAL(result.count, (len - 1) / 3 * 3);
1950
+ }
1951
+ }
1952
+ for (auto option :
1953
+ {simdutf::last_chunk_handling_options::strict,
1954
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
1955
+ std::vector<uint8_t> output_buffer(
1956
+ implementation.maximal_binary_length_from_base64(buffer.data(),
1957
+ buffer.size()));
1958
+ size_t written = output_buffer.size();
1959
+ auto result = simdutf::base64_to_binary_safe(
1960
+ buffer.data(), buffer.size(),
1961
+ reinterpret_cast<char *>(output_buffer.data()), written,
1962
+ simdutf::base64_default, option);
1963
+ if (option == simdutf::last_chunk_handling_options::strict) {
1964
+ ASSERT_EQUAL(result.error,
1965
+ simdutf::error_code::BASE64_INPUT_REMAINDER);
1966
+ } else {
1967
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
1968
+ ASSERT_EQUAL(written, (len - 1) / 3 * 3);
1969
+ }
1970
+ }
1971
+ }
1972
+ }
1973
+ }
1974
+ }
1975
+
1976
+ TEST(base64_decode_webkit_like_but_random_with_spaces_more_cases) {
1977
+ for (size_t len = 1; len <= max_len; len++) {
1978
+ for (size_t trial = 0; trial < 20; trial++) {
1979
+ std::vector<char> source(len, 0);
1980
+ std::vector<char> buffer;
1981
+ buffer.resize(simdutf::base64_length_from_binary(len));
1982
+ std::mt19937 gen((std::mt19937::result_type)(seed));
1983
+ std::uniform_int_distribution<int> byte_generator{0, 255};
1984
+ for (size_t i = 0; i < len; i++) {
1985
+ source[i] = byte_generator(gen);
1986
+ }
1987
+ simdutf_maybe_unused const size_t size = implementation.binary_to_base64(
1988
+ source.data(), source.size(), buffer.data());
1989
+ buffer = add_simple_spaces(buffer, gen, 5 + len / 4);
1990
+ auto is_space = [](char c) {
1991
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
1992
+ };
1993
+ for (size_t removed = 1; !buffer.empty() && removed <= 2; removed++) {
1994
+ while (is_space(buffer.back())) {
1995
+ buffer.pop_back();
1996
+ }
1997
+ buffer.pop_back();
1998
+ for (auto option :
1999
+ {simdutf::last_chunk_handling_options::strict,
2000
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
2001
+ std::vector<uint8_t> output_buffer(
2002
+ implementation.maximal_binary_length_from_base64(buffer.data(),
2003
+ buffer.size()));
2004
+ auto result = implementation.base64_to_binary(
2005
+ buffer.data(), buffer.size(),
2006
+ reinterpret_cast<char *>(output_buffer.data()),
2007
+ simdutf::base64_default, option);
2008
+ if (option == simdutf::last_chunk_handling_options::strict) {
2009
+ ASSERT_EQUAL(result.error,
2010
+ simdutf::error_code::BASE64_INPUT_REMAINDER);
2011
+ } else {
2012
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
2013
+ ASSERT_EQUAL(result.count, (len - 1) / 3 * 3);
2014
+ }
2015
+ }
2016
+ for (auto option :
2017
+ {simdutf::last_chunk_handling_options::strict,
2018
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
2019
+ std::vector<uint8_t> output_buffer(
2020
+ simdutf::maximal_binary_length_from_base64(buffer.data(),
2021
+ buffer.size()));
2022
+ size_t written = output_buffer.size();
2023
+ auto result = simdutf::base64_to_binary_safe(
2024
+ buffer.data(), buffer.size(),
2025
+ reinterpret_cast<char *>(output_buffer.data()), written,
2026
+ simdutf::base64_default, option);
2027
+ if (option == simdutf::last_chunk_handling_options::strict) {
2028
+ ASSERT_EQUAL(result.error,
2029
+ simdutf::error_code::BASE64_INPUT_REMAINDER);
2030
+ } else {
2031
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
2032
+ ASSERT_EQUAL(written, (len - 1) / 3 * 3);
2033
+ }
2034
+ }
2035
+ }
2036
+ }
2037
+ }
2038
+ }
2039
+
2040
+ TEST(base64_decode_strict_mode) {
2041
+ std::vector<std::pair<std::string, std::string>> test_cases = {
2042
+ {"TQ", "M"}, // Length 2 (not multiple of 4)
2043
+ {"TWE", "Ma"}, // Length 3 (not multiple of 4)
2044
+ {"TWFu", "Man"}, // Length 4 (multiple of 4)
2045
+ {"TWF1", "Mau"}, // Length 4 (multiple of 4)
2046
+ {"TWFubWFu", "Manman"}, // Length 8 (multiple of 4)
2047
+ };
2048
+ for (const std::pair<std::string, std::string> &t : test_cases) {
2049
+ auto input_data = t.first;
2050
+ auto expected_output = t.second;
2051
+ std::vector<uint8_t> output_buffer(expected_output.size() +
2052
+ 3); // Add extra space for safety
2053
+
2054
+ auto result = implementation.base64_to_binary(
2055
+ input_data.data(), input_data.size(),
2056
+ reinterpret_cast<char *>(output_buffer.data()), simdutf::base64_default,
2057
+ simdutf::last_chunk_handling_options::strict);
2058
+
2059
+ if (input_data.size() % 4 == 0) {
2060
+ // Input length is a multiple of 4, expect success
2061
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
2062
+ ASSERT_EQUAL(result.count, expected_output.size());
2063
+ ASSERT_TRUE((std::equal(output_buffer.begin(),
2064
+ output_buffer.begin() + result.count,
2065
+ expected_output.begin())));
2066
+ } else {
2067
+ // Input length is not a multiple of 4, expect failure in strict mode
2068
+ ASSERT_EQUAL(result.error, simdutf::error_code::BASE64_INPUT_REMAINDER);
2069
+ }
2070
+ }
2071
+ }
2072
+
2073
+ TEST(base64_decode_stop_before_partial) {
2074
+ std::vector<std::pair<std::string, std::string>> test_cases = {
2075
+ {"TQ", ""}, // Length 2 (no complete blocks)
2076
+ {"TWE", ""}, // Length 3 (no complete blocks)
2077
+ {"TWFu", "Man"}, // Length 4 (1 complete block)
2078
+ {"TWFuTQ", "Man"}, // Length 6 (1 complete block)
2079
+ {"TWFuTW", "Man"}, // Length 7 (1 complete block)
2080
+ {"TWFuTWFu", "ManMan"}, // Length 8 (2 complete blocks)
2081
+ };
2082
+
2083
+ for (const std::pair<std::string, std::string> &t : test_cases) {
2084
+ auto input_data = t.first;
2085
+ auto expected_output = t.second;
2086
+ std::vector<char> output_buffer(expected_output.size() + 3); // Extra space
2087
+
2088
+ auto result = implementation.base64_to_binary(
2089
+ input_data.data(), input_data.size(), output_buffer.data(),
2090
+ simdutf::base64_default,
2091
+ simdutf::last_chunk_handling_options::stop_before_partial);
2092
+
2093
+ ASSERT_EQUAL(result.error, simdutf::error_code::SUCCESS);
2094
+ ASSERT_EQUAL(result.count, expected_output.size());
2095
+ ASSERT_TRUE(
2096
+ (std::equal(output_buffer.begin(), output_buffer.begin() + result.count,
2097
+ expected_output.begin())));
2098
+ }
2099
+ }
2100
+
2101
+ TEST(issue_520_url) {
2102
+ // output differs between implementations for decode
2103
+ // impl arm64 got maxbinarylength=48 convertresult=[count=64,
2104
+ // error=INVALID_BASE64_CHARACTER] impl fallback got maxbinarylength=48
2105
+ // convertresult=[count=0, error=BASE64_INPUT_REMAINDER]
2106
+
2107
+ std::vector<unsigned char> data{
2108
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 12, 32,
2109
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2110
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
2111
+ 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 82,
2112
+ };
2113
+ std::vector<char> out(48);
2114
+
2115
+ const auto r = implementation.base64_to_binary(
2116
+ (const char *)data.data(), data.size(), out.data(), simdutf::base64_url);
2117
+ ASSERT_EQUAL(r.error, simdutf::error_code::BASE64_INPUT_REMAINDER);
2118
+ ASSERT_EQUAL(r.count, 64);
2119
+ }
2120
+
2121
+ TEST(issue_511) {
2122
+ // 0x7f is not a valid base64 character.
2123
+ std::vector<unsigned char> data{
2124
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
2125
+ 0x20, 0x7f, 0x57, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
2126
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
2127
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
2128
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
2129
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x5a};
2130
+ std::vector<char> out(48);
2131
+ const auto r = implementation.base64_to_binary(
2132
+ (const char *)data.data(), data.size(), out.data(), simdutf::base64_url);
2133
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
2134
+ ASSERT_EQUAL(r.count, 12);
2135
+ }
2136
+
2137
+ TEST(issue_509) {
2138
+ std::vector<char> data{' ', '='};
2139
+ std::vector<char> out(1);
2140
+ const auto r = implementation.base64_to_binary(
2141
+ data.data(), data.size(), out.data(), simdutf::base64_default);
2142
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
2143
+ ASSERT_EQUAL(r.count, 1);
2144
+ }
2145
+
2146
+ TEST(issue_502_alt) {
2147
+ for (std::size_t nof_equals = 1; nof_equals < 100; ++nof_equals) {
2148
+ std::vector<char> data(nof_equals, '=');
2149
+ std::vector<char> out(1);
2150
+ const auto r = implementation.base64_to_binary(
2151
+ data.data(), data.size(), out.data(), simdutf::base64_default);
2152
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
2153
+ ASSERT_EQUAL(r.count, 0);
2154
+ }
2155
+ }
2156
+
2157
+ TEST(issue_504) {
2158
+ std::array<char16_t, 1> data{61}; // 61 is the ASCII code for '='
2159
+ std::vector<char> out(1);
2160
+ const auto r = implementation.base64_to_binary(
2161
+ data.data(), data.size(), out.data(), simdutf::base64_default);
2162
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
2163
+ ASSERT_EQUAL(r.count, 0);
2164
+ }
2165
+
2166
+ TEST(issue_504_8bit) {
2167
+ std::array<char, 1> data{61}; // 61 is the ASCII code for '='
2168
+ std::vector<char> out(1);
2169
+ const auto r = implementation.base64_to_binary(
2170
+ data.data(), data.size(), out.data(), simdutf::base64_default);
2171
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
2172
+ ASSERT_EQUAL(r.count, 0);
2173
+ }
2174
+
2175
+ TEST(issue_502) {
2176
+ std::array<char, 1> data{'='};
2177
+ std::vector<char> out(1);
2178
+ const auto r = implementation.base64_to_binary(
2179
+ data.data(), data.size(), out.data(), simdutf::base64_default);
2180
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
2181
+ ASSERT_EQUAL(r.count, 0);
2182
+ }
2183
+
2184
+ TEST(issue_503) {
2185
+ std::array<char16_t, 1> data{15626}; // 0x3D0A
2186
+ std::vector<char> out(1);
2187
+ const auto r = implementation.base64_to_binary(
2188
+ data.data(), data.size(), out.data(), simdutf::base64_default);
2189
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
2190
+ ASSERT_EQUAL(r.count, 0);
2191
+ }
2192
+
2193
+ TEST(decode_non_ascii_utf16) {
2194
+ std::vector<std::u16string> cases = {u"Zg\u2009=="};
2195
+ std::vector<simdutf::error_code> codes = {
2196
+ simdutf::error_code::INVALID_BASE64_CHARACTER};
2197
+ std::vector<size_t> counts = {2};
2198
+
2199
+ for (size_t i = 0; i < cases.size(); i++) {
2200
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2201
+ cases[i].data(), cases[i].size()));
2202
+ simdutf::result r = implementation.base64_to_binary(
2203
+ cases[i].data(), cases[i].size(), buffer.data());
2204
+ ASSERT_EQUAL(r.error, codes[i]);
2205
+ ASSERT_EQUAL(r.count, counts[i]);
2206
+ size_t len = buffer.size();
2207
+ r = simdutf::base64_to_binary_safe(cases[i].data(), cases[i].size(),
2208
+ buffer.data(), len);
2209
+ ASSERT_EQUAL(r.error, codes[i]);
2210
+ ASSERT_EQUAL(r.count, counts[i]);
2211
+ }
2212
+ }
2213
+
2214
+ TEST(decode_non_ascii) {
2215
+ std::vector<std::string> cases = {"Zg\u2009=="};
2216
+ std::vector<simdutf::error_code> codes = {
2217
+ simdutf::error_code::INVALID_BASE64_CHARACTER};
2218
+ std::vector<size_t> counts = {2};
2219
+
2220
+ for (size_t i = 0; i < cases.size(); i++) {
2221
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2222
+ cases[i].data(), cases[i].size()));
2223
+ simdutf::result r = implementation.base64_to_binary(
2224
+ cases[i].data(), cases[i].size(), buffer.data());
2225
+ ASSERT_EQUAL(r.error, codes[i]);
2226
+ ASSERT_EQUAL(r.count, counts[i]);
2227
+ size_t len = buffer.size();
2228
+ r = simdutf::base64_to_binary_safe(cases[i].data(), cases[i].size(),
2229
+ buffer.data(), len);
2230
+ ASSERT_EQUAL(r.error, codes[i]);
2231
+ ASSERT_EQUAL(r.count, counts[i]);
2232
+ }
2233
+ }
2234
+
2235
+ TEST(decode_base64_cases) {
2236
+ std::vector<std::vector<char>> cases = {{0x53, 0x53}};
2237
+ std::vector<simdutf::error_code> codes = {simdutf::error_code::SUCCESS};
2238
+ std::vector<size_t> counts = {1};
2239
+
2240
+ for (size_t i = 0; i < cases.size(); i++) {
2241
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2242
+ cases[i].data(), cases[i].size()));
2243
+ simdutf::result r = implementation.base64_to_binary(
2244
+ cases[i].data(), cases[i].size(), buffer.data());
2245
+ ASSERT_EQUAL(r.error, codes[i]);
2246
+ ASSERT_EQUAL(r.count, counts[i]);
2247
+ }
2248
+ }
2249
+
2250
+ namespace cases {
2251
+ const std::vector<std::pair<std::string, std::string>> whitespaces = {
2252
+ {"abcd", " Y\fW\tJ\njZ A=\r= "},
2253
+ };
2254
+
2255
+ const std::vector<std::pair<std::string, std::string>> simple = {
2256
+ {"Hello, World!", "SGVsbG8sIFdvcmxkIQ=="},
2257
+ {"GeeksforGeeks", "R2Vla3Nmb3JHZWVrcw=="},
2258
+ {"123456", "MTIzNDU2"},
2259
+ {"Base64 Encoding", "QmFzZTY0IEVuY29kaW5n"},
2260
+ {"!R~J2jL&mI]O)3=c:G3Mo)oqmJdxoprTZDyxEvU0MI.'Ww5H{G>}y;;+B8E_Ah,Ed[ "
2261
+ "PdBqY'^N>O$4:7LK1<:|7)btV@|{YWR$$Er59-XjVrFl4L}~yzTEd4'E[@k",
2262
+ "IVJ+SjJqTCZtSV1PKTM9YzpHM01vKW9xbUpkeG9wclRaRHl4RXZVME1JLidXdzVIe0c+"
2263
+ "fXk7OytCOEVfQWgsRWRbIFBkQnFZJ15OPk8kNDo3TEsxPDp8NylidFZAfHtZV1IkJEVyNTk"
2264
+ "tWGpWckZsNEx9fnl6VEVkNCdFW0Br"}};
2265
+
2266
+ const std::vector<std::pair<std::string, std::string>> no_padding = {
2267
+ {"Hello, World!", "SGVsbG8sIFdvcmxkIQ"},
2268
+ {"GeeksforGeeks", "R2Vla3Nmb3JHZWVrcw"},
2269
+ {"123456", "MTIzNDU2"},
2270
+ {"Base64 Encoding", "QmFzZTY0IEVuY29kaW5n"},
2271
+ {"!R~J2jL&mI]O)3=c:G3Mo)oqmJdxoprTZDyxEvU0MI.'Ww5H{G>}y;;+B8E_Ah,Ed[ "
2272
+ "PdBqY'^N>O$4:7LK1<:|7)btV@|{YWR$$Er59-XjVrFl4L}~yzTEd4'E[@k",
2273
+ "IVJ+SjJqTCZtSV1PKTM9YzpHM01vKW9xbUpkeG9wclRaRHl4RXZVME1JLidXdzVIe0c+"
2274
+ "fXk7OytCOEVfQWgsRWRbIFBkQnFZJ15OPk8kNDo3TEsxPDp8NylidFZAfHtZV1IkJEVyNTk"
2275
+ "tWGpWckZsNEx9fnl6VEVkNCdFW0Br"}};
2276
+
2277
+ const std::vector<std::pair<std::string, std::string>> simple_url = {
2278
+ {"Hello, World!", "SGVsbG8sIFdvcmxkIQ"},
2279
+ {"GeeksforGeeks", "R2Vla3Nmb3JHZWVrcw"},
2280
+ {"123456", "MTIzNDU2"},
2281
+ {"Base64 Encoding", "QmFzZTY0IEVuY29kaW5n"},
2282
+ {"!R~J2jL&mI]O)3=c:G3Mo)oqmJdxoprTZDyxEvU0MI.'Ww5H{G>}y;;+B8E_Ah,Ed[ "
2283
+ "PdBqY'^N>O$4:7LK1<:|7)btV@|{YWR$$Er59-XjVrFl4L}~yzTEd4'E[@k",
2284
+ "IVJ-SjJqTCZtSV1PKTM9YzpHM01vKW9xbUpkeG9wclRaRHl4RXZVME1JLidXdzVIe0c-"
2285
+ "fXk7OytCOEVfQWgsRWRbIFBkQnFZJ15OPk8kNDo3TEsxPDp8NylidFZAfHtZV1IkJEVyNTk"
2286
+ "tWGpWckZsNEx9fnl6VEVkNCdFW0Br"}};
2287
+
2288
+ const std::vector<std::pair<std::string, std::string>> simple_url_with_padding =
2289
+ {{"Hello, World!", "SGVsbG8sIFdvcmxkIQ=="},
2290
+ {"GeeksforGeeks", "R2Vla3Nmb3JHZWVrcw=="},
2291
+ {"123456", "MTIzNDU2"},
2292
+ {"Base64 Encoding", "QmFzZTY0IEVuY29kaW5n"},
2293
+ {"!R~J2jL&mI]O)3=c:G3Mo)oqmJdxoprTZDyxEvU0MI.'Ww5H{G>}y;;+B8E_Ah,Ed[ "
2294
+ "PdBqY'^N>O$4:7LK1<:|7)btV@|{YWR$$Er59-XjVrFl4L}~yzTEd4'E[@k",
2295
+ "IVJ-"
2296
+ "SjJqTCZtSV1PKTM9YzpHM01vKW9xbUpkeG9wclRaRHl4RXZVME1JLidXdzVIe0c-"
2297
+ "fXk7OytCOEVfQWgsRWRbIFBkQnFZJ15OPk8kNDo3TEsxPDp8NylidFZAfHtZV1IkJEV"
2298
+ "yNTk"
2299
+ "tWGpWckZsNEx9fnl6VEVkNCdFW0Br"}};
2300
+ } // namespace cases
2301
+
2302
+ namespace cases16 {
2303
+ const std::vector<std::pair<std::string, std::u16string>> simple_with_padding =
2304
+ {{"Hello, World!", u"SGVsbG8sIFdvcmxkIQ=="},
2305
+ {"GeeksforGeeks", u"R2Vla3Nmb3JHZWVrcw=="},
2306
+ {"123456", u"MTIzNDU2"},
2307
+ {"Base64 Encoding", u"QmFzZTY0IEVuY29kaW5n"},
2308
+ {"!R~J2jL&mI]O)3=c:G3Mo)oqmJdxoprTZDyxEvU0MI.'Ww5H{G>}y;;+B8E_Ah,Ed[ "
2309
+ "PdBqY'^N>O$4:7LK1<:|7)btV@|{YWR$$Er59-XjVrFl4L}~yzTEd4'E[@k",
2310
+ u"IVJ+"
2311
+ u"SjJqTCZtSV1PKTM9YzpHM01vKW9xbUpkeG9wclRaRHl4RXZVME1JLidXdzVIe0c+"
2312
+ u"fXk7OytCOEVfQWgsRWRbIFBkQnFZJ15OPk8kNDo3TEsxPDp8NylidFZAfHtZV1IkJE"
2313
+ u"VyNT"
2314
+ u"ktWGpWckZsNEx9fnl6VEVkNCdFW0Br"}};
2315
+
2316
+ const std::vector<std::pair<std::string, std::u16string>>
2317
+ simple_url_without_padding = {
2318
+ {"Hello, World!", u"SGVsbG8sIFdvcmxkIQ"},
2319
+ {"GeeksforGeeks", u"R2Vla3Nmb3JHZWVrcw"},
2320
+ {"123456", u"MTIzNDU2"},
2321
+ {"Base64 Encoding", u"QmFzZTY0IEVuY29kaW5n"},
2322
+ {"!R~J2jL&mI]O)3=c:G3Mo)oqmJdxoprTZDyxEvU0MI.'Ww5H{G>}y;;+B8E_Ah,Ed[ "
2323
+ "PdBqY'^N>O$4:7LK1<:|7)btV@|{YWR$$Er59-XjVrFl4L}~yzTEd4'E[@k",
2324
+ u"IVJ-"
2325
+ u"SjJqTCZtSV1PKTM9YzpHM01vKW9xbUpkeG9wclRaRHl4RXZVME1JLidXdzVIe0c-"
2326
+ u"fXk7OytCOEVfQWgsRWRbIFBkQnFZJ15OPk8kNDo3TEsxPDp8NylidFZAfHtZV1IkJE"
2327
+ u"Vy"
2328
+ u"NT"
2329
+ u"ktWGpWckZsNEx9fnl6VEVkNCdFW0Br"}};
2330
+ } // namespace cases16
2331
+
2332
+ TEST(complete_decode_base64_cases) {
2333
+ for (const auto &p : cases::whitespaces) {
2334
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2335
+ p.second.data(), p.second.size()));
2336
+ simdutf::result r = implementation.base64_to_binary(
2337
+ p.second.data(), p.second.size(), buffer.data());
2338
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2339
+ ASSERT_EQUAL(r.count, p.first.size());
2340
+ for (size_t i = 0; i < r.count; i++) {
2341
+ ASSERT_EQUAL(buffer[i], p.first[i]);
2342
+ }
2343
+ }
2344
+ }
2345
+
2346
+ TEST(complete_safe_decode_base64_cases) {
2347
+ for (const auto &p : cases::whitespaces) {
2348
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2349
+ p.second.data(), p.second.size()));
2350
+ size_t bufsize = buffer.size();
2351
+ simdutf::result r = simdutf::base64_to_binary_safe(
2352
+ p.second.data(), p.second.size(), buffer.data(), bufsize);
2353
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2354
+ ASSERT_EQUAL(bufsize, p.first.size());
2355
+ for (size_t i = 0; i < bufsize; i++) {
2356
+ ASSERT_EQUAL(buffer[i], p.first[i]);
2357
+ }
2358
+ #if SIMDUTF_ATOMIC_REF
2359
+ bufsize = buffer.size();
2360
+ r = simdutf::atomic_base64_to_binary_safe(p.second.data(), p.second.size(),
2361
+ buffer.data(), bufsize);
2362
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2363
+ ASSERT_EQUAL(bufsize, p.first.size());
2364
+ for (size_t i = 0; i < bufsize; i++) {
2365
+ ASSERT_EQUAL(buffer[i], p.first[i]);
2366
+ }
2367
+ #endif
2368
+ }
2369
+ }
2370
+
2371
+ TEST(complete_safe_decode_base64url_cases) {
2372
+ for (const auto &p : cases::whitespaces) {
2373
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2374
+ p.second.data(), p.second.size()));
2375
+ size_t bufsize = buffer.size();
2376
+ simdutf::result r = simdutf::base64_to_binary_safe(
2377
+ p.second.data(), p.second.size(), buffer.data(), bufsize,
2378
+ simdutf::base64_url);
2379
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2380
+ ASSERT_EQUAL(bufsize, p.first.size());
2381
+ for (size_t i = 0; i < bufsize; i++) {
2382
+ ASSERT_EQUAL(buffer[i], p.first[i]);
2383
+ }
2384
+ #if SIMDUTF_ATOMIC_REF
2385
+ bufsize = buffer.size();
2386
+ r = simdutf::base64_to_binary_safe(p.second.data(), p.second.size(),
2387
+ buffer.data(), bufsize,
2388
+ simdutf::base64_url);
2389
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2390
+ ASSERT_EQUAL(bufsize, p.first.size());
2391
+ for (size_t i = 0; i < bufsize; i++) {
2392
+ ASSERT_EQUAL(buffer[i], p.first[i]);
2393
+ }
2394
+ #endif
2395
+ }
2396
+ }
2397
+
2398
+ TEST(encode_base64_cases) {
2399
+ for (const auto &p : cases::simple) {
2400
+ std::vector<char> buffer(
2401
+ simdutf::base64_length_from_binary(p.first.size()));
2402
+ ASSERT_EQUAL(buffer.size(), p.second.size());
2403
+ size_t s = implementation.binary_to_base64(p.first.data(), p.first.size(),
2404
+ buffer.data());
2405
+ ASSERT_EQUAL(s, p.second.size());
2406
+ ASSERT_EQUAL(std::string(buffer.data(), buffer.size()), p.second);
2407
+ }
2408
+ }
2409
+
2410
+ TEST(decode_base64_simple) {
2411
+ for (const auto &p : cases::simple) {
2412
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2413
+ p.second.data(), p.second.size()));
2414
+ ASSERT_EQUAL(buffer.size(), p.first.size());
2415
+ simdutf::result r = implementation.base64_to_binary(
2416
+ p.second.data(), p.second.size(), buffer.data());
2417
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2418
+ ASSERT_EQUAL(r.count, p.first.size());
2419
+ for (size_t i = 0; i < buffer.size(); i++) {
2420
+ ASSERT_EQUAL(buffer[i], p.first[i]);
2421
+ }
2422
+ }
2423
+ }
2424
+
2425
+ TEST(safe_decode_base64_simple) {
2426
+ for (const auto &p : cases::simple) {
2427
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2428
+ p.second.data(), p.second.size()));
2429
+ ASSERT_EQUAL(buffer.size(), p.first.size());
2430
+ size_t length = buffer.size();
2431
+ simdutf::result r = simdutf::base64_to_binary_safe(
2432
+ p.second.data(), p.second.size(), buffer.data(), length);
2433
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2434
+ ASSERT_EQUAL(r.count, p.second.size());
2435
+ ASSERT_EQUAL(length, p.first.size());
2436
+ for (size_t i = 0; i < buffer.size(); i++) {
2437
+ ASSERT_EQUAL(buffer[i], p.first[i]);
2438
+ }
2439
+ }
2440
+ }
2441
+
2442
+ TEST(encode_base64_cases_no_padding) {
2443
+ for (const auto &p : cases::no_padding) {
2444
+ std::vector<char> buffer(simdutf::base64_length_from_binary(
2445
+ p.first.size(), simdutf::base64_default_no_padding));
2446
+ ASSERT_EQUAL(buffer.size(), p.second.size());
2447
+ size_t s = implementation.binary_to_base64(
2448
+ p.first.data(), p.first.size(), buffer.data(),
2449
+ simdutf::base64_default_no_padding);
2450
+ ASSERT_EQUAL(s, p.second.size());
2451
+ ASSERT_EQUAL(std::string(buffer.data(), buffer.size()), p.second);
2452
+ }
2453
+ }
2454
+
2455
+ #if SIMDUTF_BASE64URL_TESTS
2456
+
2457
+ TEST(encode_base64url_simple) {
2458
+ for (const auto &p : cases::simple_url) {
2459
+ std::vector<char> buffer(simdutf::base64_length_from_binary(
2460
+ p.first.size(), simdutf::base64_url));
2461
+ ASSERT_EQUAL(buffer.size(), p.second.size());
2462
+ size_t s = implementation.binary_to_base64(
2463
+ p.first.data(), p.first.size(), buffer.data(), simdutf::base64_url);
2464
+ ASSERT_EQUAL(s, p.second.size());
2465
+ if (std::string(buffer.data(), buffer.size()) != p.second) {
2466
+ printf("difference:\n");
2467
+ printf(" %.*s\n", (int)s, buffer.data());
2468
+ printf(" %.*s\n", (int)s, p.second.data());
2469
+ }
2470
+ ASSERT_EQUAL(std::string(buffer.data(), buffer.size()), p.second);
2471
+ }
2472
+ }
2473
+
2474
+ TEST(decode_base64url) {
2475
+ for (const auto &p : cases::simple_url) {
2476
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2477
+ p.second.data(), p.second.size()));
2478
+ ASSERT_EQUAL(buffer.size(), p.first.size());
2479
+ simdutf::result r = implementation.base64_to_binary(
2480
+ p.second.data(), p.second.size(), buffer.data(), simdutf::base64_url);
2481
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2482
+ ASSERT_EQUAL(r.count, p.first.size());
2483
+ for (size_t i = 0; i < buffer.size(); i++) {
2484
+ ASSERT_EQUAL(buffer[i], p.first[i]);
2485
+ }
2486
+ }
2487
+ }
2488
+
2489
+ TEST(safe_decode_base64url) {
2490
+ for (const auto &p : cases::simple_url) {
2491
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2492
+ p.second.data(), p.second.size()));
2493
+ ASSERT_EQUAL(buffer.size(), p.first.size());
2494
+ size_t length = buffer.size();
2495
+ simdutf::result r = simdutf::base64_to_binary_safe(
2496
+ p.second.data(), p.second.size(), buffer.data(), length,
2497
+ simdutf::base64_url);
2498
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2499
+ ASSERT_EQUAL(r.count, p.second.size());
2500
+ ASSERT_EQUAL(length, p.first.size());
2501
+ for (size_t i = 0; i < buffer.size(); i++) {
2502
+ ASSERT_EQUAL(buffer[i], p.first[i]);
2503
+ }
2504
+ }
2505
+ }
2506
+
2507
+ TEST(encode_base64url_with_padding_cases) {
2508
+ for (const auto &p : cases::simple_url_with_padding) {
2509
+ std::vector<char> buffer(simdutf::base64_length_from_binary(
2510
+ p.first.size(), simdutf::base64_url_with_padding));
2511
+ ASSERT_EQUAL(buffer.size(), p.second.size());
2512
+ size_t s = implementation.binary_to_base64(
2513
+ p.first.data(), p.first.size(), buffer.data(),
2514
+ simdutf::base64_url_with_padding);
2515
+ ASSERT_EQUAL(s, p.second.size());
2516
+ if (std::string(buffer.data(), buffer.size()) != p.second) {
2517
+ printf("difference:\n");
2518
+ printf(" %.*s\n", (int)s, buffer.data());
2519
+ printf(" %.*s\n", (int)s, p.second.data());
2520
+ }
2521
+ ASSERT_EQUAL(std::string(buffer.data(), buffer.size()), p.second);
2522
+ }
2523
+ }
2524
+
2525
+ #endif
2526
+
2527
+ TEST(decode_base64_cases_16) {
2528
+ for (const auto &p : cases16::simple_with_padding) {
2529
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2530
+ p.second.data(), p.second.size()));
2531
+ ASSERT_EQUAL(buffer.size(), p.first.size());
2532
+ simdutf::result r = implementation.base64_to_binary(
2533
+ p.second.data(), p.second.size(), buffer.data());
2534
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2535
+ ASSERT_EQUAL(r.count, p.first.size());
2536
+ ASSERT_BYTES_EQUAL(buffer, p.first, r.count);
2537
+ }
2538
+ }
2539
+
2540
+ TEST(safe_decode_base64_cases_16) {
2541
+ for (const auto &p : cases16::simple_with_padding) {
2542
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2543
+ p.second.data(), p.second.size()));
2544
+ ASSERT_EQUAL(buffer.size(), p.first.size());
2545
+ size_t length = buffer.size();
2546
+ simdutf::result r = simdutf::base64_to_binary_safe(
2547
+ p.second.data(), p.second.size(), buffer.data(), length);
2548
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2549
+ ASSERT_EQUAL(r.count, p.second.size());
2550
+ ASSERT_EQUAL(length, p.first.size());
2551
+ for (size_t i = 0; i < buffer.size(); i++) {
2552
+ ASSERT_EQUAL(buffer[i], p.first[i]);
2553
+ }
2554
+ }
2555
+ }
2556
+
2557
+ #if SIMDUTF_BASE64URL_TESTS
2558
+
2559
+ TEST(decode_base64url_cases_16) {
2560
+ for (const auto &p : cases16::simple_url_without_padding) {
2561
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2562
+ p.second.data(), p.second.size()));
2563
+ ASSERT_EQUAL(buffer.size(), p.first.size());
2564
+ simdutf::result r = implementation.base64_to_binary(
2565
+ p.second.data(), p.second.size(), buffer.data(), simdutf::base64_url);
2566
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2567
+ ASSERT_EQUAL(r.count, p.first.size());
2568
+ for (size_t i = 0; i < buffer.size(); i++) {
2569
+ ASSERT_EQUAL(buffer[i], p.first[i]);
2570
+ }
2571
+ }
2572
+ }
2573
+
2574
+ TEST(safe_decode_base64url_cases_16) {
2575
+ for (const auto &p : cases16::simple_url_without_padding) {
2576
+ std::vector<char> buffer(implementation.maximal_binary_length_from_base64(
2577
+ p.second.data(), p.second.size()));
2578
+ ASSERT_EQUAL(buffer.size(), p.first.size());
2579
+ size_t length = buffer.size();
2580
+ simdutf::result r = simdutf::base64_to_binary_safe(
2581
+ p.second.data(), p.second.size(), buffer.data(), length,
2582
+ simdutf::base64_url);
2583
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2584
+ ASSERT_EQUAL(r.count, p.second.size());
2585
+ ASSERT_EQUAL(length, p.first.size());
2586
+ for (size_t i = 0; i < buffer.size(); i++) {
2587
+ ASSERT_EQUAL(buffer[i], p.first[i]);
2588
+ }
2589
+ }
2590
+ }
2591
+
2592
+ #endif
2593
+
2594
+ TEST(roundtrip_base64) {
2595
+ for (size_t len = 0; len < max_len; len++) {
2596
+ std::vector<char> source(len, 0);
2597
+ std::vector<char> buffer;
2598
+ buffer.resize(simdutf::base64_length_from_binary(len));
2599
+ std::vector<char> back(len);
2600
+ std::mt19937 gen((std::mt19937::result_type)(seed));
2601
+ std::uniform_int_distribution<int> byte_generator{0, 255};
2602
+ for (size_t trial = 0; trial < 10; trial++) {
2603
+ for (size_t i = 0; i < len; i++) {
2604
+ source[i] = byte_generator(gen);
2605
+ }
2606
+ size_t size = implementation.binary_to_base64(
2607
+ source.data(), source.size(), buffer.data());
2608
+ ASSERT_EQUAL(size, simdutf::base64_length_from_binary(len));
2609
+ simdutf::result r =
2610
+ implementation.base64_to_binary(buffer.data(), size, back.data());
2611
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2612
+ ASSERT_EQUAL(r.count, len);
2613
+ if (back != source) {
2614
+ printf("=====input size %zu\n", len);
2615
+ for (size_t i = 0; i < len; i++) {
2616
+ if (back[i] != source[i]) {
2617
+ printf("Mismatch at position %zu trial %zu\n", i, trial);
2618
+ }
2619
+ printf("%zu: %02x %02x\n", i, uint8_t(back[i]), uint8_t(source[i]));
2620
+ }
2621
+ printf("=====base64 size %zu\n", size);
2622
+ for (size_t i = 0; i < size; i++) {
2623
+ printf("%zu: %02x %c\n", i, uint8_t(buffer[i]), buffer[i]);
2624
+ }
2625
+ }
2626
+ ASSERT_TRUE(back == source);
2627
+
2628
+ // Test with all last_chunk_handling_options
2629
+ for (auto option : {simdutf::last_chunk_handling_options::strict,
2630
+ simdutf::last_chunk_handling_options::loose}) {
2631
+ r = implementation.base64_to_binary(buffer.data(), size, back.data(),
2632
+ simdutf::base64_default, option);
2633
+ ASSERT_TRUE((size % 4) == 0);
2634
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2635
+ ASSERT_EQUAL(r.count, len);
2636
+ ASSERT_TRUE(back == source);
2637
+ }
2638
+ }
2639
+ }
2640
+ }
2641
+
2642
+ TEST(roundtrip_base64_16) {
2643
+ for (size_t len = 0; len < max_len; len++) {
2644
+ std::vector<char> source(len, 0);
2645
+ std::vector<char> buffer;
2646
+ std::vector<char16_t> buffer16;
2647
+
2648
+ buffer.resize(simdutf::base64_length_from_binary(len));
2649
+ std::vector<char> back(len);
2650
+ std::mt19937 gen((std::mt19937::result_type)(seed));
2651
+ std::uniform_int_distribution<int> byte_generator{0, 255};
2652
+ for (size_t trial = 0; trial < 10; trial++) {
2653
+ for (size_t i = 0; i < len; i++) {
2654
+ source[i] = byte_generator(gen);
2655
+ }
2656
+ size_t size = implementation.binary_to_base64(
2657
+ source.data(), source.size(), buffer.data());
2658
+ buffer.resize(size);
2659
+ buffer16.resize(buffer.size());
2660
+ for (size_t i = 0; i < buffer.size(); i++) {
2661
+ buffer16[i] = buffer[i];
2662
+ }
2663
+ ASSERT_EQUAL(size, simdutf::base64_length_from_binary(len));
2664
+ simdutf::result r =
2665
+ implementation.base64_to_binary(buffer16.data(), size, back.data());
2666
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2667
+ ASSERT_EQUAL(r.count, len);
2668
+ if (back != source) {
2669
+ printf("=====input size %zu\n", len);
2670
+ for (size_t i = 0; i < len; i++) {
2671
+ if (back[i] != source[i]) {
2672
+ printf("Mismatch at position %zu trial %zu\n", i, trial);
2673
+ }
2674
+ printf("%zu: %02x %02x\n", i, uint8_t(back[i]), uint8_t(source[i]));
2675
+ }
2676
+ printf("=====base64 size %zu\n", size);
2677
+ for (size_t i = 0; i < size; i++) {
2678
+ printf("%zu: %02x %c\n", i, uint8_t(buffer[i]), buffer[i]);
2679
+ }
2680
+ }
2681
+ ASSERT_TRUE(back == source);
2682
+
2683
+ // Test with all last_chunk_handling_options
2684
+ for (auto option : {simdutf::last_chunk_handling_options::strict,
2685
+ simdutf::last_chunk_handling_options::loose}) {
2686
+ r = implementation.base64_to_binary(buffer.data(), size, back.data(),
2687
+ simdutf::base64_default, option);
2688
+ ASSERT_TRUE((size % 4) == 0);
2689
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2690
+ ASSERT_EQUAL(r.count, len);
2691
+ ASSERT_TRUE(back == source);
2692
+ }
2693
+ }
2694
+ }
2695
+ }
2696
+
2697
+ #if SIMDUTF_BASE64URL_TESTS
2698
+
2699
+ TEST(roundtrip_base64url) {
2700
+ for (size_t len = 0; len < max_len; len++) {
2701
+ std::vector<char> source(len, 0);
2702
+ std::vector<char> buffer;
2703
+ buffer.resize(simdutf::base64_length_from_binary(len, simdutf::base64_url));
2704
+ std::vector<char> back(len);
2705
+ std::mt19937 gen((std::mt19937::result_type)(seed));
2706
+ std::uniform_int_distribution<int> byte_generator{0, 255};
2707
+ for (size_t trial = 0; trial < 10; trial++) {
2708
+ for (size_t i = 0; i < len; i++) {
2709
+ source[i] = byte_generator(gen);
2710
+ }
2711
+ size_t size = implementation.binary_to_base64(
2712
+ source.data(), source.size(), buffer.data(), simdutf::base64_url);
2713
+ ASSERT_EQUAL(
2714
+ size, simdutf::base64_length_from_binary(len, simdutf::base64_url));
2715
+ simdutf::result r = implementation.base64_to_binary(
2716
+ buffer.data(), size, back.data(), simdutf::base64_url);
2717
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2718
+ ASSERT_EQUAL(r.count, len);
2719
+ if (back != source) {
2720
+ printf("=====input size %zu\n", len);
2721
+ for (size_t i = 0; i < len; i++) {
2722
+ if (back[i] != source[i]) {
2723
+ printf("Mismatch at position %zu trial %zu\n", i, trial);
2724
+ }
2725
+ printf("%zu: %02x %02x\n", i, uint8_t(back[i]), uint8_t(source[i]));
2726
+ }
2727
+ printf("=====base64 size %zu\n", size);
2728
+ for (size_t i = 0; i < size; i++) {
2729
+ printf("%zu: %02x %c\n", i, uint8_t(buffer[i]), buffer[i]);
2730
+ }
2731
+ }
2732
+ ASSERT_TRUE(back == source);
2733
+
2734
+ // Test with all last_chunk_handling_options
2735
+ for (auto option :
2736
+ {simdutf::last_chunk_handling_options::strict,
2737
+ simdutf::last_chunk_handling_options::loose,
2738
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
2739
+ r = implementation.base64_to_binary(buffer.data(), size, back.data(),
2740
+ simdutf::base64_url, option);
2741
+ if ((size % 4) == 0) {
2742
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2743
+ ASSERT_EQUAL(r.count, len);
2744
+ ASSERT_TRUE(back == source);
2745
+ } else {
2746
+ if (option == simdutf::last_chunk_handling_options::strict) {
2747
+ ASSERT_EQUAL(r.error, simdutf::error_code::BASE64_INPUT_REMAINDER);
2748
+ } else if (option == simdutf::last_chunk_handling_options::loose) {
2749
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2750
+ ASSERT_EQUAL(r.count, len);
2751
+ ASSERT_TRUE(back == source);
2752
+ } else if (option == simdutf::last_chunk_handling_options::
2753
+ stop_before_partial) {
2754
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2755
+ ASSERT_EQUAL(r.count, len / 3 * 3);
2756
+ ASSERT_TRUE(std::equal(back.begin(), back.begin() + len / 3 * 3,
2757
+ source.begin()));
2758
+ }
2759
+ }
2760
+ }
2761
+ }
2762
+ }
2763
+ }
2764
+
2765
+ TEST(roundtrip_base64url_16) {
2766
+ for (size_t len = 0; len < max_len; len++) {
2767
+ std::vector<char> source(len, 0);
2768
+ std::vector<char> buffer;
2769
+ std::vector<char16_t> buffer16;
2770
+
2771
+ buffer.resize(simdutf::base64_length_from_binary(len, simdutf::base64_url));
2772
+ std::vector<char> back(len);
2773
+ std::mt19937 gen((std::mt19937::result_type)(seed));
2774
+ std::uniform_int_distribution<int> byte_generator{0, 255};
2775
+ for (size_t trial = 0; trial < 10; trial++) {
2776
+ for (size_t i = 0; i < len; i++) {
2777
+ source[i] = byte_generator(gen);
2778
+ }
2779
+ size_t size = implementation.binary_to_base64(
2780
+ source.data(), source.size(), buffer.data(), simdutf::base64_url);
2781
+ buffer.resize(size);
2782
+ buffer16.resize(buffer.size());
2783
+ for (size_t i = 0; i < buffer.size(); i++) {
2784
+ buffer16[i] = buffer[i];
2785
+ }
2786
+ ASSERT_EQUAL(
2787
+ size, simdutf::base64_length_from_binary(len, simdutf::base64_url));
2788
+ simdutf::result r = implementation.base64_to_binary(
2789
+ buffer16.data(), size, back.data(), simdutf::base64_url);
2790
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2791
+ ASSERT_EQUAL(r.count, len);
2792
+ if (back != source) {
2793
+ printf("=====input size %zu\n", len);
2794
+ for (size_t i = 0; i < len; i++) {
2795
+ if (back[i] != source[i]) {
2796
+ printf("Mismatch at position %zu trial %zu\n", i, trial);
2797
+ }
2798
+ printf("%zu: %02x %02x\n", i, uint8_t(back[i]), uint8_t(source[i]));
2799
+ }
2800
+ printf("=====base64 size %zu\n", size);
2801
+ for (size_t i = 0; i < size; i++) {
2802
+ printf("%zu: %02x %c\n", i, uint8_t(buffer[i]), buffer[i]);
2803
+ }
2804
+ }
2805
+ ASSERT_TRUE(back == source);
2806
+ for (auto option :
2807
+ {simdutf::last_chunk_handling_options::strict,
2808
+ simdutf::last_chunk_handling_options::loose,
2809
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
2810
+ r = implementation.base64_to_binary(buffer.data(), size, back.data(),
2811
+ simdutf::base64_url, option);
2812
+ if ((size % 4) == 0) {
2813
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2814
+ ASSERT_EQUAL(r.count, len);
2815
+ ASSERT_TRUE(back == source);
2816
+ } else {
2817
+ if (option == simdutf::last_chunk_handling_options::strict) {
2818
+ ASSERT_EQUAL(r.error, simdutf::error_code::BASE64_INPUT_REMAINDER);
2819
+ } else if (option == simdutf::last_chunk_handling_options::loose) {
2820
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2821
+ ASSERT_EQUAL(r.count, len);
2822
+ ASSERT_TRUE(back == source);
2823
+ } else if (option == simdutf::last_chunk_handling_options::
2824
+ stop_before_partial) {
2825
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
2826
+ ASSERT_EQUAL(r.count, len / 3 * 3);
2827
+ ASSERT_TRUE(std::equal(back.begin(), back.begin() + len / 3 * 3,
2828
+ source.begin()));
2829
+ }
2830
+ }
2831
+ }
2832
+ }
2833
+ }
2834
+ }
2835
+ #endif
2836
+
2837
+ TEST(bad_padding_base64) {
2838
+ for (size_t len = 0; len < max_len; len++) {
2839
+ std::vector<char> source(len, 0);
2840
+ std::vector<char> buffer;
2841
+ buffer.resize(simdutf::base64_length_from_binary(len) + 1);
2842
+ std::mt19937 gen((std::mt19937::result_type)(seed));
2843
+ std::uniform_int_distribution<int> byte_generator{0, 255};
2844
+ for (size_t trial = 0; trial < 10; trial++) {
2845
+ for (size_t i = 0; i < len; i++) {
2846
+ source[i] = byte_generator(gen);
2847
+ }
2848
+ size_t size = implementation.binary_to_base64(
2849
+ source.data(), source.size(), buffer.data());
2850
+ size_t padding = 0;
2851
+ if (size > 0 && buffer[size - 1] == '=') {
2852
+ padding++;
2853
+ if (size > 1 && buffer[size - 2] == '=') {
2854
+ padding++;
2855
+ }
2856
+ }
2857
+ buffer.resize(size);
2858
+ ; // in case we need
2859
+ std::vector<char> back(simdutf::maximal_binary_length_from_base64(
2860
+ buffer.data(), buffer.size()));
2861
+ if (padding == 1) {
2862
+ // adding padding should break
2863
+ buffer.push_back('=');
2864
+ for (size_t i = 0; i < 5; i++) {
2865
+ add_space(buffer, gen);
2866
+ }
2867
+ simdutf::result r = simdutf::base64_to_binary(
2868
+ buffer.data(), buffer.size(), back.data());
2869
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
2870
+ } else if (padding == 2) {
2871
+ // adding padding should break
2872
+ {
2873
+ auto copy = buffer;
2874
+ copy.push_back('=');
2875
+ for (size_t i = 0; i < 5; i++) {
2876
+ add_space(copy, gen);
2877
+ }
2878
+ simdutf::result r =
2879
+ simdutf::base64_to_binary(copy.data(), copy.size(), back.data());
2880
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
2881
+ }
2882
+ // removing padding should break
2883
+ {
2884
+ auto copy = buffer;
2885
+ copy.resize(copy.size() - 1);
2886
+ for (size_t i = 0; i < 5; i++) {
2887
+ add_space(copy, gen);
2888
+ }
2889
+ simdutf::result r =
2890
+ simdutf::base64_to_binary(copy.data(), copy.size(), back.data());
2891
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
2892
+ }
2893
+
2894
+ } else {
2895
+ {
2896
+ auto copy = buffer;
2897
+ copy.push_back('=');
2898
+ for (size_t i = 0; i < 5; i++) {
2899
+ add_space(copy, gen);
2900
+ }
2901
+ simdutf::result r =
2902
+ simdutf::base64_to_binary(copy.data(), copy.size(), back.data());
2903
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
2904
+ }
2905
+ }
2906
+ }
2907
+ }
2908
+ }
2909
+ TEST(doomed_base64_roundtrip) {
2910
+ for (size_t len = 0; len < max_len; len++) {
2911
+ std::vector<char> source(len, 0);
2912
+ std::vector<char> buffer;
2913
+ buffer.resize(simdutf::base64_length_from_binary(len));
2914
+ std::mt19937 gen((std::mt19937::result_type)(seed));
2915
+ std::uniform_int_distribution<int> byte_generator{0, 255};
2916
+ for (size_t trial = 0; trial < 10; trial++) {
2917
+ for (size_t i = 0; i < len; i++) {
2918
+ source[i] = byte_generator(gen);
2919
+ }
2920
+ size_t size = implementation.binary_to_base64(
2921
+ source.data(), source.size(), buffer.data());
2922
+ buffer.resize(size);
2923
+ size_t location = add_garbage(buffer, gen, to_base64_value);
2924
+ std::vector<char> back(simdutf::maximal_binary_length_from_base64(
2925
+ buffer.data(), buffer.size()));
2926
+ simdutf::result r =
2927
+ simdutf::base64_to_binary(buffer.data(), buffer.size(), back.data());
2928
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
2929
+ ASSERT_EQUAL(r.count, location);
2930
+ for (auto option :
2931
+ {simdutf::last_chunk_handling_options::strict,
2932
+ simdutf::last_chunk_handling_options::loose,
2933
+ simdutf::last_chunk_handling_options::stop_before_partial}) {
2934
+ size_t back_length = back.size();
2935
+ r = simdutf::base64_to_binary_safe(buffer.data(), buffer.size(),
2936
+ back.data(), back_length,
2937
+ simdutf::base64_default, option);
2938
+ ASSERT_EQUAL(r.error, simdutf::error_code::INVALID_BASE64_CHARACTER);
2939
+ ASSERT_EQUAL(r.count, location);
2940
+ }
2941
+ }
2942
+ }
2943
+ }
2944
+
2945
+ TEST(doomed_truncated_base64_roundtrip) {
2946
+ for (size_t len = 1; len < max_len; len++) {
2947
+ std::vector<char> source(len, 0);
2948
+ std::vector<char> buffer;
2949
+ std::mt19937 gen((std::mt19937::result_type)(seed));
2950
+ std::uniform_int_distribution<int> byte_generator{0, 255};
2951
+ for (size_t trial = 0; trial < 10; trial++) {
2952
+ for (size_t i = 0; i < len; i++) {
2953
+ source[i] = byte_generator(gen);
2954
+ }
2955
+ buffer.resize(simdutf::base64_length_from_binary(len));
2956
+ size_t size = implementation.binary_to_base64(
2957
+ source.data(), source.size(), buffer.data());
2958
+ buffer.resize(size - 3);
2959
+ std::vector<char> back(simdutf::maximal_binary_length_from_base64(
2960
+ buffer.data(), buffer.size()));
2961
+ for (auto option : {simdutf::last_chunk_handling_options::loose,
2962
+ simdutf::last_chunk_handling_options::strict}) {
2963
+ simdutf::result r = implementation.base64_to_binary(
2964
+ buffer.data(), buffer.size(), back.data(), simdutf::base64_default,
2965
+ option);
2966
+ ASSERT_EQUAL(r.error, simdutf::error_code::BASE64_INPUT_REMAINDER);
2967
+ size_t back_length = back.size();
2968
+ r = simdutf::base64_to_binary_safe(buffer.data(), buffer.size(),
2969
+ back.data(), back_length);
2970
+ ASSERT_EQUAL(r.error, simdutf::error_code::BASE64_INPUT_REMAINDER);
2971
+ }
2972
+ }
2973
+ }
2974
+ }
2975
+
2976
+ TEST(doomed_truncated_base64_roundtrip_16) {
2977
+ for (size_t len = 1; len < max_len; len++) {
2978
+ std::vector<char> source(len, 0);
2979
+ std::vector<char> buffer;
2980
+ std::vector<char16_t> buffer16;
2981
+ std::mt19937 gen((std::mt19937::result_type)(seed));
2982
+ std::uniform_int_distribution<int> byte_generator{0, 255};
2983
+ for (size_t trial = 0; trial < 10; trial++) {
2984
+ for (size_t i = 0; i < len; i++) {
2985
+ source[i] = byte_generator(gen);
2986
+ }
2987
+ buffer.resize(simdutf::base64_length_from_binary(len));
2988
+ size_t size = implementation.binary_to_base64(
2989
+ source.data(), source.size(), buffer.data());
2990
+ buffer.resize(size - 3);
2991
+ buffer16.resize(buffer.size());
2992
+ for (size_t i = 0; i < buffer.size(); i++) {
2993
+ buffer16[i] = buffer[i];
2994
+ }
2995
+ std::vector<char> back(implementation.maximal_binary_length_from_base64(
2996
+ buffer16.data(), buffer16.size()));
2997
+ simdutf::result r = implementation.base64_to_binary(
2998
+ buffer16.data(), buffer16.size(), back.data());
2999
+ ASSERT_EQUAL(r.error, simdutf::error_code::BASE64_INPUT_REMAINDER);
3000
+ size_t back_length = back.size();
3001
+ r = simdutf::base64_to_binary_safe(buffer16.data(), buffer16.size(),
3002
+ back.data(), back_length);
3003
+ ASSERT_EQUAL(r.error, simdutf::error_code::BASE64_INPUT_REMAINDER);
3004
+ }
3005
+ }
3006
+ }
3007
+
3008
+ TEST(roundtrip_base64_16_with_spaces) {
3009
+ for (size_t len = 0; len < max_len; len++) {
3010
+ std::vector<char> source(len, 0);
3011
+ std::vector<char> buffer;
3012
+ std::vector<char16_t> buffer16;
3013
+
3014
+ buffer.resize(simdutf::base64_length_from_binary(len));
3015
+ std::vector<char> back(len);
3016
+ std::mt19937 gen((std::mt19937::result_type)(seed));
3017
+ std::uniform_int_distribution<int> byte_generator{0, 255};
3018
+ for (size_t trial = 0; trial < 10; trial++) {
3019
+ for (size_t i = 0; i < len; i++) {
3020
+ source[i] = byte_generator(gen);
3021
+ }
3022
+ size_t size = implementation.binary_to_base64(
3023
+ source.data(), source.size(), buffer.data());
3024
+ buffer.resize(size);
3025
+ for (size_t i = 0; i < 5; i++) {
3026
+ add_space(buffer, gen);
3027
+ }
3028
+ buffer16.resize(buffer.size());
3029
+ for (size_t i = 0; i < buffer.size(); i++) {
3030
+ buffer16[i] = buffer[i];
3031
+ }
3032
+ ASSERT_EQUAL(size, simdutf::base64_length_from_binary(len));
3033
+ simdutf::result r = implementation.base64_to_binary(
3034
+ buffer16.data(), buffer16.size(), back.data());
3035
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
3036
+ ASSERT_EQUAL(r.count, len);
3037
+ if (back != source) {
3038
+ printf("=====input size %zu\n", len);
3039
+ for (size_t i = 0; i < len; i++) {
3040
+ if (back[i] != source[i]) {
3041
+ printf("Mismatch at position %zu trial %zu\n", i, trial);
3042
+ }
3043
+ printf("%zu: %02x %02x\n", i, uint8_t(back[i]), uint8_t(source[i]));
3044
+ }
3045
+ printf("=====base64 size %zu\n", size);
3046
+ for (size_t i = 0; i < size; i++) {
3047
+ printf("%zu: %02x %c\n", i, uint8_t(buffer[i]), buffer[i]);
3048
+ }
3049
+ }
3050
+ ASSERT_TRUE(back == source);
3051
+ }
3052
+ }
3053
+ }
3054
+
3055
+ TEST(roundtrip_base64_16_with_garbage) {
3056
+ for (size_t len = 0; len < max_len; len++) {
3057
+ std::vector<char> source(len, 0);
3058
+ std::vector<char> buffer;
3059
+ std::vector<char16_t> buffer16;
3060
+
3061
+ buffer.resize(simdutf::base64_length_from_binary(len));
3062
+ std::vector<char> back(len);
3063
+ std::mt19937 gen((std::mt19937::result_type)(seed));
3064
+ std::uniform_int_distribution<int> byte_generator{0, 255};
3065
+ for (size_t trial = 0; trial < 10; trial++) {
3066
+ for (size_t i = 0; i < len; i++) {
3067
+ source[i] = byte_generator(gen);
3068
+ }
3069
+ size_t size = implementation.binary_to_base64(
3070
+ source.data(), source.size(), buffer.data());
3071
+ buffer.resize(size);
3072
+ for (size_t i = 0; i < 5; i++) {
3073
+ add_garbage(buffer, gen, to_base64_value);
3074
+ }
3075
+ buffer16.resize(buffer.size());
3076
+ for (size_t i = 0; i < buffer.size(); i++) {
3077
+ buffer16[i] = buffer[i];
3078
+ }
3079
+ ASSERT_EQUAL(size, simdutf::base64_length_from_binary(len));
3080
+ simdutf::result r = implementation.base64_to_binary(
3081
+ buffer16.data(), buffer16.size(), back.data(),
3082
+ simdutf::base64_default_accept_garbage);
3083
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
3084
+ ASSERT_EQUAL(r.count, len);
3085
+ if (back != source) {
3086
+ printf("=====input size %zu\n", len);
3087
+ for (size_t i = 0; i < len; i++) {
3088
+ if (back[i] != source[i]) {
3089
+ printf("Mismatch at position %zu trial %zu\n", i, trial);
3090
+ }
3091
+ printf("%zu: %02x %02x\n", i, uint8_t(back[i]), uint8_t(source[i]));
3092
+ }
3093
+ printf("=====base64 size %zu\n", size);
3094
+ for (size_t i = 0; i < size; i++) {
3095
+ printf("%zu: %02x %c\n", i, uint8_t(buffer[i]), buffer[i]);
3096
+ }
3097
+ }
3098
+ ASSERT_TRUE(back == source);
3099
+ }
3100
+ }
3101
+ }
3102
+
3103
+ TEST(roundtrip_base64_url_16_with_garbage) {
3104
+ for (size_t len = 0; len < max_len; len++) {
3105
+ std::vector<char> source(len, 0);
3106
+ std::vector<char> buffer;
3107
+ std::vector<char16_t> buffer16;
3108
+
3109
+ buffer.resize(simdutf::base64_length_from_binary(len));
3110
+ std::vector<char> back(len);
3111
+ std::mt19937 gen((std::mt19937::result_type)(seed));
3112
+ std::uniform_int_distribution<int> byte_generator{0, 255};
3113
+ for (size_t trial = 0; trial < 10; trial++) {
3114
+ for (size_t i = 0; i < len; i++) {
3115
+ source[i] = byte_generator(gen);
3116
+ }
3117
+ size_t size = implementation.binary_to_base64(
3118
+ source.data(), source.size(), buffer.data(), simdutf::base64_url);
3119
+ buffer.resize(size);
3120
+ for (size_t i = 0; i < 5; i++) {
3121
+ add_garbage(buffer, gen, to_base64url_value);
3122
+ }
3123
+ buffer16.resize(buffer.size());
3124
+ for (size_t i = 0; i < buffer.size(); i++) {
3125
+ buffer16[i] = buffer[i];
3126
+ }
3127
+ ASSERT_EQUAL(
3128
+ size, simdutf::base64_length_from_binary(len, simdutf::base64_url));
3129
+ simdutf::result r = implementation.base64_to_binary(
3130
+ buffer16.data(), buffer16.size(), back.data(),
3131
+ simdutf::base64_url_accept_garbage);
3132
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
3133
+ ASSERT_EQUAL(r.count, len);
3134
+ if (back != source) {
3135
+ printf("=====input size %zu\n", len);
3136
+ for (size_t i = 0; i < len; i++) {
3137
+ if (back[i] != source[i]) {
3138
+ printf("Mismatch at position %zu trial %zu\n", i, trial);
3139
+ }
3140
+ printf("%zu: %02x %02x\n", i, uint8_t(back[i]), uint8_t(source[i]));
3141
+ }
3142
+ printf("=====base64 size %zu\n", size);
3143
+ for (size_t i = 0; i < size; i++) {
3144
+ printf("%zu: %02x %c\n", i, uint8_t(buffer[i]), buffer[i]);
3145
+ }
3146
+ }
3147
+ ASSERT_TRUE(back == source);
3148
+ }
3149
+ }
3150
+ }
3151
+
3152
+ TEST(aborted_safe_roundtrip_base64) {
3153
+ for (size_t offset = 1; offset <= 16; offset += 3) {
3154
+ for (size_t len = offset; len < (max_len / 2); len++) {
3155
+ std::vector<char> source(len, 0);
3156
+ std::vector<char> buffer;
3157
+ buffer.resize(simdutf::base64_length_from_binary(len));
3158
+ std::mt19937 gen((std::mt19937::result_type)(seed));
3159
+ std::uniform_int_distribution<int> byte_generator{0, 255};
3160
+ for (size_t trial = 0; trial < 10; trial++) {
3161
+ for (size_t i = 0; i < len; i++) {
3162
+ source[i] = byte_generator(gen);
3163
+ }
3164
+ size_t size = implementation.binary_to_base64(
3165
+ source.data(), source.size(), buffer.data());
3166
+ buffer.resize(size);
3167
+ std::vector<char> back(simdutf::maximal_binary_length_from_base64(
3168
+ buffer.data(), buffer.size()));
3169
+ size_t limited_length = len - offset; // intentionally too little
3170
+ back.resize(limited_length);
3171
+ back.shrink_to_fit();
3172
+ simdutf::result r = simdutf::base64_to_binary_safe(
3173
+ buffer.data(), buffer.size(), back.data(), limited_length);
3174
+ ASSERT_EQUAL(r.error, simdutf::error_code::OUTPUT_BUFFER_TOO_SMALL);
3175
+ for (size_t i = 0; i < limited_length; i++) {
3176
+ ASSERT_EQUAL(source[i], back[i]);
3177
+ }
3178
+ // Now let us decode the rest !!!
3179
+ size_t input_index = r.count;
3180
+ back.resize(simdutf::maximal_binary_length_from_base64(
3181
+ buffer.data() + input_index, buffer.size() - input_index));
3182
+ size_t second_length = back.size();
3183
+ r = simdutf::base64_to_binary_safe(buffer.data() + input_index,
3184
+ buffer.size() - input_index,
3185
+ back.data(), second_length);
3186
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
3187
+ back.resize(second_length);
3188
+ ASSERT_EQUAL(second_length + limited_length, len);
3189
+
3190
+ for (size_t i = 0; i < second_length; i++) {
3191
+ ASSERT_EQUAL(source[i + limited_length], back[i]);
3192
+ }
3193
+ }
3194
+ }
3195
+ }
3196
+ }
3197
+
3198
+ TEST(aborted_safe_roundtrip_base64_16) {
3199
+ for (size_t offset = 1; offset <= 16; offset += 3) {
3200
+ for (size_t len = offset; len < (max_len / 2); len++) {
3201
+ std::vector<char> source(len, 0);
3202
+ std::vector<char> buffer;
3203
+ std::vector<char16_t> buffer16;
3204
+
3205
+ buffer.resize(simdutf::base64_length_from_binary(len));
3206
+ std::vector<char> back(len);
3207
+ std::mt19937 gen((std::mt19937::result_type)(seed));
3208
+ std::uniform_int_distribution<int> byte_generator{0, 255};
3209
+ for (size_t trial = 0; trial < 10; trial++) {
3210
+ for (size_t i = 0; i < len; i++) {
3211
+ source[i] = byte_generator(gen);
3212
+ }
3213
+ size_t size = implementation.binary_to_base64(
3214
+ source.data(), source.size(), buffer.data());
3215
+ buffer.resize(size);
3216
+ buffer16.resize(buffer.size());
3217
+ for (size_t i = 0; i < buffer.size(); i++) {
3218
+ buffer16[i] = buffer[i];
3219
+ }
3220
+ ASSERT_EQUAL(size, simdutf::base64_length_from_binary(len));
3221
+ size_t limited_length = len - offset; // intentionally too little
3222
+ back.resize(limited_length);
3223
+ back.shrink_to_fit();
3224
+ simdutf::result r = simdutf::base64_to_binary_safe(
3225
+ buffer.data(), buffer.size(), back.data(), limited_length);
3226
+ ASSERT_EQUAL(r.error, simdutf::error_code::OUTPUT_BUFFER_TOO_SMALL);
3227
+ for (size_t i = 0; i < limited_length; i++) {
3228
+ ASSERT_EQUAL(source[i], back[i]);
3229
+ }
3230
+ // Now let us decode the rest !!!
3231
+ size_t input_index = r.count;
3232
+ back.resize(simdutf::maximal_binary_length_from_base64(
3233
+ buffer.data() + input_index, buffer.size() - input_index));
3234
+ size_t second_length = back.size();
3235
+ r = simdutf::base64_to_binary_safe(buffer.data() + input_index,
3236
+ buffer.size() - input_index,
3237
+ back.data(), second_length);
3238
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
3239
+ back.resize(second_length);
3240
+ ASSERT_EQUAL(second_length + limited_length, len);
3241
+ for (size_t i = 0; i < second_length; i++) {
3242
+ ASSERT_EQUAL(source[i + limited_length], back[i]);
3243
+ }
3244
+ }
3245
+ }
3246
+ }
3247
+ }
3248
+
3249
+ TEST(aborted_safe_roundtrip_base64_with_spaces) {
3250
+ for (size_t offset = 1; offset <= 16; offset += 3) {
3251
+ for (size_t len = offset; len < (max_len / 2); len++) {
3252
+ std::vector<char> source(len, 0);
3253
+ std::vector<char> buffer;
3254
+ buffer.resize(simdutf::base64_length_from_binary(len));
3255
+ std::mt19937 gen((std::mt19937::result_type)(seed));
3256
+ std::uniform_int_distribution<int> byte_generator{0, 255};
3257
+ for (size_t trial = 0; trial < 10; trial++) {
3258
+ for (size_t i = 0; i < len; i++) {
3259
+ source[i] = byte_generator(gen);
3260
+ }
3261
+ size_t size = implementation.binary_to_base64(
3262
+ source.data(), source.size(), buffer.data());
3263
+ buffer.resize(size);
3264
+ for (size_t i = 0; i < 5; i++) {
3265
+ add_space(buffer, gen);
3266
+ }
3267
+ std::vector<char> back(simdutf::maximal_binary_length_from_base64(
3268
+ buffer.data(), buffer.size()));
3269
+ size_t limited_length = len - offset; // intentionally too little
3270
+ back.resize(limited_length);
3271
+ back.shrink_to_fit();
3272
+ simdutf::result r = simdutf::base64_to_binary_safe(
3273
+ buffer.data(), buffer.size(), back.data(), limited_length);
3274
+ ASSERT_EQUAL(r.error, simdutf::error_code::OUTPUT_BUFFER_TOO_SMALL);
3275
+ for (size_t i = 0; i < limited_length; i++) {
3276
+ ASSERT_EQUAL(source[i], back[i]);
3277
+ }
3278
+ // Now let us decode the rest !!!
3279
+ size_t input_index = r.count;
3280
+ back.resize(simdutf::maximal_binary_length_from_base64(
3281
+ buffer.data() + input_index, buffer.size() - input_index));
3282
+ size_t second_length = back.size();
3283
+ r = simdutf::base64_to_binary_safe(buffer.data() + input_index,
3284
+ buffer.size() - input_index,
3285
+ back.data(), second_length);
3286
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
3287
+ back.resize(second_length);
3288
+ ASSERT_EQUAL(second_length + limited_length, len);
3289
+ for (size_t i = 0; i < second_length; i++) {
3290
+ ASSERT_EQUAL(source[i + limited_length], back[i]);
3291
+ }
3292
+ }
3293
+ }
3294
+ }
3295
+ }
3296
+
3297
+ TEST(aborted_safe_roundtrip_base64_16_with_spaces) {
3298
+ for (size_t offset = 1; offset <= 16; offset += 3) {
3299
+ for (size_t len = offset; len < (max_len / 2); len++) {
3300
+ std::vector<char> source(len, 0);
3301
+ std::vector<char> buffer;
3302
+ std::vector<char16_t> buffer16;
3303
+
3304
+ buffer.resize(simdutf::base64_length_from_binary(len));
3305
+ std::vector<char> back(len);
3306
+ std::mt19937 gen((std::mt19937::result_type)(seed));
3307
+ std::uniform_int_distribution<int> byte_generator{0, 255};
3308
+ for (size_t trial = 0; trial < 10; trial++) {
3309
+ for (size_t i = 0; i < len; i++) {
3310
+ source[i] = byte_generator(gen);
3311
+ }
3312
+ size_t size = implementation.binary_to_base64(
3313
+ source.data(), source.size(), buffer.data());
3314
+ buffer.resize(size);
3315
+ for (size_t i = 0; i < 5; i++) {
3316
+ add_space(buffer, gen);
3317
+ }
3318
+ buffer16.resize(buffer.size());
3319
+ for (size_t i = 0; i < buffer.size(); i++) {
3320
+ buffer16[i] = buffer[i];
3321
+ }
3322
+ ASSERT_EQUAL(size, simdutf::base64_length_from_binary(len));
3323
+ size_t limited_length = len - offset; // intentionally too little
3324
+ back.resize(limited_length);
3325
+ back.shrink_to_fit();
3326
+ simdutf::result r = simdutf::base64_to_binary_safe(
3327
+ buffer.data(), buffer.size(), back.data(), limited_length);
3328
+ ASSERT_EQUAL(r.error, simdutf::error_code::OUTPUT_BUFFER_TOO_SMALL);
3329
+ for (size_t i = 0; i < limited_length; i++) {
3330
+ ASSERT_EQUAL(source[i], back[i]);
3331
+ }
3332
+ // Now let us decode the rest !!!
3333
+ size_t input_index = r.count;
3334
+ back.resize(simdutf::maximal_binary_length_from_base64(
3335
+ buffer.data() + input_index, buffer.size() - input_index));
3336
+ size_t second_length = back.size();
3337
+ r = simdutf::base64_to_binary_safe(buffer.data() + input_index,
3338
+ buffer.size() - input_index,
3339
+ back.data(), second_length);
3340
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
3341
+ back.resize(second_length);
3342
+ ASSERT_EQUAL(second_length + limited_length, len);
3343
+ for (size_t i = 0; i < second_length; i++) {
3344
+ ASSERT_EQUAL(source[i + limited_length], back[i]);
3345
+ }
3346
+ }
3347
+ }
3348
+ }
3349
+ }
3350
+
3351
+ TEST(streaming_base64_roundtrip) {
3352
+ size_t len = 2048;
3353
+ std::vector<char> source(len, 0);
3354
+ std::vector<char> buffer;
3355
+ buffer.resize(simdutf::base64_length_from_binary(len));
3356
+ std::mt19937 gen((std::mt19937::result_type)(seed));
3357
+ std::uniform_int_distribution<int> byte_generator{0, 255};
3358
+ for (size_t i = 0; i < len; i++) {
3359
+ source[i] = byte_generator(gen);
3360
+ }
3361
+ size_t size = implementation.binary_to_base64(source.data(), source.size(),
3362
+ buffer.data());
3363
+ for (size_t window = 16; window <= 2048; window += 7) {
3364
+ buffer.resize(size);
3365
+ // build a buffer with enough space to receive the decoded base64
3366
+ std::vector<char> back(len);
3367
+ size_t outpos = 0;
3368
+ size_t pos = 0;
3369
+ for (; pos < buffer.size();) {
3370
+ size_t count = std::min(window, buffer.size() - pos);
3371
+
3372
+ simdutf::full_result r = implementation.base64_to_binary_details(
3373
+ buffer.data() + pos, count, back.data() + outpos,
3374
+ simdutf::base64_default,
3375
+ simdutf::last_chunk_handling_options::only_full_chunks);
3376
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
3377
+ ASSERT_TRUE(r.input_count <= count);
3378
+ ASSERT_TRUE(r.output_count <= back.size() - outpos);
3379
+ ASSERT_TRUE(r.output_count % 3 == 0);
3380
+ ASSERT_TRUE(r.input_count % 4 == 0);
3381
+
3382
+ outpos += r.output_count;
3383
+ pos += r.input_count;
3384
+ if (r.input_count == 0) {
3385
+ break; // no more input
3386
+ }
3387
+ }
3388
+ if (pos < buffer.size()) {
3389
+ // we have a remainder
3390
+
3391
+ simdutf::full_result r = implementation.base64_to_binary_details(
3392
+ buffer.data() + pos, buffer.size() - pos, back.data() + outpos,
3393
+ simdutf::base64_default,
3394
+ simdutf::last_chunk_handling_options::strict);
3395
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
3396
+ outpos += r.output_count;
3397
+ pos += r.input_count;
3398
+ }
3399
+ back.resize(outpos);
3400
+ ASSERT_TRUE(back == source);
3401
+ }
3402
+ }
3403
+
3404
+ TEST(readme_test) {
3405
+ size_t len = 2048;
3406
+ std::vector<char> base64(len, 'a');
3407
+ std::vector<char> back((len + 3) / 4 * 3);
3408
+ size_t outpos = 0;
3409
+ size_t window = 512;
3410
+ for (size_t pos = 0; pos < base64.size(); pos += window) {
3411
+ // how many base64 characters we can process in this iteration
3412
+ size_t count = std::min(window, base64.size() - pos);
3413
+ simdutf::result r = simdutf::base64_to_binary(base64.data() + pos, count,
3414
+ back.data() + outpos);
3415
+ if (r.error == simdutf::error_code::INVALID_BASE64_CHARACTER) {
3416
+ printf("Invalid base64 character at position %zu\n", pos + r.count);
3417
+ return;
3418
+ }
3419
+ // If we arrived at the end of the base64 input, we must check that the
3420
+ // number of characters processed is a multiple of 4, or that we have a
3421
+ // remainder of 0, 2 or 3.
3422
+ if (count + pos == base64.size() &&
3423
+ r.error == simdutf::error_code::BASE64_INPUT_REMAINDER) {
3424
+ puts("The base64 input contained an invalid number of characters");
3425
+ }
3426
+ // If we are not at then end, we may have to reprocess either 1, 2 or 3
3427
+ // bytes, and to drop the last 0, 2 or 3 bytes decoded.
3428
+ size_t tail_bytes_to_reprocess = 0;
3429
+ if (r.error == simdutf::error_code::BASE64_INPUT_REMAINDER) {
3430
+ tail_bytes_to_reprocess = 1;
3431
+ } else {
3432
+ tail_bytes_to_reprocess = (r.count % 3) == 0 ? 0 : (r.count % 3) + 1;
3433
+ }
3434
+ pos -= tail_bytes_to_reprocess;
3435
+ r.count -= (r.count % 3);
3436
+ outpos += r.count;
3437
+ }
3438
+ // At then end, we resize the buffer to the actual number of bytes decoded.
3439
+ back.resize(outpos);
3440
+ }
3441
+
3442
+ TEST(readme_safe) {
3443
+ size_t len = 72;
3444
+ std::vector<char> base64(len, 'a');
3445
+ std::vector<char> back((len + 3) / 4 * 3);
3446
+ size_t limited_length = back.size() / 2; // Intentionally too small
3447
+ simdutf::result r = simdutf::base64_to_binary_safe(
3448
+ base64.data(), base64.size(), back.data(), limited_length);
3449
+ ASSERT_EQUAL(r.error, simdutf::error_code::OUTPUT_BUFFER_TOO_SMALL);
3450
+
3451
+ // We decoded 'limited_length' bytes to back.
3452
+ // Now let us decode the rest !!!
3453
+ size_t input_index = r.count;
3454
+ size_t limited_length2 = back.size();
3455
+ r = simdutf::base64_to_binary_safe(base64.data() + input_index,
3456
+ base64.size() - input_index, back.data(),
3457
+ limited_length2);
3458
+ ASSERT_EQUAL(r.error, simdutf::error_code::SUCCESS);
3459
+ back.resize(limited_length2);
3460
+ ASSERT_EQUAL(limited_length2 + limited_length, (len + 3) / 4 * 3);
3461
+ }
3462
+
3463
+ #if SIMDUTF_SPAN
3464
+ TEST(base64_to_binary_safe_span_api_char) {
3465
+ const std::string input{"QWJyYWNhZGFicmEh"};
3466
+ const std::string expected_output{"Abracadabra!"};
3467
+ std::string output(expected_output.size() + 4, '\0');
3468
+ const auto [ret, outlen] = simdutf::base64_to_binary_safe(input, output);
3469
+ ASSERT_EQUAL(ret.error, simdutf::SUCCESS);
3470
+ ASSERT_EQUAL(ret.count, 16); // amount of consumed input
3471
+ ASSERT_EQUAL(outlen, 12); // how much was written to output
3472
+ }
3473
+
3474
+ TEST(base64_to_binary_safe_span_api_char16) {
3475
+ const std::u16string input{u"QWJyYWNhZGFicmEh"};
3476
+ const std::string expected_output{"Abracadabra!"};
3477
+ std::string output(expected_output.size() + 4, '\0');
3478
+ const auto [ret, outlen] = simdutf::base64_to_binary_safe(input, output);
3479
+ ASSERT_EQUAL(ret.error, simdutf::SUCCESS);
3480
+ ASSERT_EQUAL(ret.count, 16); // amount of consumed input
3481
+ ASSERT_EQUAL(outlen, 12); // how much was written to output
3482
+ }
3483
+
3484
+ TEST(binary_to_base64_with_lines_span_api_char) {
3485
+ const std::string input{"Abracadabra!"};
3486
+ const std::string expected_output{"QWJyY\nWNhZG\nFicmE\nh"};
3487
+ std::string output(expected_output.size() + 4, '\0');
3488
+ const auto outlen = simdutf::binary_to_base64_with_lines(input, output, 5);
3489
+ ASSERT_EQUAL(outlen,
3490
+ expected_output.size()); // how much was written to output
3491
+ output.resize(outlen);
3492
+ ASSERT_EQUAL(expected_output, output);
3493
+ }
3494
+
3495
+ #endif
3496
+
3497
+ // Tests for binary_length_from_base64
3498
+ TEST(binary_length_from_base64_basic) {
3499
+ // Test basic strings without spaces
3500
+ // "YQ==" decodes to "a" (1 byte)
3501
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("YQ==", 4), 1);
3502
+ // "YWI=" decodes to "ab" (2 bytes)
3503
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("YWI=", 4), 2);
3504
+ // "YWJj" decodes to "abc" (3 bytes)
3505
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("YWJj", 4), 3);
3506
+ // "YWJjZA==" decodes to "abcd" (4 bytes)
3507
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("YWJjZA==", 8), 4);
3508
+ // Empty string
3509
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("", 0), 0);
3510
+ }
3511
+
3512
+ TEST(binary_length_from_base64_with_spaces) {
3513
+ // Test strings with spaces - binary_length_from_base64 should return exact
3514
+ // length "Y Q = =" with spaces, should decode to "a" (1 byte)
3515
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("Y Q = =", 7), 1);
3516
+ // " Y Q = = " with lots of spaces
3517
+ ASSERT_EQUAL(simdutf::binary_length_from_base64(" Y Q = = ", 14), 1);
3518
+ // " A A " should decode to 1 byte (2 base64 chars = 1 byte)
3519
+ ASSERT_EQUAL(simdutf::binary_length_from_base64(" A A ", 8), 1);
3520
+ // " A A G A / v 8 " should decode to 5 bytes (7 base64 chars)
3521
+ ASSERT_EQUAL(
3522
+ simdutf::binary_length_from_base64(" A A G A / v 8 ", 23), 5);
3523
+ }
3524
+
3525
+ TEST(binary_length_from_base64_matches_decode_result) {
3526
+ // Verify that binary_length_from_base64 matches the actual decode result
3527
+ std::vector<std::string> test_inputs = {
3528
+ "YQ==",
3529
+ "YWI=",
3530
+ "YWJj",
3531
+ "YWJjZA==",
3532
+ " Y Q = = ",
3533
+ " A A ",
3534
+ " A A G A / v 8 ",
3535
+ "SGVsbG8gV29ybGQh", // "Hello World!"
3536
+ "SGVs bG8g V29y bGQh",
3537
+ "dGVzdA==", // "test"
3538
+ "dGVzdA", // "test" without padding
3539
+ "dGVzdGluZw==" // "testing"
3540
+ };
3541
+
3542
+ for (const auto &input : test_inputs) {
3543
+ size_t exact_len =
3544
+ simdutf::binary_length_from_base64(input.data(), input.size());
3545
+ size_t max_len =
3546
+ simdutf::maximal_binary_length_from_base64(input.data(), input.size());
3547
+ // exact length should be <= maximal length
3548
+ ASSERT_TRUE(exact_len <= max_len);
3549
+
3550
+ // Now decode and verify the exact length matches
3551
+ std::vector<char> buffer(max_len);
3552
+ auto result =
3553
+ simdutf::base64_to_binary(input.data(), input.size(), buffer.data());
3554
+ if (result.error == simdutf::error_code::SUCCESS) {
3555
+ ASSERT_EQUAL(exact_len, result.count);
3556
+ }
3557
+ }
3558
+ }
3559
+
3560
+ TEST(binary_length_from_base64_char16) {
3561
+ // Test with char16_t input
3562
+ std::u16string input16 = u"YWJj"; // "abc"
3563
+ ASSERT_EQUAL(
3564
+ simdutf::binary_length_from_base64(input16.data(), input16.size()), 3);
3565
+
3566
+ std::u16string input16_spaces = u" Y Q = = ";
3567
+ ASSERT_EQUAL(simdutf::binary_length_from_base64(input16_spaces.data(),
3568
+ input16_spaces.size()),
3569
+ 1);
3570
+ }
3571
+
3572
+ TEST(binary_length_from_base64_url_variant) {
3573
+ // Test with URL-safe base64 input
3574
+ // The function counts non-whitespace characters regardless of variant
3575
+ std::string url_input = "YWJj"; // Same as standard for this input
3576
+ ASSERT_EQUAL(
3577
+ simdutf::binary_length_from_base64(url_input.data(), url_input.size()),
3578
+ 3);
3579
+
3580
+ // Test with actual URL-safe characters
3581
+ // "abc?" in URL-safe base64 is "YWJjPw" (no special chars needed here)
3582
+ std::string url_input2 = "YWJjPw";
3583
+ ASSERT_EQUAL(
3584
+ simdutf::binary_length_from_base64(url_input2.data(), url_input2.size()),
3585
+ 4);
3586
+ }
3587
+
3588
+ TEST(binary_length_from_base64_various_remainders) {
3589
+ // Test various remainder cases
3590
+ // 0 base64 chars = 0 bytes
3591
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("", 0), 0);
3592
+ // 1 base64 char (invalid, but function still computes) = 0 bytes
3593
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("A", 1), 0);
3594
+ // 2 base64 chars = 1 byte
3595
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("AA", 2), 1);
3596
+ // 3 base64 chars = 2 bytes
3597
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("AAA", 3), 2);
3598
+ // 4 base64 chars = 3 bytes
3599
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("AAAA", 4), 3);
3600
+ // 5 base64 chars = 3 bytes (remainder 1 contributes 0)
3601
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("AAAAA", 5), 3);
3602
+ // 6 base64 chars = 4 bytes
3603
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("AAAAAA", 6), 4);
3604
+ // 7 base64 chars = 5 bytes
3605
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("AAAAAAA", 7), 5);
3606
+ // 8 base64 chars = 6 bytes
3607
+ ASSERT_EQUAL(simdutf::binary_length_from_base64("AAAAAAAA", 8), 6);
3608
+ }
3609
+
3610
+ int main(int argc, char *argv[]) {
3611
+ const auto cmdline = simdutf::test::CommandLine::parse(argc, argv);
3612
+ seed = cmdline.seed;
3613
+
3614
+ simdutf::test::run(cmdline);
3615
+
3616
+ return 0;
3617
+ }