From a9d9bbfb4b94c9700124b3aec8bcfc2cf4a05a4f Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 08:31:22 +0200 Subject: [PATCH 01/62] Add basic github action for tests --- .github/workflows/ctest.yml | 76 +++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 .github/workflows/ctest.yml diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml new file mode 100644 index 00000000..6644cfc4 --- /dev/null +++ b/.github/workflows/ctest.yml @@ -0,0 +1,76 @@ +# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform. +# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml +name: Test bit7z on multiple platforms + +on: + push: + branches: [ "feature/github-actions" ] + pull_request: + branches: [ "master" ] + +jobs: + build: + runs-on: ${{ matrix.os }} + + strategy: + # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. + fail-fast: false + + # Set up a matrix to run the following 3 configurations: + # 1. + # 2. + # 3. + # + # To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list. + matrix: + os: [ubuntu-latest, windows-latest] + build_type: [Release] + c_compiler: [gcc, clang, cl] + include: + - os: windows-latest + c_compiler: cl + cpp_compiler: cl + - os: ubuntu-latest + c_compiler: gcc + cpp_compiler: g++ + - os: ubuntu-latest + c_compiler: clang + cpp_compiler: clang++ + exclude: + - os: windows-latest + c_compiler: gcc + - os: windows-latest + c_compiler: clang + - os: ubuntu-latest + c_compiler: cl + + steps: + - uses: actions/checkout@v3 + + - name: Set reusable strings + # Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file. + id: strings + shell: bash + run: | + echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + + - name: Configure CMake + # 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 ${{ steps.strings.outputs.build-output-dir }} + -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} + -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -DBIT7Z_BUILD_TESTS=ON + -S ${{ github.workspace }} + + - name: Build + # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). + run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} + + - name: Test + working-directory: ${{ steps.strings.outputs.build-output-dir }} + # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). + # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail + run: ctest --build-config ${{ matrix.build_type }} From bf1d9f786115be4e6c22735f25d618516227b111 Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 08:38:34 +0200 Subject: [PATCH 02/62] Fix build tests of BitArchiveReader --- tests/src/test_bitarchivereader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/test_bitarchivereader.cpp b/tests/src/test_bitarchivereader.cpp index fc3478fe..8d224148 100644 --- a/tests/src/test_bitarchivereader.cpp +++ b/tests/src/test_bitarchivereader.cpp @@ -159,7 +159,7 @@ void getInputArchive( const fs::path& path, stream_t& archive ) { } template< typename T > -using is_filesystem_archive = std::is_same< bit7z::tstring, std::decay_t< T > >; +using is_filesystem_archive = std::is_same< bit7z::tstring, std::decay< T >::type >; TEMPLATE_TEST_CASE( "BitArchiveReader: Reading archives containing only a single file", "[bitarchivereader]", tstring, buffer_t, stream_t ) { From 10486087e301950974f09f7b466af4b235fb21fa Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 08:39:38 +0200 Subject: [PATCH 03/62] Add macOS runner --- .github/workflows/ctest.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index 6644cfc4..10528c90 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -23,7 +23,7 @@ jobs: # # To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list. matrix: - os: [ubuntu-latest, windows-latest] + os: [ubuntu-latest, windows-latest, macos-latest] build_type: [Release] c_compiler: [gcc, clang, cl] include: @@ -43,6 +43,8 @@ jobs: c_compiler: clang - os: ubuntu-latest c_compiler: cl + - os: macos-latest + c_compiler: cl steps: - uses: actions/checkout@v3 From 8a796e2ea4d0b9868fe425ac0736a93aa17e971d Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 08:42:38 +0200 Subject: [PATCH 04/62] Fix build tests of BitArchiveReader --- tests/src/test_bitarchivereader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/test_bitarchivereader.cpp b/tests/src/test_bitarchivereader.cpp index 8d224148..79b9f942 100644 --- a/tests/src/test_bitarchivereader.cpp +++ b/tests/src/test_bitarchivereader.cpp @@ -159,7 +159,7 @@ void getInputArchive( const fs::path& path, stream_t& archive ) { } template< typename T > -using is_filesystem_archive = std::is_same< bit7z::tstring, std::decay< T >::type >; +using is_filesystem_archive = std::is_same< bit7z::tstring, typename std::decay< T >::type >; TEMPLATE_TEST_CASE( "BitArchiveReader: Reading archives containing only a single file", "[bitarchivereader]", tstring, buffer_t, stream_t ) { From b5d8546a1cfc879e5313fb59f0f4815a655f9c28 Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 17:53:26 +0200 Subject: [PATCH 05/62] Build 7z.so needed for tests on Linux/macOS GitHub Actions runners --- .github/workflows/ctest.yml | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index 10528c90..73037290 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -16,12 +16,6 @@ jobs: # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. fail-fast: false - # Set up a matrix to run the following 3 configurations: - # 1. - # 2. - # 3. - # - # To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list. matrix: os: [ubuntu-latest, windows-latest, macos-latest] build_type: [Release] @@ -30,12 +24,23 @@ jobs: - os: windows-latest c_compiler: cl cpp_compiler: cl + use_system_7zip: ON - os: ubuntu-latest c_compiler: gcc cpp_compiler: g++ + use_system_7zip: OFF - os: ubuntu-latest c_compiler: clang cpp_compiler: clang++ + use_system_7zip: OFF + - os: macos-latest + c_compiler: gcc + cpp_compiler: g++ + use_system_7zip: OFF + - os: macos-latest + c_compiler: clang + cpp_compiler: clang++ + use_system_7zip: OFF exclude: - os: windows-latest c_compiler: gcc @@ -55,6 +60,15 @@ jobs: shell: bash run: | echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" + + - name: Build 7z.so + shell: bash + if: matrix.os == 'ubuntu-latest' + run: | + git clone --depth 1 https://github.com/rikyoz/7-Zip ${{ github.workspace }}/../7-zip + cd ${{ github.workspace }}/../7-zip/CPP/7zip/Bundles/Format7zF/ + make -j -f ../../cmpl_gcc.mak + cp b/g/7z.so ${{ github.workspace }}/bin/x64/7z.so - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. @@ -65,6 +79,7 @@ jobs: -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DBIT7Z_BUILD_TESTS=ON + -DBIT7Z_TESTS_USE_SYSTEM_7ZIP=${{ matrix.use_system_7zip }} -S ${{ github.workspace }} - name: Build From c9a0e876984db94b6cfd0c16a360a2f9591a2284 Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 17:59:35 +0200 Subject: [PATCH 06/62] Fix order of steps in GitHub actions workflow --- .github/workflows/ctest.yml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index 73037290..9d0fc5a8 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -60,15 +60,6 @@ jobs: shell: bash run: | echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT" - - - name: Build 7z.so - shell: bash - if: matrix.os == 'ubuntu-latest' - run: | - git clone --depth 1 https://github.com/rikyoz/7-Zip ${{ github.workspace }}/../7-zip - cd ${{ github.workspace }}/../7-zip/CPP/7zip/Bundles/Format7zF/ - make -j -f ../../cmpl_gcc.mak - cp b/g/7z.so ${{ github.workspace }}/bin/x64/7z.so - name: Configure CMake # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make. @@ -82,11 +73,20 @@ jobs: -DBIT7Z_TESTS_USE_SYSTEM_7ZIP=${{ matrix.use_system_7zip }} -S ${{ github.workspace }} - - name: Build + - name: Build bit7z # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} + + - name: Build 7z.so for tests + shell: bash + if: matrix.os == 'ubuntu-latest' + run: | + git clone --depth 1 https://github.com/rikyoz/7-Zip ${{ github.workspace }}/../7-zip + cd ${{ github.workspace }}/../7-zip/CPP/7zip/Bundles/Format7zF/ + make -j -f ../../cmpl_gcc.mak + cp b/g/7z.so ${{ github.workspace }}/bin/x64/7z.so - - name: Test + - name: Test bit7z working-directory: ${{ steps.strings.outputs.build-output-dir }} # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail From acf52606795f9f9f800e867dfeb8353836f34667 Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 18:07:13 +0200 Subject: [PATCH 07/62] Build 7z.so for tests also on macOS --- .github/workflows/ctest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index 9d0fc5a8..732eb50e 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -79,7 +79,7 @@ jobs: - name: Build 7z.so for tests shell: bash - if: matrix.os == 'ubuntu-latest' + if: matrix.os != 'windows-latest' run: | git clone --depth 1 https://github.com/rikyoz/7-Zip ${{ github.workspace }}/../7-zip cd ${{ github.workspace }}/../7-zip/CPP/7zip/Bundles/Format7zF/ From 8dc17f904b652f954a4020f193a6c7aca7ec4d90 Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 18:14:57 +0200 Subject: [PATCH 08/62] Fix building 7z.so on macOS --- .github/workflows/ctest.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index 732eb50e..55f2dcda 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -79,12 +79,21 @@ jobs: - name: Build 7z.so for tests shell: bash - if: matrix.os != 'windows-latest' + if: matrix.os == 'ubuntu-latest' run: | git clone --depth 1 https://github.com/rikyoz/7-Zip ${{ github.workspace }}/../7-zip cd ${{ github.workspace }}/../7-zip/CPP/7zip/Bundles/Format7zF/ make -j -f ../../cmpl_gcc.mak cp b/g/7z.so ${{ github.workspace }}/bin/x64/7z.so + + - name: Build 7z.so for tests + shell: bash + if: matrix.os == 'macos-latest' + run: | + git clone --depth 1 https://github.com/rikyoz/7-Zip ${{ github.workspace }}/../7-zip + cd ${{ github.workspace }}/../7-zip/CPP/7zip/Bundles/Format7zF/ + make -j -f ../../cmpl_mac_x64.mak + cp b/m_x64/7z.so ${{ github.workspace }}/bin/x64/7z.so - name: Test bit7z working-directory: ${{ steps.strings.outputs.build-output-dir }} From 20fbd847368149f27e4541c8e253bf8b9ade793a Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 18:46:59 +0200 Subject: [PATCH 09/62] Add debug configuration to build matrix --- .github/workflows/ctest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index 55f2dcda..ea56e915 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -18,7 +18,7 @@ jobs: matrix: os: [ubuntu-latest, windows-latest, macos-latest] - build_type: [Release] + build_type: [Debug, Release] c_compiler: [gcc, clang, cl] include: - os: windows-latest From 5efa3c411a3413bca558145611eb29cb93fc575b Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 18:47:13 +0200 Subject: [PATCH 10/62] Fix job names --- .github/workflows/ctest.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index ea56e915..d6131585 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -77,7 +77,7 @@ jobs: # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} - - name: Build 7z.so for tests + - name: Build 7z.so for tests (Ubuntu) shell: bash if: matrix.os == 'ubuntu-latest' run: | @@ -86,7 +86,7 @@ jobs: make -j -f ../../cmpl_gcc.mak cp b/g/7z.so ${{ github.workspace }}/bin/x64/7z.so - - name: Build 7z.so for tests + - name: Build 7z.so for tests (macOS) shell: bash if: matrix.os == 'macos-latest' run: | From 602731b1592435c4947b0f5bd17eeafe82a8eddc Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 18:47:43 +0200 Subject: [PATCH 11/62] Add some bit7z configuration options to build matrix --- .github/workflows/ctest.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index d6131585..e8291ceb 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -20,6 +20,8 @@ jobs: os: [ubuntu-latest, windows-latest, macos-latest] build_type: [Debug, Release] c_compiler: [gcc, clang, cl] + bit7z_auto_format: [OFF, ON] + bit7z_regex_matching: [OFF, ON] include: - os: windows-latest c_compiler: cl @@ -71,6 +73,8 @@ jobs: -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DBIT7Z_BUILD_TESTS=ON -DBIT7Z_TESTS_USE_SYSTEM_7ZIP=${{ matrix.use_system_7zip }} + -DBIT7Z_AUTO_FORMAT=${{ matrix.bit7z_auto_format }} + -DBIT7Z_REGEX_MATCHING=${{ matrix.bit7z_regex_matching }} -S ${{ github.workspace }} - name: Build bit7z From 63511b5cf181770015ea385d49bda0350b5757ac Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 20:49:05 +0200 Subject: [PATCH 12/62] Add test build with MinGW on Windows --- .github/workflows/ctest.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index e8291ceb..1d5fe7c6 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -27,6 +27,10 @@ jobs: c_compiler: cl cpp_compiler: cl use_system_7zip: ON + - os: windows-latest + c_compiler: gcc + cpp_compiler: g++ + use_system_7zip: ON - os: ubuntu-latest c_compiler: gcc cpp_compiler: g++ @@ -44,8 +48,6 @@ jobs: cpp_compiler: clang++ use_system_7zip: OFF exclude: - - os: windows-latest - c_compiler: gcc - os: windows-latest c_compiler: clang - os: ubuntu-latest From c7f425fd0c37cbf8c5de3a4da4faba328b10c4f4 Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 21:30:28 +0200 Subject: [PATCH 13/62] Remove MinGW from test builds as GH actions don't support it natively --- .github/workflows/ctest.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index 1d5fe7c6..e8291ceb 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -27,10 +27,6 @@ jobs: c_compiler: cl cpp_compiler: cl use_system_7zip: ON - - os: windows-latest - c_compiler: gcc - cpp_compiler: g++ - use_system_7zip: ON - os: ubuntu-latest c_compiler: gcc cpp_compiler: g++ @@ -48,6 +44,8 @@ jobs: cpp_compiler: clang++ use_system_7zip: OFF exclude: + - os: windows-latest + c_compiler: gcc - os: windows-latest c_compiler: clang - os: ubuntu-latest From c1a461dc9af9beb9fd8748bfb139e353c14cd45c Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 21:30:53 +0200 Subject: [PATCH 14/62] Add more bit7z options in matrix configuration --- .github/workflows/ctest.yml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index e8291ceb..dad2c7c9 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -22,6 +22,10 @@ jobs: c_compiler: [gcc, clang, cl] bit7z_auto_format: [OFF, ON] bit7z_regex_matching: [OFF, ON] + bit7z_use_native_string: [OFF, ON] + bit7z_auto_prefix_long_paths: [OFF, ON] + bit7z_use_system_codepage: [OFF, ON] + bit7z_path_sanitization: [OFF, ON] include: - os: windows-latest c_compiler: cl @@ -50,8 +54,24 @@ jobs: c_compiler: clang - os: ubuntu-latest c_compiler: cl + - os: ubuntu-latest + bit7z_use_native_string: OFF + - os: ubuntu-latest + bit7z_auto_prefix_long_paths: OFF + - os: ubuntu-latest + bit7z_use_system_codepage: OFF + - os: ubuntu-latest + bit7z_path_sanitization: OFF - os: macos-latest c_compiler: cl + - os: macos-latest + bit7z_use_native_string: OFF + - os: macos-latest + bit7z_auto_prefix_long_paths: OFF + - os: macos-latest + bit7z_use_system_codepage: OFF + - os: macos-latest + bit7z_path_sanitization: OFF steps: - uses: actions/checkout@v3 @@ -75,6 +95,10 @@ jobs: -DBIT7Z_TESTS_USE_SYSTEM_7ZIP=${{ matrix.use_system_7zip }} -DBIT7Z_AUTO_FORMAT=${{ matrix.bit7z_auto_format }} -DBIT7Z_REGEX_MATCHING=${{ matrix.bit7z_regex_matching }} + -DBIT7Z_USE_NATIVE_STRING=${{ matrix.bit7z_use_native_string }} + -DBIT7Z_USE_PREFIX_LONG_PATHS=${{ matrix.bit7z_auto_prefix_long_paths }} + -DBIT7Z_USE_SYSTEM_CODEPAGE=${{ matrix.bit7z_use_system_codepage }} + -DBIT7Z_PATH_SANITIZATION=${{ matrix.bit7z_path_sanitization }} -S ${{ github.workspace }} - name: Build bit7z From 01af4f9ffc840d4650dd8b18e3b2786ebb31d2c0 Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 21:34:39 +0200 Subject: [PATCH 15/62] Fix GH tests workflow --- .github/workflows/ctest.yml | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index dad2c7c9..e4c3ec8f 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -54,24 +54,24 @@ jobs: c_compiler: clang - os: ubuntu-latest c_compiler: cl - - os: ubuntu-latest - bit7z_use_native_string: OFF - - os: ubuntu-latest - bit7z_auto_prefix_long_paths: OFF - - os: ubuntu-latest - bit7z_use_system_codepage: OFF - - os: ubuntu-latest - bit7z_path_sanitization: OFF + - os: ubuntu-latest + bit7z_use_native_string: ON + - os: ubuntu-latest + bit7z_auto_prefix_long_paths: ON + - os: ubuntu-latest + bit7z_use_system_codepage: ON + - os: ubuntu-latest + bit7z_path_sanitization: ON - os: macos-latest c_compiler: cl - - os: macos-latest - bit7z_use_native_string: OFF - - os: macos-latest - bit7z_auto_prefix_long_paths: OFF - - os: macos-latest - bit7z_use_system_codepage: OFF - - os: macos-latest - bit7z_path_sanitization: OFF + - os: macos-latest + bit7z_use_native_string: ON + - os: macos-latest + bit7z_auto_prefix_long_paths: ON + - os: macos-latest + bit7z_use_system_codepage: ON + - os: macos-latest + bit7z_path_sanitization: ON steps: - uses: actions/checkout@v3 From 6dfd547fb1cbaf3834eaeaff0e2378ec356eac39 Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 21:44:53 +0200 Subject: [PATCH 16/62] Add more options to tests matrix --- .github/workflows/ctest.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index e4c3ec8f..ef20fa47 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -22,6 +22,7 @@ jobs: c_compiler: [gcc, clang, cl] bit7z_auto_format: [OFF, ON] bit7z_regex_matching: [OFF, ON] + bit7z_link_libcpp: [OFF, ON] bit7z_use_native_string: [OFF, ON] bit7z_auto_prefix_long_paths: [OFF, ON] bit7z_use_system_codepage: [OFF, ON] @@ -52,8 +53,13 @@ jobs: c_compiler: gcc - os: windows-latest c_compiler: clang + - os: windows-latest + bit7z_link_libcpp: ON - os: ubuntu-latest c_compiler: cl + - os: ubuntu-latest + c_compiler: gcc + bit7z_link_libcpp: ON - os: ubuntu-latest bit7z_use_native_string: ON - os: ubuntu-latest @@ -64,6 +70,9 @@ jobs: bit7z_path_sanitization: ON - os: macos-latest c_compiler: cl + - os: macos-latest + c_compiler: gcc + bit7z_link_libcpp: ON - os: macos-latest bit7z_use_native_string: ON - os: macos-latest @@ -96,6 +105,7 @@ jobs: -DBIT7Z_AUTO_FORMAT=${{ matrix.bit7z_auto_format }} -DBIT7Z_REGEX_MATCHING=${{ matrix.bit7z_regex_matching }} -DBIT7Z_USE_NATIVE_STRING=${{ matrix.bit7z_use_native_string }} + -DBIT7Z_LINK_LIBCPP=${{ matrix.bit7z_link_libcpp }} -DBIT7Z_USE_PREFIX_LONG_PATHS=${{ matrix.bit7z_auto_prefix_long_paths }} -DBIT7Z_USE_SYSTEM_CODEPAGE=${{ matrix.bit7z_use_system_codepage }} -DBIT7Z_PATH_SANITIZATION=${{ matrix.bit7z_path_sanitization }} From 12cb9b5bc5f1435b20407249d99c65d41da308d6 Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 21:47:53 +0200 Subject: [PATCH 17/62] Fix auto prefix option used in tests GH action --- .github/workflows/ctest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index ef20fa47..edb58e3e 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -106,7 +106,7 @@ jobs: -DBIT7Z_REGEX_MATCHING=${{ matrix.bit7z_regex_matching }} -DBIT7Z_USE_NATIVE_STRING=${{ matrix.bit7z_use_native_string }} -DBIT7Z_LINK_LIBCPP=${{ matrix.bit7z_link_libcpp }} - -DBIT7Z_USE_PREFIX_LONG_PATHS=${{ matrix.bit7z_auto_prefix_long_paths }} + -DBIT7Z_AUTO_PREFIX_LONG_PATHS=${{ matrix.bit7z_auto_prefix_long_paths }} -DBIT7Z_USE_SYSTEM_CODEPAGE=${{ matrix.bit7z_use_system_codepage }} -DBIT7Z_PATH_SANITIZATION=${{ matrix.bit7z_path_sanitization }} -S ${{ github.workspace }} From bf806e67ac54611bbe50c98a723dd43d076685ad Mon Sep 17 00:00:00 2001 From: Oz Date: Fri, 13 Oct 2023 21:57:22 +0200 Subject: [PATCH 18/62] Make CTest output verbose in GH action --- .github/workflows/ctest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index edb58e3e..7e1daf17 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -137,4 +137,4 @@ jobs: working-directory: ${{ steps.strings.outputs.build-output-dir }} # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest --build-config ${{ matrix.build_type }} + run: ctest --build-config ${{ matrix.build_type }} --output-on-failure From 0994d4c903db5314bc22d1ea7c420678a53beac6 Mon Sep 17 00:00:00 2001 From: Oz Date: Sat, 14 Oct 2023 10:18:56 +0200 Subject: [PATCH 19/62] Add sanitizers option to the base project rather than only the tests --- .github/workflows/ctest.yml | 1 + CMakeLists.txt | 3 ++ cmake/Sanitizers.cmake | 59 ++++++++++++++++++++++++++++++++++++ tests/CMakeLists.txt | 2 -- tests/cmake/Sanitizers.cmake | 58 ----------------------------------- 5 files changed, 63 insertions(+), 60 deletions(-) create mode 100644 cmake/Sanitizers.cmake delete mode 100644 tests/cmake/Sanitizers.cmake diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index 7e1daf17..f744695d 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -101,6 +101,7 @@ jobs: -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} -DBIT7Z_BUILD_TESTS=ON + -DBIT7Z_ENABLE_SANITIZERS=ON -DBIT7Z_TESTS_USE_SYSTEM_7ZIP=${{ matrix.use_system_7zip }} -DBIT7Z_AUTO_FORMAT=${{ matrix.bit7z_auto_format }} -DBIT7Z_REGEX_MATCHING=${{ matrix.bit7z_regex_matching }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 23749e59..522698f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -228,6 +228,9 @@ if( UNIX ) target_link_libraries( ${LIB_TARGET} PUBLIC ${CMAKE_DL_LIBS} ) endif() +# sanitizers +include( cmake/Sanitizers.cmake ) + # tests if( BIT7Z_BUILD_TESTS ) enable_testing() diff --git a/cmake/Sanitizers.cmake b/cmake/Sanitizers.cmake new file mode 100644 index 00000000..c0c1a533 --- /dev/null +++ b/cmake/Sanitizers.cmake @@ -0,0 +1,59 @@ +macro( add_sanitizer name ) + set( CMAKE_REQUIRED_FLAGS "-fsanitize=${name}" ) + check_cxx_compiler_flag( -fsanitize=${name} COMPILER_SUPPORTS_SANITIZE_${name} ) + if( COMPILER_SUPPORTS_SANITIZE_${name} ) + message( STATUS "Supported sanitizer: ${name}" ) + set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=${name}" ) + else() + message( STATUS "Unsupported sanitizer: ${name}" ) + endif() + unset( CMAKE_REQUIRED_FLAGS ) +endmacro() + +option( BIT7Z_ENABLE_SANITIZERS "Enable or disable compiling with sanitizers" ) +message( STATUS "Enable sanitizers: ${BIT7Z_ENABLE_SANITIZERS}" ) +if ( BIT7Z_ENABLE_SANITIZERS ) + if( MSVC ) + set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /RTCsu /analyze /guard:cf" ) + elseif( NOT WIN32 ) # GCC/Clang on Linux/macOS (i.e., not MinGW) + set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer" ) + + if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "6.0.0" ) + set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -static-libsan" ) + endif() + + # Use the highest stack protection level supported by the target toolchain. + include( CheckCXXCompilerFlag ) + check_cxx_compiler_flag( -fstack-protector-strong COMPILER_SUPPORT_STRONG_STACK_PROTECTOR ) + check_cxx_compiler_flag( -fstack-protector COMPILER_SUPPORT_STACK_PROTECTOR ) + if( COMPILER_SUPPORT_STRONG_STACK_PROTECTOR ) + set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} -fstack-protector-strong" ) + elseif( COMPILER_SUPPORT_STACK_PROTECTOR ) + set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} -fstack-protector" ) + endif() + + # For some reasons, using the leak sanitizer on Clang 14 gives lots of 'undefined reference' + # issues during linking... ¯\_(ツ)_/¯ + if( NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) + add_sanitizer( leak ) + endif() + + # For some reasons, the address sanitizer gives a CHECK failed error on versions of Clang before the 3.9 + # Also, on old versions of GCC the sanitizer give some false positives. + if( ( NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "5.0" ) OR + ( CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "3.9.0" ) ) + add_sanitizer( address ) + check_cxx_compiler_flag( -fsanitize-address-use-after-scope COMPILER_SUPPORT_SANITIZE_USE_AFTER_SCOPE ) + if( COMPILER_SUPPORT_SANITIZE_USE_AFTER_SCOPE ) + set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize-address-use-after-scope" ) + endif() + endif() + + add_sanitizer( float-divide-by-zero ) + add_sanitizer( implicit-conversion ) + add_sanitizer( integer ) + add_sanitizer( local-bounds ) + add_sanitizer( nullability ) + add_sanitizer( undefined ) + endif() +endif() \ No newline at end of file diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index e0ebbe9f..05f1b54d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -148,8 +148,6 @@ if( WIN32 ) target_sources( ${TESTS_TARGET_PUBLIC} PRIVATE res/encodingLegacy.${RES_EXTENSION} ) endif() -include( cmake/Sanitizers.cmake ) - # Catch2 include( cmake/Catch2.cmake ) target_link_libraries( ${TESTS_TARGET} PRIVATE Catch2::Catch2 ) diff --git a/tests/cmake/Sanitizers.cmake b/tests/cmake/Sanitizers.cmake deleted file mode 100644 index 1c917a30..00000000 --- a/tests/cmake/Sanitizers.cmake +++ /dev/null @@ -1,58 +0,0 @@ -macro( add_sanitizer name ) - set( CMAKE_REQUIRED_FLAGS "-fsanitize=${name}" ) - check_cxx_compiler_flag( -fsanitize=${name} COMPILER_SUPPORTS_SANITIZE_${name} ) - if( COMPILER_SUPPORTS_SANITIZE_${name} ) - message( STATUS "Supported sanitizer: ${name}" ) - set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=${name}" ) - else() - message( STATUS "Unsupported sanitizer: ${name}" ) - endif() - unset( CMAKE_REQUIRED_FLAGS ) -endmacro() - -option( BIT7Z_TESTS_NO_SANITIZERS "" OFF ) - -if( MSVC ) - set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /RTCsu /analyze /guard:cf" ) -elseif( NOT WIN32 AND NOT BIT7Z_TESTS_NO_SANITIZERS ) # GCC/Clang on Linux/macOS (i.e., not MinGW) - set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fno-omit-frame-pointer" ) - - if( CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "6.0.0" ) - set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -static-libsan" ) - endif() - - # Use the highest stack protection level supported by the target toolchain. - include( CheckCXXCompilerFlag ) - check_cxx_compiler_flag( -fstack-protector-strong COMPILER_SUPPORT_STRONG_STACK_PROTECTOR ) - check_cxx_compiler_flag( -fstack-protector COMPILER_SUPPORT_STACK_PROTECTOR ) - if( COMPILER_SUPPORT_STRONG_STACK_PROTECTOR ) - set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} -fstack-protector-strong" ) - elseif( COMPILER_SUPPORT_STACK_PROTECTOR ) - set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} -fstack-protector" ) - endif() - - # For some reasons, using the leak sanitizer on Clang 14 gives lots of 'undefined reference' - # issues during linking... ¯\_(ツ)_/¯ - if( NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) - add_sanitizer( leak ) - endif() - - # For some reasons, the address sanitizer gives a CHECK failed error on versions of Clang before the 3.9 - # Also, on old versions of GCC the sanitizer give some false positives. - if( ( NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "5.0" ) OR - ( CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "3.9.0" ) ) - add_sanitizer( address ) - check_cxx_compiler_flag( -fsanitize-address-use-after-scope COMPILER_SUPPORT_SANITIZE_USE_AFTER_SCOPE ) - if( COMPILER_SUPPORT_SANITIZE_USE_AFTER_SCOPE ) - set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fsanitize-address-use-after-scope" ) - endif() - endif() - - add_sanitizer( float-divide-by-zero ) - add_sanitizer( implicit-conversion ) - add_sanitizer( integer ) - add_sanitizer( local-bounds ) - add_sanitizer( nullability ) - add_sanitizer( undefined ) -endif() - From f0477be8c12afcec5061931e785a06ccfa159149 Mon Sep 17 00:00:00 2001 From: Oz Date: Sat, 14 Oct 2023 10:35:51 +0200 Subject: [PATCH 20/62] Disabling alloc_dealloc_mismatch in CTest due to bug in clang asan --- .github/workflows/ctest.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index f744695d..c80971a4 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -136,6 +136,9 @@ jobs: - name: Test bit7z working-directory: ${{ steps.strings.outputs.build-output-dir }} + # Disabling alloc_dealloc_mismatch for address sanitizer until https://github.com/llvm/llvm-project/issues/52771 is fixed + env: + ASAN_OPTIONS: alloc_dealloc_mismatch=0 # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest --build-config ${{ matrix.build_type }} --output-on-failure From 9020c76a6f38c3ccc038517d15a87fe4f6cdb55a Mon Sep 17 00:00:00 2001 From: Oz Date: Sat, 14 Oct 2023 10:42:21 +0200 Subject: [PATCH 21/62] Re-add the leak sanitizer on Clang --- cmake/Sanitizers.cmake | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/cmake/Sanitizers.cmake b/cmake/Sanitizers.cmake index c0c1a533..7e3c1feb 100644 --- a/cmake/Sanitizers.cmake +++ b/cmake/Sanitizers.cmake @@ -32,12 +32,6 @@ if ( BIT7Z_ENABLE_SANITIZERS ) set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_DEBUG} -fstack-protector" ) endif() - # For some reasons, using the leak sanitizer on Clang 14 gives lots of 'undefined reference' - # issues during linking... ¯\_(ツ)_/¯ - if( NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang" ) - add_sanitizer( leak ) - endif() - # For some reasons, the address sanitizer gives a CHECK failed error on versions of Clang before the 3.9 # Also, on old versions of GCC the sanitizer give some false positives. if( ( NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL "5.0" ) OR @@ -52,6 +46,7 @@ if ( BIT7Z_ENABLE_SANITIZERS ) add_sanitizer( float-divide-by-zero ) add_sanitizer( implicit-conversion ) add_sanitizer( integer ) + add_sanitizer( leak ) add_sanitizer( local-bounds ) add_sanitizer( nullability ) add_sanitizer( undefined ) From 3b54b7f384eff98b6edcafda2661d5a206e5850f Mon Sep 17 00:00:00 2001 From: Oz Date: Sat, 14 Oct 2023 18:26:38 +0200 Subject: [PATCH 22/62] Update CPM.cmake to 0.38.6 --- cmake/Dependencies.cmake | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index dfa3ddb6..7fd8b764 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -1,11 +1,14 @@ # Downloading the CPM.cmake package manager -set( CPM_DOWNLOAD_VERSION 0.38.5 ) +set( CPM_DOWNLOAD_VERSION 0.38.6 ) +set( CPM_DOWNLOAD_HASH 11c3fa5f1ba14f15d31c2fb63dbc8628ee133d81c8d764caad9a8db9e0bacb07 ) set( CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake" ) -if( NOT ( EXISTS ${CPM_DOWNLOAD_LOCATION} )) +if( NOT ( EXISTS ${CPM_DOWNLOAD_LOCATION} ) ) message( STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}" ) file( DOWNLOAD https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake ${CPM_DOWNLOAD_LOCATION} + SHOW_PROGRESS + EXPECTED_HASH SHA256=${CPM_DOWNLOAD_HASH} ) endif() include( ${CPM_DOWNLOAD_LOCATION} ) From 1ca43fed520e9f1f1c03e7a9a84262bf08d0278f Mon Sep 17 00:00:00 2001 From: Oz Date: Sat, 14 Oct 2023 18:41:21 +0200 Subject: [PATCH 23/62] Fix comments in formatdetect --- src/internal/formatdetect.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/internal/formatdetect.cpp b/src/internal/formatdetect.cpp index 70b35c0a..c1be4271 100644 --- a/src/internal/formatdetect.cpp +++ b/src/internal/formatdetect.cpp @@ -340,7 +340,7 @@ struct OffsetSignature { #define bswap64 _byteswap_uint64 #elif defined(__GNUC__) || defined(__clang__) //Note: the versions of gcc and clang that can compile bit7z should also have this builtin, hence there is no need -// for checking the compiler version or using _has_builtin macro! +// for checking the compiler version or using the _has_builtin macro. #define bswap64 __builtin_bswap64 #else static inline uint64_t bswap64( uint64_t x ) { @@ -375,7 +375,7 @@ auto detect_format_from_signature( IInStream* stream ) -> const BitInFormat& { return *format; } signatureMask <<= kByteShift; // left shifting the mask of one byte, so that - fileSignature &= signatureMask; // the least significant i bytes are masked (set to 0) + fileSignature &= signatureMask; // the least significant i bytes are masked (set to 0) } static const OffsetSignature commonSignaturesWithOffset[] = { // NOLINT(*-avoid-c-arrays) @@ -385,7 +385,7 @@ auto detect_format_from_signature( IInStream* stream ) -> const BitInFormat& { { 0x436F6D7072657373, 0x10, 8, BitFormat::CramFS }, // Compress { 0x7F10DABE00000000, 0x40, 4, BitFormat::VDI }, // 0x7F 0x10 0xDA 0xBE { 0x7573746172000000, 0x101, 5, BitFormat::Tar }, // ustar - // Note: since GPT files contain also the FAT signature, GPT must be checked before! + /* Note: since GPT files contain also the FAT signature, we must check the GPT signature before the FAT one. */ { 0x4546492050415254, 0x200, 8, BitFormat::GPT }, // EFI 0x20 PART { 0x55AA000000000000, 0x1FE, 2, BitFormat::Fat }, // U 0xAA { 0x4244000000000000, 0x400, 2, BitFormat::Hfs }, // BD From 36e8e4911d98964192945dc815ba598d57c63d7b Mon Sep 17 00:00:00 2001 From: Oz Date: Sat, 14 Oct 2023 20:49:23 +0200 Subject: [PATCH 24/62] [Test] Trigger tests only in specific cases --- .github/workflows/ctest.yml | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index c80971a4..fb998a6e 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -1,16 +1,15 @@ # This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform. # See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml -name: Test bit7z on multiple platforms - -on: - push: - branches: [ "feature/github-actions" ] - pull_request: - branches: [ "master" ] +name: Test bit7z on multiple configurations +on: [pull_request, push] jobs: build: runs-on: ${{ matrix.os }} + if: | + github.event_name == 'pull_request' + || contains(github.event.head_commit.message, '[test]') + || startsWith(github.ref, 'refs/tags/v') strategy: # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. From eb4ac7e85e671154da9885a852d570e06a5bbf20 Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 11:15:12 +0200 Subject: [PATCH 25/62] Add more compiler warning flags --- cmake/CompilerOptions.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CompilerOptions.cmake b/cmake/CompilerOptions.cmake index a0861a59..580a2303 100644 --- a/cmake/CompilerOptions.cmake +++ b/cmake/CompilerOptions.cmake @@ -122,6 +122,6 @@ if( CMAKE_CXX_COMPILER_ID MATCHES "GNU" ) endif() if( CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 7.0 ) # Extra warning flags for GCC 7.0+ - target_compile_options( ${LIB_TARGET} PRIVATE -Wduplicated-branches ) + target_compile_options( ${LIB_TARGET} PRIVATE -Wduplicated-branches -Wrestrict ) endif() endif() \ No newline at end of file From 8706776e72a48ef6e58eab7b066faab791f83778 Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 11:24:24 +0200 Subject: [PATCH 26/62] [Test] Fix code and comments formatting in tests app --- tests/src/test_bititemsvector.cpp | 2 +- tests/src/test_windows.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/src/test_bititemsvector.cpp b/tests/src/test_bititemsvector.cpp index 2bb632bb..bf5e0a67 100644 --- a/tests/src/test_bititemsvector.cpp +++ b/tests/src/test_bititemsvector.cpp @@ -1973,7 +1973,7 @@ TEST_CASE( "BitItemsVector: Indexing a single buffer", "[bititemsvector]" ) { BIT7Z_STRING( "folder/subfolder2/frequency.xlsx" ), BIT7Z_STRING( "dot.folder/hello.json" ) ); - DYNAMIC_SECTION ( "Indexing file " << testInput.u8string() << " as a buffer" ) { + DYNAMIC_SECTION( "Indexing file " << testInput.u8string() << " as a buffer" ) { REQUIRE_LOAD_FILE( input_buffer, testInput ); REQUIRE_NOTHROW( itemsVector.indexBuffer( input_buffer, BIT7Z_STRING( "custom_name.ext" ) ) ); REQUIRE( itemsVector.size() == 1 ); diff --git a/tests/src/test_windows.cpp b/tests/src/test_windows.cpp index fdf011c6..9903d199 100644 --- a/tests/src/test_windows.cpp +++ b/tests/src/test_windows.cpp @@ -112,7 +112,7 @@ TEST_CASE( "winapi: Allocating from wide strings", "[winapi][string allocation]" SECTION( "SysAllocStringLen with half-length parameter" ) { // Note: flawfinder warns about potentially using non-null terminating strings, - // but, in our case, the test string is guaranteed to be null-terminated! + // but, in our case, the test string is guaranteed to be null-terminated. expectedString = std::wstring{ testStr, std::wcslen( testStr ) / 2 }; // flawfinder: ignore resultString = SysAllocStringLen( testStr, expectedString.size() ); } @@ -152,7 +152,7 @@ TEST_CASE( "winapi: Allocating from narrow strings", "[winapi][string allocation SECTION( "SysAllocStringByteLen with half-length parameter" ) { // Note: flawfinder warns about potentially using non-null terminating strings, - // but, in our case, the test string is guaranteed to be null-terminated! + // but, in our case, the test string is guaranteed to be null-terminated. expectedString = std::string{ testStr, std::strlen( testStr ) / 2 }; // flawfinder: ignore resultString = SysAllocStringByteLen( testStr, expectedString.size() ); } From b780df63b2544911b5ea59b9fa03fcaf58280c0c Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 11:37:44 +0200 Subject: [PATCH 27/62] Move safe integer comparison functions to util.hpp --- src/internal/cfixedbufferoutstream.cpp | 48 -------------------------- src/internal/util.hpp | 48 ++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/src/internal/cfixedbufferoutstream.cpp b/src/internal/cfixedbufferoutstream.cpp index b84e7b49..c9fce674 100644 --- a/src/internal/cfixedbufferoutstream.cpp +++ b/src/internal/cfixedbufferoutstream.cpp @@ -17,54 +17,6 @@ #include "internal/cfixedbufferoutstream.hpp" #include "internal/util.hpp" -/* Safe integer comparison like in C++20 */ -#ifdef __cpp_if_constexpr - -template< class T, class U > -constexpr auto cmp_less( T first, U second ) noexcept -> bool { - using UT = std::make_unsigned_t< T >; - using UU = std::make_unsigned_t< U >; - if constexpr ( std::is_signed< T >::value == std::is_signed< U >::value ) { - return first < second; - } else if constexpr ( std::is_signed< T >::value ) { - return first < 0 || UT( first ) < second; - } else { - return second >= 0 && first < UU( second ); - } -} - -#else // SFINAE implementation for C++14 - -template< class T, class U > -constexpr auto -cmp_less( T t, U u ) noexcept -> std::enable_if_t< std::is_signed< T >::value == std::is_signed< U >::value, bool > { - return t < u; -} - -template< class T, class U > -constexpr auto -cmp_less( T t, U u ) noexcept -> std::enable_if_t< std::is_signed< T >::value && !std::is_signed< U >::value, bool > { - return t < 0 || std::make_unsigned_t< T >( t ) < u; -} - -template< class T, class U > -constexpr auto -cmp_less( T t, U u ) noexcept -> std::enable_if_t< !std::is_signed< T >::value && std::is_signed< U >::value, bool > { - return u >= 0 && t < std::make_unsigned_t< U >( u ); -} - -#endif - -template< class T, class U > -constexpr auto cmp_greater( T first, U second ) noexcept -> bool { - return cmp_less( second, first ); // NOLINT(*-suspicious-call-argument) -} - -template< class T, class U > -constexpr auto cmp_greater_equal( T first, U second ) noexcept -> bool { - return !cmp_less( first, second ); -} - namespace bit7z { CFixedBufferOutStream::CFixedBufferOutStream( byte_t* buffer, std::size_t size ) diff --git a/src/internal/util.hpp b/src/internal/util.hpp index 446e432c..95436936 100644 --- a/src/internal/util.hpp +++ b/src/internal/util.hpp @@ -88,6 +88,54 @@ constexpr inline auto check_overflow( int64_t position, int64_t offset ) noexcep ( ( offset < 0 ) && ( position < ( ( std::numeric_limits< int64_t >::min )() - offset ) ) ); } +/* Safe integer comparison like in C++20 */ +#ifdef __cpp_if_constexpr + +template< class T, class U > +constexpr auto cmp_less( T first, U second ) noexcept -> bool { + using UT = std::make_unsigned_t< T >; + using UU = std::make_unsigned_t< U >; + if constexpr ( std::is_signed< T >::value == std::is_signed< U >::value ) { + return first < second; + } else if constexpr ( std::is_signed< T >::value ) { + return first < 0 || UT( first ) < second; + } else { + return second >= 0 && first < UU( second ); + } +} + +#else // SFINAE implementation for C++14 + +template< class T, class U > +constexpr auto +cmp_less( T t, U u ) noexcept -> std::enable_if_t< std::is_signed< T >::value == std::is_signed< U >::value, bool > { + return t < u; +} + +template< class T, class U > +constexpr auto +cmp_less( T t, U u ) noexcept -> std::enable_if_t< std::is_signed< T >::value && !std::is_signed< U >::value, bool > { + return t < 0 || std::make_unsigned_t< T >( t ) < u; +} + +template< class T, class U > +constexpr auto +cmp_less( T t, U u ) noexcept -> std::enable_if_t< !std::is_signed< T >::value && std::is_signed< U >::value, bool > { + return u >= 0 && t < std::make_unsigned_t< U >( u ); +} + +#endif + +template< class T, class U > +constexpr auto cmp_greater( T first, U second ) noexcept -> bool { + return cmp_less( second, first ); // NOLINT(*-suspicious-call-argument) +} + +template< class T, class U > +constexpr auto cmp_greater_equal( T first, U second ) noexcept -> bool { + return !cmp_less( first, second ); +} + template< bool B > using bool_constant = std::integral_constant< bool, B >; // like C++17's std::bool_constant From 8768fd911ae839a800b3770f1a90a91858101c5a Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 11:38:17 +0200 Subject: [PATCH 28/62] Fix implicit signed to unsigned conversion in CMultiVolumeInStream --- src/internal/cmultivolumeinstream.cpp | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/src/internal/cmultivolumeinstream.cpp b/src/internal/cmultivolumeinstream.cpp index 76633a62..778f7698 100644 --- a/src/internal/cmultivolumeinstream.cpp +++ b/src/internal/cmultivolumeinstream.cpp @@ -108,20 +108,23 @@ STDMETHODIMP CMultiVolumeInStream::Seek( Int64 offset, UInt32 seekOrigin, UInt64 return STG_E_INVALIDFUNCTION; } - // Checking if adding the (negative) offset would result in the unsigned wrap around of the current position. - if ( offset < 0 && originPosition < static_cast< uint64_t >( -offset ) ) { - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - } - - // Checking if adding the (positive) offset would result in the unsigned wrap around of the current position. - if ( offset > 0 ) { + // Checking if adding the offset would result in the unsigned wrap around of the current position. + if ( offset < 0 ) { + const auto positiveOffset = static_cast< uint64_t >( -offset ); + if ( originPosition < positiveOffset ) { + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + } + mCurrentPosition = originPosition - positiveOffset; + } else if ( offset == 0 ) { + mCurrentPosition = originPosition; + } else { const auto positiveOffset = static_cast< uint64_t >( offset ); const uint64_t seekPosition = originPosition + positiveOffset; if ( seekPosition < originPosition || seekPosition < positiveOffset ) { return E_INVALIDARG; } + mCurrentPosition = seekPosition; } - mCurrentPosition = originPosition + offset; if ( newPosition != nullptr ) { *newPosition = mCurrentPosition; From cfe1687124409893291973a1595191be4c6a44f0 Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 11:46:04 +0200 Subject: [PATCH 29/62] Fix some MISRA warnings --- src/internal/util.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/internal/util.hpp b/src/internal/util.hpp index 95436936..381614ce 100644 --- a/src/internal/util.hpp +++ b/src/internal/util.hpp @@ -98,9 +98,9 @@ constexpr auto cmp_less( T first, U second ) noexcept -> bool { if constexpr ( std::is_signed< T >::value == std::is_signed< U >::value ) { return first < second; } else if constexpr ( std::is_signed< T >::value ) { - return first < 0 || UT( first ) < second; + return ( first < 0 ) || ( UT( first ) < second ); } else { - return second >= 0 && first < UU( second ); + return ( second >= 0 ) && ( first < UU( second ) ); } } @@ -115,13 +115,13 @@ cmp_less( T t, U u ) noexcept -> std::enable_if_t< std::is_signed< T >::value == template< class T, class U > constexpr auto cmp_less( T t, U u ) noexcept -> std::enable_if_t< std::is_signed< T >::value && !std::is_signed< U >::value, bool > { - return t < 0 || std::make_unsigned_t< T >( t ) < u; + return ( t < 0 ) || ( std::make_unsigned_t< T >( t ) < u ); } template< class T, class U > constexpr auto cmp_less( T t, U u ) noexcept -> std::enable_if_t< !std::is_signed< T >::value && std::is_signed< U >::value, bool > { - return u >= 0 && t < std::make_unsigned_t< U >( u ); + return ( u >= 0 ) && ( t < std::make_unsigned_t< U >( u ) ); } #endif From 2cba7613454190eb937c6a781c3bcf0b824c3a20 Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 12:11:22 +0200 Subject: [PATCH 30/62] [Test] Add basic API tests for BitAbstractArchiveCreator --- tests/CMakeLists.txt | 1 + tests/src/test_bitabstractarchivecreator.cpp | 219 +++++++++++++++++++ tests/src/test_bitfilecompressor.cpp | 191 +--------------- 3 files changed, 221 insertions(+), 190 deletions(-) create mode 100644 tests/src/test_bitabstractarchivecreator.cpp diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 05f1b54d..5a69400f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -16,6 +16,7 @@ set( SOURCE_FILES # public API test sources set( PUBLIC_API_SOURCE_FILES src/test_bit7zlibrary.cpp + src/test_bitabstractarchivecreator.cpp src/test_bitarchiveeditor.cpp src/test_bitarchivereader.cpp src/test_bitarchivewriter.cpp diff --git a/tests/src/test_bitabstractarchivecreator.cpp b/tests/src/test_bitabstractarchivecreator.cpp new file mode 100644 index 00000000..cd356624 --- /dev/null +++ b/tests/src/test_bitabstractarchivecreator.cpp @@ -0,0 +1,219 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + +/* + * bit7z - A C++ static library to interface with the 7-zip shared libraries. + * Copyright (c) 2014-2023 Riccardo Ostani - All Rights Reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +#include + +#include +#include +#include + +#include "utils/shared_lib.hpp" + +using namespace bit7z; +using bit7z::Bit7zLibrary; +using bit7z::BitFileCompressor; +using bit7z::BitMemCompressor; +using bit7z::BitStreamCompressor; +using bit7z::BitInOutFormat; + +struct TestOutputFormat { + const char* name; + const BitInOutFormat& format; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) +}; + +TEMPLATE_TEST_CASE( "BitAbstractArchiveCreator: Basic API tests", + "[bitabstractarchivecreator]", BitFileCompressor, BitMemCompressor, BitStreamCompressor ) { + const Bit7zLibrary lib{ test::sevenzip_lib_path() }; + + SECTION( "setPassword(...) / password() / cryptHeaders()" ) { + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.password().empty() ); + REQUIRE( !compressor.cryptHeaders() ); + + compressor.setPassword( BIT7Z_STRING( "ciao" ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "ciao" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + compressor.setPassword( BIT7Z_STRING( "mondo" ), true ); + REQUIRE( compressor.password() == BIT7Z_STRING( "mondo" ) ); + REQUIRE( compressor.cryptHeaders() ); + + compressor.setPassword( BIT7Z_STRING( "hello" ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "hello" ) ); + REQUIRE( compressor.cryptHeaders() ); + + compressor.setPassword( BIT7Z_STRING( "" ) ); + REQUIRE( compressor.password().empty() ); + REQUIRE( !compressor.cryptHeaders() ); + + BitAbstractArchiveHandler& handler = compressor; + handler.setPassword( BIT7Z_STRING( "world!" ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "world!" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + compressor.setPassword( BIT7Z_STRING( "foo" ), true ); + handler.setPassword( BIT7Z_STRING( "" ) ); + REQUIRE( compressor.password().empty() ); + REQUIRE( !compressor.cryptHeaders() ); + } + + SECTION( "compressionFormat()" ) { + const auto testFormat = GENERATE( as< TestOutputFormat >(), + TestOutputFormat{ "ZIP", BitFormat::Zip }, + TestOutputFormat{ "BZIP2", BitFormat::BZip2 }, + TestOutputFormat{ "7Z", BitFormat::SevenZip }, + TestOutputFormat{ "XZ", BitFormat::Xz }, + TestOutputFormat{ "WIM", BitFormat::Wim }, + TestOutputFormat{ "TAR", BitFormat::Tar }, + TestOutputFormat{ "GZIP", BitFormat::GZip } ); + DYNAMIC_SECTION( "Format: " << testFormat.name ) { + const TestType compressor{ lib, testFormat.format }; + REQUIRE( compressor.compressionFormat() == testFormat.format ); + } + } + + SECTION( "setCompressionLevel(...) / compressionLevel()" ) { + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Normal ); + compressor.setCompressionLevel( BitCompressionLevel::None ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::None ); + compressor.setCompressionLevel( BitCompressionLevel::Fastest ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Fastest ); + compressor.setCompressionLevel( BitCompressionLevel::Fast ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Fast ); + compressor.setCompressionLevel( BitCompressionLevel::Normal ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Normal ); + compressor.setCompressionLevel( BitCompressionLevel::Max ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Max ); + compressor.setCompressionLevel( BitCompressionLevel::Ultra ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Ultra ); + } + + SECTION( "setCompressionMethod(...) / compressionMethod()" ) { + SECTION( "7Z Compression Methods" ) { + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); + compressor.setCompressionMethod( BitCompressionMethod::Copy ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); + compressor.setCompressionMethod( BitCompressionMethod::Lzma ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma ); + compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); + compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Ppmd ); + compressor.setCompressionMethod( BitCompressionMethod::BZip2 ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); + } + + SECTION( "ZIP Compression Methods" ) { + TestType compressor( lib, BitFormat::Zip ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); + compressor.setCompressionMethod( BitCompressionMethod::Copy ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); + compressor.setCompressionMethod( BitCompressionMethod::Deflate ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); + compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate64 ); + compressor.setCompressionMethod( BitCompressionMethod::BZip2 ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); + compressor.setCompressionMethod( BitCompressionMethod::Lzma ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma ); + compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Ppmd ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); + } + + SECTION( "BZIP2 Compression Methods" ) { + TestType compressor( lib, BitFormat::BZip2 ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); + } + + SECTION( "GZIP Compression Methods" ) { + TestType compressor( lib, BitFormat::GZip ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); + } + + SECTION( "TAR Compression Methods" ) { + TestType compressor( lib, BitFormat::Tar ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); + } + + SECTION( "WIM Compression Methods" ) { + TestType compressor( lib, BitFormat::Wim ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); + } + + SECTION( "XZ Compression Methods" ) { + TestType compressor( lib, BitFormat::Xz ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); + } + } + + SECTION( "setSolidMode(...) / solidMode()" ) { + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( !compressor.solidMode() ); + + compressor.setSolidMode( true ); + REQUIRE( compressor.solidMode() ); + + compressor.setSolidMode( false ); + REQUIRE( !compressor.solidMode() ); + } + + SECTION( "setVolumeSize(...) / volumeSize()" ) { + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.volumeSize() == 0u ); + compressor.setVolumeSize( 1024u ); + REQUIRE( compressor.volumeSize() == 1024u ); + } +} \ No newline at end of file diff --git a/tests/src/test_bitfilecompressor.cpp b/tests/src/test_bitfilecompressor.cpp index 5b08d76d..24a21314 100644 --- a/tests/src/test_bitfilecompressor.cpp +++ b/tests/src/test_bitfilecompressor.cpp @@ -21,196 +21,7 @@ using bit7z::Bit7zLibrary; using bit7z::BitFileCompressor; using bit7z::BitInOutFormat; -struct TestOutputFormat { - const char* name; - const BitInOutFormat& format; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) -}; +TEST_CASE( "BitFileCompressor: TODO", "[bitfilecompressor]" ) { -TEST_CASE( "BitFileCompressor: Basic API tests (BitArchiveCreator API)", "[bitfilecompressor]" ) { - const Bit7zLibrary lib{ test::sevenzip_lib_path() }; - - SECTION( "setPassword(...) / password() / cryptHeaders()" ) { - BitFileCompressor compressor( lib, BitFormat::SevenZip ); - REQUIRE( compressor.password().empty() ); - REQUIRE( !compressor.cryptHeaders() ); - - compressor.setPassword( BIT7Z_STRING( "ciao" ) ); - REQUIRE( compressor.password() == BIT7Z_STRING( "ciao" ) ); - REQUIRE( !compressor.cryptHeaders() ); - - compressor.setPassword( BIT7Z_STRING( "mondo" ), true ); - REQUIRE( compressor.password() == BIT7Z_STRING( "mondo" ) ); - REQUIRE( compressor.cryptHeaders() ); - - compressor.setPassword( BIT7Z_STRING( "hello" ) ); - REQUIRE( compressor.password() == BIT7Z_STRING( "hello" ) ); - REQUIRE( compressor.cryptHeaders() ); - - compressor.setPassword( BIT7Z_STRING( "" ) ); - REQUIRE( compressor.password().empty() ); - REQUIRE( !compressor.cryptHeaders() ); - - BitAbstractArchiveHandler& handler = compressor; - handler.setPassword( BIT7Z_STRING( "world!" ) ); - REQUIRE( compressor.password() == BIT7Z_STRING( "world!" ) ); - REQUIRE( !compressor.cryptHeaders() ); - - compressor.setPassword( BIT7Z_STRING( "foo" ), true ); - handler.setPassword( BIT7Z_STRING( "" ) ); - REQUIRE( compressor.password().empty() ); - REQUIRE( !compressor.cryptHeaders() ); - } - - SECTION( "compressionFormat()" ) { - const auto testFormat = GENERATE( as< TestOutputFormat >(), - TestOutputFormat{ "ZIP", BitFormat::Zip }, - TestOutputFormat{ "BZIP2", BitFormat::BZip2 }, - TestOutputFormat{ "7Z", BitFormat::SevenZip }, - TestOutputFormat{ "XZ", BitFormat::Xz }, - TestOutputFormat{ "WIM", BitFormat::Wim }, - TestOutputFormat{ "TAR", BitFormat::Tar }, - TestOutputFormat{ "GZIP", BitFormat::GZip } ); - DYNAMIC_SECTION( "Format: " << testFormat.name ) { - const BitFileCompressor compressor{ lib, testFormat.format }; - REQUIRE( compressor.compressionFormat() == testFormat.format ); - } - } - - SECTION( "setCompressionLevel(...) / compressionLevel()" ) { - BitFileCompressor compressor( lib, BitFormat::SevenZip ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Normal ); - compressor.setCompressionLevel( BitCompressionLevel::None ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::None ); - compressor.setCompressionLevel( BitCompressionLevel::Fastest ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Fastest ); - compressor.setCompressionLevel( BitCompressionLevel::Fast ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Fast ); - compressor.setCompressionLevel( BitCompressionLevel::Normal ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Normal ); - compressor.setCompressionLevel( BitCompressionLevel::Max ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Max ); - compressor.setCompressionLevel( BitCompressionLevel::Ultra ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Ultra ); - } - - SECTION( "setCompressionMethod(...) / compressionMethod()" ) { - SECTION( "7Z Compression Methods" ) { - BitFileCompressor compressor( lib, BitFormat::SevenZip ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); - compressor.setCompressionMethod( BitCompressionMethod::Copy ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); - compressor.setCompressionMethod( BitCompressionMethod::Lzma ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma ); - compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); - compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Ppmd ); - compressor.setCompressionMethod( BitCompressionMethod::BZip2 ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); - } - - SECTION( "ZIP Compression Methods" ) { - BitFileCompressor compressor( lib, BitFormat::Zip ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); - compressor.setCompressionMethod( BitCompressionMethod::Copy ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); - compressor.setCompressionMethod( BitCompressionMethod::Deflate ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); - compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate64 ); - compressor.setCompressionMethod( BitCompressionMethod::BZip2 ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); - compressor.setCompressionMethod( BitCompressionMethod::Lzma ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma ); - compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Ppmd ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); - } - - SECTION( "BZIP2 Compression Methods" ) { - BitFileCompressor compressor( lib, BitFormat::BZip2 ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); - REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); - } - - SECTION( "GZIP Compression Methods" ) { - BitFileCompressor compressor( lib, BitFormat::GZip ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); - REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); - } - - SECTION( "TAR Compression Methods" ) { - BitFileCompressor compressor( lib, BitFormat::Tar ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); - REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); - } - - SECTION( "WIM Compression Methods" ) { - BitFileCompressor compressor( lib, BitFormat::Wim ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); - REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); - } - - SECTION( "XZ Compression Methods" ) { - BitFileCompressor compressor( lib, BitFormat::Xz ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); - REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); - } - } - - SECTION( "setSolidMode(...) / solidMode()" ) { - BitFileCompressor compressor( lib, BitFormat::SevenZip ); - REQUIRE( !compressor.solidMode() ); - - compressor.setSolidMode( true ); - REQUIRE( compressor.solidMode() ); - - compressor.setSolidMode( false ); - REQUIRE( !compressor.solidMode() ); - } - - SECTION( "setVolumeSize(...) / volumeSize()" ) { - BitFileCompressor compressor( lib, BitFormat::SevenZip ); - REQUIRE( compressor.volumeSize() == 0u ); - compressor.setVolumeSize( 1024u ); - REQUIRE( compressor.volumeSize() == 1024u ); - } } From d80448401d5daef6336304732ee2ab46426fec2e Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 13:21:50 +0200 Subject: [PATCH 31/62] Improve comments in BitArchiveReader --- src/bitarchivereader.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bitarchivereader.cpp b/src/bitarchivereader.cpp index a065fbeb..ac75fb78 100644 --- a/src/bitarchivereader.cpp +++ b/src/bitarchivereader.cpp @@ -39,7 +39,7 @@ BitArchiveReader::BitArchiveReader( const Bit7zLibrary& lib, auto BitArchiveReader::archiveProperties() const -> map< BitProperty, BitPropVariant > { map< BitProperty, BitPropVariant > result; for ( uint32_t i = kpidNoProperty; i <= kpidCopyLink; ++i ) { - // Yeah, I know, I cast property twice (here and in archiveProperty), but the code is easier to read! + // We cast property twice (here and in archiveProperty), to make the code is easier to read. const auto property = static_cast< BitProperty >( i ); const BitPropVariant propertyValue = archiveProperty( property ); if ( !propertyValue.isEmpty() ) { @@ -54,7 +54,7 @@ auto BitArchiveReader::items() const -> vector< BitArchiveItemInfo > { for ( uint32_t i = 0; i < itemsCount(); ++i ) { BitArchiveItemInfo item( i ); for ( uint32_t j = kpidNoProperty; j <= kpidCopyLink; ++j ) { - // Yeah, I know, I cast property twice (here and in itemProperty), but the code is easier to read! + // We cast property twice (here and in archiveProperty), to make the code is easier to read. const auto property = static_cast< BitProperty >( j ); const auto propertyValue = itemProperty( i, property ); if ( !propertyValue.isEmpty() ) { @@ -90,7 +90,7 @@ auto BitArchiveReader::packSize() const -> uint64_t { auto BitArchiveReader::hasEncryptedItems() const -> bool { /* Note: simple encryption (i.e., not including the archive headers) can be detected only reading - * the properties of the files in the archive, so we search for any encrypted file inside the archive! */ + * the properties of the files in the archive, so we search for any encrypted file inside the archive. */ return std::any_of( cbegin(), cend(), []( const BitArchiveItem& item ) { return !item.isDir() && item.isEncrypted(); } ); From 4b47e2209006390e7659dd8fe779b78d64937ae8 Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 15:23:05 +0200 Subject: [PATCH 32/62] Move string utility functions to stringutil --- CMakeLists.txt | 3 +- src/bit7zlibrary.cpp | 3 +- src/bitarchiveeditor.cpp | 2 +- src/bitarchiveitem.cpp | 2 +- src/bitinputarchive.cpp | 1 + src/bititemsvector.cpp | 2 +- src/bitoutputarchive.cpp | 2 +- src/bitpropvariant.cpp | 3 +- src/bittypes.cpp | 2 +- src/internal/bufferextractcallback.cpp | 1 + src/internal/bufferitem.cpp | 1 + src/internal/cfileinstream.cpp | 2 +- src/internal/cfileoutstream.cpp | 2 +- src/internal/extractcallback.cpp | 2 +- src/internal/fileextractcallback.cpp | 1 + src/internal/fsitem.cpp | 1 + src/internal/fsutil.cpp | 2 +- src/internal/genericinputitem.cpp | 2 +- src/internal/opencallback.cpp | 1 + src/internal/renameditem.cpp | 2 +- src/internal/stdinputitem.cpp | 1 + src/internal/{util.cpp => stringutil.cpp} | 3 +- src/internal/stringutil.hpp | 79 +++++++++++++++++++ src/internal/updatecallback.cpp | 1 + src/internal/util.hpp | 81 +++----------------- tests/CMakeLists.txt | 1 + tests/src/test_bitarchivereader.cpp | 5 +- tests/src/test_stringutil.cpp | 92 +++++++++++++++++++++++ tests/src/test_util.cpp | 77 ------------------- tests/src/utils/filesystem.hpp | 5 -- 30 files changed, 211 insertions(+), 171 deletions(-) rename src/internal/{util.cpp => stringutil.cpp} (98%) create mode 100644 src/internal/stringutil.hpp create mode 100644 tests/src/test_stringutil.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 522698f5..861cc103 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,7 @@ set( HEADERS src/internal/stdinputitem.hpp src/internal/streamextractcallback.hpp src/internal/streamutil.hpp + src/internal/stringutil.hpp src/internal/updatecallback.hpp src/internal/util.hpp src/internal/windows.hpp ) @@ -156,8 +157,8 @@ set( SOURCES src/internal/renameditem.cpp src/internal/stdinputitem.cpp src/internal/streamextractcallback.cpp + src/internal/stringutil.cpp src/internal/updatecallback.cpp - src/internal/util.cpp src/internal/windows.cpp ) # library output file name options diff --git a/src/bit7zlibrary.cpp b/src/bit7zlibrary.cpp index 6be63801..0e14757c 100644 --- a/src/bit7zlibrary.cpp +++ b/src/bit7zlibrary.cpp @@ -13,8 +13,9 @@ #include "bit7zlibrary.hpp" #include "bitexception.hpp" #include "bitformat.hpp" +#include "internal/com.hpp" #include "internal/guids.hpp" -#include "internal/util.hpp" +#include "internal/stringutil.hpp" #include <7zip/Archive/IArchive.h> diff --git a/src/bitarchiveeditor.cpp b/src/bitarchiveeditor.cpp index 69f1a49d..fd4a91cc 100644 --- a/src/bitarchiveeditor.cpp +++ b/src/bitarchiveeditor.cpp @@ -18,7 +18,7 @@ #include "internal/fsitem.hpp" #include "internal/renameditem.hpp" #include "internal/stdinputitem.hpp" -#include "internal/util.hpp" +#include "internal/stringutil.hpp" namespace bit7z { diff --git a/src/bitarchiveitem.cpp b/src/bitarchiveitem.cpp index 99aa3f35..aabdadd9 100644 --- a/src/bitarchiveitem.cpp +++ b/src/bitarchiveitem.cpp @@ -12,7 +12,7 @@ #include "bitarchiveitem.hpp" #include "internal/fsutil.hpp" -#include "internal/util.hpp" +#include "internal/stringutil.hpp" // For checking posix file attributes #include diff --git a/src/bitinputarchive.cpp b/src/bitinputarchive.cpp index d98eda32..4b823d39 100644 --- a/src/bitinputarchive.cpp +++ b/src/bitinputarchive.cpp @@ -26,6 +26,7 @@ #include "internal/fixedbufferextractcallback.hpp" #include "internal/streamextractcallback.hpp" #include "internal/opencallback.hpp" +#include "internal/stringutil.hpp" #include "internal/util.hpp" #ifdef BIT7Z_AUTO_FORMAT diff --git a/src/bititemsvector.cpp b/src/bititemsvector.cpp index f4ceeba3..6f58ed78 100644 --- a/src/bititemsvector.cpp +++ b/src/bititemsvector.cpp @@ -15,7 +15,7 @@ #include "internal/bufferitem.hpp" #include "internal/fsindexer.hpp" #include "internal/stdinputitem.hpp" -#include "internal/util.hpp" +#include "internal/stringutil.hpp" using namespace bit7z; using filesystem::FilesystemItem; diff --git a/src/bitoutputarchive.cpp b/src/bitoutputarchive.cpp index 37e10aee..4682c15a 100644 --- a/src/bitoutputarchive.cpp +++ b/src/bitoutputarchive.cpp @@ -16,8 +16,8 @@ #include "internal/archiveproperties.hpp" #include "internal/cbufferoutstream.hpp" #include "internal/cmultivolumeoutstream.hpp" -#include "internal/fsutil.hpp" #include "internal/genericinputitem.hpp" +#include "internal/stringutil.hpp" #include "internal/updatecallback.hpp" #include "internal/util.hpp" diff --git a/src/bitpropvariant.cpp b/src/bitpropvariant.cpp index 110c9040..63a3d504 100644 --- a/src/bitpropvariant.cpp +++ b/src/bitpropvariant.cpp @@ -14,11 +14,12 @@ #include "biterror.hpp" #include "bitpropvariant.hpp" #include "internal/dateutil.hpp" +#include "internal/windows.hpp" #if defined( BIT7Z_USE_NATIVE_STRING ) && defined( _WIN32 ) // Windows #define BSTR_TO_TSTRING( bstr ) std::wstring( bstr, ::SysStringLen( bstr ) ) #else -#include "internal/util.hpp" +#include "internal/stringutil.hpp" #define BSTR_TO_TSTRING( bstr ) bit7z::narrow( bstr, SysStringLen( bstr ) ) #endif diff --git a/src/bittypes.cpp b/src/bittypes.cpp index 0eaba202..9044fae1 100644 --- a/src/bittypes.cpp +++ b/src/bittypes.cpp @@ -13,7 +13,7 @@ #include "bittypes.hpp" #if defined( _WIN32 ) && !defined( BIT7Z_USE_NATIVE_STRING ) -#include "internal/util.hpp" +#include "internal/stringutil.hpp" #endif namespace bit7z { diff --git a/src/internal/bufferextractcallback.cpp b/src/internal/bufferextractcallback.cpp index 5cdaab64..48201d09 100644 --- a/src/internal/bufferextractcallback.cpp +++ b/src/internal/bufferextractcallback.cpp @@ -14,6 +14,7 @@ #include "internal/bufferextractcallback.hpp" #include "internal/cbufferoutstream.hpp" #include "internal/fs.hpp" +#include "internal/stringutil.hpp" #include "internal/util.hpp" using namespace std; diff --git a/src/internal/bufferitem.cpp b/src/internal/bufferitem.cpp index 998466f1..271dc95e 100644 --- a/src/internal/bufferitem.cpp +++ b/src/internal/bufferitem.cpp @@ -15,6 +15,7 @@ #include "internal/bufferitem.hpp" #include "internal/cbufferinstream.hpp" #include "internal/dateutil.hpp" +#include "internal/stringutil.hpp" #include "internal/util.hpp" using std::vector; diff --git a/src/internal/cfileinstream.cpp b/src/internal/cfileinstream.cpp index a50cb37e..a00950a2 100644 --- a/src/internal/cfileinstream.cpp +++ b/src/internal/cfileinstream.cpp @@ -12,7 +12,7 @@ #include "bitexception.hpp" #include "internal/cfileinstream.hpp" -#include "internal/util.hpp" +#include "internal/stringutil.hpp" #if defined( _WIN32 ) && defined( __GLIBCXX__ ) && defined( _WIO_DEFINED ) #include "internal/fsutil.hpp" diff --git a/src/internal/cfileoutstream.cpp b/src/internal/cfileoutstream.cpp index e04e48cc..3c9ff1b5 100644 --- a/src/internal/cfileoutstream.cpp +++ b/src/internal/cfileoutstream.cpp @@ -14,7 +14,7 @@ #include "bitexception.hpp" #include "internal/cfileoutstream.hpp" -#include "internal/util.hpp" +#include "internal/stringutil.hpp" #if defined( _WIN32 ) && defined( __GLIBCXX__ ) && defined( _WIO_DEFINED ) #include "internal/fsutil.hpp" diff --git a/src/internal/extractcallback.cpp b/src/internal/extractcallback.cpp index d2c366be..51b30ace 100644 --- a/src/internal/extractcallback.cpp +++ b/src/internal/extractcallback.cpp @@ -15,7 +15,7 @@ #include "bitexception.hpp" #include "internal/extractcallback.hpp" #include "internal/operationcategory.hpp" -#include "internal/util.hpp" +#include "internal/stringutil.hpp" namespace bit7z { diff --git a/src/internal/fileextractcallback.cpp b/src/internal/fileextractcallback.cpp index f3d483e1..a34b81a6 100644 --- a/src/internal/fileextractcallback.cpp +++ b/src/internal/fileextractcallback.cpp @@ -13,6 +13,7 @@ #include "bitexception.hpp" #include "internal/fileextractcallback.hpp" #include "internal/fsutil.hpp" +#include "internal/stringutil.hpp" #include "internal/util.hpp" using namespace std; diff --git a/src/internal/fsitem.cpp b/src/internal/fsitem.cpp index 77082203..d7fa9cd7 100644 --- a/src/internal/fsitem.cpp +++ b/src/internal/fsitem.cpp @@ -16,6 +16,7 @@ #include "internal/cfileinstream.hpp" #include "internal/csymlinkinstream.hpp" #include "internal/fsitem.hpp" +#include "internal/stringutil.hpp" #include "internal/util.hpp" namespace bit7z { // NOLINT(modernize-concat-nested-namespaces) diff --git a/src/internal/fsutil.cpp b/src/internal/fsutil.cpp index 510c41c2..ad844cb0 100644 --- a/src/internal/fsutil.cpp +++ b/src/internal/fsutil.cpp @@ -23,7 +23,7 @@ #endif #include "internal/fsutil.hpp" -#include "internal/util.hpp" +#include "internal/stringutil.hpp" using namespace std; diff --git a/src/internal/genericinputitem.cpp b/src/internal/genericinputitem.cpp index 3555507d..0947db9e 100644 --- a/src/internal/genericinputitem.cpp +++ b/src/internal/genericinputitem.cpp @@ -11,7 +11,7 @@ */ #include "internal/genericinputitem.hpp" -#include "util.hpp" +#include "internal/stringutil.hpp" namespace bit7z { diff --git a/src/internal/opencallback.cpp b/src/internal/opencallback.cpp index cb0502ca..c5eb1f6c 100644 --- a/src/internal/opencallback.cpp +++ b/src/internal/opencallback.cpp @@ -13,6 +13,7 @@ #include "bitexception.hpp" #include "internal/cfileinstream.hpp" #include "internal/opencallback.hpp" +#include "internal/stringutil.hpp" #include "internal/util.hpp" namespace bit7z { diff --git a/src/internal/renameditem.cpp b/src/internal/renameditem.cpp index 4e57971e..fc68fe33 100644 --- a/src/internal/renameditem.cpp +++ b/src/internal/renameditem.cpp @@ -13,7 +13,7 @@ #include "internal/dateutil.hpp" #include "internal/fsutil.hpp" #include "internal/renameditem.hpp" -#include "internal/util.hpp" +#include "internal/stringutil.hpp" namespace bit7z { diff --git a/src/internal/stdinputitem.cpp b/src/internal/stdinputitem.cpp index 826eda1c..e1e56fc4 100644 --- a/src/internal/stdinputitem.cpp +++ b/src/internal/stdinputitem.cpp @@ -15,6 +15,7 @@ #include "internal/cstdinstream.hpp" #include "internal/dateutil.hpp" #include "internal/stdinputitem.hpp" +#include "internal/stringutil.hpp" #include "internal/util.hpp" using std::istream; diff --git a/src/internal/util.cpp b/src/internal/stringutil.cpp similarity index 98% rename from src/internal/util.cpp rename to src/internal/stringutil.cpp index 761136a3..64a5a3fd 100644 --- a/src/internal/util.cpp +++ b/src/internal/stringutil.cpp @@ -12,9 +12,10 @@ #include -#include "internal/util.hpp" +#include "internal/stringutil.hpp" #ifdef _WIN32 +#include #ifdef BIT7Z_USE_SYSTEM_CODEPAGE #define CODEPAGE CP_ACP #define CODEPAGE_WC_FLAGS WC_NO_BEST_FIT_CHARS diff --git a/src/internal/stringutil.hpp b/src/internal/stringutil.hpp new file mode 100644 index 00000000..2ac190bb --- /dev/null +++ b/src/internal/stringutil.hpp @@ -0,0 +1,79 @@ +/* + * bit7z - A C++ static library to interface with the 7-zip shared libraries. + * Copyright (c) 2014-2023 Riccardo Ostani - All Rights Reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ + +#ifndef STRINGUTIL_HPP +#define STRINGUTIL_HPP + +#include "bittypes.hpp" +#include "internal/fsutil.hpp" + +namespace bit7z { + +#if defined( BIT7Z_USE_NATIVE_STRING ) && defined( _WIN32 ) +// On Windows, with native strings enabled, strings are already wide! +# define WIDEN( tstr ) tstr +#else +# define WIDEN( tstr ) bit7z::widen(tstr) + +auto narrow( const wchar_t* wideString, size_t size ) -> std::string; + +auto widen( const std::string& narrowString ) -> std::wstring; +#endif + +inline auto path_to_tstring( const fs::path& path ) -> tstring { + /* In an ideal world, we should only use fs::path's string< tchar >() function for converting a path to a tstring. + * However, MSVC converts paths to std::string using the system codepage instead of UTF-8, + * which is the default encoding of bit7z. */ +#if defined( _WIN32 ) && defined( BIT7Z_USE_NATIVE_STRING ) + return path.wstring(); +#elif defined( _WIN32 ) && defined( BIT7Z_USE_SYSTEM_CODEPAGE ) + /* If we encounter a path with Unicode characters, MSVC will throw an exception + * while converting from a fs::path to std::string if any character is invalid in the system codepage. + * Hence, here we use bit7z's own string conversion function, which substitutes invalid Unicode characters + * with '?' characters. */ + const auto& native_path = path.native(); + return narrow( native_path.c_str(), native_path.size() ); +#else + return path.u8string(); +#endif +} + +#if defined( _MSC_VER ) && !defined( BIT7Z_USE_NATIVE_STRING ) && !defined( BIT7Z_USE_SYSTEM_CODEPAGE ) +#define PATH_FROM_TSTRING( str ) fs::u8path( str ) +#else +#define PATH_FROM_TSTRING( str ) fs::path{ str } +#endif + +inline auto tstring_to_path( const tstring& str ) -> fs::path { +#if defined( _WIN32 ) && defined( BIT7Z_AUTO_PREFIX_LONG_PATHS ) + auto result = PATH_FROM_TSTRING( str ); + if ( filesystem::fsutil::should_format_long_path( result ) ) { + result = filesystem::fsutil::format_long_path( result ); + } + return result; +#else + // By default, MSVC treats strings as encoded using the system codepage, but bit7z uses UTF-8. + return PATH_FROM_TSTRING( str ); +#endif +} + +inline auto path_to_wide_string( const fs::path& path ) -> std::wstring { +#if defined( _MSC_VER ) || !defined( BIT7Z_USE_STANDARD_FILESYSTEM ) + return path.wstring(); +#else + /* On some compilers and platforms (e.g., GCC before v12.3), + * the direct conversion of the fs::path to wstring might throw an exception due to unicode characters. + * So we simply convert to tstring, and then widen it if necessary. */ + return WIDEN( path.string< tchar >() ); +#endif +} + +} // namespace bit7z + +#endif //STRINGUTIL_HPP diff --git a/src/internal/updatecallback.cpp b/src/internal/updatecallback.cpp index a3a1109a..0e035aab 100644 --- a/src/internal/updatecallback.cpp +++ b/src/internal/updatecallback.cpp @@ -12,6 +12,7 @@ #include "internal/cfileoutstream.hpp" #include "internal/updatecallback.hpp" +#include "internal/stringutil.hpp" #include "internal/util.hpp" namespace bit7z { diff --git a/src/internal/util.hpp b/src/internal/util.hpp index 381614ce..916c9893 100644 --- a/src/internal/util.hpp +++ b/src/internal/util.hpp @@ -16,7 +16,6 @@ #include #include "internal/com.hpp" -#include "internal/fs.hpp" #if defined( _WIN32 ) && defined( BIT7Z_AUTO_PREFIX_LONG_PATHS ) #include "internal/fsutil.hpp" @@ -24,65 +23,6 @@ namespace bit7z { -#if defined( BIT7Z_USE_NATIVE_STRING ) && defined( _WIN32 ) -// On Windows, with native strings enabled, strings are already wide! -# define WIDEN( tstr ) tstr -#else -# define WIDEN( tstr ) bit7z::widen(tstr) - -auto narrow( const wchar_t* wideString, size_t size ) -> std::string; - -auto widen( const std::string& narrowString ) -> std::wstring; -#endif - -inline auto path_to_tstring( const fs::path& path ) -> tstring { - /* In an ideal world, we should only use fs::path's string< tchar >() function for converting a path to a tstring. - * However, MSVC converts paths to std::string using the system codepage instead of UTF-8, - * which is the default encoding of bit7z. */ -#if defined( _WIN32 ) && defined( BIT7Z_USE_NATIVE_STRING ) - return path.wstring(); -#elif defined( _WIN32 ) && defined( BIT7Z_USE_SYSTEM_CODEPAGE ) - /* If we encounter a path with Unicode characters, MSVC will throw an exception - * while converting from a fs::path to std::string if any character is invalid in the system codepage. - * Hence, here we use bit7z's own string conversion function, which substitutes invalid Unicode characters - * with '?' characters. */ - const auto& native_path = path.native(); - return narrow( native_path.c_str(), native_path.size() ); -#else - return path.u8string(); -#endif -} - -#if defined( _MSC_VER ) && !defined( BIT7Z_USE_NATIVE_STRING ) && !defined( BIT7Z_USE_SYSTEM_CODEPAGE ) -#define PATH_FROM_TSTRING( str ) fs::u8path( str ) -#else -#define PATH_FROM_TSTRING( str ) fs::path{ str } -#endif - -inline auto tstring_to_path( const tstring& str ) -> fs::path { -#if defined( _WIN32 ) && defined( BIT7Z_AUTO_PREFIX_LONG_PATHS ) - auto result = PATH_FROM_TSTRING( str ); - if ( filesystem::fsutil::should_format_long_path( result ) ) { - result = filesystem::fsutil::format_long_path( result ); - } - return result; -#else - // By default, MSVC treats strings as encoded using the system codepage, but bit7z uses UTF-8. - return PATH_FROM_TSTRING( str ); -#endif -} - -inline auto path_to_wide_string( const fs::path& path ) -> std::wstring { -#if defined( _MSC_VER ) || !defined( BIT7Z_USE_STANDARD_FILESYSTEM ) - return path.wstring(); -#else - /* On some compilers and platforms (e.g., GCC before v12.3), - * the direct conversion of the fs::path to wstring might throw an exception due to unicode characters. - * So we simply convert to tstring, and then widen it if necessary. */ - return WIDEN( path.string< tchar >() ); -#endif -} - constexpr inline auto check_overflow( int64_t position, int64_t offset ) noexcept -> bool { return ( ( offset > 0 ) && ( position > ( ( std::numeric_limits< int64_t >::max )() - offset ) ) ) || ( ( offset < 0 ) && ( position < ( ( std::numeric_limits< int64_t >::min )() - offset ) ) ); @@ -106,22 +46,19 @@ constexpr auto cmp_less( T first, U second ) noexcept -> bool { #else // SFINAE implementation for C++14 -template< class T, class U > -constexpr auto -cmp_less( T t, U u ) noexcept -> std::enable_if_t< std::is_signed< T >::value == std::is_signed< U >::value, bool > { - return t < u; +template< class T, class U, std::enable_if_t< std::is_signed< T >::value == std::is_signed< U >::value, int > = 0 > +constexpr auto cmp_less( T first, U second ) noexcept -> bool { + return first < second; } -template< class T, class U > -constexpr auto -cmp_less( T t, U u ) noexcept -> std::enable_if_t< std::is_signed< T >::value && !std::is_signed< U >::value, bool > { - return ( t < 0 ) || ( std::make_unsigned_t< T >( t ) < u ); +template< class T, class U, std::enable_if_t< std::is_signed< T >::value && !std::is_signed< U >::value, int > = 0 > +constexpr auto cmp_less( T first, U second ) noexcept -> bool { + return ( first < 0 ) || ( std::make_unsigned_t< T >( first ) < second ); } -template< class T, class U > -constexpr auto -cmp_less( T t, U u ) noexcept -> std::enable_if_t< !std::is_signed< T >::value && std::is_signed< U >::value, bool > { - return ( u >= 0 ) && ( t < std::make_unsigned_t< U >( u ) ); +template< class T, class U, std::enable_if_t< !std::is_signed< T >::value && std::is_signed< U >::value, int > = 0 > +constexpr auto cmp_less( T first, U second ) noexcept -> bool { + return ( second >= 0 ) && ( first < std::make_unsigned_t< U >( second ) ); } #endif diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5a69400f..4e0c03e8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -37,6 +37,7 @@ set( INTERNAL_API_SOURCE_FILES src/test_dateutil.cpp src/test_fsutil.cpp src/test_util.cpp + src/test_stringutil.cpp src/test_windows.cpp src/test_formatdetect.cpp ) diff --git a/tests/src/test_bitarchivereader.cpp b/tests/src/test_bitarchivereader.cpp index 79b9f942..c3fdbdb3 100644 --- a/tests/src/test_bitarchivereader.cpp +++ b/tests/src/test_bitarchivereader.cpp @@ -19,11 +19,11 @@ #include #include #include -#include +#include #include // Needed by MSVC for defining the S_XXXX macros. -#ifndef _CRT_INTERNAL_NONSTDC_NAMES // NOLINT(*-reserved-identifier) +#ifndef _CRT_INTERNAL_NONSTDC_NAMES // NOLINT(*-reserved-identifier, *-dcl37-c) #define _CRT_INTERNAL_NONSTDC_NAMES 1 #endif @@ -469,6 +469,7 @@ TEMPLATE_TEST_CASE( "BitArchiveReader: Reading an empty archive", } else { REQUIRE( info.archivePath().empty() ); // No archive path for buffer/streamed archives } + REQUIRE_FALSE( info.isEncrypted() ); REQUIRE_ARCHIVE_CONTENT( info, testArchive ); REQUIRE_ARCHIVE_TESTS( info ); } diff --git a/tests/src/test_stringutil.cpp b/tests/src/test_stringutil.cpp new file mode 100644 index 00000000..b94005d6 --- /dev/null +++ b/tests/src/test_stringutil.cpp @@ -0,0 +1,92 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check it. +// PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + +/* + * bit7z - A C++ static library to interface with the 7-zip shared libraries. + * Copyright (c) 2014-2023 Riccardo Ostani - All Rights Reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at https://mozilla.org/MPL/2.0/. + */ +#include + +#include + +#if !defined( _WIN32 ) || ( !defined( BIT7Z_USE_NATIVE_STRING ) && !defined( BIT7Z_USE_SYSTEM_CODEPAGE ) ) + +#define NARROWING_TEST_STR( str ) std::make_tuple( L##str, (str) ) + +TEST_CASE( "util: Narrowing wide string to std::string", "[util][narrow]" ) { + using bit7z::narrow; + + SECTION( "Converting from nullptr C wide string" ) { + REQUIRE( narrow( nullptr, 0 ).empty() ); + REQUIRE( narrow( nullptr, 42 ).empty() ); + } + +#if !defined( _LIBCPP_VERSION ) + SECTION( "Converting wide strings with unencodable UTF-8 chars" ) { + std::wstring testInput = L"\xDC80"; + std::string testOutput = narrow( testInput.c_str(), testInput.size() ); +#if defined( _MSC_VER ) || !defined( BIT7Z_USE_STANDARD_FILESYSTEM ) + REQUIRE( testOutput == "\uFFFD" ); +#else + REQUIRE( testOutput == "\xED\xB2\x80" ); +#endif + + testInput = L"\xD843"; + testOutput = narrow( testInput.c_str(), testInput.size() ); +#if defined( _MSC_VER ) || !defined( BIT7Z_USE_STANDARD_FILESYSTEM ) + REQUIRE( testOutput == "\uFFFD" ); +#else + REQUIRE( testOutput == "\xED\xA1\x83" ); +#endif + } +#endif + + SECTION( "Converting wide strings without unencodable UTF-8 characters" ) { + std::wstring testInput; + std::string testOutput; + std::tie( testInput, testOutput ) = GENERATE( table< const wchar_t*, const char* >( + { + NARROWING_TEST_STR( "" ), + NARROWING_TEST_STR( "h" ), + NARROWING_TEST_STR( "hello world!" ), + NARROWING_TEST_STR( "supercalifragilistichespiralidoso" ), + NARROWING_TEST_STR( "perché" ), + NARROWING_TEST_STR( "\u30e1\u30bf\u30eb\u30ac\u30eb\u30eb\u30e2\u30f3" ) // メタルガルルモン + } + ) ); + + DYNAMIC_SECTION( "Converting L\"" << testOutput << "\" to narrow string" ) { + REQUIRE( narrow( testInput.c_str(), testInput.size() ) == testOutput ); + } + } +} + +#define WIDENING_TEST_STR( str ) std::make_tuple( (str), L##str ) + +TEST_CASE( "util: Widening narrow string to std::wstring", "[util][widen]" ) { + using bit7z::widen; + using std::make_tuple; + + std::string testInput; + std::wstring testOutput; + std::tie( testInput, testOutput ) = GENERATE( table< const char*, const wchar_t* >( + { + WIDENING_TEST_STR( "" ), + WIDENING_TEST_STR( "h" ), + WIDENING_TEST_STR( "hello world!" ), + WIDENING_TEST_STR( "supercalifragilistichespiralidoso" ), + WIDENING_TEST_STR( "perché" ), + WIDENING_TEST_STR( "\u30e1\u30bf\u30eb\u30ac\u30eb\u30eb\u30e2\u30f3" ) // メタルガルルモン + } + ) ); + + DYNAMIC_SECTION( "Converting \"" << testInput << "\" to wide string" ) { + REQUIRE( widen( testInput ) == testOutput ); + } +} + +#endif \ No newline at end of file diff --git a/tests/src/test_util.cpp b/tests/src/test_util.cpp index 7bd44878..c9a41e78 100644 --- a/tests/src/test_util.cpp +++ b/tests/src/test_util.cpp @@ -14,83 +14,6 @@ #include -#if !defined( _WIN32 ) || ( !defined( BIT7Z_USE_NATIVE_STRING ) && !defined( BIT7Z_USE_SYSTEM_CODEPAGE ) ) - -#define NARROWING_TEST_STR( str ) std::make_tuple( L##str, (str) ) - -TEST_CASE( "util: Narrowing wide string to std::string", "[util][narrow]" ) { - using bit7z::narrow; - - SECTION( "Converting from nullptr C wide string" ) { - REQUIRE( narrow( nullptr, 0 ).empty() ); - REQUIRE( narrow( nullptr, 42 ).empty() ); - } - -#if !defined( _LIBCPP_VERSION ) - SECTION( "Converting wide strings with unencodable UTF-8 chars" ) { - std::wstring testInput = L"\xDC80"; - std::string testOutput = narrow( testInput.c_str(), testInput.size() ); -#if defined( _MSC_VER ) || !defined( BIT7Z_USE_STANDARD_FILESYSTEM ) - REQUIRE( testOutput == "\uFFFD" ); -#else - REQUIRE( testOutput == "\xED\xB2\x80" ); -#endif - - testInput = L"\xD843"; - testOutput = narrow( testInput.c_str(), testInput.size() ); -#if defined( _MSC_VER ) || !defined( BIT7Z_USE_STANDARD_FILESYSTEM ) - REQUIRE( testOutput == "\uFFFD" ); -#else - REQUIRE( testOutput == "\xED\xA1\x83" ); -#endif - } -#endif - - SECTION( "Converting wide strings without unencodable UTF-8 characters" ) { - std::wstring testInput; - std::string testOutput; - std::tie( testInput, testOutput ) = GENERATE( table< const wchar_t*, const char* >( - { - NARROWING_TEST_STR( "" ), - NARROWING_TEST_STR( "h" ), - NARROWING_TEST_STR( "hello world!" ), - NARROWING_TEST_STR( "supercalifragilistichespiralidoso" ), - NARROWING_TEST_STR( "perché" ), - NARROWING_TEST_STR( "\u30e1\u30bf\u30eb\u30ac\u30eb\u30eb\u30e2\u30f3" ) // メタルガルルモン - } - ) ); - - DYNAMIC_SECTION( "Converting L\"" << testOutput << "\" to narrow string" ) { - REQUIRE( narrow( testInput.c_str(), testInput.size() ) == testOutput ); - } - } -} - -#define WIDENING_TEST_STR( str ) std::make_tuple( (str), L##str ) - -TEST_CASE( "util: Widening narrow string to std::wstring", "[util][widen]" ) { - using bit7z::widen; - using std::make_tuple; - - std::string testInput; - std::wstring testOutput; - std::tie( testInput, testOutput ) = GENERATE( table< const char*, const wchar_t* >( - { - WIDENING_TEST_STR( "" ), - WIDENING_TEST_STR( "h" ), - WIDENING_TEST_STR( "hello world!" ), - WIDENING_TEST_STR( "supercalifragilistichespiralidoso" ), - WIDENING_TEST_STR( "perché" ), - WIDENING_TEST_STR( "\u30e1\u30bf\u30eb\u30ac\u30eb\u30eb\u30e2\u30f3" ) // メタルガルルモン - } - ) ); - - DYNAMIC_SECTION( "Converting \"" << testInput << "\" to wide string" ) { - REQUIRE( widen( testInput ) == testOutput ); - } -} -#endif - using bit7z::check_overflow; constexpr auto kMaxValue = ( std::numeric_limits< int64_t >::max )(); constexpr auto kMinValue = ( std::numeric_limits< int64_t >::min )(); diff --git a/tests/src/utils/filesystem.hpp b/tests/src/utils/filesystem.hpp index 628af3fe..48ca71af 100644 --- a/tests/src/utils/filesystem.hpp +++ b/tests/src/utils/filesystem.hpp @@ -28,11 +28,6 @@ #include #include -#include - -#if defined(__MINGW32__) && defined(_WIO_DEFINED) -#include "internal/fsutil.hpp" -#endif namespace bit7z { // NOLINT(modernize-concat-nested-namespaces) namespace test { From 3ab6a2b0c522a7197911e413a6b28659755e615d Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 15:23:25 +0200 Subject: [PATCH 33/62] [Test] Run only the full tests app in GH action --- .github/workflows/ctest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index fb998a6e..ee4cbde8 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -140,4 +140,4 @@ jobs: ASAN_OPTIONS: alloc_dealloc_mismatch=0 # Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail - run: ctest --build-config ${{ matrix.build_type }} --output-on-failure + run: ctest --build-target bit7z-tests --build-config ${{ matrix.build_type }} --output-on-failure From 79069f97d9271bc90ccb82c24a39221da10bb5ec Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 15:29:36 +0200 Subject: [PATCH 34/62] Fix test tag for stringutil --- tests/src/test_stringutil.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/src/test_stringutil.cpp b/tests/src/test_stringutil.cpp index b94005d6..ff51e9e9 100644 --- a/tests/src/test_stringutil.cpp +++ b/tests/src/test_stringutil.cpp @@ -17,7 +17,7 @@ #define NARROWING_TEST_STR( str ) std::make_tuple( L##str, (str) ) -TEST_CASE( "util: Narrowing wide string to std::string", "[util][narrow]" ) { +TEST_CASE( "util: Narrowing wide string to std::string", "[stringutil][narrow]" ) { using bit7z::narrow; SECTION( "Converting from nullptr C wide string" ) { @@ -67,7 +67,7 @@ TEST_CASE( "util: Narrowing wide string to std::string", "[util][narrow]" ) { #define WIDENING_TEST_STR( str ) std::make_tuple( (str), L##str ) -TEST_CASE( "util: Widening narrow string to std::wstring", "[util][widen]" ) { +TEST_CASE( "util: Widening narrow string to std::wstring", "[stringutil][widen]" ) { using bit7z::widen; using std::make_tuple; From bfd9448b4d725d64a08336778b12d9cd7189a5a0 Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 15:56:54 +0200 Subject: [PATCH 35/62] Clean up unused code and fix comments --- src/bitoutputarchive.cpp | 2 +- src/internal/cfileinstream.cpp | 4 ---- src/internal/cfileoutstream.cpp | 6 +----- src/internal/util.hpp | 4 ---- 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/bitoutputarchive.cpp b/src/bitoutputarchive.cpp index 4682c15a..2af2a11f 100644 --- a/src/bitoutputarchive.cpp +++ b/src/bitoutputarchive.cpp @@ -35,7 +35,7 @@ BitOutputArchive::BitOutputArchive( const BitAbstractArchiveCreator& creator, co return; } - if ( inArc.empty() ) { // No input file specified, so we are creating a totally new archive! + if ( inArc.empty() ) { // No input file specified, so we are creating a totally new archive. return; } diff --git a/src/internal/cfileinstream.cpp b/src/internal/cfileinstream.cpp index a00950a2..24888a37 100644 --- a/src/internal/cfileinstream.cpp +++ b/src/internal/cfileinstream.cpp @@ -14,10 +14,6 @@ #include "internal/cfileinstream.hpp" #include "internal/stringutil.hpp" -#if defined( _WIN32 ) && defined( __GLIBCXX__ ) && defined( _WIO_DEFINED ) -#include "internal/fsutil.hpp" -#endif - namespace bit7z { CFileInStream::CFileInStream( const fs::path& filePath ) : CStdInStream( mFileStream ), mBuffer{} { diff --git a/src/internal/cfileoutstream.cpp b/src/internal/cfileoutstream.cpp index 3c9ff1b5..8ccbc8a6 100644 --- a/src/internal/cfileoutstream.cpp +++ b/src/internal/cfileoutstream.cpp @@ -16,10 +16,6 @@ #include "internal/cfileoutstream.hpp" #include "internal/stringutil.hpp" -#if defined( _WIN32 ) && defined( __GLIBCXX__ ) && defined( _WIO_DEFINED ) -#include "internal/fsutil.hpp" -#endif - namespace bit7z { CFileOutStream::CFileOutStream( fs::path filePath, bool createAlways ) @@ -27,7 +23,7 @@ CFileOutStream::CFileOutStream( fs::path filePath, bool createAlways ) std::error_code error; if ( !createAlways && fs::exists( mFilePath, error ) ) { if ( !error ) { - // the call to fs::exists succeeded, but the filePath exists, and this is an error! + // The call to fs::exists succeeded, but the filePath exists, and this is an error. error = std::make_error_code( std::errc::file_exists ); } throw BitException( "Failed to create the output file", error, path_to_tstring( mFilePath ) ); diff --git a/src/internal/util.hpp b/src/internal/util.hpp index 916c9893..968226ce 100644 --- a/src/internal/util.hpp +++ b/src/internal/util.hpp @@ -17,10 +17,6 @@ #include "internal/com.hpp" -#if defined( _WIN32 ) && defined( BIT7Z_AUTO_PREFIX_LONG_PATHS ) -#include "internal/fsutil.hpp" -#endif - namespace bit7z { constexpr inline auto check_overflow( int64_t position, int64_t offset ) noexcept -> bool { From dc428796f0f186f026bbf9592af4a96b37b3ee83 Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 17:19:51 +0200 Subject: [PATCH 36/62] [Test] Parallel CMake build --- .github/workflows/ctest.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index ee4cbde8..3ee927e0 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -113,7 +113,7 @@ jobs: - name: Build bit7z # Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator). - run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} + run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} --parallel - name: Build 7z.so for tests (Ubuntu) shell: bash From e08afa45a070c2b825383be0b1ea1254029bb121 Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 17:37:52 +0200 Subject: [PATCH 37/62] Remove GCC from macOS test builds --- .github/workflows/ctest.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index 3ee927e0..e8a68623 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -71,7 +71,6 @@ jobs: c_compiler: cl - os: macos-latest c_compiler: gcc - bit7z_link_libcpp: ON - os: macos-latest bit7z_use_native_string: ON - os: macos-latest From 2680848c8981f7d20f6ad4bb90ac20b0a319098c Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 18:39:01 +0200 Subject: [PATCH 38/62] Add more tests for archive format detection --- tests/CMakeLists.txt | 2 +- tests/src/test_formatdetect.cpp | 28 ++++++++++++++++------------ 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4e0c03e8..b085f296 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -53,7 +53,7 @@ if( BIT7Z_TESTS_FILESYSTEM ) include( FetchContent ) FetchContent_Declare( bit7z-test-data GIT_REPOSITORY https://github.com/rikyoz/bit7z-test-data.git - GIT_TAG a2966c00854ecadb4dfdadbb30b48e7eeeb8772b + GIT_TAG abc1adc273dd8dd17f55969838811f98872d77b8 GIT_SHALLOW ON SOURCE_DIR ${BIT7Z_TESTS_DATA_DIR} ) FetchContent_MakeAvailable( bit7z-test-data ) diff --git a/tests/src/test_formatdetect.cpp b/tests/src/test_formatdetect.cpp index 7ce1a3a3..5d211faf 100644 --- a/tests/src/test_formatdetect.cpp +++ b/tests/src/test_formatdetect.cpp @@ -28,7 +28,7 @@ using namespace bit7z; using namespace bit7z::test; using namespace bit7z::test::filesystem; -// Note: format detection by extension doesn't actually require the file to exist! +// Note: format detection by extension doesn't actually require the file to exist. TEST_CASE( "formatdetect: Format detection by extension", "[formatdetect]" ) { const TestDirectory testDir{ fs::path{ test_archives_dir } / "detection" / "valid" }; @@ -265,19 +265,23 @@ TEST_CASE( "formatdetect: Format detection of archive with a wrong extension (Is const Bit7zLibrary lib{ test::sevenzip_lib_path() }; - // From file - REQUIRE_THROWS( BitArchiveReader( lib, BIT7Z_STRING( "wrong_extension.rar" ), BitFormat::Rar ) ); - REQUIRE_NOTHROW( BitArchiveReader( lib, BIT7Z_STRING( "wrong_extension.rar" ), BitFormat::SevenZip ) ); - REQUIRE_NOTHROW( BitArchiveReader( lib, BIT7Z_STRING( "wrong_extension.rar" ) ) ); + auto testFile = GENERATE( BIT7Z_STRING( "wrong_extension.rar" ), BIT7Z_STRING( "wrong_extension.bz2" ) ); - // From buffer - auto fileBuffer = load_file( "wrong_extension.rar" ); - REQUIRE_THROWS( BitArchiveReader( lib, fileBuffer, BitFormat::Rar ) ); - REQUIRE_NOTHROW( BitArchiveReader( lib, fileBuffer, BitFormat::SevenZip ) ); - REQUIRE_NOTHROW( BitArchiveReader( lib, fileBuffer ) ); + DYNAMIC_SECTION( "Reading file with a wrong extension: " << Catch::StringMaker< tstring >::convert( testFile ) ) { + // From file + REQUIRE_THROWS( BitArchiveReader( lib, testFile, BitFormat::Rar ) ); + REQUIRE_NOTHROW( BitArchiveReader( lib, testFile, BitFormat::SevenZip ) ); + REQUIRE_NOTHROW( BitArchiveReader( lib, testFile ) ); + + // From buffer + auto fileBuffer = load_file( testFile ); + REQUIRE_THROWS( BitArchiveReader( lib, fileBuffer, BitFormat::Rar ) ); + REQUIRE_NOTHROW( BitArchiveReader( lib, fileBuffer, BitFormat::SevenZip ) ); + REQUIRE_NOTHROW( BitArchiveReader( lib, fileBuffer ) ); + } } -TEST_CASE( "BitArchiveReader: Format detection of an archive file without extension", "[bitarchivereader]" ) { +TEST_CASE( "BitArchiveReader: Format detection of an archive file without an extension", "[bitarchivereader]" ) { const TestDirectory testDir{ fs::path{ test_archives_dir } / "detection" }; REQUIRE( detect_format_from_extension( "noextension" ) == BitFormat::Auto ); @@ -288,4 +292,4 @@ TEST_CASE( "BitArchiveReader: Format detection of an archive file without extens REQUIRE_NOTHROW( reader.test() ); } -#endif \ No newline at end of file +#endif // BIT7Z_AUTO_FORMAT \ No newline at end of file From 4a375e0a9c4b968fd2d3fb9e46426e4226e2130c Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 15 Oct 2023 18:39:13 +0200 Subject: [PATCH 39/62] Fix comments --- src/bitabstractarchivecreator.cpp | 4 ++-- src/bitinputarchive.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bitabstractarchivecreator.cpp b/src/bitabstractarchivecreator.cpp index 600e2da4..32f4930b 100644 --- a/src/bitabstractarchivecreator.cpp +++ b/src/bitabstractarchivecreator.cpp @@ -106,7 +106,7 @@ auto method_name( BitCompressionMethod method ) noexcept -> const wchar_t* { case BitCompressionMethod::Deflate64: return L"Deflate64"; default: - return L"Unknown"; //this should not happen! + return L"Unknown"; // This should not happen. } } @@ -216,7 +216,7 @@ void BitAbstractArchiveCreator::setCompressionMethod( BitCompressionMethod metho if ( mFormat.hasFeature( FormatFeatures::MultipleMethods ) ) { /* even though the compression method is valid, we set it only if the format supports * different methods than the default one (i.e., setting BitCompressionMethod::BZip2 - * of a BitFormat::BZip2 archive does nothing!) */ + * of a BitFormat::BZip2 archive does nothing) */ mCompressionMethod = method; mDictionarySize = 0; //reset dictionary size to default value for the method mWordSize = 0; //reset word size to default value for the method diff --git a/src/bitinputarchive.cpp b/src/bitinputarchive.cpp index 4b823d39..b6b2464e 100644 --- a/src/bitinputarchive.cpp +++ b/src/bitinputarchive.cpp @@ -70,7 +70,7 @@ auto BitInputArchive::openArchiveStream( const fs::path& name, IInStream* inStre CMyComPtr< IInArchive > inArchive = mArchiveHandler.library().initInArchive( mArchiveHandler.format() ); #endif // NOTE: CMyComPtr is still needed: if an error occurs, and an exception is thrown, - // the IInArchive object is deleted automatically! + // the IInArchive object is deleted automatically. // Creating open callback for the file auto openCallback = bit7z::make_com< OpenCallback >( mArchiveHandler, name ); @@ -86,9 +86,9 @@ auto BitInputArchive::openArchiveStream( const fs::path& name, IInStream* inStre /* User wanted auto-detection of the format, an extension was detected but opening failed, so we try a more * precise detection by checking the signature. * NOTE: If user specified explicitly a format (i.e., not BitFormat::Auto), this check is not performed, - * and an exception is thrown (next if)! + * and an exception is thrown (next if). * NOTE 2: If signature detection was already performed (detectedBySignature == false), it detected - * a wrong format, no further check can be done, and an exception must be thrown (next if)! */ + * a wrong format, no further check can be done, and an exception must be thrown (next if). */ /* Opening the file might have changed the current file pointer, so we reset it to the beginning of the file * to correctly read the file signature. */ From ff9bc02ca5bb88728037f83e985bb82f2bfc391a Mon Sep 17 00:00:00 2001 From: Oz Date: Mon, 16 Oct 2023 18:58:40 +0200 Subject: [PATCH 40/62] Improve test coverage of BitAbstractArchiveCreator --- tests/src/test_bitabstractarchivecreator.cpp | 303 ++++++++++++++++++- 1 file changed, 301 insertions(+), 2 deletions(-) diff --git a/tests/src/test_bitabstractarchivecreator.cpp b/tests/src/test_bitabstractarchivecreator.cpp index cd356624..a72dc2d8 100644 --- a/tests/src/test_bitabstractarchivecreator.cpp +++ b/tests/src/test_bitabstractarchivecreator.cpp @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -19,6 +20,7 @@ using namespace bit7z; using bit7z::Bit7zLibrary; +using bit7z::BitArchiveWriter; using bit7z::BitFileCompressor; using bit7z::BitMemCompressor; using bit7z::BitStreamCompressor; @@ -30,7 +32,8 @@ struct TestOutputFormat { }; TEMPLATE_TEST_CASE( "BitAbstractArchiveCreator: Basic API tests", - "[bitabstractarchivecreator]", BitFileCompressor, BitMemCompressor, BitStreamCompressor ) { + "[bitabstractarchivecreator]", + BitArchiveWriter, BitFileCompressor, BitMemCompressor, BitStreamCompressor ) { const Bit7zLibrary lib{ test::sevenzip_lib_path() }; SECTION( "setPassword(...) / password() / cryptHeaders()" ) { @@ -65,7 +68,54 @@ TEMPLATE_TEST_CASE( "BitAbstractArchiveCreator: Basic API tests", REQUIRE( !compressor.cryptHeaders() ); } - SECTION( "compressionFormat()" ) { +#ifndef BIT7Z_DISABLE_ZIP_ASCII_PWD_CHECK + SECTION( "setPassword(...) with a non-ASCII string should throw when using the ZIP format" ) { + TestType compressor{ lib, BitFormat::Zip }; + REQUIRE( compressor.password().empty() ); + REQUIRE( !compressor.cryptHeaders() ); + + REQUIRE_NOTHROW( compressor.setPassword( BIT7Z_STRING( "password" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + REQUIRE_THROWS( compressor.setPassword( BIT7Z_STRING( "contraseña" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + // The carriage return is an ASCII character, but 7-zip doesn't support + // also non-printable ASCII characters for ZIP passwords. + REQUIRE_THROWS( compressor.setPassword( BIT7Z_STRING( "car\riage" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + // The unit separator character is the last non-printable ASCII character. + REQUIRE_THROWS( compressor.setPassword( BIT7Z_STRING( "unit\x1Fseparator" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + // The DEL character is not supported by bit7z for ZIP passwords. + REQUIRE_THROWS( compressor.setPassword( BIT7Z_STRING( "del\U0000007F" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + // The space character is the first printable ASCII character supported. + REQUIRE_NOTHROW( compressor.setPassword( BIT7Z_STRING( "password with spaces" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password with spaces" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + // The tilde character is the last printable ASCII character supported. + REQUIRE_NOTHROW( compressor.setPassword( BIT7Z_STRING( "password~with~tilde" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password~with~tilde" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + // Resetting the password + REQUIRE_NOTHROW( compressor.setPassword( BIT7Z_STRING( "" ) ) ); + REQUIRE( compressor.password().empty() ); + REQUIRE( !compressor.cryptHeaders() ); + } +#endif + + SECTION( "format() / compressionFormat()" ) { const auto testFormat = GENERATE( as< TestOutputFormat >(), TestOutputFormat{ "ZIP", BitFormat::Zip }, TestOutputFormat{ "BZIP2", BitFormat::BZip2 }, @@ -77,6 +127,7 @@ TEMPLATE_TEST_CASE( "BitAbstractArchiveCreator: Basic API tests", DYNAMIC_SECTION( "Format: " << testFormat.name ) { const TestType compressor{ lib, testFormat.format }; REQUIRE( compressor.compressionFormat() == testFormat.format ); + REQUIRE( compressor.format() == testFormat.format ); } } @@ -199,6 +250,74 @@ TEMPLATE_TEST_CASE( "BitAbstractArchiveCreator: Basic API tests", } } + SECTION( "setDictionarySize(...) / dictionarySize()" ) { + + SECTION( "SevenZip format + Lzma/Lzma2 compression methods" ) { + constexpr auto kMaxLzmaDictionarySize = 1536 * ( 1LL << 20 ); // less than 1536 MiB + + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.dictionarySize() == 0 ); + + auto testMethod = GENERATE( BitCompressionMethod::Lzma, BitCompressionMethod::Lzma2 ); + compressor.setCompressionMethod( testMethod ); + + uint32_t dictionarySize = 1024 * 1024 * 1024; + compressor.setDictionarySize( dictionarySize ); + REQUIRE( compressor.dictionarySize() == dictionarySize ); + + compressor.setDictionarySize( kMaxLzmaDictionarySize ); + REQUIRE( compressor.dictionarySize() == kMaxLzmaDictionarySize ); + + dictionarySize = std::numeric_limits< uint32_t >::max(); + REQUIRE_THROWS( compressor.setDictionarySize( std::numeric_limits< uint32_t >::max() ) ); + REQUIRE( compressor.dictionarySize() == kMaxLzmaDictionarySize ); + } + + SECTION( "Zip format + Ppmd compression methods" ) { + constexpr uint32_t kMaxPpmdDictionarySize = ( 1ULL << 30 ); // less than 1 GiB, i.e., 2^30 bytes + + TestType compressor( lib, BitFormat::Zip ); + REQUIRE( compressor.dictionarySize() == 0 ); + compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); + + uint32_t dictionarySize = 1024 * 1024 * 1024; + compressor.setDictionarySize( dictionarySize ); + REQUIRE( compressor.dictionarySize() == dictionarySize ); + + compressor.setDictionarySize( kMaxPpmdDictionarySize ); + REQUIRE( compressor.dictionarySize() == kMaxPpmdDictionarySize ); + + dictionarySize = std::numeric_limits< uint32_t >::max(); + REQUIRE_THROWS( compressor.setDictionarySize( std::numeric_limits< uint32_t >::max() ) ); + REQUIRE( compressor.dictionarySize() == kMaxPpmdDictionarySize ); + + auto testMethod = GENERATE( BitCompressionMethod::Copy, + BitCompressionMethod::Deflate, + BitCompressionMethod::Deflate64 ); + compressor.setCompressionMethod( testMethod ); + REQUIRE_NOTHROW( compressor.setDictionarySize( 1024 * 1024 ) ); + REQUIRE( compressor.dictionarySize() == 0 ); + } + + SECTION( "BZip2 format and compression methods" ) { + constexpr auto kMaxBzip2DictionarySize = 900 * ( 1LL << 10 ); // less than 900 KiB + + TestType compressor( lib, BitFormat::BZip2 ); + REQUIRE( compressor.dictionarySize() == 0 ); + + uint32_t dictionarySize = 1024; + compressor.setDictionarySize( dictionarySize ); + REQUIRE( compressor.dictionarySize() == dictionarySize ); + + compressor.setDictionarySize( kMaxBzip2DictionarySize ); + REQUIRE( compressor.dictionarySize() == kMaxBzip2DictionarySize ); + + dictionarySize = std::numeric_limits< uint32_t >::max(); + REQUIRE_THROWS( compressor.setDictionarySize( std::numeric_limits< uint32_t >::max() ) ); + REQUIRE( compressor.dictionarySize() == kMaxBzip2DictionarySize ); + } + } + SECTION( "setSolidMode(...) / solidMode()" ) { TestType compressor( lib, BitFormat::SevenZip ); REQUIRE( !compressor.solidMode() ); @@ -210,10 +329,190 @@ TEMPLATE_TEST_CASE( "BitAbstractArchiveCreator: Basic API tests", REQUIRE( !compressor.solidMode() ); } + SECTION( "setStoreSymbolicLinks(...) / storeSymbolicLinks()" ) { + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.storeSymbolicLinks() == false ); + + compressor.setStoreSymbolicLinks( true ); + REQUIRE( compressor.storeSymbolicLinks() == true ); + REQUIRE( compressor.solidMode() == true ); + + compressor.setStoreSymbolicLinks( false ); + REQUIRE( compressor.storeSymbolicLinks() == false ); + REQUIRE( compressor.solidMode() == false ); + } + + SECTION( "setThreadCount(...) / threadCount()" ) { + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.threadsCount() == 0u ); + compressor.setThreadsCount( 8u ); + REQUIRE( compressor.threadsCount() == 8u ); + } + + SECTION( "setUpdateMode(...) / updateMode()" ) { + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.updateMode() == UpdateMode::None ); + + compressor.setUpdateMode( true ); + REQUIRE( compressor.updateMode() == UpdateMode::Append ); + + compressor.setUpdateMode( false ); + REQUIRE( compressor.updateMode() == UpdateMode::None ); + + compressor.setUpdateMode( UpdateMode::Append ); + REQUIRE( compressor.updateMode() == UpdateMode::Append ); + + compressor.setUpdateMode( UpdateMode::Update ); + REQUIRE( compressor.updateMode() == UpdateMode::Update ); + + compressor.setUpdateMode( UpdateMode::None ); + REQUIRE( compressor.updateMode() == UpdateMode::None ); + } + SECTION( "setVolumeSize(...) / volumeSize()" ) { TestType compressor( lib, BitFormat::SevenZip ); REQUIRE( compressor.volumeSize() == 0u ); compressor.setVolumeSize( 1024u ); REQUIRE( compressor.volumeSize() == 1024u ); } + + SECTION( "setWordSize(...) / wordSize()" ) { + constexpr auto kMinPpmdWordSize = 2u; + + SECTION( "SevenZip format + Lzma/Lzma2 compression methods" ) { + constexpr auto kMinLzmaWordSize = 5u; + constexpr auto kMaxLzmaWordSize = 273u; + + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE_THROWS( compressor.setWordSize( 4u ) ); + REQUIRE( compressor.wordSize() == 0 ); + + REQUIRE_NOTHROW( compressor.setWordSize( kMinLzmaWordSize ) ); + REQUIRE( compressor.wordSize() == kMinLzmaWordSize ); + + REQUIRE_NOTHROW( compressor.setWordSize( 128u ) ); + REQUIRE( compressor.wordSize() == 128u ); + + REQUIRE_NOTHROW( compressor.setWordSize( kMaxLzmaWordSize ) ); + REQUIRE( compressor.wordSize() == kMaxLzmaWordSize ); + + REQUIRE_THROWS( compressor.setWordSize( kMaxLzmaWordSize + 1 ) ); + REQUIRE( compressor.wordSize() == kMaxLzmaWordSize ); + + REQUIRE_THROWS( compressor.setWordSize( 512u ) ); + REQUIRE( compressor.wordSize() == kMaxLzmaWordSize ); + + REQUIRE_NOTHROW( compressor.setWordSize( 0 ) ); + REQUIRE( compressor.wordSize() == 0 ); + + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); + REQUIRE_NOTHROW( compressor.setWordSize( 64u ) ); + REQUIRE( compressor.wordSize() == 0 ); + + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); + REQUIRE_NOTHROW( compressor.setWordSize( 64u ) ); + REQUIRE( compressor.wordSize() == 0 ); + } + + SECTION( "SevenZip format + Ppmd compression method" ) { + constexpr auto kMax7zPpmdWordSize = 32u; + + TestType compressor( lib, BitFormat::SevenZip ); + compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); + + REQUIRE_THROWS( compressor.setWordSize( 1u ) ); + REQUIRE( compressor.wordSize() == 0 ); + + REQUIRE_NOTHROW( compressor.setWordSize( kMinPpmdWordSize ) ); + REQUIRE( compressor.wordSize() == kMinPpmdWordSize ); + + REQUIRE_NOTHROW( compressor.setWordSize( 16u ) ); + REQUIRE( compressor.wordSize() == 16u ); + + REQUIRE_NOTHROW( compressor.setWordSize( kMax7zPpmdWordSize ) ); + REQUIRE( compressor.wordSize() == kMax7zPpmdWordSize ); + + REQUIRE_THROWS( compressor.setWordSize( kMax7zPpmdWordSize + 1 ) ); + REQUIRE( compressor.wordSize() == kMax7zPpmdWordSize ); + + REQUIRE_THROWS( compressor.setWordSize( 64u ) ); + REQUIRE( compressor.wordSize() == kMax7zPpmdWordSize ); + + REQUIRE_NOTHROW( compressor.setWordSize( 0 ) ); + REQUIRE( compressor.wordSize() == 0 ); + } + + SECTION( "Zip format + Ppmd compression method") { + constexpr auto kMaxZipPpmdWordSize = 16u; + + TestType compressor( lib, BitFormat::Zip ); + compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); + + REQUIRE_THROWS( compressor.setWordSize( 1u ) ); + REQUIRE( compressor.wordSize() == 0 ); + + REQUIRE_NOTHROW( compressor.setWordSize( kMinPpmdWordSize ) ); + REQUIRE( compressor.wordSize() == kMinPpmdWordSize ); + + REQUIRE_NOTHROW( compressor.setWordSize( 16u ) ); + REQUIRE( compressor.wordSize() == 16u ); + + REQUIRE_NOTHROW( compressor.setWordSize( kMaxZipPpmdWordSize ) ); + REQUIRE( compressor.wordSize() == kMaxZipPpmdWordSize ); + + REQUIRE_THROWS( compressor.setWordSize( kMaxZipPpmdWordSize + 1 ) ); + REQUIRE( compressor.wordSize() == kMaxZipPpmdWordSize ); + + REQUIRE_THROWS( compressor.setWordSize( 32u ) ); + REQUIRE( compressor.wordSize() == kMaxZipPpmdWordSize ); + + REQUIRE_NOTHROW( compressor.setWordSize( 0 ) ); + REQUIRE( compressor.wordSize() == 0 ); + } + + SECTION( "Zip format + Deflate/Deflate64 compression method") { + constexpr auto kMinDeflateWordSize = 3u; + constexpr auto kMaxDeflateWordSize = 258u; + constexpr auto kMaxDeflate64WordSize = kMaxDeflateWordSize - 1; + + TestType compressor( lib, BitFormat::Zip ); + compressor.setCompressionMethod( BitCompressionMethod::Deflate ); + + REQUIRE_THROWS( compressor.setWordSize( 2u ) ); + REQUIRE( compressor.wordSize() == 0 ); + + REQUIRE_NOTHROW( compressor.setWordSize( kMinDeflateWordSize ) ); + REQUIRE( compressor.wordSize() == kMinDeflateWordSize ); + + REQUIRE_NOTHROW( compressor.setWordSize( 64u ) ); + REQUIRE( compressor.wordSize() == 64u ); + + REQUIRE_NOTHROW( compressor.setWordSize( kMaxDeflateWordSize ) ); + REQUIRE( compressor.wordSize() == kMaxDeflateWordSize ); + + REQUIRE_THROWS( compressor.setWordSize( kMaxDeflateWordSize + 1 ) ); + REQUIRE( compressor.wordSize() == kMaxDeflateWordSize ); + + compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ); + REQUIRE( compressor.wordSize() == 0 ); + + REQUIRE_THROWS( compressor.setWordSize( 1u ) ); + REQUIRE( compressor.wordSize() == 0 ); + + REQUIRE_NOTHROW( compressor.setWordSize( kMinDeflateWordSize ) ); + REQUIRE( compressor.wordSize() == kMinDeflateWordSize ); + + REQUIRE_NOTHROW( compressor.setWordSize( 64u ) ); + REQUIRE( compressor.wordSize() == 64u ); + + REQUIRE_NOTHROW( compressor.setWordSize( kMaxDeflate64WordSize ) ); + REQUIRE( compressor.wordSize() == kMaxDeflate64WordSize ); + + REQUIRE_THROWS( compressor.setWordSize( kMaxDeflate64WordSize + 1 ) ); + REQUIRE( compressor.wordSize() == kMaxDeflate64WordSize ); + + REQUIRE_NOTHROW( compressor.setWordSize( 0 ) ); + REQUIRE( compressor.wordSize() == 0 ); + } + } } \ No newline at end of file From 3309982b79088ba306efb9f13cdb4e5befe7cb03 Mon Sep 17 00:00:00 2001 From: Oz Date: Mon, 16 Oct 2023 19:00:23 +0200 Subject: [PATCH 41/62] Improve error messages when opening file streams --- src/internal/cfileinstream.cpp | 5 +---- src/internal/cfileoutstream.cpp | 4 +--- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/internal/cfileinstream.cpp b/src/internal/cfileinstream.cpp index 24888a37..65a6c31a 100644 --- a/src/internal/cfileinstream.cpp +++ b/src/internal/cfileinstream.cpp @@ -29,10 +29,7 @@ CFileInStream::CFileInStream( const fs::path& filePath ) : CStdInStream( mFileSt void CFileInStream::openFile( const fs::path& filePath ) { mFileStream.open( filePath, std::ios::in | std::ios::binary ); // flawfinder: ignore if ( mFileStream.fail() ) { - //Note: CFileInStream constructor does not directly throw exceptions since it is also used in nothrow functions. - throw BitException( "Failed to open the archive file", - make_hresult_code( HRESULT_FROM_WIN32( ERROR_OPEN_FAILED ) ), - path_to_tstring( filePath ) ); + throw BitException( "Failed to open the archive file", last_error_code(), path_to_tstring( filePath ) ); } } diff --git a/src/internal/cfileoutstream.cpp b/src/internal/cfileoutstream.cpp index 8ccbc8a6..ba7bf7e3 100644 --- a/src/internal/cfileoutstream.cpp +++ b/src/internal/cfileoutstream.cpp @@ -30,9 +30,7 @@ CFileOutStream::CFileOutStream( fs::path filePath, bool createAlways ) } mFileStream.open( mFilePath, std::ios::binary | std::ios::trunc ); // flawfinder: ignore if ( mFileStream.fail() ) { - throw BitException( "Failed to open the output file", - make_hresult_code( HRESULT_FROM_WIN32( ERROR_OPEN_FAILED ) ), - path_to_tstring( mFilePath ) ); + throw BitException( "Failed to open the output file", last_error_code(), path_to_tstring( mFilePath ) ); } mFileStream.rdbuf()->pubsetbuf( mBuffer.data(), kBufferSize ); From 03a269d821a8ea9172c11360e4c5182db18bedc6 Mon Sep 17 00:00:00 2001 From: Oz Date: Mon, 16 Oct 2023 19:00:49 +0200 Subject: [PATCH 42/62] Remove deprecated warnings in tests app --- tests/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index b085f296..f6c84feb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -131,6 +131,9 @@ endif() if( MSVC ) target_compile_options( ${TESTS_TARGET} PRIVATE /utf-8 ) target_compile_options( ${TESTS_TARGET_PUBLIC} PRIVATE /utf-8 ) +else() + target_compile_options( ${TESTS_TARGET} PRIVATE -Wno-deprecated -Wno-deprecated-declarations ) + target_compile_options( ${TESTS_TARGET_PUBLIC} PRIVATE -Wno-deprecated -Wno-deprecated-declarations ) endif() if( WIN32 ) From eb58cf1b2b53d2ea6acd9117ebb115d699b9197b Mon Sep 17 00:00:00 2001 From: Oz Date: Mon, 16 Oct 2023 19:01:17 +0200 Subject: [PATCH 43/62] Clean up code in BitAbstractArchiveCreator --- src/bitabstractarchivecreator.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bitabstractarchivecreator.cpp b/src/bitabstractarchivecreator.cpp index 32f4930b..19f31c56 100644 --- a/src/bitabstractarchivecreator.cpp +++ b/src/bitabstractarchivecreator.cpp @@ -185,7 +185,7 @@ void BitAbstractArchiveCreator::setPassword( const tstring& password ) { auto is_ascii( const tstring& str ) -> bool { return std::all_of( str.begin(), str.end(), []( tchar character ) -> bool { // Note: 7-zip supports the DEL character (code 127), while bit7z doesn't. - constexpr auto kFirstAsciiChar = 32; // A + constexpr auto kFirstAsciiChar = 32; // Space character constexpr auto kLastAsciiChar = 127; return character >= kFirstAsciiChar && character < kLastAsciiChar; } ); @@ -199,7 +199,7 @@ void BitAbstractArchiveCreator::setPassword( const tstring& password, bool crypt } #endif BitAbstractArchiveHandler::setPassword( password ); - mCryptHeaders = ( password.length() > 0 ) && cryptHeaders; + mCryptHeaders = !password.empty() && cryptHeaders; } void BitAbstractArchiveCreator::setCompressionLevel( BitCompressionLevel level ) noexcept { From 9fd6793d5462ee11dcc6a0fcbcb2f1b864011fd1 Mon Sep 17 00:00:00 2001 From: Oz Date: Mon, 16 Oct 2023 19:03:58 +0200 Subject: [PATCH 44/62] Fix manually linking bit7z when enabling BIT7Z_AUTO_FORMAT Close issue #173 --- src/internal/formatdetect.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/internal/formatdetect.cpp b/src/internal/formatdetect.cpp index c1be4271..266e0814 100644 --- a/src/internal/formatdetect.cpp +++ b/src/internal/formatdetect.cpp @@ -10,12 +10,14 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ +#include "internal/formatdetect.hpp" + +// Note: the formatdetect.hpp header must be included before this ifdef since the BIT7Z_AUTO_FORMAT +// flag might be manually specified in the bitdefines.hpp header (included by formatdetect.hpp). #ifdef BIT7Z_AUTO_FORMAT #include -#include "internal/formatdetect.hpp" - #if defined(BIT7Z_USE_NATIVE_STRING) && defined(_WIN32) #include // for std::iswdigit #else From ee52b829412f14366e03bb5902e7ea183f5b59fa Mon Sep 17 00:00:00 2001 From: Oz Date: Mon, 16 Oct 2023 19:04:51 +0200 Subject: [PATCH 45/62] [Test] Suppress unsigned-shift-base sanitizer warning in formatdetect --- src/internal/formatdetect.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/internal/formatdetect.cpp b/src/internal/formatdetect.cpp index 266e0814..da1639c0 100644 --- a/src/internal/formatdetect.cpp +++ b/src/internal/formatdetect.cpp @@ -363,6 +363,10 @@ auto read_signature( IInStream* stream, uint32_t size ) noexcept -> uint64_t { return bswap64( signature ); } +// Note: the left shifting of the signature mask might overflow, but it is intentional, so we suppress the sanitizer. +#if defined(__clang__) +__attribute__((no_sanitize("unsigned-shift-base"))) +#endif auto detect_format_from_signature( IInStream* stream ) -> const BitInFormat& { constexpr auto kSignatureSize = 8U; constexpr auto kBaseSignatureMask = 0xFFFFFFFFFFFFFFFFULL; From f2424c499697f8f2a460d80482e57f2e7d268722 Mon Sep 17 00:00:00 2001 From: Oz Date: Mon, 16 Oct 2023 19:08:10 +0200 Subject: [PATCH 46/62] Remove remaining macOS + gcc job in GH action workflow --- .github/workflows/ctest.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/ctest.yml b/.github/workflows/ctest.yml index e8a68623..191cefb2 100644 --- a/.github/workflows/ctest.yml +++ b/.github/workflows/ctest.yml @@ -39,10 +39,6 @@ jobs: c_compiler: clang cpp_compiler: clang++ use_system_7zip: OFF - - os: macos-latest - c_compiler: gcc - cpp_compiler: g++ - use_system_7zip: OFF - os: macos-latest c_compiler: clang cpp_compiler: clang++ From f8c32b5417d6de0ca52ff4bf11c3314bdfd72bf7 Mon Sep 17 00:00:00 2001 From: Oz Date: Mon, 16 Oct 2023 19:13:43 +0200 Subject: [PATCH 47/62] [Test] Update the project version in the CMakeLists.txt --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 861cc103..6ef13148 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,7 +5,7 @@ cmake_minimum_required( VERSION 3.11 ) project( bit7z - VERSION 4.0.3 + VERSION 4.0.4 DESCRIPTION "A C++ static library offering a clean and simple interface to the 7-zip/p7zip shared libraries" HOMEPAGE_URL "https://github.com/rikyoz/bit7z/" ) set( CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "ON" ) From f29b26f59c161d9805f9b30af7afb07f909b6bba Mon Sep 17 00:00:00 2001 From: Oz Date: Mon, 16 Oct 2023 19:38:19 +0200 Subject: [PATCH 48/62] Fix tag in formatdetect tests --- tests/src/test_formatdetect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/test_formatdetect.cpp b/tests/src/test_formatdetect.cpp index 5d211faf..0ce4b196 100644 --- a/tests/src/test_formatdetect.cpp +++ b/tests/src/test_formatdetect.cpp @@ -281,7 +281,7 @@ TEST_CASE( "formatdetect: Format detection of archive with a wrong extension (Is } } -TEST_CASE( "BitArchiveReader: Format detection of an archive file without an extension", "[bitarchivereader]" ) { +TEST_CASE( "formatdetect: Format detection of an archive file without an extension", "[formatdetect]" ) { const TestDirectory testDir{ fs::path{ test_archives_dir } / "detection" }; REQUIRE( detect_format_from_extension( "noextension" ) == BitFormat::Auto ); From 8d9e95fee92db4343f4d58fd6347dc9cae76b511 Mon Sep 17 00:00:00 2001 From: Oz Date: Mon, 16 Oct 2023 19:38:46 +0200 Subject: [PATCH 49/62] Remove the public API tests target from Catch2 tests discovery --- tests/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f6c84feb..7956ebc8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -160,5 +160,4 @@ target_link_libraries( ${TESTS_TARGET_PUBLIC} PRIVATE Catch2::Catch2 ) include( CTest ) include( Catch ) -catch_discover_tests( ${TESTS_TARGET} ) -catch_discover_tests( ${TESTS_TARGET_PUBLIC} ) \ No newline at end of file +catch_discover_tests( ${TESTS_TARGET} ) \ No newline at end of file From 4e6a2849189dbb2386645c4355e193fee4f5dd38 Mon Sep 17 00:00:00 2001 From: Oz Date: Mon, 16 Oct 2023 21:21:11 +0200 Subject: [PATCH 50/62] [Test] Add BitException tests on Clang --- tests/src/test_bitexception.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/src/test_bitexception.cpp b/tests/src/test_bitexception.cpp index 480ea31e..e2167593 100644 --- a/tests/src/test_bitexception.cpp +++ b/tests/src/test_bitexception.cpp @@ -10,7 +10,7 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ -#if !defined(__GNUC__) || __GNUC__ >= 5 +#if !defined(__GNUC__) || __GNUC__ >= 5 || defined( __clang__ ) #include @@ -253,7 +253,7 @@ TEST_CASE( "BitException: Checking if failed files are moved to the exception co REQUIRE( exceptionFailedFiles.size() == 1 ); REQUIRE( exceptionFailedFiles[ 0 ].first == BIT7Z_STRING( "hello.txt" ) ); REQUIRE( exceptionFailedFiles[ 0 ].second == std::errc::bad_file_descriptor ); - // Note: BitException should have cleared failedFiles, so it is again usable! + // Note: BitException should have cleared failedFiles, so it is again usable. REQUIRE( failedFiles.empty() ); // NOLINT(bugprone-use-after-move) //-V1030 } From 039953568c341ee21b893963ce79ad2420c75911 Mon Sep 17 00:00:00 2001 From: Oz Date: Sat, 21 Oct 2023 20:30:25 +0200 Subject: [PATCH 51/62] [Test] Fix implicit unsigned/signed integer conversions --- cmake/CompilerOptions.cmake | 2 +- src/internal/bufferutil.cpp | 28 +- src/internal/bufferutil.hpp | 2 +- src/internal/cbufferinstream.cpp | 14 +- src/internal/cbufferoutstream.cpp | 9 +- src/internal/cfixedbufferoutstream.cpp | 34 +-- src/internal/cfixedbufferoutstream.hpp | 2 +- src/internal/cmultivolumeinstream.cpp | 26 +- src/internal/cmultivolumeoutstream.cpp | 9 +- src/internal/cstdinstream.cpp | 3 +- src/internal/cstdoutstream.cpp | 3 +- src/internal/cvolumeoutstream.cpp | 8 +- src/internal/dateutil.cpp | 5 +- src/internal/dateutil.hpp | 2 +- src/internal/formatdetect.cpp | 6 +- src/internal/fsutil.cpp | 4 +- src/internal/hresultcategory.cpp | 9 +- src/internal/stringutil.cpp | 4 +- src/internal/util.hpp | 74 ++++- src/internal/windows.cpp | 12 +- tests/src/test_util.cpp | 369 +++++++++++++++++++++++++ 21 files changed, 521 insertions(+), 104 deletions(-) diff --git a/cmake/CompilerOptions.cmake b/cmake/CompilerOptions.cmake index 580a2303..107c26c1 100644 --- a/cmake/CompilerOptions.cmake +++ b/cmake/CompilerOptions.cmake @@ -68,7 +68,7 @@ if( MSVC ) endforeach() endif() else() - target_compile_options( ${LIB_TARGET} PRIVATE -Wall -Wextra -Werror ) + target_compile_options( ${LIB_TARGET} PRIVATE -Wall -Wextra -Werror -Wconversion -Wsign-conversion ) endif() # Extra warning flags for Clang diff --git a/src/internal/bufferutil.cpp b/src/internal/bufferutil.cpp index c8f69b30..25a321d9 100644 --- a/src/internal/bufferutil.cpp +++ b/src/internal/bufferutil.cpp @@ -17,44 +17,30 @@ auto bit7z::seek( const buffer_t& buffer, const buffer_t::const_iterator& currentPosition, int64_t offset, uint32_t seekOrigin, - int64_t& newPosition ) -> HRESULT { - int64_t currentIndex; // NOLINT(cppcoreguidelines-init-variables) + uint64_t& newPosition ) -> HRESULT { + uint64_t currentIndex{}; switch ( seekOrigin ) { case STREAM_SEEK_SET: { - currentIndex = 0; break; } case STREAM_SEEK_CUR: { - currentIndex = ( currentPosition - buffer.cbegin() ); + currentIndex = static_cast< uint64_t >( currentPosition - buffer.cbegin() ); break; } case STREAM_SEEK_END: { - currentIndex = ( buffer.cend() - buffer.cbegin() ); + currentIndex = static_cast< uint64_t >( buffer.cend() - buffer.cbegin() ); break; } default: return STG_E_INVALIDFUNCTION; } - // Checking if the sum between currentIndex and offset would result in an integer overflow or underflow. - if ( check_overflow( currentIndex, offset ) ) { - return E_INVALIDARG; - } - - const int64_t newIndex = currentIndex + offset; - - // Making sure the newIndex value is between 0 and mBuffer.size() - if ( newIndex < 0 ) { - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - } + RINOK( seek_to_offset( currentIndex, offset ) ) - /* Note: a std::vector's max size can be at most std::numeric_limits< std::ptrdiff_t >::max() - * (see https://en.cppreference.com/w/cpp/container/vector/max_size). - * Since index_t is just an alias for std::ptrdiff_t, the following cast is safe. */ - if ( newIndex > static_cast< index_t >( buffer.size() ) ) { + if ( currentIndex > buffer.size() ) { return E_INVALIDARG; } - newPosition = newIndex; + newPosition = currentIndex; return S_OK; } \ No newline at end of file diff --git a/src/internal/bufferutil.hpp b/src/internal/bufferutil.hpp index 3c0ceaac..357cb19e 100644 --- a/src/internal/bufferutil.hpp +++ b/src/internal/bufferutil.hpp @@ -19,7 +19,7 @@ auto seek( const buffer_t& buffer, const buffer_t::const_iterator& currentPosition, int64_t offset, uint32_t seekOrigin, - int64_t& newPosition ) -> HRESULT; + uint64_t& newPosition ) -> HRESULT; } // namespace bit7z diff --git a/src/internal/cbufferinstream.cpp b/src/internal/cbufferinstream.cpp index 123dff74..e3dafc45 100644 --- a/src/internal/cbufferinstream.cpp +++ b/src/internal/cbufferinstream.cpp @@ -38,11 +38,11 @@ STDMETHODIMP CBufferInStream::Read( void* data, UInt32 size, UInt32* processedSi /* Note: thanks to CBufferInStream::Seek, we can safely assume mCurrentPosition to always be a valid iterator; * so "remaining" will always be > 0 (and casts to unsigned types are safe) */ - size_t remaining = mBuffer.cend() - mCurrentPosition; - if ( remaining > static_cast< size_t >( size ) ) { - /* The remaining buffer still to read is bigger than the buffer size requested by the user, + std::ptrdiff_t remaining = mBuffer.cend() - mCurrentPosition; + if ( cmp_greater( remaining, size ) ) { + /* The remaining buffer still to read is bigger than the read size requested by the user, * so we need to read just a "size" number of bytes. */ - remaining = static_cast< size_t >( size ); + remaining = static_cast< std::ptrdiff_t >( size ); } /* Else, the user requested to read a number of bytes greater than or equal to the number * of remaining bytes to be read from the buffer. @@ -54,7 +54,7 @@ STDMETHODIMP CBufferInStream::Read( void* data, UInt32 size, UInt32* processedSi if ( processedSize != nullptr ) { /* Note: even though on 64-bit systems "remaining" will be a 64-bit unsigned integer (size_t), - * its value cannot be greater than "size", which is a 32-bit unsigned int. Hence, this cast is safe! */ + * its value cannot be greater than "size", which is a 32-bit unsigned int; hence, this cast is safe. */ *processedSize = static_cast< UInt32 >( remaining ); } return S_OK; @@ -62,7 +62,7 @@ STDMETHODIMP CBufferInStream::Read( void* data, UInt32 size, UInt32* processedSi COM_DECLSPEC_NOTHROW STDMETHODIMP CBufferInStream::Seek( Int64 offset, UInt32 seekOrigin, UInt64* newPosition ) noexcept { - int64_t newIndex{}; + uint64_t newIndex{}; const HRESULT res = seek( mBuffer, mCurrentPosition, offset, seekOrigin, newIndex ); if ( res != S_OK ) { @@ -75,7 +75,7 @@ STDMETHODIMP CBufferInStream::Seek( Int64 offset, UInt32 seekOrigin, UInt64* new if ( newPosition != nullptr ) { // Safe cast, since newIndex >= 0 - *newPosition = static_cast< UInt64 >( newIndex ); + *newPosition = newIndex; } return S_OK; diff --git a/src/internal/cbufferoutstream.cpp b/src/internal/cbufferoutstream.cpp index 0315b4a7..3b9e5ee4 100644 --- a/src/internal/cbufferoutstream.cpp +++ b/src/internal/cbufferoutstream.cpp @@ -32,7 +32,7 @@ STDMETHODIMP CBufferOutStream::SetSize( UInt64 newSize ) noexcept { COM_DECLSPEC_NOTHROW STDMETHODIMP CBufferOutStream::Seek( Int64 offset, UInt32 seekOrigin, UInt64* newPosition ) noexcept { - int64_t newIndex{}; + uint64_t newIndex{}; const HRESULT res = seek( mBuffer, mCurrentPosition, offset, seekOrigin, newIndex ); if ( res != S_OK ) { @@ -44,8 +44,7 @@ STDMETHODIMP CBufferOutStream::Seek( Int64 offset, UInt32 seekOrigin, UInt64* ne mCurrentPosition = mBuffer.begin() + static_cast< index_t >( newIndex ); if ( newPosition != nullptr ) { - // Safe cast, since newIndex >=0 0 - *newPosition = static_cast< UInt64 >( newIndex ); + *newPosition = newIndex; } return S_OK; @@ -62,14 +61,14 @@ STDMETHODIMP CBufferOutStream::Write( const void* data, UInt32 size, UInt32* pro } auto oldPos = ( mCurrentPosition - mBuffer.begin() ); - const size_t newPos = oldPos + size; + const size_t newPos = static_cast< size_t >( oldPos ) + size; if ( newPos > mBuffer.size() ) { try { mBuffer.resize( newPos ); } catch ( ... ) { return E_OUTOFMEMORY; } - mCurrentPosition = mBuffer.begin() + oldPos; //resize invalidated the old mCurrentPosition iterator + mCurrentPosition = mBuffer.begin() + oldPos; // resize(...) invalidated the old mCurrentPosition iterator } const auto* byteData = static_cast< const byte_t* >( data ); //-V2571 diff --git a/src/internal/cfixedbufferoutstream.cpp b/src/internal/cfixedbufferoutstream.cpp index c9fce674..6c310011 100644 --- a/src/internal/cfixedbufferoutstream.cpp +++ b/src/internal/cfixedbufferoutstream.cpp @@ -21,7 +21,7 @@ namespace bit7z { CFixedBufferOutStream::CFixedBufferOutStream( byte_t* buffer, std::size_t size ) : mBuffer( buffer ), mBufferSize( size ), mCurrentPosition( 0 ) { - if ( size == 0 || cmp_greater( size, ( std::numeric_limits< int64_t >::max )() ) ) { + if ( size == 0 ) { throw BitException( "Could not initialize output buffer stream", make_error_code( BitError::InvalidOutputBufferSize ) ); } @@ -34,43 +34,34 @@ STDMETHODIMP CFixedBufferOutStream::SetSize( UInt64 newSize ) noexcept { COM_DECLSPEC_NOTHROW STDMETHODIMP CFixedBufferOutStream::Seek( Int64 offset, UInt32 seekOrigin, UInt64* newPosition ) noexcept { - int64_t currentIndex{}; + uint64_t seekIndex{}; switch ( seekOrigin ) { case STREAM_SEEK_SET: { break; } case STREAM_SEEK_CUR: { - currentIndex = mCurrentPosition; + seekIndex = mCurrentPosition; break; } case STREAM_SEEK_END: { - currentIndex = static_cast< int64_t >( mBufferSize ); + seekIndex = mBufferSize; break; } default: return STG_E_INVALIDFUNCTION; } - // Checking if the sum between the currentIndex and offset would result in an integer overflow or underflow - if ( check_overflow( currentIndex, offset ) ) { - return E_INVALIDARG; - } - - const int64_t newIndex = currentIndex + offset; - - // Making sure the newIndex value is between 0 and mBufferSize - 1 - if ( newIndex < 0 ) { - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - } + RINOK( seek_to_offset( seekIndex, offset ) ) - if ( cmp_greater_equal( newIndex, mBufferSize ) ) { + // Making sure seekIndex is a valid index within the buffer (i.e., it is less than mBufferSize). + if ( seekIndex >= mBufferSize ) { return E_INVALIDARG; } - mCurrentPosition = newIndex; + mCurrentPosition = clamp_cast< size_t >( seekIndex ); if ( newPosition != nullptr ) { - *newPosition = newIndex; + *newPosition = seekIndex; } return S_OK; @@ -87,10 +78,11 @@ STDMETHODIMP CFixedBufferOutStream::Write( const void* data, UInt32 size, UInt32 } uint32_t writeSize = size; - if ( cmp_greater_equal( size, mBufferSize - mCurrentPosition ) ) { + size_t remainingSize = mBufferSize - mCurrentPosition; // The Seek method ensures mCurrentPosition < mBufferSize. + if ( size > remainingSize ) { /* Writing only to the remaining part of the output buffer! - * Note: since size is an uint32_t, and size >= mBufferSize - mCurrentPosition, the cast is safe! */ - writeSize = static_cast< uint32_t >( mBufferSize - mCurrentPosition ); + * Note: since size is an uint32_t, and size >= mBufferSize - mCurrentPosition, the cast is safe. */ + writeSize = clamp_cast< uint32_t >( remainingSize ); } const auto* byteData = static_cast< const byte_t* >( data ); //-V2571 diff --git a/src/internal/cfixedbufferoutstream.hpp b/src/internal/cfixedbufferoutstream.hpp index f46444b9..d4c76d58 100644 --- a/src/internal/cfixedbufferoutstream.hpp +++ b/src/internal/cfixedbufferoutstream.hpp @@ -46,7 +46,7 @@ class CFixedBufferOutStream final : public IOutStream, public CMyUnknownImp { private: byte_t* mBuffer; size_t mBufferSize; - int64_t mCurrentPosition; + size_t mCurrentPosition; }; } // namespace bit7z diff --git a/src/internal/cmultivolumeinstream.cpp b/src/internal/cmultivolumeinstream.cpp index 778f7698..2f888021 100644 --- a/src/internal/cmultivolumeinstream.cpp +++ b/src/internal/cmultivolumeinstream.cpp @@ -93,38 +93,22 @@ STDMETHODIMP CMultiVolumeInStream::Read( void* data, UInt32 size, UInt32* proces COM_DECLSPEC_NOTHROW STDMETHODIMP CMultiVolumeInStream::Seek( Int64 offset, UInt32 seekOrigin, UInt64* newPosition ) noexcept { - uint64_t originPosition; // NOLINT(cppcoreguidelines-init-variables) + uint64_t seekPosition{}; switch ( seekOrigin ) { case STREAM_SEEK_SET: - originPosition = 0; break; case STREAM_SEEK_CUR: - originPosition = mCurrentPosition; + seekPosition = mCurrentPosition; break; case STREAM_SEEK_END: - originPosition = mTotalSize; + seekPosition = mTotalSize; break; default: return STG_E_INVALIDFUNCTION; } - // Checking if adding the offset would result in the unsigned wrap around of the current position. - if ( offset < 0 ) { - const auto positiveOffset = static_cast< uint64_t >( -offset ); - if ( originPosition < positiveOffset ) { - return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; - } - mCurrentPosition = originPosition - positiveOffset; - } else if ( offset == 0 ) { - mCurrentPosition = originPosition; - } else { - const auto positiveOffset = static_cast< uint64_t >( offset ); - const uint64_t seekPosition = originPosition + positiveOffset; - if ( seekPosition < originPosition || seekPosition < positiveOffset ) { - return E_INVALIDARG; - } - mCurrentPosition = seekPosition; - } + RINOK( seek_to_offset( seekPosition, offset ) ) + mCurrentPosition = seekPosition; if ( newPosition != nullptr ) { *newPosition = mCurrentPosition; diff --git a/src/internal/cmultivolumeoutstream.cpp b/src/internal/cmultivolumeoutstream.cpp index 43061b27..cb23a748 100644 --- a/src/internal/cmultivolumeoutstream.cpp +++ b/src/internal/cmultivolumeoutstream.cpp @@ -103,19 +103,22 @@ STDMETHODIMP CMultiVolumeOutStream::Write( const void* data, UInt32 size, UInt32 COM_DECLSPEC_NOTHROW STDMETHODIMP CMultiVolumeOutStream::Seek( Int64 offset, UInt32 seekOrigin, UInt64* newPosition ) noexcept { + uint64_t seekPosition{}; switch ( seekOrigin ) { case STREAM_SEEK_SET: - mAbsoluteOffset = static_cast< uint64_t >( offset ); break; case STREAM_SEEK_CUR: - mAbsoluteOffset += static_cast< uint64_t >( offset ); + seekPosition = mAbsoluteOffset; break; case STREAM_SEEK_END: - mAbsoluteOffset = mFullSize + static_cast< uint64_t >( offset ); + seekPosition = mFullSize; break; default: return STG_E_INVALIDFUNCTION; } + + RINOK( seek_to_offset( seekPosition, offset ) ) + mAbsoluteOffset = seekPosition; mCurrentVolumeOffset = mAbsoluteOffset; if ( newPosition != nullptr ) { *newPosition = mAbsoluteOffset; diff --git a/src/internal/cstdinstream.cpp b/src/internal/cstdinstream.cpp index 14e09df3..78b79a4f 100644 --- a/src/internal/cstdinstream.cpp +++ b/src/internal/cstdinstream.cpp @@ -12,6 +12,7 @@ #include "internal/cstdinstream.hpp" #include "internal/streamutil.hpp" +#include "internal/util.hpp" namespace bit7z { @@ -29,7 +30,7 @@ STDMETHODIMP CStdInStream::Read( void* data, UInt32 size, UInt32* processedSize return S_OK; } - mInputStream.read( static_cast< char* >( data ), size ); // flawfinder: ignore //-V2571 + mInputStream.read( static_cast< char* >( data ), clamp_cast< std::streamsize >( size ) ); // flawfinder: ignore //-V2571 if ( processedSize != nullptr ) { *processedSize = static_cast< uint32_t >( mInputStream.gcount() ); diff --git a/src/internal/cstdoutstream.cpp b/src/internal/cstdoutstream.cpp index 40c065c5..d750132d 100644 --- a/src/internal/cstdoutstream.cpp +++ b/src/internal/cstdoutstream.cpp @@ -14,6 +14,7 @@ #include "internal/cstdoutstream.hpp" #include "internal/streamutil.hpp" +#include "internal/util.hpp" namespace bit7z { @@ -31,7 +32,7 @@ STDMETHODIMP CStdOutStream::Write( const void* data, UInt32 size, UInt32* proces const auto oldPos = mOutputStream.tellp(); - mOutputStream.write( static_cast< const char* >( data ), size ); //-V2571 + mOutputStream.write( static_cast< const char* >( data ), clamp_cast< std::streamsize >( size ) ); //-V2571 if ( processedSize != nullptr ) { *processedSize = static_cast< uint32_t >( mOutputStream.tellp() - oldPos ); diff --git a/src/internal/cvolumeoutstream.cpp b/src/internal/cvolumeoutstream.cpp index d703acf8..f7fad755 100644 --- a/src/internal/cvolumeoutstream.cpp +++ b/src/internal/cvolumeoutstream.cpp @@ -19,8 +19,12 @@ CVolumeOutStream::CVolumeOutStream( const fs::path& volumeName ) COM_DECLSPEC_NOTHROW STDMETHODIMP CVolumeOutStream::Seek( Int64 offset, UInt32 seekOrigin, UInt64* newPosition ) noexcept { - RINOK( CStdOutStream::Seek( offset, seekOrigin, newPosition ) ) - mCurrentOffset = offset; + UInt64 pos{}; + RINOK( CStdOutStream::Seek( offset, seekOrigin, &pos ) ) + mCurrentOffset = pos; + if ( newPosition != nullptr ) { + *newPosition = pos; + } return S_OK; } diff --git a/src/internal/dateutil.cpp b/src/internal/dateutil.cpp index 2df3b60f..fecbb0bc 100644 --- a/src/internal/dateutil.cpp +++ b/src/internal/dateutil.cpp @@ -31,8 +31,9 @@ auto FILETIME_to_file_time_type( FILETIME fileTime ) -> fs::file_time_type { return fs::file_time_type{ std::chrono::duration_cast< std::chrono::system_clock::duration >( unixEpoch ) }; } -auto time_to_FILETIME( const std::time_t& timeValue ) -> FILETIME { - const uint64_t timeInSeconds = ( timeValue * 10000000ull ) + 116444736000000000; // NOLINT(*-magic-numbers) +auto time_to_FILETIME( std::time_t timeValue ) -> FILETIME { + // NOLINTNEXTLINE(*-magic-numbers) + const uint64_t timeInSeconds = ( static_cast< uint64_t >( timeValue ) * 10000000ull ) + 116444736000000000; FILETIME fileTime{}; fileTime.dwLowDateTime = static_cast< DWORD >( timeInSeconds ); fileTime.dwHighDateTime = static_cast< DWORD >( timeInSeconds >> 32 ); diff --git a/src/internal/dateutil.hpp b/src/internal/dateutil.hpp index 1cf9fbd8..defc2f19 100644 --- a/src/internal/dateutil.hpp +++ b/src/internal/dateutil.hpp @@ -23,7 +23,7 @@ namespace bit7z { auto FILETIME_to_file_time_type( FILETIME fileTime ) -> fs::file_time_type; -auto time_to_FILETIME( const std::time_t& timeValue ) -> FILETIME; +auto time_to_FILETIME( std::time_t timeValue ) -> FILETIME; #endif diff --git a/src/internal/formatdetect.cpp b/src/internal/formatdetect.cpp index da1639c0..bcf2a41e 100644 --- a/src/internal/formatdetect.cpp +++ b/src/internal/formatdetect.cpp @@ -364,8 +364,8 @@ auto read_signature( IInStream* stream, uint32_t size ) noexcept -> uint64_t { } // Note: the left shifting of the signature mask might overflow, but it is intentional, so we suppress the sanitizer. -#if defined(__clang__) -__attribute__((no_sanitize("unsigned-shift-base"))) +#if defined(__clang__) && defined(__clang_major__) && (__clang_major__ >= 12) +__attribute__((no_sanitize ("unsigned-shift-base"))) #endif auto detect_format_from_signature( IInStream* stream ) -> const BitInFormat& { constexpr auto kSignatureSize = 8U; @@ -452,7 +452,7 @@ auto detect_format_from_signature( IInStream* stream ) -> const BitInFormat& { # define is_digit(ch) std::iswdigit(ch) != 0 const auto to_lower = std::towlower; #else -inline auto is_digit( unsigned char character ) -> bool { +inline auto is_digit( char character ) -> bool { return std::isdigit( character ) != 0; } diff --git a/src/internal/fsutil.cpp b/src/internal/fsutil.cpp index ad844cb0..febc36da 100644 --- a/src/internal/fsutil.cpp +++ b/src/internal/fsutil.cpp @@ -145,7 +145,7 @@ auto restore_symlink( const std::string& name ) -> bool { } // Shrinking the path string to its actual size. - linkPath.resize( ifs.gcount() ); + linkPath.resize( static_cast< size_t >( ifs.gcount() ) ); // No need to keep the file open. ifs.close(); @@ -212,7 +212,7 @@ auto fsutil::set_file_attributes( const fs::path& filePath, DWORD attributes ) n } else if ( S_ISLNK( fileStat.st_mode ) ) { return true; } else if ( !S_ISDIR( fileStat.st_mode ) && ( attributes & FILE_ATTRIBUTE_READONLY ) != 0 ) { - fileStat.st_mode &= ~( S_IWUSR | S_IWGRP | S_IWOTH ); + fileStat.st_mode &= static_cast< mode_t >( ~( S_IWUSR | S_IWGRP | S_IWOTH ) ); } const fs::perms filePermissions = static_cast< fs::perms >( fileStat.st_mode & global_umask ) & fs::perms::mask; diff --git a/src/internal/hresultcategory.cpp b/src/internal/hresultcategory.cpp index 77cb7c94..3906b274 100644 --- a/src/internal/hresultcategory.cpp +++ b/src/internal/hresultcategory.cpp @@ -28,7 +28,12 @@ auto HRESULTCategory::message( int errorValue ) const -> std::string { FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_MAX_WIDTH_MASK, - nullptr, errorValue, 0, reinterpret_cast< LPSTR >( &messageBuffer ), 0, nullptr ); + nullptr, + static_cast< DWORD >( errorValue ), + 0, + reinterpret_cast< LPSTR >( &messageBuffer ), // NOLINT(*-pro-type-reinterpret-cast) + 0, + nullptr ); if ( msgSize == 0 ) { return "Unknown error"; } @@ -39,7 +44,7 @@ auto HRESULTCategory::message( int errorValue ) const -> std::string { LocalFree( messageBuffer ); return errorMessage; #else - // Note: same messages returned by FormatMessageA on Windows platform. + // Note: same messages returned by FormatMessageA on Windows. switch ( static_cast< HRESULT >( errorValue ) ) { case E_ABORT: return "Operation aborted"; diff --git a/src/internal/stringutil.cpp b/src/internal/stringutil.cpp index 64a5a3fd..9a0a3f44 100644 --- a/src/internal/stringutil.cpp +++ b/src/internal/stringutil.cpp @@ -58,7 +58,7 @@ auto narrow( const wchar_t* wideString, size_t size ) -> std::string { return ""; } - std::string result( narrowStringSize, 0 ); + std::string result( static_cast< std::string::size_type >( narrowStringSize ), 0 ); WideCharToMultiByte( CODEPAGE, CODEPAGE_WC_FLAGS, wideString, @@ -91,7 +91,7 @@ auto widen( const std::string& narrowString ) -> std::wstring { return L""; } - std::wstring result( wideStringSize, 0 ); + std::wstring result( static_cast< std::wstring::size_type >( wideStringSize ), 0 ); MultiByteToWideChar( CODEPAGE, 0, narrowString.c_str(), diff --git a/src/internal/util.hpp b/src/internal/util.hpp index 968226ce..0b354f7f 100644 --- a/src/internal/util.hpp +++ b/src/internal/util.hpp @@ -24,6 +24,31 @@ constexpr inline auto check_overflow( int64_t position, int64_t offset ) noexcep ( ( offset < 0 ) && ( position < ( ( std::numeric_limits< int64_t >::min )() - offset ) ) ); } +#if defined(__clang__) && defined(__clang_major__) && (__clang_major__ >= 4) +__attribute__((no_sanitize ("unsigned-integer-overflow"))) +#endif +inline auto seek_to_offset( uint64_t& position, int64_t offset ) noexcept -> HRESULT { + // Checking if adding the offset would result in the unsigned wrap around of the current position. + if ( offset < 0 ) { + if ( offset == std::numeric_limits< int64_t >::min() ) { + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + } + const auto positiveOffset = static_cast< uint64_t >( -offset ); + if ( position < positiveOffset ) { + return HRESULT_WIN32_ERROR_NEGATIVE_SEEK; + } + position -= positiveOffset; + } else if ( offset > 0 ) { + const auto positiveOffset = static_cast< uint64_t >( offset ); + const uint64_t seekPosition = position + positiveOffset; + if ( seekPosition < position ) { + return E_INVALIDARG; + } + position = seekPosition; + } + return S_OK; +} + /* Safe integer comparison like in C++20 */ #ifdef __cpp_if_constexpr @@ -72,11 +97,58 @@ constexpr auto cmp_greater_equal( T first, U second ) noexcept -> bool { template< bool B > using bool_constant = std::integral_constant< bool, B >; // like C++17's std::bool_constant +// TODO: Use a variable template like have_same_signedness_v; supported from GCC 5+, MSVC 2015 Update 2 +template< typename T, typename U > +using have_same_signedness = bool_constant< std::is_signed< T >::value == std::is_signed< U >::value >; + +template< typename T, typename U > +using are_both_signed = bool_constant< std::is_signed< T >::value && std::is_signed< U >::value >; + +template< typename T, typename U > +using are_both_unsigned = bool_constant< std::is_unsigned< T >::value && std::is_unsigned< U >::value >; + +template< typename T, typename U > +using are_both_integral = bool_constant< std::is_integral< T >::value && std::is_integral< U >::value >; + +template< typename To, typename From > +using is_narrower_signed = bool_constant< are_both_signed< To, From >::value && sizeof( To ) < sizeof( From ) >; + +template< typename To, typename From > +inline auto clamp_cast( From value ) noexcept -> std::enable_if_t< are_both_integral< To, From >::value && + ( is_narrower_signed< To, From >::value || + !have_same_signedness< From, To >::value ), To > { + constexpr auto kMaxValue = std::numeric_limits< To >::max(); + if ( cmp_greater( value, kMaxValue ) ) { + return kMaxValue; + } + + constexpr auto kMinValue = std::numeric_limits< To >::min(); + if ( cmp_less( value, kMinValue ) ) { + return kMinValue; + } + + return static_cast< To >( value ); +} + +template< typename To, typename From > +inline auto clamp_cast( From value ) noexcept -> std::enable_if_t< are_both_unsigned< From, To >::value && + sizeof( To ) < sizeof( From ), To > { + constexpr auto kMaxValue = std::numeric_limits< To >::max(); + return value > kMaxValue ? kMaxValue : static_cast< To >( value ); +} + +template< typename To, typename From > +inline auto clamp_cast( From value ) noexcept -> std::enable_if_t< are_both_integral< To, From >::value && + have_same_signedness< To, From >::value && + sizeof( To ) >= sizeof( From ), To > { + return value; +} + template< typename T, typename I = T > using is_com_type = bool_constant< std::is_base_of< CMyUnknownImp, T >::value && std::is_base_of< I, T >::value >; template< typename T, typename I = T, class... Args > -inline auto make_com( Args&& ... args ) -> CMyComPtr< typename std::enable_if< is_com_type< T, I >::value, I >::type > { +inline auto make_com( Args&& ... args ) -> CMyComPtr< std::enable_if_t< is_com_type< T, I >::value, I > > { return CMyComPtr< I >( new T( std::forward< Args >( args )... ) ); //-V2511 } diff --git a/src/internal/windows.cpp b/src/internal/windows.cpp index 729bfd6c..9304aed7 100644 --- a/src/internal/windows.cpp +++ b/src/internal/windows.cpp @@ -13,6 +13,7 @@ #ifndef _WIN32 #include "bittypes.hpp" +#include "internal/util.hpp" #include "internal/windows.hpp" #include @@ -50,10 +51,8 @@ using bstr_prefix_t = uint32_t; * - We use C allocation functions instead of "new" since we must be able to also free BSTR objects * allocated by 7-zip (which uses malloc). Never mix new/delete and malloc/free. * - We use calloc instead of malloc, so that we do not have to manually add the termination character at the end. - * - The length parameter is an uint64_t, instead of the UINT parameter used in the WinAPI interface. - * This allows avoiding unsigned integer wrap around in SysAllocStringLen. * */ -auto AllocStringBuffer( LPCSTR str, uint64_t byteLength ) -> BSTR { +auto AllocStringBuffer( LPCSTR str, uint32_t byteLength ) -> BSTR { // Maximum value that can be stored in the BSTR byteLength prefix. constexpr auto kMaxPrefixValue = std::numeric_limits< bstr_prefix_t >::max(); @@ -92,9 +91,10 @@ auto AllocStringBuffer( LPCSTR str, uint64_t byteLength ) -> BSTR { } auto SysAllocStringLen( const OLECHAR* str, UINT length ) -> BSTR { - auto byteLength = static_cast< uint64_t >( length ) * sizeof( OLECHAR ); + auto byteLength = length * sizeof( OLECHAR ); + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast) - return AllocStringBuffer( reinterpret_cast< LPCSTR >( str ), byteLength ); + return AllocStringBuffer( reinterpret_cast< LPCSTR >( str ), clamp_cast< std::uint32_t >( byteLength ) ); } auto SysAllocStringByteLen( LPCSTR str, UINT length ) -> BSTR { @@ -123,7 +123,7 @@ auto SysStringByteLen( BSTR bstrString ) -> UINT { // NOLINT(readability-non-con auto SysStringLen( BSTR bstrString ) -> UINT { // NOLINT(readability-non-const-parameter) // Same as SysStringByteLen, but we count how many OLECHARs are stored in the BSTR. - return SysStringByteLen( bstrString ) / sizeof( OLECHAR ); + return SysStringByteLen( bstrString ) / static_cast< UINT >( sizeof( OLECHAR ) ); } #endif \ No newline at end of file diff --git a/tests/src/test_util.cpp b/tests/src/test_util.cpp index c9a41e78..9cf3290f 100644 --- a/tests/src/test_util.cpp +++ b/tests/src/test_util.cpp @@ -15,6 +15,8 @@ #include using bit7z::check_overflow; +using bit7z::clamp_cast; +using bit7z::cmp_greater_equal; constexpr auto kMaxValue = ( std::numeric_limits< int64_t >::max )(); constexpr auto kMinValue = ( std::numeric_limits< int64_t >::min )(); @@ -77,4 +79,371 @@ TEST_CASE( "util: Calling check_overflow on an overflowing offset", "[util][chec REQUIRE( check_overflow( kMinValue, -1 ) ); REQUIRE( check_overflow( kMinValue, -42 ) ); REQUIRE( check_overflow( kMinValue, kMinValue ) ); +} + + +TEST_CASE( "util: Calculate the absolute position from the given position, and the offset", "[util][seek_to_offset]" ) { + uint64_t position = 0; + REQUIRE( seek_to_offset( position, 0 ) == S_OK ); + REQUIRE( position == 0 ); + + REQUIRE( seek_to_offset( position, 1 ) == S_OK ); + REQUIRE( position == 1 ); + + REQUIRE( seek_to_offset( position, -1 ) == S_OK ); + REQUIRE( position == 0 ); + + REQUIRE( seek_to_offset( position, -1 ) == HRESULT_WIN32_ERROR_NEGATIVE_SEEK ); + REQUIRE( position == 0 ); + + REQUIRE( seek_to_offset( position, 42 ) == S_OK ); + REQUIRE( position == 42 ); + + REQUIRE( seek_to_offset( position, -42 ) == S_OK ); + REQUIRE( position == 0 ); + + REQUIRE( seek_to_offset( position, -42 ) == HRESULT_WIN32_ERROR_NEGATIVE_SEEK ); + REQUIRE( position == 0 ); + + REQUIRE( seek_to_offset( position, std::numeric_limits< int64_t >::min() ) == HRESULT_WIN32_ERROR_NEGATIVE_SEEK ); + REQUIRE( position == 0 ); + + REQUIRE( seek_to_offset( position, std::numeric_limits< int64_t >::min() + 1 ) == HRESULT_WIN32_ERROR_NEGATIVE_SEEK ); + REQUIRE( position == 0 ); + + REQUIRE( seek_to_offset( position, std::numeric_limits< int64_t >::max() ) == S_OK ); + REQUIRE( position == static_cast< std::uint64_t >( std::numeric_limits< int64_t >::max() ) ); + + REQUIRE( seek_to_offset( position, std::numeric_limits< int64_t >::min() + 1 ) == S_OK ); + REQUIRE( position == 0 ); + + position = 1; + REQUIRE( seek_to_offset( position, -42 ) == HRESULT_WIN32_ERROR_NEGATIVE_SEEK ); + REQUIRE( position == 1 ); + + REQUIRE( seek_to_offset( position, std::numeric_limits< int64_t >::min() ) == HRESULT_WIN32_ERROR_NEGATIVE_SEEK ); + REQUIRE( position == 1 ); + + REQUIRE( seek_to_offset( position, std::numeric_limits< int64_t >::max() ) == S_OK ); + REQUIRE( position == ( 1u + static_cast< std::uint64_t >( std::numeric_limits< int64_t >::max() ) ) ); + + REQUIRE( seek_to_offset( position, std::numeric_limits< int64_t >::min() ) == HRESULT_WIN32_ERROR_NEGATIVE_SEEK ); + REQUIRE( position == ( 1u + static_cast< std::uint64_t >( std::numeric_limits< int64_t >::max() ) ) ); + + REQUIRE( seek_to_offset( position, std::numeric_limits< int64_t >::min() + 1 ) == S_OK ); + REQUIRE( position == 1 ); + + position = 64; + REQUIRE( seek_to_offset( position, -1 ) == S_OK ); + REQUIRE( position == 63 ); + + position = 64; + REQUIRE( seek_to_offset( position, 0 ) == S_OK ); + REQUIRE( position == 64 ); + + REQUIRE( seek_to_offset( position, 1 ) == S_OK ); + REQUIRE( position == 65 ); + + position = std::numeric_limits< uint64_t >::max() - 1u; + REQUIRE( seek_to_offset( position, 1 ) == S_OK ); + REQUIRE( position == std::numeric_limits< uint64_t >::max() ); + + REQUIRE( seek_to_offset( position, 1 ) == E_INVALIDARG ); + REQUIRE( position == std::numeric_limits< uint64_t >::max() ); + + REQUIRE( seek_to_offset( position, std::numeric_limits< int64_t >::min() + 1 ) == S_OK ); + REQUIRE( position == ( std::numeric_limits< uint64_t >::max() - static_cast< uint64_t >( std::numeric_limits< int64_t >::max() ) ) ); + + position = std::numeric_limits< uint64_t >::max(); + REQUIRE( seek_to_offset( position, std::numeric_limits< int64_t >::max() ) == E_INVALIDARG ); + REQUIRE( position == std::numeric_limits< uint64_t >::max() ); +} + +/* unsigned -> unsigned */ +TEMPLATE_TEST_CASE( "util: Clamp cast from any unsigned type to std::uint8_t", "[util][clamp_cast]", + std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t ) { + REQUIRE( clamp_cast< std::uint8_t >( TestType{ 0u } ) == std::uint8_t{ 0u } ); + REQUIRE( clamp_cast< std::uint8_t >( TestType{ 1u } ) == std::uint8_t{ 1u } ); + REQUIRE( clamp_cast< std::uint8_t >( TestType{ 42u } ) == std::uint8_t{ 42u } ); + + if ( sizeof( TestType ) > sizeof( std::uint8_t ) ) { + TestType maxValue8bit{ std::numeric_limits< std::uint8_t >::max() }; + REQUIRE( clamp_cast< std::uint8_t >( maxValue8bit ) == std::numeric_limits< std::uint8_t >::max() ); + } + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + REQUIRE( clamp_cast< std::uint8_t >( maxValue ) == std::numeric_limits< std::uint8_t >::max() ); +} + +TEMPLATE_TEST_CASE( "util: Clamp cast from any unsigned type to std::uint16_t", "[util][clamp_cast]", + std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t ) { + REQUIRE( clamp_cast< std::uint16_t >( TestType{ 0u } ) == std::uint16_t{ 0u } ); + REQUIRE( clamp_cast< std::uint16_t >( TestType{ 1u } ) == std::uint16_t{ 1u } ); + REQUIRE( clamp_cast< std::uint16_t >( TestType{ 42u } ) == std::uint16_t{ 42u } ); + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + std::uint16_t maxDestinationValue{ std::numeric_limits< std::uint16_t >::max() }; + if ( maxValue >= maxDestinationValue ) { + REQUIRE( clamp_cast< std::uint16_t >( maxValue ) == maxDestinationValue ); + REQUIRE( clamp_cast< std::uint16_t >( static_cast< TestType >( maxDestinationValue ) ) == maxDestinationValue ); + } else { // widening + REQUIRE( clamp_cast< std::uint16_t >( maxValue ) == maxValue ); + } +} + +TEMPLATE_TEST_CASE( "util: Clamp cast from any unsigned type to std::uint32_t", "[util][clamp_cast]", + std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t ) { + REQUIRE( clamp_cast< std::uint32_t >( TestType{ 0u } ) == std::uint32_t{ 0u } ); + REQUIRE( clamp_cast< std::uint32_t >( TestType{ 1u } ) == std::uint32_t{ 1u } ); + REQUIRE( clamp_cast< std::uint32_t >( TestType{ 42u } ) == std::uint32_t{ 42u } ); + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + std::uint32_t maxDestinationValue{ std::numeric_limits< std::uint32_t >::max() }; + if ( maxValue >= maxDestinationValue ) { + REQUIRE( clamp_cast< std::uint32_t >( maxValue ) == maxDestinationValue ); + REQUIRE( clamp_cast< std::uint32_t >( static_cast< TestType >( maxDestinationValue ) ) == maxDestinationValue ); + } else { // widening + REQUIRE( clamp_cast< std::uint32_t >( maxValue ) == maxValue ); + } +} + +TEMPLATE_TEST_CASE( "util: Clamp cast from std::uint64_t to std::uint64_t", "[util][clamp_cast]", + std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t ) { + REQUIRE( clamp_cast< std::uint64_t >( std::uint64_t{ 0u } ) == std::uint64_t{ 0u } ); + REQUIRE( clamp_cast< std::uint64_t >( std::uint64_t{ 1u } ) == std::uint64_t{ 1u } ); + REQUIRE( clamp_cast< std::uint64_t >( std::uint64_t{ 42u } ) == std::uint64_t{ 42u } ); + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + REQUIRE( clamp_cast< std::uint64_t >( maxValue ) == maxValue ); +} + +/* signed -> unsigned */ +TEMPLATE_TEST_CASE( "util: Clamp cast from any signed type to std::uint8_t", "[util][clamp_cast]", + std::int8_t, std::int16_t, std::int32_t, std::int64_t ) { + REQUIRE( clamp_cast< std::uint8_t >( TestType{ 0 } ) == std::uint8_t{ 0u } ); + REQUIRE( clamp_cast< std::uint8_t >( TestType{ 1 } ) == std::uint8_t{ 1u } ); + REQUIRE( clamp_cast< std::uint8_t >( TestType{ 42 } ) == std::uint8_t{ 42u } ); + + REQUIRE( clamp_cast< std::uint8_t >( TestType{ -1 } ) == std::uint8_t{ 0u } ); + REQUIRE( clamp_cast< std::uint8_t >( TestType{ -42 } ) == std::uint8_t{ 0u } ); + + TestType minValue{ std::numeric_limits< TestType >::min() }; + REQUIRE( clamp_cast< std::uint8_t >( minValue ) == 0u ); + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + std::uint8_t maxDestinationValue{ std::numeric_limits< std::uint8_t >::max() }; + if ( cmp_greater_equal( maxValue, maxDestinationValue ) ) { + REQUIRE( clamp_cast< std::uint8_t >( maxValue ) == maxDestinationValue ); + } else { + REQUIRE( clamp_cast< std::uint8_t >( maxValue ) == static_cast< std::uint8_t >( maxValue ) ); + } +} + +TEMPLATE_TEST_CASE( "util: Clamp cast from any signed type to std::uint16_t", "[util][clamp_cast]", + std::int8_t, std::int16_t, std::int32_t, std::int64_t ) { + REQUIRE( clamp_cast< std::uint16_t >( TestType{ 0 } ) == std::uint16_t{ 0u } ); + REQUIRE( clamp_cast< std::uint16_t >( TestType{ 1 } ) == std::uint16_t{ 1u } ); + REQUIRE( clamp_cast< std::uint16_t >( TestType{ 42 } ) == std::uint16_t{ 42u } ); + + REQUIRE( clamp_cast< std::uint16_t >( TestType{ -1 } ) == std::uint16_t{ 0u } ); + REQUIRE( clamp_cast< std::uint16_t >( TestType{ -42 } ) == std::uint16_t{ 0u } ); + + TestType minValue{ std::numeric_limits< TestType >::min() }; + REQUIRE( clamp_cast< std::uint16_t >( minValue ) == 0u ); + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + std::uint16_t maxDestinationValue{ std::numeric_limits< std::uint16_t >::max() }; + if ( cmp_greater_equal( maxValue, maxDestinationValue ) ) { + REQUIRE( clamp_cast< std::uint16_t >( maxValue ) == maxDestinationValue ); + } else { + REQUIRE( clamp_cast< std::uint16_t >( maxValue ) == static_cast< std::uint16_t >( maxValue ) ); + } +} + +TEMPLATE_TEST_CASE( "util: Clamp cast from any signed type to std::uint32_t", "[util][clamp_cast]", + std::int8_t, std::int16_t, std::int32_t, std::int64_t ) { + REQUIRE( clamp_cast< std::uint32_t >( TestType{ 0 } ) == std::uint32_t{ 0u } ); + REQUIRE( clamp_cast< std::uint32_t >( TestType{ 1 } ) == std::uint32_t{ 1u } ); + REQUIRE( clamp_cast< std::uint32_t >( TestType{ 42 } ) == std::uint32_t{ 42u } ); + + REQUIRE( clamp_cast< std::uint32_t >( TestType{ -1 } ) == std::uint32_t{ 0u } ); + REQUIRE( clamp_cast< std::uint32_t >( TestType{ -42 } ) == std::uint32_t{ 0u } ); + + TestType minValue{ std::numeric_limits< TestType >::min() }; + REQUIRE( clamp_cast< std::uint32_t >( minValue ) == 0u ); + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + std::uint32_t maxDestinationValue{ std::numeric_limits< std::uint32_t >::max() }; + if ( cmp_greater_equal( maxValue, maxDestinationValue ) ) { + REQUIRE( clamp_cast< std::uint32_t >( maxValue ) == maxDestinationValue ); + } else { + REQUIRE( clamp_cast< std::uint32_t >( maxValue ) == static_cast< std::uint32_t >( maxValue ) ); + } +} + +TEMPLATE_TEST_CASE( "util: Clamp cast from any signed type to std::uint64_t", "[util][clamp_cast]", + std::int8_t, std::int16_t, std::int32_t, std::int64_t ) { + REQUIRE( clamp_cast< std::uint64_t >( TestType{ 0 } ) == std::uint64_t{ 0u } ); + REQUIRE( clamp_cast< std::uint64_t >( TestType{ 1 } ) == std::uint64_t{ 1u } ); + REQUIRE( clamp_cast< std::uint64_t >( TestType{ 42 } ) == std::uint64_t{ 42u } ); + + REQUIRE( clamp_cast< std::uint64_t >( TestType{ -1 } ) == std::uint64_t{ 0u } ); + REQUIRE( clamp_cast< std::uint64_t >( TestType{ -42 } ) == std::uint64_t{ 0u } ); + + TestType minValue{ std::numeric_limits< TestType >::min() }; + REQUIRE( clamp_cast< std::uint64_t >( minValue ) == 0u ); + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + REQUIRE( clamp_cast< std::uint64_t >( maxValue ) == static_cast< std::uint64_t >( maxValue ) ); +} + +/* unsigned -> signed */ +TEMPLATE_TEST_CASE( "util: Clamp cast from any unsigned type to std::int8_t", "[util][clamp_cast]", + std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t ) { + REQUIRE( clamp_cast< std::int8_t >( TestType{ 0u } ) == std::int8_t{ 0 } ); + REQUIRE( clamp_cast< std::int8_t >( TestType{ 1u } ) == std::int8_t{ 1 } ); + REQUIRE( clamp_cast< std::int8_t >( TestType{ 42u } ) == std::int8_t{ 42 } ); + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + REQUIRE( clamp_cast< std::int8_t >( maxValue ) == std::numeric_limits< std::int8_t >::max() ); +} + +TEMPLATE_TEST_CASE( "util: Clamp cast from any unsigned type to std::int16_t", "[util][clamp_cast]", + std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t ) { + REQUIRE( clamp_cast< std::int16_t >( TestType{ 0u } ) == std::int16_t{ 0 } ); + REQUIRE( clamp_cast< std::int16_t >( TestType{ 1u } ) == std::int16_t{ 1 } ); + REQUIRE( clamp_cast< std::int16_t >( TestType{ 42u } ) == std::int16_t{ 42 } ); + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + std::int16_t maxDestinationValue{ std::numeric_limits< std::int16_t >::max() }; + if ( cmp_greater_equal( maxValue, maxDestinationValue ) ) { + REQUIRE( clamp_cast< std::int16_t >( maxValue ) == maxDestinationValue ); + } else { // widening + REQUIRE( clamp_cast< std::int16_t >( maxValue ) == maxValue ); + } +} + +TEMPLATE_TEST_CASE( "util: Clamp cast from any unsigned type to std::int32_t", "[util][clamp_cast]", + std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t ) { + REQUIRE( clamp_cast< std::int32_t >( TestType{ 0u } ) == std::int32_t{ 0 } ); + REQUIRE( clamp_cast< std::int32_t >( TestType{ 1u } ) == std::int32_t{ 1 } ); + REQUIRE( clamp_cast< std::int32_t >( TestType{ 42u } ) == std::int32_t{ 42 } ); + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + std::int32_t maxDestinationValue{ std::numeric_limits< std::int32_t >::max() }; + if ( cmp_greater_equal( maxValue, maxDestinationValue ) ) { + REQUIRE( clamp_cast< std::int32_t >( maxValue ) == maxDestinationValue ); + } else { // widening + REQUIRE( clamp_cast< std::int32_t >( maxValue ) == maxValue ); + } +} + +TEMPLATE_TEST_CASE( "util: Clamp cast from any unsigned type to std::int64_t", "[util][clamp_cast]", + std::uint8_t, std::uint16_t, std::uint32_t, std::uint64_t ) { + REQUIRE( clamp_cast< std::int64_t >( TestType{ 0u } ) == std::int64_t{ 0 } ); + REQUIRE( clamp_cast< std::int64_t >( TestType{ 1u } ) == std::int64_t{ 1 } ); + REQUIRE( clamp_cast< std::int64_t >( TestType{ 42u } ) == std::int64_t{ 42 } ); + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + std::int64_t maxDestinationValue{ std::numeric_limits< std::int64_t >::max() }; + if ( cmp_greater_equal( maxValue, maxDestinationValue ) ) { + REQUIRE( clamp_cast< std::int64_t >( maxValue ) == maxDestinationValue ); + } else { // widening + REQUIRE( clamp_cast< std::int64_t >( maxValue ) == maxValue ); + } +} + +/* signed -> signed */ +TEMPLATE_TEST_CASE( "util: Clamp cast from any signed type to std::int8_t", "[util][clamp_cast]", + std::int8_t, std::int16_t, std::int32_t, std::int64_t ) { + REQUIRE( clamp_cast< std::int8_t >( TestType{ 0 } ) == std::int8_t{ 0 } ); + REQUIRE( clamp_cast< std::int8_t >( TestType{ 1 } ) == std::int8_t{ 1 } ); + REQUIRE( clamp_cast< std::int8_t >( TestType{ 42 } ) == std::int8_t{ 42 } ); + + REQUIRE( clamp_cast< std::int8_t >( TestType{ -1 } ) == std::int8_t{ -1 } ); + REQUIRE( clamp_cast< std::int8_t >( TestType{ -42 } ) == std::int8_t{ -42 } ); + + TestType minValue{ std::numeric_limits< TestType >::min() }; + REQUIRE( clamp_cast< std::int8_t >( minValue ) == std::numeric_limits< std::int8_t >::min() ); + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + REQUIRE( clamp_cast< std::int8_t >( maxValue ) == std::numeric_limits< std::int8_t >::max() ); +} + +TEMPLATE_TEST_CASE( "util: Clamp cast from any signed type to std::int16_t", "[util][clamp_cast]", + std::int8_t, std::int16_t, std::int32_t, std::int64_t ) { + REQUIRE( clamp_cast< std::int16_t >( TestType{ 0 } ) == std::int16_t{ 0 } ); + REQUIRE( clamp_cast< std::int16_t >( TestType{ 1 } ) == std::int16_t{ 1 } ); + REQUIRE( clamp_cast< std::int16_t >( TestType{ 42 } ) == std::int16_t{ 42 } ); + + REQUIRE( clamp_cast< std::int16_t >( TestType{ -1 } ) == std::int16_t{ -1 } ); + REQUIRE( clamp_cast< std::int16_t >( TestType{ -42 } ) == std::int16_t{ -42 } ); + + TestType minValue{ std::numeric_limits< TestType >::min() }; + std::int16_t minDestinationValue{ std::numeric_limits< std::int16_t >::min() }; + if ( minValue <= minDestinationValue ) { + REQUIRE( clamp_cast< std::int16_t >( minValue ) == minDestinationValue ); + } else { + REQUIRE( clamp_cast< std::int16_t >( minValue ) == minValue ); + } + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + std::int16_t maxDestinationValue{ std::numeric_limits< std::int16_t >::max() }; + if ( maxValue >= maxDestinationValue ) { + REQUIRE( clamp_cast< std::int16_t >( maxValue ) == maxDestinationValue ); + } else { + REQUIRE( clamp_cast< std::int16_t >( maxValue ) == maxValue ); + } +} + +TEMPLATE_TEST_CASE( "util: Clamp cast from any signed type to std::int32_t", "[util][clamp_cast]", + std::int8_t, std::int16_t, std::int32_t, std::int64_t ) { + REQUIRE( clamp_cast< std::int32_t >( TestType{ 0 } ) == std::int32_t{ 0 } ); + REQUIRE( clamp_cast< std::int32_t >( TestType{ 1 } ) == std::int32_t{ 1 } ); + REQUIRE( clamp_cast< std::int32_t >( TestType{ 42 } ) == std::int32_t{ 42 } ); + + REQUIRE( clamp_cast< std::int32_t >( TestType{ -1 } ) == std::int32_t{ -1 } ); + REQUIRE( clamp_cast< std::int32_t >( TestType{ -42 } ) == std::int32_t{ -42 } ); + + TestType minValue{ std::numeric_limits< TestType >::min() }; + std::int32_t minDestinationValue{ std::numeric_limits< std::int32_t >::min() }; + if ( minValue <= minDestinationValue ) { + REQUIRE( clamp_cast< std::int32_t >( minValue ) == minDestinationValue ); + } else { + REQUIRE( clamp_cast< std::int32_t >( minValue ) == minValue ); + } + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + std::int32_t maxDestinationValue{ std::numeric_limits< std::int32_t >::max() }; + if ( maxValue >= maxDestinationValue ) { + REQUIRE( clamp_cast< std::int32_t >( maxValue ) == maxDestinationValue ); + } else { + REQUIRE( clamp_cast< std::int32_t >( maxValue ) == maxValue ); + } +} + +TEMPLATE_TEST_CASE( "util: Clamp cast from std::int64_t to std::int64_t", "[util][clamp_cast]", + std::int8_t, std::int16_t, std::int32_t, std::int64_t ) { + REQUIRE( clamp_cast< std::int64_t >( TestType{ 0 } ) == std::int64_t{ 0 } ); + REQUIRE( clamp_cast< std::int64_t >( TestType{ 1 } ) == std::int64_t{ 1 } ); + REQUIRE( clamp_cast< std::int64_t >( TestType{ 42 } ) == std::int64_t{ 42 } ); + + REQUIRE( clamp_cast< std::int64_t >( TestType{ -1 } ) == std::int64_t{ -1 } ); + REQUIRE( clamp_cast< std::int64_t >( TestType{ -42 } ) == std::int64_t{ -42 } ); + + TestType minValue{ std::numeric_limits< TestType >::max() }; + std::int64_t minDestinationValue{ std::numeric_limits< std::int64_t >::min() }; + if ( minValue <= minDestinationValue ) { + REQUIRE( clamp_cast< std::int64_t >( minValue ) == minDestinationValue ); + } else { + REQUIRE( clamp_cast< std::int64_t >( minValue ) == minValue ); + } + + TestType maxValue{ std::numeric_limits< TestType >::max() }; + std::int64_t maxDestinationValue{ std::numeric_limits< std::int64_t >::max() }; + if ( maxValue >= maxDestinationValue ) { + REQUIRE( clamp_cast< std::int64_t >( maxValue ) == maxDestinationValue ); + } else { + REQUIRE( clamp_cast< std::int64_t >( maxValue ) == maxValue ); + } } \ No newline at end of file From fc6de4eb8374b7b59204a21f7acd40f88d95207c Mon Sep 17 00:00:00 2001 From: Oz Date: Sat, 21 Oct 2023 20:55:16 +0200 Subject: [PATCH 52/62] Fix implicit conversions in fsutil --- src/internal/fsutil.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/internal/fsutil.cpp b/src/internal/fsutil.cpp index febc36da..50abd499 100644 --- a/src/internal/fsutil.cpp +++ b/src/internal/fsutil.cpp @@ -158,17 +158,17 @@ auto restore_symlink( const std::string& name ) -> bool { return !error && symlink( linkPath.c_str(), name.c_str() ) == 0; } -static const mode_t global_umask = []() noexcept { +static const mode_t global_umask = []() noexcept -> mode_t { // Getting and setting the current umask. // Note: flawfinder warns about umask with the mask set to 0; // however, we use it only to read the current umask, - // then we restore the old value, hence we can ignore the warning! + // then we restore the old value, hence we can ignore the warning. const mode_t currentUmask{ umask( 0 ) }; // flawfinder: ignore // Restoring the umask. umask( currentUmask ); // flawfinder: ignore - return static_cast( fs::perms::all ) & ( ~currentUmask ); + return static_cast< mode_t >( static_cast< int >( fs::perms::all ) & ( ~currentUmask ) ); }(); #endif @@ -268,8 +268,9 @@ auto fsutil::get_file_attributes_ex( const fs::path& filePath, if ( ( statInfo.st_mode & S_IWUSR ) == 0 ) { fileMetadata.dwFileAttributes |= FILE_ATTRIBUTE_READONLY; } - constexpr auto kMask = 0xFFFF; - fileMetadata.dwFileAttributes |= FILE_ATTRIBUTE_UNIX_EXTENSION + ( ( statInfo.st_mode & kMask ) << 16 ); + constexpr auto kMask = 0xFFFFu; + std::uint32_t unixAttributes = ( ( statInfo.st_mode & kMask ) << 16u ); + fileMetadata.dwFileAttributes |= FILE_ATTRIBUTE_UNIX_EXTENSION + unixAttributes; // File times fileMetadata.ftCreationTime = time_to_FILETIME( statInfo.st_ctime ); From d9b94d31b0fce87dd401824b06eac08373dc48d9 Mon Sep 17 00:00:00 2001 From: Oz Date: Sat, 21 Oct 2023 20:55:38 +0200 Subject: [PATCH 53/62] [Test] Fix tests of util --- tests/src/test_util.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/src/test_util.cpp b/tests/src/test_util.cpp index 9cf3290f..8707d67c 100644 --- a/tests/src/test_util.cpp +++ b/tests/src/test_util.cpp @@ -17,10 +17,12 @@ using bit7z::check_overflow; using bit7z::clamp_cast; using bit7z::cmp_greater_equal; -constexpr auto kMaxValue = ( std::numeric_limits< int64_t >::max )(); -constexpr auto kMinValue = ( std::numeric_limits< int64_t >::min )(); +using bit7z::seek_to_offset; TEST_CASE( "util: Calling check_overflow on a non-overflowing offset", "[util][check_overflow]" ) { //-V2008 + constexpr auto kMaxValue = ( std::numeric_limits< int64_t >::max )(); + constexpr auto kMinValue = ( std::numeric_limits< int64_t >::min )(); + REQUIRE_FALSE( check_overflow( kMaxValue, 0 ) ); REQUIRE_FALSE( check_overflow( kMaxValue, -1 ) ); REQUIRE_FALSE( check_overflow( kMaxValue, -42 ) ); @@ -69,6 +71,9 @@ TEST_CASE( "util: Calling check_overflow on a non-overflowing offset", "[util][c } TEST_CASE( "util: Calling check_overflow on an overflowing offset", "[util][check_overflow]" ) { + constexpr auto kMaxValue = ( std::numeric_limits< int64_t >::max )(); + constexpr auto kMinValue = ( std::numeric_limits< int64_t >::min )(); + REQUIRE( check_overflow( kMaxValue, kMaxValue ) ); REQUIRE( check_overflow( kMaxValue, 42 ) ); REQUIRE( check_overflow( kMaxValue, 1 ) ); From 12d280bb66e5b0d9dcd853b8415ba7c229d1821d Mon Sep 17 00:00:00 2001 From: Oz Date: Sat, 21 Oct 2023 21:42:55 +0200 Subject: [PATCH 54/62] Improve tests of BitException --- tests/src/test_bitexception.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/src/test_bitexception.cpp b/tests/src/test_bitexception.cpp index e2167593..7161fcc5 100644 --- a/tests/src/test_bitexception.cpp +++ b/tests/src/test_bitexception.cpp @@ -197,13 +197,14 @@ TEST_CASE( "BitException: Constructing from Win32/POSIX error codes", "[BitExcep const auto exception = BitException( "Hello World", sys_error ); #ifdef _WIN32 REQUIRE( exception.nativeCode() == HRESULT_FROM_WIN32( test.error ) ); + REQUIRE( exception.hresultCode() == exception.nativeCode() ); #else REQUIRE( exception.nativeCode() == test.error ); -#endif if ( sys_error != std::errc::io_error ) { // Multiple Win32 errors might be mapped to the POSIX IO error. REQUIRE( exception.hresultCode() == HRESULT_FROM_WIN32( test.error ) ); - REQUIRE( exception.posixCode() == sys_error.default_error_condition().value() ); } +#endif + REQUIRE( exception.posixCode() == sys_error.default_error_condition().value() ); REQUIRE( exception.what() == std::string{ "Hello World: " } + sys_error.message() ); } } From b7cb71a842e01ac20f3f8ab61860273901eb9ef6 Mon Sep 17 00:00:00 2001 From: Oz Date: Sat, 21 Oct 2023 21:45:29 +0200 Subject: [PATCH 55/62] [Test] Split tests of BitAbstractArchiveCreator into multiple test cases --- tests/src/test_bitabstractarchivecreator.cpp | 821 ++++++++++--------- 1 file changed, 427 insertions(+), 394 deletions(-) diff --git a/tests/src/test_bitabstractarchivecreator.cpp b/tests/src/test_bitabstractarchivecreator.cpp index a72dc2d8..a65e663c 100644 --- a/tests/src/test_bitabstractarchivecreator.cpp +++ b/tests/src/test_bitabstractarchivecreator.cpp @@ -31,488 +31,521 @@ struct TestOutputFormat { const BitInOutFormat& format; // NOLINT(cppcoreguidelines-avoid-const-or-ref-data-members) }; -TEMPLATE_TEST_CASE( "BitAbstractArchiveCreator: Basic API tests", - "[bitabstractarchivecreator]", - BitArchiveWriter, BitFileCompressor, BitMemCompressor, BitStreamCompressor ) { +using CreatorTypes = std::tuple< BitArchiveWriter, BitFileCompressor, BitMemCompressor, BitStreamCompressor >; + +TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator: setPassword(...) / password() / cryptHeaders()", + "[bitabstractarchivecreator]", CreatorTypes ) { const Bit7zLibrary lib{ test::sevenzip_lib_path() }; - SECTION( "setPassword(...) / password() / cryptHeaders()" ) { - TestType compressor( lib, BitFormat::SevenZip ); - REQUIRE( compressor.password().empty() ); - REQUIRE( !compressor.cryptHeaders() ); - - compressor.setPassword( BIT7Z_STRING( "ciao" ) ); - REQUIRE( compressor.password() == BIT7Z_STRING( "ciao" ) ); - REQUIRE( !compressor.cryptHeaders() ); - - compressor.setPassword( BIT7Z_STRING( "mondo" ), true ); - REQUIRE( compressor.password() == BIT7Z_STRING( "mondo" ) ); - REQUIRE( compressor.cryptHeaders() ); - - compressor.setPassword( BIT7Z_STRING( "hello" ) ); - REQUIRE( compressor.password() == BIT7Z_STRING( "hello" ) ); - REQUIRE( compressor.cryptHeaders() ); - - compressor.setPassword( BIT7Z_STRING( "" ) ); - REQUIRE( compressor.password().empty() ); - REQUIRE( !compressor.cryptHeaders() ); - - BitAbstractArchiveHandler& handler = compressor; - handler.setPassword( BIT7Z_STRING( "world!" ) ); - REQUIRE( compressor.password() == BIT7Z_STRING( "world!" ) ); - REQUIRE( !compressor.cryptHeaders() ); - - compressor.setPassword( BIT7Z_STRING( "foo" ), true ); - handler.setPassword( BIT7Z_STRING( "" ) ); - REQUIRE( compressor.password().empty() ); - REQUIRE( !compressor.cryptHeaders() ); - } + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.password().empty() ); + REQUIRE( !compressor.cryptHeaders() ); + + compressor.setPassword( BIT7Z_STRING( "ciao" ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "ciao" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + compressor.setPassword( BIT7Z_STRING( "mondo" ), true ); + REQUIRE( compressor.password() == BIT7Z_STRING( "mondo" ) ); + REQUIRE( compressor.cryptHeaders() ); + + compressor.setPassword( BIT7Z_STRING( "hello" ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "hello" ) ); + REQUIRE( compressor.cryptHeaders() ); + + compressor.setPassword( BIT7Z_STRING( "" ) ); + REQUIRE( compressor.password().empty() ); + REQUIRE( !compressor.cryptHeaders() ); + + BitAbstractArchiveHandler& handler = compressor; + handler.setPassword( BIT7Z_STRING( "world!" ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "world!" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + compressor.setPassword( BIT7Z_STRING( "foo" ), true ); + handler.setPassword( BIT7Z_STRING( "" ) ); + REQUIRE( compressor.password().empty() ); + REQUIRE( !compressor.cryptHeaders() ); +} #ifndef BIT7Z_DISABLE_ZIP_ASCII_PWD_CHECK - SECTION( "setPassword(...) with a non-ASCII string should throw when using the ZIP format" ) { - TestType compressor{ lib, BitFormat::Zip }; - REQUIRE( compressor.password().empty() ); - REQUIRE( !compressor.cryptHeaders() ); - - REQUIRE_NOTHROW( compressor.setPassword( BIT7Z_STRING( "password" ) ) ); - REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); - REQUIRE( !compressor.cryptHeaders() ); - - REQUIRE_THROWS( compressor.setPassword( BIT7Z_STRING( "contraseña" ) ) ); - REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); - REQUIRE( !compressor.cryptHeaders() ); - - // The carriage return is an ASCII character, but 7-zip doesn't support - // also non-printable ASCII characters for ZIP passwords. - REQUIRE_THROWS( compressor.setPassword( BIT7Z_STRING( "car\riage" ) ) ); - REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); - REQUIRE( !compressor.cryptHeaders() ); - - // The unit separator character is the last non-printable ASCII character. - REQUIRE_THROWS( compressor.setPassword( BIT7Z_STRING( "unit\x1Fseparator" ) ) ); - REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); - REQUIRE( !compressor.cryptHeaders() ); - - // The DEL character is not supported by bit7z for ZIP passwords. - REQUIRE_THROWS( compressor.setPassword( BIT7Z_STRING( "del\U0000007F" ) ) ); - REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); - REQUIRE( !compressor.cryptHeaders() ); - - // The space character is the first printable ASCII character supported. - REQUIRE_NOTHROW( compressor.setPassword( BIT7Z_STRING( "password with spaces" ) ) ); - REQUIRE( compressor.password() == BIT7Z_STRING( "password with spaces" ) ); - REQUIRE( !compressor.cryptHeaders() ); - - // The tilde character is the last printable ASCII character supported. - REQUIRE_NOTHROW( compressor.setPassword( BIT7Z_STRING( "password~with~tilde" ) ) ); - REQUIRE( compressor.password() == BIT7Z_STRING( "password~with~tilde" ) ); - REQUIRE( !compressor.cryptHeaders() ); - - // Resetting the password - REQUIRE_NOTHROW( compressor.setPassword( BIT7Z_STRING( "" ) ) ); - REQUIRE( compressor.password().empty() ); - REQUIRE( !compressor.cryptHeaders() ); - } +TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator:" + "setPassword(...) with a non-ASCII string should throw when using the ZIP format", + "[bitabstractarchivecreator]", CreatorTypes ) { + const Bit7zLibrary lib{ test::sevenzip_lib_path() }; + + TestType compressor{ lib, BitFormat::Zip }; + REQUIRE( compressor.password().empty() ); + REQUIRE( !compressor.cryptHeaders() ); + + REQUIRE_NOTHROW( compressor.setPassword( BIT7Z_STRING( "password" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + REQUIRE_THROWS( compressor.setPassword( BIT7Z_STRING( "contraseña" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + // The carriage return is an ASCII character, but 7-zip doesn't support + // also non-printable ASCII characters for ZIP passwords. + REQUIRE_THROWS( compressor.setPassword( BIT7Z_STRING( "car\riage" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + // The unit separator character is the last non-printable ASCII character. + REQUIRE_THROWS( compressor.setPassword( BIT7Z_STRING( "unit\x1Fseparator" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + // The DEL character is not supported by bit7z for ZIP passwords. + REQUIRE_THROWS( compressor.setPassword( BIT7Z_STRING( "del\U0000007F" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + // The space character is the first printable ASCII character supported. + REQUIRE_NOTHROW( compressor.setPassword( BIT7Z_STRING( "password with spaces" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password with spaces" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + // The tilde character is the last printable ASCII character supported. + REQUIRE_NOTHROW( compressor.setPassword( BIT7Z_STRING( "password~with~tilde" ) ) ); + REQUIRE( compressor.password() == BIT7Z_STRING( "password~with~tilde" ) ); + REQUIRE( !compressor.cryptHeaders() ); + + // Resetting the password + REQUIRE_NOTHROW( compressor.setPassword( BIT7Z_STRING( "" ) ) ); + REQUIRE( compressor.password().empty() ); + REQUIRE( !compressor.cryptHeaders() ); +} #endif - SECTION( "format() / compressionFormat()" ) { - const auto testFormat = GENERATE( as< TestOutputFormat >(), - TestOutputFormat{ "ZIP", BitFormat::Zip }, - TestOutputFormat{ "BZIP2", BitFormat::BZip2 }, - TestOutputFormat{ "7Z", BitFormat::SevenZip }, - TestOutputFormat{ "XZ", BitFormat::Xz }, - TestOutputFormat{ "WIM", BitFormat::Wim }, - TestOutputFormat{ "TAR", BitFormat::Tar }, - TestOutputFormat{ "GZIP", BitFormat::GZip } ); - DYNAMIC_SECTION( "Format: " << testFormat.name ) { - const TestType compressor{ lib, testFormat.format }; - REQUIRE( compressor.compressionFormat() == testFormat.format ); - REQUIRE( compressor.format() == testFormat.format ); - } +TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator: format() / compressionFormat()", + "[bitabstractarchivecreator]", CreatorTypes ) { + const Bit7zLibrary lib{ test::sevenzip_lib_path() }; + const auto testFormat = GENERATE( as< TestOutputFormat >(), + TestOutputFormat{ "ZIP", BitFormat::Zip }, + TestOutputFormat{ "BZIP2", BitFormat::BZip2 }, + TestOutputFormat{ "7Z", BitFormat::SevenZip }, + TestOutputFormat{ "XZ", BitFormat::Xz }, + TestOutputFormat{ "WIM", BitFormat::Wim }, + TestOutputFormat{ "TAR", BitFormat::Tar }, + TestOutputFormat{ "GZIP", BitFormat::GZip } ); + DYNAMIC_SECTION( "Format: " << testFormat.name ) { + const TestType compressor{ lib, testFormat.format }; + REQUIRE( compressor.compressionFormat() == testFormat.format ); + REQUIRE( compressor.format() == testFormat.format ); } +} + +TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator: setCompressionLevel(...) / compressionLevel()", + "[bitabstractarchivecreator]", CreatorTypes ) { + const Bit7zLibrary lib{ test::sevenzip_lib_path() }; - SECTION( "setCompressionLevel(...) / compressionLevel()" ) { + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Normal ); + compressor.setCompressionLevel( BitCompressionLevel::None ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::None ); + compressor.setCompressionLevel( BitCompressionLevel::Fastest ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Fastest ); + compressor.setCompressionLevel( BitCompressionLevel::Fast ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Fast ); + compressor.setCompressionLevel( BitCompressionLevel::Normal ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Normal ); + compressor.setCompressionLevel( BitCompressionLevel::Max ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Max ); + compressor.setCompressionLevel( BitCompressionLevel::Ultra ); + REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Ultra ); +} + +TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator: setCompressionMethod(...) / compressionMethod()", + "[bitabstractarchivecreator]", CreatorTypes ) { + const Bit7zLibrary lib{ test::sevenzip_lib_path() }; + + SECTION( "7Z Compression Methods" ) { TestType compressor( lib, BitFormat::SevenZip ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Normal ); - compressor.setCompressionLevel( BitCompressionLevel::None ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::None ); - compressor.setCompressionLevel( BitCompressionLevel::Fastest ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Fastest ); - compressor.setCompressionLevel( BitCompressionLevel::Fast ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Fast ); - compressor.setCompressionLevel( BitCompressionLevel::Normal ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Normal ); - compressor.setCompressionLevel( BitCompressionLevel::Max ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Max ); - compressor.setCompressionLevel( BitCompressionLevel::Ultra ); - REQUIRE( compressor.compressionLevel() == BitCompressionLevel::Ultra ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); + compressor.setCompressionMethod( BitCompressionMethod::Copy ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); + compressor.setCompressionMethod( BitCompressionMethod::Lzma ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma ); + compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); + compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Ppmd ); + compressor.setCompressionMethod( BitCompressionMethod::BZip2 ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); } - SECTION( "setCompressionMethod(...) / compressionMethod()" ) { - SECTION( "7Z Compression Methods" ) { - TestType compressor( lib, BitFormat::SevenZip ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); - compressor.setCompressionMethod( BitCompressionMethod::Copy ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); - compressor.setCompressionMethod( BitCompressionMethod::Lzma ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma ); - compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); - compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Ppmd ); - compressor.setCompressionMethod( BitCompressionMethod::BZip2 ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); - } - - SECTION( "ZIP Compression Methods" ) { - TestType compressor( lib, BitFormat::Zip ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); - compressor.setCompressionMethod( BitCompressionMethod::Copy ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); - compressor.setCompressionMethod( BitCompressionMethod::Deflate ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); - compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate64 ); - compressor.setCompressionMethod( BitCompressionMethod::BZip2 ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); - compressor.setCompressionMethod( BitCompressionMethod::Lzma ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma ); - compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Ppmd ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); - } - - SECTION( "BZIP2 Compression Methods" ) { - TestType compressor( lib, BitFormat::BZip2 ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); - REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); - } - - SECTION( "GZIP Compression Methods" ) { - TestType compressor( lib, BitFormat::GZip ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); - REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); - } - - SECTION( "TAR Compression Methods" ) { - TestType compressor( lib, BitFormat::Tar ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); - REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); - } - - SECTION( "WIM Compression Methods" ) { - TestType compressor( lib, BitFormat::Wim ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); - REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); - } - - SECTION( "XZ Compression Methods" ) { - TestType compressor( lib, BitFormat::Xz ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); - REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); - REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); - REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); - } + SECTION( "ZIP Compression Methods" ) { + TestType compressor( lib, BitFormat::Zip ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); + compressor.setCompressionMethod( BitCompressionMethod::Copy ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); + compressor.setCompressionMethod( BitCompressionMethod::Deflate ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); + compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate64 ); + compressor.setCompressionMethod( BitCompressionMethod::BZip2 ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); + compressor.setCompressionMethod( BitCompressionMethod::Lzma ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma ); + compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Ppmd ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); } - SECTION( "setDictionarySize(...) / dictionarySize()" ) { + SECTION( "BZIP2 Compression Methods" ) { + TestType compressor( lib, BitFormat::BZip2 ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::BZip2 ); + } - SECTION( "SevenZip format + Lzma/Lzma2 compression methods" ) { - constexpr auto kMaxLzmaDictionarySize = 1536 * ( 1LL << 20 ); // less than 1536 MiB + SECTION( "GZIP Compression Methods" ) { + TestType compressor( lib, BitFormat::GZip ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Deflate ); + } - TestType compressor( lib, BitFormat::SevenZip ); - REQUIRE( compressor.dictionarySize() == 0 ); + SECTION( "TAR Compression Methods" ) { + TestType compressor( lib, BitFormat::Tar ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); + } - auto testMethod = GENERATE( BitCompressionMethod::Lzma, BitCompressionMethod::Lzma2 ); - compressor.setCompressionMethod( testMethod ); + SECTION( "WIM Compression Methods" ) { + TestType compressor( lib, BitFormat::Wim ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Copy ); + } - uint32_t dictionarySize = 1024 * 1024 * 1024; - compressor.setDictionarySize( dictionarySize ); - REQUIRE( compressor.dictionarySize() == dictionarySize ); + SECTION( "XZ Compression Methods" ) { + TestType compressor( lib, BitFormat::Xz ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Lzma ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Ppmd ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate ) ); + REQUIRE_THROWS( compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ) ); + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Lzma2 ) ); + REQUIRE( compressor.compressionMethod() == BitCompressionMethod::Lzma2 ); + } +} - compressor.setDictionarySize( kMaxLzmaDictionarySize ); - REQUIRE( compressor.dictionarySize() == kMaxLzmaDictionarySize ); +TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator: setDictionarySize(...) / dictionarySize()", + "[bitabstractarchivecreator]", CreatorTypes ) { + const Bit7zLibrary lib{ test::sevenzip_lib_path() }; - dictionarySize = std::numeric_limits< uint32_t >::max(); - REQUIRE_THROWS( compressor.setDictionarySize( std::numeric_limits< uint32_t >::max() ) ); - REQUIRE( compressor.dictionarySize() == kMaxLzmaDictionarySize ); - } + SECTION( "SevenZip format + Lzma/Lzma2 compression methods" ) { + constexpr auto kMaxLzmaDictionarySize = 1536 * ( 1LL << 20 ); // less than 1536 MiB - SECTION( "Zip format + Ppmd compression methods" ) { - constexpr uint32_t kMaxPpmdDictionarySize = ( 1ULL << 30 ); // less than 1 GiB, i.e., 2^30 bytes + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.dictionarySize() == 0 ); - TestType compressor( lib, BitFormat::Zip ); - REQUIRE( compressor.dictionarySize() == 0 ); - compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); + auto testMethod = GENERATE( BitCompressionMethod::Lzma, BitCompressionMethod::Lzma2 ); + compressor.setCompressionMethod( testMethod ); - uint32_t dictionarySize = 1024 * 1024 * 1024; - compressor.setDictionarySize( dictionarySize ); - REQUIRE( compressor.dictionarySize() == dictionarySize ); + uint32_t dictionarySize = 1024 * 1024 * 1024; + compressor.setDictionarySize( dictionarySize ); + REQUIRE( compressor.dictionarySize() == dictionarySize ); - compressor.setDictionarySize( kMaxPpmdDictionarySize ); - REQUIRE( compressor.dictionarySize() == kMaxPpmdDictionarySize ); + compressor.setDictionarySize( kMaxLzmaDictionarySize ); + REQUIRE( compressor.dictionarySize() == kMaxLzmaDictionarySize ); - dictionarySize = std::numeric_limits< uint32_t >::max(); - REQUIRE_THROWS( compressor.setDictionarySize( std::numeric_limits< uint32_t >::max() ) ); - REQUIRE( compressor.dictionarySize() == kMaxPpmdDictionarySize ); + dictionarySize = std::numeric_limits< uint32_t >::max(); + REQUIRE_THROWS( compressor.setDictionarySize( std::numeric_limits< uint32_t >::max() ) ); + REQUIRE( compressor.dictionarySize() == kMaxLzmaDictionarySize ); + } - auto testMethod = GENERATE( BitCompressionMethod::Copy, - BitCompressionMethod::Deflate, - BitCompressionMethod::Deflate64 ); - compressor.setCompressionMethod( testMethod ); - REQUIRE_NOTHROW( compressor.setDictionarySize( 1024 * 1024 ) ); - REQUIRE( compressor.dictionarySize() == 0 ); - } + SECTION( "Zip format + Ppmd compression methods" ) { + constexpr uint32_t kMaxPpmdDictionarySize = ( 1ULL << 30 ); // less than 1 GiB, i.e., 2^30 bytes - SECTION( "BZip2 format and compression methods" ) { - constexpr auto kMaxBzip2DictionarySize = 900 * ( 1LL << 10 ); // less than 900 KiB + TestType compressor( lib, BitFormat::Zip ); + REQUIRE( compressor.dictionarySize() == 0 ); + compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); - TestType compressor( lib, BitFormat::BZip2 ); - REQUIRE( compressor.dictionarySize() == 0 ); + uint32_t dictionarySize = 1024 * 1024 * 1024; + compressor.setDictionarySize( dictionarySize ); + REQUIRE( compressor.dictionarySize() == dictionarySize ); - uint32_t dictionarySize = 1024; - compressor.setDictionarySize( dictionarySize ); - REQUIRE( compressor.dictionarySize() == dictionarySize ); + compressor.setDictionarySize( kMaxPpmdDictionarySize ); + REQUIRE( compressor.dictionarySize() == kMaxPpmdDictionarySize ); - compressor.setDictionarySize( kMaxBzip2DictionarySize ); - REQUIRE( compressor.dictionarySize() == kMaxBzip2DictionarySize ); + dictionarySize = std::numeric_limits< uint32_t >::max(); + REQUIRE_THROWS( compressor.setDictionarySize( std::numeric_limits< uint32_t >::max() ) ); + REQUIRE( compressor.dictionarySize() == kMaxPpmdDictionarySize ); - dictionarySize = std::numeric_limits< uint32_t >::max(); - REQUIRE_THROWS( compressor.setDictionarySize( std::numeric_limits< uint32_t >::max() ) ); - REQUIRE( compressor.dictionarySize() == kMaxBzip2DictionarySize ); - } + auto testMethod = GENERATE( BitCompressionMethod::Copy, + BitCompressionMethod::Deflate, + BitCompressionMethod::Deflate64 ); + compressor.setCompressionMethod( testMethod ); + REQUIRE_NOTHROW( compressor.setDictionarySize( 1024 * 1024 ) ); + REQUIRE( compressor.dictionarySize() == 0 ); } - SECTION( "setSolidMode(...) / solidMode()" ) { - TestType compressor( lib, BitFormat::SevenZip ); - REQUIRE( !compressor.solidMode() ); + SECTION( "BZip2 format and compression methods" ) { + constexpr auto kMaxBzip2DictionarySize = 900 * ( 1LL << 10 ); // less than 900 KiB - compressor.setSolidMode( true ); - REQUIRE( compressor.solidMode() ); + TestType compressor( lib, BitFormat::BZip2 ); + REQUIRE( compressor.dictionarySize() == 0 ); - compressor.setSolidMode( false ); - REQUIRE( !compressor.solidMode() ); + uint32_t dictionarySize = 1024; + compressor.setDictionarySize( dictionarySize ); + REQUIRE( compressor.dictionarySize() == dictionarySize ); + + compressor.setDictionarySize( kMaxBzip2DictionarySize ); + REQUIRE( compressor.dictionarySize() == kMaxBzip2DictionarySize ); + + dictionarySize = std::numeric_limits< uint32_t >::max(); + REQUIRE_THROWS( compressor.setDictionarySize( std::numeric_limits< uint32_t >::max() ) ); + REQUIRE( compressor.dictionarySize() == kMaxBzip2DictionarySize ); } +} - SECTION( "setStoreSymbolicLinks(...) / storeSymbolicLinks()" ) { - TestType compressor( lib, BitFormat::SevenZip ); - REQUIRE( compressor.storeSymbolicLinks() == false ); +TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator: setSolidMode(...) / solidMode()", + "[bitabstractarchivecreator]", CreatorTypes ) { + const Bit7zLibrary lib{ test::sevenzip_lib_path() }; - compressor.setStoreSymbolicLinks( true ); - REQUIRE( compressor.storeSymbolicLinks() == true ); - REQUIRE( compressor.solidMode() == true ); + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( !compressor.solidMode() ); - compressor.setStoreSymbolicLinks( false ); - REQUIRE( compressor.storeSymbolicLinks() == false ); - REQUIRE( compressor.solidMode() == false ); - } + compressor.setSolidMode( true ); + REQUIRE( compressor.solidMode() ); - SECTION( "setThreadCount(...) / threadCount()" ) { - TestType compressor( lib, BitFormat::SevenZip ); - REQUIRE( compressor.threadsCount() == 0u ); - compressor.setThreadsCount( 8u ); - REQUIRE( compressor.threadsCount() == 8u ); - } + compressor.setSolidMode( false ); + REQUIRE( !compressor.solidMode() ); +} - SECTION( "setUpdateMode(...) / updateMode()" ) { - TestType compressor( lib, BitFormat::SevenZip ); - REQUIRE( compressor.updateMode() == UpdateMode::None ); +TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator: setStoreSymbolicLinks(...) / storeSymbolicLinks()", + "[bitabstractarchivecreator]", CreatorTypes ) { + const Bit7zLibrary lib{ test::sevenzip_lib_path() }; - compressor.setUpdateMode( true ); - REQUIRE( compressor.updateMode() == UpdateMode::Append ); + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.storeSymbolicLinks() == false ); - compressor.setUpdateMode( false ); - REQUIRE( compressor.updateMode() == UpdateMode::None ); + compressor.setStoreSymbolicLinks( true ); + REQUIRE( compressor.storeSymbolicLinks() == true ); + REQUIRE( compressor.solidMode() == true ); - compressor.setUpdateMode( UpdateMode::Append ); - REQUIRE( compressor.updateMode() == UpdateMode::Append ); + compressor.setStoreSymbolicLinks( false ); + REQUIRE( compressor.storeSymbolicLinks() == false ); + REQUIRE( compressor.solidMode() == false ); - compressor.setUpdateMode( UpdateMode::Update ); - REQUIRE( compressor.updateMode() == UpdateMode::Update ); +} - compressor.setUpdateMode( UpdateMode::None ); - REQUIRE( compressor.updateMode() == UpdateMode::None ); - } +TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator: setThreadCount(...) / threadCount()", + "[bitabstractarchivecreator]", CreatorTypes ) { + const Bit7zLibrary lib{ test::sevenzip_lib_path() }; - SECTION( "setVolumeSize(...) / volumeSize()" ) { - TestType compressor( lib, BitFormat::SevenZip ); - REQUIRE( compressor.volumeSize() == 0u ); - compressor.setVolumeSize( 1024u ); - REQUIRE( compressor.volumeSize() == 1024u ); - } + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.threadsCount() == 0u ); + compressor.setThreadsCount( 8u ); + REQUIRE( compressor.threadsCount() == 8u ); +} - SECTION( "setWordSize(...) / wordSize()" ) { - constexpr auto kMinPpmdWordSize = 2u; +TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator: setUpdateMode(...) / updateMode()", + "[bitabstractarchivecreator]", CreatorTypes ) { + const Bit7zLibrary lib{ test::sevenzip_lib_path() }; - SECTION( "SevenZip format + Lzma/Lzma2 compression methods" ) { - constexpr auto kMinLzmaWordSize = 5u; - constexpr auto kMaxLzmaWordSize = 273u; + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.updateMode() == UpdateMode::None ); - TestType compressor( lib, BitFormat::SevenZip ); - REQUIRE_THROWS( compressor.setWordSize( 4u ) ); - REQUIRE( compressor.wordSize() == 0 ); + compressor.setUpdateMode( true ); + REQUIRE( compressor.updateMode() == UpdateMode::Append ); - REQUIRE_NOTHROW( compressor.setWordSize( kMinLzmaWordSize ) ); - REQUIRE( compressor.wordSize() == kMinLzmaWordSize ); + compressor.setUpdateMode( false ); + REQUIRE( compressor.updateMode() == UpdateMode::None ); - REQUIRE_NOTHROW( compressor.setWordSize( 128u ) ); - REQUIRE( compressor.wordSize() == 128u ); + compressor.setUpdateMode( UpdateMode::Append ); + REQUIRE( compressor.updateMode() == UpdateMode::Append ); - REQUIRE_NOTHROW( compressor.setWordSize( kMaxLzmaWordSize ) ); - REQUIRE( compressor.wordSize() == kMaxLzmaWordSize ); + compressor.setUpdateMode( UpdateMode::Update ); + REQUIRE( compressor.updateMode() == UpdateMode::Update ); - REQUIRE_THROWS( compressor.setWordSize( kMaxLzmaWordSize + 1 ) ); - REQUIRE( compressor.wordSize() == kMaxLzmaWordSize ); + compressor.setUpdateMode( UpdateMode::None ); + REQUIRE( compressor.updateMode() == UpdateMode::None ); - REQUIRE_THROWS( compressor.setWordSize( 512u ) ); - REQUIRE( compressor.wordSize() == kMaxLzmaWordSize ); +} - REQUIRE_NOTHROW( compressor.setWordSize( 0 ) ); - REQUIRE( compressor.wordSize() == 0 ); +TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator: setVolumeSize(...) / volumeSize()", + "[bitabstractarchivecreator]", CreatorTypes ) { + const Bit7zLibrary lib{ test::sevenzip_lib_path() }; - REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); - REQUIRE_NOTHROW( compressor.setWordSize( 64u ) ); - REQUIRE( compressor.wordSize() == 0 ); + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE( compressor.volumeSize() == 0u ); + compressor.setVolumeSize( 1024u ); + REQUIRE( compressor.volumeSize() == 1024u ); +} - REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); - REQUIRE_NOTHROW( compressor.setWordSize( 64u ) ); - REQUIRE( compressor.wordSize() == 0 ); - } +TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator: setWordSize(...) / wordSize()", + "[bitabstractarchivecreator]", CreatorTypes ) { + const Bit7zLibrary lib{ test::sevenzip_lib_path() }; - SECTION( "SevenZip format + Ppmd compression method" ) { - constexpr auto kMax7zPpmdWordSize = 32u; + constexpr auto kMinPpmdWordSize = 2u; - TestType compressor( lib, BitFormat::SevenZip ); - compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); + SECTION( "SevenZip format + Lzma/Lzma2 compression methods" ) { + constexpr auto kMinLzmaWordSize = 5u; + constexpr auto kMaxLzmaWordSize = 273u; - REQUIRE_THROWS( compressor.setWordSize( 1u ) ); - REQUIRE( compressor.wordSize() == 0 ); + TestType compressor( lib, BitFormat::SevenZip ); + REQUIRE_THROWS( compressor.setWordSize( 4u ) ); + REQUIRE( compressor.wordSize() == 0 ); - REQUIRE_NOTHROW( compressor.setWordSize( kMinPpmdWordSize ) ); - REQUIRE( compressor.wordSize() == kMinPpmdWordSize ); + REQUIRE_NOTHROW( compressor.setWordSize( kMinLzmaWordSize ) ); + REQUIRE( compressor.wordSize() == kMinLzmaWordSize ); - REQUIRE_NOTHROW( compressor.setWordSize( 16u ) ); - REQUIRE( compressor.wordSize() == 16u ); + REQUIRE_NOTHROW( compressor.setWordSize( 128u ) ); + REQUIRE( compressor.wordSize() == 128u ); - REQUIRE_NOTHROW( compressor.setWordSize( kMax7zPpmdWordSize ) ); - REQUIRE( compressor.wordSize() == kMax7zPpmdWordSize ); + REQUIRE_NOTHROW( compressor.setWordSize( kMaxLzmaWordSize ) ); + REQUIRE( compressor.wordSize() == kMaxLzmaWordSize ); - REQUIRE_THROWS( compressor.setWordSize( kMax7zPpmdWordSize + 1 ) ); - REQUIRE( compressor.wordSize() == kMax7zPpmdWordSize ); + REQUIRE_THROWS( compressor.setWordSize( kMaxLzmaWordSize + 1 ) ); + REQUIRE( compressor.wordSize() == kMaxLzmaWordSize ); - REQUIRE_THROWS( compressor.setWordSize( 64u ) ); - REQUIRE( compressor.wordSize() == kMax7zPpmdWordSize ); + REQUIRE_THROWS( compressor.setWordSize( 512u ) ); + REQUIRE( compressor.wordSize() == kMaxLzmaWordSize ); - REQUIRE_NOTHROW( compressor.setWordSize( 0 ) ); - REQUIRE( compressor.wordSize() == 0 ); - } + REQUIRE_NOTHROW( compressor.setWordSize( 0 ) ); + REQUIRE( compressor.wordSize() == 0 ); - SECTION( "Zip format + Ppmd compression method") { - constexpr auto kMaxZipPpmdWordSize = 16u; + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::Copy ) ); + REQUIRE_NOTHROW( compressor.setWordSize( 64u ) ); + REQUIRE( compressor.wordSize() == 0 ); - TestType compressor( lib, BitFormat::Zip ); - compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); + REQUIRE_NOTHROW( compressor.setCompressionMethod( BitCompressionMethod::BZip2 ) ); + REQUIRE_NOTHROW( compressor.setWordSize( 64u ) ); + REQUIRE( compressor.wordSize() == 0 ); + } - REQUIRE_THROWS( compressor.setWordSize( 1u ) ); - REQUIRE( compressor.wordSize() == 0 ); + SECTION( "SevenZip format + Ppmd compression method" ) { + constexpr auto kMax7zPpmdWordSize = 32u; - REQUIRE_NOTHROW( compressor.setWordSize( kMinPpmdWordSize ) ); - REQUIRE( compressor.wordSize() == kMinPpmdWordSize ); + TestType compressor( lib, BitFormat::SevenZip ); + compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); + + REQUIRE_THROWS( compressor.setWordSize( 1u ) ); + REQUIRE( compressor.wordSize() == 0 ); + + REQUIRE_NOTHROW( compressor.setWordSize( kMinPpmdWordSize ) ); + REQUIRE( compressor.wordSize() == kMinPpmdWordSize ); + + REQUIRE_NOTHROW( compressor.setWordSize( 16u ) ); + REQUIRE( compressor.wordSize() == 16u ); + + REQUIRE_NOTHROW( compressor.setWordSize( kMax7zPpmdWordSize ) ); + REQUIRE( compressor.wordSize() == kMax7zPpmdWordSize ); + + REQUIRE_THROWS( compressor.setWordSize( kMax7zPpmdWordSize + 1 ) ); + REQUIRE( compressor.wordSize() == kMax7zPpmdWordSize ); + + REQUIRE_THROWS( compressor.setWordSize( 64u ) ); + REQUIRE( compressor.wordSize() == kMax7zPpmdWordSize ); - REQUIRE_NOTHROW( compressor.setWordSize( 16u ) ); - REQUIRE( compressor.wordSize() == 16u ); + REQUIRE_NOTHROW( compressor.setWordSize( 0 ) ); + REQUIRE( compressor.wordSize() == 0 ); + } + + SECTION( "Zip format + Ppmd compression method") { + constexpr auto kMaxZipPpmdWordSize = 16u; + + TestType compressor( lib, BitFormat::Zip ); + compressor.setCompressionMethod( BitCompressionMethod::Ppmd ); + + REQUIRE_THROWS( compressor.setWordSize( 1u ) ); + REQUIRE( compressor.wordSize() == 0 ); - REQUIRE_NOTHROW( compressor.setWordSize( kMaxZipPpmdWordSize ) ); - REQUIRE( compressor.wordSize() == kMaxZipPpmdWordSize ); + REQUIRE_NOTHROW( compressor.setWordSize( kMinPpmdWordSize ) ); + REQUIRE( compressor.wordSize() == kMinPpmdWordSize ); - REQUIRE_THROWS( compressor.setWordSize( kMaxZipPpmdWordSize + 1 ) ); - REQUIRE( compressor.wordSize() == kMaxZipPpmdWordSize ); + REQUIRE_NOTHROW( compressor.setWordSize( 16u ) ); + REQUIRE( compressor.wordSize() == 16u ); - REQUIRE_THROWS( compressor.setWordSize( 32u ) ); - REQUIRE( compressor.wordSize() == kMaxZipPpmdWordSize ); + REQUIRE_NOTHROW( compressor.setWordSize( kMaxZipPpmdWordSize ) ); + REQUIRE( compressor.wordSize() == kMaxZipPpmdWordSize ); - REQUIRE_NOTHROW( compressor.setWordSize( 0 ) ); - REQUIRE( compressor.wordSize() == 0 ); - } + REQUIRE_THROWS( compressor.setWordSize( kMaxZipPpmdWordSize + 1 ) ); + REQUIRE( compressor.wordSize() == kMaxZipPpmdWordSize ); + + REQUIRE_THROWS( compressor.setWordSize( 32u ) ); + REQUIRE( compressor.wordSize() == kMaxZipPpmdWordSize ); + + REQUIRE_NOTHROW( compressor.setWordSize( 0 ) ); + REQUIRE( compressor.wordSize() == 0 ); + } - SECTION( "Zip format + Deflate/Deflate64 compression method") { - constexpr auto kMinDeflateWordSize = 3u; - constexpr auto kMaxDeflateWordSize = 258u; - constexpr auto kMaxDeflate64WordSize = kMaxDeflateWordSize - 1; + SECTION( "Zip format + Deflate/Deflate64 compression method") { + constexpr auto kMinDeflateWordSize = 3u; + constexpr auto kMaxDeflateWordSize = 258u; + constexpr auto kMaxDeflate64WordSize = kMaxDeflateWordSize - 1; - TestType compressor( lib, BitFormat::Zip ); - compressor.setCompressionMethod( BitCompressionMethod::Deflate ); + TestType compressor( lib, BitFormat::Zip ); + compressor.setCompressionMethod( BitCompressionMethod::Deflate ); - REQUIRE_THROWS( compressor.setWordSize( 2u ) ); - REQUIRE( compressor.wordSize() == 0 ); + REQUIRE_THROWS( compressor.setWordSize( 2u ) ); + REQUIRE( compressor.wordSize() == 0 ); - REQUIRE_NOTHROW( compressor.setWordSize( kMinDeflateWordSize ) ); - REQUIRE( compressor.wordSize() == kMinDeflateWordSize ); + REQUIRE_NOTHROW( compressor.setWordSize( kMinDeflateWordSize ) ); + REQUIRE( compressor.wordSize() == kMinDeflateWordSize ); - REQUIRE_NOTHROW( compressor.setWordSize( 64u ) ); - REQUIRE( compressor.wordSize() == 64u ); + REQUIRE_NOTHROW( compressor.setWordSize( 64u ) ); + REQUIRE( compressor.wordSize() == 64u ); - REQUIRE_NOTHROW( compressor.setWordSize( kMaxDeflateWordSize ) ); - REQUIRE( compressor.wordSize() == kMaxDeflateWordSize ); + REQUIRE_NOTHROW( compressor.setWordSize( kMaxDeflateWordSize ) ); + REQUIRE( compressor.wordSize() == kMaxDeflateWordSize ); - REQUIRE_THROWS( compressor.setWordSize( kMaxDeflateWordSize + 1 ) ); - REQUIRE( compressor.wordSize() == kMaxDeflateWordSize ); + REQUIRE_THROWS( compressor.setWordSize( kMaxDeflateWordSize + 1 ) ); + REQUIRE( compressor.wordSize() == kMaxDeflateWordSize ); - compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ); - REQUIRE( compressor.wordSize() == 0 ); + compressor.setCompressionMethod( BitCompressionMethod::Deflate64 ); + REQUIRE( compressor.wordSize() == 0 ); - REQUIRE_THROWS( compressor.setWordSize( 1u ) ); - REQUIRE( compressor.wordSize() == 0 ); + REQUIRE_THROWS( compressor.setWordSize( 1u ) ); + REQUIRE( compressor.wordSize() == 0 ); - REQUIRE_NOTHROW( compressor.setWordSize( kMinDeflateWordSize ) ); - REQUIRE( compressor.wordSize() == kMinDeflateWordSize ); + REQUIRE_NOTHROW( compressor.setWordSize( kMinDeflateWordSize ) ); + REQUIRE( compressor.wordSize() == kMinDeflateWordSize ); - REQUIRE_NOTHROW( compressor.setWordSize( 64u ) ); - REQUIRE( compressor.wordSize() == 64u ); + REQUIRE_NOTHROW( compressor.setWordSize( 64u ) ); + REQUIRE( compressor.wordSize() == 64u ); - REQUIRE_NOTHROW( compressor.setWordSize( kMaxDeflate64WordSize ) ); - REQUIRE( compressor.wordSize() == kMaxDeflate64WordSize ); + REQUIRE_NOTHROW( compressor.setWordSize( kMaxDeflate64WordSize ) ); + REQUIRE( compressor.wordSize() == kMaxDeflate64WordSize ); - REQUIRE_THROWS( compressor.setWordSize( kMaxDeflate64WordSize + 1 ) ); - REQUIRE( compressor.wordSize() == kMaxDeflate64WordSize ); + REQUIRE_THROWS( compressor.setWordSize( kMaxDeflate64WordSize + 1 ) ); + REQUIRE( compressor.wordSize() == kMaxDeflate64WordSize ); - REQUIRE_NOTHROW( compressor.setWordSize( 0 ) ); - REQUIRE( compressor.wordSize() == 0 ); - } + REQUIRE_NOTHROW( compressor.setWordSize( 0 ) ); + REQUIRE( compressor.wordSize() == 0 ); } } \ No newline at end of file From dbed9c86b1085384464fa7c0279491321bf706e4 Mon Sep 17 00:00:00 2001 From: Oz Date: Sat, 21 Oct 2023 21:56:38 +0200 Subject: [PATCH 56/62] Improve tests of BitAbstractArchiveCreator --- tests/src/test_bitabstractarchivecreator.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/tests/src/test_bitabstractarchivecreator.cpp b/tests/src/test_bitabstractarchivecreator.cpp index a65e663c..7819bd0a 100644 --- a/tests/src/test_bitabstractarchivecreator.cpp +++ b/tests/src/test_bitabstractarchivecreator.cpp @@ -351,16 +351,15 @@ TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator: setStoreSymbolicLinks(...) const Bit7zLibrary lib{ test::sevenzip_lib_path() }; TestType compressor( lib, BitFormat::SevenZip ); - REQUIRE( compressor.storeSymbolicLinks() == false ); + REQUIRE_FALSE( compressor.storeSymbolicLinks() ); compressor.setStoreSymbolicLinks( true ); - REQUIRE( compressor.storeSymbolicLinks() == true ); - REQUIRE( compressor.solidMode() == true ); + REQUIRE( compressor.storeSymbolicLinks() ); + REQUIRE( compressor.solidMode() ); compressor.setStoreSymbolicLinks( false ); - REQUIRE( compressor.storeSymbolicLinks() == false ); - REQUIRE( compressor.solidMode() == false ); - + REQUIRE_FALSE( compressor.storeSymbolicLinks() ); + REQUIRE_FALSE( compressor.solidMode() ); } TEMPLATE_LIST_TEST_CASE( "BitAbstractArchiveCreator: setThreadCount(...) / threadCount()", From e173302f6498c0e174af1de360b80d33361b099a Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 22 Oct 2023 10:37:17 +0200 Subject: [PATCH 57/62] [Test] Fix warnings from PVS-Studio --- src/internal/cbufferoutstream.cpp | 2 +- src/internal/cfixedbufferoutstream.cpp | 9 +++++---- src/internal/util.hpp | 2 ++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/internal/cbufferoutstream.cpp b/src/internal/cbufferoutstream.cpp index 3b9e5ee4..173f5f19 100644 --- a/src/internal/cbufferoutstream.cpp +++ b/src/internal/cbufferoutstream.cpp @@ -61,7 +61,7 @@ STDMETHODIMP CBufferOutStream::Write( const void* data, UInt32 size, UInt32* pro } auto oldPos = ( mCurrentPosition - mBuffer.begin() ); - const size_t newPos = static_cast< size_t >( oldPos ) + size; + const size_t newPos = static_cast< size_t >( oldPos ) + static_cast< size_t >( size ); if ( newPos > mBuffer.size() ) { try { mBuffer.resize( newPos ); diff --git a/src/internal/cfixedbufferoutstream.cpp b/src/internal/cfixedbufferoutstream.cpp index 6c310011..7c8bc639 100644 --- a/src/internal/cfixedbufferoutstream.cpp +++ b/src/internal/cfixedbufferoutstream.cpp @@ -77,12 +77,12 @@ STDMETHODIMP CFixedBufferOutStream::Write( const void* data, UInt32 size, UInt32 return E_FAIL; } - uint32_t writeSize = size; + auto writeSize = static_cast< size_t >( size ); size_t remainingSize = mBufferSize - mCurrentPosition; // The Seek method ensures mCurrentPosition < mBufferSize. - if ( size > remainingSize ) { + if ( writeSize > remainingSize ) { /* Writing only to the remaining part of the output buffer! * Note: since size is an uint32_t, and size >= mBufferSize - mCurrentPosition, the cast is safe. */ - writeSize = clamp_cast< uint32_t >( remainingSize ); + writeSize = remainingSize; } const auto* byteData = static_cast< const byte_t* >( data ); //-V2571 @@ -96,7 +96,8 @@ STDMETHODIMP CFixedBufferOutStream::Write( const void* data, UInt32 size, UInt32 mCurrentPosition += writeSize; if ( processedSize != nullptr ) { - *processedSize = writeSize; + // Note: writeSize is not greater than size, which is UInt32, so the cast is safe. + *processedSize = static_cast< UInt32 >( writeSize ); } return S_OK; diff --git a/src/internal/util.hpp b/src/internal/util.hpp index 0b354f7f..6957536f 100644 --- a/src/internal/util.hpp +++ b/src/internal/util.hpp @@ -45,6 +45,8 @@ inline auto seek_to_offset( uint64_t& position, int64_t offset ) noexcept -> HRE return E_INVALIDARG; } position = seekPosition; + } else { + // No action needed } return S_OK; } From b46fef7ac06c28d28e4c646bc837cb92e8792fa9 Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 22 Oct 2023 11:07:05 +0200 Subject: [PATCH 58/62] Fix build with Android NDK --- src/bitpropvariant.cpp | 4 ++-- src/internal/cbufferoutstream.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bitpropvariant.cpp b/src/bitpropvariant.cpp index 63a3d504..1e7f094f 100644 --- a/src/bitpropvariant.cpp +++ b/src/bitpropvariant.cpp @@ -157,7 +157,7 @@ BitPropVariant::BitPropVariant( uint64_t value ) noexcept: PROPVARIANT() { BitPropVariant::BitPropVariant( int8_t value ) noexcept: PROPVARIANT() { vt = VT_I1; wReserved1 = 0; - cVal = value; + cVal = static_cast< char >( value ); } BitPropVariant::BitPropVariant( int16_t value ) noexcept: PROPVARIANT() { @@ -332,7 +332,7 @@ auto BitPropVariant::getUInt64() const -> uint64_t { auto BitPropVariant::getInt8() const -> int8_t { switch ( vt ) { case VT_I1: - return cVal; + return static_cast< int8_t >( cVal ); default: // not an 8-bits integer. throw BitException( "BitPropVariant is not an 8-bits integer", make_error_code( BitError::RequestedWrongVariantType ) ); diff --git a/src/internal/cbufferoutstream.cpp b/src/internal/cbufferoutstream.cpp index 173f5f19..dcf02db4 100644 --- a/src/internal/cbufferoutstream.cpp +++ b/src/internal/cbufferoutstream.cpp @@ -78,7 +78,7 @@ STDMETHODIMP CBufferOutStream::Write( const void* data, UInt32 size, UInt32* pro return E_OUTOFMEMORY; } - std::advance( mCurrentPosition, size ); + std::advance( mCurrentPosition, clamp_cast< std::ptrdiff_t >( size ) ); if ( processedSize != nullptr ) { *processedSize = size; From 5fd8f4c6000951a45bccf2c242a78f6043b813fb Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 22 Oct 2023 13:39:50 +0200 Subject: [PATCH 59/62] Improve clamp_cast --- src/internal/util.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/util.hpp b/src/internal/util.hpp index 6957536f..b59dc38e 100644 --- a/src/internal/util.hpp +++ b/src/internal/util.hpp @@ -143,7 +143,7 @@ template< typename To, typename From > inline auto clamp_cast( From value ) noexcept -> std::enable_if_t< are_both_integral< To, From >::value && have_same_signedness< To, From >::value && sizeof( To ) >= sizeof( From ), To > { - return value; + return static_cast< To >( value ); } template< typename T, typename I = T > From eedb4a92477077612e9f36be4b04cb9d04543c33 Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 22 Oct 2023 19:02:56 +0200 Subject: [PATCH 60/62] Suppress some excessive PVS-Studio warnings --- src/bitarchiveeditor.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/bitarchiveeditor.cpp b/src/bitarchiveeditor.cpp index fd4a91cc..92880848 100644 --- a/src/bitarchiveeditor.cpp +++ b/src/bitarchiveeditor.cpp @@ -51,43 +51,43 @@ BitArchiveEditor::~BitArchiveEditor() = default; void BitArchiveEditor::renameItem( uint32_t index, const tstring& newPath ) { checkIndex( index ); - mEditedItems[ index ] = std::make_unique< RenamedItem >( *inputArchive(), index, newPath ); + mEditedItems[ index ] = std::make_unique< RenamedItem >( *inputArchive(), index, newPath ); //-V108 } void BitArchiveEditor::renameItem( const tstring& oldPath, const tstring& newPath ) { auto index = findItem( oldPath ); - mEditedItems[ index ] = std::make_unique< RenamedItem >( *inputArchive(), index, newPath ); + mEditedItems[ index ] = std::make_unique< RenamedItem >( *inputArchive(), index, newPath ); //-V108 } void BitArchiveEditor::updateItem( uint32_t index, const tstring& inFile ) { checkIndex( index ); auto itemName = inputArchive()->itemProperty( index, BitProperty::Path ); - mEditedItems[ index ] = std::make_unique< FilesystemItem >( tstring_to_path( inFile ), itemName.getNativeString() ); + mEditedItems[ index ] = std::make_unique< FilesystemItem >( tstring_to_path( inFile ), itemName.getNativeString() ); //-V108 } void BitArchiveEditor::updateItem( uint32_t index, const std::vector< byte_t >& inBuffer ) { checkIndex( index ); auto itemName = inputArchive()->itemProperty( index, BitProperty::Path ); - mEditedItems[ index ] = std::make_unique< BufferItem >( inBuffer, itemName.getNativeString() ); + mEditedItems[ index ] = std::make_unique< BufferItem >( inBuffer, itemName.getNativeString() ); //-V108 } void BitArchiveEditor::updateItem( uint32_t index, std::istream& inStream ) { checkIndex( index ); auto itemName = inputArchive()->itemProperty( index, BitProperty::Path ); - mEditedItems[ index ] = std::make_unique< StdInputItem >( inStream, itemName.getNativeString() ); + mEditedItems[ index ] = std::make_unique< StdInputItem >( inStream, itemName.getNativeString() ); //-V108 } void BitArchiveEditor::updateItem( const tstring& itemPath, const tstring& inFile ) { - mEditedItems[ findItem( itemPath ) ] = std::make_unique< FilesystemItem >( tstring_to_path( inFile ), + mEditedItems[ findItem( itemPath ) ] = std::make_unique< FilesystemItem >( tstring_to_path( inFile ), //-V108 tstring_to_path( itemPath ) ); } void BitArchiveEditor::updateItem( const tstring& itemPath, const std::vector< byte_t >& inBuffer ) { - mEditedItems[ findItem( itemPath ) ] = std::make_unique< BufferItem >( inBuffer, itemPath ); + mEditedItems[ findItem( itemPath ) ] = std::make_unique< BufferItem >( inBuffer, itemPath ); //-V108 } void BitArchiveEditor::updateItem( const tstring& itemPath, std::istream& inStream ) { - mEditedItems[ findItem( itemPath ) ] = std::make_unique< StdInputItem >( inStream, itemPath ); + mEditedItems[ findItem( itemPath ) ] = std::make_unique< StdInputItem >( inStream, itemPath ); //-V108 } void BitArchiveEditor::deleteItem( uint32_t index ) { From 8068b91da91d82ae605fd6e07f4a9342f549a5f8 Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 22 Oct 2023 19:04:07 +0200 Subject: [PATCH 61/62] Use x86 7z.dll default path for 32 bit test app --- tests/src/utils/shared_lib.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/src/utils/shared_lib.hpp b/tests/src/utils/shared_lib.hpp index 560c1adb..41435a9b 100644 --- a/tests/src/utils/shared_lib.hpp +++ b/tests/src/utils/shared_lib.hpp @@ -21,8 +21,10 @@ namespace test { inline auto sevenzip_lib_path() -> tstring { #ifdef BIT7Z_TESTS_USE_SYSTEM_7ZIP -#ifdef _WIN32 +#ifdef _WIN64 static const tstring lib_path = BIT7Z_STRING( "C:\\Program Files\\7-Zip\\7z.dll" ); +#elif defined( _WIN32 ) + static const tstring lib_path = BIT7Z_STRING( "C:\\Program Files (x86)\\7-Zip\\7z.dll" ); #elif defined( __linux__ ) static const tstring lib_path = "/usr/lib/p7zip/7z.so"; //default installation path of p7zip's shared library #else From 94d95497149155577d033e7f4266dae4da69f527 Mon Sep 17 00:00:00 2001 From: Oz Date: Sun, 22 Oct 2023 19:04:31 +0200 Subject: [PATCH 62/62] [Test] Fix build of test app on MSVC 2015 --- tests/src/test_formatdetect.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/src/test_formatdetect.cpp b/tests/src/test_formatdetect.cpp index 0ce4b196..4e59009e 100644 --- a/tests/src/test_formatdetect.cpp +++ b/tests/src/test_formatdetect.cpp @@ -265,7 +265,9 @@ TEST_CASE( "formatdetect: Format detection of archive with a wrong extension (Is const Bit7zLibrary lib{ test::sevenzip_lib_path() }; - auto testFile = GENERATE( BIT7Z_STRING( "wrong_extension.rar" ), BIT7Z_STRING( "wrong_extension.bz2" ) ); + auto testFile = GENERATE( as< tstring >(), + BIT7Z_STRING( "wrong_extension.rar" ), + BIT7Z_STRING( "wrong_extension.bz2" ) ); DYNAMIC_SECTION( "Reading file with a wrong extension: " << Catch::StringMaker< tstring >::convert( testFile ) ) { // From file