From 882e5560ff1ef87074271ffcfbfd41b189fcbc06 Mon Sep 17 00:00:00 2001 From: Mohammad Nejati Date: Wed, 2 Jul 2025 07:35:48 +0000 Subject: [PATCH] add brotli service --- .drone.star | 2 +- .github/workflows/ci.yml | 152 ++++++++++--- CMakeLists.txt | 15 ++ build/Jamfile | 67 +++--- build/brotli.jam | 155 +++++++++++++ cmake/FindBrotli.cmake | 50 +++++ include/boost/rts/brotli.hpp | 18 ++ include/boost/rts/brotli/decode.hpp | 127 +++++++++++ include/boost/rts/brotli/encode.hpp | 175 +++++++++++++++ include/boost/rts/brotli/error.hpp | 76 +++++++ include/boost/rts/brotli/impl/error.hpp | 75 +++++++ .../boost/rts/brotli/shared_dictionary.hpp | 63 ++++++ include/boost/rts/brotli/types.hpp | 29 +++ include/boost/rts/zlib.hpp | 4 +- .../zlib/{deflate_service.hpp => deflate.hpp} | 4 +- include/boost/rts/zlib/impl/error.hpp | 2 +- .../zlib/{inflate_service.hpp => inflate.hpp} | 4 +- meta/explicit-failures-markup.xml | 1 - src/brotli/error.cpp | 104 +++++++++ src/zlib/error.cpp | 2 +- src_brotli/decode.cpp | 187 ++++++++++++++++ src_brotli/encode.cpp | 206 ++++++++++++++++++ src_brotli/shared_dictionary.cpp | 81 +++++++ src_zlib/{deflator.cpp => deflate.cpp} | 2 +- src_zlib/{inflator.cpp => inflate.cpp} | 2 +- test/unit/CMakeLists.txt | 5 + test/unit/Jamfile | 5 + test/unit/brotli.cpp | 56 +++++ 28 files changed, 1599 insertions(+), 70 deletions(-) create mode 100644 build/brotli.jam create mode 100644 cmake/FindBrotli.cmake create mode 100644 include/boost/rts/brotli.hpp create mode 100644 include/boost/rts/brotli/decode.hpp create mode 100644 include/boost/rts/brotli/encode.hpp create mode 100644 include/boost/rts/brotli/error.hpp create mode 100644 include/boost/rts/brotli/impl/error.hpp create mode 100644 include/boost/rts/brotli/shared_dictionary.hpp create mode 100644 include/boost/rts/brotli/types.hpp rename include/boost/rts/zlib/{deflate_service.hpp => deflate.hpp} (95%) rename include/boost/rts/zlib/{inflate_service.hpp => inflate.hpp} (95%) create mode 100644 src/brotli/error.cpp create mode 100644 src_brotli/decode.cpp create mode 100644 src_brotli/encode.cpp create mode 100644 src_brotli/shared_dictionary.cpp rename src_zlib/{deflator.cpp => deflate.cpp} (98%) rename src_zlib/{inflator.cpp => inflate.cpp} (98%) create mode 100644 test/unit/brotli.cpp diff --git a/.drone.star b/.drone.star index 0b9ab91..b9ae688 100644 --- a/.drone.star +++ b/.drone.star @@ -15,7 +15,7 @@ def main(ctx): # Compilers [ 'gcc >=5.0', - 'clang >=3.8', + 'clang >=3.9', 'msvc >=14.1', 'arm64-gcc latest', 's390x-gcc latest', diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d4173b2..94f21dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,8 @@ env: NET_RETRY_COUNT: 5 DEFAULT_BUILD_VARIANT: debug,release UBSAN_OPTIONS: "print_stacktrace=1" - ASAN_OPTIONS: "detect_invalid_pointer_pairs=2" + DEBIAN_FRONTEND: "noninteractive" + TZ: "Europe/London" jobs: runner-selection: @@ -60,12 +61,24 @@ jobs: # Windows compilers # + - compiler: "msvc" + version: "14.42" + cxxstd: "17,20" + latest-cxxstd: "20" + runs-on: "windows-2022" + b2-toolset: "msvc-14.4" + generator: "Visual Studio 17 2022" + is-latest: true + name: "MSVC 14.42: C++17-20" + build-type: "Release" + build-cmake: true + - compiler: "msvc" version: "14.34" cxxstd: "17,20" latest-cxxstd: "20" runs-on: "windows-2022" - b2-toolset: "msvc" + b2-toolset: "msvc-14.3" generator: "Visual Studio 17 2022" is-latest: true name: "MSVC 14.34: C++17-20" @@ -77,7 +90,7 @@ jobs: cxxstd: "17,20" latest-cxxstd: "20" runs-on: "windows-2022" - b2-toolset: "msvc" + b2-toolset: "msvc-14.3" generator: "Visual Studio 17 2022" is-latest: true name: "MSVC 14.34: C++17-20 (x86)" @@ -89,7 +102,7 @@ jobs: cxxstd: "17,20" latest-cxxstd: "20" runs-on: "windows-2022" - b2-toolset: "msvc" + b2-toolset: "msvc-14.3" generator: "Visual Studio 17 2022" is-latest: true name: "MSVC 14.34: C++17-20 (shared)" @@ -97,17 +110,6 @@ jobs: build-type: "Release" build-cmake: true - - compiler: "msvc" - version: "14.29" - cxxstd: "14,17" - latest-cxxstd: "17" - runs-on: "windows-2019" - b2-toolset: "msvc" - generator: "Visual Studio 16 2019" - is-earliest: true - name: "MSVC 14.29: C++14-17" - build-type: "Release" - - compiler: "clang-cl" version: "*" cxx: "clang++-cl" @@ -192,6 +194,7 @@ jobs: b2-toolset: "clang" name: "Apple-Clang (macOS 14)" build-type: "Release" + build-cmake: true - compiler: "apple-clang" version: "*" @@ -201,6 +204,7 @@ jobs: b2-toolset: "clang" name: "Apple-Clang (macOS 13)" build-type: "Release" + build-cmake: true # Linux compilers # @@ -217,6 +221,21 @@ jobs: is-latest: true name: "GCC 14: C++17-20" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" + build-cmake: true + + - compiler: "gcc" + version: "14" + cxxstd: "17,20" + latest-cxxstd: "20" + cxx: "g++-14" + cc: "gcc-14" + runs-on: "ubuntu-latest" + container: "ubuntu:24.04" + b2-toolset: "gcc" + is-latest: true + name: "GCC 14: C++17-20 (no zlib)" + build-type: "Release" build-cmake: true - compiler: "gcc" @@ -232,7 +251,7 @@ jobs: name: "GCC 14: C++17-20 (x86)" x86: true build-type: "Release" - install: "gcc-14-multilib g++-14-multilib" + install: "gcc-14-multilib g++-14-multilib zlib1g-dev libbrotli-dev zlib1g-dev:i386 libbrotli-dev:i386" - compiler: "gcc" version: "14" @@ -247,6 +266,7 @@ jobs: name: "GCC 14: C++17-20 (shared)" shared: true build-type: "Release" + install: "zlib1g-dev libbrotli-dev" build-cmake: true - compiler: "gcc" @@ -263,7 +283,7 @@ jobs: shared: true x86: true build-type: "Release" - install: "gcc-14-multilib g++-14-multilib" + install: "gcc-14-multilib g++-14-multilib zlib1g-dev libbrotli-dev zlib1g-dev:i386 libbrotli-dev:i386" build-cmake: true - compiler: "gcc" @@ -279,6 +299,7 @@ jobs: name: "GCC 14: C++17-20 (asan)" asan: true build-type: "RelWithDebInfo" + install: "zlib1g-dev libbrotli-dev" - compiler: "gcc" version: "14" @@ -294,7 +315,7 @@ jobs: asan: true x86: true build-type: "RelWithDebInfo" - install: "gcc-14-multilib g++-14-multilib" + install: "gcc-14-multilib g++-14-multilib zlib1g-dev libbrotli-dev zlib1g-dev:i386 libbrotli-dev:i386" - compiler: "gcc" version: "14" @@ -309,6 +330,7 @@ jobs: name: "GCC 14: C++17-20 (ubsan)" ubsan: true build-type: "RelWithDebInfo" + install: "zlib1g-dev libbrotli-dev" - compiler: "gcc" version: "14" @@ -324,7 +346,7 @@ jobs: ubsan: true x86: true build-type: "RelWithDebInfo" - install: "gcc-14-multilib g++-14-multilib" + install: "gcc-14-multilib g++-14-multilib zlib1g-dev libbrotli-dev zlib1g-dev:i386 libbrotli-dev:i386" - compiler: "gcc" version: "13" @@ -332,11 +354,11 @@ jobs: latest-cxxstd: "20" cxx: "g++-13" cc: "gcc-13" - runs-on: "ubuntu-latest" - container: "ubuntu:24.04" + runs-on: "ubuntu-24.04" b2-toolset: "gcc" name: "GCC 13: C++17-20" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "gcc" version: "13" @@ -344,8 +366,7 @@ jobs: latest-cxxstd: "20" cxx: "g++-13" cc: "gcc-13" - runs-on: "ubuntu-latest" - container: "ubuntu:24.04" + runs-on: "ubuntu-24.04" b2-toolset: "gcc" is-latest: true name: "GCC 13: C++17-20 (coverage)" @@ -353,7 +374,7 @@ jobs: build-type: "Debug" cxxflags: "--coverage -fprofile-arcs -ftest-coverage" ccflags: "--coverage -fprofile-arcs -ftest-coverage" - install: "lcov zlib1g-dev wget unzip" + install: "lcov zlib1g-dev libbrotli-dev wget unzip" - compiler: "gcc" version: "12" @@ -366,6 +387,7 @@ jobs: b2-toolset: "gcc" name: "GCC 12: C++17-20" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "gcc" version: "11" @@ -378,6 +400,7 @@ jobs: b2-toolset: "gcc" name: "GCC 11: C++17-20" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "gcc" version: "10" @@ -390,6 +413,7 @@ jobs: b2-toolset: "gcc" name: "GCC 10: C++14-17" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "gcc" version: "9" @@ -402,6 +426,7 @@ jobs: b2-toolset: "gcc" name: "GCC 9: C++14-17" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "gcc" version: "8" @@ -414,6 +439,7 @@ jobs: b2-toolset: "gcc" name: "GCC 8: C++14-17" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "gcc" version: "7" @@ -426,6 +452,7 @@ jobs: b2-toolset: "gcc" name: "GCC 7: C++14-17" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "gcc" version: "6" @@ -438,6 +465,7 @@ jobs: b2-toolset: "gcc" name: "GCC 6: C++11-14" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "gcc" version: "5" @@ -451,6 +479,7 @@ jobs: is-earliest: true name: "GCC 5: C++11" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "18" @@ -464,6 +493,7 @@ jobs: is-latest: true name: "Clang 18: C++17-20" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" build-cmake: true - compiler: "clang" @@ -479,7 +509,7 @@ jobs: name: "Clang 18: C++17-20 (x86)" x86: true build-type: "Release" - install: "gcc-multilib g++-multilib" + install: "gcc-multilib g++-multilib zlib1g-dev libbrotli-dev zlib1g-dev:i386 libbrotli-dev:i386" - compiler: "clang" version: "18" @@ -496,7 +526,7 @@ jobs: build-type: "Release" cxxflags: "-ftime-trace" ccflags: "-ftime-trace" - install: "wget unzip" + install: "zlib1g-dev libbrotli-dev wget unzip" - compiler: "clang" version: "18" @@ -511,6 +541,7 @@ jobs: name: "Clang 18: C++17-20 (asan)" asan: true build-type: "RelWithDebInfo" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "18" @@ -526,7 +557,7 @@ jobs: asan: true x86: true build-type: "RelWithDebInfo" - install: "gcc-multilib g++-multilib" + install: "gcc-multilib g++-multilib zlib1g-dev libbrotli-dev zlib1g-dev:i386 libbrotli-dev:i386" - compiler: "clang" version: "18" @@ -541,6 +572,7 @@ jobs: name: "Clang 18: C++17-20 (ubsan)" ubsan: true build-type: "RelWithDebInfo" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "18" @@ -556,7 +588,7 @@ jobs: ubsan: true x86: true build-type: "RelWithDebInfo" - install: "gcc-multilib g++-multilib" + install: "gcc-multilib g++-multilib zlib1g-dev libbrotli-dev zlib1g-dev:i386 libbrotli-dev:i386" - compiler: "clang" version: "17" @@ -564,11 +596,11 @@ jobs: latest-cxxstd: "20" cxx: "clang++-17" cc: "clang-17" - runs-on: "ubuntu-latest" - container: "ubuntu:24.04" + runs-on: "ubuntu-24.04" b2-toolset: "clang" name: "Clang 17: C++17-20" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "16" @@ -576,11 +608,11 @@ jobs: latest-cxxstd: "20" cxx: "clang++-16" cc: "clang-16" - runs-on: "ubuntu-latest" - container: "ubuntu:24.04" + runs-on: "ubuntu-24.04" b2-toolset: "clang" name: "Clang 16: C++17-20" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "15" @@ -593,6 +625,7 @@ jobs: b2-toolset: "clang" name: "Clang 15: C++17-20" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "14" @@ -605,6 +638,7 @@ jobs: b2-toolset: "clang" name: "Clang 14: C++17-20" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "13" @@ -617,6 +651,7 @@ jobs: b2-toolset: "clang" name: "Clang 13: C++17-20" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "12" @@ -629,6 +664,7 @@ jobs: b2-toolset: "clang" name: "Clang 12: C++17-20" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "11" @@ -641,6 +677,7 @@ jobs: b2-toolset: "clang" name: "Clang 11: C++14-17" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "10" @@ -653,6 +690,7 @@ jobs: b2-toolset: "clang" name: "Clang 10: C++14-17" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "9" @@ -665,6 +703,7 @@ jobs: b2-toolset: "clang" name: "Clang 9: C++14-17" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "8" @@ -677,6 +716,7 @@ jobs: b2-toolset: "clang" name: "Clang 8: C++14-17" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "7" @@ -689,6 +729,7 @@ jobs: b2-toolset: "clang" name: "Clang 7: C++14-17" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "6" @@ -701,6 +742,7 @@ jobs: b2-toolset: "clang" name: "Clang 6: C++14-17" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "5" @@ -713,6 +755,7 @@ jobs: b2-toolset: "clang" name: "Clang 5: C++11-14" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "4" @@ -725,6 +768,7 @@ jobs: b2-toolset: "clang" name: "Clang 4: C++11-14" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" - compiler: "clang" version: "3.9" @@ -738,6 +782,7 @@ jobs: is-earliest: true name: "Clang 3.9: C++11" build-type: "Release" + install: "zlib1g-dev libbrotli-dev" name: ${{ matrix.name }} runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)[matrix.runs-on] }} @@ -778,6 +823,7 @@ jobs: uses: alandefreitas/cpp-actions/package-install@v1.8.10 id: package-install with: + apt-get-add-architecture: 'i386' apt-get: >- ${{ matrix.install }} build-essential @@ -793,6 +839,42 @@ jobs: scan-modules-dir: rts-root scan-modules-ignore: rts + - name: Install Packages (Windows) + uses: alandefreitas/cpp-actions/package-install@v1.8.10 + if: ${{ startsWith(matrix.runs-on, 'windows') }} + id: package-install-windows + with: + vcpkg: zlib brotli + vcpkg-dir: vcpkg-root + vcpkg-triplet: ${{ matrix.x86 && 'x86-windows-static' || 'x64-windows' }} + + - name: Patch user-config.jam (Windows) + id: patch-user-config + shell: bash + if: ${{ startsWith(matrix.runs-on, 'windows') }} + run: | + set -xe + home=$(pwd) + + triplet=${{ matrix.x86 && 'x86-windows-static' || 'x64-windows' }} + addrmdl=${{ matrix.x86 && '32' || '64' }} + + # This is temporary until we move rts/build/brotli.jam to boost/tools/build + echo "import-search ${home}/boost-root/libs/rts/build ;" | sed 's/\/d\//D:\//g' >> user-config.jam + + echo "using zlib : : \"${home}/vcpkg-root/installed/${triplet}/include\" \"${home}/vcpkg-root/installed/${triplet}/lib\" \"${home}/vcpkg-root/installed/${triplet}/bin\" zlib : ${addrmdl} ;" | sed 's/\/d\//D:\//g' >> user-config.jam + echo "using brotli : : \"${home}/vcpkg-root/installed/${triplet}/include\" \"${home}/vcpkg-root/installed/${triplet}/lib\" \"${home}/vcpkg-root/installed/${triplet}/bin\" : ${addrmdl} ;" | sed 's/\/d\//D:\//g' >> user-config.jam + + cat user-config.jam + + toolchain=$(echo "$GITHUB_WORKSPACE/vcpkg-root/scripts/buildsystems/vcpkg.cmake" | sed 's/\/d\//D:\//g' ) + echo "toolchain=${toolchain}" >> $GITHUB_OUTPUT + + - name: ASLR Fix + if: ${{ startsWith(matrix.runs-on, 'ubuntu' )}} + run: | + sysctl vm.mmap_rnd_bits=28 + - name: Patch Boost id: patch shell: bash @@ -828,6 +910,8 @@ jobs: - name: Boost B2 Workflow uses: alandefreitas/cpp-actions/b2-workflow@v1.8.10 if: ${{ !matrix.coverage && !matrix.time-trace }} + env: + ASAN_OPTIONS: ${{ ((matrix.compiler == 'apple-clang' || matrix.compiler == 'clang') && 'detect_invalid_pointer_pairs=0:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1') || 'detect_invalid_pointer_pairs=2:strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1' }} with: source-dir: boost-root modules: rts @@ -840,8 +924,10 @@ jobs: ubsan: ${{ matrix.ubsan }} shared: ${{ matrix.shared }} rtti: ${{ (matrix.is-latest && 'on,off') || 'on' }} - cxxflags: ${{ (matrix.asan && '-fsanitize=pointer-subtract') || '' }} + cxxflags: ${{ (matrix.asan && '-fsanitize-address-use-after-scope -fsanitize=pointer-subtract') || '' }} + user-config: ${{ (startsWith(matrix.runs-on, 'windows') && !matrix.skip-zlib && format('{0}/user-config.jam', steps.patch.outputs.workspace_root)) || '' }} stop-on-error: true + extra-args: ${{ (matrix.valgrind && 'testing.launcher=valgrind' || '' )}} - name: Boost CMake Workflow uses: alandefreitas/cpp-actions/cmake-workflow@v1.8.10 diff --git a/CMakeLists.txt b/CMakeLists.txt index eedff39..47ad5f7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -165,6 +165,21 @@ if (ZLIB_FOUND) target_compile_definitions(boost_rts_zlib PRIVATE BOOST_RTS_SOURCE) endif () +# Brotli +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") +find_package(Brotli) +if (Brotli_FOUND) + file(GLOB_RECURSE BOOST_RTS_BROTLI_SOURCES CONFIGURE_DEPENDS src_brotli/*.cpp src_brotli/*.hpp) + file(GLOB_RECURSE BOOST_RTS_BROTLI_HEADERS CONFIGURE_DEPENDS include/boost/rts/brotli/*.hpp) + source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR}/src_brotli PREFIX "src" FILES ${BOOST_RTS_BROTLI_SOURCES}) + add_library(boost_rts_brotli build/Jamfile ${BOOST_RTS_BROTLI_HEADERS} ${BOOST_RTS_BROTLI_SOURCES}) + add_library(Boost::rts_brotli ALIAS boost_rts_brotli) + target_link_libraries(boost_rts_brotli PUBLIC boost_rts) + target_link_libraries(boost_rts_brotli PRIVATE Brotli::common Brotli::decoder Brotli::encoder) + target_compile_definitions(boost_rts_brotli PUBLIC BOOST_RTS_HAS_BROTLI) + target_compile_definitions(boost_rts_brotli PRIVATE BOOST_RTS_SOURCE) +endif () + #------------------------------------------------- # # Tests diff --git a/build/Jamfile b/build/Jamfile index b054624..4677316 100644 --- a/build/Jamfile +++ b/build/Jamfile @@ -10,8 +10,6 @@ import ac ; import ../../config/checks/config : requires ; -using zlib ; - constant c11-requires : [ requires cxx11_constexpr @@ -25,40 +23,59 @@ constant c11-requires : path-constant RTS_ROOT : .. ; project boost/rts - : requirements - $(c11-requires) - shared:BOOST_RTS_DYN_LINK=1 - static:BOOST_RTS_STATIC_LINK=1 - BOOST_RTS_SOURCE - : usage-requirements - shared:BOOST_RTS_DYN_LINK=1 - static:BOOST_RTS_STATIC_LINK=1 - : source-location $(RTS_ROOT) - ; + : requirements + $(c11-requires) + BOOST_RTS_SOURCE + : common-requirements + shared:BOOST_RTS_DYN_LINK + static:BOOST_RTS_STATIC_LINK + : usage-requirements + BOOST_RTS_NO_LIB + : source-location $(RTS_ROOT) + ; alias rts_sources : [ glob-tree-ex ./src : *.cpp ] ; lib boost_rts - : rts_sources - : requirements - : usage-requirements - ; + : rts_sources + : requirements + : usage-requirements + ; boost-install boost_rts ; - # Zlib +using zlib ; alias rts_zlib_sources : [ glob-tree-ex ./src_zlib : *.cpp ] ; lib boost_rts_zlib - : rts_zlib_sources - : requirements - /boost/rts//boost_rts - [ ac.check-library /zlib//zlib : /zlib//zlib : no ] - : usage-requirements - /boost/rts//boost_rts - BOOST_RTS_HAS_ZLIB - ; + : rts_zlib_sources + : requirements + /boost/rts//boost_rts + [ ac.check-library /zlib//zlib : /zlib//zlib : no ] + : usage-requirements + /boost/rts//boost_rts + BOOST_RTS_HAS_ZLIB + ; boost-install boost_rts_zlib ; + +# Brotli +using brotli ; + +alias rts_brotli_sources : [ glob-tree-ex ./src_brotli : *.cpp ] ; + +lib boost_rts_brotli + : rts_brotli_sources + : requirements + /boost/rts//boost_rts + [ ac.check-library /brotli//brotlicommon : /brotli//brotlicommon : no ] + [ ac.check-library /brotli//brotlidec : /brotli//brotlidec : no ] + [ ac.check-library /brotli//brotlienc : /brotli//brotlienc : no ] + : usage-requirements + /boost/rts//boost_rts + BOOST_RTS_HAS_BROTLI + ; + +boost-install boost_rts_brotli ; diff --git a/build/brotli.jam b/build/brotli.jam new file mode 100644 index 0000000..83f78d4 --- /dev/null +++ b/build/brotli.jam @@ -0,0 +1,155 @@ +# Copyright (c) 2025 Mohammad Nejati +# +# Use, modification and distribution is subject to the Boost Software +# License Version 1.0. (See accompanying file LICENSE.txt or +# https://www.bfgroup.xyz/b2/LICENSE.txt) + +# Supports the brotli library +# +# After 'using brotli', the following targets are available: +# +# /brotli//brotlicommon -- The brotli common library +# /brotli//brotlidec -- The brotli decoder library +# /brotli//brotlienc -- The brotli encoder library + +import project ; +import ac ; +import errors ; +import feature ; +import "class" : new ; +import targets ; +import path ; +import modules ; +import indirect ; +import property ; +import property-set ; +import args ; + +header = brotli/decode.h ; +brotlicommon_names = brotlicommon libbrotlicommon ; +brotlidec_names = brotlidec libbrotlidec ; +brotlienc_names = brotlienc libbrotlienc ; + +library-id = 0 ; + +.debug = [ args.get-arg debug-configuration ] ; + +# Initializes the brotli library. +# +# Options for configuring brotli:: +# +# +# The directory containing the brotli binaries. +# +# Overrides the default name of brotlicommon library. +# +# Overrides the default name of brotlidec library. +# +# Overrides the default name of brotlienc library. +# +# The directory containing the brotli headers. +# +# Extra directories to add to library search paths of consumers during +# runtime (multiple instances are allowed). +# +# If none of these options is specified, then the environmental +# variables BROTLI_LIBRARY_PATH, BROTLI_NAME, and BROTLI_INCLUDE will +# be used instead. +# +# Examples:: +# +# # Find brotli in the default system location +# using brotli ; +# # Find brotli in /usr/local +# using brotli : 1.1.0 +# : /usr/local/include /usr/local/lib ; +# +rule init ( + version ? + # (currently ignored) + + : options * + # A list of the options to use + + : requirements * + # The requirements for the target + + : is-default ? + ) +{ + local caller = [ project.current ] ; + + if ! $(.initialized) + { + .initialized = true ; + + project.initialize $(__name__) ; + .project = [ project.current ] ; + project brotli ; + } + + local library-path = [ feature.get-values : $(options) ] ; + local include-path = [ feature.get-values : $(options) ] ; + local brotlicommon-name = [ feature.get-values : $(options) ] ; + local brotlidec-name = [ feature.get-values : $(options) ] ; + local brotlienc-name = [ feature.get-values : $(options) ] ; + local dll-paths = [ property.select : $(options) ] ; + + if ! $(options) + { + is-default = true ; + } + + condition = [ property-set.create $(requirements) ] ; + condition = [ property-set.create [ $(condition).base ] ] ; + + if $(.configured.$(condition)) + { + if $(is-default) + { + if $(.debug) + { + ECHO "notice: [brotli] brotli is already configured" ; + } + } + else + { + errors.user-error "brotli is already configured" ; + } + return ; + } + else + { + if $(.debug) + { + ECHO "notice: [brotli] Using pre-installed library" ; + if $(condition) + { + ECHO "notice: [brotli] Condition" [ $(condition).raw ] ; + } + } + + local brotlicommon = [ new ac-library brotlicommon : $(.project) : $(condition) : + $(include-path) : $(library-path) : $(brotlicommon-name) ] ; + $(brotlicommon).set-header $(header) ; + $(brotlicommon).set-default-names $(brotlicommon_names) ; + $(brotlicommon).add-usage-requirements $(dll-paths) ; + + local brotlidec = [ new ac-library brotlidec : $(.project) : $(condition) : + $(include-path) : $(library-path) : $(brotlidec-name) ] ; + $(brotlidec).set-header $(header) ; + $(brotlidec).set-default-names $(brotlidec_names) ; + $(brotlidec).add-usage-requirements $(dll-paths) ; + + local brotlienc = [ new ac-library brotlienc : $(.project) : $(condition) : + $(include-path) : $(library-path) : $(brotlienc-name) ] ; + $(brotlienc).set-header $(header) ; + $(brotlienc).set-default-names $(brotlienc_names) ; + $(brotlienc).add-usage-requirements $(dll-paths) ; + + targets.main-target-alternative $(brotlicommon) ; + targets.main-target-alternative $(brotlidec) ; + targets.main-target-alternative $(brotlienc) ; + } + .configured.$(condition) = true ; +} diff --git a/cmake/FindBrotli.cmake b/cmake/FindBrotli.cmake new file mode 100644 index 0000000..3a51838 --- /dev/null +++ b/cmake/FindBrotli.cmake @@ -0,0 +1,50 @@ +# +# Copyright (c) 2025 Mohammad Nejati +# +# Distributed under the Boost Software License, Version 1.0. (See accompanying +# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +# +# Official repository: https://github.com/cppalliance/rts +# + +# Provides imported targets: +# Brotli::common +# Brotli::decoder +# Brotli::encoder + +find_path(Brotli_INCLUDE_DIR "brotli/decode.h") +find_library(Brotli_COMMON_LIBRARY NAMES "brotlicommon") +find_library(Brotli_DEC_LIBRARY NAMES "brotlidec") +find_library(Brotli_ENC_LIBRARY NAMES "brotlienc") + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Brotli + REQUIRED_VARS + Brotli_INCLUDE_DIR + Brotli_COMMON_LIBRARY + Brotli_DEC_LIBRARY + Brotli_ENC_LIBRARY +) + +if(Brotli_FOUND) + add_library(Brotli::common UNKNOWN IMPORTED) + set_target_properties(Brotli::common PROPERTIES + IMPORTED_LOCATION ${Brotli_COMMON_LIBRARY} + INTERFACE_INCLUDE_DIRECTORIES ${Brotli_INCLUDE_DIR}) + + add_library(Brotli::decoder UNKNOWN IMPORTED) + set_target_properties(Brotli::decoder PROPERTIES + IMPORTED_LOCATION ${Brotli_DEC_LIBRARY} + INTERFACE_INCLUDE_DIRECTORIES ${Brotli_INCLUDE_DIR}) + + add_library(Brotli::encoder UNKNOWN IMPORTED) + set_target_properties(Brotli::encoder PROPERTIES + IMPORTED_LOCATION ${Brotli_ENC_LIBRARY} + INTERFACE_INCLUDE_DIRECTORIES ${Brotli_INCLUDE_DIR}) +endif() + +mark_as_advanced( + Brotli_INCLUDE_DIR + Brotli_COMMON_LIBRARY + Brotli_DEC_LIBRARY + Brotli_ENC_LIBRARY) diff --git a/include/boost/rts/brotli.hpp b/include/boost/rts/brotli.hpp new file mode 100644 index 0000000..24becb5 --- /dev/null +++ b/include/boost/rts/brotli.hpp @@ -0,0 +1,18 @@ +// +// Copyright (c) 2025 Mohammad Nejati +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/rts +// + +#ifndef BOOST_RTS_BROTLI_HPP +#define BOOST_RTS_BROTLI_HPP + +#include +#include +#include +#include + +#endif diff --git a/include/boost/rts/brotli/decode.hpp b/include/boost/rts/brotli/decode.hpp new file mode 100644 index 0000000..2d61335 --- /dev/null +++ b/include/boost/rts/brotli/decode.hpp @@ -0,0 +1,127 @@ +// +// Copyright (c) 2025 Mohammad Nejati +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/rts +// + +#ifndef BOOST_RTS_BROTLI_DECODE_HPP +#define BOOST_RTS_BROTLI_DECODE_HPP + +#include +#include + +namespace boost { +namespace rts { +namespace brotli { + +/** Opaque structure that holds decoder state. */ +struct decoder_state; + +/** Result type for decompress and decompress_stream functions. */ +enum class decoder_result +{ + error = 0, + success = 1, + needs_more_input = 2, + needs_more_output = 3 +}; + +/** Options to be used with set_parameter. */ +enum class decoder_param +{ + disable_ring_buffer_reallocation = 0, + large_window = 1 +}; + +/** Callback to fire on metadata block start. */ +using metadata_start_func = void (*)(void* opaque, std::size_t size); + +/** Callback to fire on metadata block chunk becomes available. */ +using metadata_chunk_func = void (*)(void* opaque, const std::uint8_t* data, std::size_t size); + +/** Provides the Brotli decompression API */ +struct BOOST_SYMBOL_VISIBLE +decode_service + : public service +{ + virtual bool + set_parameter( + decoder_state* state, + decoder_param param, + std::uint32_t value) const noexcept = 0; + + virtual decoder_state* + create_instance( + alloc_func alloc_func, + free_func free_func, + void* opaque) const noexcept = 0; + + virtual void + destroy_instance(decoder_state* state) const noexcept = 0; + + virtual decoder_result + decompress( + std::size_t encoded_size, + const std::uint8_t encoded_buffer[], + std::size_t* decoded_size, + std::uint8_t decoded_buffer[]) const noexcept = 0; + + virtual decoder_result + decompress_stream( + decoder_state* state, + std::size_t* available_in, + const std::uint8_t** next_in, + std::size_t* available_out, + std::uint8_t** next_out, + std::size_t* total_out) const noexcept = 0; + + virtual bool + has_more_output(const decoder_state* state) const noexcept = 0; + + virtual const std::uint8_t* + take_output(decoder_state* state, std::size_t* size) const noexcept = 0; + + virtual bool + is_used(const decoder_state* state) const noexcept = 0; + + virtual bool + is_finished(const decoder_state* state) const noexcept = 0; + + virtual error + get_error_code(const decoder_state* state) const noexcept = 0; + + virtual const char* + error_string(error c) const noexcept = 0; + + virtual std::uint32_t + version() const noexcept = 0; + +#if 0 + virtual bool + attach_dictionary( + decoder_state* state, + shared_dictionary_type type, + std::size_t data_size, + const std::uint8_t data[]) const noexcept = 0; + + virtual void + set_metadata_callbacks( + decoder_state* state, + metadata_start_func start_func, + metadata_chunk_func chunk_func, + void* opaque) const noexcept = 0; +#endif +}; + +BOOST_RTS_DECL +decode_service& +install_decode_service(context& ctx); + +} // brotli +} // rts +} // boost + +#endif diff --git a/include/boost/rts/brotli/encode.hpp b/include/boost/rts/brotli/encode.hpp new file mode 100644 index 0000000..b3dd288 --- /dev/null +++ b/include/boost/rts/brotli/encode.hpp @@ -0,0 +1,175 @@ +// +// Copyright (c) 2025 Mohammad Nejati +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/rts +// + +#ifndef BOOST_RTS_BROTLI_ENCODE_HPP +#define BOOST_RTS_BROTLI_ENCODE_HPP + +#include + +namespace boost { +namespace rts { +namespace brotli { + +/** Opaque structure that holds encoder state. */ +struct encoder_state; + +/** Opaque type for pointer to different possible internal + structures containing dictionary prepared for the encoder +*/ +struct encoder_prepared_dictionary; + +/** Options for ::BROTLI_PARAM_MODE parameter. */ +enum class encoder_mode +{ + generic = 0, + text = 1, + font = 2 +}; + +/** Operations that can be performed by streaming encoder. */ +enum class encoder_operation +{ + process = 0, + flush = 1, + finish = 2, + emit_metadata = 3 +}; + +/** Options to be used with ::SetParameter. */ +enum class encoder_parameter +{ + mode = 0, + quality = 1, + lgwin = 2, + lgblock = 3, + disable_literal_context_modeling = 4, + size_hint = 5, + large_window = 6, + npostfix = 7, + ndirect = 8, + stream_offset = 9 +}; + +/** Different constants in Brotli API */ +enum constants +{ + min_window_bits = 10, + max_window_bits = 24, + + large_max_window_bits = 30, + + min_input_block_bits = 16, + max_input_block_bits = 24, + + min_quality = 0, + max_quality = 11, + + default_quality = 11, + default_window = 22, + default_mode = 0 +}; + +/** Provides the Brotli compression API */ +struct BOOST_SYMBOL_VISIBLE +encode_service + : public service +{ + virtual bool + set_parameter( + encoder_state* state, + encoder_parameter param, + std::uint32_t value) const noexcept = 0; + + virtual encoder_state* + create_instance( + alloc_func alloc_func, + free_func free_func, + void* opaque) const noexcept = 0; + + virtual void + destroy_instance(encoder_state* state) const noexcept = 0; + + virtual std::size_t + max_compressed_size(std::size_t input_size) const noexcept = 0; + + virtual bool + compress( + int quality, + int lgwin, + encoder_mode mode, + std::size_t input_size, + const std::uint8_t input_buffer[], + std::size_t* encoded_size, + std::uint8_t encoded_buffer[]) const noexcept = 0; + + virtual bool + compress_stream( + encoder_state* state, + encoder_operation op, + std::size_t* available_in, + const std::uint8_t** next_in, + std::size_t* available_out, + std::uint8_t** next_out, + std::size_t* total_out) const noexcept = 0; + + virtual bool + is_finished(encoder_state* state) const noexcept = 0; + + virtual bool + has_more_output(encoder_state* state) const noexcept = 0; + + virtual const std::uint8_t* + take_output( + encoder_state* state, + std::size_t* size) const noexcept = 0; + + virtual std::uint32_t + version() const noexcept = 0; + +#if 0 + virtual encoder_prepared_dictionary* + prepare_dictionary( + shared_dictionary_type type, + std::size_t data_size, + const std::uint8_t data[], + int quality, + alloc_func alloc_func, + free_func free_func, + void* opaque) const noexcept = 0; + + virtual void + destroy_prepared_dictionary( + encoder_prepared_dictionary* dictionary) const noexcept = 0; + + virtual bool + attach_prepared_dictionary( + encoder_state* state, + const encoder_prepared_dictionary* dictionary) const noexcept = 0; + + virtual std::size_t + estimate_peak_memory_usage( + int quality, + int lgwin, + std::size_t input_size) const noexcept = 0; + + virtual std::size_t + get_prepared_dictionary_size( + const encoder_prepared_dictionary* dictionary) const noexcept = 0; +#endif +}; + +BOOST_RTS_DECL +encode_service& +install_encode_service(context& ctx); + +} // brotli +} // rts +} // boost + +#endif diff --git a/include/boost/rts/brotli/error.hpp b/include/boost/rts/brotli/error.hpp new file mode 100644 index 0000000..066c1ef --- /dev/null +++ b/include/boost/rts/brotli/error.hpp @@ -0,0 +1,76 @@ +// +// Copyright (c) 2025 Mohammad Nejati +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/rts +// + +#ifndef BOOST_RTS_BROTLI_ERROR_HPP +#define BOOST_RTS_BROTLI_ERROR_HPP + +namespace boost { +namespace rts { +namespace brotli { + +/** Error codes returned from decode functions. + + Negative values are errors, positive values are used + for special but normal events. +*/ +enum class error +{ + no_error = 0, + + /* Same as decoder_result values */ + success = 1, + needs_more_input = 2, + needs_more_output = 3, + + /* Errors caused by invalid input */ + format_exuberant_nibble = -1, + format_reserved = -2, + format_exuberant_meta_nibbl = -3, + format_simple_huffman_alphabet = -4, + format_simple_huffman_same = -5, + format_cl_space = -6, + format_huffman_space = -7, + format_context_map_repea = -8, + format_block_length_1 = -9, + format_block_length_2 = -10, + format_transform = -11, + format_dictionary = -12, + format_window_bits = -13, + format_padding_1 = -14, + format_padding_2 = -15, + format_distance = -16, + + /* -17 code is reserved */ + + compound_dictionary = -18, + dictionary_not_set = -19, + invalid_arguments = -20, + + /* Memory allocation problems */ + alloc_context_modes = -21, + /* Literal, insert and distance trees together */ + alloc_tree_groups = -22, + /* -23..-24 codes are reserved for distinct tree groups */ + alloc_context_map = -25, + alloc_ring_buffer_1 = -26, + alloc_ring_buffer_2 = -27, + /* -28..-29 codes are reserved for dynamic ring-buffer allocation */ + alloc_block_type_trees = -30, + + /* "Impossible" states */ + unreachable = -31 +}; + +} // brotli +} // rts +} // boost + +#include + +#endif diff --git a/include/boost/rts/brotli/impl/error.hpp b/include/boost/rts/brotli/impl/error.hpp new file mode 100644 index 0000000..fe63319 --- /dev/null +++ b/include/boost/rts/brotli/impl/error.hpp @@ -0,0 +1,75 @@ +// +// Copyright (c) 2021 Vinnie Falco (vinnie.falco@gmail.com) +// Copyright (c) 2024 Mohammad Nejati +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/rts +// + +#ifndef BOOST_RTS_BROTLI_IMPL_ERROR_HPP +#define BOOST_RTS_BROTLI_IMPL_ERROR_HPP + +#include + +#include +#include + +namespace boost { + +namespace system { +template<> +struct is_error_code_enum< + ::boost::rts::brotli::error> +{ + static bool const value = true; +}; +} // system + +namespace rts { +namespace brotli { + +namespace detail { + +struct BOOST_SYMBOL_VISIBLE + error_cat_type + : system::error_category +{ + BOOST_RTS_DECL const char* name( + ) const noexcept override; + BOOST_RTS_DECL bool failed( + int) const noexcept override; + BOOST_RTS_DECL std::string message( + int) const override; + BOOST_RTS_DECL char const* message( + int, char*, std::size_t + ) const noexcept override; + BOOST_SYSTEM_CONSTEXPR error_cat_type() + : error_category(0xc38951ab8832fb6f) + { + } +}; + +BOOST_RTS_DECL extern + error_cat_type error_cat; + +} // detail + +inline +BOOST_SYSTEM_CONSTEXPR +system::error_code +make_error_code( + error ev) noexcept +{ + return system::error_code{ + static_cast::type>(ev), + detail::error_cat}; +} + +} // brotli +} // rts +} // boost + +#endif diff --git a/include/boost/rts/brotli/shared_dictionary.hpp b/include/boost/rts/brotli/shared_dictionary.hpp new file mode 100644 index 0000000..ece9ef1 --- /dev/null +++ b/include/boost/rts/brotli/shared_dictionary.hpp @@ -0,0 +1,63 @@ +// +// Copyright (c) 2025 Mohammad Nejati +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/rts +// + +#ifndef BOOST_RTS_BROTLI_SHARED_DICTIONARY_HPP +#define BOOST_RTS_BROTLI_SHARED_DICTIONARY_HPP + +#include +#include + +namespace boost { +namespace rts { +namespace brotli { + +/** Opaque structure that holds shared dictionary data. */ +struct shared_dictionary; + +/** Input data type for attach. */ +enum class shared_dictionary_type +{ + raw = 0, + serialized = 1 +}; + +/** Provides the Brotli shared_dictionary API */ +struct BOOST_SYMBOL_VISIBLE +shared_dictionary_service + : public service +{ +#if 0 + virtual shared_dictionary* + create_instance( + alloc_func alloc_func, + free_func free_func, + void* opaque) const noexcept = 0; + + virtual void + destroy_instance( + shared_dictionary* dict) const noexcept = 0; + + virtual bool + attach( + shared_dictionary* dict, + shared_dictionary_type type, + std::size_t data_size, + const uint8_t data[]) const noexcept = 0; +#endif +}; + +BOOST_RTS_DECL +shared_dictionary_service& +install_shared_dictionary_service(context& ctx); + +} // brotli +} // rts +} // boost + +#endif diff --git a/include/boost/rts/brotli/types.hpp b/include/boost/rts/brotli/types.hpp new file mode 100644 index 0000000..3605db1 --- /dev/null +++ b/include/boost/rts/brotli/types.hpp @@ -0,0 +1,29 @@ +// +// Copyright (c) 2025 Mohammad Nejati +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/rts +// + +#ifndef BOOST_RTS_BROTLI_TYPES_HPP +#define BOOST_RTS_BROTLI_TYPES_HPP + +#include + +namespace boost { +namespace rts { +namespace brotli { + +/** Allocating function pointer type. */ +using alloc_func = void* (*)(void* opaque, std::size_t size); + +/** Deallocating function pointer type. */ +using free_func = void (*)(void* opaque, void* address); + +} // brotli +} // rts +} // boost + +#endif diff --git a/include/boost/rts/zlib.hpp b/include/boost/rts/zlib.hpp index d0c161c..6f1a459 100644 --- a/include/boost/rts/zlib.hpp +++ b/include/boost/rts/zlib.hpp @@ -14,10 +14,10 @@ #include #include #include -#include +#include #include #include -#include +#include #include #endif diff --git a/include/boost/rts/zlib/deflate_service.hpp b/include/boost/rts/zlib/deflate.hpp similarity index 95% rename from include/boost/rts/zlib/deflate_service.hpp rename to include/boost/rts/zlib/deflate.hpp index 3a3e2c8..2e9ffb4 100644 --- a/include/boost/rts/zlib/deflate_service.hpp +++ b/include/boost/rts/zlib/deflate.hpp @@ -8,8 +8,8 @@ // Official repository: https://github.com/cppalliance/rts // -#ifndef BOOST_RTS_ZLIB_DEFLATE_SERVICE_HPP -#define BOOST_RTS_ZLIB_DEFLATE_SERVICE_HPP +#ifndef BOOST_RTS_ZLIB_DEFLATE_HPP +#define BOOST_RTS_ZLIB_DEFLATE_HPP #include #include diff --git a/include/boost/rts/zlib/impl/error.hpp b/include/boost/rts/zlib/impl/error.hpp index 7b3b2ae..eb1e307 100644 --- a/include/boost/rts/zlib/impl/error.hpp +++ b/include/boost/rts/zlib/impl/error.hpp @@ -46,7 +46,7 @@ struct BOOST_SYMBOL_VISIBLE int, char*, std::size_t ) const noexcept override; BOOST_SYSTEM_CONSTEXPR error_cat_type() - : error_category(0xe6c6d0215d1d6e22) + : error_category(0x43fd42f819852b73) { } }; diff --git a/include/boost/rts/zlib/inflate_service.hpp b/include/boost/rts/zlib/inflate.hpp similarity index 95% rename from include/boost/rts/zlib/inflate_service.hpp rename to include/boost/rts/zlib/inflate.hpp index 74d61f5..4065241 100644 --- a/include/boost/rts/zlib/inflate_service.hpp +++ b/include/boost/rts/zlib/inflate.hpp @@ -8,8 +8,8 @@ // Official repository: https://github.com/cppalliance/rts // -#ifndef BOOST_RTS_ZLIB_INFLATE_SERVICE_HPP -#define BOOST_RTS_ZLIB_INFLATE_SERVICE_HPP +#ifndef BOOST_RTS_ZLIB_INFLATE_HPP +#define BOOST_RTS_ZLIB_INFLATE_HPP #include #include diff --git a/meta/explicit-failures-markup.xml b/meta/explicit-failures-markup.xml index ec2593f..ce36f17 100644 --- a/meta/explicit-failures-markup.xml +++ b/meta/explicit-failures-markup.xml @@ -1,6 +1,5 @@ - diff --git a/src/brotli/error.cpp b/src/brotli/error.cpp new file mode 100644 index 0000000..8bb4588 --- /dev/null +++ b/src/brotli/error.cpp @@ -0,0 +1,104 @@ +// +// Copyright (c) 2024 Mohammad Nejati +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/rts +// + +#include + +namespace boost { +namespace rts { +namespace brotli { +namespace detail { + +const char* +error_cat_type:: +name() const noexcept +{ + return "boost.rts.brotli"; +} + +bool +error_cat_type:: +failed(int ev) const noexcept +{ + return ev < 0; +} + +std::string +error_cat_type:: +message(int ev) const +{ + return message(ev, nullptr, 0); +} + +char const* +error_cat_type:: +message( + int ev, + char*, + std::size_t) const noexcept +{ + switch(static_cast(ev)) + { + + case error::no_error: return "no_error"; + case error::success: return "success"; + case error::needs_more_input: return "needs_more_input"; + case error::needs_more_output: return "needs_more_output"; + case error::format_exuberant_nibble: return "format_exuberant_nibble"; + case error::format_reserved: return "format_reserved"; + case error::format_exuberant_meta_nibbl: return "format_exuberant_meta_nibbl"; + case error::format_simple_huffman_alphabet: return "format_simple_huffman_alphabet"; + case error::format_simple_huffman_same: return "format_simple_huffman_same"; + case error::format_cl_space: return "format_cl_space"; + case error::format_huffman_space: return "format_huffman_space"; + case error::format_context_map_repea: return "format_context_map_repea"; + case error::format_block_length_1: return "format_block_length_1"; + case error::format_block_length_2: return "format_block_length_2"; + case error::format_transform: return "format_transform"; + case error::format_dictionary: return "format_dictionary"; + case error::format_window_bits: return "format_window_bits"; + case error::format_padding_1: return "format_padding_1"; + case error::format_padding_2: return "format_padding_2"; + case error::format_distance: return "format_distance"; + case error::compound_dictionary: return "compound_dictionary"; + case error::dictionary_not_set: return "dictionary_not_set"; + case error::invalid_arguments: return "invalid_arguments"; + case error::alloc_context_modes: return "alloc_context_modes"; + case error::alloc_tree_groups: return "alloc_tree_groups"; + case error::alloc_context_map: return "alloc_context_map"; + case error::alloc_ring_buffer_1: return "alloc_ring_buffer_1"; + case error::alloc_ring_buffer_2: return "alloc_ring_buffer_2"; + case error::alloc_block_type_trees: return "alloc_block_type_trees"; + case error::unreachable: return "unreachable"; + default: + return "unknown"; + } +} + +// msvc 14.0 has a bug that warns about inability +// to use constexpr construction here, even though +// there's no constexpr construction +#if defined(_MSC_VER) && _MSC_VER <= 1900 +# pragma warning( push ) +# pragma warning( disable : 4592 ) +#endif + +#if defined(__cpp_constinit) && __cpp_constinit >= 201907L +constinit error_cat_type error_cat; +#else +error_cat_type error_cat; +#endif + +#if defined(_MSC_VER) && _MSC_VER <= 1900 +# pragma warning( pop ) +#endif + +} // detail +} // brotli +} // rts +} // boost diff --git a/src/zlib/error.cpp b/src/zlib/error.cpp index 409fc21..557384b 100644 --- a/src/zlib/error.cpp +++ b/src/zlib/error.cpp @@ -18,7 +18,7 @@ const char* error_cat_type:: name() const noexcept { - return "boost.http.proto.zlib"; + return "boost.rts.zlib"; } bool diff --git a/src_brotli/decode.cpp b/src_brotli/decode.cpp new file mode 100644 index 0000000..97226b0 --- /dev/null +++ b/src_brotli/decode.cpp @@ -0,0 +1,187 @@ +// +// Copyright (c) 2025 Mohammad Nejati +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/rts +// + +#include + +#include + +namespace boost { +namespace rts { +namespace brotli { + +class decode_service_impl + : public decode_service +{ +public: + using key_type = decode_service; + + explicit + decode_service_impl( + rts::context&) noexcept + { + } + + ~decode_service_impl() + { + } + + bool + set_parameter( + decoder_state* state, + decoder_param param, + std::uint32_t value) const noexcept override + { + return BrotliDecoderSetParameter( + reinterpret_cast(state), + static_cast(param), + value); + } + + decoder_state* + create_instance(alloc_func alloc_func, free_func free_func, void* opaque) + const noexcept override + { + return reinterpret_cast( + BrotliDecoderCreateInstance( + alloc_func, + free_func, + opaque)); + } + + void + destroy_instance(decoder_state* state) const noexcept override + { + BrotliDecoderDestroyInstance( + reinterpret_cast(state)); + } + + decoder_result + decompress( + std::size_t encoded_size, + const std::uint8_t encoded_buffer[], + std::size_t* decoded_size, + std::uint8_t decoded_buffer[]) const noexcept override + { + return static_cast( + BrotliDecoderDecompress( + encoded_size, + encoded_buffer, + decoded_size, + decoded_buffer)); + } + + decoder_result + decompress_stream( + decoder_state* state, + std::size_t* available_in, + const std::uint8_t** next_in, + std::size_t* available_out, + std::uint8_t** next_out, + std::size_t* total_out) const noexcept override + { + return static_cast( + BrotliDecoderDecompressStream( + reinterpret_cast(state), + available_in, + next_in, + available_out, + next_out, + total_out)); + } + + bool + has_more_output(const decoder_state* state) const noexcept override + { + return BrotliDecoderHasMoreOutput( + reinterpret_cast(state)); + } + + const std::uint8_t* + take_output(decoder_state* state, std::size_t* size) const noexcept override + { + return BrotliDecoderTakeOutput( + reinterpret_cast(state), + size); + } + + bool + is_used(const decoder_state* state) const noexcept override + { + return BrotliDecoderIsUsed( + reinterpret_cast(state)); + } + + bool + is_finished(const decoder_state* state) const noexcept override + { + return BrotliDecoderIsFinished( + reinterpret_cast(state)); + } + + error + get_error_code(const decoder_state* state) const noexcept override + { + return static_cast( + BrotliDecoderGetErrorCode( + reinterpret_cast(state))); + } + + const char* + error_string(error c) const noexcept override + { + return BrotliDecoderErrorString( + static_cast(c)); + } + + std::uint32_t + version() const noexcept override + { + return BrotliDecoderVersion(); + } + +#if 0 + bool + attach_dictionary( + decoder_state* state, + shared_dictionary_type type, + std::size_t data_size, + const std::uint8_t data[]) const noexcept override + { + return BrotliDecoderAttachDictionary( + reinterpret_cast(state), + static_cast(type), + data_size, + data); + } + + void + set_metadata_callbacks( + decoder_state* state, + metadata_start_func start_func, + metadata_chunk_func chunk_func, + void* opaque) const noexcept override + { + BrotliDecoderSetMetadataCallbacks( + reinterpret_cast(state), + start_func, + chunk_func, + opaque); + } +#endif +}; + +decode_service& +install_decode_service(context& ctx) +{ + return ctx.make_service(); +} + +} // brotli +} // rts +} // boost diff --git a/src_brotli/encode.cpp b/src_brotli/encode.cpp new file mode 100644 index 0000000..a006eaf --- /dev/null +++ b/src_brotli/encode.cpp @@ -0,0 +1,206 @@ +// +// Copyright (c) 2025 Mohammad Nejati +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/rts +// + +#include + +#include + +namespace boost { +namespace rts { +namespace brotli { + +class encode_service_impl + : public encode_service +{ +public: + using key_type = encode_service; + + explicit + encode_service_impl( + rts::context&) noexcept + { + } + + ~encode_service_impl() + { + } + + bool + set_parameter( + encoder_state* state, + encoder_parameter param, + std::uint32_t value) const noexcept override + { + return BrotliEncoderSetParameter( + reinterpret_cast(state), + static_cast(param), + value); + } + + encoder_state* + create_instance(alloc_func alloc_func, free_func free_func, void* opaque) + const noexcept override + { + return reinterpret_cast( + BrotliEncoderCreateInstance( + alloc_func, + free_func, + opaque)); + } + + void + destroy_instance(encoder_state* state) const noexcept override + { + BrotliEncoderDestroyInstance( + reinterpret_cast(state)); + } + + std::size_t + max_compressed_size(std::size_t input_size) const noexcept override + { + return BrotliEncoderMaxCompressedSize(input_size); + } + + bool + compress( + int quality, + int lgwin, + encoder_mode mode, + std::size_t input_size, + const std::uint8_t input_buffer[], + std::size_t* encoded_size, + std::uint8_t encoded_buffer[]) const noexcept override + { + return BrotliEncoderCompress( + quality, + lgwin, + static_cast(mode), + input_size, + input_buffer, + encoded_size, + encoded_buffer); + } + + bool + compress_stream( + encoder_state* state, + encoder_operation op, + std::size_t* available_in, + const std::uint8_t** next_in, + std::size_t* available_out, + std::uint8_t** next_out, + std::size_t* total_out) const noexcept override + { + return BrotliEncoderCompressStream( + reinterpret_cast(state), + static_cast(op), + available_in, + next_in, + available_out, + next_out, + total_out); + } + + bool + is_finished(encoder_state* state) const noexcept override + { + return BrotliEncoderIsFinished( + reinterpret_cast(state)); + } + + bool + has_more_output(encoder_state* state) const noexcept override + { + return BrotliEncoderHasMoreOutput( + reinterpret_cast(state)); + } + + const std::uint8_t* + take_output(encoder_state* state, std::size_t* size) const noexcept override + { + return BrotliEncoderTakeOutput( + reinterpret_cast(state), + size); + } + + std::uint32_t + version() const noexcept override + { + return BrotliEncoderVersion(); + } + +#if 0 + encoder_prepared_dictionary* + prepare_dictionary( + shared_dictionary_type type, + std::size_t data_size, + const std::uint8_t data[], + int quality, + alloc_func alloc_func, + free_func free_func, + void* opaque) const noexcept override + { + return reinterpret_cast( + BrotliEncoderPrepareDictionary( + static_cast(type), + data_size, + data, + quality, + alloc_func, + free_func, + opaque)); + } + + void + destroy_prepared_dictionary( + encoder_prepared_dictionary* dictionary) const noexcept override + { + BrotliEncoderDestroyPreparedDictionary( + reinterpret_cast(dictionary)); + } + + bool + attach_prepared_dictionary( + encoder_state* state, + const encoder_prepared_dictionary* dictionary) const noexcept override + { + return BrotliEncoderAttachPreparedDictionary( + reinterpret_cast(state), + reinterpret_cast(dictionary)); + } + + std::size_t + estimate_peak_memory_usage(int quality, int lgwin, std::size_t input_size) + const noexcept override + { + return BrotliEncoderEstimatePeakMemoryUsage( + quality, + lgwin, + input_size); + } + + std::size_t + get_prepared_dictionary_size( + const encoder_prepared_dictionary* dictionary) const noexcept override + { + return BrotliEncoderGetPreparedDictionarySize( + reinterpret_cast(dictionary)); + } +#endif +}; + +encode_service& +install_encode_service(context& ctx) +{ + return ctx.make_service(); +} + +} // brotli +} // rts +} // boost diff --git a/src_brotli/shared_dictionary.cpp b/src_brotli/shared_dictionary.cpp new file mode 100644 index 0000000..0cffa75 --- /dev/null +++ b/src_brotli/shared_dictionary.cpp @@ -0,0 +1,81 @@ +// +// Copyright (c) 2025 Mohammad Nejati +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/rts +// + +#include + +#if 0 +#include +#endif + +namespace boost { +namespace rts { +namespace brotli { + +class shared_dictionary_service_impl + : public shared_dictionary_service +{ +public: + using key_type = shared_dictionary_service; + + explicit + shared_dictionary_service_impl( + rts::context&) noexcept + { + } + + ~shared_dictionary_service_impl() + { + } +#if 0 + shared_dictionary* + create_instance( + alloc_func alloc_func, + free_func free_func, + void* opaque) const noexcept override + { + return reinterpret_cast( + BrotliSharedDictionaryCreateInstance( + alloc_func, + free_func, + opaque)); + } + + void + destroy_instance( + shared_dictionary* dict) const noexcept override + { + BrotliSharedDictionaryDestroyInstance( + reinterpret_cast(dict)); + } + + bool + attach( + shared_dictionary* dict, + shared_dictionary_type type, + std::size_t data_size, + const uint8_t data[]) const noexcept override + { + return BrotliSharedDictionaryAttach( + reinterpret_cast(dict), + static_cast(type), + data_size, + data); + } +#endif +}; + +shared_dictionary_service& +install_shared_dictionary_service(context& ctx) +{ + return ctx.make_service(); +} + +} // brotli +} // rts +} // boost diff --git a/src_zlib/deflator.cpp b/src_zlib/deflate.cpp similarity index 98% rename from src_zlib/deflator.cpp rename to src_zlib/deflate.cpp index 3e59cbb..8d96e87 100644 --- a/src_zlib/deflator.cpp +++ b/src_zlib/deflate.cpp @@ -8,7 +8,7 @@ // Official repository: https://github.com/cppalliance/rts // -#include +#include #include "stream_cast.hpp" diff --git a/src_zlib/inflator.cpp b/src_zlib/inflate.cpp similarity index 98% rename from src_zlib/inflator.cpp rename to src_zlib/inflate.cpp index cf7ea09..9174060 100644 --- a/src_zlib/inflator.cpp +++ b/src_zlib/inflate.cpp @@ -8,7 +8,7 @@ // Official repository: https://github.com/cppalliance/rts // -#include +#include #include "stream_cast.hpp" diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index ff9ed12..b40017f 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -17,6 +17,7 @@ set(PFILES CMakeLists.txt Jamfile + brotli.cpp service.cpp test_helpers.hpp virtual_service.cpp @@ -36,5 +37,9 @@ if (TARGET boost_rts_zlib) target_link_libraries(boost_rts_tests PRIVATE boost_rts_zlib) endif () +if (TARGET boost_rts_brotli) + target_link_libraries(boost_rts_tests PRIVATE boost_rts_brotli) +endif () + add_test(NAME boost_rts_tests COMMAND boost_rts_tests) add_dependencies(tests boost_rts_tests) diff --git a/test/unit/Jamfile b/test/unit/Jamfile index eb82cee..2d21e84 100644 --- a/test/unit/Jamfile +++ b/test/unit/Jamfile @@ -7,19 +7,24 @@ # Official repository: https://github.com/cppalliance/rts # +import ac ; import testing ; project : requirements $(c11-requires) /boost/rts//boost_rts + [ ac.check-library /boost/rts//boost_rts_zlib : /boost/rts//boost_rts_zlib : ] + [ ac.check-library /boost/rts//boost_rts_brotli : /boost/rts//boost_rts_brotli : ] ../../../url/extra/test_suite/test_main.cpp ../../../url/extra/test_suite/test_suite.cpp . ../../../url/extra/test_suite + darwin,norecover:static ; local SOURCES = + brotli.cpp service.cpp virtual_service.cpp zlib.cpp diff --git a/test/unit/brotli.cpp b/test/unit/brotli.cpp new file mode 100644 index 0000000..38edf74 --- /dev/null +++ b/test/unit/brotli.cpp @@ -0,0 +1,56 @@ +// +// Copyright (c) 2025 Mohammad Nejati +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/cppalliance/rts +// + +#include + +#include "test_helpers.hpp" + +namespace boost { +namespace rts { + +struct brotli_test +{ + void + test_error_code() + { + // TODO + boost::system::error_code ec{ brotli::error::no_error }; + } + + void + test_decode() + { + // TODO + context ctx; + brotli::install_decode_service(ctx); + } + + void + test_encode() + { + // TODO + context ctx; + brotli::install_encode_service(ctx); + } + + void + run() + { + test_error_code(); + #ifdef BOOST_RTS_HAS_BROTLI + test_decode(); + test_encode(); + #endif + } +}; + +TEST_SUITE(brotli_test, "boost.rts.brotli"); + +} // namespace rts +} // namespace boost