Repository: tobiaslocker/base64 Branch: master Commit: 8d96a2a737ac Files: 15 Total size: 67.7 KB Directory structure: gitextract_49o6eegi/ ├── .clang-format ├── .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 ================================================ FILE CONTENTS ================================================ ================================================ FILE: .clang-format ================================================ BasedOnStyle: Google IndentWidth: 2 UseTab: Never ColumnLimit: 0 NamespaceIndentation: None BreakBeforeBraces: Attach AllowShortFunctionsOnASingleLine: Inline ReflowComments: true ================================================ FILE: .github/workflows/bigendiancmake.yml ================================================ name: CMake on s390x emulation (Big endian system) on: [push, pull_request] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: RelWithDebInfo jobs: build-linux-s390x: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: uraimo/run-on-arch-action@v2 name: Run commands id: runcmd with: arch: s390x distro: ubuntu_latest install: | apt-get update -q -y apt-get -y install cmake apt-get -y install make apt-get -y install g++ apt-get -y install git run: | lscpu | grep Endian cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} . cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} cd ${{github.workspace}}/build ctest -C ${{env.BUILD_TYPE}} --output-on-failure ================================================ FILE: .github/workflows/cmake.yml ================================================ name: CMake on: [push, pull_request] env: # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) BUILD_TYPE: RelWithDebInfo jobs: build: # The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac. strategy: matrix: os: [ubuntu-latest, windows-latest, macos-latest] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v3 - name: Install optional tools (clang-tidy) if: matrix.os == 'ubuntu-latest' run: sudo apt-get install -y clang-tidy - name: Configure CMake (Windows) if: runner.os == 'Windows' # Configure CMake in a 'build' subdirectory. # `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} . - name: Configure CMake (Other OS) if: runner.os != 'Windows' # Configure CMake in a 'build' subdirectory. # `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type run: cmake -B ${{github.workspace}}/build -USE_ASAN=ON -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} . - name: Build # Build your program with the given configuration run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} - name: Test working-directory: ${{github.workspace}}/build # Execute tests defined by the CMake configuration. # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest -C ${{env.BUILD_TYPE}} --output-on-failure ================================================ FILE: .github/workflows/cpplint.yml ================================================ # GitHub Action to run cpplint recursively on all pushes and pull requests # https://github.com/cpplint/GitHub-Action-for-cpplint name: cpplint on: [push, pull_request] jobs: cpplint: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: actions/setup-python@v4 with: python-version: 3.x - run: pip install cpplint - run: cpplint --root=include --recursive . ================================================ FILE: .gitignore ================================================ main.cpp build *.user *.swp scripts/build.sh ================================================ FILE: CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.16) project(base64) option(BASE64_ENABLE_TESTING "Build test files." ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE RelWithDebInfo) endif() # Warnings compiler flags if(MSVC) add_compile_options(/W4) else() add_compile_options(-Wall -Wextra -Wpedantic) endif() # Optionally enable clang-tidy find_program(CLANG_TIDY_EXE NAMES clang-tidy PATHS /opt/homebrew/opt/llvm/bin/) if(NOT CLANG_TIDY_EXE) message(STATUS "clang-tidy not found. Skipping corresponding checks.") else() set(CMAKE_CXX_CLANG_TIDY ${CLANG_TIDY_EXE}; -header-filter=.*; -checks=-*,portability-*,bugprone-*,-bugprone-easily-swappable-parameters,-bugprone-sizeof-expression,clang-analyzer-*; ) message(STATUS "Found clang-tidy: ${CLANG_TIDY_EXE}.") endif() # Simplify the use of ASan option(USE_ASAN "Activate ASan compiler/linker options" OFF) if(USE_ASAN) if(MSVC) add_compile_options(/fsanitize=address) add_link_options(/fsanitize=address) set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$,$>,$<$:EditAndContinue>,$<$:ProgramDatabase>>") else() add_compile_options(-fsanitize=address -fno-omit-frame-pointer) add_link_options(-fsanitize=address) endif() endif() add_library(base64 INTERFACE) target_include_directories(base64 INTERFACE include) if (BASE64_ENABLE_TESTING) add_executable(roundtrip_test test/roundtrip_test.cpp) target_link_libraries(roundtrip_test PRIVATE base64) enable_testing() add_test(NAME roundtrip_test COMMAND roundtrip_test) # Add some more tests include(FetchContent) if(${CMAKE_CXX_BYTE_ORDER} MATCHES BIG_ENDIAN) set(FETCHCONTENT_QUIET FALSE) endif() FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG b514bdc898e2951020cbdca1304b75f5950d1f59 GIT_PROGRESS TRUE SYSTEM ) # For Windows: Prevent overriding the parent project's compiler/linker settings set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) set_target_properties(gtest PROPERTIES CXX_CLANG_TIDY "") set_target_properties(gtest_main PROPERTIES CXX_CLANG_TIDY "") set_target_properties(gmock PROPERTIES CXX_CLANG_TIDY "") set_target_properties(gmock_main PROPERTIES CXX_CLANG_TIDY "") add_executable(base64_tests test/base64_tests.cpp) target_link_libraries(base64_tests PRIVATE base64) target_link_libraries(base64_tests PRIVATE GTest::gtest GTest::gtest_main) add_test(NAME base64_tests COMMAND base64_tests) add_executable(modp_b64_tests test/modp_b64_tests.cpp) target_link_libraries(modp_b64_tests PRIVATE base64) target_link_libraries(modp_b64_tests PRIVATE GTest::gtest GTest::gtest_main) add_test(NAME modp_b64_tests COMMAND modp_b64_tests) endif() ================================================ FILE: CPPLINT.cfg ================================================ filter=-legal/copyright filter=-readability/todo ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2019 Tobias Locker Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: README.md ================================================ # base64 A simple, header-only C++17 library for Base64 encoding and decoding. Uses modern C++ features when available (e.g., `std::bit_cast` in C++20) while remaining portable and efficient. ## Features - Header-only, single-file library - Fast encoding/decoding using lookup tables - Safe type punning using `std::bit_cast` (avoids undefined behavior with unions) - Throws `std::runtime_error` for invalid Base64 input (size, padding, or characters) ## Platform Support - Compilers: GCC, Clang, MSVC - Architectures: x86, x64, ARM, AArch64 (little-endian) - Requires C++17 (C++20 features optional) ## Usage ```cpp #include #include "base64.hpp" int main() { auto encoded = base64::to_base64("Hello, World!"); std::cout << encoded << std::endl; // SGVsbG8sIFdvcmxkIQ== auto decoded = base64::from_base64("SGVsbG8sIFdvcmxkIQ=="); std::cout << decoded << std::endl; // Hello, World! } ``` ## Notes - Inspired by Nick Galbreath's modp_b64 (used by Chromium) for high performance - Compatible with C++17; optionally uses C++20 features - Avoids union-based type punning for safety - Faster implementations exist using SIMD or multithreading but are not header-only ## References - Benchmark of C/C++ Base64 libraries: https://github.com/gaspardpetit/base64/ - Chromium modp_b64: https://github.com/chromium/chromium/tree/main/third_party/modp_b64 - SIMD/optimized alternatives: - https://github.com/aklomp/base64 - https://github.com/simdutf/simdutf - https://github.com/powturbo/Turbo-Base64 ================================================ FILE: include/base64.hpp ================================================ #ifndef BASE64_HPP_ #define BASE64_HPP_ #include #include #include #include #include #include #include #include #include #if defined(__cpp_lib_bit_cast) #include // For std::bit_cast. #endif namespace base64 { namespace detail { #if defined(__cpp_lib_bit_cast) using std::bit_cast; #else template std::enable_if_t && std::is_trivially_copyable_v, To> bit_cast(const From& src) noexcept { static_assert(std::is_trivially_constructible_v, "This implementation additionally requires " "destination type to be trivially constructible"); To dst; std::memcpy(&dst, &src, sizeof(To)); return dst; } #endif inline constexpr char padding_char{'='}; inline constexpr uint32_t bad_char{0x01FFFFFF}; #if !defined(__LITTLE_ENDIAN__) && !defined(__BIG_ENDIAN__) #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || \ (defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN) || \ (defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN) || \ (defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN) || \ (defined(__sun) && defined(__SVR4) && defined(_BIG_ENDIAN)) || \ defined(__ARMEB__) || defined(__THUMBEB__) || defined(__AARCH64EB__) || \ defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) || \ defined(_M_PPC) #define __BIG_ENDIAN__ #elif (defined(__BYTE_ORDER__) && \ __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || /* gcc */ \ (defined(__BYTE_ORDER) && \ __BYTE_ORDER == __LITTLE_ENDIAN) /* linux header */ \ || (defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN) || \ (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) /* mingw header */ || \ (defined(__sun) && defined(__SVR4) && \ defined(_LITTLE_ENDIAN)) || /* solaris */ \ defined(__ARMEL__) || \ defined(__THUMBEL__) || defined(__AARCH64EL__) || defined(_MIPSEL) || \ defined(__MIPSEL) || defined(__MIPSEL__) || defined(_M_IX86) || \ defined(_M_X64) || defined(_M_IA64) || /* msvc for intel processors */ \ defined(_M_ARM) || \ defined(_M_ARM64) /* msvc code on arm executes in little endian mode */ #define __LITTLE_ENDIAN__ #endif #endif #if !defined(__LITTLE_ENDIAN__) & !defined(__BIG_ENDIAN__) #error "UNKNOWN Platform / endianness. Configure endianness explicitly." #endif #if defined(__LITTLE_ENDIAN__) std::array constexpr decode_table_0 = { 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x000000f8, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x000000fc, 0x000000d0, 0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4, 0x000000e8, 0x000000ec, 0x000000f0, 0x000000f4, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 0x00000004, 0x00000008, 0x0000000c, 0x00000010, 0x00000014, 0x00000018, 0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c, 0x00000030, 0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048, 0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060, 0x00000064, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000068, 0x0000006c, 0x00000070, 0x00000074, 0x00000078, 0x0000007c, 0x00000080, 0x00000084, 0x00000088, 0x0000008c, 0x00000090, 0x00000094, 0x00000098, 0x0000009c, 0x000000a0, 0x000000a4, 0x000000a8, 0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc, 0x000000c0, 0x000000c4, 0x000000c8, 0x000000cc, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff }; std::array constexpr decode_table_1 = { 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000e003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000f003, 0x00004003, 0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003, 0x0000a003, 0x0000b003, 0x0000c003, 0x0000d003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, 0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001, 0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001, 0x00009001, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000a001, 0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001, 0x0000f001, 0x00000002, 0x00001002, 0x00002002, 0x00003002, 0x00004002, 0x00005002, 0x00006002, 0x00007002, 0x00008002, 0x00009002, 0x0000a002, 0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002, 0x00000003, 0x00001003, 0x00002003, 0x00003003, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff }; std::array constexpr decode_table_2 = { 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00800f00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00c00f00, 0x00000d00, 0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00, 0x00800e00, 0x00c00e00, 0x00000f00, 0x00400f00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 0x00400000, 0x00800000, 0x00c00000, 0x00000100, 0x00400100, 0x00800100, 0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200, 0x00000300, 0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400, 0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600, 0x00400600, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00800600, 0x00c00600, 0x00000700, 0x00400700, 0x00800700, 0x00c00700, 0x00000800, 0x00400800, 0x00800800, 0x00c00800, 0x00000900, 0x00400900, 0x00800900, 0x00c00900, 0x00000a00, 0x00400a00, 0x00800a00, 0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00, 0x00000c00, 0x00400c00, 0x00800c00, 0x00c00c00, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff }; std::array constexpr decode_table_3 = { 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x003e0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x003f0000, 0x00340000, 0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000, 0x003a0000, 0x003b0000, 0x003c0000, 0x003d0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 0x00010000, 0x00020000, 0x00030000, 0x00040000, 0x00050000, 0x00060000, 0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000, 0x000c0000, 0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000, 0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000, 0x00190000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x001a0000, 0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000, 0x001f0000, 0x00200000, 0x00210000, 0x00220000, 0x00230000, 0x00240000, 0x00250000, 0x00260000, 0x00270000, 0x00280000, 0x00290000, 0x002a0000, 0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000, 0x00300000, 0x00310000, 0x00320000, 0x00330000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff }; // TODO fix decoding tables to avoid the need for different indices in big // endian? inline constexpr size_t decidx0{0}; inline constexpr size_t decidx1{1}; inline constexpr size_t decidx2{2}; #elif defined(__BIG_ENDIAN__) std::array constexpr decode_table_0 = { 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00f80000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00fc0000, 0x00d00000, 0x00d40000, 0x00d80000, 0x00dc0000, 0x00e00000, 0x00e40000, 0x00e80000, 0x00ec0000, 0x00f00000, 0x00f40000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 0x00040000, 0x00080000, 0x000c0000, 0x00100000, 0x00140000, 0x00180000, 0x001c0000, 0x00200000, 0x00240000, 0x00280000, 0x002c0000, 0x00300000, 0x00340000, 0x00380000, 0x003c0000, 0x00400000, 0x00440000, 0x00480000, 0x004c0000, 0x00500000, 0x00540000, 0x00580000, 0x005c0000, 0x00600000, 0x00640000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00680000, 0x006c0000, 0x00700000, 0x00740000, 0x00780000, 0x007c0000, 0x00800000, 0x00840000, 0x00880000, 0x008c0000, 0x00900000, 0x00940000, 0x00980000, 0x009c0000, 0x00a00000, 0x00a40000, 0x00a80000, 0x00ac0000, 0x00b00000, 0x00b40000, 0x00b80000, 0x00bc0000, 0x00c00000, 0x00c40000, 0x00c80000, 0x00cc0000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff }; std::array constexpr decode_table_1 = { 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0003e000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0003f000, 0x00034000, 0x00035000, 0x00036000, 0x00037000, 0x00038000, 0x00039000, 0x0003a000, 0x0003b000, 0x0003c000, 0x0003d000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, 0x0000d000, 0x0000e000, 0x0000f000, 0x00010000, 0x00011000, 0x00012000, 0x00013000, 0x00014000, 0x00015000, 0x00016000, 0x00017000, 0x00018000, 0x00019000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0001a000, 0x0001b000, 0x0001c000, 0x0001d000, 0x0001e000, 0x0001f000, 0x00020000, 0x00021000, 0x00022000, 0x00023000, 0x00024000, 0x00025000, 0x00026000, 0x00027000, 0x00028000, 0x00029000, 0x0002a000, 0x0002b000, 0x0002c000, 0x0002d000, 0x0002e000, 0x0002f000, 0x00030000, 0x00031000, 0x00032000, 0x00033000, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff }; std::array constexpr decode_table_2 = { 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000f80, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000fc0, 0x00000d00, 0x00000d40, 0x00000d80, 0x00000dc0, 0x00000e00, 0x00000e40, 0x00000e80, 0x00000ec0, 0x00000f00, 0x00000f40, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 0x00000040, 0x00000080, 0x000000c0, 0x00000100, 0x00000140, 0x00000180, 0x000001c0, 0x00000200, 0x00000240, 0x00000280, 0x000002c0, 0x00000300, 0x00000340, 0x00000380, 0x000003c0, 0x00000400, 0x00000440, 0x00000480, 0x000004c0, 0x00000500, 0x00000540, 0x00000580, 0x000005c0, 0x00000600, 0x00000640, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000680, 0x000006c0, 0x00000700, 0x00000740, 0x00000780, 0x000007c0, 0x00000800, 0x00000840, 0x00000880, 0x000008c0, 0x00000900, 0x00000940, 0x00000980, 0x000009c0, 0x00000a00, 0x00000a40, 0x00000a80, 0x00000ac0, 0x00000b00, 0x00000b40, 0x00000b80, 0x00000bc0, 0x00000c00, 0x00000c40, 0x00000c80, 0x00000cc0, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff }; std::array constexpr decode_table_3 = { 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000003e, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000003f, 0x00000034, 0x00000035, 0x00000036, 0x00000037, 0x00000038, 0x00000039, 0x0000003a, 0x0000003b, 0x0000003c, 0x0000003d, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x00000000, 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, 0x00000008, 0x00000009, 0x0000000a, 0x0000000b, 0x0000000c, 0x0000000d, 0x0000000e, 0x0000000f, 0x00000010, 0x00000011, 0x00000012, 0x00000013, 0x00000014, 0x00000015, 0x00000016, 0x00000017, 0x00000018, 0x00000019, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x0000001a, 0x0000001b, 0x0000001c, 0x0000001d, 0x0000001e, 0x0000001f, 0x00000020, 0x00000021, 0x00000022, 0x00000023, 0x00000024, 0x00000025, 0x00000026, 0x00000027, 0x00000028, 0x00000029, 0x0000002a, 0x0000002b, 0x0000002c, 0x0000002d, 0x0000002e, 0x0000002f, 0x00000030, 0x00000031, 0x00000032, 0x00000033, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff, 0x01ffffff }; // TODO fix decoding tables to avoid the need for different indices in big // endian? inline constexpr size_t decidx0{1}; inline constexpr size_t decidx1{2}; inline constexpr size_t decidx2{3}; #endif std::array constexpr encode_table_0 = { 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'C', 'C', 'C', 'C', 'D', 'D', 'D', 'D', 'E', 'E', 'E', 'E', 'F', 'F', 'F', 'F', 'G', 'G', 'G', 'G', 'H', 'H', 'H', 'H', 'I', 'I', 'I', 'I', 'J', 'J', 'J', 'J', 'K', 'K', 'K', 'K', 'L', 'L', 'L', 'L', 'M', 'M', 'M', 'M', 'N', 'N', 'N', 'N', 'O', 'O', 'O', 'O', 'P', 'P', 'P', 'P', 'Q', 'Q', 'Q', 'Q', 'R', 'R', 'R', 'R', 'S', 'S', 'S', 'S', 'T', 'T', 'T', 'T', 'U', 'U', 'U', 'U', 'V', 'V', 'V', 'V', 'W', 'W', 'W', 'W', 'X', 'X', 'X', 'X', 'Y', 'Y', 'Y', 'Y', 'Z', 'Z', 'Z', 'Z', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'c', 'c', 'c', 'c', 'd', 'd', 'd', 'd', 'e', 'e', 'e', 'e', 'f', 'f', 'f', 'f', 'g', 'g', 'g', 'g', 'h', 'h', 'h', 'h', 'i', 'i', 'i', 'i', 'j', 'j', 'j', 'j', 'k', 'k', 'k', 'k', 'l', 'l', 'l', 'l', 'm', 'm', 'm', 'm', 'n', 'n', 'n', 'n', 'o', 'o', 'o', 'o', 'p', 'p', 'p', 'p', 'q', 'q', 'q', 'q', 'r', 'r', 'r', 'r', 's', 's', 's', 's', 't', 't', 't', 't', 'u', 'u', 'u', 'u', 'v', 'v', 'v', 'v', 'w', 'w', 'w', 'w', 'x', 'x', 'x', 'x', 'y', 'y', 'y', 'y', 'z', 'z', 'z', 'z', '0', '0', '0', '0', '1', '1', '1', '1', '2', '2', '2', '2', '3', '3', '3', '3', '4', '4', '4', '4', '5', '5', '5', '5', '6', '6', '6', '6', '7', '7', '7', '7', '8', '8', '8', '8', '9', '9', '9', '9', '+', '+', '+', '+', '/', '/', '/', '/' }; std::array constexpr encode_table_1 = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' }; } // namespace detail template inline OutputBuffer encode_into(InputIterator begin, InputIterator end) { typedef std::decay_t input_value_type; static_assert(std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v); typedef typename OutputBuffer::value_type output_value_type; static_assert(std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v); const size_t binarytextsize = end - begin; const size_t encodedsize = (binarytextsize / 3 + (binarytextsize % 3 > 0)) << 2; OutputBuffer encoded(encodedsize, detail::padding_char); const uint8_t* bytes = reinterpret_cast(&*begin); char* currEncoding = reinterpret_cast(&encoded[0]); for (size_t i = binarytextsize / 3; i; --i) { const uint8_t t1 = *bytes++; const uint8_t t2 = *bytes++; const uint8_t t3 = *bytes++; *currEncoding++ = detail::encode_table_0[t1]; *currEncoding++ = detail::encode_table_1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; *currEncoding++ = detail::encode_table_1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)]; *currEncoding++ = detail::encode_table_1[t3]; } switch (binarytextsize % 3) { case 0: { break; } case 1: { const uint8_t t1 = bytes[0]; *currEncoding++ = detail::encode_table_0[t1]; *currEncoding++ = detail::encode_table_1[(t1 & 0x03) << 4]; break; } case 2: { const uint8_t t1 = bytes[0]; const uint8_t t2 = bytes[1]; *currEncoding++ = detail::encode_table_0[t1]; *currEncoding++ = detail::encode_table_1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)]; *currEncoding++ = detail::encode_table_1[(t2 & 0x0F) << 2]; break; } default: { throw std::runtime_error{"Invalid base64 encoded data"}; } } return encoded; } template inline OutputBuffer encode_into(std::string_view data) { return encode_into(std::begin(data), std::end(data)); } inline std::string to_base64(std::string_view data) { return encode_into(std::begin(data), std::end(data)); } template inline OutputBuffer decode_into(std::string_view base64Text) { typedef typename OutputBuffer::value_type output_value_type; static_assert(std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v); if (base64Text.empty()) { return OutputBuffer(); } if ((base64Text.size() & 3) != 0) { throw std::runtime_error{ "Invalid base64 encoded data - Size not divisible by 4"}; } const size_t numPadding = std::count(base64Text.rbegin(), base64Text.rbegin() + 4, '='); if (numPadding > 2) { throw std::runtime_error{ "Invalid base64 encoded data - Found more than 2 padding signs"}; } const size_t decodedsize = (base64Text.size() * 3 >> 2) - numPadding; OutputBuffer decoded(decodedsize, '.'); const uint8_t* bytes = reinterpret_cast(&base64Text[0]); char* currDecoding = reinterpret_cast(&decoded[0]); for (size_t i = (base64Text.size() >> 2) - (numPadding != 0); i; --i) { const uint8_t t1 = *bytes++; const uint8_t t2 = *bytes++; const uint8_t t3 = *bytes++; const uint8_t t4 = *bytes++; const uint32_t d1 = detail::decode_table_0[t1]; const uint32_t d2 = detail::decode_table_1[t2]; const uint32_t d3 = detail::decode_table_2[t3]; const uint32_t d4 = detail::decode_table_3[t4]; const uint32_t temp = d1 | d2 | d3 | d4; if (temp >= detail::bad_char) { throw std::runtime_error{ "Invalid base64 encoded data - Invalid character"}; } // Use bit_cast instead of union and type punning to avoid // undefined behaviour risk: // https://en.wikipedia.org/wiki/Type_punning#Use_of_union const std::array tempBytes = detail::bit_cast, uint32_t>(temp); *currDecoding++ = tempBytes[detail::decidx0]; *currDecoding++ = tempBytes[detail::decidx1]; *currDecoding++ = tempBytes[detail::decidx2]; } switch (numPadding) { case 0: { break; } case 1: { const uint8_t t1 = *bytes++; const uint8_t t2 = *bytes++; const uint8_t t3 = *bytes++; const uint32_t d1 = detail::decode_table_0[t1]; const uint32_t d2 = detail::decode_table_1[t2]; const uint32_t d3 = detail::decode_table_2[t3]; const uint32_t temp = d1 | d2 | d3; if (temp >= detail::bad_char) { throw std::runtime_error{ "Invalid base64 encoded data - Invalid character"}; } // Use bit_cast instead of union and type punning to avoid // undefined behaviour risk: // https://en.wikipedia.org/wiki/Type_punning#Use_of_union const std::array tempBytes = detail::bit_cast, uint32_t>(temp); *currDecoding++ = tempBytes[detail::decidx0]; *currDecoding++ = tempBytes[detail::decidx1]; break; } case 2: { const uint8_t t1 = *bytes++; const uint8_t t2 = *bytes++; const uint32_t d1 = detail::decode_table_0[t1]; const uint32_t d2 = detail::decode_table_1[t2]; const uint32_t temp = d1 | d2; if (temp >= detail::bad_char) { throw std::runtime_error{ "Invalid base64 encoded data - Invalid character"}; } const std::array tempBytes = detail::bit_cast, uint32_t>(temp); *currDecoding++ = tempBytes[detail::decidx0]; break; } default: { throw std::runtime_error{ "Invalid base64 encoded data - Invalid padding number"}; } } return decoded; } template inline OutputBuffer decode_into(InputIterator begin, InputIterator end) { typedef std::decay_t input_value_type; static_assert(std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v); std::string_view data(reinterpret_cast(&*begin), end - begin); return decode_into(data); } inline std::string from_base64(std::string_view data) { return decode_into(data); } } // namespace base64 #endif // BASE64_HPP_ ================================================ FILE: scripts/run-clang-format.sh ================================================ #!/usr/bin/env sh clang-format -style=Google -i include/*.hpp clang-format -style=Google -i test/*.cpp ================================================ FILE: scripts/run-s390x-emulation.sh ================================================ #!/usr/bin/env sh # #docker run --rm --privileged multiarch/qemu-user-static:register --reset docker run -it multiarch/ubuntu-core:s390x-focal /bin/bash apt-get update -q -y && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends make cmake g++ git #software-properties-common cd home git clone https://github.com/tvercaut/base64.git cd base64 git checkout modpb64xover cmake -B ./build -DCMAKE_BUILD_TYPE=Debug . cmake --build ./build --config Debug cd build ctest -C Debug --output-on-failure ================================================ FILE: test/base64_tests.cpp ================================================ // Test suite ported from https://github.com/matheusgomes28/base64pp #include #include #include #include #include #include "../include/base64.hpp" // NOLINTNEXTLINE TEST(Base64Encode, EncodesEmpty) { std::string const expected{}; std::string const actual{base64::to_base64({})}; ASSERT_EQ(expected, actual); } // NOLINTNEXTLINE TEST(Base64Encode, EncodesThreeBytesZeros) { std::array const input{0x00, 0x00, 0x00}; auto const expected{"AAAA"}; auto const actual{base64::encode_into(begin(input), end(input))}; ASSERT_EQ(expected, actual); } // NOLINTNEXTLINE TEST(Base64Encode, EncodesThreeBytesRandom) { std::array const input{0xFE, 0xE9, 0x72}; auto const expected{"/uly"}; auto const actual{base64::encode_into(begin(input), end(input))}; ASSERT_EQ(expected, actual); } // NOLINTNEXTLINE TEST(Base64Encode, EncodesTwoBytes) { std::array const input{0x00, 0x00}; auto const expected{"AAA="}; auto const actual{base64::encode_into(begin(input), end(input))}; ASSERT_EQ(expected, actual); } // NOLINTNEXTLINE TEST(Base64Encode, EncodesOneByte) { std::array const input{0x00}; auto const expected{"AA=="}; auto const actual{base64::encode_into(begin(input), end(input))}; ASSERT_EQ(expected, actual); } // NOLINTNEXTLINE TEST(Base64Encode, EncodesFourBytes) { std::array const input{0x74, 0x68, 0x65, 0x20}; auto const expected{"dGhlIA=="}; auto const actual{base64::encode_into(begin(input), end(input))}; ASSERT_EQ(expected, actual); } // NOLINTNEXTLINE TEST(Base64Encode, EncodesFiveBytes) { std::array const input{0x20, 0x62, 0x72, 0x6f, 0x77}; auto const expected{"IGJyb3c="}; auto const actual{base64::encode_into(begin(input), end(input))}; ASSERT_EQ(actual, expected); } // NOLINTNEXTLINE TEST(Base64Encode, EncodesSixBytes) { std::array const input{0x20, 0x6a, 0x75, 0x6d, 0x70, 0x73}; auto const expected{"IGp1bXBz"}; auto const actual{base64::encode_into(begin(input), end(input))}; ASSERT_EQ(actual, expected); } // NOLINTNEXTLINE TEST(Base64Encode, EncodesBrownFox) { std::array const input{ 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e, 0x20, 0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 0x6d, 0x70, 0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67}; auto const expected{ "dGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="}; auto const actual{base64::encode_into(begin(input), end(input))}; ASSERT_EQ(actual, expected); } // NOLINTNEXTLINE TEST(Base64Encode, EncodesBrownFastFoxNullInMiddle) { std::array const input{ 0x74, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x21, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e, 0x20, 0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 0x6d, 0x70, 0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x00, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67}; auto const expected{ "dGhlIHF1aWNrISBicm93biBmb3gganVtcHMgb3ZlciB0aGUAIGxhenkgZG9n"}; auto const actual{base64::encode_into(begin(input), end(input))}; ASSERT_EQ(actual, expected); } // NOLINTNEXTLINE TEST(Base64Decode, FailDecodeOneString) { std::string const input{"1"}; ASSERT_THROW(base64::from_base64(input), std::runtime_error); } // NOLINTNEXTLINE TEST(Base64Decode, FailDecodeOneStringPadded) { std::string const input{"1==="}; ASSERT_THROW(base64::from_base64(input), std::runtime_error); } // NOLINTNEXTLINE TEST(Base64Decode, FailDecodeOneCharRemaining) { std::string const input{"something"}; ASSERT_THROW(base64::from_base64(input), std::runtime_error); } // NOLINTNEXTLINE TEST(Base64Decode, FailDecodeNonSize4Bigger) { std::string const input{"SomethingEntirelyDifferent"}; ASSERT_THROW(base64::from_base64(input), std::runtime_error); // For the record - expected decoding if relaxed checks // std::vector const expected{0x4A, 0x89, 0x9E, 0xB6, 0x18, // 0xA7, 0x80, 0x49, 0xED, 0x8A, 0xB7, 0xA5, // 0xC8, 0x38, 0x9F, 0x7D, 0xEA, 0xDE, 0x9E}; } // NOLINTNEXTLINE TEST(Base64Decode, FailDecodeNonBase64Short) { std::string const input{"a aa"}; ASSERT_THROW(base64::from_base64(input), std::runtime_error); } // NOLINTNEXTLINE TEST(Base64Decode, FailDecodeNonBase64Longer) { std::string const input{"aaa`aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}; ASSERT_THROW(base64::from_base64(input), std::runtime_error); } // NOLINTNEXTLINE TEST(Base64Decode, DecodesMissingTwoPads0) { std::string const input{"12"}; ASSERT_THROW(base64::from_base64(input), std::runtime_error); // For the record - expected decoding if relaxed checks // std::vector const expected{0xD7}; } // NOLINTNEXTLINE TEST(Base64Decode, DecodesMissingTwoPads1) { std::string const input = "AA"; ASSERT_THROW(base64::from_base64(input), std::runtime_error); // For the record - expected decoding if relaxed checks // std::vector const expected{0x00}; } // NOLINTNEXTLINE TEST(Base64Decode, DecodesMissingOnePad0) { std::string const input = "AAA"; ASSERT_THROW(base64::from_base64(input), std::runtime_error); // For the record - expected decoding if relaxed checks // std::vector const expected{0x00, 0x00}; } // NOLINTNEXTLINE TEST(Base64Decode, DecodesMissingOnePad1) { std::string const input{"12a"}; ASSERT_THROW(base64::from_base64(input), std::runtime_error); // For the record - expected decoding if relaxed checks // std::vector const expected{0xD7, 0x66}; } // NOLINTNEXTLINE TEST(Base64Decode, DecodesMissingIssueExample) { std::string const input = "eyJuYW1lIjoiSm9obiBEb2UifQ"; ASSERT_THROW(base64::from_base64(input), std::runtime_error); // For the record - expected decoding if relaxed checks // std::string const expected_str = R"({"name":"John Doe"})"; // See https://github.com/matheusgomes28/base64pp/issues/84 } // NOLINTNEXTLINE TEST(Base64Decode, DecodesEmptyString) { std::string expected{}; auto const actual{base64::from_base64("")}; ASSERT_EQ(expected, actual); } // NOLINTNEXTLINE TEST(Base64Decode, DecodesZeroArray) { std::string const input{"AAAA"}; std::vector const expected{0x00, 0x00, 0x00}; auto const actual{base64::decode_into>(input)}; ASSERT_EQ(actual, expected); } // NOLINTNEXTLINE TEST(Base64Decode, DecodesZeroArrayTwice) { std::string const input{"AAAAAAAA"}; std::vector const expected{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; auto const actual{base64::decode_into>(input)}; ASSERT_EQ(actual, expected); } // NOLINTNEXTLINE TEST(Base64Decode, DecodesZeroArrayOneByte) { std::string const input{"AA=="}; std::vector const expected{0x00}; auto const actual{base64::decode_into>(input)}; ASSERT_EQ(actual, expected); } // NOLINTNEXTLINE TEST(Base64Decode, DecodesZeroArrayTwoBytes) { std::string const input{"AAA="}; std::vector const expected{0x00, 0x00}; auto const actual{base64::decode_into>(input)}; ASSERT_EQ(actual, expected); } // NOLINTNEXTLINE TEST(Base64Decode, DecodesQuickFox) { std::string const input{ "VGhlIHF1aWNrIGJyb3duIGZveCBqdW1wcyBvdmVyIHRoZSBsYXp5IGRvZw=="}; std::vector const expected{ 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e, 0x20, 0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 0x6d, 0x70, 0x73, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79, 0x20, 0x64, 0x6f, 0x67}; auto const actual{base64::decode_into>(input)}; ASSERT_EQ(actual, expected); } // NOLINTNEXTLINE TEST(Base64RoundTripTests, AllPossibleBytes) { std::vector all_possible_bytes; for (std::size_t i = 0; i <= 255; ++i) { all_possible_bytes.push_back(static_cast(i)); } auto const encode_string = base64::encode_into( begin(all_possible_bytes), end(all_possible_bytes)); auto const decoded_bytes = base64::decode_into>(encode_string); ASSERT_EQ(all_possible_bytes, decoded_bytes); } // NOLINTNEXTLINE TEST(Base64RoundTripTests, ExhaustiveTests) { std::vector const base64_strings = { "YW55IGNhcm5hbCBwbGVhcw==", "bGVnYWwgcGFzcw==", "dGVzdCBzdHJpbmc=", "bGVnYWwgcHJvdmlkZXI=", "ZW5vdWdoIHRoZSBzYW1lIG9mIHRoZSBwbGFjZQ==", "YW5vdGhlciB0aGUgc3RyYWlnaHQ=", "d2FzIG1lIGFkZHJlc3MgcHJvdmlkZXI=", "YWJvdXQgdGhlIG1hc3RlciBvZiB0aGUgZGFtYWdl", "ZW50aXJlIHRoYXQgYnJvdWdodCBvZiB0aGUgbW9uZXk=", "bGVnYWwgc2VjdXJpdHk=", "YmFzaWMgZ29vZCBvZiB0aGUgcGFkIHN0cmluZw==", "ZGVsZXRlIHN0cmluZyBvZiB0aGUgc3RyYWlnaHQ=", "YnJvdWdodCBvZiB0aGUgcGFkIGZvbGRlciBvZiB0aGUgZGFtYWdl", "aW50ZXJmYWNlIHN0cmluZw==", "Y29uc29sZS1tZS1jb21wYW55", "aW5mb3JtYXRpb24tbWVkaWE=", "c3RhdHVzLXNlY3VyZQ==", "Y3JlYXRlLWNvbXBhbnktc3RyaW5n", "b3JkZXItbGVhZGVy", "Y2F0YWxvZy1wcm9maWxl", "dGVzdC1jb25zdWx0aW5n", "YnJvdWdodC1sZWFkZXI=", "YXNzaWduLW1lY2hhbmlzbQ==", "bGVnYWwtY29udGFpbmVy", "ZW1haWwtY29udGFpbmVy", "aW5zdGFuY2UtY29udGFpbmVy", "dGVzdC1jb21wYW55LWFuZC1wcm9maWxl", "YmFzZTY0LWJhc2U=", "cGFzc3dvcmQ=", "Zm9vYmFy", "Y29vbC1iYXNl", "YmFzZTY0LXNlY3VyZQ==", "aW50ZXJ2YWw=", "dGhlLW1hc3Rlci1vZi10aGUtZGFtYWdl", "c2FtZS1wbGFjZS1vZi10aGUtZGFtYWdl", "aGFzaC1zb21ldGhpbmc="}; for (auto const& b64_string : base64_strings) { auto const decoded = base64::from_base64(b64_string); auto const encoded_round_trip = base64::to_base64(decoded); ASSERT_EQ(encoded_round_trip, b64_string); } } // NOLINTNEXTLINE TEST(Base64OverloadTests, EncodesString1) { std::array, 11> const test_cases = { {{"", ""}, {"Hello, World!", "SGVsbG8sIFdvcmxkIQ=="}, {"abcdefghijklmnopqrstuvwxyz0123456789\\`!\"£$%^&*()_+", "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5XGAhIsKjJCVeJiooKV8r"}, {"Base64 encoding", "QmFzZTY0IGVuY29kaW5n"}, {"I love coding", "SSBsb3ZlIGNvZGluZw=="}, {"C++23 is awesome", "QysrMjMgaXMgYXdlc29tZQ=="}, {"This is a sample", "VGhpcyBpcyBhIHNhbXBsZQ=="}, {"Base64 is useful", "QmFzZTY0IGlzIHVzZWZ1bA=="}, {"Encode and decode", "RW5jb2RlIGFuZCBkZWNvZGU="}, {"Data encryption", "RGF0YSBlbmNyeXB0aW9u"}, {"Th3 Quickk Br0wn f0x", "VGgzIFF1aWNrayAgQnIwd24gZjB4"}}}; for (auto const& [input, expected] : test_cases) { auto const actual = base64::to_base64(input); ASSERT_EQ(actual, expected); } } // NOLINTNEXTLINE TEST(Base64RoundTripTests, TypeMixTests) { const std::string strinput{"Hello, World!"}; const std::string stroutput{"SGVsbG8sIFdvcmxkIQ=="}; typedef std::vector u8vec_type; const u8vec_type uvecinput(strinput.begin(), strinput.end()); const u8vec_type uvecoutput(stroutput.begin(), stroutput.end()); typedef std::vector s8vec_type; const s8vec_type svecinput(strinput.begin(), strinput.end()); const s8vec_type svecoutput(stroutput.begin(), stroutput.end()); // str -> str { auto tmp1 = base64::encode_into(strinput.begin(), strinput.end()); ASSERT_EQ(tmp1, stroutput); auto tmp2 = base64::decode_into(stroutput.begin(), stroutput.end()); ASSERT_EQ(tmp2, strinput); auto tmp3 = base64::encode_into(strinput); ASSERT_EQ(tmp3, stroutput); auto tmp4 = base64::decode_into(stroutput); ASSERT_EQ(tmp4, strinput); auto tmp5 = base64::to_base64(strinput); ASSERT_EQ(tmp5, stroutput); auto tmp6 = base64::from_base64(stroutput); ASSERT_EQ(tmp6, strinput); } // str -> u8 { auto tmp1 = base64::encode_into(strinput.begin(), strinput.end()); ASSERT_EQ(tmp1, uvecoutput); auto tmp2 = base64::decode_into(stroutput.begin(), stroutput.end()); ASSERT_EQ(tmp2, uvecinput); auto tmp3 = base64::encode_into(strinput); ASSERT_EQ(tmp3, uvecoutput); auto tmp4 = base64::decode_into(stroutput); ASSERT_EQ(tmp4, uvecinput); } // str -> s8 { auto tmp1 = base64::encode_into(strinput.begin(), strinput.end()); ASSERT_EQ(tmp1, svecoutput); auto tmp2 = base64::decode_into(stroutput.begin(), stroutput.end()); ASSERT_EQ(tmp2, svecinput); auto tmp3 = base64::encode_into(strinput); ASSERT_EQ(tmp3, svecoutput); auto tmp4 = base64::decode_into(stroutput); ASSERT_EQ(tmp4, svecinput); } // u8 -> str { auto tmp1 = base64::encode_into(uvecinput.begin(), uvecinput.end()); ASSERT_EQ(tmp1, stroutput); auto tmp2 = base64::decode_into(uvecoutput.begin(), uvecoutput.end()); ASSERT_EQ(tmp2, strinput); } // u8 -> u8 { auto tmp1 = base64::encode_into(uvecinput.begin(), uvecinput.end()); ASSERT_EQ(tmp1, uvecoutput); auto tmp2 = base64::decode_into(uvecoutput.begin(), uvecoutput.end()); ASSERT_EQ(tmp2, uvecinput); } // u8 -> s8 { auto tmp1 = base64::encode_into(uvecinput.begin(), uvecinput.end()); ASSERT_EQ(tmp1, svecoutput); auto tmp2 = base64::decode_into(uvecoutput.begin(), uvecoutput.end()); ASSERT_EQ(tmp2, svecinput); } // s8 -> str { auto tmp1 = base64::encode_into(svecinput.begin(), svecinput.end()); ASSERT_EQ(tmp1, stroutput); auto tmp2 = base64::decode_into(svecoutput.begin(), svecoutput.end()); ASSERT_EQ(tmp2, strinput); } // s8 -> u8 { auto tmp1 = base64::encode_into(svecinput.begin(), svecinput.end()); ASSERT_EQ(tmp1, uvecoutput); auto tmp2 = base64::decode_into(svecoutput.begin(), svecoutput.end()); ASSERT_EQ(tmp2, uvecinput); } // s8 -> s8 { auto tmp1 = base64::encode_into(svecinput.begin(), svecinput.end()); ASSERT_EQ(tmp1, svecoutput); auto tmp2 = base64::decode_into(svecoutput.begin(), svecoutput.end()); ASSERT_EQ(tmp2, svecinput); } } int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ================================================ FILE: test/modp_b64_tests.cpp ================================================ // Test suite ported // https://github.com/client9/stringencoders/blob/master/test/modp_b64_test.c #include #include #include #include #include #include "../include/base64.hpp" // NOLINTNEXTLINE TEST(Base64Encode, Padding) { // Test 1-6 bytes input and decode { /* 1 in, 4 out */ std::string const input{1}; auto const encoded{base64::to_base64(input)}; ASSERT_EQ(4, encoded.size()); auto const decoded{base64::from_base64(encoded)}; ASSERT_EQ(input, decoded); } { /* 2 in, 4 out */ std::string const input{1, 1}; auto const encoded{base64::to_base64(input)}; ASSERT_EQ(4, encoded.size()); auto const decoded{base64::from_base64(encoded)}; ASSERT_EQ(input, decoded); } { /* 3 in, 4 out */ std::string const input{1, 1, 1}; auto const encoded{base64::to_base64(input)}; ASSERT_EQ(4, encoded.size()); auto const decoded{base64::from_base64(encoded)}; ASSERT_EQ(input, decoded); } { /* 4 in, 8 out */ std::string const input{1, 1, 1, 1}; auto const encoded{base64::to_base64(input)}; ASSERT_EQ(8, encoded.size()); auto const decoded{base64::from_base64(encoded)}; ASSERT_EQ(input, decoded); } { /* 5 in, 8 out */ std::string const input{1, 1, 1, 1, 1}; auto const encoded{base64::to_base64(input)}; ASSERT_EQ(8, encoded.size()); auto const decoded{base64::from_base64(encoded)}; ASSERT_EQ(input, decoded); } { /* 6 in, 8 out */ std::string const input{1, 1, 1, 1, 1, 6}; auto const encoded{base64::to_base64(input)}; ASSERT_EQ(8, encoded.size()); auto const decoded{base64::from_base64(encoded)}; ASSERT_EQ(input, decoded); } } // NOLINTNEXTLINE TEST(Base64Encode, EncodeDecode) { // Test all 17M 3 bytes inputs to encoder, decode // and make sure it's equal. for (int i = 0; i < 256; ++i) { for (int j = 0; j < 256; ++j) { for (int k = 0; k < 256; ++k) { std::string const input{static_cast(i), static_cast(j), static_cast(k)}; auto const encoded{base64::to_base64(input)}; ASSERT_EQ(4, encoded.size()); auto const decoded{base64::from_base64(encoded)}; ASSERT_EQ(input, decoded); } } } } // NOLINTNEXTLINE TEST(Base64Encode, DecodeErrors) { { // test bad input - all combinations char goodchar = 'A'; char badchar = '~'; std::array decode; for (int i = 1; i < 16; ++i) { decode[0] = static_cast(((i & 0x01) == 0) ? goodchar : badchar); decode[1] = static_cast(((i & 0x02) == 0) ? goodchar : badchar); decode[2] = static_cast(((i & 0x04) == 0) ? goodchar : badchar); decode[3] = static_cast(((i & 0x08) == 0) ? goodchar : badchar); ASSERT_THROW( base64::decode_into(decode.begin(), decode.end()), std::runtime_error); } } { // test just 1-4 padchars for (int i = 1; i <= 4; ++i) { std::vector decode(i, '='); ASSERT_THROW( base64::decode_into(decode.begin(), decode.end()), std::runtime_error); } } { // Test good+3 pad chars (should be impossible) std::string decode("A==="); ASSERT_THROW(base64::decode_into(decode.begin(), decode.end()), std::runtime_error); } } int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ================================================ FILE: test/roundtrip_test.cpp ================================================ #include #include #include #include #include "../include/base64.hpp" int runtests() { const std::vector lengths{5, 10, 100, 1024, 10000, 1000003}; int outcome = EXIT_SUCCESS; std::cout << "char is " << (std::is_signed::value ? "signed" : "unsigned") << std::endl; std::cout << "endianness is " #if defined(__LITTLE_ENDIAN__) << "little endian" #else << "big endian" #endif << std::endl; for (auto& length : lengths) { std::string original; for (int i = 0; i < length; i++) { original += static_cast(std::rand()); } auto encoded = base64::to_base64(original); auto s = base64::from_base64(encoded); if (s == original) { std::cout << "Test passed with length " << length << std::endl; } else { std::cout << "Test FAILED with length " << length << std::endl; outcome = EXIT_FAILURE; } } return outcome; } int main([[maybe_unused]] int argc, [[maybe_unused]] char* argv[]) { try { return runtests(); } catch (const std::exception& e) { // standard exceptions std::cout << "Caught std::exception in main: " << e.what() << std::endl; return EXIT_FAILURE; } catch (...) { // everything else std::cout << "Caught unknown exception in main" << std::endl; return EXIT_FAILURE; } }