├── .github └── workflows │ ├── bigendiancmake.yml │ ├── cmake.yml │ └── cpplint.yml ├── .gitignore ├── CMakeLists.txt ├── CPPLINT.cfg ├── LICENSE ├── README.md ├── include └── base64.hpp ├── scripts ├── run-clang-format.sh └── run-s390x-emulation.sh └── test ├── base64_tests.cpp ├── modp_b64_tests.cpp └── roundtrip_test.cpp /.github/workflows/bigendiancmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake on s390x emulation (Big endian system) 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 7 | BUILD_TYPE: RelWithDebInfo 8 | 9 | jobs: 10 | build-linux-s390x: 11 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v3 16 | 17 | - uses: uraimo/run-on-arch-action@v2 18 | name: Run commands 19 | id: runcmd 20 | with: 21 | arch: s390x 22 | distro: ubuntu_latest 23 | install: | 24 | apt-get update -q -y 25 | apt-get -y install cmake 26 | apt-get -y install make 27 | apt-get -y install g++ 28 | apt-get -y install git 29 | run: | 30 | lscpu | grep Endian 31 | cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} . 32 | cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} 33 | cd ${{github.workspace}}/build 34 | ctest -C ${{env.BUILD_TYPE}} --output-on-failure -------------------------------------------------------------------------------- /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake 2 | 3 | on: [push, pull_request] 4 | 5 | env: 6 | # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) 7 | BUILD_TYPE: RelWithDebInfo 8 | 9 | jobs: 10 | build: 11 | # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. 12 | strategy: 13 | matrix: 14 | os: [ubuntu-latest, windows-latest, macos-latest] 15 | 16 | runs-on: ${{ matrix.os }} 17 | 18 | steps: 19 | - uses: actions/checkout@v3 20 | 21 | - name: Install optional tools (clang-tidy) 22 | if: matrix.os == 'ubuntu-latest' 23 | run: sudo apt-get install -y clang-tidy 24 | 25 | - name: Configure CMake (Windows) 26 | if: runner.os == 'Windows' 27 | # Configure CMake in a 'build' subdirectory. 28 | # `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 29 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 30 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} . 31 | 32 | - name: Configure CMake (Other OS) 33 | if: runner.os != 'Windows' 34 | # Configure CMake in a 'build' subdirectory. 35 | # `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. 36 | # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type 37 | run: cmake -B ${{github.workspace}}/build -USE_ASAN=ON -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} . 38 | 39 | - name: Build 40 | # Build your program with the given configuration 41 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} 42 | 43 | - name: Test 44 | working-directory: ${{github.workspace}}/build 45 | # Execute tests defined by the CMake configuration. 46 | # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail 47 | run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure 48 | 49 | -------------------------------------------------------------------------------- /.github/workflows/cpplint.yml: -------------------------------------------------------------------------------- 1 | # GitHub Action to run cpplint recursively on all pushes and pull requests 2 | # https://github.com/cpplint/GitHub-Action-for-cpplint 3 | 4 | name: cpplint 5 | on: [push, pull_request] 6 | jobs: 7 | cpplint: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v3 11 | - uses: actions/setup-python@v4 12 | with: 13 | python-version: 3.x 14 | - run: pip install cpplint 15 | - run: cpplint --root=include --recursive . 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | main.cpp 2 | build 3 | *.user 4 | *.swp 5 | scripts/build.sh 6 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16) 2 | project(base64) 3 | 4 | option(BASE64_ENABLE_TESTING "Build test files." ON) 5 | 6 | set(CMAKE_CXX_STANDARD 17) 7 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 8 | 9 | if(NOT CMAKE_BUILD_TYPE) 10 | set(CMAKE_BUILD_TYPE RelWithDebInfo) 11 | endif() 12 | 13 | # Warnings compiler flags 14 | if(MSVC) 15 | add_compile_options(/W4) 16 | else() 17 | add_compile_options(-Wall -Wextra -Wpedantic) 18 | endif() 19 | 20 | # Optionally enable clang-tidy 21 | find_program(CLANG_TIDY_EXE NAMES clang-tidy PATHS /opt/homebrew/opt/llvm/bin/) 22 | if(NOT CLANG_TIDY_EXE) 23 | message(STATUS "clang-tidy not found. Skipping corresponding checks.") 24 | else() 25 | set(CMAKE_CXX_CLANG_TIDY 26 | ${CLANG_TIDY_EXE}; 27 | -header-filter=.*; 28 | -checks=-*,portability-*,bugprone-*,-bugprone-easily-swappable-parameters,-bugprone-sizeof-expression,clang-analyzer-*; 29 | ) 30 | message(STATUS "Found clang-tidy: ${CLANG_TIDY_EXE}.") 31 | endif() 32 | 33 | # Simplify the use of ASan 34 | option(USE_ASAN "Activate ASan compiler/linker options" OFF) 35 | if(USE_ASAN) 36 | if(MSVC) 37 | add_compile_options(/fsanitize=address) 38 | add_link_options(/fsanitize=address) 39 | set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$,$>,$<$:EditAndContinue>,$<$:ProgramDatabase>>") 40 | else() 41 | add_compile_options(-fsanitize=address -fno-omit-frame-pointer) 42 | add_link_options(-fsanitize=address) 43 | endif() 44 | endif() 45 | 46 | add_library(base64 INTERFACE) 47 | target_include_directories(base64 INTERFACE include) 48 | 49 | if (BASE64_ENABLE_TESTING) 50 | add_executable(roundtrip_test test/roundtrip_test.cpp) 51 | target_link_libraries(roundtrip_test PRIVATE base64) 52 | 53 | enable_testing() 54 | add_test(NAME roundtrip_test COMMAND roundtrip_test) 55 | 56 | # Add some more tests 57 | include(FetchContent) 58 | if(${CMAKE_CXX_BYTE_ORDER} MATCHES BIG_ENDIAN) 59 | set(FETCHCONTENT_QUIET FALSE) 60 | endif() 61 | FetchContent_Declare( 62 | googletest 63 | GIT_REPOSITORY https://github.com/google/googletest.git 64 | GIT_TAG b514bdc898e2951020cbdca1304b75f5950d1f59 65 | GIT_PROGRESS TRUE 66 | SYSTEM 67 | ) 68 | # For Windows: Prevent overriding the parent project's compiler/linker settings 69 | set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) 70 | FetchContent_MakeAvailable(googletest) 71 | 72 | set_target_properties(gtest PROPERTIES CXX_CLANG_TIDY "") 73 | set_target_properties(gtest_main PROPERTIES CXX_CLANG_TIDY "") 74 | set_target_properties(gmock PROPERTIES CXX_CLANG_TIDY "") 75 | set_target_properties(gmock_main PROPERTIES CXX_CLANG_TIDY "") 76 | 77 | add_executable(base64_tests test/base64_tests.cpp) 78 | target_link_libraries(base64_tests PRIVATE base64) 79 | target_link_libraries(base64_tests PRIVATE GTest::gtest GTest::gtest_main) 80 | add_test(NAME base64_tests COMMAND base64_tests) 81 | 82 | add_executable(modp_b64_tests test/modp_b64_tests.cpp) 83 | target_link_libraries(modp_b64_tests PRIVATE base64) 84 | target_link_libraries(modp_b64_tests PRIVATE GTest::gtest GTest::gtest_main) 85 | add_test(NAME modp_b64_tests COMMAND modp_b64_tests) 86 | endif() 87 | 88 | -------------------------------------------------------------------------------- /CPPLINT.cfg: -------------------------------------------------------------------------------- 1 | filter=-legal/copyright 2 | filter=-readability/todo -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Tobias Locker 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # base64 2 | A simple approach to convert strings from and to base64. 3 | Header only c++ library (single header). 4 | 5 | ## Usage 6 | 7 | ```cpp 8 | #include 9 | 10 | #include "base64.hpp" 11 | 12 | int main() { 13 | auto encoded_str = base64::to_base64("Hello, World!"); 14 | std::cout << encoded_str << std::endl; // SGVsbG8sIFdvcmxkIQ== 15 | auto decoded_str = base64::from_base64("SGVsbG8sIFdvcmxkIQ=="); 16 | std::cout << decoded_str << std::endl; // Hello, World! 17 | } 18 | ``` 19 | 20 | ## Notes 21 | This library relies on C++17 but will exploit some C++20 features if available (e.g. `bit_cast`). 22 | 23 | There are many implementations available and it may be worth looking at those. A benchmark of various c/c++ base64 implementations can be found at https://github.com/gaspardpetit/base64/ with summary results at: 24 | - https://rawcdn.githack.com/gaspardpetit/base64/main/result/result.html (presented as `base64tl`) 25 | 26 | This implementation here adopts the approach of Nick Galbreath's `modp_b64` library also used by chromium (e.g. https://github.com/chromium/chromium/tree/main/third_party/modp_b64 ) but offers it as a c++ single header file. This choice was based on the good computational performance of the underpinning algorithm. We also decided to avoid relying on a c++ `union` to perform type punning as this, while working in practice, is strictly speaking undefined behaviour in c++: https://en.wikipedia.org/wiki/Type_punning#Use_of_union 27 | 28 | Faster c/c++ implementations exist although these do not come as a single header library and exploit simd / openmp or similar acceleration techniques: 29 | - https://github.com/aklomp/base64 30 | - https://github.com/simdutf/simdutf 31 | - https://github.com/powturbo/Turbo-Base64 (Note that this is licensed under GPL 3.0) 32 | 33 | Many other C++ centric appraches exists although they seem to focus on readibility or genericity at the cost of performance, e.g.: 34 | - https://github.com/matheusgomes28/base64pp (C++20 library from which we borrowed the unit test code) 35 | - https://github.com/ReneNyffenegger/cpp-base64 (Implementation that works with older C++ versions) 36 | - https://github.com/azawadzki/base-n (more generic baseN such as N=16 and N=32) 37 | -------------------------------------------------------------------------------- /include/base64.hpp: -------------------------------------------------------------------------------- 1 | #ifndef BASE64_HPP_ 2 | #define BASE64_HPP_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #if defined(__cpp_lib_bit_cast) 15 | #include // For std::bit_cast. 16 | #endif 17 | 18 | namespace base64 { 19 | 20 | namespace detail { 21 | 22 | #if defined(__cpp_lib_bit_cast) 23 | using std::bit_cast; 24 | #else 25 | template 26 | std::enable_if_t && 28 | std::is_trivially_copyable_v, 29 | To> 30 | bit_cast(const From& src) noexcept { 31 | static_assert(std::is_trivially_constructible_v, 32 | "This implementation additionally requires " 33 | "destination type to be trivially constructible"); 34 | 35 | To dst; 36 | std::memcpy(&dst, &src, sizeof(To)); 37 | return dst; 38 | } 39 | #endif 40 | 41 | inline constexpr char padding_char{'='}; 42 | inline constexpr uint32_t bad_char{0x01FFFFFF}; 43 | 44 | #if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) 45 | #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ 46 | (defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN) || \ 47 | (defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN) || \ 48 | (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || \ 49 | (defined(__sun) && defined(__SVR4) && defined(_BIG_ENDIAN)) || \ 50 | defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ 51 | defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) || \ 52 | defined(_M_PPC) 53 | #define __BIG_ENDIAN__ 54 | #elif (defined(__BYTE_ORDER__) && \ 55 | __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || /* gcc */ \ 56 | (defined(__BYTE_ORDER) && \ 57 | __BYTE_ORDER == __LITTLE_ENDIAN) /* linux header */ \ 58 | || (defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN) || \ 59 | (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) /* mingw header */ || \ 60 | (defined(__sun) && defined(__SVR4) && \ 61 | defined(_LITTLE_ENDIAN)) || /* solaris */ \ 62 | defined(__ARMEL__) || \ 63 | defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \ 64 | defined(__MIPSEL) || defined(__MIPSEL__) || defined(_M_IX86) || \ 65 | defined(_M_X64) || defined(_M_IA64) || /* msvc for intel processors */ \ 66 | defined(_M_ARM) /* msvc code on arm executes in little endian mode */ 67 | #define __LITTLE_ENDIAN__ 68 | #endif 69 | #endif 70 | 71 | #if !defined(__LITTLE_ENDIAN__) & !defined(__BIG_ENDIAN__) 72 | #error "UNKNOWN Platform / endianness. Configure endianness explicitly." 73 | #endif 74 | 75 | #if defined(__LITTLE_ENDIAN__) 76 | std::array constexpr decode_table_0 = { 77 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 78 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 79 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 80 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 81 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 82 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 83 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 84 | 0x01ffffff, 0x000000f8, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x000000fc, 85 | 0x000000d0, 0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4, 86 | 0x000000e8, 0x000000ec, 0x000000f0, 0x000000f4, 0x01ffffff, 0x01ffffff, 87 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 88 | 0x00000004, 0x00000008, 0x0000000c, 0x00000010, 0x00000014, 0x00000018, 89 | 0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c, 0x00000030, 90 | 0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048, 91 | 0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060, 92 | 0x00000064, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 93 | 0x01ffffff, 0x00000068, 0x0000006c, 0x00000070, 0x00000074, 0x00000078, 94 | 0x0000007c, 0x00000080, 0x00000084, 0x00000088, 0x0000008c, 0x00000090, 95 | 0x00000094, 0x00000098, 0x0000009c, 0x000000a0, 0x000000a4, 0x000000a8, 96 | 0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc, 0x000000c0, 97 | 0x000000c4, 0x000000c8, 0x000000cc, 0x01ffffff, 0x01ffffff, 0x01ffffff, 98 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 99 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 100 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 101 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 102 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 103 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 104 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 105 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 106 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 107 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 108 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 109 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 110 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 111 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 112 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 113 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 114 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 115 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 116 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 117 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 118 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 119 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 120 | 121 | std::array constexpr decode_table_1 = { 122 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 123 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 124 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 125 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 126 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 127 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 128 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 129 | 0x01ffffff, 0x0000e003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000f003, 130 | 0x00004003, 0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003, 131 | 0x0000a003, 0x0000b003, 0x0000c003, 0x0000d003, 0x01ffffff, 0x01ffffff, 132 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 133 | 0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, 134 | 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, 135 | 0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001, 136 | 0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001, 137 | 0x00009001, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 138 | 0x01ffffff, 0x0000a001, 0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001, 139 | 0x0000f001, 0x00000002, 0x00001002, 0x00002002, 0x00003002, 0x00004002, 140 | 0x00005002, 0x00006002, 0x00007002, 0x00008002, 0x00009002, 0x0000a002, 141 | 0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002, 0x00000003, 142 | 0x00001003, 0x00002003, 0x00003003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 143 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 144 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 145 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 146 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 147 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 148 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 149 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 150 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 151 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 152 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 153 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 154 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 155 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 156 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 157 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 158 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 159 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 160 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 161 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 162 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 163 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 164 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 165 | 166 | std::array constexpr decode_table_2 = { 167 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 168 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 169 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 170 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 171 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 172 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 173 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 174 | 0x01ffffff, 0x00800f00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00c00f00, 175 | 0x00000d00, 0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00, 176 | 0x00800e00, 0x00c00e00, 0x00000f00, 0x00400f00, 0x01ffffff, 0x01ffffff, 177 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 178 | 0x00400000, 0x00800000, 0x00c00000, 0x00000100, 0x00400100, 0x00800100, 179 | 0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200, 0x00000300, 180 | 0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400, 181 | 0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600, 182 | 0x00400600, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 183 | 0x01ffffff, 0x00800600, 0x00c00600, 0x00000700, 0x00400700, 0x00800700, 184 | 0x00c00700, 0x00000800, 0x00400800, 0x00800800, 0x00c00800, 0x00000900, 185 | 0x00400900, 0x00800900, 0x00c00900, 0x00000a00, 0x00400a00, 0x00800a00, 186 | 0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00, 0x00000c00, 187 | 0x00400c00, 0x00800c00, 0x00c00c00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 188 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 189 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 190 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 191 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 192 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 193 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 194 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 195 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 196 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 197 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 198 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 199 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 200 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 201 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 202 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 203 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 204 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 205 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 206 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 207 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 208 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 209 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 210 | 211 | std::array constexpr decode_table_3 = { 212 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 213 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 214 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 215 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 216 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 217 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 218 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 219 | 0x01ffffff, 0x003e0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x003f0000, 220 | 0x00340000, 0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000, 221 | 0x003a0000, 0x003b0000, 0x003c0000, 0x003d0000, 0x01ffffff, 0x01ffffff, 222 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 223 | 0x00010000, 0x00020000, 0x00030000, 0x00040000, 0x00050000, 0x00060000, 224 | 0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000, 0x000c0000, 225 | 0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000, 226 | 0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000, 227 | 0x00190000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 228 | 0x01ffffff, 0x001a0000, 0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000, 229 | 0x001f0000, 0x00200000, 0x00210000, 0x00220000, 0x00230000, 0x00240000, 230 | 0x00250000, 0x00260000, 0x00270000, 0x00280000, 0x00290000, 0x002a0000, 231 | 0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000, 0x00300000, 232 | 0x00310000, 0x00320000, 0x00330000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 233 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 234 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 235 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 236 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 237 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 238 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 239 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 240 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 241 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 242 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 243 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 244 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 245 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 246 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 247 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 248 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 249 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 250 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 251 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 252 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 253 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 254 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 255 | 256 | // TODO fix decoding tables to avoid the need for different indices in big 257 | // endian? 258 | inline constexpr size_t decidx0{0}; 259 | inline constexpr size_t decidx1{1}; 260 | inline constexpr size_t decidx2{2}; 261 | 262 | #elif defined(__BIG_ENDIAN__) 263 | 264 | std::array constexpr decode_table_0 = { 265 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 266 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 267 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 268 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 269 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 270 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 271 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 272 | 0x01ffffff, 0x00f80000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00fc0000, 273 | 0x00d00000, 0x00d40000, 0x00d80000, 0x00dc0000, 0x00e00000, 0x00e40000, 274 | 0x00e80000, 0x00ec0000, 0x00f00000, 0x00f40000, 0x01ffffff, 0x01ffffff, 275 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 276 | 0x00040000, 0x00080000, 0x000c0000, 0x00100000, 0x00140000, 0x00180000, 277 | 0x001c0000, 0x00200000, 0x00240000, 0x00280000, 0x002c0000, 0x00300000, 278 | 0x00340000, 0x00380000, 0x003c0000, 0x00400000, 0x00440000, 0x00480000, 279 | 0x004c0000, 0x00500000, 0x00540000, 0x00580000, 0x005c0000, 0x00600000, 280 | 0x00640000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 281 | 0x01ffffff, 0x00680000, 0x006c0000, 0x00700000, 0x00740000, 0x00780000, 282 | 0x007c0000, 0x00800000, 0x00840000, 0x00880000, 0x008c0000, 0x00900000, 283 | 0x00940000, 0x00980000, 0x009c0000, 0x00a00000, 0x00a40000, 0x00a80000, 284 | 0x00ac0000, 0x00b00000, 0x00b40000, 0x00b80000, 0x00bc0000, 0x00c00000, 285 | 0x00c40000, 0x00c80000, 0x00cc0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 286 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 287 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 288 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 289 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 290 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 291 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 292 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 293 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 294 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 295 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 296 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 297 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 298 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 299 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 300 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 301 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 302 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 303 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 304 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 305 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 306 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 307 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 308 | 309 | std::array constexpr decode_table_1 = { 310 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 311 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 312 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 313 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 314 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 315 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 316 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 317 | 0x01ffffff, 0x0003e000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0003f000, 318 | 0x00034000, 0x00035000, 0x00036000, 0x00037000, 0x00038000, 0x00039000, 319 | 0x0003a000, 0x0003b000, 0x0003c000, 0x0003d000, 0x01ffffff, 0x01ffffff, 320 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 321 | 0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, 322 | 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, 323 | 0x0000d000, 0x0000e000, 0x0000f000, 0x00010000, 0x00011000, 0x00012000, 324 | 0x00013000, 0x00014000, 0x00015000, 0x00016000, 0x00017000, 0x00018000, 325 | 0x00019000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 326 | 0x01ffffff, 0x0001a000, 0x0001b000, 0x0001c000, 0x0001d000, 0x0001e000, 327 | 0x0001f000, 0x00020000, 0x00021000, 0x00022000, 0x00023000, 0x00024000, 328 | 0x00025000, 0x00026000, 0x00027000, 0x00028000, 0x00029000, 0x0002a000, 329 | 0x0002b000, 0x0002c000, 0x0002d000, 0x0002e000, 0x0002f000, 0x00030000, 330 | 0x00031000, 0x00032000, 0x00033000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 331 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 332 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 333 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 334 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 335 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 336 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 337 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 338 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 339 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 340 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 341 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 342 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 343 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 344 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 345 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 346 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 347 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 348 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 349 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 350 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 351 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 352 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 353 | 354 | std::array constexpr decode_table_2 = { 355 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 356 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 357 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 358 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 359 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 360 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 361 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 362 | 0x01ffffff, 0x00000f80, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000fc0, 363 | 0x00000d00, 0x00000d40, 0x00000d80, 0x00000dc0, 0x00000e00, 0x00000e40, 364 | 0x00000e80, 0x00000ec0, 0x00000f00, 0x00000f40, 0x01ffffff, 0x01ffffff, 365 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 366 | 0x00000040, 0x00000080, 0x000000c0, 0x00000100, 0x00000140, 0x00000180, 367 | 0x000001c0, 0x00000200, 0x00000240, 0x00000280, 0x000002c0, 0x00000300, 368 | 0x00000340, 0x00000380, 0x000003c0, 0x00000400, 0x00000440, 0x00000480, 369 | 0x000004c0, 0x00000500, 0x00000540, 0x00000580, 0x000005c0, 0x00000600, 370 | 0x00000640, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 371 | 0x01ffffff, 0x00000680, 0x000006c0, 0x00000700, 0x00000740, 0x00000780, 372 | 0x000007c0, 0x00000800, 0x00000840, 0x00000880, 0x000008c0, 0x00000900, 373 | 0x00000940, 0x00000980, 0x000009c0, 0x00000a00, 0x00000a40, 0x00000a80, 374 | 0x00000ac0, 0x00000b00, 0x00000b40, 0x00000b80, 0x00000bc0, 0x00000c00, 375 | 0x00000c40, 0x00000c80, 0x00000cc0, 0x01ffffff, 0x01ffffff, 0x01ffffff, 376 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 377 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 378 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 379 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 380 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 381 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 382 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 383 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 384 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 385 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 386 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 387 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 388 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 389 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 390 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 391 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 392 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 393 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 394 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 395 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 396 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 397 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 398 | 399 | std::array constexpr decode_table_3 = { 400 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 401 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 402 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 403 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 404 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 405 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 406 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 407 | 0x01ffffff, 0x0000003e, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000003f, 408 | 0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, 409 | 0x0000003a, 0x0000003b, 0x0000003c, 0x0000003d, 0x01ffffff, 0x01ffffff, 410 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 411 | 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 412 | 0x00000007, 0x00000008, 0x00000009, 0x0000000a, 0x0000000b, 0x0000000c, 413 | 0x0000000d, 0x0000000e, 0x0000000f, 0x00000010, 0x00000011, 0x00000012, 414 | 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 0x00000018, 415 | 0x00000019, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 416 | 0x01ffffff, 0x0000001a, 0x0000001b, 0x0000001c, 0x0000001d, 0x0000001e, 417 | 0x0000001f, 0x00000020, 0x00000021, 0x00000022, 0x00000023, 0x00000024, 418 | 0x00000025, 0x00000026, 0x00000027, 0x00000028, 0x00000029, 0x0000002a, 419 | 0x0000002b, 0x0000002c, 0x0000002d, 0x0000002e, 0x0000002f, 0x00000030, 420 | 0x00000031, 0x00000032, 0x00000033, 0x01ffffff, 0x01ffffff, 0x01ffffff, 421 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 422 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 423 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 424 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 425 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 426 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 427 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 428 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 429 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 430 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 431 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 432 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 433 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 434 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 435 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 436 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 437 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 438 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 439 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 440 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 441 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 442 | 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff}; 443 | 444 | // TODO fix decoding tables to avoid the need for different indices in big 445 | // endian? 446 | inline constexpr size_t decidx0{1}; 447 | inline constexpr size_t decidx1{2}; 448 | inline constexpr size_t decidx2{3}; 449 | 450 | #endif 451 | 452 | std::array constexpr encode_table_0 = { 453 | 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'D', 'D', 'D', 454 | 'D', 'E', 'E', 'E', 'E', 'F', 'F', 'F', 'F', 'G', 'G', 'G', 'G', 'H', 'H', 455 | 'H', 'H', 'I', 'I', 'I', 'I', 'J', 'J', 'J', 'J', 'K', 'K', 'K', 'K', 'L', 456 | 'L', 'L', 'L', 'M', 'M', 'M', 'M', 'N', 'N', 'N', 'N', 'O', 'O', 'O', 'O', 457 | 'P', 'P', 'P', 'P', 'Q', 'Q', 'Q', 'Q', 'R', 'R', 'R', 'R', 'S', 'S', 'S', 458 | 'S', 'T', 'T', 'T', 'T', 'U', 'U', 'U', 'U', 'V', 'V', 'V', 'V', 'W', 'W', 459 | 'W', 'W', 'X', 'X', 'X', 'X', 'Y', 'Y', 'Y', 'Y', 'Z', 'Z', 'Z', 'Z', 'a', 460 | 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'd', 'd', 'd', 461 | 'e', 'e', 'e', 'e', 'f', 'f', 'f', 'f', 'g', 'g', 'g', 'g', 'h', 'h', 'h', 462 | 'h', 'i', 'i', 'i', 'i', 'j', 'j', 'j', 'j', 'k', 'k', 'k', 'k', 'l', 'l', 463 | 'l', 'l', 'm', 'm', 'm', 'm', 'n', 'n', 'n', 'n', 'o', 'o', 'o', 'o', 'p', 464 | 'p', 'p', 'p', 'q', 'q', 'q', 'q', 'r', 'r', 'r', 'r', 's', 's', 's', 's', 465 | 't', 't', 't', 't', 'u', 'u', 'u', 'u', 'v', 'v', 'v', 'v', 'w', 'w', 'w', 466 | 'w', 'x', 'x', 'x', 'x', 'y', 'y', 'y', 'y', 'z', 'z', 'z', 'z', '0', '0', 467 | '0', '0', '1', '1', '1', '1', '2', '2', '2', '2', '3', '3', '3', '3', '4', 468 | '4', '4', '4', '5', '5', '5', '5', '6', '6', '6', '6', '7', '7', '7', '7', 469 | '8', '8', '8', '8', '9', '9', '9', '9', '+', '+', '+', '+', '/', '/', '/', 470 | '/'}; 471 | 472 | std::array constexpr encode_table_1 = { 473 | 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 474 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 475 | 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 476 | 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', 477 | '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 478 | 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 479 | 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 480 | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', 481 | '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 482 | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 483 | 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 484 | 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 485 | '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 486 | 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 487 | 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 488 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 489 | 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', 490 | '/'}; 491 | 492 | } // namespace detail 493 | 494 | template 495 | inline OutputBuffer encode_into(InputIterator begin, InputIterator end) { 496 | typedef std::decay_t input_value_type; 497 | static_assert(std::is_same_v || 498 | std::is_same_v || 499 | std::is_same_v || 500 | std::is_same_v); 501 | typedef typename OutputBuffer::value_type output_value_type; 502 | static_assert(std::is_same_v || 503 | std::is_same_v || 504 | std::is_same_v || 505 | std::is_same_v); 506 | const size_t binarytextsize = end - begin; 507 | const size_t encodedsize = (binarytextsize / 3 + (binarytextsize % 3 > 0)) 508 | << 2; 509 | OutputBuffer encoded(encodedsize, detail::padding_char); 510 | 511 | const uint8_t* bytes = reinterpret_cast(&*begin); 512 | char* currEncoding = reinterpret_cast(&encoded[0]); 513 | 514 | for (size_t i = binarytextsize / 3; i; --i) { 515 | const uint8_t t1 = *bytes++; 516 | const uint8_t t2 = *bytes++; 517 | const uint8_t t3 = *bytes++; 518 | *currEncoding++ = detail::encode_table_0[t1]; 519 | *currEncoding++ = 520 | detail::encode_table_1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; 521 | *currEncoding++ = 522 | detail::encode_table_1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; 523 | *currEncoding++ = detail::encode_table_1[t3]; 524 | } 525 | 526 | switch (binarytextsize % 3) { 527 | case 0: { 528 | break; 529 | } 530 | case 1: { 531 | const uint8_t t1 = bytes[0]; 532 | *currEncoding++ = detail::encode_table_0[t1]; 533 | *currEncoding++ = detail::encode_table_1[(t1 & 0x03) << 4]; 534 | // *currEncoding++ = detail::padding_char; 535 | // *currEncoding++ = detail::padding_char; 536 | break; 537 | } 538 | case 2: { 539 | const uint8_t t1 = bytes[0]; 540 | const uint8_t t2 = bytes[1]; 541 | *currEncoding++ = detail::encode_table_0[t1]; 542 | *currEncoding++ = 543 | detail::encode_table_1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; 544 | *currEncoding++ = detail::encode_table_1[(t2 & 0x0F) << 2]; 545 | // *currEncoding++ = detail::padding_char; 546 | break; 547 | } 548 | default: { 549 | throw std::runtime_error{"Invalid base64 encoded data"}; 550 | } 551 | } 552 | 553 | return encoded; 554 | } 555 | 556 | template 557 | inline OutputBuffer encode_into(std::string_view data) { 558 | return encode_into(std::begin(data), std::end(data)); 559 | } 560 | 561 | inline std::string to_base64(std::string_view data) { 562 | return encode_into(std::begin(data), std::end(data)); 563 | } 564 | 565 | template 566 | inline OutputBuffer decode_into(std::string_view base64Text) { 567 | typedef typename OutputBuffer::value_type output_value_type; 568 | static_assert(std::is_same_v || 569 | std::is_same_v || 570 | std::is_same_v || 571 | std::is_same_v); 572 | if (base64Text.empty()) { 573 | return OutputBuffer(); 574 | } 575 | 576 | if ((base64Text.size() & 3) != 0) { 577 | throw std::runtime_error{ 578 | "Invalid base64 encoded data - Size not divisible by 4"}; 579 | } 580 | 581 | const size_t numPadding = 582 | std::count(base64Text.rbegin(), base64Text.rbegin() + 4, '='); 583 | if (numPadding > 2) { 584 | throw std::runtime_error{ 585 | "Invalid base64 encoded data - Found more than 2 padding signs"}; 586 | } 587 | 588 | const size_t decodedsize = (base64Text.size() * 3 >> 2) - numPadding; 589 | OutputBuffer decoded(decodedsize, '.'); 590 | 591 | const uint8_t* bytes = reinterpret_cast(&base64Text[0]); 592 | char* currDecoding = reinterpret_cast(&decoded[0]); 593 | 594 | for (size_t i = (base64Text.size() >> 2) - (numPadding != 0); i; --i) { 595 | const uint8_t t1 = *bytes++; 596 | const uint8_t t2 = *bytes++; 597 | const uint8_t t3 = *bytes++; 598 | const uint8_t t4 = *bytes++; 599 | 600 | const uint32_t d1 = detail::decode_table_0[t1]; 601 | const uint32_t d2 = detail::decode_table_1[t2]; 602 | const uint32_t d3 = detail::decode_table_2[t3]; 603 | const uint32_t d4 = detail::decode_table_3[t4]; 604 | 605 | const uint32_t temp = d1 | d2 | d3 | d4; 606 | 607 | if (temp >= detail::bad_char) { 608 | throw std::runtime_error{ 609 | "Invalid base64 encoded data - Invalid character"}; 610 | } 611 | 612 | // Use bit_cast instead of union and type punning to avoid 613 | // undefined behaviour risk: 614 | // https://en.wikipedia.org/wiki/Type_punning#Use_of_union 615 | const std::array tempBytes = 616 | detail::bit_cast, uint32_t>(temp); 617 | 618 | *currDecoding++ = tempBytes[detail::decidx0]; 619 | *currDecoding++ = tempBytes[detail::decidx1]; 620 | *currDecoding++ = tempBytes[detail::decidx2]; 621 | } 622 | 623 | switch (numPadding) { 624 | case 0: { 625 | break; 626 | } 627 | case 1: { 628 | const uint8_t t1 = *bytes++; 629 | const uint8_t t2 = *bytes++; 630 | const uint8_t t3 = *bytes++; 631 | 632 | const uint32_t d1 = detail::decode_table_0[t1]; 633 | const uint32_t d2 = detail::decode_table_1[t2]; 634 | const uint32_t d3 = detail::decode_table_2[t3]; 635 | 636 | const uint32_t temp = d1 | d2 | d3; 637 | 638 | if (temp >= detail::bad_char) { 639 | throw std::runtime_error{ 640 | "Invalid base64 encoded data - Invalid character"}; 641 | } 642 | 643 | // Use bit_cast instead of union and type punning to avoid 644 | // undefined behaviour risk: 645 | // https://en.wikipedia.org/wiki/Type_punning#Use_of_union 646 | const std::array tempBytes = 647 | detail::bit_cast, uint32_t>(temp); 648 | *currDecoding++ = tempBytes[detail::decidx0]; 649 | *currDecoding++ = tempBytes[detail::decidx1]; 650 | break; 651 | } 652 | case 2: { 653 | const uint8_t t1 = *bytes++; 654 | const uint8_t t2 = *bytes++; 655 | 656 | const uint32_t d1 = detail::decode_table_0[t1]; 657 | const uint32_t d2 = detail::decode_table_1[t2]; 658 | 659 | const uint32_t temp = d1 | d2; 660 | 661 | if (temp >= detail::bad_char) { 662 | throw std::runtime_error{ 663 | "Invalid base64 encoded data - Invalid character"}; 664 | } 665 | 666 | const std::array tempBytes = 667 | detail::bit_cast, uint32_t>(temp); 668 | *currDecoding++ = tempBytes[detail::decidx0]; 669 | break; 670 | } 671 | default: { 672 | throw std::runtime_error{ 673 | "Invalid base64 encoded data - Invalid padding number"}; 674 | } 675 | } 676 | 677 | return decoded; 678 | } 679 | 680 | template 681 | inline OutputBuffer decode_into(InputIterator begin, InputIterator end) { 682 | typedef std::decay_t input_value_type; 683 | static_assert(std::is_same_v || 684 | std::is_same_v || 685 | std::is_same_v || 686 | std::is_same_v); 687 | std::string_view data(reinterpret_cast(&*begin), end - begin); 688 | return decode_into(data); 689 | } 690 | 691 | inline std::string from_base64(std::string_view data) { 692 | return decode_into(data); 693 | } 694 | 695 | } // namespace base64 696 | 697 | #endif // BASE64_HPP_ 698 | -------------------------------------------------------------------------------- /scripts/run-clang-format.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | clang-format -style=Google -i include/*.hpp 3 | clang-format -style=Google -i test/*.cpp 4 | -------------------------------------------------------------------------------- /scripts/run-s390x-emulation.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | # 3 | #docker run --rm --privileged multiarch/qemu-user-static:register --reset 4 | docker run -it multiarch/ubuntu-core:s390x-focal /bin/bash 5 | apt-get update -q -y && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends make cmake g++ git 6 | #software-properties-common 7 | cd home 8 | git clone https://github.com/tvercaut/base64.git 9 | cd base64 10 | git checkout modpb64xover 11 | cmake -B ./build -DCMAKE_BUILD_TYPE=Debug . 12 | cmake --build ./build --config Debug 13 | cd build 14 | ctest -C Debug --output-on-failure 15 | 16 | -------------------------------------------------------------------------------- /test/base64_tests.cpp: -------------------------------------------------------------------------------- 1 | // Test suite ported from https://github.com/matheusgomes28/base64pp 2 | #include 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../include/base64.hpp" 10 | 11 | // NOLINTNEXTLINE 12 | TEST(Base64Encode, EncodesEmpty) { 13 | std::string const expected{}; 14 | std::string const actual{base64::to_base64({})}; 15 | ASSERT_EQ(expected, actual); 16 | } 17 | 18 | // NOLINTNEXTLINE 19 | TEST(Base64Encode, EncodesThreeBytesZeros) { 20 | std::array const input{0x00, 0x00, 0x00}; 21 | auto const expected{"AAAA"}; 22 | auto const actual{base64::encode_into(begin(input), end(input))}; 23 | ASSERT_EQ(expected, actual); 24 | } 25 | 26 | // NOLINTNEXTLINE 27 | TEST(Base64Encode, EncodesThreeBytesRandom) { 28 | std::array const input{0xFE, 0xE9, 0x72}; 29 | auto const expected{"/uly"}; 30 | auto const actual{base64::encode_into(begin(input), end(input))}; 31 | ASSERT_EQ(expected, actual); 32 | } 33 | 34 | // NOLINTNEXTLINE 35 | TEST(Base64Encode, EncodesTwoBytes) { 36 | std::array const input{0x00, 0x00}; 37 | auto const expected{"AAA="}; 38 | auto const actual{base64::encode_into(begin(input), end(input))}; 39 | ASSERT_EQ(expected, actual); 40 | } 41 | 42 | // NOLINTNEXTLINE 43 | TEST(Base64Encode, EncodesOneByte) { 44 | std::array const input{0x00}; 45 | auto const expected{"AA=="}; 46 | auto const actual{base64::encode_into(begin(input), end(input))}; 47 | ASSERT_EQ(expected, actual); 48 | } 49 | 50 | // NOLINTNEXTLINE 51 | TEST(Base64Encode, EncodesFourBytes) { 52 | std::array const input{0x74, 0x68, 0x65, 0x20}; 53 | auto const expected{"dGhlIA=="}; 54 | auto const actual{base64::encode_into(begin(input), end(input))}; 55 | ASSERT_EQ(expected, actual); 56 | } 57 | 58 | // NOLINTNEXTLINE 59 | TEST(Base64Encode, EncodesFiveBytes) { 60 | std::array const input{0x20, 0x62, 0x72, 0x6f, 0x77}; 61 | auto const expected{"IGJyb3c="}; 62 | auto const actual{base64::encode_into(begin(input), end(input))}; 63 | ASSERT_EQ(actual, expected); 64 | } 65 | 66 | // NOLINTNEXTLINE 67 | TEST(Base64Encode, EncodesSixBytes) { 68 | std::array const input{0x20, 0x6a, 0x75, 0x6d, 0x70, 0x73}; 69 | auto const expected{"IGp1bXBz"}; 70 | auto const actual{base64::encode_into(begin(input), end(input))}; 71 | ASSERT_EQ(actual, expected); 72 | } 73 | 74 | // NOLINTNEXTLINE 75 | TEST(Base64Encode, EncodesBrownFox) { 76 | std::array const input{ 77 | 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x20, 0x62, 78 | 0x72, 0x6f, 0x77, 0x6e, 0x20, 0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 79 | 0x6d, 0x70, 0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 80 | 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67}; 81 | 82 | auto const expected{ 83 | "dGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="}; 84 | auto const actual{base64::encode_into(begin(input), end(input))}; 85 | ASSERT_EQ(actual, expected); 86 | } 87 | 88 | // NOLINTNEXTLINE 89 | TEST(Base64Encode, EncodesBrownFastFoxNullInMiddle) { 90 | std::array const input{ 91 | 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x21, 0x20, 0x62, 92 | 0x72, 0x6f, 0x77, 0x6e, 0x20, 0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 0x6d, 93 | 0x70, 0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x00, 94 | 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67}; 95 | 96 | auto const expected{ 97 | "dGhlIHF1aWNrISBicm93biBmb3gganVtcHMgb3ZlciB0aGUAIGxhenkgZG9n"}; 98 | auto const actual{base64::encode_into(begin(input), end(input))}; 99 | ASSERT_EQ(actual, expected); 100 | } 101 | 102 | // NOLINTNEXTLINE 103 | TEST(Base64Decode, FailDecodeOneString) { 104 | std::string const input{"1"}; 105 | ASSERT_THROW(base64::from_base64(input), std::runtime_error); 106 | } 107 | 108 | // NOLINTNEXTLINE 109 | TEST(Base64Decode, FailDecodeOneStringPadded) { 110 | std::string const input{"1==="}; 111 | ASSERT_THROW(base64::from_base64(input), std::runtime_error); 112 | } 113 | 114 | // NOLINTNEXTLINE 115 | TEST(Base64Decode, FailDecodeOneCharRemaining) { 116 | std::string const input{"something"}; 117 | ASSERT_THROW(base64::from_base64(input), std::runtime_error); 118 | } 119 | 120 | // NOLINTNEXTLINE 121 | TEST(Base64Decode, FailDecodeNonSize4Bigger) { 122 | std::string const input{"SomethingEntirelyDifferent"}; 123 | ASSERT_THROW(base64::from_base64(input), std::runtime_error); 124 | // For the record - expected decoding if relaxed checks 125 | // std::vector const expected{0x4A, 0x89, 0x9E, 0xB6, 0x18, 126 | // 0xA7, 0x80, 0x49, 0xED, 0x8A, 0xB7, 0xA5, 127 | // 0xC8, 0x38, 0x9F, 0x7D, 0xEA, 0xDE, 0x9E}; 128 | } 129 | 130 | // NOLINTNEXTLINE 131 | TEST(Base64Decode, FailDecodeNonBase64Short) { 132 | std::string const input{"a aa"}; 133 | ASSERT_THROW(base64::from_base64(input), std::runtime_error); 134 | } 135 | 136 | // NOLINTNEXTLINE 137 | TEST(Base64Decode, FailDecodeNonBase64Longer) { 138 | std::string const input{"aaa`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}; 139 | ASSERT_THROW(base64::from_base64(input), std::runtime_error); 140 | } 141 | 142 | // NOLINTNEXTLINE 143 | TEST(Base64Decode, DecodesMissingTwoPads0) { 144 | std::string const input{"12"}; 145 | ASSERT_THROW(base64::from_base64(input), std::runtime_error); 146 | // For the record - expected decoding if relaxed checks 147 | // std::vector const expected{0xD7}; 148 | } 149 | 150 | // NOLINTNEXTLINE 151 | TEST(Base64Decode, DecodesMissingTwoPads1) { 152 | std::string const input = "AA"; 153 | ASSERT_THROW(base64::from_base64(input), std::runtime_error); 154 | // For the record - expected decoding if relaxed checks 155 | // std::vector const expected{0x00}; 156 | } 157 | 158 | // NOLINTNEXTLINE 159 | TEST(Base64Decode, DecodesMissingOnePad0) { 160 | std::string const input = "AAA"; 161 | ASSERT_THROW(base64::from_base64(input), std::runtime_error); 162 | // For the record - expected decoding if relaxed checks 163 | // std::vector const expected{0x00, 0x00}; 164 | } 165 | 166 | // NOLINTNEXTLINE 167 | TEST(Base64Decode, DecodesMissingOnePad1) { 168 | std::string const input{"12a"}; 169 | ASSERT_THROW(base64::from_base64(input), std::runtime_error); 170 | // For the record - expected decoding if relaxed checks 171 | // std::vector const expected{0xD7, 0x66}; 172 | } 173 | 174 | // NOLINTNEXTLINE 175 | TEST(Base64Decode, DecodesMissingIssueExample) { 176 | std::string const input = "eyJuYW1lIjoiSm9obiBEb2UifQ"; 177 | ASSERT_THROW(base64::from_base64(input), std::runtime_error); 178 | // For the record - expected decoding if relaxed checks 179 | // std::string const expected_str = R"({"name":"John Doe"})"; 180 | // See https://github.com/matheusgomes28/base64pp/issues/84 181 | } 182 | 183 | // NOLINTNEXTLINE 184 | TEST(Base64Decode, DecodesEmptyString) { 185 | std::string expected{}; 186 | auto const actual{base64::from_base64("")}; 187 | 188 | ASSERT_EQ(expected, actual); 189 | } 190 | 191 | // NOLINTNEXTLINE 192 | TEST(Base64Decode, DecodesZeroArray) { 193 | std::string const input{"AAAA"}; 194 | std::vector const expected{0x00, 0x00, 0x00}; 195 | auto const actual{base64::decode_into>(input)}; 196 | 197 | ASSERT_EQ(actual, expected); 198 | } 199 | 200 | // NOLINTNEXTLINE 201 | TEST(Base64Decode, DecodesZeroArrayTwice) { 202 | std::string const input{"AAAAAAAA"}; 203 | std::vector const expected{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 204 | auto const actual{base64::decode_into>(input)}; 205 | 206 | ASSERT_EQ(actual, expected); 207 | } 208 | 209 | // NOLINTNEXTLINE 210 | TEST(Base64Decode, DecodesZeroArrayOneByte) { 211 | std::string const input{"AA=="}; 212 | std::vector const expected{0x00}; 213 | auto const actual{base64::decode_into>(input)}; 214 | 215 | ASSERT_EQ(actual, expected); 216 | } 217 | 218 | // NOLINTNEXTLINE 219 | TEST(Base64Decode, DecodesZeroArrayTwoBytes) { 220 | std::string const input{"AAA="}; 221 | std::vector const expected{0x00, 0x00}; 222 | auto const actual{base64::decode_into>(input)}; 223 | 224 | ASSERT_EQ(actual, expected); 225 | } 226 | 227 | // NOLINTNEXTLINE 228 | TEST(Base64Decode, DecodesQuickFox) { 229 | std::string const input{ 230 | "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="}; 231 | std::vector const expected{ 232 | 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x20, 0x62, 233 | 0x72, 0x6f, 0x77, 0x6e, 0x20, 0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 234 | 0x6d, 0x70, 0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 235 | 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67}; 236 | auto const actual{base64::decode_into>(input)}; 237 | ASSERT_EQ(actual, expected); 238 | } 239 | 240 | // NOLINTNEXTLINE 241 | TEST(Base64RoundTripTests, AllPossibleBytes) { 242 | std::vector all_possible_bytes; 243 | for (std::size_t i = 0; i <= 255; ++i) { 244 | all_possible_bytes.push_back(static_cast(i)); 245 | } 246 | 247 | auto const encode_string = base64::encode_into( 248 | begin(all_possible_bytes), end(all_possible_bytes)); 249 | auto const decoded_bytes = 250 | base64::decode_into>(encode_string); 251 | ASSERT_EQ(all_possible_bytes, decoded_bytes); 252 | } 253 | 254 | // NOLINTNEXTLINE 255 | TEST(Base64RoundTripTests, ExhaustiveTests) { 256 | std::vector const base64_strings = { 257 | "YW55IGNhcm5hbCBwbGVhcw==", 258 | "bGVnYWwgcGFzcw==", 259 | "dGVzdCBzdHJpbmc=", 260 | "bGVnYWwgcHJvdmlkZXI=", 261 | "ZW5vdWdoIHRoZSBzYW1lIG9mIHRoZSBwbGFjZQ==", 262 | "YW5vdGhlciB0aGUgc3RyYWlnaHQ=", 263 | "d2FzIG1lIGFkZHJlc3MgcHJvdmlkZXI=", 264 | "YWJvdXQgdGhlIG1hc3RlciBvZiB0aGUgZGFtYWdl", 265 | "ZW50aXJlIHRoYXQgYnJvdWdodCBvZiB0aGUgbW9uZXk=", 266 | "bGVnYWwgc2VjdXJpdHk=", 267 | "YmFzaWMgZ29vZCBvZiB0aGUgcGFkIHN0cmluZw==", 268 | "ZGVsZXRlIHN0cmluZyBvZiB0aGUgc3RyYWlnaHQ=", 269 | "YnJvdWdodCBvZiB0aGUgcGFkIGZvbGRlciBvZiB0aGUgZGFtYWdl", 270 | "aW50ZXJmYWNlIHN0cmluZw==", 271 | "Y29uc29sZS1tZS1jb21wYW55", 272 | "aW5mb3JtYXRpb24tbWVkaWE=", 273 | "c3RhdHVzLXNlY3VyZQ==", 274 | "Y3JlYXRlLWNvbXBhbnktc3RyaW5n", 275 | "b3JkZXItbGVhZGVy", 276 | "Y2F0YWxvZy1wcm9maWxl", 277 | "dGVzdC1jb25zdWx0aW5n", 278 | "YnJvdWdodC1sZWFkZXI=", 279 | "YXNzaWduLW1lY2hhbmlzbQ==", 280 | "bGVnYWwtY29udGFpbmVy", 281 | "ZW1haWwtY29udGFpbmVy", 282 | "aW5zdGFuY2UtY29udGFpbmVy", 283 | "dGVzdC1jb21wYW55LWFuZC1wcm9maWxl", 284 | "YmFzZTY0LWJhc2U=", 285 | "cGFzc3dvcmQ=", 286 | "Zm9vYmFy", 287 | "Y29vbC1iYXNl", 288 | "YmFzZTY0LXNlY3VyZQ==", 289 | "aW50ZXJ2YWw=", 290 | "dGhlLW1hc3Rlci1vZi10aGUtZGFtYWdl", 291 | "c2FtZS1wbGFjZS1vZi10aGUtZGFtYWdl", 292 | "aGFzaC1zb21ldGhpbmc="}; 293 | 294 | for (auto const& b64_string : base64_strings) { 295 | auto const decoded = base64::from_base64(b64_string); 296 | 297 | auto const encoded_round_trip = base64::to_base64(decoded); 298 | ASSERT_EQ(encoded_round_trip, b64_string); 299 | } 300 | } 301 | 302 | // NOLINTNEXTLINE 303 | TEST(Base64OverloadTests, EncodesString1) { 304 | std::array, 11> const test_cases = { 305 | {{"", ""}, 306 | {"Hello, World!", "SGVsbG8sIFdvcmxkIQ=="}, 307 | {"abcdefghijklmnopqrstuvwxyz0123456789\\`!\"£$%^&*()_+", 308 | "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5XGAhIsKjJCVeJiooKV8r"}, 309 | {"Base64 encoding", "QmFzZTY0IGVuY29kaW5n"}, 310 | {"I love coding", "SSBsb3ZlIGNvZGluZw=="}, 311 | {"C++23 is awesome", "QysrMjMgaXMgYXdlc29tZQ=="}, 312 | {"This is a sample", "VGhpcyBpcyBhIHNhbXBsZQ=="}, 313 | {"Base64 is useful", "QmFzZTY0IGlzIHVzZWZ1bA=="}, 314 | {"Encode and decode", "RW5jb2RlIGFuZCBkZWNvZGU="}, 315 | {"Data encryption", "RGF0YSBlbmNyeXB0aW9u"}, 316 | {"Th3 Quickk Br0wn f0x", "VGgzIFF1aWNrayAgQnIwd24gZjB4"}}}; 317 | 318 | for (auto const& [input, expected] : test_cases) { 319 | auto const actual = base64::to_base64(input); 320 | ASSERT_EQ(actual, expected); 321 | } 322 | } 323 | 324 | // NOLINTNEXTLINE 325 | TEST(Base64RoundTripTests, TypeMixTests) { 326 | const std::string strinput{"Hello, World!"}; 327 | const std::string stroutput{"SGVsbG8sIFdvcmxkIQ=="}; 328 | 329 | typedef std::vector u8vec_type; 330 | const u8vec_type uvecinput(strinput.begin(), strinput.end()); 331 | const u8vec_type uvecoutput(stroutput.begin(), stroutput.end()); 332 | 333 | typedef std::vector s8vec_type; 334 | const s8vec_type svecinput(strinput.begin(), strinput.end()); 335 | const s8vec_type svecoutput(stroutput.begin(), stroutput.end()); 336 | 337 | // str -> str 338 | { 339 | auto tmp1 = 340 | base64::encode_into(strinput.begin(), strinput.end()); 341 | ASSERT_EQ(tmp1, stroutput); 342 | auto tmp2 = 343 | base64::decode_into(stroutput.begin(), stroutput.end()); 344 | ASSERT_EQ(tmp2, strinput); 345 | auto tmp3 = base64::encode_into(strinput); 346 | ASSERT_EQ(tmp3, stroutput); 347 | auto tmp4 = base64::decode_into(stroutput); 348 | ASSERT_EQ(tmp4, strinput); 349 | auto tmp5 = base64::to_base64(strinput); 350 | ASSERT_EQ(tmp5, stroutput); 351 | auto tmp6 = base64::from_base64(stroutput); 352 | ASSERT_EQ(tmp6, strinput); 353 | } 354 | 355 | // str -> u8 356 | { 357 | auto tmp1 = 358 | base64::encode_into(strinput.begin(), strinput.end()); 359 | ASSERT_EQ(tmp1, uvecoutput); 360 | auto tmp2 = 361 | base64::decode_into(stroutput.begin(), stroutput.end()); 362 | ASSERT_EQ(tmp2, uvecinput); 363 | auto tmp3 = base64::encode_into(strinput); 364 | ASSERT_EQ(tmp3, uvecoutput); 365 | auto tmp4 = base64::decode_into(stroutput); 366 | ASSERT_EQ(tmp4, uvecinput); 367 | } 368 | 369 | // str -> s8 370 | { 371 | auto tmp1 = 372 | base64::encode_into(strinput.begin(), strinput.end()); 373 | ASSERT_EQ(tmp1, svecoutput); 374 | auto tmp2 = 375 | base64::decode_into(stroutput.begin(), stroutput.end()); 376 | ASSERT_EQ(tmp2, svecinput); 377 | auto tmp3 = base64::encode_into(strinput); 378 | ASSERT_EQ(tmp3, svecoutput); 379 | auto tmp4 = base64::decode_into(stroutput); 380 | ASSERT_EQ(tmp4, svecinput); 381 | } 382 | 383 | // u8 -> str 384 | { 385 | auto tmp1 = 386 | base64::encode_into(uvecinput.begin(), uvecinput.end()); 387 | ASSERT_EQ(tmp1, stroutput); 388 | auto tmp2 = 389 | base64::decode_into(uvecoutput.begin(), uvecoutput.end()); 390 | ASSERT_EQ(tmp2, strinput); 391 | } 392 | 393 | // u8 -> u8 394 | { 395 | auto tmp1 = 396 | base64::encode_into(uvecinput.begin(), uvecinput.end()); 397 | ASSERT_EQ(tmp1, uvecoutput); 398 | auto tmp2 = 399 | base64::decode_into(uvecoutput.begin(), uvecoutput.end()); 400 | ASSERT_EQ(tmp2, uvecinput); 401 | } 402 | 403 | // u8 -> s8 404 | { 405 | auto tmp1 = 406 | base64::encode_into(uvecinput.begin(), uvecinput.end()); 407 | ASSERT_EQ(tmp1, svecoutput); 408 | auto tmp2 = 409 | base64::decode_into(uvecoutput.begin(), uvecoutput.end()); 410 | ASSERT_EQ(tmp2, svecinput); 411 | } 412 | 413 | // s8 -> str 414 | { 415 | auto tmp1 = 416 | base64::encode_into(svecinput.begin(), svecinput.end()); 417 | ASSERT_EQ(tmp1, stroutput); 418 | auto tmp2 = 419 | base64::decode_into(svecoutput.begin(), svecoutput.end()); 420 | ASSERT_EQ(tmp2, strinput); 421 | } 422 | 423 | // s8 -> u8 424 | { 425 | auto tmp1 = 426 | base64::encode_into(svecinput.begin(), svecinput.end()); 427 | ASSERT_EQ(tmp1, uvecoutput); 428 | auto tmp2 = 429 | base64::decode_into(svecoutput.begin(), svecoutput.end()); 430 | ASSERT_EQ(tmp2, uvecinput); 431 | } 432 | 433 | // s8 -> s8 434 | { 435 | auto tmp1 = 436 | base64::encode_into(svecinput.begin(), svecinput.end()); 437 | ASSERT_EQ(tmp1, svecoutput); 438 | auto tmp2 = 439 | base64::decode_into(svecoutput.begin(), svecoutput.end()); 440 | ASSERT_EQ(tmp2, svecinput); 441 | } 442 | } 443 | 444 | int main(int argc, char** argv) { 445 | testing::InitGoogleTest(&argc, argv); 446 | return RUN_ALL_TESTS(); 447 | } 448 | -------------------------------------------------------------------------------- /test/modp_b64_tests.cpp: -------------------------------------------------------------------------------- 1 | // Test suite ported 2 | // https://github.com/client9/stringencoders/blob/master/test/modp_b64_test.c 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "../include/base64.hpp" 11 | 12 | // NOLINTNEXTLINE 13 | TEST(Base64Encode, Padding) { 14 | // Test 1-6 bytes input and decode 15 | { 16 | /* 1 in, 4 out */ 17 | std::string const input{1}; 18 | auto const encoded{base64::to_base64(input)}; 19 | ASSERT_EQ(4, encoded.size()); 20 | auto const decoded{base64::from_base64(encoded)}; 21 | ASSERT_EQ(input, decoded); 22 | } 23 | { 24 | /* 2 in, 4 out */ 25 | std::string const input{1, 1}; 26 | auto const encoded{base64::to_base64(input)}; 27 | ASSERT_EQ(4, encoded.size()); 28 | auto const decoded{base64::from_base64(encoded)}; 29 | ASSERT_EQ(input, decoded); 30 | } 31 | { 32 | /* 3 in, 4 out */ 33 | std::string const input{1, 1, 1}; 34 | auto const encoded{base64::to_base64(input)}; 35 | ASSERT_EQ(4, encoded.size()); 36 | auto const decoded{base64::from_base64(encoded)}; 37 | ASSERT_EQ(input, decoded); 38 | } 39 | { 40 | /* 4 in, 8 out */ 41 | std::string const input{1, 1, 1, 1}; 42 | auto const encoded{base64::to_base64(input)}; 43 | ASSERT_EQ(8, encoded.size()); 44 | auto const decoded{base64::from_base64(encoded)}; 45 | ASSERT_EQ(input, decoded); 46 | } 47 | { 48 | /* 5 in, 8 out */ 49 | std::string const input{1, 1, 1, 1, 1}; 50 | auto const encoded{base64::to_base64(input)}; 51 | ASSERT_EQ(8, encoded.size()); 52 | auto const decoded{base64::from_base64(encoded)}; 53 | ASSERT_EQ(input, decoded); 54 | } 55 | { 56 | /* 6 in, 8 out */ 57 | std::string const input{1, 1, 1, 1, 1, 6}; 58 | auto const encoded{base64::to_base64(input)}; 59 | ASSERT_EQ(8, encoded.size()); 60 | auto const decoded{base64::from_base64(encoded)}; 61 | ASSERT_EQ(input, decoded); 62 | } 63 | } 64 | 65 | // NOLINTNEXTLINE 66 | TEST(Base64Encode, EncodeDecode) { 67 | // Test all 17M 3 bytes inputs to encoder, decode 68 | // and make sure it's equal. 69 | for (int i = 0; i < 256; ++i) { 70 | for (int j = 0; j < 256; ++j) { 71 | for (int k = 0; k < 256; ++k) { 72 | std::string const input{static_cast(i), static_cast(j), 73 | static_cast(k)}; 74 | auto const encoded{base64::to_base64(input)}; 75 | ASSERT_EQ(4, encoded.size()); 76 | auto const decoded{base64::from_base64(encoded)}; 77 | ASSERT_EQ(input, decoded); 78 | } 79 | } 80 | } 81 | } 82 | 83 | // NOLINTNEXTLINE 84 | TEST(Base64Encode, DecodeErrors) { 85 | { 86 | // test bad input - all combinations 87 | char goodchar = 'A'; 88 | char badchar = '~'; 89 | std::array decode; 90 | for (int i = 1; i < 16; ++i) { 91 | decode[0] = static_cast(((i & 0x01) == 0) ? goodchar : badchar); 92 | decode[1] = static_cast(((i & 0x02) == 0) ? goodchar : badchar); 93 | decode[2] = static_cast(((i & 0x04) == 0) ? goodchar : badchar); 94 | decode[3] = static_cast(((i & 0x08) == 0) ? goodchar : badchar); 95 | 96 | ASSERT_THROW( 97 | base64::decode_into(decode.begin(), decode.end()), 98 | std::runtime_error); 99 | } 100 | } 101 | { 102 | // test just 1-4 padchars 103 | for (int i = 1; i <= 4; ++i) { 104 | std::vector decode(i, '='); 105 | ASSERT_THROW( 106 | base64::decode_into(decode.begin(), decode.end()), 107 | std::runtime_error); 108 | } 109 | } 110 | { 111 | // Test good+3 pad chars (should be impossible) 112 | std::string decode("A==="); 113 | ASSERT_THROW(base64::decode_into(decode.begin(), decode.end()), 114 | std::runtime_error); 115 | } 116 | } 117 | 118 | int main(int argc, char** argv) { 119 | testing::InitGoogleTest(&argc, argv); 120 | return RUN_ALL_TESTS(); 121 | } 122 | -------------------------------------------------------------------------------- /test/roundtrip_test.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../include/base64.hpp" 7 | 8 | int runtests() { 9 | const std::vector lengths{5, 10, 100, 1024, 10000, 1000003}; 10 | int outcome = EXIT_SUCCESS; 11 | 12 | std::cout << "char is " 13 | << (std::is_signed::value ? "signed" : "unsigned") 14 | << std::endl; 15 | 16 | std::cout << "endianness is " 17 | #if defined(__LITTLE_ENDIAN__) 18 | << "little endian" 19 | #else 20 | << "big endian" 21 | #endif 22 | << std::endl; 23 | 24 | for (auto& length : lengths) { 25 | std::string original; 26 | for (int i = 0; i < length; i++) { 27 | original += static_cast(std::rand()); 28 | } 29 | 30 | auto encoded = base64::to_base64(original); 31 | auto s = base64::from_base64(encoded); 32 | 33 | if (s == original) { 34 | std::cout << "Test passed with length " << length << std::endl; 35 | } else { 36 | std::cout << "Test FAILED with length " << length << std::endl; 37 | outcome = EXIT_FAILURE; 38 | } 39 | } 40 | return outcome; 41 | } 42 | 43 | int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) { 44 | try { 45 | return runtests(); 46 | } catch (const std::exception& e) { 47 | // standard exceptions 48 | std::cout << "Caught std::exception in main: " << e.what() << std::endl; 49 | return EXIT_FAILURE; 50 | } catch (...) { 51 | // everything else 52 | std::cout << "Caught unknown exception in main" << std::endl; 53 | return EXIT_FAILURE; 54 | } 55 | } 56 | --------------------------------------------------------------------------------