From d9d4e565735ad9f725c26baf73a8dd91f41edd00 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Fri, 31 Jan 2025 01:07:20 +0100 Subject: [PATCH 01/65] github: continuous integration script --- .github/workflows/ci.yml | 68 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..42926b8dc --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,68 @@ +name: "Build the OpenSalamander project" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +env: + # Project files expect this variable to be defined. + OPENSAL_BUILD_DIR: ${{ github.workspace }}\\OpenSalamander.bin + # Project files expect this variable to be defined. + OPENSAL_INSTALL_DIR: ${{ github.workspace }}\\OpenSalamander + # Configuration type to build. + BUILD_CONFIGURATION: Release + +jobs: + build: + name: Build + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + targetplatform: [x86, x64] # arm64 + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Create version file + run: | + mkdir ${{ env.OPENSAL_INSTALL_DIR }} + git describe --tags > ${{ env.OPENSAL_INSTALL_DIR }}\\version.txt + type ${{ env.OPENSAL_INSTALL_DIR }}\\version.txt + + - name: Setup MSBuild + uses: microsoft/setup-msbuild@v2 + + - name: Setup .NET Framework SDK + uses: actions/setup-dotnet@v2 + with: + dotnet-version: '4.7.x' # required for pe-viewer + + - name: Setup vcpkg + run: | + bootstrap-vcpkg + vcpkg integrate install + + - name: Build the project + run: msbuild src\vcxproj\salamand.sln /t:Rebuild /p:Configuration=Release + + - name: Compose installation directory + run: | + xcopy /E /I /Y ${{ github.workspace }}\\convert ${{ env.OPENSAL_INSTALL_DIR }} + xcopy /E /I /Y ${{ github.workspace }}\\doc ${{ env.OPENSAL_INSTALL_DIR }} + xcopy /E /I /Y ${{ github.workspace }}\\src\\res\\toolbars ${{ env.OPENSAL_INSTALL_DIR }} + xcopy /E /I /Y ${{ github.workspace }}\\src\\plugins\\ieviewer\\cmark-gfm\\css ${{ env.OPENSAL_INSTALL_DIR }} + pushd ${{ env.OPENSAL_BUILD_DIR }}\\Release_${{ matrix.targetplatform }} + robocopy . ${{ env.OPENSAL_INSTALL_DIR }} *.exe *.dll *.spl *.slg /S /E + for /f "delims=" %%d in ('dir ${{ env.OPENSAL_INSTALL_DIR }} /ad /s /b ^| sort /r') do rd "%%d" 2>nul + popd + + - name: Upload Artifact with installation + uses: actions/upload-artifact@v4 + with: + name: OpenSalamander-${{ matrix.targetplatform }} + path: ${{ env.OPENSAL_INSTALL_DIR }} + retention-days: 10 From 625b414799d686854aa0edc14f4a3aa610164633 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Fri, 31 Jan 2025 01:20:34 +0100 Subject: [PATCH 02/65] corrected paths --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 42926b8dc..6d62d04fc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,9 +8,9 @@ on: env: # Project files expect this variable to be defined. - OPENSAL_BUILD_DIR: ${{ github.workspace }}\\OpenSalamander.bin + OPENSAL_BUILD_DIR: c:\\OpenSalamander.bin # Project files expect this variable to be defined. - OPENSAL_INSTALL_DIR: ${{ github.workspace }}\\OpenSalamander + OPENSAL_INSTALL_DIR: c:\\OpenSalamander # Configuration type to build. BUILD_CONFIGURATION: Release @@ -47,7 +47,7 @@ jobs: vcpkg integrate install - name: Build the project - run: msbuild src\vcxproj\salamand.sln /t:Rebuild /p:Configuration=Release + run: msbuild src\vcxproj\salamand.sln /t:Rebuild /p:Configuration=Release /p:OutDir=${{ env.OPENSAL_BUILD_DIR }}\\ - name: Compose installation directory run: | From 53c735032cd6c2c5db71d86caa2c77ca4ed0613b Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Fri, 31 Jan 2025 01:24:13 +0100 Subject: [PATCH 03/65] corrected git describe command --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6d62d04fc..5bfe1eb80 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,7 +30,7 @@ jobs: - name: Create version file run: | mkdir ${{ env.OPENSAL_INSTALL_DIR }} - git describe --tags > ${{ env.OPENSAL_INSTALL_DIR }}\\version.txt + git describe --tags --always > ${{ env.OPENSAL_INSTALL_DIR }}\\version.txt type ${{ env.OPENSAL_INSTALL_DIR }}\\version.txt - name: Setup MSBuild From d46f4ce73ee124f01f64e72b0edfdb29fc39d672 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Fri, 31 Jan 2025 01:26:30 +0100 Subject: [PATCH 04/65] corrected dotnet version --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5bfe1eb80..fc9864485 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: - name: Setup .NET Framework SDK uses: actions/setup-dotnet@v2 with: - dotnet-version: '4.7.x' # required for pe-viewer + dotnet-version: '5.0.17' # required for pe-viewer - name: Setup vcpkg run: | From 70ae893a46c48fa1a17cf52e32218eb8e692352d Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Fri, 31 Jan 2025 01:29:27 +0100 Subject: [PATCH 05/65] temporarily disable dotnet install step --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc9864485..62a366994 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,6 +37,7 @@ jobs: uses: microsoft/setup-msbuild@v2 - name: Setup .NET Framework SDK + if: false uses: actions/setup-dotnet@v2 with: dotnet-version: '5.0.17' # required for pe-viewer From 82141dc40059bda78427de712dba288c75d154ee Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Fri, 31 Jan 2025 01:30:23 +0100 Subject: [PATCH 06/65] temporarily disable x64 build --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 62a366994..d3c9e4d7b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - targetplatform: [x86, x64] # arm64 + targetplatform: [x86] # x64, arm64 steps: - name: Checkout repository From 5756953aeaa6931cb382ff1023aa3691a5a135d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viliam=20Lej=C4=8D=C3=ADk?= Date: Fri, 31 Jan 2025 09:35:17 +0100 Subject: [PATCH 07/65] dotnet sdk, update to a supported version --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3c9e4d7b..8a615bb5b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: if: false uses: actions/setup-dotnet@v2 with: - dotnet-version: '5.0.17' # required for pe-viewer + dotnet-version: '6.0.x' # required for pe-viewer - name: Setup vcpkg run: | From 7b613bed8bcc2720bd6b312c18a654236d0828cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viliam=20Lej=C4=8D=C3=ADk?= Date: Fri, 31 Jan 2025 09:36:44 +0100 Subject: [PATCH 08/65] reenabled dotnet sdk install step --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8a615bb5b..42ac116e8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,6 @@ jobs: uses: microsoft/setup-msbuild@v2 - name: Setup .NET Framework SDK - if: false uses: actions/setup-dotnet@v2 with: dotnet-version: '6.0.x' # required for pe-viewer From 97546e7f313e2806df74cc6b72d6e6c2ed4f1629 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viliam=20Lej=C4=8D=C3=ADk?= Date: Fri, 31 Jan 2025 18:36:11 +0100 Subject: [PATCH 09/65] temporary fix for exif.dll Windows SDK version 10.0.26100.0 introduced an issue with __ucrt_int_to_float symbol, that is already defined in another translation unit, here is recommendation how to temporarily fix the problem: - https://github.com/InsightSoftwareConsortium/ITK/issues/4820#issuecomment-2320973858 - https://developercommunity.visualstudio.com/t/NAN-is-no-longer-compile-time-constant-i/10688907 fix will be removed once it will be fixed in Windows SDK --- src/plugins/pictview/vcxproj/exif/exif_base.props | 1 + 1 file changed, 1 insertion(+) diff --git a/src/plugins/pictview/vcxproj/exif/exif_base.props b/src/plugins/pictview/vcxproj/exif/exif_base.props index f7ca8d696..5eb3a9699 100644 --- a/src/plugins/pictview/vcxproj/exif/exif_base.props +++ b/src/plugins/pictview/vcxproj/exif/exif_base.props @@ -25,6 +25,7 @@ ..\..\exif\exif.def true Windows + MultiplyDefinedSymbolOnly WINVER=0x0601;%(PreprocessorDefinitions) From 70232f411b0df3734591d66f5637ac375d1eed52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Viliam=20Lej=C4=8D=C3=ADk?= Date: Fri, 31 Jan 2025 18:54:06 +0100 Subject: [PATCH 10/65] updated installation directory creation step --- .github/workflows/ci.yml | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 42ac116e8..ecb6cf841 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,17 +50,18 @@ jobs: run: msbuild src\vcxproj\salamand.sln /t:Rebuild /p:Configuration=Release /p:OutDir=${{ env.OPENSAL_BUILD_DIR }}\\ - name: Compose installation directory + shell: pwsh run: | - xcopy /E /I /Y ${{ github.workspace }}\\convert ${{ env.OPENSAL_INSTALL_DIR }} - xcopy /E /I /Y ${{ github.workspace }}\\doc ${{ env.OPENSAL_INSTALL_DIR }} - xcopy /E /I /Y ${{ github.workspace }}\\src\\res\\toolbars ${{ env.OPENSAL_INSTALL_DIR }} - xcopy /E /I /Y ${{ github.workspace }}\\src\\plugins\\ieviewer\\cmark-gfm\\css ${{ env.OPENSAL_INSTALL_DIR }} - pushd ${{ env.OPENSAL_BUILD_DIR }}\\Release_${{ matrix.targetplatform }} - robocopy . ${{ env.OPENSAL_INSTALL_DIR }} *.exe *.dll *.spl *.slg /S /E - for /f "delims=" %%d in ('dir ${{ env.OPENSAL_INSTALL_DIR }} /ad /s /b ^| sort /r') do rd "%%d" 2>nul + xcopy /E /I /Y $env:github_workspace\\convert $env:OPENSAL_INSTALL_DIR + xcopy /E /I /Y $env:github_workspace\\doc $env:OPENSAL_INSTALL_DIR + xcopy /E /I /Y $env:github_workspace\\src\\res\\toolbars $env:OPENSAL_INSTALL_DIR + pushd $env:OPENSAL_BUILD_DIR\\Release_$env:matrix_targetplatform + robocopy . $env:OPENSAL_INSTALL_DIR *.exe *.dll *.spl *.slg /S /E + Get-ChildItem -Path $env:OPENSAL_INSTALL_DIR -Recurse -Directory | Sort-Object -Property FullName -Descending | Remove-Item -Force -Recurse popd + xcopy /E /I /Y $env:github_workspace\\src\\plugins\\ieviewer\\cmark-gfm\\css $env:OPENSAL_INSTALL_DIR\\plugins\\ieviewer\\css - - name: Upload Artifact with installation + - name: Finalize installation package uses: actions/upload-artifact@v4 with: name: OpenSalamander-${{ matrix.targetplatform }} From 5a560bbe7bef0e4a32150038f069f9668ddac495 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Fri, 31 Jan 2025 22:15:34 +0100 Subject: [PATCH 11/65] one more correction for installation directory composition step --- .github/workflows/ci.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ecb6cf841..a6548b178 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,14 +52,14 @@ jobs: - name: Compose installation directory shell: pwsh run: | - xcopy /E /I /Y $env:github_workspace\\convert $env:OPENSAL_INSTALL_DIR - xcopy /E /I /Y $env:github_workspace\\doc $env:OPENSAL_INSTALL_DIR - xcopy /E /I /Y $env:github_workspace\\src\\res\\toolbars $env:OPENSAL_INSTALL_DIR - pushd $env:OPENSAL_BUILD_DIR\\Release_$env:matrix_targetplatform - robocopy . $env:OPENSAL_INSTALL_DIR *.exe *.dll *.spl *.slg /S /E - Get-ChildItem -Path $env:OPENSAL_INSTALL_DIR -Recurse -Directory | Sort-Object -Property FullName -Descending | Remove-Item -Force -Recurse + xcopy /E /I /Y ${env:github_workspace}\\convert ${env:OPENSAL_INSTALL_DIR} + xcopy /E /I /Y ${env:github_workspace}\\doc ${env:OPENSAL_INSTALL_DIR} + xcopy /E /I /Y ${env:github_workspace}\\src\\res\\toolbars ${env:OPENSAL_INSTALL_DIR} + pushd ${env:OPENSAL_BUILD_DIR}\\Release_${env:matrix_targetplatform} + robocopy . ${env:OPENSAL_INSTALL_DIR} *.exe *.dll *.spl *.slg /S /E + Get-ChildItem -Path ${env:OPENSAL_INSTALL_DIR} -Recurse -Directory | Sort-Object -Property FullName -Descending | Remove-Item -Force -Recurse popd - xcopy /E /I /Y $env:github_workspace\\src\\plugins\\ieviewer\\cmark-gfm\\css $env:OPENSAL_INSTALL_DIR\\plugins\\ieviewer\\css + xcopy /E /I /Y ${env:github_workspace}\\src\\plugins\\ieviewer\\cmark-gfm\\css ${env:OPENSAL_INSTALL_DIR}\\plugins\\ieviewer\\css - name: Finalize installation package uses: actions/upload-artifact@v4 From 07802843c7040fe6cbf4920aa30100cd9c9dbc6a Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Fri, 31 Jan 2025 22:29:17 +0100 Subject: [PATCH 12/65] corrected variable name --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6548b178..43749a1ec 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: xcopy /E /I /Y ${env:github_workspace}\\convert ${env:OPENSAL_INSTALL_DIR} xcopy /E /I /Y ${env:github_workspace}\\doc ${env:OPENSAL_INSTALL_DIR} xcopy /E /I /Y ${env:github_workspace}\\src\\res\\toolbars ${env:OPENSAL_INSTALL_DIR} - pushd ${env:OPENSAL_BUILD_DIR}\\Release_${env:matrix_targetplatform} + pushd ${env:OPENSAL_BUILD_DIR}\\Release_${{ matrix.targetplatform }} robocopy . ${env:OPENSAL_INSTALL_DIR} *.exe *.dll *.spl *.slg /S /E Get-ChildItem -Path ${env:OPENSAL_INSTALL_DIR} -Recurse -Directory | Sort-Object -Property FullName -Descending | Remove-Item -Force -Recurse popd From 57432bbdc8796e0e98c2c62487f0c06454082410 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Fri, 31 Jan 2025 22:43:33 +0100 Subject: [PATCH 13/65] one more path correction --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 43749a1ec..6304be48e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -55,7 +55,7 @@ jobs: xcopy /E /I /Y ${env:github_workspace}\\convert ${env:OPENSAL_INSTALL_DIR} xcopy /E /I /Y ${env:github_workspace}\\doc ${env:OPENSAL_INSTALL_DIR} xcopy /E /I /Y ${env:github_workspace}\\src\\res\\toolbars ${env:OPENSAL_INSTALL_DIR} - pushd ${env:OPENSAL_BUILD_DIR}\\Release_${{ matrix.targetplatform }} + pushd ${env:OPENSAL_BUILD_DIR} robocopy . ${env:OPENSAL_INSTALL_DIR} *.exe *.dll *.spl *.slg /S /E Get-ChildItem -Path ${env:OPENSAL_INSTALL_DIR} -Recurse -Directory | Sort-Object -Property FullName -Descending | Remove-Item -Force -Recurse popd From 5600e6ee26f3f8baddb552fe3723174efa11352b Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Fri, 31 Jan 2025 23:00:29 +0100 Subject: [PATCH 14/65] optimized the robocopy command --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6304be48e..d8eeb3d80 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,8 +56,7 @@ jobs: xcopy /E /I /Y ${env:github_workspace}\\doc ${env:OPENSAL_INSTALL_DIR} xcopy /E /I /Y ${env:github_workspace}\\src\\res\\toolbars ${env:OPENSAL_INSTALL_DIR} pushd ${env:OPENSAL_BUILD_DIR} - robocopy . ${env:OPENSAL_INSTALL_DIR} *.exe *.dll *.spl *.slg /S /E - Get-ChildItem -Path ${env:OPENSAL_INSTALL_DIR} -Recurse -Directory | Sort-Object -Property FullName -Descending | Remove-Item -Force -Recurse + robocopy . ${env:OPENSAL_INSTALL_DIR} *.exe *.dll *.spl *.slg /S popd xcopy /E /I /Y ${env:github_workspace}\\src\\plugins\\ieviewer\\cmark-gfm\\css ${env:OPENSAL_INSTALL_DIR}\\plugins\\ieviewer\\css From b9e97e0f2dce477011a9bbb26f00865db94d2b3c Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 00:02:22 +0100 Subject: [PATCH 15/65] more script improvements --- .github/workflows/ci.yml | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8eeb3d80..dd153362e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,9 +8,9 @@ on: env: # Project files expect this variable to be defined. - OPENSAL_BUILD_DIR: c:\\OpenSalamander.bin + OPENSAL_BUILD_DIR: c:\\OpenSalamander\\ # Project files expect this variable to be defined. - OPENSAL_INSTALL_DIR: c:\\OpenSalamander + OPENSAL_INSTALL_DIR: c:\\install\\OpenSalamander\\ # Configuration type to build. BUILD_CONFIGURATION: Release @@ -30,8 +30,8 @@ jobs: - name: Create version file run: | mkdir ${{ env.OPENSAL_INSTALL_DIR }} - git describe --tags --always > ${{ env.OPENSAL_INSTALL_DIR }}\\version.txt - type ${{ env.OPENSAL_INSTALL_DIR }}\\version.txt + git describe --tags --always > ${{ env.OPENSAL_INSTALL_DIR }}version.txt + type ${{ env.OPENSAL_INSTALL_DIR }}version.txt - name: Setup MSBuild uses: microsoft/setup-msbuild@v2 @@ -47,7 +47,7 @@ jobs: vcpkg integrate install - name: Build the project - run: msbuild src\vcxproj\salamand.sln /t:Rebuild /p:Configuration=Release /p:OutDir=${{ env.OPENSAL_BUILD_DIR }}\\ + run: msbuild src\vcxproj\salamand.sln /t:Rebuild /p:Configuration=Release - name: Compose installation directory shell: pwsh @@ -55,10 +55,13 @@ jobs: xcopy /E /I /Y ${env:github_workspace}\\convert ${env:OPENSAL_INSTALL_DIR} xcopy /E /I /Y ${env:github_workspace}\\doc ${env:OPENSAL_INSTALL_DIR} xcopy /E /I /Y ${env:github_workspace}\\src\\res\\toolbars ${env:OPENSAL_INSTALL_DIR} - pushd ${env:OPENSAL_BUILD_DIR} + xcopy /E /I /Y ${env:github_workspace}\\src\\plugins\\automation\\sample-scripts ${env:OPENSAL_INSTALL_DIR}plugins\\automation\\scripts + xcopy /E /I /Y ${env:github_workspace}\\src\\plugins\\ieviewer\\cmark-gfm\\css ${env:OPENSAL_INSTALL_DIR}plugins\\ieviewer\\css + xcopy /I /Y ${env:github_workspace}\\src\\plugins\\zip\\zip2sfx\\*.txt ${env:OPENSAL_INSTALL_DIR}plugins\\zip\\zip2sfx + xcopy /I /Y ${env:github_workspace}\\src\\plugins\\zip\\zip2sfx\\*.set ${env:OPENSAL_INSTALL_DIR}plugins\\zip\\zip2sfx + pushd ${env:OPENSAL_BUILD_DIR}salamander\\${env:BUILD_CONFIGURATION}_${{ matrix.targetplatform }} robocopy . ${env:OPENSAL_INSTALL_DIR} *.exe *.dll *.spl *.slg /S popd - xcopy /E /I /Y ${env:github_workspace}\\src\\plugins\\ieviewer\\cmark-gfm\\css ${env:OPENSAL_INSTALL_DIR}\\plugins\\ieviewer\\css - name: Finalize installation package uses: actions/upload-artifact@v4 From 1c7b40b2ab0b1def95532808d684e5394ffc54c6 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 00:24:56 +0100 Subject: [PATCH 16/65] restructured the install step --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dd153362e..bff53d851 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -52,6 +52,9 @@ jobs: - name: Compose installation directory shell: pwsh run: | + pushd ${env:OPENSAL_BUILD_DIR}salamander\\${env:BUILD_CONFIGURATION}_${{ matrix.targetplatform }} + robocopy . ${env:OPENSAL_INSTALL_DIR} *.exe *.dll *.spl *.slg /S + popd xcopy /E /I /Y ${env:github_workspace}\\convert ${env:OPENSAL_INSTALL_DIR} xcopy /E /I /Y ${env:github_workspace}\\doc ${env:OPENSAL_INSTALL_DIR} xcopy /E /I /Y ${env:github_workspace}\\src\\res\\toolbars ${env:OPENSAL_INSTALL_DIR} @@ -59,9 +62,6 @@ jobs: xcopy /E /I /Y ${env:github_workspace}\\src\\plugins\\ieviewer\\cmark-gfm\\css ${env:OPENSAL_INSTALL_DIR}plugins\\ieviewer\\css xcopy /I /Y ${env:github_workspace}\\src\\plugins\\zip\\zip2sfx\\*.txt ${env:OPENSAL_INSTALL_DIR}plugins\\zip\\zip2sfx xcopy /I /Y ${env:github_workspace}\\src\\plugins\\zip\\zip2sfx\\*.set ${env:OPENSAL_INSTALL_DIR}plugins\\zip\\zip2sfx - pushd ${env:OPENSAL_BUILD_DIR}salamander\\${env:BUILD_CONFIGURATION}_${{ matrix.targetplatform }} - robocopy . ${env:OPENSAL_INSTALL_DIR} *.exe *.dll *.spl *.slg /S - popd - name: Finalize installation package uses: actions/upload-artifact@v4 From 26c733cb48e66b10a44d64ada66d45a0d952e03d Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 00:43:45 +0100 Subject: [PATCH 17/65] another optimization of the install step --- .github/workflows/ci.yml | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bff53d851..9b2e4a6c5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ on: env: # Project files expect this variable to be defined. OPENSAL_BUILD_DIR: c:\\OpenSalamander\\ - # Project files expect this variable to be defined. + # Directory with installation that will be packed and uploaded as an artifact. OPENSAL_INSTALL_DIR: c:\\install\\OpenSalamander\\ # Configuration type to build. BUILD_CONFIGURATION: Release @@ -50,18 +50,17 @@ jobs: run: msbuild src\vcxproj\salamand.sln /t:Rebuild /p:Configuration=Release - name: Compose installation directory - shell: pwsh run: | - pushd ${env:OPENSAL_BUILD_DIR}salamander\\${env:BUILD_CONFIGURATION}_${{ matrix.targetplatform }} - robocopy . ${env:OPENSAL_INSTALL_DIR} *.exe *.dll *.spl *.slg /S + pushd${{ env.OPENSAL_BUILD_DIR }}salamander\\${{ env.BUILD_CONFIGURATION }}_${{ matrix.targetplatform }} + robocopy . ${{ env.OPENSAL_INSTALL_DIR }} *.exe *.dll *.spl *.slg /S popd - xcopy /E /I /Y ${env:github_workspace}\\convert ${env:OPENSAL_INSTALL_DIR} - xcopy /E /I /Y ${env:github_workspace}\\doc ${env:OPENSAL_INSTALL_DIR} - xcopy /E /I /Y ${env:github_workspace}\\src\\res\\toolbars ${env:OPENSAL_INSTALL_DIR} - xcopy /E /I /Y ${env:github_workspace}\\src\\plugins\\automation\\sample-scripts ${env:OPENSAL_INSTALL_DIR}plugins\\automation\\scripts - xcopy /E /I /Y ${env:github_workspace}\\src\\plugins\\ieviewer\\cmark-gfm\\css ${env:OPENSAL_INSTALL_DIR}plugins\\ieviewer\\css - xcopy /I /Y ${env:github_workspace}\\src\\plugins\\zip\\zip2sfx\\*.txt ${env:OPENSAL_INSTALL_DIR}plugins\\zip\\zip2sfx - xcopy /I /Y ${env:github_workspace}\\src\\plugins\\zip\\zip2sfx\\*.set ${env:OPENSAL_INSTALL_DIR}plugins\\zip\\zip2sfx + xcopy /E /I /Y ${{ github.workspace }}\\convert ${{ env.OPENSAL_INSTALL_DIR }}convert + xcopy /E /I /Y ${{ github.workspace }}\\doc ${{ env.OPENSAL_INSTALL_DIR }}doc + xcopy /E /I /Y ${{ github.workspace }}\\src\\res\\toolbars ${{ env.OPENSAL_INSTALL_DIR }}toolbars + xcopy /E /I /Y ${{ github.workspace }}\\src\\plugins\\automation\\sample-scripts ${{ env.OPENSAL_INSTALL_DIR }}plugins\\automation\\scripts + xcopy /E /I /Y ${{ github.workspace }}\\src\\plugins\\ieviewer\\cmark-gfm\\css ${{ env.OPENSAL_INSTALL_DIR }}plugins\\ieviewer\\css + xcopy /I /Y ${{ github.workspace }}\\src\\plugins\\zip\\zip2sfx\\*.txt ${{ env.OPENSAL_INSTALL_DIR }}plugins\\zip\\zip2sfx + xcopy /I /Y ${{ github.workspace }}\\src\\plugins\\zip\\zip2sfx\\*.set ${{ env.OPENSAL_INSTALL_DIR }}plugins\\zip\\zip2sfx - name: Finalize installation package uses: actions/upload-artifact@v4 From 08a7995d456c670d5e2a1a21622a407c023c2c7a Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 00:52:33 +0100 Subject: [PATCH 18/65] fixed a typo --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9b2e4a6c5..9cbb0fc70 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -51,7 +51,7 @@ jobs: - name: Compose installation directory run: | - pushd${{ env.OPENSAL_BUILD_DIR }}salamander\\${{ env.BUILD_CONFIGURATION }}_${{ matrix.targetplatform }} + pushd ${{ env.OPENSAL_BUILD_DIR }}salamander\\${{ env.BUILD_CONFIGURATION }}_${{ matrix.targetplatform }} robocopy . ${{ env.OPENSAL_INSTALL_DIR }} *.exe *.dll *.spl *.slg /S popd xcopy /E /I /Y ${{ github.workspace }}\\convert ${{ env.OPENSAL_INSTALL_DIR }}convert From 342e69547ea94fc65c23799c212ebf555dbc984e Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 10:43:33 +0100 Subject: [PATCH 19/65] updated unrar plugin, vcpkg builds unrar.dll dependency and is now linked to the plugin salamander can now load plugin with all linked libraries that are placed in its directory, plugin no longer needs to load dlls with LoadLibrary() --- src/plugins/unrar/unrar.cpp | 100 +------------ src/plugins/unrar/unrar.h | 14 +- src/plugins/unrar/unrardll.h | 177 ------------------------ src/plugins/unrar/vcpkg.json | 6 + src/plugins/unrar/vcxproj/unrar.vcxproj | 5 + src/plugins1.cpp | 16 +++ 6 files changed, 33 insertions(+), 285 deletions(-) delete mode 100644 src/plugins/unrar/unrardll.h create mode 100644 src/plugins/unrar/vcpkg.json diff --git a/src/plugins/unrar/unrar.cpp b/src/plugins/unrar/unrar.cpp index 72085f251..2e38e6fe8 100644 --- a/src/plugins/unrar/unrar.cpp +++ b/src/plugins/unrar/unrar.cpp @@ -22,19 +22,6 @@ CSalamanderSafeFileAbstract* SalamanderSafeFile = NULL; // definice promenne pro "dbg.h" CSalamanderDebugAbstract* SalamanderDebug = NULL; -HINSTANCE UnRarDll = NULL; - -// funkce vyvezene z unrar.dll -FRAROpenArchiveEx _RAROpenArchiveEx; -FRARCloseArchive _RARCloseArchive; -//FRARReadHeader RARReadHeader; -FRARReadHeaderEx _RARReadHeaderEx; -FRARProcessFile _RARProcessFile; -//FRARSetChangeVolProc _RARSetChangeVolProc; -//FRARSetProcessDataProc _RARSetProcessDataProc; -FRARSetPassword _RARSetPassword; -FRARSetCallback _RARSetCallback; - struct CConfiguration Config; const SYSTEMTIME MinTime = {1980, 01, 2, 01, 00, 00, 00, 000}; @@ -118,59 +105,6 @@ CPluginInterfaceAbstract* WINAPI SalamanderPluginEntry(CSalamanderPluginEntryAbs return &PluginInterface; } -// **************************************************************************** -// -// stuby do UnRAR.DLL (kvuli callstacku) -// - -HANDLE RAROpenArchiveEx(struct RAROpenArchiveDataEx* ArchiveData) -{ - CALL_STACK_MESSAGE1("RarOpenArchiveEx( )"); - return _RAROpenArchiveEx(ArchiveData); -} - -int RARCloseArchive(HANDLE hArcData) -{ - CALL_STACK_MESSAGE1("RARCloseArchive( )"); - return _RARCloseArchive(hArcData); -} - -int RARReadHeaderEx(HANDLE hArcData, struct RARHeaderDataEx* HeaderData) -{ - DEBUG_SLOW_CALL_STACK_MESSAGE1("RARReadHeaderEx( , )"); - return _RARReadHeaderEx(hArcData, HeaderData); -} - -int RARProcessFile(HANDLE hArcData, int Operation, const char* DestPath, char* DestName) -{ - DEBUG_SLOW_CALL_STACK_MESSAGE4("RARProcessFile( , %d, %s, %s", Operation, DestPath, DestName); - return _RARProcessFile(hArcData, Operation, DestPath, DestName); -} - -void RARSetCallback(HANDLE hArcData, UNRARCALLBACK Callback, LPARAM UserData) -{ - CALL_STACK_MESSAGE2("RARSetCallback( , , 0x%IX)", UserData); - _RARSetCallback(hArcData, Callback, UserData); -} - -/*void RARSetChangeVolProc(HANDLE hArcData,int (PASCAL *ChangeVolProc)(char *ArcName,int Mode)) -{ - CALL_STACK_MESSAGE1("RARSetChangeVolProc( , )"); - _RARSetChangeVolProc(hArcData, ChangeVolProc); -} - -void RARSetProcessDataProc(HANDLE hArcData,int (PASCAL *ProcessDataProc)(unsigned char *Addr,int Size)) -{ - CALL_STACK_MESSAGE1("RARSetProcessDataProc( , )"); - _RARSetProcessDataProc(hArcData, ProcessDataProc); -}*/ - -void RARSetPassword(HANDLE hArcData, char* Password) -{ - CALL_STACK_MESSAGE1("RARSetPassword( , ***)"); - _RARSetPassword(hArcData, Password); -} - // **************************************************************************** // // CPluginInterface @@ -190,8 +124,6 @@ void CPluginInterface::About(HWND parent) BOOL CPluginInterface::Release(HWND parent, BOOL force) { CALL_STACK_MESSAGE2("CPluginInterface::Release(, %d)", force); - // if (PakLibDLL) FreeLibrary(PakLibDLL); - FreeLibrary(UnRarDll); return TRUE; } @@ -908,37 +840,12 @@ BOOL CPluginInterfaceForArchiver::Init() { CALL_STACK_MESSAGE1("CPluginInterfaceForArchiver::Init()"); ArchiveVolumes = NULL; - char buf[MAX_PATH + 12]; - if (!GetModuleFileName(DLLInstance, buf, 1024)) - return Error(IDS_ERRMODULEFN); - SalamanderGeneral->CutDirectory(buf); - SalamanderGeneral->SalPathAppend(buf, "unrar.dll", MAX_PATH + 12); - UnRarDll = LoadLibrary(buf); - if (!UnRarDll) - return Error(IDS_ERRLOADLIB, buf); - - FRARGetDllVersion RARGetDllVersion = (FRARGetDllVersion)GetProcAddress(UnRarDll, "RARGetDllVersion"); - if (RARGetDllVersion == NULL || RARGetDllVersion() < RAR_DLL_VERSION) + + if (RARGetDllVersion() < RAR_DLL_VERSION) { - FreeLibrary(UnRarDll); - UnRarDll = NULL; return Error(IDS_BADDLL); } - if ((_RAROpenArchiveEx = (FRAROpenArchiveEx)GetProcAddress(UnRarDll, "RAROpenArchiveEx")) == NULL || - (_RARCloseArchive = (FRARCloseArchive)GetProcAddress(UnRarDll, "RARCloseArchive")) == NULL || - (_RARProcessFile = (FRARProcessFile)GetProcAddress(UnRarDll, "RARProcessFile")) == NULL || - //(RARReadHeader = (FRARReadHeader) GetProcAddress(UnRarDll, "RARReadHeader")) == NULL || - (_RARReadHeaderEx = (FRARReadHeaderEx)GetProcAddress(UnRarDll, "RARReadHeaderEx")) == NULL || - (_RARSetCallback = (FRARSetCallback)GetProcAddress(UnRarDll, "RARSetCallback")) == NULL || - //(_RARSetChangeVolProc = (FRARSetChangeVolProc) GetProcAddress(UnRarDll, "RARSetChangeVolProc")) == NULL || - //(_RARSetProcessDataProc = (FRARSetProcessDataProc) GetProcAddress(UnRarDll, "RARSetProcessDataProc")) == NULL || - (_RARSetPassword = (FRARSetPassword)GetProcAddress(UnRarDll, "RARSetPassword")) == NULL) - { - FreeLibrary(UnRarDll); - UnRarDll = NULL; - return Error(IDS_ERRGETPROCADDR); - } return TRUE; } @@ -1138,7 +1045,8 @@ BOOL CPluginInterfaceForArchiver::ProcessFile(int operation, char* fileName) DEBUG_SLOW_CALL_STACK_MESSAGE2("CPluginInterfaceForArchiver::ProcessFile(%d, )", operation); int err = 0; Success = FALSE; - int ret = RARProcessFile(ArcHandle, operation, "", NULL); + char DestPath[] = ""; + int ret = RARProcessFile(ArcHandle, operation, DestPath, NULL); if (Abort) return FALSE; switch (ret) diff --git a/src/plugins/unrar/unrar.h b/src/plugins/unrar/unrar.h index 4e5f56746..e82c69152 100644 --- a/src/plugins/unrar/unrar.h +++ b/src/plugins/unrar/unrar.h @@ -3,7 +3,8 @@ #pragma once -#include "unrardll.h" +// include unrar.dll API +#include /* winnt.h #define FILE_ATTRIBUTE_READONLY 0x00000001 @@ -255,17 +256,6 @@ extern struct CConfiguration Config; LPCTSTR LoadStr(int resID); void GetInfo(char* buffer, FILETIME* lastWrite, CQuadWord& size); -typedef int(PASCAL* FRARGetDllVersion)(); -typedef HANDLE(PASCAL* FRAROpenArchiveEx)(struct RAROpenArchiveDataEx* ArchiveData); -typedef int(PASCAL* FRARCloseArchive)(HANDLE hArcData); -//typedef int (PASCAL *FRARReadHeader)(HANDLE hArcData,struct RARHeaderData *HeaderData); -typedef int(PASCAL* FRARReadHeaderEx)(HANDLE hArcData, struct RARHeaderDataEx* HeaderData); -typedef int(PASCAL* FRARProcessFile)(HANDLE hArcData, int Operation, const char* DestPath, char* DestName); -//typedef void (PASCAL *FRARSetChangeVolProc)(HANDLE hArcData,int (PASCAL *ChangeVolProc)(char *ArcName,int Mode)); -//typedef void (PASCAL *FRARSetProcessDataProc)(HANDLE hArcData,int (PASCAL *ProcessDataProc)(unsigned char *Addr,int Size)); -typedef void(PASCAL* FRARSetPassword)(HANDLE hArcData, char* Password); -typedef void(PASCAL* FRARSetCallback)(HANDLE hArcData, UNRARCALLBACK Callback, LPARAM UserData); - //*********************************************************************************** // // Rutiny ze SHLWAPI.DLL diff --git a/src/plugins/unrar/unrardll.h b/src/plugins/unrar/unrardll.h deleted file mode 100644 index d077d7654..000000000 --- a/src/plugins/unrar/unrardll.h +++ /dev/null @@ -1,177 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Open Salamander Authors -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#pragma pack(1) - -#define ERAR_SUCCESS 0 -#define ERAR_END_ARCHIVE 10 -#define ERAR_NO_MEMORY 11 -#define ERAR_BAD_DATA 12 -#define ERAR_BAD_ARCHIVE 13 -#define ERAR_UNKNOWN_FORMAT 14 -#define ERAR_EOPEN 15 -#define ERAR_ECREATE 16 -#define ERAR_ECLOSE 17 -#define ERAR_EREAD 18 -#define ERAR_EWRITE 19 -#define ERAR_SMALL_BUF 20 -#define ERAR_UNKNOWN 21 -#define ERAR_MISSING_PASSWORD 22 -#define ERAR_EREFERENCE 23 -#define ERAR_BAD_PASSWORD 24 - -#define RAR_OM_LIST 0 -#define RAR_OM_EXTRACT 1 -#define RAR_OM_LIST_INCSPLIT 2 - -#define RAR_SKIP 0 -#define RAR_TEST 1 -#define RAR_EXTRACT 2 - -#define RAR_VOL_ASK 0 -#define RAR_VOL_NOTIFY 1 - -#define RAR_DLL_VERSION 8 - -#define RAR_HASH_NONE 0 -#define RAR_HASH_CRC32 1 -#define RAR_HASH_BLAKE2 2 - -#ifdef _UNIX -#define CALLBACK -#define PASCAL -#define LONG long -#define HANDLE void* -#define LPARAM long -#define UINT unsigned int -#endif - -#define RHDF_SPLITBEFORE 0x01 -#define RHDF_SPLITAFTER 0x02 -#define RHDF_ENCRYPTED 0x04 -#define RHDF_SOLID 0x10 -#define RHDF_DIRECTORY 0x20 - -struct RARHeaderData -{ - char ArcName[260]; - char FileName[260]; - unsigned int Flags; - unsigned int PackSize; - unsigned int UnpSize; - unsigned int HostOS; - unsigned int FileCRC; - unsigned int FileTime; - unsigned int UnpVer; - unsigned int Method; - unsigned int FileAttr; - char* CmtBuf; - unsigned int CmtBufSize; - unsigned int CmtSize; - unsigned int CmtState; -}; - -struct RARHeaderDataEx -{ - char ArcName[1024]; - wchar_t ArcNameW[1024]; - char FileName[1024]; - wchar_t FileNameW[1024]; - unsigned int Flags; - unsigned int PackSize; - unsigned int PackSizeHigh; - unsigned int UnpSize; - unsigned int UnpSizeHigh; - unsigned int HostOS; - unsigned int FileCRC; - unsigned int FileTime; - unsigned int UnpVer; - unsigned int Method; - unsigned int FileAttr; - char* CmtBuf; - unsigned int CmtBufSize; - unsigned int CmtSize; - unsigned int CmtState; - unsigned int DictSize; - unsigned int HashType; - char Hash[32]; - unsigned int RedirType; - wchar_t* RedirName; - unsigned int RedirNameSize; - unsigned int DirTarget; - unsigned int MtimeLow; - unsigned int MtimeHigh; - unsigned int CtimeLow; - unsigned int CtimeHigh; - unsigned int AtimeLow; - unsigned int AtimeHigh; - unsigned int Reserved[988]; -}; - -struct RAROpenArchiveData -{ - char* ArcName; - unsigned int OpenMode; - unsigned int OpenResult; - char* CmtBuf; - unsigned int CmtBufSize; - unsigned int CmtSize; - unsigned int CmtState; -}; - -typedef int(CALLBACK* UNRARCALLBACK)(UINT msg, LPARAM UserData, LPARAM P1, LPARAM P2); - -struct RAROpenArchiveDataEx -{ - char* ArcName; - wchar_t* ArcNameW; - unsigned int OpenMode; - unsigned int OpenResult; - char* CmtBuf; - unsigned int CmtBufSize; - unsigned int CmtSize; - unsigned int CmtState; - unsigned int Flags; - UNRARCALLBACK Callback; - LPARAM UserData; - unsigned int Reserved[28]; -}; - -enum UNRARCALLBACK_MESSAGES -{ - UCM_CHANGEVOLUME, - UCM_PROCESSDATA, - UCM_NEEDPASSWORD, - UCM_CHANGEVOLUMEW, - UCM_NEEDPASSWORDW -}; - -typedef int(PASCAL* CHANGEVOLPROC)(char* ArcName, int Mode); -typedef int(PASCAL* PROCESSDATAPROC)(unsigned char* Addr, int Size); - -/* -#ifdef __cplusplus -extern "C" { -#endif - -HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *ArchiveData); -HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *ArchiveData); -int PASCAL RARCloseArchive(HANDLE hArcData); -int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *HeaderData); -int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *HeaderData); -int PASCAL RARProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName); -int PASCAL RARProcessFileW(HANDLE hArcData,int Operation,wchar_t *DestPath,wchar_t *DestName); -void PASCAL RARSetCallback(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData); -void PASCAL RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc); -void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc); -void PASCAL RARSetPassword(HANDLE hArcData,char *Password); -int PASCAL RARGetDllVersion(); - -#ifdef __cplusplus -} -#endif -*/ - -#pragma pack() diff --git a/src/plugins/unrar/vcpkg.json b/src/plugins/unrar/vcpkg.json new file mode 100644 index 000000000..ab8acbd82 --- /dev/null +++ b/src/plugins/unrar/vcpkg.json @@ -0,0 +1,6 @@ +{ + "dependencies": [ + "unrar" + ], + "builtin-baseline": "6f29f12e82a8293156836ad81cc9bf5af41fe836" +} diff --git a/src/plugins/unrar/vcxproj/unrar.vcxproj b/src/plugins/unrar/vcxproj/unrar.vcxproj index d6b217eca..d879a2a48 100644 --- a/src/plugins/unrar/vcxproj/unrar.vcxproj +++ b/src/plugins/unrar/vcxproj/unrar.vcxproj @@ -100,6 +100,11 @@ + + true + true + true + stdcpplatest diff --git a/src/plugins1.cpp b/src/plugins1.cpp index 276235841..04a493a61 100644 --- a/src/plugins1.cpp +++ b/src/plugins1.cpp @@ -2173,11 +2173,27 @@ BOOL CPluginData::InitDLL(HWND parent, BOOL quiet, BOOL waitCursor, BOOL showUns s = buf; } + { + // pridame cestu k pluginu do dll cest (kvuli knihovnam, ktere plugin pouziva) + char path[MAX_PATH]; + strcpy_s(path, s); + char* p = strrchr(path, '\\'); + if (p) + *p = 0; + // path, je to adresar? + DWORD fileAttributes = GetFileAttributes(path); + if (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + SetDllDirectory(path); + } + } + // nacteme DLL HCURSOR oldCur; if (waitCursor) oldCur = SetCursor(LoadCursor(NULL, IDC_WAIT)); DLL = HANDLES(LoadLibrary(s)); + SetDllDirectory(NULL); // vratime dll cesty do puvodniho stavu if (waitCursor) SetCursor(oldCur); if (DLL == NULL) // chyba From 137002d2d4342d4bd0749a50575ba6c10b6fb804 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 12:15:00 +0100 Subject: [PATCH 20/65] updated msbuild, it should now build all projects in the solution --- .github/workflows/ci.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9cbb0fc70..89b1941e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - targetplatform: [x86] # x64, arm64 + targetplatform: [x86, x64] # arm64 steps: - name: Checkout repository @@ -47,7 +47,7 @@ jobs: vcpkg integrate install - name: Build the project - run: msbuild src\vcxproj\salamand.sln /t:Rebuild /p:Configuration=Release + run: msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release /p:BuildProjectReferences=true - name: Compose installation directory run: | @@ -62,6 +62,10 @@ jobs: xcopy /I /Y ${{ github.workspace }}\\src\\plugins\\zip\\zip2sfx\\*.txt ${{ env.OPENSAL_INSTALL_DIR }}plugins\\zip\\zip2sfx xcopy /I /Y ${{ github.workspace }}\\src\\plugins\\zip\\zip2sfx\\*.set ${{ env.OPENSAL_INSTALL_DIR }}plugins\\zip\\zip2sfx + #- name: Build language files + #- name: Build help files + #- name: Build setup.exe package + - name: Finalize installation package uses: actions/upload-artifact@v4 with: From 57b3eaac8ec7f8e428946cb0f307881d2f39d80f Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 12:30:22 +0100 Subject: [PATCH 21/65] fixed msbuild command line --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 89b1941e9..baa0bbc66 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,7 +47,7 @@ jobs: vcpkg integrate install - name: Build the project - run: msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release /p:BuildProjectReferences=true + run: msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release /p:platform=${{ matrix.targetplatform }} - name: Compose installation directory run: | From fb17c3eb2e8524769987c1a4c09c9eb878c444c0 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 12:40:28 +0100 Subject: [PATCH 22/65] msbuild platform argument has to be converted --- .github/workflows/ci.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index baa0bbc66..c39d10f31 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -47,7 +47,14 @@ jobs: vcpkg integrate install - name: Build the project - run: msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release /p:platform=${{ matrix.targetplatform }} + run: | + # translate targetplatform to MSBuild platform + if [ "${{ matrix.targetplatform }}" == "x86" ]; then + PLATFORM="Win32" + else + PLATFORM="${{ matrix.targetplatform }}" + fi + msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release /p:platform=$PLATFORM - name: Compose installation directory run: | From ba77c1053f7970796204fb1c226b5a10b7559348 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 12:49:08 +0100 Subject: [PATCH 23/65] specified build architecture in msbuild setup step --- .github/workflows/ci.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c39d10f31..f3ac3733e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,6 +35,8 @@ jobs: - name: Setup MSBuild uses: microsoft/setup-msbuild@v2 + with: + msbuild-architecture: ${{ matrix.targetplatform }} - name: Setup .NET Framework SDK uses: actions/setup-dotnet@v2 @@ -48,13 +50,7 @@ jobs: - name: Build the project run: | - # translate targetplatform to MSBuild platform - if [ "${{ matrix.targetplatform }}" == "x86" ]; then - PLATFORM="Win32" - else - PLATFORM="${{ matrix.targetplatform }}" - fi - msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release /p:platform=$PLATFORM + msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release - name: Compose installation directory run: | From f4d96c7eb31a6ce34e2c8f43c6ab1e2b19bee262 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 13:17:20 +0100 Subject: [PATCH 24/65] added utils to the msbuild compilation --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f3ac3733e..35b7b1a55 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,7 +50,8 @@ jobs: - name: Build the project run: | - msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release + msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release /p:platform=${{ matrix.targetplatform }} + msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration="Utils (Release)" /p:platform=${{ matrix.targetplatform }} - name: Compose installation directory run: | From c9e030254d92f92a779d2ef10e08dd0202088f60 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 13:28:27 +0100 Subject: [PATCH 25/65] corrected platform name for msbuild --- .github/workflows/ci.yml | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 35b7b1a55..1249f3729 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,8 +50,13 @@ jobs: - name: Build the project run: | - msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release /p:platform=${{ matrix.targetplatform }} - msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration="Utils (Release)" /p:platform=${{ matrix.targetplatform }} + if "%matrix_targetplatform%" == "x86" ( + set platform=Win32 + ) else ( + set platform=%matrix_targetplatform% + ) + msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release /p:platform=%platform% + msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration="Utils (Release)" /p:platform=%platform% - name: Compose installation directory run: | From e5df0fcc882da6df8cccd4f5bdcec7573da5ba88 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 13:32:42 +0100 Subject: [PATCH 26/65] another correction hint for msbuild --- .github/workflows/ci.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1249f3729..85034b073 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,13 +50,13 @@ jobs: - name: Build the project run: | - if "%matrix_targetplatform%" == "x86" ( - set platform=Win32 - ) else ( - set platform=%matrix_targetplatform% - ) - msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release /p:platform=%platform% - msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration="Utils (Release)" /p:platform=%platform% + if ($env:matrix_targetplatform -eq "x86") { + $platform = "Win32" + } else { + $platform = $env:matrix_targetplatform + } + msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release /p:platform=$platform + msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration="Utils (Release)" /p:platform=$platform - name: Compose installation directory run: | From 7fb605f25d0db3e82fa061d1b7a3e9cbd719e0b7 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 13:36:58 +0100 Subject: [PATCH 27/65] one more msbuild correction --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 85034b073..e70f84091 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,10 +50,9 @@ jobs: - name: Build the project run: | + $platform = $env:matrix_targetplatform if ($env:matrix_targetplatform -eq "x86") { $platform = "Win32" - } else { - $platform = $env:matrix_targetplatform } msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release /p:platform=$platform msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration="Utils (Release)" /p:platform=$platform From 14a6a29eeddb091b5433eff5538a49923d85962b Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 1 Feb 2025 13:39:47 +0100 Subject: [PATCH 28/65] again, one more msbuild correction --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e70f84091..d8ba45a8b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,8 +50,8 @@ jobs: - name: Build the project run: | - $platform = $env:matrix_targetplatform - if ($env:matrix_targetplatform -eq "x86") { + $platform = "${{ matrix.targetplatform }}" + if ("${{ matrix.targetplatform }}" -eq "x86") { $platform = "Win32" } msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration=Release /p:platform=$platform From 09678d26eecfd67e4c32f6092581bfce3e7fc003 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 11:31:22 +0100 Subject: [PATCH 29/65] attach redistributable files to the installation and temporarily disable project build --- .github/workflows/ci.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8ba45a8b..736ad424d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -49,6 +49,7 @@ jobs: vcpkg integrate install - name: Build the project + if: false run: | $platform = "${{ matrix.targetplatform }}" if ("${{ matrix.targetplatform }}" -eq "x86") { @@ -70,6 +71,14 @@ jobs: xcopy /I /Y ${{ github.workspace }}\\src\\plugins\\zip\\zip2sfx\\*.txt ${{ env.OPENSAL_INSTALL_DIR }}plugins\\zip\\zip2sfx xcopy /I /Y ${{ github.workspace }}\\src\\plugins\\zip\\zip2sfx\\*.set ${{ env.OPENSAL_INSTALL_DIR }}plugins\\zip\\zip2sfx + - name: Install redistributable files + shell: pwsh + run: | + $vc_redist_path = Get-ChildItem -Path "${env:VCToolsRedistDir}${{ matrix.targetplatform }}\\Microsoft.VC???.CRT" | Select-Object -ExpandProperty FullName + Copy-Item -Path "$vc_redist_path\\concrt???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force + Copy-Item -Path "$vc_redist_path\\msvcp???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force + Copy-Item -Path "$vc_redist_path\\vcruntime???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force + #- name: Build language files #- name: Build help files #- name: Build setup.exe package From a88a4189bec71e5c963d73930acea1f3594e42be Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 11:34:09 +0100 Subject: [PATCH 30/65] disabled a few more build steps --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 736ad424d..cfb50d35a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,6 +39,7 @@ jobs: msbuild-architecture: ${{ matrix.targetplatform }} - name: Setup .NET Framework SDK + if: false uses: actions/setup-dotnet@v2 with: dotnet-version: '6.0.x' # required for pe-viewer @@ -59,6 +60,7 @@ jobs: msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration="Utils (Release)" /p:platform=$platform - name: Compose installation directory + if: false run: | pushd ${{ env.OPENSAL_BUILD_DIR }}salamander\\${{ env.BUILD_CONFIGURATION }}_${{ matrix.targetplatform }} robocopy . ${{ env.OPENSAL_INSTALL_DIR }} *.exe *.dll *.spl *.slg /S From c597094ea41d3eabb13aaefc4c1142000ddb073b Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 11:48:29 +0100 Subject: [PATCH 31/65] used vcwhere tool to find visual studio install dir --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cfb50d35a..e66fa289b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,7 +76,9 @@ jobs: - name: Install redistributable files shell: pwsh run: | - $vc_redist_path = Get-ChildItem -Path "${env:VCToolsRedistDir}${{ matrix.targetplatform }}\\Microsoft.VC???.CRT" | Select-Object -ExpandProperty FullName + $vswhere_path = "${env:ProgramFiles(x86)}\\Microsoft Visual Studio\\Installer\\vswhere.exe" + $vs_install_path = & $vswhere_path -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath + $vc_redist_path = Get-ChildItem -Path "$vs_install_path\\VC\\Redist\\MSVC" -Recurse -Filter "Microsoft.VC???.CRT" | Select-Object -ExpandProperty FullName Copy-Item -Path "$vc_redist_path\\concrt???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force Copy-Item -Path "$vc_redist_path\\msvcp???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force Copy-Item -Path "$vc_redist_path\\vcruntime???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force From ea4130f76ecede1dc7a5886b0c4cd9e9087297ec Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 12:12:34 +0100 Subject: [PATCH 32/65] updated redistributables install step --- .github/workflows/ci.yml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e66fa289b..a521d715b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,12 +76,21 @@ jobs: - name: Install redistributable files shell: pwsh run: | + # find Visual Studio install path with vswhere tool $vswhere_path = "${env:ProgramFiles(x86)}\\Microsoft Visual Studio\\Installer\\vswhere.exe" $vs_install_path = & $vswhere_path -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath - $vc_redist_path = Get-ChildItem -Path "$vs_install_path\\VC\\Redist\\MSVC" -Recurse -Filter "Microsoft.VC???.CRT" | Select-Object -ExpandProperty FullName - Copy-Item -Path "$vc_redist_path\\concrt???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force - Copy-Item -Path "$vc_redist_path\\msvcp???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force - Copy-Item -Path "$vc_redist_path\\vcruntime???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force + # find out VC toolset version + $vs_vctoolset_path = "$vs_install_path\\VC\\Auxiliary\\Build" + $vctoolset_file = Get-ChildItem -Path $mydir -Filter "Microsoft.VCToolsVersion.v*.default.txt" | Select-Object -ExpandProperty Name + if ($fileName -match "VCToolsVersion\.v(\d+)\.default\.txt") { + $vctoolset = $matches[1] + $vctoolsver = Get-Content -Path "$vs_vctoolset_path\\Microsoft.VCToolsVersion.v${vctoolset}.default.txt" -Raw + # copy redistributable files to the installation directory + $vc_redist_path = "$vs_install_path\\VC\\Redist\\MSVC\\$vctoolsver\\${{ matrix.targetplatform }}\\Microsoft.VC${vctoolset}.CRT" + Copy-Item -Path "$vc_redist_path\\concrt???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force + Copy-Item -Path "$vc_redist_path\\msvcp???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force + Copy-Item -Path "$vc_redist_path\\vcruntime???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force + } #- name: Build language files #- name: Build help files From b7504eefed72ad12f3497cd889e6b879e0de2c05 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 12:14:30 +0100 Subject: [PATCH 33/65] one more correction --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a521d715b..f22803101 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,9 +87,9 @@ jobs: $vctoolsver = Get-Content -Path "$vs_vctoolset_path\\Microsoft.VCToolsVersion.v${vctoolset}.default.txt" -Raw # copy redistributable files to the installation directory $vc_redist_path = "$vs_install_path\\VC\\Redist\\MSVC\\$vctoolsver\\${{ matrix.targetplatform }}\\Microsoft.VC${vctoolset}.CRT" - Copy-Item -Path "$vc_redist_path\\concrt???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force - Copy-Item -Path "$vc_redist_path\\msvcp???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force - Copy-Item -Path "$vc_redist_path\\vcruntime???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force + Copy-Item -Path "$vc_redist_path\\concrt${vctoolset}.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force + Copy-Item -Path "$vc_redist_path\\msvcp${vctoolset}.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force + Copy-Item -Path "$vc_redist_path\\vcruntime${vctoolset}.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force } #- name: Build language files From 5d0f93cb63d6d644f9f0c72f5b5d9564a4b9afb7 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 12:18:05 +0100 Subject: [PATCH 34/65] pwsh in verbose mode --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f22803101..e4f83d7f3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,6 +76,7 @@ jobs: - name: Install redistributable files shell: pwsh run: | + $VerbosePreference = "Continue" # find Visual Studio install path with vswhere tool $vswhere_path = "${env:ProgramFiles(x86)}\\Microsoft Visual Studio\\Installer\\vswhere.exe" $vs_install_path = & $vswhere_path -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath From cee4330e8dc92e8dd7d0bbade0250bbbef8ee5ea Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 12:20:46 +0100 Subject: [PATCH 35/65] pwsh in debug mode --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e4f83d7f3..8762c1d24 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -76,7 +76,7 @@ jobs: - name: Install redistributable files shell: pwsh run: | - $VerbosePreference = "Continue" + Set-PSDebug -Trace 2 # find Visual Studio install path with vswhere tool $vswhere_path = "${env:ProgramFiles(x86)}\\Microsoft Visual Studio\\Installer\\vswhere.exe" $vs_install_path = & $vswhere_path -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath From 62dbb1411a1f888f87d862a3a69b8aa5b1c1d6bc Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 12:23:44 +0100 Subject: [PATCH 36/65] one more correction in pwsh script --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8762c1d24..8acdadfc7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,13 +77,14 @@ jobs: shell: pwsh run: | Set-PSDebug -Trace 2 + $FormatEnumerationLimit = -1 # find Visual Studio install path with vswhere tool $vswhere_path = "${env:ProgramFiles(x86)}\\Microsoft Visual Studio\\Installer\\vswhere.exe" $vs_install_path = & $vswhere_path -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath # find out VC toolset version $vs_vctoolset_path = "$vs_install_path\\VC\\Auxiliary\\Build" $vctoolset_file = Get-ChildItem -Path $mydir -Filter "Microsoft.VCToolsVersion.v*.default.txt" | Select-Object -ExpandProperty Name - if ($fileName -match "VCToolsVersion\.v(\d+)\.default\.txt") { + if ($fileName -match "Microsoft.VCToolsVersion\.v(\d+)\.default\.txt") { $vctoolset = $matches[1] $vctoolsver = Get-Content -Path "$vs_vctoolset_path\\Microsoft.VCToolsVersion.v${vctoolset}.default.txt" -Raw # copy redistributable files to the installation directory From cfb2cde876bc938fd4897e0eb8176566bb2c5ea1 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 12:30:17 +0100 Subject: [PATCH 37/65] fixed a variable name --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8acdadfc7..ffde52c22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,13 +77,12 @@ jobs: shell: pwsh run: | Set-PSDebug -Trace 2 - $FormatEnumerationLimit = -1 # find Visual Studio install path with vswhere tool $vswhere_path = "${env:ProgramFiles(x86)}\\Microsoft Visual Studio\\Installer\\vswhere.exe" $vs_install_path = & $vswhere_path -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath # find out VC toolset version $vs_vctoolset_path = "$vs_install_path\\VC\\Auxiliary\\Build" - $vctoolset_file = Get-ChildItem -Path $mydir -Filter "Microsoft.VCToolsVersion.v*.default.txt" | Select-Object -ExpandProperty Name + $vctoolset_file = Get-ChildItem -Path $vs_vctoolset_path -Filter "Microsoft.VCToolsVersion.v*.default.txt" | Select-Object -ExpandProperty Name if ($fileName -match "Microsoft.VCToolsVersion\.v(\d+)\.default\.txt") { $vctoolset = $matches[1] $vctoolsver = Get-Content -Path "$vs_vctoolset_path\\Microsoft.VCToolsVersion.v${vctoolset}.default.txt" -Raw From b070571ae40c662cb9e453747bd51acf06db3bce Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 12:42:25 +0100 Subject: [PATCH 38/65] a few more corrections --- .github/workflows/ci.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ffde52c22..9d1460238 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,14 +83,14 @@ jobs: # find out VC toolset version $vs_vctoolset_path = "$vs_install_path\\VC\\Auxiliary\\Build" $vctoolset_file = Get-ChildItem -Path $vs_vctoolset_path -Filter "Microsoft.VCToolsVersion.v*.default.txt" | Select-Object -ExpandProperty Name - if ($fileName -match "Microsoft.VCToolsVersion\.v(\d+)\.default\.txt") { + if ($vctoolset_file -match "Microsoft.VCToolsVersion\.v(\d+)\.default\.txt") { $vctoolset = $matches[1] - $vctoolsver = Get-Content -Path "$vs_vctoolset_path\\Microsoft.VCToolsVersion.v${vctoolset}.default.txt" -Raw + $vctoolsver = (Get-Content -Path "$vs_vctoolset_path\\Microsoft.VCToolsVersion.v${vctoolset}.default.txt" -Raw).Trim() # copy redistributable files to the installation directory $vc_redist_path = "$vs_install_path\\VC\\Redist\\MSVC\\$vctoolsver\\${{ matrix.targetplatform }}\\Microsoft.VC${vctoolset}.CRT" - Copy-Item -Path "$vc_redist_path\\concrt${vctoolset}.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force - Copy-Item -Path "$vc_redist_path\\msvcp${vctoolset}.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force - Copy-Item -Path "$vc_redist_path\\vcruntime${vctoolset}.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force + Copy-Item -Path "$vc_redist_path\\concrt???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force + Copy-Item -Path "$vc_redist_path\\msvcp???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force + Copy-Item -Path "$vc_redist_path\\vcruntime???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force } #- name: Build language files From e19b78b508ccdce84daac4c4187eba4857a51167 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 12:46:19 +0100 Subject: [PATCH 39/65] added a few debug helps --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9d1460238..f2e48c690 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,7 +82,9 @@ jobs: $vs_install_path = & $vswhere_path -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath # find out VC toolset version $vs_vctoolset_path = "$vs_install_path\\VC\\Auxiliary\\Build" - $vctoolset_file = Get-ChildItem -Path $vs_vctoolset_path -Filter "Microsoft.VCToolsVersion.v*.default.txt" | Select-Object -ExpandProperty Name + dir $vs_vctoolset_path + $vctoolset_file = Get-ChildItem -Path $vs_vctoolset_path -Filter "Microsoft.VCToolsVersion.v???.default.txt" | Select-Object -ExpandProperty Name + echo $vctoolset_file if ($vctoolset_file -match "Microsoft.VCToolsVersion\.v(\d+)\.default\.txt") { $vctoolset = $matches[1] $vctoolsver = (Get-Content -Path "$vs_vctoolset_path\\Microsoft.VCToolsVersion.v${vctoolset}.default.txt" -Raw).Trim() From 912bf9696e33757befe6e1d51c1bf52f3afe97e3 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 12:51:22 +0100 Subject: [PATCH 40/65] few more corrections --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f2e48c690..73a87c93c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,11 +83,11 @@ jobs: # find out VC toolset version $vs_vctoolset_path = "$vs_install_path\\VC\\Auxiliary\\Build" dir $vs_vctoolset_path - $vctoolset_file = Get-ChildItem -Path $vs_vctoolset_path -Filter "Microsoft.VCToolsVersion.v???.default.txt" | Select-Object -ExpandProperty Name + $vctoolset_file = Get-ChildItem -Path $vs_vctoolset_path -Filter "Microsoft.VCRedistVersion.v???.default.txt" | Select-Object -ExpandProperty Name echo $vctoolset_file - if ($vctoolset_file -match "Microsoft.VCToolsVersion\.v(\d+)\.default\.txt") { + if ($vctoolset_file -match "Microsoft.VCRedistVersion\.v(\d+)\.default\.txt") { $vctoolset = $matches[1] - $vctoolsver = (Get-Content -Path "$vs_vctoolset_path\\Microsoft.VCToolsVersion.v${vctoolset}.default.txt" -Raw).Trim() + $vctoolsver = (Get-Content -Path "$vs_vctoolset_path\\Microsoft.VCRedistVersion.default.txt" -Raw).Trim() # copy redistributable files to the installation directory $vc_redist_path = "$vs_install_path\\VC\\Redist\\MSVC\\$vctoolsver\\${{ matrix.targetplatform }}\\Microsoft.VC${vctoolset}.CRT" Copy-Item -Path "$vc_redist_path\\concrt???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force From 172f6c308afcf960df2256fbc63debe694cd96a2 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 12:53:13 +0100 Subject: [PATCH 41/65] fixed a typo --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 73a87c93c..18fd6eb4c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,9 +83,9 @@ jobs: # find out VC toolset version $vs_vctoolset_path = "$vs_install_path\\VC\\Auxiliary\\Build" dir $vs_vctoolset_path - $vctoolset_file = Get-ChildItem -Path $vs_vctoolset_path -Filter "Microsoft.VCRedistVersion.v???.default.txt" | Select-Object -ExpandProperty Name + $vctoolset_file = Get-ChildItem -Path $vs_vctoolset_path -Filter "Microsoft.VCRedistVersion.v???.default.props" | Select-Object -ExpandProperty Name echo $vctoolset_file - if ($vctoolset_file -match "Microsoft.VCRedistVersion\.v(\d+)\.default\.txt") { + if ($vctoolset_file -match "Microsoft.VCRedistVersion\.v(\d+)\.default\.props") { $vctoolset = $matches[1] $vctoolsver = (Get-Content -Path "$vs_vctoolset_path\\Microsoft.VCRedistVersion.default.txt" -Raw).Trim() # copy redistributable files to the installation directory From e18c97f4bf54fcf3dd0f2ef4bef989e3de81caa2 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 13:54:50 +0100 Subject: [PATCH 42/65] added build step for help files --- .github/workflows/ci.yml | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 18fd6eb4c..20465a862 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -45,6 +45,7 @@ jobs: dotnet-version: '6.0.x' # required for pe-viewer - name: Setup vcpkg + if: false run: | bootstrap-vcpkg vcpkg integrate install @@ -74,17 +75,15 @@ jobs: xcopy /I /Y ${{ github.workspace }}\\src\\plugins\\zip\\zip2sfx\\*.set ${{ env.OPENSAL_INSTALL_DIR }}plugins\\zip\\zip2sfx - name: Install redistributable files + if: false shell: pwsh run: | - Set-PSDebug -Trace 2 # find Visual Studio install path with vswhere tool $vswhere_path = "${env:ProgramFiles(x86)}\\Microsoft Visual Studio\\Installer\\vswhere.exe" $vs_install_path = & $vswhere_path -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath # find out VC toolset version $vs_vctoolset_path = "$vs_install_path\\VC\\Auxiliary\\Build" - dir $vs_vctoolset_path $vctoolset_file = Get-ChildItem -Path $vs_vctoolset_path -Filter "Microsoft.VCRedistVersion.v???.default.props" | Select-Object -ExpandProperty Name - echo $vctoolset_file if ($vctoolset_file -match "Microsoft.VCRedistVersion\.v(\d+)\.default\.props") { $vctoolset = $matches[1] $vctoolsver = (Get-Content -Path "$vs_vctoolset_path\\Microsoft.VCRedistVersion.default.txt" -Raw).Trim() @@ -95,8 +94,37 @@ jobs: Copy-Item -Path "$vc_redist_path\\vcruntime???.dll" -Destination "${env:OPENSAL_INSTALL_DIR}" -Force } + - name: Build help files + shell: pwsh + run: | + # help compiler should be available + $hhc_exe = "${env:ProgramFiles(x86)}\\HTML Help Workshop\\hhc.exe" + # create path where help files will be installed + $help_dir = "${env:OPENSAL_INSTALL_DIR}\\help\\english" + New-Item -ItemType Directory -Path $help_dir -Force | Out-Null + # compile main help file + pushd help\\src + & $hhc_exe salamand.hhp + Move-Item -Path "salamand.chm" -Destination $help_dir -Force + popd + # compile help for plugins + $plugin_dirs = Get-ChildItem -Path "src\\plugins" -Directory | Select-Object -ExpandProperty FullName + foreach ($subdir in $plugin_dirs) { + $plugin_name = Split-Path $subdir -Leaf + $help_src = "$subdir\\help" + # pak plugin has different directory structure + if ($plugin_name -eq "pak") { + $help_src = "$subdir\\spl\\help" + } + if (Test-Path $help_src) { + pushd $help_src + & $hhc_exe "$plugin_name.hhp" + Move-Item -Path "plugin_name.chm" -Destination $help_dir -Force + popd + } + } + #- name: Build language files - #- name: Build help files #- name: Build setup.exe package - name: Finalize installation package From 3ee0c974b72686a6ecd57eab5ef2ac6762fe98b0 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 13:57:22 +0100 Subject: [PATCH 43/65] fixed a typo --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 20465a862..92a38b6ae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -119,7 +119,7 @@ jobs: if (Test-Path $help_src) { pushd $help_src & $hhc_exe "$plugin_name.hhp" - Move-Item -Path "plugin_name.chm" -Destination $help_dir -Force + Move-Item -Path "$plugin_name.chm" -Destination $help_dir -Force popd } } From a9912e5daa92c84dd4ea7df977787137301d7af1 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 14:01:23 +0100 Subject: [PATCH 44/65] added a condition --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92a38b6ae..1fe33fe19 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -118,8 +118,10 @@ jobs: } if (Test-Path $help_src) { pushd $help_src - & $hhc_exe "$plugin_name.hhp" - Move-Item -Path "$plugin_name.chm" -Destination $help_dir -Force + if (Test-Path "$plugin_name.hhp") { + & $hhc_exe "$plugin_name.hhp" + Move-Item -Path "$plugin_name.chm" -Destination $help_dir -Force + } popd } } From b6081f524e1fe2df74fe31ecd7145b1c2cb61520 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 14:09:02 +0100 Subject: [PATCH 45/65] pwsh in debug mode --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1fe33fe19..1f9d05a3c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -97,6 +97,7 @@ jobs: - name: Build help files shell: pwsh run: | + Set-PSDebug -Trace 2 # help compiler should be available $hhc_exe = "${env:ProgramFiles(x86)}\\HTML Help Workshop\\hhc.exe" # create path where help files will be installed From b88549ab4dc2fb97f7f20a23bff47408a69ba5db Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 14:15:00 +0100 Subject: [PATCH 46/65] added exit code checks --- .github/workflows/ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f9d05a3c..5847214ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,6 +106,7 @@ jobs: # compile main help file pushd help\\src & $hhc_exe salamand.hhp + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Move-Item -Path "salamand.chm" -Destination $help_dir -Force popd # compile help for plugins @@ -121,6 +122,7 @@ jobs: pushd $help_src if (Test-Path "$plugin_name.hhp") { & $hhc_exe "$plugin_name.hhp" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Move-Item -Path "$plugin_name.chm" -Destination $help_dir -Force } popd From e6caf76aefe4c2617c2207f05e3f2d5f61cd079a Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 14:21:23 +0100 Subject: [PATCH 47/65] fixed hhc return code issue --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5847214ad..ae6b42661 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -106,7 +106,6 @@ jobs: # compile main help file pushd help\\src & $hhc_exe salamand.hhp - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Move-Item -Path "salamand.chm" -Destination $help_dir -Force popd # compile help for plugins @@ -122,12 +121,13 @@ jobs: pushd $help_src if (Test-Path "$plugin_name.hhp") { & $hhc_exe "$plugin_name.hhp" - if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Move-Item -Path "$plugin_name.chm" -Destination $help_dir -Force } popd } } + # help compiler exists with code 1 even if it was successful + $global:LASTEXITCODE = 0 #- name: Build language files #- name: Build setup.exe package From bbe95f5e35e5b97fc62131377db212efbbdd08f9 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sun, 2 Feb 2025 14:24:03 +0100 Subject: [PATCH 48/65] cleanup, and reenabled all build steps --- .github/workflows/ci.yml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ae6b42661..90e374cf5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,19 +39,16 @@ jobs: msbuild-architecture: ${{ matrix.targetplatform }} - name: Setup .NET Framework SDK - if: false uses: actions/setup-dotnet@v2 with: dotnet-version: '6.0.x' # required for pe-viewer - name: Setup vcpkg - if: false run: | bootstrap-vcpkg vcpkg integrate install - name: Build the project - if: false run: | $platform = "${{ matrix.targetplatform }}" if ("${{ matrix.targetplatform }}" -eq "x86") { @@ -61,7 +58,6 @@ jobs: msbuild src\vcxproj\salamand.sln /t:Build /p:Configuration="Utils (Release)" /p:platform=$platform - name: Compose installation directory - if: false run: | pushd ${{ env.OPENSAL_BUILD_DIR }}salamander\\${{ env.BUILD_CONFIGURATION }}_${{ matrix.targetplatform }} robocopy . ${{ env.OPENSAL_INSTALL_DIR }} *.exe *.dll *.spl *.slg /S @@ -75,7 +71,6 @@ jobs: xcopy /I /Y ${{ github.workspace }}\\src\\plugins\\zip\\zip2sfx\\*.set ${{ env.OPENSAL_INSTALL_DIR }}plugins\\zip\\zip2sfx - name: Install redistributable files - if: false shell: pwsh run: | # find Visual Studio install path with vswhere tool @@ -97,7 +92,6 @@ jobs: - name: Build help files shell: pwsh run: | - Set-PSDebug -Trace 2 # help compiler should be available $hhc_exe = "${env:ProgramFiles(x86)}\\HTML Help Workshop\\hhc.exe" # create path where help files will be installed From 27bdb3361cfcac8c4bd6fa370b98caf0f2f7bec8 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Mon, 17 Feb 2025 19:36:45 +0100 Subject: [PATCH 49/65] changed dependency on some 3-rd party libraries to vcpkg --- src/common/dep/bzip2/LICENSE | 42 - src/common/dep/bzip2/blocksort.c | 1094 ---------- src/common/dep/bzip2/bzlib.c | 1572 -------------- src/common/dep/bzip2/bzlib.h | 282 --- src/common/dep/bzip2/bzlib_private.h | 509 ----- src/common/dep/bzip2/compress.c | 672 ------ src/common/dep/bzip2/crctable.c | 104 - src/common/dep/bzip2/decompress.c | 646 ------ src/common/dep/bzip2/huffman.c | 205 -- src/common/dep/bzip2/internal_e.cpp | 8 - src/common/dep/bzip2/randtable.c | 84 - src/common/dep/nanosvg/nanosvg.h | 2849 -------------------------- src/common/dep/nanosvg/nanosvgrast.h | 1556 -------------- src/common/dep/zlib/README | 115 -- src/common/dep/zlib/adler32.c | 186 -- src/common/dep/zlib/compress.c | 86 - src/common/dep/zlib/crc32.c | 442 ---- src/common/dep/zlib/crc32.h | 441 ---- src/common/dep/zlib/deflate.c | 2163 ------------------- src/common/dep/zlib/deflate.h | 349 ---- src/common/dep/zlib/gzguts.h | 218 -- src/common/dep/zlib/inffast.c | 323 --- src/common/dep/zlib/inffast.h | 11 - src/common/dep/zlib/inffixed.h | 94 - src/common/dep/zlib/inflate.c | 1561 -------------- src/common/dep/zlib/inflate.h | 125 -- src/common/dep/zlib/inftrees.c | 304 --- src/common/dep/zlib/inftrees.h | 62 - src/common/dep/zlib/trees.c | 1203 ----------- src/common/dep/zlib/trees.h | 128 -- src/common/dep/zlib/zconf.h | 534 ----- src/common/dep/zlib/zlib.h | 1912 ----------------- src/common/dep/zlib/zutil.c | 325 --- src/common/dep/zlib/zutil.h | 271 --- src/salzlib.cpp | 2 +- src/svg.cpp | 4 +- src/toolbar4.cpp | 4 +- src/vcpkg.json | 8 + src/vcxproj/salamand.sln | 1 + src/vcxproj/salamand.vcxproj | 231 +-- src/vcxproj/salamand.vcxproj.filters | 63 - 41 files changed, 31 insertions(+), 20758 deletions(-) delete mode 100644 src/common/dep/bzip2/LICENSE delete mode 100644 src/common/dep/bzip2/blocksort.c delete mode 100644 src/common/dep/bzip2/bzlib.c delete mode 100644 src/common/dep/bzip2/bzlib.h delete mode 100644 src/common/dep/bzip2/bzlib_private.h delete mode 100644 src/common/dep/bzip2/compress.c delete mode 100644 src/common/dep/bzip2/crctable.c delete mode 100644 src/common/dep/bzip2/decompress.c delete mode 100644 src/common/dep/bzip2/huffman.c delete mode 100644 src/common/dep/bzip2/internal_e.cpp delete mode 100644 src/common/dep/bzip2/randtable.c delete mode 100644 src/common/dep/nanosvg/nanosvg.h delete mode 100644 src/common/dep/nanosvg/nanosvgrast.h delete mode 100644 src/common/dep/zlib/README delete mode 100644 src/common/dep/zlib/adler32.c delete mode 100644 src/common/dep/zlib/compress.c delete mode 100644 src/common/dep/zlib/crc32.c delete mode 100644 src/common/dep/zlib/crc32.h delete mode 100644 src/common/dep/zlib/deflate.c delete mode 100644 src/common/dep/zlib/deflate.h delete mode 100644 src/common/dep/zlib/gzguts.h delete mode 100644 src/common/dep/zlib/inffast.c delete mode 100644 src/common/dep/zlib/inffast.h delete mode 100644 src/common/dep/zlib/inffixed.h delete mode 100644 src/common/dep/zlib/inflate.c delete mode 100644 src/common/dep/zlib/inflate.h delete mode 100644 src/common/dep/zlib/inftrees.c delete mode 100644 src/common/dep/zlib/inftrees.h delete mode 100644 src/common/dep/zlib/trees.c delete mode 100644 src/common/dep/zlib/trees.h delete mode 100644 src/common/dep/zlib/zconf.h delete mode 100644 src/common/dep/zlib/zlib.h delete mode 100644 src/common/dep/zlib/zutil.c delete mode 100644 src/common/dep/zlib/zutil.h create mode 100644 src/vcpkg.json diff --git a/src/common/dep/bzip2/LICENSE b/src/common/dep/bzip2/LICENSE deleted file mode 100644 index f420cffb6..000000000 --- a/src/common/dep/bzip2/LICENSE +++ /dev/null @@ -1,42 +0,0 @@ - --------------------------------------------------------------------------- - -This program, "bzip2", the associated library "libbzip2", and all -documentation, are copyright (C) 1996-2007 Julian R Seward. All -rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. The origin of this software must not be misrepresented; you must - not claim that you wrote the original software. If you use this - software in a product, an acknowledgment in the product - documentation would be appreciated but is not required. - -3. Altered source versions must be plainly marked as such, and must - not be misrepresented as being the original software. - -4. The name of the author may not be used to endorse or promote - products derived from this software without specific prior written - permission. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS -OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY -DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE -GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -Julian Seward, jseward@bzip.org -bzip2/libbzip2 version 1.0.5 of 10 December 2007 - --------------------------------------------------------------------------- diff --git a/src/common/dep/bzip2/blocksort.c b/src/common/dep/bzip2/blocksort.c deleted file mode 100644 index d0d662cd4..000000000 --- a/src/common/dep/bzip2/blocksort.c +++ /dev/null @@ -1,1094 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Block sorting machinery ---*/ -/*--- blocksort.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - -/*---------------------------------------------*/ -/*--- Fallback O(N log(N)^2) sorting ---*/ -/*--- algorithm, for repetitive blocks ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -__inline__ -void fallbackSimpleSort ( UInt32* fmap, - UInt32* eclass, - Int32 lo, - Int32 hi ) -{ - Int32 i, j, tmp; - UInt32 ec_tmp; - - if (lo == hi) return; - - if (hi - lo > 3) { - for ( i = hi-4; i >= lo; i-- ) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for ( j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4 ) - fmap[j-4] = fmap[j]; - fmap[j-4] = tmp; - } - } - - for ( i = hi-1; i >= lo; i-- ) { - tmp = fmap[i]; - ec_tmp = eclass[tmp]; - for ( j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++ ) - fmap[j-1] = fmap[j]; - fmap[j-1] = tmp; - } -} - - -/*---------------------------------------------*/ -#define fswap(zz1, zz2) \ - { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } - -#define fvswap(zzp1, zzp2, zzn) \ -{ \ - Int32 yyp1 = (zzp1); \ - Int32 yyp2 = (zzp2); \ - Int32 yyn = (zzn); \ - while (yyn > 0) { \ - fswap(fmap[yyp1], fmap[yyp2]); \ - yyp1++; yyp2++; yyn--; \ - } \ -} - - -#define fmin(a,b) ((a) < (b)) ? (a) : (b) - -#define fpush(lz,hz) { stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - sp++; } - -#define fpop(lz,hz) { sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; } - -#define FALLBACK_QSORT_SMALL_THRESH 10 -#define FALLBACK_QSORT_STACK_SIZE 100 - - -static -void fallbackQSort3 ( UInt32* fmap, - UInt32* eclass, - Int32 loSt, - Int32 hiSt ) -{ - Int32 unLo, unHi, ltLo, gtHi, n, m; - Int32 sp, lo, hi; - UInt32 med, r, r3; - Int32 stackLo[FALLBACK_QSORT_STACK_SIZE]; - Int32 stackHi[FALLBACK_QSORT_STACK_SIZE]; - - r = 0; - - sp = 0; - fpush ( loSt, hiSt ); - - while (sp > 0) { - - AssertH ( sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004 ); - - fpop ( lo, hi ); - if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { - fallbackSimpleSort ( fmap, eclass, lo, hi ); - continue; - } - - /* Random partitioning. Median of 3 sometimes fails to - avoid bad cases. Median of 9 seems to help but - looks rather expensive. This too seems to work but - is cheaper. Guidance for the magic constants - 7621 and 32768 is taken from Sedgewick's algorithms - book, chapter 35. - */ - r = ((r * 7621) + 1) % 32768; - r3 = r % 3; - if (r3 == 0) med = eclass[fmap[lo]]; else - if (r3 == 1) med = eclass[fmap[(lo+hi)>>1]]; else - med = eclass[fmap[hi]]; - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (1) { - while (1) { - if (unLo > unHi) break; - n = (Int32)eclass[fmap[unLo]] - (Int32)med; - if (n == 0) { - fswap(fmap[unLo], fmap[ltLo]); - ltLo++; unLo++; - continue; - }; - if (n > 0) break; - unLo++; - } - while (1) { - if (unLo > unHi) break; - n = (Int32)eclass[fmap[unHi]] - (Int32)med; - if (n == 0) { - fswap(fmap[unHi], fmap[gtHi]); - gtHi--; unHi--; - continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) break; - fswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; - } - - AssertD ( unHi == unLo-1, "fallbackQSort3(2)" ); - - if (gtHi < ltLo) continue; - - n = fmin(ltLo-lo, unLo-ltLo); fvswap(lo, unLo-n, n); - m = fmin(hi-gtHi, gtHi-unHi); fvswap(unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - if (n - lo > hi - m) { - fpush ( lo, n ); - fpush ( m, hi ); - } else { - fpush ( m, hi ); - fpush ( lo, n ); - } - } -} - -#undef fmin -#undef fpush -#undef fpop -#undef fswap -#undef fvswap -#undef FALLBACK_QSORT_SMALL_THRESH -#undef FALLBACK_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - nblock > 0 - eclass exists for [0 .. nblock-1] - ((UChar*)eclass) [0 .. nblock-1] holds block - ptr exists for [0 .. nblock-1] - - Post: - ((UChar*)eclass) [0 .. nblock-1] holds block - All other areas of eclass destroyed - fmap [0 .. nblock-1] holds sorted order - bhtab [ 0 .. 2+(nblock/32) ] destroyed -*/ - -#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) -#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) -#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) -#define WORD_BH(zz) bhtab[(zz) >> 5] -#define UNALIGNED_BH(zz) ((zz) & 0x01f) - -static -void fallbackSort ( UInt32* fmap, - UInt32* eclass, - UInt32* bhtab, - Int32 nblock, - Int32 verb ) -{ - Int32 ftab[257]; - Int32 ftabCopy[256]; - Int32 H, i, j, k, l, r, cc, cc1; - Int32 nNotDone; - Int32 nBhtab; - UChar* eclass8 = (UChar*)eclass; - - /*-- - Initial 1-char radix sort to generate - initial fmap and initial BH bits. - --*/ - if (verb >= 4) - VPrintf0 ( " bucket sorting ...\n" ); - for (i = 0; i < 257; i++) ftab[i] = 0; - for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; - for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; - for (i = 1; i < 257; i++) ftab[i] += ftab[i-1]; - - for (i = 0; i < nblock; i++) { - j = eclass8[i]; - k = ftab[j] - 1; - ftab[j] = k; - fmap[k] = i; - } - - nBhtab = 2 + (nblock / 32); - for (i = 0; i < nBhtab; i++) bhtab[i] = 0; - for (i = 0; i < 256; i++) SET_BH(ftab[i]); - - /*-- - Inductively refine the buckets. Kind-of an - "exponential radix sort" (!), inspired by the - Manber-Myers suffix array construction algorithm. - --*/ - - /*-- set sentinel bits for block-end detection --*/ - for (i = 0; i < 32; i++) { - SET_BH(nblock + 2*i); - CLEAR_BH(nblock + 2*i + 1); - } - - /*-- the log(N) loop --*/ - H = 1; - while (1) { - - if (verb >= 4) - VPrintf1 ( " depth %6d has ", H ); - - j = 0; - for (i = 0; i < nblock; i++) { - if (ISSET_BH(i)) j = i; - k = fmap[i] - H; if (k < 0) k += nblock; - eclass[k] = j; - } - - nNotDone = 0; - r = -1; - while (1) { - - /*-- find the next non-singleton bucket --*/ - k = r + 1; - while (ISSET_BH(k) && UNALIGNED_BH(k)) k++; - if (ISSET_BH(k)) { - while (WORD_BH(k) == 0xffffffff) k += 32; - while (ISSET_BH(k)) k++; - } - l = k - 1; - if (l >= nblock) break; - while (!ISSET_BH(k) && UNALIGNED_BH(k)) k++; - if (!ISSET_BH(k)) { - while (WORD_BH(k) == 0x00000000) k += 32; - while (!ISSET_BH(k)) k++; - } - r = k - 1; - if (r >= nblock) break; - - /*-- now [l, r] bracket current bucket --*/ - if (r > l) { - nNotDone += (r - l + 1); - fallbackQSort3 ( fmap, eclass, l, r ); - - /*-- scan bucket and generate header bits-- */ - cc = -1; - for (i = l; i <= r; i++) { - cc1 = eclass[fmap[i]]; - if (cc != cc1) { SET_BH(i); cc = cc1; }; - } - } - } - - if (verb >= 4) - VPrintf1 ( "%6d unresolved strings\n", nNotDone ); - - H *= 2; - if (H > nblock || nNotDone == 0) break; - } - - /*-- - Reconstruct the original block in - eclass8 [0 .. nblock-1], since the - previous phase destroyed it. - --*/ - if (verb >= 4) - VPrintf0 ( " reconstructing block ...\n" ); - j = 0; - for (i = 0; i < nblock; i++) { - while (ftabCopy[j] == 0) j++; - ftabCopy[j]--; - eclass8[fmap[i]] = (UChar)j; - } - AssertH ( j < 256, 1005 ); -} - -#undef SET_BH -#undef CLEAR_BH -#undef ISSET_BH -#undef WORD_BH -#undef UNALIGNED_BH - - -/*---------------------------------------------*/ -/*--- The main, O(N^2 log(N)) sorting ---*/ -/*--- algorithm. Faster for "normal" ---*/ -/*--- non-repetitive blocks. ---*/ -/*---------------------------------------------*/ - -/*---------------------------------------------*/ -static -__inline__ -Bool mainGtU ( UInt32 i1, - UInt32 i2, - UChar* block, - UInt16* quadrant, - UInt32 nblock, - Int32* budget ) -{ - Int32 k; - UChar c1, c2; - UInt16 s1, s2; - - AssertD ( i1 != i2, "mainGtU" ); - /* 1 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 2 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 3 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 4 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 5 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 6 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 7 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 8 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 9 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 10 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 11 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - /* 12 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - i1++; i2++; - - k = nblock + 8; - - do { - /* 1 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 2 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 3 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 4 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 5 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 6 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 7 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - /* 8 */ - c1 = block[i1]; c2 = block[i2]; - if (c1 != c2) return (c1 > c2); - s1 = quadrant[i1]; s2 = quadrant[i2]; - if (s1 != s2) return (s1 > s2); - i1++; i2++; - - if (i1 >= nblock) i1 -= nblock; - if (i2 >= nblock) i2 -= nblock; - - k -= 8; - (*budget)--; - } - while (k >= 0); - - return False; -} - - -/*---------------------------------------------*/ -/*-- - Knuth's increments seem to work better - than Incerpi-Sedgewick here. Possibly - because the number of elems to sort is - usually small, typically <= 20. ---*/ -static -Int32 incs[14] = { 1, 4, 13, 40, 121, 364, 1093, 3280, - 9841, 29524, 88573, 265720, - 797161, 2391484 }; - -static -void mainSimpleSort ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - Int32 nblock, - Int32 lo, - Int32 hi, - Int32 d, - Int32* budget ) -{ - Int32 i, j, h, bigN, hp; - UInt32 v; - - bigN = hi - lo + 1; - if (bigN < 2) return; - - hp = 0; - while (incs[hp] < bigN) hp++; - hp--; - - for (; hp >= 0; hp--) { - h = incs[hp]; - - i = lo + h; - while (True) { - - /*-- copy 1 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - /*-- copy 2 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - /*-- copy 3 --*/ - if (i > hi) break; - v = ptr[i]; - j = i; - while ( mainGtU ( - ptr[j-h]+d, v+d, block, quadrant, nblock, budget - ) ) { - ptr[j] = ptr[j-h]; - j = j - h; - if (j <= (lo + h - 1)) break; - } - ptr[j] = v; - i++; - - if (*budget < 0) return; - } - } -} - - -/*---------------------------------------------*/ -/*-- - The following is an implementation of - an elegant 3-way quicksort for strings, - described in a paper "Fast Algorithms for - Sorting and Searching Strings", by Robert - Sedgewick and Jon L. Bentley. ---*/ - -#define mswap(zz1, zz2) \ - { Int32 zztmp = zz1; zz1 = zz2; zz2 = zztmp; } - -#define mvswap(zzp1, zzp2, zzn) \ -{ \ - Int32 yyp1 = (zzp1); \ - Int32 yyp2 = (zzp2); \ - Int32 yyn = (zzn); \ - while (yyn > 0) { \ - mswap(ptr[yyp1], ptr[yyp2]); \ - yyp1++; yyp2++; yyn--; \ - } \ -} - -static -__inline__ -UChar mmed3 ( UChar a, UChar b, UChar c ) -{ - UChar t; - if (a > b) { t = a; a = b; b = t; }; - if (b > c) { - b = c; - if (a > b) b = a; - } - return b; -} - -#define mmin(a,b) ((a) < (b)) ? (a) : (b) - -#define mpush(lz,hz,dz) { stackLo[sp] = lz; \ - stackHi[sp] = hz; \ - stackD [sp] = dz; \ - sp++; } - -#define mpop(lz,hz,dz) { sp--; \ - lz = stackLo[sp]; \ - hz = stackHi[sp]; \ - dz = stackD [sp]; } - - -#define mnextsize(az) (nextHi[az]-nextLo[az]) - -#define mnextswap(az,bz) \ - { Int32 tz; \ - tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ - tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ - tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; } - - -#define MAIN_QSORT_SMALL_THRESH 20 -#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) -#define MAIN_QSORT_STACK_SIZE 100 - -static -void mainQSort3 ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - Int32 nblock, - Int32 loSt, - Int32 hiSt, - Int32 dSt, - Int32* budget ) -{ - Int32 unLo, unHi, ltLo, gtHi, n, m, med; - Int32 sp, lo, hi, d; - - Int32 stackLo[MAIN_QSORT_STACK_SIZE]; - Int32 stackHi[MAIN_QSORT_STACK_SIZE]; - Int32 stackD [MAIN_QSORT_STACK_SIZE]; - - Int32 nextLo[3]; - Int32 nextHi[3]; - Int32 nextD [3]; - - sp = 0; - mpush ( loSt, hiSt, dSt ); - - while (sp > 0) { - - AssertH ( sp < MAIN_QSORT_STACK_SIZE - 2, 1001 ); - - mpop ( lo, hi, d ); - if (hi - lo < MAIN_QSORT_SMALL_THRESH || - d > MAIN_QSORT_DEPTH_THRESH) { - mainSimpleSort ( ptr, block, quadrant, nblock, lo, hi, d, budget ); - if (*budget < 0) return; - continue; - } - - med = (Int32) - mmed3 ( block[ptr[ lo ]+d], - block[ptr[ hi ]+d], - block[ptr[ (lo+hi)>>1 ]+d] ); - - unLo = ltLo = lo; - unHi = gtHi = hi; - - while (True) { - while (True) { - if (unLo > unHi) break; - n = ((Int32)block[ptr[unLo]+d]) - med; - if (n == 0) { - mswap(ptr[unLo], ptr[ltLo]); - ltLo++; unLo++; continue; - }; - if (n > 0) break; - unLo++; - } - while (True) { - if (unLo > unHi) break; - n = ((Int32)block[ptr[unHi]+d]) - med; - if (n == 0) { - mswap(ptr[unHi], ptr[gtHi]); - gtHi--; unHi--; continue; - }; - if (n < 0) break; - unHi--; - } - if (unLo > unHi) break; - mswap(ptr[unLo], ptr[unHi]); unLo++; unHi--; - } - - AssertD ( unHi == unLo-1, "mainQSort3(2)" ); - - if (gtHi < ltLo) { - mpush(lo, hi, d+1 ); - continue; - } - - n = mmin(ltLo-lo, unLo-ltLo); mvswap(lo, unLo-n, n); - m = mmin(hi-gtHi, gtHi-unHi); mvswap(unLo, hi-m+1, m); - - n = lo + unLo - ltLo - 1; - m = hi - (gtHi - unHi) + 1; - - nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; - nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; - nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; - - if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); - if (mnextsize(1) < mnextsize(2)) mnextswap(1,2); - if (mnextsize(0) < mnextsize(1)) mnextswap(0,1); - - AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)" ); - AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)" ); - - mpush (nextLo[0], nextHi[0], nextD[0]); - mpush (nextLo[1], nextHi[1], nextD[1]); - mpush (nextLo[2], nextHi[2], nextD[2]); - } -} - -#undef mswap -#undef mvswap -#undef mpush -#undef mpop -#undef mmin -#undef mnextsize -#undef mnextswap -#undef MAIN_QSORT_SMALL_THRESH -#undef MAIN_QSORT_DEPTH_THRESH -#undef MAIN_QSORT_STACK_SIZE - - -/*---------------------------------------------*/ -/* Pre: - nblock > N_OVERSHOOT - block32 exists for [0 .. nblock-1 +N_OVERSHOOT] - ((UChar*)block32) [0 .. nblock-1] holds block - ptr exists for [0 .. nblock-1] - - Post: - ((UChar*)block32) [0 .. nblock-1] holds block - All other areas of block32 destroyed - ftab [0 .. 65536 ] destroyed - ptr [0 .. nblock-1] holds sorted order - if (*budget < 0), sorting was abandoned -*/ - -#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) -#define SETMASK (1 << 21) -#define CLEARMASK (~(SETMASK)) - -static -void mainSort ( UInt32* ptr, - UChar* block, - UInt16* quadrant, - UInt32* ftab, - Int32 nblock, - Int32 verb, - Int32* budget ) -{ - Int32 i, j, k, ss, sb; - Int32 runningOrder[256]; - Bool bigDone[256]; - Int32 copyStart[256]; - Int32 copyEnd [256]; - UChar c1; - Int32 numQSorted; - UInt16 s; - if (verb >= 4) VPrintf0 ( " main sort initialise ...\n" ); - - /*-- set up the 2-byte frequency table --*/ - for (i = 65536; i >= 0; i--) ftab[i] = 0; - - j = block[0] << 8; - i = nblock-1; - for (; i >= 3; i -= 4) { - quadrant[i] = 0; - j = (j >> 8) | ( ((UInt16)block[i]) << 8); - ftab[j]++; - quadrant[i-1] = 0; - j = (j >> 8) | ( ((UInt16)block[i-1]) << 8); - ftab[j]++; - quadrant[i-2] = 0; - j = (j >> 8) | ( ((UInt16)block[i-2]) << 8); - ftab[j]++; - quadrant[i-3] = 0; - j = (j >> 8) | ( ((UInt16)block[i-3]) << 8); - ftab[j]++; - } - for (; i >= 0; i--) { - quadrant[i] = 0; - j = (j >> 8) | ( ((UInt16)block[i]) << 8); - ftab[j]++; - } - - /*-- (emphasises close relationship of block & quadrant) --*/ - for (i = 0; i < BZ_N_OVERSHOOT; i++) { - block [nblock+i] = block[i]; - quadrant[nblock+i] = 0; - } - - if (verb >= 4) VPrintf0 ( " bucket sorting ...\n" ); - - /*-- Complete the initial radix sort --*/ - for (i = 1; i <= 65536; i++) ftab[i] += ftab[i-1]; - - s = block[0] << 8; - i = nblock-1; - for (; i >= 3; i -= 4) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i; - s = (s >> 8) | (block[i-1] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-1; - s = (s >> 8) | (block[i-2] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-2; - s = (s >> 8) | (block[i-3] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i-3; - } - for (; i >= 0; i--) { - s = (s >> 8) | (block[i] << 8); - j = ftab[s] -1; - ftab[s] = j; - ptr[j] = i; - } - - /*-- - Now ftab contains the first loc of every small bucket. - Calculate the running order, from smallest to largest - big bucket. - --*/ - for (i = 0; i <= 255; i++) { - bigDone [i] = False; - runningOrder[i] = i; - } - - { - Int32 vv; - Int32 h = 1; - do h = 3 * h + 1; while (h <= 256); - do { - h = h / 3; - for (i = h; i <= 255; i++) { - vv = runningOrder[i]; - j = i; - while ( BIGFREQ(runningOrder[j-h]) > BIGFREQ(vv) ) { - runningOrder[j] = runningOrder[j-h]; - j = j - h; - if (j <= (h - 1)) goto zero; - } - zero: - runningOrder[j] = vv; - } - } while (h != 1); - } - - /*-- - The main sorting loop. - --*/ - - numQSorted = 0; - - for (i = 0; i <= 255; i++) { - - /*-- - Process big buckets, starting with the least full. - Basically this is a 3-step process in which we call - mainQSort3 to sort the small buckets [ss, j], but - also make a big effort to avoid the calls if we can. - --*/ - ss = runningOrder[i]; - - /*-- - Step 1: - Complete the big bucket [ss] by quicksorting - any unsorted small buckets [ss, j], for j != ss. - Hopefully previous pointer-scanning phases have already - completed many of the small buckets [ss, j], so - we don't have to sort them at all. - --*/ - for (j = 0; j <= 255; j++) { - if (j != ss) { - sb = (ss << 8) + j; - if ( ! (ftab[sb] & SETMASK) ) { - Int32 lo = ftab[sb] & CLEARMASK; - Int32 hi = (ftab[sb+1] & CLEARMASK) - 1; - if (hi > lo) { - if (verb >= 4) - VPrintf4 ( " qsort [0x%x, 0x%x] " - "done %d this %d\n", - ss, j, numQSorted, hi - lo + 1 ); - mainQSort3 ( - ptr, block, quadrant, nblock, - lo, hi, BZ_N_RADIX, budget - ); - numQSorted += (hi - lo + 1); - if (*budget < 0) return; - } - } - ftab[sb] |= SETMASK; - } - } - - AssertH ( !bigDone[ss], 1006 ); - - /*-- - Step 2: - Now scan this big bucket [ss] so as to synthesise the - sorted order for small buckets [t, ss] for all t, - including, magically, the bucket [ss,ss] too. - This will avoid doing Real Work in subsequent Step 1's. - --*/ - { - for (j = 0; j <= 255; j++) { - copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; - copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; - } - for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { - k = ptr[j]-1; if (k < 0) k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[ copyStart[c1]++ ] = k; - } - for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { - k = ptr[j]-1; if (k < 0) k += nblock; - c1 = block[k]; - if (!bigDone[c1]) - ptr[ copyEnd[c1]-- ] = k; - } - } - - AssertH ( (copyStart[ss]-1 == copyEnd[ss]) - || - /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. - Necessity for this case is demonstrated by compressing - a sequence of approximately 48.5 million of character - 251; 1.0.0/1.0.1 will then die here. */ - (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), - 1007 ) - - for (j = 0; j <= 255; j++) ftab[(j << 8) + ss] |= SETMASK; - - /*-- - Step 3: - The [ss] big bucket is now done. Record this fact, - and update the quadrant descriptors. Remember to - update quadrants in the overshoot area too, if - necessary. The "if (i < 255)" test merely skips - this updating for the last bucket processed, since - updating for the last bucket is pointless. - - The quadrant array provides a way to incrementally - cache sort orderings, as they appear, so as to - make subsequent comparisons in fullGtU() complete - faster. For repetitive blocks this makes a big - difference (but not big enough to be able to avoid - the fallback sorting mechanism, exponential radix sort). - - The precise meaning is: at all times: - - for 0 <= i < nblock and 0 <= j <= nblock - - if block[i] != block[j], - - then the relative values of quadrant[i] and - quadrant[j] are meaningless. - - else { - if quadrant[i] < quadrant[j] - then the string starting at i lexicographically - precedes the string starting at j - - else if quadrant[i] > quadrant[j] - then the string starting at j lexicographically - precedes the string starting at i - - else - the relative ordering of the strings starting - at i and j has not yet been determined. - } - --*/ - bigDone[ss] = True; - - if (i < 255) { - Int32 bbStart = ftab[ss << 8] & CLEARMASK; - Int32 bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; - Int32 shifts = 0; - - while ((bbSize >> shifts) > 65534) shifts++; - - for (j = bbSize-1; j >= 0; j--) { - Int32 a2update = ptr[bbStart + j]; - UInt16 qVal = (UInt16)(j >> shifts); - quadrant[a2update] = qVal; - if (a2update < BZ_N_OVERSHOOT) - quadrant[a2update + nblock] = qVal; - } - AssertH ( ((bbSize-1) >> shifts) <= 65535, 1002 ); - } - - } - - if (verb >= 4) - VPrintf3 ( " %d pointers, %d sorted, %d scanned\n", - nblock, numQSorted, nblock - numQSorted ); -} - -#undef BIGFREQ -#undef SETMASK -#undef CLEARMASK - - -/*---------------------------------------------*/ -/* Pre: - nblock > 0 - arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] - ((UChar*)arr2) [0 .. nblock-1] holds block - arr1 exists for [0 .. nblock-1] - - Post: - ((UChar*)arr2) [0 .. nblock-1] holds block - All other areas of block destroyed - ftab [ 0 .. 65536 ] destroyed - arr1 [0 .. nblock-1] holds sorted order -*/ -void BZ2_blockSort ( EState* s ) -{ - UInt32* ptr = s->ptr; - UChar* block = s->block; - UInt32* ftab = s->ftab; - Int32 nblock = s->nblock; - Int32 verb = s->verbosity; - Int32 wfact = s->workFactor; - UInt16* quadrant; - Int32 budget; - Int32 budgetInit; - Int32 i; - - if (nblock < 10000) { - fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); - } else { - /* Calculate the location for quadrant, remembering to get - the alignment right. Assumes that &(block[0]) is at least - 2-byte aligned -- this should be ok since block is really - the first section of arr2. - */ - i = nblock+BZ_N_OVERSHOOT; - if (i & 1) i++; - quadrant = (UInt16*)(&(block[i])); - - /* (wfact-1) / 3 puts the default-factor-30 - transition point at very roughly the same place as - with v0.1 and v0.9.0. - Not that it particularly matters any more, since the - resulting compressed stream is now the same regardless - of whether or not we use the main sort or fallback sort. - */ - if (wfact < 1 ) wfact = 1; - if (wfact > 100) wfact = 100; - budgetInit = nblock * ((wfact-1) / 3); - budget = budgetInit; - - mainSort ( ptr, block, quadrant, ftab, nblock, verb, &budget ); - if (verb >= 3) - VPrintf3 ( " %d work, %d block, ratio %5.2f\n", - budgetInit - budget, - nblock, - (float)(budgetInit - budget) / - (float)(nblock==0 ? 1 : nblock) ); - if (budget < 0) { - if (verb >= 2) - VPrintf0 ( " too repetitive; using fallback" - " sorting algorithm\n" ); - fallbackSort ( s->arr1, s->arr2, ftab, nblock, verb ); - } - } - - s->origPtr = -1; - for (i = 0; i < s->nblock; i++) - if (ptr[i] == 0) - { s->origPtr = i; break; }; - - AssertH( s->origPtr != -1, 1003 ); -} - - -/*-------------------------------------------------------------*/ -/*--- end blocksort.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/src/common/dep/bzip2/bzlib.c b/src/common/dep/bzip2/bzlib.c deleted file mode 100644 index bd358a793..000000000 --- a/src/common/dep/bzip2/bzlib.c +++ /dev/null @@ -1,1572 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Library top-level functions. ---*/ -/*--- bzlib.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - -/* CHANGES - 0.9.0 -- original version. - 0.9.0a/b -- no changes in this file. - 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). - fixed bzWrite/bzRead to ignore zero-length requests. - fixed bzread to correctly handle read requests after EOF. - wrong parameter order in call to bzDecompressInit in - bzBuffToBuffDecompress. Fixed. -*/ - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -/*--- Compression stuff ---*/ -/*---------------------------------------------------*/ - - -/*---------------------------------------------------*/ -#ifndef BZ_NO_STDIO -void BZ2_bz__AssertH__fail ( int errcode ) -{ - fprintf(stderr, - "\n\nbzip2/libbzip2: internal error number %d.\n" - "This is a bug in bzip2/libbzip2, %s.\n" - "Please report it to me at: jseward@bzip.org. If this happened\n" - "when you were using some program which uses libbzip2 as a\n" - "component, you should also report this bug to the author(s)\n" - "of that program. Please make an effort to report this bug;\n" - "timely and accurate bug reports eventually lead to higher\n" - "quality software. Thanks. Julian Seward, 10 December 2007.\n\n", - errcode, - BZ2_bzlibVersion() - ); - - if (errcode == 1007) { - fprintf(stderr, - "\n*** A special note about internal error number 1007 ***\n" - "\n" - "Experience suggests that a common cause of i.e. 1007\n" - "is unreliable memory or other hardware. The 1007 assertion\n" - "just happens to cross-check the results of huge numbers of\n" - "memory reads/writes, and so acts (unintendedly) as a stress\n" - "test of your memory system.\n" - "\n" - "I suggest the following: try compressing the file again,\n" - "possibly monitoring progress in detail with the -vv flag.\n" - "\n" - "* If the error cannot be reproduced, and/or happens at different\n" - " points in compression, you may have a flaky memory system.\n" - " Try a memory-test program. I have used Memtest86\n" - " (www.memtest86.com). At the time of writing it is free (GPLd).\n" - " Memtest86 tests memory much more thorougly than your BIOSs\n" - " power-on test, and may find failures that the BIOS doesn't.\n" - "\n" - "* If the error can be repeatably reproduced, this is a bug in\n" - " bzip2, and I would very much like to hear about it. Please\n" - " let me know, and, ideally, save a copy of the file causing the\n" - " problem -- without which I will be unable to investigate it.\n" - "\n" - ); - } - - exit(3); -} -#endif - - -/*---------------------------------------------------*/ -static -int bz_config_ok ( void ) -{ - if (sizeof(int) != 4) return 0; - if (sizeof(short) != 2) return 0; - if (sizeof(char) != 1) return 0; - return 1; -} - - -/*---------------------------------------------------*/ -static -void* default_bzalloc ( void* opaque, Int32 items, Int32 size ) -{ - void* v = malloc ( items * size ); - return v; -} - -static -void default_bzfree ( void* opaque, void* addr ) -{ - if (addr != NULL) free ( addr ); -} - - -/*---------------------------------------------------*/ -static -void prepare_new_block ( EState* s ) -{ - Int32 i; - s->nblock = 0; - s->numZ = 0; - s->state_out_pos = 0; - BZ_INITIALISE_CRC ( s->blockCRC ); - for (i = 0; i < 256; i++) s->inUse[i] = False; - s->blockNo++; -} - - -/*---------------------------------------------------*/ -static -void init_RL ( EState* s ) -{ - s->state_in_ch = 256; - s->state_in_len = 0; -} - - -static -Bool isempty_RL ( EState* s ) -{ - if (s->state_in_ch < 256 && s->state_in_len > 0) - return False; else - return True; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompressInit) - ( bz_stream* strm, - int blockSize100k, - int verbosity, - int workFactor ) -{ - Int32 n; - EState* s; - - if (!bz_config_ok()) return BZ_CONFIG_ERROR; - - if (strm == NULL || - blockSize100k < 1 || blockSize100k > 9 || - workFactor < 0 || workFactor > 250) - return BZ_PARAM_ERROR; - - if (workFactor == 0) workFactor = 30; - if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; - if (strm->bzfree == NULL) strm->bzfree = default_bzfree; - - s = BZALLOC( sizeof(EState) ); - if (s == NULL) return BZ_MEM_ERROR; - s->strm = strm; - - s->arr1 = NULL; - s->arr2 = NULL; - s->ftab = NULL; - - n = 100000 * blockSize100k; - s->arr1 = BZALLOC( n * sizeof(UInt32) ); - s->arr2 = BZALLOC( (n+BZ_N_OVERSHOOT) * sizeof(UInt32) ); - s->ftab = BZALLOC( 65537 * sizeof(UInt32) ); - - if (s->arr1 == NULL || s->arr2 == NULL || s->ftab == NULL) { - if (s->arr1 != NULL) BZFREE(s->arr1); - if (s->arr2 != NULL) BZFREE(s->arr2); - if (s->ftab != NULL) BZFREE(s->ftab); - if (s != NULL) BZFREE(s); - return BZ_MEM_ERROR; - } - - s->blockNo = 0; - s->state = BZ_S_INPUT; - s->mode = BZ_M_RUNNING; - s->combinedCRC = 0; - s->blockSize100k = blockSize100k; - s->nblockMAX = 100000 * blockSize100k - 19; - s->verbosity = verbosity; - s->workFactor = workFactor; - - s->block = (UChar*)s->arr2; - s->mtfv = (UInt16*)s->arr1; - s->zbits = NULL; - s->ptr = (UInt32*)s->arr1; - - strm->state = s; - strm->total_in_lo32 = 0; - strm->total_in_hi32 = 0; - strm->total_out_lo32 = 0; - strm->total_out_hi32 = 0; - init_RL ( s ); - prepare_new_block ( s ); - return BZ_OK; -} - - -/*---------------------------------------------------*/ -static -void add_pair_to_block ( EState* s ) -{ - Int32 i; - UChar ch = (UChar)(s->state_in_ch); - for (i = 0; i < s->state_in_len; i++) { - BZ_UPDATE_CRC( s->blockCRC, ch ); - } - s->inUse[s->state_in_ch] = True; - switch (s->state_in_len) { - case 1: - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - case 2: - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - case 3: - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - break; - default: - s->inUse[s->state_in_len-4] = True; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = (UChar)ch; s->nblock++; - s->block[s->nblock] = ((UChar)(s->state_in_len-4)); - s->nblock++; - break; - } -} - - -/*---------------------------------------------------*/ -static -void flush_RL ( EState* s ) -{ - if (s->state_in_ch < 256) add_pair_to_block ( s ); - init_RL ( s ); -} - - -/*---------------------------------------------------*/ -#define ADD_CHAR_TO_BLOCK(zs,zchh0) \ -{ \ - UInt32 zchh = (UInt32)(zchh0); \ - /*-- fast track the common case --*/ \ - if (zchh != zs->state_in_ch && \ - zs->state_in_len == 1) { \ - UChar ch = (UChar)(zs->state_in_ch); \ - BZ_UPDATE_CRC( zs->blockCRC, ch ); \ - zs->inUse[zs->state_in_ch] = True; \ - zs->block[zs->nblock] = (UChar)ch; \ - zs->nblock++; \ - zs->state_in_ch = zchh; \ - } \ - else \ - /*-- general, uncommon cases --*/ \ - if (zchh != zs->state_in_ch || \ - zs->state_in_len == 255) { \ - if (zs->state_in_ch < 256) \ - add_pair_to_block ( zs ); \ - zs->state_in_ch = zchh; \ - zs->state_in_len = 1; \ - } else { \ - zs->state_in_len++; \ - } \ -} - - -/*---------------------------------------------------*/ -static -Bool copy_input_until_stop ( EState* s ) -{ - Bool progress_in = False; - - if (s->mode == BZ_M_RUNNING) { - - /*-- fast track the common case --*/ - while (True) { - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - progress_in = True; - ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); - s->strm->next_in++; - s->strm->avail_in--; - s->strm->total_in_lo32++; - if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; - } - - } else { - - /*-- general, uncommon case --*/ - while (True) { - /*-- block full? --*/ - if (s->nblock >= s->nblockMAX) break; - /*-- no input? --*/ - if (s->strm->avail_in == 0) break; - /*-- flush/finish end? --*/ - if (s->avail_in_expect == 0) break; - progress_in = True; - ADD_CHAR_TO_BLOCK ( s, (UInt32)(*((UChar*)(s->strm->next_in))) ); - s->strm->next_in++; - s->strm->avail_in--; - s->strm->total_in_lo32++; - if (s->strm->total_in_lo32 == 0) s->strm->total_in_hi32++; - s->avail_in_expect--; - } - } - return progress_in; -} - - -/*---------------------------------------------------*/ -static -Bool copy_output_until_stop ( EState* s ) -{ - Bool progress_out = False; - - while (True) { - - /*-- no output space? --*/ - if (s->strm->avail_out == 0) break; - - /*-- block done? --*/ - if (s->state_out_pos >= s->numZ) break; - - progress_out = True; - *(s->strm->next_out) = s->zbits[s->state_out_pos]; - s->state_out_pos++; - s->strm->avail_out--; - s->strm->next_out++; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - return progress_out; -} - - -/*---------------------------------------------------*/ -static -Bool handle_compress ( bz_stream* strm ) -{ - Bool progress_in = False; - Bool progress_out = False; - EState* s = strm->state; - - while (True) { - - if (s->state == BZ_S_OUTPUT) { - progress_out |= copy_output_until_stop ( s ); - if (s->state_out_pos < s->numZ) break; - if (s->mode == BZ_M_FINISHING && - s->avail_in_expect == 0 && - isempty_RL(s)) break; - prepare_new_block ( s ); - s->state = BZ_S_INPUT; - if (s->mode == BZ_M_FLUSHING && - s->avail_in_expect == 0 && - isempty_RL(s)) break; - } - - if (s->state == BZ_S_INPUT) { - progress_in |= copy_input_until_stop ( s ); - if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { - flush_RL ( s ); - BZ2_compressBlock ( s, (Bool)(s->mode == BZ_M_FINISHING) ); - s->state = BZ_S_OUTPUT; - } - else - if (s->nblock >= s->nblockMAX) { - BZ2_compressBlock ( s, False ); - s->state = BZ_S_OUTPUT; - } - else - if (s->strm->avail_in == 0) { - break; - } - } - - } - - return progress_in || progress_out; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompress) ( bz_stream *strm, int action ) -{ - Bool progress; - EState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - preswitch: - switch (s->mode) { - - case BZ_M_IDLE: - return BZ_SEQUENCE_ERROR; - - case BZ_M_RUNNING: - if (action == BZ_RUN) { - progress = handle_compress ( strm ); - return progress ? BZ_RUN_OK : BZ_PARAM_ERROR; - } - else - if (action == BZ_FLUSH) { - s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FLUSHING; - goto preswitch; - } - else - if (action == BZ_FINISH) { - s->avail_in_expect = strm->avail_in; - s->mode = BZ_M_FINISHING; - goto preswitch; - } - else - return BZ_PARAM_ERROR; - - case BZ_M_FLUSHING: - if (action != BZ_FLUSH) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR; - progress = handle_compress ( strm ); - if (s->avail_in_expect > 0 || !isempty_RL(s) || - s->state_out_pos < s->numZ) return BZ_FLUSH_OK; - s->mode = BZ_M_RUNNING; - return BZ_RUN_OK; - - case BZ_M_FINISHING: - if (action != BZ_FINISH) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect != s->strm->avail_in) - return BZ_SEQUENCE_ERROR; - progress = handle_compress ( strm ); - if (!progress) return BZ_SEQUENCE_ERROR; - if (s->avail_in_expect > 0 || !isempty_RL(s) || - s->state_out_pos < s->numZ) return BZ_FINISH_OK; - s->mode = BZ_M_IDLE; - return BZ_STREAM_END; - } - return BZ_OK; /*--not reached--*/ -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzCompressEnd) ( bz_stream *strm ) -{ - EState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - if (s->arr1 != NULL) BZFREE(s->arr1); - if (s->arr2 != NULL) BZFREE(s->arr2); - if (s->ftab != NULL) BZFREE(s->ftab); - BZFREE(strm->state); - - strm->state = NULL; - - return BZ_OK; -} - - -/*---------------------------------------------------*/ -/*--- Decompression stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompressInit) - ( bz_stream* strm, - int verbosity, - int small ) -{ - DState* s; - - if (!bz_config_ok()) return BZ_CONFIG_ERROR; - - if (strm == NULL) return BZ_PARAM_ERROR; - if (small != 0 && small != 1) return BZ_PARAM_ERROR; - if (verbosity < 0 || verbosity > 4) return BZ_PARAM_ERROR; - - if (strm->bzalloc == NULL) strm->bzalloc = default_bzalloc; - if (strm->bzfree == NULL) strm->bzfree = default_bzfree; - - s = BZALLOC( sizeof(DState) ); - if (s == NULL) return BZ_MEM_ERROR; - s->strm = strm; - strm->state = s; - s->state = BZ_X_MAGIC_1; - s->bsLive = 0; - s->bsBuff = 0; - s->calculatedCombinedCRC = 0; - strm->total_in_lo32 = 0; - strm->total_in_hi32 = 0; - strm->total_out_lo32 = 0; - strm->total_out_hi32 = 0; - s->smallDecompress = (Bool)small; - s->ll4 = NULL; - s->ll16 = NULL; - s->tt = NULL; - s->currBlockNo = 0; - s->verbosity = verbosity; - - return BZ_OK; -} - - -/*---------------------------------------------------*/ -/* Return True iff data corruption is discovered. - Returns False if there is no problem. -*/ -static -Bool unRLE_obuf_to_output_FAST ( DState* s ) -{ - UChar k1; - - if (s->blockRandomised) { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_FAST(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_FAST(s->k0); BZ_RAND_UPD_MASK; - s->k0 ^= BZ_RAND_MASK; s->nblock_used++; - } - - } else { - - /* restore */ - UInt32 c_calculatedBlockCRC = s->calculatedBlockCRC; - UChar c_state_out_ch = s->state_out_ch; - Int32 c_state_out_len = s->state_out_len; - Int32 c_nblock_used = s->nblock_used; - Int32 c_k0 = s->k0; - UInt32* c_tt = s->tt; - UInt32 c_tPos = s->tPos; - char* cs_next_out = s->strm->next_out; - unsigned int cs_avail_out = s->strm->avail_out; - Int32 ro_blockSize100k = s->blockSize100k; - /* end restore */ - - UInt32 avail_out_INIT = cs_avail_out; - Int32 s_save_nblockPP = s->save_nblock+1; - unsigned int total_out_lo32_old; - - while (True) { - - /* try to finish existing run */ - if (c_state_out_len > 0) { - while (True) { - if (cs_avail_out == 0) goto return_notr; - if (c_state_out_len == 1) break; - *( (UChar*)(cs_next_out) ) = c_state_out_ch; - BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); - c_state_out_len--; - cs_next_out++; - cs_avail_out--; - } - s_state_out_len_eq_one: - { - if (cs_avail_out == 0) { - c_state_out_len = 1; goto return_notr; - }; - *( (UChar*)(cs_next_out) ) = c_state_out_ch; - BZ_UPDATE_CRC ( c_calculatedBlockCRC, c_state_out_ch ); - cs_next_out++; - cs_avail_out--; - } - } - /* Only caused by corrupt data stream? */ - if (c_nblock_used > s_save_nblockPP) - return True; - - /* can a new run be started? */ - if (c_nblock_used == s_save_nblockPP) { - c_state_out_len = 0; goto return_notr; - }; - c_state_out_ch = c_k0; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (k1 != c_k0) { - c_k0 = k1; goto s_state_out_len_eq_one; - }; - if (c_nblock_used == s_save_nblockPP) - goto s_state_out_len_eq_one; - - c_state_out_len = 2; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (c_nblock_used == s_save_nblockPP) continue; - if (k1 != c_k0) { c_k0 = k1; continue; }; - - c_state_out_len = 3; - BZ_GET_FAST_C(k1); c_nblock_used++; - if (c_nblock_used == s_save_nblockPP) continue; - if (k1 != c_k0) { c_k0 = k1; continue; }; - - BZ_GET_FAST_C(k1); c_nblock_used++; - c_state_out_len = ((Int32)k1) + 4; - BZ_GET_FAST_C(c_k0); c_nblock_used++; - } - - return_notr: - total_out_lo32_old = s->strm->total_out_lo32; - s->strm->total_out_lo32 += (avail_out_INIT - cs_avail_out); - if (s->strm->total_out_lo32 < total_out_lo32_old) - s->strm->total_out_hi32++; - - /* save */ - s->calculatedBlockCRC = c_calculatedBlockCRC; - s->state_out_ch = c_state_out_ch; - s->state_out_len = c_state_out_len; - s->nblock_used = c_nblock_used; - s->k0 = c_k0; - s->tt = c_tt; - s->tPos = c_tPos; - s->strm->next_out = cs_next_out; - s->strm->avail_out = cs_avail_out; - /* end save */ - } - return False; -} - - - -/*---------------------------------------------------*/ -__inline__ Int32 BZ2_indexIntoF ( Int32 indx, Int32 *cftab ) -{ - Int32 nb, na, mid; - nb = 0; - na = 256; - do { - mid = (nb + na) >> 1; - if (indx >= cftab[mid]) nb = mid; else na = mid; - } - while (na - nb != 1); - return nb; -} - - -/*---------------------------------------------------*/ -/* Return True iff data corruption is discovered. - Returns False if there is no problem. -*/ -static -Bool unRLE_obuf_to_output_SMALL ( DState* s ) -{ - UChar k1; - - if (s->blockRandomised) { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_SMALL(k1); BZ_RAND_UPD_MASK; - k1 ^= BZ_RAND_MASK; s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_SMALL(s->k0); BZ_RAND_UPD_MASK; - s->k0 ^= BZ_RAND_MASK; s->nblock_used++; - } - - } else { - - while (True) { - /* try to finish existing run */ - while (True) { - if (s->strm->avail_out == 0) return False; - if (s->state_out_len == 0) break; - *( (UChar*)(s->strm->next_out) ) = s->state_out_ch; - BZ_UPDATE_CRC ( s->calculatedBlockCRC, s->state_out_ch ); - s->state_out_len--; - s->strm->next_out++; - s->strm->avail_out--; - s->strm->total_out_lo32++; - if (s->strm->total_out_lo32 == 0) s->strm->total_out_hi32++; - } - - /* can a new run be started? */ - if (s->nblock_used == s->save_nblock+1) return False; - - /* Only caused by corrupt data stream? */ - if (s->nblock_used > s->save_nblock+1) - return True; - - s->state_out_len = 1; - s->state_out_ch = s->k0; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 2; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - s->state_out_len = 3; - BZ_GET_SMALL(k1); s->nblock_used++; - if (s->nblock_used == s->save_nblock+1) continue; - if (k1 != s->k0) { s->k0 = k1; continue; }; - - BZ_GET_SMALL(k1); s->nblock_used++; - s->state_out_len = ((Int32)k1) + 4; - BZ_GET_SMALL(s->k0); s->nblock_used++; - } - - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompress) ( bz_stream *strm ) -{ - Bool corrupt; - DState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - while (True) { - if (s->state == BZ_X_IDLE) return BZ_SEQUENCE_ERROR; - if (s->state == BZ_X_OUTPUT) { - if (s->smallDecompress) - corrupt = unRLE_obuf_to_output_SMALL ( s ); else - corrupt = unRLE_obuf_to_output_FAST ( s ); - if (corrupt) return BZ_DATA_ERROR; - if (s->nblock_used == s->save_nblock+1 && s->state_out_len == 0) { - BZ_FINALISE_CRC ( s->calculatedBlockCRC ); - if (s->verbosity >= 3) - VPrintf2 ( " {0x%08x, 0x%08x}", s->storedBlockCRC, - s->calculatedBlockCRC ); - if (s->verbosity >= 2) VPrintf0 ( "]" ); - if (s->calculatedBlockCRC != s->storedBlockCRC) - return BZ_DATA_ERROR; - s->calculatedCombinedCRC - = (s->calculatedCombinedCRC << 1) | - (s->calculatedCombinedCRC >> 31); - s->calculatedCombinedCRC ^= s->calculatedBlockCRC; - s->state = BZ_X_BLKHDR_1; - } else { - return BZ_OK; - } - } - if (s->state >= BZ_X_MAGIC_1) { - Int32 r = BZ2_decompress ( s ); - if (r == BZ_STREAM_END) { - if (s->verbosity >= 3) - VPrintf2 ( "\n combined CRCs: stored = 0x%08x, computed = 0x%08x", - s->storedCombinedCRC, s->calculatedCombinedCRC ); - if (s->calculatedCombinedCRC != s->storedCombinedCRC) - return BZ_DATA_ERROR; - return r; - } - if (s->state != BZ_X_OUTPUT) return r; - } - } - - AssertH ( 0, 6001 ); - - return 0; /*NOTREACHED*/ -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzDecompressEnd) ( bz_stream *strm ) -{ - DState* s; - if (strm == NULL) return BZ_PARAM_ERROR; - s = strm->state; - if (s == NULL) return BZ_PARAM_ERROR; - if (s->strm != strm) return BZ_PARAM_ERROR; - - if (s->tt != NULL) BZFREE(s->tt); - if (s->ll16 != NULL) BZFREE(s->ll16); - if (s->ll4 != NULL) BZFREE(s->ll4); - - BZFREE(strm->state); - strm->state = NULL; - - return BZ_OK; -} - - -#ifndef BZ_NO_STDIO -/*---------------------------------------------------*/ -/*--- File I/O stuff ---*/ -/*---------------------------------------------------*/ - -#define BZ_SETERR(eee) \ -{ \ - if (bzerror != NULL) *bzerror = eee; \ - if (bzf != NULL) bzf->lastErr = eee; \ -} - -typedef - struct { - FILE* handle; - Char buf[BZ_MAX_UNUSED]; - Int32 bufN; - Bool writing; - bz_stream strm; - Int32 lastErr; - Bool initialisedOk; - } - bzFile; - - -/*---------------------------------------------*/ -static Bool myfeof ( FILE* f ) -{ - Int32 c = fgetc ( f ); - if (c == EOF) return True; - ungetc ( c, f ); - return False; -} - - -/*---------------------------------------------------*/ -BZFILE* BZ_API(BZ2_bzWriteOpen) - ( int* bzerror, - FILE* f, - int blockSize100k, - int verbosity, - int workFactor ) -{ - Int32 ret; - bzFile* bzf = NULL; - - BZ_SETERR(BZ_OK); - - if (f == NULL || - (blockSize100k < 1 || blockSize100k > 9) || - (workFactor < 0 || workFactor > 250) || - (verbosity < 0 || verbosity > 4)) - { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; - - if (ferror(f)) - { BZ_SETERR(BZ_IO_ERROR); return NULL; }; - - bzf = malloc ( sizeof(bzFile) ); - if (bzf == NULL) - { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; - - BZ_SETERR(BZ_OK); - bzf->initialisedOk = False; - bzf->bufN = 0; - bzf->handle = f; - bzf->writing = True; - bzf->strm.bzalloc = NULL; - bzf->strm.bzfree = NULL; - bzf->strm.opaque = NULL; - - if (workFactor == 0) workFactor = 30; - ret = BZ2_bzCompressInit ( &(bzf->strm), blockSize100k, - verbosity, workFactor ); - if (ret != BZ_OK) - { BZ_SETERR(ret); free(bzf); return NULL; }; - - bzf->strm.avail_in = 0; - bzf->initialisedOk = True; - return bzf; -} - - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzWrite) - ( int* bzerror, - BZFILE* b, - void* buf, - int len ) -{ - Int32 n, n2, ret; - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - if (bzf == NULL || buf == NULL || len < 0) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - if (!(bzf->writing)) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - - if (len == 0) - { BZ_SETERR(BZ_OK); return; }; - - bzf->strm.avail_in = len; - bzf->strm.next_in = buf; - - while (True) { - bzf->strm.avail_out = BZ_MAX_UNUSED; - bzf->strm.next_out = bzf->buf; - ret = BZ2_bzCompress ( &(bzf->strm), BZ_RUN ); - if (ret != BZ_RUN_OK) - { BZ_SETERR(ret); return; }; - - if (bzf->strm.avail_out < BZ_MAX_UNUSED) { - n = BZ_MAX_UNUSED - bzf->strm.avail_out; - n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), - n, bzf->handle ); - if (n != n2 || ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (bzf->strm.avail_in == 0) - { BZ_SETERR(BZ_OK); return; }; - } -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzWriteClose) - ( int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in, - unsigned int* nbytes_out ) -{ - BZ2_bzWriteClose64 ( bzerror, b, abandon, - nbytes_in, NULL, nbytes_out, NULL ); -} - - -void BZ_API(BZ2_bzWriteClose64) - ( int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in_lo32, - unsigned int* nbytes_in_hi32, - unsigned int* nbytes_out_lo32, - unsigned int* nbytes_out_hi32 ) -{ - Int32 n, n2, ret; - bzFile* bzf = (bzFile*)b; - - if (bzf == NULL) - { BZ_SETERR(BZ_OK); return; }; - if (!(bzf->writing)) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - - if (nbytes_in_lo32 != NULL) *nbytes_in_lo32 = 0; - if (nbytes_in_hi32 != NULL) *nbytes_in_hi32 = 0; - if (nbytes_out_lo32 != NULL) *nbytes_out_lo32 = 0; - if (nbytes_out_hi32 != NULL) *nbytes_out_hi32 = 0; - - if ((!abandon) && bzf->lastErr == BZ_OK) { - while (True) { - bzf->strm.avail_out = BZ_MAX_UNUSED; - bzf->strm.next_out = bzf->buf; - ret = BZ2_bzCompress ( &(bzf->strm), BZ_FINISH ); - if (ret != BZ_FINISH_OK && ret != BZ_STREAM_END) - { BZ_SETERR(ret); return; }; - - if (bzf->strm.avail_out < BZ_MAX_UNUSED) { - n = BZ_MAX_UNUSED - bzf->strm.avail_out; - n2 = fwrite ( (void*)(bzf->buf), sizeof(UChar), - n, bzf->handle ); - if (n != n2 || ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (ret == BZ_STREAM_END) break; - } - } - - if ( !abandon && !ferror ( bzf->handle ) ) { - fflush ( bzf->handle ); - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return; }; - } - - if (nbytes_in_lo32 != NULL) - *nbytes_in_lo32 = bzf->strm.total_in_lo32; - if (nbytes_in_hi32 != NULL) - *nbytes_in_hi32 = bzf->strm.total_in_hi32; - if (nbytes_out_lo32 != NULL) - *nbytes_out_lo32 = bzf->strm.total_out_lo32; - if (nbytes_out_hi32 != NULL) - *nbytes_out_hi32 = bzf->strm.total_out_hi32; - - BZ_SETERR(BZ_OK); - BZ2_bzCompressEnd ( &(bzf->strm) ); - free ( bzf ); -} - - -/*---------------------------------------------------*/ -BZFILE* BZ_API(BZ2_bzReadOpen) - ( int* bzerror, - FILE* f, - int verbosity, - int small, - void* unused, - int nUnused ) -{ - bzFile* bzf = NULL; - int ret; - - BZ_SETERR(BZ_OK); - - if (f == NULL || - (small != 0 && small != 1) || - (verbosity < 0 || verbosity > 4) || - (unused == NULL && nUnused != 0) || - (unused != NULL && (nUnused < 0 || nUnused > BZ_MAX_UNUSED))) - { BZ_SETERR(BZ_PARAM_ERROR); return NULL; }; - - if (ferror(f)) - { BZ_SETERR(BZ_IO_ERROR); return NULL; }; - - bzf = malloc ( sizeof(bzFile) ); - if (bzf == NULL) - { BZ_SETERR(BZ_MEM_ERROR); return NULL; }; - - BZ_SETERR(BZ_OK); - - bzf->initialisedOk = False; - bzf->handle = f; - bzf->bufN = 0; - bzf->writing = False; - bzf->strm.bzalloc = NULL; - bzf->strm.bzfree = NULL; - bzf->strm.opaque = NULL; - - while (nUnused > 0) { - bzf->buf[bzf->bufN] = *((UChar*)(unused)); bzf->bufN++; - unused = ((void*)( 1 + ((UChar*)(unused)) )); - nUnused--; - } - - ret = BZ2_bzDecompressInit ( &(bzf->strm), verbosity, small ); - if (ret != BZ_OK) - { BZ_SETERR(ret); free(bzf); return NULL; }; - - bzf->strm.avail_in = bzf->bufN; - bzf->strm.next_in = bzf->buf; - - bzf->initialisedOk = True; - return bzf; -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzReadClose) ( int *bzerror, BZFILE *b ) -{ - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - if (bzf == NULL) - { BZ_SETERR(BZ_OK); return; }; - - if (bzf->writing) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - - if (bzf->initialisedOk) - (void)BZ2_bzDecompressEnd ( &(bzf->strm) ); - free ( bzf ); -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzRead) - ( int* bzerror, - BZFILE* b, - void* buf, - int len ) -{ - Int32 n, ret; - bzFile* bzf = (bzFile*)b; - - BZ_SETERR(BZ_OK); - - if (bzf == NULL || buf == NULL || len < 0) - { BZ_SETERR(BZ_PARAM_ERROR); return 0; }; - - if (bzf->writing) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return 0; }; - - if (len == 0) - { BZ_SETERR(BZ_OK); return 0; }; - - bzf->strm.avail_out = len; - bzf->strm.next_out = buf; - - while (True) { - - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return 0; }; - - if (bzf->strm.avail_in == 0 && !myfeof(bzf->handle)) { - n = fread ( bzf->buf, sizeof(UChar), - BZ_MAX_UNUSED, bzf->handle ); - if (ferror(bzf->handle)) - { BZ_SETERR(BZ_IO_ERROR); return 0; }; - bzf->bufN = n; - bzf->strm.avail_in = bzf->bufN; - bzf->strm.next_in = bzf->buf; - } - - ret = BZ2_bzDecompress ( &(bzf->strm) ); - - if (ret != BZ_OK && ret != BZ_STREAM_END) - { BZ_SETERR(ret); return 0; }; - - if (ret == BZ_OK && myfeof(bzf->handle) && - bzf->strm.avail_in == 0 && bzf->strm.avail_out > 0) - { BZ_SETERR(BZ_UNEXPECTED_EOF); return 0; }; - - if (ret == BZ_STREAM_END) - { BZ_SETERR(BZ_STREAM_END); - return len - bzf->strm.avail_out; }; - if (bzf->strm.avail_out == 0) - { BZ_SETERR(BZ_OK); return len; }; - - } - - return 0; /*not reached*/ -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzReadGetUnused) - ( int* bzerror, - BZFILE* b, - void** unused, - int* nUnused ) -{ - bzFile* bzf = (bzFile*)b; - if (bzf == NULL) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - if (bzf->lastErr != BZ_STREAM_END) - { BZ_SETERR(BZ_SEQUENCE_ERROR); return; }; - if (unused == NULL || nUnused == NULL) - { BZ_SETERR(BZ_PARAM_ERROR); return; }; - - BZ_SETERR(BZ_OK); - *nUnused = bzf->strm.avail_in; - *unused = bzf->strm.next_in; -} -#endif - - -/*---------------------------------------------------*/ -/*--- Misc convenience stuff ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzBuffToBuffCompress) - ( char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int blockSize100k, - int verbosity, - int workFactor ) -{ - bz_stream strm; - int ret; - - if (dest == NULL || destLen == NULL || - source == NULL || - blockSize100k < 1 || blockSize100k > 9 || - verbosity < 0 || verbosity > 4 || - workFactor < 0 || workFactor > 250) - return BZ_PARAM_ERROR; - - if (workFactor == 0) workFactor = 30; - strm.bzalloc = NULL; - strm.bzfree = NULL; - strm.opaque = NULL; - ret = BZ2_bzCompressInit ( &strm, blockSize100k, - verbosity, workFactor ); - if (ret != BZ_OK) return ret; - - strm.next_in = source; - strm.next_out = dest; - strm.avail_in = sourceLen; - strm.avail_out = *destLen; - - ret = BZ2_bzCompress ( &strm, BZ_FINISH ); - if (ret == BZ_FINISH_OK) goto output_overflow; - if (ret != BZ_STREAM_END) goto errhandler; - - /* normal termination */ - *destLen -= strm.avail_out; - BZ2_bzCompressEnd ( &strm ); - return BZ_OK; - - output_overflow: - BZ2_bzCompressEnd ( &strm ); - return BZ_OUTBUFF_FULL; - - errhandler: - BZ2_bzCompressEnd ( &strm ); - return ret; -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzBuffToBuffDecompress) - ( char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int small, - int verbosity ) -{ - bz_stream strm; - int ret; - - if (dest == NULL || destLen == NULL || - source == NULL || - (small != 0 && small != 1) || - verbosity < 0 || verbosity > 4) - return BZ_PARAM_ERROR; - - strm.bzalloc = NULL; - strm.bzfree = NULL; - strm.opaque = NULL; - ret = BZ2_bzDecompressInit ( &strm, verbosity, small ); - if (ret != BZ_OK) return ret; - - strm.next_in = source; - strm.next_out = dest; - strm.avail_in = sourceLen; - strm.avail_out = *destLen; - - ret = BZ2_bzDecompress ( &strm ); - if (ret == BZ_OK) goto output_overflow_or_eof; - if (ret != BZ_STREAM_END) goto errhandler; - - /* normal termination */ - *destLen -= strm.avail_out; - BZ2_bzDecompressEnd ( &strm ); - return BZ_OK; - - output_overflow_or_eof: - if (strm.avail_out > 0) { - BZ2_bzDecompressEnd ( &strm ); - return BZ_UNEXPECTED_EOF; - } else { - BZ2_bzDecompressEnd ( &strm ); - return BZ_OUTBUFF_FULL; - }; - - errhandler: - BZ2_bzDecompressEnd ( &strm ); - return ret; -} - - -/*---------------------------------------------------*/ -/*-- - Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) - to support better zlib compatibility. - This code is not _officially_ part of libbzip2 (yet); - I haven't tested it, documented it, or considered the - threading-safeness of it. - If this code breaks, please contact both Yoshioka and me. ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -/*-- - return version like "0.9.5d, 4-Sept-1999". ---*/ -const char * BZ_API(BZ2_bzlibVersion)(void) -{ - return BZ_VERSION; -} - - -#ifndef BZ_NO_STDIO -/*---------------------------------------------------*/ - -#if defined(_WIN32) || defined(OS2) || defined(MSDOS) -# include -# include -# define SET_BINARY_MODE(file) setmode(fileno(file),O_BINARY) -#else -# define SET_BINARY_MODE(file) -#endif -static -BZFILE * bzopen_or_bzdopen - ( const char *path, /* no use when bzdopen */ - int fd, /* no use when bzdopen */ - const char *mode, - int open_mode) /* bzopen: 0, bzdopen:1 */ -{ - int bzerr; - char unused[BZ_MAX_UNUSED]; - int blockSize100k = 9; - int writing = 0; - char mode2[10] = ""; - FILE *fp = NULL; - BZFILE *bzfp = NULL; - int verbosity = 0; - int workFactor = 30; - int smallMode = 0; - int nUnused = 0; - - if (mode == NULL) return NULL; - while (*mode) { - switch (*mode) { - case 'r': - writing = 0; break; - case 'w': - writing = 1; break; - case 's': - smallMode = 1; break; - default: - if (isdigit((int)(*mode))) { - blockSize100k = *mode-BZ_HDR_0; - } - } - mode++; - } - strcat(mode2, writing ? "w" : "r" ); - strcat(mode2,"b"); /* binary mode */ - - if (open_mode==0) { - if (path==NULL || strcmp(path,"")==0) { - fp = (writing ? stdout : stdin); - SET_BINARY_MODE(fp); - } else { - fp = fopen(path,mode2); - } - } else { -#ifdef BZ_STRICT_ANSI - fp = NULL; -#else - fp = fdopen(fd,mode2); -#endif - } - if (fp == NULL) return NULL; - - if (writing) { - /* Guard against total chaos and anarchy -- JRS */ - if (blockSize100k < 1) blockSize100k = 1; - if (blockSize100k > 9) blockSize100k = 9; - bzfp = BZ2_bzWriteOpen(&bzerr,fp,blockSize100k, - verbosity,workFactor); - } else { - bzfp = BZ2_bzReadOpen(&bzerr,fp,verbosity,smallMode, - unused,nUnused); - } - if (bzfp == NULL) { - if (fp != stdin && fp != stdout) fclose(fp); - return NULL; - } - return bzfp; -} - - -/*---------------------------------------------------*/ -/*-- - open file for read or write. - ex) bzopen("file","w9") - case path="" or NULL => use stdin or stdout. ---*/ -BZFILE * BZ_API(BZ2_bzopen) - ( const char *path, - const char *mode ) -{ - return bzopen_or_bzdopen(path,-1,mode,/*bzopen*/0); -} - - -/*---------------------------------------------------*/ -BZFILE * BZ_API(BZ2_bzdopen) - ( int fd, - const char *mode ) -{ - return bzopen_or_bzdopen(NULL,fd,mode,/*bzdopen*/1); -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzread) (BZFILE* b, void* buf, int len ) -{ - int bzerr, nread; - if (((bzFile*)b)->lastErr == BZ_STREAM_END) return 0; - nread = BZ2_bzRead(&bzerr,b,buf,len); - if (bzerr == BZ_OK || bzerr == BZ_STREAM_END) { - return nread; - } else { - return -1; - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzwrite) (BZFILE* b, void* buf, int len ) -{ - int bzerr; - - BZ2_bzWrite(&bzerr,b,buf,len); - if(bzerr == BZ_OK){ - return len; - }else{ - return -1; - } -} - - -/*---------------------------------------------------*/ -int BZ_API(BZ2_bzflush) (BZFILE *b) -{ - /* do nothing now... */ - return 0; -} - - -/*---------------------------------------------------*/ -void BZ_API(BZ2_bzclose) (BZFILE* b) -{ - int bzerr; - FILE *fp; - - if (b==NULL) {return;} - fp = ((bzFile *)b)->handle; - if(((bzFile*)b)->writing){ - BZ2_bzWriteClose(&bzerr,b,0,NULL,NULL); - if(bzerr != BZ_OK){ - BZ2_bzWriteClose(NULL,b,1,NULL,NULL); - } - }else{ - BZ2_bzReadClose(&bzerr,b); - } - if(fp!=stdin && fp!=stdout){ - fclose(fp); - } -} - - -/*---------------------------------------------------*/ -/*-- - return last error code ---*/ -static const char *bzerrorstrings[] = { - "OK" - ,"SEQUENCE_ERROR" - ,"PARAM_ERROR" - ,"MEM_ERROR" - ,"DATA_ERROR" - ,"DATA_ERROR_MAGIC" - ,"IO_ERROR" - ,"UNEXPECTED_EOF" - ,"OUTBUFF_FULL" - ,"CONFIG_ERROR" - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ - ,"???" /* for future */ -}; - - -const char * BZ_API(BZ2_bzerror) (BZFILE *b, int *errnum) -{ - int err = ((bzFile *)b)->lastErr; - - if(err>0) err = 0; - *errnum = err; - return bzerrorstrings[err*-1]; -} -#endif - - -/*-------------------------------------------------------------*/ -/*--- end bzlib.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/src/common/dep/bzip2/bzlib.h b/src/common/dep/bzip2/bzlib.h deleted file mode 100644 index b638391f0..000000000 --- a/src/common/dep/bzip2/bzlib.h +++ /dev/null @@ -1,282 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Public header file for the library. ---*/ -/*--- bzlib.h ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#ifndef _BZLIB_H -#define _BZLIB_H - -#ifdef __cplusplus -extern "C" { -#endif - -#define BZ_RUN 0 -#define BZ_FLUSH 1 -#define BZ_FINISH 2 - -#define BZ_OK 0 -#define BZ_RUN_OK 1 -#define BZ_FLUSH_OK 2 -#define BZ_FINISH_OK 3 -#define BZ_STREAM_END 4 -#define BZ_SEQUENCE_ERROR (-1) -#define BZ_PARAM_ERROR (-2) -#define BZ_MEM_ERROR (-3) -#define BZ_DATA_ERROR (-4) -#define BZ_DATA_ERROR_MAGIC (-5) -#define BZ_IO_ERROR (-6) -#define BZ_UNEXPECTED_EOF (-7) -#define BZ_OUTBUFF_FULL (-8) -#define BZ_CONFIG_ERROR (-9) - -typedef - struct { - char *next_in; - unsigned int avail_in; - unsigned int total_in_lo32; - unsigned int total_in_hi32; - - char *next_out; - unsigned int avail_out; - unsigned int total_out_lo32; - unsigned int total_out_hi32; - - void *state; - - void *(*bzalloc)(void *,int,int); - void (*bzfree)(void *,void *); - void *opaque; - } - bz_stream; - - -#ifndef BZ_IMPORT -#define BZ_EXPORT -#endif - -#ifndef BZ_NO_STDIO -/* Need a definitition for FILE */ -#include -#endif - -#ifdef _WIN32 -# include -# ifdef small - /* windows.h define small to char */ -# undef small -# endif -# ifdef BZ_EXPORT -# define BZ_API(func) WINAPI func -# define BZ_EXTERN extern -# else - /* import windows dll dynamically */ -# define BZ_API(func) (WINAPI * func) -# define BZ_EXTERN -# endif -#else -# define BZ_API(func) func -# define BZ_EXTERN extern -#endif - - -/*-- Core (low-level) library functions --*/ - -BZ_EXTERN int BZ_API(BZ2_bzCompressInit) ( - bz_stream* strm, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN int BZ_API(BZ2_bzCompress) ( - bz_stream* strm, - int action - ); - -BZ_EXTERN int BZ_API(BZ2_bzCompressEnd) ( - bz_stream* strm - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompressInit) ( - bz_stream *strm, - int verbosity, - int small - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompress) ( - bz_stream* strm - ); - -BZ_EXTERN int BZ_API(BZ2_bzDecompressEnd) ( - bz_stream *strm - ); - - - -/*-- High(er) level library functions --*/ - -#ifndef BZ_NO_STDIO -#define BZ_MAX_UNUSED 5000 - -typedef void BZFILE; - -BZ_EXTERN BZFILE* BZ_API(BZ2_bzReadOpen) ( - int* bzerror, - FILE* f, - int verbosity, - int small, - void* unused, - int nUnused - ); - -BZ_EXTERN void BZ_API(BZ2_bzReadClose) ( - int* bzerror, - BZFILE* b - ); - -BZ_EXTERN void BZ_API(BZ2_bzReadGetUnused) ( - int* bzerror, - BZFILE* b, - void** unused, - int* nUnused - ); - -BZ_EXTERN int BZ_API(BZ2_bzRead) ( - int* bzerror, - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN BZFILE* BZ_API(BZ2_bzWriteOpen) ( - int* bzerror, - FILE* f, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN void BZ_API(BZ2_bzWrite) ( - int* bzerror, - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN void BZ_API(BZ2_bzWriteClose) ( - int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in, - unsigned int* nbytes_out - ); - -BZ_EXTERN void BZ_API(BZ2_bzWriteClose64) ( - int* bzerror, - BZFILE* b, - int abandon, - unsigned int* nbytes_in_lo32, - unsigned int* nbytes_in_hi32, - unsigned int* nbytes_out_lo32, - unsigned int* nbytes_out_hi32 - ); -#endif - - -/*-- Utility functions --*/ - -BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffCompress) ( - char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int blockSize100k, - int verbosity, - int workFactor - ); - -BZ_EXTERN int BZ_API(BZ2_bzBuffToBuffDecompress) ( - char* dest, - unsigned int* destLen, - char* source, - unsigned int sourceLen, - int small, - int verbosity - ); - - -/*-- - Code contributed by Yoshioka Tsuneo (tsuneo@rr.iij4u.or.jp) - to support better zlib compatibility. - This code is not _officially_ part of libbzip2 (yet); - I haven't tested it, documented it, or considered the - threading-safeness of it. - If this code breaks, please contact both Yoshioka and me. ---*/ - -BZ_EXTERN const char * BZ_API(BZ2_bzlibVersion) ( - void - ); - -#ifndef BZ_NO_STDIO -BZ_EXTERN BZFILE * BZ_API(BZ2_bzopen) ( - const char *path, - const char *mode - ); - -BZ_EXTERN BZFILE * BZ_API(BZ2_bzdopen) ( - int fd, - const char *mode - ); - -BZ_EXTERN int BZ_API(BZ2_bzread) ( - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN int BZ_API(BZ2_bzwrite) ( - BZFILE* b, - void* buf, - int len - ); - -BZ_EXTERN int BZ_API(BZ2_bzflush) ( - BZFILE* b - ); - -BZ_EXTERN void BZ_API(BZ2_bzclose) ( - BZFILE* b - ); - -BZ_EXTERN const char * BZ_API(BZ2_bzerror) ( - BZFILE *b, - int *errnum - ); -#endif - -#ifdef __cplusplus -} -#endif - -#endif - -/*-------------------------------------------------------------*/ -/*--- end bzlib.h ---*/ -/*-------------------------------------------------------------*/ diff --git a/src/common/dep/bzip2/bzlib_private.h b/src/common/dep/bzip2/bzlib_private.h deleted file mode 100644 index 6b2a45f83..000000000 --- a/src/common/dep/bzip2/bzlib_private.h +++ /dev/null @@ -1,509 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Private header file for the library. ---*/ -/*--- bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#ifndef _BZLIB_PRIVATE_H -#define _BZLIB_PRIVATE_H - -#include - -#ifndef BZ_NO_STDIO -#include -#include -#include -#endif - -#include "bzlib.h" - - - -/*-- General stuff. --*/ - -#define BZ_VERSION "1.0.6, 6-Sept-2010" - -typedef char Char; -typedef unsigned char Bool; -typedef unsigned char UChar; -typedef int Int32; -typedef unsigned int UInt32; -typedef short Int16; -typedef unsigned short UInt16; - -#define True ((Bool)1) -#define False ((Bool)0) - -#ifndef __GNUC__ -#define __inline__ /* */ -#endif - -#ifndef BZ_NO_STDIO - -extern void BZ2_bz__AssertH__fail ( int errcode ); -#define AssertH(cond,errcode) \ - { if (!(cond)) BZ2_bz__AssertH__fail ( errcode ); } - -#if BZ_DEBUG -#define AssertD(cond,msg) \ - { if (!(cond)) { \ - fprintf ( stderr, \ - "\n\nlibbzip2(debug build): internal error\n\t%s\n", msg );\ - exit(1); \ - }} -#else -#define AssertD(cond,msg) /* */ -#endif - -#define VPrintf0(zf) \ - fprintf(stderr,zf) -#define VPrintf1(zf,za1) \ - fprintf(stderr,zf,za1) -#define VPrintf2(zf,za1,za2) \ - fprintf(stderr,zf,za1,za2) -#define VPrintf3(zf,za1,za2,za3) \ - fprintf(stderr,zf,za1,za2,za3) -#define VPrintf4(zf,za1,za2,za3,za4) \ - fprintf(stderr,zf,za1,za2,za3,za4) -#define VPrintf5(zf,za1,za2,za3,za4,za5) \ - fprintf(stderr,zf,za1,za2,za3,za4,za5) - -#else - -extern void bz_internal_error ( int errcode ); -#define AssertH(cond,errcode) \ - { if (!(cond)) bz_internal_error ( errcode ); } -#define AssertD(cond,msg) do { } while (0) -#define VPrintf0(zf) do { } while (0) -#define VPrintf1(zf,za1) do { } while (0) -#define VPrintf2(zf,za1,za2) do { } while (0) -#define VPrintf3(zf,za1,za2,za3) do { } while (0) -#define VPrintf4(zf,za1,za2,za3,za4) do { } while (0) -#define VPrintf5(zf,za1,za2,za3,za4,za5) do { } while (0) - -#endif - - -#define BZALLOC(nnn) (strm->bzalloc)(strm->opaque,(nnn),1) -#define BZFREE(ppp) (strm->bzfree)(strm->opaque,(ppp)) - - -/*-- Header bytes. --*/ - -#define BZ_HDR_B 0x42 /* 'B' */ -#define BZ_HDR_Z 0x5a /* 'Z' */ -#define BZ_HDR_h 0x68 /* 'h' */ -#define BZ_HDR_0 0x30 /* '0' */ - -/*-- Constants for the back end. --*/ - -#define BZ_MAX_ALPHA_SIZE 258 -#define BZ_MAX_CODE_LEN 23 - -#define BZ_RUNA 0 -#define BZ_RUNB 1 - -#define BZ_N_GROUPS 6 -#define BZ_G_SIZE 50 -#define BZ_N_ITERS 4 - -#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) - - - -/*-- Stuff for randomising repetitive blocks. --*/ - -extern Int32 BZ2_rNums[512]; - -#define BZ_RAND_DECLS \ - Int32 rNToGo; \ - Int32 rTPos \ - -#define BZ_RAND_INIT_MASK \ - s->rNToGo = 0; \ - s->rTPos = 0 \ - -#define BZ_RAND_MASK ((s->rNToGo == 1) ? 1 : 0) - -#define BZ_RAND_UPD_MASK \ - if (s->rNToGo == 0) { \ - s->rNToGo = BZ2_rNums[s->rTPos]; \ - s->rTPos++; \ - if (s->rTPos == 512) s->rTPos = 0; \ - } \ - s->rNToGo--; - - - -/*-- Stuff for doing CRCs. --*/ - -extern UInt32 BZ2_crc32Table[256]; - -#define BZ_INITIALISE_CRC(crcVar) \ -{ \ - crcVar = 0xffffffffL; \ -} - -#define BZ_FINALISE_CRC(crcVar) \ -{ \ - crcVar = ~(crcVar); \ -} - -#define BZ_UPDATE_CRC(crcVar,cha) \ -{ \ - crcVar = (crcVar << 8) ^ \ - BZ2_crc32Table[(crcVar >> 24) ^ \ - ((UChar)cha)]; \ -} - - - -/*-- States and modes for compression. --*/ - -#define BZ_M_IDLE 1 -#define BZ_M_RUNNING 2 -#define BZ_M_FLUSHING 3 -#define BZ_M_FINISHING 4 - -#define BZ_S_OUTPUT 1 -#define BZ_S_INPUT 2 - -#define BZ_N_RADIX 2 -#define BZ_N_QSORT 12 -#define BZ_N_SHELL 18 -#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) - - - - -/*-- Structure holding all the compression-side stuff. --*/ - -typedef - struct { - /* pointer back to the struct bz_stream */ - bz_stream* strm; - - /* mode this stream is in, and whether inputting */ - /* or outputting data */ - Int32 mode; - Int32 state; - - /* remembers avail_in when flush/finish requested */ - UInt32 avail_in_expect; - - /* for doing the block sorting */ - UInt32* arr1; - UInt32* arr2; - UInt32* ftab; - Int32 origPtr; - - /* aliases for arr1 and arr2 */ - UInt32* ptr; - UChar* block; - UInt16* mtfv; - UChar* zbits; - - /* for deciding when to use the fallback sorting algorithm */ - Int32 workFactor; - - /* run-length-encoding of the input */ - UInt32 state_in_ch; - Int32 state_in_len; - BZ_RAND_DECLS; - - /* input and output limits and current posns */ - Int32 nblock; - Int32 nblockMAX; - Int32 numZ; - Int32 state_out_pos; - - /* map of bytes used in block */ - Int32 nInUse; - Bool inUse[256]; - UChar unseqToSeq[256]; - - /* the buffer for bit stream creation */ - UInt32 bsBuff; - Int32 bsLive; - - /* block and combined CRCs */ - UInt32 blockCRC; - UInt32 combinedCRC; - - /* misc administratium */ - Int32 verbosity; - Int32 blockNo; - Int32 blockSize100k; - - /* stuff for coding the MTF values */ - Int32 nMTF; - Int32 mtfFreq [BZ_MAX_ALPHA_SIZE]; - UChar selector [BZ_MAX_SELECTORS]; - UChar selectorMtf[BZ_MAX_SELECTORS]; - - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 rfreq [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - /* second dimension: only 3 needed; 4 makes index calculations faster */ - UInt32 len_pack[BZ_MAX_ALPHA_SIZE][4]; - - } - EState; - - - -/*-- externs for compression. --*/ - -extern void -BZ2_blockSort ( EState* ); - -extern void -BZ2_compressBlock ( EState*, Bool ); - -extern void -BZ2_bsInitWrite ( EState* ); - -extern void -BZ2_hbAssignCodes ( Int32*, UChar*, Int32, Int32, Int32 ); - -extern void -BZ2_hbMakeCodeLengths ( UChar*, Int32*, Int32, Int32 ); - - - -/*-- states for decompression. --*/ - -#define BZ_X_IDLE 1 -#define BZ_X_OUTPUT 2 - -#define BZ_X_MAGIC_1 10 -#define BZ_X_MAGIC_2 11 -#define BZ_X_MAGIC_3 12 -#define BZ_X_MAGIC_4 13 -#define BZ_X_BLKHDR_1 14 -#define BZ_X_BLKHDR_2 15 -#define BZ_X_BLKHDR_3 16 -#define BZ_X_BLKHDR_4 17 -#define BZ_X_BLKHDR_5 18 -#define BZ_X_BLKHDR_6 19 -#define BZ_X_BCRC_1 20 -#define BZ_X_BCRC_2 21 -#define BZ_X_BCRC_3 22 -#define BZ_X_BCRC_4 23 -#define BZ_X_RANDBIT 24 -#define BZ_X_ORIGPTR_1 25 -#define BZ_X_ORIGPTR_2 26 -#define BZ_X_ORIGPTR_3 27 -#define BZ_X_MAPPING_1 28 -#define BZ_X_MAPPING_2 29 -#define BZ_X_SELECTOR_1 30 -#define BZ_X_SELECTOR_2 31 -#define BZ_X_SELECTOR_3 32 -#define BZ_X_CODING_1 33 -#define BZ_X_CODING_2 34 -#define BZ_X_CODING_3 35 -#define BZ_X_MTF_1 36 -#define BZ_X_MTF_2 37 -#define BZ_X_MTF_3 38 -#define BZ_X_MTF_4 39 -#define BZ_X_MTF_5 40 -#define BZ_X_MTF_6 41 -#define BZ_X_ENDHDR_2 42 -#define BZ_X_ENDHDR_3 43 -#define BZ_X_ENDHDR_4 44 -#define BZ_X_ENDHDR_5 45 -#define BZ_X_ENDHDR_6 46 -#define BZ_X_CCRC_1 47 -#define BZ_X_CCRC_2 48 -#define BZ_X_CCRC_3 49 -#define BZ_X_CCRC_4 50 - - - -/*-- Constants for the fast MTF decoder. --*/ - -#define MTFA_SIZE 4096 -#define MTFL_SIZE 16 - - - -/*-- Structure holding all the decompression-side stuff. --*/ - -typedef - struct { - /* pointer back to the struct bz_stream */ - bz_stream* strm; - - /* state indicator for this stream */ - Int32 state; - - /* for doing the final run-length decoding */ - UChar state_out_ch; - Int32 state_out_len; - Bool blockRandomised; - BZ_RAND_DECLS; - - /* the buffer for bit stream reading */ - UInt32 bsBuff; - Int32 bsLive; - - /* misc administratium */ - Int32 blockSize100k; - Bool smallDecompress; - Int32 currBlockNo; - Int32 verbosity; - - /* for undoing the Burrows-Wheeler transform */ - Int32 origPtr; - UInt32 tPos; - Int32 k0; - Int32 unzftab[256]; - Int32 nblock_used; - Int32 cftab[257]; - Int32 cftabCopy[257]; - - /* for undoing the Burrows-Wheeler transform (FAST) */ - UInt32 *tt; - - /* for undoing the Burrows-Wheeler transform (SMALL) */ - UInt16 *ll16; - UChar *ll4; - - /* stored and calculated CRCs */ - UInt32 storedBlockCRC; - UInt32 storedCombinedCRC; - UInt32 calculatedBlockCRC; - UInt32 calculatedCombinedCRC; - - /* map of bytes used in block */ - Int32 nInUse; - Bool inUse[256]; - Bool inUse16[16]; - UChar seqToUnseq[256]; - - /* for decoding the MTF values */ - UChar mtfa [MTFA_SIZE]; - Int32 mtfbase[256 / MTFL_SIZE]; - UChar selector [BZ_MAX_SELECTORS]; - UChar selectorMtf[BZ_MAX_SELECTORS]; - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - - Int32 limit [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 base [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 perm [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 minLens[BZ_N_GROUPS]; - - /* save area for scalars in the main decompress code */ - Int32 save_i; - Int32 save_j; - Int32 save_t; - Int32 save_alphaSize; - Int32 save_nGroups; - Int32 save_nSelectors; - Int32 save_EOB; - Int32 save_groupNo; - Int32 save_groupPos; - Int32 save_nextSym; - Int32 save_nblockMAX; - Int32 save_nblock; - Int32 save_es; - Int32 save_N; - Int32 save_curr; - Int32 save_zt; - Int32 save_zn; - Int32 save_zvec; - Int32 save_zj; - Int32 save_gSel; - Int32 save_gMinlen; - Int32* save_gLimit; - Int32* save_gBase; - Int32* save_gPerm; - - } - DState; - - - -/*-- Macros for decompression. --*/ - -#define BZ_GET_FAST(cccc) \ - /* c_tPos is unsigned, hence test < 0 is pointless. */ \ - if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ - s->tPos = s->tt[s->tPos]; \ - cccc = (UChar)(s->tPos & 0xff); \ - s->tPos >>= 8; - -#define BZ_GET_FAST_C(cccc) \ - /* c_tPos is unsigned, hence test < 0 is pointless. */ \ - if (c_tPos >= (UInt32)100000 * (UInt32)ro_blockSize100k) return True; \ - c_tPos = c_tt[c_tPos]; \ - cccc = (UChar)(c_tPos & 0xff); \ - c_tPos >>= 8; - -#define SET_LL4(i,n) \ - { if (((i) & 0x1) == 0) \ - s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0xf0) | (n); else \ - s->ll4[(i) >> 1] = (s->ll4[(i) >> 1] & 0x0f) | ((n) << 4); \ - } - -#define GET_LL4(i) \ - ((((UInt32)(s->ll4[(i) >> 1])) >> (((i) << 2) & 0x4)) & 0xF) - -#define SET_LL(i,n) \ - { s->ll16[i] = (UInt16)(n & 0x0000ffff); \ - SET_LL4(i, n >> 16); \ - } - -#define GET_LL(i) \ - (((UInt32)s->ll16[i]) | (GET_LL4(i) << 16)) - -#define BZ_GET_SMALL(cccc) \ - /* c_tPos is unsigned, hence test < 0 is pointless. */ \ - if (s->tPos >= (UInt32)100000 * (UInt32)s->blockSize100k) return True; \ - cccc = BZ2_indexIntoF ( s->tPos, s->cftab ); \ - s->tPos = GET_LL(s->tPos); - - -/*-- externs for decompression. --*/ - -extern Int32 -BZ2_indexIntoF ( Int32, Int32* ); - -extern Int32 -BZ2_decompress ( DState* ); - -extern void -BZ2_hbCreateDecodeTables ( Int32*, Int32*, Int32*, UChar*, - Int32, Int32, Int32 ); - - -#endif - - -/*-- BZ_NO_STDIO seems to make NULL disappear on some platforms. --*/ - -#ifdef BZ_NO_STDIO -#ifndef NULL -#define NULL 0 -#endif -#endif - - -/*-------------------------------------------------------------*/ -/*--- end bzlib_private.h ---*/ -/*-------------------------------------------------------------*/ diff --git a/src/common/dep/bzip2/compress.c b/src/common/dep/bzip2/compress.c deleted file mode 100644 index 9e944ab67..000000000 --- a/src/common/dep/bzip2/compress.c +++ /dev/null @@ -1,672 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Compression machinery (not incl block sorting) ---*/ -/*--- compress.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -/* CHANGES - 0.9.0 -- original version. - 0.9.0a/b -- no changes in this file. - 0.9.0c -- changed setting of nGroups in sendMTFValues() - so as to do a bit better on small files -*/ - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -/*--- Bit stream I/O ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -void BZ2_bsInitWrite ( EState* s ) -{ - s->bsLive = 0; - s->bsBuff = 0; -} - - -/*---------------------------------------------------*/ -static -void bsFinishWrite ( EState* s ) -{ - while (s->bsLive > 0) { - s->zbits[s->numZ] = (UChar)(s->bsBuff >> 24); - s->numZ++; - s->bsBuff <<= 8; - s->bsLive -= 8; - } -} - - -/*---------------------------------------------------*/ -#define bsNEEDW(nz) \ -{ \ - while (s->bsLive >= 8) { \ - s->zbits[s->numZ] \ - = (UChar)(s->bsBuff >> 24); \ - s->numZ++; \ - s->bsBuff <<= 8; \ - s->bsLive -= 8; \ - } \ -} - - -/*---------------------------------------------------*/ -static -__inline__ -void bsW ( EState* s, Int32 n, UInt32 v ) -{ - bsNEEDW ( n ); - s->bsBuff |= (v << (32 - s->bsLive - n)); - s->bsLive += n; -} - - -/*---------------------------------------------------*/ -static -void bsPutUInt32 ( EState* s, UInt32 u ) -{ - bsW ( s, 8, (u >> 24) & 0xffL ); - bsW ( s, 8, (u >> 16) & 0xffL ); - bsW ( s, 8, (u >> 8) & 0xffL ); - bsW ( s, 8, u & 0xffL ); -} - - -/*---------------------------------------------------*/ -static -void bsPutUChar ( EState* s, UChar c ) -{ - bsW( s, 8, (UInt32)c ); -} - - -/*---------------------------------------------------*/ -/*--- The back end proper ---*/ -/*---------------------------------------------------*/ - -/*---------------------------------------------------*/ -static -void makeMaps_e ( EState* s ) -{ - Int32 i; - s->nInUse = 0; - for (i = 0; i < 256; i++) - if (s->inUse[i]) { - s->unseqToSeq[i] = s->nInUse; - s->nInUse++; - } -} - - -/*---------------------------------------------------*/ -static -void generateMTFValues ( EState* s ) -{ - UChar yy[256]; - Int32 i, j; - Int32 zPend; - Int32 wr; - Int32 EOB; - - /* - After sorting (eg, here), - s->arr1 [ 0 .. s->nblock-1 ] holds sorted order, - and - ((UChar*)s->arr2) [ 0 .. s->nblock-1 ] - holds the original block data. - - The first thing to do is generate the MTF values, - and put them in - ((UInt16*)s->arr1) [ 0 .. s->nblock-1 ]. - Because there are strictly fewer or equal MTF values - than block values, ptr values in this area are overwritten - with MTF values only when they are no longer needed. - - The final compressed bitstream is generated into the - area starting at - (UChar*) (&((UChar*)s->arr2)[s->nblock]) - - These storage aliases are set up in bzCompressInit(), - except for the last one, which is arranged in - compressBlock(). - */ - UInt32* ptr = s->ptr; - UChar* block = s->block; - UInt16* mtfv = s->mtfv; - - makeMaps_e ( s ); - EOB = s->nInUse+1; - - for (i = 0; i <= EOB; i++) s->mtfFreq[i] = 0; - - wr = 0; - zPend = 0; - for (i = 0; i < s->nInUse; i++) yy[i] = (UChar) i; - - for (i = 0; i < s->nblock; i++) { - UChar ll_i; - AssertD ( wr <= i, "generateMTFValues(1)" ); - j = ptr[i]-1; if (j < 0) j += s->nblock; - ll_i = s->unseqToSeq[block[j]]; - AssertD ( ll_i < s->nInUse, "generateMTFValues(2a)" ); - - if (yy[0] == ll_i) { - zPend++; - } else { - - if (zPend > 0) { - zPend--; - while (True) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) break; - zPend = (zPend - 2) / 2; - }; - zPend = 0; - } - { - register UChar rtmp; - register UChar* ryy_j; - register UChar rll_i; - rtmp = yy[1]; - yy[1] = yy[0]; - ryy_j = &(yy[1]); - rll_i = ll_i; - while ( rll_i != rtmp ) { - register UChar rtmp2; - ryy_j++; - rtmp2 = rtmp; - rtmp = *ryy_j; - *ryy_j = rtmp2; - }; - yy[0] = rtmp; - j = (Int32)(ryy_j - &(yy[0])); - mtfv[wr] = j+1; wr++; s->mtfFreq[j+1]++; - } - - } - } - - if (zPend > 0) { - zPend--; - while (True) { - if (zPend & 1) { - mtfv[wr] = BZ_RUNB; wr++; - s->mtfFreq[BZ_RUNB]++; - } else { - mtfv[wr] = BZ_RUNA; wr++; - s->mtfFreq[BZ_RUNA]++; - } - if (zPend < 2) break; - zPend = (zPend - 2) / 2; - }; - zPend = 0; - } - - mtfv[wr] = EOB; wr++; s->mtfFreq[EOB]++; - - s->nMTF = wr; -} - - -/*---------------------------------------------------*/ -#define BZ_LESSER_ICOST 0 -#define BZ_GREATER_ICOST 15 - -static -void sendMTFValues ( EState* s ) -{ - Int32 v, t, i, j, gs, ge, totc, bt, bc, iter; - Int32 nSelectors, alphaSize, minLen, maxLen, selCtr; - Int32 nGroups, nBytes; - - /*-- - UChar len [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - is a global since the decoder also needs it. - - Int32 code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - Int32 rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; - are also globals only used in this proc. - Made global to keep stack frame size small. - --*/ - - - UInt16 cost[BZ_N_GROUPS]; - Int32 fave[BZ_N_GROUPS]; - - UInt16* mtfv = s->mtfv; - - if (s->verbosity >= 3) - VPrintf3( " %d in block, %d after MTF & 1-2 coding, " - "%d+2 syms in use\n", - s->nblock, s->nMTF, s->nInUse ); - - alphaSize = s->nInUse+2; - for (t = 0; t < BZ_N_GROUPS; t++) - for (v = 0; v < alphaSize; v++) - s->len[t][v] = BZ_GREATER_ICOST; - - /*--- Decide how many coding tables to use ---*/ - AssertH ( s->nMTF > 0, 3001 ); - if (s->nMTF < 200) nGroups = 2; else - if (s->nMTF < 600) nGroups = 3; else - if (s->nMTF < 1200) nGroups = 4; else - if (s->nMTF < 2400) nGroups = 5; else - nGroups = 6; - - /*--- Generate an initial set of coding tables ---*/ - { - Int32 nPart, remF, tFreq, aFreq; - - nPart = nGroups; - remF = s->nMTF; - gs = 0; - while (nPart > 0) { - tFreq = remF / nPart; - ge = gs-1; - aFreq = 0; - while (aFreq < tFreq && ge < alphaSize-1) { - ge++; - aFreq += s->mtfFreq[ge]; - } - - if (ge > gs - && nPart != nGroups && nPart != 1 - && ((nGroups-nPart) % 2 == 1)) { - aFreq -= s->mtfFreq[ge]; - ge--; - } - - if (s->verbosity >= 3) - VPrintf5( " initial group %d, [%d .. %d], " - "has %d syms (%4.1f%%)\n", - nPart, gs, ge, aFreq, - (100.0 * (float)aFreq) / (float)(s->nMTF) ); - - for (v = 0; v < alphaSize; v++) - if (v >= gs && v <= ge) - s->len[nPart-1][v] = BZ_LESSER_ICOST; else - s->len[nPart-1][v] = BZ_GREATER_ICOST; - - nPart--; - gs = ge+1; - remF -= aFreq; - } - } - - /*--- - Iterate up to BZ_N_ITERS times to improve the tables. - ---*/ - for (iter = 0; iter < BZ_N_ITERS; iter++) { - - for (t = 0; t < nGroups; t++) fave[t] = 0; - - for (t = 0; t < nGroups; t++) - for (v = 0; v < alphaSize; v++) - s->rfreq[t][v] = 0; - - /*--- - Set up an auxiliary length table which is used to fast-track - the common case (nGroups == 6). - ---*/ - if (nGroups == 6) { - for (v = 0; v < alphaSize; v++) { - s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; - s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; - s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; - } - } - - nSelectors = 0; - totc = 0; - gs = 0; - while (True) { - - /*--- Set group start & end marks. --*/ - if (gs >= s->nMTF) break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) ge = s->nMTF-1; - - /*-- - Calculate the cost of this group as coded - by each of the coding tables. - --*/ - for (t = 0; t < nGroups; t++) cost[t] = 0; - - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - register UInt32 cost01, cost23, cost45; - register UInt16 icv; - cost01 = cost23 = cost45 = 0; - -# define BZ_ITER(nn) \ - icv = mtfv[gs+(nn)]; \ - cost01 += s->len_pack[icv][0]; \ - cost23 += s->len_pack[icv][1]; \ - cost45 += s->len_pack[icv][2]; \ - - BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); - BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); - BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); - BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); - BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); - BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); - BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); - BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); - BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); - BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); - -# undef BZ_ITER - - cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; - cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; - cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) { - UInt16 icv = mtfv[i]; - for (t = 0; t < nGroups; t++) cost[t] += s->len[t][icv]; - } - } - - /*-- - Find the coding table which is best for this group, - and record its identity in the selector table. - --*/ - bc = 999999999; bt = -1; - for (t = 0; t < nGroups; t++) - if (cost[t] < bc) { bc = cost[t]; bt = t; }; - totc += bc; - fave[bt]++; - s->selector[nSelectors] = bt; - nSelectors++; - - /*-- - Increment the symbol frequencies for the selected table. - --*/ - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - -# define BZ_ITUR(nn) s->rfreq[bt][ mtfv[gs+(nn)] ]++ - - BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); - BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); - BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); - BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); - BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); - BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); - BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); - BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); - BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); - BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); - -# undef BZ_ITUR - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) - s->rfreq[bt][ mtfv[i] ]++; - } - - gs = ge+1; - } - if (s->verbosity >= 3) { - VPrintf2 ( " pass %d: size is %d, grp uses are ", - iter+1, totc/8 ); - for (t = 0; t < nGroups; t++) - VPrintf1 ( "%d ", fave[t] ); - VPrintf0 ( "\n" ); - } - - /*-- - Recompute the tables based on the accumulated frequencies. - --*/ - /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See - comment in huffman.c for details. */ - for (t = 0; t < nGroups; t++) - BZ2_hbMakeCodeLengths ( &(s->len[t][0]), &(s->rfreq[t][0]), - alphaSize, 17 /*20*/ ); - } - - - AssertH( nGroups < 8, 3002 ); - AssertH( nSelectors < 32768 && - nSelectors <= (2 + (900000 / BZ_G_SIZE)), - 3003 ); - - - /*--- Compute MTF values for the selectors. ---*/ - { - UChar pos[BZ_N_GROUPS], ll_i, tmp2, tmp; - for (i = 0; i < nGroups; i++) pos[i] = i; - for (i = 0; i < nSelectors; i++) { - ll_i = s->selector[i]; - j = 0; - tmp = pos[j]; - while ( ll_i != tmp ) { - j++; - tmp2 = tmp; - tmp = pos[j]; - pos[j] = tmp2; - }; - pos[0] = tmp; - s->selectorMtf[i] = j; - } - }; - - /*--- Assign actual codes for the tables. --*/ - for (t = 0; t < nGroups; t++) { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) { - if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; - if (s->len[t][i] < minLen) minLen = s->len[t][i]; - } - AssertH ( !(maxLen > 17 /*20*/ ), 3004 ); - AssertH ( !(minLen < 1), 3005 ); - BZ2_hbAssignCodes ( &(s->code[t][0]), &(s->len[t][0]), - minLen, maxLen, alphaSize ); - } - - /*--- Transmit the mapping table. ---*/ - { - Bool inUse16[16]; - for (i = 0; i < 16; i++) { - inUse16[i] = False; - for (j = 0; j < 16; j++) - if (s->inUse[i * 16 + j]) inUse16[i] = True; - } - - nBytes = s->numZ; - for (i = 0; i < 16; i++) - if (inUse16[i]) bsW(s,1,1); else bsW(s,1,0); - - for (i = 0; i < 16; i++) - if (inUse16[i]) - for (j = 0; j < 16; j++) { - if (s->inUse[i * 16 + j]) bsW(s,1,1); else bsW(s,1,0); - } - - if (s->verbosity >= 3) - VPrintf1( " bytes: mapping %d, ", s->numZ-nBytes ); - } - - /*--- Now the selectors. ---*/ - nBytes = s->numZ; - bsW ( s, 3, nGroups ); - bsW ( s, 15, nSelectors ); - for (i = 0; i < nSelectors; i++) { - for (j = 0; j < s->selectorMtf[i]; j++) bsW(s,1,1); - bsW(s,1,0); - } - if (s->verbosity >= 3) - VPrintf1( "selectors %d, ", s->numZ-nBytes ); - - /*--- Now the coding tables. ---*/ - nBytes = s->numZ; - - for (t = 0; t < nGroups; t++) { - Int32 curr = s->len[t][0]; - bsW ( s, 5, curr ); - for (i = 0; i < alphaSize; i++) { - while (curr < s->len[t][i]) { bsW(s,2,2); curr++; /* 10 */ }; - while (curr > s->len[t][i]) { bsW(s,2,3); curr--; /* 11 */ }; - bsW ( s, 1, 0 ); - } - } - - if (s->verbosity >= 3) - VPrintf1 ( "code lengths %d, ", s->numZ-nBytes ); - - /*--- And finally, the block data proper ---*/ - nBytes = s->numZ; - selCtr = 0; - gs = 0; - while (True) { - if (gs >= s->nMTF) break; - ge = gs + BZ_G_SIZE - 1; - if (ge >= s->nMTF) ge = s->nMTF-1; - AssertH ( s->selector[selCtr] < nGroups, 3006 ); - - if (nGroups == 6 && 50 == ge-gs+1) { - /*--- fast track the common case ---*/ - UInt16 mtfv_i; - UChar* s_len_sel_selCtr - = &(s->len[s->selector[selCtr]][0]); - Int32* s_code_sel_selCtr - = &(s->code[s->selector[selCtr]][0]); - -# define BZ_ITAH(nn) \ - mtfv_i = mtfv[gs+(nn)]; \ - bsW ( s, \ - s_len_sel_selCtr[mtfv_i], \ - s_code_sel_selCtr[mtfv_i] ) - - BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); - BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); - BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); - BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); - BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); - BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); - BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); - BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); - BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); - BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); - -# undef BZ_ITAH - - } else { - /*--- slow version which correctly handles all situations ---*/ - for (i = gs; i <= ge; i++) { - bsW ( s, - s->len [s->selector[selCtr]] [mtfv[i]], - s->code [s->selector[selCtr]] [mtfv[i]] ); - } - } - - - gs = ge+1; - selCtr++; - } - AssertH( selCtr == nSelectors, 3007 ); - - if (s->verbosity >= 3) - VPrintf1( "codes %d\n", s->numZ-nBytes ); -} - - -/*---------------------------------------------------*/ -void BZ2_compressBlock ( EState* s, Bool is_last_block ) -{ - if (s->nblock > 0) { - - BZ_FINALISE_CRC ( s->blockCRC ); - s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); - s->combinedCRC ^= s->blockCRC; - if (s->blockNo > 1) s->numZ = 0; - - if (s->verbosity >= 2) - VPrintf4( " block %d: crc = 0x%08x, " - "combined CRC = 0x%08x, size = %d\n", - s->blockNo, s->blockCRC, s->combinedCRC, s->nblock ); - - BZ2_blockSort ( s ); - } - - s->zbits = (UChar*) (&((UChar*)s->arr2)[s->nblock]); - - /*-- If this is the first block, create the stream header. --*/ - if (s->blockNo == 1) { - BZ2_bsInitWrite ( s ); - bsPutUChar ( s, BZ_HDR_B ); - bsPutUChar ( s, BZ_HDR_Z ); - bsPutUChar ( s, BZ_HDR_h ); - bsPutUChar ( s, (UChar)(BZ_HDR_0 + s->blockSize100k) ); - } - - if (s->nblock > 0) { - - bsPutUChar ( s, 0x31 ); bsPutUChar ( s, 0x41 ); - bsPutUChar ( s, 0x59 ); bsPutUChar ( s, 0x26 ); - bsPutUChar ( s, 0x53 ); bsPutUChar ( s, 0x59 ); - - /*-- Now the block's CRC, so it is in a known place. --*/ - bsPutUInt32 ( s, s->blockCRC ); - - /*-- - Now a single bit indicating (non-)randomisation. - As of version 0.9.5, we use a better sorting algorithm - which makes randomisation unnecessary. So always set - the randomised bit to 'no'. Of course, the decoder - still needs to be able to handle randomised blocks - so as to maintain backwards compatibility with - older versions of bzip2. - --*/ - bsW(s,1,0); - - bsW ( s, 24, s->origPtr ); - generateMTFValues ( s ); - sendMTFValues ( s ); - } - - - /*-- If this is the last block, add the stream trailer. --*/ - if (is_last_block) { - - bsPutUChar ( s, 0x17 ); bsPutUChar ( s, 0x72 ); - bsPutUChar ( s, 0x45 ); bsPutUChar ( s, 0x38 ); - bsPutUChar ( s, 0x50 ); bsPutUChar ( s, 0x90 ); - bsPutUInt32 ( s, s->combinedCRC ); - if (s->verbosity >= 2) - VPrintf1( " final combined CRC = 0x%08x\n ", s->combinedCRC ); - bsFinishWrite ( s ); - } -} - - -/*-------------------------------------------------------------*/ -/*--- end compress.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/src/common/dep/bzip2/crctable.c b/src/common/dep/bzip2/crctable.c deleted file mode 100644 index 1fea7e946..000000000 --- a/src/common/dep/bzip2/crctable.c +++ /dev/null @@ -1,104 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Table for doing CRCs ---*/ -/*--- crctable.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - -/*-- - I think this is an implementation of the AUTODIN-II, - Ethernet & FDDI 32-bit CRC standard. Vaguely derived - from code by Rob Warnock, in Section 51 of the - comp.compression FAQ. ---*/ - -UInt32 BZ2_crc32Table[256] = { - - /*-- Ugly, innit? --*/ - - 0x00000000L, 0x04c11db7L, 0x09823b6eL, 0x0d4326d9L, - 0x130476dcL, 0x17c56b6bL, 0x1a864db2L, 0x1e475005L, - 0x2608edb8L, 0x22c9f00fL, 0x2f8ad6d6L, 0x2b4bcb61L, - 0x350c9b64L, 0x31cd86d3L, 0x3c8ea00aL, 0x384fbdbdL, - 0x4c11db70L, 0x48d0c6c7L, 0x4593e01eL, 0x4152fda9L, - 0x5f15adacL, 0x5bd4b01bL, 0x569796c2L, 0x52568b75L, - 0x6a1936c8L, 0x6ed82b7fL, 0x639b0da6L, 0x675a1011L, - 0x791d4014L, 0x7ddc5da3L, 0x709f7b7aL, 0x745e66cdL, - 0x9823b6e0L, 0x9ce2ab57L, 0x91a18d8eL, 0x95609039L, - 0x8b27c03cL, 0x8fe6dd8bL, 0x82a5fb52L, 0x8664e6e5L, - 0xbe2b5b58L, 0xbaea46efL, 0xb7a96036L, 0xb3687d81L, - 0xad2f2d84L, 0xa9ee3033L, 0xa4ad16eaL, 0xa06c0b5dL, - 0xd4326d90L, 0xd0f37027L, 0xddb056feL, 0xd9714b49L, - 0xc7361b4cL, 0xc3f706fbL, 0xceb42022L, 0xca753d95L, - 0xf23a8028L, 0xf6fb9d9fL, 0xfbb8bb46L, 0xff79a6f1L, - 0xe13ef6f4L, 0xe5ffeb43L, 0xe8bccd9aL, 0xec7dd02dL, - 0x34867077L, 0x30476dc0L, 0x3d044b19L, 0x39c556aeL, - 0x278206abL, 0x23431b1cL, 0x2e003dc5L, 0x2ac12072L, - 0x128e9dcfL, 0x164f8078L, 0x1b0ca6a1L, 0x1fcdbb16L, - 0x018aeb13L, 0x054bf6a4L, 0x0808d07dL, 0x0cc9cdcaL, - 0x7897ab07L, 0x7c56b6b0L, 0x71159069L, 0x75d48ddeL, - 0x6b93dddbL, 0x6f52c06cL, 0x6211e6b5L, 0x66d0fb02L, - 0x5e9f46bfL, 0x5a5e5b08L, 0x571d7dd1L, 0x53dc6066L, - 0x4d9b3063L, 0x495a2dd4L, 0x44190b0dL, 0x40d816baL, - 0xaca5c697L, 0xa864db20L, 0xa527fdf9L, 0xa1e6e04eL, - 0xbfa1b04bL, 0xbb60adfcL, 0xb6238b25L, 0xb2e29692L, - 0x8aad2b2fL, 0x8e6c3698L, 0x832f1041L, 0x87ee0df6L, - 0x99a95df3L, 0x9d684044L, 0x902b669dL, 0x94ea7b2aL, - 0xe0b41de7L, 0xe4750050L, 0xe9362689L, 0xedf73b3eL, - 0xf3b06b3bL, 0xf771768cL, 0xfa325055L, 0xfef34de2L, - 0xc6bcf05fL, 0xc27dede8L, 0xcf3ecb31L, 0xcbffd686L, - 0xd5b88683L, 0xd1799b34L, 0xdc3abdedL, 0xd8fba05aL, - 0x690ce0eeL, 0x6dcdfd59L, 0x608edb80L, 0x644fc637L, - 0x7a089632L, 0x7ec98b85L, 0x738aad5cL, 0x774bb0ebL, - 0x4f040d56L, 0x4bc510e1L, 0x46863638L, 0x42472b8fL, - 0x5c007b8aL, 0x58c1663dL, 0x558240e4L, 0x51435d53L, - 0x251d3b9eL, 0x21dc2629L, 0x2c9f00f0L, 0x285e1d47L, - 0x36194d42L, 0x32d850f5L, 0x3f9b762cL, 0x3b5a6b9bL, - 0x0315d626L, 0x07d4cb91L, 0x0a97ed48L, 0x0e56f0ffL, - 0x1011a0faL, 0x14d0bd4dL, 0x19939b94L, 0x1d528623L, - 0xf12f560eL, 0xf5ee4bb9L, 0xf8ad6d60L, 0xfc6c70d7L, - 0xe22b20d2L, 0xe6ea3d65L, 0xeba91bbcL, 0xef68060bL, - 0xd727bbb6L, 0xd3e6a601L, 0xdea580d8L, 0xda649d6fL, - 0xc423cd6aL, 0xc0e2d0ddL, 0xcda1f604L, 0xc960ebb3L, - 0xbd3e8d7eL, 0xb9ff90c9L, 0xb4bcb610L, 0xb07daba7L, - 0xae3afba2L, 0xaafbe615L, 0xa7b8c0ccL, 0xa379dd7bL, - 0x9b3660c6L, 0x9ff77d71L, 0x92b45ba8L, 0x9675461fL, - 0x8832161aL, 0x8cf30badL, 0x81b02d74L, 0x857130c3L, - 0x5d8a9099L, 0x594b8d2eL, 0x5408abf7L, 0x50c9b640L, - 0x4e8ee645L, 0x4a4ffbf2L, 0x470cdd2bL, 0x43cdc09cL, - 0x7b827d21L, 0x7f436096L, 0x7200464fL, 0x76c15bf8L, - 0x68860bfdL, 0x6c47164aL, 0x61043093L, 0x65c52d24L, - 0x119b4be9L, 0x155a565eL, 0x18197087L, 0x1cd86d30L, - 0x029f3d35L, 0x065e2082L, 0x0b1d065bL, 0x0fdc1becL, - 0x3793a651L, 0x3352bbe6L, 0x3e119d3fL, 0x3ad08088L, - 0x2497d08dL, 0x2056cd3aL, 0x2d15ebe3L, 0x29d4f654L, - 0xc5a92679L, 0xc1683bceL, 0xcc2b1d17L, 0xc8ea00a0L, - 0xd6ad50a5L, 0xd26c4d12L, 0xdf2f6bcbL, 0xdbee767cL, - 0xe3a1cbc1L, 0xe760d676L, 0xea23f0afL, 0xeee2ed18L, - 0xf0a5bd1dL, 0xf464a0aaL, 0xf9278673L, 0xfde69bc4L, - 0x89b8fd09L, 0x8d79e0beL, 0x803ac667L, 0x84fbdbd0L, - 0x9abc8bd5L, 0x9e7d9662L, 0x933eb0bbL, 0x97ffad0cL, - 0xafb010b1L, 0xab710d06L, 0xa6322bdfL, 0xa2f33668L, - 0xbcb4666dL, 0xb8757bdaL, 0xb5365d03L, 0xb1f740b4L -}; - - -/*-------------------------------------------------------------*/ -/*--- end crctable.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/src/common/dep/bzip2/decompress.c b/src/common/dep/bzip2/decompress.c deleted file mode 100644 index 311f5668f..000000000 --- a/src/common/dep/bzip2/decompress.c +++ /dev/null @@ -1,646 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Decompression machinery ---*/ -/*--- decompress.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - - -/*---------------------------------------------------*/ -static -void makeMaps_d ( DState* s ) -{ - Int32 i; - s->nInUse = 0; - for (i = 0; i < 256; i++) - if (s->inUse[i]) { - s->seqToUnseq[s->nInUse] = i; - s->nInUse++; - } -} - - -/*---------------------------------------------------*/ -#define RETURN(rrr) \ - { retVal = rrr; goto save_state_and_return; }; - -#define GET_BITS(lll,vvv,nnn) \ - case lll: s->state = lll; \ - while (True) { \ - if (s->bsLive >= nnn) { \ - UInt32 v; \ - v = (s->bsBuff >> \ - (s->bsLive-nnn)) & ((1 << nnn)-1); \ - s->bsLive -= nnn; \ - vvv = v; \ - break; \ - } \ - if (s->strm->avail_in == 0) RETURN(BZ_OK); \ - s->bsBuff \ - = (s->bsBuff << 8) | \ - ((UInt32) \ - (*((UChar*)(s->strm->next_in)))); \ - s->bsLive += 8; \ - s->strm->next_in++; \ - s->strm->avail_in--; \ - s->strm->total_in_lo32++; \ - if (s->strm->total_in_lo32 == 0) \ - s->strm->total_in_hi32++; \ - } - -#define GET_UCHAR(lll,uuu) \ - GET_BITS(lll,uuu,8) - -#define GET_BIT(lll,uuu) \ - GET_BITS(lll,uuu,1) - -/*---------------------------------------------------*/ -#define GET_MTF_VAL(label1,label2,lval) \ -{ \ - if (groupPos == 0) { \ - groupNo++; \ - if (groupNo >= nSelectors) \ - RETURN(BZ_DATA_ERROR); \ - groupPos = BZ_G_SIZE; \ - gSel = s->selector[groupNo]; \ - gMinlen = s->minLens[gSel]; \ - gLimit = &(s->limit[gSel][0]); \ - gPerm = &(s->perm[gSel][0]); \ - gBase = &(s->base[gSel][0]); \ - } \ - groupPos--; \ - zn = gMinlen; \ - GET_BITS(label1, zvec, zn); \ - while (1) { \ - if (zn > 20 /* the longest code */) \ - RETURN(BZ_DATA_ERROR); \ - if (zvec <= gLimit[zn]) break; \ - zn++; \ - GET_BIT(label2, zj); \ - zvec = (zvec << 1) | zj; \ - }; \ - if (zvec - gBase[zn] < 0 \ - || zvec - gBase[zn] >= BZ_MAX_ALPHA_SIZE) \ - RETURN(BZ_DATA_ERROR); \ - lval = gPerm[zvec - gBase[zn]]; \ -} - - -/*---------------------------------------------------*/ -Int32 BZ2_decompress ( DState* s ) -{ - UChar uc; - Int32 retVal; - Int32 minLen, maxLen; - bz_stream* strm = s->strm; - - /* stuff that needs to be saved/restored */ - Int32 i; - Int32 j; - Int32 t; - Int32 alphaSize; - Int32 nGroups; - Int32 nSelectors; - Int32 EOB; - Int32 groupNo; - Int32 groupPos; - Int32 nextSym; - Int32 nblockMAX; - Int32 nblock; - Int32 es; - Int32 N; - Int32 curr; - Int32 zt; - Int32 zn; - Int32 zvec; - Int32 zj; - Int32 gSel; - Int32 gMinlen; - Int32* gLimit; - Int32* gBase; - Int32* gPerm; - - if (s->state == BZ_X_MAGIC_1) { - /*initialise the save area*/ - s->save_i = 0; - s->save_j = 0; - s->save_t = 0; - s->save_alphaSize = 0; - s->save_nGroups = 0; - s->save_nSelectors = 0; - s->save_EOB = 0; - s->save_groupNo = 0; - s->save_groupPos = 0; - s->save_nextSym = 0; - s->save_nblockMAX = 0; - s->save_nblock = 0; - s->save_es = 0; - s->save_N = 0; - s->save_curr = 0; - s->save_zt = 0; - s->save_zn = 0; - s->save_zvec = 0; - s->save_zj = 0; - s->save_gSel = 0; - s->save_gMinlen = 0; - s->save_gLimit = NULL; - s->save_gBase = NULL; - s->save_gPerm = NULL; - } - - /*restore from the save area*/ - i = s->save_i; - j = s->save_j; - t = s->save_t; - alphaSize = s->save_alphaSize; - nGroups = s->save_nGroups; - nSelectors = s->save_nSelectors; - EOB = s->save_EOB; - groupNo = s->save_groupNo; - groupPos = s->save_groupPos; - nextSym = s->save_nextSym; - nblockMAX = s->save_nblockMAX; - nblock = s->save_nblock; - es = s->save_es; - N = s->save_N; - curr = s->save_curr; - zt = s->save_zt; - zn = s->save_zn; - zvec = s->save_zvec; - zj = s->save_zj; - gSel = s->save_gSel; - gMinlen = s->save_gMinlen; - gLimit = s->save_gLimit; - gBase = s->save_gBase; - gPerm = s->save_gPerm; - - retVal = BZ_OK; - - switch (s->state) { - - GET_UCHAR(BZ_X_MAGIC_1, uc); - if (uc != BZ_HDR_B) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_UCHAR(BZ_X_MAGIC_2, uc); - if (uc != BZ_HDR_Z) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_UCHAR(BZ_X_MAGIC_3, uc) - if (uc != BZ_HDR_h) RETURN(BZ_DATA_ERROR_MAGIC); - - GET_BITS(BZ_X_MAGIC_4, s->blockSize100k, 8) - if (s->blockSize100k < (BZ_HDR_0 + 1) || - s->blockSize100k > (BZ_HDR_0 + 9)) RETURN(BZ_DATA_ERROR_MAGIC); - s->blockSize100k -= BZ_HDR_0; - - if (s->smallDecompress) { - s->ll16 = BZALLOC( s->blockSize100k * 100000 * sizeof(UInt16) ); - s->ll4 = BZALLOC( - ((1 + s->blockSize100k * 100000) >> 1) * sizeof(UChar) - ); - if (s->ll16 == NULL || s->ll4 == NULL) RETURN(BZ_MEM_ERROR); - } else { - s->tt = BZALLOC( s->blockSize100k * 100000 * sizeof(Int32) ); - if (s->tt == NULL) RETURN(BZ_MEM_ERROR); - } - - GET_UCHAR(BZ_X_BLKHDR_1, uc); - - if (uc == 0x17) goto endhdr_2; - if (uc != 0x31) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_2, uc); - if (uc != 0x41) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_3, uc); - if (uc != 0x59) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_4, uc); - if (uc != 0x26) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_5, uc); - if (uc != 0x53) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_BLKHDR_6, uc); - if (uc != 0x59) RETURN(BZ_DATA_ERROR); - - s->currBlockNo++; - if (s->verbosity >= 2) - VPrintf1 ( "\n [%d: huff+mtf ", s->currBlockNo ); - - s->storedBlockCRC = 0; - GET_UCHAR(BZ_X_BCRC_1, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_2, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_3, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_BCRC_4, uc); - s->storedBlockCRC = (s->storedBlockCRC << 8) | ((UInt32)uc); - - GET_BITS(BZ_X_RANDBIT, s->blockRandomised, 1); - - s->origPtr = 0; - GET_UCHAR(BZ_X_ORIGPTR_1, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - GET_UCHAR(BZ_X_ORIGPTR_2, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - GET_UCHAR(BZ_X_ORIGPTR_3, uc); - s->origPtr = (s->origPtr << 8) | ((Int32)uc); - - if (s->origPtr < 0) - RETURN(BZ_DATA_ERROR); - if (s->origPtr > 10 + 100000*s->blockSize100k) - RETURN(BZ_DATA_ERROR); - - /*--- Receive the mapping table ---*/ - for (i = 0; i < 16; i++) { - GET_BIT(BZ_X_MAPPING_1, uc); - if (uc == 1) - s->inUse16[i] = True; else - s->inUse16[i] = False; - } - - for (i = 0; i < 256; i++) s->inUse[i] = False; - - for (i = 0; i < 16; i++) - if (s->inUse16[i]) - for (j = 0; j < 16; j++) { - GET_BIT(BZ_X_MAPPING_2, uc); - if (uc == 1) s->inUse[i * 16 + j] = True; - } - makeMaps_d ( s ); - if (s->nInUse == 0) RETURN(BZ_DATA_ERROR); - alphaSize = s->nInUse+2; - - /*--- Now the selectors ---*/ - GET_BITS(BZ_X_SELECTOR_1, nGroups, 3); - if (nGroups < 2 || nGroups > 6) RETURN(BZ_DATA_ERROR); - GET_BITS(BZ_X_SELECTOR_2, nSelectors, 15); - if (nSelectors < 1) RETURN(BZ_DATA_ERROR); - for (i = 0; i < nSelectors; i++) { - j = 0; - while (True) { - GET_BIT(BZ_X_SELECTOR_3, uc); - if (uc == 0) break; - j++; - if (j >= nGroups) RETURN(BZ_DATA_ERROR); - } - s->selectorMtf[i] = j; - } - - /*--- Undo the MTF values for the selectors. ---*/ - { - UChar pos[BZ_N_GROUPS], tmp, v; - for (v = 0; v < nGroups; v++) pos[v] = v; - - for (i = 0; i < nSelectors; i++) { - v = s->selectorMtf[i]; - tmp = pos[v]; - while (v > 0) { pos[v] = pos[v-1]; v--; } - pos[0] = tmp; - s->selector[i] = tmp; - } - } - - /*--- Now the coding tables ---*/ - for (t = 0; t < nGroups; t++) { - GET_BITS(BZ_X_CODING_1, curr, 5); - for (i = 0; i < alphaSize; i++) { - while (True) { - if (curr < 1 || curr > 20) RETURN(BZ_DATA_ERROR); - GET_BIT(BZ_X_CODING_2, uc); - if (uc == 0) break; - GET_BIT(BZ_X_CODING_3, uc); - if (uc == 0) curr++; else curr--; - } - s->len[t][i] = curr; - } - } - - /*--- Create the Huffman decoding tables ---*/ - for (t = 0; t < nGroups; t++) { - minLen = 32; - maxLen = 0; - for (i = 0; i < alphaSize; i++) { - if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; - if (s->len[t][i] < minLen) minLen = s->len[t][i]; - } - BZ2_hbCreateDecodeTables ( - &(s->limit[t][0]), - &(s->base[t][0]), - &(s->perm[t][0]), - &(s->len[t][0]), - minLen, maxLen, alphaSize - ); - s->minLens[t] = minLen; - } - - /*--- Now the MTF values ---*/ - - EOB = s->nInUse+1; - nblockMAX = 100000 * s->blockSize100k; - groupNo = -1; - groupPos = 0; - - for (i = 0; i <= 255; i++) s->unzftab[i] = 0; - - /*-- MTF init --*/ - { - Int32 ii, jj, kk; - kk = MTFA_SIZE-1; - for (ii = 256 / MTFL_SIZE - 1; ii >= 0; ii--) { - for (jj = MTFL_SIZE-1; jj >= 0; jj--) { - s->mtfa[kk] = (UChar)(ii * MTFL_SIZE + jj); - kk--; - } - s->mtfbase[ii] = kk + 1; - } - } - /*-- end MTF init --*/ - - nblock = 0; - GET_MTF_VAL(BZ_X_MTF_1, BZ_X_MTF_2, nextSym); - - while (True) { - - if (nextSym == EOB) break; - - if (nextSym == BZ_RUNA || nextSym == BZ_RUNB) { - - es = -1; - N = 1; - do { - /* Check that N doesn't get too big, so that es doesn't - go negative. The maximum value that can be - RUNA/RUNB encoded is equal to the block size (post - the initial RLE), viz, 900k, so bounding N at 2 - million should guard against overflow without - rejecting any legitimate inputs. */ - if (N >= 2*1024*1024) RETURN(BZ_DATA_ERROR); - if (nextSym == BZ_RUNA) es = es + (0+1) * N; else - if (nextSym == BZ_RUNB) es = es + (1+1) * N; - N = N * 2; - GET_MTF_VAL(BZ_X_MTF_3, BZ_X_MTF_4, nextSym); - } - while (nextSym == BZ_RUNA || nextSym == BZ_RUNB); - - es++; - uc = s->seqToUnseq[ s->mtfa[s->mtfbase[0]] ]; - s->unzftab[uc] += es; - - if (s->smallDecompress) - while (es > 0) { - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - s->ll16[nblock] = (UInt16)uc; - nblock++; - es--; - } - else - while (es > 0) { - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - s->tt[nblock] = (UInt32)uc; - nblock++; - es--; - }; - - continue; - - } else { - - if (nblock >= nblockMAX) RETURN(BZ_DATA_ERROR); - - /*-- uc = MTF ( nextSym-1 ) --*/ - { - Int32 ii, jj, kk, pp, lno, off; - UInt32 nn; - nn = (UInt32)(nextSym - 1); - - if (nn < MTFL_SIZE) { - /* avoid general-case expense */ - pp = s->mtfbase[0]; - uc = s->mtfa[pp+nn]; - while (nn > 3) { - Int32 z = pp+nn; - s->mtfa[(z) ] = s->mtfa[(z)-1]; - s->mtfa[(z)-1] = s->mtfa[(z)-2]; - s->mtfa[(z)-2] = s->mtfa[(z)-3]; - s->mtfa[(z)-3] = s->mtfa[(z)-4]; - nn -= 4; - } - while (nn > 0) { - s->mtfa[(pp+nn)] = s->mtfa[(pp+nn)-1]; nn--; - }; - s->mtfa[pp] = uc; - } else { - /* general case */ - lno = nn / MTFL_SIZE; - off = nn % MTFL_SIZE; - pp = s->mtfbase[lno] + off; - uc = s->mtfa[pp]; - while (pp > s->mtfbase[lno]) { - s->mtfa[pp] = s->mtfa[pp-1]; pp--; - }; - s->mtfbase[lno]++; - while (lno > 0) { - s->mtfbase[lno]--; - s->mtfa[s->mtfbase[lno]] - = s->mtfa[s->mtfbase[lno-1] + MTFL_SIZE - 1]; - lno--; - } - s->mtfbase[0]--; - s->mtfa[s->mtfbase[0]] = uc; - if (s->mtfbase[0] == 0) { - kk = MTFA_SIZE-1; - for (ii = 256 / MTFL_SIZE-1; ii >= 0; ii--) { - for (jj = MTFL_SIZE-1; jj >= 0; jj--) { - s->mtfa[kk] = s->mtfa[s->mtfbase[ii] + jj]; - kk--; - } - s->mtfbase[ii] = kk + 1; - } - } - } - } - /*-- end uc = MTF ( nextSym-1 ) --*/ - - s->unzftab[s->seqToUnseq[uc]]++; - if (s->smallDecompress) - s->ll16[nblock] = (UInt16)(s->seqToUnseq[uc]); else - s->tt[nblock] = (UInt32)(s->seqToUnseq[uc]); - nblock++; - - GET_MTF_VAL(BZ_X_MTF_5, BZ_X_MTF_6, nextSym); - continue; - } - } - - /* Now we know what nblock is, we can do a better sanity - check on s->origPtr. - */ - if (s->origPtr < 0 || s->origPtr >= nblock) - RETURN(BZ_DATA_ERROR); - - /*-- Set up cftab to facilitate generation of T^(-1) --*/ - /* Check: unzftab entries in range. */ - for (i = 0; i <= 255; i++) { - if (s->unzftab[i] < 0 || s->unzftab[i] > nblock) - RETURN(BZ_DATA_ERROR); - } - /* Actually generate cftab. */ - s->cftab[0] = 0; - for (i = 1; i <= 256; i++) s->cftab[i] = s->unzftab[i-1]; - for (i = 1; i <= 256; i++) s->cftab[i] += s->cftab[i-1]; - /* Check: cftab entries in range. */ - for (i = 0; i <= 256; i++) { - if (s->cftab[i] < 0 || s->cftab[i] > nblock) { - /* s->cftab[i] can legitimately be == nblock */ - RETURN(BZ_DATA_ERROR); - } - } - /* Check: cftab entries non-descending. */ - for (i = 1; i <= 256; i++) { - if (s->cftab[i-1] > s->cftab[i]) { - RETURN(BZ_DATA_ERROR); - } - } - - s->state_out_len = 0; - s->state_out_ch = 0; - BZ_INITIALISE_CRC ( s->calculatedBlockCRC ); - s->state = BZ_X_OUTPUT; - if (s->verbosity >= 2) VPrintf0 ( "rt+rld" ); - - if (s->smallDecompress) { - - /*-- Make a copy of cftab, used in generation of T --*/ - for (i = 0; i <= 256; i++) s->cftabCopy[i] = s->cftab[i]; - - /*-- compute the T vector --*/ - for (i = 0; i < nblock; i++) { - uc = (UChar)(s->ll16[i]); - SET_LL(i, s->cftabCopy[uc]); - s->cftabCopy[uc]++; - } - - /*-- Compute T^(-1) by pointer reversal on T --*/ - i = s->origPtr; - j = GET_LL(i); - do { - Int32 tmp = GET_LL(j); - SET_LL(j, i); - i = j; - j = tmp; - } - while (i != s->origPtr); - - s->tPos = s->origPtr; - s->nblock_used = 0; - if (s->blockRandomised) { - BZ_RAND_INIT_MASK; - BZ_GET_SMALL(s->k0); s->nblock_used++; - BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; - } else { - BZ_GET_SMALL(s->k0); s->nblock_used++; - } - - } else { - - /*-- compute the T^(-1) vector --*/ - for (i = 0; i < nblock; i++) { - uc = (UChar)(s->tt[i] & 0xff); - s->tt[s->cftab[uc]] |= (i << 8); - s->cftab[uc]++; - } - - s->tPos = s->tt[s->origPtr] >> 8; - s->nblock_used = 0; - if (s->blockRandomised) { - BZ_RAND_INIT_MASK; - BZ_GET_FAST(s->k0); s->nblock_used++; - BZ_RAND_UPD_MASK; s->k0 ^= BZ_RAND_MASK; - } else { - BZ_GET_FAST(s->k0); s->nblock_used++; - } - - } - - RETURN(BZ_OK); - - - - endhdr_2: - - GET_UCHAR(BZ_X_ENDHDR_2, uc); - if (uc != 0x72) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_3, uc); - if (uc != 0x45) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_4, uc); - if (uc != 0x38) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_5, uc); - if (uc != 0x50) RETURN(BZ_DATA_ERROR); - GET_UCHAR(BZ_X_ENDHDR_6, uc); - if (uc != 0x90) RETURN(BZ_DATA_ERROR); - - s->storedCombinedCRC = 0; - GET_UCHAR(BZ_X_CCRC_1, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_2, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_3, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - GET_UCHAR(BZ_X_CCRC_4, uc); - s->storedCombinedCRC = (s->storedCombinedCRC << 8) | ((UInt32)uc); - - s->state = BZ_X_IDLE; - RETURN(BZ_STREAM_END); - - default: AssertH ( False, 4001 ); - } - - AssertH ( False, 4002 ); - - save_state_and_return: - - s->save_i = i; - s->save_j = j; - s->save_t = t; - s->save_alphaSize = alphaSize; - s->save_nGroups = nGroups; - s->save_nSelectors = nSelectors; - s->save_EOB = EOB; - s->save_groupNo = groupNo; - s->save_groupPos = groupPos; - s->save_nextSym = nextSym; - s->save_nblockMAX = nblockMAX; - s->save_nblock = nblock; - s->save_es = es; - s->save_N = N; - s->save_curr = curr; - s->save_zt = zt; - s->save_zn = zn; - s->save_zvec = zvec; - s->save_zj = zj; - s->save_gSel = gSel; - s->save_gMinlen = gMinlen; - s->save_gLimit = gLimit; - s->save_gBase = gBase; - s->save_gPerm = gPerm; - - return retVal; -} - - -/*-------------------------------------------------------------*/ -/*--- end decompress.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/src/common/dep/bzip2/huffman.c b/src/common/dep/bzip2/huffman.c deleted file mode 100644 index 2283fdbc5..000000000 --- a/src/common/dep/bzip2/huffman.c +++ /dev/null @@ -1,205 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Huffman coding low-level stuff ---*/ -/*--- huffman.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - -/*---------------------------------------------------*/ -#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) -#define DEPTHOF(zz1) ((zz1) & 0x000000ff) -#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) - -#define ADDWEIGHTS(zw1,zw2) \ - (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ - (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) - -#define UPHEAP(z) \ -{ \ - Int32 zz, tmp; \ - zz = z; tmp = heap[zz]; \ - while (weight[tmp] < weight[heap[zz >> 1]]) { \ - heap[zz] = heap[zz >> 1]; \ - zz >>= 1; \ - } \ - heap[zz] = tmp; \ -} - -#define DOWNHEAP(z) \ -{ \ - Int32 zz, yy, tmp; \ - zz = z; tmp = heap[zz]; \ - while (True) { \ - yy = zz << 1; \ - if (yy > nHeap) break; \ - if (yy < nHeap && \ - weight[heap[yy+1]] < weight[heap[yy]]) \ - yy++; \ - if (weight[tmp] < weight[heap[yy]]) break; \ - heap[zz] = heap[yy]; \ - zz = yy; \ - } \ - heap[zz] = tmp; \ -} - - -/*---------------------------------------------------*/ -void BZ2_hbMakeCodeLengths ( UChar *len, - Int32 *freq, - Int32 alphaSize, - Int32 maxLen ) -{ - /*-- - Nodes and heap entries run from 1. Entry 0 - for both the heap and nodes is a sentinel. - --*/ - Int32 nNodes, nHeap, n1, n2, i, j, k; - Bool tooLong; - - Int32 heap [ BZ_MAX_ALPHA_SIZE + 2 ]; - Int32 weight [ BZ_MAX_ALPHA_SIZE * 2 ]; - Int32 parent [ BZ_MAX_ALPHA_SIZE * 2 ]; - - for (i = 0; i < alphaSize; i++) - weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; - - while (True) { - - nNodes = alphaSize; - nHeap = 0; - - heap[0] = 0; - weight[0] = 0; - parent[0] = -2; - - for (i = 1; i <= alphaSize; i++) { - parent[i] = -1; - nHeap++; - heap[nHeap] = i; - UPHEAP(nHeap); - } - - AssertH( nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001 ); - - while (nHeap > 1) { - n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); - n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP(1); - nNodes++; - parent[n1] = parent[n2] = nNodes; - weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); - parent[nNodes] = -1; - nHeap++; - heap[nHeap] = nNodes; - UPHEAP(nHeap); - } - - AssertH( nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002 ); - - tooLong = False; - for (i = 1; i <= alphaSize; i++) { - j = 0; - k = i; - while (parent[k] >= 0) { k = parent[k]; j++; } - len[i-1] = j; - if (j > maxLen) tooLong = True; - } - - if (! tooLong) break; - - /* 17 Oct 04: keep-going condition for the following loop used - to be 'i < alphaSize', which missed the last element, - theoretically leading to the possibility of the compressor - looping. However, this count-scaling step is only needed if - one of the generated Huffman code words is longer than - maxLen, which up to and including version 1.0.2 was 20 bits, - which is extremely unlikely. In version 1.0.3 maxLen was - changed to 17 bits, which has minimal effect on compression - ratio, but does mean this scaling step is used from time to - time, enough to verify that it works. - - This means that bzip2-1.0.3 and later will only produce - Huffman codes with a maximum length of 17 bits. However, in - order to preserve backwards compatibility with bitstreams - produced by versions pre-1.0.3, the decompressor must still - handle lengths of up to 20. */ - - for (i = 1; i <= alphaSize; i++) { - j = weight[i] >> 8; - j = 1 + (j / 2); - weight[i] = j << 8; - } - } -} - - -/*---------------------------------------------------*/ -void BZ2_hbAssignCodes ( Int32 *code, - UChar *length, - Int32 minLen, - Int32 maxLen, - Int32 alphaSize ) -{ - Int32 n, vec, i; - - vec = 0; - for (n = minLen; n <= maxLen; n++) { - for (i = 0; i < alphaSize; i++) - if (length[i] == n) { code[i] = vec; vec++; }; - vec <<= 1; - } -} - - -/*---------------------------------------------------*/ -void BZ2_hbCreateDecodeTables ( Int32 *limit, - Int32 *base, - Int32 *perm, - UChar *length, - Int32 minLen, - Int32 maxLen, - Int32 alphaSize ) -{ - Int32 pp, i, j, vec; - - pp = 0; - for (i = minLen; i <= maxLen; i++) - for (j = 0; j < alphaSize; j++) - if (length[j] == i) { perm[pp] = j; pp++; }; - - for (i = 0; i < BZ_MAX_CODE_LEN; i++) base[i] = 0; - for (i = 0; i < alphaSize; i++) base[length[i]+1]++; - - for (i = 1; i < BZ_MAX_CODE_LEN; i++) base[i] += base[i-1]; - - for (i = 0; i < BZ_MAX_CODE_LEN; i++) limit[i] = 0; - vec = 0; - - for (i = minLen; i <= maxLen; i++) { - vec += (base[i+1] - base[i]); - limit[i] = vec-1; - vec <<= 1; - } - for (i = minLen + 1; i <= maxLen; i++) - base[i] = ((limit[i-1] + 1) << 1) - base[i]; -} - - -/*-------------------------------------------------------------*/ -/*--- end huffman.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/src/common/dep/bzip2/internal_e.cpp b/src/common/dep/bzip2/internal_e.cpp deleted file mode 100644 index 6df3f7d4f..000000000 --- a/src/common/dep/bzip2/internal_e.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// This file is not part of libbzip2. It implements external function required by libbzip2. - -#include "precomp.h" - -extern "C" void bz_internal_error(int errcode) -{ - SalMessageBox(NULL, "Internal error", "libbzip2 encountered an error", MB_OK | MB_ICONEXCLAMATION); -} diff --git a/src/common/dep/bzip2/randtable.c b/src/common/dep/bzip2/randtable.c deleted file mode 100644 index 6d6245990..000000000 --- a/src/common/dep/bzip2/randtable.c +++ /dev/null @@ -1,84 +0,0 @@ - -/*-------------------------------------------------------------*/ -/*--- Table for randomising repetitive blocks ---*/ -/*--- randtable.c ---*/ -/*-------------------------------------------------------------*/ - -/* ------------------------------------------------------------------ - This file is part of bzip2/libbzip2, a program and library for - lossless, block-sorting data compression. - - bzip2/libbzip2 version 1.0.6 of 6 September 2010 - Copyright (C) 1996-2010 Julian Seward - - Please read the WARNING, DISCLAIMER and PATENTS sections in the - README file. - - This program is released under the terms of the license contained - in the file LICENSE. - ------------------------------------------------------------------ */ - - -#include "bzlib_private.h" - - -/*---------------------------------------------*/ -Int32 BZ2_rNums[512] = { - 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, - 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, - 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, - 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, - 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, - 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, - 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, - 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, - 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, - 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, - 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, - 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, - 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, - 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, - 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, - 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, - 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, - 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, - 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, - 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, - 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, - 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, - 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, - 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, - 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, - 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, - 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, - 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, - 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, - 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, - 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, - 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, - 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, - 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, - 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, - 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, - 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, - 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, - 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, - 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, - 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, - 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, - 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, - 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, - 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, - 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, - 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, - 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, - 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, - 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, - 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, - 936, 638 -}; - - -/*-------------------------------------------------------------*/ -/*--- end randtable.c ---*/ -/*-------------------------------------------------------------*/ diff --git a/src/common/dep/nanosvg/nanosvg.h b/src/common/dep/nanosvg/nanosvg.h deleted file mode 100644 index a6c60155e..000000000 --- a/src/common/dep/nanosvg/nanosvg.h +++ /dev/null @@ -1,2849 +0,0 @@ -/* - * Copyright (c) 2013-14 Mikko Mononen memon@inside.org - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - * - * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example - * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/) - * - * Arc calculation code based on canvg (https://code.google.com/p/canvg/) - * - * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html - * - */ - -#ifndef NANOSVG_H -#define NANOSVG_H - -#ifdef __cplusplus -extern "C" { -#endif - -// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes. -// -// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game. -// -// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request! -// -// The shapes in the SVG images are transformed by the viewBox and converted to specified units. -// That is, you should get the same looking data as your designed in your favorite app. -// -// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose -// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters. -// -// The units passed to NanoVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'. -// DPI (dots-per-inch) controls how the unit conversion is done. -// -// If you don't know or care about the units stuff, "px" and 96 should get you going. - - -/* Example Usage: - // Load - NSVGImage* image; - image = nsvgParseFromFile("test.svg", "px", 96); - printf("size: %f x %f\n", image->width, image->height); - // Use... - for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { - for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { - for (int i = 0; i < path->npts-1; i += 3) { - float* p = &path->pts[i*2]; - drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); - } - } - } - // Delete - nsvgDelete(image); -*/ - -enum NSVGpaintType { - NSVG_PAINT_NONE = 0, - NSVG_PAINT_COLOR = 1, - NSVG_PAINT_LINEAR_GRADIENT = 2, - NSVG_PAINT_RADIAL_GRADIENT = 3, -}; - -enum NSVGspreadType { - NSVG_SPREAD_PAD = 0, - NSVG_SPREAD_REFLECT = 1, - NSVG_SPREAD_REPEAT = 2, -}; - -enum NSVGlineJoin { - NSVG_JOIN_MITER = 0, - NSVG_JOIN_ROUND = 1, - NSVG_JOIN_BEVEL = 2, -}; - -enum NSVGlineCap { - NSVG_CAP_BUTT = 0, - NSVG_CAP_ROUND = 1, - NSVG_CAP_SQUARE = 2, -}; - -enum NSVGfillRule { - NSVG_FILLRULE_NONZERO = 0, - NSVG_FILLRULE_EVENODD = 1, -}; - -enum NSVGflags { - NSVG_FLAGS_VISIBLE = 0x01 -}; - -typedef struct NSVGgradientStop { - unsigned int color; - float offset; -} NSVGgradientStop; - -typedef struct NSVGgradient { - float xform[6]; - char spread; - float fx, fy; - int nstops; - NSVGgradientStop stops[1]; -} NSVGgradient; - -typedef struct NSVGpaint { - char type; - union { - unsigned int color; - NSVGgradient* gradient; - }; -} NSVGpaint; - -typedef struct NSVGpath -{ - float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... - int npts; // Total number of bezier points. - char closed; // Flag indicating if shapes should be treated as closed. - float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. - struct NSVGpath* next; // Pointer to next path, or NULL if last element. -} NSVGpath; - -typedef struct NSVGshape -{ - char id[64]; // Optional 'id' attr of the shape or its group - NSVGpaint fill; // Fill paint - NSVGpaint stroke; // Stroke paint - float opacity; // Opacity of the shape. - float strokeWidth; // Stroke width (scaled). - float strokeDashOffset; // Stroke dash offset (scaled). - float strokeDashArray[8]; // Stroke dash array (scaled). - char strokeDashCount; // Number of dash values in dash array. - char strokeLineJoin; // Stroke join type. - char strokeLineCap; // Stroke cap type. - char fillRule; // Fill rule, see NSVGfillRule. - unsigned char flags; // Logical or of NSVG_FLAGS_* flags - float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. - NSVGpath* paths; // Linked list of paths in the image. - struct NSVGshape* next; // Pointer to next shape, or NULL if last element. -} NSVGshape; - -typedef struct NSVGimage -{ - float width; // Width of the image. - float height; // Height of the image. - NSVGshape* shapes; // Linked list of shapes in the image. -} NSVGimage; - -// Parses SVG file from a file, returns SVG image as paths. -NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi); - -// Parses SVG file from a null terminated string, returns SVG image as paths. -// Important note: changes the string. -NSVGimage* nsvgParse(char* input, const char* units, float dpi); - -// Deletes list of paths. -void nsvgDelete(NSVGimage* image); - -#ifdef __cplusplus -}; -#endif - -#endif // NANOSVG_H - -#ifdef NANOSVG_IMPLEMENTATION - -#include -#include -#include - -#define NSVG_PI (3.14159265358979323846264338327f) -#define NSVG_KAPPA90 (0.5522847493f) // Lenght proportional to radius of a cubic bezier handle for 90deg arcs. - -#define NSVG_ALIGN_MIN 0 -#define NSVG_ALIGN_MID 1 -#define NSVG_ALIGN_MAX 2 -#define NSVG_ALIGN_NONE 0 -#define NSVG_ALIGN_MEET 1 -#define NSVG_ALIGN_SLICE 2 - -#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) -#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) - -#ifdef _MSC_VER - #pragma warning (disable: 4996) // Switch off security warnings - #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings - #ifdef __cplusplus - #define NSVG_INLINE inline - #else - #define NSVG_INLINE - #endif -#else - #define NSVG_INLINE inline -#endif - - -static int nsvg__isspace(char c) -{ - return strchr(" \t\n\v\f\r", c) != 0; -} - -static int nsvg__isdigit(char c) -{ - return strchr("0123456789", c) != 0; -} - -static int nsvg__isnum(char c) -{ - return strchr("0123456789+-.eE", c) != 0; -} - -static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; } -static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; } - - -// Simple XML parser - -#define NSVG_XML_TAG 1 -#define NSVG_XML_CONTENT 2 -#define NSVG_XML_MAX_ATTRIBS 256 - -static void nsvg__parseContent(char* s, - void (*contentCb)(void* ud, const char* s), - void* ud) -{ - // Trim start white spaces - while (*s && nsvg__isspace(*s)) s++; - if (!*s) return; - - if (contentCb) - (*contentCb)(ud, s); -} - -static void nsvg__parseElement(char* s, - void (*startelCb)(void* ud, const char* el, const char** attr), - void (*endelCb)(void* ud, const char* el), - void* ud) -{ - const char* attr[NSVG_XML_MAX_ATTRIBS]; - int nattr = 0; - char* name; - int start = 0; - int end = 0; - char quote; - - // Skip white space after the '<' - while (*s && nsvg__isspace(*s)) s++; - - // Check if the tag is end tag - if (*s == '/') { - s++; - end = 1; - } else { - start = 1; - } - - // Skip comments, data and preprocessor stuff. - if (!*s || *s == '?' || *s == '!') - return; - - // Get tag name - name = s; - while (*s && !nsvg__isspace(*s)) s++; - if (*s) { *s++ = '\0'; } - - // Get attribs - while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { - // Skip white space before the attrib name - while (*s && nsvg__isspace(*s)) s++; - if (!*s) break; - if (*s == '/') { - end = 1; - break; - } - attr[nattr++] = s; - // Find end of the attrib name. - while (*s && !nsvg__isspace(*s) && *s != '=') s++; - if (*s) { *s++ = '\0'; } - // Skip until the beginning of the value. - while (*s && *s != '\"' && *s != '\'') s++; - if (!*s) break; - quote = *s; - s++; - // Store value and find the end of it. - attr[nattr++] = s; - while (*s && *s != quote) s++; - if (*s) { *s++ = '\0'; } - } - - // List terminator - attr[nattr++] = 0; - attr[nattr++] = 0; - - // Call callbacks. - if (start && startelCb) - (*startelCb)(ud, name, attr); - if (end && endelCb) - (*endelCb)(ud, name); -} - -int nsvg__parseXML(char* input, - void (*startelCb)(void* ud, const char* el, const char** attr), - void (*endelCb)(void* ud, const char* el), - void (*contentCb)(void* ud, const char* s), - void* ud) -{ - char* s = input; - char* mark = s; - int state = NSVG_XML_CONTENT; - while (*s) { - if (*s == '<' && state == NSVG_XML_CONTENT) { - // Start of a tag - *s++ = '\0'; - nsvg__parseContent(mark, contentCb, ud); - mark = s; - state = NSVG_XML_TAG; - } else if (*s == '>' && state == NSVG_XML_TAG) { - // Start of a content or new tag. - *s++ = '\0'; - nsvg__parseElement(mark, startelCb, endelCb, ud); - mark = s; - state = NSVG_XML_CONTENT; - } else { - s++; - } - } - - return 1; -} - - -/* Simple SVG parser. */ - -#define NSVG_MAX_ATTR 128 - -enum NSVGgradientUnits { - NSVG_USER_SPACE = 0, - NSVG_OBJECT_SPACE = 1, -}; - -#define NSVG_MAX_DASHES 8 - -enum NSVGunits { - NSVG_UNITS_USER, - NSVG_UNITS_PX, - NSVG_UNITS_PT, - NSVG_UNITS_PC, - NSVG_UNITS_MM, - NSVG_UNITS_CM, - NSVG_UNITS_IN, - NSVG_UNITS_PERCENT, - NSVG_UNITS_EM, - NSVG_UNITS_EX, -}; - -typedef struct NSVGcoordinate { - float value; - int units; -} NSVGcoordinate; - -typedef struct NSVGlinearData { - NSVGcoordinate x1, y1, x2, y2; -} NSVGlinearData; - -typedef struct NSVGradialData { - NSVGcoordinate cx, cy, r, fx, fy; -} NSVGradialData; - -typedef struct NSVGgradientData -{ - char id[64]; - char ref[64]; - char type; - union { - NSVGlinearData linear; - NSVGradialData radial; - }; - char spread; - char units; - float xform[6]; - int nstops; - NSVGgradientStop* stops; - struct NSVGgradientData* next; -} NSVGgradientData; - -typedef struct NSVGattrib -{ - char id[64]; - float xform[6]; - unsigned int fillColor; - unsigned int strokeColor; - float opacity; - float fillOpacity; - float strokeOpacity; - char fillGradient[64]; - char strokeGradient[64]; - float strokeWidth; - float strokeDashOffset; - float strokeDashArray[NSVG_MAX_DASHES]; - int strokeDashCount; - char strokeLineJoin; - char strokeLineCap; - char fillRule; - float fontSize; - unsigned int stopColor; - float stopOpacity; - float stopOffset; - char hasFill; - char hasStroke; - char visible; -} NSVGattrib; - -typedef struct NSVGparser -{ - NSVGattrib attr[NSVG_MAX_ATTR]; - int attrHead; - float* pts; - int npts; - int cpts; - NSVGpath* plist; - NSVGimage* image; - NSVGgradientData* gradients; - float viewMinx, viewMiny, viewWidth, viewHeight; - int alignX, alignY, alignType; - float dpi; - char pathFlag; - char defsFlag; -} NSVGparser; - -static void nsvg__xformIdentity(float* t) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = 0.0f; t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetTranslation(float* t, float tx, float ty) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = 0.0f; t[3] = 1.0f; - t[4] = tx; t[5] = ty; -} - -static void nsvg__xformSetScale(float* t, float sx, float sy) -{ - t[0] = sx; t[1] = 0.0f; - t[2] = 0.0f; t[3] = sy; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetSkewX(float* t, float a) -{ - t[0] = 1.0f; t[1] = 0.0f; - t[2] = tanf(a); t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetSkewY(float* t, float a) -{ - t[0] = 1.0f; t[1] = tanf(a); - t[2] = 0.0f; t[3] = 1.0f; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformSetRotation(float* t, float a) -{ - float cs = cosf(a), sn = sinf(a); - t[0] = cs; t[1] = sn; - t[2] = -sn; t[3] = cs; - t[4] = 0.0f; t[5] = 0.0f; -} - -static void nsvg__xformMultiply(float* t, float* s) -{ - float t0 = t[0] * s[0] + t[1] * s[2]; - float t2 = t[2] * s[0] + t[3] * s[2]; - float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; - t[1] = t[0] * s[1] + t[1] * s[3]; - t[3] = t[2] * s[1] + t[3] * s[3]; - t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; - t[0] = t0; - t[2] = t2; - t[4] = t4; -} - -static void nsvg__xformInverse(float* inv, float* t) -{ - double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; - if (det > -1e-6 && det < 1e-6) { - nsvg__xformIdentity(t); - return; - } - invdet = 1.0 / det; - inv[0] = (float)(t[3] * invdet); - inv[2] = (float)(-t[2] * invdet); - inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); - inv[1] = (float)(-t[1] * invdet); - inv[3] = (float)(t[0] * invdet); - inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); -} - -static void nsvg__xformPremultiply(float* t, float* s) -{ - float s2[6]; - memcpy(s2, s, sizeof(float)*6); - nsvg__xformMultiply(s2, t); - memcpy(t, s2, sizeof(float)*6); -} - -static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t) -{ - *dx = x*t[0] + y*t[2] + t[4]; - *dy = x*t[1] + y*t[3] + t[5]; -} - -static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t) -{ - *dx = x*t[0] + y*t[2]; - *dy = x*t[1] + y*t[3]; -} - -#define NSVG_EPSILON (1e-12) - -static int nsvg__ptInBounds(float* pt, float* bounds) -{ - return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; -} - - -static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) -{ - double it = 1.0-t; - return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3; -} - -static void nsvg__curveBounds(float* bounds, float* curve) -{ - int i, j, count; - double roots[2], a, b, c, b2ac, t, v; - float* v0 = &curve[0]; - float* v1 = &curve[2]; - float* v2 = &curve[4]; - float* v3 = &curve[6]; - - // Start the bounding box by end points - bounds[0] = nsvg__minf(v0[0], v3[0]); - bounds[1] = nsvg__minf(v0[1], v3[1]); - bounds[2] = nsvg__maxf(v0[0], v3[0]); - bounds[3] = nsvg__maxf(v0[1], v3[1]); - - // Bezier curve fits inside the convex hull of it's control points. - // If control points are inside the bounds, we're done. - if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) - return; - - // Add bezier curve inflection points in X and Y. - for (i = 0; i < 2; i++) { - a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; - b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; - c = 3.0 * v1[i] - 3.0 * v0[i]; - count = 0; - if (fabs(a) < NSVG_EPSILON) { - if (fabs(b) > NSVG_EPSILON) { - t = -c / b; - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - } - } else { - b2ac = b*b - 4.0*c*a; - if (b2ac > NSVG_EPSILON) { - t = (-b + sqrt(b2ac)) / (2.0 * a); - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - t = (-b - sqrt(b2ac)) / (2.0 * a); - if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) - roots[count++] = t; - } - } - for (j = 0; j < count; j++) { - v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); - bounds[0+i] = nsvg__minf(bounds[0+i], (float)v); - bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v); - } - } -} - -static NSVGparser* nsvg__createParser() -{ - NSVGparser* p; - p = (NSVGparser*)malloc(sizeof(NSVGparser)); - if (p == NULL) goto error; - memset(p, 0, sizeof(NSVGparser)); - - p->image = (NSVGimage*)malloc(sizeof(NSVGimage)); - if (p->image == NULL) goto error; - memset(p->image, 0, sizeof(NSVGimage)); - - // Init style - nsvg__xformIdentity(p->attr[0].xform); - memset(p->attr[0].id, 0, sizeof p->attr[0].id); - p->attr[0].fillColor = NSVG_RGB(0,0,0); - p->attr[0].strokeColor = NSVG_RGB(0,0,0); - p->attr[0].opacity = 1; - p->attr[0].fillOpacity = 1; - p->attr[0].strokeOpacity = 1; - p->attr[0].stopOpacity = 1; - p->attr[0].strokeWidth = 1; - p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; - p->attr[0].strokeLineCap = NSVG_CAP_BUTT; - p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; - p->attr[0].hasFill = 1; - p->attr[0].visible = 1; - - return p; - -error: - if (p) { - if (p->image) free(p->image); - free(p); - } - return NULL; -} - -static void nsvg__deletePaths(NSVGpath* path) -{ - while (path) { - NSVGpath *next = path->next; - if (path->pts != NULL) - free(path->pts); - free(path); - path = next; - } -} - -static void nsvg__deletePaint(NSVGpaint* paint) -{ - if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) - free(paint->gradient); -} - -static void nsvg__deleteGradientData(NSVGgradientData* grad) -{ - NSVGgradientData* next; - while (grad != NULL) { - next = grad->next; - free(grad->stops); - free(grad); - grad = next; - } -} - -static void nsvg__deleteParser(NSVGparser* p) -{ - if (p != NULL) { - nsvg__deletePaths(p->plist); - nsvg__deleteGradientData(p->gradients); - nsvgDelete(p->image); - free(p->pts); - free(p); - } -} - -static void nsvg__resetPath(NSVGparser* p) -{ - p->npts = 0; -} - -static void nsvg__addPoint(NSVGparser* p, float x, float y) -{ - if (p->npts+1 > p->cpts) { - p->cpts = p->cpts ? p->cpts*2 : 8; - p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float)); - if (!p->pts) return; - } - p->pts[p->npts*2+0] = x; - p->pts[p->npts*2+1] = y; - p->npts++; -} - -static void nsvg__moveTo(NSVGparser* p, float x, float y) -{ - if (p->npts > 0) { - p->pts[(p->npts-1)*2+0] = x; - p->pts[(p->npts-1)*2+1] = y; - } else { - nsvg__addPoint(p, x, y); - } -} - -static void nsvg__lineTo(NSVGparser* p, float x, float y) -{ - float px,py, dx,dy; - if (p->npts > 0) { - px = p->pts[(p->npts-1)*2+0]; - py = p->pts[(p->npts-1)*2+1]; - dx = x - px; - dy = y - py; - nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f); - nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f); - nsvg__addPoint(p, x, y); - } -} - -static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) -{ - nsvg__addPoint(p, cpx1, cpy1); - nsvg__addPoint(p, cpx2, cpy2); - nsvg__addPoint(p, x, y); -} - -static NSVGattrib* nsvg__getAttr(NSVGparser* p) -{ - return &p->attr[p->attrHead]; -} - -static void nsvg__pushAttr(NSVGparser* p) -{ - if (p->attrHead < NSVG_MAX_ATTR-1) { - p->attrHead++; - memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib)); - } -} - -static void nsvg__popAttr(NSVGparser* p) -{ - if (p->attrHead > 0) - p->attrHead--; -} - -static float nsvg__actualOrigX(NSVGparser* p) -{ - return p->viewMinx; -} - -static float nsvg__actualOrigY(NSVGparser* p) -{ - return p->viewMiny; -} - -static float nsvg__actualWidth(NSVGparser* p) -{ - return p->viewWidth; -} - -static float nsvg__actualHeight(NSVGparser* p) -{ - return p->viewHeight; -} - -static float nsvg__actualLength(NSVGparser* p) -{ - float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); - return sqrtf(w*w + h*h) / sqrtf(2.0f); -} - -static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length) -{ - NSVGattrib* attr = nsvg__getAttr(p); - switch (c.units) { - case NSVG_UNITS_USER: return c.value; - case NSVG_UNITS_PX: return c.value; - case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi; - case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi; - case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi; - case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi; - case NSVG_UNITS_IN: return c.value * p->dpi; - case NSVG_UNITS_EM: return c.value * attr->fontSize; - case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. - case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length; - default: return c.value; - } - return c.value; -} - -static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id) -{ - NSVGgradientData* grad = p->gradients; - while (grad) { - if (strcmp(grad->id, id) == 0) - return grad; - grad = grad->next; - } - return NULL; -} - -static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, char* paintType) -{ - NSVGattrib* attr = nsvg__getAttr(p); - NSVGgradientData* data = NULL; - NSVGgradientData* ref = NULL; - NSVGgradientStop* stops = NULL; - NSVGgradient* grad; - float ox, oy, sw, sh, sl; - int nstops = 0; - - data = nsvg__findGradientData(p, id); - if (data == NULL) return NULL; - - // TODO: use ref to fill in all unset values too. - ref = data; - while (ref != NULL) { - if (stops == NULL && ref->stops != NULL) { - stops = ref->stops; - nstops = ref->nstops; - break; - } - ref = nsvg__findGradientData(p, ref->ref); - } - if (stops == NULL) return NULL; - - grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1)); - if (grad == NULL) return NULL; - - // The shape width and height. - if (data->units == NSVG_OBJECT_SPACE) { - ox = localBounds[0]; - oy = localBounds[1]; - sw = localBounds[2] - localBounds[0]; - sh = localBounds[3] - localBounds[1]; - } else { - ox = nsvg__actualOrigX(p); - oy = nsvg__actualOrigY(p); - sw = nsvg__actualWidth(p); - sh = nsvg__actualHeight(p); - } - sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f); - - if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { - float x1, y1, x2, y2, dx, dy; - x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); - y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); - x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); - y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); - // Calculate transform aligned to the line - dx = x2 - x1; - dy = y2 - y1; - grad->xform[0] = dy; grad->xform[1] = -dx; - grad->xform[2] = dx; grad->xform[3] = dy; - grad->xform[4] = x1; grad->xform[5] = y1; - } else { - float cx, cy, fx, fy, r; - cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); - cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); - fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); - fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); - r = nsvg__convertToPixels(p, data->radial.r, 0, sl); - // Calculate transform aligned to the circle - grad->xform[0] = r; grad->xform[1] = 0; - grad->xform[2] = 0; grad->xform[3] = r; - grad->xform[4] = cx; grad->xform[5] = cy; - grad->fx = fx / r; - grad->fy = fy / r; - } - - nsvg__xformMultiply(grad->xform, data->xform); - nsvg__xformMultiply(grad->xform, attr->xform); - - grad->spread = data->spread; - memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop)); - grad->nstops = nstops; - - *paintType = data->type; - - return grad; -} - -static float nsvg__getAverageScale(float* t) -{ - float sx = sqrtf(t[0]*t[0] + t[2]*t[2]); - float sy = sqrtf(t[1]*t[1] + t[3]*t[3]); - return (sx + sy) * 0.5f; -} - -static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform) -{ - NSVGpath* path; - float curve[4*2], curveBounds[4]; - int i, first = 1; - for (path = shape->paths; path != NULL; path = path->next) { - nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); - for (i = 0; i < path->npts-1; i += 3) { - nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform); - nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform); - nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform); - nsvg__curveBounds(curveBounds, curve); - if (first) { - bounds[0] = curveBounds[0]; - bounds[1] = curveBounds[1]; - bounds[2] = curveBounds[2]; - bounds[3] = curveBounds[3]; - first = 0; - } else { - bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); - bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); - bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); - bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); - } - curve[0] = curve[6]; - curve[1] = curve[7]; - } - } -} - -static void nsvg__addShape(NSVGparser* p) -{ - NSVGattrib* attr = nsvg__getAttr(p); - float scale = 1.0f; - NSVGshape *shape, *cur, *prev; - NSVGpath* path; - int i; - - if (p->plist == NULL) - return; - - shape = (NSVGshape*)malloc(sizeof(NSVGshape)); - if (shape == NULL) goto error; - memset(shape, 0, sizeof(NSVGshape)); - - memcpy(shape->id, attr->id, sizeof shape->id); - scale = nsvg__getAverageScale(attr->xform); - shape->strokeWidth = attr->strokeWidth * scale; - shape->strokeDashOffset = attr->strokeDashOffset * scale; - shape->strokeDashCount = attr->strokeDashCount; - for (i = 0; i < attr->strokeDashCount; i++) - shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; - shape->strokeLineJoin = attr->strokeLineJoin; - shape->strokeLineCap = attr->strokeLineCap; - shape->fillRule = attr->fillRule; - shape->opacity = attr->opacity; - - shape->paths = p->plist; - p->plist = NULL; - - // Calculate shape bounds - shape->bounds[0] = shape->paths->bounds[0]; - shape->bounds[1] = shape->paths->bounds[1]; - shape->bounds[2] = shape->paths->bounds[2]; - shape->bounds[3] = shape->paths->bounds[3]; - for (path = shape->paths->next; path != NULL; path = path->next) { - shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); - shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); - shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); - shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); - } - - // Set fill - if (attr->hasFill == 0) { - shape->fill.type = NSVG_PAINT_NONE; - } else if (attr->hasFill == 1) { - shape->fill.type = NSVG_PAINT_COLOR; - shape->fill.color = attr->fillColor; - shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24; - } else if (attr->hasFill == 2) { - float inv[6], localBounds[4]; - nsvg__xformInverse(inv, attr->xform); - nsvg__getLocalBounds(localBounds, shape, inv); - shape->fill.gradient = nsvg__createGradient(p, attr->fillGradient, localBounds, &shape->fill.type); - if (shape->fill.gradient == NULL) { - shape->fill.type = NSVG_PAINT_NONE; - } - } - - // Set stroke - if (attr->hasStroke == 0) { - shape->stroke.type = NSVG_PAINT_NONE; - } else if (attr->hasStroke == 1) { - shape->stroke.type = NSVG_PAINT_COLOR; - shape->stroke.color = attr->strokeColor; - shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24; - } else if (attr->hasStroke == 2) { - float inv[6], localBounds[4]; - nsvg__xformInverse(inv, attr->xform); - nsvg__getLocalBounds(localBounds, shape, inv); - shape->stroke.gradient = nsvg__createGradient(p, attr->strokeGradient, localBounds, &shape->stroke.type); - if (shape->stroke.gradient == NULL) - shape->stroke.type = NSVG_PAINT_NONE; - } - - // Set flags - shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); - - // Add to tail - prev = NULL; - cur = p->image->shapes; - while (cur != NULL) { - prev = cur; - cur = cur->next; - } - if (prev == NULL) - p->image->shapes = shape; - else - prev->next = shape; - - return; - -error: - if (shape) free(shape); -} - -static void nsvg__addPath(NSVGparser* p, char closed) -{ - NSVGattrib* attr = nsvg__getAttr(p); - NSVGpath* path = NULL; - float bounds[4]; - float* curve; - int i; - - if (p->npts < 4) - return; - - if (closed) - nsvg__lineTo(p, p->pts[0], p->pts[1]); - - path = (NSVGpath*)malloc(sizeof(NSVGpath)); - if (path == NULL) goto error; - memset(path, 0, sizeof(NSVGpath)); - - path->pts = (float*)malloc(p->npts*2*sizeof(float)); - if (path->pts == NULL) goto error; - path->closed = closed; - path->npts = p->npts; - - // Transform path. - for (i = 0; i < p->npts; ++i) - nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform); - - // Find bounds - for (i = 0; i < path->npts-1; i += 3) { - curve = &path->pts[i*2]; - nsvg__curveBounds(bounds, curve); - if (i == 0) { - path->bounds[0] = bounds[0]; - path->bounds[1] = bounds[1]; - path->bounds[2] = bounds[2]; - path->bounds[3] = bounds[3]; - } else { - path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); - path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); - path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); - path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); - } - } - - path->next = p->plist; - p->plist = path; - - return; - -error: - if (path != NULL) { - if (path->pts != NULL) free(path->pts); - free(path); - } -} - -static const char* nsvg__parseNumber(const char* s, char* it, const int size) -{ - const int last = size-1; - int i = 0; - - // sign - if (*s == '-' || *s == '+') { - if (i < last) it[i++] = *s; - s++; - } - // integer part - while (*s && nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - if (*s == '.') { - // decimal point - if (i < last) it[i++] = *s; - s++; - // fraction part - while (*s && nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - } - // exponent - if (*s == 'e' || *s == 'E') { - if (i < last) it[i++] = *s; - s++; - if (*s == '-' || *s == '+') { - if (i < last) it[i++] = *s; - s++; - } - while (*s && nsvg__isdigit(*s)) { - if (i < last) it[i++] = *s; - s++; - } - } - it[i] = '\0'; - - return s; -} - -static const char* nsvg__getNextPathItem(const char* s, char* it) -{ - it[0] = '\0'; - // Skip white spaces and commas - while (*s && (nsvg__isspace(*s) || *s == ',')) s++; - if (!*s) return s; - if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { - s = nsvg__parseNumber(s, it, 64); - } else { - // Parse command - it[0] = *s++; - it[1] = '\0'; - return s; - } - - return s; -} - -static unsigned int nsvg__parseColorHex(const char* str) -{ - unsigned int c = 0, r = 0, g = 0, b = 0; - int n = 0; - str++; // skip # - // Calculate number of characters. - while(str[n] && !nsvg__isspace(str[n])) - n++; - if (n == 6) { - sscanf(str, "%x", &c); - } else if (n == 3) { - sscanf(str, "%x", &c); - c = (c&0xf) | ((c&0xf0) << 4) | ((c&0xf00) << 8); - c |= c<<4; - } - r = (c >> 16) & 0xff; - g = (c >> 8) & 0xff; - b = c & 0xff; - return NSVG_RGB(r,g,b); -} - -static unsigned int nsvg__parseColorRGB(const char* str) -{ - int r = -1, g = -1, b = -1; - char s1[32]="", s2[32]=""; - sscanf(str + 4, "%d%[%%, \t]%d%[%%, \t]%d", &r, s1, &g, s2, &b); - if (strchr(s1, '%')) { - return NSVG_RGB((r*255)/100,(g*255)/100,(b*255)/100); - } else { - return NSVG_RGB(r,g,b); - } -} - -typedef struct NSVGNamedColor { - const char* name; - unsigned int color; -} NSVGNamedColor; - -NSVGNamedColor nsvg__colors[] = { - - { "red", NSVG_RGB(255, 0, 0) }, - { "green", NSVG_RGB( 0, 128, 0) }, - { "blue", NSVG_RGB( 0, 0, 255) }, - { "yellow", NSVG_RGB(255, 255, 0) }, - { "cyan", NSVG_RGB( 0, 255, 255) }, - { "magenta", NSVG_RGB(255, 0, 255) }, - { "black", NSVG_RGB( 0, 0, 0) }, - { "grey", NSVG_RGB(128, 128, 128) }, - { "gray", NSVG_RGB(128, 128, 128) }, - { "white", NSVG_RGB(255, 255, 255) }, - -#ifdef NANOSVG_ALL_COLOR_KEYWORDS - { "aliceblue", NSVG_RGB(240, 248, 255) }, - { "antiquewhite", NSVG_RGB(250, 235, 215) }, - { "aqua", NSVG_RGB( 0, 255, 255) }, - { "aquamarine", NSVG_RGB(127, 255, 212) }, - { "azure", NSVG_RGB(240, 255, 255) }, - { "beige", NSVG_RGB(245, 245, 220) }, - { "bisque", NSVG_RGB(255, 228, 196) }, - { "blanchedalmond", NSVG_RGB(255, 235, 205) }, - { "blueviolet", NSVG_RGB(138, 43, 226) }, - { "brown", NSVG_RGB(165, 42, 42) }, - { "burlywood", NSVG_RGB(222, 184, 135) }, - { "cadetblue", NSVG_RGB( 95, 158, 160) }, - { "chartreuse", NSVG_RGB(127, 255, 0) }, - { "chocolate", NSVG_RGB(210, 105, 30) }, - { "coral", NSVG_RGB(255, 127, 80) }, - { "cornflowerblue", NSVG_RGB(100, 149, 237) }, - { "cornsilk", NSVG_RGB(255, 248, 220) }, - { "crimson", NSVG_RGB(220, 20, 60) }, - { "darkblue", NSVG_RGB( 0, 0, 139) }, - { "darkcyan", NSVG_RGB( 0, 139, 139) }, - { "darkgoldenrod", NSVG_RGB(184, 134, 11) }, - { "darkgray", NSVG_RGB(169, 169, 169) }, - { "darkgreen", NSVG_RGB( 0, 100, 0) }, - { "darkgrey", NSVG_RGB(169, 169, 169) }, - { "darkkhaki", NSVG_RGB(189, 183, 107) }, - { "darkmagenta", NSVG_RGB(139, 0, 139) }, - { "darkolivegreen", NSVG_RGB( 85, 107, 47) }, - { "darkorange", NSVG_RGB(255, 140, 0) }, - { "darkorchid", NSVG_RGB(153, 50, 204) }, - { "darkred", NSVG_RGB(139, 0, 0) }, - { "darksalmon", NSVG_RGB(233, 150, 122) }, - { "darkseagreen", NSVG_RGB(143, 188, 143) }, - { "darkslateblue", NSVG_RGB( 72, 61, 139) }, - { "darkslategray", NSVG_RGB( 47, 79, 79) }, - { "darkslategrey", NSVG_RGB( 47, 79, 79) }, - { "darkturquoise", NSVG_RGB( 0, 206, 209) }, - { "darkviolet", NSVG_RGB(148, 0, 211) }, - { "deeppink", NSVG_RGB(255, 20, 147) }, - { "deepskyblue", NSVG_RGB( 0, 191, 255) }, - { "dimgray", NSVG_RGB(105, 105, 105) }, - { "dimgrey", NSVG_RGB(105, 105, 105) }, - { "dodgerblue", NSVG_RGB( 30, 144, 255) }, - { "firebrick", NSVG_RGB(178, 34, 34) }, - { "floralwhite", NSVG_RGB(255, 250, 240) }, - { "forestgreen", NSVG_RGB( 34, 139, 34) }, - { "fuchsia", NSVG_RGB(255, 0, 255) }, - { "gainsboro", NSVG_RGB(220, 220, 220) }, - { "ghostwhite", NSVG_RGB(248, 248, 255) }, - { "gold", NSVG_RGB(255, 215, 0) }, - { "goldenrod", NSVG_RGB(218, 165, 32) }, - { "greenyellow", NSVG_RGB(173, 255, 47) }, - { "honeydew", NSVG_RGB(240, 255, 240) }, - { "hotpink", NSVG_RGB(255, 105, 180) }, - { "indianred", NSVG_RGB(205, 92, 92) }, - { "indigo", NSVG_RGB( 75, 0, 130) }, - { "ivory", NSVG_RGB(255, 255, 240) }, - { "khaki", NSVG_RGB(240, 230, 140) }, - { "lavender", NSVG_RGB(230, 230, 250) }, - { "lavenderblush", NSVG_RGB(255, 240, 245) }, - { "lawngreen", NSVG_RGB(124, 252, 0) }, - { "lemonchiffon", NSVG_RGB(255, 250, 205) }, - { "lightblue", NSVG_RGB(173, 216, 230) }, - { "lightcoral", NSVG_RGB(240, 128, 128) }, - { "lightcyan", NSVG_RGB(224, 255, 255) }, - { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) }, - { "lightgray", NSVG_RGB(211, 211, 211) }, - { "lightgreen", NSVG_RGB(144, 238, 144) }, - { "lightgrey", NSVG_RGB(211, 211, 211) }, - { "lightpink", NSVG_RGB(255, 182, 193) }, - { "lightsalmon", NSVG_RGB(255, 160, 122) }, - { "lightseagreen", NSVG_RGB( 32, 178, 170) }, - { "lightskyblue", NSVG_RGB(135, 206, 250) }, - { "lightslategray", NSVG_RGB(119, 136, 153) }, - { "lightslategrey", NSVG_RGB(119, 136, 153) }, - { "lightsteelblue", NSVG_RGB(176, 196, 222) }, - { "lightyellow", NSVG_RGB(255, 255, 224) }, - { "lime", NSVG_RGB( 0, 255, 0) }, - { "limegreen", NSVG_RGB( 50, 205, 50) }, - { "linen", NSVG_RGB(250, 240, 230) }, - { "maroon", NSVG_RGB(128, 0, 0) }, - { "mediumaquamarine", NSVG_RGB(102, 205, 170) }, - { "mediumblue", NSVG_RGB( 0, 0, 205) }, - { "mediumorchid", NSVG_RGB(186, 85, 211) }, - { "mediumpurple", NSVG_RGB(147, 112, 219) }, - { "mediumseagreen", NSVG_RGB( 60, 179, 113) }, - { "mediumslateblue", NSVG_RGB(123, 104, 238) }, - { "mediumspringgreen", NSVG_RGB( 0, 250, 154) }, - { "mediumturquoise", NSVG_RGB( 72, 209, 204) }, - { "mediumvioletred", NSVG_RGB(199, 21, 133) }, - { "midnightblue", NSVG_RGB( 25, 25, 112) }, - { "mintcream", NSVG_RGB(245, 255, 250) }, - { "mistyrose", NSVG_RGB(255, 228, 225) }, - { "moccasin", NSVG_RGB(255, 228, 181) }, - { "navajowhite", NSVG_RGB(255, 222, 173) }, - { "navy", NSVG_RGB( 0, 0, 128) }, - { "oldlace", NSVG_RGB(253, 245, 230) }, - { "olive", NSVG_RGB(128, 128, 0) }, - { "olivedrab", NSVG_RGB(107, 142, 35) }, - { "orange", NSVG_RGB(255, 165, 0) }, - { "orangered", NSVG_RGB(255, 69, 0) }, - { "orchid", NSVG_RGB(218, 112, 214) }, - { "palegoldenrod", NSVG_RGB(238, 232, 170) }, - { "palegreen", NSVG_RGB(152, 251, 152) }, - { "paleturquoise", NSVG_RGB(175, 238, 238) }, - { "palevioletred", NSVG_RGB(219, 112, 147) }, - { "papayawhip", NSVG_RGB(255, 239, 213) }, - { "peachpuff", NSVG_RGB(255, 218, 185) }, - { "peru", NSVG_RGB(205, 133, 63) }, - { "pink", NSVG_RGB(255, 192, 203) }, - { "plum", NSVG_RGB(221, 160, 221) }, - { "powderblue", NSVG_RGB(176, 224, 230) }, - { "purple", NSVG_RGB(128, 0, 128) }, - { "rosybrown", NSVG_RGB(188, 143, 143) }, - { "royalblue", NSVG_RGB( 65, 105, 225) }, - { "saddlebrown", NSVG_RGB(139, 69, 19) }, - { "salmon", NSVG_RGB(250, 128, 114) }, - { "sandybrown", NSVG_RGB(244, 164, 96) }, - { "seagreen", NSVG_RGB( 46, 139, 87) }, - { "seashell", NSVG_RGB(255, 245, 238) }, - { "sienna", NSVG_RGB(160, 82, 45) }, - { "silver", NSVG_RGB(192, 192, 192) }, - { "skyblue", NSVG_RGB(135, 206, 235) }, - { "slateblue", NSVG_RGB(106, 90, 205) }, - { "slategray", NSVG_RGB(112, 128, 144) }, - { "slategrey", NSVG_RGB(112, 128, 144) }, - { "snow", NSVG_RGB(255, 250, 250) }, - { "springgreen", NSVG_RGB( 0, 255, 127) }, - { "steelblue", NSVG_RGB( 70, 130, 180) }, - { "tan", NSVG_RGB(210, 180, 140) }, - { "teal", NSVG_RGB( 0, 128, 128) }, - { "thistle", NSVG_RGB(216, 191, 216) }, - { "tomato", NSVG_RGB(255, 99, 71) }, - { "turquoise", NSVG_RGB( 64, 224, 208) }, - { "violet", NSVG_RGB(238, 130, 238) }, - { "wheat", NSVG_RGB(245, 222, 179) }, - { "whitesmoke", NSVG_RGB(245, 245, 245) }, - { "yellowgreen", NSVG_RGB(154, 205, 50) }, -#endif -}; - -static unsigned int nsvg__parseColorName(const char* str) -{ - int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); - - for (i = 0; i < ncolors; i++) { - if (strcmp(nsvg__colors[i].name, str) == 0) { - return nsvg__colors[i].color; - } - } - - return NSVG_RGB(128, 128, 128); -} - -static unsigned int nsvg__parseColor(const char* str) -{ - size_t len = 0; - while(*str == ' ') ++str; - len = strlen(str); - if (len >= 1 && *str == '#') - return nsvg__parseColorHex(str); - else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') - return nsvg__parseColorRGB(str); - return nsvg__parseColorName(str); -} - -static float nsvg__parseOpacity(const char* str) -{ - float val = 0; - sscanf(str, "%f", &val); - if (val < 0.0f) val = 0.0f; - if (val > 1.0f) val = 1.0f; - return val; -} - -static int nsvg__parseUnits(const char* units) -{ - if (units[0] == 'p' && units[1] == 'x') - return NSVG_UNITS_PX; - else if (units[0] == 'p' && units[1] == 't') - return NSVG_UNITS_PT; - else if (units[0] == 'p' && units[1] == 'c') - return NSVG_UNITS_PC; - else if (units[0] == 'm' && units[1] == 'm') - return NSVG_UNITS_MM; - else if (units[0] == 'c' && units[1] == 'm') - return NSVG_UNITS_CM; - else if (units[0] == 'i' && units[1] == 'n') - return NSVG_UNITS_IN; - else if (units[0] == '%') - return NSVG_UNITS_PERCENT; - else if (units[0] == 'e' && units[1] == 'm') - return NSVG_UNITS_EM; - else if (units[0] == 'e' && units[1] == 'x') - return NSVG_UNITS_EX; - return NSVG_UNITS_USER; -} - -static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str) -{ - NSVGcoordinate coord = {0, NSVG_UNITS_USER}; - char units[32]=""; - sscanf(str, "%f%s", &coord.value, units); - coord.units = nsvg__parseUnits(units); - return coord; -} - -static NSVGcoordinate nsvg__coord(float v, int units) -{ - NSVGcoordinate coord = {v, units}; - return coord; -} - -static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length) -{ - NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); - return nsvg__convertToPixels(p, coord, orig, length); -} - -static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na) -{ - const char* end; - const char* ptr; - char it[64]; - - *na = 0; - ptr = str; - while (*ptr && *ptr != '(') ++ptr; - if (*ptr == 0) - return 1; - end = ptr; - while (*end && *end != ')') ++end; - if (*end == 0) - return 1; - - while (ptr < end) { - if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { - if (*na >= maxNa) return 0; - ptr = nsvg__parseNumber(ptr, it, 64); - args[(*na)++] = (float)atof(it); - } else { - ++ptr; - } - } - return (int)(end - str); -} - - -static int nsvg__parseMatrix(float* xform, const char* str) -{ - float t[6]; - int na = 0; - int len = nsvg__parseTransformArgs(str, t, 6, &na); - if (na != 6) return len; - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseTranslate(float* xform, const char* str) -{ - float args[2]; - float t[6]; - int na = 0; - int len = nsvg__parseTransformArgs(str, args, 2, &na); - if (na == 1) args[1] = 0.0; - - nsvg__xformSetTranslation(t, args[0], args[1]); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseScale(float* xform, const char* str) -{ - float args[2]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 2, &na); - if (na == 1) args[1] = args[0]; - nsvg__xformSetScale(t, args[0], args[1]); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseSkewX(float* xform, const char* str) -{ - float args[1]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 1, &na); - nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseSkewY(float* xform, const char* str) -{ - float args[1]; - int na = 0; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 1, &na); - nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI); - memcpy(xform, t, sizeof(float)*6); - return len; -} - -static int nsvg__parseRotate(float* xform, const char* str) -{ - float args[3]; - int na = 0; - float m[6]; - float t[6]; - int len = nsvg__parseTransformArgs(str, args, 3, &na); - if (na == 1) - args[1] = args[2] = 0.0f; - nsvg__xformIdentity(m); - - if (na > 1) { - nsvg__xformSetTranslation(t, -args[1], -args[2]); - nsvg__xformMultiply(m, t); - } - - nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI); - nsvg__xformMultiply(m, t); - - if (na > 1) { - nsvg__xformSetTranslation(t, args[1], args[2]); - nsvg__xformMultiply(m, t); - } - - memcpy(xform, m, sizeof(float)*6); - - return len; -} - -static void nsvg__parseTransform(float* xform, const char* str) -{ - float t[6]; - nsvg__xformIdentity(xform); - while (*str) - { - if (strncmp(str, "matrix", 6) == 0) - str += nsvg__parseMatrix(t, str); - else if (strncmp(str, "translate", 9) == 0) - str += nsvg__parseTranslate(t, str); - else if (strncmp(str, "scale", 5) == 0) - str += nsvg__parseScale(t, str); - else if (strncmp(str, "rotate", 6) == 0) - str += nsvg__parseRotate(t, str); - else if (strncmp(str, "skewX", 5) == 0) - str += nsvg__parseSkewX(t, str); - else if (strncmp(str, "skewY", 5) == 0) - str += nsvg__parseSkewY(t, str); - else{ - ++str; - continue; - } - - nsvg__xformPremultiply(xform, t); - } -} - -static void nsvg__parseUrl(char* id, const char* str) -{ - int i = 0; - str += 4; // "url("; - if (*str == '#') - str++; - while (i < 63 && *str != ')') { - id[i] = *str++; - i++; - } - id[i] = '\0'; -} - -static char nsvg__parseLineCap(const char* str) -{ - if (strcmp(str, "butt") == 0) - return NSVG_CAP_BUTT; - else if (strcmp(str, "round") == 0) - return NSVG_CAP_ROUND; - else if (strcmp(str, "square") == 0) - return NSVG_CAP_SQUARE; - // TODO: handle inherit. - return NSVG_CAP_BUTT; -} - -static char nsvg__parseLineJoin(const char* str) -{ - if (strcmp(str, "miter") == 0) - return NSVG_JOIN_MITER; - else if (strcmp(str, "round") == 0) - return NSVG_JOIN_ROUND; - else if (strcmp(str, "bevel") == 0) - return NSVG_JOIN_BEVEL; - // TODO: handle inherit. - return NSVG_CAP_BUTT; -} - -static char nsvg__parseFillRule(const char* str) -{ - if (strcmp(str, "nonzero") == 0) - return NSVG_FILLRULE_NONZERO; - else if (strcmp(str, "evenodd") == 0) - return NSVG_FILLRULE_EVENODD; - // TODO: handle inherit. - return NSVG_FILLRULE_NONZERO; -} - -static const char* nsvg__getNextDashItem(const char* s, char* it) -{ - int n = 0; - it[0] = '\0'; - // Skip white spaces and commas - while (*s && (nsvg__isspace(*s) || *s == ',')) s++; - // Advance until whitespace, comma or end. - while (*s && (!nsvg__isspace(*s) && *s != ',')) { - if (n < 63) - it[n++] = *s; - s++; - } - it[n++] = '\0'; - return s; -} - -static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray) -{ - char item[64]; - int count = 0, i; - float sum = 0.0f; - - // Handle "none" - if (str[0] == 'n') - return 0; - - // Parse dashes - while (*str) { - str = nsvg__getNextDashItem(str, item); - if (!*item) break; - if (count < NSVG_MAX_DASHES) - strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); - } - - for (i = 0; i < count; i++) - sum += strokeDashArray[i]; - if (sum <= 1e-6f) - count = 0; - - return count; -} - -static void nsvg__parseStyle(NSVGparser* p, const char* str); - -static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) -{ - float xform[6]; - NSVGattrib* attr = nsvg__getAttr(p); - if (!attr) return 0; - - if (strcmp(name, "style") == 0) { - nsvg__parseStyle(p, value); - } else if (strcmp(name, "display") == 0) { - if (strcmp(value, "none") == 0) - attr->visible = 0; - // Don't reset ->visible on display:inline, one display:none hides the whole subtree - - } else if (strcmp(name, "fill") == 0) { - if (strcmp(value, "none") == 0) { - attr->hasFill = 0; - } else if (strncmp(value, "url(", 4) == 0) { - attr->hasFill = 2; - nsvg__parseUrl(attr->fillGradient, value); - } else { - attr->hasFill = 1; - attr->fillColor = nsvg__parseColor(value); - } - } else if (strcmp(name, "opacity") == 0) { - attr->opacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "fill-opacity") == 0) { - attr->fillOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "stroke") == 0) { - if (strcmp(value, "none") == 0) { - attr->hasStroke = 0; - } else if (strncmp(value, "url(", 4) == 0) { - attr->hasStroke = 2; - nsvg__parseUrl(attr->strokeGradient, value); - } else { - attr->hasStroke = 1; - attr->strokeColor = nsvg__parseColor(value); - } - } else if (strcmp(name, "stroke-width") == 0) { - attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "stroke-dasharray") == 0) { - attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); - } else if (strcmp(name, "stroke-dashoffset") == 0) { - attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "stroke-opacity") == 0) { - attr->strokeOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "stroke-linecap") == 0) { - attr->strokeLineCap = nsvg__parseLineCap(value); - } else if (strcmp(name, "stroke-linejoin") == 0) { - attr->strokeLineJoin = nsvg__parseLineJoin(value); - } else if (strcmp(name, "fill-rule") == 0) { - attr->fillRule = nsvg__parseFillRule(value); - } else if (strcmp(name, "font-size") == 0) { - attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); - } else if (strcmp(name, "transform") == 0) { - nsvg__parseTransform(xform, value); - nsvg__xformPremultiply(attr->xform, xform); - } else if (strcmp(name, "stop-color") == 0) { - attr->stopColor = nsvg__parseColor(value); - } else if (strcmp(name, "stop-opacity") == 0) { - attr->stopOpacity = nsvg__parseOpacity(value); - } else if (strcmp(name, "offset") == 0) { - attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); - } else if (strcmp(name, "id") == 0) { - strncpy(attr->id, value, 63); - attr->id[63] = '\0'; - } else { - return 0; - } - return 1; -} - -static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end) -{ - const char* str; - const char* val; - char name[512]; - char value[512]; - int n; - - str = start; - while (str < end && *str != ':') ++str; - - val = str; - - // Right Trim - while (str > start && (*str == ':' || nsvg__isspace(*str))) --str; - ++str; - - n = (int)(str - start); - if (n > 511) n = 511; - if (n) memcpy(name, start, n); - name[n] = 0; - - while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val; - - n = (int)(end - val); - if (n > 511) n = 511; - if (n) memcpy(value, val, n); - value[n] = 0; - - return nsvg__parseAttr(p, name, value); -} - -static void nsvg__parseStyle(NSVGparser* p, const char* str) -{ - const char* start; - const char* end; - - while (*str) { - // Left Trim - while(*str && nsvg__isspace(*str)) ++str; - start = str; - while(*str && *str != ';') ++str; - end = str; - - // Right Trim - while (end > start && (*end == ';' || nsvg__isspace(*end))) --end; - ++end; - - nsvg__parseNameValue(p, start, end); - if (*str) ++str; - } -} - -static void nsvg__parseAttribs(NSVGparser* p, const char** attr) -{ - int i; - for (i = 0; attr[i]; i += 2) - { - if (strcmp(attr[i], "style") == 0) - nsvg__parseStyle(p, attr[i + 1]); - else - nsvg__parseAttr(p, attr[i], attr[i + 1]); - } -} - -static int nsvg__getArgsPerElement(char cmd) -{ - switch (cmd) { - case 'v': - case 'V': - case 'h': - case 'H': - return 1; - case 'm': - case 'M': - case 'l': - case 'L': - case 't': - case 'T': - return 2; - case 'q': - case 'Q': - case 's': - case 'S': - return 4; - case 'c': - case 'C': - return 6; - case 'a': - case 'A': - return 7; - } - return 0; -} - -static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) { - *cpx += args[0]; - *cpy += args[1]; - } else { - *cpx = args[0]; - *cpy = args[1]; - } - nsvg__moveTo(p, *cpx, *cpy); -} - -static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) { - *cpx += args[0]; - *cpy += args[1]; - } else { - *cpx = args[0]; - *cpy = args[1]; - } - nsvg__lineTo(p, *cpx, *cpy); -} - -static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) - *cpx += args[0]; - else - *cpx = args[0]; - nsvg__lineTo(p, *cpx, *cpy); -} - -static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - if (rel) - *cpy += args[0]; - else - *cpy = args[0]; - nsvg__lineTo(p, *cpx, *cpy); -} - -static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x2, y2, cx1, cy1, cx2, cy2; - - if (rel) { - cx1 = *cpx + args[0]; - cy1 = *cpy + args[1]; - cx2 = *cpx + args[2]; - cy2 = *cpy + args[3]; - x2 = *cpx + args[4]; - y2 = *cpy + args[5]; - } else { - cx1 = args[0]; - cy1 = args[1]; - cx2 = args[2]; - cy2 = args[3]; - x2 = args[4]; - y2 = args[5]; - } - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx2; - *cpy2 = cy2; - *cpx = x2; - *cpy = y2; -} - -static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx1, cy1, cx2, cy2; - - x1 = *cpx; - y1 = *cpy; - if (rel) { - cx2 = *cpx + args[0]; - cy2 = *cpy + args[1]; - x2 = *cpx + args[2]; - y2 = *cpy + args[3]; - } else { - cx2 = args[0]; - cy2 = args[1]; - x2 = args[2]; - y2 = args[3]; - } - - cx1 = 2*x1 - *cpx2; - cy1 = 2*y1 - *cpy2; - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx2; - *cpy2 = cy2; - *cpx = x2; - *cpy = y2; -} - -static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx, cy; - float cx1, cy1, cx2, cy2; - - x1 = *cpx; - y1 = *cpy; - if (rel) { - cx = *cpx + args[0]; - cy = *cpy + args[1]; - x2 = *cpx + args[2]; - y2 = *cpy + args[3]; - } else { - cx = args[0]; - cy = args[1]; - x2 = args[2]; - y2 = args[3]; - } - - // Convert to cubic bezier - cx1 = x1 + 2.0f/3.0f*(cx - x1); - cy1 = y1 + 2.0f/3.0f*(cy - y1); - cx2 = x2 + 2.0f/3.0f*(cx - x2); - cy2 = y2 + 2.0f/3.0f*(cy - y2); - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx; - *cpy2 = cy; - *cpx = x2; - *cpy = y2; -} - -static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, - float* cpx2, float* cpy2, float* args, int rel) -{ - float x1, y1, x2, y2, cx, cy; - float cx1, cy1, cx2, cy2; - - x1 = *cpx; - y1 = *cpy; - if (rel) { - x2 = *cpx + args[0]; - y2 = *cpy + args[1]; - } else { - x2 = args[0]; - y2 = args[1]; - } - - cx = 2*x1 - *cpx2; - cy = 2*y1 - *cpy2; - - // Convert to cubix bezier - cx1 = x1 + 2.0f/3.0f*(cx - x1); - cy1 = y1 + 2.0f/3.0f*(cy - y1); - cx2 = x2 + 2.0f/3.0f*(cx - x2); - cy2 = y2 + 2.0f/3.0f*(cy - y2); - - nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); - - *cpx2 = cx; - *cpy2 = cy; - *cpx = x2; - *cpy = y2; -} - -static float nsvg__sqr(float x) { return x*x; } -static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); } - -static float nsvg__vecrat(float ux, float uy, float vx, float vy) -{ - return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy)); -} - -static float nsvg__vecang(float ux, float uy, float vx, float vy) -{ - float r = nsvg__vecrat(ux,uy, vx,vy); - if (r < -1.0f) r = -1.0f; - if (r > 1.0f) r = 1.0f; - return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r); -} - -static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) -{ - // Ported from canvg (https://code.google.com/p/canvg/) - float rx, ry, rotx; - float x1, y1, x2, y2, cx, cy, dx, dy, d; - float x1p, y1p, cxp, cyp, s, sa, sb; - float ux, uy, vx, vy, a1, da; - float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; - float sinrx, cosrx; - int fa, fs; - int i, ndivs; - float hda, kappa; - - rx = fabsf(args[0]); // y radius - ry = fabsf(args[1]); // x radius - rotx = args[2] / 180.0f * NSVG_PI; // x rotation engle - fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc - fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction - x1 = *cpx; // start point - y1 = *cpy; - if (rel) { // end point - x2 = *cpx + args[5]; - y2 = *cpy + args[6]; - } else { - x2 = args[5]; - y2 = args[6]; - } - - dx = x1 - x2; - dy = y1 - y2; - d = sqrtf(dx*dx + dy*dy); - if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { - // The arc degenerates to a line - nsvg__lineTo(p, x2, y2); - *cpx = x2; - *cpy = y2; - return; - } - - sinrx = sinf(rotx); - cosrx = cosf(rotx); - - // Convert to center point parameterization. - // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes - // 1) Compute x1', y1' - x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; - y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; - d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry); - if (d > 1) { - d = sqrtf(d); - rx *= d; - ry *= d; - } - // 2) Compute cx', cy' - s = 0.0f; - sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p); - sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p); - if (sa < 0.0f) sa = 0.0f; - if (sb > 0.0f) - s = sqrtf(sa / sb); - if (fa == fs) - s = -s; - cxp = s * rx * y1p / ry; - cyp = s * -ry * x1p / rx; - - // 3) Compute cx,cy from cx',cy' - cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp; - cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp; - - // 4) Calculate theta1, and delta theta. - ux = (x1p - cxp) / rx; - uy = (y1p - cyp) / ry; - vx = (-x1p - cxp) / rx; - vy = (-y1p - cyp) / ry; - a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle - da = nsvg__vecang(ux,uy, vx,vy); // Delta angle - -// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; -// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; - - if (fa) { - // Choose large arc - if (da > 0.0f) - da = da - 2*NSVG_PI; - else - da = 2*NSVG_PI + da; - } - - // Approximate the arc using cubic spline segments. - t[0] = cosrx; t[1] = sinrx; - t[2] = -sinrx; t[3] = cosrx; - t[4] = cx; t[5] = cy; - - // Split arc into max 90 degree segments. - // The loop assumes an iteration per end point (including start and end), this +1. - ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f); - hda = (da / (float)ndivs) / 2.0f; - kappa = fabsf(4.0f / 3.0f * (1.0f - cosf(hda)) / sinf(hda)); - if (da < 0.0f) - kappa = -kappa; - - for (i = 0; i <= ndivs; i++) { - a = a1 + da * (i/(float)ndivs); - dx = cosf(a); - dy = sinf(a); - nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position - nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent - if (i > 0) - nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y); - px = x; - py = y; - ptanx = tanx; - ptany = tany; - } - - *cpx = x2; - *cpy = y2; -} - -static void nsvg__parsePath(NSVGparser* p, const char** attr) -{ - const char* s = NULL; - char cmd = '\0'; - float args[10]; - int nargs; - int rargs = 0; - float cpx, cpy, cpx2, cpy2; - const char* tmp[4]; - char closedFlag; - int i; - char item[64]; - - for (i = 0; attr[i]; i += 2) { - if (strcmp(attr[i], "d") == 0) { - s = attr[i + 1]; - } else { - tmp[0] = attr[i]; - tmp[1] = attr[i + 1]; - tmp[2] = 0; - tmp[3] = 0; - nsvg__parseAttribs(p, tmp); - } - } - - if (s) { - nsvg__resetPath(p); - cpx = 0; cpy = 0; - cpx2 = 0; cpy2 = 0; - closedFlag = 0; - nargs = 0; - - while (*s) { - s = nsvg__getNextPathItem(s, item); - if (!*item) break; - if (nsvg__isnum(item[0])) { - if (nargs < 10) - args[nargs++] = (float)atof(item); - if (nargs >= rargs) { - switch (cmd) { - case 'm': - case 'M': - nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); - // Moveto can be followed by multiple coordinate pairs, - // which should be treated as linetos. - cmd = (cmd == 'm') ? 'l' : 'L'; - rargs = nsvg__getArgsPerElement(cmd); - cpx2 = cpx; cpy2 = cpy; - break; - case 'l': - case 'L': - nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'H': - case 'h': - nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'V': - case 'v': - nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - case 'C': - case 'c': - nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); - break; - case 'S': - case 's': - nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); - break; - case 'Q': - case 'q': - nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); - break; - case 'T': - case 't': - nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); - break; - case 'A': - case 'a': - nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); - cpx2 = cpx; cpy2 = cpy; - break; - default: - if (nargs >= 2) { - cpx = args[nargs-2]; - cpy = args[nargs-1]; - cpx2 = cpx; cpy2 = cpy; - } - break; - } - nargs = 0; - } - } else { - cmd = item[0]; - rargs = nsvg__getArgsPerElement(cmd); - if (cmd == 'M' || cmd == 'm') { - // Commit path. - if (p->npts > 0) - nsvg__addPath(p, closedFlag); - // Start new subpath. - nsvg__resetPath(p); - closedFlag = 0; - nargs = 0; - } else if (cmd == 'Z' || cmd == 'z') { - closedFlag = 1; - // Commit path. - if (p->npts > 0) { - // Move current point to first point - cpx = p->pts[0]; - cpy = p->pts[1]; - cpx2 = cpx; cpy2 = cpy; - nsvg__addPath(p, closedFlag); - } - // Start new subpath. - nsvg__resetPath(p); - nsvg__moveTo(p, cpx, cpy); - closedFlag = 0; - nargs = 0; - } - } - } - // Commit path. - if (p->npts) - nsvg__addPath(p, closedFlag); - } - - nsvg__addShape(p); -} - -static void nsvg__parseRect(NSVGparser* p, const char** attr) -{ - float x = 0.0f; - float y = 0.0f; - float w = 0.0f; - float h = 0.0f; - float rx = -1.0f; // marks not set - float ry = -1.0f; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)); - if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)); - if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); - if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); - } - } - - if (rx < 0.0f && ry > 0.0f) rx = ry; - if (ry < 0.0f && rx > 0.0f) ry = rx; - if (rx < 0.0f) rx = 0.0f; - if (ry < 0.0f) ry = 0.0f; - if (rx > w/2.0f) rx = w/2.0f; - if (ry > h/2.0f) ry = h/2.0f; - - if (w != 0.0f && h != 0.0f) { - nsvg__resetPath(p); - - if (rx < 0.00001f || ry < 0.0001f) { - nsvg__moveTo(p, x, y); - nsvg__lineTo(p, x+w, y); - nsvg__lineTo(p, x+w, y+h); - nsvg__lineTo(p, x, y+h); - } else { - // Rounded rectangle - nsvg__moveTo(p, x+rx, y); - nsvg__lineTo(p, x+w-rx, y); - nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry); - nsvg__lineTo(p, x+w, y+h-ry); - nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h); - nsvg__lineTo(p, x+rx, y+h); - nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry); - nsvg__lineTo(p, x, y+ry); - nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y); - } - - nsvg__addPath(p, 1); - - nsvg__addShape(p); - } -} - -static void nsvg__parseCircle(NSVGparser* p, const char** attr) -{ - float cx = 0.0f; - float cy = 0.0f; - float r = 0.0f; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p))); - } - } - - if (r > 0.0f) { - nsvg__resetPath(p); - - nsvg__moveTo(p, cx+r, cy); - nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r); - nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy); - nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r); - nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy); - - nsvg__addPath(p, 1); - - nsvg__addShape(p); - } -} - -static void nsvg__parseEllipse(NSVGparser* p, const char** attr) -{ - float cx = 0.0f; - float cy = 0.0f; - float rx = 0.0f; - float ry = 0.0f; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); - if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); - } - } - - if (rx > 0.0f && ry > 0.0f) { - - nsvg__resetPath(p); - - nsvg__moveTo(p, cx+rx, cy); - nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry); - nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy); - nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry); - nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy); - - nsvg__addPath(p, 1); - - nsvg__addShape(p); - } -} - -static void nsvg__parseLine(NSVGparser* p, const char** attr) -{ - float x1 = 0.0; - float y1 = 0.0; - float x2 = 0.0; - float y2 = 0.0; - int i; - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); - if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); - } - } - - nsvg__resetPath(p); - - nsvg__moveTo(p, x1, y1); - nsvg__lineTo(p, x2, y2); - - nsvg__addPath(p, 0); - - nsvg__addShape(p); -} - -static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag) -{ - int i; - const char* s; - float args[2]; - int nargs, npts = 0; - char item[64]; - - nsvg__resetPath(p); - - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "points") == 0) { - s = attr[i + 1]; - nargs = 0; - while (*s) { - s = nsvg__getNextPathItem(s, item); - args[nargs++] = (float)atof(item); - if (nargs >= 2) { - if (npts == 0) - nsvg__moveTo(p, args[0], args[1]); - else - nsvg__lineTo(p, args[0], args[1]); - nargs = 0; - npts++; - } - } - } - } - } - - nsvg__addPath(p, (char)closeFlag); - - nsvg__addShape(p); -} - -static void nsvg__parseSVG(NSVGparser* p, const char** attr) -{ - int i; - for (i = 0; attr[i]; i += 2) { - if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "width") == 0) { - p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 1.0f); - } else if (strcmp(attr[i], "height") == 0) { - p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 1.0f); - } else if (strcmp(attr[i], "viewBox") == 0) { - sscanf(attr[i + 1], "%f%*[%%, \t]%f%*[%%, \t]%f%*[%%, \t]%f", &p->viewMinx, &p->viewMiny, &p->viewWidth, &p->viewHeight); - } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { - if (strstr(attr[i + 1], "none") != 0) { - // No uniform scaling - p->alignType = NSVG_ALIGN_NONE; - } else { - // Parse X align - if (strstr(attr[i + 1], "xMin") != 0) - p->alignX = NSVG_ALIGN_MIN; - else if (strstr(attr[i + 1], "xMid") != 0) - p->alignX = NSVG_ALIGN_MID; - else if (strstr(attr[i + 1], "xMax") != 0) - p->alignX = NSVG_ALIGN_MAX; - // Parse X align - if (strstr(attr[i + 1], "yMin") != 0) - p->alignY = NSVG_ALIGN_MIN; - else if (strstr(attr[i + 1], "yMid") != 0) - p->alignY = NSVG_ALIGN_MID; - else if (strstr(attr[i + 1], "yMax") != 0) - p->alignY = NSVG_ALIGN_MAX; - // Parse meet/slice - p->alignType = NSVG_ALIGN_MEET; - if (strstr(attr[i + 1], "slice") != 0) - p->alignType = NSVG_ALIGN_SLICE; - } - } - } - } -} - -static void nsvg__parseGradient(NSVGparser* p, const char** attr, char type) -{ - int i; - NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData)); - if (grad == NULL) return; - memset(grad, 0, sizeof(NSVGgradientData)); - grad->units = NSVG_OBJECT_SPACE; - grad->type = type; - if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { - grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); - grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); - } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { - grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); - } - - nsvg__xformIdentity(grad->xform); - - for (i = 0; attr[i]; i += 2) { - if (strcmp(attr[i], "id") == 0) { - strncpy(grad->id, attr[i+1], 63); - grad->id[63] = '\0'; - } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { - if (strcmp(attr[i], "gradientUnits") == 0) { - if (strcmp(attr[i+1], "objectBoundingBox") == 0) - grad->units = NSVG_OBJECT_SPACE; - else - grad->units = NSVG_USER_SPACE; - } else if (strcmp(attr[i], "gradientTransform") == 0) { - nsvg__parseTransform(grad->xform, attr[i + 1]); - } else if (strcmp(attr[i], "cx") == 0) { - grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "cy") == 0) { - grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "r") == 0) { - grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "fx") == 0) { - grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "fy") == 0) { - grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "x1") == 0) { - grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "y1") == 0) { - grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "x2") == 0) { - grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "y2") == 0) { - grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); - } else if (strcmp(attr[i], "spreadMethod") == 0) { - if (strcmp(attr[i+1], "pad") == 0) - grad->spread = NSVG_SPREAD_PAD; - else if (strcmp(attr[i+1], "reflect") == 0) - grad->spread = NSVG_SPREAD_REFLECT; - else if (strcmp(attr[i+1], "repeat") == 0) - grad->spread = NSVG_SPREAD_REPEAT; - } else if (strcmp(attr[i], "xlink:href") == 0) { - const char *href = attr[i+1]; - strncpy(grad->ref, href+1, 62); - grad->ref[62] = '\0'; - } - } - } - - grad->next = p->gradients; - p->gradients = grad; -} - -static void nsvg__parseGradientStop(NSVGparser* p, const char** attr) -{ - NSVGattrib* curAttr = nsvg__getAttr(p); - NSVGgradientData* grad; - NSVGgradientStop* stop; - int i, idx; - - curAttr->stopOffset = 0; - curAttr->stopColor = 0; - curAttr->stopOpacity = 1.0f; - - for (i = 0; attr[i]; i += 2) { - nsvg__parseAttr(p, attr[i], attr[i + 1]); - } - - // Add stop to the last gradient. - grad = p->gradients; - if (grad == NULL) return; - - grad->nstops++; - grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops); - if (grad->stops == NULL) return; - - // Insert - idx = grad->nstops-1; - for (i = 0; i < grad->nstops-1; i++) { - if (curAttr->stopOffset < grad->stops[i].offset) { - idx = i; - break; - } - } - if (idx != grad->nstops-1) { - for (i = grad->nstops-1; i > idx; i--) - grad->stops[i] = grad->stops[i-1]; - } - - stop = &grad->stops[idx]; - stop->color = curAttr->stopColor; - stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24; - stop->offset = curAttr->stopOffset; -} - -static void nsvg__startElement(void* ud, const char* el, const char** attr) -{ - NSVGparser* p = (NSVGparser*)ud; - - if (p->defsFlag) { - // Skip everything but gradients in defs - if (strcmp(el, "linearGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); - } else if (strcmp(el, "radialGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); - } else if (strcmp(el, "stop") == 0) { - nsvg__parseGradientStop(p, attr); - } - return; - } - - if (strcmp(el, "g") == 0) { - nsvg__pushAttr(p); - nsvg__parseAttribs(p, attr); - } else if (strcmp(el, "path") == 0) { - if (p->pathFlag) // Do not allow nested paths. - return; - nsvg__pushAttr(p); - nsvg__parsePath(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "rect") == 0) { - nsvg__pushAttr(p); - nsvg__parseRect(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "circle") == 0) { - nsvg__pushAttr(p); - nsvg__parseCircle(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "ellipse") == 0) { - nsvg__pushAttr(p); - nsvg__parseEllipse(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "line") == 0) { - nsvg__pushAttr(p); - nsvg__parseLine(p, attr); - nsvg__popAttr(p); - } else if (strcmp(el, "polyline") == 0) { - nsvg__pushAttr(p); - nsvg__parsePoly(p, attr, 0); - nsvg__popAttr(p); - } else if (strcmp(el, "polygon") == 0) { - nsvg__pushAttr(p); - nsvg__parsePoly(p, attr, 1); - nsvg__popAttr(p); - } else if (strcmp(el, "linearGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); - } else if (strcmp(el, "radialGradient") == 0) { - nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); - } else if (strcmp(el, "stop") == 0) { - nsvg__parseGradientStop(p, attr); - } else if (strcmp(el, "defs") == 0) { - p->defsFlag = 1; - } else if (strcmp(el, "svg") == 0) { - nsvg__parseSVG(p, attr); - } -} - -static void nsvg__endElement(void* ud, const char* el) -{ - NSVGparser* p = (NSVGparser*)ud; - - if (strcmp(el, "g") == 0) { - nsvg__popAttr(p); - } else if (strcmp(el, "path") == 0) { - p->pathFlag = 0; - } else if (strcmp(el, "defs") == 0) { - p->defsFlag = 0; - } -} - -static void nsvg__content(void* ud, const char* s) -{ - NSVG_NOTUSED(ud); - NSVG_NOTUSED(s); - // empty -} - -static void nsvg__imageBounds(NSVGparser* p, float* bounds) -{ - NSVGshape* shape; - shape = p->image->shapes; - if (shape == NULL) { - bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; - return; - } - bounds[0] = shape->bounds[0]; - bounds[1] = shape->bounds[1]; - bounds[2] = shape->bounds[2]; - bounds[3] = shape->bounds[3]; - for (shape = shape->next; shape != NULL; shape = shape->next) { - bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); - bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); - bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); - bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); - } -} - -static float nsvg__viewAlign(float content, float container, int type) -{ - if (type == NSVG_ALIGN_MIN) - return 0; - else if (type == NSVG_ALIGN_MAX) - return container - content; - // mid - return (container - content) * 0.5f; -} - -static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy) -{ - grad->xform[0] *= sx; - grad->xform[1] *= sx; - grad->xform[2] *= sy; - grad->xform[3] *= sy; - grad->xform[4] += tx*sx; - grad->xform[5] += ty*sx; -} - -static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) -{ - NSVGshape* shape; - NSVGpath* path; - float tx, ty, sx, sy, us, bounds[4], t[6], avgs; - int i; - float* pt; - - // Guess image size if not set completely. - nsvg__imageBounds(p, bounds); - - if (p->viewWidth == 0) { - if (p->image->width > 0) { - p->viewWidth = p->image->width; - } else { - p->viewMinx = bounds[0]; - p->viewWidth = bounds[2] - bounds[0]; - } - } - if (p->viewHeight == 0) { - if (p->image->height > 0) { - p->viewHeight = p->image->height; - } else { - p->viewMiny = bounds[1]; - p->viewHeight = bounds[3] - bounds[1]; - } - } - if (p->image->width == 0) - p->image->width = p->viewWidth; - if (p->image->height == 0) - p->image->height = p->viewHeight; - - tx = -p->viewMinx; - ty = -p->viewMiny; - sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; - sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; - // Unit scaling - us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); - - // Fix aspect ratio - if (p->alignType == NSVG_ALIGN_MEET) { - // fit whole image into viewbox - sx = sy = nsvg__minf(sx, sy); - tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; - ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; - } else if (p->alignType == NSVG_ALIGN_SLICE) { - // fill whole viewbox with image - sx = sy = nsvg__maxf(sx, sy); - tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; - ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; - } - - // Transform - sx *= us; - sy *= us; - avgs = (sx+sy) / 2.0f; - for (shape = p->image->shapes; shape != NULL; shape = shape->next) { - shape->bounds[0] = (shape->bounds[0] + tx) * sx; - shape->bounds[1] = (shape->bounds[1] + ty) * sy; - shape->bounds[2] = (shape->bounds[2] + tx) * sx; - shape->bounds[3] = (shape->bounds[3] + ty) * sy; - for (path = shape->paths; path != NULL; path = path->next) { - path->bounds[0] = (path->bounds[0] + tx) * sx; - path->bounds[1] = (path->bounds[1] + ty) * sy; - path->bounds[2] = (path->bounds[2] + tx) * sx; - path->bounds[3] = (path->bounds[3] + ty) * sy; - for (i =0; i < path->npts; i++) { - pt = &path->pts[i*2]; - pt[0] = (pt[0] + tx) * sx; - pt[1] = (pt[1] + ty) * sy; - } - } - - if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { - nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy); - memcpy(t, shape->fill.gradient->xform, sizeof(float)*6); - nsvg__xformInverse(shape->fill.gradient->xform, t); - } - if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { - nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy); - memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6); - nsvg__xformInverse(shape->stroke.gradient->xform, t); - } - - shape->strokeWidth *= avgs; - shape->strokeDashOffset *= avgs; - for (i = 0; i < shape->strokeDashCount; i++) - shape->strokeDashArray[i] *= avgs; - } -} - -NSVGimage* nsvgParse(char* input, const char* units, float dpi) -{ - NSVGparser* p; - NSVGimage* ret = 0; - - p = nsvg__createParser(); - if (p == NULL) { - return NULL; - } - p->dpi = dpi; - - nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); - - // Scale to viewBox - nsvg__scaleToViewbox(p, units); - - ret = p->image; - p->image = NULL; - - nsvg__deleteParser(p); - - return ret; -} - -NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) -{ - FILE* fp = NULL; - size_t size; - char* data = NULL; - NSVGimage* image = NULL; - - fp = fopen(filename, "rb"); - if (!fp) goto error; - fseek(fp, 0, SEEK_END); - size = ftell(fp); - fseek(fp, 0, SEEK_SET); - data = (char*)malloc(size+1); - if (data == NULL) goto error; - if (fread(data, 1, size, fp) != size) goto error; - data[size] = '\0'; // Must be null terminated. - fclose(fp); - image = nsvgParse(data, units, dpi); - free(data); - - return image; - -error: - if (fp) fclose(fp); - if (data) free(data); - if (image) nsvgDelete(image); - return NULL; -} - -void nsvgDelete(NSVGimage* image) -{ - NSVGshape *snext, *shape; - if (image == NULL) return; - shape = image->shapes; - while (shape != NULL) { - snext = shape->next; - nsvg__deletePaths(shape->paths); - nsvg__deletePaint(&shape->fill); - nsvg__deletePaint(&shape->stroke); - free(shape); - shape = snext; - } - free(image); -} - -#endif diff --git a/src/common/dep/nanosvg/nanosvgrast.h b/src/common/dep/nanosvg/nanosvgrast.h deleted file mode 100644 index f0ef0be4a..000000000 --- a/src/common/dep/nanosvg/nanosvgrast.h +++ /dev/null @@ -1,1556 +0,0 @@ -/* - * Copyright (c) 2013-14 Mikko Mononen memon@inside.org - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would be - * appreciated but is not required. - * 2. Altered source versions must be plainly marked as such, and must not be - * misrepresented as being the original software. - * 3. This notice may not be removed or altered from any source distribution. - * - * The polygon rasterization is heavily based on stb_truetype rasterizer - * by Sean Barrett - http://nothings.org/ - * - */ - -#ifndef NANOSVGRAST_H -#define NANOSVGRAST_H - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct NSVGrasterizer NSVGrasterizer; - -/* Example Usage: - // Load SVG - struct SNVGImage* image = nsvgParseFromFile("test.svg."); - - // Create rasterizer (can be used to render multiple images). - struct NSVGrasterizer* rast = nsvgCreateRasterizer(); - // Allocate memory for image - unsigned char* img = malloc(w*h*4); - // Rasterize - nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4); -*/ - -// Allocated rasterizer context. -NSVGrasterizer* nsvgCreateRasterizer(); - -// Rasterizes SVG image, returns RGBA image (non-premultiplied alpha) -// r - pointer to rasterizer context -// image - pointer to image to rasterize -// tx,ty - image offset (applied after scaling) -// scale - image scale -// dst - pointer to destination image data, 4 bytes per pixel (RGBA) -// w - width of the image to render -// h - height of the image to render -// stride - number of bytes per scaleline in the destination buffer -void nsvgRasterize(NSVGrasterizer* r, - NSVGimage* image, float tx, float ty, float scale, - unsigned char* dst, int w, int h, int stride); - -// Deletes rasterizer context. -void nsvgDeleteRasterizer(NSVGrasterizer*); - - -#ifdef __cplusplus -}; -#endif - -#endif // NANOSVGRAST_H - -#ifdef NANOSVGRAST_IMPLEMENTATION - -#include - -#define NSVG__SUBSAMPLES 5 -#define NSVG__FIXSHIFT 10 -#define NSVG__FIX (1 << NSVG__FIXSHIFT) -#define NSVG__FIXMASK (NSVG__FIX-1) -#define NSVG__MEMPAGE_SIZE 1024 - -typedef struct NSVGedge { - float x0,y0, x1,y1; - int dir; - struct NSVGedge* next; -} NSVGedge; - -typedef struct NSVGpoint { - float x, y; - float dx, dy; - float len; - float dmx, dmy; - unsigned char flags; -} NSVGpoint; - -typedef struct NSVGactiveEdge { - int x,dx; - float ey; - int dir; - struct NSVGactiveEdge *next; -} NSVGactiveEdge; - -typedef struct NSVGmemPage { - unsigned char mem[NSVG__MEMPAGE_SIZE]; - int size; - struct NSVGmemPage* next; -} NSVGmemPage; - -typedef struct NSVGcachedPaint { - char type; - char spread; - float xform[6]; - unsigned int colors[256]; -} NSVGcachedPaint; - -struct NSVGrasterizer -{ - float px, py; - - float tessTol; - float distTol; - - NSVGedge* edges; - int nedges; - int cedges; - - NSVGpoint* points; - int npoints; - int cpoints; - - NSVGpoint* points2; - int npoints2; - int cpoints2; - - NSVGactiveEdge* freelist; - NSVGmemPage* pages; - NSVGmemPage* curpage; - - unsigned char* scanline; - int cscanline; - - unsigned char* bitmap; - int width, height, stride; -}; - -NSVGrasterizer* nsvgCreateRasterizer() -{ - NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer)); - if (r == NULL) goto error; - memset(r, 0, sizeof(NSVGrasterizer)); - - r->tessTol = 0.25f; - r->distTol = 0.01f; - - return r; - -error: - nsvgDeleteRasterizer(r); - return NULL; -} - -void nsvgDeleteRasterizer(NSVGrasterizer* r) -{ - NSVGmemPage* p; - - if (r == NULL) return; - - p = r->pages; - while (p != NULL) { - NSVGmemPage* next = p->next; - free(p); - p = next; - } - - if (r->edges) free(r->edges); - if (r->points) free(r->points); - if (r->points2) free(r->points2); - if (r->scanline) free(r->scanline); - - free(r); -} - -static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur) -{ - NSVGmemPage *newp; - - // If using existing chain, return the next page in chain - if (cur != NULL && cur->next != NULL) { - return cur->next; - } - - // Alloc new page - newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage)); - if (newp == NULL) return NULL; - memset(newp, 0, sizeof(NSVGmemPage)); - - // Add to linked list - if (cur != NULL) - cur->next = newp; - else - r->pages = newp; - - return newp; -} - -static void nsvg__resetPool(NSVGrasterizer* r) -{ - NSVGmemPage* p = r->pages; - while (p != NULL) { - p->size = 0; - p = p->next; - } - r->curpage = r->pages; -} - -static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size) -{ - unsigned char* buf; - if (size > NSVG__MEMPAGE_SIZE) return NULL; - if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) { - r->curpage = nsvg__nextPage(r, r->curpage); - } - buf = &r->curpage->mem[r->curpage->size]; - r->curpage->size += size; - return buf; -} - -static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol) -{ - float dx = x2 - x1; - float dy = y2 - y1; - return dx*dx + dy*dy < tol*tol; -} - -static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags) -{ - NSVGpoint* pt; - - if (r->npoints > 0) { - pt = &r->points[r->npoints-1]; - if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) { - pt->flags |= flags; - return; - } - } - - if (r->npoints+1 > r->cpoints) { - r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; - r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); - if (r->points == NULL) return; - } - - pt = &r->points[r->npoints]; - pt->x = x; - pt->y = y; - pt->flags = (unsigned char)flags; - r->npoints++; -} - -static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt) -{ - if (r->npoints+1 > r->cpoints) { - r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; - r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); - if (r->points == NULL) return; - } - r->points[r->npoints] = pt; - r->npoints++; -} - -static void nsvg__duplicatePoints(NSVGrasterizer* r) -{ - if (r->npoints > r->cpoints2) { - r->cpoints2 = r->npoints; - r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2); - if (r->points2 == NULL) return; - } - - memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints); - r->npoints2 = r->npoints; -} - -static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1) -{ - NSVGedge* e; - - // Skip horizontal edges - if (y0 == y1) - return; - - if (r->nedges+1 > r->cedges) { - r->cedges = r->cedges > 0 ? r->cedges * 2 : 64; - r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges); - if (r->edges == NULL) return; - } - - e = &r->edges[r->nedges]; - r->nedges++; - - if (y0 < y1) { - e->x0 = x0; - e->y0 = y0; - e->x1 = x1; - e->y1 = y1; - e->dir = 1; - } else { - e->x0 = x1; - e->y0 = y1; - e->x1 = x0; - e->y1 = y0; - e->dir = -1; - } -} - -static float nsvg__normalize(float *x, float* y) -{ - float d = sqrtf((*x)*(*x) + (*y)*(*y)); - if (d > 1e-6f) { - float id = 1.0f / d; - *x *= id; - *y *= id; - } - return d; -} - -static float nsvg__absf(float x) { return x < 0 ? -x : x; } - -static void nsvg__flattenCubicBez(NSVGrasterizer* r, - float x1, float y1, float x2, float y2, - float x3, float y3, float x4, float y4, - int level, int type) -{ - float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234; - float dx,dy,d2,d3; - - if (level > 10) return; - - x12 = (x1+x2)*0.5f; - y12 = (y1+y2)*0.5f; - x23 = (x2+x3)*0.5f; - y23 = (y2+y3)*0.5f; - x34 = (x3+x4)*0.5f; - y34 = (y3+y4)*0.5f; - x123 = (x12+x23)*0.5f; - y123 = (y12+y23)*0.5f; - - dx = x4 - x1; - dy = y4 - y1; - d2 = nsvg__absf(((x2 - x4) * dy - (y2 - y4) * dx)); - d3 = nsvg__absf(((x3 - x4) * dy - (y3 - y4) * dx)); - - if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) { - nsvg__addPathPoint(r, x4, y4, type); - return; - } - - x234 = (x23+x34)*0.5f; - y234 = (y23+y34)*0.5f; - x1234 = (x123+x234)*0.5f; - y1234 = (y123+y234)*0.5f; - - nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0); - nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type); -} - -static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale) -{ - int i, j; - NSVGpath* path; - - for (path = shape->paths; path != NULL; path = path->next) { - r->npoints = 0; - // Flatten path - nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); - for (i = 0; i < path->npts-1; i += 3) { - float* p = &path->pts[i*2]; - nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0); - } - // Close path - nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); - // Build edges - for (i = 0, j = r->npoints-1; i < r->npoints; j = i++) - nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y); - } -} - -enum NSVGpointFlags -{ - NSVG_PT_CORNER = 0x01, - NSVG_PT_BEVEL = 0x02, - NSVG_PT_LEFT = 0x04, -}; - -static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) -{ - float w = lineWidth * 0.5f; - float dx = p1->x - p0->x; - float dy = p1->y - p0->y; - float len = nsvg__normalize(&dx, &dy); - float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f; - float dlx = dy, dly = -dx; - float lx = px - dlx*w, ly = py - dly*w; - float rx = px + dlx*w, ry = py + dly*w; - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; -} - -static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) -{ - float w = lineWidth * 0.5f; - float px = p->x, py = p->y; - float dlx = dy, dly = -dx; - float lx = px - dlx*w, ly = py - dly*w; - float rx = px + dlx*w, ry = py + dly*w; - - nsvg__addEdge(r, lx, ly, rx, ry); - - if (connect) { - nsvg__addEdge(r, left->x, left->y, lx, ly); - nsvg__addEdge(r, rx, ry, right->x, right->y); - } - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; -} - -static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) -{ - float w = lineWidth * 0.5f; - float px = p->x - dx*w, py = p->y - dy*w; - float dlx = dy, dly = -dx; - float lx = px - dlx*w, ly = py - dly*w; - float rx = px + dlx*w, ry = py + dly*w; - - nsvg__addEdge(r, lx, ly, rx, ry); - - if (connect) { - nsvg__addEdge(r, left->x, left->y, lx, ly); - nsvg__addEdge(r, rx, ry, right->x, right->y); - } - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; -} - -#ifndef NSVG_PI -#define NSVG_PI (3.14159265358979323846264338327f) -#endif - -static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect) -{ - int i; - float w = lineWidth * 0.5f; - float px = p->x, py = p->y; - float dlx = dy, dly = -dx; - float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0; - - for (i = 0; i < ncap; i++) { - float a = i/(float)(ncap-1)*NSVG_PI; - float ax = cosf(a) * w, ay = sinf(a) * w; - float x = px - dlx*ax - dx*ay; - float y = py - dly*ax - dy*ay; - - if (i > 0) - nsvg__addEdge(r, prevx, prevy, x, y); - - prevx = x; - prevy = y; - - if (i == 0) { - lx = x; ly = y; - } else if (i == ncap-1) { - rx = x; ry = y; - } - } - - if (connect) { - nsvg__addEdge(r, left->x, left->y, lx, ly); - nsvg__addEdge(r, rx, ry, right->x, right->y); - } - - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; -} - -static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) -{ - float w = lineWidth * 0.5f; - float dlx0 = p0->dy, dly0 = -p0->dx; - float dlx1 = p1->dy, dly1 = -p1->dx; - float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w); - float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w); - float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w); - float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w); - - nsvg__addEdge(r, lx0, ly0, left->x, left->y); - nsvg__addEdge(r, lx1, ly1, lx0, ly0); - - nsvg__addEdge(r, right->x, right->y, rx0, ry0); - nsvg__addEdge(r, rx0, ry0, rx1, ry1); - - left->x = lx1; left->y = ly1; - right->x = rx1; right->y = ry1; -} - -static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) -{ - float w = lineWidth * 0.5f; - float dlx0 = p0->dy, dly0 = -p0->dx; - float dlx1 = p1->dy, dly1 = -p1->dx; - float lx0, rx0, lx1, rx1; - float ly0, ry0, ly1, ry1; - - if (p1->flags & NSVG_PT_LEFT) { - lx0 = lx1 = p1->x - p1->dmx * w; - ly0 = ly1 = p1->y - p1->dmy * w; - nsvg__addEdge(r, lx1, ly1, left->x, left->y); - - rx0 = p1->x + (dlx0 * w); - ry0 = p1->y + (dly0 * w); - rx1 = p1->x + (dlx1 * w); - ry1 = p1->y + (dly1 * w); - nsvg__addEdge(r, right->x, right->y, rx0, ry0); - nsvg__addEdge(r, rx0, ry0, rx1, ry1); - } else { - lx0 = p1->x - (dlx0 * w); - ly0 = p1->y - (dly0 * w); - lx1 = p1->x - (dlx1 * w); - ly1 = p1->y - (dly1 * w); - nsvg__addEdge(r, lx0, ly0, left->x, left->y); - nsvg__addEdge(r, lx1, ly1, lx0, ly0); - - rx0 = rx1 = p1->x + p1->dmx * w; - ry0 = ry1 = p1->y + p1->dmy * w; - nsvg__addEdge(r, right->x, right->y, rx1, ry1); - } - - left->x = lx1; left->y = ly1; - right->x = rx1; right->y = ry1; -} - -static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap) -{ - int i, n; - float w = lineWidth * 0.5f; - float dlx0 = p0->dy, dly0 = -p0->dx; - float dlx1 = p1->dy, dly1 = -p1->dx; - float a0 = atan2f(dly0, dlx0); - float a1 = atan2f(dly1, dlx1); - float da = a1 - a0; - float lx, ly, rx, ry; - - if (da < NSVG_PI) da += NSVG_PI*2; - if (da > NSVG_PI) da -= NSVG_PI*2; - - n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * ncap); - if (n < 2) n = 2; - if (n > ncap) n = ncap; - - lx = left->x; - ly = left->y; - rx = right->x; - ry = right->y; - - for (i = 0; i < n; i++) { - float u = i/(float)(n-1); - float a = a0 + u*da; - float ax = cosf(a) * w, ay = sinf(a) * w; - float lx1 = p1->x - ax, ly1 = p1->y - ay; - float rx1 = p1->x + ax, ry1 = p1->y + ay; - - nsvg__addEdge(r, lx1, ly1, lx, ly); - nsvg__addEdge(r, rx, ry, rx1, ry1); - - lx = lx1; ly = ly1; - rx = rx1; ry = ry1; - } - - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; -} - -static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth) -{ - float w = lineWidth * 0.5f; - float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w); - float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w); - - nsvg__addEdge(r, lx, ly, left->x, left->y); - nsvg__addEdge(r, right->x, right->y, rx, ry); - - left->x = lx; left->y = ly; - right->x = rx; right->y = ry; -} - -static int nsvg__curveDivs(float r, float arc, float tol) -{ - float da = acosf(r / (r + tol)) * 2.0f; - int divs = (int)ceilf(arc / da); - if (divs < 2) divs = 2; - return divs; -} - -static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth) -{ - int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol); // Calculate divisions per half circle. - NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0}; - NSVGpoint* p0, *p1; - int j, s, e; - - // Build stroke edges - if (closed) { - // Looping - p0 = &points[npoints-1]; - p1 = &points[0]; - s = 0; - e = npoints; - } else { - // Add cap - p0 = &points[0]; - p1 = &points[1]; - s = 1; - e = npoints-1; - } - - if (closed) { - nsvg__initClosed(&left, &right, p0, p1, lineWidth); - firstLeft = left; - firstRight = right; - } else { - // Add cap - float dx = p1->x - p0->x; - float dy = p1->y - p0->y; - nsvg__normalize(&dx, &dy); - if (lineCap == NSVG_CAP_BUTT) - nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0); - else if (lineCap == NSVG_CAP_SQUARE) - nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0); - else if (lineCap == NSVG_CAP_ROUND) - nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0); - } - - for (j = s; j < e; ++j) { - if (p1->flags & NSVG_PT_CORNER) { - if (lineJoin == NSVG_JOIN_ROUND) - nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap); - else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL)) - nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth); - else - nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth); - } else { - nsvg__straightJoin(r, &left, &right, p1, lineWidth); - } - p0 = p1++; - } - - if (closed) { - // Loop it - nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y); - nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y); - } else { - // Add cap - float dx = p1->x - p0->x; - float dy = p1->y - p0->y; - nsvg__normalize(&dx, &dy); - if (lineCap == NSVG_CAP_BUTT) - nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1); - else if (lineCap == NSVG_CAP_SQUARE) - nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1); - else if (lineCap == NSVG_CAP_ROUND) - nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1); - } -} - -static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin) -{ - int i, j; - NSVGpoint* p0, *p1; - - p0 = &r->points[r->npoints-1]; - p1 = &r->points[0]; - for (i = 0; i < r->npoints; i++) { - // Calculate segment direction and length - p0->dx = p1->x - p0->x; - p0->dy = p1->y - p0->y; - p0->len = nsvg__normalize(&p0->dx, &p0->dy); - // Advance - p0 = p1++; - } - - // calculate joins - p0 = &r->points[r->npoints-1]; - p1 = &r->points[0]; - for (j = 0; j < r->npoints; j++) { - float dlx0, dly0, dlx1, dly1, dmr2, cross; - dlx0 = p0->dy; - dly0 = -p0->dx; - dlx1 = p1->dy; - dly1 = -p1->dx; - // Calculate extrusions - p1->dmx = (dlx0 + dlx1) * 0.5f; - p1->dmy = (dly0 + dly1) * 0.5f; - dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy; - if (dmr2 > 0.000001f) { - float s2 = 1.0f / dmr2; - if (s2 > 600.0f) { - s2 = 600.0f; - } - p1->dmx *= s2; - p1->dmy *= s2; - } - - // Clear flags, but keep the corner. - p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0; - - // Keep track of left turns. - cross = p1->dx * p0->dy - p0->dx * p1->dy; - if (cross > 0.0f) - p1->flags |= NSVG_PT_LEFT; - - // Check to see if the corner needs to be beveled. - if (p1->flags & NSVG_PT_CORNER) { - if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) { - p1->flags |= NSVG_PT_BEVEL; - } - } - - p0 = p1++; - } -} - -static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale) -{ - int i, j, closed; - NSVGpath* path; - NSVGpoint* p0, *p1; - float miterLimit = 4; - int lineJoin = shape->strokeLineJoin; - int lineCap = shape->strokeLineCap; - float lineWidth = shape->strokeWidth * scale; - - for (path = shape->paths; path != NULL; path = path->next) { - // Flatten path - r->npoints = 0; - nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER); - for (i = 0; i < path->npts-1; i += 3) { - float* p = &path->pts[i*2]; - nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER); - } - if (r->npoints < 2) - continue; - - closed = path->closed; - - // If the first and last points are the same, remove the last, mark as closed path. - p0 = &r->points[r->npoints-1]; - p1 = &r->points[0]; - if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) { - r->npoints--; - p0 = &r->points[r->npoints-1]; - closed = 1; - } - - if (shape->strokeDashCount > 0) { - int idash = 0, dashState = 1; - float totalDist = 0, dashLen, allDashLen, dashOffset; - NSVGpoint cur; - - if (closed) - nsvg__appendPathPoint(r, r->points[0]); - - // Duplicate points -> points2. - nsvg__duplicatePoints(r); - - r->npoints = 0; - cur = r->points2[0]; - nsvg__appendPathPoint(r, cur); - - // Figure out dash offset. - allDashLen = 0; - for (j = 0; j < shape->strokeDashCount; j++) - allDashLen += shape->strokeDashArray[j]; - if (shape->strokeDashCount & 1) - allDashLen *= 2.0f; - // Find location inside pattern - dashOffset = fmodf(shape->strokeDashOffset, allDashLen); - if (dashOffset < 0.0f) - dashOffset += allDashLen; - - while (dashOffset > shape->strokeDashArray[idash]) { - dashOffset -= shape->strokeDashArray[idash]; - idash = (idash + 1) % shape->strokeDashCount; - } - dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale; - - for (j = 1; j < r->npoints2; ) { - float dx = r->points2[j].x - cur.x; - float dy = r->points2[j].y - cur.y; - float dist = sqrtf(dx*dx + dy*dy); - - if ((totalDist + dist) > dashLen) { - // Calculate intermediate point - float d = (dashLen - totalDist) / dist; - float x = cur.x + dx * d; - float y = cur.y + dy * d; - nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER); - - // Stroke - if (r->npoints > 1 && dashState) { - nsvg__prepareStroke(r, miterLimit, lineJoin); - nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); - } - // Advance dash pattern - dashState = !dashState; - idash = (idash+1) % shape->strokeDashCount; - dashLen = shape->strokeDashArray[idash] * scale; - // Restart - cur.x = x; - cur.y = y; - cur.flags = NSVG_PT_CORNER; - totalDist = 0.0f; - r->npoints = 0; - nsvg__appendPathPoint(r, cur); - } else { - totalDist += dist; - cur = r->points2[j]; - nsvg__appendPathPoint(r, cur); - j++; - } - } - // Stroke any leftover path - if (r->npoints > 1 && dashState) - nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); - } else { - nsvg__prepareStroke(r, miterLimit, lineJoin); - nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth); - } - } -} - -static int nsvg__cmpEdge(const void *p, const void *q) -{ - NSVGedge* a = (NSVGedge*)p; - NSVGedge* b = (NSVGedge*)q; - - if (a->y0 < b->y0) return -1; - if (a->y0 > b->y0) return 1; - return 0; -} - - -static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint) -{ - NSVGactiveEdge* z; - - if (r->freelist != NULL) { - // Restore from freelist. - z = r->freelist; - r->freelist = z->next; - } else { - // Alloc new edge. - z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge)); - if (z == NULL) return NULL; - } - - float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); -// STBTT_assert(e->y0 <= start_point); - // round dx down to avoid going too far - if (dxdy < 0) - z->dx = (int)(-floorf(NSVG__FIX * -dxdy)); - else - z->dx = (int)floorf(NSVG__FIX * dxdy); - z->x = (int)floorf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0))); -// z->x -= off_x * FIX; - z->ey = e->y1; - z->next = 0; - z->dir = e->dir; - - return z; -} - -static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z) -{ - z->next = r->freelist; - r->freelist = z; -} - -static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax) -{ - int i = x0 >> NSVG__FIXSHIFT; - int j = x1 >> NSVG__FIXSHIFT; - if (i < *xmin) *xmin = i; - if (j > *xmax) *xmax = j; - if (i < len && j >= 0) { - if (i == j) { - // x0,x1 are the same pixel, so compute combined coverage - scanline[i] += (unsigned char)((x1 - x0) * maxWeight >> NSVG__FIXSHIFT); - } else { - if (i >= 0) // add antialiasing for x0 - scanline[i] += (unsigned char)(((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT); - else - i = -1; // clip - - if (j < len) // add antialiasing for x1 - scanline[j] += (unsigned char)(((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT); - else - j = len; // clip - - for (++i; i < j; ++i) // fill pixels between x0 and x1 - scanline[i] += (unsigned char)maxWeight; - } - } -} - -// note: this routine clips fills that extend off the edges... ideally this -// wouldn't happen, but it could happen if the truetype glyph bounding boxes -// are wrong, or if the user supplies a too-small bitmap -static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule) -{ - // non-zero winding fill - int x0 = 0, w = 0; - - if (fillRule == NSVG_FILLRULE_NONZERO) { - // Non-zero - while (e != NULL) { - if (w == 0) { - // if we're currently at zero, we need to record the edge start point - x0 = e->x; w += e->dir; - } else { - int x1 = e->x; w += e->dir; - // if we went to zero, we need to draw - if (w == 0) - nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); - } - e = e->next; - } - } else if (fillRule == NSVG_FILLRULE_EVENODD) { - // Even-odd - while (e != NULL) { - if (w == 0) { - // if we're currently at zero, we need to record the edge start point - x0 = e->x; w = 1; - } else { - int x1 = e->x; w = 0; - nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); - } - e = e->next; - } - } -} - -static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); } - -static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) -{ - return (r) | (g << 8) | (b << 16) | (a << 24); -} - -static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u) -{ - int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); - int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8; - int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8; - int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8; - int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8; - return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); -} - -static unsigned int nsvg__applyOpacity(unsigned int c, float u) -{ - int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); - int r = (c) & 0xff; - int g = (c>>8) & 0xff; - int b = (c>>16) & 0xff; - int a = (((c>>24) & 0xff)*iu) >> 8; - return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); -} - -static inline int nsvg__div255(int x) -{ - return ((x+1) * 257) >> 16; -} - -static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y, - float tx, float ty, float scale, NSVGcachedPaint* cache) -{ - - if (cache->type == NSVG_PAINT_COLOR) { -// JRY patch -//#define NSVG_USESSE2 -#ifdef NSVG_USESSE2 - int i, cr, cg, cb, ca; - cr = cache->colors[0] & 0xff; - cg = (cache->colors[0] >> 8) & 0xff; - cb = (cache->colors[0] >> 16) & 0xff; - ca = (cache->colors[0] >> 24) & 0xff; - - __m128i const0 = _mm_setzero_si128(); - __m128i const1 = _mm_set1_epi16(1); - __m128i const255 = _mm_set1_epi16(255); - __m128i constCA = _mm_set1_epi16((short)ca); - __m128i constC = _mm_set_epi16(0, (short)cb, (short)cg, (short)cr, 0, (short)cb, (short)cg, (short)cr); - - for (i = 0; i < count / 4; i++) { - //int a = nsvg__div255((int)cover[0] * ca); - __m128i cover_ca = _mm_mullo_epi16(_mm_unpacklo_epi8(_mm_cvtsi32_si128(*(const int*)cover), const0), constCA); - //nsvg__div255: (x + 1 + ((x + 1) >> 8)) >> 8 - __m128i coverplusone = _mm_add_epi16(cover_ca, const1); - __m128i a = _mm_srli_epi16(_mm_add_epi16(coverplusone, _mm_srli_epi16(coverplusone, 8)), 8); - //int ia = 255 - a; - __m128i ia = _mm_sub_epi16(const255, a); - - __m128i a_01 = _mm_set_epi16(a.m128i_u16[1], a.m128i_u16[1], a.m128i_u16[1], a.m128i_u16[1], a.m128i_u16[0], a.m128i_u16[0], a.m128i_u16[0], a.m128i_u16[0]); - __m128i ia_01 = _mm_set_epi16(ia.m128i_u16[1], ia.m128i_u16[1], ia.m128i_u16[1], ia.m128i_u16[1], ia.m128i_u16[0], ia.m128i_u16[0], ia.m128i_u16[0], ia.m128i_u16[0]); - __m128i a_23 = _mm_set_epi16(a.m128i_u16[3], a.m128i_u16[3], a.m128i_u16[3], a.m128i_u16[3], a.m128i_u16[2], a.m128i_u16[2], a.m128i_u16[2], a.m128i_u16[2]); - __m128i ia_23 = _mm_set_epi16(ia.m128i_u16[3], ia.m128i_u16[3], ia.m128i_u16[3], ia.m128i_u16[3], ia.m128i_u16[2], ia.m128i_u16[2], ia.m128i_u16[2], ia.m128i_u16[2]); - - // Premultiply - //r = nsvg__div255(cr * a); - //g = nsvg__div255(cg * a); - //b = nsvg__div255(cb * a); - //nsvg__div255: (x + 1 + ((x + 1) >> 8)) >> 8 - __m128i rgbplusone_01 = _mm_add_epi16(_mm_mullo_epi16(constC, a_01), const1); - __m128i rgbout_01 = _mm_srli_epi16(_mm_add_epi16(rgbplusone_01, _mm_srli_epi16(rgbplusone_01, 8)), 8); - rgbout_01.m128i_u16[3] = a.m128i_u16[0]; - rgbout_01.m128i_u16[7] = a.m128i_u16[1]; - __m128i rgbplusone_23 = _mm_add_epi16(_mm_mullo_epi16(constC, a_23), const1); - __m128i rgbout_23 = _mm_srli_epi16(_mm_add_epi16(rgbplusone_23, _mm_srli_epi16(rgbplusone_23, 8)), 8); - rgbout_23.m128i_u16[3] = a.m128i_u16[2]; - rgbout_23.m128i_u16[7] = a.m128i_u16[3]; - - // Blend over - //r += nsvg__div255(ia * (int)dst[0]); - //g += nsvg__div255(ia * (int)dst[1]); - //b += nsvg__div255(ia * (int)dst[2]); - //a += nsvg__div255(ia * (int)dst[3]); - __m128i dst16 = _mm_loadu_si128((__m128i*)dst); - __m128i dst_01 = _mm_unpacklo_epi8(dst16, const0); - __m128i dst_23 = _mm_unpackhi_epi8(dst16, const0); - - //nsvg__div255: (x + 1 + ((x + 1) >> 8)) >> 8 - __m128i blendplusone_01 = _mm_add_epi16(_mm_mullo_epi16(ia_01, dst_01), const1); - __m128i blend16_01 = _mm_srli_epi16(_mm_add_epi16(blendplusone_01, _mm_srli_epi16(blendplusone_01, 8)), 8); - rgbout_01 = _mm_add_epi16(rgbout_01, blend16_01); - __m128i blendplusone_23 = _mm_add_epi16(_mm_mullo_epi16(ia_23, dst_23), const1); - __m128i blend16_23 = _mm_srli_epi16(_mm_add_epi16(blendplusone_23, _mm_srli_epi16(blendplusone_23, 8)), 8); - rgbout_23 = _mm_add_epi16(rgbout_23, blend16_23); - - //dst[0] = (unsigned char)r; - //dst[1] = (unsigned char)g; - //dst[2] = (unsigned char)b; - //dst[3] = (unsigned char)a; - __m128i out = _mm_packus_epi16(rgbout_01, rgbout_23); - _mm_storeu_si128((__m128i*)dst, out); - - cover += 4; - dst += 16; - } - for (i = 4 * (count / 4); i < count; i++) { - int r, g, b; - - int a = nsvg__div255((int)cover[0] * ca); - int ia = 255 - a; - - // Premultiply - r = nsvg__div255(cr * a); - g = nsvg__div255(cg * a); - b = nsvg__div255(cb * a); - - // Blend over - r += nsvg__div255(ia * (int)dst[0]); - g += nsvg__div255(ia * (int)dst[1]); - b += nsvg__div255(ia * (int)dst[2]); - a += nsvg__div255(ia * (int)dst[3]); - - dst[0] = (unsigned char)r; - dst[1] = (unsigned char)g; - dst[2] = (unsigned char)b; - dst[3] = (unsigned char)a; - - cover++; - dst += 4; - } -#else // NSVG_USESSE2 - int i, cr, cg, cb, ca; - cr = cache->colors[0] & 0xff; - cg = (cache->colors[0] >> 8) & 0xff; - cb = (cache->colors[0] >> 16) & 0xff; - ca = (cache->colors[0] >> 24) & 0xff; - - for (i = 0; i < count; i++) { - int r,g,b; - int a = nsvg__div255((int)cover[0] * ca); - int ia = 255 - a; - // Premultiply - r = nsvg__div255(cr * a); - g = nsvg__div255(cg * a); - b = nsvg__div255(cb * a); - - // Blend over - r += nsvg__div255(ia * (int)dst[0]); - g += nsvg__div255(ia * (int)dst[1]); - b += nsvg__div255(ia * (int)dst[2]); - a += nsvg__div255(ia * (int)dst[3]); - - dst[0] = (unsigned char)r; - dst[1] = (unsigned char)g; - dst[2] = (unsigned char)b; - dst[3] = (unsigned char)a; - - cover++; - dst += 4; - } -#endif // NSVG_USESSE2 - } else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) { - // TODO: spread modes. - // TODO: plenty of opportunities to optimize. - float fx, fy, dx, gy; - float* t = cache->xform; - int i, cr, cg, cb, ca; - unsigned int c; - - fx = (x - tx) / scale; - fy = (y - ty) / scale; - dx = 1.0f / scale; - - for (i = 0; i < count; i++) { - int r,g,b,a,ia; - gy = fx*t[1] + fy*t[3] + t[5]; - c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)]; - cr = (c) & 0xff; - cg = (c >> 8) & 0xff; - cb = (c >> 16) & 0xff; - ca = (c >> 24) & 0xff; - - a = nsvg__div255((int)cover[0] * ca); - ia = 255 - a; - - // Premultiply - r = nsvg__div255(cr * a); - g = nsvg__div255(cg * a); - b = nsvg__div255(cb * a); - - // Blend over - r += nsvg__div255(ia * (int)dst[0]); - g += nsvg__div255(ia * (int)dst[1]); - b += nsvg__div255(ia * (int)dst[2]); - a += nsvg__div255(ia * (int)dst[3]); - - dst[0] = (unsigned char)r; - dst[1] = (unsigned char)g; - dst[2] = (unsigned char)b; - dst[3] = (unsigned char)a; - - cover++; - dst += 4; - fx += dx; - } - } else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) { - // TODO: spread modes. - // TODO: plenty of opportunities to optimize. - // TODO: focus (fx,fy) - float fx, fy, dx, gx, gy, gd; - float* t = cache->xform; - int i, cr, cg, cb, ca; - unsigned int c; - - fx = (x - tx) / scale; - fy = (y - ty) / scale; - dx = 1.0f / scale; - - for (i = 0; i < count; i++) { - int r,g,b,a,ia; - gx = fx*t[0] + fy*t[2] + t[4]; - gy = fx*t[1] + fy*t[3] + t[5]; - gd = sqrtf(gx*gx + gy*gy); - c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)]; - cr = (c) & 0xff; - cg = (c >> 8) & 0xff; - cb = (c >> 16) & 0xff; - ca = (c >> 24) & 0xff; - - a = nsvg__div255((int)cover[0] * ca); - ia = 255 - a; - - // Premultiply - r = nsvg__div255(cr * a); - g = nsvg__div255(cg * a); - b = nsvg__div255(cb * a); - - // Blend over - r += nsvg__div255(ia * (int)dst[0]); - g += nsvg__div255(ia * (int)dst[1]); - b += nsvg__div255(ia * (int)dst[2]); - a += nsvg__div255(ia * (int)dst[3]); - - dst[0] = (unsigned char)r; - dst[1] = (unsigned char)g; - dst[2] = (unsigned char)b; - dst[3] = (unsigned char)a; - - cover++; - dst += 4; - fx += dx; - } - } -} - -static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule) -{ - NSVGactiveEdge *active = NULL; - int y, s; - int e = 0; - int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline - int xmin, xmax; - - for (y = 0; y < r->height; y++) { - memset(r->scanline, 0, r->width); - xmin = r->width; - xmax = 0; - for (s = 0; s < NSVG__SUBSAMPLES; ++s) { - // find center of pixel for this scanline - float scany = y*NSVG__SUBSAMPLES + s + 0.5f; - NSVGactiveEdge **step = &active; - - // update all active edges; - // remove all active edges that terminate before the center of this scanline - while (*step) { - NSVGactiveEdge *z = *step; - if (z->ey <= scany) { - *step = z->next; // delete from list -// NSVG__assert(z->valid); - nsvg__freeActive(r, z); - } else { - z->x += z->dx; // advance to position for current scanline - step = &((*step)->next); // advance through list - } - } - - // resort the list if needed - for (;;) { - int changed = 0; - step = &active; - while (*step && (*step)->next) { - if ((*step)->x > (*step)->next->x) { - NSVGactiveEdge* t = *step; - NSVGactiveEdge* q = t->next; - t->next = q->next; - q->next = t; - *step = q; - changed = 1; - } - step = &(*step)->next; - } - if (!changed) break; - } - - // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline - while (e < r->nedges && r->edges[e].y0 <= scany) { - if (r->edges[e].y1 > scany) { - NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany); - if (z == NULL) break; - // find insertion point - if (active == NULL) { - active = z; - } else if (z->x < active->x) { - // insert at front - z->next = active; - active = z; - } else { - // find thing to insert AFTER - NSVGactiveEdge* p = active; - while (p->next && p->next->x < z->x) - p = p->next; - // at this point, p->next->x is NOT < z->x - z->next = p->next; - p->next = z; - } - } - e++; - } - - // now process all active edges in non-zero fashion - if (active != NULL) - nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule); - } - // Blit - if (xmin < 0) xmin = 0; - if (xmax > r->width-1) xmax = r->width-1; - if (xmin <= xmax) { - nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache); - } - } - -} - -static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride) -{ - int x,y; - - // Unpremultiply - for (y = 0; y < h; y++) { - unsigned char *row = &image[y*stride]; - for (x = 0; x < w; x++) { - int r = row[0], g = row[1], b = row[2], a = row[3]; - if (a != 0) { - row[0] = (unsigned char)(r*255/a); - row[1] = (unsigned char)(g*255/a); - row[2] = (unsigned char)(b*255/a); - } - row += 4; - } - } - - // Defringe - for (y = 0; y < h; y++) { - unsigned char *row = &image[y*stride]; - for (x = 0; x < w; x++) { - int r = 0, g = 0, b = 0, a = row[3], n = 0; - if (a == 0) { - if (x-1 > 0 && row[-1] != 0) { - r += row[-4]; - g += row[-3]; - b += row[-2]; - n++; - } - if (x+1 < w && row[7] != 0) { - r += row[4]; - g += row[5]; - b += row[6]; - n++; - } - if (y-1 > 0 && row[-stride+3] != 0) { - r += row[-stride]; - g += row[-stride+1]; - b += row[-stride+2]; - n++; - } - if (y+1 < h && row[stride+3] != 0) { - r += row[stride]; - g += row[stride+1]; - b += row[stride+2]; - n++; - } - if (n > 0) { - row[0] = (unsigned char)(r/n); - row[1] = (unsigned char)(g/n); - row[2] = (unsigned char)(b/n); - } - } - row += 4; - } - } -} - - -static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity) -{ - int i, j; - NSVGgradient* grad; - - cache->type = paint->type; - - if (paint->type == NSVG_PAINT_COLOR) { - cache->colors[0] = nsvg__applyOpacity(paint->color, opacity); - return; - } - - grad = paint->gradient; - - cache->spread = grad->spread; - memcpy(cache->xform, grad->xform, sizeof(float)*6); - - if (grad->nstops == 0) { - for (i = 0; i < 256; i++) - cache->colors[i] = 0; - } if (grad->nstops == 1) { - for (i = 0; i < 256; i++) - cache->colors[i] = nsvg__applyOpacity(grad->stops[i].color, opacity); - } else { - unsigned int ca, cb = 0; - float ua, ub, du, u; - int ia, ib, count; - - ca = nsvg__applyOpacity(grad->stops[0].color, opacity); - ua = nsvg__clampf(grad->stops[0].offset, 0, 1); - ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1); - ia = (int)(ua * 255.0f); - ib = (int)(ub * 255.0f); - for (i = 0; i < ia; i++) { - cache->colors[i] = ca; - } - - for (i = 0; i < grad->nstops-1; i++) { - ca = nsvg__applyOpacity(grad->stops[i].color, opacity); - cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity); - ua = nsvg__clampf(grad->stops[i].offset, 0, 1); - ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1); - ia = (int)(ua * 255.0f); - ib = (int)(ub * 255.0f); - count = ib - ia; - if (count <= 0) continue; - u = 0; - du = 1.0f / (float)count; - for (j = 0; j < count; j++) { - cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u); - u += du; - } - } - - for (i = ib; i < 256; i++) - cache->colors[i] = cb; - } - -} - -/* -static void dumpEdges(NSVGrasterizer* r, const char* name) -{ - float xmin = 0, xmax = 0, ymin = 0, ymax = 0; - NSVGedge *e = NULL; - int i; - if (r->nedges == 0) return; - FILE* fp = fopen(name, "w"); - if (fp == NULL) return; - - xmin = xmax = r->edges[0].x0; - ymin = ymax = r->edges[0].y0; - for (i = 0; i < r->nedges; i++) { - e = &r->edges[i]; - xmin = nsvg__minf(xmin, e->x0); - xmin = nsvg__minf(xmin, e->x1); - xmax = nsvg__maxf(xmax, e->x0); - xmax = nsvg__maxf(xmax, e->x1); - ymin = nsvg__minf(ymin, e->y0); - ymin = nsvg__minf(ymin, e->y1); - ymax = nsvg__maxf(ymax, e->y0); - ymax = nsvg__maxf(ymax, e->y1); - } - - fprintf(fp, "", xmin, ymin, (xmax - xmin), (ymax - ymin)); - - for (i = 0; i < r->nedges; i++) { - e = &r->edges[i]; - fprintf(fp ,"", e->x0,e->y0, e->x1,e->y1); - } - - for (i = 0; i < r->npoints; i++) { - if (i+1 < r->npoints) - fprintf(fp ,"", r->points[i].x, r->points[i].y, r->points[i+1].x, r->points[i+1].y); - fprintf(fp ,"", r->points[i].x, r->points[i].y, r->points[i].flags == 0 ? "#f00" : "#0f0"); - } - - fprintf(fp, ""); - fclose(fp); -} -*/ - -void nsvgRasterize(NSVGrasterizer* r, - NSVGimage* image, float tx, float ty, float scale, - unsigned char* dst, int w, int h, int stride) -{ - NSVGshape *shape = NULL; - NSVGedge *e = NULL; - NSVGcachedPaint cache; - int i; - - r->bitmap = dst; - r->width = w; - r->height = h; - r->stride = stride; - - if (w > r->cscanline) { - r->cscanline = w; - r->scanline = (unsigned char*)realloc(r->scanline, w); - if (r->scanline == NULL) return; - } - - for (i = 0; i < h; i++) - memset(&dst[i*stride], 0, w*4); - - for (shape = image->shapes; shape != NULL; shape = shape->next) { - if (!(shape->flags & NSVG_FLAGS_VISIBLE)) - continue; - - if (shape->fill.type != NSVG_PAINT_NONE) { - nsvg__resetPool(r); - r->freelist = NULL; - r->nedges = 0; - - nsvg__flattenShape(r, shape, scale); - - // Scale and translate edges - for (i = 0; i < r->nedges; i++) { - e = &r->edges[i]; - e->x0 = tx + e->x0; - e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; - e->x1 = tx + e->x1; - e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES; - } - - // Rasterize edges - qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); - - // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule - nsvg__initPaint(&cache, &shape->fill, shape->opacity); - - nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule); - } - if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) { - nsvg__resetPool(r); - r->freelist = NULL; - r->nedges = 0; - - nsvg__flattenShapeStroke(r, shape, scale); - -// dumpEdges(r, "edge.svg"); - - // Scale and translate edges - for (i = 0; i < r->nedges; i++) { - e = &r->edges[i]; - e->x0 = tx + e->x0; - e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; - e->x1 = tx + e->x1; - e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES; - } - - // Rasterize edges - qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); - - // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule - nsvg__initPaint(&cache, &shape->stroke, shape->opacity); - - nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO); - } - } - - // JRY patch - // JRYFIXME: AlphaBlend wants premultiplied format; look what does Defringe section in nsvg__unpremultiplyAlpha - // nsvg__unpremultiplyAlpha(dst, w, h, stride); - - // JRYFIXME: patch directly nanosvg to skip this step? - for (i = 0; i < w * h; i++) - { - BYTE *b = ((BYTE*)dst) + i * 4; - BYTE b0 = b[0]; - b[0] = b[2]; - b[2] = b0; - } - - - r->bitmap = NULL; - r->width = 0; - r->height = 0; - r->stride = 0; -} - -#endif diff --git a/src/common/dep/zlib/README b/src/common/dep/zlib/README deleted file mode 100644 index 51106de47..000000000 --- a/src/common/dep/zlib/README +++ /dev/null @@ -1,115 +0,0 @@ -ZLIB DATA COMPRESSION LIBRARY - -zlib 1.2.11 is a general purpose data compression library. All the code is -thread safe. The data format used by the zlib library is described by RFCs -(Request for Comments) 1950 to 1952 in the files -http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and -rfc1952 (gzip format). - -All functions of the compression library are documented in the file zlib.h -(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example -of the library is given in the file test/example.c which also tests that -the library is working correctly. Another example is given in the file -test/minigzip.c. The compression library itself is composed of all source -files in the root directory. - -To compile all files and run the test program, follow the instructions given at -the top of Makefile.in. In short "./configure; make test", and if that goes -well, "make install" should work for most flavors of Unix. For Windows, use -one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use -make_vms.com. - -Questions about zlib should be sent to , or to Gilles Vollant - for the Windows DLL version. The zlib home page is -http://zlib.net/ . Before reporting a problem, please check this site to -verify that you have the latest version of zlib; otherwise get the latest -version and check whether the problem still exists or not. - -PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help. - -Mark Nelson wrote an article about zlib for the Jan. 1997 -issue of Dr. Dobb's Journal; a copy of the article is available at -http://marknelson.us/1997/01/01/zlib-engine/ . - -The changes made in version 1.2.11 are documented in the file ChangeLog. - -Unsupported third party contributions are provided in directory contrib/ . - -zlib is available in Java using the java.util.zip package, documented at -http://java.sun.com/developer/technicalArticles/Programming/compression/ . - -A Perl interface to zlib written by Paul Marquess is available -at CPAN (Comprehensive Perl Archive Network) sites, including -http://search.cpan.org/~pmqs/IO-Compress-Zlib/ . - -A Python interface to zlib written by A.M. Kuchling is -available in Python 1.5 and later versions, see -http://docs.python.org/library/zlib.html . - -zlib is built into tcl: http://wiki.tcl.tk/4610 . - -An experimental package to read and write files in .zip format, written on top -of zlib by Gilles Vollant , is available in the -contrib/minizip directory of zlib. - - -Notes for some targets: - -- For Windows DLL versions, please see win32/DLL_FAQ.txt - -- For 64-bit Irix, deflate.c must be compiled without any optimization. With - -O, one libpng test fails. The test works in 32 bit mode (with the -n32 - compiler flag). The compiler bug has been reported to SGI. - -- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works - when compiled with cc. - -- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is - necessary to get gzprintf working correctly. This is done by configure. - -- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with - other compilers. Use "make test" to check your compiler. - -- gzdopen is not supported on RISCOS or BEOS. - -- For PalmOs, see http://palmzlib.sourceforge.net/ - - -Acknowledgments: - - The deflate format used by zlib was defined by Phil Katz. The deflate and - zlib specifications were written by L. Peter Deutsch. Thanks to all the - people who reported problems and suggested various improvements in zlib; they - are too numerous to cite here. - -Copyright notice: - - (C) 1995-2017 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - -If you use the zlib library in a product, we would appreciate *not* receiving -lengthy legal documents to sign. The sources are provided for free but without -warranty of any kind. The library has been entirely written by Jean-loup -Gailly and Mark Adler; it does not include third-party code. - -If you redistribute modified sources, we would appreciate that you include in -the file ChangeLog history information documenting your changes. Please read -the FAQ for more information on the distribution of modified source versions. diff --git a/src/common/dep/zlib/adler32.c b/src/common/dep/zlib/adler32.c deleted file mode 100644 index d0be4380a..000000000 --- a/src/common/dep/zlib/adler32.c +++ /dev/null @@ -1,186 +0,0 @@ -/* adler32.c -- compute the Adler-32 checksum of a data stream - * Copyright (C) 1995-2011, 2016 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#include "zutil.h" - -local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2)); - -#define BASE 65521U /* largest prime smaller than 65536 */ -#define NMAX 5552 -/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ - -#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;} -#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); -#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); -#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); -#define DO16(buf) DO8(buf,0); DO8(buf,8); - -/* use NO_DIVIDE if your processor does not do division in hardware -- - try it both ways to see which is faster */ -#ifdef NO_DIVIDE -/* note that this assumes BASE is 65521, where 65536 % 65521 == 15 - (thank you to John Reiser for pointing this out) */ -# define CHOP(a) \ - do { \ - unsigned long tmp = a >> 16; \ - a &= 0xffffUL; \ - a += (tmp << 4) - tmp; \ - } while (0) -# define MOD28(a) \ - do { \ - CHOP(a); \ - if (a >= BASE) a -= BASE; \ - } while (0) -# define MOD(a) \ - do { \ - CHOP(a); \ - MOD28(a); \ - } while (0) -# define MOD63(a) \ - do { /* this assumes a is not negative */ \ - z_off64_t tmp = a >> 32; \ - a &= 0xffffffffL; \ - a += (tmp << 8) - (tmp << 5) + tmp; \ - tmp = a >> 16; \ - a &= 0xffffL; \ - a += (tmp << 4) - tmp; \ - tmp = a >> 16; \ - a &= 0xffffL; \ - a += (tmp << 4) - tmp; \ - if (a >= BASE) a -= BASE; \ - } while (0) -#else -# define MOD(a) a %= BASE -# define MOD28(a) a %= BASE -# define MOD63(a) a %= BASE -#endif - -/* ========================================================================= */ -uLong ZEXPORT adler32_z(adler, buf, len) - uLong adler; - const Bytef *buf; - z_size_t len; -{ - unsigned long sum2; - unsigned n; - - /* split Adler-32 into component sums */ - sum2 = (adler >> 16) & 0xffff; - adler &= 0xffff; - - /* in case user likes doing a byte at a time, keep it fast */ - if (len == 1) { - adler += buf[0]; - if (adler >= BASE) - adler -= BASE; - sum2 += adler; - if (sum2 >= BASE) - sum2 -= BASE; - return adler | (sum2 << 16); - } - - /* initial Adler-32 value (deferred check for len == 1 speed) */ - if (buf == Z_NULL) - return 1L; - - /* in case short lengths are provided, keep it somewhat fast */ - if (len < 16) { - while (len--) { - adler += *buf++; - sum2 += adler; - } - if (adler >= BASE) - adler -= BASE; - MOD28(sum2); /* only added so many BASE's */ - return adler | (sum2 << 16); - } - - /* do length NMAX blocks -- requires just one modulo operation */ - while (len >= NMAX) { - len -= NMAX; - n = NMAX / 16; /* NMAX is divisible by 16 */ - do { - DO16(buf); /* 16 sums unrolled */ - buf += 16; - } while (--n); - MOD(adler); - MOD(sum2); - } - - /* do remaining bytes (less than NMAX, still just one modulo) */ - if (len) { /* avoid modulos if none remaining */ - while (len >= 16) { - len -= 16; - DO16(buf); - buf += 16; - } - while (len--) { - adler += *buf++; - sum2 += adler; - } - MOD(adler); - MOD(sum2); - } - - /* return recombined sums */ - return adler | (sum2 << 16); -} - -/* ========================================================================= */ -uLong ZEXPORT adler32(adler, buf, len) - uLong adler; - const Bytef *buf; - uInt len; -{ - return adler32_z(adler, buf, len); -} - -/* ========================================================================= */ -local uLong adler32_combine_(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off64_t len2; -{ - unsigned long sum1; - unsigned long sum2; - unsigned rem; - - /* for negative len, return invalid adler32 as a clue for debugging */ - if (len2 < 0) - return 0xffffffffUL; - - /* the derivation of this formula is left as an exercise for the reader */ - MOD63(len2); /* assumes len2 >= 0 */ - rem = (unsigned)len2; - sum1 = adler1 & 0xffff; - sum2 = rem * sum1; - MOD(sum2); - sum1 += (adler2 & 0xffff) + BASE - 1; - sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem; - if (sum1 >= BASE) sum1 -= BASE; - if (sum1 >= BASE) sum1 -= BASE; - if (sum2 >= ((unsigned long)BASE << 1)) sum2 -= ((unsigned long)BASE << 1); - if (sum2 >= BASE) sum2 -= BASE; - return sum1 | (sum2 << 16); -} - -/* ========================================================================= */ -uLong ZEXPORT adler32_combine(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off_t len2; -{ - return adler32_combine_(adler1, adler2, len2); -} - -uLong ZEXPORT adler32_combine64(adler1, adler2, len2) - uLong adler1; - uLong adler2; - z_off64_t len2; -{ - return adler32_combine_(adler1, adler2, len2); -} diff --git a/src/common/dep/zlib/compress.c b/src/common/dep/zlib/compress.c deleted file mode 100644 index e2db404ab..000000000 --- a/src/common/dep/zlib/compress.c +++ /dev/null @@ -1,86 +0,0 @@ -/* compress.c -- compress a memory buffer - * Copyright (C) 1995-2005, 2014, 2016 Jean-loup Gailly, Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#define ZLIB_INTERNAL -#include "zlib.h" - -/* =========================================================================== - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least 0.1% larger than sourceLen plus - 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ -int ZEXPORT compress2 (dest, destLen, source, sourceLen, level) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; - int level; -{ - z_stream stream; - int err; - const uInt max = (uInt)-1; - uLong left; - - left = *destLen; - *destLen = 0; - - stream.zalloc = (alloc_func)0; - stream.zfree = (free_func)0; - stream.opaque = (voidpf)0; - - err = deflateInit(&stream, level); - if (err != Z_OK) return err; - - stream.next_out = dest; - stream.avail_out = 0; - stream.next_in = (z_const Bytef *)source; - stream.avail_in = 0; - - do { - if (stream.avail_out == 0) { - stream.avail_out = left > (uLong)max ? max : (uInt)left; - left -= stream.avail_out; - } - if (stream.avail_in == 0) { - stream.avail_in = sourceLen > (uLong)max ? max : (uInt)sourceLen; - sourceLen -= stream.avail_in; - } - err = deflate(&stream, sourceLen ? Z_NO_FLUSH : Z_FINISH); - } while (err == Z_OK); - - *destLen = stream.total_out; - deflateEnd(&stream); - return err == Z_STREAM_END ? Z_OK : err; -} - -/* =========================================================================== - */ -int ZEXPORT compress (dest, destLen, source, sourceLen) - Bytef *dest; - uLongf *destLen; - const Bytef *source; - uLong sourceLen; -{ - return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION); -} - -/* =========================================================================== - If the default memLevel or windowBits for deflateInit() is changed, then - this function needs to be updated. - */ -uLong ZEXPORT compressBound (sourceLen) - uLong sourceLen; -{ - return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + - (sourceLen >> 25) + 13; -} diff --git a/src/common/dep/zlib/crc32.c b/src/common/dep/zlib/crc32.c deleted file mode 100644 index 9580440c0..000000000 --- a/src/common/dep/zlib/crc32.c +++ /dev/null @@ -1,442 +0,0 @@ -/* crc32.c -- compute the CRC-32 of a data stream - * Copyright (C) 1995-2006, 2010, 2011, 2012, 2016 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - * - * Thanks to Rodney Brown for his contribution of faster - * CRC methods: exclusive-oring 32 bits of data at a time, and pre-computing - * tables for updating the shift register in one step with three exclusive-ors - * instead of four steps with four exclusive-ors. This results in about a - * factor of two increase in speed on a Power PC G4 (PPC7455) using gcc -O3. - */ - -/* @(#) $Id$ */ - -/* - Note on the use of DYNAMIC_CRC_TABLE: there is no mutex or semaphore - protection on the static variables used to control the first-use generation - of the crc tables. Therefore, if you #define DYNAMIC_CRC_TABLE, you should - first call get_crc_table() to initialize the tables before allowing more than - one thread to use crc32(). - - DYNAMIC_CRC_TABLE and MAKECRCH can be #defined to write out crc32.h. - */ - -#ifdef MAKECRCH -# include -# ifndef DYNAMIC_CRC_TABLE -# define DYNAMIC_CRC_TABLE -# endif /* !DYNAMIC_CRC_TABLE */ -#endif /* MAKECRCH */ - -#include "zutil.h" /* for STDC and FAR definitions */ - -/* Definitions for doing the crc four data bytes at a time. */ -#if !defined(NOBYFOUR) && defined(Z_U4) -# define BYFOUR -#endif -#ifdef BYFOUR - local unsigned long crc32_little OF((unsigned long, - const unsigned char FAR *, z_size_t)); - local unsigned long crc32_big OF((unsigned long, - const unsigned char FAR *, z_size_t)); -# define TBLS 8 -#else -# define TBLS 1 -#endif /* BYFOUR */ - -/* Local functions for crc concatenation */ -local unsigned long gf2_matrix_times OF((unsigned long *mat, - unsigned long vec)); -local void gf2_matrix_square OF((unsigned long *square, unsigned long *mat)); -local uLong crc32_combine_ OF((uLong crc1, uLong crc2, z_off64_t len2)); - - -#ifdef DYNAMIC_CRC_TABLE - -local volatile int crc_table_empty = 1; -local z_crc_t FAR crc_table[TBLS][256]; -local void make_crc_table OF((void)); -#ifdef MAKECRCH - local void write_table OF((FILE *, const z_crc_t FAR *)); -#endif /* MAKECRCH */ -/* - Generate tables for a byte-wise 32-bit CRC calculation on the polynomial: - x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. - - Polynomials over GF(2) are represented in binary, one bit per coefficient, - with the lowest powers in the most significant bit. Then adding polynomials - is just exclusive-or, and multiplying a polynomial by x is a right shift by - one. If we call the above polynomial p, and represent a byte as the - polynomial q, also with the lowest power in the most significant bit (so the - byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, - where a mod b means the remainder after dividing a by b. - - This calculation is done using the shift-register method of multiplying and - taking the remainder. The register is initialized to zero, and for each - incoming bit, x^32 is added mod p to the register if the bit is a one (where - x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by - x (which is shifting right by one and adding x^32 mod p if the bit shifted - out is a one). We start with the highest power (least significant bit) of - q and repeat for all eight bits of q. - - The first table is simply the CRC of all possible eight bit values. This is - all the information needed to generate CRCs on data a byte at a time for all - combinations of CRC register values and incoming bytes. The remaining tables - allow for word-at-a-time CRC calculation for both big-endian and little- - endian machines, where a word is four bytes. -*/ -local void make_crc_table() -{ - z_crc_t c; - int n, k; - z_crc_t poly; /* polynomial exclusive-or pattern */ - /* terms of polynomial defining this crc (except x^32): */ - static volatile int first = 1; /* flag to limit concurrent making */ - static const unsigned char p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; - - /* See if another task is already doing this (not thread-safe, but better - than nothing -- significantly reduces duration of vulnerability in - case the advice about DYNAMIC_CRC_TABLE is ignored) */ - if (first) { - first = 0; - - /* make exclusive-or pattern from polynomial (0xedb88320UL) */ - poly = 0; - for (n = 0; n < (int)(sizeof(p)/sizeof(unsigned char)); n++) - poly |= (z_crc_t)1 << (31 - p[n]); - - /* generate a crc for every 8-bit value */ - for (n = 0; n < 256; n++) { - c = (z_crc_t)n; - for (k = 0; k < 8; k++) - c = c & 1 ? poly ^ (c >> 1) : c >> 1; - crc_table[0][n] = c; - } - -#ifdef BYFOUR - /* generate crc for each value followed by one, two, and three zeros, - and then the byte reversal of those as well as the first table */ - for (n = 0; n < 256; n++) { - c = crc_table[0][n]; - crc_table[4][n] = ZSWAP32(c); - for (k = 1; k < 4; k++) { - c = crc_table[0][c & 0xff] ^ (c >> 8); - crc_table[k][n] = c; - crc_table[k + 4][n] = ZSWAP32(c); - } - } -#endif /* BYFOUR */ - - crc_table_empty = 0; - } - else { /* not first */ - /* wait for the other guy to finish (not efficient, but rare) */ - while (crc_table_empty) - ; - } - -#ifdef MAKECRCH - /* write out CRC tables to crc32.h */ - { - FILE *out; - - out = fopen("crc32.h", "w"); - if (out == NULL) return; - fprintf(out, "/* crc32.h -- tables for rapid CRC calculation\n"); - fprintf(out, " * Generated automatically by crc32.c\n */\n\n"); - fprintf(out, "local const z_crc_t FAR "); - fprintf(out, "crc_table[TBLS][256] =\n{\n {\n"); - write_table(out, crc_table[0]); -# ifdef BYFOUR - fprintf(out, "#ifdef BYFOUR\n"); - for (k = 1; k < 8; k++) { - fprintf(out, " },\n {\n"); - write_table(out, crc_table[k]); - } - fprintf(out, "#endif\n"); -# endif /* BYFOUR */ - fprintf(out, " }\n};\n"); - fclose(out); - } -#endif /* MAKECRCH */ -} - -#ifdef MAKECRCH -local void write_table(out, table) - FILE *out; - const z_crc_t FAR *table; -{ - int n; - - for (n = 0; n < 256; n++) - fprintf(out, "%s0x%08lxUL%s", n % 5 ? "" : " ", - (unsigned long)(table[n]), - n == 255 ? "\n" : (n % 5 == 4 ? ",\n" : ", ")); -} -#endif /* MAKECRCH */ - -#else /* !DYNAMIC_CRC_TABLE */ -/* ======================================================================== - * Tables of CRC-32s of all single-byte values, made by make_crc_table(). - */ -#include "crc32.h" -#endif /* DYNAMIC_CRC_TABLE */ - -/* ========================================================================= - * This function can be used by asm versions of crc32() - */ -const z_crc_t FAR * ZEXPORT get_crc_table() -{ -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - return (const z_crc_t FAR *)crc_table; -} - -/* ========================================================================= */ -#define DO1 crc = crc_table[0][((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8) -#define DO8 DO1; DO1; DO1; DO1; DO1; DO1; DO1; DO1 - -/* ========================================================================= */ -unsigned long ZEXPORT crc32_z(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - z_size_t len; -{ - if (buf == Z_NULL) return 0UL; - -#ifdef DYNAMIC_CRC_TABLE - if (crc_table_empty) - make_crc_table(); -#endif /* DYNAMIC_CRC_TABLE */ - -#ifdef BYFOUR - if (sizeof(void *) == sizeof(ptrdiff_t)) { - z_crc_t endian; - - endian = 1; - if (*((unsigned char *)(&endian))) - return crc32_little(crc, buf, len); - else - return crc32_big(crc, buf, len); - } -#endif /* BYFOUR */ - crc = crc ^ 0xffffffffUL; - while (len >= 8) { - DO8; - len -= 8; - } - if (len) do { - DO1; - } while (--len); - return crc ^ 0xffffffffUL; -} - -/* ========================================================================= */ -unsigned long ZEXPORT crc32(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - uInt len; -{ - return crc32_z(crc, buf, len); -} - -#ifdef BYFOUR - -/* - This BYFOUR code accesses the passed unsigned char * buffer with a 32-bit - integer pointer type. This violates the strict aliasing rule, where a - compiler can assume, for optimization purposes, that two pointers to - fundamentally different types won't ever point to the same memory. This can - manifest as a problem only if one of the pointers is written to. This code - only reads from those pointers. So long as this code remains isolated in - this compilation unit, there won't be a problem. For this reason, this code - should not be copied and pasted into a compilation unit in which other code - writes to the buffer that is passed to these routines. - */ - -/* ========================================================================= */ -#define DOLIT4 c ^= *buf4++; \ - c = crc_table[3][c & 0xff] ^ crc_table[2][(c >> 8) & 0xff] ^ \ - crc_table[1][(c >> 16) & 0xff] ^ crc_table[0][c >> 24] -#define DOLIT32 DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4; DOLIT4 - -/* ========================================================================= */ -local unsigned long crc32_little(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - z_size_t len; -{ - register z_crc_t c; - register const z_crc_t FAR *buf4; - - c = (z_crc_t)crc; - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - len--; - } - - buf4 = (const z_crc_t FAR *)(const void FAR *)buf; - while (len >= 32) { - DOLIT32; - len -= 32; - } - while (len >= 4) { - DOLIT4; - len -= 4; - } - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[0][(c ^ *buf++) & 0xff] ^ (c >> 8); - } while (--len); - c = ~c; - return (unsigned long)c; -} - -/* ========================================================================= */ -#define DOBIG4 c ^= *buf4++; \ - c = crc_table[4][c & 0xff] ^ crc_table[5][(c >> 8) & 0xff] ^ \ - crc_table[6][(c >> 16) & 0xff] ^ crc_table[7][c >> 24] -#define DOBIG32 DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4; DOBIG4 - -/* ========================================================================= */ -local unsigned long crc32_big(crc, buf, len) - unsigned long crc; - const unsigned char FAR *buf; - z_size_t len; -{ - register z_crc_t c; - register const z_crc_t FAR *buf4; - - c = ZSWAP32((z_crc_t)crc); - c = ~c; - while (len && ((ptrdiff_t)buf & 3)) { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - len--; - } - - buf4 = (const z_crc_t FAR *)(const void FAR *)buf; - while (len >= 32) { - DOBIG32; - len -= 32; - } - while (len >= 4) { - DOBIG4; - len -= 4; - } - buf = (const unsigned char FAR *)buf4; - - if (len) do { - c = crc_table[4][(c >> 24) ^ *buf++] ^ (c << 8); - } while (--len); - c = ~c; - return (unsigned long)(ZSWAP32(c)); -} - -#endif /* BYFOUR */ - -#define GF2_DIM 32 /* dimension of GF(2) vectors (length of CRC) */ - -/* ========================================================================= */ -local unsigned long gf2_matrix_times(mat, vec) - unsigned long *mat; - unsigned long vec; -{ - unsigned long sum; - - sum = 0; - while (vec) { - if (vec & 1) - sum ^= *mat; - vec >>= 1; - mat++; - } - return sum; -} - -/* ========================================================================= */ -local void gf2_matrix_square(square, mat) - unsigned long *square; - unsigned long *mat; -{ - int n; - - for (n = 0; n < GF2_DIM; n++) - square[n] = gf2_matrix_times(mat, mat[n]); -} - -/* ========================================================================= */ -local uLong crc32_combine_(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off64_t len2; -{ - int n; - unsigned long row; - unsigned long even[GF2_DIM]; /* even-power-of-two zeros operator */ - unsigned long odd[GF2_DIM]; /* odd-power-of-two zeros operator */ - - /* degenerate case (also disallow negative lengths) */ - if (len2 <= 0) - return crc1; - - /* put operator for one zero bit in odd */ - odd[0] = 0xedb88320UL; /* CRC-32 polynomial */ - row = 1; - for (n = 1; n < GF2_DIM; n++) { - odd[n] = row; - row <<= 1; - } - - /* put operator for two zero bits in even */ - gf2_matrix_square(even, odd); - - /* put operator for four zero bits in odd */ - gf2_matrix_square(odd, even); - - /* apply len2 zeros to crc1 (first square will put the operator for one - zero byte, eight zero bits, in even) */ - do { - /* apply zeros operator for this bit of len2 */ - gf2_matrix_square(even, odd); - if (len2 & 1) - crc1 = gf2_matrix_times(even, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - if (len2 == 0) - break; - - /* another iteration of the loop with odd and even swapped */ - gf2_matrix_square(odd, even); - if (len2 & 1) - crc1 = gf2_matrix_times(odd, crc1); - len2 >>= 1; - - /* if no more bits set, then done */ - } while (len2 != 0); - - /* return combined crc */ - crc1 ^= crc2; - return crc1; -} - -/* ========================================================================= */ -uLong ZEXPORT crc32_combine(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off_t len2; -{ - return crc32_combine_(crc1, crc2, len2); -} - -uLong ZEXPORT crc32_combine64(crc1, crc2, len2) - uLong crc1; - uLong crc2; - z_off64_t len2; -{ - return crc32_combine_(crc1, crc2, len2); -} diff --git a/src/common/dep/zlib/crc32.h b/src/common/dep/zlib/crc32.h deleted file mode 100644 index 9e0c77810..000000000 --- a/src/common/dep/zlib/crc32.h +++ /dev/null @@ -1,441 +0,0 @@ -/* crc32.h -- tables for rapid CRC calculation - * Generated automatically by crc32.c - */ - -local const z_crc_t FAR crc_table[TBLS][256] = -{ - { - 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, - 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, - 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, - 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, - 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, - 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, - 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, - 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, - 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, - 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, - 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, - 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, - 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, - 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, - 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, - 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, - 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, - 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, - 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, - 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, - 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, - 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, - 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, - 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, - 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, - 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, - 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, - 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, - 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, - 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, - 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, - 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, - 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, - 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, - 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, - 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, - 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, - 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, - 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, - 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, - 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, - 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, - 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, - 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, - 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, - 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, - 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, - 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, - 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, - 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, - 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, - 0x2d02ef8dUL -#ifdef BYFOUR - }, - { - 0x00000000UL, 0x191b3141UL, 0x32366282UL, 0x2b2d53c3UL, 0x646cc504UL, - 0x7d77f445UL, 0x565aa786UL, 0x4f4196c7UL, 0xc8d98a08UL, 0xd1c2bb49UL, - 0xfaefe88aUL, 0xe3f4d9cbUL, 0xacb54f0cUL, 0xb5ae7e4dUL, 0x9e832d8eUL, - 0x87981ccfUL, 0x4ac21251UL, 0x53d92310UL, 0x78f470d3UL, 0x61ef4192UL, - 0x2eaed755UL, 0x37b5e614UL, 0x1c98b5d7UL, 0x05838496UL, 0x821b9859UL, - 0x9b00a918UL, 0xb02dfadbUL, 0xa936cb9aUL, 0xe6775d5dUL, 0xff6c6c1cUL, - 0xd4413fdfUL, 0xcd5a0e9eUL, 0x958424a2UL, 0x8c9f15e3UL, 0xa7b24620UL, - 0xbea97761UL, 0xf1e8e1a6UL, 0xe8f3d0e7UL, 0xc3de8324UL, 0xdac5b265UL, - 0x5d5daeaaUL, 0x44469febUL, 0x6f6bcc28UL, 0x7670fd69UL, 0x39316baeUL, - 0x202a5aefUL, 0x0b07092cUL, 0x121c386dUL, 0xdf4636f3UL, 0xc65d07b2UL, - 0xed705471UL, 0xf46b6530UL, 0xbb2af3f7UL, 0xa231c2b6UL, 0x891c9175UL, - 0x9007a034UL, 0x179fbcfbUL, 0x0e848dbaUL, 0x25a9de79UL, 0x3cb2ef38UL, - 0x73f379ffUL, 0x6ae848beUL, 0x41c51b7dUL, 0x58de2a3cUL, 0xf0794f05UL, - 0xe9627e44UL, 0xc24f2d87UL, 0xdb541cc6UL, 0x94158a01UL, 0x8d0ebb40UL, - 0xa623e883UL, 0xbf38d9c2UL, 0x38a0c50dUL, 0x21bbf44cUL, 0x0a96a78fUL, - 0x138d96ceUL, 0x5ccc0009UL, 0x45d73148UL, 0x6efa628bUL, 0x77e153caUL, - 0xbabb5d54UL, 0xa3a06c15UL, 0x888d3fd6UL, 0x91960e97UL, 0xded79850UL, - 0xc7cca911UL, 0xece1fad2UL, 0xf5facb93UL, 0x7262d75cUL, 0x6b79e61dUL, - 0x4054b5deUL, 0x594f849fUL, 0x160e1258UL, 0x0f152319UL, 0x243870daUL, - 0x3d23419bUL, 0x65fd6ba7UL, 0x7ce65ae6UL, 0x57cb0925UL, 0x4ed03864UL, - 0x0191aea3UL, 0x188a9fe2UL, 0x33a7cc21UL, 0x2abcfd60UL, 0xad24e1afUL, - 0xb43fd0eeUL, 0x9f12832dUL, 0x8609b26cUL, 0xc94824abUL, 0xd05315eaUL, - 0xfb7e4629UL, 0xe2657768UL, 0x2f3f79f6UL, 0x362448b7UL, 0x1d091b74UL, - 0x04122a35UL, 0x4b53bcf2UL, 0x52488db3UL, 0x7965de70UL, 0x607eef31UL, - 0xe7e6f3feUL, 0xfefdc2bfUL, 0xd5d0917cUL, 0xcccba03dUL, 0x838a36faUL, - 0x9a9107bbUL, 0xb1bc5478UL, 0xa8a76539UL, 0x3b83984bUL, 0x2298a90aUL, - 0x09b5fac9UL, 0x10aecb88UL, 0x5fef5d4fUL, 0x46f46c0eUL, 0x6dd93fcdUL, - 0x74c20e8cUL, 0xf35a1243UL, 0xea412302UL, 0xc16c70c1UL, 0xd8774180UL, - 0x9736d747UL, 0x8e2de606UL, 0xa500b5c5UL, 0xbc1b8484UL, 0x71418a1aUL, - 0x685abb5bUL, 0x4377e898UL, 0x5a6cd9d9UL, 0x152d4f1eUL, 0x0c367e5fUL, - 0x271b2d9cUL, 0x3e001cddUL, 0xb9980012UL, 0xa0833153UL, 0x8bae6290UL, - 0x92b553d1UL, 0xddf4c516UL, 0xc4eff457UL, 0xefc2a794UL, 0xf6d996d5UL, - 0xae07bce9UL, 0xb71c8da8UL, 0x9c31de6bUL, 0x852aef2aUL, 0xca6b79edUL, - 0xd37048acUL, 0xf85d1b6fUL, 0xe1462a2eUL, 0x66de36e1UL, 0x7fc507a0UL, - 0x54e85463UL, 0x4df36522UL, 0x02b2f3e5UL, 0x1ba9c2a4UL, 0x30849167UL, - 0x299fa026UL, 0xe4c5aeb8UL, 0xfdde9ff9UL, 0xd6f3cc3aUL, 0xcfe8fd7bUL, - 0x80a96bbcUL, 0x99b25afdUL, 0xb29f093eUL, 0xab84387fUL, 0x2c1c24b0UL, - 0x350715f1UL, 0x1e2a4632UL, 0x07317773UL, 0x4870e1b4UL, 0x516bd0f5UL, - 0x7a468336UL, 0x635db277UL, 0xcbfad74eUL, 0xd2e1e60fUL, 0xf9ccb5ccUL, - 0xe0d7848dUL, 0xaf96124aUL, 0xb68d230bUL, 0x9da070c8UL, 0x84bb4189UL, - 0x03235d46UL, 0x1a386c07UL, 0x31153fc4UL, 0x280e0e85UL, 0x674f9842UL, - 0x7e54a903UL, 0x5579fac0UL, 0x4c62cb81UL, 0x8138c51fUL, 0x9823f45eUL, - 0xb30ea79dUL, 0xaa1596dcUL, 0xe554001bUL, 0xfc4f315aUL, 0xd7626299UL, - 0xce7953d8UL, 0x49e14f17UL, 0x50fa7e56UL, 0x7bd72d95UL, 0x62cc1cd4UL, - 0x2d8d8a13UL, 0x3496bb52UL, 0x1fbbe891UL, 0x06a0d9d0UL, 0x5e7ef3ecUL, - 0x4765c2adUL, 0x6c48916eUL, 0x7553a02fUL, 0x3a1236e8UL, 0x230907a9UL, - 0x0824546aUL, 0x113f652bUL, 0x96a779e4UL, 0x8fbc48a5UL, 0xa4911b66UL, - 0xbd8a2a27UL, 0xf2cbbce0UL, 0xebd08da1UL, 0xc0fdde62UL, 0xd9e6ef23UL, - 0x14bce1bdUL, 0x0da7d0fcUL, 0x268a833fUL, 0x3f91b27eUL, 0x70d024b9UL, - 0x69cb15f8UL, 0x42e6463bUL, 0x5bfd777aUL, 0xdc656bb5UL, 0xc57e5af4UL, - 0xee530937UL, 0xf7483876UL, 0xb809aeb1UL, 0xa1129ff0UL, 0x8a3fcc33UL, - 0x9324fd72UL - }, - { - 0x00000000UL, 0x01c26a37UL, 0x0384d46eUL, 0x0246be59UL, 0x0709a8dcUL, - 0x06cbc2ebUL, 0x048d7cb2UL, 0x054f1685UL, 0x0e1351b8UL, 0x0fd13b8fUL, - 0x0d9785d6UL, 0x0c55efe1UL, 0x091af964UL, 0x08d89353UL, 0x0a9e2d0aUL, - 0x0b5c473dUL, 0x1c26a370UL, 0x1de4c947UL, 0x1fa2771eUL, 0x1e601d29UL, - 0x1b2f0bacUL, 0x1aed619bUL, 0x18abdfc2UL, 0x1969b5f5UL, 0x1235f2c8UL, - 0x13f798ffUL, 0x11b126a6UL, 0x10734c91UL, 0x153c5a14UL, 0x14fe3023UL, - 0x16b88e7aUL, 0x177ae44dUL, 0x384d46e0UL, 0x398f2cd7UL, 0x3bc9928eUL, - 0x3a0bf8b9UL, 0x3f44ee3cUL, 0x3e86840bUL, 0x3cc03a52UL, 0x3d025065UL, - 0x365e1758UL, 0x379c7d6fUL, 0x35dac336UL, 0x3418a901UL, 0x3157bf84UL, - 0x3095d5b3UL, 0x32d36beaUL, 0x331101ddUL, 0x246be590UL, 0x25a98fa7UL, - 0x27ef31feUL, 0x262d5bc9UL, 0x23624d4cUL, 0x22a0277bUL, 0x20e69922UL, - 0x2124f315UL, 0x2a78b428UL, 0x2bbade1fUL, 0x29fc6046UL, 0x283e0a71UL, - 0x2d711cf4UL, 0x2cb376c3UL, 0x2ef5c89aUL, 0x2f37a2adUL, 0x709a8dc0UL, - 0x7158e7f7UL, 0x731e59aeUL, 0x72dc3399UL, 0x7793251cUL, 0x76514f2bUL, - 0x7417f172UL, 0x75d59b45UL, 0x7e89dc78UL, 0x7f4bb64fUL, 0x7d0d0816UL, - 0x7ccf6221UL, 0x798074a4UL, 0x78421e93UL, 0x7a04a0caUL, 0x7bc6cafdUL, - 0x6cbc2eb0UL, 0x6d7e4487UL, 0x6f38fadeUL, 0x6efa90e9UL, 0x6bb5866cUL, - 0x6a77ec5bUL, 0x68315202UL, 0x69f33835UL, 0x62af7f08UL, 0x636d153fUL, - 0x612bab66UL, 0x60e9c151UL, 0x65a6d7d4UL, 0x6464bde3UL, 0x662203baUL, - 0x67e0698dUL, 0x48d7cb20UL, 0x4915a117UL, 0x4b531f4eUL, 0x4a917579UL, - 0x4fde63fcUL, 0x4e1c09cbUL, 0x4c5ab792UL, 0x4d98dda5UL, 0x46c49a98UL, - 0x4706f0afUL, 0x45404ef6UL, 0x448224c1UL, 0x41cd3244UL, 0x400f5873UL, - 0x4249e62aUL, 0x438b8c1dUL, 0x54f16850UL, 0x55330267UL, 0x5775bc3eUL, - 0x56b7d609UL, 0x53f8c08cUL, 0x523aaabbUL, 0x507c14e2UL, 0x51be7ed5UL, - 0x5ae239e8UL, 0x5b2053dfUL, 0x5966ed86UL, 0x58a487b1UL, 0x5deb9134UL, - 0x5c29fb03UL, 0x5e6f455aUL, 0x5fad2f6dUL, 0xe1351b80UL, 0xe0f771b7UL, - 0xe2b1cfeeUL, 0xe373a5d9UL, 0xe63cb35cUL, 0xe7fed96bUL, 0xe5b86732UL, - 0xe47a0d05UL, 0xef264a38UL, 0xeee4200fUL, 0xeca29e56UL, 0xed60f461UL, - 0xe82fe2e4UL, 0xe9ed88d3UL, 0xebab368aUL, 0xea695cbdUL, 0xfd13b8f0UL, - 0xfcd1d2c7UL, 0xfe976c9eUL, 0xff5506a9UL, 0xfa1a102cUL, 0xfbd87a1bUL, - 0xf99ec442UL, 0xf85cae75UL, 0xf300e948UL, 0xf2c2837fUL, 0xf0843d26UL, - 0xf1465711UL, 0xf4094194UL, 0xf5cb2ba3UL, 0xf78d95faUL, 0xf64fffcdUL, - 0xd9785d60UL, 0xd8ba3757UL, 0xdafc890eUL, 0xdb3ee339UL, 0xde71f5bcUL, - 0xdfb39f8bUL, 0xddf521d2UL, 0xdc374be5UL, 0xd76b0cd8UL, 0xd6a966efUL, - 0xd4efd8b6UL, 0xd52db281UL, 0xd062a404UL, 0xd1a0ce33UL, 0xd3e6706aUL, - 0xd2241a5dUL, 0xc55efe10UL, 0xc49c9427UL, 0xc6da2a7eUL, 0xc7184049UL, - 0xc25756ccUL, 0xc3953cfbUL, 0xc1d382a2UL, 0xc011e895UL, 0xcb4dafa8UL, - 0xca8fc59fUL, 0xc8c97bc6UL, 0xc90b11f1UL, 0xcc440774UL, 0xcd866d43UL, - 0xcfc0d31aUL, 0xce02b92dUL, 0x91af9640UL, 0x906dfc77UL, 0x922b422eUL, - 0x93e92819UL, 0x96a63e9cUL, 0x976454abUL, 0x9522eaf2UL, 0x94e080c5UL, - 0x9fbcc7f8UL, 0x9e7eadcfUL, 0x9c381396UL, 0x9dfa79a1UL, 0x98b56f24UL, - 0x99770513UL, 0x9b31bb4aUL, 0x9af3d17dUL, 0x8d893530UL, 0x8c4b5f07UL, - 0x8e0de15eUL, 0x8fcf8b69UL, 0x8a809decUL, 0x8b42f7dbUL, 0x89044982UL, - 0x88c623b5UL, 0x839a6488UL, 0x82580ebfUL, 0x801eb0e6UL, 0x81dcdad1UL, - 0x8493cc54UL, 0x8551a663UL, 0x8717183aUL, 0x86d5720dUL, 0xa9e2d0a0UL, - 0xa820ba97UL, 0xaa6604ceUL, 0xaba46ef9UL, 0xaeeb787cUL, 0xaf29124bUL, - 0xad6fac12UL, 0xacadc625UL, 0xa7f18118UL, 0xa633eb2fUL, 0xa4755576UL, - 0xa5b73f41UL, 0xa0f829c4UL, 0xa13a43f3UL, 0xa37cfdaaUL, 0xa2be979dUL, - 0xb5c473d0UL, 0xb40619e7UL, 0xb640a7beUL, 0xb782cd89UL, 0xb2cddb0cUL, - 0xb30fb13bUL, 0xb1490f62UL, 0xb08b6555UL, 0xbbd72268UL, 0xba15485fUL, - 0xb853f606UL, 0xb9919c31UL, 0xbcde8ab4UL, 0xbd1ce083UL, 0xbf5a5edaUL, - 0xbe9834edUL - }, - { - 0x00000000UL, 0xb8bc6765UL, 0xaa09c88bUL, 0x12b5afeeUL, 0x8f629757UL, - 0x37def032UL, 0x256b5fdcUL, 0x9dd738b9UL, 0xc5b428efUL, 0x7d084f8aUL, - 0x6fbde064UL, 0xd7018701UL, 0x4ad6bfb8UL, 0xf26ad8ddUL, 0xe0df7733UL, - 0x58631056UL, 0x5019579fUL, 0xe8a530faUL, 0xfa109f14UL, 0x42acf871UL, - 0xdf7bc0c8UL, 0x67c7a7adUL, 0x75720843UL, 0xcdce6f26UL, 0x95ad7f70UL, - 0x2d111815UL, 0x3fa4b7fbUL, 0x8718d09eUL, 0x1acfe827UL, 0xa2738f42UL, - 0xb0c620acUL, 0x087a47c9UL, 0xa032af3eUL, 0x188ec85bUL, 0x0a3b67b5UL, - 0xb28700d0UL, 0x2f503869UL, 0x97ec5f0cUL, 0x8559f0e2UL, 0x3de59787UL, - 0x658687d1UL, 0xdd3ae0b4UL, 0xcf8f4f5aUL, 0x7733283fUL, 0xeae41086UL, - 0x525877e3UL, 0x40edd80dUL, 0xf851bf68UL, 0xf02bf8a1UL, 0x48979fc4UL, - 0x5a22302aUL, 0xe29e574fUL, 0x7f496ff6UL, 0xc7f50893UL, 0xd540a77dUL, - 0x6dfcc018UL, 0x359fd04eUL, 0x8d23b72bUL, 0x9f9618c5UL, 0x272a7fa0UL, - 0xbafd4719UL, 0x0241207cUL, 0x10f48f92UL, 0xa848e8f7UL, 0x9b14583dUL, - 0x23a83f58UL, 0x311d90b6UL, 0x89a1f7d3UL, 0x1476cf6aUL, 0xaccaa80fUL, - 0xbe7f07e1UL, 0x06c36084UL, 0x5ea070d2UL, 0xe61c17b7UL, 0xf4a9b859UL, - 0x4c15df3cUL, 0xd1c2e785UL, 0x697e80e0UL, 0x7bcb2f0eUL, 0xc377486bUL, - 0xcb0d0fa2UL, 0x73b168c7UL, 0x6104c729UL, 0xd9b8a04cUL, 0x446f98f5UL, - 0xfcd3ff90UL, 0xee66507eUL, 0x56da371bUL, 0x0eb9274dUL, 0xb6054028UL, - 0xa4b0efc6UL, 0x1c0c88a3UL, 0x81dbb01aUL, 0x3967d77fUL, 0x2bd27891UL, - 0x936e1ff4UL, 0x3b26f703UL, 0x839a9066UL, 0x912f3f88UL, 0x299358edUL, - 0xb4446054UL, 0x0cf80731UL, 0x1e4da8dfUL, 0xa6f1cfbaUL, 0xfe92dfecUL, - 0x462eb889UL, 0x549b1767UL, 0xec277002UL, 0x71f048bbUL, 0xc94c2fdeUL, - 0xdbf98030UL, 0x6345e755UL, 0x6b3fa09cUL, 0xd383c7f9UL, 0xc1366817UL, - 0x798a0f72UL, 0xe45d37cbUL, 0x5ce150aeUL, 0x4e54ff40UL, 0xf6e89825UL, - 0xae8b8873UL, 0x1637ef16UL, 0x048240f8UL, 0xbc3e279dUL, 0x21e91f24UL, - 0x99557841UL, 0x8be0d7afUL, 0x335cb0caUL, 0xed59b63bUL, 0x55e5d15eUL, - 0x47507eb0UL, 0xffec19d5UL, 0x623b216cUL, 0xda874609UL, 0xc832e9e7UL, - 0x708e8e82UL, 0x28ed9ed4UL, 0x9051f9b1UL, 0x82e4565fUL, 0x3a58313aUL, - 0xa78f0983UL, 0x1f336ee6UL, 0x0d86c108UL, 0xb53aa66dUL, 0xbd40e1a4UL, - 0x05fc86c1UL, 0x1749292fUL, 0xaff54e4aUL, 0x322276f3UL, 0x8a9e1196UL, - 0x982bbe78UL, 0x2097d91dUL, 0x78f4c94bUL, 0xc048ae2eUL, 0xd2fd01c0UL, - 0x6a4166a5UL, 0xf7965e1cUL, 0x4f2a3979UL, 0x5d9f9697UL, 0xe523f1f2UL, - 0x4d6b1905UL, 0xf5d77e60UL, 0xe762d18eUL, 0x5fdeb6ebUL, 0xc2098e52UL, - 0x7ab5e937UL, 0x680046d9UL, 0xd0bc21bcUL, 0x88df31eaUL, 0x3063568fUL, - 0x22d6f961UL, 0x9a6a9e04UL, 0x07bda6bdUL, 0xbf01c1d8UL, 0xadb46e36UL, - 0x15080953UL, 0x1d724e9aUL, 0xa5ce29ffUL, 0xb77b8611UL, 0x0fc7e174UL, - 0x9210d9cdUL, 0x2aacbea8UL, 0x38191146UL, 0x80a57623UL, 0xd8c66675UL, - 0x607a0110UL, 0x72cfaefeUL, 0xca73c99bUL, 0x57a4f122UL, 0xef189647UL, - 0xfdad39a9UL, 0x45115eccUL, 0x764dee06UL, 0xcef18963UL, 0xdc44268dUL, - 0x64f841e8UL, 0xf92f7951UL, 0x41931e34UL, 0x5326b1daUL, 0xeb9ad6bfUL, - 0xb3f9c6e9UL, 0x0b45a18cUL, 0x19f00e62UL, 0xa14c6907UL, 0x3c9b51beUL, - 0x842736dbUL, 0x96929935UL, 0x2e2efe50UL, 0x2654b999UL, 0x9ee8defcUL, - 0x8c5d7112UL, 0x34e11677UL, 0xa9362eceUL, 0x118a49abUL, 0x033fe645UL, - 0xbb838120UL, 0xe3e09176UL, 0x5b5cf613UL, 0x49e959fdUL, 0xf1553e98UL, - 0x6c820621UL, 0xd43e6144UL, 0xc68bceaaUL, 0x7e37a9cfUL, 0xd67f4138UL, - 0x6ec3265dUL, 0x7c7689b3UL, 0xc4caeed6UL, 0x591dd66fUL, 0xe1a1b10aUL, - 0xf3141ee4UL, 0x4ba87981UL, 0x13cb69d7UL, 0xab770eb2UL, 0xb9c2a15cUL, - 0x017ec639UL, 0x9ca9fe80UL, 0x241599e5UL, 0x36a0360bUL, 0x8e1c516eUL, - 0x866616a7UL, 0x3eda71c2UL, 0x2c6fde2cUL, 0x94d3b949UL, 0x090481f0UL, - 0xb1b8e695UL, 0xa30d497bUL, 0x1bb12e1eUL, 0x43d23e48UL, 0xfb6e592dUL, - 0xe9dbf6c3UL, 0x516791a6UL, 0xccb0a91fUL, 0x740cce7aUL, 0x66b96194UL, - 0xde0506f1UL - }, - { - 0x00000000UL, 0x96300777UL, 0x2c610eeeUL, 0xba510999UL, 0x19c46d07UL, - 0x8ff46a70UL, 0x35a563e9UL, 0xa395649eUL, 0x3288db0eUL, 0xa4b8dc79UL, - 0x1ee9d5e0UL, 0x88d9d297UL, 0x2b4cb609UL, 0xbd7cb17eUL, 0x072db8e7UL, - 0x911dbf90UL, 0x6410b71dUL, 0xf220b06aUL, 0x4871b9f3UL, 0xde41be84UL, - 0x7dd4da1aUL, 0xebe4dd6dUL, 0x51b5d4f4UL, 0xc785d383UL, 0x56986c13UL, - 0xc0a86b64UL, 0x7af962fdUL, 0xecc9658aUL, 0x4f5c0114UL, 0xd96c0663UL, - 0x633d0ffaUL, 0xf50d088dUL, 0xc8206e3bUL, 0x5e10694cUL, 0xe44160d5UL, - 0x727167a2UL, 0xd1e4033cUL, 0x47d4044bUL, 0xfd850dd2UL, 0x6bb50aa5UL, - 0xfaa8b535UL, 0x6c98b242UL, 0xd6c9bbdbUL, 0x40f9bcacUL, 0xe36cd832UL, - 0x755cdf45UL, 0xcf0dd6dcUL, 0x593dd1abUL, 0xac30d926UL, 0x3a00de51UL, - 0x8051d7c8UL, 0x1661d0bfUL, 0xb5f4b421UL, 0x23c4b356UL, 0x9995bacfUL, - 0x0fa5bdb8UL, 0x9eb80228UL, 0x0888055fUL, 0xb2d90cc6UL, 0x24e90bb1UL, - 0x877c6f2fUL, 0x114c6858UL, 0xab1d61c1UL, 0x3d2d66b6UL, 0x9041dc76UL, - 0x0671db01UL, 0xbc20d298UL, 0x2a10d5efUL, 0x8985b171UL, 0x1fb5b606UL, - 0xa5e4bf9fUL, 0x33d4b8e8UL, 0xa2c90778UL, 0x34f9000fUL, 0x8ea80996UL, - 0x18980ee1UL, 0xbb0d6a7fUL, 0x2d3d6d08UL, 0x976c6491UL, 0x015c63e6UL, - 0xf4516b6bUL, 0x62616c1cUL, 0xd8306585UL, 0x4e0062f2UL, 0xed95066cUL, - 0x7ba5011bUL, 0xc1f40882UL, 0x57c40ff5UL, 0xc6d9b065UL, 0x50e9b712UL, - 0xeab8be8bUL, 0x7c88b9fcUL, 0xdf1ddd62UL, 0x492dda15UL, 0xf37cd38cUL, - 0x654cd4fbUL, 0x5861b24dUL, 0xce51b53aUL, 0x7400bca3UL, 0xe230bbd4UL, - 0x41a5df4aUL, 0xd795d83dUL, 0x6dc4d1a4UL, 0xfbf4d6d3UL, 0x6ae96943UL, - 0xfcd96e34UL, 0x468867adUL, 0xd0b860daUL, 0x732d0444UL, 0xe51d0333UL, - 0x5f4c0aaaUL, 0xc97c0dddUL, 0x3c710550UL, 0xaa410227UL, 0x10100bbeUL, - 0x86200cc9UL, 0x25b56857UL, 0xb3856f20UL, 0x09d466b9UL, 0x9fe461ceUL, - 0x0ef9de5eUL, 0x98c9d929UL, 0x2298d0b0UL, 0xb4a8d7c7UL, 0x173db359UL, - 0x810db42eUL, 0x3b5cbdb7UL, 0xad6cbac0UL, 0x2083b8edUL, 0xb6b3bf9aUL, - 0x0ce2b603UL, 0x9ad2b174UL, 0x3947d5eaUL, 0xaf77d29dUL, 0x1526db04UL, - 0x8316dc73UL, 0x120b63e3UL, 0x843b6494UL, 0x3e6a6d0dUL, 0xa85a6a7aUL, - 0x0bcf0ee4UL, 0x9dff0993UL, 0x27ae000aUL, 0xb19e077dUL, 0x44930ff0UL, - 0xd2a30887UL, 0x68f2011eUL, 0xfec20669UL, 0x5d5762f7UL, 0xcb676580UL, - 0x71366c19UL, 0xe7066b6eUL, 0x761bd4feUL, 0xe02bd389UL, 0x5a7ada10UL, - 0xcc4add67UL, 0x6fdfb9f9UL, 0xf9efbe8eUL, 0x43beb717UL, 0xd58eb060UL, - 0xe8a3d6d6UL, 0x7e93d1a1UL, 0xc4c2d838UL, 0x52f2df4fUL, 0xf167bbd1UL, - 0x6757bca6UL, 0xdd06b53fUL, 0x4b36b248UL, 0xda2b0dd8UL, 0x4c1b0aafUL, - 0xf64a0336UL, 0x607a0441UL, 0xc3ef60dfUL, 0x55df67a8UL, 0xef8e6e31UL, - 0x79be6946UL, 0x8cb361cbUL, 0x1a8366bcUL, 0xa0d26f25UL, 0x36e26852UL, - 0x95770cccUL, 0x03470bbbUL, 0xb9160222UL, 0x2f260555UL, 0xbe3bbac5UL, - 0x280bbdb2UL, 0x925ab42bUL, 0x046ab35cUL, 0xa7ffd7c2UL, 0x31cfd0b5UL, - 0x8b9ed92cUL, 0x1daede5bUL, 0xb0c2649bUL, 0x26f263ecUL, 0x9ca36a75UL, - 0x0a936d02UL, 0xa906099cUL, 0x3f360eebUL, 0x85670772UL, 0x13570005UL, - 0x824abf95UL, 0x147ab8e2UL, 0xae2bb17bUL, 0x381bb60cUL, 0x9b8ed292UL, - 0x0dbed5e5UL, 0xb7efdc7cUL, 0x21dfdb0bUL, 0xd4d2d386UL, 0x42e2d4f1UL, - 0xf8b3dd68UL, 0x6e83da1fUL, 0xcd16be81UL, 0x5b26b9f6UL, 0xe177b06fUL, - 0x7747b718UL, 0xe65a0888UL, 0x706a0fffUL, 0xca3b0666UL, 0x5c0b0111UL, - 0xff9e658fUL, 0x69ae62f8UL, 0xd3ff6b61UL, 0x45cf6c16UL, 0x78e20aa0UL, - 0xeed20dd7UL, 0x5483044eUL, 0xc2b30339UL, 0x612667a7UL, 0xf71660d0UL, - 0x4d476949UL, 0xdb776e3eUL, 0x4a6ad1aeUL, 0xdc5ad6d9UL, 0x660bdf40UL, - 0xf03bd837UL, 0x53aebca9UL, 0xc59ebbdeUL, 0x7fcfb247UL, 0xe9ffb530UL, - 0x1cf2bdbdUL, 0x8ac2bacaUL, 0x3093b353UL, 0xa6a3b424UL, 0x0536d0baUL, - 0x9306d7cdUL, 0x2957de54UL, 0xbf67d923UL, 0x2e7a66b3UL, 0xb84a61c4UL, - 0x021b685dUL, 0x942b6f2aUL, 0x37be0bb4UL, 0xa18e0cc3UL, 0x1bdf055aUL, - 0x8def022dUL - }, - { - 0x00000000UL, 0x41311b19UL, 0x82623632UL, 0xc3532d2bUL, 0x04c56c64UL, - 0x45f4777dUL, 0x86a75a56UL, 0xc796414fUL, 0x088ad9c8UL, 0x49bbc2d1UL, - 0x8ae8effaUL, 0xcbd9f4e3UL, 0x0c4fb5acUL, 0x4d7eaeb5UL, 0x8e2d839eUL, - 0xcf1c9887UL, 0x5112c24aUL, 0x1023d953UL, 0xd370f478UL, 0x9241ef61UL, - 0x55d7ae2eUL, 0x14e6b537UL, 0xd7b5981cUL, 0x96848305UL, 0x59981b82UL, - 0x18a9009bUL, 0xdbfa2db0UL, 0x9acb36a9UL, 0x5d5d77e6UL, 0x1c6c6cffUL, - 0xdf3f41d4UL, 0x9e0e5acdUL, 0xa2248495UL, 0xe3159f8cUL, 0x2046b2a7UL, - 0x6177a9beUL, 0xa6e1e8f1UL, 0xe7d0f3e8UL, 0x2483dec3UL, 0x65b2c5daUL, - 0xaaae5d5dUL, 0xeb9f4644UL, 0x28cc6b6fUL, 0x69fd7076UL, 0xae6b3139UL, - 0xef5a2a20UL, 0x2c09070bUL, 0x6d381c12UL, 0xf33646dfUL, 0xb2075dc6UL, - 0x715470edUL, 0x30656bf4UL, 0xf7f32abbUL, 0xb6c231a2UL, 0x75911c89UL, - 0x34a00790UL, 0xfbbc9f17UL, 0xba8d840eUL, 0x79dea925UL, 0x38efb23cUL, - 0xff79f373UL, 0xbe48e86aUL, 0x7d1bc541UL, 0x3c2ade58UL, 0x054f79f0UL, - 0x447e62e9UL, 0x872d4fc2UL, 0xc61c54dbUL, 0x018a1594UL, 0x40bb0e8dUL, - 0x83e823a6UL, 0xc2d938bfUL, 0x0dc5a038UL, 0x4cf4bb21UL, 0x8fa7960aUL, - 0xce968d13UL, 0x0900cc5cUL, 0x4831d745UL, 0x8b62fa6eUL, 0xca53e177UL, - 0x545dbbbaUL, 0x156ca0a3UL, 0xd63f8d88UL, 0x970e9691UL, 0x5098d7deUL, - 0x11a9ccc7UL, 0xd2fae1ecUL, 0x93cbfaf5UL, 0x5cd76272UL, 0x1de6796bUL, - 0xdeb55440UL, 0x9f844f59UL, 0x58120e16UL, 0x1923150fUL, 0xda703824UL, - 0x9b41233dUL, 0xa76bfd65UL, 0xe65ae67cUL, 0x2509cb57UL, 0x6438d04eUL, - 0xa3ae9101UL, 0xe29f8a18UL, 0x21cca733UL, 0x60fdbc2aUL, 0xafe124adUL, - 0xeed03fb4UL, 0x2d83129fUL, 0x6cb20986UL, 0xab2448c9UL, 0xea1553d0UL, - 0x29467efbUL, 0x687765e2UL, 0xf6793f2fUL, 0xb7482436UL, 0x741b091dUL, - 0x352a1204UL, 0xf2bc534bUL, 0xb38d4852UL, 0x70de6579UL, 0x31ef7e60UL, - 0xfef3e6e7UL, 0xbfc2fdfeUL, 0x7c91d0d5UL, 0x3da0cbccUL, 0xfa368a83UL, - 0xbb07919aUL, 0x7854bcb1UL, 0x3965a7a8UL, 0x4b98833bUL, 0x0aa99822UL, - 0xc9fab509UL, 0x88cbae10UL, 0x4f5def5fUL, 0x0e6cf446UL, 0xcd3fd96dUL, - 0x8c0ec274UL, 0x43125af3UL, 0x022341eaUL, 0xc1706cc1UL, 0x804177d8UL, - 0x47d73697UL, 0x06e62d8eUL, 0xc5b500a5UL, 0x84841bbcUL, 0x1a8a4171UL, - 0x5bbb5a68UL, 0x98e87743UL, 0xd9d96c5aUL, 0x1e4f2d15UL, 0x5f7e360cUL, - 0x9c2d1b27UL, 0xdd1c003eUL, 0x120098b9UL, 0x533183a0UL, 0x9062ae8bUL, - 0xd153b592UL, 0x16c5f4ddUL, 0x57f4efc4UL, 0x94a7c2efUL, 0xd596d9f6UL, - 0xe9bc07aeUL, 0xa88d1cb7UL, 0x6bde319cUL, 0x2aef2a85UL, 0xed796bcaUL, - 0xac4870d3UL, 0x6f1b5df8UL, 0x2e2a46e1UL, 0xe136de66UL, 0xa007c57fUL, - 0x6354e854UL, 0x2265f34dUL, 0xe5f3b202UL, 0xa4c2a91bUL, 0x67918430UL, - 0x26a09f29UL, 0xb8aec5e4UL, 0xf99fdefdUL, 0x3accf3d6UL, 0x7bfde8cfUL, - 0xbc6ba980UL, 0xfd5ab299UL, 0x3e099fb2UL, 0x7f3884abUL, 0xb0241c2cUL, - 0xf1150735UL, 0x32462a1eUL, 0x73773107UL, 0xb4e17048UL, 0xf5d06b51UL, - 0x3683467aUL, 0x77b25d63UL, 0x4ed7facbUL, 0x0fe6e1d2UL, 0xccb5ccf9UL, - 0x8d84d7e0UL, 0x4a1296afUL, 0x0b238db6UL, 0xc870a09dUL, 0x8941bb84UL, - 0x465d2303UL, 0x076c381aUL, 0xc43f1531UL, 0x850e0e28UL, 0x42984f67UL, - 0x03a9547eUL, 0xc0fa7955UL, 0x81cb624cUL, 0x1fc53881UL, 0x5ef42398UL, - 0x9da70eb3UL, 0xdc9615aaUL, 0x1b0054e5UL, 0x5a314ffcUL, 0x996262d7UL, - 0xd85379ceUL, 0x174fe149UL, 0x567efa50UL, 0x952dd77bUL, 0xd41ccc62UL, - 0x138a8d2dUL, 0x52bb9634UL, 0x91e8bb1fUL, 0xd0d9a006UL, 0xecf37e5eUL, - 0xadc26547UL, 0x6e91486cUL, 0x2fa05375UL, 0xe836123aUL, 0xa9070923UL, - 0x6a542408UL, 0x2b653f11UL, 0xe479a796UL, 0xa548bc8fUL, 0x661b91a4UL, - 0x272a8abdUL, 0xe0bccbf2UL, 0xa18dd0ebUL, 0x62defdc0UL, 0x23efe6d9UL, - 0xbde1bc14UL, 0xfcd0a70dUL, 0x3f838a26UL, 0x7eb2913fUL, 0xb924d070UL, - 0xf815cb69UL, 0x3b46e642UL, 0x7a77fd5bUL, 0xb56b65dcUL, 0xf45a7ec5UL, - 0x370953eeUL, 0x763848f7UL, 0xb1ae09b8UL, 0xf09f12a1UL, 0x33cc3f8aUL, - 0x72fd2493UL - }, - { - 0x00000000UL, 0x376ac201UL, 0x6ed48403UL, 0x59be4602UL, 0xdca80907UL, - 0xebc2cb06UL, 0xb27c8d04UL, 0x85164f05UL, 0xb851130eUL, 0x8f3bd10fUL, - 0xd685970dUL, 0xe1ef550cUL, 0x64f91a09UL, 0x5393d808UL, 0x0a2d9e0aUL, - 0x3d475c0bUL, 0x70a3261cUL, 0x47c9e41dUL, 0x1e77a21fUL, 0x291d601eUL, - 0xac0b2f1bUL, 0x9b61ed1aUL, 0xc2dfab18UL, 0xf5b56919UL, 0xc8f23512UL, - 0xff98f713UL, 0xa626b111UL, 0x914c7310UL, 0x145a3c15UL, 0x2330fe14UL, - 0x7a8eb816UL, 0x4de47a17UL, 0xe0464d38UL, 0xd72c8f39UL, 0x8e92c93bUL, - 0xb9f80b3aUL, 0x3cee443fUL, 0x0b84863eUL, 0x523ac03cUL, 0x6550023dUL, - 0x58175e36UL, 0x6f7d9c37UL, 0x36c3da35UL, 0x01a91834UL, 0x84bf5731UL, - 0xb3d59530UL, 0xea6bd332UL, 0xdd011133UL, 0x90e56b24UL, 0xa78fa925UL, - 0xfe31ef27UL, 0xc95b2d26UL, 0x4c4d6223UL, 0x7b27a022UL, 0x2299e620UL, - 0x15f32421UL, 0x28b4782aUL, 0x1fdeba2bUL, 0x4660fc29UL, 0x710a3e28UL, - 0xf41c712dUL, 0xc376b32cUL, 0x9ac8f52eUL, 0xada2372fUL, 0xc08d9a70UL, - 0xf7e75871UL, 0xae591e73UL, 0x9933dc72UL, 0x1c259377UL, 0x2b4f5176UL, - 0x72f11774UL, 0x459bd575UL, 0x78dc897eUL, 0x4fb64b7fUL, 0x16080d7dUL, - 0x2162cf7cUL, 0xa4748079UL, 0x931e4278UL, 0xcaa0047aUL, 0xfdcac67bUL, - 0xb02ebc6cUL, 0x87447e6dUL, 0xdefa386fUL, 0xe990fa6eUL, 0x6c86b56bUL, - 0x5bec776aUL, 0x02523168UL, 0x3538f369UL, 0x087faf62UL, 0x3f156d63UL, - 0x66ab2b61UL, 0x51c1e960UL, 0xd4d7a665UL, 0xe3bd6464UL, 0xba032266UL, - 0x8d69e067UL, 0x20cbd748UL, 0x17a11549UL, 0x4e1f534bUL, 0x7975914aUL, - 0xfc63de4fUL, 0xcb091c4eUL, 0x92b75a4cUL, 0xa5dd984dUL, 0x989ac446UL, - 0xaff00647UL, 0xf64e4045UL, 0xc1248244UL, 0x4432cd41UL, 0x73580f40UL, - 0x2ae64942UL, 0x1d8c8b43UL, 0x5068f154UL, 0x67023355UL, 0x3ebc7557UL, - 0x09d6b756UL, 0x8cc0f853UL, 0xbbaa3a52UL, 0xe2147c50UL, 0xd57ebe51UL, - 0xe839e25aUL, 0xdf53205bUL, 0x86ed6659UL, 0xb187a458UL, 0x3491eb5dUL, - 0x03fb295cUL, 0x5a456f5eUL, 0x6d2fad5fUL, 0x801b35e1UL, 0xb771f7e0UL, - 0xeecfb1e2UL, 0xd9a573e3UL, 0x5cb33ce6UL, 0x6bd9fee7UL, 0x3267b8e5UL, - 0x050d7ae4UL, 0x384a26efUL, 0x0f20e4eeUL, 0x569ea2ecUL, 0x61f460edUL, - 0xe4e22fe8UL, 0xd388ede9UL, 0x8a36abebUL, 0xbd5c69eaUL, 0xf0b813fdUL, - 0xc7d2d1fcUL, 0x9e6c97feUL, 0xa90655ffUL, 0x2c101afaUL, 0x1b7ad8fbUL, - 0x42c49ef9UL, 0x75ae5cf8UL, 0x48e900f3UL, 0x7f83c2f2UL, 0x263d84f0UL, - 0x115746f1UL, 0x944109f4UL, 0xa32bcbf5UL, 0xfa958df7UL, 0xcdff4ff6UL, - 0x605d78d9UL, 0x5737bad8UL, 0x0e89fcdaUL, 0x39e33edbUL, 0xbcf571deUL, - 0x8b9fb3dfUL, 0xd221f5ddUL, 0xe54b37dcUL, 0xd80c6bd7UL, 0xef66a9d6UL, - 0xb6d8efd4UL, 0x81b22dd5UL, 0x04a462d0UL, 0x33cea0d1UL, 0x6a70e6d3UL, - 0x5d1a24d2UL, 0x10fe5ec5UL, 0x27949cc4UL, 0x7e2adac6UL, 0x494018c7UL, - 0xcc5657c2UL, 0xfb3c95c3UL, 0xa282d3c1UL, 0x95e811c0UL, 0xa8af4dcbUL, - 0x9fc58fcaUL, 0xc67bc9c8UL, 0xf1110bc9UL, 0x740744ccUL, 0x436d86cdUL, - 0x1ad3c0cfUL, 0x2db902ceUL, 0x4096af91UL, 0x77fc6d90UL, 0x2e422b92UL, - 0x1928e993UL, 0x9c3ea696UL, 0xab546497UL, 0xf2ea2295UL, 0xc580e094UL, - 0xf8c7bc9fUL, 0xcfad7e9eUL, 0x9613389cUL, 0xa179fa9dUL, 0x246fb598UL, - 0x13057799UL, 0x4abb319bUL, 0x7dd1f39aUL, 0x3035898dUL, 0x075f4b8cUL, - 0x5ee10d8eUL, 0x698bcf8fUL, 0xec9d808aUL, 0xdbf7428bUL, 0x82490489UL, - 0xb523c688UL, 0x88649a83UL, 0xbf0e5882UL, 0xe6b01e80UL, 0xd1dadc81UL, - 0x54cc9384UL, 0x63a65185UL, 0x3a181787UL, 0x0d72d586UL, 0xa0d0e2a9UL, - 0x97ba20a8UL, 0xce0466aaUL, 0xf96ea4abUL, 0x7c78ebaeUL, 0x4b1229afUL, - 0x12ac6fadUL, 0x25c6adacUL, 0x1881f1a7UL, 0x2feb33a6UL, 0x765575a4UL, - 0x413fb7a5UL, 0xc429f8a0UL, 0xf3433aa1UL, 0xaafd7ca3UL, 0x9d97bea2UL, - 0xd073c4b5UL, 0xe71906b4UL, 0xbea740b6UL, 0x89cd82b7UL, 0x0cdbcdb2UL, - 0x3bb10fb3UL, 0x620f49b1UL, 0x55658bb0UL, 0x6822d7bbUL, 0x5f4815baUL, - 0x06f653b8UL, 0x319c91b9UL, 0xb48adebcUL, 0x83e01cbdUL, 0xda5e5abfUL, - 0xed3498beUL - }, - { - 0x00000000UL, 0x6567bcb8UL, 0x8bc809aaUL, 0xeeafb512UL, 0x5797628fUL, - 0x32f0de37UL, 0xdc5f6b25UL, 0xb938d79dUL, 0xef28b4c5UL, 0x8a4f087dUL, - 0x64e0bd6fUL, 0x018701d7UL, 0xb8bfd64aUL, 0xddd86af2UL, 0x3377dfe0UL, - 0x56106358UL, 0x9f571950UL, 0xfa30a5e8UL, 0x149f10faUL, 0x71f8ac42UL, - 0xc8c07bdfUL, 0xada7c767UL, 0x43087275UL, 0x266fcecdUL, 0x707fad95UL, - 0x1518112dUL, 0xfbb7a43fUL, 0x9ed01887UL, 0x27e8cf1aUL, 0x428f73a2UL, - 0xac20c6b0UL, 0xc9477a08UL, 0x3eaf32a0UL, 0x5bc88e18UL, 0xb5673b0aUL, - 0xd00087b2UL, 0x6938502fUL, 0x0c5fec97UL, 0xe2f05985UL, 0x8797e53dUL, - 0xd1878665UL, 0xb4e03addUL, 0x5a4f8fcfUL, 0x3f283377UL, 0x8610e4eaUL, - 0xe3775852UL, 0x0dd8ed40UL, 0x68bf51f8UL, 0xa1f82bf0UL, 0xc49f9748UL, - 0x2a30225aUL, 0x4f579ee2UL, 0xf66f497fUL, 0x9308f5c7UL, 0x7da740d5UL, - 0x18c0fc6dUL, 0x4ed09f35UL, 0x2bb7238dUL, 0xc518969fUL, 0xa07f2a27UL, - 0x1947fdbaUL, 0x7c204102UL, 0x928ff410UL, 0xf7e848a8UL, 0x3d58149bUL, - 0x583fa823UL, 0xb6901d31UL, 0xd3f7a189UL, 0x6acf7614UL, 0x0fa8caacUL, - 0xe1077fbeUL, 0x8460c306UL, 0xd270a05eUL, 0xb7171ce6UL, 0x59b8a9f4UL, - 0x3cdf154cUL, 0x85e7c2d1UL, 0xe0807e69UL, 0x0e2fcb7bUL, 0x6b4877c3UL, - 0xa20f0dcbUL, 0xc768b173UL, 0x29c70461UL, 0x4ca0b8d9UL, 0xf5986f44UL, - 0x90ffd3fcUL, 0x7e5066eeUL, 0x1b37da56UL, 0x4d27b90eUL, 0x284005b6UL, - 0xc6efb0a4UL, 0xa3880c1cUL, 0x1ab0db81UL, 0x7fd76739UL, 0x9178d22bUL, - 0xf41f6e93UL, 0x03f7263bUL, 0x66909a83UL, 0x883f2f91UL, 0xed589329UL, - 0x546044b4UL, 0x3107f80cUL, 0xdfa84d1eUL, 0xbacff1a6UL, 0xecdf92feUL, - 0x89b82e46UL, 0x67179b54UL, 0x027027ecUL, 0xbb48f071UL, 0xde2f4cc9UL, - 0x3080f9dbUL, 0x55e74563UL, 0x9ca03f6bUL, 0xf9c783d3UL, 0x176836c1UL, - 0x720f8a79UL, 0xcb375de4UL, 0xae50e15cUL, 0x40ff544eUL, 0x2598e8f6UL, - 0x73888baeUL, 0x16ef3716UL, 0xf8408204UL, 0x9d273ebcUL, 0x241fe921UL, - 0x41785599UL, 0xafd7e08bUL, 0xcab05c33UL, 0x3bb659edUL, 0x5ed1e555UL, - 0xb07e5047UL, 0xd519ecffUL, 0x6c213b62UL, 0x094687daUL, 0xe7e932c8UL, - 0x828e8e70UL, 0xd49eed28UL, 0xb1f95190UL, 0x5f56e482UL, 0x3a31583aUL, - 0x83098fa7UL, 0xe66e331fUL, 0x08c1860dUL, 0x6da63ab5UL, 0xa4e140bdUL, - 0xc186fc05UL, 0x2f294917UL, 0x4a4ef5afUL, 0xf3762232UL, 0x96119e8aUL, - 0x78be2b98UL, 0x1dd99720UL, 0x4bc9f478UL, 0x2eae48c0UL, 0xc001fdd2UL, - 0xa566416aUL, 0x1c5e96f7UL, 0x79392a4fUL, 0x97969f5dUL, 0xf2f123e5UL, - 0x05196b4dUL, 0x607ed7f5UL, 0x8ed162e7UL, 0xebb6de5fUL, 0x528e09c2UL, - 0x37e9b57aUL, 0xd9460068UL, 0xbc21bcd0UL, 0xea31df88UL, 0x8f566330UL, - 0x61f9d622UL, 0x049e6a9aUL, 0xbda6bd07UL, 0xd8c101bfUL, 0x366eb4adUL, - 0x53090815UL, 0x9a4e721dUL, 0xff29cea5UL, 0x11867bb7UL, 0x74e1c70fUL, - 0xcdd91092UL, 0xa8beac2aUL, 0x46111938UL, 0x2376a580UL, 0x7566c6d8UL, - 0x10017a60UL, 0xfeaecf72UL, 0x9bc973caUL, 0x22f1a457UL, 0x479618efUL, - 0xa939adfdUL, 0xcc5e1145UL, 0x06ee4d76UL, 0x6389f1ceUL, 0x8d2644dcUL, - 0xe841f864UL, 0x51792ff9UL, 0x341e9341UL, 0xdab12653UL, 0xbfd69aebUL, - 0xe9c6f9b3UL, 0x8ca1450bUL, 0x620ef019UL, 0x07694ca1UL, 0xbe519b3cUL, - 0xdb362784UL, 0x35999296UL, 0x50fe2e2eUL, 0x99b95426UL, 0xfcdee89eUL, - 0x12715d8cUL, 0x7716e134UL, 0xce2e36a9UL, 0xab498a11UL, 0x45e63f03UL, - 0x208183bbUL, 0x7691e0e3UL, 0x13f65c5bUL, 0xfd59e949UL, 0x983e55f1UL, - 0x2106826cUL, 0x44613ed4UL, 0xaace8bc6UL, 0xcfa9377eUL, 0x38417fd6UL, - 0x5d26c36eUL, 0xb389767cUL, 0xd6eecac4UL, 0x6fd61d59UL, 0x0ab1a1e1UL, - 0xe41e14f3UL, 0x8179a84bUL, 0xd769cb13UL, 0xb20e77abUL, 0x5ca1c2b9UL, - 0x39c67e01UL, 0x80fea99cUL, 0xe5991524UL, 0x0b36a036UL, 0x6e511c8eUL, - 0xa7166686UL, 0xc271da3eUL, 0x2cde6f2cUL, 0x49b9d394UL, 0xf0810409UL, - 0x95e6b8b1UL, 0x7b490da3UL, 0x1e2eb11bUL, 0x483ed243UL, 0x2d596efbUL, - 0xc3f6dbe9UL, 0xa6916751UL, 0x1fa9b0ccUL, 0x7ace0c74UL, 0x9461b966UL, - 0xf10605deUL -#endif - } -}; diff --git a/src/common/dep/zlib/deflate.c b/src/common/dep/zlib/deflate.c deleted file mode 100644 index 1ec761448..000000000 --- a/src/common/dep/zlib/deflate.c +++ /dev/null @@ -1,2163 +0,0 @@ -/* deflate.c -- compress data using the deflation algorithm - * Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process depends on being able to identify portions - * of the input text which are identical to earlier input (within a - * sliding window trailing behind the input currently being processed). - * - * The most straightforward technique turns out to be the fastest for - * most input files: try all possible matches and select the longest. - * The key feature of this algorithm is that insertions into the string - * dictionary are very simple and thus fast, and deletions are avoided - * completely. Insertions are performed at each input character, whereas - * string matches are performed only when the previous match ends. So it - * is preferable to spend more time in matches to allow very fast string - * insertions and avoid deletions. The matching algorithm for small - * strings is inspired from that of Rabin & Karp. A brute force approach - * is used to find longer strings when a small match has been found. - * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze - * (by Leonid Broukhis). - * A previous version of this file used a more sophisticated algorithm - * (by Fiala and Greene) which is guaranteed to run in linear amortized - * time, but has a larger average cost, uses more memory and is patented. - * However the F&G algorithm may be faster for some highly redundant - * files if the parameter max_chain_length (described below) is too large. - * - * ACKNOWLEDGEMENTS - * - * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and - * I found it in 'freeze' written by Leonid Broukhis. - * Thanks to many people for bug reports and testing. - * - * REFERENCES - * - * Deutsch, L.P.,"DEFLATE Compressed Data Format Specification". - * Available in http://tools.ietf.org/html/rfc1951 - * - * A description of the Rabin and Karp algorithm is given in the book - * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. - * - * Fiala,E.R., and Greene,D.H. - * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 - * - */ - -/* @(#) $Id$ */ - -#include "deflate.h" - -const char deflate_copyright[] = - " deflate 1.2.11 Copyright 1995-2017 Jean-loup Gailly and Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* =========================================================================== - * Function prototypes. - */ -typedef enum { - need_more, /* block not completed, need more input or more output */ - block_done, /* block flush performed */ - finish_started, /* finish started, need only more output at next deflate */ - finish_done /* finish done, accept no more input or output */ -} block_state; - -typedef block_state (*compress_func) OF((deflate_state *s, int flush)); -/* Compression function. Returns the block state after the call. */ - -local int deflateStateCheck OF((z_streamp strm)); -local void slide_hash OF((deflate_state *s)); -local void fill_window OF((deflate_state *s)); -local block_state deflate_stored OF((deflate_state *s, int flush)); -local block_state deflate_fast OF((deflate_state *s, int flush)); -#ifndef FASTEST -local block_state deflate_slow OF((deflate_state *s, int flush)); -#endif -local block_state deflate_rle OF((deflate_state *s, int flush)); -local block_state deflate_huff OF((deflate_state *s, int flush)); -local void lm_init OF((deflate_state *s)); -local void putShortMSB OF((deflate_state *s, uInt b)); -local void flush_pending OF((z_streamp strm)); -local unsigned read_buf OF((z_streamp strm, Bytef *buf, unsigned size)); -#ifdef ASMV -# pragma message("Assembler code may have bugs -- use at your own risk") - void match_init OF((void)); /* asm code initialization */ - uInt longest_match OF((deflate_state *s, IPos cur_match)); -#else -local uInt longest_match OF((deflate_state *s, IPos cur_match)); -#endif - -#ifdef ZLIB_DEBUG -local void check_match OF((deflate_state *s, IPos start, IPos match, - int length)); -#endif - -/* =========================================================================== - * Local data - */ - -#define NIL 0 -/* Tail of hash chains */ - -#ifndef TOO_FAR -# define TOO_FAR 4096 -#endif -/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ - -/* Values for max_lazy_match, good_match and max_chain_length, depending on - * the desired pack level (0..9). The values given below have been tuned to - * exclude worst case performance for pathological files. Better values may be - * found for specific files. - */ -typedef struct config_s { - ush good_length; /* reduce lazy search above this match length */ - ush max_lazy; /* do not perform lazy search above this match length */ - ush nice_length; /* quit search above this match length */ - ush max_chain; - compress_func func; -} config; - -#ifdef FASTEST -local const config configuration_table[2] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}}; /* max speed, no lazy matches */ -#else -local const config configuration_table[10] = { -/* good lazy nice chain */ -/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ -/* 1 */ {4, 4, 8, 4, deflate_fast}, /* max speed, no lazy matches */ -/* 2 */ {4, 5, 16, 8, deflate_fast}, -/* 3 */ {4, 6, 32, 32, deflate_fast}, - -/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ -/* 5 */ {8, 16, 32, 32, deflate_slow}, -/* 6 */ {8, 16, 128, 128, deflate_slow}, -/* 7 */ {8, 32, 128, 256, deflate_slow}, -/* 8 */ {32, 128, 258, 1024, deflate_slow}, -/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* max compression */ -#endif - -/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 - * For deflate_fast() (levels <= 3) good is ignored and lazy has a different - * meaning. - */ - -/* rank Z_BLOCK between Z_NO_FLUSH and Z_PARTIAL_FLUSH */ -#define RANK(f) (((f) * 2) - ((f) > 4 ? 9 : 0)) - -/* =========================================================================== - * Update a hash value with the given input byte - * IN assertion: all calls to UPDATE_HASH are made with consecutive input - * characters, so that a running hash key can be computed from the previous - * key instead of complete recalculation each time. - */ -#define UPDATE_HASH(s,h,c) (h = (((h)<hash_shift) ^ (c)) & s->hash_mask) - - -/* =========================================================================== - * Insert string str in the dictionary and set match_head to the previous head - * of the hash chain (the most recent string with same hash key). Return - * the previous length of the hash chain. - * If this file is compiled with -DFASTEST, the compression level is forced - * to 1, and no hash chains are maintained. - * IN assertion: all calls to INSERT_STRING are made with consecutive input - * characters and the first MIN_MATCH bytes of str are valid (except for - * the last MIN_MATCH-1 bytes of the input file). - */ -#ifdef FASTEST -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#else -#define INSERT_STRING(s, str, match_head) \ - (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ - match_head = s->prev[(str) & s->w_mask] = s->head[s->ins_h], \ - s->head[s->ins_h] = (Pos)(str)) -#endif - -/* =========================================================================== - * Initialize the hash table (avoiding 64K overflow for 16 bit systems). - * prev[] will be initialized on the fly. - */ -#define CLEAR_HASH(s) \ - s->head[s->hash_size-1] = NIL; \ - zmemzero((Bytef *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); - -/* =========================================================================== - * Slide the hash table when sliding the window down (could be avoided with 32 - * bit values at the expense of memory usage). We slide even when level == 0 to - * keep the hash table consistent if we switch back to level > 0 later. - */ -local void slide_hash(s) - deflate_state *s; -{ - unsigned n, m; - Posf *p; - uInt wsize = s->w_size; - - n = s->hash_size; - p = &s->head[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m - wsize : NIL); - } while (--n); - n = wsize; -#ifndef FASTEST - p = &s->prev[n]; - do { - m = *--p; - *p = (Pos)(m >= wsize ? m - wsize : NIL); - /* If n is not on any hash chain, prev[n] is garbage but - * its value will never be used. - */ - } while (--n); -#endif -} - -/* ========================================================================= */ -int ZEXPORT deflateInit_(strm, level, version, stream_size) - z_streamp strm; - int level; - const char *version; - int stream_size; -{ - return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, - Z_DEFAULT_STRATEGY, version, stream_size); - /* To do: ignore strm->next_in if we use it as window */ -} - -/* ========================================================================= */ -int ZEXPORT deflateInit2_(strm, level, method, windowBits, memLevel, strategy, - version, stream_size) - z_streamp strm; - int level; - int method; - int windowBits; - int memLevel; - int strategy; - const char *version; - int stream_size; -{ - deflate_state *s; - int wrap = 1; - static const char my_version[] = ZLIB_VERSION; - - ushf *overlay; - /* We overlay pending_buf and d_buf+l_buf. This works since the average - * output size for (length,distance) codes is <= 24 bits. - */ - - if (version == Z_NULL || version[0] != my_version[0] || - stream_size != sizeof(z_stream)) { - return Z_VERSION_ERROR; - } - if (strm == Z_NULL) return Z_STREAM_ERROR; - - strm->msg = Z_NULL; - if (strm->zalloc == (alloc_func)0) { -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; -#endif - } - if (strm->zfree == (free_func)0) -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zfree = zcfree; -#endif - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - - if (windowBits < 0) { /* suppress zlib wrapper */ - wrap = 0; - windowBits = -windowBits; - } -#ifdef GZIP - else if (windowBits > 15) { - wrap = 2; /* write gzip wrapper instead */ - windowBits -= 16; - } -#endif - if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || - strategy < 0 || strategy > Z_FIXED || (windowBits == 8 && wrap != 1)) { - return Z_STREAM_ERROR; - } - if (windowBits == 8) windowBits = 9; /* until 256-byte window bug fixed */ - s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); - if (s == Z_NULL) return Z_MEM_ERROR; - strm->state = (struct internal_state FAR *)s; - s->strm = strm; - s->status = INIT_STATE; /* to pass state test in deflateReset() */ - - s->wrap = wrap; - s->gzhead = Z_NULL; - s->w_bits = (uInt)windowBits; - s->w_size = 1 << s->w_bits; - s->w_mask = s->w_size - 1; - - s->hash_bits = (uInt)memLevel + 7; - s->hash_size = 1 << s->hash_bits; - s->hash_mask = s->hash_size - 1; - s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); - - s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); - s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); - s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); - - s->high_water = 0; /* nothing written to s->window yet */ - - s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ - - overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); - s->pending_buf = (uchf *) overlay; - s->pending_buf_size = (ulg)s->lit_bufsize * (sizeof(ush)+2L); - - if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || - s->pending_buf == Z_NULL) { - s->status = FINISH_STATE; - strm->msg = ERR_MSG(Z_MEM_ERROR); - deflateEnd (strm); - return Z_MEM_ERROR; - } - s->d_buf = overlay + s->lit_bufsize/sizeof(ush); - s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; - - s->level = level; - s->strategy = strategy; - s->method = (Byte)method; - - return deflateReset(strm); -} - -/* ========================================================================= - * Check for a valid deflate stream state. Return 0 if ok, 1 if not. - */ -local int deflateStateCheck (strm) - z_streamp strm; -{ - deflate_state *s; - if (strm == Z_NULL || - strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) - return 1; - s = strm->state; - if (s == Z_NULL || s->strm != strm || (s->status != INIT_STATE && -#ifdef GZIP - s->status != GZIP_STATE && -#endif - s->status != EXTRA_STATE && - s->status != NAME_STATE && - s->status != COMMENT_STATE && - s->status != HCRC_STATE && - s->status != BUSY_STATE && - s->status != FINISH_STATE)) - return 1; - return 0; -} - -/* ========================================================================= */ -int ZEXPORT deflateSetDictionary (strm, dictionary, dictLength) - z_streamp strm; - const Bytef *dictionary; - uInt dictLength; -{ - deflate_state *s; - uInt str, n; - int wrap; - unsigned avail; - z_const unsigned char *next; - - if (deflateStateCheck(strm) || dictionary == Z_NULL) - return Z_STREAM_ERROR; - s = strm->state; - wrap = s->wrap; - if (wrap == 2 || (wrap == 1 && s->status != INIT_STATE) || s->lookahead) - return Z_STREAM_ERROR; - - /* when using zlib wrappers, compute Adler-32 for provided dictionary */ - if (wrap == 1) - strm->adler = adler32(strm->adler, dictionary, dictLength); - s->wrap = 0; /* avoid computing Adler-32 in read_buf */ - - /* if dictionary would fill window, just replace the history */ - if (dictLength >= s->w_size) { - if (wrap == 0) { /* already empty otherwise */ - CLEAR_HASH(s); - s->strstart = 0; - s->block_start = 0L; - s->insert = 0; - } - dictionary += dictLength - s->w_size; /* use the tail */ - dictLength = s->w_size; - } - - /* insert dictionary into window and hash */ - avail = strm->avail_in; - next = strm->next_in; - strm->avail_in = dictLength; - strm->next_in = (z_const Bytef *)dictionary; - fill_window(s); - while (s->lookahead >= MIN_MATCH) { - str = s->strstart; - n = s->lookahead - (MIN_MATCH-1); - do { - UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); -#ifndef FASTEST - s->prev[str & s->w_mask] = s->head[s->ins_h]; -#endif - s->head[s->ins_h] = (Pos)str; - str++; - } while (--n); - s->strstart = str; - s->lookahead = MIN_MATCH-1; - fill_window(s); - } - s->strstart += s->lookahead; - s->block_start = (long)s->strstart; - s->insert = s->lookahead; - s->lookahead = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - strm->next_in = next; - strm->avail_in = avail; - s->wrap = wrap; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateGetDictionary (strm, dictionary, dictLength) - z_streamp strm; - Bytef *dictionary; - uInt *dictLength; -{ - deflate_state *s; - uInt len; - - if (deflateStateCheck(strm)) - return Z_STREAM_ERROR; - s = strm->state; - len = s->strstart + s->lookahead; - if (len > s->w_size) - len = s->w_size; - if (dictionary != Z_NULL && len) - zmemcpy(dictionary, s->window + s->strstart + s->lookahead - len, len); - if (dictLength != Z_NULL) - *dictLength = len; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateResetKeep (strm) - z_streamp strm; -{ - deflate_state *s; - - if (deflateStateCheck(strm)) { - return Z_STREAM_ERROR; - } - - strm->total_in = strm->total_out = 0; - strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ - strm->data_type = Z_UNKNOWN; - - s = (deflate_state *)strm->state; - s->pending = 0; - s->pending_out = s->pending_buf; - - if (s->wrap < 0) { - s->wrap = -s->wrap; /* was made negative by deflate(..., Z_FINISH); */ - } - s->status = -#ifdef GZIP - s->wrap == 2 ? GZIP_STATE : -#endif - s->wrap ? INIT_STATE : BUSY_STATE; - strm->adler = -#ifdef GZIP - s->wrap == 2 ? crc32(0L, Z_NULL, 0) : -#endif - adler32(0L, Z_NULL, 0); - s->last_flush = Z_NO_FLUSH; - - _tr_init(s); - - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateReset (strm) - z_streamp strm; -{ - int ret; - - ret = deflateResetKeep(strm); - if (ret == Z_OK) - lm_init(strm->state); - return ret; -} - -/* ========================================================================= */ -int ZEXPORT deflateSetHeader (strm, head) - z_streamp strm; - gz_headerp head; -{ - if (deflateStateCheck(strm) || strm->state->wrap != 2) - return Z_STREAM_ERROR; - strm->state->gzhead = head; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflatePending (strm, pending, bits) - unsigned *pending; - int *bits; - z_streamp strm; -{ - if (deflateStateCheck(strm)) return Z_STREAM_ERROR; - if (pending != Z_NULL) - *pending = strm->state->pending; - if (bits != Z_NULL) - *bits = strm->state->bi_valid; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflatePrime (strm, bits, value) - z_streamp strm; - int bits; - int value; -{ - deflate_state *s; - int put; - - if (deflateStateCheck(strm)) return Z_STREAM_ERROR; - s = strm->state; - if ((Bytef *)(s->d_buf) < s->pending_out + ((Buf_size + 7) >> 3)) - return Z_BUF_ERROR; - do { - put = Buf_size - s->bi_valid; - if (put > bits) - put = bits; - s->bi_buf |= (ush)((value & ((1 << put) - 1)) << s->bi_valid); - s->bi_valid += put; - _tr_flush_bits(s); - value >>= put; - bits -= put; - } while (bits); - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateParams(strm, level, strategy) - z_streamp strm; - int level; - int strategy; -{ - deflate_state *s; - compress_func func; - - if (deflateStateCheck(strm)) return Z_STREAM_ERROR; - s = strm->state; - -#ifdef FASTEST - if (level != 0) level = 1; -#else - if (level == Z_DEFAULT_COMPRESSION) level = 6; -#endif - if (level < 0 || level > 9 || strategy < 0 || strategy > Z_FIXED) { - return Z_STREAM_ERROR; - } - func = configuration_table[s->level].func; - - if ((strategy != s->strategy || func != configuration_table[level].func) && - s->high_water) { - /* Flush the last buffer: */ - int err = deflate(strm, Z_BLOCK); - if (err == Z_STREAM_ERROR) - return err; - if (strm->avail_out == 0) - return Z_BUF_ERROR; - } - if (s->level != level) { - if (s->level == 0 && s->matches != 0) { - if (s->matches == 1) - slide_hash(s); - else - CLEAR_HASH(s); - s->matches = 0; - } - s->level = level; - s->max_lazy_match = configuration_table[level].max_lazy; - s->good_match = configuration_table[level].good_length; - s->nice_match = configuration_table[level].nice_length; - s->max_chain_length = configuration_table[level].max_chain; - } - s->strategy = strategy; - return Z_OK; -} - -/* ========================================================================= */ -int ZEXPORT deflateTune(strm, good_length, max_lazy, nice_length, max_chain) - z_streamp strm; - int good_length; - int max_lazy; - int nice_length; - int max_chain; -{ - deflate_state *s; - - if (deflateStateCheck(strm)) return Z_STREAM_ERROR; - s = strm->state; - s->good_match = (uInt)good_length; - s->max_lazy_match = (uInt)max_lazy; - s->nice_match = nice_length; - s->max_chain_length = (uInt)max_chain; - return Z_OK; -} - -/* ========================================================================= - * For the default windowBits of 15 and memLevel of 8, this function returns - * a close to exact, as well as small, upper bound on the compressed size. - * They are coded as constants here for a reason--if the #define's are - * changed, then this function needs to be changed as well. The return - * value for 15 and 8 only works for those exact settings. - * - * For any setting other than those defaults for windowBits and memLevel, - * the value returned is a conservative worst case for the maximum expansion - * resulting from using fixed blocks instead of stored blocks, which deflate - * can emit on compressed data for some combinations of the parameters. - * - * This function could be more sophisticated to provide closer upper bounds for - * every combination of windowBits and memLevel. But even the conservative - * upper bound of about 14% expansion does not seem onerous for output buffer - * allocation. - */ -uLong ZEXPORT deflateBound(strm, sourceLen) - z_streamp strm; - uLong sourceLen; -{ - deflate_state *s; - uLong complen, wraplen; - - /* conservative upper bound for compressed data */ - complen = sourceLen + - ((sourceLen + 7) >> 3) + ((sourceLen + 63) >> 6) + 5; - - /* if can't get parameters, return conservative bound plus zlib wrapper */ - if (deflateStateCheck(strm)) - return complen + 6; - - /* compute wrapper length */ - s = strm->state; - switch (s->wrap) { - case 0: /* raw deflate */ - wraplen = 0; - break; - case 1: /* zlib wrapper */ - wraplen = 6 + (s->strstart ? 4 : 0); - break; -#ifdef GZIP - case 2: /* gzip wrapper */ - wraplen = 18; - if (s->gzhead != Z_NULL) { /* user-supplied gzip header */ - Bytef *str; - if (s->gzhead->extra != Z_NULL) - wraplen += 2 + s->gzhead->extra_len; - str = s->gzhead->name; - if (str != Z_NULL) - do { - wraplen++; - } while (*str++); - str = s->gzhead->comment; - if (str != Z_NULL) - do { - wraplen++; - } while (*str++); - if (s->gzhead->hcrc) - wraplen += 2; - } - break; -#endif - default: /* for compiler happiness */ - wraplen = 6; - } - - /* if not default parameters, return conservative bound */ - if (s->w_bits != 15 || s->hash_bits != 8 + 7) - return complen + wraplen; - - /* default settings: return tight bound for that case */ - return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) + - (sourceLen >> 25) + 13 - 6 + wraplen; -} - -/* ========================================================================= - * Put a short in the pending buffer. The 16-bit value is put in MSB order. - * IN assertion: the stream state is correct and there is enough room in - * pending_buf. - */ -local void putShortMSB (s, b) - deflate_state *s; - uInt b; -{ - put_byte(s, (Byte)(b >> 8)); - put_byte(s, (Byte)(b & 0xff)); -} - -/* ========================================================================= - * Flush as much pending output as possible. All deflate() output, except for - * some deflate_stored() output, goes through this function so some - * applications may wish to modify it to avoid allocating a large - * strm->next_out buffer and copying into it. (See also read_buf()). - */ -local void flush_pending(strm) - z_streamp strm; -{ - unsigned len; - deflate_state *s = strm->state; - - _tr_flush_bits(s); - len = s->pending; - if (len > strm->avail_out) len = strm->avail_out; - if (len == 0) return; - - zmemcpy(strm->next_out, s->pending_out, len); - strm->next_out += len; - s->pending_out += len; - strm->total_out += len; - strm->avail_out -= len; - s->pending -= len; - if (s->pending == 0) { - s->pending_out = s->pending_buf; - } -} - -/* =========================================================================== - * Update the header CRC with the bytes s->pending_buf[beg..s->pending - 1]. - */ -#define HCRC_UPDATE(beg) \ - do { \ - if (s->gzhead->hcrc && s->pending > (beg)) \ - strm->adler = crc32(strm->adler, s->pending_buf + (beg), \ - s->pending - (beg)); \ - } while (0) - -/* ========================================================================= */ -int ZEXPORT deflate (strm, flush) - z_streamp strm; - int flush; -{ - int old_flush; /* value of flush param for previous deflate call */ - deflate_state *s; - - if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) { - return Z_STREAM_ERROR; - } - s = strm->state; - - if (strm->next_out == Z_NULL || - (strm->avail_in != 0 && strm->next_in == Z_NULL) || - (s->status == FINISH_STATE && flush != Z_FINISH)) { - ERR_RETURN(strm, Z_STREAM_ERROR); - } - if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); - - old_flush = s->last_flush; - s->last_flush = flush; - - /* Flush as much pending output as possible */ - if (s->pending != 0) { - flush_pending(strm); - if (strm->avail_out == 0) { - /* Since avail_out is 0, deflate will be called again with - * more output space, but possibly with both pending and - * avail_in equal to zero. There won't be anything to do, - * but this is not an error situation so make sure we - * return OK instead of BUF_ERROR at next call of deflate: - */ - s->last_flush = -1; - return Z_OK; - } - - /* Make sure there is something to do and avoid duplicate consecutive - * flushes. For repeated and useless calls with Z_FINISH, we keep - * returning Z_STREAM_END instead of Z_BUF_ERROR. - */ - } else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) && - flush != Z_FINISH) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* User must not provide more input after the first FINISH: */ - if (s->status == FINISH_STATE && strm->avail_in != 0) { - ERR_RETURN(strm, Z_BUF_ERROR); - } - - /* Write the header */ - if (s->status == INIT_STATE) { - /* zlib header */ - uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; - uInt level_flags; - - if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2) - level_flags = 0; - else if (s->level < 6) - level_flags = 1; - else if (s->level == 6) - level_flags = 2; - else - level_flags = 3; - header |= (level_flags << 6); - if (s->strstart != 0) header |= PRESET_DICT; - header += 31 - (header % 31); - - putShortMSB(s, header); - - /* Save the adler32 of the preset dictionary: */ - if (s->strstart != 0) { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - strm->adler = adler32(0L, Z_NULL, 0); - s->status = BUSY_STATE; - - /* Compression must start with an empty pending buffer */ - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - } -#ifdef GZIP - if (s->status == GZIP_STATE) { - /* gzip header */ - strm->adler = crc32(0L, Z_NULL, 0); - put_byte(s, 31); - put_byte(s, 139); - put_byte(s, 8); - if (s->gzhead == Z_NULL) { - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, 0); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, OS_CODE); - s->status = BUSY_STATE; - - /* Compression must start with an empty pending buffer */ - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - } - else { - put_byte(s, (s->gzhead->text ? 1 : 0) + - (s->gzhead->hcrc ? 2 : 0) + - (s->gzhead->extra == Z_NULL ? 0 : 4) + - (s->gzhead->name == Z_NULL ? 0 : 8) + - (s->gzhead->comment == Z_NULL ? 0 : 16) - ); - put_byte(s, (Byte)(s->gzhead->time & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 8) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 16) & 0xff)); - put_byte(s, (Byte)((s->gzhead->time >> 24) & 0xff)); - put_byte(s, s->level == 9 ? 2 : - (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ? - 4 : 0)); - put_byte(s, s->gzhead->os & 0xff); - if (s->gzhead->extra != Z_NULL) { - put_byte(s, s->gzhead->extra_len & 0xff); - put_byte(s, (s->gzhead->extra_len >> 8) & 0xff); - } - if (s->gzhead->hcrc) - strm->adler = crc32(strm->adler, s->pending_buf, - s->pending); - s->gzindex = 0; - s->status = EXTRA_STATE; - } - } - if (s->status == EXTRA_STATE) { - if (s->gzhead->extra != Z_NULL) { - ulg beg = s->pending; /* start of bytes to update crc */ - uInt left = (s->gzhead->extra_len & 0xffff) - s->gzindex; - while (s->pending + left > s->pending_buf_size) { - uInt copy = s->pending_buf_size - s->pending; - zmemcpy(s->pending_buf + s->pending, - s->gzhead->extra + s->gzindex, copy); - s->pending = s->pending_buf_size; - HCRC_UPDATE(beg); - s->gzindex += copy; - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - beg = 0; - left -= copy; - } - zmemcpy(s->pending_buf + s->pending, - s->gzhead->extra + s->gzindex, left); - s->pending += left; - HCRC_UPDATE(beg); - s->gzindex = 0; - } - s->status = NAME_STATE; - } - if (s->status == NAME_STATE) { - if (s->gzhead->name != Z_NULL) { - ulg beg = s->pending; /* start of bytes to update crc */ - int val; - do { - if (s->pending == s->pending_buf_size) { - HCRC_UPDATE(beg); - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - beg = 0; - } - val = s->gzhead->name[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - HCRC_UPDATE(beg); - s->gzindex = 0; - } - s->status = COMMENT_STATE; - } - if (s->status == COMMENT_STATE) { - if (s->gzhead->comment != Z_NULL) { - ulg beg = s->pending; /* start of bytes to update crc */ - int val; - do { - if (s->pending == s->pending_buf_size) { - HCRC_UPDATE(beg); - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - beg = 0; - } - val = s->gzhead->comment[s->gzindex++]; - put_byte(s, val); - } while (val != 0); - HCRC_UPDATE(beg); - } - s->status = HCRC_STATE; - } - if (s->status == HCRC_STATE) { - if (s->gzhead->hcrc) { - if (s->pending + 2 > s->pending_buf_size) { - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - } - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - strm->adler = crc32(0L, Z_NULL, 0); - } - s->status = BUSY_STATE; - - /* Compression must start with an empty pending buffer */ - flush_pending(strm); - if (s->pending != 0) { - s->last_flush = -1; - return Z_OK; - } - } -#endif - - /* Start a new block or continue the current one. - */ - if (strm->avail_in != 0 || s->lookahead != 0 || - (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { - block_state bstate; - - bstate = s->level == 0 ? deflate_stored(s, flush) : - s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) : - s->strategy == Z_RLE ? deflate_rle(s, flush) : - (*(configuration_table[s->level].func))(s, flush); - - if (bstate == finish_started || bstate == finish_done) { - s->status = FINISH_STATE; - } - if (bstate == need_more || bstate == finish_started) { - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ - } - return Z_OK; - /* If flush != Z_NO_FLUSH && avail_out == 0, the next call - * of deflate should use the same flush parameter to make sure - * that the flush is complete. So we don't have to output an - * empty block here, this will be done at next call. This also - * ensures that for a very small output buffer, we emit at most - * one empty block. - */ - } - if (bstate == block_done) { - if (flush == Z_PARTIAL_FLUSH) { - _tr_align(s); - } else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */ - _tr_stored_block(s, (char*)0, 0L, 0); - /* For a full flush, this empty block will be recognized - * as a special marker by inflate_sync(). - */ - if (flush == Z_FULL_FLUSH) { - CLEAR_HASH(s); /* forget history */ - if (s->lookahead == 0) { - s->strstart = 0; - s->block_start = 0L; - s->insert = 0; - } - } - } - flush_pending(strm); - if (strm->avail_out == 0) { - s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ - return Z_OK; - } - } - } - - if (flush != Z_FINISH) return Z_OK; - if (s->wrap <= 0) return Z_STREAM_END; - - /* Write the trailer */ -#ifdef GZIP - if (s->wrap == 2) { - put_byte(s, (Byte)(strm->adler & 0xff)); - put_byte(s, (Byte)((strm->adler >> 8) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 16) & 0xff)); - put_byte(s, (Byte)((strm->adler >> 24) & 0xff)); - put_byte(s, (Byte)(strm->total_in & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 8) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 16) & 0xff)); - put_byte(s, (Byte)((strm->total_in >> 24) & 0xff)); - } - else -#endif - { - putShortMSB(s, (uInt)(strm->adler >> 16)); - putShortMSB(s, (uInt)(strm->adler & 0xffff)); - } - flush_pending(strm); - /* If avail_out is zero, the application will call deflate again - * to flush the rest. - */ - if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */ - return s->pending != 0 ? Z_OK : Z_STREAM_END; -} - -/* ========================================================================= */ -int ZEXPORT deflateEnd (strm) - z_streamp strm; -{ - int status; - - if (deflateStateCheck(strm)) return Z_STREAM_ERROR; - - status = strm->state->status; - - /* Deallocate in reverse order of allocations: */ - TRY_FREE(strm, strm->state->pending_buf); - TRY_FREE(strm, strm->state->head); - TRY_FREE(strm, strm->state->prev); - TRY_FREE(strm, strm->state->window); - - ZFREE(strm, strm->state); - strm->state = Z_NULL; - - return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; -} - -/* ========================================================================= - * Copy the source state to the destination state. - * To simplify the source, this is not supported for 16-bit MSDOS (which - * doesn't have enough memory anyway to duplicate compression states). - */ -int ZEXPORT deflateCopy (dest, source) - z_streamp dest; - z_streamp source; -{ -#ifdef MAXSEG_64K - return Z_STREAM_ERROR; -#else - deflate_state *ds; - deflate_state *ss; - ushf *overlay; - - - if (deflateStateCheck(source) || dest == Z_NULL) { - return Z_STREAM_ERROR; - } - - ss = source->state; - - zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); - - ds = (deflate_state *) ZALLOC(dest, 1, sizeof(deflate_state)); - if (ds == Z_NULL) return Z_MEM_ERROR; - dest->state = (struct internal_state FAR *) ds; - zmemcpy((voidpf)ds, (voidpf)ss, sizeof(deflate_state)); - ds->strm = dest; - - ds->window = (Bytef *) ZALLOC(dest, ds->w_size, 2*sizeof(Byte)); - ds->prev = (Posf *) ZALLOC(dest, ds->w_size, sizeof(Pos)); - ds->head = (Posf *) ZALLOC(dest, ds->hash_size, sizeof(Pos)); - overlay = (ushf *) ZALLOC(dest, ds->lit_bufsize, sizeof(ush)+2); - ds->pending_buf = (uchf *) overlay; - - if (ds->window == Z_NULL || ds->prev == Z_NULL || ds->head == Z_NULL || - ds->pending_buf == Z_NULL) { - deflateEnd (dest); - return Z_MEM_ERROR; - } - /* following zmemcpy do not work for 16-bit MSDOS */ - zmemcpy(ds->window, ss->window, ds->w_size * 2 * sizeof(Byte)); - zmemcpy((voidpf)ds->prev, (voidpf)ss->prev, ds->w_size * sizeof(Pos)); - zmemcpy((voidpf)ds->head, (voidpf)ss->head, ds->hash_size * sizeof(Pos)); - zmemcpy(ds->pending_buf, ss->pending_buf, (uInt)ds->pending_buf_size); - - ds->pending_out = ds->pending_buf + (ss->pending_out - ss->pending_buf); - ds->d_buf = overlay + ds->lit_bufsize/sizeof(ush); - ds->l_buf = ds->pending_buf + (1+sizeof(ush))*ds->lit_bufsize; - - ds->l_desc.dyn_tree = ds->dyn_ltree; - ds->d_desc.dyn_tree = ds->dyn_dtree; - ds->bl_desc.dyn_tree = ds->bl_tree; - - return Z_OK; -#endif /* MAXSEG_64K */ -} - -/* =========================================================================== - * Read a new buffer from the current input stream, update the adler32 - * and total number of bytes read. All deflate() input goes through - * this function so some applications may wish to modify it to avoid - * allocating a large strm->next_in buffer and copying from it. - * (See also flush_pending()). - */ -local unsigned read_buf(strm, buf, size) - z_streamp strm; - Bytef *buf; - unsigned size; -{ - unsigned len = strm->avail_in; - - if (len > size) len = size; - if (len == 0) return 0; - - strm->avail_in -= len; - - zmemcpy(buf, strm->next_in, len); - if (strm->state->wrap == 1) { - strm->adler = adler32(strm->adler, buf, len); - } -#ifdef GZIP - else if (strm->state->wrap == 2) { - strm->adler = crc32(strm->adler, buf, len); - } -#endif - strm->next_in += len; - strm->total_in += len; - - return len; -} - -/* =========================================================================== - * Initialize the "longest match" routines for a new zlib stream - */ -local void lm_init (s) - deflate_state *s; -{ - s->window_size = (ulg)2L*s->w_size; - - CLEAR_HASH(s); - - /* Set the default configuration parameters: - */ - s->max_lazy_match = configuration_table[s->level].max_lazy; - s->good_match = configuration_table[s->level].good_length; - s->nice_match = configuration_table[s->level].nice_length; - s->max_chain_length = configuration_table[s->level].max_chain; - - s->strstart = 0; - s->block_start = 0L; - s->lookahead = 0; - s->insert = 0; - s->match_length = s->prev_length = MIN_MATCH-1; - s->match_available = 0; - s->ins_h = 0; -#ifndef FASTEST -#ifdef ASMV - match_init(); /* initialize the asm code */ -#endif -#endif -} - -#ifndef FASTEST -/* =========================================================================== - * Set match_start to the longest match starting at the given string and - * return its length. Matches shorter or equal to prev_length are discarded, - * in which case the result is equal to prev_length and match_start is - * garbage. - * IN assertions: cur_match is the head of the hash chain for the current - * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 - * OUT assertion: the match length is not greater than s->lookahead. - */ -#ifndef ASMV -/* For 80x86 and 680x0, an optimized version will be provided in match.asm or - * match.S. The code will be functionally equivalent. - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - unsigned chain_length = s->max_chain_length;/* max hash chain length */ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - int best_len = (int)s->prev_length; /* best match length so far */ - int nice_match = s->nice_match; /* stop if match long enough */ - IPos limit = s->strstart > (IPos)MAX_DIST(s) ? - s->strstart - (IPos)MAX_DIST(s) : NIL; - /* Stop when cur_match becomes <= limit. To simplify the code, - * we prevent matches with the string of window index 0. - */ - Posf *prev = s->prev; - uInt wmask = s->w_mask; - -#ifdef UNALIGNED_OK - /* Compare two bytes at a time. Note: this is not always beneficial. - * Try with and without -DUNALIGNED_OK to check. - */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; - register ush scan_start = *(ushf*)scan; - register ush scan_end = *(ushf*)(scan+best_len-1); -#else - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - register Byte scan_end1 = scan[best_len-1]; - register Byte scan_end = scan[best_len]; -#endif - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - /* Do not waste too much time if we already have a good match: */ - if (s->prev_length >= s->good_match) { - chain_length >>= 2; - } - /* Do not look for matches beyond the end of the input. This is necessary - * to make deflate deterministic. - */ - if ((uInt)nice_match > s->lookahead) nice_match = (int)s->lookahead; - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - do { - Assert(cur_match < s->strstart, "no future"); - match = s->window + cur_match; - - /* Skip to next match if the match length cannot increase - * or if the match length is less than 2. Note that the checks below - * for insufficient lookahead only occur occasionally for performance - * reasons. Therefore uninitialized memory will be accessed, and - * conditional jumps will be made that depend on those values. - * However the length of the match is limited to the lookahead, so - * the output of deflate is not affected by the uninitialized values. - */ -#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) - /* This code assumes sizeof(unsigned short) == 2. Do not use - * UNALIGNED_OK if your compiler uses a different size. - */ - if (*(ushf*)(match+best_len-1) != scan_end || - *(ushf*)match != scan_start) continue; - - /* It is not necessary to compare scan[2] and match[2] since they are - * always equal when the other bytes match, given that the hash keys - * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at - * strstart+3, +5, ... up to strstart+257. We check for insufficient - * lookahead only every 4th comparison; the 128th check will be made - * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is - * necessary to put more guard bytes at the end of the window, or - * to check more often for insufficient lookahead. - */ - Assert(scan[2] == match[2], "scan[2]?"); - scan++, match++; - do { - } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - *(ushf*)(scan+=2) == *(ushf*)(match+=2) && - scan < strend); - /* The funny "do {}" generates better code on most compilers */ - - /* Here, scan <= window+strstart+257 */ - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - if (*scan == *match) scan++; - - len = (MAX_MATCH - 1) - (int)(strend-scan); - scan = strend - (MAX_MATCH-1); - -#else /* UNALIGNED_OK */ - - if (match[best_len] != scan_end || - match[best_len-1] != scan_end1 || - *match != *scan || - *++match != scan[1]) continue; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match++; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - scan = strend - MAX_MATCH; - -#endif /* UNALIGNED_OK */ - - if (len > best_len) { - s->match_start = cur_match; - best_len = len; - if (len >= nice_match) break; -#ifdef UNALIGNED_OK - scan_end = *(ushf*)(scan+best_len-1); -#else - scan_end1 = scan[best_len-1]; - scan_end = scan[best_len]; -#endif - } - } while ((cur_match = prev[cur_match & wmask]) > limit - && --chain_length != 0); - - if ((uInt)best_len <= s->lookahead) return (uInt)best_len; - return s->lookahead; -} -#endif /* ASMV */ - -#else /* FASTEST */ - -/* --------------------------------------------------------------------------- - * Optimized version for FASTEST only - */ -local uInt longest_match(s, cur_match) - deflate_state *s; - IPos cur_match; /* current match */ -{ - register Bytef *scan = s->window + s->strstart; /* current string */ - register Bytef *match; /* matched string */ - register int len; /* length of current match */ - register Bytef *strend = s->window + s->strstart + MAX_MATCH; - - /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. - * It is easy to get rid of this optimization if necessary. - */ - Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); - - Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); - - Assert(cur_match < s->strstart, "no future"); - - match = s->window + cur_match; - - /* Return failure if the match length is less than 2: - */ - if (match[0] != scan[0] || match[1] != scan[1]) return MIN_MATCH-1; - - /* The check at best_len-1 can be removed because it will be made - * again later. (This heuristic is not always a win.) - * It is not necessary to compare scan[2] and match[2] since they - * are always equal when the other bytes match, given that - * the hash keys are equal and that HASH_BITS >= 8. - */ - scan += 2, match += 2; - Assert(*scan == *match, "match[2]?"); - - /* We check for insufficient lookahead only every 8th comparison; - * the 256th check will be made at strstart+258. - */ - do { - } while (*++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - *++scan == *++match && *++scan == *++match && - scan < strend); - - Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); - - len = MAX_MATCH - (int)(strend - scan); - - if (len < MIN_MATCH) return MIN_MATCH - 1; - - s->match_start = cur_match; - return (uInt)len <= s->lookahead ? (uInt)len : s->lookahead; -} - -#endif /* FASTEST */ - -#ifdef ZLIB_DEBUG - -#define EQUAL 0 -/* result of memcmp for equal strings */ - -/* =========================================================================== - * Check that the match at match_start is indeed a match. - */ -local void check_match(s, start, match, length) - deflate_state *s; - IPos start, match; - int length; -{ - /* check that the match is indeed a match */ - if (zmemcmp(s->window + match, - s->window + start, length) != EQUAL) { - fprintf(stderr, " start %u, match %u, length %d\n", - start, match, length); - do { - fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); - } while (--length != 0); - z_error("invalid match"); - } - if (z_verbose > 1) { - fprintf(stderr,"\\[%d,%d]", start-match, length); - do { putc(s->window[start++], stderr); } while (--length != 0); - } -} -#else -# define check_match(s, start, match, length) -#endif /* ZLIB_DEBUG */ - -/* =========================================================================== - * Fill the window when the lookahead becomes insufficient. - * Updates strstart and lookahead. - * - * IN assertion: lookahead < MIN_LOOKAHEAD - * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD - * At least one byte has been read, or avail_in == 0; reads are - * performed for at least two bytes (required for the zip translate_eol - * option -- not supported here). - */ -local void fill_window(s) - deflate_state *s; -{ - unsigned n; - unsigned more; /* Amount of free space at the end of the window. */ - uInt wsize = s->w_size; - - Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead"); - - do { - more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); - - /* Deal with !@#$% 64K limit: */ - if (sizeof(int) <= 2) { - if (more == 0 && s->strstart == 0 && s->lookahead == 0) { - more = wsize; - - } else if (more == (unsigned)(-1)) { - /* Very unlikely, but possible on 16 bit machine if - * strstart == 0 && lookahead == 1 (input done a byte at time) - */ - more--; - } - } - - /* If the window is almost full and there is insufficient lookahead, - * move the upper half to the lower one to make room in the upper half. - */ - if (s->strstart >= wsize+MAX_DIST(s)) { - - zmemcpy(s->window, s->window+wsize, (unsigned)wsize - more); - s->match_start -= wsize; - s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ - s->block_start -= (long) wsize; - slide_hash(s); - more += wsize; - } - if (s->strm->avail_in == 0) break; - - /* If there was no sliding: - * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && - * more == window_size - lookahead - strstart - * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) - * => more >= window_size - 2*WSIZE + 2 - * In the BIG_MEM or MMAP case (not yet supported), - * window_size == input_size + MIN_LOOKAHEAD && - * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. - * Otherwise, window_size == 2*WSIZE so more >= 2. - * If there was sliding, more >= WSIZE. So in all cases, more >= 2. - */ - Assert(more >= 2, "more < 2"); - - n = read_buf(s->strm, s->window + s->strstart + s->lookahead, more); - s->lookahead += n; - - /* Initialize the hash value now that we have some input: */ - if (s->lookahead + s->insert >= MIN_MATCH) { - uInt str = s->strstart - s->insert; - s->ins_h = s->window[str]; - UPDATE_HASH(s, s->ins_h, s->window[str + 1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - while (s->insert) { - UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); -#ifndef FASTEST - s->prev[str & s->w_mask] = s->head[s->ins_h]; -#endif - s->head[s->ins_h] = (Pos)str; - str++; - s->insert--; - if (s->lookahead + s->insert < MIN_MATCH) - break; - } - } - /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, - * but this is not important since only literal bytes will be emitted. - */ - - } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); - - /* If the WIN_INIT bytes after the end of the current data have never been - * written, then zero those bytes in order to avoid memory check reports of - * the use of uninitialized (or uninitialised as Julian writes) bytes by - * the longest match routines. Update the high water mark for the next - * time through here. WIN_INIT is set to MAX_MATCH since the longest match - * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead. - */ - if (s->high_water < s->window_size) { - ulg curr = s->strstart + (ulg)(s->lookahead); - ulg init; - - if (s->high_water < curr) { - /* Previous high water mark below current data -- zero WIN_INIT - * bytes or up to end of window, whichever is less. - */ - init = s->window_size - curr; - if (init > WIN_INIT) - init = WIN_INIT; - zmemzero(s->window + curr, (unsigned)init); - s->high_water = curr + init; - } - else if (s->high_water < (ulg)curr + WIN_INIT) { - /* High water mark at or above current data, but below current data - * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up - * to end of window, whichever is less. - */ - init = (ulg)curr + WIN_INIT - s->high_water; - if (init > s->window_size - s->high_water) - init = s->window_size - s->high_water; - zmemzero(s->window + s->high_water, (unsigned)init); - s->high_water += init; - } - } - - Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD, - "not enough room for search"); -} - -/* =========================================================================== - * Flush the current block, with given end-of-file flag. - * IN assertion: strstart is set to the end of the current match. - */ -#define FLUSH_BLOCK_ONLY(s, last) { \ - _tr_flush_block(s, (s->block_start >= 0L ? \ - (charf *)&s->window[(unsigned)s->block_start] : \ - (charf *)Z_NULL), \ - (ulg)((long)s->strstart - s->block_start), \ - (last)); \ - s->block_start = s->strstart; \ - flush_pending(s->strm); \ - Tracev((stderr,"[FLUSH]")); \ -} - -/* Same but force premature exit if necessary. */ -#define FLUSH_BLOCK(s, last) { \ - FLUSH_BLOCK_ONLY(s, last); \ - if (s->strm->avail_out == 0) return (last) ? finish_started : need_more; \ -} - -/* Maximum stored block length in deflate format (not including header). */ -#define MAX_STORED 65535 - -/* Minimum of a and b. */ -#define MIN(a, b) ((a) > (b) ? (b) : (a)) - -/* =========================================================================== - * Copy without compression as much as possible from the input stream, return - * the current block state. - * - * In case deflateParams() is used to later switch to a non-zero compression - * level, s->matches (otherwise unused when storing) keeps track of the number - * of hash table slides to perform. If s->matches is 1, then one hash table - * slide will be done when switching. If s->matches is 2, the maximum value - * allowed here, then the hash table will be cleared, since two or more slides - * is the same as a clear. - * - * deflate_stored() is written to minimize the number of times an input byte is - * copied. It is most efficient with large input and output buffers, which - * maximizes the opportunites to have a single copy from next_in to next_out. - */ -local block_state deflate_stored(s, flush) - deflate_state *s; - int flush; -{ - /* Smallest worthy block size when not flushing or finishing. By default - * this is 32K. This can be as small as 507 bytes for memLevel == 1. For - * large input and output buffers, the stored block size will be larger. - */ - unsigned min_block = MIN(s->pending_buf_size - 5, s->w_size); - - /* Copy as many min_block or larger stored blocks directly to next_out as - * possible. If flushing, copy the remaining available input to next_out as - * stored blocks, if there is enough space. - */ - unsigned len, left, have, last = 0; - unsigned used = s->strm->avail_in; - do { - /* Set len to the maximum size block that we can copy directly with the - * available input data and output space. Set left to how much of that - * would be copied from what's left in the window. - */ - len = MAX_STORED; /* maximum deflate stored block length */ - have = (s->bi_valid + 42) >> 3; /* number of header bytes */ - if (s->strm->avail_out < have) /* need room for header */ - break; - /* maximum stored block length that will fit in avail_out: */ - have = s->strm->avail_out - have; - left = s->strstart - s->block_start; /* bytes left in window */ - if (len > (ulg)left + s->strm->avail_in) - len = left + s->strm->avail_in; /* limit len to the input */ - if (len > have) - len = have; /* limit len to the output */ - - /* If the stored block would be less than min_block in length, or if - * unable to copy all of the available input when flushing, then try - * copying to the window and the pending buffer instead. Also don't - * write an empty block when flushing -- deflate() does that. - */ - if (len < min_block && ((len == 0 && flush != Z_FINISH) || - flush == Z_NO_FLUSH || - len != left + s->strm->avail_in)) - break; - - /* Make a dummy stored block in pending to get the header bytes, - * including any pending bits. This also updates the debugging counts. - */ - last = flush == Z_FINISH && len == left + s->strm->avail_in ? 1 : 0; - _tr_stored_block(s, (char *)0, 0L, last); - - /* Replace the lengths in the dummy stored block with len. */ - s->pending_buf[s->pending - 4] = len; - s->pending_buf[s->pending - 3] = len >> 8; - s->pending_buf[s->pending - 2] = ~len; - s->pending_buf[s->pending - 1] = ~len >> 8; - - /* Write the stored block header bytes. */ - flush_pending(s->strm); - -#ifdef ZLIB_DEBUG - /* Update debugging counts for the data about to be copied. */ - s->compressed_len += len << 3; - s->bits_sent += len << 3; -#endif - - /* Copy uncompressed bytes from the window to next_out. */ - if (left) { - if (left > len) - left = len; - zmemcpy(s->strm->next_out, s->window + s->block_start, left); - s->strm->next_out += left; - s->strm->avail_out -= left; - s->strm->total_out += left; - s->block_start += left; - len -= left; - } - - /* Copy uncompressed bytes directly from next_in to next_out, updating - * the check value. - */ - if (len) { - read_buf(s->strm, s->strm->next_out, len); - s->strm->next_out += len; - s->strm->avail_out -= len; - s->strm->total_out += len; - } - } while (last == 0); - - /* Update the sliding window with the last s->w_size bytes of the copied - * data, or append all of the copied data to the existing window if less - * than s->w_size bytes were copied. Also update the number of bytes to - * insert in the hash tables, in the event that deflateParams() switches to - * a non-zero compression level. - */ - used -= s->strm->avail_in; /* number of input bytes directly copied */ - if (used) { - /* If any input was used, then no unused input remains in the window, - * therefore s->block_start == s->strstart. - */ - if (used >= s->w_size) { /* supplant the previous history */ - s->matches = 2; /* clear hash */ - zmemcpy(s->window, s->strm->next_in - s->w_size, s->w_size); - s->strstart = s->w_size; - } - else { - if (s->window_size - s->strstart <= used) { - /* Slide the window down. */ - s->strstart -= s->w_size; - zmemcpy(s->window, s->window + s->w_size, s->strstart); - if (s->matches < 2) - s->matches++; /* add a pending slide_hash() */ - } - zmemcpy(s->window + s->strstart, s->strm->next_in - used, used); - s->strstart += used; - } - s->block_start = s->strstart; - s->insert += MIN(used, s->w_size - s->insert); - } - if (s->high_water < s->strstart) - s->high_water = s->strstart; - - /* If the last block was written to next_out, then done. */ - if (last) - return finish_done; - - /* If flushing and all input has been consumed, then done. */ - if (flush != Z_NO_FLUSH && flush != Z_FINISH && - s->strm->avail_in == 0 && (long)s->strstart == s->block_start) - return block_done; - - /* Fill the window with any remaining input. */ - have = s->window_size - s->strstart - 1; - if (s->strm->avail_in > have && s->block_start >= (long)s->w_size) { - /* Slide the window down. */ - s->block_start -= s->w_size; - s->strstart -= s->w_size; - zmemcpy(s->window, s->window + s->w_size, s->strstart); - if (s->matches < 2) - s->matches++; /* add a pending slide_hash() */ - have += s->w_size; /* more space now */ - } - if (have > s->strm->avail_in) - have = s->strm->avail_in; - if (have) { - read_buf(s->strm, s->window + s->strstart, have); - s->strstart += have; - } - if (s->high_water < s->strstart) - s->high_water = s->strstart; - - /* There was not enough avail_out to write a complete worthy or flushed - * stored block to next_out. Write a stored block to pending instead, if we - * have enough input for a worthy block, or if flushing and there is enough - * room for the remaining input as a stored block in the pending buffer. - */ - have = (s->bi_valid + 42) >> 3; /* number of header bytes */ - /* maximum stored block length that will fit in pending: */ - have = MIN(s->pending_buf_size - have, MAX_STORED); - min_block = MIN(have, s->w_size); - left = s->strstart - s->block_start; - if (left >= min_block || - ((left || flush == Z_FINISH) && flush != Z_NO_FLUSH && - s->strm->avail_in == 0 && left <= have)) { - len = MIN(left, have); - last = flush == Z_FINISH && s->strm->avail_in == 0 && - len == left ? 1 : 0; - _tr_stored_block(s, (charf *)s->window + s->block_start, len, last); - s->block_start += len; - flush_pending(s->strm); - } - - /* We've done all we can with the available input and output. */ - return last ? finish_started : need_more; -} - -/* =========================================================================== - * Compress as much as possible from the input stream, return the current - * block state. - * This function does not perform lazy evaluation of matches and inserts - * new strings in the dictionary only for unmatched strings or for short - * matches. It is used only for the fast compression options. - */ -local block_state deflate_fast(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head; /* head of the hash chain */ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = NIL; - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - * At this point we have always match_length < MIN_MATCH - */ - if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s->match_length = longest_match (s, hash_head); - /* longest_match() sets match_start */ - } - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->match_start, s->match_length); - - _tr_tally_dist(s, s->strstart - s->match_start, - s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->match_length; - - /* Insert new strings in the hash table only if the match length - * is not too large. This saves time but degrades compression. - */ -#ifndef FASTEST - if (s->match_length <= s->max_insert_length && - s->lookahead >= MIN_MATCH) { - s->match_length--; /* string at strstart already in table */ - do { - s->strstart++; - INSERT_STRING(s, s->strstart, hash_head); - /* strstart never exceeds WSIZE-MAX_MATCH, so there are - * always MIN_MATCH bytes ahead. - */ - } while (--s->match_length != 0); - s->strstart++; - } else -#endif - { - s->strstart += s->match_length; - s->match_length = 0; - s->ins_h = s->window[s->strstart]; - UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); -#if MIN_MATCH != 3 - Call UPDATE_HASH() MIN_MATCH-3 more times -#endif - /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not - * matter since it will be recomputed at next deflate call. - */ - } - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} - -#ifndef FASTEST -/* =========================================================================== - * Same as above, but achieves better compression. We use a lazy - * evaluation for matches: a match is finally adopted only if there is - * no better match at the next window position. - */ -local block_state deflate_slow(s, flush) - deflate_state *s; - int flush; -{ - IPos hash_head; /* head of hash chain */ - int bflush; /* set if current block must be flushed */ - - /* Process the input block. */ - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the next match, plus MIN_MATCH bytes to insert the - * string following the next match. - */ - if (s->lookahead < MIN_LOOKAHEAD) { - fill_window(s); - if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* Insert the string window[strstart .. strstart+2] in the - * dictionary, and set hash_head to the head of the hash chain: - */ - hash_head = NIL; - if (s->lookahead >= MIN_MATCH) { - INSERT_STRING(s, s->strstart, hash_head); - } - - /* Find the longest match, discarding those <= prev_length. - */ - s->prev_length = s->match_length, s->prev_match = s->match_start; - s->match_length = MIN_MATCH-1; - - if (hash_head != NIL && s->prev_length < s->max_lazy_match && - s->strstart - hash_head <= MAX_DIST(s)) { - /* To simplify the code, we prevent matches with the string - * of window index 0 (in particular we have to avoid a match - * of the string with itself at the start of the input file). - */ - s->match_length = longest_match (s, hash_head); - /* longest_match() sets match_start */ - - if (s->match_length <= 5 && (s->strategy == Z_FILTERED -#if TOO_FAR <= 32767 - || (s->match_length == MIN_MATCH && - s->strstart - s->match_start > TOO_FAR) -#endif - )) { - - /* If prev_match is also MIN_MATCH, match_start is garbage - * but we will ignore the current match anyway. - */ - s->match_length = MIN_MATCH-1; - } - } - /* If there was a match at the previous step and the current - * match is not better, output the previous match: - */ - if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { - uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; - /* Do not insert strings in hash table beyond this. */ - - check_match(s, s->strstart-1, s->prev_match, s->prev_length); - - _tr_tally_dist(s, s->strstart -1 - s->prev_match, - s->prev_length - MIN_MATCH, bflush); - - /* Insert in hash table all strings up to the end of the match. - * strstart-1 and strstart are already inserted. If there is not - * enough lookahead, the last two strings are not inserted in - * the hash table. - */ - s->lookahead -= s->prev_length-1; - s->prev_length -= 2; - do { - if (++s->strstart <= max_insert) { - INSERT_STRING(s, s->strstart, hash_head); - } - } while (--s->prev_length != 0); - s->match_available = 0; - s->match_length = MIN_MATCH-1; - s->strstart++; - - if (bflush) FLUSH_BLOCK(s, 0); - - } else if (s->match_available) { - /* If there was no match at the previous position, output a - * single literal. If there was a match but the current match - * is longer, truncate the previous match to a single literal. - */ - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - if (bflush) { - FLUSH_BLOCK_ONLY(s, 0); - } - s->strstart++; - s->lookahead--; - if (s->strm->avail_out == 0) return need_more; - } else { - /* There is no previous match to compare with, wait for - * the next step to decide. - */ - s->match_available = 1; - s->strstart++; - s->lookahead--; - } - } - Assert (flush != Z_NO_FLUSH, "no flush?"); - if (s->match_available) { - Tracevv((stderr,"%c", s->window[s->strstart-1])); - _tr_tally_lit(s, s->window[s->strstart-1], bflush); - s->match_available = 0; - } - s->insert = s->strstart < MIN_MATCH-1 ? s->strstart : MIN_MATCH-1; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} -#endif /* FASTEST */ - -/* =========================================================================== - * For Z_RLE, simply look for runs of bytes, generate matches only of distance - * one. Do not maintain a hash table. (It will be regenerated if this run of - * deflate switches away from Z_RLE.) - */ -local block_state deflate_rle(s, flush) - deflate_state *s; - int flush; -{ - int bflush; /* set if current block must be flushed */ - uInt prev; /* byte at distance one to match */ - Bytef *scan, *strend; /* scan goes up to strend for length of run */ - - for (;;) { - /* Make sure that we always have enough lookahead, except - * at the end of the input file. We need MAX_MATCH bytes - * for the longest run, plus one for the unrolled loop. - */ - if (s->lookahead <= MAX_MATCH) { - fill_window(s); - if (s->lookahead <= MAX_MATCH && flush == Z_NO_FLUSH) { - return need_more; - } - if (s->lookahead == 0) break; /* flush the current block */ - } - - /* See how many times the previous byte repeats */ - s->match_length = 0; - if (s->lookahead >= MIN_MATCH && s->strstart > 0) { - scan = s->window + s->strstart - 1; - prev = *scan; - if (prev == *++scan && prev == *++scan && prev == *++scan) { - strend = s->window + s->strstart + MAX_MATCH; - do { - } while (prev == *++scan && prev == *++scan && - prev == *++scan && prev == *++scan && - prev == *++scan && prev == *++scan && - prev == *++scan && prev == *++scan && - scan < strend); - s->match_length = MAX_MATCH - (uInt)(strend - scan); - if (s->match_length > s->lookahead) - s->match_length = s->lookahead; - } - Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan"); - } - - /* Emit match if have run of MIN_MATCH or longer, else emit literal */ - if (s->match_length >= MIN_MATCH) { - check_match(s, s->strstart, s->strstart - 1, s->match_length); - - _tr_tally_dist(s, 1, s->match_length - MIN_MATCH, bflush); - - s->lookahead -= s->match_length; - s->strstart += s->match_length; - s->match_length = 0; - } else { - /* No match, output a literal byte */ - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - } - if (bflush) FLUSH_BLOCK(s, 0); - } - s->insert = 0; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} - -/* =========================================================================== - * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table. - * (It will be regenerated if this run of deflate switches away from Huffman.) - */ -local block_state deflate_huff(s, flush) - deflate_state *s; - int flush; -{ - int bflush; /* set if current block must be flushed */ - - for (;;) { - /* Make sure that we have a literal to write. */ - if (s->lookahead == 0) { - fill_window(s); - if (s->lookahead == 0) { - if (flush == Z_NO_FLUSH) - return need_more; - break; /* flush the current block */ - } - } - - /* Output a literal byte */ - s->match_length = 0; - Tracevv((stderr,"%c", s->window[s->strstart])); - _tr_tally_lit (s, s->window[s->strstart], bflush); - s->lookahead--; - s->strstart++; - if (bflush) FLUSH_BLOCK(s, 0); - } - s->insert = 0; - if (flush == Z_FINISH) { - FLUSH_BLOCK(s, 1); - return finish_done; - } - if (s->last_lit) - FLUSH_BLOCK(s, 0); - return block_done; -} diff --git a/src/common/dep/zlib/deflate.h b/src/common/dep/zlib/deflate.h deleted file mode 100644 index 23ecdd312..000000000 --- a/src/common/dep/zlib/deflate.h +++ /dev/null @@ -1,349 +0,0 @@ -/* deflate.h -- internal compression state - * Copyright (C) 1995-2016 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef DEFLATE_H -#define DEFLATE_H - -#include "zutil.h" - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer creation by deflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip encoding - should be left enabled. */ -#ifndef NO_GZIP -# define GZIP -#endif - -/* =========================================================================== - * Internal compression state. - */ - -#define LENGTH_CODES 29 -/* number of length codes, not counting the special END_BLOCK code */ - -#define LITERALS 256 -/* number of literal bytes 0..255 */ - -#define L_CODES (LITERALS+1+LENGTH_CODES) -/* number of Literal or Length codes, including the END_BLOCK code */ - -#define D_CODES 30 -/* number of distance codes */ - -#define BL_CODES 19 -/* number of codes used to transfer the bit lengths */ - -#define HEAP_SIZE (2*L_CODES+1) -/* maximum heap size */ - -#define MAX_BITS 15 -/* All codes must not exceed MAX_BITS bits */ - -#define Buf_size 16 -/* size of bit buffer in bi_buf */ - -#define INIT_STATE 42 /* zlib header -> BUSY_STATE */ -#ifdef GZIP -# define GZIP_STATE 57 /* gzip header -> BUSY_STATE | EXTRA_STATE */ -#endif -#define EXTRA_STATE 69 /* gzip extra block -> NAME_STATE */ -#define NAME_STATE 73 /* gzip file name -> COMMENT_STATE */ -#define COMMENT_STATE 91 /* gzip comment -> HCRC_STATE */ -#define HCRC_STATE 103 /* gzip header CRC -> BUSY_STATE */ -#define BUSY_STATE 113 /* deflate -> FINISH_STATE */ -#define FINISH_STATE 666 /* stream complete */ -/* Stream status */ - - -/* Data structure describing a single value and its code string. */ -typedef struct ct_data_s { - union { - ush freq; /* frequency count */ - ush code; /* bit string */ - } fc; - union { - ush dad; /* father node in Huffman tree */ - ush len; /* length of bit string */ - } dl; -} FAR ct_data; - -#define Freq fc.freq -#define Code fc.code -#define Dad dl.dad -#define Len dl.len - -typedef struct static_tree_desc_s static_tree_desc; - -typedef struct tree_desc_s { - ct_data *dyn_tree; /* the dynamic tree */ - int max_code; /* largest code with non zero frequency */ - const static_tree_desc *stat_desc; /* the corresponding static tree */ -} FAR tree_desc; - -typedef ush Pos; -typedef Pos FAR Posf; -typedef unsigned IPos; - -/* A Pos is an index in the character window. We use short instead of int to - * save space in the various tables. IPos is used only for parameter passing. - */ - -typedef struct internal_state { - z_streamp strm; /* pointer back to this zlib stream */ - int status; /* as the name implies */ - Bytef *pending_buf; /* output still pending */ - ulg pending_buf_size; /* size of pending_buf */ - Bytef *pending_out; /* next pending byte to output to the stream */ - ulg pending; /* nb of bytes in the pending buffer */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip */ - gz_headerp gzhead; /* gzip header information to write */ - ulg gzindex; /* where in extra, name, or comment */ - Byte method; /* can only be DEFLATED */ - int last_flush; /* value of flush param for previous deflate call */ - - /* used by deflate.c: */ - - uInt w_size; /* LZ77 window size (32K by default) */ - uInt w_bits; /* log2(w_size) (8..16) */ - uInt w_mask; /* w_size - 1 */ - - Bytef *window; - /* Sliding window. Input bytes are read into the second half of the window, - * and move to the first half later to keep a dictionary of at least wSize - * bytes. With this organization, matches are limited to a distance of - * wSize-MAX_MATCH bytes, but this ensures that IO is always - * performed with a length multiple of the block size. Also, it limits - * the window size to 64K, which is quite useful on MSDOS. - * To do: use the user input buffer as sliding window. - */ - - ulg window_size; - /* Actual size of window: 2*wSize, except when the user input buffer - * is directly used as sliding window. - */ - - Posf *prev; - /* Link to older string with same hash index. To limit the size of this - * array to 64K, this link is maintained only for the last 32K strings. - * An index in this array is thus a window index modulo 32K. - */ - - Posf *head; /* Heads of the hash chains or NIL. */ - - uInt ins_h; /* hash index of string to be inserted */ - uInt hash_size; /* number of elements in hash table */ - uInt hash_bits; /* log2(hash_size) */ - uInt hash_mask; /* hash_size-1 */ - - uInt hash_shift; - /* Number of bits by which ins_h must be shifted at each input - * step. It must be such that after MIN_MATCH steps, the oldest - * byte no longer takes part in the hash key, that is: - * hash_shift * MIN_MATCH >= hash_bits - */ - - long block_start; - /* Window position at the beginning of the current output block. Gets - * negative when the window is moved backwards. - */ - - uInt match_length; /* length of best match */ - IPos prev_match; /* previous match */ - int match_available; /* set if previous match exists */ - uInt strstart; /* start of string to insert */ - uInt match_start; /* start of matching string */ - uInt lookahead; /* number of valid bytes ahead in window */ - - uInt prev_length; - /* Length of the best match at previous step. Matches not greater than this - * are discarded. This is used in the lazy match evaluation. - */ - - uInt max_chain_length; - /* To speed up deflation, hash chains are never searched beyond this - * length. A higher limit improves compression ratio but degrades the - * speed. - */ - - uInt max_lazy_match; - /* Attempt to find a better match only when the current match is strictly - * smaller than this value. This mechanism is used only for compression - * levels >= 4. - */ -# define max_insert_length max_lazy_match - /* Insert new strings in the hash table only if the match length is not - * greater than this length. This saves time but degrades compression. - * max_insert_length is used only for compression levels <= 3. - */ - - int level; /* compression level (1..9) */ - int strategy; /* favor or force Huffman coding*/ - - uInt good_match; - /* Use a faster search when the previous match is longer than this */ - - int nice_match; /* Stop searching when current match exceeds this */ - - /* used by trees.c: */ - /* Didn't use ct_data typedef below to suppress compiler warning */ - struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ - struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ - struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ - - struct tree_desc_s l_desc; /* desc. for literal tree */ - struct tree_desc_s d_desc; /* desc. for distance tree */ - struct tree_desc_s bl_desc; /* desc. for bit length tree */ - - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ - int heap_len; /* number of elements in the heap */ - int heap_max; /* element of largest frequency */ - /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. - * The same heap array is used to build all trees. - */ - - uch depth[2*L_CODES+1]; - /* Depth of each subtree used as tie breaker for trees of equal frequency - */ - - uchf *l_buf; /* buffer for literals or lengths */ - - uInt lit_bufsize; - /* Size of match buffer for literals/lengths. There are 4 reasons for - * limiting lit_bufsize to 64K: - * - frequencies can be kept in 16 bit counters - * - if compression is not successful for the first block, all input - * data is still in the window so we can still emit a stored block even - * when input comes from standard input. (This can also be done for - * all blocks if lit_bufsize is not greater than 32K.) - * - if compression is not successful for a file smaller than 64K, we can - * even emit a stored file instead of a stored block (saving 5 bytes). - * This is applicable only for zip (not gzip or zlib). - * - creating new Huffman trees less frequently may not provide fast - * adaptation to changes in the input data statistics. (Take for - * example a binary file with poorly compressible code followed by - * a highly compressible string table.) Smaller buffer sizes give - * fast adaptation but have of course the overhead of transmitting - * trees more frequently. - * - I can't count above 4 - */ - - uInt last_lit; /* running index in l_buf */ - - ushf *d_buf; - /* Buffer for distances. To simplify the code, d_buf and l_buf have - * the same number of elements. To use different lengths, an extra flag - * array would be necessary. - */ - - ulg opt_len; /* bit length of current block with optimal trees */ - ulg static_len; /* bit length of current block with static trees */ - uInt matches; /* number of string matches in current block */ - uInt insert; /* bytes at end of window left to insert */ - -#ifdef ZLIB_DEBUG - ulg compressed_len; /* total bit length of compressed file mod 2^32 */ - ulg bits_sent; /* bit length of compressed data sent mod 2^32 */ -#endif - - ush bi_buf; - /* Output buffer. bits are inserted starting at the bottom (least - * significant bits). - */ - int bi_valid; - /* Number of valid bits in bi_buf. All bits above the last valid bit - * are always zero. - */ - - ulg high_water; - /* High water mark offset in window for initialized bytes -- bytes above - * this are set to zero in order to avoid memory check warnings when - * longest match routines access bytes past the input. This is then - * updated to the new high water mark. - */ - -} FAR deflate_state; - -/* Output a byte on the stream. - * IN assertion: there is enough room in pending_buf. - */ -#define put_byte(s, c) {s->pending_buf[s->pending++] = (Bytef)(c);} - - -#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) -/* Minimum amount of lookahead, except at the end of the input file. - * See deflate.c for comments about the MIN_MATCH+1. - */ - -#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) -/* In order to simplify the code, particularly on 16 bit machines, match - * distances are limited to MAX_DIST instead of WSIZE. - */ - -#define WIN_INIT MAX_MATCH -/* Number of bytes after end of data in window to initialize in order to avoid - memory checker errors from longest match routines */ - - /* in trees.c */ -void ZLIB_INTERNAL _tr_init OF((deflate_state *s)); -int ZLIB_INTERNAL _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); -void ZLIB_INTERNAL _tr_flush_block OF((deflate_state *s, charf *buf, - ulg stored_len, int last)); -void ZLIB_INTERNAL _tr_flush_bits OF((deflate_state *s)); -void ZLIB_INTERNAL _tr_align OF((deflate_state *s)); -void ZLIB_INTERNAL _tr_stored_block OF((deflate_state *s, charf *buf, - ulg stored_len, int last)); - -#define d_code(dist) \ - ((dist) < 256 ? _dist_code[dist] : _dist_code[256+((dist)>>7)]) -/* Mapping from a distance to a distance code. dist is the distance - 1 and - * must not have side effects. _dist_code[256] and _dist_code[257] are never - * used. - */ - -#ifndef ZLIB_DEBUG -/* Inline versions of _tr_tally for speed: */ - -#if defined(GEN_TREES_H) || !defined(STDC) - extern uch ZLIB_INTERNAL _length_code[]; - extern uch ZLIB_INTERNAL _dist_code[]; -#else - extern const uch ZLIB_INTERNAL _length_code[]; - extern const uch ZLIB_INTERNAL _dist_code[]; -#endif - -# define _tr_tally_lit(s, c, flush) \ - { uch cc = (c); \ - s->d_buf[s->last_lit] = 0; \ - s->l_buf[s->last_lit++] = cc; \ - s->dyn_ltree[cc].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -# define _tr_tally_dist(s, distance, length, flush) \ - { uch len = (uch)(length); \ - ush dist = (ush)(distance); \ - s->d_buf[s->last_lit] = dist; \ - s->l_buf[s->last_lit++] = len; \ - dist--; \ - s->dyn_ltree[_length_code[len]+LITERALS+1].Freq++; \ - s->dyn_dtree[d_code(dist)].Freq++; \ - flush = (s->last_lit == s->lit_bufsize-1); \ - } -#else -# define _tr_tally_lit(s, c, flush) flush = _tr_tally(s, 0, c) -# define _tr_tally_dist(s, distance, length, flush) \ - flush = _tr_tally(s, distance, length) -#endif - -#endif /* DEFLATE_H */ diff --git a/src/common/dep/zlib/gzguts.h b/src/common/dep/zlib/gzguts.h deleted file mode 100644 index 990a4d251..000000000 --- a/src/common/dep/zlib/gzguts.h +++ /dev/null @@ -1,218 +0,0 @@ -/* gzguts.h -- zlib internal header definitions for gz* operations - * Copyright (C) 2004, 2005, 2010, 2011, 2012, 2013, 2016 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#ifdef _LARGEFILE64_SOURCE -# ifndef _LARGEFILE_SOURCE -# define _LARGEFILE_SOURCE 1 -# endif -# ifdef _FILE_OFFSET_BITS -# undef _FILE_OFFSET_BITS -# endif -#endif - -#ifdef HAVE_HIDDEN -# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) -#else -# define ZLIB_INTERNAL -#endif - -#include -#include "zlib.h" -#ifdef STDC -# include -# include -# include -#endif - -#ifndef _POSIX_SOURCE -# define _POSIX_SOURCE -#endif -#include - -#ifdef _WIN32 -# include -#endif - -#if defined(__TURBOC__) || defined(_MSC_VER) || defined(_WIN32) -# include -#endif - -#if defined(_WIN32) || defined(__CYGWIN__) -# define WIDECHAR -#endif - -#ifdef WINAPI_FAMILY -# define open _open -# define read _read -# define write _write -# define close _close -#endif - -#ifdef NO_DEFLATE /* for compatibility with old definition */ -# define NO_GZCOMPRESS -#endif - -#if defined(STDC99) || (defined(__TURBOC__) && __TURBOC__ >= 0x550) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif - -#if defined(__CYGWIN__) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif - -#if defined(MSDOS) && defined(__BORLANDC__) && (BORLANDC > 0x410) -# ifndef HAVE_VSNPRINTF -# define HAVE_VSNPRINTF -# endif -#endif - -#ifndef HAVE_VSNPRINTF -# ifdef MSDOS -/* vsnprintf may exist on some MS-DOS compilers (DJGPP?), - but for now we just assume it doesn't. */ -# define NO_vsnprintf -# endif -# ifdef __TURBOC__ -# define NO_vsnprintf -# endif -# ifdef WIN32 -/* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -# if !defined(vsnprintf) && !defined(NO_vsnprintf) -# if !defined(_MSC_VER) || ( defined(_MSC_VER) && _MSC_VER < 1500 ) -# define vsnprintf _vsnprintf -# endif -# endif -# endif -# ifdef __SASC -# define NO_vsnprintf -# endif -# ifdef VMS -# define NO_vsnprintf -# endif -# ifdef __OS400__ -# define NO_vsnprintf -# endif -# ifdef __MVS__ -# define NO_vsnprintf -# endif -#endif - -/* unlike snprintf (which is required in C99), _snprintf does not guarantee - null termination of the result -- however this is only used in gzlib.c where - the result is assured to fit in the space provided */ -#if defined(_MSC_VER) && _MSC_VER < 1900 -# define snprintf _snprintf -#endif - -#ifndef local -# define local static -#endif -/* since "static" is used to mean two completely different things in C, we - define "local" for the non-static meaning of "static", for readability - (compile with -Dlocal if your debugger can't find static symbols) */ - -/* gz* functions always use library allocation functions */ -#ifndef STDC - extern voidp malloc OF((uInt size)); - extern void free OF((voidpf ptr)); -#endif - -/* get errno and strerror definition */ -#if defined UNDER_CE -# include -# define zstrerror() gz_strwinerror((DWORD)GetLastError()) -#else -# ifndef NO_STRERROR -# include -# define zstrerror() strerror(errno) -# else -# define zstrerror() "stdio error (consult errno)" -# endif -#endif - -/* provide prototypes for these when building zlib without LFS */ -#if !defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); - ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); -#endif - -/* default memLevel */ -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif - -/* default i/o buffer size -- double this for output when reading (this and - twice this must be able to fit in an unsigned type) */ -#define GZBUFSIZE 8192 - -/* gzip modes, also provide a little integrity check on the passed structure */ -#define GZ_NONE 0 -#define GZ_READ 7247 -#define GZ_WRITE 31153 -#define GZ_APPEND 1 /* mode set to GZ_WRITE after the file is opened */ - -/* values for gz_state how */ -#define LOOK 0 /* look for a gzip header */ -#define COPY 1 /* copy input directly */ -#define GZIP 2 /* decompress a gzip stream */ - -/* internal gzip file state data structure */ -typedef struct { - /* exposed contents for gzgetc() macro */ - struct gzFile_s x; /* "x" for exposed */ - /* x.have: number of bytes available at x.next */ - /* x.next: next output data to deliver or write */ - /* x.pos: current position in uncompressed data */ - /* used for both reading and writing */ - int mode; /* see gzip modes above */ - int fd; /* file descriptor */ - char *path; /* path or fd for error messages */ - unsigned size; /* buffer size, zero if not allocated yet */ - unsigned want; /* requested buffer size, default is GZBUFSIZE */ - unsigned char *in; /* input buffer (double-sized when writing) */ - unsigned char *out; /* output buffer (double-sized when reading) */ - int direct; /* 0 if processing gzip, 1 if transparent */ - /* just for reading */ - int how; /* 0: get header, 1: copy, 2: decompress */ - z_off64_t start; /* where the gzip data started, for rewinding */ - int eof; /* true if end of input file reached */ - int past; /* true if read requested past end */ - /* just for writing */ - int level; /* compression level */ - int strategy; /* compression strategy */ - /* seek request */ - z_off64_t skip; /* amount to skip (already rewound if backwards) */ - int seek; /* true if seek request pending */ - /* error information */ - int err; /* error code */ - char *msg; /* error message */ - /* zlib inflate or deflate stream */ - z_stream strm; /* stream structure in-place (not a pointer) */ -} gz_state; -typedef gz_state FAR *gz_statep; - -/* shared functions */ -void ZLIB_INTERNAL gz_error OF((gz_statep, int, const char *)); -#if defined UNDER_CE -char ZLIB_INTERNAL *gz_strwinerror OF((DWORD error)); -#endif - -/* GT_OFF(x), where x is an unsigned value, is true if x > maximum z_off64_t - value -- needed when comparing unsigned to z_off64_t, which is signed - (possible z_off64_t types off_t, off64_t, and long are all signed) */ -#ifdef INT_MAX -# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > INT_MAX) -#else -unsigned ZLIB_INTERNAL gz_intmax OF((void)); -# define GT_OFF(x) (sizeof(int) == sizeof(z_off64_t) && (x) > gz_intmax()) -#endif diff --git a/src/common/dep/zlib/inffast.c b/src/common/dep/zlib/inffast.c deleted file mode 100644 index 0dbd1dbc0..000000000 --- a/src/common/dep/zlib/inffast.c +++ /dev/null @@ -1,323 +0,0 @@ -/* inffast.c -- fast decoding - * Copyright (C) 1995-2017 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifdef ASMINF -# pragma message("Assembler code may have bugs -- use at your own risk") -#else - -/* - Decode literal, length, and distance codes and write out the resulting - literal and match bytes until either not enough input or output is - available, an end-of-block is encountered, or a data error is encountered. - When large enough input and output buffers are supplied to inflate(), for - example, a 16K input buffer and a 64K output buffer, more than 95% of the - inflate execution time is spent in this routine. - - Entry assumptions: - - state->mode == LEN - strm->avail_in >= 6 - strm->avail_out >= 258 - start >= strm->avail_out - state->bits < 8 - - On return, state->mode is one of: - - LEN -- ran out of enough output space or enough available input - TYPE -- reached end of block code, inflate() to interpret next block - BAD -- error in block data - - Notes: - - - The maximum input bits used by a length/distance pair is 15 bits for the - length code, 5 bits for the length extra, 15 bits for the distance code, - and 13 bits for the distance extra. This totals 48 bits, or six bytes. - Therefore if strm->avail_in >= 6, then there is enough input to avoid - checking for available input while decoding. - - - The maximum bytes that a single length/distance pair can output is 258 - bytes, which is the maximum length that can be coded. inflate_fast() - requires strm->avail_out >= 258 for each loop to avoid checking for - output space. - */ -void ZLIB_INTERNAL inflate_fast(strm, start) -z_streamp strm; -unsigned start; /* inflate()'s starting value for strm->avail_out */ -{ - struct inflate_state FAR *state; - z_const unsigned char FAR *in; /* local strm->next_in */ - z_const unsigned char FAR *last; /* have enough input while in < last */ - unsigned char FAR *out; /* local strm->next_out */ - unsigned char FAR *beg; /* inflate()'s initial strm->next_out */ - unsigned char FAR *end; /* while out < end, enough space available */ -#ifdef INFLATE_STRICT - unsigned dmax; /* maximum distance from zlib header */ -#endif - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned wnext; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if wsize != 0 */ - unsigned long hold; /* local strm->hold */ - unsigned bits; /* local strm->bits */ - code const FAR *lcode; /* local strm->lencode */ - code const FAR *dcode; /* local strm->distcode */ - unsigned lmask; /* mask for first level of length codes */ - unsigned dmask; /* mask for first level of distance codes */ - code here; /* retrieved table entry */ - unsigned op; /* code bits, operation, extra bits, or */ - /* window position, window bytes to copy */ - unsigned len; /* match length, unused bytes */ - unsigned dist; /* match distance */ - unsigned char FAR *from; /* where to copy match from */ - - /* copy state to local variables */ - state = (struct inflate_state FAR *)strm->state; - in = strm->next_in; - last = in + (strm->avail_in - 5); - out = strm->next_out; - beg = out - (start - strm->avail_out); - end = out + (strm->avail_out - 257); -#ifdef INFLATE_STRICT - dmax = state->dmax; -#endif - wsize = state->wsize; - whave = state->whave; - wnext = state->wnext; - window = state->window; - hold = state->hold; - bits = state->bits; - lcode = state->lencode; - dcode = state->distcode; - lmask = (1U << state->lenbits) - 1; - dmask = (1U << state->distbits) - 1; - - /* decode literals and length/distances until end-of-block or not enough - input data or output space */ - do { - if (bits < 15) { - hold += (unsigned long)(*in++) << bits; - bits += 8; - hold += (unsigned long)(*in++) << bits; - bits += 8; - } - here = lcode[hold & lmask]; - dolen: - op = (unsigned)(here.bits); - hold >>= op; - bits -= op; - op = (unsigned)(here.op); - if (op == 0) { /* literal */ - Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", here.val)); - *out++ = (unsigned char)(here.val); - } - else if (op & 16) { /* length base */ - len = (unsigned)(here.val); - op &= 15; /* number of extra bits */ - if (op) { - if (bits < op) { - hold += (unsigned long)(*in++) << bits; - bits += 8; - } - len += (unsigned)hold & ((1U << op) - 1); - hold >>= op; - bits -= op; - } - Tracevv((stderr, "inflate: length %u\n", len)); - if (bits < 15) { - hold += (unsigned long)(*in++) << bits; - bits += 8; - hold += (unsigned long)(*in++) << bits; - bits += 8; - } - here = dcode[hold & dmask]; - dodist: - op = (unsigned)(here.bits); - hold >>= op; - bits -= op; - op = (unsigned)(here.op); - if (op & 16) { /* distance base */ - dist = (unsigned)(here.val); - op &= 15; /* number of extra bits */ - if (bits < op) { - hold += (unsigned long)(*in++) << bits; - bits += 8; - if (bits < op) { - hold += (unsigned long)(*in++) << bits; - bits += 8; - } - } - dist += (unsigned)hold & ((1U << op) - 1); -#ifdef INFLATE_STRICT - if (dist > dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - hold >>= op; - bits -= op; - Tracevv((stderr, "inflate: distance %u\n", dist)); - op = (unsigned)(out - beg); /* max distance in output */ - if (dist > op) { /* see if copy from window */ - op = dist - op; /* distance back in window */ - if (op > whave) { - if (state->sane) { - strm->msg = - (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - if (len <= op - whave) { - do { - *out++ = 0; - } while (--len); - continue; - } - len -= op - whave; - do { - *out++ = 0; - } while (--op > whave); - if (op == 0) { - from = out - dist; - do { - *out++ = *from++; - } while (--len); - continue; - } -#endif - } - from = window; - if (wnext == 0) { /* very common case */ - from += wsize - op; - if (op < len) { /* some from window */ - len -= op; - do { - *out++ = *from++; - } while (--op); - from = out - dist; /* rest from output */ - } - } - else if (wnext < op) { /* wrap around window */ - from += wsize + wnext - op; - op -= wnext; - if (op < len) { /* some from end of window */ - len -= op; - do { - *out++ = *from++; - } while (--op); - from = window; - if (wnext < len) { /* some from start of window */ - op = wnext; - len -= op; - do { - *out++ = *from++; - } while (--op); - from = out - dist; /* rest from output */ - } - } - } - else { /* contiguous in window */ - from += wnext - op; - if (op < len) { /* some from window */ - len -= op; - do { - *out++ = *from++; - } while (--op); - from = out - dist; /* rest from output */ - } - } - while (len > 2) { - *out++ = *from++; - *out++ = *from++; - *out++ = *from++; - len -= 3; - } - if (len) { - *out++ = *from++; - if (len > 1) - *out++ = *from++; - } - } - else { - from = out - dist; /* copy direct from output */ - do { /* minimum length is three */ - *out++ = *from++; - *out++ = *from++; - *out++ = *from++; - len -= 3; - } while (len > 2); - if (len) { - *out++ = *from++; - if (len > 1) - *out++ = *from++; - } - } - } - else if ((op & 64) == 0) { /* 2nd level distance code */ - here = dcode[here.val + (hold & ((1U << op) - 1))]; - goto dodist; - } - else { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - } - else if ((op & 64) == 0) { /* 2nd level length code */ - here = lcode[here.val + (hold & ((1U << op) - 1))]; - goto dolen; - } - else if (op & 32) { /* end-of-block */ - Tracevv((stderr, "inflate: end of block\n")); - state->mode = TYPE; - break; - } - else { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - } while (in < last && out < end); - - /* return unused bytes (on entry, bits < 8, so in won't go too far back) */ - len = bits >> 3; - in -= len; - bits -= len << 3; - hold &= (1U << bits) - 1; - - /* update state and return */ - strm->next_in = in; - strm->next_out = out; - strm->avail_in = (unsigned)(in < last ? 5 + (last - in) : 5 - (in - last)); - strm->avail_out = (unsigned)(out < end ? - 257 + (end - out) : 257 - (out - end)); - state->hold = hold; - state->bits = bits; - return; -} - -/* - inflate_fast() speedups that turned out slower (on a PowerPC G3 750CXe): - - Using bit fields for code structure - - Different op definition to avoid & for extra bits (do & for table bits) - - Three separate decoding do-loops for direct, window, and wnext == 0 - - Special case for distance > 1 copies to do overlapped load and store copy - - Explicit branch predictions (based on measured branch probabilities) - - Deferring match copy and interspersed it with decoding subsequent codes - - Swapping literal/length else - - Swapping window/direct else - - Larger unrolled copy loops (three is about right) - - Moving len -= 3 statement into middle of loop - */ - -#endif /* !ASMINF */ diff --git a/src/common/dep/zlib/inffast.h b/src/common/dep/zlib/inffast.h deleted file mode 100644 index e5c1aa4ca..000000000 --- a/src/common/dep/zlib/inffast.h +++ /dev/null @@ -1,11 +0,0 @@ -/* inffast.h -- header to use inffast.c - * Copyright (C) 1995-2003, 2010 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -void ZLIB_INTERNAL inflate_fast OF((z_streamp strm, unsigned start)); diff --git a/src/common/dep/zlib/inffixed.h b/src/common/dep/zlib/inffixed.h deleted file mode 100644 index d62832776..000000000 --- a/src/common/dep/zlib/inffixed.h +++ /dev/null @@ -1,94 +0,0 @@ - /* inffixed.h -- table for decoding fixed codes - * Generated automatically by makefixed(). - */ - - /* WARNING: this file should *not* be used by applications. - It is part of the implementation of this library and is - subject to change. Applications should only use zlib.h. - */ - - static const code lenfix[512] = { - {96,7,0},{0,8,80},{0,8,16},{20,8,115},{18,7,31},{0,8,112},{0,8,48}, - {0,9,192},{16,7,10},{0,8,96},{0,8,32},{0,9,160},{0,8,0},{0,8,128}, - {0,8,64},{0,9,224},{16,7,6},{0,8,88},{0,8,24},{0,9,144},{19,7,59}, - {0,8,120},{0,8,56},{0,9,208},{17,7,17},{0,8,104},{0,8,40},{0,9,176}, - {0,8,8},{0,8,136},{0,8,72},{0,9,240},{16,7,4},{0,8,84},{0,8,20}, - {21,8,227},{19,7,43},{0,8,116},{0,8,52},{0,9,200},{17,7,13},{0,8,100}, - {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},{16,7,8}, - {0,8,92},{0,8,28},{0,9,152},{20,7,83},{0,8,124},{0,8,60},{0,9,216}, - {18,7,23},{0,8,108},{0,8,44},{0,9,184},{0,8,12},{0,8,140},{0,8,76}, - {0,9,248},{16,7,3},{0,8,82},{0,8,18},{21,8,163},{19,7,35},{0,8,114}, - {0,8,50},{0,9,196},{17,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2}, - {0,8,130},{0,8,66},{0,9,228},{16,7,7},{0,8,90},{0,8,26},{0,9,148}, - {20,7,67},{0,8,122},{0,8,58},{0,9,212},{18,7,19},{0,8,106},{0,8,42}, - {0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},{16,7,5},{0,8,86}, - {0,8,22},{64,8,0},{19,7,51},{0,8,118},{0,8,54},{0,9,204},{17,7,15}, - {0,8,102},{0,8,38},{0,9,172},{0,8,6},{0,8,134},{0,8,70},{0,9,236}, - {16,7,9},{0,8,94},{0,8,30},{0,9,156},{20,7,99},{0,8,126},{0,8,62}, - {0,9,220},{18,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142}, - {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{21,8,131},{18,7,31}, - {0,8,113},{0,8,49},{0,9,194},{16,7,10},{0,8,97},{0,8,33},{0,9,162}, - {0,8,1},{0,8,129},{0,8,65},{0,9,226},{16,7,6},{0,8,89},{0,8,25}, - {0,9,146},{19,7,59},{0,8,121},{0,8,57},{0,9,210},{17,7,17},{0,8,105}, - {0,8,41},{0,9,178},{0,8,9},{0,8,137},{0,8,73},{0,9,242},{16,7,4}, - {0,8,85},{0,8,21},{16,8,258},{19,7,43},{0,8,117},{0,8,53},{0,9,202}, - {17,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},{0,8,69}, - {0,9,234},{16,7,8},{0,8,93},{0,8,29},{0,9,154},{20,7,83},{0,8,125}, - {0,8,61},{0,9,218},{18,7,23},{0,8,109},{0,8,45},{0,9,186},{0,8,13}, - {0,8,141},{0,8,77},{0,9,250},{16,7,3},{0,8,83},{0,8,19},{21,8,195}, - {19,7,35},{0,8,115},{0,8,51},{0,9,198},{17,7,11},{0,8,99},{0,8,35}, - {0,9,166},{0,8,3},{0,8,131},{0,8,67},{0,9,230},{16,7,7},{0,8,91}, - {0,8,27},{0,9,150},{20,7,67},{0,8,123},{0,8,59},{0,9,214},{18,7,19}, - {0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},{0,8,75},{0,9,246}, - {16,7,5},{0,8,87},{0,8,23},{64,8,0},{19,7,51},{0,8,119},{0,8,55}, - {0,9,206},{17,7,15},{0,8,103},{0,8,39},{0,9,174},{0,8,7},{0,8,135}, - {0,8,71},{0,9,238},{16,7,9},{0,8,95},{0,8,31},{0,9,158},{20,7,99}, - {0,8,127},{0,8,63},{0,9,222},{18,7,27},{0,8,111},{0,8,47},{0,9,190}, - {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},{0,8,16}, - {20,8,115},{18,7,31},{0,8,112},{0,8,48},{0,9,193},{16,7,10},{0,8,96}, - {0,8,32},{0,9,161},{0,8,0},{0,8,128},{0,8,64},{0,9,225},{16,7,6}, - {0,8,88},{0,8,24},{0,9,145},{19,7,59},{0,8,120},{0,8,56},{0,9,209}, - {17,7,17},{0,8,104},{0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72}, - {0,9,241},{16,7,4},{0,8,84},{0,8,20},{21,8,227},{19,7,43},{0,8,116}, - {0,8,52},{0,9,201},{17,7,13},{0,8,100},{0,8,36},{0,9,169},{0,8,4}, - {0,8,132},{0,8,68},{0,9,233},{16,7,8},{0,8,92},{0,8,28},{0,9,153}, - {20,7,83},{0,8,124},{0,8,60},{0,9,217},{18,7,23},{0,8,108},{0,8,44}, - {0,9,185},{0,8,12},{0,8,140},{0,8,76},{0,9,249},{16,7,3},{0,8,82}, - {0,8,18},{21,8,163},{19,7,35},{0,8,114},{0,8,50},{0,9,197},{17,7,11}, - {0,8,98},{0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229}, - {16,7,7},{0,8,90},{0,8,26},{0,9,149},{20,7,67},{0,8,122},{0,8,58}, - {0,9,213},{18,7,19},{0,8,106},{0,8,42},{0,9,181},{0,8,10},{0,8,138}, - {0,8,74},{0,9,245},{16,7,5},{0,8,86},{0,8,22},{64,8,0},{19,7,51}, - {0,8,118},{0,8,54},{0,9,205},{17,7,15},{0,8,102},{0,8,38},{0,9,173}, - {0,8,6},{0,8,134},{0,8,70},{0,9,237},{16,7,9},{0,8,94},{0,8,30}, - {0,9,157},{20,7,99},{0,8,126},{0,8,62},{0,9,221},{18,7,27},{0,8,110}, - {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},{96,7,0}, - {0,8,81},{0,8,17},{21,8,131},{18,7,31},{0,8,113},{0,8,49},{0,9,195}, - {16,7,10},{0,8,97},{0,8,33},{0,9,163},{0,8,1},{0,8,129},{0,8,65}, - {0,9,227},{16,7,6},{0,8,89},{0,8,25},{0,9,147},{19,7,59},{0,8,121}, - {0,8,57},{0,9,211},{17,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9}, - {0,8,137},{0,8,73},{0,9,243},{16,7,4},{0,8,85},{0,8,21},{16,8,258}, - {19,7,43},{0,8,117},{0,8,53},{0,9,203},{17,7,13},{0,8,101},{0,8,37}, - {0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},{16,7,8},{0,8,93}, - {0,8,29},{0,9,155},{20,7,83},{0,8,125},{0,8,61},{0,9,219},{18,7,23}, - {0,8,109},{0,8,45},{0,9,187},{0,8,13},{0,8,141},{0,8,77},{0,9,251}, - {16,7,3},{0,8,83},{0,8,19},{21,8,195},{19,7,35},{0,8,115},{0,8,51}, - {0,9,199},{17,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131}, - {0,8,67},{0,9,231},{16,7,7},{0,8,91},{0,8,27},{0,9,151},{20,7,67}, - {0,8,123},{0,8,59},{0,9,215},{18,7,19},{0,8,107},{0,8,43},{0,9,183}, - {0,8,11},{0,8,139},{0,8,75},{0,9,247},{16,7,5},{0,8,87},{0,8,23}, - {64,8,0},{19,7,51},{0,8,119},{0,8,55},{0,9,207},{17,7,15},{0,8,103}, - {0,8,39},{0,9,175},{0,8,7},{0,8,135},{0,8,71},{0,9,239},{16,7,9}, - {0,8,95},{0,8,31},{0,9,159},{20,7,99},{0,8,127},{0,8,63},{0,9,223}, - {18,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},{0,8,79}, - {0,9,255} - }; - - static const code distfix[32] = { - {16,5,1},{23,5,257},{19,5,17},{27,5,4097},{17,5,5},{25,5,1025}, - {21,5,65},{29,5,16385},{16,5,3},{24,5,513},{20,5,33},{28,5,8193}, - {18,5,9},{26,5,2049},{22,5,129},{64,5,0},{16,5,2},{23,5,385}, - {19,5,25},{27,5,6145},{17,5,7},{25,5,1537},{21,5,97},{29,5,24577}, - {16,5,4},{24,5,769},{20,5,49},{28,5,12289},{18,5,13},{26,5,3073}, - {22,5,193},{64,5,0} - }; diff --git a/src/common/dep/zlib/inflate.c b/src/common/dep/zlib/inflate.c deleted file mode 100644 index ac333e8c2..000000000 --- a/src/common/dep/zlib/inflate.c +++ /dev/null @@ -1,1561 +0,0 @@ -/* inflate.c -- zlib decompression - * Copyright (C) 1995-2016 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * Change history: - * - * 1.2.beta0 24 Nov 2002 - * - First version -- complete rewrite of inflate to simplify code, avoid - * creation of window when not needed, minimize use of window when it is - * needed, make inffast.c even faster, implement gzip decoding, and to - * improve code readability and style over the previous zlib inflate code - * - * 1.2.beta1 25 Nov 2002 - * - Use pointers for available input and output checking in inffast.c - * - Remove input and output counters in inffast.c - * - Change inffast.c entry and loop from avail_in >= 7 to >= 6 - * - Remove unnecessary second byte pull from length extra in inffast.c - * - Unroll direct copy to three copies per loop in inffast.c - * - * 1.2.beta2 4 Dec 2002 - * - Change external routine names to reduce potential conflicts - * - Correct filename to inffixed.h for fixed tables in inflate.c - * - Make hbuf[] unsigned char to match parameter type in inflate.c - * - Change strm->next_out[-state->offset] to *(strm->next_out - state->offset) - * to avoid negation problem on Alphas (64 bit) in inflate.c - * - * 1.2.beta3 22 Dec 2002 - * - Add comments on state->bits assertion in inffast.c - * - Add comments on op field in inftrees.h - * - Fix bug in reuse of allocated window after inflateReset() - * - Remove bit fields--back to byte structure for speed - * - Remove distance extra == 0 check in inflate_fast()--only helps for lengths - * - Change post-increments to pre-increments in inflate_fast(), PPC biased? - * - Add compile time option, POSTINC, to use post-increments instead (Intel?) - * - Make MATCH copy in inflate() much faster for when inflate_fast() not used - * - Use local copies of stream next and avail values, as well as local bit - * buffer and bit count in inflate()--for speed when inflate_fast() not used - * - * 1.2.beta4 1 Jan 2003 - * - Split ptr - 257 statements in inflate_table() to avoid compiler warnings - * - Move a comment on output buffer sizes from inffast.c to inflate.c - * - Add comments in inffast.c to introduce the inflate_fast() routine - * - Rearrange window copies in inflate_fast() for speed and simplification - * - Unroll last copy for window match in inflate_fast() - * - Use local copies of window variables in inflate_fast() for speed - * - Pull out common wnext == 0 case for speed in inflate_fast() - * - Make op and len in inflate_fast() unsigned for consistency - * - Add FAR to lcode and dcode declarations in inflate_fast() - * - Simplified bad distance check in inflate_fast() - * - Added inflateBackInit(), inflateBack(), and inflateBackEnd() in new - * source file infback.c to provide a call-back interface to inflate for - * programs like gzip and unzip -- uses window as output buffer to avoid - * window copying - * - * 1.2.beta5 1 Jan 2003 - * - Improved inflateBack() interface to allow the caller to provide initial - * input in strm. - * - Fixed stored blocks bug in inflateBack() - * - * 1.2.beta6 4 Jan 2003 - * - Added comments in inffast.c on effectiveness of POSTINC - * - Typecasting all around to reduce compiler warnings - * - Changed loops from while (1) or do {} while (1) to for (;;), again to - * make compilers happy - * - Changed type of window in inflateBackInit() to unsigned char * - * - * 1.2.beta7 27 Jan 2003 - * - Changed many types to unsigned or unsigned short to avoid warnings - * - Added inflateCopy() function - * - * 1.2.0 9 Mar 2003 - * - Changed inflateBack() interface to provide separate opaque descriptors - * for the in() and out() functions - * - Changed inflateBack() argument and in_func typedef to swap the length - * and buffer address return values for the input function - * - Check next_in and next_out for Z_NULL on entry to inflate() - * - * The history for versions after 1.2.0 are in ChangeLog in zlib distribution. - */ - -#include "zutil.h" -#include "inftrees.h" -#include "inflate.h" -#include "inffast.h" - -#ifdef MAKEFIXED -# ifndef BUILDFIXED -# define BUILDFIXED -# endif -#endif - -/* function prototypes */ -local int inflateStateCheck OF((z_streamp strm)); -local void fixedtables OF((struct inflate_state FAR *state)); -local int updatewindow OF((z_streamp strm, const unsigned char FAR *end, - unsigned copy)); -#ifdef BUILDFIXED - void makefixed OF((void)); -#endif -local unsigned syncsearch OF((unsigned FAR *have, const unsigned char FAR *buf, - unsigned len)); - -local int inflateStateCheck(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - if (strm == Z_NULL || - strm->zalloc == (alloc_func)0 || strm->zfree == (free_func)0) - return 1; - state = (struct inflate_state FAR *)strm->state; - if (state == Z_NULL || state->strm != strm || - state->mode < HEAD || state->mode > SYNC) - return 1; - return 0; -} - -int ZEXPORT inflateResetKeep(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - strm->total_in = strm->total_out = state->total = 0; - strm->msg = Z_NULL; - if (state->wrap) /* to support ill-conceived Java test suite */ - strm->adler = state->wrap & 1; - state->mode = HEAD; - state->last = 0; - state->havedict = 0; - state->dmax = 32768U; - state->head = Z_NULL; - state->hold = 0; - state->bits = 0; - state->lencode = state->distcode = state->next = state->codes; - state->sane = 1; - state->back = -1; - Tracev((stderr, "inflate: reset\n")); - return Z_OK; -} - -int ZEXPORT inflateReset(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - state->wsize = 0; - state->whave = 0; - state->wnext = 0; - return inflateResetKeep(strm); -} - -int ZEXPORT inflateReset2(strm, windowBits) -z_streamp strm; -int windowBits; -{ - int wrap; - struct inflate_state FAR *state; - - /* get the state */ - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* extract wrap request from windowBits parameter */ - if (windowBits < 0) { - wrap = 0; - windowBits = -windowBits; - } - else { - wrap = (windowBits >> 4) + 5; -#ifdef GUNZIP - if (windowBits < 48) - windowBits &= 15; -#endif - } - - /* set number of window bits, free window if different */ - if (windowBits && (windowBits < 8 || windowBits > 15)) - return Z_STREAM_ERROR; - if (state->window != Z_NULL && state->wbits != (unsigned)windowBits) { - ZFREE(strm, state->window); - state->window = Z_NULL; - } - - /* update state and reset the rest of it */ - state->wrap = wrap; - state->wbits = (unsigned)windowBits; - return inflateReset(strm); -} - -int ZEXPORT inflateInit2_(strm, windowBits, version, stream_size) -z_streamp strm; -int windowBits; -const char *version; -int stream_size; -{ - int ret; - struct inflate_state FAR *state; - - if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || - stream_size != (int)(sizeof(z_stream))) - return Z_VERSION_ERROR; - if (strm == Z_NULL) return Z_STREAM_ERROR; - strm->msg = Z_NULL; /* in case we return an error */ - if (strm->zalloc == (alloc_func)0) { -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zalloc = zcalloc; - strm->opaque = (voidpf)0; -#endif - } - if (strm->zfree == (free_func)0) -#ifdef Z_SOLO - return Z_STREAM_ERROR; -#else - strm->zfree = zcfree; -#endif - state = (struct inflate_state FAR *) - ZALLOC(strm, 1, sizeof(struct inflate_state)); - if (state == Z_NULL) return Z_MEM_ERROR; - Tracev((stderr, "inflate: allocated\n")); - strm->state = (struct internal_state FAR *)state; - state->strm = strm; - state->window = Z_NULL; - state->mode = HEAD; /* to pass state test in inflateReset2() */ - ret = inflateReset2(strm, windowBits); - if (ret != Z_OK) { - ZFREE(strm, state); - strm->state = Z_NULL; - } - return ret; -} - -int ZEXPORT inflateInit_(strm, version, stream_size) -z_streamp strm; -const char *version; -int stream_size; -{ - return inflateInit2_(strm, DEF_WBITS, version, stream_size); -} - -int ZEXPORT inflatePrime(strm, bits, value) -z_streamp strm; -int bits; -int value; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (bits < 0) { - state->hold = 0; - state->bits = 0; - return Z_OK; - } - if (bits > 16 || state->bits + (uInt)bits > 32) return Z_STREAM_ERROR; - value &= (1L << bits) - 1; - state->hold += (unsigned)value << state->bits; - state->bits += (uInt)bits; - return Z_OK; -} - -/* - Return state with length and distance decoding tables and index sizes set to - fixed code decoding. Normally this returns fixed tables from inffixed.h. - If BUILDFIXED is defined, then instead this routine builds the tables the - first time it's called, and returns those tables the first time and - thereafter. This reduces the size of the code by about 2K bytes, in - exchange for a little execution time. However, BUILDFIXED should not be - used for threaded applications, since the rewriting of the tables and virgin - may not be thread-safe. - */ -local void fixedtables(state) -struct inflate_state FAR *state; -{ -#ifdef BUILDFIXED - static int virgin = 1; - static code *lenfix, *distfix; - static code fixed[544]; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - unsigned sym, bits; - static code *next; - - /* literal/length table */ - sym = 0; - while (sym < 144) state->lens[sym++] = 8; - while (sym < 256) state->lens[sym++] = 9; - while (sym < 280) state->lens[sym++] = 7; - while (sym < 288) state->lens[sym++] = 8; - next = fixed; - lenfix = next; - bits = 9; - inflate_table(LENS, state->lens, 288, &(next), &(bits), state->work); - - /* distance table */ - sym = 0; - while (sym < 32) state->lens[sym++] = 5; - distfix = next; - bits = 5; - inflate_table(DISTS, state->lens, 32, &(next), &(bits), state->work); - - /* do this just once */ - virgin = 0; - } -#else /* !BUILDFIXED */ -# include "inffixed.h" -#endif /* BUILDFIXED */ - state->lencode = lenfix; - state->lenbits = 9; - state->distcode = distfix; - state->distbits = 5; -} - -#ifdef MAKEFIXED -#include - -/* - Write out the inffixed.h that is #include'd above. Defining MAKEFIXED also - defines BUILDFIXED, so the tables are built on the fly. makefixed() writes - those tables to stdout, which would be piped to inffixed.h. A small program - can simply call makefixed to do this: - - void makefixed(void); - - int main(void) - { - makefixed(); - return 0; - } - - Then that can be linked with zlib built with MAKEFIXED defined and run: - - a.out > inffixed.h - */ -void makefixed() -{ - unsigned low, size; - struct inflate_state state; - - fixedtables(&state); - puts(" /* inffixed.h -- table for decoding fixed codes"); - puts(" * Generated automatically by makefixed()."); - puts(" */"); - puts(""); - puts(" /* WARNING: this file should *not* be used by applications."); - puts(" It is part of the implementation of this library and is"); - puts(" subject to change. Applications should only use zlib.h."); - puts(" */"); - puts(""); - size = 1U << 9; - printf(" static const code lenfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 7) == 0) printf("\n "); - printf("{%u,%u,%d}", (low & 127) == 99 ? 64 : state.lencode[low].op, - state.lencode[low].bits, state.lencode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); - size = 1U << 5; - printf("\n static const code distfix[%u] = {", size); - low = 0; - for (;;) { - if ((low % 6) == 0) printf("\n "); - printf("{%u,%u,%d}", state.distcode[low].op, state.distcode[low].bits, - state.distcode[low].val); - if (++low == size) break; - putchar(','); - } - puts("\n };"); -} -#endif /* MAKEFIXED */ - -/* - Update the window with the last wsize (normally 32K) bytes written before - returning. If window does not exist yet, create it. This is only called - when a window is already in use, or when output has been written during this - inflate call, but the end of the deflate stream has not been reached yet. - It is also called to create a window for dictionary data when a dictionary - is loaded. - - Providing output buffers larger than 32K to inflate() should provide a speed - advantage, since only the last 32K of output is copied to the sliding window - upon return from inflate(), and since all distances after the first 32K of - output will fall in the output data, making match copies simpler and faster. - The advantage may be dependent on the size of the processor's data caches. - */ -local int updatewindow(strm, end, copy) -z_streamp strm; -const Bytef *end; -unsigned copy; -{ - struct inflate_state FAR *state; - unsigned dist; - - state = (struct inflate_state FAR *)strm->state; - - /* if it hasn't been done already, allocate space for the window */ - if (state->window == Z_NULL) { - state->window = (unsigned char FAR *) - ZALLOC(strm, 1U << state->wbits, - sizeof(unsigned char)); - if (state->window == Z_NULL) return 1; - } - - /* if window not in use yet, initialize */ - if (state->wsize == 0) { - state->wsize = 1U << state->wbits; - state->wnext = 0; - state->whave = 0; - } - - /* copy state->wsize or less output bytes into the circular window */ - if (copy >= state->wsize) { - zmemcpy(state->window, end - state->wsize, state->wsize); - state->wnext = 0; - state->whave = state->wsize; - } - else { - dist = state->wsize - state->wnext; - if (dist > copy) dist = copy; - zmemcpy(state->window + state->wnext, end - copy, dist); - copy -= dist; - if (copy) { - zmemcpy(state->window, end - copy, copy); - state->wnext = copy; - state->whave = state->wsize; - } - else { - state->wnext += dist; - if (state->wnext == state->wsize) state->wnext = 0; - if (state->whave < state->wsize) state->whave += dist; - } - } - return 0; -} - -/* Macros for inflate(): */ - -/* check function to use adler32() for zlib or crc32() for gzip */ -#ifdef GUNZIP -# define UPDATE(check, buf, len) \ - (state->flags ? crc32(check, buf, len) : adler32(check, buf, len)) -#else -# define UPDATE(check, buf, len) adler32(check, buf, len) -#endif - -/* check macros for header crc */ -#ifdef GUNZIP -# define CRC2(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - check = crc32(check, hbuf, 2); \ - } while (0) - -# define CRC4(check, word) \ - do { \ - hbuf[0] = (unsigned char)(word); \ - hbuf[1] = (unsigned char)((word) >> 8); \ - hbuf[2] = (unsigned char)((word) >> 16); \ - hbuf[3] = (unsigned char)((word) >> 24); \ - check = crc32(check, hbuf, 4); \ - } while (0) -#endif - -/* Load registers with state in inflate() for speed */ -#define LOAD() \ - do { \ - put = strm->next_out; \ - left = strm->avail_out; \ - next = strm->next_in; \ - have = strm->avail_in; \ - hold = state->hold; \ - bits = state->bits; \ - } while (0) - -/* Restore state from registers in inflate() */ -#define RESTORE() \ - do { \ - strm->next_out = put; \ - strm->avail_out = left; \ - strm->next_in = next; \ - strm->avail_in = have; \ - state->hold = hold; \ - state->bits = bits; \ - } while (0) - -/* Clear the input bit accumulator */ -#define INITBITS() \ - do { \ - hold = 0; \ - bits = 0; \ - } while (0) - -/* Get a byte of input into the bit accumulator, or return from inflate() - if there is no input available. */ -#define PULLBYTE() \ - do { \ - if (have == 0) goto inf_leave; \ - have--; \ - hold += (unsigned long)(*next++) << bits; \ - bits += 8; \ - } while (0) - -/* Assure that there are at least n bits in the bit accumulator. If there is - not enough available input to do that, then return from inflate(). */ -#define NEEDBITS(n) \ - do { \ - while (bits < (unsigned)(n)) \ - PULLBYTE(); \ - } while (0) - -/* Return the low n bits of the bit accumulator (n < 16) */ -#define BITS(n) \ - ((unsigned)hold & ((1U << (n)) - 1)) - -/* Remove n bits from the bit accumulator */ -#define DROPBITS(n) \ - do { \ - hold >>= (n); \ - bits -= (unsigned)(n); \ - } while (0) - -/* Remove zero to seven bits as needed to go to a byte boundary */ -#define BYTEBITS() \ - do { \ - hold >>= bits & 7; \ - bits -= bits & 7; \ - } while (0) - -/* - inflate() uses a state machine to process as much input data and generate as - much output data as possible before returning. The state machine is - structured roughly as follows: - - for (;;) switch (state) { - ... - case STATEn: - if (not enough input data or output space to make progress) - return; - ... make progress ... - state = STATEm; - break; - ... - } - - so when inflate() is called again, the same case is attempted again, and - if the appropriate resources are provided, the machine proceeds to the - next state. The NEEDBITS() macro is usually the way the state evaluates - whether it can proceed or should return. NEEDBITS() does the return if - the requested bits are not available. The typical use of the BITS macros - is: - - NEEDBITS(n); - ... do something with BITS(n) ... - DROPBITS(n); - - where NEEDBITS(n) either returns from inflate() if there isn't enough - input left to load n bits into the accumulator, or it continues. BITS(n) - gives the low n bits in the accumulator. When done, DROPBITS(n) drops - the low n bits off the accumulator. INITBITS() clears the accumulator - and sets the number of available bits to zero. BYTEBITS() discards just - enough bits to put the accumulator on a byte boundary. After BYTEBITS() - and a NEEDBITS(8), then BITS(8) would return the next byte in the stream. - - NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return - if there is no input available. The decoding of variable length codes uses - PULLBYTE() directly in order to pull just enough bytes to decode the next - code, and no more. - - Some states loop until they get enough input, making sure that enough - state information is maintained to continue the loop where it left off - if NEEDBITS() returns in the loop. For example, want, need, and keep - would all have to actually be part of the saved state in case NEEDBITS() - returns: - - case STATEw: - while (want < need) { - NEEDBITS(n); - keep[want++] = BITS(n); - DROPBITS(n); - } - state = STATEx; - case STATEx: - - As shown above, if the next state is also the next case, then the break - is omitted. - - A state may also return if there is not enough output space available to - complete that state. Those states are copying stored data, writing a - literal byte, and copying a matching string. - - When returning, a "goto inf_leave" is used to update the total counters, - update the check value, and determine whether any progress has been made - during that inflate() call in order to return the proper return code. - Progress is defined as a change in either strm->avail_in or strm->avail_out. - When there is a window, goto inf_leave will update the window with the last - output written. If a goto inf_leave occurs in the middle of decompression - and there is no window currently, goto inf_leave will create one and copy - output to the window for the next call of inflate(). - - In this implementation, the flush parameter of inflate() only affects the - return code (per zlib.h). inflate() always writes as much as possible to - strm->next_out, given the space available and the provided input--the effect - documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers - the allocation of and copying into a sliding window until necessary, which - provides the effect documented in zlib.h for Z_FINISH when the entire input - stream available. So the only thing the flush parameter actually does is: - when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it - will return Z_BUF_ERROR if it has not reached the end of the stream. - */ - -int ZEXPORT inflate(strm, flush) -z_streamp strm; -int flush; -{ - struct inflate_state FAR *state; - z_const unsigned char FAR *next; /* next input */ - unsigned char FAR *put; /* next output */ - unsigned have, left; /* available input and output */ - unsigned long hold; /* bit buffer */ - unsigned bits; /* bits in bit buffer */ - unsigned in, out; /* save starting available input and output */ - unsigned copy; /* number of stored or match bytes to copy */ - unsigned char FAR *from; /* where to copy match bytes from */ - code here; /* current decoding table entry */ - code last; /* parent table entry */ - unsigned len; /* length to copy for repeats, bits to drop */ - int ret; /* return code */ -#ifdef GUNZIP - unsigned char hbuf[4]; /* buffer for gzip header crc calculation */ -#endif - static const unsigned short order[19] = /* permutation of code lengths */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - if (inflateStateCheck(strm) || strm->next_out == Z_NULL || - (strm->next_in == Z_NULL && strm->avail_in != 0)) - return Z_STREAM_ERROR; - - state = (struct inflate_state FAR *)strm->state; - if (state->mode == TYPE) state->mode = TYPEDO; /* skip check */ - LOAD(); - in = have; - out = left; - ret = Z_OK; - for (;;) - switch (state->mode) { - case HEAD: - if (state->wrap == 0) { - state->mode = TYPEDO; - break; - } - NEEDBITS(16); -#ifdef GUNZIP - if ((state->wrap & 2) && hold == 0x8b1f) { /* gzip header */ - if (state->wbits == 0) - state->wbits = 15; - state->check = crc32(0L, Z_NULL, 0); - CRC2(state->check, hold); - INITBITS(); - state->mode = FLAGS; - break; - } - state->flags = 0; /* expect zlib header */ - if (state->head != Z_NULL) - state->head->done = -1; - if (!(state->wrap & 1) || /* check if zlib header allowed */ -#else - if ( -#endif - ((BITS(8) << 8) + (hold >> 8)) % 31) { - strm->msg = (char *)"incorrect header check"; - state->mode = BAD; - break; - } - if (BITS(4) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - DROPBITS(4); - len = BITS(4) + 8; - if (state->wbits == 0) - state->wbits = len; - if (len > 15 || len > state->wbits) { - strm->msg = (char *)"invalid window size"; - state->mode = BAD; - break; - } - state->dmax = 1U << len; - Tracev((stderr, "inflate: zlib header ok\n")); - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = hold & 0x200 ? DICTID : TYPE; - INITBITS(); - break; -#ifdef GUNZIP - case FLAGS: - NEEDBITS(16); - state->flags = (int)(hold); - if ((state->flags & 0xff) != Z_DEFLATED) { - strm->msg = (char *)"unknown compression method"; - state->mode = BAD; - break; - } - if (state->flags & 0xe000) { - strm->msg = (char *)"unknown header flags set"; - state->mode = BAD; - break; - } - if (state->head != Z_NULL) - state->head->text = (int)((hold >> 8) & 1); - if ((state->flags & 0x0200) && (state->wrap & 4)) - CRC2(state->check, hold); - INITBITS(); - state->mode = TIME; - case TIME: - NEEDBITS(32); - if (state->head != Z_NULL) - state->head->time = hold; - if ((state->flags & 0x0200) && (state->wrap & 4)) - CRC4(state->check, hold); - INITBITS(); - state->mode = OS; - case OS: - NEEDBITS(16); - if (state->head != Z_NULL) { - state->head->xflags = (int)(hold & 0xff); - state->head->os = (int)(hold >> 8); - } - if ((state->flags & 0x0200) && (state->wrap & 4)) - CRC2(state->check, hold); - INITBITS(); - state->mode = EXLEN; - case EXLEN: - if (state->flags & 0x0400) { - NEEDBITS(16); - state->length = (unsigned)(hold); - if (state->head != Z_NULL) - state->head->extra_len = (unsigned)hold; - if ((state->flags & 0x0200) && (state->wrap & 4)) - CRC2(state->check, hold); - INITBITS(); - } - else if (state->head != Z_NULL) - state->head->extra = Z_NULL; - state->mode = EXTRA; - case EXTRA: - if (state->flags & 0x0400) { - copy = state->length; - if (copy > have) copy = have; - if (copy) { - if (state->head != Z_NULL && - state->head->extra != Z_NULL) { - len = state->head->extra_len - state->length; - zmemcpy(state->head->extra + len, next, - len + copy > state->head->extra_max ? - state->head->extra_max - len : copy); - } - if ((state->flags & 0x0200) && (state->wrap & 4)) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - state->length -= copy; - } - if (state->length) goto inf_leave; - } - state->length = 0; - state->mode = NAME; - case NAME: - if (state->flags & 0x0800) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->name != Z_NULL && - state->length < state->head->name_max) - state->head->name[state->length++] = (Bytef)len; - } while (len && copy < have); - if ((state->flags & 0x0200) && (state->wrap & 4)) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->name = Z_NULL; - state->length = 0; - state->mode = COMMENT; - case COMMENT: - if (state->flags & 0x1000) { - if (have == 0) goto inf_leave; - copy = 0; - do { - len = (unsigned)(next[copy++]); - if (state->head != Z_NULL && - state->head->comment != Z_NULL && - state->length < state->head->comm_max) - state->head->comment[state->length++] = (Bytef)len; - } while (len && copy < have); - if ((state->flags & 0x0200) && (state->wrap & 4)) - state->check = crc32(state->check, next, copy); - have -= copy; - next += copy; - if (len) goto inf_leave; - } - else if (state->head != Z_NULL) - state->head->comment = Z_NULL; - state->mode = HCRC; - case HCRC: - if (state->flags & 0x0200) { - NEEDBITS(16); - if ((state->wrap & 4) && hold != (state->check & 0xffff)) { - strm->msg = (char *)"header crc mismatch"; - state->mode = BAD; - break; - } - INITBITS(); - } - if (state->head != Z_NULL) { - state->head->hcrc = (int)((state->flags >> 9) & 1); - state->head->done = 1; - } - strm->adler = state->check = crc32(0L, Z_NULL, 0); - state->mode = TYPE; - break; -#endif - case DICTID: - NEEDBITS(32); - strm->adler = state->check = ZSWAP32(hold); - INITBITS(); - state->mode = DICT; - case DICT: - if (state->havedict == 0) { - RESTORE(); - return Z_NEED_DICT; - } - strm->adler = state->check = adler32(0L, Z_NULL, 0); - state->mode = TYPE; - case TYPE: - if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave; - case TYPEDO: - if (state->last) { - BYTEBITS(); - state->mode = CHECK; - break; - } - NEEDBITS(3); - state->last = BITS(1); - DROPBITS(1); - switch (BITS(2)) { - case 0: /* stored block */ - Tracev((stderr, "inflate: stored block%s\n", - state->last ? " (last)" : "")); - state->mode = STORED; - break; - case 1: /* fixed block */ - fixedtables(state); - Tracev((stderr, "inflate: fixed codes block%s\n", - state->last ? " (last)" : "")); - state->mode = LEN_; /* decode codes */ - if (flush == Z_TREES) { - DROPBITS(2); - goto inf_leave; - } - break; - case 2: /* dynamic block */ - Tracev((stderr, "inflate: dynamic codes block%s\n", - state->last ? " (last)" : "")); - state->mode = TABLE; - break; - case 3: - strm->msg = (char *)"invalid block type"; - state->mode = BAD; - } - DROPBITS(2); - break; - case STORED: - BYTEBITS(); /* go to byte boundary */ - NEEDBITS(32); - if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) { - strm->msg = (char *)"invalid stored block lengths"; - state->mode = BAD; - break; - } - state->length = (unsigned)hold & 0xffff; - Tracev((stderr, "inflate: stored length %u\n", - state->length)); - INITBITS(); - state->mode = COPY_; - if (flush == Z_TREES) goto inf_leave; - case COPY_: - state->mode = COPY; - case COPY: - copy = state->length; - if (copy) { - if (copy > have) copy = have; - if (copy > left) copy = left; - if (copy == 0) goto inf_leave; - zmemcpy(put, next, copy); - have -= copy; - next += copy; - left -= copy; - put += copy; - state->length -= copy; - break; - } - Tracev((stderr, "inflate: stored end\n")); - state->mode = TYPE; - break; - case TABLE: - NEEDBITS(14); - state->nlen = BITS(5) + 257; - DROPBITS(5); - state->ndist = BITS(5) + 1; - DROPBITS(5); - state->ncode = BITS(4) + 4; - DROPBITS(4); -#ifndef PKZIP_BUG_WORKAROUND - if (state->nlen > 286 || state->ndist > 30) { - strm->msg = (char *)"too many length or distance symbols"; - state->mode = BAD; - break; - } -#endif - Tracev((stderr, "inflate: table sizes ok\n")); - state->have = 0; - state->mode = LENLENS; - case LENLENS: - while (state->have < state->ncode) { - NEEDBITS(3); - state->lens[order[state->have++]] = (unsigned short)BITS(3); - DROPBITS(3); - } - while (state->have < 19) - state->lens[order[state->have++]] = 0; - state->next = state->codes; - state->lencode = (const code FAR *)(state->next); - state->lenbits = 7; - ret = inflate_table(CODES, state->lens, 19, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid code lengths set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: code lengths ok\n")); - state->have = 0; - state->mode = CODELENS; - case CODELENS: - while (state->have < state->nlen + state->ndist) { - for (;;) { - here = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if (here.val < 16) { - DROPBITS(here.bits); - state->lens[state->have++] = here.val; - } - else { - if (here.val == 16) { - NEEDBITS(here.bits + 2); - DROPBITS(here.bits); - if (state->have == 0) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - len = state->lens[state->have - 1]; - copy = 3 + BITS(2); - DROPBITS(2); - } - else if (here.val == 17) { - NEEDBITS(here.bits + 3); - DROPBITS(here.bits); - len = 0; - copy = 3 + BITS(3); - DROPBITS(3); - } - else { - NEEDBITS(here.bits + 7); - DROPBITS(here.bits); - len = 0; - copy = 11 + BITS(7); - DROPBITS(7); - } - if (state->have + copy > state->nlen + state->ndist) { - strm->msg = (char *)"invalid bit length repeat"; - state->mode = BAD; - break; - } - while (copy--) - state->lens[state->have++] = (unsigned short)len; - } - } - - /* handle error breaks in while */ - if (state->mode == BAD) break; - - /* check for end-of-block code (better have one) */ - if (state->lens[256] == 0) { - strm->msg = (char *)"invalid code -- missing end-of-block"; - state->mode = BAD; - break; - } - - /* build code tables -- note: do not change the lenbits or distbits - values here (9 and 6) without reading the comments in inftrees.h - concerning the ENOUGH constants, which depend on those values */ - state->next = state->codes; - state->lencode = (const code FAR *)(state->next); - state->lenbits = 9; - ret = inflate_table(LENS, state->lens, state->nlen, &(state->next), - &(state->lenbits), state->work); - if (ret) { - strm->msg = (char *)"invalid literal/lengths set"; - state->mode = BAD; - break; - } - state->distcode = (const code FAR *)(state->next); - state->distbits = 6; - ret = inflate_table(DISTS, state->lens + state->nlen, state->ndist, - &(state->next), &(state->distbits), state->work); - if (ret) { - strm->msg = (char *)"invalid distances set"; - state->mode = BAD; - break; - } - Tracev((stderr, "inflate: codes ok\n")); - state->mode = LEN_; - if (flush == Z_TREES) goto inf_leave; - case LEN_: - state->mode = LEN; - case LEN: - if (have >= 6 && left >= 258) { - RESTORE(); - inflate_fast(strm, out); - LOAD(); - if (state->mode == TYPE) - state->back = -1; - break; - } - state->back = 0; - for (;;) { - here = state->lencode[BITS(state->lenbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if (here.op && (here.op & 0xf0) == 0) { - last = here; - for (;;) { - here = state->lencode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + here.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - state->back += last.bits; - } - DROPBITS(here.bits); - state->back += here.bits; - state->length = (unsigned)here.val; - if ((int)(here.op) == 0) { - Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ? - "inflate: literal '%c'\n" : - "inflate: literal 0x%02x\n", here.val)); - state->mode = LIT; - break; - } - if (here.op & 32) { - Tracevv((stderr, "inflate: end of block\n")); - state->back = -1; - state->mode = TYPE; - break; - } - if (here.op & 64) { - strm->msg = (char *)"invalid literal/length code"; - state->mode = BAD; - break; - } - state->extra = (unsigned)(here.op) & 15; - state->mode = LENEXT; - case LENEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->length += BITS(state->extra); - DROPBITS(state->extra); - state->back += state->extra; - } - Tracevv((stderr, "inflate: length %u\n", state->length)); - state->was = state->length; - state->mode = DIST; - case DIST: - for (;;) { - here = state->distcode[BITS(state->distbits)]; - if ((unsigned)(here.bits) <= bits) break; - PULLBYTE(); - } - if ((here.op & 0xf0) == 0) { - last = here; - for (;;) { - here = state->distcode[last.val + - (BITS(last.bits + last.op) >> last.bits)]; - if ((unsigned)(last.bits + here.bits) <= bits) break; - PULLBYTE(); - } - DROPBITS(last.bits); - state->back += last.bits; - } - DROPBITS(here.bits); - state->back += here.bits; - if (here.op & 64) { - strm->msg = (char *)"invalid distance code"; - state->mode = BAD; - break; - } - state->offset = (unsigned)here.val; - state->extra = (unsigned)(here.op) & 15; - state->mode = DISTEXT; - case DISTEXT: - if (state->extra) { - NEEDBITS(state->extra); - state->offset += BITS(state->extra); - DROPBITS(state->extra); - state->back += state->extra; - } -#ifdef INFLATE_STRICT - if (state->offset > state->dmax) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#endif - Tracevv((stderr, "inflate: distance %u\n", state->offset)); - state->mode = MATCH; - case MATCH: - if (left == 0) goto inf_leave; - copy = out - left; - if (state->offset > copy) { /* copy from window */ - copy = state->offset - copy; - if (copy > state->whave) { - if (state->sane) { - strm->msg = (char *)"invalid distance too far back"; - state->mode = BAD; - break; - } -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - Trace((stderr, "inflate.c too far\n")); - copy -= state->whave; - if (copy > state->length) copy = state->length; - if (copy > left) copy = left; - left -= copy; - state->length -= copy; - do { - *put++ = 0; - } while (--copy); - if (state->length == 0) state->mode = LEN; - break; -#endif - } - if (copy > state->wnext) { - copy -= state->wnext; - from = state->window + (state->wsize - copy); - } - else - from = state->window + (state->wnext - copy); - if (copy > state->length) copy = state->length; - } - else { /* copy from output */ - from = put - state->offset; - copy = state->length; - } - if (copy > left) copy = left; - left -= copy; - state->length -= copy; - do { - *put++ = *from++; - } while (--copy); - if (state->length == 0) state->mode = LEN; - break; - case LIT: - if (left == 0) goto inf_leave; - *put++ = (unsigned char)(state->length); - left--; - state->mode = LEN; - break; - case CHECK: - if (state->wrap) { - NEEDBITS(32); - out -= left; - strm->total_out += out; - state->total += out; - if ((state->wrap & 4) && out) - strm->adler = state->check = - UPDATE(state->check, put - out, out); - out = left; - if ((state->wrap & 4) && ( -#ifdef GUNZIP - state->flags ? hold : -#endif - ZSWAP32(hold)) != state->check) { - strm->msg = (char *)"incorrect data check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: check matches trailer\n")); - } -#ifdef GUNZIP - state->mode = LENGTH; - case LENGTH: - if (state->wrap && state->flags) { - NEEDBITS(32); - if (hold != (state->total & 0xffffffffUL)) { - strm->msg = (char *)"incorrect length check"; - state->mode = BAD; - break; - } - INITBITS(); - Tracev((stderr, "inflate: length matches trailer\n")); - } -#endif - state->mode = DONE; - case DONE: - ret = Z_STREAM_END; - goto inf_leave; - case BAD: - ret = Z_DATA_ERROR; - goto inf_leave; - case MEM: - return Z_MEM_ERROR; - case SYNC: - default: - return Z_STREAM_ERROR; - } - - /* - Return from inflate(), updating the total counts and the check value. - If there was no progress during the inflate() call, return a buffer - error. Call updatewindow() to create and/or update the window state. - Note: a memory error from inflate() is non-recoverable. - */ - inf_leave: - RESTORE(); - if (state->wsize || (out != strm->avail_out && state->mode < BAD && - (state->mode < CHECK || flush != Z_FINISH))) - if (updatewindow(strm, strm->next_out, out - strm->avail_out)) { - state->mode = MEM; - return Z_MEM_ERROR; - } - in -= strm->avail_in; - out -= strm->avail_out; - strm->total_in += in; - strm->total_out += out; - state->total += out; - if ((state->wrap & 4) && out) - strm->adler = state->check = - UPDATE(state->check, strm->next_out - out, out); - strm->data_type = (int)state->bits + (state->last ? 64 : 0) + - (state->mode == TYPE ? 128 : 0) + - (state->mode == LEN_ || state->mode == COPY_ ? 256 : 0); - if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK) - ret = Z_BUF_ERROR; - return ret; -} - -int ZEXPORT inflateEnd(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - if (inflateStateCheck(strm)) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->window != Z_NULL) ZFREE(strm, state->window); - ZFREE(strm, strm->state); - strm->state = Z_NULL; - Tracev((stderr, "inflate: end\n")); - return Z_OK; -} - -int ZEXPORT inflateGetDictionary(strm, dictionary, dictLength) -z_streamp strm; -Bytef *dictionary; -uInt *dictLength; -{ - struct inflate_state FAR *state; - - /* check state */ - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - - /* copy dictionary */ - if (state->whave && dictionary != Z_NULL) { - zmemcpy(dictionary, state->window + state->wnext, - state->whave - state->wnext); - zmemcpy(dictionary + state->whave - state->wnext, - state->window, state->wnext); - } - if (dictLength != Z_NULL) - *dictLength = state->whave; - return Z_OK; -} - -int ZEXPORT inflateSetDictionary(strm, dictionary, dictLength) -z_streamp strm; -const Bytef *dictionary; -uInt dictLength; -{ - struct inflate_state FAR *state; - unsigned long dictid; - int ret; - - /* check state */ - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (state->wrap != 0 && state->mode != DICT) - return Z_STREAM_ERROR; - - /* check for correct dictionary identifier */ - if (state->mode == DICT) { - dictid = adler32(0L, Z_NULL, 0); - dictid = adler32(dictid, dictionary, dictLength); - if (dictid != state->check) - return Z_DATA_ERROR; - } - - /* copy dictionary to window using updatewindow(), which will amend the - existing dictionary if appropriate */ - ret = updatewindow(strm, dictionary + dictLength, dictLength); - if (ret) { - state->mode = MEM; - return Z_MEM_ERROR; - } - state->havedict = 1; - Tracev((stderr, "inflate: dictionary set\n")); - return Z_OK; -} - -int ZEXPORT inflateGetHeader(strm, head) -z_streamp strm; -gz_headerp head; -{ - struct inflate_state FAR *state; - - /* check state */ - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if ((state->wrap & 2) == 0) return Z_STREAM_ERROR; - - /* save header structure */ - state->head = head; - head->done = 0; - return Z_OK; -} - -/* - Search buf[0..len-1] for the pattern: 0, 0, 0xff, 0xff. Return when found - or when out of input. When called, *have is the number of pattern bytes - found in order so far, in 0..3. On return *have is updated to the new - state. If on return *have equals four, then the pattern was found and the - return value is how many bytes were read including the last byte of the - pattern. If *have is less than four, then the pattern has not been found - yet and the return value is len. In the latter case, syncsearch() can be - called again with more data and the *have state. *have is initialized to - zero for the first call. - */ -local unsigned syncsearch(have, buf, len) -unsigned FAR *have; -const unsigned char FAR *buf; -unsigned len; -{ - unsigned got; - unsigned next; - - got = *have; - next = 0; - while (next < len && got < 4) { - if ((int)(buf[next]) == (got < 2 ? 0 : 0xff)) - got++; - else if (buf[next]) - got = 0; - else - got = 4 - got; - next++; - } - *have = got; - return next; -} - -int ZEXPORT inflateSync(strm) -z_streamp strm; -{ - unsigned len; /* number of bytes to look at or looked at */ - unsigned long in, out; /* temporary to save total_in and total_out */ - unsigned char buf[4]; /* to restore bit buffer to byte string */ - struct inflate_state FAR *state; - - /* check parameters */ - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (strm->avail_in == 0 && state->bits < 8) return Z_BUF_ERROR; - - /* if first time, start search in bit buffer */ - if (state->mode != SYNC) { - state->mode = SYNC; - state->hold <<= state->bits & 7; - state->bits -= state->bits & 7; - len = 0; - while (state->bits >= 8) { - buf[len++] = (unsigned char)(state->hold); - state->hold >>= 8; - state->bits -= 8; - } - state->have = 0; - syncsearch(&(state->have), buf, len); - } - - /* search available input */ - len = syncsearch(&(state->have), strm->next_in, strm->avail_in); - strm->avail_in -= len; - strm->next_in += len; - strm->total_in += len; - - /* return no joy or set up to restart inflate() on a new block */ - if (state->have != 4) return Z_DATA_ERROR; - in = strm->total_in; out = strm->total_out; - inflateReset(strm); - strm->total_in = in; strm->total_out = out; - state->mode = TYPE; - return Z_OK; -} - -/* - Returns true if inflate is currently at the end of a block generated by - Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP - implementation to provide an additional safety check. PPP uses - Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored - block. When decompressing, PPP checks that at the end of input packet, - inflate is waiting for these length bytes. - */ -int ZEXPORT inflateSyncPoint(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - return state->mode == STORED && state->bits == 0; -} - -int ZEXPORT inflateCopy(dest, source) -z_streamp dest; -z_streamp source; -{ - struct inflate_state FAR *state; - struct inflate_state FAR *copy; - unsigned char FAR *window; - unsigned wsize; - - /* check input */ - if (inflateStateCheck(source) || dest == Z_NULL) - return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)source->state; - - /* allocate space */ - copy = (struct inflate_state FAR *) - ZALLOC(source, 1, sizeof(struct inflate_state)); - if (copy == Z_NULL) return Z_MEM_ERROR; - window = Z_NULL; - if (state->window != Z_NULL) { - window = (unsigned char FAR *) - ZALLOC(source, 1U << state->wbits, sizeof(unsigned char)); - if (window == Z_NULL) { - ZFREE(source, copy); - return Z_MEM_ERROR; - } - } - - /* copy state */ - zmemcpy((voidpf)dest, (voidpf)source, sizeof(z_stream)); - zmemcpy((voidpf)copy, (voidpf)state, sizeof(struct inflate_state)); - copy->strm = dest; - if (state->lencode >= state->codes && - state->lencode <= state->codes + ENOUGH - 1) { - copy->lencode = copy->codes + (state->lencode - state->codes); - copy->distcode = copy->codes + (state->distcode - state->codes); - } - copy->next = copy->codes + (state->next - state->codes); - if (window != Z_NULL) { - wsize = 1U << state->wbits; - zmemcpy(window, state->window, wsize); - } - copy->window = window; - dest->state = (struct internal_state FAR *)copy; - return Z_OK; -} - -int ZEXPORT inflateUndermine(strm, subvert) -z_streamp strm; -int subvert; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - state->sane = !subvert; - return Z_OK; -#else - (void)subvert; - state->sane = 1; - return Z_DATA_ERROR; -#endif -} - -int ZEXPORT inflateValidate(strm, check) -z_streamp strm; -int check; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) return Z_STREAM_ERROR; - state = (struct inflate_state FAR *)strm->state; - if (check) - state->wrap |= 4; - else - state->wrap &= ~4; - return Z_OK; -} - -long ZEXPORT inflateMark(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - - if (inflateStateCheck(strm)) - return -(1L << 16); - state = (struct inflate_state FAR *)strm->state; - return (long)(((unsigned long)((long)state->back)) << 16) + - (state->mode == COPY ? state->length : - (state->mode == MATCH ? state->was - state->length : 0)); -} - -unsigned long ZEXPORT inflateCodesUsed(strm) -z_streamp strm; -{ - struct inflate_state FAR *state; - if (inflateStateCheck(strm)) return (unsigned long)-1; - state = (struct inflate_state FAR *)strm->state; - return (unsigned long)(state->next - state->codes); -} diff --git a/src/common/dep/zlib/inflate.h b/src/common/dep/zlib/inflate.h deleted file mode 100644 index a46cce6b6..000000000 --- a/src/common/dep/zlib/inflate.h +++ /dev/null @@ -1,125 +0,0 @@ -/* inflate.h -- internal inflate state definition - * Copyright (C) 1995-2016 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* define NO_GZIP when compiling if you want to disable gzip header and - trailer decoding by inflate(). NO_GZIP would be used to avoid linking in - the crc code when it is not needed. For shared libraries, gzip decoding - should be left enabled. */ -#ifndef NO_GZIP -# define GUNZIP -#endif - -/* Possible inflate modes between inflate() calls */ -typedef enum { - HEAD = 16180, /* i: waiting for magic header */ - FLAGS, /* i: waiting for method and flags (gzip) */ - TIME, /* i: waiting for modification time (gzip) */ - OS, /* i: waiting for extra flags and operating system (gzip) */ - EXLEN, /* i: waiting for extra length (gzip) */ - EXTRA, /* i: waiting for extra bytes (gzip) */ - NAME, /* i: waiting for end of file name (gzip) */ - COMMENT, /* i: waiting for end of comment (gzip) */ - HCRC, /* i: waiting for header crc (gzip) */ - DICTID, /* i: waiting for dictionary check value */ - DICT, /* waiting for inflateSetDictionary() call */ - TYPE, /* i: waiting for type bits, including last-flag bit */ - TYPEDO, /* i: same, but skip check to exit inflate on new block */ - STORED, /* i: waiting for stored size (length and complement) */ - COPY_, /* i/o: same as COPY below, but only first time in */ - COPY, /* i/o: waiting for input or output to copy stored block */ - TABLE, /* i: waiting for dynamic block table lengths */ - LENLENS, /* i: waiting for code length code lengths */ - CODELENS, /* i: waiting for length/lit and distance code lengths */ - LEN_, /* i: same as LEN below, but only first time in */ - LEN, /* i: waiting for length/lit/eob code */ - LENEXT, /* i: waiting for length extra bits */ - DIST, /* i: waiting for distance code */ - DISTEXT, /* i: waiting for distance extra bits */ - MATCH, /* o: waiting for output space to copy string */ - LIT, /* o: waiting for output space to write literal */ - CHECK, /* i: waiting for 32-bit check value */ - LENGTH, /* i: waiting for 32-bit length (gzip) */ - DONE, /* finished check, done -- remain here until reset */ - BAD, /* got a data error -- remain here until reset */ - MEM, /* got an inflate() memory error -- remain here until reset */ - SYNC /* looking for synchronization bytes to restart inflate() */ -} inflate_mode; - -/* - State transitions between above modes - - - (most modes can go to BAD or MEM on error -- not shown for clarity) - - Process header: - HEAD -> (gzip) or (zlib) or (raw) - (gzip) -> FLAGS -> TIME -> OS -> EXLEN -> EXTRA -> NAME -> COMMENT -> - HCRC -> TYPE - (zlib) -> DICTID or TYPE - DICTID -> DICT -> TYPE - (raw) -> TYPEDO - Read deflate blocks: - TYPE -> TYPEDO -> STORED or TABLE or LEN_ or CHECK - STORED -> COPY_ -> COPY -> TYPE - TABLE -> LENLENS -> CODELENS -> LEN_ - LEN_ -> LEN - Read deflate codes in fixed or dynamic block: - LEN -> LENEXT or LIT or TYPE - LENEXT -> DIST -> DISTEXT -> MATCH -> LEN - LIT -> LEN - Process trailer: - CHECK -> LENGTH -> DONE - */ - -/* State maintained between inflate() calls -- approximately 7K bytes, not - including the allocated sliding window, which is up to 32K bytes. */ -struct inflate_state { - z_streamp strm; /* pointer back to this zlib stream */ - inflate_mode mode; /* current inflate mode */ - int last; /* true if processing last block */ - int wrap; /* bit 0 true for zlib, bit 1 true for gzip, - bit 2 true to validate check value */ - int havedict; /* true if dictionary provided */ - int flags; /* gzip header method and flags (0 if zlib) */ - unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */ - unsigned long check; /* protected copy of check value */ - unsigned long total; /* protected copy of output count */ - gz_headerp head; /* where to save gzip header information */ - /* sliding window */ - unsigned wbits; /* log base 2 of requested window size */ - unsigned wsize; /* window size or zero if not using window */ - unsigned whave; /* valid bytes in the window */ - unsigned wnext; /* window write index */ - unsigned char FAR *window; /* allocated sliding window, if needed */ - /* bit accumulator */ - unsigned long hold; /* input bit accumulator */ - unsigned bits; /* number of bits in "in" */ - /* for string and stored block copying */ - unsigned length; /* literal or length of data to copy */ - unsigned offset; /* distance back to copy string from */ - /* for table and code decoding */ - unsigned extra; /* extra bits needed */ - /* fixed and dynamic code tables */ - code const FAR *lencode; /* starting table for length/literal codes */ - code const FAR *distcode; /* starting table for distance codes */ - unsigned lenbits; /* index bits for lencode */ - unsigned distbits; /* index bits for distcode */ - /* dynamic table building */ - unsigned ncode; /* number of code length code lengths */ - unsigned nlen; /* number of length code lengths */ - unsigned ndist; /* number of distance code lengths */ - unsigned have; /* number of code lengths in lens[] */ - code FAR *next; /* next available space in codes[] */ - unsigned short lens[320]; /* temporary storage for code lengths */ - unsigned short work[288]; /* work area for code table building */ - code codes[ENOUGH]; /* space for code tables */ - int sane; /* if false, allow invalid distance too far */ - int back; /* bits back of last unprocessed length/lit */ - unsigned was; /* initial length of match */ -}; diff --git a/src/common/dep/zlib/inftrees.c b/src/common/dep/zlib/inftrees.c deleted file mode 100644 index 2ea08fc13..000000000 --- a/src/common/dep/zlib/inftrees.c +++ /dev/null @@ -1,304 +0,0 @@ -/* inftrees.c -- generate Huffman trees for efficient decoding - * Copyright (C) 1995-2017 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -#include "zutil.h" -#include "inftrees.h" - -#define MAXBITS 15 - -const char inflate_copyright[] = - " inflate 1.2.11 Copyright 1995-2017 Mark Adler "; -/* - If you use the zlib library in a product, an acknowledgment is welcome - in the documentation of your product. If for some reason you cannot - include such an acknowledgment, I would appreciate that you keep this - copyright string in the executable of your product. - */ - -/* - Build a set of tables to decode the provided canonical Huffman code. - The code lengths are lens[0..codes-1]. The result starts at *table, - whose indices are 0..2^bits-1. work is a writable array of at least - lens shorts, which is used as a work area. type is the type of code - to be generated, CODES, LENS, or DISTS. On return, zero is success, - -1 is an invalid code, and +1 means that ENOUGH isn't enough. table - on return points to the next available entry's address. bits is the - requested root table index bits, and on return it is the actual root - table index bits. It will differ if the request is greater than the - longest code or if it is less than the shortest code. - */ -int ZLIB_INTERNAL inflate_table(type, lens, codes, table, bits, work) -codetype type; -unsigned short FAR *lens; -unsigned codes; -code FAR * FAR *table; -unsigned FAR *bits; -unsigned short FAR *work; -{ - unsigned len; /* a code's length in bits */ - unsigned sym; /* index of code symbols */ - unsigned min, max; /* minimum and maximum code lengths */ - unsigned root; /* number of index bits for root table */ - unsigned curr; /* number of index bits for current table */ - unsigned drop; /* code bits to drop for sub-table */ - int left; /* number of prefix codes available */ - unsigned used; /* code entries in table used */ - unsigned huff; /* Huffman code */ - unsigned incr; /* for incrementing code, index */ - unsigned fill; /* index for replicating entries */ - unsigned low; /* low bits for current root entry */ - unsigned mask; /* mask for low root bits */ - code here; /* table entry for duplication */ - code FAR *next; /* next available space in table */ - const unsigned short FAR *base; /* base value table to use */ - const unsigned short FAR *extra; /* extra bits table to use */ - unsigned match; /* use base and extra for symbol >= match */ - unsigned short count[MAXBITS+1]; /* number of codes of each length */ - unsigned short offs[MAXBITS+1]; /* offsets in table for each length */ - static const unsigned short lbase[31] = { /* Length codes 257..285 base */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; - static const unsigned short lext[31] = { /* Length codes 257..285 extra */ - 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, - 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 77, 202}; - static const unsigned short dbase[32] = { /* Distance codes 0..29 base */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577, 0, 0}; - static const unsigned short dext[32] = { /* Distance codes 0..29 extra */ - 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, - 23, 23, 24, 24, 25, 25, 26, 26, 27, 27, - 28, 28, 29, 29, 64, 64}; - - /* - Process a set of code lengths to create a canonical Huffman code. The - code lengths are lens[0..codes-1]. Each length corresponds to the - symbols 0..codes-1. The Huffman code is generated by first sorting the - symbols by length from short to long, and retaining the symbol order - for codes with equal lengths. Then the code starts with all zero bits - for the first code of the shortest length, and the codes are integer - increments for the same length, and zeros are appended as the length - increases. For the deflate format, these bits are stored backwards - from their more natural integer increment ordering, and so when the - decoding tables are built in the large loop below, the integer codes - are incremented backwards. - - This routine assumes, but does not check, that all of the entries in - lens[] are in the range 0..MAXBITS. The caller must assure this. - 1..MAXBITS is interpreted as that code length. zero means that that - symbol does not occur in this code. - - The codes are sorted by computing a count of codes for each length, - creating from that a table of starting indices for each length in the - sorted table, and then entering the symbols in order in the sorted - table. The sorted table is work[], with that space being provided by - the caller. - - The length counts are used for other purposes as well, i.e. finding - the minimum and maximum length codes, determining if there are any - codes at all, checking for a valid set of lengths, and looking ahead - at length counts to determine sub-table sizes when building the - decoding tables. - */ - - /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */ - for (len = 0; len <= MAXBITS; len++) - count[len] = 0; - for (sym = 0; sym < codes; sym++) - count[lens[sym]]++; - - /* bound code lengths, force root to be within code lengths */ - root = *bits; - for (max = MAXBITS; max >= 1; max--) - if (count[max] != 0) break; - if (root > max) root = max; - if (max == 0) { /* no symbols to code at all */ - here.op = (unsigned char)64; /* invalid code marker */ - here.bits = (unsigned char)1; - here.val = (unsigned short)0; - *(*table)++ = here; /* make a table to force an error */ - *(*table)++ = here; - *bits = 1; - return 0; /* no symbols, but wait for decoding to report error */ - } - for (min = 1; min < max; min++) - if (count[min] != 0) break; - if (root < min) root = min; - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; - left -= count[len]; - if (left < 0) return -1; /* over-subscribed */ - } - if (left > 0 && (type == CODES || max != 1)) - return -1; /* incomplete set */ - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) - offs[len + 1] = offs[len] + count[len]; - - /* sort symbols by length, by symbol order within each length */ - for (sym = 0; sym < codes; sym++) - if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym; - - /* - Create and fill in decoding tables. In this loop, the table being - filled is at next and has curr index bits. The code being used is huff - with length len. That code is converted to an index by dropping drop - bits off of the bottom. For codes where len is less than drop + curr, - those top drop + curr - len bits are incremented through all values to - fill the table with replicated entries. - - root is the number of index bits for the root table. When len exceeds - root, sub-tables are created pointed to by the root entry with an index - of the low root bits of huff. This is saved in low to check for when a - new sub-table should be started. drop is zero when the root table is - being filled, and drop is root when sub-tables are being filled. - - When a new sub-table is needed, it is necessary to look ahead in the - code lengths to determine what size sub-table is needed. The length - counts are used for this, and so count[] is decremented as codes are - entered in the tables. - - used keeps track of how many table entries have been allocated from the - provided *table space. It is checked for LENS and DIST tables against - the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in - the initial root table size constants. See the comments in inftrees.h - for more information. - - sym increments through all symbols, and the loop terminates when - all codes of length max, i.e. all codes, have been processed. This - routine permits incomplete codes, so another loop after this one fills - in the rest of the decoding tables with invalid code markers. - */ - - /* set up for code type */ - switch (type) { - case CODES: - base = extra = work; /* dummy value--not used */ - match = 20; - break; - case LENS: - base = lbase; - extra = lext; - match = 257; - break; - default: /* DISTS */ - base = dbase; - extra = dext; - match = 0; - } - - /* initialize state for loop */ - huff = 0; /* starting code */ - sym = 0; /* starting code symbol */ - len = min; /* starting code length */ - next = *table; /* current table to fill in */ - curr = root; /* current table index bits */ - drop = 0; /* current bits to drop from code for index */ - low = (unsigned)(-1); /* trigger new sub-table when len > root */ - used = 1U << root; /* use root table entries */ - mask = used - 1; /* mask for comparing low */ - - /* check available table space */ - if ((type == LENS && used > ENOUGH_LENS) || - (type == DISTS && used > ENOUGH_DISTS)) - return 1; - - /* process all codes and make table entries */ - for (;;) { - /* create table entry */ - here.bits = (unsigned char)(len - drop); - if (work[sym] + 1U < match) { - here.op = (unsigned char)0; - here.val = work[sym]; - } - else if (work[sym] >= match) { - here.op = (unsigned char)(extra[work[sym] - match]); - here.val = base[work[sym] - match]; - } - else { - here.op = (unsigned char)(32 + 64); /* end of block */ - here.val = 0; - } - - /* replicate for those indices with low len bits equal to huff */ - incr = 1U << (len - drop); - fill = 1U << curr; - min = fill; /* save offset to next table */ - do { - fill -= incr; - next[(huff >> drop) + fill] = here; - } while (fill != 0); - - /* backwards increment the len-bit code huff */ - incr = 1U << (len - 1); - while (huff & incr) - incr >>= 1; - if (incr != 0) { - huff &= incr - 1; - huff += incr; - } - else - huff = 0; - - /* go to next symbol, update count, len */ - sym++; - if (--(count[len]) == 0) { - if (len == max) break; - len = lens[work[sym]]; - } - - /* create new sub-table if needed */ - if (len > root && (huff & mask) != low) { - /* if first time, transition to sub-tables */ - if (drop == 0) - drop = root; - - /* increment past last table */ - next += min; /* here min is 1 << curr */ - - /* determine length of next table */ - curr = len - drop; - left = (int)(1 << curr); - while (curr + drop < max) { - left -= count[curr + drop]; - if (left <= 0) break; - curr++; - left <<= 1; - } - - /* check for enough space */ - used += 1U << curr; - if ((type == LENS && used > ENOUGH_LENS) || - (type == DISTS && used > ENOUGH_DISTS)) - return 1; - - /* point entry in root table to sub-table */ - low = huff & mask; - (*table)[low].op = (unsigned char)curr; - (*table)[low].bits = (unsigned char)root; - (*table)[low].val = (unsigned short)(next - *table); - } - } - - /* fill in remaining table entry if code is incomplete (guaranteed to have - at most one remaining entry, since if the code is incomplete, the - maximum code length that was allowed to get this far is one bit) */ - if (huff != 0) { - here.op = (unsigned char)64; /* invalid code marker */ - here.bits = (unsigned char)(len - drop); - here.val = (unsigned short)0; - next[huff] = here; - } - - /* set return parameters */ - *table += used; - *bits = root; - return 0; -} diff --git a/src/common/dep/zlib/inftrees.h b/src/common/dep/zlib/inftrees.h deleted file mode 100644 index baa53a0b1..000000000 --- a/src/common/dep/zlib/inftrees.h +++ /dev/null @@ -1,62 +0,0 @@ -/* inftrees.h -- header to use inftrees.c - * Copyright (C) 1995-2005, 2010 Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* Structure for decoding tables. Each entry provides either the - information needed to do the operation requested by the code that - indexed that table entry, or it provides a pointer to another - table that indexes more bits of the code. op indicates whether - the entry is a pointer to another table, a literal, a length or - distance, an end-of-block, or an invalid code. For a table - pointer, the low four bits of op is the number of index bits of - that table. For a length or distance, the low four bits of op - is the number of extra bits to get after the code. bits is - the number of bits in this code or part of the code to drop off - of the bit buffer. val is the actual byte to output in the case - of a literal, the base length or distance, or the offset from - the current table to the next table. Each entry is four bytes. */ -typedef struct { - unsigned char op; /* operation, extra bits, table bits */ - unsigned char bits; /* bits in this part of the code */ - unsigned short val; /* offset in table or code value */ -} code; - -/* op values as set by inflate_table(): - 00000000 - literal - 0000tttt - table link, tttt != 0 is the number of table index bits - 0001eeee - length or distance, eeee is the number of extra bits - 01100000 - end of block - 01000000 - invalid code - */ - -/* Maximum size of the dynamic table. The maximum number of code structures is - 1444, which is the sum of 852 for literal/length codes and 592 for distance - codes. These values were found by exhaustive searches using the program - examples/enough.c found in the zlib distribtution. The arguments to that - program are the number of symbols, the initial root table size, and the - maximum bit length of a code. "enough 286 9 15" for literal/length codes - returns returns 852, and "enough 30 6 15" for distance codes returns 592. - The initial root table size (9 or 6) is found in the fifth argument of the - inflate_table() calls in inflate.c and infback.c. If the root table size is - changed, then these maximum sizes would be need to be recalculated and - updated. */ -#define ENOUGH_LENS 852 -#define ENOUGH_DISTS 592 -#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS) - -/* Type of code to build for inflate_table() */ -typedef enum { - CODES, - LENS, - DISTS -} codetype; - -int ZLIB_INTERNAL inflate_table OF((codetype type, unsigned short FAR *lens, - unsigned codes, code FAR * FAR *table, - unsigned FAR *bits, unsigned short FAR *work)); diff --git a/src/common/dep/zlib/trees.c b/src/common/dep/zlib/trees.c deleted file mode 100644 index 50cf4b457..000000000 --- a/src/common/dep/zlib/trees.c +++ /dev/null @@ -1,1203 +0,0 @@ -/* trees.c -- output deflated data using Huffman coding - * Copyright (C) 1995-2017 Jean-loup Gailly - * detect_data_type() function provided freely by Cosmin Truta, 2006 - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* - * ALGORITHM - * - * The "deflation" process uses several Huffman trees. The more - * common source values are represented by shorter bit sequences. - * - * Each code tree is stored in a compressed form which is itself - * a Huffman encoding of the lengths of all the code strings (in - * ascending order by source values). The actual code strings are - * reconstructed from the lengths in the inflate process, as described - * in the deflate specification. - * - * REFERENCES - * - * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". - * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc - * - * Storer, James A. - * Data Compression: Methods and Theory, pp. 49-50. - * Computer Science Press, 1988. ISBN 0-7167-8156-5. - * - * Sedgewick, R. - * Algorithms, p290. - * Addison-Wesley, 1983. ISBN 0-201-06672-6. - */ - -/* @(#) $Id$ */ - -/* #define GEN_TREES_H */ - -#include "deflate.h" - -#ifdef ZLIB_DEBUG -# include -#endif - -/* =========================================================================== - * Constants - */ - -#define MAX_BL_BITS 7 -/* Bit length codes must not exceed MAX_BL_BITS bits */ - -#define END_BLOCK 256 -/* end of block literal code */ - -#define REP_3_6 16 -/* repeat previous bit length 3-6 times (2 bits of repeat count) */ - -#define REPZ_3_10 17 -/* repeat a zero length 3-10 times (3 bits of repeat count) */ - -#define REPZ_11_138 18 -/* repeat a zero length 11-138 times (7 bits of repeat count) */ - -local const int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ - = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; - -local const int extra_dbits[D_CODES] /* extra bits for each distance code */ - = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; - -local const int extra_blbits[BL_CODES]/* extra bits for each bit length code */ - = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; - -local const uch bl_order[BL_CODES] - = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; -/* The lengths of the bit length codes are sent in order of decreasing - * probability, to avoid transmitting the lengths for unused bit length codes. - */ - -/* =========================================================================== - * Local data. These are initialized only once. - */ - -#define DIST_CODE_LEN 512 /* see definition of array dist_code below */ - -#if defined(GEN_TREES_H) || !defined(STDC) -/* non ANSI compilers may not accept trees.h */ - -local ct_data static_ltree[L_CODES+2]; -/* The static literal tree. Since the bit lengths are imposed, there is no - * need for the L_CODES extra codes used during heap construction. However - * The codes 286 and 287 are needed to build a canonical tree (see _tr_init - * below). - */ - -local ct_data static_dtree[D_CODES]; -/* The static distance tree. (Actually a trivial tree since all codes use - * 5 bits.) - */ - -uch _dist_code[DIST_CODE_LEN]; -/* Distance codes. The first 256 values correspond to the distances - * 3 .. 258, the last 256 values correspond to the top 8 bits of - * the 15 bit distances. - */ - -uch _length_code[MAX_MATCH-MIN_MATCH+1]; -/* length code for each normalized match length (0 == MIN_MATCH) */ - -local int base_length[LENGTH_CODES]; -/* First normalized length for each code (0 = MIN_MATCH) */ - -local int base_dist[D_CODES]; -/* First normalized distance for each code (0 = distance of 1) */ - -#else -# include "trees.h" -#endif /* GEN_TREES_H */ - -struct static_tree_desc_s { - const ct_data *static_tree; /* static tree or NULL */ - const intf *extra_bits; /* extra bits for each code or NULL */ - int extra_base; /* base index for extra_bits */ - int elems; /* max number of elements in the tree */ - int max_length; /* max bit length for the codes */ -}; - -local const static_tree_desc static_l_desc = -{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; - -local const static_tree_desc static_d_desc = -{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; - -local const static_tree_desc static_bl_desc = -{(const ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; - -/* =========================================================================== - * Local (static) routines in this file. - */ - -local void tr_static_init OF((void)); -local void init_block OF((deflate_state *s)); -local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); -local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); -local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); -local void build_tree OF((deflate_state *s, tree_desc *desc)); -local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); -local int build_bl_tree OF((deflate_state *s)); -local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, - int blcodes)); -local void compress_block OF((deflate_state *s, const ct_data *ltree, - const ct_data *dtree)); -local int detect_data_type OF((deflate_state *s)); -local unsigned bi_reverse OF((unsigned value, int length)); -local void bi_windup OF((deflate_state *s)); -local void bi_flush OF((deflate_state *s)); - -#ifdef GEN_TREES_H -local void gen_trees_header OF((void)); -#endif - -#ifndef ZLIB_DEBUG -# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) - /* Send a code of the given tree. c and tree must not have side effects */ - -#else /* !ZLIB_DEBUG */ -# define send_code(s, c, tree) \ - { if (z_verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ - send_bits(s, tree[c].Code, tree[c].Len); } -#endif - -/* =========================================================================== - * Output a short LSB first on the stream. - * IN assertion: there is enough room in pendingBuf. - */ -#define put_short(s, w) { \ - put_byte(s, (uch)((w) & 0xff)); \ - put_byte(s, (uch)((ush)(w) >> 8)); \ -} - -/* =========================================================================== - * Send a value on a given number of bits. - * IN assertion: length <= 16 and value fits in length bits. - */ -#ifdef ZLIB_DEBUG -local void send_bits OF((deflate_state *s, int value, int length)); - -local void send_bits(s, value, length) - deflate_state *s; - int value; /* value to send */ - int length; /* number of bits */ -{ - Tracevv((stderr," l %2d v %4x ", length, value)); - Assert(length > 0 && length <= 15, "invalid length"); - s->bits_sent += (ulg)length; - - /* If not enough room in bi_buf, use (valid) bits from bi_buf and - * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) - * unused bits in value. - */ - if (s->bi_valid > (int)Buf_size - length) { - s->bi_buf |= (ush)value << s->bi_valid; - put_short(s, s->bi_buf); - s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); - s->bi_valid += length - Buf_size; - } else { - s->bi_buf |= (ush)value << s->bi_valid; - s->bi_valid += length; - } -} -#else /* !ZLIB_DEBUG */ - -#define send_bits(s, value, length) \ -{ int len = length;\ - if (s->bi_valid > (int)Buf_size - len) {\ - int val = (int)value;\ - s->bi_buf |= (ush)val << s->bi_valid;\ - put_short(s, s->bi_buf);\ - s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ - s->bi_valid += len - Buf_size;\ - } else {\ - s->bi_buf |= (ush)(value) << s->bi_valid;\ - s->bi_valid += len;\ - }\ -} -#endif /* ZLIB_DEBUG */ - - -/* the arguments must not have side effects */ - -/* =========================================================================== - * Initialize the various 'constant' tables. - */ -local void tr_static_init() -{ -#if defined(GEN_TREES_H) || !defined(STDC) - static int static_init_done = 0; - int n; /* iterates over tree elements */ - int bits; /* bit counter */ - int length; /* length value */ - int code; /* code value */ - int dist; /* distance index */ - ush bl_count[MAX_BITS+1]; - /* number of codes at each bit length for an optimal tree */ - - if (static_init_done) return; - - /* For some embedded targets, global variables are not initialized: */ -#ifdef NO_INIT_GLOBAL_POINTERS - static_l_desc.static_tree = static_ltree; - static_l_desc.extra_bits = extra_lbits; - static_d_desc.static_tree = static_dtree; - static_d_desc.extra_bits = extra_dbits; - static_bl_desc.extra_bits = extra_blbits; -#endif - - /* Initialize the mapping length (0..255) -> length code (0..28) */ - length = 0; - for (code = 0; code < LENGTH_CODES-1; code++) { - base_length[code] = length; - for (n = 0; n < (1< dist code (0..29) */ - dist = 0; - for (code = 0 ; code < 16; code++) { - base_dist[code] = dist; - for (n = 0; n < (1<>= 7; /* from now on, all distances are divided by 128 */ - for ( ; code < D_CODES; code++) { - base_dist[code] = dist << 7; - for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { - _dist_code[256 + dist++] = (uch)code; - } - } - Assert (dist == 256, "tr_static_init: 256+dist != 512"); - - /* Construct the codes of the static literal tree */ - for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; - n = 0; - while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; - while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; - while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; - while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; - /* Codes 286 and 287 do not exist, but we must include them in the - * tree construction to get a canonical Huffman tree (longest code - * all ones) - */ - gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); - - /* The static distance tree is trivial: */ - for (n = 0; n < D_CODES; n++) { - static_dtree[n].Len = 5; - static_dtree[n].Code = bi_reverse((unsigned)n, 5); - } - static_init_done = 1; - -# ifdef GEN_TREES_H - gen_trees_header(); -# endif -#endif /* defined(GEN_TREES_H) || !defined(STDC) */ -} - -/* =========================================================================== - * Genererate the file trees.h describing the static trees. - */ -#ifdef GEN_TREES_H -# ifndef ZLIB_DEBUG -# include -# endif - -# define SEPARATOR(i, last, width) \ - ((i) == (last)? "\n};\n\n" : \ - ((i) % (width) == (width)-1 ? ",\n" : ", ")) - -void gen_trees_header() -{ - FILE *header = fopen("trees.h", "w"); - int i; - - Assert (header != NULL, "Can't open trees.h"); - fprintf(header, - "/* header created automatically with -DGEN_TREES_H */\n\n"); - - fprintf(header, "local const ct_data static_ltree[L_CODES+2] = {\n"); - for (i = 0; i < L_CODES+2; i++) { - fprintf(header, "{{%3u},{%3u}}%s", static_ltree[i].Code, - static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); - } - - fprintf(header, "local const ct_data static_dtree[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "{{%2u},{%2u}}%s", static_dtree[i].Code, - static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); - } - - fprintf(header, "const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = {\n"); - for (i = 0; i < DIST_CODE_LEN; i++) { - fprintf(header, "%2u%s", _dist_code[i], - SEPARATOR(i, DIST_CODE_LEN-1, 20)); - } - - fprintf(header, - "const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= {\n"); - for (i = 0; i < MAX_MATCH-MIN_MATCH+1; i++) { - fprintf(header, "%2u%s", _length_code[i], - SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); - } - - fprintf(header, "local const int base_length[LENGTH_CODES] = {\n"); - for (i = 0; i < LENGTH_CODES; i++) { - fprintf(header, "%1u%s", base_length[i], - SEPARATOR(i, LENGTH_CODES-1, 20)); - } - - fprintf(header, "local const int base_dist[D_CODES] = {\n"); - for (i = 0; i < D_CODES; i++) { - fprintf(header, "%5u%s", base_dist[i], - SEPARATOR(i, D_CODES-1, 10)); - } - - fclose(header); -} -#endif /* GEN_TREES_H */ - -/* =========================================================================== - * Initialize the tree data structures for a new zlib stream. - */ -void ZLIB_INTERNAL _tr_init(s) - deflate_state *s; -{ - tr_static_init(); - - s->l_desc.dyn_tree = s->dyn_ltree; - s->l_desc.stat_desc = &static_l_desc; - - s->d_desc.dyn_tree = s->dyn_dtree; - s->d_desc.stat_desc = &static_d_desc; - - s->bl_desc.dyn_tree = s->bl_tree; - s->bl_desc.stat_desc = &static_bl_desc; - - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef ZLIB_DEBUG - s->compressed_len = 0L; - s->bits_sent = 0L; -#endif - - /* Initialize the first block of the first file: */ - init_block(s); -} - -/* =========================================================================== - * Initialize a new block. - */ -local void init_block(s) - deflate_state *s; -{ - int n; /* iterates over tree elements */ - - /* Initialize the trees. */ - for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; - for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; - for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; - - s->dyn_ltree[END_BLOCK].Freq = 1; - s->opt_len = s->static_len = 0L; - s->last_lit = s->matches = 0; -} - -#define SMALLEST 1 -/* Index within the heap array of least frequent node in the Huffman tree */ - - -/* =========================================================================== - * Remove the smallest element from the heap and recreate the heap with - * one less element. Updates heap and heap_len. - */ -#define pqremove(s, tree, top) \ -{\ - top = s->heap[SMALLEST]; \ - s->heap[SMALLEST] = s->heap[s->heap_len--]; \ - pqdownheap(s, tree, SMALLEST); \ -} - -/* =========================================================================== - * Compares to subtrees, using the tree depth as tie breaker when - * the subtrees have equal frequency. This minimizes the worst case length. - */ -#define smaller(tree, n, m, depth) \ - (tree[n].Freq < tree[m].Freq || \ - (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) - -/* =========================================================================== - * Restore the heap property by moving down the tree starting at node k, - * exchanging a node with the smallest of its two sons if necessary, stopping - * when the heap property is re-established (each father smaller than its - * two sons). - */ -local void pqdownheap(s, tree, k) - deflate_state *s; - ct_data *tree; /* the tree to restore */ - int k; /* node to move down */ -{ - int v = s->heap[k]; - int j = k << 1; /* left son of k */ - while (j <= s->heap_len) { - /* Set j to the smallest of the two sons: */ - if (j < s->heap_len && - smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { - j++; - } - /* Exit if v is smaller than both sons */ - if (smaller(tree, v, s->heap[j], s->depth)) break; - - /* Exchange v with the smallest son */ - s->heap[k] = s->heap[j]; k = j; - - /* And continue down the tree, setting j to the left son of k */ - j <<= 1; - } - s->heap[k] = v; -} - -/* =========================================================================== - * Compute the optimal bit lengths for a tree and update the total bit length - * for the current block. - * IN assertion: the fields freq and dad are set, heap[heap_max] and - * above are the tree nodes sorted by increasing frequency. - * OUT assertions: the field len is set to the optimal bit length, the - * array bl_count contains the frequencies for each bit length. - * The length opt_len is updated; static_len is also updated if stree is - * not null. - */ -local void gen_bitlen(s, desc) - deflate_state *s; - tree_desc *desc; /* the tree descriptor */ -{ - ct_data *tree = desc->dyn_tree; - int max_code = desc->max_code; - const ct_data *stree = desc->stat_desc->static_tree; - const intf *extra = desc->stat_desc->extra_bits; - int base = desc->stat_desc->extra_base; - int max_length = desc->stat_desc->max_length; - int h; /* heap index */ - int n, m; /* iterate over the tree elements */ - int bits; /* bit length */ - int xbits; /* extra bits */ - ush f; /* frequency */ - int overflow = 0; /* number of elements with bit length too large */ - - for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; - - /* In a first pass, compute the optimal bit lengths (which may - * overflow in the case of the bit length tree). - */ - tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ - - for (h = s->heap_max+1; h < HEAP_SIZE; h++) { - n = s->heap[h]; - bits = tree[tree[n].Dad].Len + 1; - if (bits > max_length) bits = max_length, overflow++; - tree[n].Len = (ush)bits; - /* We overwrite tree[n].Dad which is no longer needed */ - - if (n > max_code) continue; /* not a leaf node */ - - s->bl_count[bits]++; - xbits = 0; - if (n >= base) xbits = extra[n-base]; - f = tree[n].Freq; - s->opt_len += (ulg)f * (unsigned)(bits + xbits); - if (stree) s->static_len += (ulg)f * (unsigned)(stree[n].Len + xbits); - } - if (overflow == 0) return; - - Tracev((stderr,"\nbit length overflow\n")); - /* This happens for example on obj2 and pic of the Calgary corpus */ - - /* Find the first bit length which could increase: */ - do { - bits = max_length-1; - while (s->bl_count[bits] == 0) bits--; - s->bl_count[bits]--; /* move one leaf down the tree */ - s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ - s->bl_count[max_length]--; - /* The brother of the overflow item also moves one step up, - * but this does not affect bl_count[max_length] - */ - overflow -= 2; - } while (overflow > 0); - - /* Now recompute all bit lengths, scanning in increasing frequency. - * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all - * lengths instead of fixing only the wrong ones. This idea is taken - * from 'ar' written by Haruhiko Okumura.) - */ - for (bits = max_length; bits != 0; bits--) { - n = s->bl_count[bits]; - while (n != 0) { - m = s->heap[--h]; - if (m > max_code) continue; - if ((unsigned) tree[m].Len != (unsigned) bits) { - Tracev((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); - s->opt_len += ((ulg)bits - tree[m].Len) * tree[m].Freq; - tree[m].Len = (ush)bits; - } - n--; - } - } -} - -/* =========================================================================== - * Generate the codes for a given tree and bit counts (which need not be - * optimal). - * IN assertion: the array bl_count contains the bit length statistics for - * the given tree and the field len is set for all tree elements. - * OUT assertion: the field code is set for all tree elements of non - * zero code length. - */ -local void gen_codes (tree, max_code, bl_count) - ct_data *tree; /* the tree to decorate */ - int max_code; /* largest code with non zero frequency */ - ushf *bl_count; /* number of codes at each bit length */ -{ - ush next_code[MAX_BITS+1]; /* next code value for each bit length */ - unsigned code = 0; /* running code value */ - int bits; /* bit index */ - int n; /* code index */ - - /* The distribution counts are first used to generate the code values - * without bit reversal. - */ - for (bits = 1; bits <= MAX_BITS; bits++) { - code = (code + bl_count[bits-1]) << 1; - next_code[bits] = (ush)code; - } - /* Check that the bit counts in bl_count are consistent. The last code - * must be all ones. - */ - Assert (code + bl_count[MAX_BITS]-1 == (1<dyn_tree; - const ct_data *stree = desc->stat_desc->static_tree; - int elems = desc->stat_desc->elems; - int n, m; /* iterate over heap elements */ - int max_code = -1; /* largest code with non zero frequency */ - int node; /* new node being created */ - - /* Construct the initial heap, with least frequent element in - * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. - * heap[0] is not used. - */ - s->heap_len = 0, s->heap_max = HEAP_SIZE; - - for (n = 0; n < elems; n++) { - if (tree[n].Freq != 0) { - s->heap[++(s->heap_len)] = max_code = n; - s->depth[n] = 0; - } else { - tree[n].Len = 0; - } - } - - /* The pkzip format requires that at least one distance code exists, - * and that at least one bit should be sent even if there is only one - * possible code. So to avoid special checks later on we force at least - * two codes of non zero frequency. - */ - while (s->heap_len < 2) { - node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); - tree[node].Freq = 1; - s->depth[node] = 0; - s->opt_len--; if (stree) s->static_len -= stree[node].Len; - /* node is 0 or 1 so it does not have extra bits */ - } - desc->max_code = max_code; - - /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, - * establish sub-heaps of increasing lengths: - */ - for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); - - /* Construct the Huffman tree by repeatedly combining the least two - * frequent nodes. - */ - node = elems; /* next internal node of the tree */ - do { - pqremove(s, tree, n); /* n = node of least frequency */ - m = s->heap[SMALLEST]; /* m = node of next least frequency */ - - s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ - s->heap[--(s->heap_max)] = m; - - /* Create a new node father of n and m */ - tree[node].Freq = tree[n].Freq + tree[m].Freq; - s->depth[node] = (uch)((s->depth[n] >= s->depth[m] ? - s->depth[n] : s->depth[m]) + 1); - tree[n].Dad = tree[m].Dad = (ush)node; -#ifdef DUMP_BL_TREE - if (tree == s->bl_tree) { - fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", - node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); - } -#endif - /* and insert the new node in the heap */ - s->heap[SMALLEST] = node++; - pqdownheap(s, tree, SMALLEST); - - } while (s->heap_len >= 2); - - s->heap[--(s->heap_max)] = s->heap[SMALLEST]; - - /* At this point, the fields freq and dad are set. We can now - * generate the bit lengths. - */ - gen_bitlen(s, (tree_desc *)desc); - - /* The field len is now set, we can generate the bit codes */ - gen_codes ((ct_data *)tree, max_code, s->bl_count); -} - -/* =========================================================================== - * Scan a literal or distance tree to determine the frequencies of the codes - * in the bit length tree. - */ -local void scan_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - if (nextlen == 0) max_count = 138, min_count = 3; - tree[max_code+1].Len = (ush)0xffff; /* guard */ - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - s->bl_tree[curlen].Freq += count; - } else if (curlen != 0) { - if (curlen != prevlen) s->bl_tree[curlen].Freq++; - s->bl_tree[REP_3_6].Freq++; - } else if (count <= 10) { - s->bl_tree[REPZ_3_10].Freq++; - } else { - s->bl_tree[REPZ_11_138].Freq++; - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Send a literal or distance tree in compressed form, using the codes in - * bl_tree. - */ -local void send_tree (s, tree, max_code) - deflate_state *s; - ct_data *tree; /* the tree to be scanned */ - int max_code; /* and its largest code of non zero frequency */ -{ - int n; /* iterates over all tree elements */ - int prevlen = -1; /* last emitted length */ - int curlen; /* length of current code */ - int nextlen = tree[0].Len; /* length of next code */ - int count = 0; /* repeat count of the current code */ - int max_count = 7; /* max repeat count */ - int min_count = 4; /* min repeat count */ - - /* tree[max_code+1].Len = -1; */ /* guard already set */ - if (nextlen == 0) max_count = 138, min_count = 3; - - for (n = 0; n <= max_code; n++) { - curlen = nextlen; nextlen = tree[n+1].Len; - if (++count < max_count && curlen == nextlen) { - continue; - } else if (count < min_count) { - do { send_code(s, curlen, s->bl_tree); } while (--count != 0); - - } else if (curlen != 0) { - if (curlen != prevlen) { - send_code(s, curlen, s->bl_tree); count--; - } - Assert(count >= 3 && count <= 6, " 3_6?"); - send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); - - } else if (count <= 10) { - send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); - - } else { - send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); - } - count = 0; prevlen = curlen; - if (nextlen == 0) { - max_count = 138, min_count = 3; - } else if (curlen == nextlen) { - max_count = 6, min_count = 3; - } else { - max_count = 7, min_count = 4; - } - } -} - -/* =========================================================================== - * Construct the Huffman tree for the bit lengths and return the index in - * bl_order of the last bit length code to send. - */ -local int build_bl_tree(s) - deflate_state *s; -{ - int max_blindex; /* index of last bit length code of non zero freq */ - - /* Determine the bit length frequencies for literal and distance trees */ - scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); - scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); - - /* Build the bit length tree: */ - build_tree(s, (tree_desc *)(&(s->bl_desc))); - /* opt_len now includes the length of the tree representations, except - * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. - */ - - /* Determine the number of bit length codes to send. The pkzip format - * requires that at least 4 bit length codes be sent. (appnote.txt says - * 3 but the actual value used is 4.) - */ - for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { - if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; - } - /* Update opt_len to include the bit length tree and counts */ - s->opt_len += 3*((ulg)max_blindex+1) + 5+5+4; - Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", - s->opt_len, s->static_len)); - - return max_blindex; -} - -/* =========================================================================== - * Send the header for a block using dynamic Huffman trees: the counts, the - * lengths of the bit length codes, the literal tree and the distance tree. - * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. - */ -local void send_all_trees(s, lcodes, dcodes, blcodes) - deflate_state *s; - int lcodes, dcodes, blcodes; /* number of codes for each tree */ -{ - int rank; /* index in bl_order */ - - Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); - Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, - "too many codes"); - Tracev((stderr, "\nbl counts: ")); - send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ - send_bits(s, dcodes-1, 5); - send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ - for (rank = 0; rank < blcodes; rank++) { - Tracev((stderr, "\nbl code %2d ", bl_order[rank])); - send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); - } - Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ - Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); - - send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ - Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); -} - -/* =========================================================================== - * Send a stored block - */ -void ZLIB_INTERNAL _tr_stored_block(s, buf, stored_len, last) - deflate_state *s; - charf *buf; /* input block */ - ulg stored_len; /* length of input block */ - int last; /* one if this is the last block for a file */ -{ - send_bits(s, (STORED_BLOCK<<1)+last, 3); /* send block type */ - bi_windup(s); /* align on byte boundary */ - put_short(s, (ush)stored_len); - put_short(s, (ush)~stored_len); - zmemcpy(s->pending_buf + s->pending, (Bytef *)buf, stored_len); - s->pending += stored_len; -#ifdef ZLIB_DEBUG - s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; - s->compressed_len += (stored_len + 4) << 3; - s->bits_sent += 2*16; - s->bits_sent += stored_len<<3; -#endif -} - -/* =========================================================================== - * Flush the bits in the bit buffer to pending output (leaves at most 7 bits) - */ -void ZLIB_INTERNAL _tr_flush_bits(s) - deflate_state *s; -{ - bi_flush(s); -} - -/* =========================================================================== - * Send one empty static block to give enough lookahead for inflate. - * This takes 10 bits, of which 7 may remain in the bit buffer. - */ -void ZLIB_INTERNAL _tr_align(s) - deflate_state *s; -{ - send_bits(s, STATIC_TREES<<1, 3); - send_code(s, END_BLOCK, static_ltree); -#ifdef ZLIB_DEBUG - s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ -#endif - bi_flush(s); -} - -/* =========================================================================== - * Determine the best encoding for the current block: dynamic trees, static - * trees or store, and write out the encoded block. - */ -void ZLIB_INTERNAL _tr_flush_block(s, buf, stored_len, last) - deflate_state *s; - charf *buf; /* input block, or NULL if too old */ - ulg stored_len; /* length of input block */ - int last; /* one if this is the last block for a file */ -{ - ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ - int max_blindex = 0; /* index of last bit length code of non zero freq */ - - /* Build the Huffman trees unless a stored block is forced */ - if (s->level > 0) { - - /* Check if the file is binary or text */ - if (s->strm->data_type == Z_UNKNOWN) - s->strm->data_type = detect_data_type(s); - - /* Construct the literal and distance trees */ - build_tree(s, (tree_desc *)(&(s->l_desc))); - Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - - build_tree(s, (tree_desc *)(&(s->d_desc))); - Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, - s->static_len)); - /* At this point, opt_len and static_len are the total bit lengths of - * the compressed block data, excluding the tree representations. - */ - - /* Build the bit length tree for the above two trees, and get the index - * in bl_order of the last bit length code to send. - */ - max_blindex = build_bl_tree(s); - - /* Determine the best encoding. Compute the block lengths in bytes. */ - opt_lenb = (s->opt_len+3+7)>>3; - static_lenb = (s->static_len+3+7)>>3; - - Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", - opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, - s->last_lit)); - - if (static_lenb <= opt_lenb) opt_lenb = static_lenb; - - } else { - Assert(buf != (char*)0, "lost buf"); - opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ - } - -#ifdef FORCE_STORED - if (buf != (char*)0) { /* force stored block */ -#else - if (stored_len+4 <= opt_lenb && buf != (char*)0) { - /* 4: two words for the lengths */ -#endif - /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. - * Otherwise we can't have processed more than WSIZE input bytes since - * the last block flush, because compression would have been - * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to - * transform a block into a stored block. - */ - _tr_stored_block(s, buf, stored_len, last); - -#ifdef FORCE_STATIC - } else if (static_lenb >= 0) { /* force static trees */ -#else - } else if (s->strategy == Z_FIXED || static_lenb == opt_lenb) { -#endif - send_bits(s, (STATIC_TREES<<1)+last, 3); - compress_block(s, (const ct_data *)static_ltree, - (const ct_data *)static_dtree); -#ifdef ZLIB_DEBUG - s->compressed_len += 3 + s->static_len; -#endif - } else { - send_bits(s, (DYN_TREES<<1)+last, 3); - send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, - max_blindex+1); - compress_block(s, (const ct_data *)s->dyn_ltree, - (const ct_data *)s->dyn_dtree); -#ifdef ZLIB_DEBUG - s->compressed_len += 3 + s->opt_len; -#endif - } - Assert (s->compressed_len == s->bits_sent, "bad compressed size"); - /* The above check is made mod 2^32, for files larger than 512 MB - * and uLong implemented on 32 bits. - */ - init_block(s); - - if (last) { - bi_windup(s); -#ifdef ZLIB_DEBUG - s->compressed_len += 7; /* align on byte boundary */ -#endif - } - Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, - s->compressed_len-7*last)); -} - -/* =========================================================================== - * Save the match info and tally the frequency counts. Return true if - * the current block must be flushed. - */ -int ZLIB_INTERNAL _tr_tally (s, dist, lc) - deflate_state *s; - unsigned dist; /* distance of matched string */ - unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ -{ - s->d_buf[s->last_lit] = (ush)dist; - s->l_buf[s->last_lit++] = (uch)lc; - if (dist == 0) { - /* lc is the unmatched char */ - s->dyn_ltree[lc].Freq++; - } else { - s->matches++; - /* Here, lc is the match length - MIN_MATCH */ - dist--; /* dist = match distance - 1 */ - Assert((ush)dist < (ush)MAX_DIST(s) && - (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && - (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); - - s->dyn_ltree[_length_code[lc]+LITERALS+1].Freq++; - s->dyn_dtree[d_code(dist)].Freq++; - } - -#ifdef TRUNCATE_BLOCK - /* Try to guess if it is profitable to stop the current block here */ - if ((s->last_lit & 0x1fff) == 0 && s->level > 2) { - /* Compute an upper bound for the compressed length */ - ulg out_length = (ulg)s->last_lit*8L; - ulg in_length = (ulg)((long)s->strstart - s->block_start); - int dcode; - for (dcode = 0; dcode < D_CODES; dcode++) { - out_length += (ulg)s->dyn_dtree[dcode].Freq * - (5L+extra_dbits[dcode]); - } - out_length >>= 3; - Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", - s->last_lit, in_length, out_length, - 100L - out_length*100L/in_length)); - if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; - } -#endif - return (s->last_lit == s->lit_bufsize-1); - /* We avoid equality with lit_bufsize because of wraparound at 64K - * on 16 bit machines and because stored blocks are restricted to - * 64K-1 bytes. - */ -} - -/* =========================================================================== - * Send the block data compressed using the given Huffman trees - */ -local void compress_block(s, ltree, dtree) - deflate_state *s; - const ct_data *ltree; /* literal tree */ - const ct_data *dtree; /* distance tree */ -{ - unsigned dist; /* distance of matched string */ - int lc; /* match length or unmatched char (if dist == 0) */ - unsigned lx = 0; /* running index in l_buf */ - unsigned code; /* the code to send */ - int extra; /* number of extra bits to send */ - - if (s->last_lit != 0) do { - dist = s->d_buf[lx]; - lc = s->l_buf[lx++]; - if (dist == 0) { - send_code(s, lc, ltree); /* send a literal byte */ - Tracecv(isgraph(lc), (stderr," '%c' ", lc)); - } else { - /* Here, lc is the match length - MIN_MATCH */ - code = _length_code[lc]; - send_code(s, code+LITERALS+1, ltree); /* send the length code */ - extra = extra_lbits[code]; - if (extra != 0) { - lc -= base_length[code]; - send_bits(s, lc, extra); /* send the extra length bits */ - } - dist--; /* dist is now the match distance - 1 */ - code = d_code(dist); - Assert (code < D_CODES, "bad d_code"); - - send_code(s, code, dtree); /* send the distance code */ - extra = extra_dbits[code]; - if (extra != 0) { - dist -= (unsigned)base_dist[code]; - send_bits(s, dist, extra); /* send the extra distance bits */ - } - } /* literal or match pair ? */ - - /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ - Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx, - "pendingBuf overflow"); - - } while (lx < s->last_lit); - - send_code(s, END_BLOCK, ltree); -} - -/* =========================================================================== - * Check if the data type is TEXT or BINARY, using the following algorithm: - * - TEXT if the two conditions below are satisfied: - * a) There are no non-portable control characters belonging to the - * "black list" (0..6, 14..25, 28..31). - * b) There is at least one printable character belonging to the - * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255). - * - BINARY otherwise. - * - The following partially-portable control characters form a - * "gray list" that is ignored in this detection algorithm: - * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}). - * IN assertion: the fields Freq of dyn_ltree are set. - */ -local int detect_data_type(s) - deflate_state *s; -{ - /* black_mask is the bit mask of black-listed bytes - * set bits 0..6, 14..25, and 28..31 - * 0xf3ffc07f = binary 11110011111111111100000001111111 - */ - unsigned long black_mask = 0xf3ffc07fUL; - int n; - - /* Check for non-textual ("black-listed") bytes. */ - for (n = 0; n <= 31; n++, black_mask >>= 1) - if ((black_mask & 1) && (s->dyn_ltree[n].Freq != 0)) - return Z_BINARY; - - /* Check for textual ("white-listed") bytes. */ - if (s->dyn_ltree[9].Freq != 0 || s->dyn_ltree[10].Freq != 0 - || s->dyn_ltree[13].Freq != 0) - return Z_TEXT; - for (n = 32; n < LITERALS; n++) - if (s->dyn_ltree[n].Freq != 0) - return Z_TEXT; - - /* There are no "black-listed" or "white-listed" bytes: - * this stream either is empty or has tolerated ("gray-listed") bytes only. - */ - return Z_BINARY; -} - -/* =========================================================================== - * Reverse the first len bits of a code, using straightforward code (a faster - * method would use a table) - * IN assertion: 1 <= len <= 15 - */ -local unsigned bi_reverse(code, len) - unsigned code; /* the value to invert */ - int len; /* its bit length */ -{ - register unsigned res = 0; - do { - res |= code & 1; - code >>= 1, res <<= 1; - } while (--len > 0); - return res >> 1; -} - -/* =========================================================================== - * Flush the bit buffer, keeping at most 7 bits in it. - */ -local void bi_flush(s) - deflate_state *s; -{ - if (s->bi_valid == 16) { - put_short(s, s->bi_buf); - s->bi_buf = 0; - s->bi_valid = 0; - } else if (s->bi_valid >= 8) { - put_byte(s, (Byte)s->bi_buf); - s->bi_buf >>= 8; - s->bi_valid -= 8; - } -} - -/* =========================================================================== - * Flush the bit buffer and align the output on a byte boundary - */ -local void bi_windup(s) - deflate_state *s; -{ - if (s->bi_valid > 8) { - put_short(s, s->bi_buf); - } else if (s->bi_valid > 0) { - put_byte(s, (Byte)s->bi_buf); - } - s->bi_buf = 0; - s->bi_valid = 0; -#ifdef ZLIB_DEBUG - s->bits_sent = (s->bits_sent+7) & ~7; -#endif -} diff --git a/src/common/dep/zlib/trees.h b/src/common/dep/zlib/trees.h deleted file mode 100644 index d35639d82..000000000 --- a/src/common/dep/zlib/trees.h +++ /dev/null @@ -1,128 +0,0 @@ -/* header created automatically with -DGEN_TREES_H */ - -local const ct_data static_ltree[L_CODES+2] = { -{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, -{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, -{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, -{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, -{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, -{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, -{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, -{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, -{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, -{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, -{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, -{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, -{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, -{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, -{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, -{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, -{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, -{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, -{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, -{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, -{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, -{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, -{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, -{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, -{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, -{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, -{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, -{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, -{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, -{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, -{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, -{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, -{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, -{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, -{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, -{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, -{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, -{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, -{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, -{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, -{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, -{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, -{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, -{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, -{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, -{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, -{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, -{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, -{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, -{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, -{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, -{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, -{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, -{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, -{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, -{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, -{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, -{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} -}; - -local const ct_data static_dtree[D_CODES] = { -{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, -{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, -{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, -{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, -{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, -{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} -}; - -const uch ZLIB_INTERNAL _dist_code[DIST_CODE_LEN] = { - 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, - 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, -10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, -11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, -12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, -13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, -14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, -15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, -18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, -28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, -29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 -}; - -const uch ZLIB_INTERNAL _length_code[MAX_MATCH-MIN_MATCH+1]= { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, -13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, -17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, -19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, -21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, -22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, -23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, -25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, -26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, -27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 -}; - -local const int base_length[LENGTH_CODES] = { -0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, -64, 80, 96, 112, 128, 160, 192, 224, 0 -}; - -local const int base_dist[D_CODES] = { - 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, - 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, - 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 -}; - diff --git a/src/common/dep/zlib/zconf.h b/src/common/dep/zlib/zconf.h deleted file mode 100644 index 5e1d68a00..000000000 --- a/src/common/dep/zlib/zconf.h +++ /dev/null @@ -1,534 +0,0 @@ -/* zconf.h -- configuration of the zlib compression library - * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#ifndef ZCONF_H -#define ZCONF_H - -/* - * If you *really* need a unique prefix for all types and library functions, - * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. - * Even better than compiling with -DZ_PREFIX would be to use configure to set - * this permanently in zconf.h using "./configure --zprefix". - */ -#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */ -# define Z_PREFIX_SET - -/* all linked symbols and init macros */ -# define _dist_code z__dist_code -# define _length_code z__length_code -# define _tr_align z__tr_align -# define _tr_flush_bits z__tr_flush_bits -# define _tr_flush_block z__tr_flush_block -# define _tr_init z__tr_init -# define _tr_stored_block z__tr_stored_block -# define _tr_tally z__tr_tally -# define adler32 z_adler32 -# define adler32_combine z_adler32_combine -# define adler32_combine64 z_adler32_combine64 -# define adler32_z z_adler32_z -# ifndef Z_SOLO -# define compress z_compress -# define compress2 z_compress2 -# define compressBound z_compressBound -# endif -# define crc32 z_crc32 -# define crc32_combine z_crc32_combine -# define crc32_combine64 z_crc32_combine64 -# define crc32_z z_crc32_z -# define deflate z_deflate -# define deflateBound z_deflateBound -# define deflateCopy z_deflateCopy -# define deflateEnd z_deflateEnd -# define deflateGetDictionary z_deflateGetDictionary -# define deflateInit z_deflateInit -# define deflateInit2 z_deflateInit2 -# define deflateInit2_ z_deflateInit2_ -# define deflateInit_ z_deflateInit_ -# define deflateParams z_deflateParams -# define deflatePending z_deflatePending -# define deflatePrime z_deflatePrime -# define deflateReset z_deflateReset -# define deflateResetKeep z_deflateResetKeep -# define deflateSetDictionary z_deflateSetDictionary -# define deflateSetHeader z_deflateSetHeader -# define deflateTune z_deflateTune -# define deflate_copyright z_deflate_copyright -# define get_crc_table z_get_crc_table -# ifndef Z_SOLO -# define gz_error z_gz_error -# define gz_intmax z_gz_intmax -# define gz_strwinerror z_gz_strwinerror -# define gzbuffer z_gzbuffer -# define gzclearerr z_gzclearerr -# define gzclose z_gzclose -# define gzclose_r z_gzclose_r -# define gzclose_w z_gzclose_w -# define gzdirect z_gzdirect -# define gzdopen z_gzdopen -# define gzeof z_gzeof -# define gzerror z_gzerror -# define gzflush z_gzflush -# define gzfread z_gzfread -# define gzfwrite z_gzfwrite -# define gzgetc z_gzgetc -# define gzgetc_ z_gzgetc_ -# define gzgets z_gzgets -# define gzoffset z_gzoffset -# define gzoffset64 z_gzoffset64 -# define gzopen z_gzopen -# define gzopen64 z_gzopen64 -# ifdef _WIN32 -# define gzopen_w z_gzopen_w -# endif -# define gzprintf z_gzprintf -# define gzputc z_gzputc -# define gzputs z_gzputs -# define gzread z_gzread -# define gzrewind z_gzrewind -# define gzseek z_gzseek -# define gzseek64 z_gzseek64 -# define gzsetparams z_gzsetparams -# define gztell z_gztell -# define gztell64 z_gztell64 -# define gzungetc z_gzungetc -# define gzvprintf z_gzvprintf -# define gzwrite z_gzwrite -# endif -# define inflate z_inflate -# define inflateBack z_inflateBack -# define inflateBackEnd z_inflateBackEnd -# define inflateBackInit z_inflateBackInit -# define inflateBackInit_ z_inflateBackInit_ -# define inflateCodesUsed z_inflateCodesUsed -# define inflateCopy z_inflateCopy -# define inflateEnd z_inflateEnd -# define inflateGetDictionary z_inflateGetDictionary -# define inflateGetHeader z_inflateGetHeader -# define inflateInit z_inflateInit -# define inflateInit2 z_inflateInit2 -# define inflateInit2_ z_inflateInit2_ -# define inflateInit_ z_inflateInit_ -# define inflateMark z_inflateMark -# define inflatePrime z_inflatePrime -# define inflateReset z_inflateReset -# define inflateReset2 z_inflateReset2 -# define inflateResetKeep z_inflateResetKeep -# define inflateSetDictionary z_inflateSetDictionary -# define inflateSync z_inflateSync -# define inflateSyncPoint z_inflateSyncPoint -# define inflateUndermine z_inflateUndermine -# define inflateValidate z_inflateValidate -# define inflate_copyright z_inflate_copyright -# define inflate_fast z_inflate_fast -# define inflate_table z_inflate_table -# ifndef Z_SOLO -# define uncompress z_uncompress -# define uncompress2 z_uncompress2 -# endif -# define zError z_zError -# ifndef Z_SOLO -# define zcalloc z_zcalloc -# define zcfree z_zcfree -# endif -# define zlibCompileFlags z_zlibCompileFlags -# define zlibVersion z_zlibVersion - -/* all zlib typedefs in zlib.h and zconf.h */ -# define Byte z_Byte -# define Bytef z_Bytef -# define alloc_func z_alloc_func -# define charf z_charf -# define free_func z_free_func -# ifndef Z_SOLO -# define gzFile z_gzFile -# endif -# define gz_header z_gz_header -# define gz_headerp z_gz_headerp -# define in_func z_in_func -# define intf z_intf -# define out_func z_out_func -# define uInt z_uInt -# define uIntf z_uIntf -# define uLong z_uLong -# define uLongf z_uLongf -# define voidp z_voidp -# define voidpc z_voidpc -# define voidpf z_voidpf - -/* all zlib structs in zlib.h and zconf.h */ -# define gz_header_s z_gz_header_s -# define internal_state z_internal_state - -#endif - -#if defined(__MSDOS__) && !defined(MSDOS) -# define MSDOS -#endif -#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2) -# define OS2 -#endif -#if defined(_WINDOWS) && !defined(WINDOWS) -# define WINDOWS -#endif -#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__) -# ifndef WIN32 -# define WIN32 -# endif -#endif -#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32) -# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__) -# ifndef SYS16BIT -# define SYS16BIT -# endif -# endif -#endif - -/* - * Compile with -DMAXSEG_64K if the alloc function cannot allocate more - * than 64k bytes at a time (needed on systems with 16-bit int). - */ -#ifdef SYS16BIT -# define MAXSEG_64K -#endif -#ifdef MSDOS -# define UNALIGNED_OK -#endif - -#ifdef __STDC_VERSION__ -# ifndef STDC -# define STDC -# endif -# if __STDC_VERSION__ >= 199901L -# ifndef STDC99 -# define STDC99 -# endif -# endif -#endif -#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus)) -# define STDC -#endif -#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__)) -# define STDC -#endif -#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32)) -# define STDC -#endif -#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__)) -# define STDC -#endif - -#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */ -# define STDC -#endif - -#ifndef STDC -# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ -# define const /* note: need a more gentle solution here */ -# endif -#endif - -#if defined(ZLIB_CONST) && !defined(z_const) -# define z_const const -#else -# define z_const -#endif - -#ifdef Z_SOLO - typedef unsigned long z_size_t; -#else -# define z_longlong long long -# if defined(NO_SIZE_T) - typedef unsigned NO_SIZE_T z_size_t; -# elif defined(STDC) -# include - typedef size_t z_size_t; -# else - typedef unsigned long z_size_t; -# endif -# undef z_longlong -#endif - -/* Maximum value for memLevel in deflateInit2 */ -#ifndef MAX_MEM_LEVEL -# ifdef MAXSEG_64K -# define MAX_MEM_LEVEL 8 -# else -# define MAX_MEM_LEVEL 9 -# endif -#endif - -/* Maximum value for windowBits in deflateInit2 and inflateInit2. - * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files - * created by gzip. (Files created by minigzip can still be extracted by - * gzip.) - */ -#ifndef MAX_WBITS -# define MAX_WBITS 15 /* 32K LZ77 window */ -#endif - -/* The memory requirements for deflate are (in bytes): - (1 << (windowBits+2)) + (1 << (memLevel+9)) - that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) - plus a few kilobytes for small objects. For example, if you want to reduce - the default memory requirements from 256K to 128K, compile with - make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" - Of course this will generally degrade compression (there's no free lunch). - - The memory requirements for inflate are (in bytes) 1 << windowBits - that is, 32K for windowBits=15 (default value) plus about 7 kilobytes - for small objects. -*/ - - /* Type declarations */ - -#ifndef OF /* function prototypes */ -# ifdef STDC -# define OF(args) args -# else -# define OF(args) () -# endif -#endif - -#ifndef Z_ARG /* function prototypes for stdarg */ -# if defined(STDC) || defined(Z_HAVE_STDARG_H) -# define Z_ARG(args) args -# else -# define Z_ARG(args) () -# endif -#endif - -/* The following definitions for FAR are needed only for MSDOS mixed - * model programming (small or medium model with some far allocations). - * This was tested only with MSC; for other MSDOS compilers you may have - * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, - * just define FAR to be empty. - */ -#ifdef SYS16BIT -# if defined(M_I86SM) || defined(M_I86MM) - /* MSC small or medium model */ -# define SMALL_MEDIUM -# ifdef _MSC_VER -# define FAR _far -# else -# define FAR far -# endif -# endif -# if (defined(__SMALL__) || defined(__MEDIUM__)) - /* Turbo C small or medium model */ -# define SMALL_MEDIUM -# ifdef __BORLANDC__ -# define FAR _far -# else -# define FAR far -# endif -# endif -#endif - -#if defined(WINDOWS) || defined(WIN32) - /* If building or using zlib as a DLL, define ZLIB_DLL. - * This is not mandatory, but it offers a little performance increase. - */ -# ifdef ZLIB_DLL -# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500)) -# ifdef ZLIB_INTERNAL -# define ZEXTERN extern __declspec(dllexport) -# else -# define ZEXTERN extern __declspec(dllimport) -# endif -# endif -# endif /* ZLIB_DLL */ - /* If building or using zlib with the WINAPI/WINAPIV calling convention, - * define ZLIB_WINAPI. - * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI. - */ -# ifdef ZLIB_WINAPI -# ifdef FAR -# undef FAR -# endif -# include - /* No need for _export, use ZLIB.DEF instead. */ - /* For complete Windows compatibility, use WINAPI, not __stdcall. */ -# define ZEXPORT WINAPI -# ifdef WIN32 -# define ZEXPORTVA WINAPIV -# else -# define ZEXPORTVA FAR CDECL -# endif -# endif -#endif - -#if defined (__BEOS__) -# ifdef ZLIB_DLL -# ifdef ZLIB_INTERNAL -# define ZEXPORT __declspec(dllexport) -# define ZEXPORTVA __declspec(dllexport) -# else -# define ZEXPORT __declspec(dllimport) -# define ZEXPORTVA __declspec(dllimport) -# endif -# endif -#endif - -#ifndef ZEXTERN -# define ZEXTERN extern -#endif -#ifndef ZEXPORT -# define ZEXPORT -#endif -#ifndef ZEXPORTVA -# define ZEXPORTVA -#endif - -#ifndef FAR -# define FAR -#endif - -#if !defined(__MACTYPES__) -typedef unsigned char Byte; /* 8 bits */ -#endif -typedef unsigned int uInt; /* 16 bits or more */ -typedef unsigned long uLong; /* 32 bits or more */ - -#ifdef SMALL_MEDIUM - /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */ -# define Bytef Byte FAR -#else - typedef Byte FAR Bytef; -#endif -typedef char FAR charf; -typedef int FAR intf; -typedef uInt FAR uIntf; -typedef uLong FAR uLongf; - -#ifdef STDC - typedef void const *voidpc; - typedef void FAR *voidpf; - typedef void *voidp; -#else - typedef Byte const *voidpc; - typedef Byte FAR *voidpf; - typedef Byte *voidp; -#endif - -#if !defined(Z_U4) && !defined(Z_SOLO) && defined(STDC) -# include -# if (UINT_MAX == 0xffffffffUL) -# define Z_U4 unsigned -# elif (ULONG_MAX == 0xffffffffUL) -# define Z_U4 unsigned long -# elif (USHRT_MAX == 0xffffffffUL) -# define Z_U4 unsigned short -# endif -#endif - -#ifdef Z_U4 - typedef Z_U4 z_crc_t; -#else - typedef unsigned long z_crc_t; -#endif - -#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */ -# define Z_HAVE_UNISTD_H -#endif - -#ifdef HAVE_STDARG_H /* may be set to #if 1 by ./configure */ -# define Z_HAVE_STDARG_H -#endif - -#ifdef STDC -# ifndef Z_SOLO -# include /* for off_t */ -# endif -#endif - -#if defined(STDC) || defined(Z_HAVE_STDARG_H) -# ifndef Z_SOLO -# include /* for va_list */ -# endif -#endif - -#ifdef _WIN32 -# ifndef Z_SOLO -# include /* for wchar_t */ -# endif -#endif - -/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and - * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even - * though the former does not conform to the LFS document), but considering - * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as - * equivalently requesting no 64-bit operations - */ -#if defined(_LARGEFILE64_SOURCE) && -_LARGEFILE64_SOURCE - -1 == 1 -# undef _LARGEFILE64_SOURCE -#endif - -#if defined(__WATCOMC__) && !defined(Z_HAVE_UNISTD_H) -# define Z_HAVE_UNISTD_H -#endif -#ifndef Z_SOLO -# if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE) -# include /* for SEEK_*, off_t, and _LFS64_LARGEFILE */ -# ifdef VMS -# include /* for off_t */ -# endif -# ifndef z_off_t -# define z_off_t off_t -# endif -# endif -#endif - -#if defined(_LFS64_LARGEFILE) && _LFS64_LARGEFILE-0 -# define Z_LFS64 -#endif - -#if defined(_LARGEFILE64_SOURCE) && defined(Z_LFS64) -# define Z_LARGE64 -#endif - -#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS-0 == 64 && defined(Z_LFS64) -# define Z_WANT64 -#endif - -#if !defined(SEEK_SET) && !defined(Z_SOLO) -# define SEEK_SET 0 /* Seek from beginning of file. */ -# define SEEK_CUR 1 /* Seek from current position. */ -# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ -#endif - -#ifndef z_off_t -# define z_off_t long -#endif - -#if !defined(_WIN32) && defined(Z_LARGE64) -# define z_off64_t off64_t -#else -# if defined(_WIN32) && !defined(__GNUC__) && !defined(Z_SOLO) -# define z_off64_t __int64 -# else -# define z_off64_t z_off_t -# endif -#endif - -/* MVS linker does not support external names larger than 8 bytes */ -#if defined(__MVS__) - #pragma map(deflateInit_,"DEIN") - #pragma map(deflateInit2_,"DEIN2") - #pragma map(deflateEnd,"DEEND") - #pragma map(deflateBound,"DEBND") - #pragma map(inflateInit_,"ININ") - #pragma map(inflateInit2_,"ININ2") - #pragma map(inflateEnd,"INEND") - #pragma map(inflateSync,"INSY") - #pragma map(inflateSetDictionary,"INSEDI") - #pragma map(compressBound,"CMBND") - #pragma map(inflate_table,"INTABL") - #pragma map(inflate_fast,"INFA") - #pragma map(inflate_copyright,"INCOPY") -#endif - -#endif /* ZCONF_H */ diff --git a/src/common/dep/zlib/zlib.h b/src/common/dep/zlib/zlib.h deleted file mode 100644 index f09cdaf1e..000000000 --- a/src/common/dep/zlib/zlib.h +++ /dev/null @@ -1,1912 +0,0 @@ -/* zlib.h -- interface of the 'zlib' general purpose compression library - version 1.2.11, January 15th, 2017 - - Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Jean-loup Gailly Mark Adler - jloup@gzip.org madler@alumni.caltech.edu - - - The data format used by the zlib library is described by RFCs (Request for - Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 - (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). -*/ - -#ifndef ZLIB_H -#define ZLIB_H - -#include "zconf.h" - -#ifdef __cplusplus -extern "C" { -#endif - -#define ZLIB_VERSION "1.2.11" -#define ZLIB_VERNUM 0x12b0 -#define ZLIB_VER_MAJOR 1 -#define ZLIB_VER_MINOR 2 -#define ZLIB_VER_REVISION 11 -#define ZLIB_VER_SUBREVISION 0 - -/* - The 'zlib' compression library provides in-memory compression and - decompression functions, including integrity checks of the uncompressed data. - This version of the library supports only one compression method (deflation) - but other algorithms will be added later and will have the same stream - interface. - - Compression can be done in a single step if the buffers are large enough, - or can be done by repeated calls of the compression function. In the latter - case, the application must provide more input and/or consume the output - (providing more output space) before each call. - - The compressed data format used by default by the in-memory functions is - the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped - around a deflate stream, which is itself documented in RFC 1951. - - The library also supports reading and writing files in gzip (.gz) format - with an interface similar to that of stdio using the functions that start - with "gz". The gzip format is different from the zlib format. gzip is a - gzip wrapper, documented in RFC 1952, wrapped around a deflate stream. - - This library can optionally read and write gzip and raw deflate streams in - memory as well. - - The zlib format was designed to be compact and fast for use in memory - and on communications channels. The gzip format was designed for single- - file compression on file systems, has a larger header than zlib to maintain - directory information, and uses a different, slower check method than zlib. - - The library does not install any signal handler. The decoder checks - the consistency of the compressed data, so the library should never crash - even in the case of corrupted input. -*/ - -typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); -typedef void (*free_func) OF((voidpf opaque, voidpf address)); - -struct internal_state; - -typedef struct z_stream_s { - z_const Bytef *next_in; /* next input byte */ - uInt avail_in; /* number of bytes available at next_in */ - uLong total_in; /* total number of input bytes read so far */ - - Bytef *next_out; /* next output byte will go here */ - uInt avail_out; /* remaining free space at next_out */ - uLong total_out; /* total number of bytes output so far */ - - z_const char *msg; /* last error message, NULL if no error */ - struct internal_state FAR *state; /* not visible by applications */ - - alloc_func zalloc; /* used to allocate the internal state */ - free_func zfree; /* used to free the internal state */ - voidpf opaque; /* private data object passed to zalloc and zfree */ - - int data_type; /* best guess about the data type: binary or text - for deflate, or the decoding state for inflate */ - uLong adler; /* Adler-32 or CRC-32 value of the uncompressed data */ - uLong reserved; /* reserved for future use */ -} z_stream; - -typedef z_stream FAR *z_streamp; - -/* - gzip header information passed to and from zlib routines. See RFC 1952 - for more details on the meanings of these fields. -*/ -typedef struct gz_header_s { - int text; /* true if compressed data believed to be text */ - uLong time; /* modification time */ - int xflags; /* extra flags (not used when writing a gzip file) */ - int os; /* operating system */ - Bytef *extra; /* pointer to extra field or Z_NULL if none */ - uInt extra_len; /* extra field length (valid if extra != Z_NULL) */ - uInt extra_max; /* space at extra (only when reading header) */ - Bytef *name; /* pointer to zero-terminated file name or Z_NULL */ - uInt name_max; /* space at name (only when reading header) */ - Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */ - uInt comm_max; /* space at comment (only when reading header) */ - int hcrc; /* true if there was or will be a header crc */ - int done; /* true when done reading gzip header (not used - when writing a gzip file) */ -} gz_header; - -typedef gz_header FAR *gz_headerp; - -/* - The application must update next_in and avail_in when avail_in has dropped - to zero. It must update next_out and avail_out when avail_out has dropped - to zero. The application must initialize zalloc, zfree and opaque before - calling the init function. All other fields are set by the compression - library and must not be updated by the application. - - The opaque value provided by the application will be passed as the first - parameter for calls of zalloc and zfree. This can be useful for custom - memory management. The compression library attaches no meaning to the - opaque value. - - zalloc must return Z_NULL if there is not enough memory for the object. - If zlib is used in a multi-threaded application, zalloc and zfree must be - thread safe. In that case, zlib is thread-safe. When zalloc and zfree are - Z_NULL on entry to the initialization function, they are set to internal - routines that use the standard library functions malloc() and free(). - - On 16-bit systems, the functions zalloc and zfree must be able to allocate - exactly 65536 bytes, but will not be required to allocate more than this if - the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers - returned by zalloc for objects of exactly 65536 bytes *must* have their - offset normalized to zero. The default allocation function provided by this - library ensures this (see zutil.c). To reduce memory requirements and avoid - any allocation of 64K objects, at the expense of compression ratio, compile - the library with -DMAX_WBITS=14 (see zconf.h). - - The fields total_in and total_out can be used for statistics or progress - reports. After compression, total_in holds the total size of the - uncompressed data and may be saved for use by the decompressor (particularly - if the decompressor wants to decompress everything in a single step). -*/ - - /* constants */ - -#define Z_NO_FLUSH 0 -#define Z_PARTIAL_FLUSH 1 -#define Z_SYNC_FLUSH 2 -#define Z_FULL_FLUSH 3 -#define Z_FINISH 4 -#define Z_BLOCK 5 -#define Z_TREES 6 -/* Allowed flush values; see deflate() and inflate() below for details */ - -#define Z_OK 0 -#define Z_STREAM_END 1 -#define Z_NEED_DICT 2 -#define Z_ERRNO (-1) -#define Z_STREAM_ERROR (-2) -#define Z_DATA_ERROR (-3) -#define Z_MEM_ERROR (-4) -#define Z_BUF_ERROR (-5) -#define Z_VERSION_ERROR (-6) -/* Return codes for the compression/decompression functions. Negative values - * are errors, positive values are used for special but normal events. - */ - -#define Z_NO_COMPRESSION 0 -#define Z_BEST_SPEED 1 -#define Z_BEST_COMPRESSION 9 -#define Z_DEFAULT_COMPRESSION (-1) -/* compression levels */ - -#define Z_FILTERED 1 -#define Z_HUFFMAN_ONLY 2 -#define Z_RLE 3 -#define Z_FIXED 4 -#define Z_DEFAULT_STRATEGY 0 -/* compression strategy; see deflateInit2() below for details */ - -#define Z_BINARY 0 -#define Z_TEXT 1 -#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */ -#define Z_UNKNOWN 2 -/* Possible values of the data_type field for deflate() */ - -#define Z_DEFLATED 8 -/* The deflate compression method (the only one supported in this version) */ - -#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ - -#define zlib_version zlibVersion() -/* for compatibility with versions < 1.0.2 */ - - - /* basic functions */ - -ZEXTERN const char * ZEXPORT zlibVersion OF((void)); -/* The application can compare zlibVersion and ZLIB_VERSION for consistency. - If the first character differs, the library code actually used is not - compatible with the zlib.h header file used by the application. This check - is automatically made by deflateInit and inflateInit. - */ - -/* -ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level)); - - Initializes the internal stream state for compression. The fields - zalloc, zfree and opaque must be initialized before by the caller. If - zalloc and zfree are set to Z_NULL, deflateInit updates them to use default - allocation functions. - - The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: - 1 gives best speed, 9 gives best compression, 0 gives no compression at all - (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION - requests a default compromise between speed and compression (currently - equivalent to level 6). - - deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if level is not a valid compression level, or - Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible - with the version assumed by the caller (ZLIB_VERSION). msg is set to null - if there is no error message. deflateInit does not perform any compression: - this will be done by deflate(). -*/ - - -ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush)); -/* - deflate compresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. deflate performs one or both of the - following actions: - - - Compress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), next_in and avail_in are updated and - processing will resume at this point for the next call of deflate(). - - - Generate more output starting at next_out and update next_out and avail_out - accordingly. This action is forced if the parameter flush is non zero. - Forcing flush frequently degrades the compression ratio, so this parameter - should be set only when necessary. Some output may be provided even if - flush is zero. - - Before the call of deflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming more - output, and updating avail_in or avail_out accordingly; avail_out should - never be zero before the call. The application can consume the compressed - output when it wants, for example when the output buffer is full (avail_out - == 0), or after each call of deflate(). If deflate returns Z_OK and with - zero avail_out, it must be called again after making room in the output - buffer because there might be more output pending. See deflatePending(), - which can be used if desired to determine whether or not there is more ouput - in that case. - - Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to - decide how much data to accumulate before producing output, in order to - maximize compression. - - If the parameter flush is set to Z_SYNC_FLUSH, all pending output is - flushed to the output buffer and the output is aligned on a byte boundary, so - that the decompressor can get all input data available so far. (In - particular avail_in is zero after the call if enough output space has been - provided before the call.) Flushing may degrade compression for some - compression algorithms and so it should be used only when necessary. This - completes the current deflate block and follows it with an empty stored block - that is three bits plus filler bits to the next byte, followed by four bytes - (00 00 ff ff). - - If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the - output buffer, but the output is not aligned to a byte boundary. All of the - input data so far will be available to the decompressor, as for Z_SYNC_FLUSH. - This completes the current deflate block and follows it with an empty fixed - codes block that is 10 bits long. This assures that enough bytes are output - in order for the decompressor to finish the block before the empty fixed - codes block. - - If flush is set to Z_BLOCK, a deflate block is completed and emitted, as - for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to - seven bits of the current block are held to be written as the next byte after - the next deflate block is completed. In this case, the decompressor may not - be provided enough bits at this point in order to complete decompression of - the data provided so far to the compressor. It may need to wait for the next - block to be emitted. This is for advanced applications that need to control - the emission of deflate blocks. - - If flush is set to Z_FULL_FLUSH, all output is flushed as with - Z_SYNC_FLUSH, and the compression state is reset so that decompression can - restart from this point if previous compressed data has been damaged or if - random access is desired. Using Z_FULL_FLUSH too often can seriously degrade - compression. - - If deflate returns with avail_out == 0, this function must be called again - with the same value of the flush parameter and more output space (updated - avail_out), until the flush is complete (deflate returns with non-zero - avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that - avail_out is greater than six to avoid repeated flush markers due to - avail_out == 0 on return. - - If the parameter flush is set to Z_FINISH, pending input is processed, - pending output is flushed and deflate returns with Z_STREAM_END if there was - enough output space. If deflate returns with Z_OK or Z_BUF_ERROR, this - function must be called again with Z_FINISH and more output space (updated - avail_out) but no more input data, until it returns with Z_STREAM_END or an - error. After deflate has returned Z_STREAM_END, the only possible operations - on the stream are deflateReset or deflateEnd. - - Z_FINISH can be used in the first deflate call after deflateInit if all the - compression is to be done in a single step. In order to complete in one - call, avail_out must be at least the value returned by deflateBound (see - below). Then deflate is guaranteed to return Z_STREAM_END. If not enough - output space is provided, deflate will not return Z_STREAM_END, and it must - be called again as described above. - - deflate() sets strm->adler to the Adler-32 checksum of all input read - so far (that is, total_in bytes). If a gzip stream is being generated, then - strm->adler will be the CRC-32 checksum of the input read so far. (See - deflateInit2 below.) - - deflate() may update strm->data_type if it can make a good guess about - the input data type (Z_BINARY or Z_TEXT). If in doubt, the data is - considered binary. This field is only for information purposes and does not - affect the compression algorithm in any manner. - - deflate() returns Z_OK if some progress has been made (more input - processed or more output produced), Z_STREAM_END if all input has been - consumed and all output has been produced (only when flush is set to - Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example - if next_in or next_out was Z_NULL or the state was inadvertently written over - by the application), or Z_BUF_ERROR if no progress is possible (for example - avail_in or avail_out was zero). Note that Z_BUF_ERROR is not fatal, and - deflate() can be called again with more input and more output space to - continue compressing. -*/ - - -ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any pending - output. - - deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the - stream state was inconsistent, Z_DATA_ERROR if the stream was freed - prematurely (some input or output was discarded). In the error case, msg - may be set but then points to a static string (which must not be - deallocated). -*/ - - -/* -ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm)); - - Initializes the internal stream state for decompression. The fields - next_in, avail_in, zalloc, zfree and opaque must be initialized before by - the caller. In the current version of inflate, the provided input is not - read or consumed. The allocation of a sliding window will be deferred to - the first call of inflate (if the decompression does not complete on the - first call). If zalloc and zfree are set to Z_NULL, inflateInit updates - them to use default allocation functions. - - inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller, or Z_STREAM_ERROR if the parameters are - invalid, such as a null pointer to the structure. msg is set to null if - there is no error message. inflateInit does not perform any decompression. - Actual decompression will be done by inflate(). So next_in, and avail_in, - next_out, and avail_out are unused and unchanged. The current - implementation of inflateInit() does not process any header information -- - that is deferred until inflate() is called. -*/ - - -ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush)); -/* - inflate decompresses as much data as possible, and stops when the input - buffer becomes empty or the output buffer becomes full. It may introduce - some output latency (reading input without producing any output) except when - forced to flush. - - The detailed semantics are as follows. inflate performs one or both of the - following actions: - - - Decompress more input starting at next_in and update next_in and avail_in - accordingly. If not all input can be processed (because there is not - enough room in the output buffer), then next_in and avail_in are updated - accordingly, and processing will resume at this point for the next call of - inflate(). - - - Generate more output starting at next_out and update next_out and avail_out - accordingly. inflate() provides as much output as possible, until there is - no more input data or no more space in the output buffer (see below about - the flush parameter). - - Before the call of inflate(), the application should ensure that at least - one of the actions is possible, by providing more input and/or consuming more - output, and updating the next_* and avail_* values accordingly. If the - caller of inflate() does not provide both available input and available - output space, it is possible that there will be no progress made. The - application can consume the uncompressed output when it wants, for example - when the output buffer is full (avail_out == 0), or after each call of - inflate(). If inflate returns Z_OK and with zero avail_out, it must be - called again after making room in the output buffer because there might be - more output pending. - - The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH, - Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much - output as possible to the output buffer. Z_BLOCK requests that inflate() - stop if and when it gets to the next deflate block boundary. When decoding - the zlib or gzip format, this will cause inflate() to return immediately - after the header and before the first block. When doing a raw inflate, - inflate() will go ahead and process the first block, and will return when it - gets to the end of that block, or when it runs out of data. - - The Z_BLOCK option assists in appending to or combining deflate streams. - To assist in this, on return inflate() always sets strm->data_type to the - number of unused bits in the last byte taken from strm->next_in, plus 64 if - inflate() is currently decoding the last block in the deflate stream, plus - 128 if inflate() returned immediately after decoding an end-of-block code or - decoding the complete header up to just before the first byte of the deflate - stream. The end-of-block will not be indicated until all of the uncompressed - data from that block has been written to strm->next_out. The number of - unused bits may in general be greater than seven, except when bit 7 of - data_type is set, in which case the number of unused bits will be less than - eight. data_type is set as noted here every time inflate() returns for all - flush options, and so can be used to determine the amount of currently - consumed input in bits. - - The Z_TREES option behaves as Z_BLOCK does, but it also returns when the - end of each deflate block header is reached, before any actual data in that - block is decoded. This allows the caller to determine the length of the - deflate block header for later use in random access within a deflate block. - 256 is added to the value of strm->data_type when inflate() returns - immediately after reaching the end of the deflate block header. - - inflate() should normally be called until it returns Z_STREAM_END or an - error. However if all decompression is to be performed in a single step (a - single call of inflate), the parameter flush should be set to Z_FINISH. In - this case all pending input is processed and all pending output is flushed; - avail_out must be large enough to hold all of the uncompressed data for the - operation to complete. (The size of the uncompressed data may have been - saved by the compressor for this purpose.) The use of Z_FINISH is not - required to perform an inflation in one step. However it may be used to - inform inflate that a faster approach can be used for the single inflate() - call. Z_FINISH also informs inflate to not maintain a sliding window if the - stream completes, which reduces inflate's memory footprint. If the stream - does not complete, either because not all of the stream is provided or not - enough output space is provided, then a sliding window will be allocated and - inflate() can be called again to continue the operation as if Z_NO_FLUSH had - been used. - - In this implementation, inflate() always flushes as much output as - possible to the output buffer, and always uses the faster approach on the - first call. So the effects of the flush parameter in this implementation are - on the return value of inflate() as noted below, when inflate() returns early - when Z_BLOCK or Z_TREES is used, and when inflate() avoids the allocation of - memory for a sliding window when Z_FINISH is used. - - If a preset dictionary is needed after this call (see inflateSetDictionary - below), inflate sets strm->adler to the Adler-32 checksum of the dictionary - chosen by the compressor and returns Z_NEED_DICT; otherwise it sets - strm->adler to the Adler-32 checksum of all output produced so far (that is, - total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described - below. At the end of the stream, inflate() checks that its computed Adler-32 - checksum is equal to that saved by the compressor and returns Z_STREAM_END - only if the checksum is correct. - - inflate() can decompress and check either zlib-wrapped or gzip-wrapped - deflate data. The header type is detected automatically, if requested when - initializing with inflateInit2(). Any information contained in the gzip - header is not retained unless inflateGetHeader() is used. When processing - gzip-wrapped deflate data, strm->adler32 is set to the CRC-32 of the output - produced so far. The CRC-32 is checked against the gzip trailer, as is the - uncompressed length, modulo 2^32. - - inflate() returns Z_OK if some progress has been made (more input processed - or more output produced), Z_STREAM_END if the end of the compressed data has - been reached and all uncompressed output has been produced, Z_NEED_DICT if a - preset dictionary is needed at this point, Z_DATA_ERROR if the input data was - corrupted (input stream not conforming to the zlib format or incorrect check - value, in which case strm->msg points to a string with a more specific - error), Z_STREAM_ERROR if the stream structure was inconsistent (for example - next_in or next_out was Z_NULL, or the state was inadvertently written over - by the application), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR - if no progress was possible or if there was not enough room in the output - buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and - inflate() can be called again with more input and more output space to - continue decompressing. If Z_DATA_ERROR is returned, the application may - then call inflateSync() to look for a good compression block if a partial - recovery of the data is to be attempted. -*/ - - -ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm)); -/* - All dynamically allocated data structures for this stream are freed. - This function discards any unprocessed input and does not flush any pending - output. - - inflateEnd returns Z_OK if success, or Z_STREAM_ERROR if the stream state - was inconsistent. -*/ - - - /* Advanced functions */ - -/* - The following functions are needed only in some special applications. -*/ - -/* -ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm, - int level, - int method, - int windowBits, - int memLevel, - int strategy)); - - This is another version of deflateInit with more compression options. The - fields next_in, zalloc, zfree and opaque must be initialized before by the - caller. - - The method parameter is the compression method. It must be Z_DEFLATED in - this version of the library. - - The windowBits parameter is the base two logarithm of the window size - (the size of the history buffer). It should be in the range 8..15 for this - version of the library. Larger values of this parameter result in better - compression at the expense of memory usage. The default value is 15 if - deflateInit is used instead. - - For the current implementation of deflate(), a windowBits value of 8 (a - window size of 256 bytes) is not supported. As a result, a request for 8 - will result in 9 (a 512-byte window). In that case, providing 8 to - inflateInit2() will result in an error when the zlib header with 9 is - checked against the initialization of inflate(). The remedy is to not use 8 - with deflateInit2() with this initialization, or at least in that case use 9 - with inflateInit2(). - - windowBits can also be -8..-15 for raw deflate. In this case, -windowBits - determines the window size. deflate() will then generate raw deflate data - with no zlib header or trailer, and will not compute a check value. - - windowBits can also be greater than 15 for optional gzip encoding. Add - 16 to windowBits to write a simple gzip header and trailer around the - compressed data instead of a zlib wrapper. The gzip header will have no - file name, no extra data, no comment, no modification time (set to zero), no - header crc, and the operating system will be set to the appropriate value, - if the operating system was determined at compile time. If a gzip stream is - being written, strm->adler is a CRC-32 instead of an Adler-32. - - For raw deflate or gzip encoding, a request for a 256-byte window is - rejected as invalid, since only the zlib header provides a means of - transmitting the window size to the decompressor. - - The memLevel parameter specifies how much memory should be allocated - for the internal compression state. memLevel=1 uses minimum memory but is - slow and reduces compression ratio; memLevel=9 uses maximum memory for - optimal speed. The default value is 8. See zconf.h for total memory usage - as a function of windowBits and memLevel. - - The strategy parameter is used to tune the compression algorithm. Use the - value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a - filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no - string match), or Z_RLE to limit match distances to one (run-length - encoding). Filtered data consists mostly of small values with a somewhat - random distribution. In this case, the compression algorithm is tuned to - compress them better. The effect of Z_FILTERED is to force more Huffman - coding and less string matching; it is somewhat intermediate between - Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as - fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The - strategy parameter only affects the compression ratio but not the - correctness of the compressed output even if it is not set appropriately. - Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler - decoder for special applications. - - deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid - method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is - incompatible with the version assumed by the caller (ZLIB_VERSION). msg is - set to null if there is no error message. deflateInit2 does not perform any - compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the compression dictionary from the given byte sequence - without producing any compressed output. When using the zlib format, this - function must be called immediately after deflateInit, deflateInit2 or - deflateReset, and before any call of deflate. When doing raw deflate, this - function must be called either before any call of deflate, or immediately - after the completion of a deflate block, i.e. after all input has been - consumed and all output has been delivered when using any of the flush - options Z_BLOCK, Z_PARTIAL_FLUSH, Z_SYNC_FLUSH, or Z_FULL_FLUSH. The - compressor and decompressor must use exactly the same dictionary (see - inflateSetDictionary). - - The dictionary should consist of strings (byte sequences) that are likely - to be encountered later in the data to be compressed, with the most commonly - used strings preferably put towards the end of the dictionary. Using a - dictionary is most useful when the data to be compressed is short and can be - predicted with good accuracy; the data can then be compressed better than - with the default empty dictionary. - - Depending on the size of the compression data structures selected by - deflateInit or deflateInit2, a part of the dictionary may in effect be - discarded, for example if the dictionary is larger than the window size - provided in deflateInit or deflateInit2. Thus the strings most likely to be - useful should be put at the end of the dictionary, not at the front. In - addition, the current implementation of deflate will use at most the window - size minus 262 bytes of the provided dictionary. - - Upon return of this function, strm->adler is set to the Adler-32 value - of the dictionary; the decompressor may later use this value to determine - which dictionary has been used by the compressor. (The Adler-32 value - applies to the whole dictionary even if only a subset of the dictionary is - actually used by the compressor.) If a raw deflate was requested, then the - Adler-32 value is not computed and strm->adler is not set. - - deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a - parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is - inconsistent (for example if deflate has already been called for this stream - or if not at a block boundary for raw deflate). deflateSetDictionary does - not perform any compression: this will be done by deflate(). -*/ - -ZEXTERN int ZEXPORT deflateGetDictionary OF((z_streamp strm, - Bytef *dictionary, - uInt *dictLength)); -/* - Returns the sliding dictionary being maintained by deflate. dictLength is - set to the number of bytes in the dictionary, and that many bytes are copied - to dictionary. dictionary must have enough space, where 32768 bytes is - always enough. If deflateGetDictionary() is called with dictionary equal to - Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. - - deflateGetDictionary() may return a length less than the window size, even - when more than the window size in input has been provided. It may return up - to 258 bytes less in that case, due to how zlib's implementation of deflate - manages the sliding window and lookahead for matches, where matches can be - up to 258 bytes long. If the application needs the last window-size bytes of - input, then that would need to be saved by the application outside of zlib. - - deflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the - stream state is inconsistent. -*/ - -ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when several compression strategies will be - tried, for example when there are several ways of pre-processing the input - data with a filter. The streams that will be discarded should then be freed - by calling deflateEnd. Note that deflateCopy duplicates the internal - compression state which can be quite large, so this strategy is slow and can - consume lots of memory. - - deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being Z_NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm)); -/* - This function is equivalent to deflateEnd followed by deflateInit, but - does not free and reallocate the internal compression state. The stream - will leave the compression level and any other attributes that may have been - set unchanged. - - deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being Z_NULL). -*/ - -ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm, - int level, - int strategy)); -/* - Dynamically update the compression level and compression strategy. The - interpretation of level and strategy is as in deflateInit2(). This can be - used to switch between compression and straight copy of the input data, or - to switch to a different kind of input data requiring a different strategy. - If the compression approach (which is a function of the level) or the - strategy is changed, and if any input has been consumed in a previous - deflate() call, then the input available so far is compressed with the old - level and strategy using deflate(strm, Z_BLOCK). There are three approaches - for the compression levels 0, 1..3, and 4..9 respectively. The new level - and strategy will take effect at the next call of deflate(). - - If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does - not have enough output space to complete, then the parameter change will not - take effect. In this case, deflateParams() can be called again with the - same parameters and more output space to try again. - - In order to assure a change in the parameters on the first try, the - deflate stream should be flushed using deflate() with Z_BLOCK or other flush - request until strm.avail_out is not zero, before calling deflateParams(). - Then no more input data should be provided before the deflateParams() call. - If this is done, the old level and strategy will be applied to the data - compressed before deflateParams(), and the new level and strategy will be - applied to the the data compressed after deflateParams(). - - deflateParams returns Z_OK on success, Z_STREAM_ERROR if the source stream - state was inconsistent or if a parameter was invalid, or Z_BUF_ERROR if - there was not enough output space to complete the compression of the - available input data before a change in the strategy or approach. Note that - in the case of a Z_BUF_ERROR, the parameters are not changed. A return - value of Z_BUF_ERROR is not fatal, in which case deflateParams() can be - retried with more output space. -*/ - -ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm, - int good_length, - int max_lazy, - int nice_length, - int max_chain)); -/* - Fine tune deflate's internal compression parameters. This should only be - used by someone who understands the algorithm used by zlib's deflate for - searching for the best matching string, and even then only by the most - fanatic optimizer trying to squeeze out the last compressed bit for their - specific input data. Read the deflate.c source code for the meaning of the - max_lazy, good_length, nice_length, and max_chain parameters. - - deflateTune() can be called after deflateInit() or deflateInit2(), and - returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream. - */ - -ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm, - uLong sourceLen)); -/* - deflateBound() returns an upper bound on the compressed size after - deflation of sourceLen bytes. It must be called after deflateInit() or - deflateInit2(), and after deflateSetHeader(), if used. This would be used - to allocate an output buffer for deflation in a single pass, and so would be - called before deflate(). If that first deflate() call is provided the - sourceLen input bytes, an output buffer allocated to the size returned by - deflateBound(), and the flush value Z_FINISH, then deflate() is guaranteed - to return Z_STREAM_END. Note that it is possible for the compressed size to - be larger than the value returned by deflateBound() if flush options other - than Z_FINISH or Z_NO_FLUSH are used. -*/ - -ZEXTERN int ZEXPORT deflatePending OF((z_streamp strm, - unsigned *pending, - int *bits)); -/* - deflatePending() returns the number of bytes and bits of output that have - been generated, but not yet provided in the available output. The bytes not - provided would be due to the available output space having being consumed. - The number of bits of output not provided are between 0 and 7, where they - await more bits to join them in order to fill out a full byte. If pending - or bits are Z_NULL, then those values are not set. - - deflatePending returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. - */ - -ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - deflatePrime() inserts bits in the deflate output stream. The intent - is that this function is used to start off the deflate output with the bits - leftover from a previous deflate stream when appending to it. As such, this - function can only be used for raw deflate, and must be used before the first - deflate() call after a deflateInit2() or deflateReset(). bits must be less - than or equal to 16, and that many of the least significant bits of value - will be inserted in the output. - - deflatePrime returns Z_OK if success, Z_BUF_ERROR if there was not enough - room in the internal buffer to insert the bits, or Z_STREAM_ERROR if the - source stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm, - gz_headerp head)); -/* - deflateSetHeader() provides gzip header information for when a gzip - stream is requested by deflateInit2(). deflateSetHeader() may be called - after deflateInit2() or deflateReset() and before the first call of - deflate(). The text, time, os, extra field, name, and comment information - in the provided gz_header structure are written to the gzip header (xflag is - ignored -- the extra flags are set according to the compression level). The - caller must assure that, if not Z_NULL, name and comment are terminated with - a zero byte, and that if extra is not Z_NULL, that extra_len bytes are - available there. If hcrc is true, a gzip header crc is included. Note that - the current versions of the command-line version of gzip (up through version - 1.3.x) do not support header crc's, and will report that it is a "multi-part - gzip file" and give up. - - If deflateSetHeader is not used, the default gzip header has text false, - the time set to zero, and os set to 255, with no extra, name, or comment - fields. The gzip header is returned to the default state by deflateReset(). - - deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm, - int windowBits)); - - This is another version of inflateInit with an extra parameter. The - fields next_in, avail_in, zalloc, zfree and opaque must be initialized - before by the caller. - - The windowBits parameter is the base two logarithm of the maximum window - size (the size of the history buffer). It should be in the range 8..15 for - this version of the library. The default value is 15 if inflateInit is used - instead. windowBits must be greater than or equal to the windowBits value - provided to deflateInit2() while compressing, or it must be equal to 15 if - deflateInit2() was not used. If a compressed stream with a larger window - size is given as input, inflate() will return with the error code - Z_DATA_ERROR instead of trying to allocate a larger window. - - windowBits can also be zero to request that inflate use the window size in - the zlib header of the compressed stream. - - windowBits can also be -8..-15 for raw inflate. In this case, -windowBits - determines the window size. inflate() will then process raw deflate data, - not looking for a zlib or gzip header, not generating a check value, and not - looking for any check values for comparison at the end of the stream. This - is for use with other formats that use the deflate compressed data format - such as zip. Those formats provide their own check values. If a custom - format is developed using the raw deflate format for compressed data, it is - recommended that a check value such as an Adler-32 or a CRC-32 be applied to - the uncompressed data as is done in the zlib, gzip, and zip formats. For - most applications, the zlib format should be used as is. Note that comments - above on the use in deflateInit2() applies to the magnitude of windowBits. - - windowBits can also be greater than 15 for optional gzip decoding. Add - 32 to windowBits to enable zlib and gzip decoding with automatic header - detection, or add 16 to decode only the gzip format (the zlib format will - return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a - CRC-32 instead of an Adler-32. Unlike the gunzip utility and gzread() (see - below), inflate() will not automatically decode concatenated gzip streams. - inflate() will return Z_STREAM_END at the end of the gzip stream. The state - would need to be reset to continue decoding a subsequent gzip stream. - - inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_VERSION_ERROR if the zlib library version is incompatible with the - version assumed by the caller, or Z_STREAM_ERROR if the parameters are - invalid, such as a null pointer to the structure. msg is set to null if - there is no error message. inflateInit2 does not perform any decompression - apart from possibly reading the zlib header if present: actual decompression - will be done by inflate(). (So next_in and avail_in may be modified, but - next_out and avail_out are unused and unchanged.) The current implementation - of inflateInit2() does not process any header information -- that is - deferred until inflate() is called. -*/ - -ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm, - const Bytef *dictionary, - uInt dictLength)); -/* - Initializes the decompression dictionary from the given uncompressed byte - sequence. This function must be called immediately after a call of inflate, - if that call returned Z_NEED_DICT. The dictionary chosen by the compressor - can be determined from the Adler-32 value returned by that call of inflate. - The compressor and decompressor must use exactly the same dictionary (see - deflateSetDictionary). For raw inflate, this function can be called at any - time to set the dictionary. If the provided dictionary is smaller than the - window and there is already data in the window, then the provided dictionary - will amend what's there. The application must insure that the dictionary - that was used for compression is provided. - - inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a - parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is - inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the - expected one (incorrect Adler-32 value). inflateSetDictionary does not - perform any decompression: this will be done by subsequent calls of - inflate(). -*/ - -ZEXTERN int ZEXPORT inflateGetDictionary OF((z_streamp strm, - Bytef *dictionary, - uInt *dictLength)); -/* - Returns the sliding dictionary being maintained by inflate. dictLength is - set to the number of bytes in the dictionary, and that many bytes are copied - to dictionary. dictionary must have enough space, where 32768 bytes is - always enough. If inflateGetDictionary() is called with dictionary equal to - Z_NULL, then only the dictionary length is returned, and nothing is copied. - Similary, if dictLength is Z_NULL, then it is not set. - - inflateGetDictionary returns Z_OK on success, or Z_STREAM_ERROR if the - stream state is inconsistent. -*/ - -ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm)); -/* - Skips invalid compressed data until a possible full flush point (see above - for the description of deflate with Z_FULL_FLUSH) can be found, or until all - available input is skipped. No output is provided. - - inflateSync searches for a 00 00 FF FF pattern in the compressed data. - All full flush points have this pattern, but not all occurrences of this - pattern are full flush points. - - inflateSync returns Z_OK if a possible full flush point has been found, - Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point - has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. - In the success case, the application may save the current current value of - total_in which indicates where valid compressed data was found. In the - error case, the application may repeatedly call inflateSync, providing more - input each time, until success or end of the input data. -*/ - -ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest, - z_streamp source)); -/* - Sets the destination stream as a complete copy of the source stream. - - This function can be useful when randomly accessing a large stream. The - first pass through the stream can periodically record the inflate state, - allowing restarting inflate at those points when randomly accessing the - stream. - - inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_STREAM_ERROR if the source stream state was inconsistent - (such as zalloc being Z_NULL). msg is left unchanged in both source and - destination. -*/ - -ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm)); -/* - This function is equivalent to inflateEnd followed by inflateInit, - but does not free and reallocate the internal decompression state. The - stream will keep attributes that may have been set by inflateInit2. - - inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being Z_NULL). -*/ - -ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm, - int windowBits)); -/* - This function is the same as inflateReset, but it also permits changing - the wrap and window size requests. The windowBits parameter is interpreted - the same as it is for inflateInit2. If the window size is changed, then the - memory allocated for the window is freed, and the window will be reallocated - by inflate() if needed. - - inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent (such as zalloc or state being Z_NULL), or if - the windowBits parameter is invalid. -*/ - -ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm, - int bits, - int value)); -/* - This function inserts bits in the inflate input stream. The intent is - that this function is used to start inflating at a bit position in the - middle of a byte. The provided bits will be used before any bytes are used - from next_in. This function should only be used with raw inflate, and - should be used before the first inflate() call after inflateInit2() or - inflateReset(). bits must be less than or equal to 16, and that many of the - least significant bits of value will be inserted in the input. - - If bits is negative, then the input stream bit buffer is emptied. Then - inflatePrime() can be called again to put bits in the buffer. This is used - to clear out bits leftover after feeding inflate a block description prior - to feeding inflate codes. - - inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm)); -/* - This function returns two values, one in the lower 16 bits of the return - value, and the other in the remaining upper bits, obtained by shifting the - return value down 16 bits. If the upper value is -1 and the lower value is - zero, then inflate() is currently decoding information outside of a block. - If the upper value is -1 and the lower value is non-zero, then inflate is in - the middle of a stored block, with the lower value equaling the number of - bytes from the input remaining to copy. If the upper value is not -1, then - it is the number of bits back from the current bit position in the input of - the code (literal or length/distance pair) currently being processed. In - that case the lower value is the number of bytes already emitted for that - code. - - A code is being processed if inflate is waiting for more input to complete - decoding of the code, or if it has completed decoding but is waiting for - more output space to write the literal or match data. - - inflateMark() is used to mark locations in the input data for random - access, which may be at bit positions, and to note those cases where the - output of a code may span boundaries of random access blocks. The current - location in the input stream can be determined from avail_in and data_type - as noted in the description for the Z_BLOCK flush parameter for inflate. - - inflateMark returns the value noted above, or -65536 if the provided - source stream state was inconsistent. -*/ - -ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm, - gz_headerp head)); -/* - inflateGetHeader() requests that gzip header information be stored in the - provided gz_header structure. inflateGetHeader() may be called after - inflateInit2() or inflateReset(), and before the first call of inflate(). - As inflate() processes the gzip stream, head->done is zero until the header - is completed, at which time head->done is set to one. If a zlib stream is - being decoded, then head->done is set to -1 to indicate that there will be - no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be - used to force inflate() to return immediately after header processing is - complete and before any actual data is decompressed. - - The text, time, xflags, and os fields are filled in with the gzip header - contents. hcrc is set to true if there is a header CRC. (The header CRC - was valid if done is set to one.) If extra is not Z_NULL, then extra_max - contains the maximum number of bytes to write to extra. Once done is true, - extra_len contains the actual extra field length, and extra contains the - extra field, or that field truncated if extra_max is less than extra_len. - If name is not Z_NULL, then up to name_max characters are written there, - terminated with a zero unless the length is greater than name_max. If - comment is not Z_NULL, then up to comm_max characters are written there, - terminated with a zero unless the length is greater than comm_max. When any - of extra, name, or comment are not Z_NULL and the respective field is not - present in the header, then that field is set to Z_NULL to signal its - absence. This allows the use of deflateSetHeader() with the returned - structure to duplicate the header. However if those fields are set to - allocated memory, then the application will need to save those pointers - elsewhere so that they can be eventually freed. - - If inflateGetHeader is not used, then the header information is simply - discarded. The header is always checked for validity, including the header - CRC if present. inflateReset() will reset the process to discard the header - information. The application would need to call inflateGetHeader() again to - retrieve the header from the next gzip stream. - - inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source - stream state was inconsistent. -*/ - -/* -ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits, - unsigned char FAR *window)); - - Initialize the internal stream state for decompression using inflateBack() - calls. The fields zalloc, zfree and opaque in strm must be initialized - before the call. If zalloc and zfree are Z_NULL, then the default library- - derived memory allocation routines are used. windowBits is the base two - logarithm of the window size, in the range 8..15. window is a caller - supplied buffer of that size. Except for special applications where it is - assured that deflate was used with small window sizes, windowBits must be 15 - and a 32K byte window must be supplied to be able to decompress general - deflate streams. - - See inflateBack() for the usage of these routines. - - inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of - the parameters are invalid, Z_MEM_ERROR if the internal state could not be - allocated, or Z_VERSION_ERROR if the version of the library does not match - the version of the header file. -*/ - -typedef unsigned (*in_func) OF((void FAR *, - z_const unsigned char FAR * FAR *)); -typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned)); - -ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm, - in_func in, void FAR *in_desc, - out_func out, void FAR *out_desc)); -/* - inflateBack() does a raw inflate with a single call using a call-back - interface for input and output. This is potentially more efficient than - inflate() for file i/o applications, in that it avoids copying between the - output and the sliding window by simply making the window itself the output - buffer. inflate() can be faster on modern CPUs when used with large - buffers. inflateBack() trusts the application to not change the output - buffer passed by the output function, at least until inflateBack() returns. - - inflateBackInit() must be called first to allocate the internal state - and to initialize the state with the user-provided window buffer. - inflateBack() may then be used multiple times to inflate a complete, raw - deflate stream with each call. inflateBackEnd() is then called to free the - allocated state. - - A raw deflate stream is one with no zlib or gzip header or trailer. - This routine would normally be used in a utility that reads zip or gzip - files and writes out uncompressed files. The utility would decode the - header and process the trailer on its own, hence this routine expects only - the raw deflate stream to decompress. This is different from the default - behavior of inflate(), which expects a zlib header and trailer around the - deflate stream. - - inflateBack() uses two subroutines supplied by the caller that are then - called by inflateBack() for input and output. inflateBack() calls those - routines until it reads a complete deflate stream and writes out all of the - uncompressed data, or until it encounters an error. The function's - parameters and return types are defined above in the in_func and out_func - typedefs. inflateBack() will call in(in_desc, &buf) which should return the - number of bytes of provided input, and a pointer to that input in buf. If - there is no input available, in() must return zero -- buf is ignored in that - case -- and inflateBack() will return a buffer error. inflateBack() will - call out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. - out() should return zero on success, or non-zero on failure. If out() - returns non-zero, inflateBack() will return with an error. Neither in() nor - out() are permitted to change the contents of the window provided to - inflateBackInit(), which is also the buffer that out() uses to write from. - The length written by out() will be at most the window size. Any non-zero - amount of input may be provided by in(). - - For convenience, inflateBack() can be provided input on the first call by - setting strm->next_in and strm->avail_in. If that input is exhausted, then - in() will be called. Therefore strm->next_in must be initialized before - calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called - immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in - must also be initialized, and then if strm->avail_in is not zero, input will - initially be taken from strm->next_in[0 .. strm->avail_in - 1]. - - The in_desc and out_desc parameters of inflateBack() is passed as the - first parameter of in() and out() respectively when they are called. These - descriptors can be optionally used to pass any information that the caller- - supplied in() and out() functions need to do their job. - - On return, inflateBack() will set strm->next_in and strm->avail_in to - pass back any unused input that was provided by the last in() call. The - return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR - if in() or out() returned an error, Z_DATA_ERROR if there was a format error - in the deflate stream (in which case strm->msg is set to indicate the nature - of the error), or Z_STREAM_ERROR if the stream was not properly initialized. - In the case of Z_BUF_ERROR, an input or output error can be distinguished - using strm->next_in which will be Z_NULL only if in() returned an error. If - strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning - non-zero. (in() will always be called before out(), so strm->next_in is - assured to be defined if out() returns non-zero.) Note that inflateBack() - cannot return Z_OK. -*/ - -ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm)); -/* - All memory allocated by inflateBackInit() is freed. - - inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream - state was inconsistent. -*/ - -ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void)); -/* Return flags indicating compile-time options. - - Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other: - 1.0: size of uInt - 3.2: size of uLong - 5.4: size of voidpf (pointer) - 7.6: size of z_off_t - - Compiler, assembler, and debug options: - 8: ZLIB_DEBUG - 9: ASMV or ASMINF -- use ASM code - 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention - 11: 0 (reserved) - - One-time table building (smaller code, but not thread-safe if true): - 12: BUILDFIXED -- build static block decoding tables when needed - 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed - 14,15: 0 (reserved) - - Library content (indicates missing functionality): - 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking - deflate code when not needed) - 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect - and decode gzip streams (to avoid linking crc code) - 18-19: 0 (reserved) - - Operation variations (changes in library functionality): - 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate - 21: FASTEST -- deflate algorithm with only one, lowest compression level - 22,23: 0 (reserved) - - The sprintf variant used by gzprintf (zero is best): - 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format - 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure! - 26: 0 = returns value, 1 = void -- 1 means inferred string length returned - - Remainder: - 27-31: 0 (reserved) - */ - -#ifndef Z_SOLO - - /* utility functions */ - -/* - The following utility functions are implemented on top of the basic - stream-oriented functions. To simplify the interface, some default options - are assumed (compression level and memory usage, standard memory allocation - functions). The source code of these utility functions can be modified if - you need special options. -*/ - -ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Compresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total size - of the destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed data. compress() is equivalent to compress2() with a level - parameter of Z_DEFAULT_COMPRESSION. - - compress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer. -*/ - -ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen, - int level)); -/* - Compresses the source buffer into the destination buffer. The level - parameter has the same meaning as in deflateInit. sourceLen is the byte - length of the source buffer. Upon entry, destLen is the total size of the - destination buffer, which must be at least the value returned by - compressBound(sourceLen). Upon exit, destLen is the actual size of the - compressed data. - - compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough - memory, Z_BUF_ERROR if there was not enough room in the output buffer, - Z_STREAM_ERROR if the level parameter is invalid. -*/ - -ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen)); -/* - compressBound() returns an upper bound on the compressed size after - compress() or compress2() on sourceLen bytes. It would be used before a - compress() or compress2() call to allocate the destination buffer. -*/ - -ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong sourceLen)); -/* - Decompresses the source buffer into the destination buffer. sourceLen is - the byte length of the source buffer. Upon entry, destLen is the total size - of the destination buffer, which must be large enough to hold the entire - uncompressed data. (The size of the uncompressed data must have been saved - previously by the compressor and transmitted to the decompressor by some - mechanism outside the scope of this compression library.) Upon exit, destLen - is the actual size of the uncompressed data. - - uncompress returns Z_OK if success, Z_MEM_ERROR if there was not - enough memory, Z_BUF_ERROR if there was not enough room in the output - buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete. In - the case where there is not enough room, uncompress() will fill the output - buffer with the uncompressed data up to that point. -*/ - -ZEXTERN int ZEXPORT uncompress2 OF((Bytef *dest, uLongf *destLen, - const Bytef *source, uLong *sourceLen)); -/* - Same as uncompress, except that sourceLen is a pointer, where the - length of the source is *sourceLen. On return, *sourceLen is the number of - source bytes consumed. -*/ - - /* gzip file access functions */ - -/* - This library supports reading and writing files in gzip (.gz) format with - an interface similar to that of stdio, using the functions that start with - "gz". The gzip format is different from the zlib format. gzip is a gzip - wrapper, documented in RFC 1952, wrapped around a deflate stream. -*/ - -typedef struct gzFile_s *gzFile; /* semi-opaque gzip file descriptor */ - -/* -ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode)); - - Opens a gzip (.gz) file for reading or writing. The mode parameter is as - in fopen ("rb" or "wb") but can also include a compression level ("wb9") or - a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only - compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F' - for fixed code compression as in "wb9F". (See the description of - deflateInit2 for more information about the strategy parameter.) 'T' will - request transparent writing or appending with no compression and not using - the gzip format. - - "a" can be used instead of "w" to request that the gzip stream that will - be written be appended to the file. "+" will result in an error, since - reading and writing to the same gzip file is not supported. The addition of - "x" when writing will create the file exclusively, which fails if the file - already exists. On systems that support it, the addition of "e" when - reading or writing will set the flag to close the file on an execve() call. - - These functions, as well as gzip, will read and decode a sequence of gzip - streams in a file. The append function of gzopen() can be used to create - such a file. (Also see gzflush() for another way to do this.) When - appending, gzopen does not test whether the file begins with a gzip stream, - nor does it look for the end of the gzip streams to begin appending. gzopen - will simply append a gzip stream to the existing file. - - gzopen can be used to read a file which is not in gzip format; in this - case gzread will directly read from the file without decompression. When - reading, this will be detected automatically by looking for the magic two- - byte gzip header. - - gzopen returns NULL if the file could not be opened, if there was - insufficient memory to allocate the gzFile state, or if an invalid mode was - specified (an 'r', 'w', or 'a' was not provided, or '+' was provided). - errno can be checked to determine if the reason gzopen failed was that the - file could not be opened. -*/ - -ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode)); -/* - gzdopen associates a gzFile with the file descriptor fd. File descriptors - are obtained from calls like open, dup, creat, pipe or fileno (if the file - has been previously opened with fopen). The mode parameter is as in gzopen. - - The next call of gzclose on the returned gzFile will also close the file - descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor - fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd, - mode);. The duplicated descriptor should be saved to avoid a leak, since - gzdopen does not close fd if it fails. If you are using fileno() to get the - file descriptor from a FILE *, then you will have to use dup() to avoid - double-close()ing the file descriptor. Both gzclose() and fclose() will - close the associated file descriptor, so they need to have different file - descriptors. - - gzdopen returns NULL if there was insufficient memory to allocate the - gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not - provided, or '+' was provided), or if fd is -1. The file descriptor is not - used until the next gz* read, write, seek, or close operation, so gzdopen - will not detect if fd is invalid (unless fd is -1). -*/ - -ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size)); -/* - Set the internal buffer size used by this library's functions. The - default buffer size is 8192 bytes. This function must be called after - gzopen() or gzdopen(), and before any other calls that read or write the - file. The buffer memory allocation is always deferred to the first read or - write. Three times that size in buffer space is allocated. A larger buffer - size of, for example, 64K or 128K bytes will noticeably increase the speed - of decompression (reading). - - The new buffer size also affects the maximum length for gzprintf(). - - gzbuffer() returns 0 on success, or -1 on failure, such as being called - too late. -*/ - -ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy)); -/* - Dynamically update the compression level or strategy. See the description - of deflateInit2 for the meaning of these parameters. Previously provided - data is flushed before the parameter change. - - gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not - opened for writing, Z_ERRNO if there is an error writing the flushed data, - or Z_MEM_ERROR if there is a memory allocation error. -*/ - -ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len)); -/* - Reads the given number of uncompressed bytes from the compressed file. If - the input file is not in gzip format, gzread copies the given number of - bytes into the buffer directly from the file. - - After reaching the end of a gzip stream in the input, gzread will continue - to read, looking for another gzip stream. Any number of gzip streams may be - concatenated in the input file, and will all be decompressed by gzread(). - If something other than a gzip stream is encountered after a gzip stream, - that remaining trailing garbage is ignored (and no error is returned). - - gzread can be used to read a gzip file that is being concurrently written. - Upon reaching the end of the input, gzread will return with the available - data. If the error code returned by gzerror is Z_OK or Z_BUF_ERROR, then - gzclearerr can be used to clear the end of file indicator in order to permit - gzread to be tried again. Z_OK indicates that a gzip stream was completed - on the last gzread. Z_BUF_ERROR indicates that the input file ended in the - middle of a gzip stream. Note that gzread does not return -1 in the event - of an incomplete gzip stream. This error is deferred until gzclose(), which - will return Z_BUF_ERROR if the last gzread ended in the middle of a gzip - stream. Alternatively, gzerror can be used before gzclose to detect this - case. - - gzread returns the number of uncompressed bytes actually read, less than - len for end of file, or -1 for error. If len is too large to fit in an int, - then nothing is read, -1 is returned, and the error state is set to - Z_STREAM_ERROR. -*/ - -ZEXTERN z_size_t ZEXPORT gzfread OF((voidp buf, z_size_t size, z_size_t nitems, - gzFile file)); -/* - Read up to nitems items of size size from file to buf, otherwise operating - as gzread() does. This duplicates the interface of stdio's fread(), with - size_t request and return types. If the library defines size_t, then - z_size_t is identical to size_t. If not, then z_size_t is an unsigned - integer type that can contain a pointer. - - gzfread() returns the number of full items read of size size, or zero if - the end of the file was reached and a full item could not be read, or if - there was an error. gzerror() must be consulted if zero is returned in - order to determine if there was an error. If the multiplication of size and - nitems overflows, i.e. the product does not fit in a z_size_t, then nothing - is read, zero is returned, and the error state is set to Z_STREAM_ERROR. - - In the event that the end of file is reached and only a partial item is - available at the end, i.e. the remaining uncompressed data length is not a - multiple of size, then the final partial item is nevetheless read into buf - and the end-of-file flag is set. The length of the partial item read is not - provided, but could be inferred from the result of gztell(). This behavior - is the same as the behavior of fread() implementations in common libraries, - but it prevents the direct use of gzfread() to read a concurrently written - file, reseting and retrying on end-of-file, when size is not 1. -*/ - -ZEXTERN int ZEXPORT gzwrite OF((gzFile file, - voidpc buf, unsigned len)); -/* - Writes the given number of uncompressed bytes into the compressed file. - gzwrite returns the number of uncompressed bytes written or 0 in case of - error. -*/ - -ZEXTERN z_size_t ZEXPORT gzfwrite OF((voidpc buf, z_size_t size, - z_size_t nitems, gzFile file)); -/* - gzfwrite() writes nitems items of size size from buf to file, duplicating - the interface of stdio's fwrite(), with size_t request and return types. If - the library defines size_t, then z_size_t is identical to size_t. If not, - then z_size_t is an unsigned integer type that can contain a pointer. - - gzfwrite() returns the number of full items written of size size, or zero - if there was an error. If the multiplication of size and nitems overflows, - i.e. the product does not fit in a z_size_t, then nothing is written, zero - is returned, and the error state is set to Z_STREAM_ERROR. -*/ - -ZEXTERN int ZEXPORTVA gzprintf Z_ARG((gzFile file, const char *format, ...)); -/* - Converts, formats, and writes the arguments to the compressed file under - control of the format string, as in fprintf. gzprintf returns the number of - uncompressed bytes actually written, or a negative zlib error code in case - of error. The number of uncompressed bytes written is limited to 8191, or - one less than the buffer size given to gzbuffer(). The caller should assure - that this limit is not exceeded. If it is exceeded, then gzprintf() will - return an error (0) with nothing written. In this case, there may also be a - buffer overflow with unpredictable consequences, which is possible only if - zlib was compiled with the insecure functions sprintf() or vsprintf() - because the secure snprintf() or vsnprintf() functions were not available. - This can be determined using zlibCompileFlags(). -*/ - -ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s)); -/* - Writes the given null-terminated string to the compressed file, excluding - the terminating null character. - - gzputs returns the number of characters written, or -1 in case of error. -*/ - -ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len)); -/* - Reads bytes from the compressed file until len-1 characters are read, or a - newline character is read and transferred to buf, or an end-of-file - condition is encountered. If any characters are read or if len == 1, the - string is terminated with a null character. If no characters are read due - to an end-of-file or len < 1, then the buffer is left untouched. - - gzgets returns buf which is a null-terminated string, or it returns NULL - for end-of-file or in case of error. If there was an error, the contents at - buf are indeterminate. -*/ - -ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c)); -/* - Writes c, converted to an unsigned char, into the compressed file. gzputc - returns the value that was written, or -1 in case of error. -*/ - -ZEXTERN int ZEXPORT gzgetc OF((gzFile file)); -/* - Reads one byte from the compressed file. gzgetc returns this byte or -1 - in case of end of file or error. This is implemented as a macro for speed. - As such, it does not do all of the checking the other functions do. I.e. - it does not check to see if file is NULL, nor whether the structure file - points to has been clobbered or not. -*/ - -ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file)); -/* - Push one character back onto the stream to be read as the first character - on the next read. At least one character of push-back is allowed. - gzungetc() returns the character pushed, or -1 on failure. gzungetc() will - fail if c is -1, and may fail if a character has been pushed but not read - yet. If gzungetc is used immediately after gzopen or gzdopen, at least the - output buffer size of pushed characters is allowed. (See gzbuffer above.) - The pushed character will be discarded if the stream is repositioned with - gzseek() or gzrewind(). -*/ - -ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush)); -/* - Flushes all pending output into the compressed file. The parameter flush - is as in the deflate() function. The return value is the zlib error number - (see function gzerror below). gzflush is only permitted when writing. - - If the flush parameter is Z_FINISH, the remaining data is written and the - gzip stream is completed in the output. If gzwrite() is called again, a new - gzip stream will be started in the output. gzread() is able to read such - concatenated gzip streams. - - gzflush should be called only when strictly necessary because it will - degrade compression if called too often. -*/ - -/* -ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file, - z_off_t offset, int whence)); - - Sets the starting position for the next gzread or gzwrite on the given - compressed file. The offset represents a number of bytes in the - uncompressed data stream. The whence parameter is defined as in lseek(2); - the value SEEK_END is not supported. - - If the file is opened for reading, this function is emulated but can be - extremely slow. If the file is opened for writing, only forward seeks are - supported; gzseek then compresses a sequence of zeroes up to the new - starting position. - - gzseek returns the resulting offset location as measured in bytes from - the beginning of the uncompressed stream, or -1 in case of error, in - particular if the file is opened for writing and the new starting position - would be before the current position. -*/ - -ZEXTERN int ZEXPORT gzrewind OF((gzFile file)); -/* - Rewinds the given file. This function is supported only for reading. - - gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) -*/ - -/* -ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file)); - - Returns the starting position for the next gzread or gzwrite on the given - compressed file. This position represents a number of bytes in the - uncompressed data stream, and is zero when starting, even if appending or - reading a gzip stream from the middle of a file using gzdopen(). - - gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) -*/ - -/* -ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file)); - - Returns the current offset in the file being read or written. This offset - includes the count of bytes that precede the gzip stream, for example when - appending or when using gzdopen() for reading. When reading, the offset - does not include as yet unused buffered input. This information can be used - for a progress indicator. On error, gzoffset() returns -1. -*/ - -ZEXTERN int ZEXPORT gzeof OF((gzFile file)); -/* - Returns true (1) if the end-of-file indicator has been set while reading, - false (0) otherwise. Note that the end-of-file indicator is set only if the - read tried to go past the end of the input, but came up short. Therefore, - just like feof(), gzeof() may return false even if there is no more data to - read, in the event that the last read request was for the exact number of - bytes remaining in the input file. This will happen if the input file size - is an exact multiple of the buffer size. - - If gzeof() returns true, then the read functions will return no more data, - unless the end-of-file indicator is reset by gzclearerr() and the input file - has grown since the previous end of file was detected. -*/ - -ZEXTERN int ZEXPORT gzdirect OF((gzFile file)); -/* - Returns true (1) if file is being copied directly while reading, or false - (0) if file is a gzip stream being decompressed. - - If the input file is empty, gzdirect() will return true, since the input - does not contain a gzip stream. - - If gzdirect() is used immediately after gzopen() or gzdopen() it will - cause buffers to be allocated to allow reading the file to determine if it - is a gzip file. Therefore if gzbuffer() is used, it should be called before - gzdirect(). - - When writing, gzdirect() returns true (1) if transparent writing was - requested ("wT" for the gzopen() mode), or false (0) otherwise. (Note: - gzdirect() is not needed when writing. Transparent writing must be - explicitly requested, so the application already knows the answer. When - linking statically, using gzdirect() will include all of the zlib code for - gzip file reading and decompression, which may not be desired.) -*/ - -ZEXTERN int ZEXPORT gzclose OF((gzFile file)); -/* - Flushes all pending output if necessary, closes the compressed file and - deallocates the (de)compression state. Note that once file is closed, you - cannot call gzerror with file, since its structures have been deallocated. - gzclose must not be called more than once on the same file, just as free - must not be called more than once on the same allocation. - - gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a - file operation error, Z_MEM_ERROR if out of memory, Z_BUF_ERROR if the - last read ended in the middle of a gzip stream, or Z_OK on success. -*/ - -ZEXTERN int ZEXPORT gzclose_r OF((gzFile file)); -ZEXTERN int ZEXPORT gzclose_w OF((gzFile file)); -/* - Same as gzclose(), but gzclose_r() is only for use when reading, and - gzclose_w() is only for use when writing or appending. The advantage to - using these instead of gzclose() is that they avoid linking in zlib - compression or decompression code that is not used when only reading or only - writing respectively. If gzclose() is used, then both compression and - decompression code will be included the application when linking to a static - zlib library. -*/ - -ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum)); -/* - Returns the error message for the last error which occurred on the given - compressed file. errnum is set to zlib error number. If an error occurred - in the file system and not in the compression library, errnum is set to - Z_ERRNO and the application may consult errno to get the exact error code. - - The application must not modify the returned string. Future calls to - this function may invalidate the previously returned string. If file is - closed, then the string previously returned by gzerror will no longer be - available. - - gzerror() should be used to distinguish errors from end-of-file for those - functions above that do not distinguish those cases in their return values. -*/ - -ZEXTERN void ZEXPORT gzclearerr OF((gzFile file)); -/* - Clears the error and end-of-file flags for file. This is analogous to the - clearerr() function in stdio. This is useful for continuing to read a gzip - file that is being written concurrently. -*/ - -#endif /* !Z_SOLO */ - - /* checksum functions */ - -/* - These functions are not related to compression but are exported - anyway because they might be useful in applications using the compression - library. -*/ - -ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); -/* - Update a running Adler-32 checksum with the bytes buf[0..len-1] and - return the updated checksum. If buf is Z_NULL, this function returns the - required initial value for the checksum. - - An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed - much faster. - - Usage example: - - uLong adler = adler32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - adler = adler32(adler, buffer, length); - } - if (adler != original_adler) error(); -*/ - -ZEXTERN uLong ZEXPORT adler32_z OF((uLong adler, const Bytef *buf, - z_size_t len)); -/* - Same as adler32(), but with a size_t length. -*/ - -/* -ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2, - z_off_t len2)); - - Combine two Adler-32 checksums into one. For two sequences of bytes, seq1 - and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for - each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of - seq1 and seq2 concatenated, requiring only adler1, adler2, and len2. Note - that the z_off_t type (like off_t) is a signed integer. If len2 is - negative, the result has no meaning or utility. -*/ - -ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); -/* - Update a running CRC-32 with the bytes buf[0..len-1] and return the - updated CRC-32. If buf is Z_NULL, this function returns the required - initial value for the crc. Pre- and post-conditioning (one's complement) is - performed within this function so it shouldn't be done by the application. - - Usage example: - - uLong crc = crc32(0L, Z_NULL, 0); - - while (read_buffer(buffer, length) != EOF) { - crc = crc32(crc, buffer, length); - } - if (crc != original_crc) error(); -*/ - -ZEXTERN uLong ZEXPORT crc32_z OF((uLong adler, const Bytef *buf, - z_size_t len)); -/* - Same as crc32(), but with a size_t length. -*/ - -/* -ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2)); - - Combine two CRC-32 check values into one. For two sequences of bytes, - seq1 and seq2 with lengths len1 and len2, CRC-32 check values were - calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32 - check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and - len2. -*/ - - - /* various hacks, don't look :) */ - -/* deflateInit and inflateInit are macros to allow checking the zlib version - * and the compiler's view of z_stream: - */ -ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method, - int windowBits, int memLevel, - int strategy, const char *version, - int stream_size)); -ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits, - const char *version, int stream_size)); -ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits, - unsigned char FAR *window, - const char *version, - int stream_size)); -#ifdef Z_PREFIX_SET -# define z_deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) -# define z_inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) -# define z_deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) -# define z_inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ - (int)sizeof(z_stream)) -# define z_inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, (int)sizeof(z_stream)) -#else -# define deflateInit(strm, level) \ - deflateInit_((strm), (level), ZLIB_VERSION, (int)sizeof(z_stream)) -# define inflateInit(strm) \ - inflateInit_((strm), ZLIB_VERSION, (int)sizeof(z_stream)) -# define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ - deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ - (strategy), ZLIB_VERSION, (int)sizeof(z_stream)) -# define inflateInit2(strm, windowBits) \ - inflateInit2_((strm), (windowBits), ZLIB_VERSION, \ - (int)sizeof(z_stream)) -# define inflateBackInit(strm, windowBits, window) \ - inflateBackInit_((strm), (windowBits), (window), \ - ZLIB_VERSION, (int)sizeof(z_stream)) -#endif - -#ifndef Z_SOLO - -/* gzgetc() macro and its supporting function and exposed data structure. Note - * that the real internal state is much larger than the exposed structure. - * This abbreviated structure exposes just enough for the gzgetc() macro. The - * user should not mess with these exposed elements, since their names or - * behavior could change in the future, perhaps even capriciously. They can - * only be used by the gzgetc() macro. You have been warned. - */ -struct gzFile_s { - unsigned have; - unsigned char *next; - z_off64_t pos; -}; -ZEXTERN int ZEXPORT gzgetc_ OF((gzFile file)); /* backward compatibility */ -#ifdef Z_PREFIX_SET -# undef z_gzgetc -# define z_gzgetc(g) \ - ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) -#else -# define gzgetc(g) \ - ((g)->have ? ((g)->have--, (g)->pos++, *((g)->next)++) : (gzgetc)(g)) -#endif - -/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or - * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if - * both are true, the application gets the *64 functions, and the regular - * functions are changed to 64 bits) -- in case these are set on systems - * without large file support, _LFS64_LARGEFILE must also be true - */ -#ifdef Z_LARGE64 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int)); - ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t)); -#endif - -#if !defined(ZLIB_INTERNAL) && defined(Z_WANT64) -# ifdef Z_PREFIX_SET -# define z_gzopen z_gzopen64 -# define z_gzseek z_gzseek64 -# define z_gztell z_gztell64 -# define z_gzoffset z_gzoffset64 -# define z_adler32_combine z_adler32_combine64 -# define z_crc32_combine z_crc32_combine64 -# else -# define gzopen gzopen64 -# define gzseek gzseek64 -# define gztell gztell64 -# define gzoffset gzoffset64 -# define adler32_combine adler32_combine64 -# define crc32_combine crc32_combine64 -# endif -# ifndef Z_LARGE64 - ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *)); - ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int)); - ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); - ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); -# endif -#else - ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *)); - ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); - ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); - ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); - ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); -#endif - -#else /* Z_SOLO */ - - ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t)); - -#endif /* !Z_SOLO */ - -/* undocumented functions */ -ZEXTERN const char * ZEXPORT zError OF((int)); -ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp)); -ZEXTERN const z_crc_t FAR * ZEXPORT get_crc_table OF((void)); -ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int)); -ZEXTERN int ZEXPORT inflateValidate OF((z_streamp, int)); -ZEXTERN unsigned long ZEXPORT inflateCodesUsed OF ((z_streamp)); -ZEXTERN int ZEXPORT inflateResetKeep OF((z_streamp)); -ZEXTERN int ZEXPORT deflateResetKeep OF((z_streamp)); -#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(Z_SOLO) -ZEXTERN gzFile ZEXPORT gzopen_w OF((const wchar_t *path, - const char *mode)); -#endif -#if defined(STDC) || defined(Z_HAVE_STDARG_H) -# ifndef Z_SOLO -ZEXTERN int ZEXPORTVA gzvprintf Z_ARG((gzFile file, - const char *format, - va_list va)); -# endif -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* ZLIB_H */ diff --git a/src/common/dep/zlib/zutil.c b/src/common/dep/zlib/zutil.c deleted file mode 100644 index a76c6b0c7..000000000 --- a/src/common/dep/zlib/zutil.c +++ /dev/null @@ -1,325 +0,0 @@ -/* zutil.c -- target dependent utility functions for the compression library - * Copyright (C) 1995-2017 Jean-loup Gailly - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* @(#) $Id$ */ - -#include "zutil.h" -#ifndef Z_SOLO -# include "gzguts.h" -#endif - -z_const char * const z_errmsg[10] = { - (z_const char *)"need dictionary", /* Z_NEED_DICT 2 */ - (z_const char *)"stream end", /* Z_STREAM_END 1 */ - (z_const char *)"", /* Z_OK 0 */ - (z_const char *)"file error", /* Z_ERRNO (-1) */ - (z_const char *)"stream error", /* Z_STREAM_ERROR (-2) */ - (z_const char *)"data error", /* Z_DATA_ERROR (-3) */ - (z_const char *)"insufficient memory", /* Z_MEM_ERROR (-4) */ - (z_const char *)"buffer error", /* Z_BUF_ERROR (-5) */ - (z_const char *)"incompatible version",/* Z_VERSION_ERROR (-6) */ - (z_const char *)"" -}; - - -const char * ZEXPORT zlibVersion() -{ - return ZLIB_VERSION; -} - -uLong ZEXPORT zlibCompileFlags() -{ - uLong flags; - - flags = 0; - switch ((int)(sizeof(uInt))) { - case 2: break; - case 4: flags += 1; break; - case 8: flags += 2; break; - default: flags += 3; - } - switch ((int)(sizeof(uLong))) { - case 2: break; - case 4: flags += 1 << 2; break; - case 8: flags += 2 << 2; break; - default: flags += 3 << 2; - } - switch ((int)(sizeof(voidpf))) { - case 2: break; - case 4: flags += 1 << 4; break; - case 8: flags += 2 << 4; break; - default: flags += 3 << 4; - } - switch ((int)(sizeof(z_off_t))) { - case 2: break; - case 4: flags += 1 << 6; break; - case 8: flags += 2 << 6; break; - default: flags += 3 << 6; - } -#ifdef ZLIB_DEBUG - flags += 1 << 8; -#endif -#if defined(ASMV) || defined(ASMINF) - flags += 1 << 9; -#endif -#ifdef ZLIB_WINAPI - flags += 1 << 10; -#endif -#ifdef BUILDFIXED - flags += 1 << 12; -#endif -#ifdef DYNAMIC_CRC_TABLE - flags += 1 << 13; -#endif -#ifdef NO_GZCOMPRESS - flags += 1L << 16; -#endif -#ifdef NO_GZIP - flags += 1L << 17; -#endif -#ifdef PKZIP_BUG_WORKAROUND - flags += 1L << 20; -#endif -#ifdef FASTEST - flags += 1L << 21; -#endif -#if defined(STDC) || defined(Z_HAVE_STDARG_H) -# ifdef NO_vsnprintf - flags += 1L << 25; -# ifdef HAS_vsprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_vsnprintf_void - flags += 1L << 26; -# endif -# endif -#else - flags += 1L << 24; -# ifdef NO_snprintf - flags += 1L << 25; -# ifdef HAS_sprintf_void - flags += 1L << 26; -# endif -# else -# ifdef HAS_snprintf_void - flags += 1L << 26; -# endif -# endif -#endif - return flags; -} - -#ifdef ZLIB_DEBUG -#include -# ifndef verbose -# define verbose 0 -# endif -int ZLIB_INTERNAL z_verbose = verbose; - -void ZLIB_INTERNAL z_error (m) - char *m; -{ - fprintf(stderr, "%s\n", m); - exit(1); -} -#endif - -/* exported to allow conversion of error code to string for compress() and - * uncompress() - */ -const char * ZEXPORT zError(err) - int err; -{ - return ERR_MSG(err); -} - -#if defined(_WIN32_WCE) - /* The Microsoft C Run-Time Library for Windows CE doesn't have - * errno. We define it as a global variable to simplify porting. - * Its value is always 0 and should not be used. - */ - int errno = 0; -#endif - -#ifndef HAVE_MEMCPY - -void ZLIB_INTERNAL zmemcpy(dest, source, len) - Bytef* dest; - const Bytef* source; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = *source++; /* ??? to be unrolled */ - } while (--len != 0); -} - -int ZLIB_INTERNAL zmemcmp(s1, s2, len) - const Bytef* s1; - const Bytef* s2; - uInt len; -{ - uInt j; - - for (j = 0; j < len; j++) { - if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; - } - return 0; -} - -void ZLIB_INTERNAL zmemzero(dest, len) - Bytef* dest; - uInt len; -{ - if (len == 0) return; - do { - *dest++ = 0; /* ??? to be unrolled */ - } while (--len != 0); -} -#endif - -#ifndef Z_SOLO - -#ifdef SYS16BIT - -#ifdef __TURBOC__ -/* Turbo C in 16-bit mode */ - -# define MY_ZCALLOC - -/* Turbo C malloc() does not allow dynamic allocation of 64K bytes - * and farmalloc(64K) returns a pointer with an offset of 8, so we - * must fix the pointer. Warning: the pointer must be put back to its - * original form in order to free it, use zcfree(). - */ - -#define MAX_PTR 10 -/* 10*64K = 640K */ - -local int next_ptr = 0; - -typedef struct ptr_table_s { - voidpf org_ptr; - voidpf new_ptr; -} ptr_table; - -local ptr_table table[MAX_PTR]; -/* This table is used to remember the original form of pointers - * to large buffers (64K). Such pointers are normalized with a zero offset. - * Since MSDOS is not a preemptive multitasking OS, this table is not - * protected from concurrent access. This hack doesn't work anyway on - * a protected system like OS/2. Use Microsoft C instead. - */ - -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, unsigned items, unsigned size) -{ - voidpf buf; - ulg bsize = (ulg)items*size; - - (void)opaque; - - /* If we allocate less than 65520 bytes, we assume that farmalloc - * will return a usable pointer which doesn't have to be normalized. - */ - if (bsize < 65520L) { - buf = farmalloc(bsize); - if (*(ush*)&buf != 0) return buf; - } else { - buf = farmalloc(bsize + 16L); - } - if (buf == NULL || next_ptr >= MAX_PTR) return NULL; - table[next_ptr].org_ptr = buf; - - /* Normalize the pointer to seg:0 */ - *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; - *(ush*)&buf = 0; - table[next_ptr++].new_ptr = buf; - return buf; -} - -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) -{ - int n; - - (void)opaque; - - if (*(ush*)&ptr != 0) { /* object < 64K */ - farfree(ptr); - return; - } - /* Find the original pointer */ - for (n = 0; n < next_ptr; n++) { - if (ptr != table[n].new_ptr) continue; - - farfree(table[n].org_ptr); - while (++n < next_ptr) { - table[n-1] = table[n]; - } - next_ptr--; - return; - } - Assert(0, "zcfree: ptr not found"); -} - -#endif /* __TURBOC__ */ - - -#ifdef M_I86 -/* Microsoft C in 16-bit mode */ - -# define MY_ZCALLOC - -#if (!defined(_MSC_VER) || (_MSC_VER <= 600)) -# define _halloc halloc -# define _hfree hfree -#endif - -voidpf ZLIB_INTERNAL zcalloc (voidpf opaque, uInt items, uInt size) -{ - (void)opaque; - return _halloc((long)items, size); -} - -void ZLIB_INTERNAL zcfree (voidpf opaque, voidpf ptr) -{ - (void)opaque; - _hfree(ptr); -} - -#endif /* M_I86 */ - -#endif /* SYS16BIT */ - - -#ifndef MY_ZCALLOC /* Any system without a special alloc function */ - -#ifndef STDC -extern voidp malloc OF((uInt size)); -extern voidp calloc OF((uInt items, uInt size)); -extern void free OF((voidpf ptr)); -#endif - -voidpf ZLIB_INTERNAL zcalloc (opaque, items, size) - voidpf opaque; - unsigned items; - unsigned size; -{ - (void)opaque; - return sizeof(uInt) > 2 ? (voidpf)malloc(items * size) : - (voidpf)calloc(items, size); -} - -void ZLIB_INTERNAL zcfree (opaque, ptr) - voidpf opaque; - voidpf ptr; -{ - (void)opaque; - free(ptr); -} - -#endif /* MY_ZCALLOC */ - -#endif /* !Z_SOLO */ diff --git a/src/common/dep/zlib/zutil.h b/src/common/dep/zlib/zutil.h deleted file mode 100644 index b079ea6a8..000000000 --- a/src/common/dep/zlib/zutil.h +++ /dev/null @@ -1,271 +0,0 @@ -/* zutil.h -- internal interface and configuration of the compression library - * Copyright (C) 1995-2016 Jean-loup Gailly, Mark Adler - * For conditions of distribution and use, see copyright notice in zlib.h - */ - -/* WARNING: this file should *not* be used by applications. It is - part of the implementation of the compression library and is - subject to change. Applications should only use zlib.h. - */ - -/* @(#) $Id$ */ - -#ifndef ZUTIL_H -#define ZUTIL_H - -#ifdef HAVE_HIDDEN -# define ZLIB_INTERNAL __attribute__((visibility ("hidden"))) -#else -# define ZLIB_INTERNAL -#endif - -#include "zlib.h" - -#if defined(STDC) && !defined(Z_SOLO) -# if !(defined(_WIN32_WCE) && defined(_MSC_VER)) -# include -# endif -# include -# include -#endif - -#ifdef Z_SOLO - typedef long ptrdiff_t; /* guess -- will be caught if guess is wrong */ -#endif - -#ifndef local -# define local static -#endif -/* since "static" is used to mean two completely different things in C, we - define "local" for the non-static meaning of "static", for readability - (compile with -Dlocal if your debugger can't find static symbols) */ - -typedef unsigned char uch; -typedef uch FAR uchf; -typedef unsigned short ush; -typedef ush FAR ushf; -typedef unsigned long ulg; - -extern z_const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ -/* (size given to avoid silly warnings with Visual C++) */ - -#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] - -#define ERR_RETURN(strm,err) \ - return (strm->msg = ERR_MSG(err), (err)) -/* To be used only when the state is known to be valid */ - - /* common constants */ - -#ifndef DEF_WBITS -# define DEF_WBITS MAX_WBITS -#endif -/* default windowBits for decompression. MAX_WBITS is for compression only */ - -#if MAX_MEM_LEVEL >= 8 -# define DEF_MEM_LEVEL 8 -#else -# define DEF_MEM_LEVEL MAX_MEM_LEVEL -#endif -/* default memLevel */ - -#define STORED_BLOCK 0 -#define STATIC_TREES 1 -#define DYN_TREES 2 -/* The three kinds of block type */ - -#define MIN_MATCH 3 -#define MAX_MATCH 258 -/* The minimum and maximum match lengths */ - -#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ - - /* target dependencies */ - -#if defined(MSDOS) || (defined(WINDOWS) && !defined(WIN32)) -# define OS_CODE 0x00 -# ifndef Z_SOLO -# if defined(__TURBOC__) || defined(__BORLANDC__) -# if (__STDC__ == 1) && (defined(__LARGE__) || defined(__COMPACT__)) - /* Allow compilation with ANSI keywords only enabled */ - void _Cdecl farfree( void *block ); - void *_Cdecl farmalloc( unsigned long nbytes ); -# else -# include -# endif -# else /* MSC or DJGPP */ -# include -# endif -# endif -#endif - -#ifdef AMIGA -# define OS_CODE 1 -#endif - -#if defined(VAXC) || defined(VMS) -# define OS_CODE 2 -# define F_OPEN(name, mode) \ - fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") -#endif - -#ifdef __370__ -# if __TARGET_LIB__ < 0x20000000 -# define OS_CODE 4 -# elif __TARGET_LIB__ < 0x40000000 -# define OS_CODE 11 -# else -# define OS_CODE 8 -# endif -#endif - -#if defined(ATARI) || defined(atarist) -# define OS_CODE 5 -#endif - -#ifdef OS2 -# define OS_CODE 6 -# if defined(M_I86) && !defined(Z_SOLO) -# include -# endif -#endif - -#if defined(MACOS) || defined(TARGET_OS_MAC) -# define OS_CODE 7 -# ifndef Z_SOLO -# if defined(__MWERKS__) && __dest_os != __be_os && __dest_os != __win32_os -# include /* for fdopen */ -# else -# ifndef fdopen -# define fdopen(fd,mode) NULL /* No fdopen() */ -# endif -# endif -# endif -#endif - -#ifdef __acorn -# define OS_CODE 13 -#endif - -#if defined(WIN32) && !defined(__CYGWIN__) -# define OS_CODE 10 -#endif - -#ifdef _BEOS_ -# define OS_CODE 16 -#endif - -#ifdef __TOS_OS400__ -# define OS_CODE 18 -#endif - -#ifdef __APPLE__ -# define OS_CODE 19 -#endif - -#if defined(_BEOS_) || defined(RISCOS) -# define fdopen(fd,mode) NULL /* No fdopen() */ -#endif - -#if (defined(_MSC_VER) && (_MSC_VER > 600)) && !defined __INTERIX -# if defined(_WIN32_WCE) -# define fdopen(fd,mode) NULL /* No fdopen() */ -# ifndef _PTRDIFF_T_DEFINED - typedef int ptrdiff_t; -# define _PTRDIFF_T_DEFINED -# endif -# else -# define fdopen(fd,type) _fdopen(fd,type) -# endif -#endif - -#if defined(__BORLANDC__) && !defined(MSDOS) - #pragma warn -8004 - #pragma warn -8008 - #pragma warn -8066 -#endif - -/* provide prototypes for these when building zlib without LFS */ -#if !defined(_WIN32) && \ - (!defined(_LARGEFILE64_SOURCE) || _LFS64_LARGEFILE-0 == 0) - ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t)); - ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t)); -#endif - - /* common defaults */ - -#ifndef OS_CODE -# define OS_CODE 3 /* assume Unix */ -#endif - -#ifndef F_OPEN -# define F_OPEN(name, mode) fopen((name), (mode)) -#endif - - /* functions */ - -#if defined(pyr) || defined(Z_SOLO) -# define NO_MEMCPY -#endif -#if defined(SMALL_MEDIUM) && !defined(_MSC_VER) && !defined(__SC__) - /* Use our own functions for small and medium model with MSC <= 5.0. - * You may have to use the same strategy for Borland C (untested). - * The __SC__ check is for Symantec. - */ -# define NO_MEMCPY -#endif -#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) -# define HAVE_MEMCPY -#endif -#ifdef HAVE_MEMCPY -# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ -# define zmemcpy _fmemcpy -# define zmemcmp _fmemcmp -# define zmemzero(dest, len) _fmemset(dest, 0, len) -# else -# define zmemcpy memcpy -# define zmemcmp memcmp -# define zmemzero(dest, len) memset(dest, 0, len) -# endif -#else - void ZLIB_INTERNAL zmemcpy OF((Bytef* dest, const Bytef* source, uInt len)); - int ZLIB_INTERNAL zmemcmp OF((const Bytef* s1, const Bytef* s2, uInt len)); - void ZLIB_INTERNAL zmemzero OF((Bytef* dest, uInt len)); -#endif - -/* Diagnostic functions */ -#ifdef ZLIB_DEBUG -# include - extern int ZLIB_INTERNAL z_verbose; - extern void ZLIB_INTERNAL z_error OF((char *m)); -# define Assert(cond,msg) {if(!(cond)) z_error(msg);} -# define Trace(x) {if (z_verbose>=0) fprintf x ;} -# define Tracev(x) {if (z_verbose>0) fprintf x ;} -# define Tracevv(x) {if (z_verbose>1) fprintf x ;} -# define Tracec(c,x) {if (z_verbose>0 && (c)) fprintf x ;} -# define Tracecv(c,x) {if (z_verbose>1 && (c)) fprintf x ;} -#else -# define Assert(cond,msg) -# define Trace(x) -# define Tracev(x) -# define Tracevv(x) -# define Tracec(c,x) -# define Tracecv(c,x) -#endif - -#ifndef Z_SOLO - voidpf ZLIB_INTERNAL zcalloc OF((voidpf opaque, unsigned items, - unsigned size)); - void ZLIB_INTERNAL zcfree OF((voidpf opaque, voidpf ptr)); -#endif - -#define ZALLOC(strm, items, size) \ - (*((strm)->zalloc))((strm)->opaque, (items), (size)) -#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) -#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} - -/* Reverse the bytes in a 32-bit value */ -#define ZSWAP32(q) ((((q) >> 24) & 0xff) + (((q) >> 8) & 0xff00) + \ - (((q) & 0xff00) << 8) + (((q) & 0xff) << 24)) - -#endif /* ZUTIL_H */ diff --git a/src/salzlib.cpp b/src/salzlib.cpp index 2bc9f3dfb..45bc6c356 100644 --- a/src/salzlib.cpp +++ b/src/salzlib.cpp @@ -5,7 +5,7 @@ //#include #include "plugins.h" -#include "zlib\zlib.h" +#include // // **************************************************************************** diff --git a/src/svg.cpp b/src/svg.cpp index 3035f1971..fbeb5657d 100644 --- a/src/svg.cpp +++ b/src/svg.cpp @@ -6,9 +6,9 @@ #include "svg.h" #define NANOSVG_IMPLEMENTATION -#include "nanosvg\nanosvg.h" +#include #define NANOSVGRAST_IMPLEMENTATION -#include "nanosvg\nanosvgrast.h" +#include CSVGSprite SVGArrowRight; CSVGSprite SVGArrowRightSmall; diff --git a/src/toolbar4.cpp b/src/toolbar4.cpp index 0b0e6a0ad..83e10defb 100644 --- a/src/toolbar4.cpp +++ b/src/toolbar4.cpp @@ -11,8 +11,8 @@ #include "plugins.h" #include "fileswnd.h" -#include "nanosvg\nanosvg.h" -#include "nanosvg\nanosvgrast.h" +#include +#include #include "svg.h" struct CButtonData diff --git a/src/vcpkg.json b/src/vcpkg.json new file mode 100644 index 000000000..8d18577ac --- /dev/null +++ b/src/vcpkg.json @@ -0,0 +1,8 @@ +{ + "dependencies": [ + "bzip2", + "nanosvg", + "zlib" + ], + "builtin-baseline": "6f29f12e82a8293156836ad81cc9bf5af41fe836" +} diff --git a/src/vcxproj/salamand.sln b/src/vcxproj/salamand.sln index f45010095..409587c22 100644 --- a/src/vcxproj/salamand.sln +++ b/src/vcxproj/salamand.sln @@ -990,6 +990,7 @@ Global {89CD2440-2844-4C0B-9CDE-1045334E9EC0}.Utils (Release)|x64.ActiveCfg = Release|x64 {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Debug|Win32.ActiveCfg = Debug|Win32 {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Debug|x64.ActiveCfg = Debug|Win32 + {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Debug|x64.Build.0 = Debug|Win32 {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Release|Win32.ActiveCfg = Release|Win32 {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Release|x64.ActiveCfg = Release|Win32 {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Utils (Release)|Win32.ActiveCfg = Release|Win32 diff --git a/src/vcxproj/salamand.vcxproj b/src/vcxproj/salamand.vcxproj index 84a2ad313..db4e369f1 100644 --- a/src/vcxproj/salamand.vcxproj +++ b/src/vcxproj/salamand.vcxproj @@ -92,6 +92,23 @@ + + true + true + true + + + true + + + true + + + true + + + true + stdcpplatest @@ -117,124 +134,6 @@ - - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - - - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - - - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - $(IntDir)bzip2_compress.obj - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - $(IntDir)bzip2_compress.obj - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - $(IntDir)bzip2_compress.obj - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - $(IntDir)bzip2_compress.obj - - - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - - - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - - - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - - - - - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - MaxSpeed - BZ_NO_STDIO;%(PreprocessorDefinitions) - - - @@ -583,106 +482,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - false - - - false - - - - - - - - - - - - - - - - - - - - - diff --git a/src/vcxproj/salamand.vcxproj.filters b/src/vcxproj/salamand.vcxproj.filters index 3f3c5f368..8b9b3ac5f 100644 --- a/src/vcxproj/salamand.vcxproj.filters +++ b/src/vcxproj/salamand.vcxproj.filters @@ -16,12 +16,6 @@ {8a207bdc-245b-40bc-a918-5d6fd02fbab2} - - {5bda093c-97de-4740-9887-23bd128dd496} - - - {ef14f658-710e-4121-8489-ef4153552efa} - {ba542554-32da-4655-b4c3-c20982541b09} @@ -411,57 +405,6 @@ common - - zlib - - - zlib - - - zlib - - - zlib - - - zlib - - - zlib - - - zlib - - - zlib - - - zlib - - - bzip2 - - - bzip2 - - - bzip2 - - - bzip2 - - - bzip2 - - - bzip2 - - - bzip2 - - - bzip2 - pnglite @@ -722,12 +665,6 @@ common - - bzip2 - - - bzip2 - pnglite From cc68f793af40ae1b40fdc567e6f5e1e65208ba1a Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Mon, 17 Feb 2025 19:58:13 +0100 Subject: [PATCH 50/65] fixed forgotten includes --- src/gui.cpp | 4 ++-- src/salbzip2.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui.cpp b/src/gui.cpp index 11b7d00cc..a5231bbc7 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -11,8 +11,8 @@ #include #include -#include "nanosvg\nanosvg.h" -#include "nanosvg\nanosvgrast.h" +#include +#include #include "mainwnd.h" diff --git a/src/salbzip2.cpp b/src/salbzip2.cpp index 24a51a5b1..1373a97dc 100644 --- a/src/salbzip2.cpp +++ b/src/salbzip2.cpp @@ -4,7 +4,7 @@ #include "precomp.h" #include "plugins.h" -#include "bzip2/bzlib.h" +#include // // **************************************************************************** From 882548ed21d666938eb0ca6dfdc2f84a75d6d517 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Mon, 17 Feb 2025 20:10:01 +0100 Subject: [PATCH 51/65] one more forgotten include file fix --- src/common/dep/pnglite/pnglite.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/dep/pnglite/pnglite.c b/src/common/dep/pnglite/pnglite.c index 0eb4487ac..d5ed99f34 100644 --- a/src/common/dep/pnglite/pnglite.c +++ b/src/common/dep/pnglite/pnglite.c @@ -11,7 +11,7 @@ #define USE_ZLIB 1 #if USE_ZLIB -#include "../zlib/zlib.h" +#include #else #include "zlite.h" #endif From abf66467435c34d88abaca43670b776831f0da8b Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Mon, 17 Feb 2025 21:09:34 +0100 Subject: [PATCH 52/65] added salpvenv to x64 build --- src/vcxproj/salamand.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vcxproj/salamand.sln b/src/vcxproj/salamand.sln index 409587c22..5dd1b0ef2 100644 --- a/src/vcxproj/salamand.sln +++ b/src/vcxproj/salamand.sln @@ -993,6 +993,7 @@ Global {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Debug|x64.Build.0 = Debug|Win32 {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Release|Win32.ActiveCfg = Release|Win32 {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Release|x64.ActiveCfg = Release|Win32 + {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Release|x64.Build.0 = Release|Win32 {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Utils (Release)|Win32.ActiveCfg = Release|Win32 {17CF5E05-F29C-4E5D-BA41-83254E342E0B}.Utils (Release)|x64.ActiveCfg = Release|Win32 {49D6CEED-804F-4EA6-BD12-2D825E13DAE3}.Debug|Win32.ActiveCfg = Debug|Win32 From abb06a99f0c645a0a9a1da118c3ed26ba5f7f320 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 15 Mar 2025 13:51:08 +0100 Subject: [PATCH 53/65] reverted nanosvg from vcpkg.json, as it has to be patched --- src/common/dep/nanosvg/nanosvg.h | 3098 ++++++++++++++++++++++++++ src/common/dep/nanosvg/nanosvgrast.h | 1472 ++++++++++++ src/gui.cpp | 4 +- src/svg.cpp | 4 +- src/toolbar4.cpp | 4 +- src/vcpkg.json | 1 - 6 files changed, 4576 insertions(+), 7 deletions(-) create mode 100644 src/common/dep/nanosvg/nanosvg.h create mode 100644 src/common/dep/nanosvg/nanosvgrast.h diff --git a/src/common/dep/nanosvg/nanosvg.h b/src/common/dep/nanosvg/nanosvg.h new file mode 100644 index 000000000..60a323820 --- /dev/null +++ b/src/common/dep/nanosvg/nanosvg.h @@ -0,0 +1,3098 @@ +/* + * Copyright (c) 2013-14 Mikko Mononen memon@inside.org + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * The SVG parser is based on Anti-Grain Geometry 2.4 SVG example + * Copyright (C) 2002-2004 Maxim Shemanarev (McSeem) (http://www.antigrain.com/) + * + * Arc calculation code based on canvg (https://code.google.com/p/canvg/) + * + * Bounding box calculation based on http://blog.hackers-cafe.net/2009/06/how-to-calculate-bezier-curves-bounding.html + * + */ + +#ifndef NANOSVG_H +#define NANOSVG_H + +#ifndef NANOSVG_CPLUSPLUS +#ifdef __cplusplus +extern "C" { +#endif +#endif + +// NanoSVG is a simple stupid single-header-file SVG parse. The output of the parser is a list of cubic bezier shapes. +// +// The library suits well for anything from rendering scalable icons in your editor application to prototyping a game. +// +// NanoSVG supports a wide range of SVG features, but something may be missing, feel free to create a pull request! +// +// The shapes in the SVG images are transformed by the viewBox and converted to specified units. +// That is, you should get the same looking data as your designed in your favorite app. +// +// NanoSVG can return the paths in few different units. For example if you want to render an image, you may choose +// to get the paths in pixels, or if you are feeding the data into a CNC-cutter, you may want to use millimeters. +// +// The units passed to NanoSVG should be one of: 'px', 'pt', 'pc' 'mm', 'cm', or 'in'. +// DPI (dots-per-inch) controls how the unit conversion is done. +// +// If you don't know or care about the units stuff, "px" and 96 should get you going. + + +/* Example Usage: + // Load SVG + NSVGimage* image; + image = nsvgParseFromFile("test.svg", "px", 96); + printf("size: %f x %f\n", image->width, image->height); + // Use... + for (NSVGshape *shape = image->shapes; shape != NULL; shape = shape->next) { + for (NSVGpath *path = shape->paths; path != NULL; path = path->next) { + for (int i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + drawCubicBez(p[0],p[1], p[2],p[3], p[4],p[5], p[6],p[7]); + } + } + } + // Delete + nsvgDelete(image); +*/ + +enum NSVGpaintType { + NSVG_PAINT_UNDEF = -1, + NSVG_PAINT_NONE = 0, + NSVG_PAINT_COLOR = 1, + NSVG_PAINT_LINEAR_GRADIENT = 2, + NSVG_PAINT_RADIAL_GRADIENT = 3 +}; + +enum NSVGspreadType { + NSVG_SPREAD_PAD = 0, + NSVG_SPREAD_REFLECT = 1, + NSVG_SPREAD_REPEAT = 2 +}; + +enum NSVGlineJoin { + NSVG_JOIN_MITER = 0, + NSVG_JOIN_ROUND = 1, + NSVG_JOIN_BEVEL = 2 +}; + +enum NSVGlineCap { + NSVG_CAP_BUTT = 0, + NSVG_CAP_ROUND = 1, + NSVG_CAP_SQUARE = 2 +}; + +enum NSVGfillRule { + NSVG_FILLRULE_NONZERO = 0, + NSVG_FILLRULE_EVENODD = 1 +}; + +enum NSVGflags { + NSVG_FLAGS_VISIBLE = 0x01 +}; + +typedef struct NSVGgradientStop { + unsigned int color; + float offset; +} NSVGgradientStop; + +typedef struct NSVGgradient { + float xform[6]; + char spread; + float fx, fy; + int nstops; + NSVGgradientStop stops[1]; +} NSVGgradient; + +typedef struct NSVGpaint { + signed char type; + union { + unsigned int color; + NSVGgradient* gradient; + }; +} NSVGpaint; + +typedef struct NSVGpath +{ + float* pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ... + int npts; // Total number of bezier points. + char closed; // Flag indicating if shapes should be treated as closed. + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + struct NSVGpath* next; // Pointer to next path, or NULL if last element. +} NSVGpath; + +typedef struct NSVGshape +{ + char id[64]; // Optional 'id' attr of the shape or its group + NSVGpaint fill; // Fill paint + NSVGpaint stroke; // Stroke paint + float opacity; // Opacity of the shape. + float strokeWidth; // Stroke width (scaled). + float strokeDashOffset; // Stroke dash offset (scaled). + float strokeDashArray[8]; // Stroke dash array (scaled). + char strokeDashCount; // Number of dash values in dash array. + char strokeLineJoin; // Stroke join type. + char strokeLineCap; // Stroke cap type. + float miterLimit; // Miter limit + char fillRule; // Fill rule, see NSVGfillRule. + unsigned char flags; // Logical or of NSVG_FLAGS_* flags + float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. + char fillGradient[64]; // Optional 'id' of fill gradient + char strokeGradient[64]; // Optional 'id' of stroke gradient + float xform[6]; // Root transformation for fill/stroke gradient + NSVGpath* paths; // Linked list of paths in the image. + struct NSVGshape* next; // Pointer to next shape, or NULL if last element. +} NSVGshape; + +typedef struct NSVGimage +{ + float width; // Width of the image. + float height; // Height of the image. + NSVGshape* shapes; // Linked list of shapes in the image. +} NSVGimage; + +// Parses SVG file from a file, returns SVG image as paths. +NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi); + +// Parses SVG file from a null terminated string, returns SVG image as paths. +// Important note: changes the string. +NSVGimage* nsvgParse(char* input, const char* units, float dpi); + +// Duplicates a path. +NSVGpath* nsvgDuplicatePath(NSVGpath* p); + +// Deletes an image. +void nsvgDelete(NSVGimage* image); + +#ifndef NANOSVG_CPLUSPLUS +#ifdef __cplusplus +} +#endif +#endif + +#ifdef NANOSVG_IMPLEMENTATION + +#include +#include +#include +#include + +#define NSVG_PI (3.14159265358979323846264338327f) +#define NSVG_KAPPA90 (0.5522847493f) // Length proportional to radius of a cubic bezier handle for 90deg arcs. + +#define NSVG_ALIGN_MIN 0 +#define NSVG_ALIGN_MID 1 +#define NSVG_ALIGN_MAX 2 +#define NSVG_ALIGN_NONE 0 +#define NSVG_ALIGN_MEET 1 +#define NSVG_ALIGN_SLICE 2 + +#define NSVG_NOTUSED(v) do { (void)(1 ? (void)0 : ( (void)(v) ) ); } while(0) +#define NSVG_RGB(r, g, b) (((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16)) + +#ifdef _MSC_VER + #pragma warning (disable: 4996) // Switch off security warnings + #pragma warning (disable: 4100) // Switch off unreferenced formal parameter warnings + #ifdef __cplusplus + #define NSVG_INLINE inline + #else + #define NSVG_INLINE + #endif +#else + #define NSVG_INLINE inline +#endif + + +static int nsvg__isspace(char c) +{ + return strchr(" \t\n\v\f\r", c) != 0; +} + +static int nsvg__isdigit(char c) +{ + return c >= '0' && c <= '9'; +} + +static NSVG_INLINE float nsvg__minf(float a, float b) { return a < b ? a : b; } +static NSVG_INLINE float nsvg__maxf(float a, float b) { return a > b ? a : b; } + + +// Simple XML parser + +#define NSVG_XML_TAG 1 +#define NSVG_XML_CONTENT 2 +#define NSVG_XML_MAX_ATTRIBS 256 + +static void nsvg__parseContent(char* s, + void (*contentCb)(void* ud, const char* s), + void* ud) +{ + // Trim start white spaces + while (*s && nsvg__isspace(*s)) s++; + if (!*s) return; + + if (contentCb) + (*contentCb)(ud, s); +} + +static void nsvg__parseElement(char* s, + void (*startelCb)(void* ud, const char* el, const char** attr), + void (*endelCb)(void* ud, const char* el), + void* ud) +{ + const char* attr[NSVG_XML_MAX_ATTRIBS]; + int nattr = 0; + char* name; + int start = 0; + int end = 0; + char quote; + + // Skip white space after the '<' + while (*s && nsvg__isspace(*s)) s++; + + // Check if the tag is end tag + if (*s == '/') { + s++; + end = 1; + } else { + start = 1; + } + + // Skip comments, data and preprocessor stuff. + if (!*s || *s == '?' || *s == '!') + return; + + // Get tag name + name = s; + while (*s && !nsvg__isspace(*s)) s++; + if (*s) { *s++ = '\0'; } + + // Get attribs + while (!end && *s && nattr < NSVG_XML_MAX_ATTRIBS-3) { + char* name = NULL; + char* value = NULL; + + // Skip white space before the attrib name + while (*s && nsvg__isspace(*s)) s++; + if (!*s) break; + if (*s == '/') { + end = 1; + break; + } + name = s; + // Find end of the attrib name. + while (*s && !nsvg__isspace(*s) && *s != '=') s++; + if (*s) { *s++ = '\0'; } + // Skip until the beginning of the value. + while (*s && *s != '\"' && *s != '\'') s++; + if (!*s) break; + quote = *s; + s++; + // Store value and find the end of it. + value = s; + while (*s && *s != quote) s++; + if (*s) { *s++ = '\0'; } + + // Store only well formed attributes + if (name && value) { + attr[nattr++] = name; + attr[nattr++] = value; + } + } + + // List terminator + attr[nattr++] = 0; + attr[nattr++] = 0; + + // Call callbacks. + if (start && startelCb) + (*startelCb)(ud, name, attr); + if (end && endelCb) + (*endelCb)(ud, name); +} + +int nsvg__parseXML(char* input, + void (*startelCb)(void* ud, const char* el, const char** attr), + void (*endelCb)(void* ud, const char* el), + void (*contentCb)(void* ud, const char* s), + void* ud) +{ + char* s = input; + char* mark = s; + int state = NSVG_XML_CONTENT; + while (*s) { + if (*s == '<' && state == NSVG_XML_CONTENT) { + // Start of a tag + *s++ = '\0'; + nsvg__parseContent(mark, contentCb, ud); + mark = s; + state = NSVG_XML_TAG; + } else if (*s == '>' && state == NSVG_XML_TAG) { + // Start of a content or new tag. + *s++ = '\0'; + nsvg__parseElement(mark, startelCb, endelCb, ud); + mark = s; + state = NSVG_XML_CONTENT; + } else { + s++; + } + } + + return 1; +} + + +/* Simple SVG parser. */ + +#define NSVG_MAX_ATTR 128 + +enum NSVGgradientUnits { + NSVG_USER_SPACE = 0, + NSVG_OBJECT_SPACE = 1 +}; + +#define NSVG_MAX_DASHES 8 + +enum NSVGunits { + NSVG_UNITS_USER, + NSVG_UNITS_PX, + NSVG_UNITS_PT, + NSVG_UNITS_PC, + NSVG_UNITS_MM, + NSVG_UNITS_CM, + NSVG_UNITS_IN, + NSVG_UNITS_PERCENT, + NSVG_UNITS_EM, + NSVG_UNITS_EX +}; + +typedef struct NSVGcoordinate { + float value; + int units; +} NSVGcoordinate; + +typedef struct NSVGlinearData { + NSVGcoordinate x1, y1, x2, y2; +} NSVGlinearData; + +typedef struct NSVGradialData { + NSVGcoordinate cx, cy, r, fx, fy; +} NSVGradialData; + +typedef struct NSVGgradientData +{ + char id[64]; + char ref[64]; + signed char type; + union { + NSVGlinearData linear; + NSVGradialData radial; + }; + char spread; + char units; + float xform[6]; + int nstops; + NSVGgradientStop* stops; + struct NSVGgradientData* next; +} NSVGgradientData; + +typedef struct NSVGattrib +{ + char id[64]; + float xform[6]; + unsigned int fillColor; + unsigned int strokeColor; + float opacity; + float fillOpacity; + float strokeOpacity; + char fillGradient[64]; + char strokeGradient[64]; + float strokeWidth; + float strokeDashOffset; + float strokeDashArray[NSVG_MAX_DASHES]; + int strokeDashCount; + char strokeLineJoin; + char strokeLineCap; + float miterLimit; + char fillRule; + float fontSize; + unsigned int stopColor; + float stopOpacity; + float stopOffset; + char hasFill; + char hasStroke; + char visible; +} NSVGattrib; + +typedef struct NSVGparser +{ + NSVGattrib attr[NSVG_MAX_ATTR]; + int attrHead; + float* pts; + int npts; + int cpts; + NSVGpath* plist; + NSVGimage* image; + NSVGgradientData* gradients; + NSVGshape* shapesTail; + float viewMinx, viewMiny, viewWidth, viewHeight; + int alignX, alignY, alignType; + float dpi; + char pathFlag; + char defsFlag; +} NSVGparser; + +static void nsvg__xformIdentity(float* t) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = 0.0f; t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetTranslation(float* t, float tx, float ty) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = 0.0f; t[3] = 1.0f; + t[4] = tx; t[5] = ty; +} + +static void nsvg__xformSetScale(float* t, float sx, float sy) +{ + t[0] = sx; t[1] = 0.0f; + t[2] = 0.0f; t[3] = sy; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetSkewX(float* t, float a) +{ + t[0] = 1.0f; t[1] = 0.0f; + t[2] = tanf(a); t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetSkewY(float* t, float a) +{ + t[0] = 1.0f; t[1] = tanf(a); + t[2] = 0.0f; t[3] = 1.0f; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformSetRotation(float* t, float a) +{ + float cs = cosf(a), sn = sinf(a); + t[0] = cs; t[1] = sn; + t[2] = -sn; t[3] = cs; + t[4] = 0.0f; t[5] = 0.0f; +} + +static void nsvg__xformMultiply(float* t, float* s) +{ + float t0 = t[0] * s[0] + t[1] * s[2]; + float t2 = t[2] * s[0] + t[3] * s[2]; + float t4 = t[4] * s[0] + t[5] * s[2] + s[4]; + t[1] = t[0] * s[1] + t[1] * s[3]; + t[3] = t[2] * s[1] + t[3] * s[3]; + t[5] = t[4] * s[1] + t[5] * s[3] + s[5]; + t[0] = t0; + t[2] = t2; + t[4] = t4; +} + +static void nsvg__xformInverse(float* inv, float* t) +{ + double invdet, det = (double)t[0] * t[3] - (double)t[2] * t[1]; + if (det > -1e-6 && det < 1e-6) { + nsvg__xformIdentity(t); + return; + } + invdet = 1.0 / det; + inv[0] = (float)(t[3] * invdet); + inv[2] = (float)(-t[2] * invdet); + inv[4] = (float)(((double)t[2] * t[5] - (double)t[3] * t[4]) * invdet); + inv[1] = (float)(-t[1] * invdet); + inv[3] = (float)(t[0] * invdet); + inv[5] = (float)(((double)t[1] * t[4] - (double)t[0] * t[5]) * invdet); +} + +static void nsvg__xformPremultiply(float* t, float* s) +{ + float s2[6]; + memcpy(s2, s, sizeof(float)*6); + nsvg__xformMultiply(s2, t); + memcpy(t, s2, sizeof(float)*6); +} + +static void nsvg__xformPoint(float* dx, float* dy, float x, float y, float* t) +{ + *dx = x*t[0] + y*t[2] + t[4]; + *dy = x*t[1] + y*t[3] + t[5]; +} + +static void nsvg__xformVec(float* dx, float* dy, float x, float y, float* t) +{ + *dx = x*t[0] + y*t[2]; + *dy = x*t[1] + y*t[3]; +} + +#define NSVG_EPSILON (1e-12) + +static int nsvg__ptInBounds(float* pt, float* bounds) +{ + return pt[0] >= bounds[0] && pt[0] <= bounds[2] && pt[1] >= bounds[1] && pt[1] <= bounds[3]; +} + + +static double nsvg__evalBezier(double t, double p0, double p1, double p2, double p3) +{ + double it = 1.0-t; + return it*it*it*p0 + 3.0*it*it*t*p1 + 3.0*it*t*t*p2 + t*t*t*p3; +} + +static void nsvg__curveBounds(float* bounds, float* curve) +{ + int i, j, count; + double roots[2], a, b, c, b2ac, t, v; + float* v0 = &curve[0]; + float* v1 = &curve[2]; + float* v2 = &curve[4]; + float* v3 = &curve[6]; + + // Start the bounding box by end points + bounds[0] = nsvg__minf(v0[0], v3[0]); + bounds[1] = nsvg__minf(v0[1], v3[1]); + bounds[2] = nsvg__maxf(v0[0], v3[0]); + bounds[3] = nsvg__maxf(v0[1], v3[1]); + + // Bezier curve fits inside the convex hull of it's control points. + // If control points are inside the bounds, we're done. + if (nsvg__ptInBounds(v1, bounds) && nsvg__ptInBounds(v2, bounds)) + return; + + // Add bezier curve inflection points in X and Y. + for (i = 0; i < 2; i++) { + a = -3.0 * v0[i] + 9.0 * v1[i] - 9.0 * v2[i] + 3.0 * v3[i]; + b = 6.0 * v0[i] - 12.0 * v1[i] + 6.0 * v2[i]; + c = 3.0 * v1[i] - 3.0 * v0[i]; + count = 0; + if (fabs(a) < NSVG_EPSILON) { + if (fabs(b) > NSVG_EPSILON) { + t = -c / b; + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + } + } else { + b2ac = b*b - 4.0*c*a; + if (b2ac > NSVG_EPSILON) { + t = (-b + sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + t = (-b - sqrt(b2ac)) / (2.0 * a); + if (t > NSVG_EPSILON && t < 1.0-NSVG_EPSILON) + roots[count++] = t; + } + } + for (j = 0; j < count; j++) { + v = nsvg__evalBezier(roots[j], v0[i], v1[i], v2[i], v3[i]); + bounds[0+i] = nsvg__minf(bounds[0+i], (float)v); + bounds[2+i] = nsvg__maxf(bounds[2+i], (float)v); + } + } +} + +static NSVGparser* nsvg__createParser(void) +{ + NSVGparser* p; + p = (NSVGparser*)malloc(sizeof(NSVGparser)); + if (p == NULL) goto error; + memset(p, 0, sizeof(NSVGparser)); + + p->image = (NSVGimage*)malloc(sizeof(NSVGimage)); + if (p->image == NULL) goto error; + memset(p->image, 0, sizeof(NSVGimage)); + + // Init style + nsvg__xformIdentity(p->attr[0].xform); + memset(p->attr[0].id, 0, sizeof p->attr[0].id); + p->attr[0].fillColor = NSVG_RGB(0,0,0); + p->attr[0].strokeColor = NSVG_RGB(0,0,0); + p->attr[0].opacity = 1; + p->attr[0].fillOpacity = 1; + p->attr[0].strokeOpacity = 1; + p->attr[0].stopOpacity = 1; + p->attr[0].strokeWidth = 1; + p->attr[0].strokeLineJoin = NSVG_JOIN_MITER; + p->attr[0].strokeLineCap = NSVG_CAP_BUTT; + p->attr[0].miterLimit = 4; + p->attr[0].fillRule = NSVG_FILLRULE_NONZERO; + p->attr[0].hasFill = 1; + p->attr[0].visible = 1; + + return p; + +error: + if (p) { + if (p->image) free(p->image); + free(p); + } + return NULL; +} + +static void nsvg__deletePaths(NSVGpath* path) +{ + while (path) { + NSVGpath *next = path->next; + if (path->pts != NULL) + free(path->pts); + free(path); + path = next; + } +} + +static void nsvg__deletePaint(NSVGpaint* paint) +{ + if (paint->type == NSVG_PAINT_LINEAR_GRADIENT || paint->type == NSVG_PAINT_RADIAL_GRADIENT) + free(paint->gradient); +} + +static void nsvg__deleteGradientData(NSVGgradientData* grad) +{ + NSVGgradientData* next; + while (grad != NULL) { + next = grad->next; + free(grad->stops); + free(grad); + grad = next; + } +} + +static void nsvg__deleteParser(NSVGparser* p) +{ + if (p != NULL) { + nsvg__deletePaths(p->plist); + nsvg__deleteGradientData(p->gradients); + nsvgDelete(p->image); + free(p->pts); + free(p); + } +} + +static void nsvg__resetPath(NSVGparser* p) +{ + p->npts = 0; +} + +static void nsvg__addPoint(NSVGparser* p, float x, float y) +{ + if (p->npts+1 > p->cpts) { + p->cpts = p->cpts ? p->cpts*2 : 8; + p->pts = (float*)realloc(p->pts, p->cpts*2*sizeof(float)); + if (!p->pts) return; + } + p->pts[p->npts*2+0] = x; + p->pts[p->npts*2+1] = y; + p->npts++; +} + +static void nsvg__moveTo(NSVGparser* p, float x, float y) +{ + if (p->npts > 0) { + p->pts[(p->npts-1)*2+0] = x; + p->pts[(p->npts-1)*2+1] = y; + } else { + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__lineTo(NSVGparser* p, float x, float y) +{ + float px,py, dx,dy; + if (p->npts > 0) { + px = p->pts[(p->npts-1)*2+0]; + py = p->pts[(p->npts-1)*2+1]; + dx = x - px; + dy = y - py; + nsvg__addPoint(p, px + dx/3.0f, py + dy/3.0f); + nsvg__addPoint(p, x - dx/3.0f, y - dy/3.0f); + nsvg__addPoint(p, x, y); + } +} + +static void nsvg__cubicBezTo(NSVGparser* p, float cpx1, float cpy1, float cpx2, float cpy2, float x, float y) +{ + if (p->npts > 0) { + nsvg__addPoint(p, cpx1, cpy1); + nsvg__addPoint(p, cpx2, cpy2); + nsvg__addPoint(p, x, y); + } +} + +static NSVGattrib* nsvg__getAttr(NSVGparser* p) +{ + return &p->attr[p->attrHead]; +} + +static void nsvg__pushAttr(NSVGparser* p) +{ + if (p->attrHead < NSVG_MAX_ATTR-1) { + p->attrHead++; + memcpy(&p->attr[p->attrHead], &p->attr[p->attrHead-1], sizeof(NSVGattrib)); + } +} + +static void nsvg__popAttr(NSVGparser* p) +{ + if (p->attrHead > 0) + p->attrHead--; +} + +static float nsvg__actualOrigX(NSVGparser* p) +{ + return p->viewMinx; +} + +static float nsvg__actualOrigY(NSVGparser* p) +{ + return p->viewMiny; +} + +static float nsvg__actualWidth(NSVGparser* p) +{ + return p->viewWidth; +} + +static float nsvg__actualHeight(NSVGparser* p) +{ + return p->viewHeight; +} + +static float nsvg__actualLength(NSVGparser* p) +{ + float w = nsvg__actualWidth(p), h = nsvg__actualHeight(p); + return sqrtf(w*w + h*h) / sqrtf(2.0f); +} + +static float nsvg__convertToPixels(NSVGparser* p, NSVGcoordinate c, float orig, float length) +{ + NSVGattrib* attr = nsvg__getAttr(p); + switch (c.units) { + case NSVG_UNITS_USER: return c.value; + case NSVG_UNITS_PX: return c.value; + case NSVG_UNITS_PT: return c.value / 72.0f * p->dpi; + case NSVG_UNITS_PC: return c.value / 6.0f * p->dpi; + case NSVG_UNITS_MM: return c.value / 25.4f * p->dpi; + case NSVG_UNITS_CM: return c.value / 2.54f * p->dpi; + case NSVG_UNITS_IN: return c.value * p->dpi; + case NSVG_UNITS_EM: return c.value * attr->fontSize; + case NSVG_UNITS_EX: return c.value * attr->fontSize * 0.52f; // x-height of Helvetica. + case NSVG_UNITS_PERCENT: return orig + c.value / 100.0f * length; + default: return c.value; + } + return c.value; +} + +static NSVGgradientData* nsvg__findGradientData(NSVGparser* p, const char* id) +{ + NSVGgradientData* grad = p->gradients; + if (id == NULL || *id == '\0') + return NULL; + while (grad != NULL) { + if (strcmp(grad->id, id) == 0) + return grad; + grad = grad->next; + } + return NULL; +} + +static NSVGgradient* nsvg__createGradient(NSVGparser* p, const char* id, const float* localBounds, float *xform, signed char* paintType) +{ + NSVGgradientData* data = NULL; + NSVGgradientData* ref = NULL; + NSVGgradientStop* stops = NULL; + NSVGgradient* grad; + float ox, oy, sw, sh, sl; + int nstops = 0; + int refIter; + + data = nsvg__findGradientData(p, id); + if (data == NULL) return NULL; + + // TODO: use ref to fill in all unset values too. + ref = data; + refIter = 0; + while (ref != NULL) { + NSVGgradientData* nextRef = NULL; + if (stops == NULL && ref->stops != NULL) { + stops = ref->stops; + nstops = ref->nstops; + break; + } + nextRef = nsvg__findGradientData(p, ref->ref); + if (nextRef == ref) break; // prevent infite loops on malformed data + ref = nextRef; + refIter++; + if (refIter > 32) break; // prevent infite loops on malformed data + } + if (stops == NULL) return NULL; + + grad = (NSVGgradient*)malloc(sizeof(NSVGgradient) + sizeof(NSVGgradientStop)*(nstops-1)); + if (grad == NULL) return NULL; + + // The shape width and height. + if (data->units == NSVG_OBJECT_SPACE) { + ox = localBounds[0]; + oy = localBounds[1]; + sw = localBounds[2] - localBounds[0]; + sh = localBounds[3] - localBounds[1]; + } else { + ox = nsvg__actualOrigX(p); + oy = nsvg__actualOrigY(p); + sw = nsvg__actualWidth(p); + sh = nsvg__actualHeight(p); + } + sl = sqrtf(sw*sw + sh*sh) / sqrtf(2.0f); + + if (data->type == NSVG_PAINT_LINEAR_GRADIENT) { + float x1, y1, x2, y2, dx, dy; + x1 = nsvg__convertToPixels(p, data->linear.x1, ox, sw); + y1 = nsvg__convertToPixels(p, data->linear.y1, oy, sh); + x2 = nsvg__convertToPixels(p, data->linear.x2, ox, sw); + y2 = nsvg__convertToPixels(p, data->linear.y2, oy, sh); + // Calculate transform aligned to the line + dx = x2 - x1; + dy = y2 - y1; + grad->xform[0] = dy; grad->xform[1] = -dx; + grad->xform[2] = dx; grad->xform[3] = dy; + grad->xform[4] = x1; grad->xform[5] = y1; + } else { + float cx, cy, fx, fy, r; + cx = nsvg__convertToPixels(p, data->radial.cx, ox, sw); + cy = nsvg__convertToPixels(p, data->radial.cy, oy, sh); + fx = nsvg__convertToPixels(p, data->radial.fx, ox, sw); + fy = nsvg__convertToPixels(p, data->radial.fy, oy, sh); + r = nsvg__convertToPixels(p, data->radial.r, 0, sl); + // Calculate transform aligned to the circle + grad->xform[0] = r; grad->xform[1] = 0; + grad->xform[2] = 0; grad->xform[3] = r; + grad->xform[4] = cx; grad->xform[5] = cy; + grad->fx = fx / r; + grad->fy = fy / r; + } + + nsvg__xformMultiply(grad->xform, data->xform); + nsvg__xformMultiply(grad->xform, xform); + + grad->spread = data->spread; + memcpy(grad->stops, stops, nstops*sizeof(NSVGgradientStop)); + grad->nstops = nstops; + + *paintType = data->type; + + return grad; +} + +static float nsvg__getAverageScale(float* t) +{ + float sx = sqrtf(t[0]*t[0] + t[2]*t[2]); + float sy = sqrtf(t[1]*t[1] + t[3]*t[3]); + return (sx + sy) * 0.5f; +} + +static void nsvg__getLocalBounds(float* bounds, NSVGshape *shape, float* xform) +{ + NSVGpath* path; + float curve[4*2], curveBounds[4]; + int i, first = 1; + for (path = shape->paths; path != NULL; path = path->next) { + nsvg__xformPoint(&curve[0], &curve[1], path->pts[0], path->pts[1], xform); + for (i = 0; i < path->npts-1; i += 3) { + nsvg__xformPoint(&curve[2], &curve[3], path->pts[(i+1)*2], path->pts[(i+1)*2+1], xform); + nsvg__xformPoint(&curve[4], &curve[5], path->pts[(i+2)*2], path->pts[(i+2)*2+1], xform); + nsvg__xformPoint(&curve[6], &curve[7], path->pts[(i+3)*2], path->pts[(i+3)*2+1], xform); + nsvg__curveBounds(curveBounds, curve); + if (first) { + bounds[0] = curveBounds[0]; + bounds[1] = curveBounds[1]; + bounds[2] = curveBounds[2]; + bounds[3] = curveBounds[3]; + first = 0; + } else { + bounds[0] = nsvg__minf(bounds[0], curveBounds[0]); + bounds[1] = nsvg__minf(bounds[1], curveBounds[1]); + bounds[2] = nsvg__maxf(bounds[2], curveBounds[2]); + bounds[3] = nsvg__maxf(bounds[3], curveBounds[3]); + } + curve[0] = curve[6]; + curve[1] = curve[7]; + } + } +} + +static void nsvg__addShape(NSVGparser* p) +{ + NSVGattrib* attr = nsvg__getAttr(p); + float scale = 1.0f; + NSVGshape* shape; + NSVGpath* path; + int i; + + if (p->plist == NULL) + return; + + shape = (NSVGshape*)malloc(sizeof(NSVGshape)); + if (shape == NULL) goto error; + memset(shape, 0, sizeof(NSVGshape)); + + memcpy(shape->id, attr->id, sizeof shape->id); + memcpy(shape->fillGradient, attr->fillGradient, sizeof shape->fillGradient); + memcpy(shape->strokeGradient, attr->strokeGradient, sizeof shape->strokeGradient); + memcpy(shape->xform, attr->xform, sizeof shape->xform); + scale = nsvg__getAverageScale(attr->xform); + shape->strokeWidth = attr->strokeWidth * scale; + shape->strokeDashOffset = attr->strokeDashOffset * scale; + shape->strokeDashCount = (char)attr->strokeDashCount; + for (i = 0; i < attr->strokeDashCount; i++) + shape->strokeDashArray[i] = attr->strokeDashArray[i] * scale; + shape->strokeLineJoin = attr->strokeLineJoin; + shape->strokeLineCap = attr->strokeLineCap; + shape->miterLimit = attr->miterLimit; + shape->fillRule = attr->fillRule; + shape->opacity = attr->opacity; + + shape->paths = p->plist; + p->plist = NULL; + + // Calculate shape bounds + shape->bounds[0] = shape->paths->bounds[0]; + shape->bounds[1] = shape->paths->bounds[1]; + shape->bounds[2] = shape->paths->bounds[2]; + shape->bounds[3] = shape->paths->bounds[3]; + for (path = shape->paths->next; path != NULL; path = path->next) { + shape->bounds[0] = nsvg__minf(shape->bounds[0], path->bounds[0]); + shape->bounds[1] = nsvg__minf(shape->bounds[1], path->bounds[1]); + shape->bounds[2] = nsvg__maxf(shape->bounds[2], path->bounds[2]); + shape->bounds[3] = nsvg__maxf(shape->bounds[3], path->bounds[3]); + } + + // Set fill + if (attr->hasFill == 0) { + shape->fill.type = NSVG_PAINT_NONE; + } else if (attr->hasFill == 1) { + shape->fill.type = NSVG_PAINT_COLOR; + shape->fill.color = attr->fillColor; + shape->fill.color |= (unsigned int)(attr->fillOpacity*255) << 24; + } else if (attr->hasFill == 2) { + shape->fill.type = NSVG_PAINT_UNDEF; + } + + // Set stroke + if (attr->hasStroke == 0) { + shape->stroke.type = NSVG_PAINT_NONE; + } else if (attr->hasStroke == 1) { + shape->stroke.type = NSVG_PAINT_COLOR; + shape->stroke.color = attr->strokeColor; + shape->stroke.color |= (unsigned int)(attr->strokeOpacity*255) << 24; + } else if (attr->hasStroke == 2) { + shape->stroke.type = NSVG_PAINT_UNDEF; + } + + // Set flags + shape->flags = (attr->visible ? NSVG_FLAGS_VISIBLE : 0x00); + + // Add to tail + if (p->image->shapes == NULL) + p->image->shapes = shape; + else + p->shapesTail->next = shape; + p->shapesTail = shape; + + return; + +error: + if (shape) free(shape); +} + +static void nsvg__addPath(NSVGparser* p, char closed) +{ + NSVGattrib* attr = nsvg__getAttr(p); + NSVGpath* path = NULL; + float bounds[4]; + float* curve; + int i; + + if (p->npts < 4) + return; + + if (closed) + nsvg__lineTo(p, p->pts[0], p->pts[1]); + + // Expect 1 + N*3 points (N = number of cubic bezier segments). + if ((p->npts % 3) != 1) + return; + + path = (NSVGpath*)malloc(sizeof(NSVGpath)); + if (path == NULL) goto error; + memset(path, 0, sizeof(NSVGpath)); + + path->pts = (float*)malloc(p->npts*2*sizeof(float)); + if (path->pts == NULL) goto error; + path->closed = closed; + path->npts = p->npts; + + // Transform path. + for (i = 0; i < p->npts; ++i) + nsvg__xformPoint(&path->pts[i*2], &path->pts[i*2+1], p->pts[i*2], p->pts[i*2+1], attr->xform); + + // Find bounds + for (i = 0; i < path->npts-1; i += 3) { + curve = &path->pts[i*2]; + nsvg__curveBounds(bounds, curve); + if (i == 0) { + path->bounds[0] = bounds[0]; + path->bounds[1] = bounds[1]; + path->bounds[2] = bounds[2]; + path->bounds[3] = bounds[3]; + } else { + path->bounds[0] = nsvg__minf(path->bounds[0], bounds[0]); + path->bounds[1] = nsvg__minf(path->bounds[1], bounds[1]); + path->bounds[2] = nsvg__maxf(path->bounds[2], bounds[2]); + path->bounds[3] = nsvg__maxf(path->bounds[3], bounds[3]); + } + } + + path->next = p->plist; + p->plist = path; + + return; + +error: + if (path != NULL) { + if (path->pts != NULL) free(path->pts); + free(path); + } +} + +// We roll our own string to float because the std library one uses locale and messes things up. +static double nsvg__atof(const char* s) +{ + char* cur = (char*)s; + char* end = NULL; + double res = 0.0, sign = 1.0; + long long intPart = 0, fracPart = 0; + char hasIntPart = 0, hasFracPart = 0; + + // Parse optional sign + if (*cur == '+') { + cur++; + } else if (*cur == '-') { + sign = -1; + cur++; + } + + // Parse integer part + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + intPart = strtoll(cur, &end, 10); + if (cur != end) { + res = (double)intPart; + hasIntPart = 1; + cur = end; + } + } + + // Parse fractional part. + if (*cur == '.') { + cur++; // Skip '.' + if (nsvg__isdigit(*cur)) { + // Parse digit sequence + fracPart = strtoll(cur, &end, 10); + if (cur != end) { + res += (double)fracPart / pow(10.0, (double)(end - cur)); + hasFracPart = 1; + cur = end; + } + } + } + + // A valid number should have integer or fractional part. + if (!hasIntPart && !hasFracPart) + return 0.0; + + // Parse optional exponent + if (*cur == 'e' || *cur == 'E') { + long expPart = 0; + cur++; // skip 'E' + expPart = strtol(cur, &end, 10); // Parse digit sequence with sign + if (cur != end) { + res *= pow(10.0, (double)expPart); + } + } + + return res * sign; +} + + +static const char* nsvg__parseNumber(const char* s, char* it, const int size) +{ + const int last = size-1; + int i = 0; + + // sign + if (*s == '-' || *s == '+') { + if (i < last) it[i++] = *s; + s++; + } + // integer part + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + if (*s == '.') { + // decimal point + if (i < last) it[i++] = *s; + s++; + // fraction part + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + } + // exponent + if ((*s == 'e' || *s == 'E') && (s[1] != 'm' && s[1] != 'x')) { + if (i < last) it[i++] = *s; + s++; + if (*s == '-' || *s == '+') { + if (i < last) it[i++] = *s; + s++; + } + while (*s && nsvg__isdigit(*s)) { + if (i < last) it[i++] = *s; + s++; + } + } + it[i] = '\0'; + + return s; +} + +static const char* nsvg__getNextPathItemWhenArcFlag(const char* s, char* it) +{ + it[0] = '\0'; + while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + if (!*s) return s; + if (*s == '0' || *s == '1') { + it[0] = *s++; + it[1] = '\0'; + return s; + } + return s; +} + +static const char* nsvg__getNextPathItem(const char* s, char* it) +{ + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + if (!*s) return s; + if (*s == '-' || *s == '+' || *s == '.' || nsvg__isdigit(*s)) { + s = nsvg__parseNumber(s, it, 64); + } else { + // Parse command + it[0] = *s++; + it[1] = '\0'; + return s; + } + + return s; +} + +static unsigned int nsvg__parseColorHex(const char* str) +{ + unsigned int r=0, g=0, b=0; + if (sscanf(str, "#%2x%2x%2x", &r, &g, &b) == 3 ) // 2 digit hex + return NSVG_RGB(r, g, b); + if (sscanf(str, "#%1x%1x%1x", &r, &g, &b) == 3 ) // 1 digit hex, e.g. #abc -> 0xccbbaa + return NSVG_RGB(r*17, g*17, b*17); // same effect as (r<<4|r), (g<<4|g), .. + return NSVG_RGB(128, 128, 128); +} + +// Parse rgb color. The pointer 'str' must point at "rgb(" (4+ characters). +// This function returns gray (rgb(128, 128, 128) == '#808080') on parse errors +// for backwards compatibility. Note: other image viewers return black instead. + +static unsigned int nsvg__parseColorRGB(const char* str) +{ + int i; + unsigned int rgbi[3]; + float rgbf[3]; + // try decimal integers first + if (sscanf(str, "rgb(%u, %u, %u)", &rgbi[0], &rgbi[1], &rgbi[2]) != 3) { + // integers failed, try percent values (float, locale independent) + const char delimiter[3] = {',', ',', ')'}; + str += 4; // skip "rgb(" + for (i = 0; i < 3; i++) { + while (*str && (nsvg__isspace(*str))) str++; // skip leading spaces + if (*str == '+') str++; // skip '+' (don't allow '-') + if (!*str) break; + rgbf[i] = nsvg__atof(str); + + // Note 1: it would be great if nsvg__atof() returned how many + // bytes it consumed but it doesn't. We need to skip the number, + // the '%' character, spaces, and the delimiter ',' or ')'. + + // Note 2: The following code does not allow values like "33.%", + // i.e. a decimal point w/o fractional part, but this is consistent + // with other image viewers, e.g. firefox, chrome, eog, gimp. + + while (*str && nsvg__isdigit(*str)) str++; // skip integer part + if (*str == '.') { + str++; + if (!nsvg__isdigit(*str)) break; // error: no digit after '.' + while (*str && nsvg__isdigit(*str)) str++; // skip fractional part + } + if (*str == '%') str++; else break; + while (nsvg__isspace(*str)) str++; + if (*str == delimiter[i]) str++; + else break; + } + if (i == 3) { + rgbi[0] = roundf(rgbf[0] * 2.55f); + rgbi[1] = roundf(rgbf[1] * 2.55f); + rgbi[2] = roundf(rgbf[2] * 2.55f); + } else { + rgbi[0] = rgbi[1] = rgbi[2] = 128; + } + } + // clip values as the CSS spec requires + for (i = 0; i < 3; i++) { + if (rgbi[i] > 255) rgbi[i] = 255; + } + return NSVG_RGB(rgbi[0], rgbi[1], rgbi[2]); +} + +typedef struct NSVGNamedColor { + const char* name; + unsigned int color; +} NSVGNamedColor; + +NSVGNamedColor nsvg__colors[] = { + + { "red", NSVG_RGB(255, 0, 0) }, + { "green", NSVG_RGB( 0, 128, 0) }, + { "blue", NSVG_RGB( 0, 0, 255) }, + { "yellow", NSVG_RGB(255, 255, 0) }, + { "cyan", NSVG_RGB( 0, 255, 255) }, + { "magenta", NSVG_RGB(255, 0, 255) }, + { "black", NSVG_RGB( 0, 0, 0) }, + { "grey", NSVG_RGB(128, 128, 128) }, + { "gray", NSVG_RGB(128, 128, 128) }, + { "white", NSVG_RGB(255, 255, 255) }, + +#ifdef NANOSVG_ALL_COLOR_KEYWORDS + { "aliceblue", NSVG_RGB(240, 248, 255) }, + { "antiquewhite", NSVG_RGB(250, 235, 215) }, + { "aqua", NSVG_RGB( 0, 255, 255) }, + { "aquamarine", NSVG_RGB(127, 255, 212) }, + { "azure", NSVG_RGB(240, 255, 255) }, + { "beige", NSVG_RGB(245, 245, 220) }, + { "bisque", NSVG_RGB(255, 228, 196) }, + { "blanchedalmond", NSVG_RGB(255, 235, 205) }, + { "blueviolet", NSVG_RGB(138, 43, 226) }, + { "brown", NSVG_RGB(165, 42, 42) }, + { "burlywood", NSVG_RGB(222, 184, 135) }, + { "cadetblue", NSVG_RGB( 95, 158, 160) }, + { "chartreuse", NSVG_RGB(127, 255, 0) }, + { "chocolate", NSVG_RGB(210, 105, 30) }, + { "coral", NSVG_RGB(255, 127, 80) }, + { "cornflowerblue", NSVG_RGB(100, 149, 237) }, + { "cornsilk", NSVG_RGB(255, 248, 220) }, + { "crimson", NSVG_RGB(220, 20, 60) }, + { "darkblue", NSVG_RGB( 0, 0, 139) }, + { "darkcyan", NSVG_RGB( 0, 139, 139) }, + { "darkgoldenrod", NSVG_RGB(184, 134, 11) }, + { "darkgray", NSVG_RGB(169, 169, 169) }, + { "darkgreen", NSVG_RGB( 0, 100, 0) }, + { "darkgrey", NSVG_RGB(169, 169, 169) }, + { "darkkhaki", NSVG_RGB(189, 183, 107) }, + { "darkmagenta", NSVG_RGB(139, 0, 139) }, + { "darkolivegreen", NSVG_RGB( 85, 107, 47) }, + { "darkorange", NSVG_RGB(255, 140, 0) }, + { "darkorchid", NSVG_RGB(153, 50, 204) }, + { "darkred", NSVG_RGB(139, 0, 0) }, + { "darksalmon", NSVG_RGB(233, 150, 122) }, + { "darkseagreen", NSVG_RGB(143, 188, 143) }, + { "darkslateblue", NSVG_RGB( 72, 61, 139) }, + { "darkslategray", NSVG_RGB( 47, 79, 79) }, + { "darkslategrey", NSVG_RGB( 47, 79, 79) }, + { "darkturquoise", NSVG_RGB( 0, 206, 209) }, + { "darkviolet", NSVG_RGB(148, 0, 211) }, + { "deeppink", NSVG_RGB(255, 20, 147) }, + { "deepskyblue", NSVG_RGB( 0, 191, 255) }, + { "dimgray", NSVG_RGB(105, 105, 105) }, + { "dimgrey", NSVG_RGB(105, 105, 105) }, + { "dodgerblue", NSVG_RGB( 30, 144, 255) }, + { "firebrick", NSVG_RGB(178, 34, 34) }, + { "floralwhite", NSVG_RGB(255, 250, 240) }, + { "forestgreen", NSVG_RGB( 34, 139, 34) }, + { "fuchsia", NSVG_RGB(255, 0, 255) }, + { "gainsboro", NSVG_RGB(220, 220, 220) }, + { "ghostwhite", NSVG_RGB(248, 248, 255) }, + { "gold", NSVG_RGB(255, 215, 0) }, + { "goldenrod", NSVG_RGB(218, 165, 32) }, + { "greenyellow", NSVG_RGB(173, 255, 47) }, + { "honeydew", NSVG_RGB(240, 255, 240) }, + { "hotpink", NSVG_RGB(255, 105, 180) }, + { "indianred", NSVG_RGB(205, 92, 92) }, + { "indigo", NSVG_RGB( 75, 0, 130) }, + { "ivory", NSVG_RGB(255, 255, 240) }, + { "khaki", NSVG_RGB(240, 230, 140) }, + { "lavender", NSVG_RGB(230, 230, 250) }, + { "lavenderblush", NSVG_RGB(255, 240, 245) }, + { "lawngreen", NSVG_RGB(124, 252, 0) }, + { "lemonchiffon", NSVG_RGB(255, 250, 205) }, + { "lightblue", NSVG_RGB(173, 216, 230) }, + { "lightcoral", NSVG_RGB(240, 128, 128) }, + { "lightcyan", NSVG_RGB(224, 255, 255) }, + { "lightgoldenrodyellow", NSVG_RGB(250, 250, 210) }, + { "lightgray", NSVG_RGB(211, 211, 211) }, + { "lightgreen", NSVG_RGB(144, 238, 144) }, + { "lightgrey", NSVG_RGB(211, 211, 211) }, + { "lightpink", NSVG_RGB(255, 182, 193) }, + { "lightsalmon", NSVG_RGB(255, 160, 122) }, + { "lightseagreen", NSVG_RGB( 32, 178, 170) }, + { "lightskyblue", NSVG_RGB(135, 206, 250) }, + { "lightslategray", NSVG_RGB(119, 136, 153) }, + { "lightslategrey", NSVG_RGB(119, 136, 153) }, + { "lightsteelblue", NSVG_RGB(176, 196, 222) }, + { "lightyellow", NSVG_RGB(255, 255, 224) }, + { "lime", NSVG_RGB( 0, 255, 0) }, + { "limegreen", NSVG_RGB( 50, 205, 50) }, + { "linen", NSVG_RGB(250, 240, 230) }, + { "maroon", NSVG_RGB(128, 0, 0) }, + { "mediumaquamarine", NSVG_RGB(102, 205, 170) }, + { "mediumblue", NSVG_RGB( 0, 0, 205) }, + { "mediumorchid", NSVG_RGB(186, 85, 211) }, + { "mediumpurple", NSVG_RGB(147, 112, 219) }, + { "mediumseagreen", NSVG_RGB( 60, 179, 113) }, + { "mediumslateblue", NSVG_RGB(123, 104, 238) }, + { "mediumspringgreen", NSVG_RGB( 0, 250, 154) }, + { "mediumturquoise", NSVG_RGB( 72, 209, 204) }, + { "mediumvioletred", NSVG_RGB(199, 21, 133) }, + { "midnightblue", NSVG_RGB( 25, 25, 112) }, + { "mintcream", NSVG_RGB(245, 255, 250) }, + { "mistyrose", NSVG_RGB(255, 228, 225) }, + { "moccasin", NSVG_RGB(255, 228, 181) }, + { "navajowhite", NSVG_RGB(255, 222, 173) }, + { "navy", NSVG_RGB( 0, 0, 128) }, + { "oldlace", NSVG_RGB(253, 245, 230) }, + { "olive", NSVG_RGB(128, 128, 0) }, + { "olivedrab", NSVG_RGB(107, 142, 35) }, + { "orange", NSVG_RGB(255, 165, 0) }, + { "orangered", NSVG_RGB(255, 69, 0) }, + { "orchid", NSVG_RGB(218, 112, 214) }, + { "palegoldenrod", NSVG_RGB(238, 232, 170) }, + { "palegreen", NSVG_RGB(152, 251, 152) }, + { "paleturquoise", NSVG_RGB(175, 238, 238) }, + { "palevioletred", NSVG_RGB(219, 112, 147) }, + { "papayawhip", NSVG_RGB(255, 239, 213) }, + { "peachpuff", NSVG_RGB(255, 218, 185) }, + { "peru", NSVG_RGB(205, 133, 63) }, + { "pink", NSVG_RGB(255, 192, 203) }, + { "plum", NSVG_RGB(221, 160, 221) }, + { "powderblue", NSVG_RGB(176, 224, 230) }, + { "purple", NSVG_RGB(128, 0, 128) }, + { "rosybrown", NSVG_RGB(188, 143, 143) }, + { "royalblue", NSVG_RGB( 65, 105, 225) }, + { "saddlebrown", NSVG_RGB(139, 69, 19) }, + { "salmon", NSVG_RGB(250, 128, 114) }, + { "sandybrown", NSVG_RGB(244, 164, 96) }, + { "seagreen", NSVG_RGB( 46, 139, 87) }, + { "seashell", NSVG_RGB(255, 245, 238) }, + { "sienna", NSVG_RGB(160, 82, 45) }, + { "silver", NSVG_RGB(192, 192, 192) }, + { "skyblue", NSVG_RGB(135, 206, 235) }, + { "slateblue", NSVG_RGB(106, 90, 205) }, + { "slategray", NSVG_RGB(112, 128, 144) }, + { "slategrey", NSVG_RGB(112, 128, 144) }, + { "snow", NSVG_RGB(255, 250, 250) }, + { "springgreen", NSVG_RGB( 0, 255, 127) }, + { "steelblue", NSVG_RGB( 70, 130, 180) }, + { "tan", NSVG_RGB(210, 180, 140) }, + { "teal", NSVG_RGB( 0, 128, 128) }, + { "thistle", NSVG_RGB(216, 191, 216) }, + { "tomato", NSVG_RGB(255, 99, 71) }, + { "turquoise", NSVG_RGB( 64, 224, 208) }, + { "violet", NSVG_RGB(238, 130, 238) }, + { "wheat", NSVG_RGB(245, 222, 179) }, + { "whitesmoke", NSVG_RGB(245, 245, 245) }, + { "yellowgreen", NSVG_RGB(154, 205, 50) }, +#endif +}; + +static unsigned int nsvg__parseColorName(const char* str) +{ + int i, ncolors = sizeof(nsvg__colors) / sizeof(NSVGNamedColor); + + for (i = 0; i < ncolors; i++) { + if (strcmp(nsvg__colors[i].name, str) == 0) { + return nsvg__colors[i].color; + } + } + + return NSVG_RGB(128, 128, 128); +} + +static unsigned int nsvg__parseColor(const char* str) +{ + size_t len = 0; + while(*str == ' ') ++str; + len = strlen(str); + if (len >= 1 && *str == '#') + return nsvg__parseColorHex(str); + else if (len >= 4 && str[0] == 'r' && str[1] == 'g' && str[2] == 'b' && str[3] == '(') + return nsvg__parseColorRGB(str); + return nsvg__parseColorName(str); +} + +static float nsvg__parseOpacity(const char* str) +{ + float val = nsvg__atof(str); + if (val < 0.0f) val = 0.0f; + if (val > 1.0f) val = 1.0f; + return val; +} + +static float nsvg__parseMiterLimit(const char* str) +{ + float val = nsvg__atof(str); + if (val < 0.0f) val = 0.0f; + return val; +} + +static int nsvg__parseUnits(const char* units) +{ + if (units[0] == 'p' && units[1] == 'x') + return NSVG_UNITS_PX; + else if (units[0] == 'p' && units[1] == 't') + return NSVG_UNITS_PT; + else if (units[0] == 'p' && units[1] == 'c') + return NSVG_UNITS_PC; + else if (units[0] == 'm' && units[1] == 'm') + return NSVG_UNITS_MM; + else if (units[0] == 'c' && units[1] == 'm') + return NSVG_UNITS_CM; + else if (units[0] == 'i' && units[1] == 'n') + return NSVG_UNITS_IN; + else if (units[0] == '%') + return NSVG_UNITS_PERCENT; + else if (units[0] == 'e' && units[1] == 'm') + return NSVG_UNITS_EM; + else if (units[0] == 'e' && units[1] == 'x') + return NSVG_UNITS_EX; + return NSVG_UNITS_USER; +} + +static int nsvg__isCoordinate(const char* s) +{ + // optional sign + if (*s == '-' || *s == '+') + s++; + // must have at least one digit, or start by a dot + return (nsvg__isdigit(*s) || *s == '.'); +} + +static NSVGcoordinate nsvg__parseCoordinateRaw(const char* str) +{ + NSVGcoordinate coord = {0, NSVG_UNITS_USER}; + char buf[64]; + coord.units = nsvg__parseUnits(nsvg__parseNumber(str, buf, 64)); + coord.value = nsvg__atof(buf); + return coord; +} + +static NSVGcoordinate nsvg__coord(float v, int units) +{ + NSVGcoordinate coord = {v, units}; + return coord; +} + +static float nsvg__parseCoordinate(NSVGparser* p, const char* str, float orig, float length) +{ + NSVGcoordinate coord = nsvg__parseCoordinateRaw(str); + return nsvg__convertToPixels(p, coord, orig, length); +} + +static int nsvg__parseTransformArgs(const char* str, float* args, int maxNa, int* na) +{ + const char* end; + const char* ptr; + char it[64]; + + *na = 0; + ptr = str; + while (*ptr && *ptr != '(') ++ptr; + if (*ptr == 0) + return 1; + end = ptr; + while (*end && *end != ')') ++end; + if (*end == 0) + return 1; + + while (ptr < end) { + if (*ptr == '-' || *ptr == '+' || *ptr == '.' || nsvg__isdigit(*ptr)) { + if (*na >= maxNa) return 0; + ptr = nsvg__parseNumber(ptr, it, 64); + args[(*na)++] = (float)nsvg__atof(it); + } else { + ++ptr; + } + } + return (int)(end - str); +} + + +static int nsvg__parseMatrix(float* xform, const char* str) +{ + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, t, 6, &na); + if (na != 6) return len; + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseTranslate(float* xform, const char* str) +{ + float args[2]; + float t[6]; + int na = 0; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) args[1] = 0.0; + + nsvg__xformSetTranslation(t, args[0], args[1]); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseScale(float* xform, const char* str) +{ + float args[2]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 2, &na); + if (na == 1) args[1] = args[0]; + nsvg__xformSetScale(t, args[0], args[1]); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseSkewX(float* xform, const char* str) +{ + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewX(t, args[0]/180.0f*NSVG_PI); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseSkewY(float* xform, const char* str) +{ + float args[1]; + int na = 0; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 1, &na); + nsvg__xformSetSkewY(t, args[0]/180.0f*NSVG_PI); + memcpy(xform, t, sizeof(float)*6); + return len; +} + +static int nsvg__parseRotate(float* xform, const char* str) +{ + float args[3]; + int na = 0; + float m[6]; + float t[6]; + int len = nsvg__parseTransformArgs(str, args, 3, &na); + if (na == 1) + args[1] = args[2] = 0.0f; + nsvg__xformIdentity(m); + + if (na > 1) { + nsvg__xformSetTranslation(t, -args[1], -args[2]); + nsvg__xformMultiply(m, t); + } + + nsvg__xformSetRotation(t, args[0]/180.0f*NSVG_PI); + nsvg__xformMultiply(m, t); + + if (na > 1) { + nsvg__xformSetTranslation(t, args[1], args[2]); + nsvg__xformMultiply(m, t); + } + + memcpy(xform, m, sizeof(float)*6); + + return len; +} + +static void nsvg__parseTransform(float* xform, const char* str) +{ + float t[6]; + int len; + nsvg__xformIdentity(xform); + while (*str) + { + if (strncmp(str, "matrix", 6) == 0) + len = nsvg__parseMatrix(t, str); + else if (strncmp(str, "translate", 9) == 0) + len = nsvg__parseTranslate(t, str); + else if (strncmp(str, "scale", 5) == 0) + len = nsvg__parseScale(t, str); + else if (strncmp(str, "rotate", 6) == 0) + len = nsvg__parseRotate(t, str); + else if (strncmp(str, "skewX", 5) == 0) + len = nsvg__parseSkewX(t, str); + else if (strncmp(str, "skewY", 5) == 0) + len = nsvg__parseSkewY(t, str); + else{ + ++str; + continue; + } + if (len != 0) { + str += len; + } else { + ++str; + continue; + } + + nsvg__xformPremultiply(xform, t); + } +} + +static void nsvg__parseUrl(char* id, const char* str) +{ + int i = 0; + str += 4; // "url("; + if (*str && *str == '#') + str++; + while (i < 63 && *str && *str != ')') { + id[i] = *str++; + i++; + } + id[i] = '\0'; +} + +static char nsvg__parseLineCap(const char* str) +{ + if (strcmp(str, "butt") == 0) + return NSVG_CAP_BUTT; + else if (strcmp(str, "round") == 0) + return NSVG_CAP_ROUND; + else if (strcmp(str, "square") == 0) + return NSVG_CAP_SQUARE; + // TODO: handle inherit. + return NSVG_CAP_BUTT; +} + +static char nsvg__parseLineJoin(const char* str) +{ + if (strcmp(str, "miter") == 0) + return NSVG_JOIN_MITER; + else if (strcmp(str, "round") == 0) + return NSVG_JOIN_ROUND; + else if (strcmp(str, "bevel") == 0) + return NSVG_JOIN_BEVEL; + // TODO: handle inherit. + return NSVG_JOIN_MITER; +} + +static char nsvg__parseFillRule(const char* str) +{ + if (strcmp(str, "nonzero") == 0) + return NSVG_FILLRULE_NONZERO; + else if (strcmp(str, "evenodd") == 0) + return NSVG_FILLRULE_EVENODD; + // TODO: handle inherit. + return NSVG_FILLRULE_NONZERO; +} + +static const char* nsvg__getNextDashItem(const char* s, char* it) +{ + int n = 0; + it[0] = '\0'; + // Skip white spaces and commas + while (*s && (nsvg__isspace(*s) || *s == ',')) s++; + // Advance until whitespace, comma or end. + while (*s && (!nsvg__isspace(*s) && *s != ',')) { + if (n < 63) + it[n++] = *s; + s++; + } + it[n++] = '\0'; + return s; +} + +static int nsvg__parseStrokeDashArray(NSVGparser* p, const char* str, float* strokeDashArray) +{ + char item[64]; + int count = 0, i; + float sum = 0.0f; + + // Handle "none" + if (str[0] == 'n') + return 0; + + // Parse dashes + while (*str) { + str = nsvg__getNextDashItem(str, item); + if (!*item) break; + if (count < NSVG_MAX_DASHES) + strokeDashArray[count++] = fabsf(nsvg__parseCoordinate(p, item, 0.0f, nsvg__actualLength(p))); + } + + for (i = 0; i < count; i++) + sum += strokeDashArray[i]; + if (sum <= 1e-6f) + count = 0; + + return count; +} + +static void nsvg__parseStyle(NSVGparser* p, const char* str); + +static int nsvg__parseAttr(NSVGparser* p, const char* name, const char* value) +{ + float xform[6]; + NSVGattrib* attr = nsvg__getAttr(p); + if (!attr) return 0; + + if (strcmp(name, "style") == 0) { + nsvg__parseStyle(p, value); + } else if (strcmp(name, "display") == 0) { + if (strcmp(value, "none") == 0) + attr->visible = 0; + // Don't reset ->visible on display:inline, one display:none hides the whole subtree + + } else if (strcmp(name, "fill") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasFill = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasFill = 2; + nsvg__parseUrl(attr->fillGradient, value); + } else { + attr->hasFill = 1; + attr->fillColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "opacity") == 0) { + attr->opacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "fill-opacity") == 0) { + attr->fillOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke") == 0) { + if (strcmp(value, "none") == 0) { + attr->hasStroke = 0; + } else if (strncmp(value, "url(", 4) == 0) { + attr->hasStroke = 2; + nsvg__parseUrl(attr->strokeGradient, value); + } else { + attr->hasStroke = 1; + attr->strokeColor = nsvg__parseColor(value); + } + } else if (strcmp(name, "stroke-width") == 0) { + attr->strokeWidth = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-dasharray") == 0) { + attr->strokeDashCount = nsvg__parseStrokeDashArray(p, value, attr->strokeDashArray); + } else if (strcmp(name, "stroke-dashoffset") == 0) { + attr->strokeDashOffset = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "stroke-opacity") == 0) { + attr->strokeOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "stroke-linecap") == 0) { + attr->strokeLineCap = nsvg__parseLineCap(value); + } else if (strcmp(name, "stroke-linejoin") == 0) { + attr->strokeLineJoin = nsvg__parseLineJoin(value); + } else if (strcmp(name, "stroke-miterlimit") == 0) { + attr->miterLimit = nsvg__parseMiterLimit(value); + } else if (strcmp(name, "fill-rule") == 0) { + attr->fillRule = nsvg__parseFillRule(value); + } else if (strcmp(name, "font-size") == 0) { + attr->fontSize = nsvg__parseCoordinate(p, value, 0.0f, nsvg__actualLength(p)); + } else if (strcmp(name, "transform") == 0) { + nsvg__parseTransform(xform, value); + nsvg__xformPremultiply(attr->xform, xform); + } else if (strcmp(name, "stop-color") == 0) { + attr->stopColor = nsvg__parseColor(value); + } else if (strcmp(name, "stop-opacity") == 0) { + attr->stopOpacity = nsvg__parseOpacity(value); + } else if (strcmp(name, "offset") == 0) { + attr->stopOffset = nsvg__parseCoordinate(p, value, 0.0f, 1.0f); + } else if (strcmp(name, "id") == 0) { + strncpy(attr->id, value, 63); + attr->id[63] = '\0'; + } else { + return 0; + } + return 1; +} + +static int nsvg__parseNameValue(NSVGparser* p, const char* start, const char* end) +{ + const char* str; + const char* val; + char name[512]; + char value[512]; + int n; + + str = start; + while (str < end && *str != ':') ++str; + + val = str; + + // Right Trim + while (str > start && (*str == ':' || nsvg__isspace(*str))) --str; + ++str; + + n = (int)(str - start); + if (n > 511) n = 511; + if (n) memcpy(name, start, n); + name[n] = 0; + + while (val < end && (*val == ':' || nsvg__isspace(*val))) ++val; + + n = (int)(end - val); + if (n > 511) n = 511; + if (n) memcpy(value, val, n); + value[n] = 0; + + return nsvg__parseAttr(p, name, value); +} + +static void nsvg__parseStyle(NSVGparser* p, const char* str) +{ + const char* start; + const char* end; + + while (*str) { + // Left Trim + while(*str && nsvg__isspace(*str)) ++str; + start = str; + while(*str && *str != ';') ++str; + end = str; + + // Right Trim + while (end > start && (*end == ';' || nsvg__isspace(*end))) --end; + ++end; + + nsvg__parseNameValue(p, start, end); + if (*str) ++str; + } +} + +static void nsvg__parseAttribs(NSVGparser* p, const char** attr) +{ + int i; + for (i = 0; attr[i]; i += 2) + { + if (strcmp(attr[i], "style") == 0) + nsvg__parseStyle(p, attr[i + 1]); + else + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } +} + +static int nsvg__getArgsPerElement(char cmd) +{ + switch (cmd) { + case 'v': + case 'V': + case 'h': + case 'H': + return 1; + case 'm': + case 'M': + case 'l': + case 'L': + case 't': + case 'T': + return 2; + case 'q': + case 'Q': + case 's': + case 'S': + return 4; + case 'c': + case 'C': + return 6; + case 'a': + case 'A': + return 7; + case 'z': + case 'Z': + return 0; + } + return -1; +} + +static void nsvg__pathMoveTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__moveTo(p, *cpx, *cpy); +} + +static void nsvg__pathLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) { + *cpx += args[0]; + *cpy += args[1]; + } else { + *cpx = args[0]; + *cpy = args[1]; + } + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathHLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) + *cpx += args[0]; + else + *cpx = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathVLineTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + if (rel) + *cpy += args[0]; + else + *cpy = args[0]; + nsvg__lineTo(p, *cpx, *cpy); +} + +static void nsvg__pathCubicBezTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x2, y2, cx1, cy1, cx2, cy2; + + if (rel) { + cx1 = *cpx + args[0]; + cy1 = *cpy + args[1]; + cx2 = *cpx + args[2]; + cy2 = *cpy + args[3]; + x2 = *cpx + args[4]; + y2 = *cpy + args[5]; + } else { + cx1 = args[0]; + cy1 = args[1]; + cx2 = args[2]; + cy2 = args[3]; + x2 = args[4]; + y2 = args[5]; + } + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathCubicBezShortTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx2 = *cpx + args[0]; + cy2 = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx2 = args[0]; + cy2 = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + cx1 = 2*x1 - *cpx2; + cy1 = 2*y1 - *cpy2; + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx2; + *cpy2 = cy2; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + cx = *cpx + args[0]; + cy = *cpy + args[1]; + x2 = *cpx + args[2]; + y2 = *cpy + args[3]; + } else { + cx = args[0]; + cy = args[1]; + x2 = args[2]; + y2 = args[3]; + } + + // Convert to cubic bezier + cx1 = x1 + 2.0f/3.0f*(cx - x1); + cy1 = y1 + 2.0f/3.0f*(cy - y1); + cx2 = x2 + 2.0f/3.0f*(cx - x2); + cy2 = y2 + 2.0f/3.0f*(cy - y2); + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static void nsvg__pathQuadBezShortTo(NSVGparser* p, float* cpx, float* cpy, + float* cpx2, float* cpy2, float* args, int rel) +{ + float x1, y1, x2, y2, cx, cy; + float cx1, cy1, cx2, cy2; + + x1 = *cpx; + y1 = *cpy; + if (rel) { + x2 = *cpx + args[0]; + y2 = *cpy + args[1]; + } else { + x2 = args[0]; + y2 = args[1]; + } + + cx = 2*x1 - *cpx2; + cy = 2*y1 - *cpy2; + + // Convert to cubix bezier + cx1 = x1 + 2.0f/3.0f*(cx - x1); + cy1 = y1 + 2.0f/3.0f*(cy - y1); + cx2 = x2 + 2.0f/3.0f*(cx - x2); + cy2 = y2 + 2.0f/3.0f*(cy - y2); + + nsvg__cubicBezTo(p, cx1,cy1, cx2,cy2, x2,y2); + + *cpx2 = cx; + *cpy2 = cy; + *cpx = x2; + *cpy = y2; +} + +static float nsvg__sqr(float x) { return x*x; } +static float nsvg__vmag(float x, float y) { return sqrtf(x*x + y*y); } + +static float nsvg__vecrat(float ux, float uy, float vx, float vy) +{ + return (ux*vx + uy*vy) / (nsvg__vmag(ux,uy) * nsvg__vmag(vx,vy)); +} + +static float nsvg__vecang(float ux, float uy, float vx, float vy) +{ + float r = nsvg__vecrat(ux,uy, vx,vy); + if (r < -1.0f) r = -1.0f; + if (r > 1.0f) r = 1.0f; + return ((ux*vy < uy*vx) ? -1.0f : 1.0f) * acosf(r); +} + +static void nsvg__pathArcTo(NSVGparser* p, float* cpx, float* cpy, float* args, int rel) +{ + // Ported from canvg (https://code.google.com/p/canvg/) + float rx, ry, rotx; + float x1, y1, x2, y2, cx, cy, dx, dy, d; + float x1p, y1p, cxp, cyp, s, sa, sb; + float ux, uy, vx, vy, a1, da; + float x, y, tanx, tany, a, px = 0, py = 0, ptanx = 0, ptany = 0, t[6]; + float sinrx, cosrx; + int fa, fs; + int i, ndivs; + float hda, kappa; + + rx = fabsf(args[0]); // y radius + ry = fabsf(args[1]); // x radius + rotx = args[2] / 180.0f * NSVG_PI; // x rotation angle + fa = fabsf(args[3]) > 1e-6 ? 1 : 0; // Large arc + fs = fabsf(args[4]) > 1e-6 ? 1 : 0; // Sweep direction + x1 = *cpx; // start point + y1 = *cpy; + if (rel) { // end point + x2 = *cpx + args[5]; + y2 = *cpy + args[6]; + } else { + x2 = args[5]; + y2 = args[6]; + } + + dx = x1 - x2; + dy = y1 - y2; + d = sqrtf(dx*dx + dy*dy); + if (d < 1e-6f || rx < 1e-6f || ry < 1e-6f) { + // The arc degenerates to a line + nsvg__lineTo(p, x2, y2); + *cpx = x2; + *cpy = y2; + return; + } + + sinrx = sinf(rotx); + cosrx = cosf(rotx); + + // Convert to center point parameterization. + // http://www.w3.org/TR/SVG11/implnote.html#ArcImplementationNotes + // 1) Compute x1', y1' + x1p = cosrx * dx / 2.0f + sinrx * dy / 2.0f; + y1p = -sinrx * dx / 2.0f + cosrx * dy / 2.0f; + d = nsvg__sqr(x1p)/nsvg__sqr(rx) + nsvg__sqr(y1p)/nsvg__sqr(ry); + if (d > 1) { + d = sqrtf(d); + rx *= d; + ry *= d; + } + // 2) Compute cx', cy' + s = 0.0f; + sa = nsvg__sqr(rx)*nsvg__sqr(ry) - nsvg__sqr(rx)*nsvg__sqr(y1p) - nsvg__sqr(ry)*nsvg__sqr(x1p); + sb = nsvg__sqr(rx)*nsvg__sqr(y1p) + nsvg__sqr(ry)*nsvg__sqr(x1p); + if (sa < 0.0f) sa = 0.0f; + if (sb > 0.0f) + s = sqrtf(sa / sb); + if (fa == fs) + s = -s; + cxp = s * rx * y1p / ry; + cyp = s * -ry * x1p / rx; + + // 3) Compute cx,cy from cx',cy' + cx = (x1 + x2)/2.0f + cosrx*cxp - sinrx*cyp; + cy = (y1 + y2)/2.0f + sinrx*cxp + cosrx*cyp; + + // 4) Calculate theta1, and delta theta. + ux = (x1p - cxp) / rx; + uy = (y1p - cyp) / ry; + vx = (-x1p - cxp) / rx; + vy = (-y1p - cyp) / ry; + a1 = nsvg__vecang(1.0f,0.0f, ux,uy); // Initial angle + da = nsvg__vecang(ux,uy, vx,vy); // Delta angle + +// if (vecrat(ux,uy,vx,vy) <= -1.0f) da = NSVG_PI; +// if (vecrat(ux,uy,vx,vy) >= 1.0f) da = 0; + + if (fs == 0 && da > 0) + da -= 2 * NSVG_PI; + else if (fs == 1 && da < 0) + da += 2 * NSVG_PI; + + // Approximate the arc using cubic spline segments. + t[0] = cosrx; t[1] = sinrx; + t[2] = -sinrx; t[3] = cosrx; + t[4] = cx; t[5] = cy; + + // Split arc into max 90 degree segments. + // The loop assumes an iteration per end point (including start and end), this +1. + ndivs = (int)(fabsf(da) / (NSVG_PI*0.5f) + 1.0f); + hda = (da / (float)ndivs) / 2.0f; + // Fix for ticket #179: division by 0: avoid cotangens around 0 (infinite) + if ((hda < 1e-3f) && (hda > -1e-3f)) + hda *= 0.5f; + else + hda = (1.0f - cosf(hda)) / sinf(hda); + kappa = fabsf(4.0f / 3.0f * hda); + if (da < 0.0f) + kappa = -kappa; + + for (i = 0; i <= ndivs; i++) { + a = a1 + da * ((float)i/(float)ndivs); + dx = cosf(a); + dy = sinf(a); + nsvg__xformPoint(&x, &y, dx*rx, dy*ry, t); // position + nsvg__xformVec(&tanx, &tany, -dy*rx * kappa, dx*ry * kappa, t); // tangent + if (i > 0) + nsvg__cubicBezTo(p, px+ptanx,py+ptany, x-tanx, y-tany, x, y); + px = x; + py = y; + ptanx = tanx; + ptany = tany; + } + + *cpx = x2; + *cpy = y2; +} + +static void nsvg__parsePath(NSVGparser* p, const char** attr) +{ + const char* s = NULL; + char cmd = '\0'; + float args[10]; + int nargs; + int rargs = 0; + char initPoint; + float cpx, cpy, cpx2, cpy2; + const char* tmp[4]; + char closedFlag; + int i; + char item[64]; + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "d") == 0) { + s = attr[i + 1]; + } else { + tmp[0] = attr[i]; + tmp[1] = attr[i + 1]; + tmp[2] = 0; + tmp[3] = 0; + nsvg__parseAttribs(p, tmp); + } + } + + if (s) { + nsvg__resetPath(p); + cpx = 0; cpy = 0; + cpx2 = 0; cpy2 = 0; + initPoint = 0; + closedFlag = 0; + nargs = 0; + + while (*s) { + item[0] = '\0'; + if ((cmd == 'A' || cmd == 'a') && (nargs == 3 || nargs == 4)) + s = nsvg__getNextPathItemWhenArcFlag(s, item); + if (!*item) + s = nsvg__getNextPathItem(s, item); + if (!*item) break; + if (cmd != '\0' && nsvg__isCoordinate(item)) { + if (nargs < 10) + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= rargs) { + switch (cmd) { + case 'm': + case 'M': + nsvg__pathMoveTo(p, &cpx, &cpy, args, cmd == 'm' ? 1 : 0); + // Moveto can be followed by multiple coordinate pairs, + // which should be treated as linetos. + cmd = (cmd == 'm') ? 'l' : 'L'; + rargs = nsvg__getArgsPerElement(cmd); + cpx2 = cpx; cpy2 = cpy; + initPoint = 1; + break; + case 'l': + case 'L': + nsvg__pathLineTo(p, &cpx, &cpy, args, cmd == 'l' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'H': + case 'h': + nsvg__pathHLineTo(p, &cpx, &cpy, args, cmd == 'h' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'V': + case 'v': + nsvg__pathVLineTo(p, &cpx, &cpy, args, cmd == 'v' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + case 'C': + case 'c': + nsvg__pathCubicBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'c' ? 1 : 0); + break; + case 'S': + case 's': + nsvg__pathCubicBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 's' ? 1 : 0); + break; + case 'Q': + case 'q': + nsvg__pathQuadBezTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 'q' ? 1 : 0); + break; + case 'T': + case 't': + nsvg__pathQuadBezShortTo(p, &cpx, &cpy, &cpx2, &cpy2, args, cmd == 't' ? 1 : 0); + break; + case 'A': + case 'a': + nsvg__pathArcTo(p, &cpx, &cpy, args, cmd == 'a' ? 1 : 0); + cpx2 = cpx; cpy2 = cpy; + break; + default: + if (nargs >= 2) { + cpx = args[nargs-2]; + cpy = args[nargs-1]; + cpx2 = cpx; cpy2 = cpy; + } + break; + } + nargs = 0; + } + } else { + cmd = item[0]; + if (cmd == 'M' || cmd == 'm') { + // Commit path. + if (p->npts > 0) + nsvg__addPath(p, closedFlag); + // Start new subpath. + nsvg__resetPath(p); + closedFlag = 0; + nargs = 0; + } else if (initPoint == 0) { + // Do not allow other commands until initial point has been set (moveTo called once). + cmd = '\0'; + } + if (cmd == 'Z' || cmd == 'z') { + closedFlag = 1; + // Commit path. + if (p->npts > 0) { + // Move current point to first point + cpx = p->pts[0]; + cpy = p->pts[1]; + cpx2 = cpx; cpy2 = cpy; + nsvg__addPath(p, closedFlag); + } + // Start new subpath. + nsvg__resetPath(p); + nsvg__moveTo(p, cpx, cpy); + closedFlag = 0; + nargs = 0; + } + rargs = nsvg__getArgsPerElement(cmd); + if (rargs == -1) { + // Command not recognized + cmd = '\0'; + rargs = 0; + } + } + } + // Commit path. + if (p->npts) + nsvg__addPath(p, closedFlag); + } + + nsvg__addShape(p); +} + +static void nsvg__parseRect(NSVGparser* p, const char** attr) +{ + float x = 0.0f; + float y = 0.0f; + float w = 0.0f; + float h = 0.0f; + float rx = -1.0f; // marks not set + float ry = -1.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x") == 0) x = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y") == 0) y = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "width") == 0) w = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p)); + if (strcmp(attr[i], "height") == 0) h = nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx < 0.0f && ry > 0.0f) rx = ry; + if (ry < 0.0f && rx > 0.0f) ry = rx; + if (rx < 0.0f) rx = 0.0f; + if (ry < 0.0f) ry = 0.0f; + if (rx > w/2.0f) rx = w/2.0f; + if (ry > h/2.0f) ry = h/2.0f; + + if (w != 0.0f && h != 0.0f) { + nsvg__resetPath(p); + + if (rx < 0.00001f || ry < 0.0001f) { + nsvg__moveTo(p, x, y); + nsvg__lineTo(p, x+w, y); + nsvg__lineTo(p, x+w, y+h); + nsvg__lineTo(p, x, y+h); + } else { + // Rounded rectangle + nsvg__moveTo(p, x+rx, y); + nsvg__lineTo(p, x+w-rx, y); + nsvg__cubicBezTo(p, x+w-rx*(1-NSVG_KAPPA90), y, x+w, y+ry*(1-NSVG_KAPPA90), x+w, y+ry); + nsvg__lineTo(p, x+w, y+h-ry); + nsvg__cubicBezTo(p, x+w, y+h-ry*(1-NSVG_KAPPA90), x+w-rx*(1-NSVG_KAPPA90), y+h, x+w-rx, y+h); + nsvg__lineTo(p, x+rx, y+h); + nsvg__cubicBezTo(p, x+rx*(1-NSVG_KAPPA90), y+h, x, y+h-ry*(1-NSVG_KAPPA90), x, y+h-ry); + nsvg__lineTo(p, x, y+ry); + nsvg__cubicBezTo(p, x, y+ry*(1-NSVG_KAPPA90), x+rx*(1-NSVG_KAPPA90), y, x+rx, y); + } + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseCircle(NSVGparser* p, const char** attr) +{ + float cx = 0.0f; + float cy = 0.0f; + float r = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "r") == 0) r = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualLength(p))); + } + } + + if (r > 0.0f) { + nsvg__resetPath(p); + + nsvg__moveTo(p, cx+r, cy); + nsvg__cubicBezTo(p, cx+r, cy+r*NSVG_KAPPA90, cx+r*NSVG_KAPPA90, cy+r, cx, cy+r); + nsvg__cubicBezTo(p, cx-r*NSVG_KAPPA90, cy+r, cx-r, cy+r*NSVG_KAPPA90, cx-r, cy); + nsvg__cubicBezTo(p, cx-r, cy-r*NSVG_KAPPA90, cx-r*NSVG_KAPPA90, cy-r, cx, cy-r); + nsvg__cubicBezTo(p, cx+r*NSVG_KAPPA90, cy-r, cx+r, cy-r*NSVG_KAPPA90, cx+r, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseEllipse(NSVGparser* p, const char** attr) +{ + float cx = 0.0f; + float cy = 0.0f; + float rx = 0.0f; + float ry = 0.0f; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "cx") == 0) cx = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "cy") == 0) cy = nsvg__parseCoordinate(p, attr[i+1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "rx") == 0) rx = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualWidth(p))); + if (strcmp(attr[i], "ry") == 0) ry = fabsf(nsvg__parseCoordinate(p, attr[i+1], 0.0f, nsvg__actualHeight(p))); + } + } + + if (rx > 0.0f && ry > 0.0f) { + + nsvg__resetPath(p); + + nsvg__moveTo(p, cx+rx, cy); + nsvg__cubicBezTo(p, cx+rx, cy+ry*NSVG_KAPPA90, cx+rx*NSVG_KAPPA90, cy+ry, cx, cy+ry); + nsvg__cubicBezTo(p, cx-rx*NSVG_KAPPA90, cy+ry, cx-rx, cy+ry*NSVG_KAPPA90, cx-rx, cy); + nsvg__cubicBezTo(p, cx-rx, cy-ry*NSVG_KAPPA90, cx-rx*NSVG_KAPPA90, cy-ry, cx, cy-ry); + nsvg__cubicBezTo(p, cx+rx*NSVG_KAPPA90, cy-ry, cx+rx, cy-ry*NSVG_KAPPA90, cx+rx, cy); + + nsvg__addPath(p, 1); + + nsvg__addShape(p); + } +} + +static void nsvg__parseLine(NSVGparser* p, const char** attr) +{ + float x1 = 0.0; + float y1 = 0.0; + float x2 = 0.0; + float y2 = 0.0; + int i; + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "x1") == 0) x1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y1") == 0) y1 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + if (strcmp(attr[i], "x2") == 0) x2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigX(p), nsvg__actualWidth(p)); + if (strcmp(attr[i], "y2") == 0) y2 = nsvg__parseCoordinate(p, attr[i + 1], nsvg__actualOrigY(p), nsvg__actualHeight(p)); + } + } + + nsvg__resetPath(p); + + nsvg__moveTo(p, x1, y1); + nsvg__lineTo(p, x2, y2); + + nsvg__addPath(p, 0); + + nsvg__addShape(p); +} + +static void nsvg__parsePoly(NSVGparser* p, const char** attr, int closeFlag) +{ + int i; + const char* s; + float args[2]; + int nargs, npts = 0; + char item[64]; + + nsvg__resetPath(p); + + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "points") == 0) { + s = attr[i + 1]; + nargs = 0; + while (*s) { + s = nsvg__getNextPathItem(s, item); + args[nargs++] = (float)nsvg__atof(item); + if (nargs >= 2) { + if (npts == 0) + nsvg__moveTo(p, args[0], args[1]); + else + nsvg__lineTo(p, args[0], args[1]); + nargs = 0; + npts++; + } + } + } + } + } + + nsvg__addPath(p, (char)closeFlag); + + nsvg__addShape(p); +} + +static void nsvg__parseSVG(NSVGparser* p, const char** attr) +{ + int i; + for (i = 0; attr[i]; i += 2) { + if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "width") == 0) { + p->image->width = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "height") == 0) { + p->image->height = nsvg__parseCoordinate(p, attr[i + 1], 0.0f, 0.0f); + } else if (strcmp(attr[i], "viewBox") == 0) { + const char *s = attr[i + 1]; + char buf[64]; + s = nsvg__parseNumber(s, buf, 64); + p->viewMinx = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; + if (!*s) return; + s = nsvg__parseNumber(s, buf, 64); + p->viewMiny = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; + if (!*s) return; + s = nsvg__parseNumber(s, buf, 64); + p->viewWidth = nsvg__atof(buf); + while (*s && (nsvg__isspace(*s) || *s == '%' || *s == ',')) s++; + if (!*s) return; + s = nsvg__parseNumber(s, buf, 64); + p->viewHeight = nsvg__atof(buf); + } else if (strcmp(attr[i], "preserveAspectRatio") == 0) { + if (strstr(attr[i + 1], "none") != 0) { + // No uniform scaling + p->alignType = NSVG_ALIGN_NONE; + } else { + // Parse X align + if (strstr(attr[i + 1], "xMin") != 0) + p->alignX = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "xMid") != 0) + p->alignX = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "xMax") != 0) + p->alignX = NSVG_ALIGN_MAX; + // Parse X align + if (strstr(attr[i + 1], "yMin") != 0) + p->alignY = NSVG_ALIGN_MIN; + else if (strstr(attr[i + 1], "yMid") != 0) + p->alignY = NSVG_ALIGN_MID; + else if (strstr(attr[i + 1], "yMax") != 0) + p->alignY = NSVG_ALIGN_MAX; + // Parse meet/slice + p->alignType = NSVG_ALIGN_MEET; + if (strstr(attr[i + 1], "slice") != 0) + p->alignType = NSVG_ALIGN_SLICE; + } + } + } + } +} + +static void nsvg__parseGradient(NSVGparser* p, const char** attr, signed char type) +{ + int i; + NSVGgradientData* grad = (NSVGgradientData*)malloc(sizeof(NSVGgradientData)); + if (grad == NULL) return; + memset(grad, 0, sizeof(NSVGgradientData)); + grad->units = NSVG_OBJECT_SPACE; + grad->type = type; + if (grad->type == NSVG_PAINT_LINEAR_GRADIENT) { + grad->linear.x1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.y1 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + grad->linear.x2 = nsvg__coord(100.0f, NSVG_UNITS_PERCENT); + grad->linear.y2 = nsvg__coord(0.0f, NSVG_UNITS_PERCENT); + } else if (grad->type == NSVG_PAINT_RADIAL_GRADIENT) { + grad->radial.cx = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.cy = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + grad->radial.r = nsvg__coord(50.0f, NSVG_UNITS_PERCENT); + } + + nsvg__xformIdentity(grad->xform); + + for (i = 0; attr[i]; i += 2) { + if (strcmp(attr[i], "id") == 0) { + strncpy(grad->id, attr[i+1], 63); + grad->id[63] = '\0'; + } else if (!nsvg__parseAttr(p, attr[i], attr[i + 1])) { + if (strcmp(attr[i], "gradientUnits") == 0) { + if (strcmp(attr[i+1], "objectBoundingBox") == 0) + grad->units = NSVG_OBJECT_SPACE; + else + grad->units = NSVG_USER_SPACE; + } else if (strcmp(attr[i], "gradientTransform") == 0) { + nsvg__parseTransform(grad->xform, attr[i + 1]); + } else if (strcmp(attr[i], "cx") == 0) { + grad->radial.cx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "cy") == 0) { + grad->radial.cy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "r") == 0) { + grad->radial.r = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fx") == 0) { + grad->radial.fx = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "fy") == 0) { + grad->radial.fy = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x1") == 0) { + grad->linear.x1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y1") == 0) { + grad->linear.y1 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "x2") == 0) { + grad->linear.x2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "y2") == 0) { + grad->linear.y2 = nsvg__parseCoordinateRaw(attr[i + 1]); + } else if (strcmp(attr[i], "spreadMethod") == 0) { + if (strcmp(attr[i+1], "pad") == 0) + grad->spread = NSVG_SPREAD_PAD; + else if (strcmp(attr[i+1], "reflect") == 0) + grad->spread = NSVG_SPREAD_REFLECT; + else if (strcmp(attr[i+1], "repeat") == 0) + grad->spread = NSVG_SPREAD_REPEAT; + } else if (strcmp(attr[i], "xlink:href") == 0) { + const char *href = attr[i+1]; + strncpy(grad->ref, href+1, 62); + grad->ref[62] = '\0'; + } + } + } + + grad->next = p->gradients; + p->gradients = grad; +} + +static void nsvg__parseGradientStop(NSVGparser* p, const char** attr) +{ + NSVGattrib* curAttr = nsvg__getAttr(p); + NSVGgradientData* grad; + NSVGgradientStop* stop; + int i, idx; + + curAttr->stopOffset = 0; + curAttr->stopColor = 0; + curAttr->stopOpacity = 1.0f; + + for (i = 0; attr[i]; i += 2) { + nsvg__parseAttr(p, attr[i], attr[i + 1]); + } + + // Add stop to the last gradient. + grad = p->gradients; + if (grad == NULL) return; + + grad->nstops++; + grad->stops = (NSVGgradientStop*)realloc(grad->stops, sizeof(NSVGgradientStop)*grad->nstops); + if (grad->stops == NULL) return; + + // Insert + idx = grad->nstops-1; + for (i = 0; i < grad->nstops-1; i++) { + if (curAttr->stopOffset < grad->stops[i].offset) { + idx = i; + break; + } + } + if (idx != grad->nstops-1) { + for (i = grad->nstops-1; i > idx; i--) + grad->stops[i] = grad->stops[i-1]; + } + + stop = &grad->stops[idx]; + stop->color = curAttr->stopColor; + stop->color |= (unsigned int)(curAttr->stopOpacity*255) << 24; + stop->offset = curAttr->stopOffset; +} + +static void nsvg__startElement(void* ud, const char* el, const char** attr) +{ + NSVGparser* p = (NSVGparser*)ud; + + if (p->defsFlag) { + // Skip everything but gradients in defs + if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } + return; + } + + if (strcmp(el, "g") == 0) { + nsvg__pushAttr(p); + nsvg__parseAttribs(p, attr); + } else if (strcmp(el, "path") == 0) { + if (p->pathFlag) // Do not allow nested paths. + return; + nsvg__pushAttr(p); + nsvg__parsePath(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "rect") == 0) { + nsvg__pushAttr(p); + nsvg__parseRect(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "circle") == 0) { + nsvg__pushAttr(p); + nsvg__parseCircle(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "ellipse") == 0) { + nsvg__pushAttr(p); + nsvg__parseEllipse(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "line") == 0) { + nsvg__pushAttr(p); + nsvg__parseLine(p, attr); + nsvg__popAttr(p); + } else if (strcmp(el, "polyline") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 0); + nsvg__popAttr(p); + } else if (strcmp(el, "polygon") == 0) { + nsvg__pushAttr(p); + nsvg__parsePoly(p, attr, 1); + nsvg__popAttr(p); + } else if (strcmp(el, "linearGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_LINEAR_GRADIENT); + } else if (strcmp(el, "radialGradient") == 0) { + nsvg__parseGradient(p, attr, NSVG_PAINT_RADIAL_GRADIENT); + } else if (strcmp(el, "stop") == 0) { + nsvg__parseGradientStop(p, attr); + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 1; + } else if (strcmp(el, "svg") == 0) { + nsvg__parseSVG(p, attr); + } +} + +static void nsvg__endElement(void* ud, const char* el) +{ + NSVGparser* p = (NSVGparser*)ud; + + if (strcmp(el, "g") == 0) { + nsvg__popAttr(p); + } else if (strcmp(el, "path") == 0) { + p->pathFlag = 0; + } else if (strcmp(el, "defs") == 0) { + p->defsFlag = 0; + } +} + +static void nsvg__content(void* ud, const char* s) +{ + NSVG_NOTUSED(ud); + NSVG_NOTUSED(s); + // empty +} + +static void nsvg__imageBounds(NSVGparser* p, float* bounds) +{ + NSVGshape* shape; + shape = p->image->shapes; + if (shape == NULL) { + bounds[0] = bounds[1] = bounds[2] = bounds[3] = 0.0; + return; + } + bounds[0] = shape->bounds[0]; + bounds[1] = shape->bounds[1]; + bounds[2] = shape->bounds[2]; + bounds[3] = shape->bounds[3]; + for (shape = shape->next; shape != NULL; shape = shape->next) { + bounds[0] = nsvg__minf(bounds[0], shape->bounds[0]); + bounds[1] = nsvg__minf(bounds[1], shape->bounds[1]); + bounds[2] = nsvg__maxf(bounds[2], shape->bounds[2]); + bounds[3] = nsvg__maxf(bounds[3], shape->bounds[3]); + } +} + +static float nsvg__viewAlign(float content, float container, int type) +{ + if (type == NSVG_ALIGN_MIN) + return 0; + else if (type == NSVG_ALIGN_MAX) + return container - content; + // mid + return (container - content) * 0.5f; +} + +static void nsvg__scaleGradient(NSVGgradient* grad, float tx, float ty, float sx, float sy) +{ + float t[6]; + nsvg__xformSetTranslation(t, tx, ty); + nsvg__xformMultiply (grad->xform, t); + + nsvg__xformSetScale(t, sx, sy); + nsvg__xformMultiply (grad->xform, t); +} + +static void nsvg__scaleToViewbox(NSVGparser* p, const char* units) +{ + NSVGshape* shape; + NSVGpath* path; + float tx, ty, sx, sy, us, bounds[4], t[6], avgs; + int i; + float* pt; + + // Guess image size if not set completely. + nsvg__imageBounds(p, bounds); + + if (p->viewWidth == 0) { + if (p->image->width > 0) { + p->viewWidth = p->image->width; + } else { + p->viewMinx = bounds[0]; + p->viewWidth = bounds[2] - bounds[0]; + } + } + if (p->viewHeight == 0) { + if (p->image->height > 0) { + p->viewHeight = p->image->height; + } else { + p->viewMiny = bounds[1]; + p->viewHeight = bounds[3] - bounds[1]; + } + } + if (p->image->width == 0) + p->image->width = p->viewWidth; + if (p->image->height == 0) + p->image->height = p->viewHeight; + + tx = -p->viewMinx; + ty = -p->viewMiny; + sx = p->viewWidth > 0 ? p->image->width / p->viewWidth : 0; + sy = p->viewHeight > 0 ? p->image->height / p->viewHeight : 0; + // Unit scaling + us = 1.0f / nsvg__convertToPixels(p, nsvg__coord(1.0f, nsvg__parseUnits(units)), 0.0f, 1.0f); + + // Fix aspect ratio + if (p->alignType == NSVG_ALIGN_MEET) { + // fit whole image into viewbox + sx = sy = nsvg__minf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; + } else if (p->alignType == NSVG_ALIGN_SLICE) { + // fill whole viewbox with image + sx = sy = nsvg__maxf(sx, sy); + tx += nsvg__viewAlign(p->viewWidth*sx, p->image->width, p->alignX) / sx; + ty += nsvg__viewAlign(p->viewHeight*sy, p->image->height, p->alignY) / sy; + } + + // Transform + sx *= us; + sy *= us; + avgs = (sx+sy) / 2.0f; + for (shape = p->image->shapes; shape != NULL; shape = shape->next) { + shape->bounds[0] = (shape->bounds[0] + tx) * sx; + shape->bounds[1] = (shape->bounds[1] + ty) * sy; + shape->bounds[2] = (shape->bounds[2] + tx) * sx; + shape->bounds[3] = (shape->bounds[3] + ty) * sy; + for (path = shape->paths; path != NULL; path = path->next) { + path->bounds[0] = (path->bounds[0] + tx) * sx; + path->bounds[1] = (path->bounds[1] + ty) * sy; + path->bounds[2] = (path->bounds[2] + tx) * sx; + path->bounds[3] = (path->bounds[3] + ty) * sy; + for (i =0; i < path->npts; i++) { + pt = &path->pts[i*2]; + pt[0] = (pt[0] + tx) * sx; + pt[1] = (pt[1] + ty) * sy; + } + } + + if (shape->fill.type == NSVG_PAINT_LINEAR_GRADIENT || shape->fill.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->fill.gradient, tx,ty, sx,sy); + memcpy(t, shape->fill.gradient->xform, sizeof(float)*6); + nsvg__xformInverse(shape->fill.gradient->xform, t); + } + if (shape->stroke.type == NSVG_PAINT_LINEAR_GRADIENT || shape->stroke.type == NSVG_PAINT_RADIAL_GRADIENT) { + nsvg__scaleGradient(shape->stroke.gradient, tx,ty, sx,sy); + memcpy(t, shape->stroke.gradient->xform, sizeof(float)*6); + nsvg__xformInverse(shape->stroke.gradient->xform, t); + } + + shape->strokeWidth *= avgs; + shape->strokeDashOffset *= avgs; + for (i = 0; i < shape->strokeDashCount; i++) + shape->strokeDashArray[i] *= avgs; + } +} + +static void nsvg__createGradients(NSVGparser* p) +{ + NSVGshape* shape; + + for (shape = p->image->shapes; shape != NULL; shape = shape->next) { + if (shape->fill.type == NSVG_PAINT_UNDEF) { + if (shape->fillGradient[0] != '\0') { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, shape->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->fill.gradient = nsvg__createGradient(p, shape->fillGradient, localBounds, shape->xform, &shape->fill.type); + } + if (shape->fill.type == NSVG_PAINT_UNDEF) { + shape->fill.type = NSVG_PAINT_NONE; + } + } + if (shape->stroke.type == NSVG_PAINT_UNDEF) { + if (shape->strokeGradient[0] != '\0') { + float inv[6], localBounds[4]; + nsvg__xformInverse(inv, shape->xform); + nsvg__getLocalBounds(localBounds, shape, inv); + shape->stroke.gradient = nsvg__createGradient(p, shape->strokeGradient, localBounds, shape->xform, &shape->stroke.type); + } + if (shape->stroke.type == NSVG_PAINT_UNDEF) { + shape->stroke.type = NSVG_PAINT_NONE; + } + } + } +} + +NSVGimage* nsvgParse(char* input, const char* units, float dpi) +{ + NSVGparser* p; + NSVGimage* ret = 0; + + p = nsvg__createParser(); + if (p == NULL) { + return NULL; + } + p->dpi = dpi; + + nsvg__parseXML(input, nsvg__startElement, nsvg__endElement, nsvg__content, p); + + // Create gradients after all definitions have been parsed + nsvg__createGradients(p); + + // Scale to viewBox + nsvg__scaleToViewbox(p, units); + + ret = p->image; + p->image = NULL; + + nsvg__deleteParser(p); + + return ret; +} + +NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) +{ + FILE* fp = NULL; + size_t size; + char* data = NULL; + NSVGimage* image = NULL; + + fp = fopen(filename, "rb"); + if (!fp) goto error; + fseek(fp, 0, SEEK_END); + size = ftell(fp); + fseek(fp, 0, SEEK_SET); + data = (char*)malloc(size+1); + if (data == NULL) goto error; + if (fread(data, 1, size, fp) != size) goto error; + data[size] = '\0'; // Must be null terminated. + fclose(fp); + image = nsvgParse(data, units, dpi); + free(data); + + return image; + +error: + if (fp) fclose(fp); + if (data) free(data); + if (image) nsvgDelete(image); + return NULL; +} + +NSVGpath* nsvgDuplicatePath(NSVGpath* p) +{ + NSVGpath* res = NULL; + + if (p == NULL) + return NULL; + + res = (NSVGpath*)malloc(sizeof(NSVGpath)); + if (res == NULL) goto error; + memset(res, 0, sizeof(NSVGpath)); + + res->pts = (float*)malloc(p->npts*2*sizeof(float)); + if (res->pts == NULL) goto error; + memcpy(res->pts, p->pts, p->npts * sizeof(float) * 2); + res->npts = p->npts; + + memcpy(res->bounds, p->bounds, sizeof(p->bounds)); + + res->closed = p->closed; + + return res; + +error: + if (res != NULL) { + free(res->pts); + free(res); + } + return NULL; +} + +void nsvgDelete(NSVGimage* image) +{ + NSVGshape *snext, *shape; + if (image == NULL) return; + shape = image->shapes; + while (shape != NULL) { + snext = shape->next; + nsvg__deletePaths(shape->paths); + nsvg__deletePaint(&shape->fill); + nsvg__deletePaint(&shape->stroke); + free(shape); + shape = snext; + } + free(image); +} + +#endif // NANOSVG_IMPLEMENTATION + +#endif // NANOSVG_H diff --git a/src/common/dep/nanosvg/nanosvgrast.h b/src/common/dep/nanosvg/nanosvgrast.h new file mode 100644 index 000000000..4cf109ad9 --- /dev/null +++ b/src/common/dep/nanosvg/nanosvgrast.h @@ -0,0 +1,1472 @@ +/* + * Copyright (c) 2013-14 Mikko Mononen memon@inside.org + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + * The polygon rasterization is heavily based on stb_truetype rasterizer + * by Sean Barrett - http://nothings.org/ + * + */ + +#ifndef NANOSVGRAST_H +#define NANOSVGRAST_H + +#include "nanosvg.h" + +#ifndef NANOSVGRAST_CPLUSPLUS +#ifdef __cplusplus +extern "C" { +#endif +#endif + +typedef struct NSVGrasterizer NSVGrasterizer; + +/* Example Usage: + // Load SVG + NSVGimage* image; + image = nsvgParseFromFile("test.svg", "px", 96); + + // Create rasterizer (can be used to render multiple images). + struct NSVGrasterizer* rast = nsvgCreateRasterizer(); + // Allocate memory for image + unsigned char* img = malloc(w*h*4); + // Rasterize + nsvgRasterize(rast, image, 0,0,1, img, w, h, w*4); +*/ + +// Allocated rasterizer context. +NSVGrasterizer* nsvgCreateRasterizer(void); + +// Rasterizes SVG image, returns RGBA image (non-premultiplied alpha) +// r - pointer to rasterizer context +// image - pointer to image to rasterize +// tx,ty - image offset (applied after scaling) +// scale - image scale +// dst - pointer to destination image data, 4 bytes per pixel (RGBA) +// w - width of the image to render +// h - height of the image to render +// stride - number of bytes per scaleline in the destination buffer +void nsvgRasterize(NSVGrasterizer* r, + NSVGimage* image, float tx, float ty, float scale, + unsigned char* dst, int w, int h, int stride); + +// Deletes rasterizer context. +void nsvgDeleteRasterizer(NSVGrasterizer*); + + +#ifndef NANOSVGRAST_CPLUSPLUS +#ifdef __cplusplus +} +#endif +#endif + +#ifdef NANOSVGRAST_IMPLEMENTATION + +#include +#include +#include + +#define NSVG__SUBSAMPLES 5 +#define NSVG__FIXSHIFT 10 +#define NSVG__FIX (1 << NSVG__FIXSHIFT) +#define NSVG__FIXMASK (NSVG__FIX-1) +#define NSVG__MEMPAGE_SIZE 1024 + +typedef struct NSVGedge { + float x0,y0, x1,y1; + int dir; + struct NSVGedge* next; +} NSVGedge; + +typedef struct NSVGpoint { + float x, y; + float dx, dy; + float len; + float dmx, dmy; + unsigned char flags; +} NSVGpoint; + +typedef struct NSVGactiveEdge { + int x,dx; + float ey; + int dir; + struct NSVGactiveEdge *next; +} NSVGactiveEdge; + +typedef struct NSVGmemPage { + unsigned char mem[NSVG__MEMPAGE_SIZE]; + int size; + struct NSVGmemPage* next; +} NSVGmemPage; + +typedef struct NSVGcachedPaint { + signed char type; + char spread; + float xform[6]; + unsigned int colors[256]; +} NSVGcachedPaint; + +struct NSVGrasterizer +{ + float px, py; + + float tessTol; + float distTol; + + NSVGedge* edges; + int nedges; + int cedges; + + NSVGpoint* points; + int npoints; + int cpoints; + + NSVGpoint* points2; + int npoints2; + int cpoints2; + + NSVGactiveEdge* freelist; + NSVGmemPage* pages; + NSVGmemPage* curpage; + + unsigned char* scanline; + int cscanline; + + unsigned char* bitmap; + int width, height, stride; +}; + +NSVGrasterizer* nsvgCreateRasterizer(void) +{ + NSVGrasterizer* r = (NSVGrasterizer*)malloc(sizeof(NSVGrasterizer)); + if (r == NULL) goto error; + memset(r, 0, sizeof(NSVGrasterizer)); + + r->tessTol = 0.25f; + r->distTol = 0.01f; + + return r; + +error: + nsvgDeleteRasterizer(r); + return NULL; +} + +void nsvgDeleteRasterizer(NSVGrasterizer* r) +{ + NSVGmemPage* p; + + if (r == NULL) return; + + p = r->pages; + while (p != NULL) { + NSVGmemPage* next = p->next; + free(p); + p = next; + } + + if (r->edges) free(r->edges); + if (r->points) free(r->points); + if (r->points2) free(r->points2); + if (r->scanline) free(r->scanline); + + free(r); +} + +static NSVGmemPage* nsvg__nextPage(NSVGrasterizer* r, NSVGmemPage* cur) +{ + NSVGmemPage *newp; + + // If using existing chain, return the next page in chain + if (cur != NULL && cur->next != NULL) { + return cur->next; + } + + // Alloc new page + newp = (NSVGmemPage*)malloc(sizeof(NSVGmemPage)); + if (newp == NULL) return NULL; + memset(newp, 0, sizeof(NSVGmemPage)); + + // Add to linked list + if (cur != NULL) + cur->next = newp; + else + r->pages = newp; + + return newp; +} + +static void nsvg__resetPool(NSVGrasterizer* r) +{ + NSVGmemPage* p = r->pages; + while (p != NULL) { + p->size = 0; + p = p->next; + } + r->curpage = r->pages; +} + +static unsigned char* nsvg__alloc(NSVGrasterizer* r, int size) +{ + unsigned char* buf; + if (size > NSVG__MEMPAGE_SIZE) return NULL; + if (r->curpage == NULL || r->curpage->size+size > NSVG__MEMPAGE_SIZE) { + r->curpage = nsvg__nextPage(r, r->curpage); + } + buf = &r->curpage->mem[r->curpage->size]; + r->curpage->size += size; + return buf; +} + +static int nsvg__ptEquals(float x1, float y1, float x2, float y2, float tol) +{ + float dx = x2 - x1; + float dy = y2 - y1; + return dx*dx + dy*dy < tol*tol; +} + +static void nsvg__addPathPoint(NSVGrasterizer* r, float x, float y, int flags) +{ + NSVGpoint* pt; + + if (r->npoints > 0) { + pt = &r->points[r->npoints-1]; + if (nsvg__ptEquals(pt->x,pt->y, x,y, r->distTol)) { + pt->flags = (unsigned char)(pt->flags | flags); + return; + } + } + + if (r->npoints+1 > r->cpoints) { + r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; + r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); + if (r->points == NULL) return; + } + + pt = &r->points[r->npoints]; + pt->x = x; + pt->y = y; + pt->flags = (unsigned char)flags; + r->npoints++; +} + +static void nsvg__appendPathPoint(NSVGrasterizer* r, NSVGpoint pt) +{ + if (r->npoints+1 > r->cpoints) { + r->cpoints = r->cpoints > 0 ? r->cpoints * 2 : 64; + r->points = (NSVGpoint*)realloc(r->points, sizeof(NSVGpoint) * r->cpoints); + if (r->points == NULL) return; + } + r->points[r->npoints] = pt; + r->npoints++; +} + +static void nsvg__duplicatePoints(NSVGrasterizer* r) +{ + if (r->npoints > r->cpoints2) { + r->cpoints2 = r->npoints; + r->points2 = (NSVGpoint*)realloc(r->points2, sizeof(NSVGpoint) * r->cpoints2); + if (r->points2 == NULL) return; + } + + memcpy(r->points2, r->points, sizeof(NSVGpoint) * r->npoints); + r->npoints2 = r->npoints; +} + +static void nsvg__addEdge(NSVGrasterizer* r, float x0, float y0, float x1, float y1) +{ + NSVGedge* e; + + // Skip horizontal edges + if (y0 == y1) + return; + + if (r->nedges+1 > r->cedges) { + r->cedges = r->cedges > 0 ? r->cedges * 2 : 64; + r->edges = (NSVGedge*)realloc(r->edges, sizeof(NSVGedge) * r->cedges); + if (r->edges == NULL) return; + } + + e = &r->edges[r->nedges]; + r->nedges++; + + if (y0 < y1) { + e->x0 = x0; + e->y0 = y0; + e->x1 = x1; + e->y1 = y1; + e->dir = 1; + } else { + e->x0 = x1; + e->y0 = y1; + e->x1 = x0; + e->y1 = y0; + e->dir = -1; + } +} + +static float nsvg__normalize(float *x, float* y) +{ + float d = sqrtf((*x)*(*x) + (*y)*(*y)); + if (d > 1e-6f) { + float id = 1.0f / d; + *x *= id; + *y *= id; + } + return d; +} + +static float nsvg__absf(float x) { return x < 0 ? -x : x; } +static float nsvg__roundf(float x) { return (x >= 0) ? floorf(x + 0.5) : ceilf(x - 0.5); } + +static void nsvg__flattenCubicBez(NSVGrasterizer* r, + float x1, float y1, float x2, float y2, + float x3, float y3, float x4, float y4, + int level, int type) +{ + float x12,y12,x23,y23,x34,y34,x123,y123,x234,y234,x1234,y1234; + float dx,dy,d2,d3; + + if (level > 10) return; + + x12 = (x1+x2)*0.5f; + y12 = (y1+y2)*0.5f; + x23 = (x2+x3)*0.5f; + y23 = (y2+y3)*0.5f; + x34 = (x3+x4)*0.5f; + y34 = (y3+y4)*0.5f; + x123 = (x12+x23)*0.5f; + y123 = (y12+y23)*0.5f; + + dx = x4 - x1; + dy = y4 - y1; + d2 = nsvg__absf((x2 - x4) * dy - (y2 - y4) * dx); + d3 = nsvg__absf((x3 - x4) * dy - (y3 - y4) * dx); + + if ((d2 + d3)*(d2 + d3) < r->tessTol * (dx*dx + dy*dy)) { + nsvg__addPathPoint(r, x4, y4, type); + return; + } + + x234 = (x23+x34)*0.5f; + y234 = (y23+y34)*0.5f; + x1234 = (x123+x234)*0.5f; + y1234 = (y123+y234)*0.5f; + + nsvg__flattenCubicBez(r, x1,y1, x12,y12, x123,y123, x1234,y1234, level+1, 0); + nsvg__flattenCubicBez(r, x1234,y1234, x234,y234, x34,y34, x4,y4, level+1, type); +} + +static void nsvg__flattenShape(NSVGrasterizer* r, NSVGshape* shape, float scale) +{ + int i, j; + NSVGpath* path; + + for (path = shape->paths; path != NULL; path = path->next) { + r->npoints = 0; + // Flatten path + nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); + for (i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0); + } + // Close path + nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, 0); + // Build edges + for (i = 0, j = r->npoints-1; i < r->npoints; j = i++) + nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y); + } +} + +enum NSVGpointFlags +{ + NSVG_PT_CORNER = 0x01, + NSVG_PT_BEVEL = 0x02, + NSVG_PT_LEFT = 0x04 +}; + +static void nsvg__initClosed(NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) +{ + float w = lineWidth * 0.5f; + float dx = p1->x - p0->x; + float dy = p1->y - p0->y; + float len = nsvg__normalize(&dx, &dy); + float px = p0->x + dx*len*0.5f, py = p0->y + dy*len*0.5f; + float dlx = dy, dly = -dx; + float lx = px - dlx*w, ly = py - dly*w; + float rx = px + dlx*w, ry = py + dly*w; + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static void nsvg__buttCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) +{ + float w = lineWidth * 0.5f; + float px = p->x, py = p->y; + float dlx = dy, dly = -dx; + float lx = px - dlx*w, ly = py - dly*w; + float rx = px + dlx*w, ry = py + dly*w; + + nsvg__addEdge(r, lx, ly, rx, ry); + + if (connect) { + nsvg__addEdge(r, left->x, left->y, lx, ly); + nsvg__addEdge(r, rx, ry, right->x, right->y); + } + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static void nsvg__squareCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int connect) +{ + float w = lineWidth * 0.5f; + float px = p->x - dx*w, py = p->y - dy*w; + float dlx = dy, dly = -dx; + float lx = px - dlx*w, ly = py - dly*w; + float rx = px + dlx*w, ry = py + dly*w; + + nsvg__addEdge(r, lx, ly, rx, ry); + + if (connect) { + nsvg__addEdge(r, left->x, left->y, lx, ly); + nsvg__addEdge(r, rx, ry, right->x, right->y); + } + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +#ifndef NSVG_PI +#define NSVG_PI (3.14159265358979323846264338327f) +#endif + +static void nsvg__roundCap(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p, float dx, float dy, float lineWidth, int ncap, int connect) +{ + int i; + float w = lineWidth * 0.5f; + float px = p->x, py = p->y; + float dlx = dy, dly = -dx; + float lx = 0, ly = 0, rx = 0, ry = 0, prevx = 0, prevy = 0; + + for (i = 0; i < ncap; i++) { + float a = (float)i/(float)(ncap-1)*NSVG_PI; + float ax = cosf(a) * w, ay = sinf(a) * w; + float x = px - dlx*ax - dx*ay; + float y = py - dly*ax - dy*ay; + + if (i > 0) + nsvg__addEdge(r, prevx, prevy, x, y); + + prevx = x; + prevy = y; + + if (i == 0) { + lx = x; ly = y; + } else if (i == ncap-1) { + rx = x; ry = y; + } + } + + if (connect) { + nsvg__addEdge(r, left->x, left->y, lx, ly); + nsvg__addEdge(r, rx, ry, right->x, right->y); + } + + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static void nsvg__bevelJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) +{ + float w = lineWidth * 0.5f; + float dlx0 = p0->dy, dly0 = -p0->dx; + float dlx1 = p1->dy, dly1 = -p1->dx; + float lx0 = p1->x - (dlx0 * w), ly0 = p1->y - (dly0 * w); + float rx0 = p1->x + (dlx0 * w), ry0 = p1->y + (dly0 * w); + float lx1 = p1->x - (dlx1 * w), ly1 = p1->y - (dly1 * w); + float rx1 = p1->x + (dlx1 * w), ry1 = p1->y + (dly1 * w); + + nsvg__addEdge(r, lx0, ly0, left->x, left->y); + nsvg__addEdge(r, lx1, ly1, lx0, ly0); + + nsvg__addEdge(r, right->x, right->y, rx0, ry0); + nsvg__addEdge(r, rx0, ry0, rx1, ry1); + + left->x = lx1; left->y = ly1; + right->x = rx1; right->y = ry1; +} + +static void nsvg__miterJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth) +{ + float w = lineWidth * 0.5f; + float dlx0 = p0->dy, dly0 = -p0->dx; + float dlx1 = p1->dy, dly1 = -p1->dx; + float lx0, rx0, lx1, rx1; + float ly0, ry0, ly1, ry1; + + if (p1->flags & NSVG_PT_LEFT) { + lx0 = lx1 = p1->x - p1->dmx * w; + ly0 = ly1 = p1->y - p1->dmy * w; + nsvg__addEdge(r, lx1, ly1, left->x, left->y); + + rx0 = p1->x + (dlx0 * w); + ry0 = p1->y + (dly0 * w); + rx1 = p1->x + (dlx1 * w); + ry1 = p1->y + (dly1 * w); + nsvg__addEdge(r, right->x, right->y, rx0, ry0); + nsvg__addEdge(r, rx0, ry0, rx1, ry1); + } else { + lx0 = p1->x - (dlx0 * w); + ly0 = p1->y - (dly0 * w); + lx1 = p1->x - (dlx1 * w); + ly1 = p1->y - (dly1 * w); + nsvg__addEdge(r, lx0, ly0, left->x, left->y); + nsvg__addEdge(r, lx1, ly1, lx0, ly0); + + rx0 = rx1 = p1->x + p1->dmx * w; + ry0 = ry1 = p1->y + p1->dmy * w; + nsvg__addEdge(r, right->x, right->y, rx1, ry1); + } + + left->x = lx1; left->y = ly1; + right->x = rx1; right->y = ry1; +} + +static void nsvg__roundJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p0, NSVGpoint* p1, float lineWidth, int ncap) +{ + int i, n; + float w = lineWidth * 0.5f; + float dlx0 = p0->dy, dly0 = -p0->dx; + float dlx1 = p1->dy, dly1 = -p1->dx; + float a0 = atan2f(dly0, dlx0); + float a1 = atan2f(dly1, dlx1); + float da = a1 - a0; + float lx, ly, rx, ry; + + if (da < NSVG_PI) da += NSVG_PI*2; + if (da > NSVG_PI) da -= NSVG_PI*2; + + n = (int)ceilf((nsvg__absf(da) / NSVG_PI) * (float)ncap); + if (n < 2) n = 2; + if (n > ncap) n = ncap; + + lx = left->x; + ly = left->y; + rx = right->x; + ry = right->y; + + for (i = 0; i < n; i++) { + float u = (float)i/(float)(n-1); + float a = a0 + u*da; + float ax = cosf(a) * w, ay = sinf(a) * w; + float lx1 = p1->x - ax, ly1 = p1->y - ay; + float rx1 = p1->x + ax, ry1 = p1->y + ay; + + nsvg__addEdge(r, lx1, ly1, lx, ly); + nsvg__addEdge(r, rx, ry, rx1, ry1); + + lx = lx1; ly = ly1; + rx = rx1; ry = ry1; + } + + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static void nsvg__straightJoin(NSVGrasterizer* r, NSVGpoint* left, NSVGpoint* right, NSVGpoint* p1, float lineWidth) +{ + float w = lineWidth * 0.5f; + float lx = p1->x - (p1->dmx * w), ly = p1->y - (p1->dmy * w); + float rx = p1->x + (p1->dmx * w), ry = p1->y + (p1->dmy * w); + + nsvg__addEdge(r, lx, ly, left->x, left->y); + nsvg__addEdge(r, right->x, right->y, rx, ry); + + left->x = lx; left->y = ly; + right->x = rx; right->y = ry; +} + +static int nsvg__curveDivs(float r, float arc, float tol) +{ + float da = acosf(r / (r + tol)) * 2.0f; + int divs = (int)ceilf(arc / da); + if (divs < 2) divs = 2; + return divs; +} + +static void nsvg__expandStroke(NSVGrasterizer* r, NSVGpoint* points, int npoints, int closed, int lineJoin, int lineCap, float lineWidth) +{ + int ncap = nsvg__curveDivs(lineWidth*0.5f, NSVG_PI, r->tessTol); // Calculate divisions per half circle. + NSVGpoint left = {0,0,0,0,0,0,0,0}, right = {0,0,0,0,0,0,0,0}, firstLeft = {0,0,0,0,0,0,0,0}, firstRight = {0,0,0,0,0,0,0,0}; + NSVGpoint* p0, *p1; + int j, s, e; + + // Build stroke edges + if (closed) { + // Looping + p0 = &points[npoints-1]; + p1 = &points[0]; + s = 0; + e = npoints; + } else { + // Add cap + p0 = &points[0]; + p1 = &points[1]; + s = 1; + e = npoints-1; + } + + if (closed) { + nsvg__initClosed(&left, &right, p0, p1, lineWidth); + firstLeft = left; + firstRight = right; + } else { + // Add cap + float dx = p1->x - p0->x; + float dy = p1->y - p0->y; + nsvg__normalize(&dx, &dy); + if (lineCap == NSVG_CAP_BUTT) + nsvg__buttCap(r, &left, &right, p0, dx, dy, lineWidth, 0); + else if (lineCap == NSVG_CAP_SQUARE) + nsvg__squareCap(r, &left, &right, p0, dx, dy, lineWidth, 0); + else if (lineCap == NSVG_CAP_ROUND) + nsvg__roundCap(r, &left, &right, p0, dx, dy, lineWidth, ncap, 0); + } + + for (j = s; j < e; ++j) { + if (p1->flags & NSVG_PT_CORNER) { + if (lineJoin == NSVG_JOIN_ROUND) + nsvg__roundJoin(r, &left, &right, p0, p1, lineWidth, ncap); + else if (lineJoin == NSVG_JOIN_BEVEL || (p1->flags & NSVG_PT_BEVEL)) + nsvg__bevelJoin(r, &left, &right, p0, p1, lineWidth); + else + nsvg__miterJoin(r, &left, &right, p0, p1, lineWidth); + } else { + nsvg__straightJoin(r, &left, &right, p1, lineWidth); + } + p0 = p1++; + } + + if (closed) { + // Loop it + nsvg__addEdge(r, firstLeft.x, firstLeft.y, left.x, left.y); + nsvg__addEdge(r, right.x, right.y, firstRight.x, firstRight.y); + } else { + // Add cap + float dx = p1->x - p0->x; + float dy = p1->y - p0->y; + nsvg__normalize(&dx, &dy); + if (lineCap == NSVG_CAP_BUTT) + nsvg__buttCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1); + else if (lineCap == NSVG_CAP_SQUARE) + nsvg__squareCap(r, &right, &left, p1, -dx, -dy, lineWidth, 1); + else if (lineCap == NSVG_CAP_ROUND) + nsvg__roundCap(r, &right, &left, p1, -dx, -dy, lineWidth, ncap, 1); + } +} + +static void nsvg__prepareStroke(NSVGrasterizer* r, float miterLimit, int lineJoin) +{ + int i, j; + NSVGpoint* p0, *p1; + + p0 = &r->points[r->npoints-1]; + p1 = &r->points[0]; + for (i = 0; i < r->npoints; i++) { + // Calculate segment direction and length + p0->dx = p1->x - p0->x; + p0->dy = p1->y - p0->y; + p0->len = nsvg__normalize(&p0->dx, &p0->dy); + // Advance + p0 = p1++; + } + + // calculate joins + p0 = &r->points[r->npoints-1]; + p1 = &r->points[0]; + for (j = 0; j < r->npoints; j++) { + float dlx0, dly0, dlx1, dly1, dmr2, cross; + dlx0 = p0->dy; + dly0 = -p0->dx; + dlx1 = p1->dy; + dly1 = -p1->dx; + // Calculate extrusions + p1->dmx = (dlx0 + dlx1) * 0.5f; + p1->dmy = (dly0 + dly1) * 0.5f; + dmr2 = p1->dmx*p1->dmx + p1->dmy*p1->dmy; + if (dmr2 > 0.000001f) { + float s2 = 1.0f / dmr2; + if (s2 > 600.0f) { + s2 = 600.0f; + } + p1->dmx *= s2; + p1->dmy *= s2; + } + + // Clear flags, but keep the corner. + p1->flags = (p1->flags & NSVG_PT_CORNER) ? NSVG_PT_CORNER : 0; + + // Keep track of left turns. + cross = p1->dx * p0->dy - p0->dx * p1->dy; + if (cross > 0.0f) + p1->flags |= NSVG_PT_LEFT; + + // Check to see if the corner needs to be beveled. + if (p1->flags & NSVG_PT_CORNER) { + if ((dmr2 * miterLimit*miterLimit) < 1.0f || lineJoin == NSVG_JOIN_BEVEL || lineJoin == NSVG_JOIN_ROUND) { + p1->flags |= NSVG_PT_BEVEL; + } + } + + p0 = p1++; + } +} + +static void nsvg__flattenShapeStroke(NSVGrasterizer* r, NSVGshape* shape, float scale) +{ + int i, j, closed; + NSVGpath* path; + NSVGpoint* p0, *p1; + float miterLimit = shape->miterLimit; + int lineJoin = shape->strokeLineJoin; + int lineCap = shape->strokeLineCap; + float lineWidth = shape->strokeWidth * scale; + + for (path = shape->paths; path != NULL; path = path->next) { + // Flatten path + r->npoints = 0; + nsvg__addPathPoint(r, path->pts[0]*scale, path->pts[1]*scale, NSVG_PT_CORNER); + for (i = 0; i < path->npts-1; i += 3) { + float* p = &path->pts[i*2]; + nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, NSVG_PT_CORNER); + } + if (r->npoints < 2) + continue; + + closed = path->closed; + + // If the first and last points are the same, remove the last, mark as closed path. + p0 = &r->points[r->npoints-1]; + p1 = &r->points[0]; + if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) { + r->npoints--; + p0 = &r->points[r->npoints-1]; + closed = 1; + } + + if (shape->strokeDashCount > 0) { + int idash = 0, dashState = 1; + float totalDist = 0, dashLen, allDashLen, dashOffset; + NSVGpoint cur; + + if (closed) + nsvg__appendPathPoint(r, r->points[0]); + + // Duplicate points -> points2. + nsvg__duplicatePoints(r); + + r->npoints = 0; + cur = r->points2[0]; + nsvg__appendPathPoint(r, cur); + + // Figure out dash offset. + allDashLen = 0; + for (j = 0; j < shape->strokeDashCount; j++) + allDashLen += shape->strokeDashArray[j]; + if (shape->strokeDashCount & 1) + allDashLen *= 2.0f; + // Find location inside pattern + dashOffset = fmodf(shape->strokeDashOffset, allDashLen); + if (dashOffset < 0.0f) + dashOffset += allDashLen; + + while (dashOffset > shape->strokeDashArray[idash]) { + dashOffset -= shape->strokeDashArray[idash]; + idash = (idash + 1) % shape->strokeDashCount; + } + dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale; + + for (j = 1; j < r->npoints2; ) { + float dx = r->points2[j].x - cur.x; + float dy = r->points2[j].y - cur.y; + float dist = sqrtf(dx*dx + dy*dy); + + if ((totalDist + dist) > dashLen) { + // Calculate intermediate point + float d = (dashLen - totalDist) / dist; + float x = cur.x + dx * d; + float y = cur.y + dy * d; + nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER); + + // Stroke + if (r->npoints > 1 && dashState) { + nsvg__prepareStroke(r, miterLimit, lineJoin); + nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); + } + // Advance dash pattern + dashState = !dashState; + idash = (idash+1) % shape->strokeDashCount; + dashLen = shape->strokeDashArray[idash] * scale; + // Restart + cur.x = x; + cur.y = y; + cur.flags = NSVG_PT_CORNER; + totalDist = 0.0f; + r->npoints = 0; + nsvg__appendPathPoint(r, cur); + } else { + totalDist += dist; + cur = r->points2[j]; + nsvg__appendPathPoint(r, cur); + j++; + } + } + // Stroke any leftover path + if (r->npoints > 1 && dashState) + nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin, lineCap, lineWidth); + } else { + nsvg__prepareStroke(r, miterLimit, lineJoin); + nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin, lineCap, lineWidth); + } + } +} + +static int nsvg__cmpEdge(const void *p, const void *q) +{ + const NSVGedge* a = (const NSVGedge*)p; + const NSVGedge* b = (const NSVGedge*)q; + + if (a->y0 < b->y0) return -1; + if (a->y0 > b->y0) return 1; + return 0; +} + + +static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint) +{ + NSVGactiveEdge* z; + + if (r->freelist != NULL) { + // Restore from freelist. + z = r->freelist; + r->freelist = z->next; + } else { + // Alloc new edge. + z = (NSVGactiveEdge*)nsvg__alloc(r, sizeof(NSVGactiveEdge)); + if (z == NULL) return NULL; + } + + float dxdy = (e->x1 - e->x0) / (e->y1 - e->y0); +// STBTT_assert(e->y0 <= start_point); + // round dx down to avoid going too far + if (dxdy < 0) + z->dx = (int)(-nsvg__roundf(NSVG__FIX * -dxdy)); + else + z->dx = (int)nsvg__roundf(NSVG__FIX * dxdy); + z->x = (int)nsvg__roundf(NSVG__FIX * (e->x0 + dxdy * (startPoint - e->y0))); +// z->x -= off_x * FIX; + z->ey = e->y1; + z->next = 0; + z->dir = e->dir; + + return z; +} + +static void nsvg__freeActive(NSVGrasterizer* r, NSVGactiveEdge* z) +{ + z->next = r->freelist; + r->freelist = z; +} + +static void nsvg__fillScanline(unsigned char* scanline, int len, int x0, int x1, int maxWeight, int* xmin, int* xmax) +{ + int i = x0 >> NSVG__FIXSHIFT; + int j = x1 >> NSVG__FIXSHIFT; + if (i < *xmin) *xmin = i; + if (j > *xmax) *xmax = j; + if (i < len && j >= 0) { + if (i == j) { + // x0,x1 are the same pixel, so compute combined coverage + scanline[i] = (unsigned char)(scanline[i] + ((x1 - x0) * maxWeight >> NSVG__FIXSHIFT)); + } else { + if (i >= 0) // add antialiasing for x0 + scanline[i] = (unsigned char)(scanline[i] + (((NSVG__FIX - (x0 & NSVG__FIXMASK)) * maxWeight) >> NSVG__FIXSHIFT)); + else + i = -1; // clip + + if (j < len) // add antialiasing for x1 + scanline[j] = (unsigned char)(scanline[j] + (((x1 & NSVG__FIXMASK) * maxWeight) >> NSVG__FIXSHIFT)); + else + j = len; // clip + + for (++i; i < j; ++i) // fill pixels between x0 and x1 + scanline[i] = (unsigned char)(scanline[i] + maxWeight); + } + } +} + +// note: this routine clips fills that extend off the edges... ideally this +// wouldn't happen, but it could happen if the truetype glyph bounding boxes +// are wrong, or if the user supplies a too-small bitmap +static void nsvg__fillActiveEdges(unsigned char* scanline, int len, NSVGactiveEdge* e, int maxWeight, int* xmin, int* xmax, char fillRule) +{ + // non-zero winding fill + int x0 = 0, w = 0; + + if (fillRule == NSVG_FILLRULE_NONZERO) { + // Non-zero + while (e != NULL) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; w += e->dir; + } else { + int x1 = e->x; w += e->dir; + // if we went to zero, we need to draw + if (w == 0) + nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); + } + e = e->next; + } + } else if (fillRule == NSVG_FILLRULE_EVENODD) { + // Even-odd + while (e != NULL) { + if (w == 0) { + // if we're currently at zero, we need to record the edge start point + x0 = e->x; w = 1; + } else { + int x1 = e->x; w = 0; + nsvg__fillScanline(scanline, len, x0, x1, maxWeight, xmin, xmax); + } + e = e->next; + } + } +} + +static float nsvg__clampf(float a, float mn, float mx) { return a < mn ? mn : (a > mx ? mx : a); } + +static unsigned int nsvg__RGBA(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + return ((unsigned int)r) | ((unsigned int)g << 8) | ((unsigned int)b << 16) | ((unsigned int)a << 24); +} + +static unsigned int nsvg__lerpRGBA(unsigned int c0, unsigned int c1, float u) +{ + int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); + int r = (((c0) & 0xff)*(256-iu) + (((c1) & 0xff)*iu)) >> 8; + int g = (((c0>>8) & 0xff)*(256-iu) + (((c1>>8) & 0xff)*iu)) >> 8; + int b = (((c0>>16) & 0xff)*(256-iu) + (((c1>>16) & 0xff)*iu)) >> 8; + int a = (((c0>>24) & 0xff)*(256-iu) + (((c1>>24) & 0xff)*iu)) >> 8; + return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); +} + +static unsigned int nsvg__applyOpacity(unsigned int c, float u) +{ + int iu = (int)(nsvg__clampf(u, 0.0f, 1.0f) * 256.0f); + int r = (c) & 0xff; + int g = (c>>8) & 0xff; + int b = (c>>16) & 0xff; + int a = (((c>>24) & 0xff)*iu) >> 8; + return nsvg__RGBA((unsigned char)r, (unsigned char)g, (unsigned char)b, (unsigned char)a); +} + +static inline int nsvg__div255(int x) +{ + return ((x+1) * 257) >> 16; +} + +static void nsvg__scanlineSolid(unsigned char* dst, int count, unsigned char* cover, int x, int y, + float tx, float ty, float scale, NSVGcachedPaint* cache) +{ + + if (cache->type == NSVG_PAINT_COLOR) { + int i, cr, cg, cb, ca; + cr = cache->colors[0] & 0xff; + cg = (cache->colors[0] >> 8) & 0xff; + cb = (cache->colors[0] >> 16) & 0xff; + ca = (cache->colors[0] >> 24) & 0xff; + + for (i = 0; i < count; i++) { + int r,g,b; + int a = nsvg__div255((int)cover[0] * ca); + int ia = 255 - a; + // Premultiply + r = nsvg__div255(cr * a); + g = nsvg__div255(cg * a); + b = nsvg__div255(cb * a); + + // Blend over + r += nsvg__div255(ia * (int)dst[0]); + g += nsvg__div255(ia * (int)dst[1]); + b += nsvg__div255(ia * (int)dst[2]); + a += nsvg__div255(ia * (int)dst[3]); + + dst[0] = (unsigned char)r; + dst[1] = (unsigned char)g; + dst[2] = (unsigned char)b; + dst[3] = (unsigned char)a; + + cover++; + dst += 4; + } + } else if (cache->type == NSVG_PAINT_LINEAR_GRADIENT) { + // TODO: spread modes. + // TODO: plenty of opportunities to optimize. + float fx, fy, dx, gy; + float* t = cache->xform; + int i, cr, cg, cb, ca; + unsigned int c; + + fx = ((float)x - tx) / scale; + fy = ((float)y - ty) / scale; + dx = 1.0f / scale; + + for (i = 0; i < count; i++) { + int r,g,b,a,ia; + gy = fx*t[1] + fy*t[3] + t[5]; + c = cache->colors[(int)nsvg__clampf(gy*255.0f, 0, 255.0f)]; + cr = (c) & 0xff; + cg = (c >> 8) & 0xff; + cb = (c >> 16) & 0xff; + ca = (c >> 24) & 0xff; + + a = nsvg__div255((int)cover[0] * ca); + ia = 255 - a; + + // Premultiply + r = nsvg__div255(cr * a); + g = nsvg__div255(cg * a); + b = nsvg__div255(cb * a); + + // Blend over + r += nsvg__div255(ia * (int)dst[0]); + g += nsvg__div255(ia * (int)dst[1]); + b += nsvg__div255(ia * (int)dst[2]); + a += nsvg__div255(ia * (int)dst[3]); + + dst[0] = (unsigned char)r; + dst[1] = (unsigned char)g; + dst[2] = (unsigned char)b; + dst[3] = (unsigned char)a; + + cover++; + dst += 4; + fx += dx; + } + } else if (cache->type == NSVG_PAINT_RADIAL_GRADIENT) { + // TODO: spread modes. + // TODO: plenty of opportunities to optimize. + // TODO: focus (fx,fy) + float fx, fy, dx, gx, gy, gd; + float* t = cache->xform; + int i, cr, cg, cb, ca; + unsigned int c; + + fx = ((float)x - tx) / scale; + fy = ((float)y - ty) / scale; + dx = 1.0f / scale; + + for (i = 0; i < count; i++) { + int r,g,b,a,ia; + gx = fx*t[0] + fy*t[2] + t[4]; + gy = fx*t[1] + fy*t[3] + t[5]; + gd = sqrtf(gx*gx + gy*gy); + c = cache->colors[(int)nsvg__clampf(gd*255.0f, 0, 255.0f)]; + cr = (c) & 0xff; + cg = (c >> 8) & 0xff; + cb = (c >> 16) & 0xff; + ca = (c >> 24) & 0xff; + + a = nsvg__div255((int)cover[0] * ca); + ia = 255 - a; + + // Premultiply + r = nsvg__div255(cr * a); + g = nsvg__div255(cg * a); + b = nsvg__div255(cb * a); + + // Blend over + r += nsvg__div255(ia * (int)dst[0]); + g += nsvg__div255(ia * (int)dst[1]); + b += nsvg__div255(ia * (int)dst[2]); + a += nsvg__div255(ia * (int)dst[3]); + + dst[0] = (unsigned char)r; + dst[1] = (unsigned char)g; + dst[2] = (unsigned char)b; + dst[3] = (unsigned char)a; + + cover++; + dst += 4; + fx += dx; + } + } +} + +static void nsvg__rasterizeSortedEdges(NSVGrasterizer *r, float tx, float ty, float scale, NSVGcachedPaint* cache, char fillRule) +{ + NSVGactiveEdge *active = NULL; + int y, s; + int e = 0; + int maxWeight = (255 / NSVG__SUBSAMPLES); // weight per vertical scanline + int xmin, xmax; + + for (y = 0; y < r->height; y++) { + memset(r->scanline, 0, r->width); + xmin = r->width; + xmax = 0; + for (s = 0; s < NSVG__SUBSAMPLES; ++s) { + // find center of pixel for this scanline + float scany = (float)(y*NSVG__SUBSAMPLES + s) + 0.5f; + NSVGactiveEdge **step = &active; + + // update all active edges; + // remove all active edges that terminate before the center of this scanline + while (*step) { + NSVGactiveEdge *z = *step; + if (z->ey <= scany) { + *step = z->next; // delete from list +// NSVG__assert(z->valid); + nsvg__freeActive(r, z); + } else { + z->x += z->dx; // advance to position for current scanline + step = &((*step)->next); // advance through list + } + } + + // resort the list if needed + for (;;) { + int changed = 0; + step = &active; + while (*step && (*step)->next) { + if ((*step)->x > (*step)->next->x) { + NSVGactiveEdge* t = *step; + NSVGactiveEdge* q = t->next; + t->next = q->next; + q->next = t; + *step = q; + changed = 1; + } + step = &(*step)->next; + } + if (!changed) break; + } + + // insert all edges that start before the center of this scanline -- omit ones that also end on this scanline + while (e < r->nedges && r->edges[e].y0 <= scany) { + if (r->edges[e].y1 > scany) { + NSVGactiveEdge* z = nsvg__addActive(r, &r->edges[e], scany); + if (z == NULL) break; + // find insertion point + if (active == NULL) { + active = z; + } else if (z->x < active->x) { + // insert at front + z->next = active; + active = z; + } else { + // find thing to insert AFTER + NSVGactiveEdge* p = active; + while (p->next && p->next->x < z->x) + p = p->next; + // at this point, p->next->x is NOT < z->x + z->next = p->next; + p->next = z; + } + } + e++; + } + + // now process all active edges in non-zero fashion + if (active != NULL) + nsvg__fillActiveEdges(r->scanline, r->width, active, maxWeight, &xmin, &xmax, fillRule); + } + // Blit + if (xmin < 0) xmin = 0; + if (xmax > r->width-1) xmax = r->width-1; + if (xmin <= xmax) { + nsvg__scanlineSolid(&r->bitmap[y * r->stride] + xmin*4, xmax-xmin+1, &r->scanline[xmin], xmin, y, tx,ty, scale, cache); + } + } + +} + +static void nsvg__unpremultiplyAlpha(unsigned char* image, int w, int h, int stride) +{ + int x,y; + + // Unpremultiply + for (y = 0; y < h; y++) { + unsigned char *row = &image[y*stride]; + for (x = 0; x < w; x++) { + int r = row[0], g = row[1], b = row[2], a = row[3]; + if (a != 0) { + row[0] = (unsigned char)(r*255/a); + row[1] = (unsigned char)(g*255/a); + row[2] = (unsigned char)(b*255/a); + } + row += 4; + } + } + + // Defringe + for (y = 0; y < h; y++) { + unsigned char *row = &image[y*stride]; + for (x = 0; x < w; x++) { + int r = 0, g = 0, b = 0, a = row[3], n = 0; + if (a == 0) { + if (x-1 > 0 && row[-1] != 0) { + r += row[-4]; + g += row[-3]; + b += row[-2]; + n++; + } + if (x+1 < w && row[7] != 0) { + r += row[4]; + g += row[5]; + b += row[6]; + n++; + } + if (y-1 > 0 && row[-stride+3] != 0) { + r += row[-stride]; + g += row[-stride+1]; + b += row[-stride+2]; + n++; + } + if (y+1 < h && row[stride+3] != 0) { + r += row[stride]; + g += row[stride+1]; + b += row[stride+2]; + n++; + } + if (n > 0) { + row[0] = (unsigned char)(r/n); + row[1] = (unsigned char)(g/n); + row[2] = (unsigned char)(b/n); + } + } + row += 4; + } + } +} + + +static void nsvg__initPaint(NSVGcachedPaint* cache, NSVGpaint* paint, float opacity) +{ + int i, j; + NSVGgradient* grad; + + cache->type = paint->type; + + if (paint->type == NSVG_PAINT_COLOR) { + cache->colors[0] = nsvg__applyOpacity(paint->color, opacity); + return; + } + + grad = paint->gradient; + + cache->spread = grad->spread; + memcpy(cache->xform, grad->xform, sizeof(float)*6); + + if (grad->nstops == 0) { + for (i = 0; i < 256; i++) + cache->colors[i] = 0; + } else if (grad->nstops == 1) { + unsigned int color = nsvg__applyOpacity(grad->stops[0].color, opacity); + for (i = 0; i < 256; i++) + cache->colors[i] = color; + } else { + unsigned int ca, cb = 0; + float ua, ub, du, u; + int ia, ib, count; + + ca = nsvg__applyOpacity(grad->stops[0].color, opacity); + ua = nsvg__clampf(grad->stops[0].offset, 0, 1); + ub = nsvg__clampf(grad->stops[grad->nstops-1].offset, ua, 1); + ia = (int)(ua * 255.0f); + ib = (int)(ub * 255.0f); + for (i = 0; i < ia; i++) { + cache->colors[i] = ca; + } + + for (i = 0; i < grad->nstops-1; i++) { + ca = nsvg__applyOpacity(grad->stops[i].color, opacity); + cb = nsvg__applyOpacity(grad->stops[i+1].color, opacity); + ua = nsvg__clampf(grad->stops[i].offset, 0, 1); + ub = nsvg__clampf(grad->stops[i+1].offset, 0, 1); + ia = (int)(ua * 255.0f); + ib = (int)(ub * 255.0f); + count = ib - ia; + if (count <= 0) continue; + u = 0; + du = 1.0f / (float)count; + for (j = 0; j < count; j++) { + cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u); + u += du; + } + } + + for (i = ib; i < 256; i++) + cache->colors[i] = cb; + } + +} + +/* +static void dumpEdges(NSVGrasterizer* r, const char* name) +{ + float xmin = 0, xmax = 0, ymin = 0, ymax = 0; + NSVGedge *e = NULL; + int i; + if (r->nedges == 0) return; + FILE* fp = fopen(name, "w"); + if (fp == NULL) return; + + xmin = xmax = r->edges[0].x0; + ymin = ymax = r->edges[0].y0; + for (i = 0; i < r->nedges; i++) { + e = &r->edges[i]; + xmin = nsvg__minf(xmin, e->x0); + xmin = nsvg__minf(xmin, e->x1); + xmax = nsvg__maxf(xmax, e->x0); + xmax = nsvg__maxf(xmax, e->x1); + ymin = nsvg__minf(ymin, e->y0); + ymin = nsvg__minf(ymin, e->y1); + ymax = nsvg__maxf(ymax, e->y0); + ymax = nsvg__maxf(ymax, e->y1); + } + + fprintf(fp, "", xmin, ymin, (xmax - xmin), (ymax - ymin)); + + for (i = 0; i < r->nedges; i++) { + e = &r->edges[i]; + fprintf(fp ,"", e->x0,e->y0, e->x1,e->y1); + } + + for (i = 0; i < r->npoints; i++) { + if (i+1 < r->npoints) + fprintf(fp ,"", r->points[i].x, r->points[i].y, r->points[i+1].x, r->points[i+1].y); + fprintf(fp ,"", r->points[i].x, r->points[i].y, r->points[i].flags == 0 ? "#f00" : "#0f0"); + } + + fprintf(fp, ""); + fclose(fp); +} +*/ + +void nsvgRasterize(NSVGrasterizer* r, + NSVGimage* image, float tx, float ty, float scale, + unsigned char* dst, int w, int h, int stride) +{ + NSVGshape *shape = NULL; + NSVGedge *e = NULL; + NSVGcachedPaint cache; + int i; + + r->bitmap = dst; + r->width = w; + r->height = h; + r->stride = stride; + + if (w > r->cscanline) { + r->cscanline = w; + r->scanline = (unsigned char*)realloc(r->scanline, w); + if (r->scanline == NULL) return; + } + + for (i = 0; i < h; i++) + memset(&dst[i*stride], 0, w*4); + + for (shape = image->shapes; shape != NULL; shape = shape->next) { + if (!(shape->flags & NSVG_FLAGS_VISIBLE)) + continue; + + if (shape->fill.type != NSVG_PAINT_NONE) { + nsvg__resetPool(r); + r->freelist = NULL; + r->nedges = 0; + + nsvg__flattenShape(r, shape, scale); + + // Scale and translate edges + for (i = 0; i < r->nedges; i++) { + e = &r->edges[i]; + e->x0 = tx + e->x0; + e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; + e->x1 = tx + e->x1; + e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES; + } + + // Rasterize edges + if (r->nedges != 0) + qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); + + // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule + nsvg__initPaint(&cache, &shape->fill, shape->opacity); + + nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule); + } + if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) { + nsvg__resetPool(r); + r->freelist = NULL; + r->nedges = 0; + + nsvg__flattenShapeStroke(r, shape, scale); + +// dumpEdges(r, "edge.svg"); + + // Scale and translate edges + for (i = 0; i < r->nedges; i++) { + e = &r->edges[i]; + e->x0 = tx + e->x0; + e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES; + e->x1 = tx + e->x1; + e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES; + } + + // Rasterize edges + if (r->nedges != 0) + qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge); + + // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule + nsvg__initPaint(&cache, &shape->stroke, shape->opacity); + + nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO); + } + } + + // JRY patch + // JRYFIXME: AlphaBlend wants premultiplied format; look what does Defringe section in nsvg__unpremultiplyAlpha + // nsvg__unpremultiplyAlpha(dst, w, h, stride); + + // JRYFIXME: patch directly nanosvg to skip this step? + for (i = 0; i < w * h; i++) + { + BYTE *b = ((BYTE*)dst) + i * 4; + BYTE b0 = b[0]; + b[0] = b[2]; + b[2] = b0; + } + + + r->bitmap = NULL; + r->width = 0; + r->height = 0; + r->stride = 0; +} + +#endif // NANOSVGRAST_IMPLEMENTATION + +#endif // NANOSVGRAST_H diff --git a/src/gui.cpp b/src/gui.cpp index a5231bbc7..fb3366531 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -11,8 +11,8 @@ #include #include -#include -#include +#include "nanosvg/nanosvg.h" +#include "nanosvg/nanosvgrast.h" #include "mainwnd.h" diff --git a/src/svg.cpp b/src/svg.cpp index fbeb5657d..5c1c6a4be 100644 --- a/src/svg.cpp +++ b/src/svg.cpp @@ -6,9 +6,9 @@ #include "svg.h" #define NANOSVG_IMPLEMENTATION -#include +#include "nanosvg/nanosvg.h" #define NANOSVGRAST_IMPLEMENTATION -#include +#include "nanosvg/nanosvgrast.h" CSVGSprite SVGArrowRight; CSVGSprite SVGArrowRightSmall; diff --git a/src/toolbar4.cpp b/src/toolbar4.cpp index 83e10defb..2bd68ede1 100644 --- a/src/toolbar4.cpp +++ b/src/toolbar4.cpp @@ -11,8 +11,8 @@ #include "plugins.h" #include "fileswnd.h" -#include -#include +#include "nanosvg/nanosvg.h" +#include "nanosvg/nanosvgrast.h" #include "svg.h" struct CButtonData diff --git a/src/vcpkg.json b/src/vcpkg.json index 8d18577ac..dbf24b1f0 100644 --- a/src/vcpkg.json +++ b/src/vcpkg.json @@ -1,7 +1,6 @@ { "dependencies": [ "bzip2", - "nanosvg", "zlib" ], "builtin-baseline": "6f29f12e82a8293156836ad81cc9bf5af41fe836" From 0adff5b83c1f3b62af6f37f59bf4f2d3b32b2150 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 15 Mar 2025 13:52:19 +0100 Subject: [PATCH 54/65] moved wil dependency to vcpkg --- src/common/dep/wil/Tracelogging.h | 3925 ---------- src/common/dep/wil/com.h | 3007 -------- src/common/dep/wil/com_apartment_variable.h | 467 -- src/common/dep/wil/common.h | 798 --- src/common/dep/wil/coroutine.h | 810 --- src/common/dep/wil/cppwinrt.h | 491 -- src/common/dep/wil/cppwinrt_authoring.h | 290 - src/common/dep/wil/cppwinrt_helpers.h | 352 - src/common/dep/wil/cppwinrt_wrl.h | 74 - src/common/dep/wil/filesystem.h | 1050 --- src/common/dep/wil/fine_readme.txt | 1 - src/common/dep/wil/nt_result_macros.h | 168 - src/common/dep/wil/registry.h | 3270 --------- src/common/dep/wil/registry_helpers.h | 1860 ----- src/common/dep/wil/resource.h | 7103 ------------------- src/common/dep/wil/result.h | 1280 ---- src/common/dep/wil/result_macros.h | 6249 ---------------- src/common/dep/wil/result_originate.h | 126 - src/common/dep/wil/rpc_helpers.h | 206 - src/common/dep/wil/safecast.h | 369 - src/common/dep/wil/stl.h | 196 - src/common/dep/wil/token_helpers.h | 613 -- src/common/dep/wil/traceloggingconfig.h | 71 - src/common/dep/wil/wil.natvis | 170 - src/common/dep/wil/win32_helpers.h | 897 --- src/common/dep/wil/win32_result_macros.h | 104 - src/common/dep/wil/winrt.h | 2334 ------ src/common/dep/wil/wistd_config.h | 571 -- src/common/dep/wil/wistd_functional.h | 548 -- src/common/dep/wil/wistd_memory.h | 1038 --- src/common/dep/wil/wistd_type_traits.h | 4504 ------------ src/common/dep/wil/wrl.h | 127 - src/vcpkg.json | 1 + 33 files changed, 1 insertion(+), 43069 deletions(-) delete mode 100644 src/common/dep/wil/Tracelogging.h delete mode 100644 src/common/dep/wil/com.h delete mode 100644 src/common/dep/wil/com_apartment_variable.h delete mode 100644 src/common/dep/wil/common.h delete mode 100644 src/common/dep/wil/coroutine.h delete mode 100644 src/common/dep/wil/cppwinrt.h delete mode 100644 src/common/dep/wil/cppwinrt_authoring.h delete mode 100644 src/common/dep/wil/cppwinrt_helpers.h delete mode 100644 src/common/dep/wil/cppwinrt_wrl.h delete mode 100644 src/common/dep/wil/filesystem.h delete mode 100644 src/common/dep/wil/fine_readme.txt delete mode 100644 src/common/dep/wil/nt_result_macros.h delete mode 100644 src/common/dep/wil/registry.h delete mode 100644 src/common/dep/wil/registry_helpers.h delete mode 100644 src/common/dep/wil/resource.h delete mode 100644 src/common/dep/wil/result.h delete mode 100644 src/common/dep/wil/result_macros.h delete mode 100644 src/common/dep/wil/result_originate.h delete mode 100644 src/common/dep/wil/rpc_helpers.h delete mode 100644 src/common/dep/wil/safecast.h delete mode 100644 src/common/dep/wil/stl.h delete mode 100644 src/common/dep/wil/token_helpers.h delete mode 100644 src/common/dep/wil/traceloggingconfig.h delete mode 100644 src/common/dep/wil/wil.natvis delete mode 100644 src/common/dep/wil/win32_helpers.h delete mode 100644 src/common/dep/wil/win32_result_macros.h delete mode 100644 src/common/dep/wil/winrt.h delete mode 100644 src/common/dep/wil/wistd_config.h delete mode 100644 src/common/dep/wil/wistd_functional.h delete mode 100644 src/common/dep/wil/wistd_memory.h delete mode 100644 src/common/dep/wil/wistd_type_traits.h delete mode 100644 src/common/dep/wil/wrl.h diff --git a/src/common/dep/wil/Tracelogging.h b/src/common/dep/wil/Tracelogging.h deleted file mode 100644 index a1bde6989..000000000 --- a/src/common/dep/wil/Tracelogging.h +++ /dev/null @@ -1,3925 +0,0 @@ -#pragma once -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* - -#ifndef __WIL_TRACELOGGING_H_INCLUDED -#define __WIL_TRACELOGGING_H_INCLUDED - -#ifdef _KERNEL_MODE -#error This header is not supported in kernel-mode. -#endif - -// Note that we avoid pulling in STL's memory header from TraceLogging.h through Resource.h as we have -// TraceLogging customers who are still on older versions of STL (without std::shared_ptr<>). -#define RESOURCE_SUPPRESS_STL -#ifndef __WIL_RESULT_INCLUDED -#include -#endif -#undef RESOURCE_SUPPRESS_STL -#include -#include -#include -#ifndef __WIL_TRACELOGGING_CONFIG_H -#include -#endif -#ifndef TRACELOGGING_SUPPRESS_NEW -#include -#endif - -#pragma warning(push) -#pragma warning(disable: 26135) // Missing locking annotation, Caller failing to hold lock - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wmicrosoft-template-shadow" -#endif - -#ifndef __TRACELOGGING_TEST_HOOK_ERROR -#define __TRACELOGGING_TEST_HOOK_ERROR(failure) -#define __TRACELOGGING_TEST_HOOK_ACTIVITY_ERROR(failure) -#define __TRACELOGGING_TEST_HOOK_CALLCONTEXT_ERROR(pFailure, hr) -#define __TRACELOGGING_TEST_HOOK_ACTIVITY_START() -#define __TRACELOGGING_TEST_HOOK_ACTIVITY_STOP(pFailure, hr) -#define __TRACELOGGING_TEST_HOOK_SET_ENABLED false -#define __TRACELOGGING_TEST_HOOK_VERIFY_API_TELEMETRY(nameSpace, apiList, specializationList, countArray, numCounters) -#define __TRACELOGGING_TEST_HOOK_API_TELEMETRY_EVENT_DELAY_MS 5000 -#endif - -// For use only within wil\TraceLogging.h: -#define _wiltlg_STRINGIZE(x) _wiltlg_STRINGIZE_imp(x) -#define _wiltlg_STRINGIZE_imp(x) #x -#define _wiltlg_LSTRINGIZE(x) _wiltlg_LSTRINGIZE_imp1(x) -#define _wiltlg_LSTRINGIZE_imp1(x) _wiltlg_LSTRINGIZE_imp2(#x) -#define _wiltlg_LSTRINGIZE_imp2(s) L##s - -/* -Macro __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK(name1, name2): -This macro defines a storage link association between two names for use by the -TlgReflector static analysis tool. -*/ -#define __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK(name1, name2) \ - __annotation(L"_TlgProviderLink:|" _wiltlg_LSTRINGIZE(__LINE__) L"|Key|" _wiltlg_LSTRINGIZE(name1) L"=" _wiltlg_LSTRINGIZE(name2)) - -// Utility macro for writing relevant fields from a wil::FailureInfo structure into a TraceLoggingWrite -// statement. Most fields are relevant for telemetry or for simple ETW, but there are a few additional -// fields reported via ETW. - -#define __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure) \ - TraceLoggingUInt32((failure).hr, "hresult", "Failure error code"), \ - TraceLoggingString((failure).pszFile, "fileName", "Source code file name where the error occurred"), \ - TraceLoggingUInt32((failure).uLineNumber, "lineNumber", "Line number within the source code file where the error occurred"), \ - TraceLoggingString((failure).pszModule, "module", "Name of the binary where the error occurred"), \ - TraceLoggingUInt32(static_cast((failure).type), "failureType", "Indicates what type of failure was observed (exception, returned error, logged error or fail fast"), \ - TraceLoggingWideString((failure).pszMessage, "message", "Custom message associated with the failure (if any)"), \ - TraceLoggingUInt32((failure).threadId, "threadId", "Identifier of the thread the error occurred on"), \ - TraceLoggingString((failure).pszCallContext, "callContext", "List of telemetry activities containing this error"), \ - TraceLoggingUInt32((failure).callContextOriginating.contextId, "originatingContextId", "Identifier for the oldest telemetry activity containing this error"), \ - TraceLoggingString((failure).callContextOriginating.contextName, "originatingContextName", "Name of the oldest telemetry activity containing this error"), \ - TraceLoggingWideString((failure).callContextOriginating.contextMessage, "originatingContextMessage", "Custom message associated with the oldest telemetry activity containing this error (if any)"), \ - TraceLoggingUInt32((failure).callContextCurrent.contextId, "currentContextId", "Identifier for the newest telemetry activity containing this error"), \ - TraceLoggingString((failure).callContextCurrent.contextName, "currentContextName", "Name of the newest telemetry activity containing this error"), \ - TraceLoggingWideString((failure).callContextCurrent.contextMessage, "currentContextMessage", "Custom message associated with the newest telemetry activity containing this error (if any)") - -#define __RESULT_TRACELOGGING_COMMON_FAILURE_PARAMS(failure) \ - __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure), \ - TraceLoggingUInt32(static_cast((failure).failureId), "failureId", "Identifier assigned to this failure"), \ - TraceLoggingUInt32(static_cast((failure).cFailureCount), "failureCount", "Number of failures seen within the binary where the error occurred"), \ - TraceLoggingString((failure).pszFunction, "function", "Name of the function where the error occurred") - -// Activity Start Event (ALL) -#define __ACTIVITY_START_PARAMS() \ - TraceLoggingStruct(1, "wilActivity"), \ - TraceLoggingUInt32(::GetCurrentThreadId(), "threadId", "Identifier of the thread the activity was run on") - -// Activity Stop Event (SUCCESSFUL or those WITHOUT full failure info -- just hr) -// Also utilized for intermediate stop events (a successful call to 'Stop()' from a Split activity -#define __ACTIVITY_STOP_PARAMS(hr) \ - TraceLoggingStruct(2, "wilActivity"), \ - TraceLoggingUInt32(hr, "hresult", "Failure error code"), \ - TraceLoggingUInt32(::GetCurrentThreadId(), "threadId", "Identifier of the thread the activity was run on") - -// Activity Stop Event (FAILED with full failure info) -#define __ACTIVITY_STOP_TELEMETRY_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), \ - TraceLoggingStruct(14, "wilActivity"), \ - __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure) -#define __ACTIVITY_STOP_TRACELOGGING_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), \ - TraceLoggingStruct(17, "wilActivity"), \ - __RESULT_TRACELOGGING_COMMON_FAILURE_PARAMS(failure) - -// "ActivityError" tagged event (all distinct FAILURES occurring within the outer activity scope) -#define __ACTIVITY_ERROR_TELEMETRY_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), \ - TraceLoggingStruct(14, "wilActivity"), \ - __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure) -#define __ACTIVITY_ERROR_TRACELOGGING_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), \ - TraceLoggingStruct(17, "wilActivity"), \ - __RESULT_TRACELOGGING_COMMON_FAILURE_PARAMS(failure) - -// "ActivityFailure" tagged event (only comes through on TELEMETRY for CallContext activities that have FAILED) -#define __ACTIVITY_FAILURE_TELEMETRY_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), \ - TraceLoggingStruct(14, "wilActivity"), \ - __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure) -#define __ACTIVITY_FAILURE_TELEMETRY_PARAMS(hr, contextName, contextMessage) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), \ - TraceLoggingStruct(4, "wilActivity"), \ - TraceLoggingUInt32(hr, "hresult", "Failure error code"), \ - TraceLoggingUInt32(::GetCurrentThreadId(), "threadId", "Identifier of the thread the activity was run on"), \ - TraceLoggingString(contextName, "currentContextName", "Name of the activity containing this error"), \ - TraceLoggingWideString(contextMessage, "currentContextMessage", "Custom message for the activity containing this error (if any)") - -// "FallbackError" events (all FAILURE events happening outside of ANY activity context) -#define __RESULT_TELEMETRY_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), \ - TraceLoggingStruct(14, "wilResult"), \ - __RESULT_TELEMETRY_COMMON_FAILURE_PARAMS(failure) -#define __RESULT_TRACELOGGING_FAILURE_PARAMS(failure) \ - TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), \ - TraceLoggingStruct(17, "wilResult"), \ - __RESULT_TRACELOGGING_COMMON_FAILURE_PARAMS(failure) - -namespace wil -{ - enum class ActivityOptions - { - None = 0, - TelemetryOnFailure = 0x1, - TraceLoggingOnFailure = 0x2 - }; - DEFINE_ENUM_FLAG_OPERATORS(ActivityOptions) - - template - class ActivityBase; - - /// @cond - namespace details - { - // Lazy static initialization helper for holding a singleton telemetry class to maintain - // the provider handle. - - template - class static_lazy - { - public: - void __cdecl cleanup() WI_NOEXCEPT - { - void* pVoid; - BOOL pending; - - // If object is being constructed on another thread, wait until construction completes. - // Need a memory barrier here (see get() and ~Completer below) so use the result that we - // get from InitOnceBeginInitialize(..., &pVoid, ...) - if (::InitOnceBeginInitialize(&m_initOnce, INIT_ONCE_CHECK_ONLY, &pending, &pVoid) && !pending) - { - static_cast(pVoid)->~T(); - } - } - - T* get(void(__cdecl *cleanupFunc)(void)) WI_NOEXCEPT - { - void* pVoid{}; - BOOL pending; - if (::InitOnceBeginInitialize(&m_initOnce, 0, &pending, &pVoid) && pending) - { - // Don't do anything non-trivial from DllMain, fail fast. - // Some 3rd party code in IE calls shell functions this way, so we can only enforce - // this in DEBUG. -#ifdef DEBUG - FAIL_FAST_IMMEDIATE_IF_IN_LOADER_CALLOUT(); -#endif - - Completer completer(this); - pVoid = &m_storage; - ::new(pVoid)T(); - atexit(cleanupFunc); // ignore failure (that's what the C runtime does, too) - completer.Succeed(); - } - return static_cast(pVoid); - } - - private: - INIT_ONCE m_initOnce; - alignas(T) BYTE m_storage[sizeof(T)]; - struct Completer - { - static_lazy *m_pSelf; - DWORD m_flags; - - explicit Completer(static_lazy *pSelf) WI_NOEXCEPT : m_pSelf(pSelf), m_flags(INIT_ONCE_INIT_FAILED) { } - void Succeed() WI_NOEXCEPT { m_flags = 0; } - - ~Completer() WI_NOEXCEPT - { - if (m_flags == 0) - { - reinterpret_cast(&m_pSelf->m_storage)->Create(); - } - ::InitOnceComplete(&m_pSelf->m_initOnce, m_flags, &m_pSelf->m_storage); - } - }; - }; - - // This class serves as a simple RAII wrapper around CallContextInfo. It presumes that - // the contextName parameter is always a static string, but copies or allocates the - // contextMessage as needed. - - class StoredCallContextInfo : public wil::CallContextInfo - { - public: - StoredCallContextInfo() WI_NOEXCEPT - { - ::ZeroMemory(this, sizeof(*this)); - } - - StoredCallContextInfo(StoredCallContextInfo &&other) WI_NOEXCEPT : - StoredCallContextInfo() - { - operator=(wistd::move(other)); - } - - StoredCallContextInfo& operator=(StoredCallContextInfo &&other) WI_NOEXCEPT - { - contextId = other.contextId; - contextName = other.contextName; - ClearMessage(); - contextMessage = other.contextMessage; - other.contextMessage = nullptr; - m_ownsMessage = other.m_ownsMessage; - other.m_ownsMessage = false; - return *this; - } - - StoredCallContextInfo(StoredCallContextInfo const &other) WI_NOEXCEPT : - m_ownsMessage(false) - { - contextId = other.contextId; - contextName = other.contextName; - if (other.m_ownsMessage) - { - AssignMessage(other.contextMessage); - } - else - { - contextMessage = other.contextMessage; - } - } - - StoredCallContextInfo(_In_opt_ PCSTR staticContextName) WI_NOEXCEPT : - m_ownsMessage(false) - { - contextId = 0; - contextName = staticContextName; - contextMessage = nullptr; - } - - StoredCallContextInfo(PCSTR staticContextName, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT : - StoredCallContextInfo(staticContextName) - { - SetMessage(formatString, argList); - } - - void SetMessage(_Printf_format_string_ PCSTR formatString, va_list argList) - { - wchar_t loggingMessage[2048]; - PrintLoggingMessage(loggingMessage, ARRAYSIZE(loggingMessage), formatString, argList); - ClearMessage(); - AssignMessage(loggingMessage); - } - - void SetMessage(_In_opt_ PCWSTR message) - { - ClearMessage(); - contextMessage = message; - } - - void SetMessageCopy(_In_opt_ PCWSTR message) - { - ClearMessage(); - if (message != nullptr) - { - AssignMessage(message); - } - } - - void ClearMessage() - { - if (m_ownsMessage) - { - WIL_FreeMemory(const_cast(contextMessage)); - m_ownsMessage = false; - } - contextMessage = nullptr; - } - - ~StoredCallContextInfo() - { - ClearMessage(); - } - - StoredCallContextInfo& operator=(StoredCallContextInfo const &) = delete; - - private: - void AssignMessage(PCWSTR message) - { - auto length = wcslen(message); - if (length > 0) - { - auto sizeBytes = (length + 1) * sizeof(wchar_t); - contextMessage = static_cast(WIL_AllocateMemory(sizeBytes)); - if (contextMessage != nullptr) - { - m_ownsMessage = true; - memcpy_s(const_cast(contextMessage), sizeBytes, message, sizeBytes); - } - } - } - - bool m_ownsMessage; - }; - - template - void SetRelatedActivityId(TActivity&) - { - } - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - template - void SetRelatedActivityId(wil::ActivityBase& activity) - { - GUID capturedRelatedId; - EventActivityIdControl(EVENT_ACTIVITY_CTRL_GET_ID, &capturedRelatedId); - activity.SetRelatedActivityId(capturedRelatedId); - } -#endif - - typedef wistd::integral_constant tag_start; - typedef wistd::integral_constant tag_start_cv; - } // namespace details - /// @endcond - - - // This class acts as a simple RAII class returned by a call to ContinueOnCurrentThread() for an activity - // or by a call to WatchCurrentThread() on a provider. The result is meant to be a stack local variable - // whose scope controls the lifetime of an error watcher on the given thread. That error watcher re-directs - // errors occurrent within the object's lifetime to the associated provider or activity. - - class ActivityThreadWatcher - { - public: - ActivityThreadWatcher() WI_NOEXCEPT - : m_callbackHolder(nullptr, nullptr, false) - {} - - ActivityThreadWatcher(_In_ details::IFailureCallback *pCallback, PCSTR staticContextName) WI_NOEXCEPT : - m_callContext(staticContextName), - m_callbackHolder(pCallback, &m_callContext) - { - } - - ActivityThreadWatcher(_In_ details::IFailureCallback *pCallback, PCSTR staticContextName, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT : - ActivityThreadWatcher(pCallback, staticContextName) - { - m_callContext.SetMessage(formatString, argList); - } - - // Uses the supplied StoredCallContextInfo rather than producing one itself - ActivityThreadWatcher(_In_ details::IFailureCallback *pCallback, _In_ details::StoredCallContextInfo const &callContext) WI_NOEXCEPT : - m_callContext(callContext), - m_callbackHolder(pCallback, &m_callContext) - { - } - - ActivityThreadWatcher(ActivityThreadWatcher &&other) WI_NOEXCEPT : - m_callContext(wistd::move(other.m_callContext)), - m_callbackHolder(wistd::move(other.m_callbackHolder)) - { - m_callbackHolder.SetCallContext(&m_callContext); - } - - ActivityThreadWatcher(ActivityThreadWatcher const &) = delete; - ActivityThreadWatcher& operator=(ActivityThreadWatcher const &) = delete; - - void SetMessage(_Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - m_callContext.SetMessage(formatString, argList); - va_end(argList); - } - - void SetMessage(_In_opt_ PCWSTR message) - { - m_callContext.SetMessage(message); - } - - void SetMessageCopy(_In_opt_ PCWSTR message) - { - m_callContext.SetMessageCopy(message); - } - - private: - details::StoredCallContextInfo m_callContext; - details::ThreadFailureCallbackHolder m_callbackHolder; - }; - - - // This is the base-class implementation of a TraceLogging class. TraceLogging classes are defined with - // BEGIN_TRACELOGGING_CLASS and automatically derive from this class - - enum class ErrorReportingType - { - None = 0, - Telemetry, - TraceLogging - }; - - class TraceLoggingProvider : public details::IFailureCallback - { - public: - // Only one instance of each of these derived classes should be created - TraceLoggingProvider(_In_ TraceLoggingProvider const&) = delete; - TraceLoggingProvider& operator=(TraceLoggingProvider const&) = delete; - void* operator new(size_t) = delete; - void* operator new[](size_t) = delete; - - protected: - - // This can be overridden to provide specific initialization code for any individual provider. - // It will be ran once when the single static singleton instance of this class is created. - virtual void Initialize() WI_NOEXCEPT {} - - // This method can be overridden by a provider to more tightly control what happens in the event - // of a failure in a CallContext activity, WatchCurrentThread() object, or attributed to a specific failure. - virtual void OnErrorReported(bool alreadyReported, FailureInfo const &failure) WI_NOEXCEPT - { - if (!alreadyReported && WI_IsFlagClear(failure.flags, FailureFlags::RequestSuppressTelemetry)) - { - if (m_errorReportingType == ErrorReportingType::Telemetry) - { - ReportTelemetryFailure(failure); - } - else if (m_errorReportingType == ErrorReportingType::TraceLogging) - { - ReportTraceLoggingFailure(failure); - } - } - } - - public: - WI_NODISCARD TraceLoggingHProvider Provider_() const WI_NOEXCEPT - { - return m_providerHandle; - } - - protected: - TraceLoggingProvider() WI_NOEXCEPT {} - - virtual ~TraceLoggingProvider() WI_NOEXCEPT - { - if (m_ownsProviderHandle) - { - TraceLoggingUnregister(m_providerHandle); - } - } - - WI_NODISCARD bool IsEnabled_(UCHAR eventLevel /* WINEVENT_LEVEL_XXX, e.g. WINEVENT_LEVEL_VERBOSE */, ULONGLONG eventKeywords /* MICROSOFT_KEYWORD_XXX */) const WI_NOEXCEPT - { - return ((m_providerHandle != nullptr) && TraceLoggingProviderEnabled(m_providerHandle, eventLevel, eventKeywords)) || __TRACELOGGING_TEST_HOOK_SET_ENABLED; - } - - void SetErrorReportingType_(ErrorReportingType type) - { - m_errorReportingType = type; - } - - static bool WasAlreadyReportedToTelemetry(long failureId) WI_NOEXCEPT - { - static long volatile s_lastFailureSeen = -1; - auto wasSeen = (s_lastFailureSeen == failureId); - s_lastFailureSeen = failureId; - return wasSeen; - } - - void ReportTelemetryFailure(FailureInfo const &failure) WI_NOEXCEPT - { - __TRACELOGGING_TEST_HOOK_ERROR(failure); - TraceLoggingWrite(m_providerHandle, "FallbackError", TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TraceLoggingLevel(WINEVENT_LEVEL_ERROR), __RESULT_TELEMETRY_FAILURE_PARAMS(failure)); - } - - void ReportTraceLoggingFailure(FailureInfo const &failure) WI_NOEXCEPT - { - TraceLoggingWrite(m_providerHandle, "FallbackError", TraceLoggingLevel(WINEVENT_LEVEL_ERROR), __RESULT_TRACELOGGING_FAILURE_PARAMS(failure)); - } - - // Helper function for TraceLoggingError. - // It prints out a trace message for debug purposes. The message does not go into the telemetry. - void ReportTraceLoggingError(_In_ _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - if (IsEnabled_(WINEVENT_LEVEL_ERROR, 0)) - { - wchar_t loggingMessage[2048]; - details::PrintLoggingMessage(loggingMessage, ARRAYSIZE(loggingMessage), formatString, argList); - TraceLoggingWrite(m_providerHandle, "TraceLoggingError", TraceLoggingLevel(WINEVENT_LEVEL_ERROR), TraceLoggingWideString(loggingMessage, "traceLoggingMessage")); - } - } - - // Helper function for TraceLoggingInfo. - // It prints out a trace message for debug purposes. The message does not go into the telemetry. - void ReportTraceLoggingMessage(_In_ _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - if (IsEnabled_(WINEVENT_LEVEL_VERBOSE, 0)) - { - wchar_t loggingMessage[2048]; - details::PrintLoggingMessage(loggingMessage, ARRAYSIZE(loggingMessage), formatString, argList); - TraceLoggingWrite(m_providerHandle, "TraceLoggingInfo", TraceLoggingLevel(WINEVENT_LEVEL_VERBOSE), TraceLoggingWideString(loggingMessage, "traceLoggingMessage")); - } - } - - void Register(TraceLoggingHProvider const providerHandle, TLG_PENABLECALLBACK callback = nullptr) WI_NOEXCEPT - { - // taking over the lifetime and management of providerHandle - m_providerHandle = providerHandle; - m_ownsProviderHandle = true; - TraceLoggingRegisterEx(providerHandle, callback, nullptr); - InternalInitialize(); - } - - void AttachProvider(TraceLoggingHProvider const providerHandle) WI_NOEXCEPT - { - m_providerHandle = providerHandle; - m_ownsProviderHandle = false; - InternalInitialize(); - } - - private: - // IFailureCallback - bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT override - { - if (!WasAlreadyReportedToTelemetry(failure.failureId)) - { - OnErrorReported(false, failure); - } - return true; - } - - void InternalInitialize() - { - m_errorReportingType = ErrorReportingType::Telemetry; - Initialize(); - } - - TraceLoggingHProvider m_providerHandle{}; - bool m_ownsProviderHandle{}; - ErrorReportingType m_errorReportingType{}; - }; - - template< - typename TraceLoggingType, - UINT64 keyword = 0, - UINT8 level = WINEVENT_LEVEL_VERBOSE, - typename TlgReflectorTag = _TlgReflectorTag_Param0IsProviderType> // helps TlgReflector understand that this is a wrapper type - class BasicActivity - : public _TlgActivityBase, keyword, level> - { - using BaseTy = _TlgActivityBase, keyword, level>; - friend BaseTy; - - void OnStarted() - { - } - - void OnStopped() - { - } - - public: - - BasicActivity() - { - } - - BasicActivity(BasicActivity&& rhs) : - BaseTy(wistd::move(rhs)) - { - } - - BasicActivity& operator=(BasicActivity&& rhs) - { - BaseTy::operator=(wistd::move(rhs)); - return *this; - } - - /* - Returns a handle to the TraceLogging provider associated with this activity. - */ - WI_NODISCARD TraceLoggingHProvider Provider() const - { - return TraceLoggingType::Provider(); - } - - /* - Sets the related (parent) activity. - May only be called once. If used, must be called before starting the activity. - */ - template - void SetRelatedActivity(_In_ const ActivityTy& relatedActivity) - { - this->SetRelatedId(*relatedActivity.Id()); - } - - /* - Sets the related (parent) activity. - May only be called once. If used, must be called before starting the activity. - */ - void SetRelatedActivityId(_In_ const GUID& relatedActivityId) - { - this->SetRelatedId(relatedActivityId); - } - - /* - Sets the related (parent) activity. - May only be called once. If used, must be called before starting the activity. - */ - void SetRelatedActivityId(_In_ const GUID* relatedActivityId) - { - __FAIL_FAST_IMMEDIATE_ASSERT__(relatedActivityId != NULL); - this->SetRelatedId(*relatedActivityId); - } - }; - - template< - typename TraceLoggingType, - UINT64 keyword = 0, - UINT8 level = WINEVENT_LEVEL_VERBOSE, - typename TlgReflectorTag = _TlgReflectorTag_Param0IsProviderType> // helps TlgReflector understand that this is a wrapper type - class BasicThreadActivity - : public _TlgActivityBase, keyword, level> - { - using BaseTy = _TlgActivityBase, keyword, level>; - friend BaseTy; - - void OnStarted() - { - this->PushThreadActivityId(); - } - - void OnStopped() - { - this->PopThreadActivityId(); - } - - public: - - BasicThreadActivity() - { - } - - BasicThreadActivity(BasicThreadActivity&& rhs) - : BaseTy(wistd::move(rhs)) - { - } - - BasicThreadActivity& operator=(BasicThreadActivity&& rhs) - { - BaseTy::operator=(wistd::move(rhs)); - return *this; - } - - /* - Returns a handle to the TraceLogging provider associated with this activity. - */ - WI_NODISCARD TraceLoggingHProvider Provider() const - { - return TraceLoggingType::Provider(); - } - }; - -#define __WI_TraceLoggingWriteTagged(activity, name, ...) \ - __pragma(warning(push)) __pragma(warning(disable:4127)) \ - do { \ - _tlgActivityDecl(activity) \ - TraceLoggingWriteActivity( \ - TraceLoggingType::Provider(), \ - (name), \ - _tlgActivityRef(activity).Id(), \ - NULL, \ - __VA_ARGS__); \ - } while(0) \ - __pragma(warning(pop)) \ - - - // This is the ultimate base class implementation for all activities. Activity classes are defined with - // DEFINE_TRACELOGGING_ACTIVITY, DEFINE_CALLCONTEXT_ACTIVITY, DEFINE_TELEMETRY_ACTIVITY and others - - - template - class ActivityBase : public details::IFailureCallback - { - public: - typedef ActivityTraceLoggingType TraceLoggingType; - - static UINT64 const Keyword = keyword; - static UINT8 const Level = level; - static UINT64 const PrivacyTag = privacyTag; - - ActivityBase(PCSTR contextName, bool shouldWatchErrors = false) WI_NOEXCEPT : - m_activityData(contextName), - m_pActivityData(&m_activityData), - m_callbackHolder(this, m_activityData.GetCallContext(), shouldWatchErrors) - { - } - - ActivityBase(ActivityBase &&other, bool shouldWatchErrors) WI_NOEXCEPT : - m_activityData(wistd::move(other.m_activityData)), - m_sharedActivityData(wistd::move(other.m_sharedActivityData)), - m_callbackHolder(this, nullptr, shouldWatchErrors) - { - m_pActivityData = m_sharedActivityData ? m_sharedActivityData.get() : &m_activityData; - m_callbackHolder.SetCallContext(m_pActivityData->GetCallContext()); - other.m_pActivityData = &other.m_activityData; - if (other.m_callbackHolder.IsWatching()) - { - other.m_callbackHolder.StopWatching(); - } - } - - ActivityBase(ActivityBase &&other) WI_NOEXCEPT : - ActivityBase(wistd::move(other), other.m_callbackHolder.IsWatching()) - { - } - - ActivityBase(ActivityBase const &other) WI_NOEXCEPT : - m_activityData(), - m_pActivityData(&m_activityData), - m_callbackHolder(this, nullptr, false) // false = do not automatically watch for failures - { - operator=(other); - } - - ActivityBase& operator=(ActivityBase &&other) WI_NOEXCEPT - { - m_activityData = wistd::move(other.m_activityData); - m_sharedActivityData = wistd::move(other.m_sharedActivityData); - m_pActivityData = m_sharedActivityData ? m_sharedActivityData.get() : &m_activityData; - m_callbackHolder.SetCallContext(m_pActivityData->GetCallContext()); - m_callbackHolder.SetWatching(other.m_callbackHolder.IsWatching()); - other.m_pActivityData = &other.m_activityData; - if (other.m_callbackHolder.IsWatching()) - { - other.m_callbackHolder.StopWatching(); - } - return *this; - } - - ActivityBase& operator=(ActivityBase const &other) WI_NOEXCEPT - { - if (m_callbackHolder.IsWatching()) - { - m_callbackHolder.StopWatching(); - } - - if (other.m_sharedActivityData) - { - m_pActivityData = other.m_pActivityData; - m_sharedActivityData = other.m_sharedActivityData; - } - else if (m_sharedActivityData.create(wistd::move(other.m_activityData))) - { - // Locking should not be required as the first copy should always take place on the owning - // thread... - m_pActivityData = m_sharedActivityData.get(); - other.m_sharedActivityData = m_sharedActivityData; - other.m_pActivityData = m_pActivityData; - other.m_callbackHolder.SetCallContext(m_pActivityData->GetCallContext()); - } - m_callbackHolder.SetCallContext(m_pActivityData->GetCallContext()); - return *this; - } - - // These calls all result in setting a message to associate with any failures that might occur while - // running the activity. For example, you could associate a filename with a call context activity - // so that the file name is only reported if the activity fails with the failure. - - void SetMessage(_In_ _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - auto lock = LockExclusive(); - GetCallContext()->SetMessage(formatString, argList); - va_end(argList); - } - - void SetMessage(_In_opt_ PCWSTR message) - { - auto lock = LockExclusive(); - GetCallContext()->SetMessage(message); - } - - void SetMessageCopy(_In_opt_ PCWSTR message) - { - auto lock = LockExclusive(); - GetCallContext()->SetMessageCopy(message); - } - - // This call stops watching for errors on the thread that the activity was originally - // created on. Use it when moving the activity into a thread-agnostic class or moving - // an activity across threads. - - void IgnoreCurrentThread() WI_NOEXCEPT - { - if (m_callbackHolder.IsWatching()) - { - m_callbackHolder.StopWatching(); - } - } - - // Call this API to retrieve an RAII object to watch events on the current thread. The returned - // object should only be used on the stack. - - WI_NODISCARD ActivityThreadWatcher ContinueOnCurrentThread() WI_NOEXCEPT - { - if (IsRunning()) - { - return ActivityThreadWatcher(this, *m_pActivityData->GetCallContext()); - } - return ActivityThreadWatcher(); - } - - // This is the 'default' Stop routine that accepts an HRESULT and completes the activity... - - void Stop(HRESULT hr = S_OK) WI_NOEXCEPT - { - bool stopActivity; - HRESULT hrLocal; - { - auto lock = LockExclusive(); - stopActivity = m_pActivityData->SetStopResult(hr, &hrLocal); - } - if (stopActivity) - { - ReportStopActivity(hrLocal); - } - else - { - __WI_TraceLoggingWriteTagged(*this, "ActivityIntermediateStop", TraceLoggingKeyword(Keyword), TelemetryPrivacyDataTag(PDT_ProductAndServicePerformance), __ACTIVITY_STOP_PARAMS(hr)); - } - IgnoreCurrentThread(); - } - - // IFailureCallback - - bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT override - { - // We always report errors to the ETW stream, but we hold-back the telemetry keyword if we've already reported this error to this - // particular telemetry provider. - - __TRACELOGGING_TEST_HOOK_ACTIVITY_ERROR(failure); - - if (WI_IsFlagClear(failure.flags, FailureFlags::RequestSuppressTelemetry)) - { -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunused-value" -#endif -#pragma warning(push) -#pragma warning(disable: 6319) - if (false, WI_IsFlagSet(options, ActivityOptions::TelemetryOnFailure) && !WasAlreadyReportedToTelemetry(failure.failureId)) - { - __WI_TraceLoggingWriteTagged(*this, "ActivityError", TraceLoggingKeyword(Keyword | MICROSOFT_KEYWORD_TELEMETRY), TraceLoggingLevel(WINEVENT_LEVEL_ERROR), __ACTIVITY_ERROR_TELEMETRY_FAILURE_PARAMS(failure)); - } - else if (false, WI_IsFlagSet(options, ActivityOptions::TraceLoggingOnFailure)) - { - __WI_TraceLoggingWriteTagged(*this, "ActivityError", TraceLoggingKeyword(0), TraceLoggingLevel(WINEVENT_LEVEL_ERROR), __ACTIVITY_ERROR_TRACELOGGING_FAILURE_PARAMS(failure)); - } - else - { - __WI_TraceLoggingWriteTagged(*this, "ActivityError", TraceLoggingKeyword(Keyword), TraceLoggingLevel(WINEVENT_LEVEL_ERROR), __ACTIVITY_ERROR_TRACELOGGING_FAILURE_PARAMS(failure)); - } -#pragma warning(pop) -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - } - - auto lock = LockExclusive(); - m_pActivityData->NotifyFailure(failure); - return true; - } - - // This is the base TraceLoggingActivity<> contract... we implement it so that this class - // can be used by all of the activity macros and we re-route the request as needed. - // - // The contract required by the TraceLogging Activity macros is: - // - activity.Keyword // compile-time constant - // - activity.Level // compile-time constant - // - activity.PrivacyTag // compile-time constant - // - activity.Provider() - // - activity.Id() - // - activity.zInternalRelatedId() - // - activity.zInternalStart() - // - activity.zInternalStop() - // In addition, for TlgReflector to work correctly, it must be possible for - // TlgReflector to statically map from typeof(activity) to hProvider. - - WI_NODISCARD GUID const* zInternalRelatedId() const WI_NOEXCEPT - { - return m_pActivityData->zInternalRelatedId(); - } - - void zInternalStart() WI_NOEXCEPT - { - auto lock = LockExclusive(); m_pActivityData->zInternalStart(); - } - - void zInternalStop() WI_NOEXCEPT - { - auto lock = LockExclusive(); m_pActivityData->zInternalStop(); - } - - static TraceLoggingHProvider Provider() WI_NOEXCEPT - { - return ActivityTraceLoggingType::Provider(); - } - - WI_NODISCARD GUID const* Id() const WI_NOEXCEPT - { - return m_pActivityData->Id(); - } - - WI_NODISCARD GUID const* providerGuid() const WI_NOEXCEPT - { - return m_pActivityData->providerGuid(); - } - - template - void SetRelatedActivity(OtherTy const &relatedActivity) WI_NOEXCEPT - { - auto lock = LockExclusive(); - m_pActivityData->SetRelatedActivityId(relatedActivity.Id()); - } - - void SetRelatedActivityId(_In_ const GUID& relatedActivityId) WI_NOEXCEPT - { - auto lock = LockExclusive(); - m_pActivityData->SetRelatedActivityId(&relatedActivityId); - } - - void SetRelatedActivityId(_In_ const GUID* relatedActivityId) WI_NOEXCEPT - { - auto lock = LockExclusive(); - m_pActivityData->SetRelatedActivityId(relatedActivityId); - } - - WI_NODISCARD inline bool IsRunning() const WI_NOEXCEPT - { - return m_pActivityData->NeedsStopped(); - } - protected: - virtual void StopActivity() WI_NOEXCEPT = 0; - virtual bool WasAlreadyReportedToTelemetry(long failureId) WI_NOEXCEPT = 0; - - void EnsureWatchingCurrentThread() - { - if (!m_callbackHolder.IsWatching()) - { - m_callbackHolder.StartWatching(); - } - } - - void SetStopResult(HRESULT hr, _Out_opt_ HRESULT *phr = nullptr) WI_NOEXCEPT - { - auto lock = LockExclusive(); - m_pActivityData->SetStopResult(hr, phr); - } - - void IncrementExpectedStopCount() WI_NOEXCEPT - { - auto lock = LockExclusive(); - m_pActivityData->IncrementExpectedStopCount(); - } - - // Locking should not be required on these accessors as we only use this at reporting (which will only happen from - // the final stop) - - FailureInfo const* GetFailureInfo() WI_NOEXCEPT - { - return m_pActivityData->GetFailureInfo(); - } - - WI_NODISCARD inline HRESULT GetResult() const WI_NOEXCEPT - { - return m_pActivityData->GetResult(); - } - - WI_NODISCARD details::StoredCallContextInfo* GetCallContext() const WI_NOEXCEPT - { - return m_pActivityData->GetCallContext(); - } - - // Think of this routine as the destructor -- since we need to call virtual derived methods, we can't use it as - // a destructor without a pure virtual method call, so we have the derived class call it in its destructor... - - void Destroy() WI_NOEXCEPT - { - bool fStop = true; - if (m_sharedActivityData) - { - // The lock unifies the 'unique()' check and the 'reset()' of any non-unique activity so that we - // can positively identify the final release of the internal data - - auto lock = LockExclusive(); - if (!m_sharedActivityData.unique()) - { - fStop = false; - m_sharedActivityData.reset(); - } - } - - if (fStop && m_pActivityData->NeedsStopped()) - { - ReportStopActivity(m_pActivityData->SetUnhandledException()); - } - } - - private: - void ReportStopActivity(HRESULT hr) WI_NOEXCEPT - { - if (FAILED(hr) && WI_AreAllFlagsClear(Keyword, (MICROSOFT_KEYWORD_TELEMETRY | MICROSOFT_KEYWORD_MEASURES | MICROSOFT_KEYWORD_CRITICAL_DATA)) && WI_IsFlagSet(options, ActivityOptions::TelemetryOnFailure)) - { - wil::FailureInfo const* pFailure = GetFailureInfo(); - if (pFailure != nullptr) - { - __TRACELOGGING_TEST_HOOK_CALLCONTEXT_ERROR(pFailure, pFailure->hr); - auto & failure = *pFailure; - __WI_TraceLoggingWriteTagged(*this, "ActivityFailure", TraceLoggingKeyword(Keyword | MICROSOFT_KEYWORD_TELEMETRY), TraceLoggingLevel(WINEVENT_LEVEL_ERROR), __ACTIVITY_FAILURE_TELEMETRY_FAILURE_PARAMS(failure)); - } - else - { - __TRACELOGGING_TEST_HOOK_CALLCONTEXT_ERROR(nullptr, hr); - __WI_TraceLoggingWriteTagged(*this, "ActivityFailure", TraceLoggingKeyword(Keyword | MICROSOFT_KEYWORD_TELEMETRY), TraceLoggingLevel(WINEVENT_LEVEL_ERROR), - __ACTIVITY_FAILURE_TELEMETRY_PARAMS(hr, m_pActivityData->GetCallContext()->contextName, m_pActivityData->GetCallContext()->contextMessage)); - } - } - - StopActivity(); - } - - rwlock_release_exclusive_scope_exit LockExclusive() WI_NOEXCEPT - { - // We only need to lock when we're sharing.... - return (m_sharedActivityData ? m_sharedActivityData->LockExclusive() : rwlock_release_exclusive_scope_exit()); - } - - template - class ActivityData : - public _TlgActivityBase, keyword, level> - { - using BaseTy = _TlgActivityBase, keyword, level>; - friend BaseTy; - void OnStarted() {} - void OnStopped() {} - - // SFINAE dispatching on presence of ActivityTraceLoggingType::CreateActivityId(_Out_ GUID& childActivityId, _In_opt_ const GUID* relatedActivityId) - template - auto CreateActivityIdByProviderType(int, _Out_ GUID& childActivityId) -> - decltype(ProviderType::CreateActivityId(childActivityId, this->GetRelatedId()), (void)0) - { - ProviderType::CreateActivityId(childActivityId, this->GetRelatedId()); - } - - template - auto CreateActivityIdByProviderType(long, _Out_ GUID& childActivityId) -> - void - { - EventActivityIdControl(EVENT_ACTIVITY_CTRL_CREATE_ID, &childActivityId); - } - - void CreateActivityId(_Out_ GUID& childActivityId) - { - CreateActivityIdByProviderType(0, childActivityId); - } - - public: - ActivityData(_In_opt_ PCSTR contextName = nullptr) WI_NOEXCEPT : - BaseTy(), - m_callContext(contextName), - m_result(S_OK), - m_stopCountExpected(1) - { - } - - ActivityData(ActivityData &&other) WI_NOEXCEPT : - BaseTy(wistd::move(other)), - m_callContext(wistd::move(other.m_callContext)), - m_result(other.m_result), - m_failure(wistd::move(other.m_failure)), - m_stopCountExpected(other.m_stopCountExpected) - { - } - - ActivityData & operator=(ActivityData &&other) WI_NOEXCEPT - { - BaseTy::operator=(wistd::move(other)); - m_callContext = wistd::move(other.m_callContext); - m_result = other.m_result; - m_failure = wistd::move(other.m_failure); - m_stopCountExpected = other.m_stopCountExpected; - return *this; - } - - ActivityData(ActivityData const &other) = delete; - ActivityData & operator=(ActivityData const &other) = delete; - - // returns true if the event was reported to telemetry - void NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT - { - if ((failure.hr != m_failure.GetFailureInfo().hr) && // don't replace with the same error (likely propagation up the stack) - ((failure.hr != m_result) || SUCCEEDED(m_result))) // don't replace if we've already got the current explicitly supplied failure code - { - m_failure.SetFailureInfo(failure); - } - } - - rwlock_release_exclusive_scope_exit LockExclusive() WI_NOEXCEPT - { - return m_lock.lock_exclusive(); - } - - static TraceLoggingHProvider Provider() - { - return ActivityTraceLoggingType::Provider(); - } - - WI_NODISCARD bool NeedsStopped() const WI_NOEXCEPT - { - return BaseTy::IsStarted(); - } - - void SetRelatedActivityId(const GUID* relatedId) - { - this->SetRelatedId(*relatedId); - } - - bool SetStopResult(HRESULT hr, _Out_opt_ HRESULT *phr) WI_NOEXCEPT - { - // We must be expecting at least one Stop -- otherwise the caller is calling Stop() more times - // than it can (normally once, or +1 for each call to Split()) - __FAIL_FAST_IMMEDIATE_ASSERT__(m_stopCountExpected >= 1); - if (SUCCEEDED(m_result)) - { - m_result = hr; - } - if (phr != nullptr) - { - *phr = m_result; - } - return ((--m_stopCountExpected) == 0); - } - - HRESULT SetUnhandledException() WI_NOEXCEPT - { - HRESULT hr = m_failure.GetFailureInfo().hr; - SetStopResult(FAILED(hr) ? hr : HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), &hr); - return hr; - } - - void IncrementExpectedStopCount() WI_NOEXCEPT - { - m_stopCountExpected++; - } - - WI_NODISCARD FailureInfo const* GetFailureInfo() const WI_NOEXCEPT - { - return (FAILED(m_result) && (m_result == m_failure.GetFailureInfo().hr)) ? &m_failure.GetFailureInfo() : nullptr; - } - - WI_NODISCARD inline HRESULT GetResult() const WI_NOEXCEPT - { - return m_result; - } - - details::StoredCallContextInfo *GetCallContext() WI_NOEXCEPT - { - return &m_callContext; - } - - private: - details::StoredCallContextInfo m_callContext; - HRESULT m_result; - StoredFailureInfo m_failure; - int m_stopCountExpected; - wil::srwlock m_lock; - }; - - mutable ActivityData m_activityData; - mutable ActivityData *m_pActivityData; - mutable details::shared_object> m_sharedActivityData; - mutable details::ThreadFailureCallbackHolder m_callbackHolder; - }; - -} // namespace wil - - -// Internal MACRO implementation of Activities. -// Do NOT use these macros directly. - -#define __WI_TraceLoggingWriteStart(activity, name, ...) \ - __pragma(warning(push)) __pragma(warning(disable:4127)) \ - do { \ - _tlgActivityDecl(activity) \ - static const UINT64 _tlgActivity_Keyword = _tlgActivityRef(activity).Keyword;\ - static const UINT8 _tlgActivity_Level = _tlgActivityRef(activity).Level;\ - static const UINT64 _tlgActivityPrivacyTag = _tlgActivityRef(activity).PrivacyTag;\ - static_assert( \ - _tlgActivity_Keyword == (_tlgActivity_Keyword _tlg_FOREACH(_tlgKeywordVal, __VA_ARGS__)), \ - "Do not use TraceLoggingKeyword in TraceLoggingWriteStart. Keywords for START events are " \ - "specified in the activity type, e.g. TraceLoggingActivity."); \ - static_assert( \ - _tlgActivity_Level == (_tlgActivity_Level _tlg_FOREACH(_tlgLevelVal, __VA_ARGS__)), \ - "Do not use TraceLoggingLevel in TraceLoggingWriteStart. The Level for START events is " \ - "specified in the activity type, e.g. TraceLoggingActivity."); \ - _tlgActivityRef(activity).zInternalStart(); \ - TraceLoggingWriteActivity( \ - TraceLoggingType::Provider(), \ - (name), \ - _tlgActivityRef(activity).Id(), \ - _tlgActivityRef(activity).zInternalRelatedId(), \ - TraceLoggingOpcode(1 /* WINEVENT_OPCODE_START */), \ - TraceLoggingKeyword(_tlgActivity_Keyword), \ - TraceLoggingLevel(_tlgActivity_Level), \ - TelemetryPrivacyDataTag(_tlgActivityPrivacyTag), \ - TraceLoggingDescription("~^" _wiltlg_LSTRINGIZE(activity) L"^~"), \ - __VA_ARGS__); \ - } while(0) \ - __pragma(warning(pop)) \ - -#define __WRITE_ACTIVITY_START(EventId, ...) \ - __TRACELOGGING_TEST_HOOK_ACTIVITY_START(); \ - __WI_TraceLoggingWriteStart(*this, #EventId, __ACTIVITY_START_PARAMS(), __VA_ARGS__); \ - EnsureWatchingCurrentThread() - -#define __WI_TraceLoggingWriteStop(activity, name, ...) \ - __pragma(warning(push)) __pragma(warning(disable:4127)) \ - do { \ - _tlgActivityDecl(activity) \ - static const UINT64 _tlgActivity_Keyword = _tlgActivityRef(activity).Keyword;\ - static const UINT8 _tlgActivity_Level = _tlgActivityRef(activity).Level;\ - static const UINT64 _tlgActivityPrivacyTag = _tlgActivityRef(activity).PrivacyTag;\ - static_assert( \ - _tlgActivity_Keyword == (_tlgActivity_Keyword _tlg_FOREACH(_tlgKeywordVal, __VA_ARGS__)), \ - "Do not use TraceLoggingKeyword in TraceLoggingWriteStop. Keywords for STOP events are " \ - "specified in the activity type, e.g. TraceLoggingActivity."); \ - static_assert( \ - _tlgActivity_Level == (_tlgActivity_Level _tlg_FOREACH(_tlgLevelVal, __VA_ARGS__)), \ - "Do not use TraceLoggingLevel in TraceLoggingWriteStop. The Level for STOP events is " \ - "specified in the activity type, e.g. TraceLoggingActivity."); \ - _tlgActivityRef(activity).zInternalStop(); \ - TraceLoggingWriteActivity( \ - TraceLoggingType::Provider(), \ - (name), \ - _tlgActivityRef(activity).Id(), \ - NULL, \ - TraceLoggingOpcode(2 /* WINEVENT_OPCODE_STOP */),\ - TraceLoggingKeyword(_tlgActivity_Keyword),\ - TraceLoggingLevel(_tlgActivity_Level),\ - TelemetryPrivacyDataTag(_tlgActivityPrivacyTag), \ - TraceLoggingDescription("~^" _wiltlg_LSTRINGIZE(activity) L"^~"),\ - __VA_ARGS__); \ - } while(0) \ - __pragma(warning(pop)) \ - -#define __WRITE_ACTIVITY_STOP(EventId, ...) \ - wil::FailureInfo const* pFailure = GetFailureInfo(); \ - if (pFailure != nullptr) \ - { \ - __TRACELOGGING_TEST_HOOK_ACTIVITY_STOP(pFailure, pFailure->hr); \ - auto &failure = *pFailure; \ - if (false, WI_IsAnyFlagSet(Keyword, (MICROSOFT_KEYWORD_TELEMETRY | MICROSOFT_KEYWORD_MEASURES | MICROSOFT_KEYWORD_CRITICAL_DATA))) \ - { \ - __WI_TraceLoggingWriteStop(*this, #EventId, __ACTIVITY_STOP_TELEMETRY_FAILURE_PARAMS(failure), __VA_ARGS__); \ - } \ - else \ - { \ - __WI_TraceLoggingWriteStop(*this, #EventId, __ACTIVITY_STOP_TRACELOGGING_FAILURE_PARAMS(failure), __VA_ARGS__); \ - } \ - } \ - else \ - { \ - __TRACELOGGING_TEST_HOOK_ACTIVITY_STOP(nullptr, GetResult()); \ - __WI_TraceLoggingWriteStop(*this, #EventId, __ACTIVITY_STOP_PARAMS(GetResult()), __VA_ARGS__); \ - } \ - IgnoreCurrentThread(); - -// optional params are: KeyWord, Level, PrivacyTags, Options -#define __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, ...) \ - class ActivityClassName final : public wil::ActivityBase \ - { \ - protected: \ - void StopActivity() WI_NOEXCEPT override \ - { __WRITE_ACTIVITY_STOP(ActivityClassName); } \ - bool WasAlreadyReportedToTelemetry(long failureId) WI_NOEXCEPT override \ - { return TraceLoggingType::WasAlreadyReportedToTelemetry(failureId); } \ - public: \ - static bool IsEnabled() WI_NOEXCEPT \ - { return TraceLoggingType::IsEnabled(); } \ - ~ActivityClassName() WI_NOEXCEPT { ActivityBase::Destroy(); } \ - ActivityClassName(ActivityClassName const &other) WI_NOEXCEPT : ActivityBase(other) {} \ - ActivityClassName(ActivityClassName &&other) WI_NOEXCEPT : ActivityBase(wistd::move(other)) {} \ - ActivityClassName(ActivityClassName &&other, bool shouldWatchErrors) WI_NOEXCEPT : ActivityBase(wistd::move(other), shouldWatchErrors) {} \ - ActivityClassName& operator=(ActivityClassName const &other) WI_NOEXCEPT \ - { ActivityBase::operator=(other); return *this; } \ - ActivityClassName& operator=(ActivityClassName &&other) WI_NOEXCEPT \ - { auto localActivity(wistd::move(*this)); ActivityBase::operator=(wistd::move(other)); return *this; } \ - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT \ - { return IsRunning(); } \ - void StopWithResult(HRESULT hr) \ - { ActivityBase::Stop(hr); } \ - template \ - void StopWithResult(HRESULT hr, TArgs&&... args) \ - { SetStopResult(hr); Stop(wistd::forward(args)...); } \ - void Stop(HRESULT hr = S_OK) WI_NOEXCEPT \ - { ActivityBase::Stop(hr); } \ - void StartActivity() WI_NOEXCEPT \ - { __WRITE_ACTIVITY_START(ActivityClassName); } \ - void StartRelatedActivity() WI_NOEXCEPT \ - { wil::details::SetRelatedActivityId(*this); StartActivity(); } \ - void StartActivityWithCorrelationVector(PCSTR correlationVector) WI_NOEXCEPT \ - { __WRITE_ACTIVITY_START(ActivityClassName, TraceLoggingString(correlationVector, "__TlgCV__")); } \ - WI_NODISCARD ActivityClassName Split() WI_NOEXCEPT \ - { __FAIL_FAST_IMMEDIATE_ASSERT__(IsRunning()); IncrementExpectedStopCount(); return ActivityClassName(*this); } \ - WI_NODISCARD ActivityClassName TransferToCurrentThread() WI_NOEXCEPT \ - { return ActivityClassName(wistd::move(*this), IsRunning()); } \ - WI_NODISCARD ActivityClassName TransferToMember() WI_NOEXCEPT \ - { return ActivityClassName(wistd::move(*this), false); } - -#define __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) \ - private: \ - template \ - ActivityClassName(wil::details::tag_start, TArgs&&... args) WI_NOEXCEPT : ActivityBase(#ActivityClassName) \ - { StartActivity(wistd::forward(args)...); \ - __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK("this", ActivityClassName); } \ - template \ - ActivityClassName(wil::details::tag_start_cv, _In_opt_ PCSTR correlationVector, TArgs&&... args) WI_NOEXCEPT : ActivityBase(#ActivityClassName) \ - { StartActivityWithCorrelationVector(correlationVector, wistd::forward(args)...); \ - __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK("this", ActivityClassName); } \ - public: \ - ActivityClassName() WI_NOEXCEPT : ActivityBase(#ActivityClassName, false) {} \ - template \ - WI_NODISCARD static ActivityClassName Start(TArgs&&... args) \ - { return ActivityClassName(wil::details::tag_start(), wistd::forward(args)...); } \ - template \ - WI_NODISCARD static ActivityClassName StartWithCorrelationVector(_In_ PCSTR correlationVector, TArgs&&... args) \ - { return ActivityClassName(wil::details::tag_start_cv(), correlationVector, wistd::forward(args)...); } - -#define __IMPLEMENT_CALLCONTEXT_CLASS(ActivityClassName) \ - protected: \ - ActivityClassName(_In_opt_ void **, PCSTR contextName, _In_opt_ _Printf_format_string_ PCSTR formatString, _In_opt_ va_list argList) : \ - ActivityBase(contextName) \ - { GetCallContext()->SetMessage(formatString, argList); StartActivity(); } \ - ActivityClassName(_In_opt_ void **, PCSTR contextName) : \ - ActivityBase(contextName) \ - { StartActivity(); } \ - public: \ - ActivityClassName(PCSTR contextName) : ActivityBase(contextName, false) {} \ - ActivityClassName(PCSTR contextName, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT : ActivityClassName(contextName) \ - { va_list argList; va_start(argList, formatString); GetCallContext()->SetMessage(formatString, argList); } \ - WI_NODISCARD static ActivityClassName Start(PCSTR contextName) WI_NOEXCEPT \ - { return ActivityClassName(static_cast(__nullptr), contextName); } \ - WI_NODISCARD static ActivityClassName Start(PCSTR contextName, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ - { va_list argList; va_start(argList, formatString); return ActivityClassName(static_cast(__nullptr), contextName, formatString, argList); } - -#define __END_TRACELOGGING_ACTIVITY_CLASS() \ - }; - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, ...) \ - void EventId() \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, _GENERIC_PARTB_FIELDS_ENABLED, __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, ...) \ - void EventId() \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_CV(EventId, ...) \ - void EventId(PCSTR correlationVector) \ - { __WI_TraceLoggingWriteTagged(*this, #EventId, _GENERIC_PARTB_FIELDS_ENABLED, TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_CV(EventId, ...) \ - void EventId(PCSTR correlationVector) \ - { __WI_TraceLoggingWriteTagged(*this, #EventId, TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, ...) \ - template void EventId(T1 &&varName1) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, ...) \ - template void EventId(T1 &&varName1) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, ...) \ - template void EventId(T1 &&varName1, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, ...) \ - template void EventId(T1 &&varName1, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8, PCSTR correlationVector) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8, T9 &&varName9) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, ...) \ - template void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8, T9 &&varName9) \ - { \ - __WI_TraceLoggingWriteTagged(*this, #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - __VA_ARGS__); \ - } -#endif - -#define DEFINE_TAGGED_TRACELOGGING_EVENT_UINT32(EventId, varName, ...) DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, UINT32, varName, __VA_ARGS__) -#define DEFINE_TAGGED_TRACELOGGING_EVENT_BOOL(EventId, varName, ...) DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, bool, varName, __VA_ARGS__) -#define DEFINE_TAGGED_TRACELOGGING_EVENT_STRING(EventId, varName, ...) DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, PCWSTR, varName, __VA_ARGS__) - - -// Internal MACRO implementation of TraceLogging classes. -// Do NOT use these macros directly. - -#define __IMPLEMENT_TRACELOGGING_CLASS_BASE(TraceLoggingClassName, TraceLoggingProviderOwnerClassName) \ - public: \ - typedef TraceLoggingProviderOwnerClassName TraceLoggingType; \ - static bool IsEnabled(UCHAR eventLevel = 0 /* WINEVENT_LEVEL_XXX, e.g. WINEVENT_LEVEL_VERBOSE */, ULONGLONG eventKeywords = 0 /* MICROSOFT_KEYWORD_XXX */) WI_NOEXCEPT \ - { return Instance()->IsEnabled_(eventLevel, eventKeywords); } \ - static TraceLoggingHProvider Provider() WI_NOEXCEPT \ - { return static_cast(Instance())->Provider_(); } \ - static void SetTelemetryEnabled(bool) WI_NOEXCEPT {} \ - static void SetErrorReportingType(wil::ErrorReportingType type) WI_NOEXCEPT \ - { return Instance()->SetErrorReportingType_(type); } \ - static void __stdcall FallbackTelemetryCallback(bool alreadyReported, wil::FailureInfo const &failure) WI_NOEXCEPT \ - { return Instance()->OnErrorReported(alreadyReported, failure); } \ - WI_NODISCARD static wil::ActivityThreadWatcher WatchCurrentThread(PCSTR contextName) WI_NOEXCEPT \ - { return wil::ActivityThreadWatcher(Instance(), contextName); } \ - WI_NODISCARD static wil::ActivityThreadWatcher WatchCurrentThread(PCSTR contextName, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ - { va_list argList; va_start(argList, formatString); return wil::ActivityThreadWatcher(Instance(), contextName, formatString, argList); } \ - __BEGIN_TRACELOGGING_ACTIVITY_CLASS(CallContext, wil::ActivityOptions::TelemetryOnFailure) \ - __IMPLEMENT_CALLCONTEXT_CLASS(CallContext); \ - __END_TRACELOGGING_ACTIVITY_CLASS(); \ - static CallContext Start(PCSTR contextName) WI_NOEXCEPT \ - { return CallContext(contextName, __nullptr, __nullptr); } \ - static CallContext Start(PCSTR contextName, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ - { va_list argList; va_start(argList, formatString); return CallContext(contextName, formatString, argList); } \ - static void TraceLoggingInfo(_Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ - { va_list argList; va_start(argList, formatString); return Instance()->ReportTraceLoggingMessage(formatString, argList); } \ - static void TraceLoggingError(_Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT \ - { va_list argList; va_start(argList, formatString); return Instance()->ReportTraceLoggingError(formatString, argList); } \ - private: \ - TraceLoggingHProvider Provider_() const WI_NOEXCEPT = delete; \ - TraceLoggingClassName() WI_NOEXCEPT {}; \ - protected: \ - static TraceLoggingClassName* Instance() WI_NOEXCEPT \ - { static wil::details::static_lazy wrapper; return wrapper.get([](){wrapper.cleanup();}); } \ - friend class wil::details::static_lazy; \ - - -#define __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, TraceLoggingOption) \ - __IMPLEMENT_TRACELOGGING_CLASS_BASE(TraceLoggingClassName, TraceLoggingClassName) \ - private: \ - struct StaticHandle \ - { \ - TraceLoggingHProvider handle; \ - StaticHandle() WI_NOEXCEPT \ - { \ - TRACELOGGING_DEFINE_PROVIDER_STORAGE(__hInner, ProviderName, ProviderId, TraceLoggingOption); \ - _tlg_DefineProvider_annotation(TraceLoggingClassName, _Tlg##TraceLoggingClassName##Prov, 0, ProviderName); \ - handle = &__hInner; \ - } \ - } m_staticHandle; \ - protected: \ - void Create() WI_NOEXCEPT \ - { Register(m_staticHandle.handle); } \ - public: - -#define __IMPLEMENT_TRACELOGGING_CLASS(TraceLoggingClassName, ProviderName, ProviderId) \ - __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, TraceLoggingOptionMicrosoftTelemetry()) - -#define __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB(TraceLoggingClassName, ProviderName, ProviderId, TraceLoggingOption) \ - __IMPLEMENT_TRACELOGGING_CLASS_BASE(TraceLoggingClassName, TraceLoggingClassName) \ - private: \ - struct StaticHandle \ - { \ - TraceLoggingHProvider handle; \ - StaticHandle() WI_NOEXCEPT \ - { \ - TRACELOGGING_DEFINE_PROVIDER_STORAGE(__hInner, ProviderName, ProviderId, TraceLoggingOption); \ - _tlg_DefineProvider_annotation(TraceLoggingClassName, _Tlg##TraceLoggingClassName##Prov, 0, ProviderName); \ - handle = &__hInner; \ - } \ - } m_staticHandle; \ - static VOID NTAPI Callback( _In_ const GUID* SourceId, \ - ULONG ControlCode, \ - UCHAR Level, \ - ULONGLONG MatchAnyKeyword, \ - ULONGLONG MatchAllKeyword, \ - _In_opt_ EVENT_FILTER_DESCRIPTOR* FilterData, \ - void* CallbackContext ); \ - protected: \ - void Create() WI_NOEXCEPT \ - { Register(m_staticHandle.handle, &TraceLoggingClassName::Callback); } \ - public: - - -#define __IMPLEMENT_TRACELOGGING_CLASS_WITHOUT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) \ - __IMPLEMENT_TRACELOGGING_CLASS_BASE(TraceLoggingClassName, TraceLoggingClassName) \ - private: \ - struct StaticHandle \ - { \ - TraceLoggingHProvider handle; \ - StaticHandle() WI_NOEXCEPT \ - { \ - TRACELOGGING_DEFINE_PROVIDER_STORAGE(__hInner, ProviderName, ProviderId); \ - _tlg_DefineProvider_annotation(TraceLoggingClassName, _Tlg##TraceLoggingClassName##Prov, 0, ProviderName); \ - handle = &__hInner; \ - } \ - } m_staticHandle; \ - protected: \ - void Create() WI_NOEXCEPT \ - { Register(m_staticHandle.handle); } \ - public: - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT(EventId, ...) \ - static void EventId() { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT(EventId, ...) \ - static void EventId() { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_CV(EventId, ...) \ - static void EventId(PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_CV(EventId, ...) \ - static void EventId(PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, ...) \ - template static void EventId(T1 &&varName1) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, ...) \ - template static void EventId(T1 &&varName1) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, ...) \ - template static void EventId(T1 &&varName1, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, ...) \ - template static void EventId(T1 &&varName1, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8, T9 &&varName9) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8, T9 &&varName9) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM9_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8, T9 &&varName9, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM9_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8, T9 &&varName9, PCSTR correlationVector) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - TraceLoggingString(correlationVector, "__TlgCV__"), __VA_ARGS__); \ - } -#endif - -#ifdef _GENERIC_PARTB_FIELDS_ENABLED - #define DEFINE_TRACELOGGING_EVENT_PARAM10(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, VarType10, varName10, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8, T9 &&varName9, T10 &&varName10) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - TraceLoggingValue(static_cast(wistd::forward(varName10)), _wiltlg_STRINGIZE(varName10)), \ - _GENERIC_PARTB_FIELDS_ENABLED, \ - __VA_ARGS__); \ - } -#else - #define DEFINE_TRACELOGGING_EVENT_PARAM10(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, VarType10, varName10, ...) \ - template static void EventId(T1 &&varName1, T2 &&varName2, T3 &&varName3, T4 &&varName4, T5 &&varName5, T6 &&varName6, T7 &&varName7, T8 &&varName8, T9 &&varName9, T10 &&varName10) \ - { \ - TraceLoggingWrite(TraceLoggingType::Provider(), #EventId, \ - TraceLoggingValue(static_cast(wistd::forward(varName1)), _wiltlg_STRINGIZE(varName1)), \ - TraceLoggingValue(static_cast(wistd::forward(varName2)), _wiltlg_STRINGIZE(varName2)), \ - TraceLoggingValue(static_cast(wistd::forward(varName3)), _wiltlg_STRINGIZE(varName3)), \ - TraceLoggingValue(static_cast(wistd::forward(varName4)), _wiltlg_STRINGIZE(varName4)), \ - TraceLoggingValue(static_cast(wistd::forward(varName5)), _wiltlg_STRINGIZE(varName5)), \ - TraceLoggingValue(static_cast(wistd::forward(varName6)), _wiltlg_STRINGIZE(varName6)), \ - TraceLoggingValue(static_cast(wistd::forward(varName7)), _wiltlg_STRINGIZE(varName7)), \ - TraceLoggingValue(static_cast(wistd::forward(varName8)), _wiltlg_STRINGIZE(varName8)), \ - TraceLoggingValue(static_cast(wistd::forward(varName9)), _wiltlg_STRINGIZE(varName9)), \ - TraceLoggingValue(static_cast(wistd::forward(varName10)), _wiltlg_STRINGIZE(varName10)), \ - __VA_ARGS__); \ - } -#endif - -#define DEFINE_TRACELOGGING_EVENT_UINT32(EventId, varName, ...) DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, UINT32, varName, __VA_ARGS__) -#define DEFINE_TRACELOGGING_EVENT_BOOL(EventId, varName, ...) DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, bool, varName, __VA_ARGS__) -#define DEFINE_TRACELOGGING_EVENT_STRING(EventId, varName, ...) DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, PCWSTR, varName, __VA_ARGS__) - - -// Declaring a pure TraceLogging class -// To declare a tracelogging class, declare your class derived from wil::TraceLoggingProvider, populate the uuid -// attribute of the class with the GUID of your provider, and then include the IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY -// macro within your class. -// -// If you want to register a provider using a callback to log events, you can instead use the IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY_AND_CALLBACK -// Additionally your tracelogging class will have to implement a static Callback method. See the declaration within __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB. -// -// If you don't need or use telemetry, you can instead use the IMPLEMENT_TRACELOGGING_CLASS_WITHOUT_TELEMETRY. -// This prevents telemetry from enabling your provider even if you're not using telemetry. - -#define IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, GroupName) \ - __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, GroupName) - -#define IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB(TraceLoggingClassName, ProviderName, ProviderId, GroupName) \ - __IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB(TraceLoggingClassName, ProviderName, ProviderId, GroupName) - -#define IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) \ - IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, TraceLoggingOptionMicrosoftTelemetry()) -#define IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY_AND_CALLBACK(TraceLoggingClassName, ProviderName, ProviderId) \ - IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP_CB(TraceLoggingClassName, ProviderName, ProviderId, TraceLoggingOptionMicrosoftTelemetry()) -#define IMPLEMENT_TRACELOGGING_CLASS_WITH_WINDOWS_CORE_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) \ - IMPLEMENT_TRACELOGGING_CLASS_WITH_GROUP(TraceLoggingClassName, ProviderName, ProviderId, TraceLoggingOptionWindowsCoreTelemetry()) -#define IMPLEMENT_TRACELOGGING_CLASS_WITHOUT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) \ - __IMPLEMENT_TRACELOGGING_CLASS_WITHOUT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId) - -#ifndef WIL_HIDE_DEPRECATED_1612 -WIL_WARN_DEPRECATED_1612_PRAGMA("IMPLEMENT_TRACELOGGING_CLASS") -// DEPRECATED: Use IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY -#define IMPLEMENT_TRACELOGGING_CLASS IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY -#endif - -// [Optional] Externally using a Tracelogging class -// Use TraceLoggingProviderWrite to directly use the trace logging provider externally from the class in code. -// This is recommended only for simple TraceLogging events. Telemetry events and activities are better defined -// within your Tracelogging class using one of the macros below. - -#define TraceLoggingProviderWrite(TraceLoggingClassName, EventId, ...) \ - TraceLoggingWrite(TraceLoggingClassName::TraceLoggingType::Provider(), EventId, __VA_ARGS__) - -#define TraceLoggingProviderWriteTelemetry(TraceLoggingClassName, EventId, ...) \ - TraceLoggingWrite(TraceLoggingClassName::TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), __VA_ARGS__) - -#define TraceLoggingProviderWriteMeasure(TraceLoggingClassName, EventId, ...) \ - TraceLoggingWrite(TraceLoggingClassName::TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), __VA_ARGS__) - -#define TraceLoggingProviderWriteCriticalData(TraceLoggingClassName, EventId, ...) \ - TraceLoggingWrite(TraceLoggingClassName::TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), __VA_ARGS__) - - -// [Optional] Custom Events -// Use these macros to define a Custom Event for a Provider. Use the TraceLoggingClassWrite or TraceLoggingClassWriteTelemetry -// from within a custom event to issue the event. Methods will be a no-op (and not be called) if the provider is not -// enabled. - -#define TraceLoggingClassWrite(EventId, ...) \ - TraceLoggingWrite(TraceLoggingType::Provider(), EventId, __VA_ARGS__) - -#define TraceLoggingClassWriteTelemetry(EventId, ...) \ - TraceLoggingWrite(TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), __VA_ARGS__) - -#define TraceLoggingClassWriteMeasure(EventId, ...) \ - TraceLoggingWrite(TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), __VA_ARGS__) - -#define TraceLoggingClassWriteCriticalData(EventId, ...) \ - TraceLoggingWrite(TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), __VA_ARGS__) - -#define DEFINE_EVENT_METHOD(MethodName) \ - template \ - static void MethodName(TArgs&&... args) WI_NOEXCEPT \ - { \ - if (IsEnabled()) \ - { Instance()->MethodName##_(wistd::forward(args)...); } \ - } \ - void MethodName##_ - - -// [Optional] Simple Events -// Use these macros to define very simple telemetry events for a Provider. The events can -// be TELEMETRY events or TRACELOGGING events. - -#define DEFINE_TELEMETRY_EVENT(EventId) \ - DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) - -#define DEFINE_TELEMETRY_EVENT_PARAM1(EventId, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) - -#define DEFINE_TELEMETRY_EVENT_CV(EventId) \ - DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TELEMETRY_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) - -#define DEFINE_TELEMETRY_EVENT_UINT32(EventId, varName) DEFINE_TELEMETRY_EVENT_PARAM1(EventId, UINT32, varName) -#define DEFINE_TELEMETRY_EVENT_BOOL(EventId, varName) DEFINE_TELEMETRY_EVENT_PARAM1(EventId, bool, varName) -#define DEFINE_TELEMETRY_EVENT_STRING(EventId, varName) DEFINE_TELEMETRY_EVENT_PARAM1(EventId, PCWSTR, varName) - -#define DEFINE_COMPLIANT_TELEMETRY_EVENT(EventId, PrivacyTag) \ - DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) - -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM4(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM5(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM6(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM7(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM8(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) - -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_CV(EventId, PrivacyTag) \ - DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM1_CV(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM2_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM3_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM4_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM5_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM6_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM7_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM8_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) - -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_CV(EventId, PrivacyTag, EventTag) \ - DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM1_CV(EventId, PrivacyTag, EventTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM2_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM3_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM4_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM5_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM6_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM7_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_TELEMETRY_EVENT_PARAM8_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) - -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_UINT32(EventId, PrivacyTag, varName) DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, UINT32, varName) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_BOOL(EventId, PrivacyTag, varName) DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, bool, varName) -#define DEFINE_COMPLIANT_TELEMETRY_EVENT_STRING(EventId, PrivacyTag, varName) DEFINE_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, PCWSTR, varName) - -// [Optional] Simple Events -// Use these macros to define very simple measure events for a Provider. - -#define DEFINE_MEASURES_EVENT(EventId) \ - DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM1(EventId, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) - -#define DEFINE_MEASURES_EVENT_CV(EventId) \ - DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_MEASURES_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) - -#define DEFINE_MEASURES_EVENT_UINT32(EventId, varName) DEFINE_MEASURES_EVENT_PARAM1(EventId, UINT32, varName) -#define DEFINE_MEASURES_EVENT_BOOL(EventId, varName) DEFINE_MEASURES_EVENT_PARAM1(EventId, bool, varName) -#define DEFINE_MEASURES_EVENT_STRING(EventId, varName) DEFINE_MEASURES_EVENT_PARAM1(EventId, PCWSTR, varName) - -#define DEFINE_COMPLIANT_MEASURES_EVENT(EventId, PrivacyTag) \ - DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM4(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM5(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM6(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM7(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM8(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM9(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9) \ - DEFINE_TRACELOGGING_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM10(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, VarType10, varName10) \ - DEFINE_TRACELOGGING_EVENT_PARAM10(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, VarType10, varName10, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) - -#define DEFINE_COMPLIANT_MEASURES_EVENT_CV(EventId, PrivacyTag) \ - DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM1_CV(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM2_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM3_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM4_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM5_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM6_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM7_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_MEASURES_EVENT_PARAM8_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) - -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_CV(EventId, PrivacyTag, EventTag) \ - DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM1_CV(EventId, PrivacyTag, EventTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM2_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM3_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM4_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM5_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM6_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM7_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM8_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_MEASURES_EVENT_PARAM9_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9) \ - DEFINE_TRACELOGGING_EVENT_PARAM9_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) - -#define DEFINE_COMPLIANT_MEASURES_EVENT_UINT32(EventId, PrivacyTag, varName) DEFINE_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, UINT32, varName) -#define DEFINE_COMPLIANT_MEASURES_EVENT_BOOL(EventId, PrivacyTag, varName) DEFINE_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, bool, varName) -#define DEFINE_COMPLIANT_MEASURES_EVENT_STRING(EventId, PrivacyTag, varName) DEFINE_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, PCWSTR, varName) - -// [Optional] Simple Events -// Use these macros to define very simple critical data events for a Provider. - -#define DEFINE_CRITICAL_DATA_EVENT(EventId) \ - DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM1(EventId, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) - -#define DEFINE_CRITICAL_DATA_EVENT_CV(EventId) \ - DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_CRITICAL_DATA_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) - -#define DEFINE_CRITICAL_DATA_EVENT_UINT32(EventId, varName) DEFINE_CRITICAL_DATA_EVENT_PARAM1(EventId, UINT32, varName) -#define DEFINE_CRITICAL_DATA_EVENT_BOOL(EventId, varName) DEFINE_CRITICAL_DATA_EVENT_PARAM1(EventId, bool, varName) -#define DEFINE_CRITICAL_DATA_EVENT_STRING(EventId, varName) DEFINE_CRITICAL_DATA_EVENT_PARAM1(EventId, PCWSTR, varName) - -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT(EventId, PrivacyTag) \ - DEFINE_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM4(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM5(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM6(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM7(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM8(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) - -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_CV(EventId, PrivacyTag) \ - DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1_CV(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM2_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM3_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM4_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM5_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM6_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM7_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM8_CV(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) - -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_CV(EventId, PrivacyTag, EventTag) \ - DEFINE_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM1_CV(EventId, PrivacyTag, EventTag, VarType1, varName1) \ - DEFINE_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM2_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM3_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM4_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM5_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM6_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM7_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM8_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) -#define DEFINE_COMPLIANT_EVENTTAGGED_CRITICAL_DATA_EVENT_PARAM9_CV(EventId, PrivacyTag, EventTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9) \ - DEFINE_TRACELOGGING_EVENT_PARAM9_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag), TraceLoggingEventTag(EventTag)) - -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_UINT32(EventId, PrivacyTag, varName) DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, UINT32, varName) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_BOOL(EventId, PrivacyTag, varName) DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, bool, varName) -#define DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_STRING(EventId, PrivacyTag, varName) DEFINE_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, PCWSTR, varName) - -// Custom Activities -// For these you pair the appropriate BEGIN and END macros to define your activity. Within the pair -// you can use the (TODO: LIST MACRO NAMES) macros to add behavior. - -// [optional] params are: Options, Keyword, Level, PrivacyTag -#define BEGIN_CUSTOM_ACTIVITY_CLASS(ActivityClassName, ...) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, __VA_ARGS__) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) - -// [optional] param is: Level, PrivacyTag -#define BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_TRACELOGGING_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::None, 0, Level) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::None, 0, WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_TRACELOGGING_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::None, 0, Level, PrivacyTag) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) - -// [optional] param is: Level -#define BEGIN_CALLCONTEXT_ACTIVITY_CLASS(ActivityClassName) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_CALLCONTEXT_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, 0, Level) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_CALLCONTEXT_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, 0, WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_CALLCONTEXT_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, 0, Level, PrivacyTag) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) - -// [optional] param is: Level -#define BEGIN_TELEMETRY_ACTIVITY_CLASS(ActivityClassName) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_TELEMETRY) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_TELEMETRY_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_TELEMETRY, Level) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_TELEMETRY_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_TELEMETRY, WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_TELEMETRY_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_TELEMETRY, Level, PrivacyTag) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) - -// [optional] param is: Level -#define BEGIN_MEASURES_ACTIVITY_CLASS(ActivityClassName) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_MEASURES) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_MEASURES_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_MEASURES, Level) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_MEASURES, WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_MEASURES, Level, PrivacyTag) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) - -// [optional] param is: Level -#define BEGIN_CRITICAL_DATA_ACTIVITY_CLASS(ActivityClassName) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_CRITICAL_DATA) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_CRITICAL_DATA_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_CRITICAL_DATA, Level) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_CRITICAL_DATA_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_CRITICAL_DATA, WINEVENT_LEVEL_VERBOSE, PrivacyTag) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) -#define BEGIN_COMPLIANT_CRITICAL_DATA_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) __BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName, wil::ActivityOptions::TelemetryOnFailure, MICROSOFT_KEYWORD_CRITICAL_DATA, Level, PrivacyTag) \ - __IMPLEMENT_ACTIVITY_CLASS(ActivityClassName) - -// Use to end ALL activity class definitions -#define END_ACTIVITY_CLASS() __END_TRACELOGGING_ACTIVITY_CLASS() - - -// Simple Activities -// For these you just use the appropriate macro to define the KIND of activity you want and specify -// the name (for tracelogging you can give other options) - -// [optional] params are: Options, Keyword, Level -#define DEFINE_CUSTOM_ACTIVITY(ActivityClassName, ...) \ - BEGIN_CUSTOM_ACTIVITY_CLASS(ActivityClassName, __VA_ARGS__) \ - END_ACTIVITY_CLASS() - -#define DEFINE_TRACELOGGING_ACTIVITY(ActivityClassName) \ - BEGIN_TRACELOGGING_ACTIVITY_CLASS(ActivityClassName) \ - END_ACTIVITY_CLASS() -#define DEFINE_TRACELOGGING_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ - BEGIN_TRACELOGGING_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ - END_ACTIVITY_CLASS() - -#define DEFINE_CALLCONTEXT_ACTIVITY(ActivityClassName) \ - BEGIN_CALLCONTEXT_ACTIVITY_CLASS(ActivityClassName) \ - END_ACTIVITY_CLASS() -#define DEFINE_CALLCONTEXT_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ - BEGIN_CALLCONTEXT_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ - END_ACTIVITY_CLASS() - -#define DEFINE_TELEMETRY_ACTIVITY(ActivityClassName) \ - BEGIN_TELEMETRY_ACTIVITY_CLASS(ActivityClassName) \ - END_ACTIVITY_CLASS() -#define DEFINE_TELEMETRY_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ - BEGIN_TELEMETRY_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ - END_ACTIVITY_CLASS() -#define DEFINE_COMPLIANT_TELEMETRY_ACTIVITY(ActivityClassName, PrivacyTag) \ - BEGIN_COMPLIANT_TELEMETRY_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ - END_ACTIVITY_CLASS() -#define DEFINE_COMPLIANT_TELEMETRY_ACTIVITY_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - BEGIN_COMPLIANT_TELEMETRY_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - END_ACTIVITY_CLASS() - -#define DEFINE_MEASURES_ACTIVITY(ActivityClassName) \ - BEGIN_MEASURES_ACTIVITY_CLASS(ActivityClassName) \ - END_ACTIVITY_CLASS() -#define DEFINE_MEASURES_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ - BEGIN_MEASURES_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ - END_ACTIVITY_CLASS() -#define DEFINE_COMPLIANT_MEASURES_ACTIVITY(ActivityClassName, PrivacyTag) \ - BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ - END_ACTIVITY_CLASS() -#define DEFINE_COMPLIANT_MEASURES_ACTIVITY_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - BEGIN_COMPLIANT_MEASURES_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - END_ACTIVITY_CLASS() - -#define DEFINE_CRITICAL_DATA_ACTIVITY(ActivityClassName) \ - BEGIN_CRITICAL_DATA_ACTIVITY_CLASS(ActivityClassName) \ - END_ACTIVITY_CLASS() -#define DEFINE_CRITICAL_DATA_ACTIVITY_WITH_LEVEL(ActivityClassName, Level) \ - BEGIN_CRITICAL_DATA_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, Level) \ - END_ACTIVITY_CLASS() -#define DEFINE_COMPLIANT_CRITICAL_DATA_ACTIVITY(ActivityClassName, PrivacyTag) \ - BEGIN_COMPLIANT_CRITICAL_DATA_ACTIVITY_CLASS(ActivityClassName, PrivacyTag) \ - END_ACTIVITY_CLASS() -#define DEFINE_COMPLIANT_CRITICAL_DATA_ACTIVITY_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - BEGIN_COMPLIANT_CRITICAL_DATA_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, PrivacyTag, Level) \ - END_ACTIVITY_CLASS() - - -// [Optional] Custom Start or Stop Events for Activities -// Use these macros to define custom start or custom stop methods for an activity. Any activity can -// have multiple start or stop methods. To add custom start or stop events, define a StartActivity instance -// method or a Stop instance method within the BEGIN/END pair of a custom activity. Within that function, use -// TraceLoggingClassWriteStart or TraceLoggingClassWriteStop. - -// Params: (EventId, ...) -#define TraceLoggingClassWriteStart __WRITE_ACTIVITY_START -#define TraceLoggingClassWriteStop __WRITE_ACTIVITY_STOP - - -// [Optional] Custom Tagged Events for Activities -// Use these macros to define a Custom Tagged Event for a Custom Activity. Use the -// TraceLoggingClassWriteTagged or TraceLoggingClassWriteTaggedTelemetry macros from within a custom event -// to write the event. - -#define TraceLoggingClassWriteTagged(EventId, ...) \ - __WI_TraceLoggingWriteTagged(*this, #EventId, __VA_ARGS__) - -#define TraceLoggingClassWriteTaggedTelemetry(EventId, ...) \ - __WI_TraceLoggingWriteTagged(*this, #EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), __VA_ARGS__) - -#define TraceLoggingClassWriteTaggedMeasure(EventId, ...) \ - __WI_TraceLoggingWriteTagged(*this, #EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), __VA_ARGS__) - -#define TraceLoggingClassWriteTaggedCriticalData(EventId, ...) \ - __WI_TraceLoggingWriteTagged(*this, #EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), __VA_ARGS__) - -// [Optional] Simple Tagged Events for Activities -// Use these methods to define very simple tagged events for a Custom Activity. - -#define DEFINE_TAGGED_TELEMETRY_EVENT(EventId) \ - DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1(EventId, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) - -#define DEFINE_TAGGED_TELEMETRY_EVENT_CV(EventId) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) -#define DEFINE_TAGGED_TELEMETRY_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY)) - -#define DEFINE_TAGGED_TELEMETRY_EVENT_UINT32(EventId, varName) DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1(EventId, UINT32, varName) -#define DEFINE_TAGGED_TELEMETRY_EVENT_BOOL(EventId, varName) DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1(EventId, bool, varName) -#define DEFINE_TAGGED_TELEMETRY_EVENT_STRING(EventId, varName) DEFINE_TAGGED_TELEMETRY_EVENT_PARAM1(EventId, PCWSTR, varName) - -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT(EventId, PrivacyTag) \ - DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM4(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM5(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM6(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM7(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM8(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), TelemetryPrivacyDataTag(PrivacyTag)) - -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_UINT32(EventId, PrivacyTag, varName) DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, UINT32, varName) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_BOOL(EventId, PrivacyTag, varName) DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, bool, varName) -#define DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_STRING(EventId, PrivacyTag, varName) DEFINE_TAGGED_COMPLIANT_TELEMETRY_EVENT_PARAM1(EventId, PrivacyTag, PCWSTR, varName) - -// [Optional] Simple Tagged Events for Activities -// Use these methods to define very simple tagged measures events for a Custom Activity. - -#define DEFINE_TAGGED_MEASURES_EVENT(EventId) \ - DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM1(EventId, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) - -#define DEFINE_TAGGED_MEASURES_EVENT_CV(EventId) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) -#define DEFINE_TAGGED_MEASURES_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)) - -#define DEFINE_TAGGED_MEASURES_EVENT_UINT32(EventId, varName) DEFINE_TAGGED_MEASURES_EVENT_PARAM1(EventId, UINT32, varName) -#define DEFINE_TAGGED_MEASURES_EVENT_BOOL(EventId, varName) DEFINE_TAGGED_MEASURES_EVENT_PARAM1(EventId, bool, varName) -#define DEFINE_TAGGED_MEASURES_EVENT_STRING(EventId, varName) DEFINE_TAGGED_MEASURES_EVENT_PARAM1(EventId, PCWSTR, varName) - -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT(EventId, PrivacyTag) \ - DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM4(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM5(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM6(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM7(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM8(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), TelemetryPrivacyDataTag(PrivacyTag)) - -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_UINT32(EventId, PrivacyTag, varName) DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, UINT32, varName) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_BOOL(EventId, PrivacyTag, varName) DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, bool, varName) -#define DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_STRING(EventId, PrivacyTag, varName) DEFINE_TAGGED_COMPLIANT_MEASURES_EVENT_PARAM1(EventId, PrivacyTag, PCWSTR, varName) - -// [Optional] Simple Tagged Events for Activities -// Use these methods to define very simple tagged CRITICAL_DATA events for a Custom Activity. - -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT(EventId) \ - DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM1(EventId, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM9(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, VarType9, varName9, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) - -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_CV(EventId) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_CV(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM1_CV(EventId, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1_CV(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2_CV(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8_CV(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)) - -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_UINT32(EventId, varName) DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM1(EventId, UINT32, varName) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_BOOL(EventId, varName) DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM1(EventId, bool, varName) -#define DEFINE_TAGGED_CRITICAL_DATA_EVENT_STRING(EventId, varName) DEFINE_TAGGED_CRITICAL_DATA_EVENT_PARAM1(EventId, PCWSTR, varName) - -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT(EventId, PrivacyTag) \ - DEFINE_TAGGED_TRACELOGGING_EVENT(EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, VarType1, varName1) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1(EventId, VarType1, varName1, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM2(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2(EventId, VarType1, varName1, VarType2, varName2, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM3(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM4(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM5(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM6(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM7(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM8(EventId, PrivacyTag, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8) \ - DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM8(EventId, VarType1, varName1, VarType2, varName2, VarType3, varName3, VarType4, varName4, VarType5, varName5, VarType6, varName6, VarType7, varName7, VarType8, varName8, TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA), TelemetryPrivacyDataTag(PrivacyTag)) - -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_UINT32(EventId, PrivacyTag, varName) DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, UINT32, varName) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_BOOL(EventId, PrivacyTag, varName) DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, bool, varName) -#define DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_STRING(EventId, PrivacyTag, varName) DEFINE_TAGGED_COMPLIANT_CRITICAL_DATA_EVENT_PARAM1(EventId, PrivacyTag, PCWSTR, varName) - -// Thread Activities [deprecated] -// These are desktop only and are not recommended by the fundamentals team. These activities lag behind regular activities in -// their ability to use CallContext or to be cross-thread portable, so their usage should be limited. - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD_LEVEL(ActivityClassName, keyword, level) \ - class ActivityClassName final : public _TlgActivityBase \ - { \ - static const UINT64 PrivacyTag = 0; \ - friend class _TlgActivityBase; \ - void OnStarted() { PushThreadActivityId(); } \ - void OnStopped() { PopThreadActivityId(); } \ - public: \ - ActivityClassName() : m_result(S_OK) \ - { \ - } \ - private: \ - template \ - ActivityClassName(_In_ void **, TArgs&&... args) : m_result(S_OK) \ - { \ - StartActivity(wistd::forward(args)...); \ - } \ - protected: \ - void EnsureWatchingCurrentThread() {} \ - void IgnoreCurrentThread() {} \ - wil::FailureInfo const *GetFailureInfo() \ - { \ - return (FAILED(m_result) && (m_cache.GetFailure() != nullptr) && (m_result == m_cache.GetFailure()->hr)) ? m_cache.GetFailure() : nullptr; \ - } \ - HRESULT GetResult() \ - { \ - return m_result; \ - } \ - public: \ - ~ActivityClassName() \ - { \ - Stop(HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); \ - } \ - ActivityClassName(ActivityClassName &&) = default; \ - WI_NODISCARD TraceLoggingHProvider Provider() const \ - { \ - return TraceLoggingType::Provider(); \ - } \ - void Stop(HRESULT hr = S_OK) \ - { \ - if (IsStarted()) \ - { \ - m_result = hr; \ - TRACELOGGING_WRITE_ACTIVITY_STOP(ActivityClassName); \ - } \ - } \ - template \ - void StopWithResult(HRESULT hr, TArgs&&... args) \ - { \ - m_result = hr; \ - Stop(wistd::forward(args)...); \ - } \ - template \ - static ActivityClassName Start(TArgs&&... args) \ - { \ - return ActivityClassName(static_cast(__nullptr), wistd::forward(args)...); \ - } \ - void StartActivity() \ - { \ - TRACELOGGING_WRITE_ACTIVITY_START(ActivityClassName); \ - } \ - -#define BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD(ActivityClassName, keyword) \ - BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD_LEVEL(ActivityClassName, keyword, WINEVENT_LEVEL_VERBOSE) - -#define BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, level) \ - BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD_LEVEL(ActivityClassName, 0, level) - -#define BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS(ActivityClassName) \ - BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD_LEVEL(ActivityClassName, 0, WINEVENT_LEVEL_VERBOSE) - -#define END_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS() \ - private: \ - HRESULT m_result; \ - wil::ThreadFailureCache m_cache; \ - }; - -#define BEGIN_DEFINE_TELEMETRY_THREAD_ACTIVITY_CLASS(ActivityClassName) \ - BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD(ActivityClassName, MICROSOFT_KEYWORD_TELEMETRY) - -#define END_DEFINE_TELEMETRY_THREAD_ACTIVITY_CLASS() \ - END_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS() - -#define DEFINE_TRACELOGGING_THREAD_ACTIVITY_WITH_KEYWORD_LEVEL(ActivityClassName, keyword, level) \ - BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD_LEVEL(ActivityClassName, keyword, level) \ - END_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS() - -#define DEFINE_TRACELOGGING_THREAD_ACTIVITY_WITH_KEYWORD(ActivityClassName, keyword) \ - BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_KEYWORD(ActivityClassName, keyword) \ - END_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS() - -#define DEFINE_TRACELOGGING_THREAD_ACTIVITY_WITH_LEVEL(ActivityClassName, level) \ - BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS_WITH_LEVEL(ActivityClassName, level) \ - END_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS() - -#define DEFINE_TRACELOGGING_THREAD_ACTIVITY(ActivityClassName) \ - BEGIN_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS(ActivityClassName) \ - END_DEFINE_TRACELOGGING_THREAD_ACTIVITY_CLASS() - -#define DEFINE_TELEMETRY_THREAD_ACTIVITY(ActivityClassName) \ - BEGIN_DEFINE_TELEMETRY_THREAD_ACTIVITY_CLASS(ActivityClassName) \ - END_DEFINE_TELEMETRY_THREAD_ACTIVITY_CLASS() - -#endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) */ - - -// [deprecated] -// DO NOT USE these concepts -// These should be removed post RI/FI cycle... - -#define DEFINE_TRACELOGGING_METHOD DEFINE_EVENT_METHOD -#define BEGIN_DEFINE_TELEMETRY_ACTIVITY_CLASS BEGIN_TELEMETRY_ACTIVITY_CLASS -#define END_DEFINE_TELEMETRY_ACTIVITY_CLASS END_ACTIVITY_CLASS -#define BEGIN_DEFINE_TRACELOGGING_ACTIVITY_CLASS BEGIN_TRACELOGGING_ACTIVITY_CLASS -#define END_DEFINE_TRACELOGGING_ACTIVITY_CLASS END_ACTIVITY_CLASS -#define TELEMETRY_WRITE_ACTIVITY_START TraceLoggingClassWriteStart -#define TRACELOGGING_WRITE_ACTIVITY_START TraceLoggingClassWriteStart -#define TELEMETRY_WRITE_ACTIVITY_STOP TraceLoggingClassWriteStop -#define TRACELOGGING_WRITE_ACTIVITY_STOP TraceLoggingClassWriteStop -#define WRITE_TRACELOGGING_EVENT TraceLoggingClassWrite -#define WRITE_TELEMETRY_EVENT TraceLoggingClassWriteTelemetry -#define TRACELOGGING_WRITE_TAGGED_EVENT TraceLoggingClassWriteTagged -#define TELEMETRY_WRITE_TAGGED_EVENT TraceLoggingClassWriteTaggedTelemetry - -// [deprecated] -// DO NOT USE these concepts -// These should be removed post RI/FI cycle... -#define __DEFINE_EVENT DEFINE_TRACELOGGING_EVENT -#define __DEFINE_EVENT_PARAM1 DEFINE_TRACELOGGING_EVENT_PARAM1 -#define __DEFINE_EVENT_PARAM2 DEFINE_TRACELOGGING_EVENT_PARAM2 -#define __DEFINE_EVENT_PARAM3 DEFINE_TRACELOGGING_EVENT_PARAM3 -#define __DEFINE_EVENT_PARAM4 DEFINE_TRACELOGGING_EVENT_PARAM4 -#define __DEFINE_EVENT_PARAM5 DEFINE_TRACELOGGING_EVENT_PARAM5 -#define __DEFINE_EVENT_PARAM6 DEFINE_TRACELOGGING_EVENT_PARAM6 -#define __DEFINE_EVENT_PARAM7 DEFINE_TRACELOGGING_EVENT_PARAM7 -#define __DEFINE_EVENT_UINT32 DEFINE_TRACELOGGING_EVENT_UINT32 -#define __DEFINE_EVENT_BOOL DEFINE_TRACELOGGING_EVENT_BOOL -#define __DEFINE_EVENT_STRING DEFINE_TRACELOGGING_EVENT_STRING - -// [deprecated] -// DO NOT USE these concepts -// These should be removed post RI/FI cycle... -#define __DEFINE_TAGGED_EVENT DEFINE_TAGGED_TRACELOGGING_EVENT -#define __DEFINE_TAGGED_EVENT_PARAM1 DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM1 -#define __DEFINE_TAGGED_EVENT_PARAM2 DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM2 -#define __DEFINE_TAGGED_EVENT_PARAM3 DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM3 -#define __DEFINE_TAGGED_EVENT_PARAM4 DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM4 -#define __DEFINE_TAGGED_EVENT_PARAM5 DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM5 -#define __DEFINE_TAGGED_EVENT_PARAM6 DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM6 -#define __DEFINE_TAGGED_EVENT_PARAM7 DEFINE_TAGGED_TRACELOGGING_EVENT_PARAM7 -#define __DEFINE_TAGGED_EVENT_UINT32 DEFINE_TAGGED_TRACELOGGING_EVENT_UINT32 -#define __DEFINE_TAGGED_EVENT_BOOL DEFINE_TAGGED_TRACELOGGING_EVENT_BOOL -#define __DEFINE_TAGGED_EVENT_STRING DEFINE_TAGGED_TRACELOGGING_EVENT_STRING - -template -class ActivityErrorTracer -{ -public: - ActivityErrorTracer(T const &) {} -}; - -using TelemetryBase = wil::TraceLoggingProvider; - -#define TRACELOGGING_WRITE_EVENT(TraceLoggingClassName, EventId, ...) \ - TraceLoggingWrite(TraceLoggingClassName::TraceLoggingType::Provider(), EventId, __VA_ARGS__) - -#define TELEMETRY_WRITE_EVENT(EventId, ...) \ - TraceLoggingWrite(TraceLoggingType::Provider(), EventId, TraceLoggingKeyword(MICROSOFT_KEYWORD_TELEMETRY), __VA_ARGS__) - -#define DEFINE_TAGGED_EVENT_METHOD(MethodName) \ - public: void MethodName - -#define DEFINE_ACTIVITY_START(...) \ - void StartActivity(__VA_ARGS__) - -#define DEFINE_ACTIVITY_STOP(...) \ - void Stop(__VA_ARGS__) - -#define DECLARE_TRACELOGGING_CLASS(TraceLoggingClassName, ProviderName, ProviderId) \ - class TraceLoggingClassName : public wil::TraceLoggingProvider \ - { \ - IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY(TraceLoggingClassName, ProviderName, ProviderId); \ - }; - -#define IMPLEMENT_TELEMETRY_CLASS(TelemetryClassName, TraceLoggingClassName) \ - __IMPLEMENT_TRACELOGGING_CLASS_BASE(TelemetryClassName, TraceLoggingClassName) \ - protected: \ - void Create() \ - { AttachProvider(TraceLoggingClassName::Provider()); \ - __TRACELOGGING_DEFINE_PROVIDER_STORAGE_LINK(TelemetryClassName, TraceLoggingClassName); } \ - public: - -namespace wil -{ - /// @cond - namespace details - { -#ifdef WIL_API_TELEMETRY_SUSPEND_HANDLER -#pragma detect_mismatch("ODR_violation_WIL_API_TELEMETRY_SUSPEND_HANDLER_mismatch", "1") -#else -#pragma detect_mismatch("ODR_violation_WIL_API_TELEMETRY_SUSPEND_HANDLER_mismatch", "0") -#endif - - class ApiTelemetryLogger : public wil::TraceLoggingProvider - { - // {fb7fcbc6-7156-5a5b-eabd-0be47b14f453} - IMPLEMENT_TRACELOGGING_CLASS_WITH_MICROSOFT_TELEMETRY(ApiTelemetryLogger, "Microsoft.Windows.ApiTelemetry", (0xfb7fcbc6, 0x7156, 0x5a5b, 0xea, 0xbd, 0x0b, 0xe4, 0x7b, 0x14, 0xf4, 0x53)); - public: - // Used to store of list of APIs (with namespace, class, custom and call count data per API). - // This is public so that it can be unit tested. - class ApiDataList - { - public: - struct ApiData - { - PCWSTR className = nullptr; - PCWSTR apiName = nullptr; - PCSTR specialization = nullptr; - volatile long* counterReference = nullptr; - wistd::unique_ptr next; - - ApiData(PCWSTR className_, PCWSTR apiName_, PCSTR specialization_, volatile long* counterReference_) : - className(className_), apiName(apiName_), specialization(specialization_), counterReference(counterReference_) - { - } - }; - - // Inserts a new Api call counter into the list, keeping the list sorted by className - void Insert(PCWSTR className, PCWSTR apiName, _In_opt_ PCSTR specialization, volatile long* counterReference) - { - wistd::unique_ptr newApiData(new(std::nothrow) ApiData(className, apiName, specialization, counterReference)); - if (newApiData) - { - auto lock = m_lock.lock_exclusive(); - - // Insert the new ApiData, keeping the list sorted by className. - wistd::unique_ptr* currentNode = &m_root; - while (*currentNode) - { - wistd::unique_ptr& node = *currentNode; - if (wcscmp(className, node->className) <= 0) - { - break; - } - currentNode = &(node->next); - } - newApiData->next.reset(currentNode->release()); - currentNode->reset(newApiData.release()); - } - } - - // For each distinct namespace, calls the provided flushCallback function. - // After returning, it will have deleted all ApiData elements, and zeroed the *counterReference stored in each ApiData. - void Flush(wistd::function flushCallback) - { - wistd::unique_ptr root; - if (m_root) - { - auto lock = m_lock.lock_exclusive(); - root.swap(m_root); - } - - while (root) - { - // First find the number of characters we need to allocate for each string, and the number of items in the counter array to allocate - size_t totalApiListLength = 1; // Init to 1 to account for null terminator - size_t totalSpecializationsLength = 1; // Init to 1 to account for null terminator - UINT16 numCounts = 0; - - ProcessSingleNamespace(&root, - [&](wistd::unique_ptr& node) - { - // Get the length needed for the class string - const wchar_t* strAfterNamespace = GetClassStringPointer(node->className); - size_t classStrLen = wcslen(strAfterNamespace ? strAfterNamespace : node->className); - - totalApiListLength += (classStrLen + wcslen(node->apiName) + 1); // We add 1 to account for the comma delimeter - if (node->specialization) - { - totalSpecializationsLength += strlen(node->specialization) + 1; // We add 1 to account for the comma delimeter - } - else - { - totalSpecializationsLength += 2; // '-' plus comma delimeter - } - numCounts++; - }); - - // Fill arrays with the API data, and then pass it to the callback function - wistd::unique_ptr apiList(new(std::nothrow) wchar_t[totalApiListLength]); - wistd::unique_ptr specializationList(new(std::nothrow) char[totalSpecializationsLength]); - wistd::unique_ptr countArray(new(std::nothrow) UINT32[numCounts]); - size_t nameSpaceLength = GetNameSpaceLength(root->className) + 1; - wistd::unique_ptr nameSpace(new(std::nothrow) wchar_t[nameSpaceLength]); - if (!apiList || !specializationList || !countArray || !nameSpace) - { - return; - } - - ZeroMemory(apiList.get(), totalApiListLength * sizeof(wchar_t)); - ZeroMemory(specializationList.get(), totalSpecializationsLength * sizeof(char)); - ZeroMemory(countArray.get(), numCounts * sizeof(UINT32)); - ZeroMemory(nameSpace.get(), nameSpaceLength * sizeof(wchar_t)); - - StringCchCopyNW(nameSpace.get(), STRSAFE_MAX_CCH, root->className, nameSpaceLength - 1); - - int countArrayIndex = 0; - - wistd::unique_ptr* lastNamespaceNode = ProcessSingleNamespace(&root, - [&](wistd::unique_ptr& node) - { - countArray[countArrayIndex] = static_cast(::InterlockedExchangeNoFence(node->counterReference, 0)); - - // Prepend the portion of the apiName group string that's after the '.'. So for example, if the - // className is "Windows.System.Launcher", then we prepend "Launcher." to the apiName string. - const wchar_t* strAfterNamespace = GetClassStringPointer(node->className); - if (strAfterNamespace) - { - FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, strAfterNamespace + 1)); - FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, L".")); - } - - FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, node->apiName)); - if (node->specialization) - { - FAIL_FAST_IF(strncat_s(specializationList.get(), totalSpecializationsLength, node->specialization, strlen(node->specialization)) != 0); - } - else - { - FAIL_FAST_IF(strncat_s(specializationList.get(), totalSpecializationsLength, "-", 1) != 0); - } - - if (countArrayIndex != (numCounts - 1)) - { - FAIL_FAST_IF_FAILED(StringCchCatW(apiList.get(), totalApiListLength, L",")); - FAIL_FAST_IF(strncat_s(specializationList.get(), totalSpecializationsLength, ",", 1) != 0); - } - - countArrayIndex++; - }); - - // Call the callback function with the data we've collected for this namespace - flushCallback(nameSpace.get(), apiList.get(), specializationList.get(), countArray.get(), numCounts); - - if (*lastNamespaceNode) - { - root.swap((*lastNamespaceNode)->next); - } - else - { - root.reset(); - } - } - } - - private: - static wistd::unique_ptr* ProcessSingleNamespace(wistd::unique_ptr* root, wistd::function&)> workerCallback) - { - wistd::unique_ptr* currentNode = root; - while (*currentNode) - { - wistd::unique_ptr& node = *currentNode; - - workerCallback(node); - - // Check if our next node would be a new namespace; if so, then break out - if (node->next && !IsSameNameSpace(node->className, node->next->className)) - { - break; - } - - currentNode = &(node->next); - } - - return currentNode; - } - - static bool IsSameNameSpace(PCWSTR namespaceClass1, PCWSTR namespaceClass2) - { - return (wcsncmp(namespaceClass1, namespaceClass2, GetNameSpaceLength(namespaceClass2) + 1) == 0); - } - - static size_t GetNameSpaceLength(PCWSTR nameSpaceClass) - { - const wchar_t* strAfterNamespace = GetClassStringPointer(nameSpaceClass); - return (strAfterNamespace ? (strAfterNamespace - nameSpaceClass) : wcslen(nameSpaceClass)); - } - - static const wchar_t* GetClassStringPointer(PCWSTR nameSpaceClass) - { - // Note: Usage of wcsrchr can cause build errors in some components, so we implement a way of getting the pointer to the 'class' portion - // of the string ourselves. - int retIndex = 0; - while (nameSpaceClass[retIndex] != '\0') - { - retIndex++; - } - while (retIndex > 0 && nameSpaceClass[retIndex] != '.') - { - retIndex--; - } - return (retIndex != 0 ? &(nameSpaceClass[retIndex]) : nullptr); - } - - wistd::unique_ptr m_root; - wil::srwlock m_lock; - }; - - public: - // Initializes an entry that holds the className.apiName, along with a counter for that className.apiName. - // The counterReference passed to this should later be passed to LogApiInfo. - // - // A separate entry will be created for each apiName that has a distinct specialization value. - // - // This function only needs to be called once for each API, although it doesn't hurt if it gets called more than once. - // - // The apiName, className, and specialization parameters should be compile time constants. specialization can be null. - DEFINE_EVENT_METHOD(InitApiData)(PCWSTR className, PCWSTR apiName, _In_opt_ PCSTR specialization, volatile long* counterReference) - { - // TODO: Validate that apiName and className are a compile-time constants; validate that specialization is - // either compile-time constant or nullptr; validate that counterReference points to static variable. - // Can do this by making sure address is <= (GetModuleHandle() + DLL size). - m_apiDataList.Insert(className, apiName, specialization, counterReference); - } - - // Fires a telemetry event that contains the method call apiName that has been logged by the component, - // since the last FireEvent() call, or since the component was loaded. - DEFINE_EVENT_METHOD(FireEvent)() - { - m_apiDataList.Flush( - [](PCWSTR nameSpace, PCWSTR apiList, PCSTR specializationList, UINT32* countArray, UINT16 numCounters) - { - if (::wil::details::IsDebuggerPresent()) - { - TraceLoggingWrite(Provider(), "ApiCallCountsWithDebuggerPresent", TraceLoggingValue(nameSpace, "Namespace"), TraceLoggingValue(apiList, "ApiDataList"), - TraceLoggingValue(specializationList, "CustomList"), TraceLoggingUInt32Array(countArray, numCounters, "HitCounts"), TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_CRITICAL_DATA)); - } - else - { - TraceLoggingWrite(Provider(), "ApiCallCounts", TraceLoggingValue(nameSpace, "Namespace"), TraceLoggingValue(apiList, "ApiDataList"), - TraceLoggingValue(specializationList, "CustomList"), TraceLoggingUInt32Array(countArray, numCounters, "HitCounts"), TraceLoggingBoolean(TRUE, "UTCReplace_AppSessionGuid"), - TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES)); - } - - __TRACELOGGING_TEST_HOOK_VERIFY_API_TELEMETRY(nameSpace, apiList, specializationList, countArray, numCounters); - }); - - if (m_fireEventDelay < c_fireEventDelayLimit) - { - // Double the exponential backoff timer, until it reaches the maximum - m_fireEventDelay *= 2; - if (m_fireEventDelay > c_fireEventDelayLimit) - { - m_fireEventDelay = c_fireEventDelayLimit; - } - } - - ScheduleFireEventCallback(); - } - - // Used to declare that the component will handle calling FireEvent() in its own suspend handler. - // This optimizes the frequency at which the event will be fired. - DEFINE_EVENT_METHOD(UsingOwnSuspendHandler)() - { - m_fireEventDelay = c_fireEventDelayLimit; - ScheduleFireEventCallback(); - } - - private: - void Initialize() WI_NOEXCEPT override - { -#ifdef WIL_API_TELEMETRY_SUSPEND_HANDLER - m_fireEventDelay = c_fireEventDelayLimit; - - PPSM_APPSTATE_REGISTRATION psmReg; - BOOLEAN quiesced; - PsmRegisterAppStateChangeNotification( - [](BOOLEAN quiesced, PVOID, HANDLE) - { - if (quiesced) - { - FireEvent(); - } - }, - StateChangeCategoryApplication, 0, nullptr, &quiesced, &psmReg); -#else - m_fireEventDelay = __TRACELOGGING_TEST_HOOK_API_TELEMETRY_EVENT_DELAY_MS; -#endif - m_fireEventThreadPoolTimer.reset(::CreateThreadpoolTimer( - [](PTP_CALLBACK_INSTANCE, PVOID, PTP_TIMER) - { - FireEvent(); - }, - nullptr, - nullptr)); - ScheduleFireEventCallback(); - } - - ~ApiTelemetryLogger() WI_NOEXCEPT override - { - FireEvent(); - - // release handle to thread pool timer instead of its destructor being call, if process is being terminated and dll is not being unloaded dynamically - // destruction of threadpool timer is considered invalid during process termination - if (ProcessShutdownInProgress()) - { - m_fireEventThreadPoolTimer.release(); - } - } - - void ScheduleFireEventCallback() - { - // do not schedule thread pool timer callback, if process is being terminated and dll is not being unloaded dynamically - if (m_fireEventThreadPoolTimer && !ProcessShutdownInProgress()) - { - // Note this will override any pending scheduled callback - FILETIME dueTime{}; - *reinterpret_cast(&dueTime) = -static_cast(m_fireEventDelay) * 10000; - SetThreadpoolTimer(m_fireEventThreadPoolTimer.get(), &dueTime, 0, 0); - } - } - - ApiDataList m_apiDataList; - wil::unique_threadpool_timer m_fireEventThreadPoolTimer; - - // The timer used to determine when to fire the next telemetry event (when it's fired based on a timer). - UINT m_fireEventDelay{}; - DWORD const c_fireEventDelayLimit = 20 * 60 * 1000; // 20 minutes - }; - } // namespace details - /// @endcond -} // namespace wil - -// Insert WI_LOG_API_USE near the top of a WinRT method to log that a method was called. -// The parameter should be the method name, for example: -// - WI_LOG_API_USE(L"LaunchUriAsync"); -// -// To log that the WinRT method reached a certain line of code, pass an override string: -// - WI_LOG_API_USE(L"LaunchUriAsync", "PointA"); -// -// If the class name can't be obtained at runtime, or if instrumenting a non-WinRT API, use the below macro, -// and pass the fully qualified class name (in the case of WinRT), or a string identifying the group of the non-WinRT API: -// - WI_LOG_CLASS_API_USE(RuntimeClass_Windows_System_Launcher, L"LaunchUriAsync"); -// -// Note: If the component can have a suspend handler, the following line should be added before including TraceLogging.h: -// - #define WIL_API_TELEMETRY_SUSPEND_HANDLER -// This will optimize the component's ability to upload telemetry, as it will upload on suspend. It will also disable -// frequent telemetry upload early in process execution. -// -// Alternatively, a component can call wil::details:ApiTelemetryLogger::FireEvent() from it's own suspend handler. -// If this is done, then in DLLMain it should also call wil::details::ApiTelemetryLogger::UsingOwnSuspendHandler(). -// -// Note: In your DLLMain method, please also add following code snippet -// -// wil::details::g_processShutdownInProgress = (lpReserved == nullptr); -// -// Adding this code snippet ensures that during process termination, thread pool timer -// destructor or SetThreadPoolTimer methods are not called, because they are invalid to call -// when dll is not getting dynamically unloaded. Skipping this code block will result in a continuable -// exception being thrown if process is getting terminated and dll in which ApiTelemetryLogger is not getting dynamically -// unloaded. For more details about lpReserved parameter, please refer to MSDN. - -#define __WI_LOG_CLASS_API_USE3(className, apiName, specialization) \ - do \ - { \ - static volatile long __wil_apiCallCounter = 0; \ - if (1 == ::InterlockedIncrementNoFence(&__wil_apiCallCounter)) \ - { \ - ::wil::details::ApiTelemetryLogger::InitApiData(className, apiName, specialization, &__wil_apiCallCounter); \ - } \ - } \ - while (0,0) -#define __WI_LOG_CLASS_API_USE2(className, apiName) \ - __WI_LOG_CLASS_API_USE3(className, apiName, nullptr) -#define __WI_LOG_API_USE2(apiName, specialization) \ - __WI_LOG_CLASS_API_USE3(InternalGetRuntimeClassName(), apiName, specialization) -#define __WI_LOG_API_USE1(apiName) \ - __WI_LOG_CLASS_API_USE3(InternalGetRuntimeClassName(), apiName, nullptr) - -#define WI_LOG_CLASS_API_USE(...) \ - WI_MACRO_DISPATCH(__WI_LOG_CLASS_API_USE, __VA_ARGS__) - -#define WI_LOG_API_USE(...) \ - WI_MACRO_DISPATCH(__WI_LOG_API_USE, __VA_ARGS__) - -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - -#pragma warning(pop) -#endif // __WIL_TRACELOGGING_H_INCLUDED diff --git a/src/common/dep/wil/com.h b/src/common/dep/wil/com.h deleted file mode 100644 index 3ee0ea005..000000000 --- a/src/common/dep/wil/com.h +++ /dev/null @@ -1,3007 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_COM_INCLUDED -#define __WIL_COM_INCLUDED - -#include -#include -#include "result.h" -#include "resource.h" // last to ensure _COMBASEAPI_H_ protected definitions are available - -#if __has_include() -#include -#endif -#if __has_include() -#include -#endif - -// Forward declaration within WIL (see https://msdn.microsoft.com/en-us/library/br244983.aspx) -/// @cond -namespace Microsoft -{ - namespace WRL - { - template - class ComPtr; - } -} -/// @endcond - -namespace wil -{ - /// @cond - namespace details - { - // We can't directly use wistd::is_convertible as it returns TRUE for an ambiguous conversion. - // Adding is_abstract to the mix, enables us to allow conversion for interfaces, but deny it for - // classes (where the multiple inheritance causes ambiguity). - // NOTE: I've reached out to vcsig on this topic and it turns out that __is_convertible_to should NEVER - // return true for ambiguous conversions. This was a bug in our compiler that has since been fixed. - // Eventually, once that fix propagates we can move to a more efficient __is_convertible_to without - // the added complexity. - template - struct is_com_convertible : - wistd::bool_constant<__is_convertible_to(TFrom, TTo) && (__is_abstract(TFrom) || wistd::is_same::value)> - { - }; - - using tag_com_query = wistd::integral_constant; - using tag_try_com_query = wistd::integral_constant; - using tag_com_copy = wistd::integral_constant; - using tag_try_com_copy = wistd::integral_constant; - - class default_query_policy - { - public: - template - inline static HRESULT query(_In_ T* ptr, REFIID riid, _COM_Outptr_ void** result) - { - return ptr->QueryInterface(riid, result); - } - - template - inline static HRESULT query(_In_ T* ptr, _COM_Outptr_ TResult** result) - { - return query_dispatch(ptr, typename details::is_com_convertible::type(), result); - } - - private: - template - inline static HRESULT query_dispatch(_In_ T* ptr, wistd::true_type, _COM_Outptr_ TResult** result) // convertible - { - *result = ptr; - (*result)->AddRef(); - return S_OK; - } - - template - inline static HRESULT query_dispatch(_In_ T* ptr, wistd::false_type, _COM_Outptr_ TResult** result) // not convertible - { - auto hr = ptr->QueryInterface(IID_PPV_ARGS(result)); - __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); - return hr; - } - }; - - template - struct query_policy_helper - { - using type = default_query_policy; - }; - - class weak_query_policy - { - public: - inline static HRESULT query(_In_ IWeakReference* ptr, REFIID riid, _COM_Outptr_ void** result) - { - WI_ASSERT_MSG(riid != __uuidof(IWeakReference), "Cannot resolve a weak reference to IWeakReference"); - *result = nullptr; - - IInspectable* temp; - HRESULT hr = ptr->Resolve(__uuidof(IInspectable), &temp); - if (SUCCEEDED(hr)) - { - if (temp == nullptr) - { - return E_NOT_SET; - } - hr = temp->QueryInterface(riid, result); - __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); - temp->Release(); - } - - return hr; - } - - template - inline static HRESULT query(_In_ IWeakReference* ptr, _COM_Outptr_ TResult** result) - { - static_assert(!wistd::is_same::value, "Cannot resolve a weak reference to IWeakReference"); - return query_dispatch(ptr, wistd::is_base_of(), result); - } - - private: - template - static HRESULT query_dispatch(_In_ IWeakReference* ptr, wistd::true_type, _COM_Outptr_ TResult** result) - { - auto hr = ptr->Resolve(__uuidof(TResult), reinterpret_cast(result)); - if (SUCCEEDED(hr) && (*result == nullptr)) - { - hr = E_NOT_SET; - } - __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); - return hr; - } - - template - static HRESULT query_dispatch(_In_ IWeakReference* ptr, wistd::false_type, _COM_Outptr_ TResult** result) - { - return query(ptr, IID_PPV_ARGS(result)); - } - }; - - template <> - struct query_policy_helper - { - using type = weak_query_policy; - }; - -#if (NTDDI_VERSION >= NTDDI_WINBLUE) - class agile_query_policy - { - public: - inline static HRESULT query(_In_ IAgileReference* ptr, REFIID riid, _COM_Outptr_ void** result) - { - WI_ASSERT_MSG(riid != __uuidof(IAgileReference), "Cannot resolve a agile reference to IAgileReference"); - auto hr = ptr->Resolve(riid, result); - __analysis_assume(SUCCEEDED(hr) || (*result == nullptr)); // IAgileReference::Resolve not annotated correctly - return hr; - } - - template - static HRESULT query(_In_ IAgileReference* ptr, _COM_Outptr_ TResult** result) - { - static_assert(!wistd::is_same::value, "Cannot resolve a agile reference to IAgileReference"); - return query(ptr, __uuidof(TResult), reinterpret_cast(result)); - } - }; - - template <> - struct query_policy_helper - { - using type = agile_query_policy; - }; -#endif - - template - using query_policy_t = typename query_policy_helper::type>::type; - - } // details - /// @endcond - - //! Represents the base template type that implements com_ptr, com_weak_ref, and com_agile_ref. - //! See @ref page_comptr for more background. See @ref page_query for more information on querying with WIL. - //! @tparam T Represents the type being held by the com_ptr_t. - //! For com_ptr, this will always be the interface being represented. For com_weak_ref, this will always be - //! IWeakReference. For com_agile_ref, this will always be IAgileReference. - //! @tparam err_policy Represents the error policy for the class (error codes, exceptions, or fail fast; see @ref page_errors) - template - class com_ptr_t - { - private: - using element_type_reference = typename wistd::add_lvalue_reference::type; - using query_policy = details::query_policy_t; - public: - //! The function return result (HRESULT or void) for the given err_policy (see @ref page_errors). - using result = typename err_policy::result; - //! The template type `T` being held by the com_ptr_t. - using element_type = T; - //! A pointer to the template type `T` being held by the com_ptr_t (what `get()` returns). - using pointer = T*; - - //! @name Constructors - //! @{ - - //! Default constructor (holds nullptr). - com_ptr_t() WI_NOEXCEPT : - m_ptr(nullptr) - { - } - - //! Implicit construction from nullptr_t (holds nullptr). - com_ptr_t(wistd::nullptr_t) WI_NOEXCEPT : - com_ptr_t() - { - } - - //! Implicit construction from a compatible raw interface pointer (AddRef's the parameter). - com_ptr_t(pointer ptr) WI_NOEXCEPT : - m_ptr(ptr) - { - if (m_ptr) - { - m_ptr->AddRef(); - } - } - - //! Copy-construction from a like `com_ptr_t` (copies and AddRef's the parameter). - com_ptr_t(const com_ptr_t& other) WI_NOEXCEPT : - com_ptr_t(other.get()) - { - } - - //! Copy-construction from a convertible `com_ptr_t` (copies and AddRef's the parameter). - template > - com_ptr_t(const com_ptr_t& other) WI_NOEXCEPT : - com_ptr_t(static_cast(other.get())) - { - } - - //! Move construction from a like `com_ptr_t` (avoids AddRef/Release by moving from the parameter). - com_ptr_t(com_ptr_t&& other) WI_NOEXCEPT : - m_ptr(other.detach()) - { - } - - //! Move construction from a compatible `com_ptr_t` (avoids AddRef/Release by moving from the parameter). - template > - com_ptr_t(com_ptr_t&& other) WI_NOEXCEPT : - m_ptr(other.detach()) - { - } - //! @} - - //! Destructor (releases the pointer). - ~com_ptr_t() WI_NOEXCEPT - { - if (m_ptr) - { - m_ptr->Release(); - } - } - - //! @name Assignment operators - //! @{ - - //! Assign to nullptr (releases the current pointer, holds nullptr). - com_ptr_t& operator=(wistd::nullptr_t) WI_NOEXCEPT - { - reset(); - return *this; - } - - //! Assign a compatible raw interface pointer (releases current pointer, copies and AddRef's the parameter). - com_ptr_t& operator=(pointer other) WI_NOEXCEPT - { - auto ptr = m_ptr; - m_ptr = other; - if (m_ptr) - { - m_ptr->AddRef(); - } - if (ptr) - { - ptr->Release(); - } - return *this; - } - - //! Assign a like `com_ptr_t` (releases current pointer, copies and AddRef's the parameter). - com_ptr_t& operator=(const com_ptr_t& other) WI_NOEXCEPT - { - return operator=(other.get()); - } - - //! Assign a convertible `com_ptr_t` (releases current pointer, copies and AddRef's the parameter). - template > - com_ptr_t& operator=(const com_ptr_t& other) WI_NOEXCEPT - { - return operator=(static_cast(other.get())); - } - - //! Move assign from a like `com_ptr_t` (releases current pointer, avoids AddRef/Release by moving the parameter). - com_ptr_t& operator=(com_ptr_t&& other) WI_NOEXCEPT - { - attach(other.detach()); - return *this; - } - - //! Move assignment from a compatible `com_ptr_t` (releases current pointer, avoids AddRef/Release by moving from the parameter). - template > - com_ptr_t& operator=(com_ptr_t&& other) WI_NOEXCEPT - { - attach(other.detach()); - return *this; - } - //! @} - - //! @name Modifiers - //! @{ - - //! Swap pointers with an another named com_ptr_t object. - template - void swap(com_ptr_t& other) WI_NOEXCEPT - { - auto ptr = m_ptr; - m_ptr = other.m_ptr; - other.m_ptr = ptr; - } - - //! Swap pointers with a rvalue reference to another com_ptr_t object. - template - void swap(com_ptr_t&& other) WI_NOEXCEPT - { - swap(other); - } - - //! Releases the pointer and sets it to nullptr. - void reset() WI_NOEXCEPT - { - auto ptr = m_ptr; - m_ptr = nullptr; - if (ptr) - { - ptr->Release(); - } - } - - //! Releases the pointer and sets it to nullptr. - void reset(wistd::nullptr_t) WI_NOEXCEPT - { - reset(); - } - - //! Takes ownership of a compatible raw interface pointer (releases pointer, copies but DOES NOT AddRef the parameter). - void attach(pointer other) WI_NOEXCEPT - { - auto ptr = m_ptr; - m_ptr = other; - if (ptr) - { - ULONG ref = ptr->Release(); - WI_ASSERT_MSG(((other != ptr) || (ref > 0)), "Bug: Attaching the same already assigned, destructed pointer"); - } - } - - //! Relinquishes ownership and returns the internal interface pointer (DOES NOT release the detached pointer, sets class pointer to null). - WI_NODISCARD pointer detach() WI_NOEXCEPT - { - auto temp = m_ptr; - m_ptr = nullptr; - return temp; - } - - //! Returns the address of the internal pointer (releases ownership of the pointer BEFORE returning the address). - //! The pointer is explicitly released to prevent accidental leaks of the pointer. Coding standards generally indicate that - //! there is little valid `_Inout_` use of `IInterface**`, making this safe to do under typical use. - //! @see addressof - //! ~~~~ - //! STDAPI GetMuffin(IMuffin **muffin); - //! wil::com_ptr myMuffin; - //! THROW_IF_FAILED(GetMuffin(myMuffin.put())); - //! ~~~~ - pointer* put() WI_NOEXCEPT - { - reset(); - return &m_ptr; - } - - //! Returns the address of the internal pointer casted to void** (releases ownership of the pointer BEFORE returning the address). - //! @see put - void** put_void() WI_NOEXCEPT - { - return reinterpret_cast(put()); - } - - //! Returns the address of the internal pointer casted to IUnknown** (releases ownership of the pointer BEFORE returning the address). - //! @see put - ::IUnknown** put_unknown() WI_NOEXCEPT - { - return reinterpret_cast<::IUnknown**>(put()); - } - - //! Returns the address of the internal pointer (releases ownership of the pointer BEFORE returning the address). - //! The pointer is explicitly released to prevent accidental leaks of the pointer. Coding standards generally indicate that - //! there is little valid `_Inout_` use of `IInterface**`, making this safe to do under typical use. Since this behavior is not always immediately - //! apparent, prefer to scope variables as close to use as possible (generally avoiding use of the same com_ptr variable in successive calls to - //! receive an output interface). - //! @see addressof - pointer* operator&() WI_NOEXCEPT - { - return put(); - } - - //! Returns the address of the internal pointer (does not release the pointer; should not be used for `_Out_` parameters) - pointer* addressof() WI_NOEXCEPT - { - return &m_ptr; - } - //! @} - - //! @name Inspection - //! @{ - - //! Returns the address of the const internal pointer (does not release the pointer) - WI_NODISCARD const pointer* addressof() const WI_NOEXCEPT - { - return &m_ptr; - } - - //! Returns 'true' if the pointer is assigned (NOT nullptr) - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_ptr != nullptr); - } - - //! Returns the pointer - WI_NODISCARD pointer get() const WI_NOEXCEPT - { - return m_ptr; - } - - //! Allows direct calls against the pointer (AV on internal nullptr) - WI_NODISCARD pointer operator->() const WI_NOEXCEPT - { - return m_ptr; - } - - //! Dereferences the pointer (AV on internal nullptr) - WI_NODISCARD element_type_reference operator*() const WI_NOEXCEPT - { - return *m_ptr; - } - //! @} - - //! @name Query helpers - //! * Retrieves the requested interface - //! * AV if the pointer is null - //! * Produce an error if the requested interface is unsupported - //! - //! See @ref page_query for more information - //! @{ - - //! Query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.query();`. - //! See @ref page_query for more information. - //! - //! This method is the primary method that should be used to query a com_ptr in exception-based or fail-fast based code. - //! Error-code returning code should use @ref query_to so that the returned HRESULT can be examined. In the following - //! examples, `m_ptr` is an exception-based or fail-fast based com_ptr, com_weak_ref, or com_agile_ref: - //! ~~~~ - //! auto foo = ptr.query(); - //! foo->Method1(); - //! foo->Method2(); - //! ~~~~ - //! For simple single-method calls, this method allows removing the temporary that holds the com_ptr: - //! ~~~~ - //! ptr.query()->Method1(); - //! ~~~~ - //! @tparam U Represents the interface being queried - //! @return A `com_ptr_t` pointer to the given interface `U`. The pointer is guaranteed not null. The returned - //! `com_ptr_t` type will be @ref com_ptr or @ref com_ptr_failfast (matching the error handling form of the - //! pointer being queried (exception based or fail-fast). - template - WI_NODISCARD inline com_ptr_t query() const - { - static_assert(wistd::is_same::value, "query requires exceptions or fail fast; use try_query or query_to"); - return com_ptr_t(m_ptr, details::tag_com_query()); - } - - //! Query for the interface of the given out parameter `U`: `ptr.query_to(&foo);`. - //! See @ref page_query for more information. - //! - //! For fail-fast and exception-based behavior this routine should primarily be used to write to out parameters and @ref query should - //! be used to perform most queries. For error-code based code, this routine is the primary method that should be used to query a com_ptr. - //! - //! Error-code based samples: - //! ~~~~ - //! // class member being queried: - //! wil::com_ptr_nothrow m_ptr; - //! - //! // simple query example: - //! wil::com_ptr_nothrow foo; - //! RETURN_IF_FAILED(m_ptr.query_to(&foo)); - //! foo->FooMethod1(); - //! - //! // output parameter example: - //! HRESULT GetFoo(_COM_Outptr_ IFoo** fooPtr) - //! { - //! RETURN_IF_FAILED(m_ptr.query_to(fooPtr)); - //! return S_OK; - //! } - //! ~~~~ - //! Exception or fail-fast samples: - //! ~~~~ - //! // class member being queried - //! wil::com_ptr m_ptr; - //! - //! void GetFoo(_COM_Outptr_ IFoo** fooPtr) - //! { - //! m_ptr.query_to(fooPtr); - //! } - //! ~~~~ - //! @tparam U Represents the interface being queried (type of the output parameter). This interface does not need to - //! be specified directly. Rely upon template type deduction to pick up the type from the output parameter. - //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure. - //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, @ref com_agile_ref_nothrow) this - //! method returns an `HRESULT` indicating whether the query was successful. Exception-based and fail-fast based classes - //! do not return a value (void). - template - result query_to(_COM_Outptr_ U** ptrResult) const - { - // Prefast cannot see through the error policy + query_policy mapping and as a result fires 6388 and 28196 for this function. - // Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 28196) does not stop all of the prefast errors - // from being emitted. -#if defined(_PREFAST_) - *ptrResult = nullptr; - return err_policy::HResult(E_NOINTERFACE); -#else - return err_policy::HResult(query_policy::query(m_ptr, ptrResult)); -#endif - } - - //! Query for the requested interface using the iid, ppv pattern: `ptr.query_to(riid, ptr);`. - //! See @ref page_query for more information. - //! - //! This method is built to implement an API boundary that exposes a returned pointer to a caller through the REFIID and void** pointer - //! pattern (like QueryInterface). This pattern should not be used outside of that pattern (through IID_PPV_ARGS) as it is less efficient - //! than the typed version of @ref query_to which can elide the QueryInterface in favor of AddRef when the types are convertible. - //! ~~~~ - //! // class member being queried: - //! wil::com_ptr_nothrow m_ptr; - //! - //! // output parameter example: - //! HRESULT GetFoo(REFIID riid, _COM_Outptr_ void** ptrResult) - //! { - //! RETURN_IF_FAILED(m_ptr.query_to(riid, ptrResult)); - //! return S_OK; - //! } - //! ~~~~ - //! @param riid The interface to query for. - //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure. - //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, @ref com_agile_ref_nothrow) this - //! method returns an `HRESULT` indicating whether the query was successful. Exception-based and fail-fast based classes - //! do not return a value (void). - result query_to(REFIID riid, _COM_Outptr_ void** ptrResult) const - { - // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result fires 6388 and 28196 for this function. - // Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 28196) does not stop the prefast errors - // from being emitted. -#if defined(_PREFAST_) - *ptrResult = nullptr; - return err_policy::HResult(E_NOINTERFACE); -#else - return err_policy::HResult(query_policy::query(m_ptr, riid, ptrResult)); -#endif - } - //! @} - - //! @name Try query helpers - //! * Attempts to retrieves the requested interface - //! * AV if the pointer is null - //! * Produce null if the requested interface is unsupported - //! * bool returns 'true' when query was successful - //! - //! See @ref page_query for more information. - //! @{ - - //! Attempt a query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.try_query();` (null result when interface is unsupported). - //! See @ref page_query for more information. - //! - //! This method can be used to query a com_ptr for an interface when it's known that support for that interface is - //! optional (failing the query should not produce an error). The caller must examine the returned pointer to see - //! if it's null before using it: - //! ~~~~ - //! auto foo = ptr.try_query(); - //! if (foo) - //! { - //! foo->Method1(); - //! foo->Method2(); - //! } - //! ~~~~ - //! @tparam U Represents the interface being queried - //! @return A `com_ptr_t` pointer to the given interface `U`. The returned pointer will be null if the interface is - //! not supported. The returned `com_ptr_t` will have the same error handling policy (exceptions, failfast or error codes) as - //! the pointer being queried. - template - WI_NODISCARD inline com_ptr_t try_query() const - { - return com_ptr_t(m_ptr, details::tag_try_com_query()); - } - - //! Attempts to query for the interface matching the given output parameter; returns a bool indicating if the query was successful (non-null). - //! See @ref page_query for more information. - //! - //! This method can be used to perform a query against a non-null interface when it's known that support for that interface is - //! optional (failing the query should not produce an error). The caller must examine the returned bool before using the returned pointer. - //! ~~~~ - //! wil::com_ptr_nothrow foo; - //! if (ptr.try_query_to(&foo)) - //! { - //! foo->Method1(); - //! foo->Method2(); - //! } - //! ~~~~ - //! @param ptrResult The pointer to query for. The interface to query is deduced from the type of this out parameter; do not specify - //! the type directly to the template. - //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). - template - _Success_return_ bool try_query_to(_COM_Outptr_ U** ptrResult) const - { - return SUCCEEDED(query_policy::query(m_ptr, ptrResult)); - } - - //! Attempts a query for the requested interface using the iid, ppv pattern: `ptr.try_query_to(riid, ptr);`. - //! See @ref page_query for more information. - //! - //! This method is built to implement an API boundary that exposes a returned pointer to a caller through the REFIID and void** pointer - //! pattern (like QueryInterface). The key distinction is that this routine does not produce an error if the request isn't fulfilled, so - //! it's appropriate for `_COM_Outptr_result_maybenull_` cases. This pattern should not be used outside of that pattern (through IID_PPV_ARGS) as - //! it is less efficient than the typed version of @ref try_query_to which can elide the QueryInterface in favor of AddRef when the types are convertible. - //! The caller must examine the returned bool before using the returned pointer. - //! ~~~~ - //! // class member being queried: - //! wil::com_ptr_nothrow m_ptr; - //! - //! // output parameter example (result may be null): - //! HRESULT GetFoo(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) - //! { - //! m_ptr.try_query_to(riid, ptrResult); - //! return S_OK; - //! } - //! ~~~~ - //! @param riid The interface to query for. - //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure. - //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). - _Success_return_ bool try_query_to(REFIID riid, _COM_Outptr_ void** ptrResult) const - { - return SUCCEEDED(query_policy::query(m_ptr, riid, ptrResult)); - } - //! @} - - //! @name Copy helpers - //! * Retrieves the requested interface - //! * Succeeds with null if the pointer is null - //! * Produce an error if the requested interface is unsupported - //! - //! See @ref page_query for more information. - //! @{ - - //! Query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.copy();` (succeeds and returns a null ptr if the queried pointer is null). - //! See @ref page_query for more information. - //! - //! This method is identical to @ref query with the exception that it can be used when the pointer is null. When used - //! against a null pointer, the returned pointer will always be null and an error will not be produced. Like query it will - //! produce an error for a non-null pointer that does not support the requested interface. - //! @tparam U Represents the interface being queried - //! @return A `com_ptr_t` pointer to the given interface `U`. The pointer will be null ONLY if the pointer being queried is null. The returned - //! `com_ptr_t` type will be @ref com_ptr or @ref com_ptr_failfast (matching the error handling form of the - //! pointer being queried (exception based or fail-fast). - template - WI_NODISCARD inline com_ptr_t copy() const - { - static_assert(wistd::is_same::value, "copy requires exceptions or fail fast; use the try_copy or copy_to method"); - return com_ptr_t(m_ptr, details::tag_com_copy()); - } - - //! Query for the interface of the given out parameter `U`: `ptr.copy_to(&foo);` (succeeds and returns null ptr if the queried pointer is null). - //! See @ref page_query for more information. - //! - //! This method is identical to @ref query_to with the exception that it can be used when the pointer is null. When used - //! against a null pointer, the returned pointer will always be null and an error will not be produced. Like query_to it will - //! produce an error for a non-null pointer that does not support the requested interface. - //! @tparam U Represents the interface being queried (type of the output parameter). This interface does not need to - //! be specified directly. Rely upon template type deduction to pick up the type from the output parameter. - //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure OR assigned null - //! when the source pointer is null. - //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, @ref com_agile_ref_nothrow) this - //! method returns an `HRESULT` indicating whether the query was successful. Copying a null value is considered success. Exception-based - //! and fail-fast based classes do not return a value (void). - template - result copy_to(_COM_Outptr_result_maybenull_ U** ptrResult) const - { - if (m_ptr) - { - // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result fires 6388 and 28196 for this function. - // Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 28196) does not stop the prefast errors - // from being emitted. -#if defined(_PREFAST_) - *ptrResult = nullptr; - return err_policy::HResult(E_NOINTERFACE); -#else - return err_policy::HResult(query_policy::query(m_ptr, ptrResult)); -#endif - } - *ptrResult = nullptr; - return err_policy::OK(); - } - - //! Query for the requested interface using the iid, ppv pattern: `ptr.copy_to(riid, ptr);`. (succeeds and returns null ptr if the queried pointer is null). - //! See @ref page_query for more information. - //! - //! Identical to the corresponding @ref query_to method with the exception that it can be used when the pointer is null. When used - //! against a null pointer, the returned pointer will always be null and an error will not be produced. Like query_to it will - //! produce an error for a non-null pointer that does not support the requested interface. - //! @param riid The interface to query for. - //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure OR assigned null - //! when the source pointer is null. - //! @return For the nothrow (error code-based) classes (@ref com_ptr_nothrow, @ref com_weak_ref_nothrow, @ref com_agile_ref_nothrow) this - //! method returns an `HRESULT` indicating whether the query was successful. Copying a null value is considered success. Exception-based - //! and fail-fast based classes do not return a value (void). - result copy_to(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) const - { - if (m_ptr) - { - // Prefast cannot see through the error policy + query_policy mapping and as a result and as a result fires 6388 and 28196 for this function. - // Suppression is also not working. Wrapping this entire function in #pragma warning(disable: 6388 28196) does not stop the prefast errors - // from being emitted. -#if defined(_PREFAST_) - *ptrResult = nullptr; - return err_policy::HResult(E_NOINTERFACE); -#else - return err_policy::HResult(query_policy::query(m_ptr, riid, ptrResult)); -#endif - } - *ptrResult = nullptr; - return err_policy::OK(); - } - //! @} - - //! @name Try copy helpers - //! * Attempts to retrieves the requested interface - //! * Successfully produces null if the queried pointer is already null - //! * Produce null if the requested interface is unsupported - //! * bool returns 'false' ONLY when the queried pointer is not null and the requested interface is unsupported - //! - //! See @ref page_query for more information. - //! @{ - - //! Attempt a query and return a smart pointer matching the interface specified by 'U': `auto foo = m_ptr.try_query();` (null result when interface is unsupported or queried pointer is null). - //! See @ref page_query for more information. - //! - //! Identical to the corresponding @ref try_query method with the exception that it can be used when the pointer is null. When used - //! against a null pointer, the returned pointer will always be null and an error will not be produced. - //! @tparam U Represents the interface being queried - //! @return A `com_ptr_t` pointer to the given interface `U`. The returned pointer will be null if the interface was - //! not supported or the pointer being queried is null. The returned `com_ptr_t` will have the same error handling - //! policy (exceptions, failfast or error codes) as the pointer being queried. - template - WI_NODISCARD inline com_ptr_t try_copy() const - { - return com_ptr_t(m_ptr, details::tag_try_com_copy()); - } - - //! Attempts to query for the interface matching the given output parameter; returns a bool indicating if the query was successful (returns `false` if the pointer is null). - //! See @ref page_query for more information. - //! - //! Identical to the corresponding @ref try_query_to method with the exception that it can be used when the pointer is null. When used - //! against a null pointer, the returned pointer will be null and the return value will be `false`. - //! @param ptrResult The pointer to query for. The interface to query is deduced from the type of this out parameter; do not specify - //! the type directly to the template. - //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). - template - _Success_return_ bool try_copy_to(_COM_Outptr_result_maybenull_ U** ptrResult) const - { - if (m_ptr) - { - return SUCCEEDED(query_policy::query(m_ptr, ptrResult)); - } - *ptrResult = nullptr; - return false; - } - - //! Attempts a query for the requested interface using the iid, ppv pattern: `ptr.try_query_to(riid, ptr);` (returns `false` if the pointer is null) - //! See @ref page_query for more information. - //! - //! Identical to the corresponding @ref try_query_to method with the exception that it can be used when the pointer is null. When used - //! against a null pointer, the returned pointer will be null and the return value will be `false`. - //! @param riid The interface to query for. - //! @param ptrResult The output pointer that will receive the newly queried interface. This pointer will be assigned null on failure or - //! if the source pointer being queried is null. - //! @return A `bool` indicating `true` of the query was successful (the returned parameter is non-null). Querying a null - //! pointer will return `false` with a null result. - _Success_return_ bool try_copy_to(REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) const - { - if (m_ptr) - { - return SUCCEEDED(query_policy::query(m_ptr, riid, ptrResult)); - } - *ptrResult = nullptr; - return false; - } - //! @} - - //! @name WRL compatibility - //! @{ - - //! Copy construct from a compatible WRL ComPtr. - template > - com_ptr_t(const Microsoft::WRL::ComPtr& other) WI_NOEXCEPT : - com_ptr_t(static_cast(other.Get())) - { - } - - //! Move construct from a compatible WRL ComPtr. - template > - com_ptr_t(Microsoft::WRL::ComPtr&& other) WI_NOEXCEPT : - m_ptr(other.Detach()) - { - } - - //! Assign from a compatible WRL ComPtr. - template > - com_ptr_t& operator=(const Microsoft::WRL::ComPtr& other) WI_NOEXCEPT - { - return operator=(static_cast(other.Get())); - } - - //! Move assign from a compatible WRL ComPtr. - template > - com_ptr_t& operator=(Microsoft::WRL::ComPtr&& other) WI_NOEXCEPT - { - attach(other.Detach()); - return *this; - } - - //! Swap pointers with a WRL ComPtr to the same interface. - void swap(Microsoft::WRL::ComPtr& other) WI_NOEXCEPT - { - auto ptr = m_ptr; - m_ptr = other.Detach(); - other.Attach(ptr); - } - - //! Swap pointers with a rvalue reference to a WRL ComPtr to the same interface. - void swap(Microsoft::WRL::ComPtr&& other) WI_NOEXCEPT - { - swap(other); - } - //! @} // WRL compatibility - - public: - // Internal Helpers - /// @cond - template - inline com_ptr_t(_In_ U* ptr, details::tag_com_query) : m_ptr(nullptr) - { - err_policy::HResult(details::query_policy_t::query(ptr, &m_ptr)); - } - - template - inline com_ptr_t(_In_ U* ptr, details::tag_try_com_query) WI_NOEXCEPT : m_ptr(nullptr) - { - details::query_policy_t::query(ptr, &m_ptr); - } - - template - inline com_ptr_t(_In_opt_ U* ptr, details::tag_com_copy) : m_ptr(nullptr) - { - if (ptr) - { - err_policy::HResult(details::query_policy_t::query(ptr, &m_ptr)); - } - } - - template - inline com_ptr_t(_In_opt_ U* ptr, details::tag_try_com_copy) WI_NOEXCEPT : m_ptr(nullptr) - { - if (ptr) - { - details::query_policy_t::query(ptr, &m_ptr); - } - } - /// @endcond - - private: - pointer m_ptr; - }; - - // Error-policy driven forms of com_ptr - -#ifdef WIL_ENABLE_EXCEPTIONS - //! COM pointer, errors throw exceptions (see @ref com_ptr_t for details) - template - using com_ptr = com_ptr_t; -#endif - - //! COM pointer, errors return error codes (see @ref com_ptr_t for details) - template - using com_ptr_nothrow = com_ptr_t; - - //! COM pointer, errors fail-fast (see @ref com_ptr_t for details) - template - using com_ptr_failfast = com_ptr_t; - - - // Global operators / swap - - //! Swaps the given com pointers that have different error handling. - //! Note that there are also corresponding versions to allow you to swap any wil com_ptr with a WRL ComPtr. - template - inline void swap(com_ptr_t& left, com_ptr_t& right) WI_NOEXCEPT - { - left.swap(right); - } - - //! Swaps the given com pointers that have the same error handling. - template - inline void swap(com_ptr_t& left, com_ptr_t& right) WI_NOEXCEPT - { - left.swap(right); - } - - //! Compare two com pointers. - //! Compares the two raw com pointers for equivalence. Does NOT compare object identity with a QI for IUnknown. - //! - //! Note that documentation for all of the various comparators has not been generated to reduce global function - //! clutter, but ALL standard comparison operators are supported between wil com_ptr objects, nullptr_t, and - //! WRL ComPtr. - template - inline bool operator==(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT - { - static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); - return (left.get() == right.get()); - } - - // We don't document all of the global comparison operators (reduce clutter) - /// @cond - template - inline bool operator<(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT - { - static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); - return (left.get() < right.get()); - } - - template - inline bool operator==(const com_ptr_t& left, wistd::nullptr_t) WI_NOEXCEPT - { - return (left.get() == nullptr); - } - - template - inline bool operator!=(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT - { return (!(left == right)); } - - template - inline bool operator>=(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT - { return (!(left < right)); } - - template - inline bool operator>(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT - { return (right < left); } - - template - inline bool operator<=(const com_ptr_t& left, const com_ptr_t& right) WI_NOEXCEPT - { return (!(right < left)); } - - template - inline bool operator==(wistd::nullptr_t, const com_ptr_t& right) WI_NOEXCEPT - { - return (right.get() == nullptr); - } - - template - inline bool operator!=(const com_ptr_t& left, wistd::nullptr_t) WI_NOEXCEPT - { return (!(left == nullptr)); } - - template - inline bool operator!=(wistd::nullptr_t, const com_ptr_t& right) WI_NOEXCEPT - { return (!(right == nullptr)); } - - // WRL ComPtr support - - template - inline void swap(com_ptr_t& left, Microsoft::WRL::ComPtr& right) WI_NOEXCEPT - { - left.swap(right); - } - - template - inline bool operator==(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT - { - static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); - return (left.get() == right.Get()); - } - - template - inline bool operator<(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT - { - static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); - return (left.get() < right.Get()); - } - - template - inline bool operator!=(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT - { return (!(left == right)); } - - template - inline bool operator>=(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT - { return (!(left < right)); } - - template - inline bool operator>(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT - { return (right < left); } - - template - inline bool operator<=(const com_ptr_t& left, const Microsoft::WRL::ComPtr& right) WI_NOEXCEPT - { return (!(right < left)); } - - template - inline void swap(Microsoft::WRL::ComPtr& left, com_ptr_t& right) WI_NOEXCEPT - { - right.swap(left); - } - - template - inline bool operator==(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT - { - static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); - return (left.Get() == right.get()); - } - - template - inline bool operator<(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT - { - static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); - return (left.Get() < right.get()); - } - - template - inline bool operator!=(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT - { return (!(left == right)); } - - template - inline bool operator>=(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT - { return (!(left < right)); } - - template - inline bool operator>(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT - { return (right < left); } - - template - inline bool operator<=(const Microsoft::WRL::ComPtr& left, const com_ptr_t& right) WI_NOEXCEPT - { return (!(right < left)); } - - // raw COM pointer support - // - // Use these for convenience and to avoid unnecessary AddRef/Release cyles when using raw - // pointers to access STL containers. Specify std::less<> to benefit from operator<. - // - // Example: std::set, std::less<>> set; - - template - inline bool operator==(const com_ptr_t& left, TRight* right) WI_NOEXCEPT - { - static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); - return (left.get() == right); - } - - template - inline bool operator<(const com_ptr_t& left, TRight* right) WI_NOEXCEPT - { - static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); - return (left.get() < right); - } - - template - inline bool operator!=(const com_ptr_t& left, TRight* right) WI_NOEXCEPT - { return (!(left == right)); } - - template - inline bool operator>=(const com_ptr_t& left, TRight* right) WI_NOEXCEPT - { return (!(left < right)); } - - template - inline bool operator>(const com_ptr_t& left, TRight* right) WI_NOEXCEPT - { return (right < left); } - - template - inline bool operator<=(const com_ptr_t& left, TRight* right) WI_NOEXCEPT - { return (!(right < left)); } - - template - inline bool operator==(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT - { - static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); - return (left == right.get()); - } - - template - inline bool operator<(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT - { - static_assert(__is_convertible_to(TLeft*, TRight*) || __is_convertible_to(TRight*, TLeft*), "comparison operator requires left and right pointers to be compatible"); - return (left < right.get()); - } - - template - inline bool operator!=(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT - { return (!(left == right)); } - - template - inline bool operator>=(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT - { return (!(left < right)); } - - template - inline bool operator>(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT - { return (right < left); } - - template - inline bool operator<=(TLeft* left, const com_ptr_t& right) WI_NOEXCEPT - { return (!(right < left)); } - - // suppress documentation of every single comparison operator - /// @endcond - - - //! An overloaded function that retrieves the raw com pointer from a raw pointer, wil::com_ptr_t, WRL ComPtr, or Platform::Object^. - //! This function is primarily useful by library or helper code. It allows code to be written to accept a forwarding reference - //! template that can be used as an input com pointer. That input com pointer is allowed to be any of: - //! * Raw Pointer: `T* com_raw_ptr(T* ptr)` - //! * Wil com_ptr: `T* com_raw_ptr(const wil::com_ptr_t& ptr)` - //! * WRL ComPtr: `T* com_raw_ptr(const Microsoft::WRL::ComPtr& ptr)` - //! * C++/CX hat: `IInspectable* com_raw_ptr(Platform::Object^ ptr)` - //! - //! Which in turn allows code like the following to be written: - //! ~~~~ - //! template - //! void com_query_to(T&& ptrSource, _COM_Outptr_ U** ptrResult) - //! { - //! auto raw = com_raw_ptr(wistd::forward(ptrSource)); - //! // decltype(raw) has the type of the inner pointer and raw is guaranteed to be a raw com pointer - //! ~~~~ - template - T* com_raw_ptr(T* ptr) - { - return ptr; - } - - /// @cond - template - T* com_raw_ptr(const wil::com_ptr_t& ptr) - { - return ptr.get(); - } - - template - T* com_raw_ptr(const Microsoft::WRL::ComPtr& ptr) - { - return ptr.Get(); - } - -#ifdef __cplusplus_winrt - - template - inline IInspectable* com_raw_ptr(T^ ptr) - { - return reinterpret_cast(static_cast<::Platform::Object^>(ptr)); - } - -#endif - /// @endcond - -#ifdef WIL_ENABLE_EXCEPTIONS - //! Constructs a `com_ptr` from a raw pointer. - //! This avoids having to restate the interface in pre-C++20. - //! Starting in C++20, you can write `wil::com_ptr(p)` directly. - //! ~~~ - //! void example(ILongNamedThing* thing) - //! { - //! callback([thing = wil::make_com_ptr(thing)] { /* do something */ }); - //! } - //! ~~~ - template - com_ptr make_com_ptr(T* p) { return p; } -#endif - - //! Constructs a `com_ptr_nothrow` from a raw pointer. - //! This avoids having to restate the interface in pre-C++20. - //! Starting in C++20, you can write `wil::com_ptr_nothrow(p)` directly. - //! ~~~ - //! void example(ILongNamedThing* thing) - //! { - //! callback([thing = wil::make_com_ptr_nothrow(thing)] { /* do something */ }); - //! } - //! ~~~ - template - com_ptr_nothrow make_com_ptr_nothrow(T* p) { return p; } - - //! Constructs a `com_ptr_failfast` from a raw pointer. - //! This avoids having to restate the interface in pre-C++20. - //! Starting in C++20, you can write `wil::com_ptr_failfast(p)` directly. - //! ~~~ - //! void example(ILongNamedThing* thing) - //! { - //! callback([thing = wil::make_com_ptr_failfast(thing)] { /* do something */ }); - //! } - //! ~~~ - template - com_ptr_failfast make_com_ptr_failfast(T* p) { return p; } - - //! @name Stand-alone query helpers - //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr - //! * Retrieves the requested interface - //! * AV if the source pointer is null - //! * Produce an error if the requested interface is unsupported - //! - //! See @ref page_query for more information - //! @{ - -#ifdef WIL_ENABLE_EXCEPTIONS - //! Queries for the specified interface and returns an exception-based wil::com_ptr to that interface (exception if unsupported). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null - //! @tparam U Represents the interface being queried - //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is guaranteed not null. - template - inline com_ptr com_query(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr(raw, details::tag_com_query()); - } -#endif - - //! Queries for the specified interface and returns a fail-fast-based wil::com_ptr_failfast to that interface (fail-fast if unsupported). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null - //! @tparam U Represents the interface being queried - //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is guaranteed not null. - template - inline com_ptr_failfast com_query_failfast(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr_failfast(raw, details::tag_com_query()); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - //! Queries for the interface specified by the type of the output parameter (throws an exception if unsupported). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null - //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. - template - _Success_true_ void com_query_to(T&& ptrSource, _COM_Outptr_ U** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - THROW_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); - __analysis_assume(*ptrResult != nullptr); - } -#endif - - //! Queries for the interface specified by the type of the output parameter (fail-fast if unsupported). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null - //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. - template - _Success_true_ void com_query_to_failfast(T&& ptrSource, _COM_Outptr_ U** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); - __analysis_assume(*ptrResult != nullptr); - } - - //! Queries for the interface specified by the type of the output parameter (returns an error if unsupported). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null - //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure. - //! @return Returns an HRESULT representing whether the query succeeded. - template - HRESULT com_query_to_nothrow(T&& ptrSource, _COM_Outptr_ U** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - auto hr = details::query_policy_t::query(raw, ptrResult); - __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); - return hr; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - //! Queries for the interface specified by the given REFIID parameter (throws an exception if unsupported). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null - //! @param riid The interface to query for - //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. - template - _Success_true_ void com_query_to(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - THROW_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); - __analysis_assume(*ptrResult != nullptr); - } -#endif - - //! Queries for the interface specified by the given REFIID parameter (fail-fast if unsupported). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null - //! @param riid The interface to query for - //! @param ptrResult Represents the output pointer to populate. The returned pointer is guaranteed not null. - template - _Success_true_ void com_query_to_failfast(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); - __analysis_assume(*ptrResult != nullptr); - } - - //! Queries for the interface specified by the given REFIID parameter (returns an error if unsupported). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null - //! @param riid The interface to query for - //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure. - template - HRESULT com_query_to_nothrow(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - auto hr = details::query_policy_t::query(raw, riid, ptrResult); - __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); - return hr; - } - //! @} - - //! @name Stand-alone try query helpers - //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr - //! * Attempts to retrieves the requested interface - //! * AV if the source pointer is null - //! * Produce null if the requested interface is unsupported - //! * bool returns 'true' when query was successful (non-null return result) - //! - //! See @ref page_query for more information. - //! @{ - -#ifdef WIL_ENABLE_EXCEPTIONS - //! Attempts a query for the specified interface and returns an exception-based wil::com_ptr to that interface (returns null if unsupported). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null - //! @tparam U Represents the interface being queried - //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported. - template - inline com_ptr try_com_query(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr(raw, details::tag_try_com_query()); - } -#endif - - //! Attempts a query for the specified interface and returns an fail-fast wil::com_ptr_failfast to that interface (returns null if unsupported). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null - //! @tparam U Represents the interface being queried - //! @return A `wil::com_ptr_failfast` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported. - template - inline com_ptr_failfast try_com_query_failfast(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr_failfast(raw, details::tag_try_com_query()); - } - - //! Attempts a query for the specified interface and returns an error-code-based wil::com_ptr_nothrow to that interface (returns null if unsupported). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null - //! @tparam U Represents the interface being queried - //! @return A `wil::com_ptr_nothrow` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported. - template - inline com_ptr_nothrow try_com_query_nothrow(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr_nothrow(raw, details::tag_try_com_query()); - } - - //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null. - //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be null. - //! @return A bool value representing whether the query was successful (non-null return result). - template - _Success_return_ bool try_com_query_to(T&& ptrSource, _COM_Outptr_ U** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return (SUCCEEDED(details::query_policy_t::query(raw, ptrResult))); - } - - //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), should not be null. - //! @param riid The interface to query for - //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be null. - //! @return A bool value representing whether the query was successful (non-null return result). - template - _Success_return_ bool try_com_query_to(T&& ptrSource, REFIID riid, _COM_Outptr_ void** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return (SUCCEEDED(details::query_policy_t::query(raw, riid, ptrResult))); - } - //! @} - - - //! @name Stand-alone copy helpers - //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr - //! * Retrieves the requested interface - //! * Succeeds with null if the source pointer is null - //! * Produce an error if the requested interface is unsupported - //! - //! See @ref page_query for more information - //! @{ - -#ifdef WIL_ENABLE_EXCEPTIONS - //! Queries for the specified interface and returns an exception-based wil::com_ptr to that interface (exception if unsupported, preserves null). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null - //! @tparam U Represents the interface being queried - //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer will be null only if the source is null. - template - inline com_ptr com_copy(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr(raw, details::tag_com_copy()); - } -#endif - - //! Queries for the specified interface and returns a fail-fast-based wil::com_ptr_failfast to that interface (fail-fast if unsupported, preserves null). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null - //! @tparam U Represents the interface being queried - //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer will be null only if the source is null. - template - inline com_ptr_failfast com_copy_failfast(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr_failfast(raw, details::tag_com_copy()); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - //! Queries for the interface specified by the type of the output parameter (throws an exception if unsupported, preserves null). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null - //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null. - template - _Success_true_ void com_copy_to(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) - { - THROW_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); - return; - } - *ptrResult = nullptr; - } -#endif - - //! Queries for the interface specified by the type of the output parameter (fail-fast if unsupported, preserves null). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null - //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null. - template - _Success_true_ void com_copy_to_failfast(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) - { - FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, ptrResult)); - return; - } - *ptrResult = nullptr; - } - - //! Queries for the interface specified by the type of the output parameter (returns an error if unsupported, preserves null). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null - //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure or if the source is null. - //! @return Returns an HRESULT representing whether the query succeeded (returns S_OK if the source is null). - template - HRESULT com_copy_to_nothrow(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) - { - RETURN_HR(details::query_policy_t::query(raw, ptrResult)); - } - *ptrResult = nullptr; - return S_OK; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - //! Queries for the interface specified by the given REFIID parameter (throws an exception if unsupported, preserves null). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null - //! @param riid The interface to query for - //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null. - template - _Success_true_ void com_copy_to(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) - { - THROW_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); - return; - } - *ptrResult = nullptr; - } -#endif - - //! Queries for the interface specified by the given REFIID parameter (fail-fast if unsupported, preserves null). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null - //! @param riid The interface to query for - //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null only if the source is null. - template - _Success_true_ void com_copy_to_failfast(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) - { - FAIL_FAST_IF_FAILED(details::query_policy_t::query(raw, riid, ptrResult)); - return; - } - *ptrResult = nullptr; - } - - //! Queries for the interface specified by the given REFIID parameter (returns an error if unsupported, preserves null). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null - //! @param riid The interface to query for - //! @param ptrResult Represents the output pointer to populate. The returned pointer will be null upon failure or if the source is null. - //! @return Returns an HRESULT representing whether the query succeeded (returns S_OK if the source is null). - template - HRESULT com_copy_to_nothrow(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) - { - RETURN_HR(details::query_policy_t::query(raw, riid, ptrResult)); - } - *ptrResult = nullptr; - return S_OK; - } - //! @} - - - //! @name Stand-alone try copy helpers - //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr - //! * Attempts to retrieves the requested interface - //! * Succeeds with null if the source pointer is null - //! * Produce null if the requested interface is unsupported - //! * bool returns 'true' when query was successful (non-null return result) - //! - //! See @ref page_query for more information. - //! @{ - -#ifdef WIL_ENABLE_EXCEPTIONS - //! Attempts a query for the specified interface and returns an exception-based wil::com_ptr to that interface (returns null if unsupported, preserves null). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null - //! @tparam U Represents the interface being queried - //! @return A `wil::com_ptr` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported. - template - inline com_ptr try_com_copy(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr(raw, details::tag_try_com_copy()); - } -#endif - - //! Attempts a query for the specified interface and returns an fail-fast wil::com_ptr_failfast to that interface (returns null if unsupported, preserves null). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null - //! @tparam U Represents the interface being queried - //! @return A `wil::com_ptr_failfast` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported. - template - inline com_ptr_failfast try_com_copy_failfast(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr_failfast(raw, details::tag_try_com_copy()); - } - - //! Attempts a query for the specified interface and returns an error-code-based wil::com_ptr_nothrow to that interface (returns null if unsupported, preserves null). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null - //! @tparam U Represents the interface being queried - //! @return A `wil::com_ptr_nothrow` pointer to the given interface `U`. The returned pointer is null if the requested interface was not supported. - template - inline com_ptr_nothrow try_com_copy_nothrow(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - return com_ptr_nothrow(raw, details::tag_try_com_copy()); - } - - //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported, preserves null). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null. - //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be null. - //! @return A bool value representing whether the query was successful (non-null return result). - template - _Success_return_ bool try_com_copy_to(T&& ptrSource, _COM_Outptr_result_maybenull_ U** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) - { - return SUCCEEDED(details::query_policy_t::query(raw, ptrResult)); - } - *ptrResult = nullptr; - return false; - } - - //! Attempts a query for the interface specified by the type of the output parameter (returns `false` if unsupported, preserves null). - //! See @ref page_query for more information. - //! @param ptrSource The pointer to query (may be a raw interface pointer, wil com_ptr, or WRL ComPtr), may be null. - //! @param riid The interface to query for - //! @param ptrResult Represents the output pointer to populate. If the interface is unsupported, the returned pointer will be null. - //! @return A bool value representing whether the query was successful (non-null return result). - template - _Success_return_ bool try_com_copy_to(T&& ptrSource, REFIID riid, _COM_Outptr_result_maybenull_ void** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) - { - return SUCCEEDED(details::query_policy_t::query(raw, riid, ptrResult)); - } - *ptrResult = nullptr; - return false; - } - //! @} - -#ifdef __cplusplus_winrt - //! @name Stand-alone helpers to query for CX ref ("hat") types from ABI COM types. - //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr - //! * Retrieves the requested C++/CX interface or ref class. - //! * Preserves null if the source pointer is null - //! * Produce an error if the requested interface is unsupported - //! - //! See @ref page_query for more information - //! @{ - - template - ::Platform::Object^ cx_object_from_abi(T&& ptr) WI_NOEXCEPT - { - IInspectable* const inspectable = com_raw_ptr(wistd::forward(ptr)); - return reinterpret_cast<::Platform::Object^>(inspectable); - } - - template - inline U^ cx_safe_cast(T&& ptrSource) - { - return safe_cast(cx_object_from_abi(wistd::forward(ptrSource))); - } - - template - inline U^ cx_dynamic_cast(T&& ptrSource) WI_NOEXCEPT - { - return dynamic_cast(cx_object_from_abi(wistd::forward(ptrSource))); - } - //! @} -#endif - - - //***************************************************************************** - // Agile References - //***************************************************************************** - -#if (NTDDI_VERSION >= NTDDI_WINBLUE) -#ifdef WIL_ENABLE_EXCEPTIONS - //! Agile reference to a COM interface, errors throw exceptions (see @ref com_ptr_t and @ref com_agile_query for details) - using com_agile_ref = com_ptr; -#endif - //! Agile reference to a COM interface, errors return error codes (see @ref com_ptr_t and @ref com_agile_query_nothrow for details) - using com_agile_ref_nothrow = com_ptr_nothrow; - //! Agile reference to a COM interface, errors fail fast (see @ref com_ptr_t and @ref com_agile_query_failfast for details) - using com_agile_ref_failfast = com_ptr_failfast; - - //! @name Create agile reference helpers - //! * Attempts to retrieve an agile reference to the requested interface (see [RoGetAgileReference](https://msdn.microsoft.com/en-us/library/dn269839.aspx)) - //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr - //! * `query` methods AV if the source pointer is null - //! * `copy` methods succeed with null if the source pointer is null - //! * Accept optional [AgileReferenceOptions](https://msdn.microsoft.com/en-us/library/dn269836.aspx) - //! - //! See @ref page_query for more information on resolving an agile ref - //! @{ - -#ifdef WIL_ENABLE_EXCEPTIONS - //! return a com_agile_ref representing the given source pointer (throws an exception on failure) - template - com_agile_ref com_agile_query(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_agile_ref agileRef; - THROW_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); - return agileRef; - } -#endif - - //! return a com_agile_ref_failfast representing the given source pointer (fail-fast on failure) - template - com_agile_ref_failfast com_agile_query_failfast(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_agile_ref_failfast agileRef; - FAIL_FAST_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); - return agileRef; - } - - //! return a com_agile_ref_nothrow representing the given source pointer (returns an HRESULT on failure) - template - HRESULT com_agile_query_nothrow(T&& ptrSource, _COM_Outptr_ IAgileReference** ptrResult, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - auto hr = ::RoGetAgileReference(options, __uuidof(raw), raw, ptrResult); - __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); - return hr; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - //! return a com_agile_ref representing the given source pointer (throws an exception on failure, source maybe null) - template - com_agile_ref com_agile_copy(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_agile_ref agileRef; - if (raw) - { - THROW_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); - } - return agileRef; - } -#endif - - //! return a com_agile_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null) - template - com_agile_ref_failfast com_agile_copy_failfast(T&& ptrSource, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_agile_ref_failfast agileRef; - if (raw) - { - FAIL_FAST_IF_FAILED(::RoGetAgileReference(options, __uuidof(raw), raw, &agileRef)); - } - return agileRef; - } - - //! return an agile ref (com_agile_ref_XXX or other representation) representing the given source pointer (return error on failure, source maybe null) - template - HRESULT com_agile_copy_nothrow(T&& ptrSource, _COM_Outptr_result_maybenull_ IAgileReference** ptrResult, AgileReferenceOptions options = AGILEREFERENCE_DEFAULT) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) - { - RETURN_HR(::RoGetAgileReference(options, __uuidof(raw), raw, ptrResult)); - } - *ptrResult = nullptr; - return S_OK; - } - //! @} -#endif - - //***************************************************************************** - // Weak References - //***************************************************************************** - - namespace details - { - template - HRESULT GetWeakReference(T* ptr, _COM_Outptr_ IWeakReference** weakReference) - { - static_assert(!wistd::is_same::value, "Cannot get an IWeakReference to an IWeakReference"); - - *weakReference = nullptr; - com_ptr_nothrow source; - HRESULT hr = ptr->QueryInterface(IID_PPV_ARGS(&source)); - if (SUCCEEDED(hr)) - { - hr = source->GetWeakReference(weakReference); - } - return hr; - } - } - -#ifdef WIL_ENABLE_EXCEPTIONS - //! Weak reference to a COM interface, errors throw exceptions (see @ref com_ptr_t and @ref com_weak_query for details) - using com_weak_ref = com_ptr; -#endif - //! Weak reference to a COM interface, errors return error codes (see @ref com_ptr_t and @ref com_weak_query_nothrow for details) - using com_weak_ref_nothrow = com_ptr_nothrow; - //! Weak reference to a COM interface, errors fail fast (see @ref com_ptr_t and @ref com_weak_query_failfast for details) - using com_weak_ref_failfast = com_ptr_failfast; - - //! @name Create weak reference helpers - //! * Attempts to retrieve a weak reference to the requested interface (see WRL's similar [WeakRef](https://msdn.microsoft.com/en-us/library/br244853.aspx)) - //! * Source pointer can be raw interface pointer, any wil com_ptr, or WRL ComPtr - //! * `query` methods AV if the source pointer is null - //! * `copy` methods succeed with null if the source pointer is null - //! - //! See @ref page_query for more information on resolving a weak ref - //! @{ - -#ifdef WIL_ENABLE_EXCEPTIONS - //! return a com_weak_ref representing the given source pointer (throws an exception on failure) - template - com_weak_ref com_weak_query(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_weak_ref weakRef; - THROW_IF_FAILED(details::GetWeakReference(raw, &weakRef)); - return weakRef; - } -#endif - - //! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure) - template - com_weak_ref_failfast com_weak_query_failfast(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_weak_ref_failfast weakRef; - FAIL_FAST_IF_FAILED(details::GetWeakReference(raw, &weakRef)); - return weakRef; - } - - //! return a com_weak_ref_nothrow representing the given source pointer (returns an HRESULT on failure) - template - HRESULT com_weak_query_nothrow(T&& ptrSource, _COM_Outptr_ IWeakReference** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - auto hr = details::GetWeakReference(raw, ptrResult); - __analysis_assume(SUCCEEDED(hr) || (*ptrResult == nullptr)); - return hr; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - //! return a com_weak_ref representing the given source pointer (throws an exception on failure, source maybe null) - template - com_weak_ref com_weak_copy(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_weak_ref weakRef; - if (raw) - { - THROW_IF_FAILED(details::GetWeakReference(raw, &weakRef)); - } - return weakRef; - } -#endif - - //! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null) - template - com_weak_ref_failfast com_weak_copy_failfast(T&& ptrSource) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - com_weak_ref_failfast weakRef; - if (raw) - { - FAIL_FAST_IF_FAILED(details::GetWeakReference(raw, &weakRef)); - } - return weakRef; - } - - //! return a com_weak_ref_failfast representing the given source pointer (fail-fast on failure, source maybe null) - template - HRESULT com_weak_copy_nothrow(T&& ptrSource, _COM_Outptr_result_maybenull_ IWeakReference** ptrResult) - { - auto raw = com_raw_ptr(wistd::forward(ptrSource)); - if (raw) - { - RETURN_HR(details::GetWeakReference(raw, ptrResult)); - } - *ptrResult = nullptr; - return S_OK; - } - -#pragma region COM Object Helpers - - template - inline bool is_agile(T&& ptrSource) - { - wil::com_ptr_nothrow agileObject; - return SUCCEEDED(com_raw_ptr(wistd::forward(ptrSource))->QueryInterface(IID_PPV_ARGS(&agileObject))); - } - - /** constructs a COM object using an CLSID on a specific interface or IUnknown.*/ - template - wil::com_ptr_t CoCreateInstance(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) - { - wil::com_ptr_t result; - error_policy::HResult(::CoCreateInstance(rclsid, nullptr, dwClsContext, IID_PPV_ARGS(&result))); - return result; - } - - /** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or IUnknown. */ - template - wil::com_ptr_t CoCreateInstance(DWORD dwClsContext = CLSCTX_INPROC_SERVER) - { - return CoCreateInstance(__uuidof(Class), dwClsContext); - } - - /** constructs a COM object using an CLSID on a specific interface or IUnknown. */ - template - wil::com_ptr_failfast CoCreateInstanceFailFast(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT - { - return CoCreateInstance(rclsid, dwClsContext); - } - - /** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or IUnknown. */ - template - wil::com_ptr_failfast CoCreateInstanceFailFast(DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT - { - return CoCreateInstanceFailFast(__uuidof(Class), dwClsContext); - } - - /** constructs a COM object using an CLSID on a specific interface or IUnknown. - Note, failures are reported as a null result, the HRESULT is lost. */ - template - wil::com_ptr_nothrow CoCreateInstanceNoThrow(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT - { - return CoCreateInstance(rclsid, dwClsContext); - } - - /** constructs a COM object using the class as the identifier (that has an associated CLSID) on a specific interface or IUnknown. - Note, failures are reported as a null result, the HRESULT is lost. */ - template - wil::com_ptr_nothrow CoCreateInstanceNoThrow(DWORD dwClsContext = CLSCTX_INPROC_SERVER) WI_NOEXCEPT - { - return CoCreateInstanceNoThrow(__uuidof(Class), dwClsContext); - } - - /** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. */ - template - wil::com_ptr_t CoGetClassObject(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) - { - wil::com_ptr_t result; - error_policy::HResult(CoGetClassObject(rclsid, dwClsContext, nullptr, IID_PPV_ARGS(&result))); - return result; - } - - /** constructs a COM object class factory using the class as the identifier (that has an associated CLSID) - on IClassFactory or a specific interface. */ - template - wil::com_ptr_t CoGetClassObject(DWORD dwClsContext = CLSCTX_INPROC_SERVER) - { - return CoGetClassObject(__uuidof(Class), dwClsContext); - } - - /** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. */ - template - wil::com_ptr_failfast CoGetClassObjectFailFast(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) - { - return CoGetClassObject(rclsid, dwClsContext); - } - - /** constructs a COM object class factory using the class as the identifier (that has an associated CLSID) - on IClassFactory or a specific interface. */ - template - wil::com_ptr_failfast CoGetClassObjectFailFast(DWORD dwClsContext = CLSCTX_INPROC_SERVER) - { - return CoGetClassObjectFailFast(__uuidof(Class), dwClsContext); - } - - /** constructs a COM object class factory using an CLSID on IClassFactory or a specific interface. - Note, failures are reported as a null result, the HRESULT is lost. */ - template - wil::com_ptr_nothrow CoGetClassObjectNoThrow(REFCLSID rclsid, DWORD dwClsContext = CLSCTX_INPROC_SERVER) - { - return CoGetClassObject(rclsid, dwClsContext); - } - - /** constructs a COM object class factory using the class as the identifier (that has an associated CLSID) - on IClassFactory or a specific interface. - Note, failures are reported as a null result, the HRESULT is lost. */ - template - wil::com_ptr_nothrow CoGetClassObjectNoThrow(DWORD dwClsContext = CLSCTX_INPROC_SERVER) - { - return CoGetClassObjectNoThrow(__uuidof(Class), dwClsContext); - } - -#if __cpp_lib_apply && __has_include() - namespace details - { - template - auto CoCreateInstanceEx(REFCLSID clsid, CLSCTX clsCtx) noexcept - { - MULTI_QI multiQis[sizeof...(Results)]{}; - const IID* iids[sizeof...(Results)]{ &__uuidof(Results)... }; - - static_assert(sizeof...(Results) > 0); - - for (auto i = 0U; i < sizeof...(Results); ++i) - { - multiQis[i].pIID = iids[i]; - } - - const auto hr = CoCreateInstanceEx(clsid, nullptr, clsCtx, nullptr, - ARRAYSIZE(multiQis), multiQis); - - std::tuple...> resultTuple; - - std::apply([i = 0, &multiQis](auto&... a) mutable - { - (a.attach(reinterpret_cast::type::pointer>(multiQis[i++].pItf)), ...); - }, resultTuple); - return std::tuple(hr, std::move(resultTuple)); - } - - template - auto com_multi_query(IUnknown* obj) - { - MULTI_QI multiQis[sizeof...(Results)]{}; - const IID* iids[sizeof...(Results)]{ &__uuidof(Results)... }; - - static_assert(sizeof...(Results) > 0); - - for (auto i = 0U; i < sizeof...(Results); ++i) - { - multiQis[i].pIID = iids[i]; - } - - std::tuple...> resultTuple{}; - - wil::com_ptr_nothrow multiQi; - auto hr = obj->QueryInterface(IID_PPV_ARGS(&multiQi)); - if (SUCCEEDED(hr)) - { - hr = multiQi->QueryMultipleInterfaces(ARRAYSIZE(multiQis), multiQis); - std::apply([i = 0, &multiQis](auto&... a) mutable - { - (a.attach(reinterpret_cast::type::pointer>(multiQis[i++].pItf)), ...); - }, resultTuple); - } - return std::tuple{hr, std::move(resultTuple)}; - } - } - -#ifdef WIL_ENABLE_EXCEPTIONS - // CoCreateInstanceEx can be used to improve performance by requesting multiple interfaces - // from an object at create time. This is most useful for out of process (OOP) servers, saving - // and RPC per extra interface requested. - template - auto CoCreateInstanceEx(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) - { - auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); - THROW_IF_FAILED(error); - THROW_HR_IF(E_NOINTERFACE, error == CO_S_NOTALLINTERFACES); - return result; - } - - template - auto TryCoCreateInstanceEx(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) - { - auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); - return result; - } -#endif - - // Returns [error, result] where result is a tuple with each of the requested interfaces. - template - auto CoCreateInstanceExNoThrow(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept - { - auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); - if (SUCCEEDED(error) && (error == CO_S_NOTALLINTERFACES)) - { - return std::tuple{E_NOINTERFACE, {}}; - } - return std::tuple{error, result}; - } - - template - auto TryCoCreateInstanceExNoThrow(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept - { - auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); - return result; - } - - template - auto CoCreateInstanceExFailFast(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept - { - auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); - FAIL_FAST_IF_FAILED(error); - FAIL_FAST_HR_IF(E_NOINTERFACE, error == CO_S_NOTALLINTERFACES); - return result; - } - - template - auto TryCoCreateInstanceExFailFast(REFCLSID clsid, CLSCTX clsCtx = CLSCTX_LOCAL_SERVER) noexcept - { - auto [error, result] = details::CoCreateInstanceEx(clsid, clsCtx); - return result; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - template - auto com_multi_query(IUnknown* obj) - { - auto [error, result] = details::com_multi_query(obj); - THROW_IF_FAILED(error); - THROW_HR_IF(E_NOINTERFACE, error == S_FALSE); - return result; - } - - template - auto try_com_multi_query(IUnknown* obj) - { - auto [error, result] = details::com_multi_query(obj); - return result; - } -#endif - -#endif // __cpp_lib_apply && __has_include() - -#pragma endregion - -#pragma region Stream helpers - - /** Read data from a stream into a buffer. - Reads up to a certain number of bytes into a buffer. Returns the amount of data written, which - may be less than the amount requested if the stream ran out. - ~~~~ - IStream* source = // ... - ULONG dataBlob = 0; - size_t read = 0; - RETURN_IF_FAILED(wil::stream_read_partial_nothrow(source, &dataBlob, sizeof(dataBlob), &read)); - if (read != sizeof(dataBlob)) - { - // end of stream, probably - } - else if (dataBlob == 0x8675309) - { - DoThing(dataBlob); - } - ~~~~ - @param stream The stream from which to read at most `size` bytes. - @param data A buffer into which up to `size` bytes will be read - @param size The size, in bytes, of the buffer pointed to by `data` - @param wrote The amount, in bytes, of data read from `stream` into `data` - */ - inline HRESULT stream_read_partial_nothrow(_In_ ISequentialStream* stream, _Out_writes_bytes_to_(size, *wrote) void* data, unsigned long size, unsigned long *wrote) - { - RETURN_HR(stream->Read(data, size, wrote)); - } - - /** Read an exact number of bytes from a stream into a buffer. - Fails if the stream didn't read all the bytes requested. - ~~~~ - IStream* source = // ... - ULONG dataBlob = 0; - RETURN_IF_FAILED(wil::stream_read_nothrow(source, &dataBlob, sizeof(dataBlob))); - if (dataBlob == 0x8675309) - { - DoThing(dataBlob); - } - ~~~~ - @param stream The stream from which to read at most `size` bytes. - @param data A buffer into which up to `size` bytes will be read - @param size The size, in bytes, of the buffer pointed to by `data` - @return The underlying stream read result, or HRESULT_FROM_WIN32(ERROR_INVALID_DATA) if the stream - did not read the complete buffer. - */ - inline HRESULT stream_read_nothrow(_In_ ISequentialStream* stream, _Out_writes_bytes_all_(size) void* data, unsigned long size) - { - unsigned long didRead; - RETURN_IF_FAILED(stream_read_partial_nothrow(stream, data, size, &didRead)); - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), didRead != size); - - return S_OK; - } - - /** Read from a stream into a POD type. - Fails if the stream didn't have enough bytes. - ~~~~ - IStream* source = // ... - MY_HEADER header{}; - RETURN_IF_FAILED(wil::stream_read_nothrow(source, &header)); - if (header.Version == 0x8675309) - { - ConsumeOldHeader(stream, header); - } - ~~~~ - @param stream The stream from which to read at most `size` bytes. - @param pThing The POD data type to read from the stream. - @return The underlying stream read result, or HRESULT_FROM_WIN32(ERROR_INVALID_DATA) if the stream - did not read the complete buffer. - */ - template HRESULT stream_read_nothrow(_In_ ISequentialStream* stream, _Out_ T* pThing) - { - static_assert(__is_pod(T), "Type must be POD."); - return stream_read_nothrow(stream, pThing, sizeof(T)); - } - - /** Write an exact number of bytes to a stream from a buffer. - Fails if the stream didn't read write the bytes requested. - ~~~~ - IStream* source = // ... - ULONG dataBlob = 0x8675309; - RETURN_IF_FAILED(wil::stream_write_nothrow(source, &dataBlob, sizeof(dataBlob))); - ~~~~ - @param stream The stream to which to write at most `size` bytes. - @param data A buffer from which up to `size` bytes will be read - @param size The size, in bytes, of the buffer pointed to by `data` - */ - inline HRESULT stream_write_nothrow(_In_ ISequentialStream* stream, _In_reads_bytes_(size) const void* data, unsigned long size) - { - unsigned long wrote; - RETURN_IF_FAILED(stream->Write(data, size, &wrote)); - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), wrote != size); - - return S_OK; - } - - /** Write a POD type to a stream. - Fails if not all the bytes were written. - ~~~~ - IStream* source = // ... - MY_HEADER header { 0x8675309, HEADER_FLAG_1 | HEADER_FLAG_2 }; - RETURN_IF_FAILED(wil::stream_write_nothrow(source, header)); - - ULONGLONG value = 16; - RETURN_IF_FAILED(wil::stream_write_nothrow(source, value)); - ~~~~ - @param stream The stream to which to write `thing` - @param thing The POD data type to write to the stream. - */ - template inline HRESULT stream_write_nothrow(_In_ ISequentialStream* stream, const T& thing) - { - return stream_write_nothrow(stream, wistd::addressof(thing), sizeof(thing)); - } - - /** Retrieve the size of this stream, in bytes - ~~~~ - IStream* source = // ... - ULONGLONG size; - RETURN_IF_FAILED(wil::stream_size_nothrow(source, &size)); - RETURN_HR_IF(E_INVALIDARG, size > ULONG_MAX); - ~~~~ - @param stream The stream whose size is to be returned in `value` - @param value The size, in bytes, reported by `stream` - */ - inline HRESULT stream_size_nothrow(_In_ IStream* stream, _Out_ unsigned long long* value) - { - STATSTG st{}; - RETURN_IF_FAILED(stream->Stat(&st, STATFLAG_NONAME)); - *value = st.cbSize.QuadPart; - - return S_OK; - } - - /** Seek a stream to a relative offset or absolute position - ~~~~ - IStream* source = // ... - unsigned long long landed; - RETURN_IF_FAILED(wil::stream_seek_nothrow(source, 16, STREAM_SEEK_CUR, &landed)); - RETURN_IF_FAILED(wil::stream_seek_nothrow(source, -5, STREAM_SEEK_END)); - RETURN_IF_FAILED(wil::stream_seek_nothrow(source, LLONG_MAX, STREAM_SEEK_CUR)); - ~~~~ - @param stream The stream to seek - @param offset The position, in bytes from the current position, to seek - @param from The starting point from which to seek, from the STREAM_SEEK_* set of values - @param value Optionally recieves the new absolute position from the stream - */ - inline HRESULT stream_seek_nothrow(_In_ IStream* stream, long long offset, unsigned long from, _Out_opt_ unsigned long long* value = nullptr) - { - LARGE_INTEGER amount{}; - ULARGE_INTEGER landed{}; - amount.QuadPart = offset; - RETURN_IF_FAILED(stream->Seek(amount, from, value ? &landed : nullptr)); - assign_to_opt_param(value, landed.QuadPart); - - return S_OK; - } - - /** Seek a stream to an absolute offset - ~~~~ - IStream* source = // ... - RETURN_HR(wil::stream_set_position_nothrow(source, 16)); - ~~~~ - @param stream The stream whose size is to be returned in `value` - @param offset The position, in bytes from the start of the stream, to seek to - @param value Optionally recieves the new absolute position from the stream - */ - inline HRESULT stream_set_position_nothrow(_In_ IStream* stream, unsigned long long offset, _Out_opt_ unsigned long long* value = nullptr) - { - // IStream::Seek(..., _SET) interprets the first parameter as an unsigned value. - return stream_seek_nothrow(stream, static_cast(offset), STREAM_SEEK_SET, value); - } - - /** Seek a relative amount in a stream - ~~~~ - IStream* source = // ... - RETURN_IF_FAILED(wil::stream_seek_from_current_position_nothrow(source, -16)); - - ULONGLONG newPosition; - RETURN_IF_FAILED(wil::stream_seek_from_current_position_nothrow(source, 16, &newPosition)); - ~~~~ - @param stream The stream whose location is to be moved - @param amount The offset, in bytes, to seek the stream. - @param value Set to the new absolute steam position, in bytes - */ - inline HRESULT stream_seek_from_current_position_nothrow(_In_ IStream* stream, long long amount, _Out_opt_ unsigned long long* value = nullptr) - { - return stream_seek_nothrow(stream, amount, STREAM_SEEK_CUR, value); - } - - /** Determine the current byte position in the stream - ~~~~ - IStream* source = // ... - ULONGLONG currentPos; - RETURN_IF_FAILED(wil::stream_get_position_nothrow(source, ¤tPos)); - ~~~~ - @param stream The stream whose location is to be moved - @param position Set to the current absolute steam position, in bytes - */ - inline HRESULT stream_get_position_nothrow(_In_ IStream* stream, _Out_ unsigned long long* position) - { - return stream_seek_from_current_position_nothrow(stream, 0, position); - } - - /** Moves the stream to absolute position 0 - ~~~~ - IStream* source = // ... - RETURN_IF_FAILED(wil::stream_reset_nothrow(source)); - ~~~~ - @param stream The stream whose location is to be moved - */ - inline HRESULT stream_reset_nothrow(_In_ IStream* stream) - { - return stream_set_position_nothrow(stream, 0); - } - - /** Copy data from one stream to another, returning the final amount copied. - ~~~~ - IStream* source = // ... - IStream* target = // ... - ULONGLONG copied; - RETURN_IF_FAILED(wil::stream_copy_bytes_nothrow(source, target, sizeof(MyType), &copied)); - if (copied < sizeof(MyType)) - { - DoSomethingAboutPartialCopy(); - } - ~~~~ - @param source The stream from which to copy at most `amount` bytes - @param target The steam to which to copy at most `amount` bytes - @param amount The maximum number of bytes to copy from `source` to `target` - @param pCopied If non-null, set to the number of bytes copied between the two. - */ - inline HRESULT stream_copy_bytes_nothrow(_In_ IStream* source, _In_ IStream* target, unsigned long long amount, _Out_opt_ unsigned long long* pCopied = nullptr) - { - ULARGE_INTEGER toCopy{}; - ULARGE_INTEGER copied{}; - toCopy.QuadPart = amount; - RETURN_IF_FAILED(source->CopyTo(target, toCopy, nullptr, &copied)); - assign_to_opt_param(pCopied, copied.QuadPart); - - return S_OK; - } - - /** Copy all data from one stream to another, returning the final amount copied. - ~~~~ - IStream* source = // ... - IStream* target = // ... - ULONGLONG copied; - RETURN_IF_FAILED(wil::stream_copy_all_nothrow(source, target, &copied)); - if (copied < 8) - { - DoSomethingAboutPartialCopy(); - } - ~~~~ - @param source The stream from which to copy all content - @param target The steam to which to copy all content - @param pCopied If non-null, set to the number of bytes copied between the two. - */ - inline HRESULT stream_copy_all_nothrow(_In_ IStream* source, _In_ IStream* target, _Out_opt_ unsigned long long* pCopied = nullptr) - { - return stream_copy_bytes_nothrow(source, target, ULLONG_MAX, pCopied); - } - - /** Copies an exact amount of data from one stream to another, failing otherwise - ~~~~ - IStream* source = // ... - IStream* target = // ... - RETURN_IF_FAILED(wil::stream_copy_all_nothrow(source, target, 16)); - ~~~~ - @param source The stream from which to copy at most `amount` bytes - @param target The steam to which to copy at most `amount` bytes - @param amount The number of bytes to copy from `source` to `target` - */ - inline HRESULT stream_copy_exact_nothrow(_In_ IStream* source, _In_ IStream* target, unsigned long long amount) - { - unsigned long long copied; - RETURN_IF_FAILED(stream_copy_bytes_nothrow(source, target, ULLONG_MAX, &copied)); - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), copied != amount); - - return S_OK; - } - - //! Controls behavior when reading a zero-length string from a stream - enum class empty_string_options - { - //! Zero-length strings are returned as nullptr - returns_null, - - //! Zero-length strings are allocated and returned with zero characters - returns_empty, - }; - -#ifdef __WIL_OBJBASE_H_ - - /** Read a string from a stream and returns an allocated copy - Deserializes strings in streams written by both IStream_WriteStr and wil::stream_write_string[_nothrow]. The format - is a single 16-bit quantity, followed by that many wchar_ts. The returned string is allocated with CoTaskMemAlloc. - Returns a zero-length (but non-null) string if the stream contained a zero-length string. - ~~~~ - IStream* source = // ... - wil::unique_cotaskmem_string content; - RETURN_IF_FAILED(wil::stream_read_string_nothrow(source, &content)); - if (wcscmp(content.get(), L"waffles") == 0) - { - // Waffles! - } - ~~~~ - @param source The stream from which to read a string - @param value Set to point to the allocated result of reading a string from `source` - */ - inline HRESULT stream_read_string_nothrow( - _In_ ISequentialStream* source, - _When_(options == empty_string_options::returns_empty, _Outptr_result_z_) _When_(options == empty_string_options::returns_null, _Outptr_result_maybenull_z_) wchar_t** value, - empty_string_options options = empty_string_options::returns_empty) - { - unsigned short cch; - RETURN_IF_FAILED(stream_read_nothrow(source, &cch)); - - if ((cch == 0) && (options == empty_string_options::returns_null)) - { - *value = nullptr; - } - else - { - auto allocated = make_unique_cotaskmem_nothrow(static_cast(cch) + 1); - RETURN_IF_NULL_ALLOC(allocated); - RETURN_IF_FAILED(stream_read_nothrow(source, allocated.get(), static_cast(cch) * sizeof(wchar_t))); - allocated[cch] = 0; - - *value = allocated.release(); - } - - return S_OK; - } - -#endif // __WIL_OBJBASE_H - - /** Write a string to a stream - Serializes a string into a stream by putting its length and then the wchar_ts in the string - into the stream. Zero-length strings have their length but no data written. This is the - form expected by IStream_ReadStr and wil::string_read_stream. - ~~~~ - IStream* target = // ... - RETURN_IF_FAILED(wil::stream_write_string_nothrow(target, L"Waffles", 3)); - // Produces wchar_t[] { 0x3, L'W', L'a', L'f' }; - ~~~~ - @param target The stream to which to write a string - @param source The string to write. Can be null if `writeLength` is zero - @param writeLength The number of characters to write from source into `target` - */ - inline HRESULT stream_write_string_nothrow(_In_ ISequentialStream* target, _In_reads_opt_(writeLength) const wchar_t* source, _In_ size_t writeLength) - { - FAIL_FAST_IF(writeLength > USHRT_MAX); - - RETURN_IF_FAILED(stream_write_nothrow(target, static_cast(writeLength))); - - if (writeLength > 0) - { - RETURN_IF_FAILED(stream_write_nothrow(target, source, static_cast(writeLength) * sizeof(wchar_t))); - } - - return S_OK; - } - - /** Write a string to a stream - Serializes a string into a stream by putting its length and then the wchar_ts in the string - into the stream. Zero-length strings have their length but no data written. This is the - form expected by IStream_ReadStr and wil::string_read_stream. - ~~~~ - IStream* target = // ... - RETURN_IF_FAILED(wil::stream_write_string_nothrow(target, L"Waffles")); - // Produces wchar_t[] { 0x3, L'W', L'a', L'f', L'f', L'l', L'e', L's' }; - ~~~~ - @param target The stream to which to write a string - @param source The string to write. When nullptr, a zero-length string is written. - */ - inline HRESULT stream_write_string_nothrow(_In_ ISequentialStream* target, _In_opt_z_ const wchar_t* source) - { - return stream_write_string_nothrow(target, source, source ? wcslen(source) : 0); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - - /** Read data from a stream into a buffer. - ~~~~ - IStream* source = // ... - ULONG dataBlob = 0; - auto read = wil::stream_read_partial(source, &dataBlob, sizeof(dataBlob)); - if (read != sizeof(dataBlob)) - { - // end of stream, probably - } - else if (dataBlob == 0x8675309) - { - DoThing(dataBlob); - } - ~~~~ - @param stream The stream from which to read at most `size` bytes. - @param data A buffer into which up to `size` bytes will be read - @param size The size, in bytes, of the buffer pointed to by `data` - @return The amount, in bytes, of data read from `stream` into `data` - */ - inline unsigned long stream_read_partial(_In_ ISequentialStream* stream, _Out_writes_bytes_to_(size, return) void* data, unsigned long size) - { - unsigned long didRead; - THROW_IF_FAILED(stream_read_partial_nothrow(stream, data, size, &didRead)); - - return didRead; - } - - /** Read an exact number of bytes from a stream into a buffer. - Fails if the stream didn't read all the bytes requested by throwing HRESULT_FROM_WIN32(ERROR_INVALID_DATA). - ~~~~ - IStream* source = // ... - ULONG dataBlob = 0; - wil::stream_read(source, &dataBlob, sizeof(dataBlob)); - if (dataBlob == 0x8675309) - { - DoThing(dataBlob); - } - ~~~~ - @param stream The stream from which to read at most `size` bytes. - @param data A buffer into which up to `size` bytes will be read - @param size The size, in bytes, of the buffer pointed to by `data` - */ - inline void stream_read(_In_ ISequentialStream* stream, _Out_writes_bytes_all_(size) void* data, unsigned long size) - { - THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), stream_read_partial(stream, data, size) != size); - } - - /** Read from a stream into a POD type. - Fails if the stream didn't have enough bytes by throwing HRESULT_FROM_WIN32(ERROR_INVALID_DATA). - ~~~~ - IStream* source = // ... - MY_HEADER header = wil::stream_read(source); - if (header.Version == 0x8675309) - { - ConsumeOldHeader(stream, header); - } - ~~~~ - @param stream The stream from which to read at most `sizeof(T)` bytes. - @return An instance of `T` read from the stream - */ - template T stream_read(_In_ ISequentialStream* stream) - { - static_assert(__is_pod(T), "Read type must be POD"); - T temp{}; - stream_read(stream, &temp, sizeof(temp)); - - return temp; - } - - /** Write an exact number of bytes to a stream from a buffer. - Fails if the stream didn't read write the bytes requested. - ~~~~ - IStream* source = // ... - ULONG dataBlob = 0; - wil::stream_write(source, dataBlob, sizeof(dataBlob)); - ~~~~ - @param stream The stream to which to write at most `size` bytes. - @param data A buffer from which up to `size` bytes will be read - @param size The size, in bytes, of the buffer pointed to by `data` - */ - inline void stream_write(_In_ ISequentialStream* stream, _In_reads_bytes_(size) const void* data, unsigned long size) - { - THROW_IF_FAILED(stream_write_nothrow(stream, data, size)); - } - - /** Write a POD type to a stream. - Fails if the stream didn't accept the entire size. - ~~~~ - IStream* target = // ... - - MY_HEADER header { 0x8675309, HEADER_FLAG_1 | HEADER_FLAG_2 }; - wil::stream_write(target, header) - - wil::stream_write(target, 16); - ~~~~ - @param stream The stream to which to write `thing` - @param thing The POD data type to write to the stream. - */ - template inline void stream_write(_In_ ISequentialStream* stream, const T& thing) - { - stream_write(stream, wistd::addressof(thing), sizeof(thing)); - } - - /** Retrieve the size of this stream, in bytes - ~~~~ - IStream* source = // ... - ULONGLONG size = wil::stream_size(source); - ~~~~ - @param stream The stream whose size is to be returned in `value` - @return The size, in bytes, reported by `stream` - */ - inline unsigned long long stream_size(_In_ IStream* stream) - { - unsigned long long size; - THROW_IF_FAILED(stream_size_nothrow(stream, &size)); - - return size; - } - - /** Seek a stream to an absolute offset - ~~~~ - IStream* source = // ... - wil::stream_set_position(source, sizeof(HEADER)); - ~~~~ - @param stream The stream whose size is to be returned in `value` - @param offset The offset, in bytes, to seek the stream. - @return The new absolute stream position, in bytes - */ - inline unsigned long long stream_set_position(_In_ IStream* stream, unsigned long long offset) - { - unsigned long long landed; - THROW_IF_FAILED(stream_set_position_nothrow(stream, offset, &landed)); - return landed; - } - - /** Seek a relative amount in a stream - ~~~~ - IStream* source = // ... - ULONGLONG newPosition = wil::stream_seek_from_current_position(source, 16); - ~~~~ - @param stream The stream whose location is to be moved - @param amount The offset, in bytes, to seek the stream. - @return The new absolute stream position, in bytes - */ - inline unsigned long long stream_seek_from_current_position(_In_ IStream* stream, long long amount) - { - unsigned long long landed; - THROW_IF_FAILED(stream_seek_from_current_position_nothrow(stream, amount, &landed)); - - return landed; - } - - /** Determine the current byte position in the stream - ~~~~ - IStream* source = // ... - ULONGLONG currentPos = wil::stream_get_position(source); - ~~~~ - @param stream The stream whose location is to be moved - @return The current position reported by `stream` - */ - inline unsigned long long stream_get_position(_In_ IStream* stream) - { - return stream_seek_from_current_position(stream, 0); - } - - /** Moves the stream to absolute position 0 - ~~~~ - IStream* source = // ... - wil::stream_reset(source); - ASSERT(wil::stream_get_position(source) == 0); - ~~~~ - @param stream The stream whose location is to be moved - */ - inline void stream_reset(_In_ IStream* stream) - { - stream_set_position(stream, 0); - } - - /** Copy data from one stream to another - ~~~~ - IStream* source = // ... - IStream* target = // ... - ULONGLONG copied = ; - if (wil::stream_copy_bytes(source, target, sizeof(Header)) < sizeof(Header)) - { - DoSomethingAboutPartialCopy(); - } - ~~~~ - @param source The stream from which to copy at most `amount` bytes - @param target The steam to which to copy at most `amount` bytes - @param amount The maximum number of bytes to copy from `source` to `target` - @return The number of bytes copied between the two streams - */ - inline unsigned long long stream_copy_bytes(_In_ IStream* source, _In_ IStream* target, unsigned long long amount) - { - unsigned long long copied; - THROW_IF_FAILED(stream_copy_bytes_nothrow(source, target, amount, &copied)); - - return copied; - } - - /** Copy all data from one stream to another - ~~~~ - IStream* source = // ... - IStream* target = // ... - ULONGLONG copied = wil::stream_copy_all(source, target); - ~~~~ - @param source The stream from which to copy all content - @param target The steam to which to copy all content - @return The number of bytes copied between the two. - */ - inline unsigned long long stream_copy_all(_In_ IStream* source, _In_ IStream* target) - { - return stream_copy_bytes(source, target, ULLONG_MAX); - } - - /** Copies an exact amount of data from one stream to another, failing otherwise - ~~~~ - IStream* source = // ... - IStream* target = // ... - wil::stream_copy_all_nothrow(source, target, sizeof(SOMETHING)); - ~~~~ - @param source The stream from which to copy at most `amount` bytes - @param target The steam to which to copy at most `amount` bytes - @param amount The number of bytes to copy from `source` to `target` - */ - inline void stream_copy_exact(_In_ IStream* source, _In_ IStream* target, unsigned long long amount) - { - THROW_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), stream_copy_bytes(source, target, amount) != amount); - } - -#ifdef __WIL_OBJBASE_H_ - - /** Read a string from a stream and returns an allocated copy - Deserializes strings in streams written by both IStream_WriteStr and wil::stream_write_string[_nothrow]. The format - is a single 16-bit quantity, followed by that many wchar_ts. The returned string is allocated with CoTaskMemAlloc. - Returns a zero-length (but non-null) string if the stream contained a zero-length string. - ~~~~ - IStream* source = // ... - wil::unique_cotaskmem_string content = wil::stream_read_string(source); - if (wcscmp(content.get(), L"waffles") == 0) - { - // Waffles! - } - ~~~~ - @param source The stream from which to read a string - @return An non-null string (but possibly zero lengh) string read from `source` - */ - inline wil::unique_cotaskmem_string stream_read_string(_In_ ISequentialStream* source, empty_string_options options = empty_string_options::returns_empty) - { - wil::unique_cotaskmem_string result; - THROW_IF_FAILED(stream_read_string_nothrow(source, &result, options)); - - return result; - } - -#endif // __WIL_OBJBASE_H - - /** Write a string to a stream - Serializes a string into a stream by putting its length and then the wchar_ts in the string - into the stream. Zero-length strings have their length but no data written. This is the - form expected by IStream_ReadStr and wil::string_read_stream. - ~~~~ - IStream* target = // ... - wil::stream_write_string(target, L"Waffles", 3); - ~~~~ - @param target The stream to which to write a string - @param source The string to write. Can be null if `toWriteCch` is zero - @param toWriteCch The number of characters to write from source into `target` - */ - inline void stream_write_string(_In_ ISequentialStream* target, _In_reads_opt_(toWriteCch) const wchar_t* source, _In_ size_t toWriteCch) - { - THROW_IF_FAILED(stream_write_string_nothrow(target, source, toWriteCch)); - } - - /** Write a string to a stream - Serializes a string into a stream by putting its length and then the wchar_ts in the string - into the stream. Zero-length strings have their length but no data written.This is the - form expected by IStream_ReadStr and wil::string_read_stream. - ~~~~ - IStream* target = // ... - wil::stream_write_string(target, L"Waffles"); - ~~~~ - @param target The stream to which to write a string - @param source The string to write. When nullptr, a zero-length string is written. - */ - inline void stream_write_string(_In_ ISequentialStream* target, _In_opt_z_ const wchar_t* source) - { - THROW_IF_FAILED(stream_write_string_nothrow(target, source, source ? wcslen(source) : 0)); - } - - /** Saves and restores the position of a stream - Useful for potentially reading data from a stream, or being able to read ahead, then reset - back to where one left off, such as conditionally reading content from a stream. - ~~~~ - void MaybeConsumeStream(IStream* stream) - { - // On error, reset the read position in the stream to where we left off - auto saver = wil::stream_position_saver(stream); - auto header = wil::stream_read(stream); - for (ULONG i = 0; i < header.Count; ++i) - { - ProcessElement(wil::stream_read(stream)); - } - } - ~~~~ - */ - class stream_position_saver - { - public: - //! Constructs a saver from the current position of this stream - //! @param stream The stream instance whose position is to be saved. - explicit stream_position_saver(_In_opt_ IStream* stream) : - m_stream(stream), - m_position(stream ? stream_get_position(stream) : 0) - { - } - - ~stream_position_saver() - { - if (m_stream) - { - LOG_IF_FAILED(stream_set_position_nothrow(m_stream.get(), m_position)); - } - } - - /** Updates the current position in the stream - ~~~~ - // Read a size marker from the stream, then advance that much. - IStream* stream1 = // ... - auto saver = wil::stream_position_saver(stream1); - auto size = wil::stream_read(stream1); - wil::stream_seek_from_current_position(stream, size); - saver.update(); - ~~~~ - */ - void update() - { - m_position = stream_get_position(m_stream.get()); - } - - //! Returns the current position being saved for the stream - //! @returns The position, in bytes, being saved for the stream - WI_NODISCARD unsigned long long position() const - { - return m_position; - } - - /** Resets the position saver to manage a new stream - Reverts the position of any stream this saver is currently holding a place for. - ~~~~ - IStream* stream1 = // ... - IStream* stream2 = // ... - auto saver = wil::stream_position_saver(stream1); - if (wil::stream_read(stream1).Flags != 0) - { - saver.reset(stream2); // position in stream1 is reverted, now holding stream2 - } - ~~~~ - @param stream The stream whose position is to be saved - */ - void reset(_In_ IStream* stream) - { - reset(); - - m_stream = stream; - m_position = wil::stream_get_position(m_stream.get()); - } - - /** Resets the position of the stream - ~~~~ - IStream* stream1 = // ... - auto saver = wil::stream_position_saver(stream1); - MyType mt = wil::stream_read(stream1); - if (mt.Flags & MyTypeFlags::Extended) - { - saver.reset(); - ProcessExtended(stream1, wil::stream_read(stream1)); - } - else - { - ProcessStandard(stream1, mt); - } - ~~~~ - */ - void reset() - { - if (m_stream) - { - wil::stream_set_position(m_stream.get(), m_position); - } - } - - /** Stops saving the position of the stream - ~~~~ - // The stream has either a standard or extended header, followed by interesting content. - // Read either one, leaving the stream after the headers have been read off. On failure, - // the stream's position is restored. - std::pair get_headers(_In_ IStream* source) - { - auto saver = wil::stream_position_saver(stream1); - MyType mt = wil::stream_read(stream1); - MyTypeExtended mte{}; - if (mt.Flags & MyTypeFlags::Extended) - { - mte = wil::stream_read(stream1); - } - saver.dismiss(); - return { mt, mte }; - } - ~~~~ - */ - void dismiss() - { - m_stream.reset(); - } - - stream_position_saver(stream_position_saver&&) = default; - stream_position_saver& operator=(stream_position_saver&&) = default; - - stream_position_saver(const stream_position_saver&) = delete; - void operator=(const stream_position_saver&) = delete; - - private: - com_ptr m_stream; - unsigned long long m_position; - }; -#endif // WIL_ENABLE_EXCEPTIONS -#pragma endregion // stream helpers - -#if defined(__IObjectWithSite_INTERFACE_DEFINED__) - /// @cond - namespace details - { - inline void __stdcall SetSiteNull(IObjectWithSite* objWithSite) - { - objWithSite->SetSite(nullptr); // break the cycle - } - } // details - /// @endcond - - using unique_set_site_null_call = wil::unique_com_call; - - /** RAII support for managing the site chain. This function sets the site pointer on an object and return an object - that resets it on destruction to break the cycle. - Note, this does not preserve the existing site if there is one (an uncommon case) so only use this when that is not required. - ~~~ - auto cleanup = wil::com_set_site(execCommand.get(), serviceProvider->GetAsSite()); - ~~~ - Include ocidl.h before wil\com.h to use this. - */ - WI_NODISCARD inline unique_set_site_null_call com_set_site(_In_opt_ IUnknown* obj, _In_opt_ IUnknown* site) - { - wil::com_ptr_nothrow objWithSite; - if (site && wil::try_com_copy_to(obj, &objWithSite)) - { - objWithSite->SetSite(site); - } - return unique_set_site_null_call(objWithSite.get()); - } - - /** Iterate over each object in a site chain. Useful for debugging site issues, here is sample use. - ~~~ - void OutputDebugSiteChainWatchWindowText(IUnknown* site) - { - OutputDebugStringW(L"Copy and paste these entries into the Visual Studio Watch Window\n"); - wil::for_each_site(site, [](IUnknown* site) - { - wchar_t msg[64]; - StringCchPrintfW(msg, ARRAYSIZE(msg), L"((IUnknown*)0x%p)->__vfptr[0]\n", site); - OutputDebugStringW(msg); - }); - } - */ - - template - void for_each_site(_In_opt_ IUnknown* siteInput, TLambda&& callback) - { - wil::com_ptr_nothrow site(siteInput); - while (site) - { - callback(site.get()); - auto objWithSite = site.try_query(); - site.reset(); - if (objWithSite) - { - objWithSite->GetSite(IID_PPV_ARGS(&site)); - } - } - } - -#endif // __IObjectWithSite_INTERFACE_DEFINED__ - -} // wil - -#endif diff --git a/src/common/dep/wil/com_apartment_variable.h b/src/common/dep/wil/com_apartment_variable.h deleted file mode 100644 index 1ff631dd3..000000000 --- a/src/common/dep/wil/com_apartment_variable.h +++ /dev/null @@ -1,467 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_COM_APARTMENT_VARIABLE_INCLUDED -#define __WIL_COM_APARTMENT_VARIABLE_INCLUDED - -#include -#include -#include -#include -#include -#include - -#include "com.h" -#include "cppwinrt.h" -#include "result_macros.h" -#include "win32_helpers.h" - -#ifndef WIL_ENABLE_EXCEPTIONS -#error This header requires exceptions -#endif - -namespace wil -{ - // Determine if apartment variables are supported in the current process context. - // Prior to build 22365, the APIs needed to create apartment variables (e.g. RoGetApartmentIdentifier) - // failed for unpackaged processes. For MS people, see http://task.ms/31861017 for details. - // APIs needed to implement apartment variables did not work in non-packaged processes. - inline bool are_apartment_variables_supported() - { - unsigned long long apartmentId{}; - return RoGetApartmentIdentifier(&apartmentId) != HRESULT_FROM_WIN32(ERROR_API_UNAVAILABLE); - } - - // COM will implicitly rundown the apartment registration when it invokes a handler - // and blocks calling unregister when executing the callback. So be careful to release() - // this when callback is invoked to avoid a double free of the cookie. - using unique_apartment_shutdown_registration = unique_any; - - struct apartment_variable_platform - { - static unsigned long long GetApartmentId() - { - unsigned long long apartmentId{}; - FAIL_FAST_IF_FAILED(RoGetApartmentIdentifier(&apartmentId)); - return apartmentId; - } - - static auto RegisterForApartmentShutdown(IApartmentShutdown* observer) - { - unsigned long long id{}; - shutdown_type cookie; - THROW_IF_FAILED(RoRegisterForApartmentShutdown(observer, &id, cookie.put())); - return cookie; - } - - static void UnRegisterForApartmentShutdown(APARTMENT_SHUTDOWN_REGISTRATION_COOKIE cookie) - { - FAIL_FAST_IF_FAILED(RoUnregisterForApartmentShutdown(cookie)); - } - - static auto CoInitializeEx(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/) - { - return wil::CoInitializeEx(coinitFlags); - } - - // disable the test hook - inline static constexpr unsigned long AsyncRundownDelayForTestingRaces = INFINITE; - - using shutdown_type = wil::unique_apartment_shutdown_registration; - }; - - enum class apartment_variable_leak_action { fail_fast, ignore }; - - // "pins" the current module in memory by incrementing the module reference count and leaking that. - inline void ensure_module_stays_loaded() - { - static INIT_ONCE s_initLeakModule{}; // avoiding magic statics - wil::init_once_failfast(s_initLeakModule, []() - { - HMODULE result{}; - FAIL_FAST_IF(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, L"", &result)); - return S_OK; - }); - } - - namespace details - { - // For the address of data, you can detect global variables by the ability to resolve the module from the address. - inline bool IsGlobalVariable(const void* moduleAddress) noexcept - { - wil::unique_hmodule moduleHandle; - return GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast(moduleAddress), &moduleHandle) != FALSE; - } - - struct any_maker_base - { - std::any(*adapter)(void*); - void* inner; - - WI_NODISCARD std::any operator()() const - { - return adapter(inner); - } - }; - - template - struct any_maker : any_maker_base - { - any_maker() - { - adapter = [](auto) -> std::any { return T{}; }; - } - - any_maker(T(*maker)()) - { - adapter = [](auto maker) -> std::any { return reinterpret_cast(maker)(); }; - inner = reinterpret_cast(maker); - } - - template - any_maker(F&& f) - { - adapter = [](auto maker) -> std::any { return reinterpret_cast(maker)[0](); }; - inner = std::addressof(f); - } - }; - - template - struct apartment_variable_base - { - inline static winrt::slim_mutex s_lock; - - struct apartment_variable_storage - { - apartment_variable_storage(apartment_variable_storage&& other) noexcept = default; - apartment_variable_storage(const apartment_variable_storage& other) = delete; - - apartment_variable_storage(typename test_hook::shutdown_type&& cookie_) : cookie(std::move(cookie_)) - { - } - - winrt::apartment_context context; - typename test_hook::shutdown_type cookie; - // Variables are stored using the address of the apartment_variable_base<> as the key. - std::unordered_map*, std::any> variables; - }; - - // Apartment id -> variables storage. - inline static wil::object_without_destructor_on_shutdown< - std::unordered_map> - s_apartmentStorage; - - constexpr apartment_variable_base() = default; - ~apartment_variable_base() - { - // Global variables (object with static storage duration) - // are run down when the process is shutting down or when the - // dll is unloaded. At these points it is not possible to start - // an async operation and the work performed is not needed, - // the apartments with variable have been run down already. - const auto isGlobal = details::IsGlobalVariable(this); - if (!isGlobal) - { - clear_all_apartments_async(); - } - - if constexpr (leak_action == apartment_variable_leak_action::fail_fast) - { - if (isGlobal && !ProcessShutdownInProgress()) - { - // If you hit this fail fast it means the storage in s_apartmentStorage will be leaked. - // For apartment variables used in .exes, this is expected and - // this fail fast should be disabled using - // wil::apartment_variable - // - // For DLLs, if this is expected, disable this fail fast using - // wil::apartment_variable - // - // Use of apartment variables in DLLs only loaded by COM will never hit this case - // as COM will unload DLLs before apartments are rundown, - // providing the opportunity to empty s_apartmentStorage. - // - // But DLLs loaded and unloaded to call DLL entry points (outside of COM) may - // create variable storage that can't be cleaned up as the DLL lifetime is - // shorter that the COM lifetime. In these cases either - // 1) accept the leaks and disable the fail fast as describe above - // 2) disable module unloading by calling wil::ensure_module_stays_loaded - // 3) CoCreate an object from this DLL to make COM aware of the DLL - FAIL_FAST_IF(!s_apartmentStorage.get().empty()); - } - } - } - - // non-copyable, non-assignable - apartment_variable_base(apartment_variable_base const&) = delete; - void operator=(apartment_variable_base const&) = delete; - - // get current value or throw if no value has been set - std::any& get_existing() - { - if (auto any = get_if()) - { - return *any; - } - THROW_HR(E_NOT_SET); - } - - static apartment_variable_storage* get_current_apartment_variable_storage() - { - auto storage = s_apartmentStorage.get().find(test_hook::GetApartmentId()); - if (storage != s_apartmentStorage.get().end()) - { - return &storage->second; - } - return nullptr; - } - - apartment_variable_storage* ensure_current_apartment_variables() - { - auto variables = get_current_apartment_variable_storage(); - if (variables) - { - return variables; - } - - struct ApartmentObserver : public winrt::implements - { - void STDMETHODCALLTYPE OnUninitialize(unsigned long long apartmentId) noexcept override - { - // This code runs at apartment rundown so be careful to avoid deadlocks by - // extracting the variables under the lock then release them outside. - auto variables = [apartmentId]() - { - auto lock = winrt::slim_lock_guard(s_lock); - return s_apartmentStorage.get().extract(apartmentId); - }(); - WI_ASSERT(variables.key() == apartmentId); - // The system implicitly releases the shutdown observer - // after invoking the callback and does not allow calling unregister - // in the callback. So release the reference to the registration. - variables.mapped().cookie.release(); - } - }; - auto shutdownRegistration = test_hook::RegisterForApartmentShutdown(winrt::make().get()); - return &s_apartmentStorage.get().insert({ test_hook::GetApartmentId(), apartment_variable_storage(std::move(shutdownRegistration)) }).first->second; - } - - // get current value or custom-construct one on demand - template - std::any& get_or_create(any_maker && creator) - { - apartment_variable_storage* variable_storage = nullptr; - - { // scope for lock - auto lock = winrt::slim_lock_guard(s_lock); - variable_storage = ensure_current_apartment_variables(); - - auto variable = variable_storage->variables.find(this); - if (variable != variable_storage->variables.end()) - { - return variable->second; - } - } // drop the lock - - // create the object outside the lock to avoid reentrant deadlock - auto value = creator(); - - auto insert_lock = winrt::slim_lock_guard(s_lock); - // The insertion may fail if creator() recursively caused itself to be created, - // in which case we return the existing object and the falsely-created one is discarded. - return variable_storage->variables.insert({ this, std::move(value) }).first->second; - } - - // get pointer to current value or nullptr if no value has been set - std::any* get_if() - { - auto lock = winrt::slim_lock_guard(s_lock); - - if (auto variable_storage = get_current_apartment_variable_storage()) - { - auto variable = variable_storage->variables.find(this); - if (variable != variable_storage->variables.end()) - { - return &(variable->second); - } - } - return nullptr; - } - - // replace or create the current value, fail fasts if the value is not already stored - void set(std::any value) - { - // release value, with the swapped value, outside of the lock - { - auto lock = winrt::slim_lock_guard(s_lock); - auto storage = s_apartmentStorage.get().find(test_hook::GetApartmentId()); - FAIL_FAST_IF(storage == s_apartmentStorage.get().end()); - auto& variable_storage = storage->second; - auto variable = variable_storage.variables.find(this); - FAIL_FAST_IF(variable == variable_storage.variables.end()); - variable->second.swap(value); - } - } - - // remove any current value - void clear() - { - auto lock = winrt::slim_lock_guard(s_lock); - if (auto variable_storage = get_current_apartment_variable_storage()) - { - variable_storage->variables.erase(this); - if (variable_storage->variables.size() == 0) - { - s_apartmentStorage.get().erase(test_hook::GetApartmentId()); - } - } - } - - winrt::Windows::Foundation::IAsyncAction clear_all_apartments_async() - { - // gather all the apartments that hold objects we need to destruct - // (do not gather the objects themselves, because the apartment might - // destruct before we get around to it, and we should let the apartment - // destruct the object while it still can). - - std::vector contexts; - { // scope for lock - auto lock = winrt::slim_lock_guard(s_lock); - for (auto& [id, storage] : s_apartmentStorage.get()) - { - auto variable = storage.variables.find(this); - if (variable != storage.variables.end()) - { - contexts.push_back(storage.context); - } - } - } - - if (contexts.empty()) - { - co_return; - } - - wil::unique_mta_usage_cookie mta_reference; // need to extend the MTA due to async cleanup - FAIL_FAST_IF_FAILED(CoIncrementMTAUsage(mta_reference.put())); - - // From a background thread hop into each apartment to run down the object - // if it's still there. - co_await winrt::resume_background(); - - // This hook enables testing the case where execution of this method loses the race with - // apartment rundown by other means. - if constexpr (test_hook::AsyncRundownDelayForTestingRaces != INFINITE) - { - Sleep(test_hook::AsyncRundownDelayForTestingRaces); - } - - for (auto&& context : contexts) - { - try - { - co_await context; - clear(); - } - catch (winrt::hresult_error const& e) - { - // Ignore failure if apartment ran down before we could clean it up. - // The object already ran down as part of apartment cleanup. - if ((e.code() != RPC_E_SERVER_DIED_DNE) && - (e.code() != RPC_E_DISCONNECTED)) - { - throw; - } - } - catch (...) - { - FAIL_FAST(); - } - } - } - - static const auto& storage() - { - return s_apartmentStorage.get(); - } - - static size_t current_apartment_variable_count() - { - auto lock = winrt::slim_lock_guard(s_lock); - if (auto variable_storage = get_current_apartment_variable_storage()) - { - return variable_storage->variables.size(); - } - return 0; - } - }; - } - - // Apartment variables enable storing COM objects safely in globals - // (objects with static storage duration) by creating a unique copy - // in each apartment and managing their lifetime based on apartment rundown - // notifications. - // They can also be used for automatic or dynamic storage duration but those - // cases are less common. - // This type is also useful for storing references to apartment affine objects. - // - // Note, that apartment variables hosted in a COM DLL need to integrate with - // the DllCanUnloadNow() function to include the ref counts contributed by - // C++ WinRT objects. This is automatic for DLLs that host C++ WinRT objects - // but WRL projects will need to be updated to call winrt::get_module_lock(). - - template - struct apartment_variable : details::apartment_variable_base - { - using base = details::apartment_variable_base; - - constexpr apartment_variable() = default; - - // Get current value or throw if no value has been set. - T& get_existing() { return std::any_cast(base::get_existing()); } - - // Get current value or default-construct one on demand. - T& get_or_create() - { - return std::any_cast(base::get_or_create(details::any_maker())); - } - - // Get current value or custom-construct one on demand. - template - T& get_or_create(F&& f) - { - return std::any_cast(base::get_or_create(details::any_maker(std::forward(f)))); - } - - // get pointer to current value or nullptr if no value has been set - T* get_if() { return std::any_cast(base::get_if()); } - - // replace or create the current value, fail fasts if the value is not already stored - template void set(V&& value) { return base::set(std::forward(value)); } - - // Clear the value in the current apartment. - using base::clear; - - // Asynchronously clear the value in all apartments it is present in. - using base::clear_all_apartments_async; - - // For testing only. - // 1) To observe the state of the storage in the debugger assign this to - // a temporary variable (const&) and watch its contents. - // 2) Use this to test the implementation. - using base::storage; - // For testing only. The number of variables in the current apartment. - using base::current_apartment_variable_count; - }; -} - -#endif // __WIL_COM_APARTMENT_VARIABLE_INCLUDED diff --git a/src/common/dep/wil/common.h b/src/common/dep/wil/common.h deleted file mode 100644 index 9edfdc040..000000000 --- a/src/common/dep/wil/common.h +++ /dev/null @@ -1,798 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_COMMON_INCLUDED -#define __WIL_COMMON_INCLUDED - -#if defined(_KERNEL_MODE ) && !defined(__WIL_MIN_KERNEL) -// This define indicates that the WIL usage is in a kernel mode context where -// a high degree of WIL functionality is desired. -// -// Use (sparingly) to change behavior based on whether WIL is being used in kernel -// mode or user mode. -#define WIL_KERNEL_MODE -#endif - -// Defining WIL_HIDE_DEPRECATED will hide everything deprecated. -// Each wave of deprecation will add a new WIL_HIDE_DEPRECATED_YYMM number that can be used to lock deprecation at -// a particular point, allowing components to avoid backslide and catch up to the current independently. -#ifdef WIL_HIDE_DEPRECATED -#define WIL_HIDE_DEPRECATED_1809 -#endif -#ifdef WIL_HIDE_DEPRECATED_1809 -#define WIL_HIDE_DEPRECATED_1612 -#endif -#ifdef WIL_HIDE_DEPRECATED_1612 -#define WIL_HIDE_DEPRECATED_1611 -#endif - -// Implementation side note: ideally the deprecation would be done with the function-level declspec -// as it allows you to utter the error text when used. The declspec works, but doing it selectively with -// a macro makes intellisense deprecation comments not work. So we just use the #pragma deprecation. -#ifdef WIL_WARN_DEPRECATED -#define WIL_WARN_DEPRECATED_1809 -#endif -#ifdef WIL_WARN_DEPRECATED_1809 -#define WIL_WARN_DEPRECATED_1612 -#endif -#ifdef WIL_WARN_DEPRECATED_1612 -#define WIL_WARN_DEPRECATED_1611 -#endif -#ifdef WIL_WARN_DEPRECATED_1809 -#define WIL_WARN_DEPRECATED_1809_PRAGMA(...) __pragma(deprecated(__VA_ARGS__)) -#else -#define WIL_WARN_DEPRECATED_1809_PRAGMA(...) -#endif -#ifdef WIL_WARN_DEPRECATED_1611 -#define WIL_WARN_DEPRECATED_1611_PRAGMA(...) __pragma(deprecated(__VA_ARGS__)) -#else -#define WIL_WARN_DEPRECATED_1611_PRAGMA(...) -#endif -#ifdef WIL_WARN_DEPRECATED_1612 -#define WIL_WARN_DEPRECATED_1612_PRAGMA(...) __pragma(deprecated(__VA_ARGS__)) -#else -#define WIL_WARN_DEPRECATED_1612_PRAGMA(...) -#endif - -#if defined(_MSVC_LANG) -#define __WI_SUPPRESS_4127_S __pragma(warning(push)) __pragma(warning(disable:4127)) __pragma(warning(disable:26498)) __pragma(warning(disable:4245)) -#define __WI_SUPPRESS_4127_E __pragma(warning(pop)) -#define __WI_SUPPRESS_NULLPTR_ANALYSIS __pragma(warning(suppress:28285)) __pragma(warning(suppress:6504)) -#define __WI_SUPPRESS_NONINIT_ANALYSIS __pragma(warning(suppress:26495)) -#define __WI_SUPPRESS_NOEXCEPT_ANALYSIS __pragma(warning(suppress:26439)) -#else -#define __WI_SUPPRESS_4127_S -#define __WI_SUPPRESS_4127_E -#define __WI_SUPPRESS_NULLPTR_ANALYSIS -#define __WI_SUPPRESS_NONINIT_ANALYSIS -#define __WI_SUPPRESS_NOEXCEPT_ANALYSIS -#endif - -#include - -// Some SAL remapping / decoration to better support Doxygen. Macros that look like function calls can -// confuse Doxygen when they are used to decorate a function or variable. We simplify some of these to -// basic macros without the function for common use cases. -/// @cond -#define _Success_return_ _Success_(return) -#define _Success_true_ _Success_(true) -#define __declspec_noinline_ __declspec(noinline) -#define __declspec_selectany_ __declspec(selectany) -/// @endcond - -//! @defgroup macrobuilding Macro Composition -//! The following macros are building blocks primarily intended for authoring other macros. -//! @{ - -//! Re-state a macro value (indirection for composition) -#define WI_FLATTEN(...) __VA_ARGS__ - -/// @cond -#define __WI_PASTE_imp(a, b) a##b -/// @endcond - -//! This macro is for use in other macros to paste two tokens together, such as a constant and the __LINE__ macro. -#define WI_PASTE(a, b) __WI_PASTE_imp(a, b) - -/// @cond -#define __WI_HAS_VA_OPT_IMPL(F, T, ...) T -#define __WI_HAS_VA_OPT_(...) __WI_HAS_VA_OPT_IMPL(__VA_OPT__(0,) 1, 0) -/// @endcond - -//! Evaluates to '1' when support for '__VA_OPT__' is available, else '0' -#define WI_HAS_VA_OPT __WI_HAS_VA_OPT_(unused) - -/// @cond -#define __WI_ARGS_COUNT1(A0, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, \ - A30, A31, A32, A33, A34, A35, A36, A37, A38, A39, A40, A41, A42, A43, A44, A45, A46, A47, A48, A49, A50, A51, A52, A53, A54, A55, A56, A57, A58, A59, \ - A60, A61, A62, A63, A64, A65, A66, A67, A68, A69, A70, A71, A72, A73, A74, A75, A76, A77, A78, A79, A80, A81, A82, A83, A84, A85, A86, A87, A88, A89, \ - A90, A91, A92, A93, A94, A95, A96, A97, A98, A99, count, ...) count -#define __WI_ARGS_COUNT0(...) WI_FLATTEN(__WI_ARGS_COUNT1(__VA_ARGS__, 99, 98, 97, 96, 95, 94, 93, 92, 91, 90, 89, 88, 87, 86, 85, 84, 83, 82, 81, 80, \ - 79, 78, 77, 76, 75, 74, 73, 72, 71, 70, 69, 68, 67, 66, 65, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, \ - 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)) -#define __WI_ARGS_COUNT_PREFIX(...) 0, __VA_ARGS__ -/// @endcond - -//! This variadic macro returns the number of arguments passed to it (up to 99). -#if WI_HAS_VA_OPT -#define WI_ARGS_COUNT(...) __WI_ARGS_COUNT0(0 __VA_OPT__(, __VA_ARGS__)) -#else -#define WI_ARGS_COUNT(...) __WI_ARGS_COUNT0(__WI_ARGS_COUNT_PREFIX(__VA_ARGS__)) -#endif - -/// @cond -#define __WI_FOR_imp0( fn) -#define __WI_FOR_imp1( fn, arg) fn(arg) -#define __WI_FOR_imp2( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp1(fn, __VA_ARGS__)) -#define __WI_FOR_imp3( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp2(fn, __VA_ARGS__)) -#define __WI_FOR_imp4( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp3(fn, __VA_ARGS__)) -#define __WI_FOR_imp5( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp4(fn, __VA_ARGS__)) -#define __WI_FOR_imp6( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp5(fn, __VA_ARGS__)) -#define __WI_FOR_imp7( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp6(fn, __VA_ARGS__)) -#define __WI_FOR_imp8( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp7(fn, __VA_ARGS__)) -#define __WI_FOR_imp9( fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp8(fn, __VA_ARGS__)) -#define __WI_FOR_imp10(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp9(fn, __VA_ARGS__)) -#define __WI_FOR_imp11(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp10(fn, __VA_ARGS__)) -#define __WI_FOR_imp12(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp11(fn, __VA_ARGS__)) -#define __WI_FOR_imp13(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp12(fn, __VA_ARGS__)) -#define __WI_FOR_imp14(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp13(fn, __VA_ARGS__)) -#define __WI_FOR_imp15(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp14(fn, __VA_ARGS__)) -#define __WI_FOR_imp16(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp15(fn, __VA_ARGS__)) -#define __WI_FOR_imp17(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp16(fn, __VA_ARGS__)) -#define __WI_FOR_imp18(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp17(fn, __VA_ARGS__)) -#define __WI_FOR_imp19(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp18(fn, __VA_ARGS__)) -#define __WI_FOR_imp20(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp19(fn, __VA_ARGS__)) -#define __WI_FOR_imp21(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp20(fn, __VA_ARGS__)) -#define __WI_FOR_imp22(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp21(fn, __VA_ARGS__)) -#define __WI_FOR_imp23(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp22(fn, __VA_ARGS__)) -#define __WI_FOR_imp24(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp23(fn, __VA_ARGS__)) -#define __WI_FOR_imp25(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp24(fn, __VA_ARGS__)) -#define __WI_FOR_imp26(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp25(fn, __VA_ARGS__)) -#define __WI_FOR_imp27(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp26(fn, __VA_ARGS__)) -#define __WI_FOR_imp28(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp27(fn, __VA_ARGS__)) -#define __WI_FOR_imp29(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp28(fn, __VA_ARGS__)) -#define __WI_FOR_imp30(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp29(fn, __VA_ARGS__)) -#define __WI_FOR_imp31(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp30(fn, __VA_ARGS__)) -#define __WI_FOR_imp32(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp31(fn, __VA_ARGS__)) -#define __WI_FOR_imp33(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp32(fn, __VA_ARGS__)) -#define __WI_FOR_imp34(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp33(fn, __VA_ARGS__)) -#define __WI_FOR_imp35(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp34(fn, __VA_ARGS__)) -#define __WI_FOR_imp36(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp35(fn, __VA_ARGS__)) -#define __WI_FOR_imp37(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp36(fn, __VA_ARGS__)) -#define __WI_FOR_imp38(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp37(fn, __VA_ARGS__)) -#define __WI_FOR_imp39(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp38(fn, __VA_ARGS__)) -#define __WI_FOR_imp40(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp39(fn, __VA_ARGS__)) -#define __WI_FOR_imp41(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp40(fn, __VA_ARGS__)) -#define __WI_FOR_imp42(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp41(fn, __VA_ARGS__)) -#define __WI_FOR_imp43(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp42(fn, __VA_ARGS__)) -#define __WI_FOR_imp44(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp43(fn, __VA_ARGS__)) -#define __WI_FOR_imp45(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp44(fn, __VA_ARGS__)) -#define __WI_FOR_imp46(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp45(fn, __VA_ARGS__)) -#define __WI_FOR_imp47(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp46(fn, __VA_ARGS__)) -#define __WI_FOR_imp48(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp47(fn, __VA_ARGS__)) -#define __WI_FOR_imp49(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp48(fn, __VA_ARGS__)) -#define __WI_FOR_imp50(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp49(fn, __VA_ARGS__)) -#define __WI_FOR_imp51(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp50(fn, __VA_ARGS__)) -#define __WI_FOR_imp52(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp51(fn, __VA_ARGS__)) -#define __WI_FOR_imp53(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp52(fn, __VA_ARGS__)) -#define __WI_FOR_imp54(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp53(fn, __VA_ARGS__)) -#define __WI_FOR_imp55(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp54(fn, __VA_ARGS__)) -#define __WI_FOR_imp56(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp55(fn, __VA_ARGS__)) -#define __WI_FOR_imp57(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp56(fn, __VA_ARGS__)) -#define __WI_FOR_imp58(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp57(fn, __VA_ARGS__)) -#define __WI_FOR_imp59(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp58(fn, __VA_ARGS__)) -#define __WI_FOR_imp60(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp59(fn, __VA_ARGS__)) -#define __WI_FOR_imp61(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp60(fn, __VA_ARGS__)) -#define __WI_FOR_imp62(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp61(fn, __VA_ARGS__)) -#define __WI_FOR_imp63(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp62(fn, __VA_ARGS__)) -#define __WI_FOR_imp64(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp63(fn, __VA_ARGS__)) -#define __WI_FOR_imp65(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp64(fn, __VA_ARGS__)) -#define __WI_FOR_imp66(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp65(fn, __VA_ARGS__)) -#define __WI_FOR_imp67(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp66(fn, __VA_ARGS__)) -#define __WI_FOR_imp68(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp67(fn, __VA_ARGS__)) -#define __WI_FOR_imp69(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp68(fn, __VA_ARGS__)) -#define __WI_FOR_imp70(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp69(fn, __VA_ARGS__)) -#define __WI_FOR_imp71(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp70(fn, __VA_ARGS__)) -#define __WI_FOR_imp72(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp71(fn, __VA_ARGS__)) -#define __WI_FOR_imp73(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp72(fn, __VA_ARGS__)) -#define __WI_FOR_imp74(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp73(fn, __VA_ARGS__)) -#define __WI_FOR_imp75(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp74(fn, __VA_ARGS__)) -#define __WI_FOR_imp76(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp75(fn, __VA_ARGS__)) -#define __WI_FOR_imp77(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp76(fn, __VA_ARGS__)) -#define __WI_FOR_imp78(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp77(fn, __VA_ARGS__)) -#define __WI_FOR_imp79(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp78(fn, __VA_ARGS__)) -#define __WI_FOR_imp80(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp79(fn, __VA_ARGS__)) -#define __WI_FOR_imp81(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp80(fn, __VA_ARGS__)) -#define __WI_FOR_imp82(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp81(fn, __VA_ARGS__)) -#define __WI_FOR_imp83(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp82(fn, __VA_ARGS__)) -#define __WI_FOR_imp84(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp83(fn, __VA_ARGS__)) -#define __WI_FOR_imp85(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp84(fn, __VA_ARGS__)) -#define __WI_FOR_imp86(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp85(fn, __VA_ARGS__)) -#define __WI_FOR_imp87(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp86(fn, __VA_ARGS__)) -#define __WI_FOR_imp88(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp87(fn, __VA_ARGS__)) -#define __WI_FOR_imp89(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp88(fn, __VA_ARGS__)) -#define __WI_FOR_imp90(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp89(fn, __VA_ARGS__)) -#define __WI_FOR_imp91(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp90(fn, __VA_ARGS__)) -#define __WI_FOR_imp92(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp91(fn, __VA_ARGS__)) -#define __WI_FOR_imp93(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp92(fn, __VA_ARGS__)) -#define __WI_FOR_imp94(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp93(fn, __VA_ARGS__)) -#define __WI_FOR_imp95(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp94(fn, __VA_ARGS__)) -#define __WI_FOR_imp96(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp95(fn, __VA_ARGS__)) -#define __WI_FOR_imp97(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp96(fn, __VA_ARGS__)) -#define __WI_FOR_imp98(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp97(fn, __VA_ARGS__)) -#define __WI_FOR_imp99(fn, arg, ...) fn(arg) WI_FLATTEN(__WI_FOR_imp98(fn, __VA_ARGS__)) - -#define __WI_FOR_imp(n, fnAndArgs) WI_PASTE(__WI_FOR_imp, n) fnAndArgs -/// @endcond - -//! Iterates through each of the given arguments invoking the specified macro against each one. -#define WI_FOREACH(fn, ...) __WI_FOR_imp(WI_ARGS_COUNT(__VA_ARGS__), (fn, ##__VA_ARGS__)) - -//! Dispatches a single macro name to separate macros based on the number of arguments passed to it. -#define WI_MACRO_DISPATCH(name, ...) WI_PASTE(WI_PASTE(name, WI_ARGS_COUNT(__VA_ARGS__)), (__VA_ARGS__)) - -//! @} // Macro composition helpers - -#if !defined(__cplusplus) || defined(__WIL_MIN_KERNEL) - -#define WI_ODR_PRAGMA(NAME, TOKEN) -#define WI_NOEXCEPT - -#else -#pragma warning(push) -#pragma warning(disable:4714) // __forceinline not honored - -// DO NOT add *any* further includes to this file -- there should be no dependencies from its usage -#include "wistd_type_traits.h" - -//! This macro inserts ODR violation protection; the macro allows it to be compatible with straight "C" code -#define WI_ODR_PRAGMA(NAME, TOKEN) __pragma(detect_mismatch("ODR_violation_" NAME "_mismatch", TOKEN)) - -#ifdef WIL_KERNEL_MODE -WI_ODR_PRAGMA("WIL_KERNEL_MODE", "1") -#else -WI_ODR_PRAGMA("WIL_KERNEL_MODE", "0") -#endif - -#if (defined(_CPPUNWIND) || defined(__EXCEPTIONS)) && !defined(WIL_SUPPRESS_EXCEPTIONS) -/** This define is automatically set when exceptions are enabled within wil. -It is automatically defined when your code is compiled with exceptions enabled (via checking for the built-in -_CPPUNWIND or __EXCEPTIONS flag) unless you explicitly define WIL_SUPPRESS_EXCEPTIONS ahead of including your first wil -header. All exception-based WIL methods and classes are included behind: -~~~~ -#ifdef WIL_ENABLE_EXCEPTIONS -// code -#endif -~~~~ -This enables exception-free code to directly include WIL headers without worrying about exception-based -routines suddenly becoming available. */ -#define WIL_ENABLE_EXCEPTIONS -#endif -/// @endcond - -/// @cond -#if defined(WIL_EXCEPTION_MODE) -static_assert(WIL_EXCEPTION_MODE <= 2, "Invalid exception mode"); -#elif !defined(WIL_LOCK_EXCEPTION_MODE) -#define WIL_EXCEPTION_MODE 0 // default, can link exception-based and non-exception based libraries together -#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "0") -#elif defined(WIL_ENABLE_EXCEPTIONS) -#define WIL_EXCEPTION_MODE 1 // new code optimization: ONLY support linking libraries together that have exceptions enabled -#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "1") -#else -#define WIL_EXCEPTION_MODE 2 // old code optimization: ONLY support linking libraries that are NOT using exceptions -#pragma detect_mismatch("ODR_violation_WIL_EXCEPTION_MODE_mismatch", "2") -#endif - -#if WIL_EXCEPTION_MODE == 1 && !defined(WIL_ENABLE_EXCEPTIONS) -#error Must enable exceptions when WIL_EXCEPTION_MODE == 1 -#endif - -// block for documentation only -#if defined(WIL_DOXYGEN) -/** This define can be explicitly set to disable exception usage within wil. -Normally this define is never needed as the WIL_ENABLE_EXCEPTIONS macro is enabled automatically by looking -at _CPPUNWIND. If your code compiles with exceptions enabled, but does not want to enable the exception-based -classes and methods from WIL, define this macro ahead of including the first WIL header. */ -#define WIL_SUPPRESS_EXCEPTIONS - -/** This define can be explicitly set to lock the process exception mode to WIL_ENABLE_EXCEPTIONS. -Locking the exception mode provides optimizations to exception barriers, staging hooks and DLL load costs as it eliminates the need to -do copy-on-write initialization of various function pointers and the necessary indirection that's done within WIL to avoid ODR violations -when linking libraries together with different exception handling semantics. */ -#define WIL_LOCK_EXCEPTION_MODE - -/** This define explicit sets the exception mode for the process to control optimizations. -Three exception modes are available: -0) This is the default. This enables a binary to link both exception-based and non-exception based libraries together that - use WIL. This adds overhead to exception barriers, DLL copy on write pages and indirection through function pointers to avoid ODR - violations when linking libraries together with different exception handling semantics. -1) Prefer this setting when it can be used. This locks the binary to only supporting libraries which were built with exceptions enabled. -2) This locks the binary to libraries built without exceptions. */ -#define WIL_EXCEPTION_MODE -#endif - -#if (__cplusplus >= 201703) || (_MSVC_LANG >= 201703) -#define WIL_HAS_CXX_17 1 -#else -#define WIL_HAS_CXX_17 0 -#endif - -// Until we'll have C++17 enabled in our code base, we're falling back to SAL -#define WI_NODISCARD __WI_LIBCPP_NODISCARD_ATTRIBUTE - -#define __R_ENABLE_IF_IS_CLASS(ptrType) wistd::enable_if_t::value, void*> = nullptr -#define __R_ENABLE_IF_IS_NOT_CLASS(ptrType) wistd::enable_if_t::value, void*> = nullptr - -//! @defgroup bitwise Bitwise Inspection and Manipulation -//! Bitwise helpers to improve readability and reduce the error rate of bitwise operations. -//! Several macros have been constructed to assist with bitwise inspection and manipulation. These macros exist -//! for two primary purposes: -//! -//! 1. To improve the readability of bitwise comparisons and manipulation. -//! -//! The macro names are the more concise, readable form of what's being done and do not require that any flags -//! or variables be specified multiple times for the comparisons. -//! -//! 2. To reduce the error rate associated with bitwise operations. -//! -//! The readability improvements naturally lend themselves to this by cutting down the number of concepts. -//! Using `WI_IsFlagSet(var, MyEnum::Flag)` rather than `((var & MyEnum::Flag) == MyEnum::Flag)` removes the comparison -//! operator and repetition in the flag value. -//! -//! Additionally, these macros separate single flag operations (which tend to be the most common) from multi-flag -//! operations so that compile-time errors are generated for bitwise operations which are likely incorrect, -//! such as: `WI_IsFlagSet(var, MyEnum::None)` or `WI_IsFlagSet(var, MyEnum::ValidMask)`. -//! -//! Note that the single flag helpers should be used when a compile-time constant single flag is being manipulated. These -//! helpers provide compile-time errors on misuse and should be preferred over the multi-flag helpers. The multi-flag helpers -//! should be used when multiple flags are being used simultaneously or when the flag values are not compile-time constants. -//! -//! Common example usage (manipulation of flag variables): -//! ~~~~ -//! WI_SetFlag(m_flags, MyFlags::Foo); // Set a single flag in the given variable -//! WI_SetAllFlags(m_flags, MyFlags::Foo | MyFlags::Bar); // Set one or more flags -//! WI_ClearFlagIf(m_flags, MyFlags::Bar, isBarClosed); // Conditionally clear a single flag based upon a bool -//! WI_ClearAllFlags(m_flags, MyFlags::Foo | MyFlags::Bar); // Clear one or more flags from the given variable -//! WI_ToggleFlag(m_flags, MyFlags::Foo); // Toggle (change to the opposite value) a single flag -//! WI_UpdateFlag(m_flags, MyFlags::Bar, isBarClosed); // Sets or Clears a single flag from the given variable based upon a bool value -//! WI_UpdateFlagsInMask(m_flags, flagsMask, newFlagValues); // Sets or Clears the flags in flagsMask to the masked values from newFlagValues -//! ~~~~ -//! Common example usage (inspection of flag variables): -//! ~~~~ -//! if (WI_IsFlagSet(m_flags, MyFlags::Foo)) // Is a single flag set in the given variable? -//! if (WI_IsAnyFlagSet(m_flags, MyFlags::Foo | MyFlags::Bar)) // Is at least one flag from the given mask set? -//! if (WI_AreAllFlagsClear(m_flags, MyFlags::Foo | MyFlags::Bar)) // Are all flags in the given list clear? -//! if (WI_IsSingleFlagSet(m_flags)) // Is *exactly* one flag set in the given variable? -//! ~~~~ -//! @{ - -//! Returns the unsigned type of the same width and numeric value as the given enum -#define WI_EnumValue(val) static_cast<::wil::integral_from_enum>(val) -//! Validates that exactly ONE bit is set in compile-time constant `flag` -#define WI_StaticAssertSingleBitSet(flag) static_cast(::wil::details::verify_single_flag_helper(WI_EnumValue(flag))>::value) - -//! @name Bitwise manipulation macros -//! @{ - -//! Set zero or more bitflags specified by `flags` in the variable `var`. -#define WI_SetAllFlags(var, flags) ((var) |= (flags)) -//! Set a single compile-time constant `flag` in the variable `var`. -#define WI_SetFlag(var, flag) WI_SetAllFlags(var, WI_StaticAssertSingleBitSet(flag)) -//! Conditionally sets a single compile-time constant `flag` in the variable `var` only if `condition` is true. -#define WI_SetFlagIf(var, flag, condition) do { if (wil::verify_bool(condition)) { WI_SetFlag(var, flag); } } while ((void)0, 0) - -//! Clear zero or more bitflags specified by `flags` from the variable `var`. -#define WI_ClearAllFlags(var, flags) ((var) &= ~(flags)) -//! Clear a single compile-time constant `flag` from the variable `var`. -#define WI_ClearFlag(var, flag) WI_ClearAllFlags(var, WI_StaticAssertSingleBitSet(flag)) -//! Conditionally clear a single compile-time constant `flag` in the variable `var` only if `condition` is true. -#define WI_ClearFlagIf(var, flag, condition) do { if (wil::verify_bool(condition)) { WI_ClearFlag(var, flag); } } while ((void)0, 0) - -//! Changes a single compile-time constant `flag` in the variable `var` to be set if `isFlagSet` is true or cleared if `isFlagSet` is false. -#define WI_UpdateFlag(var, flag, isFlagSet) (wil::verify_bool(isFlagSet) ? WI_SetFlag(var, flag) : WI_ClearFlag(var, flag)) -//! Changes only the flags specified by `flagsMask` in the variable `var` to match the corresponding flags in `newFlags`. -#define WI_UpdateFlagsInMask(var, flagsMask, newFlags) wil::details::UpdateFlagsInMaskHelper(var, flagsMask, newFlags) - -//! Toggles (XOR the value) of multiple bitflags specified by `flags` in the variable `var`. -#define WI_ToggleAllFlags(var, flags) ((var) ^= (flags)) -//! Toggles (XOR the value) of a single compile-time constant `flag` in the variable `var`. -#define WI_ToggleFlag(var, flag) WI_ToggleAllFlags(var, WI_StaticAssertSingleBitSet(flag)) -//! @} // bitwise manipulation macros - -//! @name Bitwise inspection macros -//! @{ - -//! Evaluates as true if every bitflag specified in `flags` is set within `val`. -#define WI_AreAllFlagsSet(val, flags) wil::details::AreAllFlagsSetHelper(val, flags) -//! Evaluates as true if one or more bitflags specified in `flags` are set within `val`. -#define WI_IsAnyFlagSet(val, flags) (static_cast(WI_EnumValue(val) & WI_EnumValue(flags)) != static_cast(0)) -//! Evaluates as true if a single compile-time constant `flag` is set within `val`. -#define WI_IsFlagSet(val, flag) WI_IsAnyFlagSet(val, WI_StaticAssertSingleBitSet(flag)) - -//! Evaluates as true if every bitflag specified in `flags` is clear within `val`. -#define WI_AreAllFlagsClear(val, flags) (static_cast(WI_EnumValue(val) & WI_EnumValue(flags)) == static_cast(0)) -//! Evaluates as true if one or more bitflags specified in `flags` are clear within `val`. -#define WI_IsAnyFlagClear(val, flags) (!wil::details::AreAllFlagsSetHelper(val, flags)) -//! Evaluates as true if a single compile-time constant `flag` is clear within `val`. -#define WI_IsFlagClear(val, flag) WI_AreAllFlagsClear(val, WI_StaticAssertSingleBitSet(flag)) - -//! Evaluates as true if exactly one bit (any bit) is set within `val`. -#define WI_IsSingleFlagSet(val) wil::details::IsSingleFlagSetHelper(val) -//! Evaluates as true if exactly one bit from within the specified `mask` is set within `val`. -#define WI_IsSingleFlagSetInMask(val, mask) wil::details::IsSingleFlagSetHelper((val) & (mask)) -//! Evaluates as true if exactly one bit (any bit) is set within `val` or if there are no bits set within `val`. -#define WI_IsClearOrSingleFlagSet(val) wil::details::IsClearOrSingleFlagSetHelper(val) -//! Evaluates as true if exactly one bit from within the specified `mask` is set within `val` or if there are no bits from `mask` set within `val`. -#define WI_IsClearOrSingleFlagSetInMask(val, mask) wil::details::IsClearOrSingleFlagSetHelper((val) & (mask)) -//! @} - -#if defined(WIL_DOXYGEN) -/** This macro provides a C++ header with a guaranteed initialization function. -Normally, were a global object's constructor used for this purpose, the optimizer/linker might throw -the object away if it's unreferenced (which throws away the side-effects that the initialization function -was trying to achieve). Using this macro forces linker inclusion of a variable that's initialized by the -provided function to elide that optimization. -//! -This functionality is primarily provided as a building block for header-based libraries (such as WIL) -to be able to layer additional functionality into other libraries by their mere inclusion. Alternative models -of initialization should be used whenever they are available. -~~~~ -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -WI_HEADER_INITITALIZATION_FUNCTION(InitializeDesktopFamilyApis, [] -{ - g_pfnGetModuleName = GetCurrentModuleName; - g_pfnFailFastInLoaderCallout = FailFastInLoaderCallout; - return 1; -}); -#endif -~~~~ -The above example is used within WIL to decide whether or not the library containing WIL is allowed to use -desktop APIs. Building this functionality as #IFDEFs within functions would create ODR violations, whereas -doing it with global function pointers and header initialization allows a runtime determination. */ -#define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) -#elif defined(_M_IX86) -#define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) \ - extern "C" { __declspec(selectany) unsigned char g_header_init_ ## name = static_cast(fn()); } \ - __pragma(comment(linker, "/INCLUDE:_g_header_init_" #name)) -#elif defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM) || defined(_M_ARM64) -#define WI_HEADER_INITITALIZATION_FUNCTION(name, fn) \ - extern "C" { __declspec(selectany) unsigned char g_header_init_ ## name = static_cast(fn()); } \ - __pragma(comment(linker, "/INCLUDE:g_header_init_" #name)) -#else - #error linker pragma must include g_header_init variation -#endif - - -/** All Windows Implementation Library classes and functions are located within the "wil" namespace. -The 'wil' namespace is an intentionally short name as the intent is for code to be able to reference -the namespace directly (example: `wil::srwlock lock;`) without a using statement. Resist adding a using -statement for wil to avoid introducing potential name collisions between wil and other namespaces. */ -namespace wil -{ - /// @cond - namespace details - { - template - class pointer_range - { - public: - pointer_range(T begin_, T end_) : m_begin(begin_), m_end(end_) {} - WI_NODISCARD T begin() const { return m_begin; } - WI_NODISCARD T end() const { return m_end; } - private: - T m_begin; - T m_end; - }; - } - /// @endcond - - /** Enables using range-based for between a begin and end object pointer. - ~~~~ - for (auto& obj : make_range(objPointerBegin, objPointerEnd)) { } - ~~~~ */ - template - details::pointer_range make_range(T begin, T end) - { - return details::pointer_range(begin, end); - } - - /** Enables using range-based for on a range when given the base pointer and the number of objects in the range. - ~~~~ - for (auto& obj : make_range(objPointer, objCount)) { } - ~~~~ */ - template - details::pointer_range make_range(T begin, size_t count) - { - return details::pointer_range(begin, begin + count); - } - - - //! @defgroup outparam Output Parameters - //! Improve the conciseness of assigning values to optional output parameters. - //! @{ - - /** Assign the given value to an optional output parameter. - Makes code more concise by removing trivial `if (outParam)` blocks. */ - template - inline void assign_to_opt_param(_Out_opt_ T *outParam, T val) - { - if (outParam != nullptr) - { - *outParam = val; - } - } - - /** Assign NULL to an optional output pointer parameter. - Makes code more concise by removing trivial `if (outParam)` blocks. */ - template - inline void assign_null_to_opt_param(_Out_opt_ T *outParam) - { - if (outParam != nullptr) - { - *outParam = nullptr; - } - } - //! @} // end output parameter helpers - - /** Performs a logical or of the given variadic template parameters allowing indirect compile-time boolean evaluation. - Example usage: - ~~~~ - template - struct FeatureRequiredBy - { - static const bool enabled = wil::variadic_logical_or::enabled...>::value; - }; - ~~~~ */ - template struct variadic_logical_or; - /// @cond - template <> struct variadic_logical_or<> : wistd::false_type { }; - template struct variadic_logical_or : wistd::true_type { }; - template struct variadic_logical_or : variadic_logical_or::type { }; - /// @endcond - - /// @cond - namespace details - { - template - struct verify_single_flag_helper - { - static_assert((flag != 0) && ((flag & (flag - 1)) == 0), "Single flag expected, zero or multiple flags found"); - static const unsigned long long value = flag; - }; - } - /// @endcond - - - //! @defgroup typesafety Type Validation - //! Helpers to validate variable types to prevent accidental, but allowed type conversions. - //! These helpers are most useful when building macros that accept a particular type. Putting these functions around the types accepted - //! prior to pushing that type through to a function (or using it within the macro) allows the macro to add an additional layer of type - //! safety that would ordinarily be stripped away by C++ implicit conversions. This system is extensively used in the error handling helper - //! macros to validate the types given to various macro parameters. - //! @{ - - /** Verify that `val` can be evaluated as a logical bool. - Other types will generate an intentional compilation error. Allowed types for a logical bool are bool, BOOL, - boolean, BOOLEAN, and classes with an explicit bool cast. - @param val The logical bool expression - @return A C++ bool representing the evaluation of `val`. */ - template - _Post_satisfies_(return == static_cast(val)) - __forceinline constexpr bool verify_bool(const T& val) - { - return static_cast(val); - } - - template - __forceinline constexpr bool verify_bool(T /*val*/) - { - static_assert(!wistd::is_same::value, "Wrong Type: bool/BOOL/BOOLEAN/boolean expected"); - return false; - } - - template <> - _Post_satisfies_(return == val) - __forceinline constexpr bool verify_bool(bool val) - { - return val; - } - - template <> - _Post_satisfies_(return == (val != 0)) - __forceinline constexpr bool verify_bool(int val) - { - return (val != 0); - } - - template <> - _Post_satisfies_(return == (val != 0)) - __forceinline constexpr bool verify_bool(unsigned char val) - { - return (val != 0); - } - - /** Verify that `val` is a Win32 BOOL value. - Other types (including other logical bool expressions) will generate an intentional compilation error. Note that this will - accept any `int` value as long as that is the underlying typedef behind `BOOL`. - @param val The Win32 BOOL returning expression - @return A Win32 BOOL representing the evaluation of `val`. */ - template - _Post_satisfies_(return == val) - __forceinline constexpr int verify_BOOL(T val) - { - // Note: Written in terms of 'int' as BOOL is actually: typedef int BOOL; - static_assert((wistd::is_same::value), "Wrong Type: BOOL expected"); - return val; - } - - /** Verify that `hr` is an HRESULT value. - Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is the - underlying typedef behind HRESULT. - //! - Note that occasionally you might run into an HRESULT which is directly defined with a #define, such as: - ~~~~ - #define UIA_E_NOTSUPPORTED 0x80040204 - ~~~~ - Though this looks like an `HRESULT`, this is actually an `unsigned long` (the hex specification forces this). When - these are encountered and they are NOT in the public SDK (have not yet shipped to the public), then you should change - their definition to match the manner in which `HRESULT` constants are defined in winerror.h: - ~~~~ - #define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L) - ~~~~ - When these are encountered in the public SDK, their type should not be changed and you should use a static_cast - to use this value in a macro that utilizes `verify_hresult`, for example: - ~~~~ - RETURN_HR_IF(static_cast(UIA_E_NOTSUPPORTED), (patternId != UIA_DragPatternId)); - ~~~~ - @param hr The HRESULT returning expression - @return An HRESULT representing the evaluation of `val`. */ - template - _Post_satisfies_(return == hr) - inline constexpr long verify_hresult(T hr) - { - // Note: Written in terms of 'long' as HRESULT is actually: typedef _Return_type_success_(return >= 0) long HRESULT - static_assert(wistd::is_same::value, "Wrong Type: HRESULT expected"); - return hr; - } - - /** Verify that `status` is an NTSTATUS value. - Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is the - underlying typedef behind NTSTATUS. - //! - Note that occasionally you might run into an NTSTATUS which is directly defined with a #define, such as: - ~~~~ - #define STATUS_NOT_SUPPORTED 0x1 - ~~~~ - Though this looks like an `NTSTATUS`, this is actually an `unsigned long` (the hex specification forces this). When - these are encountered and they are NOT in the public SDK (have not yet shipped to the public), then you should change - their definition to match the manner in which `NTSTATUS` constants are defined in ntstatus.h: - ~~~~ - #define STATUS_NOT_SUPPORTED ((NTSTATUS)0xC00000BBL) - ~~~~ - When these are encountered in the public SDK, their type should not be changed and you should use a static_cast - to use this value in a macro that utilizes `verify_ntstatus`, for example: - ~~~~ - NT_RETURN_IF_FALSE(static_cast(STATUS_NOT_SUPPORTED), (dispatch->Version == HKE_V1_0)); - ~~~~ - @param status The NTSTATUS returning expression - @return An NTSTATUS representing the evaluation of `val`. */ - template - _Post_satisfies_(return == status) - inline long verify_ntstatus(T status) - { - // Note: Written in terms of 'long' as NTSTATUS is actually: typedef _Return_type_success_(return >= 0) long NTSTATUS - static_assert(wistd::is_same::value, "Wrong Type: NTSTATUS expected"); - return status; - } - - /** Verify that `error` is a Win32 error code. - Other types will generate an intentional compilation error. Note that this will accept any `long` value as that is - the underlying type used for WIN32 error codes, as well as any `DWORD` (`unsigned long`) value since this is the type - commonly used when manipulating Win32 error codes. - @param error The Win32 error code returning expression - @return An Win32 error code representing the evaluation of `error`. */ - template - _Post_satisfies_(return == error) - inline T verify_win32(T error) - { - // Note: Win32 error code are defined as 'long' (#define ERROR_SUCCESS 0L), but are more frequently used as DWORD (unsigned long). - // This accept both types. - static_assert(wistd::is_same::value || wistd::is_same::value, "Wrong Type: Win32 error code (long / unsigned long) expected"); - return error; - } - /// @} // end type validation routines - - /// @cond - // Implementation details for macros and helper functions... do not use directly. - namespace details - { - // Use size-specific casts to avoid sign extending numbers -- avoid warning C4310: cast truncates constant value - #define __WI_MAKE_UNSIGNED(val) \ - (__pragma(warning(push)) __pragma(warning(disable: 4310 4309)) (sizeof(val) == 1 ? static_cast(val) : \ - sizeof(val) == 2 ? static_cast(val) : \ - sizeof(val) == 4 ? static_cast(val) : \ - static_cast(val)) __pragma(warning(pop))) - #define __WI_IS_UNSIGNED_SINGLE_FLAG_SET(val) ((val) && !((val) & ((val) - 1))) - #define __WI_IS_SINGLE_FLAG_SET(val) __WI_IS_UNSIGNED_SINGLE_FLAG_SET(__WI_MAKE_UNSIGNED(val)) - - template - __forceinline constexpr bool AreAllFlagsSetHelper(TVal val, TFlags flags) - { - return ((val & flags) == static_cast(flags)); - } - - template - __forceinline constexpr bool IsSingleFlagSetHelper(TVal val) - { - return __WI_IS_SINGLE_FLAG_SET(val); - } - - template - __forceinline constexpr bool IsClearOrSingleFlagSetHelper(TVal val) - { - return ((val == static_cast>(0)) || IsSingleFlagSetHelper(val)); - } - - template - __forceinline constexpr void UpdateFlagsInMaskHelper(_Inout_ TVal& val, TMask mask, TFlags flags) - { - val = static_cast>((val & ~mask) | (flags & mask)); - } - - template - struct variable_size; - - template <> - struct variable_size<1> - { - using type = unsigned char; - }; - - template <> - struct variable_size<2> - { - using type = unsigned short; - }; - - template <> - struct variable_size<4> - { - using type = unsigned long; - }; - - template <> - struct variable_size<8> - { - using type = unsigned long long; - }; - - template - struct variable_size_mapping - { - using type = typename variable_size::type; - }; - } // details - /// @endcond - - /** Defines the unsigned type of the same width (1, 2, 4, or 8 bytes) as the given type. - This allows code to generically convert any enum class to it's corresponding underlying type. */ - template - using integral_from_enum = typename details::variable_size_mapping::type; - - //! Declares a name that intentionally hides a name from an outer scope. - //! Use this to prevent accidental use of a parameter or lambda captured variable. - using hide_name = void(struct hidden_name); -} // wil - -#pragma warning(pop) - -#endif // __cplusplus -#endif // __WIL_COMMON_INCLUDED diff --git a/src/common/dep/wil/coroutine.h b/src/common/dep/wil/coroutine.h deleted file mode 100644 index c115983df..000000000 --- a/src/common/dep/wil/coroutine.h +++ /dev/null @@ -1,810 +0,0 @@ -#ifndef __WIL_COROUTINE_INCLUDED -#define __WIL_COROUTINE_INCLUDED - - /* - * A wil::task / com_task is a coroutine with the following characteristics: - * - * - T must be a copyable object, movable object, reference, or void. - * - The coroutine may be awaited at most once. The second await will crash. - * - The coroutine may be abandoned (allowed to destruct without co_await), - * in which case unobserved exceptions are fatal. - * - By default, wil::task resumes on an arbitrary thread. - * - By default, wil::com_task resumes in the same COM apartment. - * - task.resume_any_thread() allows resumption on any thread. - * - task.resume_same_apartment() forces resumption in the same COM apartment. - * - * The wil::task and wil::com_task are intended to supplement PPL and C++/WinRT, - * not to replace them. It provides coroutine implementations for scenarios that PPL - * and C++/WinRT do not support, but it does not support everything that PPL and - * C++/WinRT do. - * - * The implementation is optimized on the assumption that the coroutine is - * awaited only once, and that the coroutine is discarded after completion. - * To ensure proper usage, the task object is move-only, and - * co_await takes ownership of the task. See further discussion below. - * - * Comparison with PPL and C++/WinRT: - * - * | | PPL | C++/WinRT | wil::*task | - * |-----------------------------------------------------|-----------|-----------|---------------| - * | T can be non-constructible | No | Yes | Yes | - * | T can be void | Yes | Yes | Yes | - * | T can be reference | No | No | Yes | - * | T can be WinRT object | Yes | Yes | Yes | - * | T can be non-WinRT object | Yes | No | Yes | - * | T can be move-only | No | No | Yes | - * | Coroutine can be cancelled | Yes | Yes | No | - * | Coroutine can throw arbitrary exceptions | Yes | No | Yes | - * | Can co_await more than once | Yes | No | No | - * | Can have multiple clients waiting for completion | Yes | No | No | - * | co_await resumes in same COM context | Sometimes | Yes | You choose [1]| - * | Can force co_await to resume in same context | Yes | N/A | Yes [1] | - * | Can force co_await to resume in any thread | Yes | No | Yes | - * | Can change coroutine's resumption model | No | No | Yes | - * | Can wait synchronously | Yes | Yes | Yes [2] | - * | Can be consumed by non-C++ languages | No | Yes | No | - * | Implementation is small and efficient | No | Yes | Yes | - * | Can abandon coroutine (fail to co_await) | Yes | Yes | Yes | - * | Exception in abandoned coroutine | Crash | Ignored | Crash | - * | Coroutine starts automatically | Yes | Yes | Yes | - * | Coroutine starts synchronously | No | Yes | Yes | - * | Integrates with C++/WinRT coroutine callouts | No | Yes | No | - * - * [1] Resumption in the same COM apartment requires that you include COM headers. - * [2] Synchronous waiting requires that you include (usually via ). - * - * You can include the COM headers and/or synchapi.h headers, and then - * re-include this header file to activate the features dependent upon - * those headers. - * - * Examples: - * - * Implement a coroutine that returns a move-only non-WinRT type - * and which resumes on an arbitrary thread. - * - * wil::task GetNameAsync() - * { - * co_await resume_background(); // do work on BG thread - * wil::unique_cotaskmem_string name; - * THROW_IF_FAILED(GetNameSlow(&name)); - * co_return name; // awaiter will resume on arbitrary thread - * } - * - * Consumers: - * - * winrt::IAsyncAction UpdateNameAsync() - * { - * // wil::task resumes on an arbitrary thread. - * auto name = co_await GetNameAsync(); - * // could be on any thread now - * co_await SendNameAsync(name.get()); - * } - * - * winrt::IAsyncAction UpdateNameAsync() - * { - * // override default behavior of wil::task and - * // force it to resume in the same COM apartment. - * auto name = co_await GetNameAsync().resume_same_apartment(); - * // so we are still on the UI thread - * NameElement().Text(winrt::hstring(name.get())); - * } - * - * Conversely, a coroutine that returns a - * wil::com_task defaults to resuming in the same - * COM apartment, but you can allow it to resume on any thread - * by doing co_await GetNameAsync().resume_any_thread(). - * - * There is no harm in doing resume_same_apartment() / resume_any_thread() for a - * task that already defaults to resuming in that manner. In fact, awaiting the - * task directly is just a shorthand for awaiting the corresponding - * resume_whatever() method. - * - * Alternatively, you can just convert between wil::task and wil::com_task - * to change the default resumption context. - * - * co_await wil::com_task(GetNameAsync()); // now defaults to resume_same_apartment(); - * - * You can store the task in a variable, but since it is a move-only - * object, you will have to use std::move in order to transfer ownership out of - * an lvalue. - * - * winrt::IAsyncAction SomethingAsync() - * { - * wil::com_task task; - * switch (source) - * { - * // Some of these might return wil::task, - * // but assigning to a wil::com_task will make - * // the task resume in the same COM apartment. - * case widget: task = GetValueFromWidgetAsync(); break; - * case gadget: task = GetValueFromGadgetAsync(); break; - * case doodad: task = GetValueFromDoodadAsync(); break; - * default: FAIL_FAST(); // unknown source - * } - * auto value = co_await std::move(task); // **** need std::move - * DoSomethingWith(value); - * } - * - * You can wait synchronously by calling get(). The usual caveats - * about synchronous waits on STA threads apply. - * - * auto value = GetValueFromWidgetAsync().get(); - * - * auto task = GetValueFromWidgetAsync(); - * auto value = std::move(task).get(); // **** need std::move - */ - -// Detect which version of the coroutine standard we have. -#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) -#include -#define __WI_COROUTINE_NAMESPACE ::std::experimental -#elif defined(__cpp_lib_coroutine) -#include -#define __WI_COROUTINE_NAMESPACE ::std -#else -#error You must compile with C++20 coroutine support to use coroutine.h. -#endif -#include -#include -#include -#include -#include - -namespace wil -{ - // There are three general categories of T that you can - // use with a task. We give them these names: - // - // T = void ("void category") - // T = some kind of reference ("reference category") - // T = non-void non-reference ("object category") - // - // Take care that the implementation supports all three categories. - // - // There is a sub-category of object category for move-only types. - // We designed our task to be co_awaitable only once, so that - // it can contain a move-only type. Any transfer of T as an - // object category must be done as an rvalue reference. - template - struct task; - - template - struct com_task; -} - -namespace wil::details::coro -{ - template - struct task_promise; - - // Unions may not contain references, C++/CX types, or void. - // To work around that, we put everything inside a result_wrapper - // struct, and put the struct in the union. For void, - // we create a special empty structure. - // - // get_value returns rvalue reference to T for object - // category, or just T itself for void and reference - // category. - // - // We take advantage of the reference collapsing rules - // so that T&& = T if T is reference category. - - template - struct result_wrapper - { - T value; - T get_value() { return wistd::forward(value); } - }; - - template<> - struct result_wrapper - { - void get_value() { } - }; - - - // The result_holder is basically a - // std::variant - // but with these extra quirks: - // * The only valid transition is monotype -> something-else. - // Consequently, it does not have valueless_by_exception. - - template - struct result_holder - { - // The content of the result_holder - // depends on the result_status: - // - // empty: No active member. - // value: Active member is wrap. - // error: Active member is error. - enum class result_status { empty, value, error }; - - result_status status{ result_status::empty }; - union variant - { - variant() {} - ~variant() {} - result_wrapper wrap; - std::exception_ptr error; - } result; - - // emplace_value will be called with - // - // * no parameters (void category) - // * The reference type T (reference category) - // * Some kind of reference to T (object category) - // - // Set the status after constructing the object. - // That way, if object construction throws an exception, - // the holder remains empty. - template - void emplace_value(Args&&... args) - { - WI_ASSERT(status == result_status::empty); - new (wistd::addressof(result.wrap)) result_wrapper{ wistd::forward(args)... }; - status = result_status::value; - } - - void unhandled_exception() noexcept - { - WI_ASSERT(status == result_status::empty); - new (wistd::addressof(result.error)) std::exception_ptr(std::current_exception()); - status = result_status::error; - } - - T get_value() - { - if (status == result_status::value) - { - return result.wrap.get_value(); - } - WI_ASSERT(status == result_status::error); - std::rethrow_exception(wistd::exchange(result.error, {})); - } - - result_holder() = default; - result_holder(result_holder const&) = delete; - void operator=(result_holder const&) = delete; - - ~result_holder() noexcept(false) - { - switch (status) - { - case result_status::value: - result.wrap.~result_wrapper(); - break; - case result_status::error: - // Rethrow unobserved exception. Delete this line to - // discard unobserved exceptions. - if (result.error) std::rethrow_exception(result.error); - result.error.~exception_ptr(); - } - } - }; - - // Most of the work is done in the promise_base, - // It is a CRTP-like base class for task_promise and - // task_promise because the language forbids - // a single promise from containing both return_value and - // return_void methods (even if one of them is deleted by SFINAE). - template - struct promise_base - { - // The coroutine state remains alive as long as the coroutine is - // still running (hasn't reached final_suspend) or the associated - // task has not yet abandoned the coroutine (either finished awaiting - // or destructed without awaiting). - // - // This saves an allocation, but does mean that the local - // frame of the coroutine will remain allocated (with the - // coroutine's imbound parameters still live) until all - // references are destroyed. To force the promise_base to be - // destroyed after co_await, we make the promise_base a - // move-only object and require co_await to be given an rvalue reference. - - // Special values for m_waiting. - static void* running_ptr() { return nullptr; } - static void* completed_ptr() { return reinterpret_cast(1); } - static void* abandoned_ptr() { return reinterpret_cast(2); } - - // The awaiting coroutine is resumed by calling the - // m_resumer with the m_waiting. If the resumer is null, - // then the m_waiting is assumed to be the address of a - // coroutine_handle<>, which is resumed synchronously. - // Externalizing the resumer allows unused awaiters to be - // removed by the linker and removes a hard dependency on COM. - // Using nullptr to represent the default resumer avoids a - // CFG check. - - void(__stdcall* m_resumer)(void*); - std::atomic m_waiting{ running_ptr() }; - result_holder m_holder; - - // Make it easier to access our CRTP derived class. - using Promise = task_promise; - auto as_promise() noexcept - { - return static_cast(this); - } - - // Make it easier to access the coroutine handle. - auto as_handle() noexcept - { - return __WI_COROUTINE_NAMESPACE::coroutine_handle::from_promise(*as_promise()); - } - - auto get_return_object() noexcept - { - // let the compiler construct the task / com_task from the promise. - return as_promise(); - } - - void destroy() - { - as_handle().destroy(); - } - - // The client lost interest in the coroutine, either because they are discarding - // the result without awaiting (risky!), or because they have finished awaiting. - // Discarding the result without awaiting is risky because any exception in the coroutine - // will be unobserved and result in a crash. If you want to disallow it, then - // raise an exception if waiting == running_ptr. - void abandon() - { - auto waiting = m_waiting.exchange(abandoned_ptr(), std::memory_order_acq_rel); - if (waiting != running_ptr()) destroy(); - } - - __WI_COROUTINE_NAMESPACE::suspend_never initial_suspend() noexcept - { - return {}; - } - - template - void emplace_value(Args&&... args) - { - m_holder.emplace_value(wistd::forward(args)...); - } - - void unhandled_exception() noexcept - { - m_holder.unhandled_exception(); - } - - void resume_waiting_coroutine(void* waiting) const - { - if (m_resumer) - { - m_resumer(waiting); - } - else - { - __WI_COROUTINE_NAMESPACE::coroutine_handle<>::from_address(waiting).resume(); - } - } - - auto final_suspend() noexcept - { - struct awaiter : __WI_COROUTINE_NAMESPACE::suspend_always - { - promise_base& self; - void await_suspend(__WI_COROUTINE_NAMESPACE::coroutine_handle<>) const noexcept - { - // Need acquire so we can read from m_resumer. - // Need release so that the results are published in the case that nobody - // is awaiting right now, so that the eventual awaiter (possibly on another thread) - // can read the results. - auto waiting = self.m_waiting.exchange(completed_ptr(), std::memory_order_acq_rel); - if (waiting == abandoned_ptr()) - { - self.destroy(); - } - else if (waiting != running_ptr()) - { - WI_ASSERT(waiting != completed_ptr()); - self.resume_waiting_coroutine(waiting); - } - }; - }; - return awaiter{ {}, *this }; - } - - // The remaining methods are used by the awaiters. - bool client_await_ready() - { - // Need acquire in case the coroutine has already completed, - // so we can read the results. This matches the release in - // the final_suspend's await_suspend. - auto waiting = m_waiting.load(std::memory_order_acquire); - WI_ASSERT((waiting == running_ptr()) || (waiting == completed_ptr())); - return waiting != running_ptr(); - } - - auto client_await_suspend(void* waiting, void(__stdcall* resumer)(void*)) - { - // "waiting" needs to be a pointer to an object. We reserve the first 16 - // pseudo-pointers as sentinels. - WI_ASSERT(reinterpret_cast(waiting) > 16); - - m_resumer = resumer; - - // Acquire to ensure that we can read the results of the return value, if the coroutine is completed. - // Release to ensure that our resumption state is published, if the coroutine is not completed. - auto previous = m_waiting.exchange(waiting, std::memory_order_acq_rel); - - // Suspend if the coroutine is still running. - // Otherwise, the coroutine is completed: Nobody will resume us, so we will have to resume ourselves. - WI_ASSERT((previous == running_ptr()) || (previous == completed_ptr())); - return previous == running_ptr(); - } - - T client_await_resume() - { - return m_holder.get_value(); - } - }; - - template - struct task_promise : promise_base - { - template - void return_value(U&& value) - { - this->emplace_value(wistd::forward(value)); - } - - template - wistd::enable_if_t, Dummy> - return_value(T const& value) - { - this->emplace_value(value); - } - }; - - template<> - struct task_promise : promise_base - { - void return_void() - { - this->emplace_value(); - } - }; - - template - struct promise_deleter - { - void operator()(promise_base* promise) const noexcept - { - promise->abandon(); - } - }; - - template - using promise_ptr = wistd::unique_ptr, promise_deleter>; - - template - struct agile_awaiter - { - agile_awaiter(promise_ptr&& initial) : promise(wistd::move(initial)) { } - - promise_ptr promise; - - bool await_ready() - { - return promise->client_await_ready(); - } - - auto await_suspend(__WI_COROUTINE_NAMESPACE::coroutine_handle<> handle) - { - // Use the default resumer. - return promise->client_await_suspend(handle.address(), nullptr); - } - - T await_resume() - { - return promise->client_await_resume(); - } - }; - - template - struct task_base - { - auto resume_any_thread() && noexcept - { - return agile_awaiter{ wistd::move(promise) }; - } - - // You must #include before to enable apartment-aware awaiting. - auto resume_same_apartment() && noexcept; - - // Compiler error message metaprogramming: Tell people that they - // need to use std::move() if they try to co_await an lvalue. - struct cannot_await_lvalue_use_std_move { void await_ready() {} }; - cannot_await_lvalue_use_std_move operator co_await() & = delete; - - // You must #include (usually via ) to enable synchronous waiting. - decltype(auto) get() &&; - - protected: - task_base(task_promise* initial = nullptr) noexcept : promise(initial) {} - - template - D& assign(D* self, task_base&& other) noexcept - { - static_cast(*this) = wistd::move(other); - return *self; - } - - private: - promise_ptr promise; - - static void __stdcall wake_by_address(void* completed); - }; -} - -namespace wil -{ - // Must write out both classes separately - // Cannot use deduction guides with alias template type prior to C++20. - template - struct task : details::coro::task_base - { - using base = details::coro::task_base; - // Constructing from task_promise* cannot be explicit because get_return_object relies on implicit conversion. - task(details::coro::task_promise* initial = nullptr) noexcept : base(initial) {} - explicit task(base&& other) noexcept : base(wistd::move(other)) {} - task& operator=(base&& other) noexcept - { - return base::assign(this, wistd::move(other)); - } - - using base::operator co_await; - - auto operator co_await() && noexcept - { - return wistd::move(*this).resume_any_thread(); - } - }; - - template - struct com_task : details::coro::task_base - { - using base = details::coro::task_base; - // Constructing from task_promise* cannot be explicit because get_return_object relies on implicit conversion. - com_task(details::coro::task_promise* initial = nullptr) noexcept : base(initial) {} - explicit com_task(base&& other) noexcept : base(wistd::move(other)) {} - com_task& operator=(base&& other) noexcept - { - return base::assign(this, wistd::move(other)); - } - - using base::operator co_await; - - auto operator co_await() && noexcept - { - // You must #include before to enable non-agile awaiting. - return wistd::move(*this).resume_same_apartment(); - } - }; - - template - task(com_task&&)->task; - template - com_task(task&&)->com_task; -} - -template -struct __WI_COROUTINE_NAMESPACE::coroutine_traits, Args...> -{ - using promise_type = wil::details::coro::task_promise; -}; - -template -struct __WI_COROUTINE_NAMESPACE::coroutine_traits, Args...> -{ - using promise_type = wil::details::coro::task_promise; -}; - -#endif // __WIL_COROUTINE_INCLUDED - -// Can re-include this header after including synchapi.h (usually via windows.h) to enable synchronous wait. -#if defined(_SYNCHAPI_H_) && !defined(__WIL_COROUTINE_SYNCHRONOUS_GET_INCLUDED) -#define __WIL_COROUTINE_SYNCHRONOUS_GET_INCLUDED - -namespace wil::details::coro -{ - template - decltype(auto) task_base::get() && - { - if (!promise->client_await_ready()) - { - bool completed = false; - if (promise->client_await_suspend(&completed, wake_by_address)) - { - bool pending = false; - while (!completed) - { - WaitOnAddress(&completed, &pending, sizeof(pending), INFINITE); - } - } - } - return std::exchange(promise, {})->client_await_resume(); - } - - template - void __stdcall task_base::wake_by_address(void* completed) - { - *reinterpret_cast(completed) = true; - WakeByAddressSingle(completed); - } -} -#endif // __WIL_COROUTINE_SYNCHRONOUS_GET_INCLUDED - -// Can re-include this header after including COM header files to enable non-agile tasks. -#if defined(_COMBASEAPI_H_) && defined(_THREADPOOLAPISET_H_) && !defined(__WIL_COROUTINE_NON_AGILE_INCLUDED) -#define __WIL_COROUTINE_NON_AGILE_INCLUDED -#include -#include - -namespace wil::details::coro -{ - struct apartment_info - { - APTTYPE aptType; - APTTYPEQUALIFIER aptTypeQualifier; - - void load() - { - if (FAILED(CoGetApartmentType(&aptType, &aptTypeQualifier))) - { - // If COM is not initialized, then act as if we are running - // on the implicit MTA. - aptType = APTTYPE_MTA; - aptTypeQualifier = APTTYPEQUALIFIER_IMPLICIT_MTA; - } - } - }; - - // apartment_resumer resumes a coroutine in a captured apartment. - struct apartment_resumer - { - static auto as_self(void* p) - { - return reinterpret_cast(p); - } - - static bool is_sta() - { - apartment_info info; - info.load(); - switch (info.aptType) - { - case APTTYPE_STA: - case APTTYPE_MAINSTA: - return true; - case APTTYPE_NA: - return info.aptTypeQualifier == APTTYPEQUALIFIER_NA_ON_STA || - info.aptTypeQualifier == APTTYPEQUALIFIER_NA_ON_MAINSTA; - default: - return false; - } - } - - static wil::com_ptr current_context() - { - wil::com_ptr context; - // This will fail if COM is not initialized. Treat as implicit MTA. - // Do not use IID_PPV_ARGS to avoid ambiguity between ::IUnknown and winrt::IUnknown. - CoGetObjectContext(__uuidof(IContextCallback), reinterpret_cast(&context)); - return context; - } - - __WI_COROUTINE_NAMESPACE::coroutine_handle<> waiter; - wil::com_ptr context{ nullptr }; - apartment_info info; - HRESULT resume_result = S_OK; - - void capture_context(__WI_COROUTINE_NAMESPACE::coroutine_handle<> handle) - { - waiter = handle; - info.load(); - context = current_context(); - if (context == nullptr) - { - __debugbreak(); - } - } - - static void __stdcall resume_in_context(void* parameter) - { - auto self = as_self(parameter); - if (self->context == nullptr || self->context == current_context()) - { - self->context = nullptr; // removes the context cleanup from the resume path - self->waiter(); - } - else if (is_sta()) - { - submit_threadpool_callback(resume_context, self); - } - else - { - self->resume_context_sync(); - } - } - - static void submit_threadpool_callback(PTP_SIMPLE_CALLBACK callback, void* context) - { - THROW_IF_WIN32_BOOL_FALSE(TrySubmitThreadpoolCallback(callback, context, nullptr)); - } - - static void CALLBACK resume_context(PTP_CALLBACK_INSTANCE /*instance*/, void* parameter) - { - as_self(parameter)->resume_context_sync(); - } - - void resume_context_sync() - { - ComCallData data{}; - data.pUserDefined = this; - // The call to resume_apartment_callback will destruct the context. - // Capture into a local so we don't destruct it while it's in use. - // This also removes the context cleanup from the resume path. - auto local_context = wistd::move(context); - auto result = local_context->ContextCallback(resume_apartment_callback, &data, IID_ICallbackWithNoReentrancyToApplicationSTA, 5, nullptr); - if (FAILED(result)) - { - // Unable to resume on the correct apartment. - // Resume on the wrong apartment, but tell the coroutine why. - resume_result = result; - waiter(); - } - } - - static HRESULT CALLBACK resume_apartment_callback(ComCallData* data) noexcept - { - as_self(data->pUserDefined)->waiter(); - return S_OK; - } - - void check() - { - THROW_IF_FAILED(resume_result); - } - }; - - // The COM awaiter captures the COM context when the co_await begins. - // When the co_await completes, it uses that COM context to resume execution. - // This follows the same algorithm employed by C++/WinRT, which has features like - // avoiding stack buildup and proper handling of the neutral apartment. - // It does, however, introduce fail-fast code paths if thread pool tasks cannot - // be submitted. (Those fail-fasts could be removed by preallocating the tasks, - // but that means paying an up-front cost for something that may never end up used, - // as well as introducing extra cleanup code in the fast-path.) - template - struct com_awaiter : agile_awaiter - { - com_awaiter(promise_ptr&& initial) : agile_awaiter(wistd::move(initial)) { } - apartment_resumer resumer; - - auto await_suspend(__WI_COROUTINE_NAMESPACE::coroutine_handle<> handle) - { - resumer.capture_context(handle); - return this->promise->client_await_suspend(wistd::addressof(resumer), apartment_resumer::resume_in_context); - } - - decltype(auto) await_resume() - { - resumer.check(); - return agile_awaiter::await_resume(); - } - }; - - template - auto task_base::resume_same_apartment() && noexcept - { - return com_awaiter{ wistd::move(promise) }; - } -} -#endif // __WIL_COROUTINE_NON_AGILE_INCLUDED diff --git a/src/common/dep/wil/cppwinrt.h b/src/common/dep/wil/cppwinrt.h deleted file mode 100644 index c69a85194..000000000 --- a/src/common/dep/wil/cppwinrt.h +++ /dev/null @@ -1,491 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_CPPWINRT_INCLUDED -#define __WIL_CPPWINRT_INCLUDED - -#include "common.h" -#include -#include -#include -#include - -// WIL and C++/WinRT use two different exception types for communicating HRESULT failures. Thus, both libraries need to -// understand how to translate these exception types into the correct HRESULT values at the ABI boundary. Prior to -// C++/WinRT "2.0" this was accomplished by injecting the WINRT_EXTERNAL_CATCH_CLAUSE macro - that WIL defines below - -// into its exception handler (winrt::to_hresult). Starting with C++/WinRT "2.0" this mechanism has shifted to a global -// function pointer - winrt_to_hresult_handler - that WIL sets automatically when this header is included and -// 'CPPWINRT_SUPPRESS_STATIC_INITIALIZERS' is not defined. - -/// @cond -namespace wil::details -{ - // Since the C++/WinRT version macro is a string... - // For example: "2.0.221104.6" - inline constexpr int version_from_string(const char* versionString) - { - int result = 0; - while ((*versionString >= '0') && (*versionString <= '9')) - { - result = result * 10 + (*versionString - '0'); - ++versionString; - } - - return result; - } - - inline constexpr int major_version_from_string(const char* versionString) - { - return version_from_string(versionString); - } - - inline constexpr int minor_version_from_string(const char* versionString) - { - int dotCount = 0; - while ((*versionString != '\0')) - { - if (*versionString == '.') - { - ++dotCount; - } - - ++versionString; - if (dotCount == 2) - { - return version_from_string(versionString); - } - } - - return 0; - } -} -/// @endcond - -#ifdef CPPWINRT_VERSION -// Prior to C++/WinRT "2.0" this header needed to be included before 'winrt/base.h' so that our definition of -// 'WINRT_EXTERNAL_CATCH_CLAUSE' would get picked up in the implementation of 'winrt::to_hresult'. This is no longer -// problematic, so only emit an error when using a version of C++/WinRT prior to 2.0 -static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2, - "Please include wil/cppwinrt.h before including any C++/WinRT headers"); -#endif - -// NOTE: Will eventually be removed once C++/WinRT 2.0 use can be assumed -#ifdef WINRT_EXTERNAL_CATCH_CLAUSE -#define __WI_CONFLICTING_WINRT_EXTERNAL_CATCH_CLAUSE 1 -#else -#define WINRT_EXTERNAL_CATCH_CLAUSE \ - catch (const wil::ResultException& e) \ - { \ - return winrt::hresult_error(e.GetErrorCode(), winrt::to_hstring(e.what())).to_abi(); \ - } -#endif - -#include "result_macros.h" -#include - -#if __WI_CONFLICTING_WINRT_EXTERNAL_CATCH_CLAUSE -static_assert(::wil::details::major_version_from_string(CPPWINRT_VERSION) >= 2, - "C++/WinRT external catch clause already defined outside of WIL"); -#endif - -// In C++/WinRT 2.0 and beyond, this function pointer exists. In earlier versions it does not. It's much easier to avoid -// linker errors than it is to SFINAE on variable existence, so we declare the variable here, but are careful not to -// use it unless the version of C++/WinRT is high enough -extern std::int32_t(__stdcall* winrt_to_hresult_handler)(void*) noexcept; - -// The same is true with this function pointer as well, except that the version must be 2.X or higher. -extern void(__stdcall* winrt_throw_hresult_handler)(uint32_t, char const*, char const*, void*, winrt::hresult const) noexcept; - -/// @cond -namespace wil::details -{ - inline void MaybeGetExceptionString( - const winrt::hresult_error& exception, - _Out_writes_opt_(debugStringChars) PWSTR debugString, - _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) - { - if (debugString) - { - StringCchPrintfW(debugString, debugStringChars, L"winrt::hresult_error: %ls", exception.message().c_str()); - } - } - - inline HRESULT __stdcall ResultFromCaughtException_CppWinRt( - _Inout_updates_opt_(debugStringChars) PWSTR debugString, - _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, - _Inout_ bool* isNormalized) noexcept - { - if (g_pfnResultFromCaughtException) - { - try - { - throw; - } - catch (const ResultException& exception) - { - *isNormalized = true; - MaybeGetExceptionString(exception, debugString, debugStringChars); - return exception.GetErrorCode(); - } - catch (const winrt::hresult_error& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return exception.to_abi(); - } - catch (const std::bad_alloc& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return E_OUTOFMEMORY; - } - catch (const std::out_of_range& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return E_BOUNDS; - } - catch (const std::invalid_argument& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return E_INVALIDARG; - } - catch (...) - { - auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars); - if (FAILED(hr)) - { - return hr; - } - } - } - else - { - try - { - throw; - } - catch (const ResultException& exception) - { - *isNormalized = true; - MaybeGetExceptionString(exception, debugString, debugStringChars); - return exception.GetErrorCode(); - } - catch (const winrt::hresult_error& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return exception.to_abi(); - } - catch (const std::bad_alloc& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return E_OUTOFMEMORY; - } - catch (const std::out_of_range& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return E_BOUNDS; - } - catch (const std::invalid_argument& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return E_INVALIDARG; - } - catch (const std::exception& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); - } - catch (...) - { - // Fall through to returning 'S_OK' below - } - } - - // Tell the caller that we were unable to map the exception by succeeding... - return S_OK; - } -} -/// @endcond - -namespace wil -{ - inline std::int32_t __stdcall winrt_to_hresult(void* returnAddress) noexcept - { - // C++/WinRT only gives us the return address (caller), so pass along an empty 'DiagnosticsInfo' since we don't - // have accurate file/line/etc. information - return static_cast(details::ReportFailure_CaughtException(__R_DIAGNOSTICS_RA(DiagnosticsInfo{}, returnAddress))); - } - - inline void __stdcall winrt_throw_hresult(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept - { - void* callerReturnAddress{nullptr}; PCSTR code{nullptr}; - wil::details::ReportFailure_Hr(__R_FN_CALL_FULL __R_COMMA result); - } - - inline void WilInitialize_CppWinRT() - { - details::g_pfnResultFromCaughtException_CppWinRt = details::ResultFromCaughtException_CppWinRt; - if constexpr (details::major_version_from_string(CPPWINRT_VERSION) >= 2) - { - WI_ASSERT(winrt_to_hresult_handler == nullptr); - winrt_to_hresult_handler = winrt_to_hresult; - - if constexpr (details::minor_version_from_string(CPPWINRT_VERSION) >= 210122) - { - WI_ASSERT(winrt_throw_hresult_handler == nullptr); - winrt_throw_hresult_handler = winrt_throw_hresult; - } - } - } - - /// @cond - namespace details - { -#ifndef CPPWINRT_SUPPRESS_STATIC_INITIALIZERS - WI_ODR_PRAGMA("CPPWINRT_SUPPRESS_STATIC_INITIALIZERS", "0") - WI_HEADER_INITITALIZATION_FUNCTION(WilInitialize_CppWinRT, [] - { - ::wil::WilInitialize_CppWinRT(); - return 1; - }); -#else - WI_ODR_PRAGMA("CPPWINRT_SUPPRESS_STATIC_INITIALIZERS", "1") -#endif - } - /// @endcond - - // Provides an overload of verify_hresult so that the WIL macros can recognize winrt::hresult as a valid "hresult" type. - inline long verify_hresult(winrt::hresult hr) noexcept - { - return hr; - } - - // Provides versions of get_abi and put_abi for genericity that directly use HSTRING for convenience. - template - auto get_abi(T const& object) noexcept - { - return winrt::get_abi(object); - } - - inline auto get_abi(winrt::hstring const& object) noexcept - { - return static_cast(winrt::get_abi(object)); - } - - inline auto str_raw_ptr(const winrt::hstring& str) noexcept - { - return str.c_str(); - } - - template - auto put_abi(T& object) noexcept - { - return winrt::put_abi(object); - } - - inline auto put_abi(winrt::hstring& object) noexcept - { - return reinterpret_cast(winrt::put_abi(object)); - } - - inline ::IUnknown* com_raw_ptr(const winrt::Windows::Foundation::IUnknown& ptr) noexcept - { - return static_cast<::IUnknown*>(winrt::get_abi(ptr)); - } - - // Needed to power wil::cx_object_from_abi that requires IInspectable - inline ::IInspectable* com_raw_ptr(const winrt::Windows::Foundation::IInspectable& ptr) noexcept - { - return static_cast<::IInspectable*>(winrt::get_abi(ptr)); - } - - // Taken from the docs.microsoft.com article - template - T convert_from_abi(::IUnknown* from) - { - T to{ nullptr }; // `T` is a projected type. - winrt::check_hresult(from->QueryInterface(winrt::guid_of(), winrt::put_abi(to))); - return to; - } - - // For obtaining an object from an interop method on the factory. Example: - // winrt::InputPane inputPane = wil::capture_interop(&IInputPaneInterop::GetForWindow, hwnd); - // If the method produces something different from the factory type: - // winrt::IAsyncAction action = wil::capture_interop(&IAccountsSettingsPaneInterop::ShowAddAccountForWindow, hwnd); - template - auto capture_interop(HRESULT(__stdcall Interface::* method)(InterfaceArgs...), Args&&... args) - { - auto interop = winrt::get_activation_factory(); - return winrt::capture(interop, method, std::forward(args)...); - } - - // For obtaining an object from an interop method on an instance. Example: - // winrt::UserActivitySession session = wil::capture_interop(activity, &IUserActivityInterop::CreateSessionForWindow, hwnd); - template - auto capture_interop(winrt::Windows::Foundation::IUnknown const& o, HRESULT(__stdcall Interface::* method)(InterfaceArgs...), Args&&... args) - { - return winrt::capture(o.as(), method, std::forward(args)...); - } - - /** Holds a reference to the host C++/WinRT module to prevent it from being unloaded. - Normally, this is done by being in an IAsyncOperation coroutine or by holding a strong - reference to a C++/WinRT object hosted in the same module, but if you have neither, - you will need to hold a reference explicitly. For the WRL equivalent, see wrl_module_reference. - - This can be used as a base, which permits EBO: - ~~~~ - struct NonWinrtObject : wil::winrt_module_reference - { - int value; - }; - - // DLL will not be unloaded as long as NonWinrtObject is still alive. - auto p = std::make_unique(); - ~~~~ - - Or it can be used as a member (with [[no_unique_address]] to avoid - occupying any memory): - ~~~~ - struct NonWinrtObject - { - int value; - - [[no_unique_address]] wil::winrt_module_reference module_ref; - }; - - // DLL will not be unloaded as long as NonWinrtObject is still alive. - auto p = std::make_unique(); - ~~~~ - - If using it to prevent the host DLL from unloading while a thread - or threadpool work item is still running, create the object before - starting the thread, and pass it to the thread. This avoids a race - condition where the host DLL could get unloaded before the thread starts. - ~~~~ - std::thread([module_ref = wil::winrt_module_reference()]() { do_background_work(); }); - - // Don't do this (race condition) - std::thread([]() { wil::winrt_module_reference module_ref; do_background_work(); }); // WRONG - ~~~~ - - Also useful in coroutines that neither capture DLL-hosted COM objects, nor are themselves - DLL-hosted COM objects. (If the coroutine returns IAsyncAction or captures a get_strong() - of its containing WinRT class, then the IAsyncAction or strong reference will itself keep - a strong reference to the host module.) - ~~~~ - winrt::fire_and_forget ContinueBackgroundWork() - { - // prevent DLL from unloading while we are running on a background thread. - // Do this before switching to the background thread. - wil::winrt_module_reference module_ref; - - co_await winrt::resume_background(); - do_background_work(); - }; - ~~~~ - */ - struct [[nodiscard]] winrt_module_reference - { - winrt_module_reference() - { - ++winrt::get_module_lock(); - } - - winrt_module_reference(winrt_module_reference const&) : winrt_module_reference() {} - - ~winrt_module_reference() - { - --winrt::get_module_lock(); - } - }; - - /** Implements a C++/WinRT class where some interfaces are conditionally supported. - ~~~~ - // Assume the existence of a class "Version2" which says whether - // the IMyThing2 interface should be supported. - struct Version2 { static bool IsEnabled(); }; - - // Declare implementation class which conditionally supports IMyThing2. - struct MyThing : wil::winrt_conditionally_implements, - Version2, IMyThing2> - { - // implementation goes here - }; - - ~~~~ - - If `Version2::IsEnabled()` returns `false`, then the `QueryInterface` - for `IMyThing2` will fail. - - Any interface not listed as conditional is assumed to be enabled unconditionally. - - You can add additional Version / Interface pairs to the template parameter list. - Interfaces may be conditionalized on at most one Version class. If you need a - complex conditional, create a new helper class. - - ~~~~ - // Helper class for testing two Versions. - struct Version2_or_greater { - static bool IsEnabled() { return Version2::IsEnabled() || Version3::IsEnabled(); } - }; - - // This implementation supports IMyThing2 if either Version2 or Version3 is enabled, - // and supports IMyThing3 only if Version3 is enabled. - struct MyThing : wil::winrt_conditionally_implements, - Version2_or_greater, IMyThing2, Version3, IMyThing3> - { - // implementation goes here - }; - ~~~~ - */ - template - struct winrt_conditionally_implements : Implements - { - using Implements::Implements; - - void* find_interface(winrt::guid const& iid) const noexcept override - { - static_assert(sizeof...(Rest) % 2 == 0, "Extra template parameters should come in groups of two"); - if (is_enabled<0, std::tuple>(iid)) - { - return Implements::find_interface(iid); - } - return nullptr; - } - - private: - template - static bool is_enabled(winrt::guid const& iid) - { - if constexpr (index >= std::tuple_size_v) - { - return true; - } - else - { - check_no_duplicates<1, index + 1, Tuple>(); - return (iid == winrt::guid_of>()) ? - std::tuple_element_t::IsEnabled() : - is_enabled(iid); - } - } - - template - static constexpr void check_no_duplicates() - { - if constexpr (index < upto) - { - static_assert(!std::is_same_v, std::tuple_element_t>, - "Duplicate interfaces found in winrt_conditionally_implements"); - check_no_duplicates(); - } - } - }; -} - -#endif // __WIL_CPPWINRT_INCLUDED diff --git a/src/common/dep/wil/cppwinrt_authoring.h b/src/common/dep/wil/cppwinrt_authoring.h deleted file mode 100644 index 0b524b2fb..000000000 --- a/src/common/dep/wil/cppwinrt_authoring.h +++ /dev/null @@ -1,290 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* - -namespace wil -{ -#ifndef __WIL_CPPWINRT_AUTHORING_PROPERTIES_INCLUDED -#define __WIL_CPPWINRT_AUTHORING_PROPERTIES_INCLUDED - namespace details - { - template - struct single_threaded_property_storage - { - T m_value{}; - single_threaded_property_storage() = default; - single_threaded_property_storage(const T& value) : m_value(value) {} - operator T& () { return m_value; } - operator T const& () const { return m_value; } - template auto operator=(Q&& q) - { - m_value = wistd::forward(q); - return *this; - } - }; - } - - template - struct single_threaded_property : std::conditional_t || std::is_final_v, wil::details::single_threaded_property_storage, T> - { - single_threaded_property() = default; - template single_threaded_property(TArgs&&... value) : base_type(std::forward(value)...) {} - - using base_type = std::conditional_t || std::is_final_v, wil::details::single_threaded_property_storage, T>; - - T operator()() const - { - return *this; - } - - // This is the only setter exposed. We don't expose `operator()(Q&& q)`, - // since that is what C++/WinRT uses to implement public setters. Since - // single_threaded_property is intended for readonly properties, we - // don't want to expose that. - // - // To set the value of this property *internally* (within your - // implementation), use this `operator=`: - // - // MyProperty = 42; - // // MyProperty(42); // won't work - // - // For settable properties, use single_threaded_rw_property instead. - template auto& operator=(Q&& q) - { - static_cast(*this) = std::forward(q); - return *this; - } - }; - - template - struct single_threaded_rw_property : single_threaded_property - { - using base_type = single_threaded_property; - template single_threaded_rw_property(TArgs&&... value) : base_type(std::forward(value)...) {} - - using base_type::operator(); - - // needed in lieu of deducing-this - template auto& operator()(Q&& q) - { - return *this = std::forward(q); - } - - // needed in lieu of deducing-this - template auto& operator=(Q&& q) - { - base_type::operator=(std::forward(q)); - return *this; - } - }; - -#endif // __WIL_CPPWINRT_AUTHORING_PROPERTIES_INCLUDED - -#if !defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_FOUNDATION) && defined(WINRT_Windows_Foundation_H) // WinRT / XAML helpers -#define __WIL_CPPWINRT_AUTHORING_INCLUDED_FOUNDATION - namespace details - { - template - struct event_base { - winrt::event_token operator()(const T& handler) - { - return m_handler.add(handler); - } - - auto operator()(const winrt::event_token& token) noexcept - { - return m_handler.remove(token); - } - - template - auto invoke(TArgs&&... args) - { - return m_handler(std::forward(args)...); - } - private: - winrt::event m_handler; - }; - } - - /** - * @brief A default event handler that maps to [Windows.Foundation.EventHandler](https://docs.microsoft.com/uwp/api/windows.foundation.eventhandler-1). - * @tparam T The event data type. - */ - template - struct untyped_event : wil::details::event_base> {}; - - /** - * @brief A default event handler that maps to [Windows.Foundation.TypedEventHandler](https://docs.microsoft.com/uwp/api/windows.foundation.typedeventhandler-2). - * @tparam T The event data type. - * @details Usage example: - * @code - * // In IDL, this corresponds to: - * // event Windows.Foundation.TypedEventHandler OkClicked; - * wil::typed_event OkClicked; - * @endcode - */ - template - struct typed_event : wil::details::event_base> {}; - -#endif // !defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_FOUNDATION) && defined(WINRT_Windows_Foundation_H) - -#if !defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_XAML_DATA) && (defined(WINRT_Microsoft_UI_Xaml_Data_H) || defined(WINRT_Windows_UI_Xaml_Data_H)) // INotifyPropertyChanged helpers -#define __WIL_CPPWINRT_AUTHORING_INCLUDED_XAML_DATA - namespace details - { -#ifdef WINRT_Microsoft_UI_Xaml_Data_H - using Xaml_Data_PropertyChangedEventHandler = winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventHandler; - using Xaml_Data_PropertyChangedEventArgs = winrt::Microsoft::UI::Xaml::Data::PropertyChangedEventArgs; -#elif defined(WINRT_Windows_UI_Xaml_Data_H) - using Xaml_Data_PropertyChangedEventHandler = winrt::Windows::UI::Xaml::Data::PropertyChangedEventHandler; - using Xaml_Data_PropertyChangedEventArgs = winrt::Windows::UI::Xaml::Data::PropertyChangedEventArgs; -#endif - } - - /** - * @brief Helper base class to inherit from to have a simple implementation of [INotifyPropertyChanged](https://docs.microsoft.com/uwp/api/windows.ui.xaml.data.inotifypropertychanged). - * @tparam T CRTP type - * @details When you declare your class, make this class a base class and pass your class as a template parameter: - * @code - * struct MyPage : MyPageT, wil::notify_property_changed_base - * { - * wil::single_threaded_notifying_property MyInt; - * MyPage() : INIT_NOTIFYING_PROPERTY(MyInt, 42) { } - * // or - * WIL_NOTIFYING_PROPERTY(int, MyInt, 42); - * }; - * @endcode - */ - template - struct notify_property_changed_base - { - using Type = T; - auto PropertyChanged(Xaml_Data_PropertyChangedEventHandler const& value) - { - return m_propertyChanged.add(value); - } - - void PropertyChanged(winrt::event_token const& token) - { - m_propertyChanged.remove(token); - } - - Type& self() - { - return *static_cast(this); - } - - /** - * @brief Raises a property change notification event - * @param name The name of the property - * @return - * @details Usage example\n - * C++ - * @code - * void MyPage::DoSomething() - * { - * // modify MyInt - * // MyInt = ... - * - * // now send a notification to update the bound UI elements - * RaisePropertyChanged(L"MyInt"); - * } - * @endcode - */ - auto RaisePropertyChanged(std::wstring_view name) - { - return m_propertyChanged(self(), Xaml_Data_PropertyChangedEventArgs{ name }); - } - protected: - winrt::event m_propertyChanged; - }; - - /** - * @brief Implements a property type with notifications - * @tparam T the property type - * @details Use the #INIT_NOTIFY_PROPERTY macro to initialize this property in your class constructor. This will set up the right property name, and bind it to the `notify_property_changed_base` implementation. - */ - template - struct single_threaded_notifying_property : single_threaded_rw_property - { - using Type = T; - using base_type = single_threaded_rw_property; - using base_type::operator(); - - template auto& operator()(Q&& q) - { - return *this = std::forward(q); - } - - template auto& operator=(Q&& q) - { - if (q != this->operator()()) - { - static_cast(*this) = std::forward(q); - if (auto strong = m_sender.get(); (m_npc != nullptr) && (strong != nullptr)) - { - (*m_npc)(strong, Xaml_Data_PropertyChangedEventArgs{ m_name }); - } - } - return *this; - } - - template - single_threaded_notifying_property( - winrt::event* npc, - const winrt::Windows::Foundation::IInspectable& sender, - std::wstring_view name, - TArgs&&... args) : - single_threaded_rw_property(std::forward(args)...), - m_name(name), - m_npc(npc), - m_sender(sender) - {} - - single_threaded_notifying_property(const single_threaded_notifying_property&) = default; - single_threaded_notifying_property(single_threaded_notifying_property&&) = default; - std::wstring_view Name() const noexcept { return m_name; } - private: - std::wstring_view m_name; - winrt::event* m_npc; - winrt::weak_ref m_sender; - }; - - /** - * @def WIL_NOTIFYING_PROPERTY - * @brief use this to stamp out a property that calls RaisePropertyChanged upon changing its value. This is a zero-storage alternative to wil::single_threaded_notifying_property - * @details You can pass an initializer list for the initial property value in the variadic arguments to this macro. - */ -#define WIL_NOTIFYING_PROPERTY(type, name, ...) \ - type m_##name{__VA_ARGS__}; \ - auto name() const noexcept { return m_##name; } \ - auto& name(type value) \ - { \ - if (m_##name != value) \ - { \ - m_##name = std::move(value); \ - RaisePropertyChanged(L"" #name); \ - } \ - return *this; \ - } \ - - /** - * @def INIT_NOTIFYING_PROPERTY - * @brief use this to initialize a wil::single_threaded_notifying_property in your class constructor. - */ -#define INIT_NOTIFYING_PROPERTY(NAME, VALUE) \ - NAME(&m_propertyChanged, *this, L"" #NAME, VALUE) - -#endif // !defined(__WIL_CPPWINRT_AUTHORING_INCLUDED_XAML_DATA) && (defined(WINRT_Microsoft_UI_Xaml_Data_H) || defined(WINRT_Windows_UI_Xaml_Data_H)) -} // namespace wil diff --git a/src/common/dep/wil/cppwinrt_helpers.h b/src/common/dep/wil/cppwinrt_helpers.h deleted file mode 100644 index 0e2c960a7..000000000 --- a/src/common/dep/wil/cppwinrt_helpers.h +++ /dev/null @@ -1,352 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* - -#ifndef __WIL_CPPWINRT_HELPERS_DEFINED -#define __WIL_CPPWINRT_HELPERS_DEFINED - -/// @cond -namespace wil::details -{ - struct dispatcher_RunAsync - { - template - static void Schedule(Dispatcher const& dispatcher, Args&&... args) - { - dispatcher.RunAsync(std::forward(args)...); - } - }; - - struct dispatcher_TryEnqueue - { - template - static void Schedule(Dispatcher const& dispatcher, Args&&... args) - { - dispatcher.TryEnqueue(std::forward(args)...); - } - }; - - template struct dispatcher_traits; -} - -#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) -#include -namespace wil::details -{ - template using coroutine_handle = std::experimental::coroutine_handle; -} -#elif defined(__cpp_lib_coroutine) && (__cpp_lib_coroutine >= 201902L) -#include -namespace wil::details -{ - template using coroutine_handle = std::coroutine_handle; -} -#endif -/// @endcond - -#if defined(_RESUMABLE_FUNCTIONS_SUPPORTED) || (defined(__cpp_lib_coroutine) && (__cpp_lib_coroutine >= 201902L)) -/// @cond -namespace wil::details -{ - struct dispatched_handler_state - { - details::coroutine_handle<> handle{}; - bool orphaned = false; - }; - - struct dispatcher_handler - { - dispatcher_handler(dispatched_handler_state* state) : m_state(state) { } - dispatcher_handler(dispatcher_handler&& other) noexcept : m_state(std::exchange(other.m_state, {})) {} - - ~dispatcher_handler() - { - if (m_state && m_state->handle) - { - m_state->orphaned = true; - Complete(); - } - } - void operator()() - { - Complete(); - } - - void Complete() - { - auto state = std::exchange(m_state, nullptr); - std::exchange(state->handle, {}).resume(); - } - - dispatched_handler_state* m_state; - }; -} -/// @endcond - -namespace wil -{ - //! Resumes coroutine execution on the thread associated with the dispatcher, or throws - //! an exception (from an arbitrary thread) if unable. Supported dispatchers are - //! Windows.System.DispatcherQueue, Microsoft.System.DispatcherQueue, - //! Microsoft.UI.Dispatching.DispatcherQueue, and Windows.UI.Core.CoreDispatcher, - //! but you must include the corresponding header before including - //! wil\cppwinrt_helpers.h. It is okay to include wil\cppwinrt_helpers.h multiple times: - //! support will be enabled for any winrt/Namespace.h headers that were included since - //! the previous inclusion of wil\cppwinrt_headers.h. - template - [[nodiscard]] auto resume_foreground(Dispatcher const& dispatcher, - typename details::dispatcher_traits::Priority priority = details::dispatcher_traits::Priority::Normal) - { - using Traits = details::dispatcher_traits; - using Priority = typename Traits::Priority; - using Handler = typename Traits::Handler; - - struct awaitable - { - awaitable(Dispatcher const& dispatcher, Priority priority) noexcept : - m_dispatcher(dispatcher), - m_priority(priority) - { - } - bool await_ready() const noexcept { return false; } - - void await_suspend(details::coroutine_handle<> handle) - { - m_state.handle = handle; - Handler handler{ details::dispatcher_handler(&m_state) }; - try - { - // The return value of Schedule is not reliable. Use the dispatcher_handler destructor - // to detect whether the work item failed to run. - Traits::Scheduler::Schedule(m_dispatcher, m_priority, handler); - } - catch (...) - { - m_state.handle = nullptr; // the exception will resume the coroutine, so the handler shouldn't do it - throw; - } - } - - void await_resume() const - { - if (m_state.orphaned) - { - throw winrt::hresult_error(static_cast(0x800701ab)); // HRESULT_FROM_WIN32(ERROR_NO_TASK_QUEUE) - } - } - - private: - Dispatcher const& m_dispatcher; - Priority const m_priority; - details::dispatched_handler_state m_state; - }; - return awaitable{ dispatcher, priority }; - } -} -#endif // Coroutines are supported - -#endif // __WIL_CPPWINRT_HELPERS_DEFINED - -/// @cond -#if defined(WINRT_Windows_UI_Core_H) && !defined(__WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS) -#define __WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS -namespace wil::details -{ - template<> - struct dispatcher_traits - { - using Priority = winrt::Windows::UI::Core::CoreDispatcherPriority; - using Handler = winrt::Windows::UI::Core::DispatchedHandler; - using Scheduler = dispatcher_RunAsync; - }; -} -#endif // __WIL_CPPWINRT_WINDOWS_UI_CORE_HELPERS - -#if defined(WINRT_Windows_System_H) && !defined(__WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS) -#define __WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS -namespace wil::details -{ - template<> - struct dispatcher_traits - { - using Priority = winrt::Windows::System::DispatcherQueuePriority; - using Handler = winrt::Windows::System::DispatcherQueueHandler; - using Scheduler = dispatcher_TryEnqueue; - }; -} -#endif // __WIL_CPPWINRT_WINDOWS_SYSTEM_HELPERS - -#if defined(WINRT_Microsoft_System_H) && !defined(__WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS) -#define __WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS -namespace wil::details -{ - template<> - struct dispatcher_traits - { - using Priority = winrt::Microsoft::System::DispatcherQueuePriority; - using Handler = winrt::Microsoft::System::DispatcherQueueHandler; - using Scheduler = dispatcher_TryEnqueue; - }; -} -#endif // __WIL_CPPWINRT_MICROSOFT_SYSTEM_HELPERS - -#if defined(WINRT_Microsoft_UI_Dispatching_H) && !defined(__WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS) -#define __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS -namespace wil::details -{ - template<> - struct dispatcher_traits - { - using Priority = winrt::Microsoft::UI::Dispatching::DispatcherQueuePriority; - using Handler = winrt::Microsoft::UI::Dispatching::DispatcherQueueHandler; - using Scheduler = dispatcher_TryEnqueue; - }; -} -#endif // __WIL_CPPWINRT_MICROSOFT_UI_DISPATCHING_HELPERS -/// @endcond - -#if defined(WINRT_Windows_Foundation_Collections_H) && !defined(__WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS) -#define __WIL_CPPWINRT_WINDOWS_FOUNDATION_COLLECTION_HELPERS -namespace wil -{ - /// @cond - namespace details - { - template struct is_winrt_vector_like { - private: - template ().GetMany(std::declval().Size(), - winrt::array_view().GetAt(0))>{}))> - static constexpr bool get_value(int) { return true; } - template static constexpr bool get_value(...) { return false; } - public: - static constexpr bool value = get_value(0); - }; - - template struct is_winrt_iterator_like { - private: - template ().GetMany(winrt::array_view().Current())>{}))> - static constexpr bool get_value(int) { return true; } - template static constexpr bool get_value(...) { return false; } - public: - static constexpr bool value = get_value(0); - }; - - template constexpr T empty() noexcept - { - if constexpr (std::is_base_of_v) - { - return nullptr; - } - else - { - return {}; - } - } - } - /// @endcond - - /** Converts C++ / WinRT vectors, iterators, and iterables to std::vector by requesting the - collection's data in bulk. This can be more efficient in terms of IPC cost than iteratively - processing the collection. - ~~~ - winrt::IVector collection = GetCollection(); - std::vector allData = wil::to_vector(collection); // read all data from collection - for (winrt::hstring const& item : allData) - { - // use item - } - ~~~ - Can be used for IVector, IVectorView, IIterable, IIterator, and any type or - interface that C++/WinRT projects those interfaces for (PropertySet, IMap, etc.) - Iterable-only types fetch content in units of 64. When used with an iterator, the returned - vector contains the iterator's current position and any others after it. - */ - template auto to_vector(TSrc const& src) - { - if constexpr (details::is_winrt_vector_like::value) - { - using T = decltype(src.GetAt(0)); - std::vector result; - if (auto expected = src.Size()) - { - result.resize(expected + 1, details::empty()); - auto actual = src.GetMany(0, result); - if (actual > expected) - { - throw winrt::hresult_changed_state(); - } - result.resize(actual, details::empty()); - } - return result; - } - else if constexpr (details::is_winrt_iterator_like::value) - { - using T = decltype(src.Current()); - std::vector result; - constexpr uint32_t chunkSize = 64; - while (true) - { - auto const lastSize = result.size(); - result.resize(lastSize + chunkSize, details::empty()); - auto fetched = src.GetMany({result.data() + lastSize, result.data() + lastSize + chunkSize }); - if (fetched < chunkSize) - { - result.resize(lastSize + fetched, details::empty()); - break; - } - } - return result; - } - else - { - return to_vector(src.First()); - } - } -} -#endif - -#if defined(WINRT_Windows_UI_H) && defined(_WINDOWS_UI_INTEROP_H_) && !defined(__WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS) -#define __WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS -#if !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) && !defined(MIDL_NS_PREFIX) -#pragma push_macro("ABI") -#undef ABI -#define ABI -#endif - -namespace wil -{ -#if defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_WIN10_CU) - //! The following methods require that you include both - //! before including wil/cppwinrt_helpers.h, and that NTDDI_VERSION - //! is at least NTDDI_WIN10_CU. It is okay to include wil\cppwinrt_helpers.h multiple times: - //! support will be enabled for any headers that were included since the previous inclusion - //! of wil\cppwinrt_headers.h. - inline winrt::Windows::UI::WindowId GetWindowIdFromWindow(HWND hwnd) - { - ABI::Windows::UI::WindowId abiWindowId; - winrt::check_hresult(::GetWindowIdFromWindow(hwnd, &abiWindowId)); - return winrt::Windows::UI::WindowId{ abiWindowId.Value }; - } - - inline HWND GetWindowFromWindowId(winrt::Windows::UI::WindowId windowId) - { - HWND hwnd; - winrt::check_hresult(::GetWindowFromWindowId({ windowId.Value }, &hwnd)); - return hwnd; - } -#endif /*defined(NTDDI_VERSION) && (NTDDI_VERSION >= NTDDI_WIN10_CU)*/ -} - -#if !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) && !defined(MIDL_NS_PREFIX) -#pragma pop_macro("ABI") -#endif -#endif // __WIL_CPPWINRT_WINDOWS_UI_INTEROP_HELPERS diff --git a/src/common/dep/wil/cppwinrt_wrl.h b/src/common/dep/wil/cppwinrt_wrl.h deleted file mode 100644 index afd6f8e99..000000000 --- a/src/common/dep/wil/cppwinrt_wrl.h +++ /dev/null @@ -1,74 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_CPPWINRT_WRL_INCLUDED -#define __WIL_CPPWINRT_WRL_INCLUDED - -#include "cppwinrt.h" -#include - -#include "result_macros.h" -#include - -// wil::wrl_factory_for_winrt_com_class provides interopability between a -// C++/WinRT class and the WRL Module system, allowing the winrt class to be -// CoCreatable. -// -// Usage: -// - In your cpp, add: -// CoCreatableCppWinRtClass(className) -// -// - In the dll.cpp (or equivalent) for the module containing your class, add: -// CoCreatableClassWrlCreatorMapInclude(className) -// -namespace wil -{ - namespace details - { - template - class module_count_wrapper : public TCppWinRTClass - { - public: - module_count_wrapper() - { - if (auto modulePtr = ::Microsoft::WRL::GetModuleBase()) - { - modulePtr->IncrementObjectCount(); - } - } - - virtual ~module_count_wrapper() - { - if (auto modulePtr = ::Microsoft::WRL::GetModuleBase()) - { - modulePtr->DecrementObjectCount(); - } - } - }; - } - - template - class wrl_factory_for_winrt_com_class : public ::Microsoft::WRL::ClassFactory<> - { - public: - IFACEMETHODIMP CreateInstance(_In_opt_ ::IUnknown* unknownOuter, REFIID riid, _COM_Outptr_ void **object) noexcept try - { - *object = nullptr; - RETURN_HR_IF(CLASS_E_NOAGGREGATION, unknownOuter != nullptr); - - return winrt::make>().as(riid, object); - } - CATCH_RETURN() - }; -} - -#define CoCreatableCppWinRtClass(className) CoCreatableClassWithFactory(className, ::wil::wrl_factory_for_winrt_com_class) - -#endif // __WIL_CPPWINRT_WRL_INCLUDED diff --git a/src/common/dep/wil/filesystem.h b/src/common/dep/wil/filesystem.h deleted file mode 100644 index 4434cbea9..000000000 --- a/src/common/dep/wil/filesystem.h +++ /dev/null @@ -1,1050 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_FILESYSTEM_INCLUDED -#define __WIL_FILESYSTEM_INCLUDED - -#ifdef _KERNEL_MODE -#error This header is not supported in kernel-mode. -#endif - -#include -#include // Needed for CoTaskMemFree() used in output of some helpers. -#include // LocalAlloc -#include -#include "result.h" -#include "win32_helpers.h" -#include "resource.h" - -namespace wil -{ - //! Determines if a path is an extended length path that can be used to access paths longer than MAX_PATH. - inline bool is_extended_length_path(_In_ PCWSTR path) - { - return wcsncmp(path, L"\\\\?\\", 4) == 0; - } - -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN7) - //! Find the last segment of a path. Matches the behavior of shlwapi!PathFindFileNameW() - //! note, does not support streams being specified like PathFindFileNameW(), is that a bug or a feature? - inline PCWSTR find_last_path_segment(_In_ PCWSTR path) - { - auto const pathLength = wcslen(path); - // If there is a trailing slash ignore that in the search. - auto const limitedLength = ((pathLength > 0) && (path[pathLength - 1] == L'\\')) ? (pathLength - 1) : pathLength; - - PCWSTR result = nullptr; - auto const offset = FindStringOrdinal(FIND_FROMEND, path, static_cast(limitedLength), L"\\", 1, TRUE); - if (offset == -1) - { - result = path + pathLength; // null terminator - } - else - { - result = path + offset + 1; // just past the slash - } - return result; - } -#endif - - //! Determine if the file name is one of the special "." or ".." names. - inline bool path_is_dot_or_dotdot(_In_ PCWSTR fileName) - { - return ((fileName[0] == L'.') && - ((fileName[1] == L'\0') || ((fileName[1] == L'.') && (fileName[2] == L'\0')))); - } - - //! Returns the drive number, if it has one. Returns true if there is a drive number, false otherwise. Supports regular and extended length paths. - inline bool try_get_drive_letter_number(_In_ PCWSTR path, _Out_ int* driveNumber) - { - if (path[0] == L'\\' && path[1] == L'\\' && path[2] == L'?' && path[3] == L'\\') - { - path += 4; - } - if (path[0] && (path[1] == L':')) - { - if ((path[0] >= L'a') && (path[0] <= L'z')) - { - *driveNumber = path[0] - L'a'; - return true; - } - else if ((path[0] >= L'A') && (path[0] <= L'Z')) - { - *driveNumber = path[0] - L'A'; - return true; - } - } - *driveNumber = -1; - return false; - } - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7) - - // PathCch.h APIs are only in desktop API for now. - - // Compute the substring in the input value that is the parent folder path. - // returns: - // true + parentPathLength - path has a parent starting at the beginning path and of parentPathLength length. - // false, no parent path, the input is a root path. - inline bool try_get_parent_path_range(_In_ PCWSTR path, _Out_ size_t* parentPathLength) - { - *parentPathLength = 0; - bool hasParent = false; - PCWSTR rootEnd = nullptr; - if (SUCCEEDED(PathCchSkipRoot(path, &rootEnd)) && (*rootEnd != L'\0')) - { - auto const lastSegment = find_last_path_segment(path); - *parentPathLength = lastSegment - path; - hasParent = (*parentPathLength != 0); - } - return hasParent; - } - - // Creates directories for the specified path, creating parent paths - // as needed. - inline HRESULT CreateDirectoryDeepNoThrow(PCWSTR path) WI_NOEXCEPT - { - if (::CreateDirectoryW(path, nullptr) == FALSE) - { - DWORD lastError = ::GetLastError(); - if (lastError == ERROR_PATH_NOT_FOUND) - { - size_t parentLength{}; - if (try_get_parent_path_range(path, &parentLength)) - { - wistd::unique_ptr parent(new (std::nothrow) wchar_t[parentLength + 1]); - RETURN_IF_NULL_ALLOC(parent.get()); - RETURN_IF_FAILED(StringCchCopyNW(parent.get(), parentLength + 1, path, parentLength)); - RETURN_IF_FAILED(CreateDirectoryDeepNoThrow(parent.get())); // recurs - } - if (::CreateDirectoryW(path, nullptr) == FALSE) - { - lastError = ::GetLastError(); - if (lastError != ERROR_ALREADY_EXISTS) - { - RETURN_WIN32(lastError); - } - } - } - else if (lastError != ERROR_ALREADY_EXISTS) - { - RETURN_WIN32(lastError); - } - } - return S_OK; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - inline void CreateDirectoryDeep(PCWSTR path) - { - THROW_IF_FAILED(CreateDirectoryDeepNoThrow(path)); - } -#endif // WIL_ENABLE_EXCEPTIONS - - //! A strongly typed version of the Win32 API GetFullPathNameW. - //! Return a path in an allocated buffer for handling long paths. - //! Optionally return the pointer to the file name part. - template - HRESULT GetFullPathNameW(PCWSTR file, string_type& path, _Outptr_opt_ PCWSTR* filePart = nullptr) - { - wil::assign_null_to_opt_param(filePart); - const auto hr = AdaptFixedSizeToAllocatedResult(path, - [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNull) -> HRESULT - { - // Note that GetFullPathNameW() is not limited to MAX_PATH - // but it does take a fixed size buffer. - *valueLengthNeededWithNull = ::GetFullPathNameW(file, static_cast(valueLength), value, nullptr); - RETURN_LAST_ERROR_IF(*valueLengthNeededWithNull == 0); - WI_ASSERT((*value != L'\0') == (*valueLengthNeededWithNull < valueLength)); - if (*valueLengthNeededWithNull < valueLength) - { - (*valueLengthNeededWithNull)++; // it fit, account for the null - } - return S_OK; - }); - if (SUCCEEDED(hr) && filePart) - { - *filePart = wil::find_last_path_segment(details::string_maker::get(path)); - } - return hr; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - //! A strongly typed version of the Win32 API of GetFullPathNameW. - //! Return a path in an allocated buffer for handling long paths. - //! Optionally return the pointer to the file name part. - template - string_type GetFullPathNameW(PCWSTR file, _Outptr_opt_ PCWSTR* filePart = nullptr) - { - string_type result{}; - THROW_IF_FAILED((GetFullPathNameW(file, result, filePart))); - return result; - } -#endif - - enum class RemoveDirectoryOptions - { - None = 0, - KeepRootDirectory = 0x1, - RemoveReadOnly = 0x2, - }; - DEFINE_ENUM_FLAG_OPERATORS(RemoveDirectoryOptions); - - namespace details - { - // Reparse points should not be traversed in most recursive walks of the file system, - // unless allowed through the appropriate reparse tag. - inline bool CanRecurseIntoDirectory(const FILE_ATTRIBUTE_TAG_INFO& info) - { - return (WI_IsFlagSet(info.FileAttributes, FILE_ATTRIBUTE_DIRECTORY) && - (WI_IsFlagClear(info.FileAttributes, FILE_ATTRIBUTE_REPARSE_POINT) || - (IsReparseTagDirectory(info.ReparseTag) || (info.ReparseTag == IO_REPARSE_TAG_WCI)))); - } - } - - // Retrieve a handle to a directory only if it is safe to recurse into. - inline wil::unique_hfile TryCreateFileCanRecurseIntoDirectory(PCWSTR path, PWIN32_FIND_DATAW fileFindData, DWORD access = GENERIC_READ | /*DELETE*/ 0x00010000L, DWORD share = FILE_SHARE_READ) - { - wil::unique_hfile result(CreateFileW(path, access, share, - nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr)); - if (result) - { - FILE_ATTRIBUTE_TAG_INFO fati{}; - if (GetFileInformationByHandleEx(result.get(), FileAttributeTagInfo, &fati, sizeof(fati)) && - details::CanRecurseIntoDirectory(fati)) - { - if (fileFindData) - { - // Refresh the found file's data now that we have secured the directory from external manipulation. - fileFindData->dwFileAttributes = fati.FileAttributes; - fileFindData->dwReserved0 = fati.ReparseTag; - } - } - else - { - result.reset(); - } - } - - return result; - } - - // If inputPath is a non-normalized name be sure to pass an extended length form to ensure - // it can be addressed and deleted. - inline HRESULT RemoveDirectoryRecursiveNoThrow(PCWSTR inputPath, RemoveDirectoryOptions options = RemoveDirectoryOptions::None, HANDLE deleteHandle = INVALID_HANDLE_VALUE) WI_NOEXCEPT - { - wil::unique_hlocal_string path; - PATHCCH_OPTIONS combineOptions = PATHCCH_NONE; - - if (is_extended_length_path(inputPath)) - { - path = wil::make_hlocal_string_nothrow(inputPath); - RETURN_IF_NULL_ALLOC(path); - // PathAllocCombine will convert extended length paths to regular paths if shorter than - // MAX_PATH, avoid that behavior to provide access inputPath with non-normalized names. - combineOptions = PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH; - } - else - { - // For regular paths normalize here to get consistent results when searching and deleting. - RETURN_IF_FAILED(wil::GetFullPathNameW(inputPath, path)); - combineOptions = PATHCCH_ALLOW_LONG_PATHS; - } - - wil::unique_hlocal_string searchPath; - RETURN_IF_FAILED(::PathAllocCombine(path.get(), L"*", combineOptions, &searchPath)); - - WIN32_FIND_DATAW fd{}; - wil::unique_hfind findHandle(::FindFirstFileW(searchPath.get(), &fd)); - RETURN_LAST_ERROR_IF(!findHandle); - - for (;;) - { - // skip "." and ".." - if (!(WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY) && path_is_dot_or_dotdot(fd.cFileName))) - { - // Need to form an extended length path to provide the ability to delete paths > MAX_PATH - // and files with non-normalized names (dots or spaces at the end). - wil::unique_hlocal_string pathToDelete; - RETURN_IF_FAILED(::PathAllocCombine(path.get(), fd.cFileName, - PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH | PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, &pathToDelete)); - if (WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY)) - { - // Get a handle to the directory to delete, preventing it from being replaced to prevent writes which could be used - // to bypass permission checks, and verify that it is not a name surrogate (e.g. symlink, mount point, etc). - wil::unique_hfile recursivelyDeletableDirectoryHandle = TryCreateFileCanRecurseIntoDirectory(pathToDelete.get(), &fd); - if (recursivelyDeletableDirectoryHandle) - { - RemoveDirectoryOptions localOptions = options; - RETURN_IF_FAILED(RemoveDirectoryRecursiveNoThrow(pathToDelete.get(), WI_ClearFlag(localOptions, RemoveDirectoryOptions::KeepRootDirectory), recursivelyDeletableDirectoryHandle.get())); - } - else if (WI_IsFlagSet(fd.dwFileAttributes, FILE_ATTRIBUTE_REPARSE_POINT)) - { - // This is a directory reparse point that should not be recursed. Delete it without traversing into it. - RETURN_IF_WIN32_BOOL_FALSE(::RemoveDirectoryW(pathToDelete.get())); - } - else - { - // Failed to grab a handle to the file or to read its attributes. This is not safe to recurse. - RETURN_WIN32(::GetLastError()); - } - } - else - { - // Try a DeleteFile. Some errors may be recoverable. - if (!::DeleteFileW(pathToDelete.get())) - { - // Fail for anything other than ERROR_ACCESS_DENIED with option to RemoveReadOnly available - bool potentiallyFixableReadOnlyProblem = - WI_IsFlagSet(options, RemoveDirectoryOptions::RemoveReadOnly) && ::GetLastError() == ERROR_ACCESS_DENIED; - RETURN_LAST_ERROR_IF(!potentiallyFixableReadOnlyProblem); - - // Fail if the file does not have read-only set, likely just an ACL problem - DWORD fileAttr = ::GetFileAttributesW(pathToDelete.get()); - RETURN_LAST_ERROR_IF(!WI_IsFlagSet(fileAttr, FILE_ATTRIBUTE_READONLY)); - - // Remove read-only flag, setting to NORMAL if completely empty - WI_ClearFlag(fileAttr, FILE_ATTRIBUTE_READONLY); - if (fileAttr == 0) - { - fileAttr = FILE_ATTRIBUTE_NORMAL; - } - - // Set the new attributes and try to delete the file again, returning any failure - ::SetFileAttributesW(pathToDelete.get(), fileAttr); - RETURN_IF_WIN32_BOOL_FALSE(::DeleteFileW(pathToDelete.get())); - } - } - } - - if (!::FindNextFileW(findHandle.get(), &fd)) - { - auto const err = ::GetLastError(); - if (err == ERROR_NO_MORE_FILES) - { - break; - } - RETURN_WIN32(err); - } - } - - if (WI_IsFlagClear(options, RemoveDirectoryOptions::KeepRootDirectory)) - { - if (deleteHandle != INVALID_HANDLE_VALUE) - { -#if (NTDDI_VERSION >= NTDDI_WIN10_RS1) - // DeleteFile and RemoveDirectory use POSIX delete, falling back to non-POSIX on most errors. Do the same here. - FILE_DISPOSITION_INFO_EX fileInfoEx{}; - fileInfoEx.Flags = FILE_DISPOSITION_FLAG_DELETE | FILE_DISPOSITION_FLAG_POSIX_SEMANTICS; - if (!SetFileInformationByHandle(deleteHandle, FileDispositionInfoEx, &fileInfoEx, sizeof(fileInfoEx))) - { - auto const err = ::GetLastError(); - // The real error we're looking for is STATUS_CANNOT_DELETE, but that's mapped to ERROR_ACCESS_DENIED. - if (err != ERROR_ACCESS_DENIED) - { -#endif - FILE_DISPOSITION_INFO fileInfo{}; - fileInfo.DeleteFile = TRUE; - RETURN_IF_WIN32_BOOL_FALSE(SetFileInformationByHandle(deleteHandle, FileDispositionInfo, &fileInfo, sizeof(fileInfo))); -#if (NTDDI_VERSION >= NTDDI_WIN10_RS1) - } - else - { - RETURN_WIN32(err); - } - } -#endif - } - else - { - RETURN_IF_WIN32_BOOL_FALSE(::RemoveDirectoryW(path.get())); - } - } - return S_OK; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - inline void RemoveDirectoryRecursive(PCWSTR path, RemoveDirectoryOptions options = RemoveDirectoryOptions::None) - { - THROW_IF_FAILED(RemoveDirectoryRecursiveNoThrow(path, options)); - } -#endif // WIL_ENABLE_EXCEPTIONS - - // Range based for that supports Win32 structures that use NextEntryOffset as the basis of traversing - // a result buffer that contains data. This is used in the following FileIO calls: - // FileStreamInfo, FILE_STREAM_INFO - // FileIdBothDirectoryInfo, FILE_ID_BOTH_DIR_INFO - // FileFullDirectoryInfo, FILE_FULL_DIR_INFO - // FileIdExtdDirectoryInfo, FILE_ID_EXTD_DIR_INFO - // ReadDirectoryChangesW, FILE_NOTIFY_INFORMATION - - template - struct next_entry_offset_iterator - { - // Fulfill std::iterator_traits requirements - using difference_type = ptrdiff_t; - using value_type = T; - using pointer = const T*; - using reference = const T&; -#ifdef _XUTILITY_ - using iterator_category = ::std::forward_iterator_tag; -#endif - - next_entry_offset_iterator(T *iterable = __nullptr) : current_(iterable) {} - - // range based for requires operator!=, operator++ and operator* to do its work - // on the type returned from begin() and end(), provide those here. - WI_NODISCARD bool operator!=(const next_entry_offset_iterator& other) const { return current_ != other.current_; } - - next_entry_offset_iterator& operator++() - { - current_ = (current_->NextEntryOffset != 0) ? - reinterpret_cast(reinterpret_cast(current_) + current_->NextEntryOffset) : - __nullptr; - return *this; - } - - next_entry_offset_iterator operator++(int) - { - auto copy = *this; - ++(*this); - return copy; - } - - WI_NODISCARD reference operator*() const WI_NOEXCEPT { return *current_; } - WI_NODISCARD pointer operator->() const WI_NOEXCEPT { return current_; } - - next_entry_offset_iterator begin() { return *this; } - next_entry_offset_iterator end() { return next_entry_offset_iterator(); } - - T* current_; - }; - - template - next_entry_offset_iterator create_next_entry_offset_iterator(T* p) - { - return next_entry_offset_iterator(p); - } - -#pragma region Folder Watcher - // Example use in exception based code: - // auto watcher = wil::make_folder_watcher(folder.Path().c_str(), true, wil::allChangeEvents, []() - // { - // // respond - // }); - // - // Example use in result code based code: - // wil::unique_folder_watcher watcher; - // THROW_IF_FAILED(watcher.create(folder, true, wil::allChangeEvents, []() - // { - // // respond - // })); - - enum class FolderChangeEvent : DWORD - { - ChangesLost = 0, // requies special handling, reset state as events were lost - Added = FILE_ACTION_ADDED, - Removed = FILE_ACTION_REMOVED, - Modified = FILE_ACTION_MODIFIED, - RenameOldName = FILE_ACTION_RENAMED_OLD_NAME, - RenameNewName = FILE_ACTION_RENAMED_NEW_NAME, - }; - - enum class FolderChangeEvents : DWORD - { - None = 0, - FileName = FILE_NOTIFY_CHANGE_FILE_NAME, - DirectoryName = FILE_NOTIFY_CHANGE_DIR_NAME, - Attributes = FILE_NOTIFY_CHANGE_ATTRIBUTES, - FileSize = FILE_NOTIFY_CHANGE_SIZE, - LastWriteTime = FILE_NOTIFY_CHANGE_LAST_WRITE, - Security = FILE_NOTIFY_CHANGE_SECURITY, - All = FILE_NOTIFY_CHANGE_FILE_NAME | - FILE_NOTIFY_CHANGE_DIR_NAME | - FILE_NOTIFY_CHANGE_ATTRIBUTES | - FILE_NOTIFY_CHANGE_SIZE | - FILE_NOTIFY_CHANGE_LAST_WRITE | - FILE_NOTIFY_CHANGE_SECURITY - }; - DEFINE_ENUM_FLAG_OPERATORS(FolderChangeEvents); - - /// @cond - namespace details - { - struct folder_watcher_state - { - folder_watcher_state(wistd::function &&callback) : m_callback(wistd::move(callback)) - { - } - wistd::function m_callback; - // Order is important, need to close the thread pool wait before the change handle. - unique_hfind_change m_findChangeHandle; - unique_threadpool_wait m_threadPoolWait; - }; - - inline void delete_folder_watcher_state(_In_opt_ folder_watcher_state *storage) { delete storage; } - - typedef resource_policy folder_watcher_state_resource_policy; - } - /// @endcond - - template - class folder_watcher_t : public storage_t - { - public: - // forward all base class constructors... - template - explicit folder_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} - - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Exception-based constructors - folder_watcher_t(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); - create(folderToWatch, isRecursive, filter, wistd::move(callback)); - } - - result create(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) - { - return err_policy::HResult(create_common(folderToWatch, isRecursive, filter, wistd::move(callback))); - } - private: - // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas - // to __stdcall - static void __stdcall callback(PTP_CALLBACK_INSTANCE /*Instance*/, void *context, TP_WAIT *pThreadPoolWait, TP_WAIT_RESULT /*result*/) - { - auto watcherState = static_cast(context); - watcherState->m_callback(); - - // Rearm the wait. Should not fail with valid parameters. - FindNextChangeNotification(watcherState->m_findChangeHandle.get()); - SetThreadpoolWait(pThreadPoolWait, watcherState->m_findChangeHandle.get(), __nullptr); - } - - // This function exists to avoid template expansion of this code based on err_policy. - HRESULT create_common(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) - { - wistd::unique_ptr watcherState(new(std::nothrow) details::folder_watcher_state(wistd::move(callback))); - RETURN_IF_NULL_ALLOC(watcherState); - - watcherState->m_findChangeHandle.reset(FindFirstChangeNotificationW(folderToWatch, isRecursive, static_cast(filter))); - RETURN_LAST_ERROR_IF(!watcherState->m_findChangeHandle); - - watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(&folder_watcher_t::callback, watcherState.get(), __nullptr)); - RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); - this->reset(watcherState.release()); // no more failures after this, pass ownership - SetThreadpoolWait(this->get()->m_threadPoolWait.get(), this->get()->m_findChangeHandle.get(), __nullptr); - return S_OK; - } - }; - - typedef unique_any_t, err_returncode_policy>> unique_folder_watcher_nothrow; - - inline unique_folder_watcher_nothrow make_folder_watcher_nothrow(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) WI_NOEXCEPT - { - unique_folder_watcher_nothrow watcher; - watcher.create(folderToWatch, isRecursive, filter, wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) - } - -#ifdef WIL_ENABLE_EXCEPTIONS - typedef unique_any_t, err_exception_policy>> unique_folder_watcher; - - inline unique_folder_watcher make_folder_watcher(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) - { - return unique_folder_watcher(folderToWatch, isRecursive, filter, wistd::move(callback)); - } -#endif // WIL_ENABLE_EXCEPTIONS - -#pragma endregion - -#pragma region Folder Reader - - // Example use for throwing: - // auto reader = wil::make_folder_change_reader(folder.Path().c_str(), true, wil::FolderChangeEvents::All, - // [](wil::FolderChangeEvent event, PCWSTR fileName) - // { - // switch (event) - // { - // case wil::FolderChangeEvent::ChangesLost: break; - // case wil::FolderChangeEvent::Added: break; - // case wil::FolderChangeEvent::Removed: break; - // case wil::FolderChangeEvent::Modified: break; - // case wil::FolderChangeEvent::RenamedOldName: break; - // case wil::FolderChangeEvent::RenamedNewName: break; - // }); - // - // Example use for non throwing: - // wil::unique_folder_change_reader_nothrow reader; - // THROW_IF_FAILED(reader.create(folder, true, wil::FolderChangeEvents::All, - // [](wil::FolderChangeEvent event, PCWSTR fileName) - // { - // // handle changes - // })); - // - - // @cond - namespace details - { - struct folder_change_reader_state - { - folder_change_reader_state(bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) - : m_callback(wistd::move(callback)), m_isRecursive(isRecursive), m_filter(filter) - { - } - - ~folder_change_reader_state() - { - if (m_tpIo != __nullptr) - { - TP_IO *tpIo = m_tpIo; - - // Indicate to the callback function that this object is being torn - // down. - - { - auto autoLock = m_cancelLock.lock_exclusive(); - m_tpIo = __nullptr; - } - - // Cancel IO to terminate the file system monitoring operation. - - if (m_folderHandle) - { - CancelIoEx(m_folderHandle.get(), &m_overlapped); - - DWORD bytesTransferredIgnored = 0; - GetOverlappedResult(m_folderHandle.get(), &m_overlapped, &bytesTransferredIgnored, TRUE); - } - - // Wait for callbacks to complete. - // - // N.B. This is a blocking call and must not be made within a - // callback or within a lock which is taken inside the - // callback. - - WaitForThreadpoolIoCallbacks(tpIo, TRUE); - CloseThreadpoolIo(tpIo); - } - } - - HRESULT StartIo() - { - // Unfortunately we have to handle ref-counting of IOs on behalf of the - // thread pool. - StartThreadpoolIo(m_tpIo); - HRESULT hr = ReadDirectoryChangesW(m_folderHandle.get(), m_readBuffer, sizeof(m_readBuffer), - m_isRecursive, static_cast(m_filter), __nullptr, &m_overlapped, __nullptr) ? - S_OK : HRESULT_FROM_WIN32(::GetLastError()); - if (FAILED(hr)) - { - // This operation does not have the usual semantic of returning - // ERROR_IO_PENDING. - // WI_ASSERT(hr != HRESULT_FROM_WIN32(ERROR_IO_PENDING)); - - // If the operation failed for whatever reason, ensure the TP - // ref counts are accurate. - - CancelThreadpoolIo(m_tpIo); - } - return hr; - } - - // void (wil::FolderChangeEvent event, PCWSTR fileName) - wistd::function m_callback; - unique_handle m_folderHandle; - BOOL m_isRecursive = FALSE; - FolderChangeEvents m_filter = FolderChangeEvents::None; - OVERLAPPED m_overlapped{}; - TP_IO *m_tpIo = __nullptr; - srwlock m_cancelLock; - unsigned char m_readBuffer[4096]{}; // Consider alternative buffer sizes. With 512 byte buffer i was not able to observe overflow. - }; - - inline void delete_folder_change_reader_state(_In_opt_ folder_change_reader_state *storage) { delete storage; } - - typedef resource_policy folder_change_reader_state_resource_policy; - } - /// @endcond - - template - class folder_change_reader_t : public storage_t - { - public: - // forward all base class constructors... - template - explicit folder_change_reader_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} - - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Exception-based constructors - folder_change_reader_t(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); - create(folderToWatch, isRecursive, filter, wistd::move(callback)); - } - - result create(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) - { - return err_policy::HResult(create_common(folderToWatch, isRecursive, filter, wistd::move(callback))); - } - - wil::unique_hfile& folder_handle() { return this->get()->m_folderHandle; } - - private: - // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas - // to __stdcall - static void __stdcall callback(PTP_CALLBACK_INSTANCE /* Instance */, void *context, void * /*overlapped*/, - ULONG result, ULONG_PTR /* BytesTransferred */, TP_IO * /* Io */) - { - auto readerState = static_cast(context); - // WI_ASSERT(overlapped == &readerState->m_overlapped); - - if (result == ERROR_SUCCESS) - { - for (auto const& info : create_next_entry_offset_iterator(reinterpret_cast(readerState->m_readBuffer))) - { - wchar_t realtiveFileName[MAX_PATH]; - StringCchCopyNW(realtiveFileName, ARRAYSIZE(realtiveFileName), info.FileName, info.FileNameLength / sizeof(info.FileName[0])); - - readerState->m_callback(static_cast(info.Action), realtiveFileName); - } - } - else if (result == ERROR_NOTIFY_ENUM_DIR) - { - readerState->m_callback(FolderChangeEvent::ChangesLost, __nullptr); - } - else - { - // No need to requeue - return; - } - - // If the lock is held non-shared or the TP IO is nullptr, this - // structure is being torn down. Otherwise, monitor for further - // changes. - auto autoLock = readerState->m_cancelLock.try_lock_shared(); - if (autoLock && readerState->m_tpIo) - { - readerState->StartIo(); // ignoring failure here - } - } - - // This function exists to avoid template expansion of this code based on err_policy. - HRESULT create_common(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, wistd::function &&callback) - { - wistd::unique_ptr readerState(new(std::nothrow) details::folder_change_reader_state( - isRecursive, filter, wistd::move(callback))); - RETURN_IF_NULL_ALLOC(readerState); - - readerState->m_folderHandle.reset(CreateFileW(folderToWatch, - FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, - __nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, __nullptr)); - RETURN_LAST_ERROR_IF(!readerState->m_folderHandle); - - readerState->m_tpIo = CreateThreadpoolIo(readerState->m_folderHandle.get(), &folder_change_reader_t::callback, readerState.get(), __nullptr); - RETURN_LAST_ERROR_IF_NULL(readerState->m_tpIo); - RETURN_IF_FAILED(readerState->StartIo()); - this->reset(readerState.release()); - return S_OK; - } - }; - - typedef unique_any_t, err_returncode_policy>> unique_folder_change_reader_nothrow; - - inline unique_folder_change_reader_nothrow make_folder_change_reader_nothrow(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, - wistd::function &&callback) WI_NOEXCEPT - { - unique_folder_change_reader_nothrow watcher; - watcher.create(folderToWatch, isRecursive, filter, wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) - } - -#ifdef WIL_ENABLE_EXCEPTIONS - typedef unique_any_t, err_exception_policy>> unique_folder_change_reader; - - inline unique_folder_change_reader make_folder_change_reader(PCWSTR folderToWatch, bool isRecursive, FolderChangeEvents filter, - wistd::function &&callback) - { - return unique_folder_change_reader(folderToWatch, isRecursive, filter, wistd::move(callback)); - } -#endif // WIL_ENABLE_EXCEPTIONS -#pragma endregion - - //! Dos and VolumeGuid paths are always extended length paths with the \\?\ prefix. - enum class VolumePrefix - { - Dos = VOLUME_NAME_DOS, // Extended Dos Device path form, e.g. \\?\C:\Users\Chris\AppData\Local\Temp\wil8C31.tmp - VolumeGuid = VOLUME_NAME_GUID, // \\?\Volume{588fb606-b95b-4eae-b3cb-1e49861aaf18}\Users\Chris\AppData\Local\Temp\wil8C31.tmp - // The following are special paths which can't be used with Win32 APIs, but are useful in other scenarios. - None = VOLUME_NAME_NONE, // Path without the volume root, e.g. \Users\Chris\AppData\Local\Temp\wil8C31.tmp - NtObjectName = VOLUME_NAME_NT, // Unique name used by Object Manager, e.g. \Device\HarddiskVolume4\Users\Chris\AppData\Local\Temp\wil8C31.tmp - }; - enum class PathOptions - { - Normalized = FILE_NAME_NORMALIZED, - Opened = FILE_NAME_OPENED, - }; - DEFINE_ENUM_FLAG_OPERATORS(PathOptions); - - /** A strongly typed version of the Win32 API GetFinalPathNameByHandleW. - Get the full path name in different forms - Use this instead + VolumePrefix::None instead of GetFileInformationByHandleEx(FileNameInfo) to - get that path form. */ - template - HRESULT GetFinalPathNameByHandleW(HANDLE fileHandle, string_type& path, - wil::VolumePrefix volumePrefix = wil::VolumePrefix::Dos, wil::PathOptions options = wil::PathOptions::Normalized) - { - return AdaptFixedSizeToAllocatedResult(path, - [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNull) -> HRESULT - { - *valueLengthNeededWithNull = ::GetFinalPathNameByHandleW(fileHandle, value, static_cast(valueLength), - static_cast(volumePrefix) | static_cast(options)); - RETURN_LAST_ERROR_IF(*valueLengthNeededWithNull == 0); - WI_ASSERT((*value != L'\0') == (*valueLengthNeededWithNull < valueLength)); - if (*valueLengthNeededWithNull < valueLength) - { - (*valueLengthNeededWithNull)++; // it fit, account for the null - } - return S_OK; - }); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - /** A strongly typed version of the Win32 API GetFinalPathNameByHandleW. - Get the full path name in different forms. Use this + VolumePrefix::None - instead of GetFileInformationByHandleEx(FileNameInfo) to get that path form. */ - template - string_type GetFinalPathNameByHandleW(HANDLE fileHandle, - wil::VolumePrefix volumePrefix = wil::VolumePrefix::Dos, wil::PathOptions options = wil::PathOptions::Normalized) - { - string_type result{}; - THROW_IF_FAILED((GetFinalPathNameByHandleW(fileHandle, result, volumePrefix, options))); - return result; - } -#endif - - //! A strongly typed version of the Win32 API of GetCurrentDirectoryW. - //! Return a path in an allocated buffer for handling long paths. - template - HRESULT GetCurrentDirectoryW(string_type& path) - { - return AdaptFixedSizeToAllocatedResult(path, - [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNull) -> HRESULT - { - *valueLengthNeededWithNull = ::GetCurrentDirectoryW(static_cast(valueLength), value); - RETURN_LAST_ERROR_IF(*valueLengthNeededWithNull == 0); - WI_ASSERT((*value != L'\0') == (*valueLengthNeededWithNull < valueLength)); - if (*valueLengthNeededWithNull < valueLength) - { - (*valueLengthNeededWithNull)++; // it fit, account for the null - } - return S_OK; - }); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - //! A strongly typed version of the Win32 API of GetCurrentDirectoryW. - //! Return a path in an allocated buffer for handling long paths. - template - string_type GetCurrentDirectoryW() - { - string_type result{}; - THROW_IF_FAILED((GetCurrentDirectoryW(result))); - return result; - } -#endif - - // TODO: add support for these and other similar APIs. - // GetShortPathNameW() - // GetLongPathNameW() - // GetTempDirectory() - - /// @cond - namespace details - { - template struct MapInfoClassToInfoStruct; // failure to map is a usage error caught by the compiler -#define MAP_INFOCLASS_TO_STRUCT(InfoClass, InfoStruct, IsFixed, Extra) \ - template <> struct MapInfoClassToInfoStruct \ - { \ - typedef InfoStruct type; \ - static bool const isFixed = IsFixed; \ - static size_t const extraSize = Extra; \ - }; - - MAP_INFOCLASS_TO_STRUCT(FileBasicInfo, FILE_BASIC_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileStandardInfo, FILE_STANDARD_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileNameInfo, FILE_NAME_INFO, false, 32); - MAP_INFOCLASS_TO_STRUCT(FileRenameInfo, FILE_RENAME_INFO, false, 32); - MAP_INFOCLASS_TO_STRUCT(FileDispositionInfo, FILE_DISPOSITION_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileAllocationInfo, FILE_ALLOCATION_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileEndOfFileInfo, FILE_END_OF_FILE_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileStreamInfo, FILE_STREAM_INFO, false, 32); - MAP_INFOCLASS_TO_STRUCT(FileCompressionInfo, FILE_COMPRESSION_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileAttributeTagInfo, FILE_ATTRIBUTE_TAG_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileIdBothDirectoryInfo, FILE_ID_BOTH_DIR_INFO, false, 4096); - MAP_INFOCLASS_TO_STRUCT(FileIdBothDirectoryRestartInfo, FILE_ID_BOTH_DIR_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileIoPriorityHintInfo, FILE_IO_PRIORITY_HINT_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileRemoteProtocolInfo, FILE_REMOTE_PROTOCOL_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileFullDirectoryInfo, FILE_FULL_DIR_INFO, false, 4096); - MAP_INFOCLASS_TO_STRUCT(FileFullDirectoryRestartInfo, FILE_FULL_DIR_INFO, true, 0); -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - MAP_INFOCLASS_TO_STRUCT(FileStorageInfo, FILE_STORAGE_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileAlignmentInfo, FILE_ALIGNMENT_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileIdInfo, FILE_ID_INFO, true, 0); - MAP_INFOCLASS_TO_STRUCT(FileIdExtdDirectoryInfo, FILE_ID_EXTD_DIR_INFO, false, 4096); - MAP_INFOCLASS_TO_STRUCT(FileIdExtdDirectoryRestartInfo, FILE_ID_EXTD_DIR_INFO, true, 0); -#endif - - // Type unsafe version used in the implementation to avoid template bloat. - inline HRESULT GetFileInfo(HANDLE fileHandle, FILE_INFO_BY_HANDLE_CLASS infoClass, size_t allocationSize, - _Outptr_result_maybenull_ void **result) - { - *result = nullptr; - - wistd::unique_ptr resultHolder(new(std::nothrow) char[allocationSize]); - RETURN_IF_NULL_ALLOC(resultHolder); - - for (;;) - { - if (GetFileInformationByHandleEx(fileHandle, infoClass, resultHolder.get(), static_cast(allocationSize))) - { - *result = resultHolder.release(); - break; - } - else - { - DWORD const lastError = ::GetLastError(); - if (lastError == ERROR_MORE_DATA) - { - allocationSize *= 2; - resultHolder.reset(new(std::nothrow) char[allocationSize]); - RETURN_IF_NULL_ALLOC(resultHolder); - } - else if (lastError == ERROR_NO_MORE_FILES) // for folder enumeration cases - { - break; - } - else if (lastError == ERROR_INVALID_PARAMETER) // operation not supported by file system - { - return HRESULT_FROM_WIN32(lastError); - } - else - { - RETURN_WIN32(lastError); - } - } - } - return S_OK; - } - } - /// @endcond - - /** Get file information for a variable sized structure, returns an HRESULT. - ~~~ - wistd::unique_ptr fileNameInfo; - RETURN_IF_FAILED(GetFileInfoNoThrow(fileHandle, fileNameInfo)); - ~~~ - */ - template ::isFixed, int>::type = 0> - HRESULT GetFileInfoNoThrow(HANDLE fileHandle, wistd::unique_ptr::type> &result) WI_NOEXCEPT - { - void *rawResult; - HRESULT hr = details::GetFileInfo(fileHandle, infoClass, - sizeof(typename details::MapInfoClassToInfoStruct::type) + details::MapInfoClassToInfoStruct::extraSize, - &rawResult); - result.reset(static_cast::type*>(rawResult)); - RETURN_HR_IF_EXPECTED(hr, hr == E_INVALIDARG); // operation not supported by file system - RETURN_IF_FAILED(hr); - return S_OK; - } - - /** Get file information for a fixed sized structure, returns an HRESULT. - ~~~ - FILE_BASIC_INFO fileBasicInfo; - RETURN_IF_FAILED(GetFileInfoNoThrow(fileHandle, &fileBasicInfo)); - ~~~ - */ - template ::isFixed, int>::type = 0> - HRESULT GetFileInfoNoThrow(HANDLE fileHandle, _Out_ typename details::MapInfoClassToInfoStruct::type *result) WI_NOEXCEPT - { - const HRESULT hr = GetFileInformationByHandleEx(fileHandle, infoClass, result, sizeof(*result)) ? - S_OK : HRESULT_FROM_WIN32(::GetLastError()); - RETURN_HR_IF_EXPECTED(hr, hr == E_INVALIDARG); // operation not supported by file system - RETURN_IF_FAILED(hr); - return S_OK; - } - - // Verifies that the given file path is not a hard or a soft link. If the file is present at the path, returns - // a handle to it without delete permissions to block an attacker from swapping the file. - inline HRESULT CreateFileAndEnsureNotLinked(PCWSTR path, wil::unique_hfile& fileHandle) - { - // Open handles to the original path and to the final path and compare each file's information - // to verify they are the same file. If they are different, the file is a soft link. - fileHandle.reset(CreateFileW(path, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, nullptr)); - RETURN_LAST_ERROR_IF(!fileHandle); - BY_HANDLE_FILE_INFORMATION fileInfo; - RETURN_IF_WIN32_BOOL_FALSE(GetFileInformationByHandle(fileHandle.get(), &fileInfo)); - - // Open a handle without the reparse point flag to get the final path in case it is a soft link. - wil::unique_hfile finalPathHandle(CreateFileW(path, 0, 0, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr)); - RETURN_LAST_ERROR_IF(!finalPathHandle); - BY_HANDLE_FILE_INFORMATION finalFileInfo; - RETURN_IF_WIN32_BOOL_FALSE(GetFileInformationByHandle(finalPathHandle.get(), &finalFileInfo)); - finalPathHandle.reset(); - - // The low and high indices and volume serial number uniquely identify a file. These must match if they are the same file. - const bool isSoftLink = - ((fileInfo.nFileIndexLow != finalFileInfo.nFileIndexLow) || - (fileInfo.nFileIndexHigh != finalFileInfo.nFileIndexHigh) || - (fileInfo.dwVolumeSerialNumber != finalFileInfo.dwVolumeSerialNumber)); - - // Return failure if it is a soft link or a hard link (number of links greater than 1). - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME), (isSoftLink || fileInfo.nNumberOfLinks > 1)); - - return S_OK; - } - -#ifdef _CPPUNWIND - /** Get file information for a fixed sized structure, throws on failure. - ~~~ - auto fileBasicInfo = GetFileInfo(fileHandle); - ~~~ - */ - template ::isFixed, int>::type = 0> - typename details::MapInfoClassToInfoStruct::type GetFileInfo(HANDLE fileHandle) - { - typename details::MapInfoClassToInfoStruct::type result{}; - THROW_IF_FAILED(GetFileInfoNoThrow(fileHandle, &result)); - return result; - } - - /** Get file information for a variable sized structure, throws on failure. - ~~~ - auto fileBasicInfo = GetFileInfo(fileHandle); - ~~~ - */ - template ::isFixed, int>::type = 0> - wistd::unique_ptr::type> GetFileInfo(HANDLE fileHandle) - { - wistd::unique_ptr::type> result; - THROW_IF_FAILED(GetFileInfoNoThrow(fileHandle, result)); - return result; - } -#endif // _CPPUNWIND -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7) -} - -#endif // __WIL_FILESYSTEM_INCLUDED diff --git a/src/common/dep/wil/fine_readme.txt b/src/common/dep/wil/fine_readme.txt deleted file mode 100644 index 1329e1971..000000000 --- a/src/common/dep/wil/fine_readme.txt +++ /dev/null @@ -1 +0,0 @@ -For FINE patches search for FINE_PATCH string... \ No newline at end of file diff --git a/src/common/dep/wil/nt_result_macros.h b/src/common/dep/wil/nt_result_macros.h deleted file mode 100644 index 82882fede..000000000 --- a/src/common/dep/wil/nt_result_macros.h +++ /dev/null @@ -1,168 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_NT_RESULTMACROS_INCLUDED -#define __WIL_NT_RESULTMACROS_INCLUDED - -#include "result_macros.h" - -// Helpers for return macros -#define __NT_RETURN_NTSTATUS(status, str) __WI_SUPPRESS_4127_S do { NTSTATUS __status = (status); if (FAILED_NTSTATUS(__status)) { __R_FN(Return_NtStatus)(__R_INFO(str) __status); } return __status; } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __NT_RETURN_NTSTATUS_MSG(status, str, fmt, ...) __WI_SUPPRESS_4127_S do { NTSTATUS __status = (status); if (FAILED_NTSTATUS(__status)) { __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); } return __status; } __WI_SUPPRESS_4127_E while ((void)0, 0) - -//***************************************************************************** -// Macros for returning failures as NTSTATUS -//***************************************************************************** - -// Always returns a known result (NTSTATUS) - always logs failures -#define NT_RETURN_NTSTATUS(status) __NT_RETURN_NTSTATUS(wil::verify_ntstatus(status), #status) - -// Always returns a known failure (NTSTATUS) - always logs a var-arg message on failure -#define NT_RETURN_NTSTATUS_MSG(status, fmt, ...) __NT_RETURN_NTSTATUS_MSG(wil::verify_ntstatus(status), #status, fmt, ##__VA_ARGS__) - -// Conditionally returns failures (NTSTATUS) - always logs failures -#define NT_RETURN_IF_NTSTATUS_FAILED(status) __WI_SUPPRESS_4127_S do { const auto __statusRet = wil::verify_ntstatus(status); if (FAILED_NTSTATUS(__statusRet)) { __NT_RETURN_NTSTATUS(__statusRet, #status); }} __WI_SUPPRESS_4127_E while ((void)0, 0) - -// Conditionally returns failures (NTSTATUS) - always logs a var-arg message on failure -#define NT_RETURN_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) __WI_SUPPRESS_4127_S do { const auto __statusRet = wil::verify_ntstatus(status); if (FAILED_NTSTATUS(__statusRet)) { __NT_RETURN_NTSTATUS_MSG(__statusRet, #status, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) - -//***************************************************************************** -// Macros to catch and convert exceptions on failure -//***************************************************************************** - -// Use these macros *within* a catch (...) block to handle exceptions -#define NT_RETURN_CAUGHT_EXCEPTION() return __R_FN(Nt_Return_CaughtException)(__R_INFO_ONLY(nullptr)) -#define NT_RETURN_CAUGHT_EXCEPTION_MSG(fmt, ...) return __R_FN(Nt_Return_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) - -// Use these macros in place of a catch block to handle exceptions -#define NT_CATCH_RETURN() catch (...) { NT_RETURN_CAUGHT_EXCEPTION(); } -#define NT_CATCH_RETURN_MSG(fmt, ...) catch (...) { NT_RETURN_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); } - - -namespace wil -{ - //***************************************************************************** - // Public Helpers that catch -- mostly only enabled when exceptions are enabled - //***************************************************************************** - - // StatusFromCaughtException is a function that is meant to be called from within a catch(...) block. Internally - // it re-throws and catches the exception to convert it to an NTSTATUS. If an exception is of an unrecognized type - // the function will fail fast. - // - // try - // { - // // Code - // } - // catch (...) - // { - // status = wil::StatusFromCaughtException(); - // } - _Always_(_Post_satisfies_(return < 0)) - __declspec(noinline) inline NTSTATUS StatusFromCaughtException() WI_NOEXCEPT - { - bool isNormalized = false; - NTSTATUS status = STATUS_SUCCESS; - if (details::g_pfnResultFromCaughtExceptionInternal) - { - status = details::g_pfnResultFromCaughtExceptionInternal(nullptr, 0, &isNormalized).status; - } - if (FAILED_NTSTATUS(status)) - { - return status; - } - - // Caller bug: an unknown exception was thrown - __WIL_PRIVATE_FAIL_FAST_HR_IF(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), g_fResultFailFastUnknownExceptions); - return wil::details::HrToNtStatus(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); - } - - namespace details - { - template - __declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported = SupportedExceptions::Default); - template - __declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList); - - namespace __R_NS_NAME - { -#ifdef WIL_ENABLE_EXCEPTIONS - __R_DIRECT_METHOD(NTSTATUS, Nt_Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - return wil::details::ReportStatus_CaughtException(__R_DIRECT_FN_CALL_ONLY); - } - - __R_DIRECT_METHOD(NTSTATUS, Nt_Return_CaughtExceptionMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - return wil::details::ReportStatus_CaughtExceptionMsg(__R_DIRECT_FN_CALL formatString, argList); - } -#endif - } - - template - __declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) - { - wchar_t message[2048]; - message[0] = L'\0'; - return ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status; - } - - template<> - __declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) - { - wchar_t message[2048]; - message[0] = L'\0'; - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status); - } - - template<> - __declspec(noinline) inline NTSTATUS ReportStatus_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) - { - wchar_t message[2048]; - message[0] = L'\0'; - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).status); - } - - template - __declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - // Pre-populate the buffer with our message, the exception message will be added to it... - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - StringCchCatW(message, ARRAYSIZE(message), L" -- "); - return ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).status; - } - - template<> - __declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - // Pre-populate the buffer with our message, the exception message will be added to it... - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - StringCchCatW(message, ARRAYSIZE(message), L" -- "); - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).status); - } - - template<> - __declspec(noinline) inline NTSTATUS ReportStatus_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - // Pre-populate the buffer with our message, the exception message will be added to it... - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - StringCchCatW(message, ARRAYSIZE(message), L" -- "); - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).status); - } - } -} - -#endif // __WIL_NT_RESULTMACROS_INCLUDED diff --git a/src/common/dep/wil/registry.h b/src/common/dep/wil/registry.h deleted file mode 100644 index aaff74f08..000000000 --- a/src/common/dep/wil/registry.h +++ /dev/null @@ -1,3270 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_REGISTRY_INCLUDED -#define __WIL_REGISTRY_INCLUDED - -#ifdef _KERNEL_MODE -#error This header is not supported in kernel-mode. -#endif - -#include -#include // new(std::nothrow) -#include "registry_helpers.h" -#include "resource.h" - -// wil registry does not require the use of the STL or C++ exceptions (see _nothrow functions) -// wil registry natively supports std::vector and std::wstring when preferring those types -// wil registry uses the __WIL_WINREG_STL define to enable support for wil::shared_* types (defined in resource.h) - -namespace wil -{ - namespace reg - { -#if defined(WIL_ENABLE_EXCEPTIONS) - /** - * \brief Opens a new HKEY to the specified path - see RegOpenKeyExW - * \param key An open or well-known registry key - * \param subKey The name of the registry subkey to be opened. - * If `nullptr`, then `key` is used without modification. - * \param access The requested access desired for the opened key - * \return A wil::unique_hkey containing the resulting opened HKEY - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline ::wil::unique_hkey open_unique_key(HKEY key, _In_opt_ PCWSTR subKey, ::wil::reg::key_access access = ::wil::reg::key_access::read) - { - const reg_view_details::reg_view regview{ key }; - ::wil::unique_hkey return_value; - regview.open_key(subKey, &return_value, access); - return return_value; - } - - /** - * \brief Creates a new HKEY to the specified path - see RegCreateKeyExW - * \param key An open or well-known registry key - * \param subKey The name of a subkey that this function opens or creates. - * Note: this cannot be null (see the above referenced API documentation) - * \param access The requested access desired for the opened key - * \return A wil::unique_hkey or wil::shared_hkey containing the resulting opened HKEY - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline ::wil::unique_hkey create_unique_key(HKEY key, PCWSTR subKey, ::wil::reg::key_access access = ::wil::reg::key_access::read) - { - const reg_view_details::reg_view regview{ key }; - ::wil::unique_hkey return_value; - regview.create_key(subKey, &return_value, access); - return return_value; - } - -#if defined(__WIL_WINREG_STL) - /** - * \brief Opens a new HKEY to the specified path - see RegOpenKeyExW - * \param key An open or well-known registry key - * \param subKey The name of the registry subkey to be opened. - * If `nullptr`, then `key` is used without modification. - * \param access The requested access desired for the opened key - * \return A wil::shared_hkey containing the resulting opened HKEY - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline ::wil::shared_hkey open_shared_key(HKEY key, _In_opt_ PCWSTR subKey, ::wil::reg::key_access access = ::wil::reg::key_access::read) - { - const reg_view_details::reg_view regview{ key }; - ::wil::shared_hkey return_value; - regview.open_key(subKey, &return_value, access); - return return_value; - } - - /** - * \brief Creates a new HKEY to the specified path - see RegCreateKeyExW - * \param key An open or well-known registry key - * \param subKey The name of a subkey that this function opens or creates. - * Note: this cannot be null (see the above referenced API documentation) - * \param access The requested access desired for the opened key - * \return A wil::shared_hkey or wil::shared_hkey containing the resulting opened HKEY - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline ::wil::shared_hkey create_shared_key(HKEY key, PCWSTR subKey, ::wil::reg::key_access access = ::wil::reg::key_access::read) - { - const reg_view_details::reg_view regview{ key }; - ::wil::shared_hkey return_value; - regview.create_key(subKey, &return_value, access); - return return_value; - } -#endif // #if defined(__WIL_WINREG_STL) -#endif // #if defined(WIL_ENABLE_EXCEPTIONS) - - /** - * \brief Opens a new HKEY to the specified path - see RegOpenKeyExW - * \param key An open or well-known registry key - * \param subKey The name of the registry subkey to be opened. - * If `nullptr`, then `key` is used without modification. - * \param[out] hkey A reference to a wil::unique_hkey to receive the opened HKEY - * \param access The requested access desired for the opened key - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT open_unique_key_nothrow(HKEY key, _In_opt_ PCWSTR subKey, ::wil::unique_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.open_key(subKey, hkey.put(), access); - } - - /** - * \brief Creates a new HKEY to the specified path - see RegCreateKeyExW - * \param key An open or well-known registry key - * \param subKey The name of a subkey that this function opens or creates. - * Note: this cannot be null (see the above referenced API documentation) - * \param[out] hkey A reference to a wil::unique_hkey to receive the opened HKEY - * \param access The requested access desired for the opened key - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT create_unique_key_nothrow(HKEY key, PCWSTR subKey, ::wil::unique_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.create_key(subKey, hkey.put(), access); - } - -#if defined(__WIL_WINREG_STL) - /** - * \brief Opens a new HKEY to the specified path - see RegOpenKeyExW - * \param key An open or well-known registry key - * \param subKey The name of the registry subkey to be opened. - * If `nullptr`, then `key` is used without modification. - * \param[out] hkey A reference to a wil::shared_hkey to receive the opened HKEY - * \param access The requested access desired for the opened key - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT open_shared_key_nothrow(HKEY key, _In_opt_ PCWSTR subKey, ::wil::shared_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.open_key(subKey, hkey.put(), access); - } - - /** - * \brief Creates a new HKEY to the specified path - see RegCreateKeyExW - * \param key An open or well-known registry key - * \param subKey The name of a subkey that this function opens or creates. - * Note: this cannot be null (see the above referenced API documentation) - * \param[out] hkey A reference to a wil::shared_hkey to receive the opened HKEY - * \param access The requested access desired for the opened key - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT create_shared_key_nothrow(HKEY key, PCWSTR subKey, ::wil::shared_hkey& hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.create_key(subKey, hkey.put(), access); - } -#endif // #define __WIL_WINREG_STL - // - // wil::key_iterator and wil::value_iterator objects enable enumerating registry keys and values. - // - // Examples of usage when std::wstring is included: - // - // for (const auto& key_data : wil::make_range(wil::reg::key_iterator{hkey}, wil::reg::key_iterator{})) - // { - // key_data.name; // the std::wstring of the enumerated key - // } - // - // for (const auto& value_data : wil::make_range(wil::reg::value_iterator{hkey}, wil::reg::value_iterator{})) - // { - // value_data.name; // the std::wstring of the enumerated value - // value_data.type; // the REG_ type of the enumerated value - // } - // - // When std::wstring is not included, wil::unique_process_heap_string can be used instead: - // - // for (const auto& key_data : wil::make_range(wil::reg::key_heap_string_iterator{hkey}, wil::reg::key_heap_string_iterator{})) - // { - // key_data.name.get(); // the PCWSTR of the enumerated key - // } - // - // for (const auto& value_data : wil::make_range(wil::reg::value_heap_string_iterator{hkey}, wil::reg::value_heap_string_iterator{})) - // { - // value_data.name.get(); // the PCWSTR of the enumerated value - // value_data.type; // the REG_ type of the enumerated value - // } - // - // When not using exceptions, can manually walk the iterator using wil::unique_process_heap_string: - // - // auto iterate_keys = wil::reg::key_heap_string_nothrow_iterator{hkey}; - // for (const auto& key_data : wil::make_range(iterate_keys, wil::reg::key_heap_string_nothrow_iterator{})) - // { - // key_data.name.get(); // the PCWSTR of the enumerated key - // } - // if (FAILED(iterate_keys.last_error())) - // { - // // the HRESULT last_error() returns the registry error that prevented enumeration - // } - // - // auto iterate_values = wil::reg::value_heap_string_nothrow_iterator{hkey}; - // for (const auto& value_data : wil::make_range(iterate_values, wil::reg::value_heap_string_nothrow_iterator{})) - // { - // value_data.name.get(); // the PCWSTR of the enumerated value - // value_data.type; // the REG_ type of the enumerated value - // } - // if (FAILED(iterate_values.last_error())) - // { - // // the HRESULT last_error() returns the registry error that prevented enumeration - // } - // -#if defined(WIL_ENABLE_EXCEPTIONS) - -#if defined(_STRING_) - using key_iterator = ::wil::reg::iterator_t<::wil::reg::key_iterator_data<::std::wstring>>; - using value_iterator = ::wil::reg::iterator_t<::wil::reg::value_iterator_data<::std::wstring>>; -#endif - -#if defined(__WIL_OLEAUTO_H_) - using key_bstr_iterator = ::wil::reg::iterator_t<::wil::reg::key_iterator_data<::wil::unique_bstr>>; - using value_bstr_iterator = ::wil::reg::iterator_t<::wil::reg::value_iterator_data<::wil::unique_bstr>>; -#endif // #if defined(__WIL_OLEAUTO_H_) - - using key_heap_string_iterator = ::wil::reg::iterator_t<::wil::reg::key_iterator_data<::wil::unique_process_heap_string>>; - using value_heap_string_iterator = ::wil::reg::iterator_t<::wil::reg::value_iterator_data<::wil::unique_process_heap_string>>; -#endif // #if defined(WIL_ENABLE_EXCEPTIONS) - - // no-throw versions of applicable registry iterators -#if defined(__WIL_OLEAUTO_H_) - using key_bstr_nothrow_iterator = ::wil::reg::iterator_nothrow_t<::wil::reg::key_iterator_data<::wil::unique_bstr>>; - using value_bstr_nothrow_iterator = ::wil::reg::iterator_nothrow_t<::wil::reg::value_iterator_data<::wil::unique_bstr>>; -#endif // #if defined(__WIL_OLEAUTO_H_) - using key_heap_string_nothrow_iterator = ::wil::reg::iterator_nothrow_t<::wil::reg::key_iterator_data<::wil::unique_process_heap_string>>; - using value_heap_string_nothrow_iterator = ::wil::reg::iterator_nothrow_t<::wil::reg::value_iterator_data<::wil::unique_process_heap_string>>; - - /** - * \brief Queries for number of sub-keys - * \param key The HKEY to query for number of sub-keys - * \param[out] numSubKeys A pointer to a DWORD to receive the returned count - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_child_key_count_nothrow(HKEY key, _Out_ DWORD* numSubKeys) WI_NOEXCEPT - { - RETURN_IF_WIN32_ERROR( - RegQueryInfoKeyW( - key, - nullptr, // null class - nullptr, // null class character count, - nullptr, // null reserved - numSubKeys, - nullptr, // null max subkey length - nullptr, // null max class length - nullptr, // null value count - nullptr, // null max value name length - nullptr, // null max value length - nullptr, // null security descriptor - nullptr)); // null last write filetime - return S_OK; - } - - inline HRESULT get_child_key_count_nothrow(HKEY key, _Out_ uint32_t* numSubKeys) WI_NOEXCEPT - { - DWORD subKeys{}; - RETURN_IF_FAILED(::wil::reg::get_child_key_count_nothrow(key, &subKeys)); - *numSubKeys = subKeys; - return S_OK; - } - - /** - * \brief Queries for number of values - * \param key The HKEY to query for number of values - * \param[out] numSubValues A pointer to a DWORD to receive the returned count - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_child_value_count_nothrow(HKEY key, _Out_ DWORD* numSubValues) WI_NOEXCEPT - { - RETURN_IF_WIN32_ERROR( - RegQueryInfoKeyW( - key, - nullptr, // null class - nullptr, // null class char count, - nullptr, // null reserved - nullptr, // null subkey count - nullptr, // null max subkey length - nullptr, // null max class length - numSubValues, - nullptr, // null max value name length - nullptr, // null max value length - nullptr, // null security descriptor - nullptr)); // null last write filetime - return S_OK; - } - - inline HRESULT get_child_value_count_nothrow(HKEY key, _Out_ uint32_t* numSubValues) WI_NOEXCEPT - { - DWORD subValues{}; - RETURN_IF_FAILED(::wil::reg::get_child_value_count_nothrow(key, &subValues)); - *numSubValues = subValues; - return S_OK; - } - - /** - * \brief Queries for the filetime when the registry key was last written - * \param key The HKEY to query for number of values - * \param[out] lastModified A pointer to a FILETIME to receive the last write time - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline HRESULT get_last_write_filetime_nothrow(HKEY key, _Out_ FILETIME* lastModified) WI_NOEXCEPT - { - RETURN_IF_WIN32_ERROR( - RegQueryInfoKeyW( - key, - nullptr, // null class - nullptr, // null class char count, - nullptr, // null reserved - nullptr, // null subkey count - nullptr, // null max subkey length - nullptr, // null max class length - nullptr, // null value count - nullptr, // null max value name length - nullptr, // null max value length - nullptr, // null security descriptor - lastModified)); - return S_OK; - } - -#if defined(WIL_ENABLE_EXCEPTIONS) - /** - * \brief Queries for number of sub-keys - * \param key The HKEY to query for number of sub-keys - * \return The queried number of sub-keys if succeeded - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline uint32_t get_child_key_count(HKEY key) - { - uint32_t numSubKeys{}; - THROW_IF_FAILED(::wil::reg::get_child_key_count_nothrow(key, &numSubKeys)); - return numSubKeys; - } - - /** - * \brief Queries for number of values - * \param key The HKEY to query for number of values - * \return The queried number of value if succeeded - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline uint32_t get_child_value_count(HKEY key) - { - uint32_t numSubValues{}; - THROW_IF_FAILED(::wil::reg::get_child_value_count_nothrow(key, &numSubValues)); - return numSubValues; - } - - /** - * \brief Queries for the filetime when the registry key was last written - * \param key The HKEY to query for number of values - * \return The queried filetime if succeeded - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline FILETIME get_last_write_filetime(HKEY key) - { - FILETIME lastModified{}; - THROW_IF_FAILED(::wil::reg::get_last_write_filetime_nothrow(key, &lastModified)); - return lastModified; - } -#endif // #if defined(WIL_ENABLE_EXCEPTIONS) - -#if defined(WIL_ENABLE_EXCEPTIONS) - // - // template - // void set_value(...) - // - // - Writes a value to a specified key and subkey, deducing the type from the given data - // - Throws a std::exception on failure (including wil::ResultException) - // - // Examples of usage (the template type does not need to be explicitly specified) - // wil::reg::set_value(key, L"subkey", L"dword_value_name", 0); // writes a REG_DWORD - // wil::reg::set_value(key, L"subkey", L"qword_value_name", 0ull); // writes a REG_QWORD - // wil::reg::set_value(key, L"subkey", L"string_value_name", L"hello"); // writes a REG_SZ - // - // A subkey is not required if the key is opened where this should write the value: - // wil::reg::set_value(key, L"dword_value_name", 0); // writes a REG_DWORD - // wil::reg::set_value(key, L"qword_value_name", 0ull); // writes a REG_QWORD - // wil::reg::set_value(key, L"string_value_name", L"hello"); // writes a REG_SZ - // - // Example usage writing a vector of wstrings to a REG_MULTI_SZ - // std::vector data { L"string1", L"string2", L"string3" }; - // wil::reg::set_value(key, L"multi_string_value_name", data); - // wil::reg::set_value(key, L"multi_string_value_name", data); - // - // Example of usage writing directly to a registry value from a raw byte vector - // - notice the registry type is required, not implied - // std::vector data { 0x00, 0xff, 0xee, 0xdd, 0xcc }; - // wil::reg::set_value_binary(key, L"binary_value_name", REG_BINARY, data); - // wil::reg::set_value_binary(key, L"binary_value_name", REG_BINARY, data); - // - - /** - * \brief Writes a value to a specified key and subkey, deducing the type from the given data. - * \tparam T The type of the data being set (the registry value type is deduced from T). - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The data (of type T) to write to the specified registry value - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - template - void set_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const T& data) - { - const reg_view_details::reg_view regview{ key }; - regview.set_value(subkey, value_name, data); - } - - /** - * \brief Writes a value under a specified key, the registry type based off the templated type passed as data - * \tparam T The type of the data being set (the registry value type is deduced from T). - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The data (of type T) to write to the specified registry value - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - template - void set_value(HKEY key, _In_opt_ PCWSTR value_name, const T& data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } - - /** - * \brief Writes a null-terminated string value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The null-terminated string to write to the specified registry value - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) - { - const reg_view_details::reg_view regview{ key }; - regview.set_value(subkey, value_name, data); - } - - /** - * \brief Writes a null-terminated string value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The null-terminated string to write to the specified registry value - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } - - - /** - * \brief Writes a REG_DWORD value from a uint32_t - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The 32-bit value to write to the specified registry value - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_dword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t data) - { - ::wil::reg::set_value(key, subkey, value_name, data); - } - - /** - * \brief Writes a REG_DWORD value from a uint32_t - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The 32-bit value to write to the specified registry value - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_dword(HKEY key, _In_opt_ PCWSTR value_name, uint32_t data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } - - /** - * \brief Writes a REG_QWORD value from a uint64_t - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The 64-bit value to write to the specified registry value - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_qword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint64_t data) - { - ::wil::reg::set_value(key, subkey, value_name, data); - } - - /** - * \brief Writes a REG_QWORD value from a uint64_t - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The 64-bit value to write to the specified registry value - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_qword(HKEY key, _In_opt_ PCWSTR value_name, uint64_t data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } - - /** - * \brief Writes a REG_SZ value from a null-terminated string - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The null-terminated string value to write to the specified registry value - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) - { - ::wil::reg::set_value(key, subkey, value_name, data); - } - - /** - * \brief Writes a REG_SZ value from a null-terminated string - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The null-terminated string value to write to the specified registry value - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_string(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } - - /** - * \brief Writes a REG_EXPAND_SZ value from a null-terminated string - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The null-terminated, unexpanded string value to write to the specified registry value. For example, `%PATH%`. - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_expanded_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) - { - const reg_view_details::reg_view regview{ key }; - regview.set_value(subkey, value_name, data, REG_EXPAND_SZ); - } - - /** - * \brief Writes a REG_EXPAND_SZ value from a null-terminated string - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The null-terminated, unexpanded string value to write to the specified registry value. For example, `%PATH%`. - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_expanded_string(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) - { - ::wil::reg::set_value_expanded_string(key, nullptr, value_name, data); - } - -#if defined(_VECTOR_) && defined(_STRING_) - /** - * \brief The generic set_value template function to write a REG_MULTI_SZ value from a std::vector - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data A std::vector to write to the specified registry value. - * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const ::std::vector<::std::wstring>& data) - { - const auto multiStringWcharVector(reg_view_details::get_multistring_from_wstrings(::std::begin(data), ::std::end(data))); - const reg_view_details::reg_view regview{ key }; - regview.set_value(subkey, value_name, multiStringWcharVector, REG_MULTI_SZ); - } - - /** - * \brief The generic set_value template function to write a REG_MULTI_SZ value from a std::vector - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data A std::vector to write to the specified registry value. - * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string. - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value(HKEY key, _In_opt_ PCWSTR value_name, const ::std::vector<::std::wstring>& data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } - - /** - * \brief Writes a REG_MULTI_SZ value from a std::vector - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data A std::vector to write to the specified registry value. - * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_multistring(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const ::std::vector<::std::wstring>& data) - { - ::wil::reg::set_value(key, subkey, value_name, data); - } - - /** - * \brief Writes a REG_MULTI_SZ value from a std::vector - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data A std::vector to write to the specified registry value. - * Each string will be marshaled to a contiguous null-terminator-delimited multi-sz string. - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_multistring(HKEY key, _In_opt_ PCWSTR value_name, const ::std::vector<::std::wstring>& data) - { - ::wil::reg::set_value(key, nullptr, value_name, data); - } -#endif // #if defined(_VECTOR_) && defined(_STRING_) - -#if defined(_VECTOR_) - /** - * \brief Writes a registry value of the specified type from a std::vector/std::vector - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param type The registry type for the specified registry value - see RegSetKeyValueW - * \param data A std::vector/std::vector to write to the specified registry value. - * The vector contents will be directly marshaled to the specified value. - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_binary(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type, const ::std::vector& data) - { - const reg_view_details::reg_view regview{ key }; - regview.set_value(subkey, value_name, data, type); - } - - /** - * \brief Writes a registry value of the specified type from a std::vector/std::vector - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param type The registry type for the specified registry value - see RegSetKeyValueW - * \param data A std::vector/std::vector to write to the specified registry value. - * The vector contents will be directly marshaled to the specified value. - * \exception std::exception (including wil::ResultException) will be thrown on all failures - */ - inline void set_value_binary(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type, const ::std::vector& data) - { - ::wil::reg::set_value_binary(key, nullptr, value_name, type, data); - } -#endif // #if defined(_VECTOR_) -#endif // #if defined(WIL_ENABLE_EXCEPTIONS) - - // - // template - // HRESULT set_value_nothrow(...) - // - // - Writes a value under a specified key - // - The type of registry value is determined by the template type T of data given - // - Returns an HRESULT error code indicating success or failure (does not throw C++ exceptions) - // - // Examples of usage (the template type does not need to be explicitly specified) - // hr = wil::reg::set_value_nothrow(key, L"subkey", L"dword_value_name", 0); // writes a REG_DWORD - // hr = wil::reg::set_value_nothrow(key, L"subkey", L"qword_value_name", 0ull); // writes a REG_QWORD - // hr = wil::reg::set_value_nothrow(key, L"subkey", L"string_value_name", L"hello"); // writes a REG_SZ - // - // A subkey is not required if the key is opened where this should write the value: - // hr = wil::reg::set_value_nothrow(key, L"dword_value_name", 0); // writes a REG_DWORD - // hr = wil::reg::set_value_nothrow(key, L"qword_value_name", 0ull); // writes a REG_QWORD - // hr = wil::reg::set_value_nothrow(key, L"string_value_name", L"hello"); // writes a REG_SZ - // - // Example of usage writing a REG_MULTI_SZ - // std::vector multisz_data { L"string1", L"string2", L"string3" }; - // hr = wil::reg::set_value_nothrow(key, L"multi_string_value_name", multisz_data); - // - // Values can be written directly from a vector of bytes - the registry type must be specified; e.g.: - // std::vector data { 0x00, 0xff, 0xee, 0xdd, 0xcc }; - // hr = wil::reg::set_value_binary_nothrow(key, L"binary_value_name", REG_BINARY, data); - // - /** - * \brief Writes a value to a specified key and subkey, deducing the type from the given data. - * \tparam T The type of the data being set (the registry value type is deduced from T). - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The data (of type T) to write to the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const T& data) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.set_value(subkey, value_name, data); - } - - /** - * \brief Writes a value under a specified key, the registry type based off the templated type passed as data - * \tparam T The type of the data being set (the registry value type is deduced from T). - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The data (of type T) to write to the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, const T& data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); - } - - /** - * \brief Writes a null-terminated string value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The null-terminated string to write to the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.set_value(subkey, value_name, data); - } - - /** - * \brief Writes a null-terminated string value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The null-terminated string to write to the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); - } - - /** - * \brief Writes a REG_DWORD value from a uint32_t - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The 32-bit value to write to the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, subkey, value_name, data); - } - - /** - * \brief Writes a REG_DWORD value from a uint32_t - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The 32-bit value to write to the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, uint32_t data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); - } - - /** - * \brief Writes a REG_QWORD value from a uint64_t - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The 64-bit value to write to the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint64_t data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, subkey, value_name, data); - } - - /** - * \brief Writes a REG_QWORD value from a uint64_t - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The 64-bit value to write to the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, uint64_t data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); - } - - /** - * \brief Writes a REG_SZ value from a null-terminated string - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The null-terminated string value to write to the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, subkey, value_name, data); - } - - /** - * \brief Writes a REG_SZ value from a null-terminated string - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The null-terminated string value to write to the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT - { - return ::wil::reg::set_value_nothrow(key, nullptr, value_name, data); - } - - /** - * \brief Writes a REG_EXPAND_SZ value from a null-terminated string - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The null-terminated string value to write to the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.set_value(subkey, value_name, data, REG_EXPAND_SZ); - } - - /** - * \brief Writes a REG_EXPAND_SZ value from a null-terminated string - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param data The null-terminated string value to write to the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, PCWSTR data) WI_NOEXCEPT - { - return ::wil::reg::set_value_expanded_string_nothrow(key, nullptr, value_name, data); - } - -#if defined(__WIL_OBJBASE_H_) - /** - * \brief Writes raw bytes into a registry value under a specified key of the specified type - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param type The registry type for the specified registry value to write to - see RegSetValue - * \param value A ::wil::unique_cotaskmem_array_ptr holding the bytes to write into the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_binary_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type, const ::wil::unique_cotaskmem_array_ptr& value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - RETURN_IF_FAILED(regview.set_value<::wil::unique_cotaskmem_array_ptr>(subkey, value_name, value, type)); - return S_OK; - } - - /** - * \brief Writes raw bytes into a registry value under a specified key of the specified type - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to write to the unnamed default registry value. - * \param type The registry type for the specified registry value to write to - see RegSetValue - * \param value A ::wil::unique_cotaskmem_array_ptr holding the bytes to write into the specified registry value - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT set_value_binary_nothrow(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type, const ::wil::unique_cotaskmem_array_ptr& value) WI_NOEXCEPT - { - return ::wil::reg::set_value_binary_nothrow(key, nullptr, value_name, type, value); - } -#endif - -#if defined(WIL_ENABLE_EXCEPTIONS) - // - // template - // T get_value(...) - // - // - Reads a value under a specified key. - // - Requires a type T to be specified. - // - Throws a std::exception on failure (including wil::ResultException), including registry value not found. - // If you don't want an exception when the value does not exist, use try_get_value(...) - // - // Examples of usage (ensure the code handles a possible std::exception that will be thrown on all errors) - // uint32_t dword_value = wil::reg::get_value(key, L"subkey", L"dword_value_name"); - // uint64_t qword_value = wil::reg::get_value(key, L"subkey", L"qword_value_name); - // std::wstring string_value = wil::reg::get_value(key, L"subkey", L"string_value_name"); - // - // A subkey is not required if the key is opened where this should write the value: - // uint32_t dword_value = wil::reg::get_value(key, L"dword_value_name"); - // uint64_t qword_value = wil::reg::get_value(key, L"qword_value_name); - // std::wstring string_value = wil::reg::get_value(key, L"string_value_name"); - // - // The template type does not need to be specified if using functions written for a targeted type - // uint32_t dword_value = wil::reg::get_value_dword(key, L"dword_value_name"); - // uint64_t qword_value = wil::reg::get_value_qword(key, L"qword_value_name"); - // std::wstring string_value = wil::reg::get_value_string(key, L"string_value_name"); - // - // Values with REG_EXPAND_SZ can be read into each of the string types; e.g.: - // std::wstring expanded_string_value = wil::reg::get_value_expanded_string(key, L"string_value_name_with_environment_variables"); - // - // Values can be read directly into a vector of bytes - the registry type must be specified; e.g.: - // std::vector data = wil::reg::get_value_binary(key, L"binary_value_name", REG_BINARY); - // - // Multi-string values can be read into a vector; e.g.: - // std::vector multi_string_value = wil::reg::get_value_multistring(key, L"multi_string_value_name"); - // for (const auto& sub_string_value : multi_string_value) - // { - // // can read each string parsed from the multi-string - // PCWSTR string_value = sub_string_value.c_str(); - // } - // - // Reading REG_SZ and REG_EXPAND_SZ types are done through the below templated get_value_string and get_value_expanded_string functions - // Where the template type is the type to receive the string value - // The default template type is std::wstring, available if the caller has included the STL header - // - // Reading a bstr can be stored in a wil::shared_bstr or wil::unique_bstr - wil::shared_bstr has a c'tor taking a wil::unique_bstr - // wil::unique_bstr unique_value { wil::reg::get_value_string<::wil::unique_bstr>(key, L"string_value_name") }; - // wil::shared_bstr shared_value { wil::reg::get_value_string<::wil::shared_bstr>(key, L"string_value_name") }; - // - // Reading a cotaskmem string can be stored in a wil::unique_cotaskmem_string or wil::shared_cotaskmem_string - // wil::unique_cotaskmem_string unique_value { wil::reg::get_value_string(key, L"string_value_name") }; - // wil::shared_cotaskmem_string shared_value { wil::reg::get_value_string(key, L"string_value_name") }; - // - // Blocking get_value_string template types that are not already specialized - this gives a much friendlier compiler error message - template - T get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_string"); - } - - template - T get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_string"); - } - - template - T get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_expanded_string"); - } - - template - T get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_expanded_string"); - } - - /** - * \brief Reads a value from a specified key and subkey, deducing registry type from the type parameter T. - * \tparam T The type to read (the registry value type is deduced from T) - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type T - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template - T get_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - T return_value{}; - const reg_view_details::reg_view regview{ key }; - regview.get_value(subkey, value_name, return_value); - return return_value; - } - - /** - * \brief Reads a value under a specified key, deducing registry type from the type parameter T. - * \tparam T The type to read (the registry value type is deduced from T) - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type T - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template - T get_value(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value(key, nullptr, value_name); - } - - /** - * \brief Reads a REG_DWORD value, returning a uint32_t - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The uint32_t value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline uint32_t get_value_dword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value(key, subkey, value_name); - } - - /** - * \brief Reads a REG_DWORD value, returning a uint32_t - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The uint32_t value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline uint32_t get_value_dword(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value(key, nullptr, value_name); - } - - /** - * \brief Reads a REG_QWORD value, returning a uint64_t - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The uint64_t value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline uint64_t get_value_qword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value(key, subkey, value_name); - } - - /** - * \brief Reads a REG_QWORD value, returning a uint64_t - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The uint64_t value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline uint64_t get_value_qword(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value(key, nullptr, value_name); - } - -#if defined(_STRING_) - /** - * \brief Reads a REG_SZ value, returning a std::wstring - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A std::wstring created from the string value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline ::std::wstring get_value_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::wstring>(key, subkey, value_name); - } - - /** - * \brief Reads a REG_SZ value, returning a std::wstring - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A std::wstring created from the string value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline ::std::wstring get_value_string(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::wstring>(key, nullptr, value_name); - } - - /** - * \brief Reads a REG_SZ value, returning a std::wstring - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A std::wstring created from the string value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::std::wstring get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::wstring>(key, subkey, value_name); - } - - /** - * \brief Reads a REG_SZ value, returning a std::wstring - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A std::wstring created from the string value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::std::wstring get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::wstring>(key, nullptr, value_name); - } - - /** - * \brief Reads a REG_EXPAND_SZ value, returning a std::wstring - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A std::wstring created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline ::std::wstring get_value_expanded_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::std::wstring value; - const reg_view_details::reg_view regview{ key }; - regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); - return value; - } - - /** - * \brief Reads a REG_EXPAND_SZ value, returning a std::wstring - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A std::wstring created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline ::std::wstring get_value_expanded_string(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value_expanded_string(key, nullptr, value_name); - } - - /** - * \brief Reads a REG_EXPAND_SZ value, returning a std::wstring - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A std::wstring created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::std::wstring get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value_expanded_string(key, subkey, value_name); - } - - /** - * \brief Reads a REG_EXPAND_SZ value, returning a std::wstring - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A std::wstring created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::std::wstring get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value_expanded_string(key, nullptr, value_name); - } -#endif // #if defined(_STRING_) - -#if defined(__WIL_OLEAUTO_H_) - /** - * \brief Reads a REG_SZ value, returning a wil::unique_bstr - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::unique_bstr created from the string value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_bstr get_value_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::unique_bstr>(key, subkey, value_name); - } - - /** - * \brief Reads a REG_SZ value, returning a wil::unique_bstr - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::unique_bstr created from the string value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_bstr get_value_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::unique_bstr>(key, nullptr, value_name); - } - - /** - * \brief Reads a REG_EXPAND_SZ value, returning a wil::unique_bstr - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::unique_bstr created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_bstr get_value_expanded_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::wil::unique_bstr value; - const reg_view_details::reg_view regview{ key }; - regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); - return value; - } - - /** - * \brief Reads a REG_EXPAND_SZ value, returning a wil::unique_bstr - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::unique_bstr created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_bstr get_value_expanded_string<::wil::unique_bstr>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value_expanded_string<::wil::unique_bstr>(key, nullptr, value_name); - } -#if defined(__WIL_OLEAUTO_H_STL) - /** - * \brief Reads a REG_SZ value, returning a wil::shared_bstr - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::shared_bstr created from the string value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_bstr get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::shared_bstr>(key, subkey, value_name); - } - - /** - * \brief Reads a REG_SZ value, returning a wil::shared_bstr - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::shared_bstr created from the string value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_bstr get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::shared_bstr>(key, nullptr, value_name); - } - - /** - * \brief Reads a REG_EXPAND_SZ value, returning a wil::unique_bstr - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::shared_bstr created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_bstr get_value_expanded_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::wil::shared_bstr value; - const reg_view_details::reg_view regview{ key }; - regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); - return value; - } - - /** - * \brief Reads a REG_EXPAND_SZ value, returning a wil::shared_bstr - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::shared_bstr created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_bstr get_value_expanded_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value_expanded_string<::wil::shared_bstr>(key, nullptr, value_name); - } -#endif // #if defined(__WIL_OLEAUTO_H_STL) -#endif // #if defined(__WIL_OLEAUTO_H_) - -#if defined(__WIL_OBJBASE_H_) - /** - * \brief Reads a REG_SZ value, returning a wil::unique_cotaskmem_string - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::unique_cotaskmem_string created from the string value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_cotaskmem_string get_value_string<::wil::unique_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::unique_cotaskmem_string>(key, subkey, value_name); - } - - /** - * \brief Reads a REG_SZ value, returning a wil::unique_cotaskmem_string - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::unique_cotaskmem_string created from the string value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_cotaskmem_string get_value_string<::wil::unique_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::unique_cotaskmem_string>(key, nullptr, value_name); - } - - /** - * \brief Reads a REG_EXPAND_SZ value, returning a wil::unique_cotaskmem_string - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::unique_cotaskmem_string created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_cotaskmem_string get_value_expanded_string<::wil::unique_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::wil::unique_cotaskmem_string value; - const reg_view_details::reg_view regview{ key }; - regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); - return value; - } - - /** - * \brief Reads a REG_EXPAND_SZ value, returning a wil::unique_cotaskmem_string - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::unique_cotaskmem_string created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::unique_cotaskmem_string get_value_expanded_string<::wil::unique_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) - { - return wil::reg::get_value_expanded_string<::wil::unique_cotaskmem_string>(key, nullptr, value_name); - } -#if defined(__WIL_OBJBASE_H_STL) - /** - * \brief Reads a REG_SZ value, returning a wil::shared_cotaskmem_string - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::shared_cotaskmem_string created from the string value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_cotaskmem_string get_value_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::shared_cotaskmem_string>(key, subkey, value_name); - } - - /** - * \brief Reads a REG_SZ value, returning a wil::shared_cotaskmem_string - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::shared_cotaskmem_string created from the string value read from the registry - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_cotaskmem_string get_value_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::wil::shared_cotaskmem_string>(key, nullptr, value_name); - } - - /** - * \brief Reads a REG_EXPAND_SZ value, returning a wil::shared_cotaskmem_string - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::shared_cotaskmem_string created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_cotaskmem_string get_value_expanded_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::wil::shared_cotaskmem_string value; - const reg_view_details::reg_view regview{ key }; - regview.get_value(subkey, value_name, value, REG_EXPAND_SZ); - return value; - } - - /** - * \brief Reads a REG_EXPAND_SZ value, returning a wil::shared_cotaskmem_string - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A wil::shared_cotaskmem_string created from the string value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - template <> - inline ::wil::shared_cotaskmem_string get_value_expanded_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) - { - return wil::reg::get_value_expanded_string<::wil::shared_cotaskmem_string>(key, nullptr, value_name); - } -#endif // #if defined(__WIL_OBJBASE_H_STL) -#endif // defined(__WIL_OBJBASE_H_) - -#if defined(_VECTOR_) - /** - * \brief Reads a registry value of the specified type, returning a std::vector - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \param type The registry type for the specified registry value to read from - see RegGetValueW - * \return A std::vector containing the bytes of the specified registry value - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline ::std::vector get_value_binary(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type) - { - ::std::vector return_value{}; - const reg_view_details::reg_view regview{ key }; - regview.get_value(subkey, value_name, return_value, type); - return return_value; - } - - /** - * \brief Reads a registry value of the specified type, returning a std::vector - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \param type The registry type for the specified registry value to read from - see RegGetValueW - * \return A std::vector containing the bytes of the specified registry value - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - */ - inline ::std::vector get_value_binary(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type) - { - return ::wil::reg::get_value_binary(key, nullptr, value_name, type); - } -#endif // #if defined(_VECTOR_) - -#if defined(_VECTOR_) && defined(_STRING_) - /** - * \brief Reads a REG_MULTI_SZ value, returning a std::vector - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. See remarks. - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - * - * \remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null character - * e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" - * returns a vector of size 5: L"string1", empty-string, L"string2", empty-string, L"string3" - */ - template <> - inline ::std::vector<::std::wstring> get_value<::std::vector<::std::wstring>>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::std::vector<::std::wstring> return_value; - ::std::vector rawData{ ::wil::reg::get_value_binary(key, subkey, value_name, REG_MULTI_SZ) }; - if (!rawData.empty()) - { - auto* const begin = reinterpret_cast(rawData.data()); - auto* const end = begin + rawData.size() / sizeof(wchar_t); - return_value = ::wil::reg::reg_view_details::get_wstring_vector_from_multistring(begin, end); - } - - return return_value; - } - - /** - * \brief Reads a REG_MULTI_SZ value, returning a std::vector - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. See remarks. - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - * - * \remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null character - * e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" - * returns a vector of size 5: L"string1", empty-string, L"string2", empty-string, L"string3" - */ - template <> - inline ::std::vector<::std::wstring> get_value<::std::vector<::std::wstring>>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); - } - - /** - * \brief Reads a REG_MULTI_SZ value, returning a std::vector - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. See remarks. - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - * - * \remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null character - * e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" - * returns a vector of size 5: L"string1", empty-string, L"string2", empty-string, L"string3" - */ - inline ::std::vector<::std::wstring> get_value_multistring(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::vector<::std::wstring>>(key, subkey, value_name); - } - - /** - * \brief Reads a REG_MULTI_SZ value, returning a std::vector - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return A vector of strings read from the REG_MULTI_SZ. Note: embedded nulls will be read as empty strings. See remarks. - * \exception std::exception (including wil::ResultException) will be thrown on all failures, including value not found - * - * \remark Note that will return empty strings for embedded nulls - it won't stop at the first double-null character - * e.g. a REG_MULTI_SZ of L"string1\0\0string2\0\0string3\0\0" - * returns a vector of size 5: L"string1", empty-string, L"string2", empty-string, L"string3" - */ - inline ::std::vector<::std::wstring> get_value_multistring(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); - } -#endif // #if defined(_VECTOR_) && defined(_STRING_) - -#if defined (_OPTIONAL_) && defined(__cpp_lib_optional) - // - // template - // void try_get_value(...) - // - // - Reads a value under a specified key and subkey, deducing registry type from the type parameter T. - // - throws a std::exception on failure (including wil::ResultException), except if the registry value was not found - // returns a std::nullopt if the registry value is not found - // - // Examples using the returned std::optional - // - Caller should ensure the code handles a possible std::exception that will be thrown on all errors except value not found - // - // std::optional opt_dword_value = wil::reg::try_get_value(key, L"dword_value_name"); - // if (opt_dword_value.has_value()) - // { - // // opt_dword_value.value() returns the uint32_t read from the registry - // } - // else - // { - // // the registry value did not exist - // } - // // if the caller wants to apply a default value of 0, they can call value_or() - // uint32_t opt_dword_value = wil::reg::try_get_value(key, L"dword_value_name").value_or(0); - // - // Examples using the returned std::optional - // std::optional opt_string_value = wil::reg::try_get_value_string(key, L"string_value_name"); - // if (opt_string_value.has_value()) - // { - // // opt_string_value.value() returns the std::wstring read from the registry - // // the below avoids copying the std::wstring as value() here returns a std::wstring& - // PCWSTR string_value = opt_string_value.value().c_str(); - // } - // else - // { - // // the registry value did not exist - // } - // - // // if the caller wants to apply a default value of L"default", they can call value_or() - // // note that std::optional only attempts to construct a std::wstring for L"default" if the std::optional is empty (std::nullopt) - // // thus only allocating a new std::wstring for the default value when it's needed - // std::optional opt_string_value = wil::reg::try_get_value_string(key, L"string_value_name").value_or(L"default"); - // - // Examples of usage: - // std::optional opt_dword_value = wil::reg::try_get_value(key, L"subkey", L"dword_value_name"); - // std::optional opt_qword_value = wil::reg::try_get_value(key, L"subkey", L"qword_value_name); - // std::optional opt_string_value = wil::reg::try_get_value(key, L"subkey", L"string_value_name"); - // - // A subkey is not required if the key is opened where this should write the value; e.g. - // std::optional opt_dword_value = wil::reg::try_get_value(key, L"dword_value_name"); - // std::optional opt_qword_value = wil::reg::try_get_value(key, L"qword_value_name); - // std::optional opt_string_value = wil::reg::try_get_value(key, L"string_value_name"); - // - // The template type does not need to be specified if using functions written for a targeted type; e.g. - // std::optional opt_dword_value = wil::reg::try_get_value_dword(key, L"dword_value_name"); - // std::optional opt_qword_value = wil::reg::try_get_value_qword(key, L"qword_value_name"); - // std::optional opt_string_value = wil::reg::try_get_value_string(key, L"string_value_name"); - // - // Values with REG_EXPAND_SZ can be read into each of the string types; e.g.: - // std::optional opt_expanded_string_value = wil::reg::try_get_value_expanded_string(key, L"string_value_name_with_environment_variables"); - // - // Values can be read directly into a vector of bytes - the registry type must be specified; e.g.: - // std::optional> opt_data = wil::reg::try_get_value_binary(key, L"binary_value_name", REG_BINARY); - // - // Multi-string values can be read into a std::vector; e.g.: - // std::optional<::std::vector<::std::wstring>> try_get_value_multistring(key, L"multi_string_value_name"); - // See the definition of try_get_value_multistring before for usage guidance - // - // Reading REG_SZ and REG_EXPAND_SZ types are done through the below templated try_get_value_string and try_get_value_expanded_string functions - // Where the template type is the type to receive the string value - // The default template type is std::wstring, available if the caller has included the STL header - // - // Reading a bstr is returned in a std::optional - because wil::unique_bstr cannot be copied and thus is difficult to work with a std::optional - // std::optional shared_value { wil::reg::try_get_value_string<::wil::shared_bstr>(key, L"string_value_name") }; - // - // Reading a cotaskmem string is returned in a std::optional - because wil::unique_cotaskmem_string cannot be copied and thus is difficult to work with a std::optional - // std::optional opt_shared_value { wil::reg::try_get_value_string(key, L"string_value_name") }; - // - // Blocking try_get_value_string template types that are not already specialized - this gives a much friendlier compiler error message - template - ::std::optional try_get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_string"); - } - - template - ::std::optional try_get_value_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_string"); - } - - template - ::std::optional try_get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*subkey*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_expanded_string"); - } - - template - ::std::optional try_get_value_expanded_string(HKEY /*key*/, _In_opt_ PCWSTR /*value_name*/) - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for try_get_value_expanded_string"); - } - - /** - * \brief Attempts to read a value under a specified key and subkey, returning in a std::optional, deducing registry type from the type parameter T. - * \tparam T The type to read, which will be placed into a std::optional (the registry value type is deduced from T) - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value (of type T) read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template - ::std::optional try_get_value(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { -#if defined(__WIL_OLEAUTO_H_) - // not allowing unique types with try_get_value: wil::unique_bstr cannot be copied and thus is difficult to work with a std::optional - static_assert(!wistd::is_same_v, "try_get with wil::unique_bstr is disabled"); -#endif // #if defined(__WIL_OLEAUTO_H_) -#if defined(__WIL_OBJBASE_H_) - // not allowing unique types with try_get_value: wil::unique_cotaskmem_string cannot be copied and thus is difficult to work with a std::optional - static_assert(!wistd::is_same_v, "try_get with wil::unique_cotaskmem_string is disabled"); -#endif // #if defined(__WIL_OBJBASE_H_) - - const reg_view_details::reg_view regview{ key }; - return regview.try_get_value(subkey, value_name); - } - - /** - * \brief Attempts to read a value under a specified key, returning the value in a std::optional, deducing registry type from the type parameter T. - * \tparam T The type to read, which will be placed into a std::optional (the registry value type is deduced from T) - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value (of type T) read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template - ::std::optional try_get_value(HKEY key, _In_opt_ PCWSTR value_name) - { -#if defined(__WIL_OLEAUTO_H_) - // not allowing unique types with try_get_value: wil::unique_bstr cannot be copied and thus is difficult to work with a std::optional - static_assert(!wistd::is_same_v, "try_get with wil::unique_bstr is disabled"); -#endif // #if defined(__WIL_OLEAUTO_H_) -#if defined(__WIL_OBJBASE_H_) - // not allowing unique types with try_get_value: wil::unique_cotaskmem_string cannot be copied and thus is difficult to work with a std::optional - static_assert(!wistd::is_same_v, "try_get with wil::unique_cotaskmem_string is disabled"); -#endif // #if defined(__WIL_OBJBASE_H_) - - return ::wil::reg::try_get_value(key, nullptr, value_name); - } - - /** - * \brief Attempts to read a REG_DWORD value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional try_get_value_dword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value(key, subkey, value_name); - } - - /** - * \brief Attempts to read a REG_DWORD value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional try_get_value_dword(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value(key, nullptr, value_name); - } - - /** - * \brief Attempts to read a REG_QWORD value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional try_get_value_qword(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value(key, subkey, value_name); - } - - /** - * \brief Attempts to read a REG_QWORD value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional try_get_value_qword(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value(key, nullptr, value_name); - } - -#if defined(_VECTOR_) - /** - * \brief Attempts to read a value under a specified key requiring the specified type, returning the raw bytes in a std::optional - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \param type The registry type for the specified registry value to read from - see RegGetValueW - * \return The raw bytes read from the registry value stored in a std::optional>. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::vector> try_get_value_binary(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type) - { - const reg_view_details::reg_view regview{ key }; - return regview.try_get_value<::std::vector>(subkey, value_name, type); - } - - /** - * \brief Attempts to read a value under a specified key requiring the specified type, returning the raw bytes in a std::optional - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \param type The registry type for the specified registry value to read from - see RegGetValueW - * \return The raw bytes read from the registry value stored in a std::optional>. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::vector> try_get_value_binary(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type) - { - return ::wil::reg::try_get_value_binary(key, nullptr, value_name, type); - } -#endif // #if defined(_VECTOR_) - -#if defined(_STRING_) - /** - * \brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::wstring> try_get_value_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - const reg_view_details::reg_view regview{ key }; - return regview.try_get_value<::std::wstring>(subkey, value_name); - } - - /** - * \brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::wstring> try_get_value_string(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_string(key, nullptr, value_name); - } - - /** - * \brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::std::wstring> try_get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_string(key, subkey, value_name); - } - - /** - * \brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value, in a std::optional. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::std::wstring> try_get_value_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_string(key, nullptr, value_name); - } - - /** - * \brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::wstring> try_get_value_expanded_string(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - const reg_view_details::reg_view regview{ key }; - return regview.try_get_value<::std::wstring>(subkey, value_name, REG_EXPAND_SZ); - } - - /** - * \brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::wstring> try_get_value_expanded_string(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_expanded_string(key, nullptr, value_name); - } - - /** - * \brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::std::wstring> try_get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_expanded_string(key, subkey, value_name); - } - - /** - * \brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::std::wstring> try_get_value_expanded_string<::std::wstring>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_expanded_string(key, nullptr, value_name); - } -#endif // #if defined(_STRING_) - -#if defined(__WIL_OLEAUTO_H_STL) - /** - * \brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type std::optional. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_bstr> try_get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - const reg_view_details::reg_view regview{ key }; - return regview.try_get_value<::wil::shared_bstr>(subkey, value_name); - } - - /** - * \brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type std::optional. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_bstr> try_get_value_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_string<::wil::shared_bstr>(key, nullptr, value_name); - } - - /** - * \brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_bstr> try_get_value_expanded_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - const reg_view_details::reg_view regview{ key }; - return regview.try_get_value<::wil::shared_bstr>(subkey, value_name, REG_EXPAND_SZ); - } - - /** - * \brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_bstr> try_get_value_expanded_string<::wil::shared_bstr>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_expanded_string<::wil::shared_bstr>(key, nullptr, value_name); - } -#endif // #if defined(__WIL_OLEAUTO_H_STL) - -#if defined(__WIL_OBJBASE_H_STL) - /** - * \brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type std::optional. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - const reg_view_details::reg_view regview{ key }; - return regview.try_get_value<::wil::shared_cotaskmem_string>(subkey, value_name); - } - - /** - * \brief Attempts to read a REG_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type std::optional - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_string<::wil::shared_cotaskmem_string>(key, nullptr, value_name); - } - - /** - * \brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type std::optional<:wil::shared_cotaskmem_string>, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_expanded_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - const reg_view_details::reg_view regview{ key }; - return regview.try_get_value<::wil::shared_cotaskmem_string>(subkey, value_name, REG_EXPAND_SZ); - } - - /** - * \brief Attempts to read a REG_EXPAND_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value of the template type std::optional, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::wil::shared_cotaskmem_string> try_get_value_expanded_string<::wil::shared_cotaskmem_string>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value_expanded_string<::wil::shared_cotaskmem_string>(key, nullptr, value_name); - } -#endif // defined(__WIL_OBJBASE_H_STL) - -#if defined (_VECTOR_) && defined (_STRING_) - /** - * \brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value marshaled to a std::optional>. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::std::vector<::std::wstring>> try_get_value<::std::vector<::std::wstring>>(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - ::std::vector<::std::wstring> value; - const auto hr = ::wil::ResultFromException([&] { - value = ::wil::reg::get_value_multistring(key, subkey, value_name); - }); - if (SUCCEEDED(hr)) - { - return { value }; - } - - if (::wil::reg::is_registry_not_found(hr)) - { - return { ::std::nullopt }; - } - - THROW_HR(HRESULT_FROM_WIN32(hr)); - } - - /** - * \brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value marshaled to a std::optional>. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - template <> - inline ::std::optional<::std::vector<::std::wstring>> try_get_value<::std::vector<::std::wstring>>(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); - } - - /** - * \brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value marshaled to a std::optional>. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::vector<::std::wstring>> try_get_value_multistring(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value<::std::vector<::std::wstring>>(key, subkey, value_name); - } - - /** - * \brief Attempts to read a REG_MULTI_SZ value under a specified key, returning the value in a std::optional - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be updated. - * Can be nullptr to read from the unnamed default registry value. - * \return The value read from the registry value marshaled to a std::optional>. - * Returns std::nullopt if the value does not exist. - * \exception std::exception (including wil::ResultException) will be thrown on failures except value not found - */ - inline ::std::optional<::std::vector<::std::wstring>> try_get_value_multistring(HKEY key, _In_opt_ PCWSTR value_name) - { - return ::wil::reg::try_get_value<::std::vector<::std::wstring>>(key, nullptr, value_name); - } -#endif // #if defined (_VECTOR_) && defined (_STRING_) -#endif // #if defined (_OPTIONAL_) && defined(__cpp_lib_optional) -#endif // #if defined(WIL_ENABLE_EXCEPTIONS) - - // - // template - // HRESULT get_value_nothrow(...) - // - // - Reads a value from under a specified key - // - The required type of registry value being read from is determined by the template type T - // - Returns an HRESULT error code indicating success or failure (does not throw C++ exceptions) - // - // Examples of usage (the template type does not need to be explicitly specified) - // uint32_t dword_value{}; - // hr = wil::reg::get_value_nothrow(key, L"subkey", L"dword_value_name", &dword_value); // reads a REG_DWORD - // uint64_t qword_value{}; - // hr = wil::reg::get_value_nothrow(key, L"subkey", L"qword_value_name", &qword_value); // reads a REG_QWORD - // wil::unique_bstr string_value{}; - // hr = wil::reg::get_value_nothrow(key, L"subkey", L"string_value_name", string_value); // reads a REG_SZ - // - // A subkey is not required if the key is opened where this should write the value: - // hr = wil::reg::get_value_nothrow(key, L"dword_value_name", &dword_value); // reads a REG_DWORD - // hr = wil::reg::get_value_nothrow(key, L"qword_value_name", &qword_value); // reads a REG_QWORD - // hr = wil::reg::get_value_nothrow(key, L"string_value_name", string_value); // reads a REG_SZ - // - // Can also specify the registry type in the function name: - // hr = wil::reg::get_value_dword_nothrow(key, L"dword_value_name", &dword_value); // reads a REG_DWORD - // hr = wil::reg::get_value_qword_nothrow(key, L"qword_value_name", &qword_value); // reads a REG_QWORD - // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", string_value); // reads a REG_SZ - // - // Example storing directly into a WCHAR array - note will return the required number of bytes if the supplied array is too small - // WCHAR string_value[100]{}; - // uint32_t requiredBytes{}; - // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", string_value, &requiredBytes); - // - // Example of usage writing a REG_MULTI_SZ - // wil::unique_cotaskmem_array_ptr string_values{}; - // hr = wil::reg::get_value_multistring_nothrow(key, L"multi_string_value_name", string_values); - // - // Values can be written directly from a vector of bytes - the registry type must be specified; e.g.: - // wil::unique_cotaskmem_array_ptr raw_value{}; - // hr = wil::reg::get_value_binary_nothrow(key, L"binary_value_name", REG_BINARY, raw_value); - // - // Reading REG_SZ and REG_EXPAND_SZ types are done through the below templated get_value_string_nothrow and get_value_expanded_string_nothrow functions - // Where the template type is the type to receive the string value - // The default template type is std::wstring, available if the caller has included the STL header - // - // Example storing a string in a wil::unique_bstr, wil::shared_bstr, wil::unique_cotaskmem_string, or wil::shared_cotaskmem_string - /// - These string types are passed by reference, not by pointer, because the wil types overload the & operator - // - // wil::unique_bstr bstr_value{}; - // hr = wil::reg::get_value_nothrow(key, L"string_value_name", bstr_value); - // // or can specify explicitly reading a string into a wil::unique_bstr type - // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", bstr_value); - // - // wil::shared_bstr shared_bstr_value{}; - // hr = wil::reg::get_value_nothrow(key, L"string_value_name", shared_bstr_value); - // // or can specify explicitly reading a string into a wil::shared_bstr type - // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", shared_bstr_value); - // - // wil::unique_cotaskmem_string string_value{}; - // hr = wil::reg::get_value_nothrow(key, L"string_value_name", string_value); - // // or can specify explicitly reading a string into a wil::unique_cotaskmem_string type - // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", string_value); - // - // wil::shared_cotaskmem_string shared_string_value{}; - // hr = wil::reg::get_value_nothrow(key, L"string_value_name", shared_string_value); - // // or can specify explicitly reading a string into a wil::shared_cotaskmem_string type - // hr = wil::reg::get_value_string_nothrow(key, L"string_value_name", shared_string_value); - // - - /** - * \brief Reads a value under a specified key, the registry type based off the templated type passed as data - * \tparam T The type of the data being set (the registry value type is deduced from T). - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A pointer-to-T receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template >* = nullptr> - HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, _Out_ T* return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.get_value(subkey, value_name, *return_value); - } - - /** - * \brief Reads a value under a specified key, the registry type based off the templated type passed as data - * \tparam T The type of the data being set (the registry value type is deduced from T). - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A pointer-to-T receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template >* = nullptr> - HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, _Out_ T* return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \tparam Length The length of the WCHAR array passed as an OUT parameter - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A WCHAR array receiving the value read from the registry. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * \param[out] requiredBytes An optional pointer to a unsigned 32-bit value to receive the required bytes of the string in the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR(&return_value)[Length], _Out_opt_ DwordType * requiredBytes) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.get_value_char_array(subkey, value_name, return_value, REG_SZ, requiredBytes); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \tparam Length The length of the WCHAR array passed as an OUT parameter - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A WCHAR array receiving the value read from the registry. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * \param[out] requiredBytes An optional pointer to an unsigned 32-bit value to receive the required bytes of the string to be read - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR(&return_value)[Length], _Out_opt_ DwordType * requiredBytes) WI_NOEXCEPT - { - return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value, requiredBytes); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \tparam Length The length of the WCHAR array passed as an OUT parameter - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A WCHAR array receiving the value read from the registry. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR(&return_value)[Length]) WI_NOEXCEPT - { - constexpr uint32_t* null_out_param = nullptr; - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.get_value_char_array(subkey, value_name, return_value, REG_SZ, null_out_param); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \tparam Length The length of the WCHAR array passed as an OUT parameter - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A WCHAR array receiving the value read from the registry. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR(&return_value)[Length]) WI_NOEXCEPT - { - return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \tparam Length The length of the WCHAR array passed as an OUT parameter - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A WCHAR array receiving the value read from the registry. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR(&return_value)[Length]) WI_NOEXCEPT - { - return ::wil::reg::get_value_string_nothrow(key, subkey, value_name, return_value); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \tparam Length The length of the WCHAR array passed as an OUT parameter - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A WCHAR array receiving the value read from the registry. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR(&return_value)[Length]) WI_NOEXCEPT - { - return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); - } - - /** - * \brief Reads a REG_DWORD value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A pointer to an unsigned 32-bit value receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, _Out_ DwordType * return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); - } - - /** - * \brief Reads a REG_DWORD value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A pointer to an unsigned 32-bit value receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_dword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, _Out_ DwordType * return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } - - /** - * \brief Reads a REG_QWORD value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A uint64_t receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, _Out_ QwordType * return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); - } - - /** - * \brief Reads a REG_QWORD value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A uint64_t receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_qword_nothrow(HKEY key, _In_opt_ PCWSTR value_name, _Out_ QwordType * return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } - -#if defined(__WIL_OLEAUTO_H_) - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::unique_bstr receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.get_value(subkey, value_name, return_value); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::unique_bstr receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::unique_bstr receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value.addressof()); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::unique_bstr receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); - } - -#if defined(__WIL_OLEAUTO_H_STL) - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::shared_bstr receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.get_value(subkey, value_name, return_value); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::shared_bstr receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::shared_bstr receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value.addressof()); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::shared_bstr receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_string_nothrow(key, nullptr, value_name, return_value); - } -#endif // #if defined(__WIL_OLEAUTO_H_STL) -#endif // #if defined(__WIL_OLEAUTO_H_) - -#if defined(__WIL_OBJBASE_H_) - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT - { - return_value.reset(); - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.get_value(subkey, value_name, return_value); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } - -#if defined(__WIL_OBJBASE_H_STL) - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT - { - return_value.reset(); - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.get_value(subkey, value_name, return_value); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); - } - - /** - * \brief Reads a REG_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } -#endif // #if defined(__WIL_OBJBASE_H_STL) -#endif // defined(__WIL_OBJBASE_H_) - -#if defined(__WIL_OBJBASE_H_) - /** - * \brief Reads the raw bytes from a registry value under a specified key of the specified type - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param type The registry type for the specified registry value to read from - see RegGetValueW - * \param[out] return_value A ::wil::unique_cotaskmem_array_ptr receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_binary_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, uint32_t type, ::wil::unique_cotaskmem_array_ptr& return_value) WI_NOEXCEPT - { - // zero the vector if it already had a buffer - for (auto& byte_value : return_value) - { - byte_value = 0x00; - } - const reg_view_details::reg_view_nothrow regview{ key }; - RETURN_IF_FAILED(regview.get_value<::wil::unique_cotaskmem_array_ptr>(subkey, value_name, return_value, type)); - return S_OK; - } - - /** - * \brief Reads the raw bytes from a registry value under a specified key of the specified type - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param type The registry type for the specified registry value to read from - see RegGetValueW - * \param[out] return_value A ::wil::unique_cotaskmem_array_ptr receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_binary_nothrow(HKEY key, _In_opt_ PCWSTR value_name, uint32_t type, ::wil::unique_cotaskmem_array_ptr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_binary_nothrow(key, nullptr, value_name, type, return_value); - } -#endif// #if defined(__WIL_OBJBASE_H_) - - /** - * \brief Reads a REG_EXPAND_SZ value under a specified key - * \tparam Length The length of the WCHAR array passed as an OUT parameter - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A WCHAR array receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * \param[out] requiredBytes An optional pointer to a uint32_t to receive the required bytes of the string to be read - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR(&return_value)[Length], _Out_opt_ DwordType * requiredBytes) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.get_value_char_array(subkey, value_name, return_value, REG_EXPAND_SZ, requiredBytes); - } - - /** - * \brief Reads a REG_EXPAND_SZ value under a specified key - * \tparam Length The length of the WCHAR array passed as an OUT parameter - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A WCHAR array receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * \param[out] requiredBytes An optional pointer to a uint32_t to receive the required bytes of the string to be read - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template || wistd::is_same_v>* = nullptr> - HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR(&return_value)[Length], _Out_opt_ DwordType * requiredBytes) WI_NOEXCEPT - { - return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value, requiredBytes); - } - - /** - * \brief Reads a REG_EXPAND_SZ value under a specified key - * \tparam Length The length of the WCHAR array passed as an OUT parameter - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A WCHAR array receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR(&return_value)[Length]) WI_NOEXCEPT - { - constexpr uint32_t* null_out_param = nullptr; - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.get_value_char_array(subkey, value_name, return_value, REG_EXPAND_SZ, null_out_param); - } - - /** - * \brief Reads a REG_EXPAND_SZ value under a specified key - * \tparam Length The length of the WCHAR array passed as an OUT parameter - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A WCHAR array receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * Will write to the WCHAR array the string value read from the registry, guaranteeing null-termination - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - template - HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, WCHAR(&return_value)[Length]) WI_NOEXCEPT - { - return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); - } - - -#if defined(__WIL_OLEAUTO_H_) - /** - * \brief Reads a REG_EXPAND_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::unique_bstr receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.get_value<::wil::unique_bstr>(subkey, value_name, return_value, REG_EXPAND_SZ); - } - - /** - * \brief Reads a REG_EXPAND_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::unique_bstr receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); - } - -#if defined(__WIL_OLEAUTO_H_STL) - /** - * \brief Reads a REG_EXPAND_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::shared_bstr receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.get_value<::wil::shared_bstr>(subkey, value_name, return_value, REG_EXPAND_SZ); - } - - /** - * \brief Reads a REG_EXPAND_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::shared_bstr receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_bstr& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); - } -#endif // #if defined(__WIL_OLEAUTO_H_STL) -#endif // #if defined(__WIL_OLEAUTO_H_) - -#if defined(__WIL_OBJBASE_H_) - /** - * \brief Reads a REG_EXPAND_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.get_value<::wil::unique_cotaskmem_string>(subkey, value_name, return_value, REG_EXPAND_SZ); - } - - /** - * \brief Reads a REG_EXPAND_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::unique_cotaskmem_string receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); - } - -#if defined(__WIL_OBJBASE_H_STL) - /** - * \brief Reads a REG_EXPAND_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT - { - const reg_view_details::reg_view_nothrow regview{ key }; - return regview.get_value<::wil::shared_cotaskmem_string>(subkey, value_name, return_value, REG_EXPAND_SZ); - } - - /** - * \brief Reads a REG_EXPAND_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A wil::shared_cotaskmem_string receiving the value read from the registry, - * with environment variables expanded, as though passed through ExpandEnvironmentStringsW. - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_expanded_string_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::shared_cotaskmem_string& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_expanded_string_nothrow(key, nullptr, value_name, return_value); - } -#endif // #if defined(__WIL_OBJBASE_H_STL) -#endif // defined(__WIL_OBJBASE_H_) - -#if defined(__WIL_OBJBASE_H_) - /** - * \brief Reads a REG_MULTI_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& return_value) WI_NOEXCEPT - { - ::wil::unique_cotaskmem_array_ptr rawData; - RETURN_IF_FAILED(::wil::reg::get_value_binary_nothrow(key, subkey, value_name, REG_MULTI_SZ, rawData)); - if (!rawData.empty()) - { - auto* const begin = reinterpret_cast(rawData.data()); - auto* const end = begin + rawData.size() / sizeof(wchar_t); - ::wil::reg::reg_view_details::get_cotaskmemstring_array_from_multistring_nothrow(begin, end, return_value); - } - return S_OK; - } - - /** - * \brief Reads a REG_MULTI_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } - - /** - * \brief Reads a REG_MULTI_SZ value under a specified key - * \param key An open or well-known registry key - * \param subkey The name of the subkey to append to `key`. - * If `nullptr`, then `key` is used without modification. - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_multistring_nothrow(HKEY key, _In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, subkey, value_name, return_value); - } - - /** - * \brief Reads a REG_MULTI_SZ value under a specified key - * \param key An open or well-known registry key - * \param value_name The name of the registry value whose data is to be read. - * Can be nullptr to read from the unnamed default registry value. - * \param[out] return_value A ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string> receiving the value read from the registry - * \return HRESULT error code indicating success or failure (does not throw C++ exceptions) - */ - inline HRESULT get_value_multistring_nothrow(HKEY key, _In_opt_ PCWSTR value_name, ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& return_value) WI_NOEXCEPT - { - return ::wil::reg::get_value_nothrow(key, nullptr, value_name, return_value); - } -#endif // #if defined(__WIL_OBJBASE_H_) - } - - // unique_registry_watcher/unique_registry_watcher_nothrow/unique_registry_watcher_failfast - // These classes make it easy to execute a provided function when a - // registry key changes (optionally recursively). Specify the key - // either as a root key + path, or an open registry handle as wil::unique_hkey - // or a raw HKEY value (that will be duplicated). - // - // Example use with exceptions base error handling: - // auto watcher = wil::make_registry_watcher(HKEY_CURRENT_USER, L"Software\\MyApp", true, wil::RegistryChangeKind changeKind[] - // { - // if (changeKind == RegistryChangeKind::Delete) - // { - // watcher.reset(); - // } - // // invalidate cached registry data here - // }); - // - // Example use with error code base error handling: - // auto watcher = wil::make_registry_watcher_nothrow(HKEY_CURRENT_USER, L"Software\\MyApp", true, wil::RegistryChangeKind[] - // { - // // invalidate cached registry data here - // }); - // RETURN_IF_NULL_ALLOC(watcher); - - enum class RegistryChangeKind - { - Modify = 0, - Delete = 1, - }; - - /// @cond - namespace details - { - struct registry_watcher_state - { - registry_watcher_state(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) - : m_callback(wistd::move(callback)), m_keyToWatch(wistd::move(keyToWatch)), m_isRecursive(isRecursive) - { - } - wistd::function m_callback; - unique_hkey m_keyToWatch; - unique_event_nothrow m_eventHandle; - - // While not strictly needed since this is ref counted the thread pool wait - // should be last to ensure that the other members are valid - // when it is destructed as it will reference them. - unique_threadpool_wait m_threadPoolWait; - bool m_isRecursive; - - volatile long m_refCount = 1; - srwlock m_lock; - - // Returns true if the ref-count can be increased from a non zero value, - // false it was zero implying that the object is in or on the way to the destructor. - // In this case ReleaseFromCallback() should not be called. - bool TryAddRef() - { - return ::InterlockedIncrement(&m_refCount) > 1; - } - - void Release() - { - auto lock = m_lock.lock_exclusive(); - if (0 == ::InterlockedDecrement(&m_refCount)) - { - lock.reset(); // leave the lock before deleting it. - delete this; - } - } - - void ReleaseFromCallback(bool rearm) - { - auto lock = m_lock.lock_exclusive(); - if (0 == ::InterlockedDecrement(&m_refCount)) - { - // Destroy the thread pool wait now to avoid the wait that would occur in the - // destructor. That wait would cause a deadlock since we are doing this from the callback. - ::CloseThreadpoolWait(m_threadPoolWait.release()); - lock.reset(); // leave the lock before deleting it. - delete this; - // Sleep(1); // Enable for testing to find use after free bugs. - } - else if (rearm) - { - ::SetThreadpoolWait(m_threadPoolWait.get(), m_eventHandle.get(), nullptr); - } - } - }; - - inline void delete_registry_watcher_state(_In_opt_ registry_watcher_state* watcherStorage) { watcherStorage->Release(); } - - typedef resource_policy registry_watcher_state_resource_policy; - } - /// @endcond - - template - class registry_watcher_t : public storage_t - { - public: - // forward all base class constructors... - template - explicit registry_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} - - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Exception-based constructors - registry_watcher_t(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); - create(rootKey, subKey, isRecursive, wistd::move(callback)); - } - - registry_watcher_t(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions; use the create method"); - create(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); - } - - // Pass a root key, sub key pair or use an empty string to use rootKey as the key to watch. - result create(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) - { - // Most use will want to create the key, consider adding an option for open as a future design change. - unique_hkey keyToWatch; - HRESULT hr = HRESULT_FROM_WIN32(RegCreateKeyExW(rootKey, subKey, 0, nullptr, 0, KEY_NOTIFY, nullptr, &keyToWatch, nullptr)); - if (FAILED(hr)) - { - return err_policy::HResult(hr); - } - return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); - } - - result create(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) - { - return err_policy::HResult(create_common(wistd::move(keyToWatch), isRecursive, wistd::move(callback))); - } - - private: - // Factored into a standalone function to support Clang which does not support conversion of stateless lambdas - // to __stdcall - static void __stdcall callback(PTP_CALLBACK_INSTANCE, void* context, TP_WAIT*, TP_WAIT_RESULT) - { -#ifndef __WIL_REGISTRY_CHANGE_CALLBACK_TEST -#define __WIL_REGISTRY_CHANGE_CALLBACK_TEST -#endif - __WIL_REGISTRY_CHANGE_CALLBACK_TEST - const auto watcherState = static_cast(context); - if (watcherState->TryAddRef()) - { - // using auto reset event so don't need to manually reset. - - // failure here is a programming error. - const LSTATUS error = RegNotifyChangeKeyValue(watcherState->m_keyToWatch.get(), watcherState->m_isRecursive, - REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_THREAD_AGNOSTIC, - watcherState->m_eventHandle.get(), TRUE); - - // Call the client before re-arming to ensure that multiple callbacks don't - // run concurrently. - switch (error) - { - case ERROR_SUCCESS: - case ERROR_ACCESS_DENIED: - // Normal modification: send RegistryChangeKind::Modify and re-arm. - watcherState->m_callback(RegistryChangeKind::Modify); - watcherState->ReleaseFromCallback(true); - break; - - case ERROR_KEY_DELETED: - // Key deleted, send RegistryChangeKind::Delete, do not re-arm. - watcherState->m_callback(RegistryChangeKind::Delete); - watcherState->ReleaseFromCallback(false); - break; - - case ERROR_HANDLE_REVOKED: - // Handle revoked. This can occur if the user session ends before - // the watcher shuts-down. Disarm silently since there is generally no way to respond. - watcherState->ReleaseFromCallback(false); - break; - - default: - FAIL_FAST_HR(HRESULT_FROM_WIN32(error)); - } - } - } - - // This function exists to avoid template expansion of this code based on err_policy. - HRESULT create_common(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) - { - wistd::unique_ptr watcherState(new(std::nothrow) details::registry_watcher_state( - wistd::move(keyToWatch), isRecursive, wistd::move(callback))); - RETURN_IF_NULL_ALLOC(watcherState); - RETURN_IF_FAILED(watcherState->m_eventHandle.create()); - RETURN_IF_WIN32_ERROR(RegNotifyChangeKeyValue(watcherState->m_keyToWatch.get(), - watcherState->m_isRecursive, REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_THREAD_AGNOSTIC, - watcherState->m_eventHandle.get(), TRUE)); - - watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(®istry_watcher_t::callback, watcherState.get(), nullptr)); - RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); - storage_t::reset(watcherState.release()); // no more failures after this, pass ownership - SetThreadpoolWait(storage_t::get()->m_threadPoolWait.get(), storage_t::get()->m_eventHandle.get(), nullptr); - return S_OK; - } - }; - - typedef unique_any_t, err_returncode_policy>> unique_registry_watcher_nothrow; - typedef unique_any_t, err_failfast_policy>> unique_registry_watcher_failfast; - - inline unique_registry_watcher_nothrow make_registry_watcher_nothrow(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) WI_NOEXCEPT - { - unique_registry_watcher_nothrow watcher; - watcher.create(rootKey, subKey, isRecursive, wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) - } - - inline unique_registry_watcher_nothrow make_registry_watcher_nothrow(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) WI_NOEXCEPT - { - unique_registry_watcher_nothrow watcher; - watcher.create(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) - } - - inline unique_registry_watcher_failfast make_registry_watcher_failfast(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) - { - return unique_registry_watcher_failfast(rootKey, subKey, isRecursive, wistd::move(callback)); - } - - inline unique_registry_watcher_failfast make_registry_watcher_failfast(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) - { - return unique_registry_watcher_failfast(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - typedef unique_any_t, err_exception_policy >> unique_registry_watcher; - - inline unique_registry_watcher make_registry_watcher(HKEY rootKey, _In_ PCWSTR subKey, bool isRecursive, wistd::function&& callback) - { - return unique_registry_watcher(rootKey, subKey, isRecursive, wistd::move(callback)); - } - - inline unique_registry_watcher make_registry_watcher(unique_hkey&& keyToWatch, bool isRecursive, wistd::function&& callback) - { - return unique_registry_watcher(wistd::move(keyToWatch), isRecursive, wistd::move(callback)); - } -#endif // WIL_ENABLE_EXCEPTIONS -} // namespace wil - -#endif diff --git a/src/common/dep/wil/registry_helpers.h b/src/common/dep/wil/registry_helpers.h deleted file mode 100644 index 3cb344c80..000000000 --- a/src/common/dep/wil/registry_helpers.h +++ /dev/null @@ -1,1860 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_REGISTRY_HELPERS_INCLUDED -#define __WIL_REGISTRY_HELPERS_INCLUDED - -#if defined(_STRING_) || defined (_VECTOR_) || (defined (__cpp_lib_optional) && defined (_OPTIONAL_)) -#include -#include -#endif - -#include -#include -#include "resource.h" - -#ifdef _KERNEL_MODE -#error This header is not supported in kernel-mode. -#endif - -namespace wil -{ - namespace reg - { - /** - * \brief Helper function to translate registry return values if the value was not found - * \param hr HRESULT to test from registry APIs - * \return boolean if the HRESULT indicates the registry value was not found - */ - constexpr bool is_registry_not_found(HRESULT hr) WI_NOEXCEPT - { - return (hr == __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) || - (hr == __HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)); - } - - /** - * \brief Helper function to translate registry return values if the buffer was too small - * \param hr HRESULT to test from registry APIs - * \return boolean if the HRESULT indicates the buffer was too small for the value being read - */ - constexpr bool is_registry_buffer_too_small(HRESULT hr) WI_NOEXCEPT - { - return hr == __HRESULT_FROM_WIN32(ERROR_MORE_DATA); - } - - // Access rights for opening registry keys. See https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-key-security-and-access-rights. - enum class key_access - { - // Open key for reading. - read, - - // Open key for reading and writing. Equivalent to KEY_ALL_ACCESS. - readwrite, - }; - - namespace reg_view_details - { - constexpr DWORD get_value_flags_from_value_type(DWORD type) WI_NOEXCEPT - { - switch (type) - { - case REG_DWORD: - return RRF_RT_REG_DWORD; - case REG_QWORD: - return RRF_RT_REG_QWORD; - case REG_SZ: - return RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ | RRF_NOEXPAND; - case REG_EXPAND_SZ: - return RRF_RT_REG_SZ | RRF_RT_REG_EXPAND_SZ; - case REG_MULTI_SZ: - return RRF_RT_REG_MULTI_SZ; - case REG_BINARY: - return RRF_RT_REG_BINARY; - // the caller can directly specify their own flags if they need to - default: - return type; - } - } - - constexpr DWORD get_access_flags(key_access access) WI_NOEXCEPT - { - switch (access) - { - case key_access::read: - return KEY_READ; - case key_access::readwrite: - return KEY_ALL_ACCESS; - } - FAIL_FAST(); - } - - /** - * \brief A utility function that walks a contiguous wchar_t container looking for strings within a multi-string - * \tparam InputIt An iterator type that reference a container that holds wchar_t characters to translate into individual strings - * \tparam Fn A callback function to be called each time a string is found - given the [begin, end] iterators referencing the found string - * \param first An iterator referencing to the beginning of the target container (like a std::begin iterator) - * \param last An iterator referencing one-past-the-end of the target container (like a std::end iterator) - * \param func A callback function to be called each time a string is found - given the [begin, end] iterators referencing the found string - */ - template - void walk_multistring(const InputIt& first, const InputIt& last, Fn func) - { - auto current = first; - const auto end_iterator = last; - const auto last_null = (end_iterator - 1); - while (current != end_iterator) - { - // hand rolling ::std::find(current, end_iterator, L'\0'); - // as this may be called when isn't available - auto next = current; - while (next != end_iterator && *next != L'\0') - { - ++next; - } - - if (next != end_iterator) - { - // don't add an empty string for the final 2nd-null-terminator - if (next != last_null) - { - // call the function provided with the [begin, end] pair referencing a string found - func(current, next); - } - current = next + 1; - } - else - { - current = next; - } - } - } - -#if defined(_VECTOR_) && defined(_STRING_) && defined(WIL_ENABLE_EXCEPTIONS) - /** - * \brief A translation function taking iterators referencing std::wstring objects and returns a corresponding std::vector to be written to a MULTI_SZ registry value - * The translation follows the rules for how MULTI_SZ registry values should be formatted, notably how null characters should be embedded within the returned vector - * \tparam InputIt An iterator type that references a container that holds std::wstring objects to translate into a wchar_t buffer - * \param first An iterator referencing to the beginning of the target container (like a std::begin iterator) - * \param last An iterator referencing one-past-the-end of the target container (like a std::end iterator) - * \return A std::vector with the raw wchar_t buffer of bytes prepared to write to a MULTI_SZ registry value - */ - template - ::std::vector get_multistring_from_wstrings(const InputIt& first, const InputIt& last) - { - ::std::vector multistring; - - if (first == last) - { - multistring.push_back(L'\0'); - multistring.push_back(L'\0'); - return multistring; - } - - for (const auto& wstr : ::wil::make_range(first, last)) - { - multistring.insert(multistring.end(), ::std::begin(wstr), ::std::end(wstr)); - multistring.push_back(L'\0'); - } - - // double-null-terminate the last string - multistring.push_back(L'\0'); - return multistring; - } - - /** - * \brief A translation function taking iterators referencing wchar_t characters and returns extracted individual std::wstring objects - * The translation follows the rules for how MULTI_SZ registry value can be formatted, notably with embedded null characters - * Note that this conversion avoids returning empty std::wstring objects even though the input may contain contiguous null wchar_t values - * \tparam InputIt An iterator type that reference a container that holds wchar_t characters to translate into individual strings - * \param first An iterator referencing to the beginning of the target container (like a std::begin iterator) - * \param last An iterator referencing one-past-the-end of the target container (like a std::end iterator) - * \return A std::vector of the extracted strings from the input container of wchar_t characters - */ - template - ::std::vector<::std::wstring> get_wstring_vector_from_multistring(const InputIt& first, const InputIt& last) - { - if (last - first < 3) - { - // it doesn't have the required 2 terminating null characters - return an empty string - return ::std::vector<::std::wstring>(1); - } - - ::std::vector<::std::wstring> strings; - walk_multistring(first, last, [&](const InputIt& string_first, const InputIt& string_last) - { - strings.emplace_back(string_first, string_last); - } - ); - return strings; - } -#endif // #if defined(_VECTOR_) && defined(_STRING_) && defined(WIL_ENABLE_EXCEPTIONS) - -#if defined(__WIL_OBJBASE_H_) - template - void get_multistring_bytearray_from_strings_nothrow(const PCWSTR data[C], ::wil::unique_cotaskmem_array_ptr& multistring) WI_NOEXCEPT - { - constexpr uint8_t nullTermination[2]{ 0x00, 0x00 }; - - size_t total_array_length_bytes = 0; - for (size_t i = 0; i < C; ++i) - { - total_array_length_bytes += wcslen(data[i]) * sizeof(wchar_t); - total_array_length_bytes += sizeof(wchar_t); // plus one for the null-terminator - } - total_array_length_bytes += sizeof(wchar_t); // plus one for the ending double-null-terminator - - *multistring.addressof() = static_cast(::CoTaskMemAlloc(total_array_length_bytes)); - if (!multistring.get()) - { - multistring.reset(); - return; - } - *multistring.size_address() = total_array_length_bytes; - - size_t array_offset = 0; - for (size_t i = 0; i < C; ++i) - { - const auto string_length_bytes = wcslen(data[i]) * sizeof(wchar_t); - memcpy(multistring.get() + array_offset, data[i], string_length_bytes); - array_offset += string_length_bytes; - - static_assert(sizeof(nullTermination) == sizeof(wchar_t), "null terminator must be a wchar"); - memcpy(multistring.get() + array_offset, nullTermination, sizeof(nullTermination)); - array_offset += sizeof(nullTermination); - } - - // double-null-terminate the last string - memcpy(multistring.get() + array_offset, nullTermination, sizeof(nullTermination)); - } - - /** - * \brief A translation function taking iterators referencing wchar_t characters and returns extracted individual wil::unique_cotaskmem_string objects - * The translation follows the rules for how MULTI_SZ registry value can be formatted, notably with embedded null characters - * Note that this conversion avoids returning empty wil::unique_cotaskmem_string objects even though the input may contain contiguous null wchar_t values - * \tparam InputIt An iterator type that reference a container that holds wchar_t characters to translate into individual strings - * \param first An iterator referencing to the beginning of the target container (like a std::begin iterator) - * \param last An iterator referencing one-past-the-end of the target container (like a std::end iterator) - * \param cotaskmem_array The [out] wil::unique_cotaskmem_array_ptr to contain the array of strings - * A wil::unique_cotaskmem_array_ptr of the extracted strings from the input container of wchar_t characters - * An empty wil::unique_cotaskmem_array_ptr should be translated as out-of-memory as there should always be at least one wil::unique_cotaskmem_string - */ - template - void get_cotaskmemstring_array_from_multistring_nothrow(const InputIt& first, const InputIt& last, ::wil::unique_cotaskmem_array_ptr<::wil::unique_cotaskmem_string>& cotaskmem_array) WI_NOEXCEPT - { - if (last - first < 3) - { - // it doesn't have the required 2 terminating null characters - return an empty string - *cotaskmem_array.addressof() = static_cast(::CoTaskMemAlloc(sizeof(PWSTR) * 1)); - if (cotaskmem_array) - { - auto new_string = ::wil::make_cotaskmem_string_nothrow(L""); - if (new_string) - { - *cotaskmem_array.size_address() = 1; - cotaskmem_array[0] = new_string.release(); - } - else - { - // oom will return an empty array - cotaskmem_array.reset(); - } - } - else - { - // oom will return an empty array - cotaskmem_array.reset(); - } - return; - } - - // we must first count the # of strings for the array - size_t arraySize = 0; - walk_multistring(first, last, [&](const InputIt&, const InputIt&) - { - ++arraySize; - } - ); - - // allocate the array size necessary to hold all the unique_cotaskmem_strings - *cotaskmem_array.addressof() = static_cast(::CoTaskMemAlloc(sizeof(PWSTR) * arraySize)); - if (!cotaskmem_array) - { - // oom will return an empty array - cotaskmem_array.reset(); - return; - } - - *cotaskmem_array.size_address() = arraySize; - ZeroMemory(cotaskmem_array.data(), sizeof(PWSTR) * arraySize); - - size_t arrayOffset = 0; - walk_multistring(first, last, [&](const InputIt& string_first, const InputIt& string_last) - { - FAIL_FAST_IF(arrayOffset >= arraySize); - const auto stringSize = string_last - string_first; - auto new_string = ::wil::make_cotaskmem_string_nothrow(&(*string_first), stringSize); - if (!new_string) - { - // oom will return an empty array - cotaskmem_array.reset(); - return; - } - cotaskmem_array[arrayOffset] = new_string.release(); - ++arrayOffset; - } - ); - } -#endif // #if defined(__WIL_OBJBASE_H_) - - namespace reg_value_type_info - { - // supports_prepare_buffer is used to determine if the input buffer to read a registry value should be prepared - // before the first call to the registry read API - template - constexpr bool supports_prepare_buffer() WI_NOEXCEPT - { - return false; - } - template - HRESULT prepare_buffer(T&) WI_NOEXCEPT - { - // no-op in the default case - return S_OK; - } - - // supports_resize_buffer is used to determine if the input buffer to read a registry value can be resized - // for those cases if the error from the registry read API indicates it needs a larger buffer - template - constexpr bool supports_resize_buffer() WI_NOEXCEPT - { - return false; - } - template - constexpr HRESULT resize_buffer(T&, DWORD) WI_NOEXCEPT - { - return E_NOTIMPL; - } - - // supports_trim_buffer is used to determine if the input buffer to read a registry value must be trimmed - // after the registry read API has successfully written into the supplied buffer - // note that currently only std::wstring requires this as it cannot have embedded nulls - template - constexpr bool supports_trim_buffer() WI_NOEXCEPT - { - return false; - } - template - constexpr void trim_buffer(T&) WI_NOEXCEPT - { - } - - constexpr void* get_buffer(const int32_t& value) WI_NOEXCEPT - { - return const_cast(&value); - } - - constexpr DWORD get_buffer_size_bytes(int32_t) WI_NOEXCEPT - { - return static_cast(sizeof(int32_t)); - } - - constexpr void* get_buffer(const uint32_t& value) WI_NOEXCEPT - { - return const_cast(&value); - } - - constexpr DWORD get_buffer_size_bytes(uint32_t) WI_NOEXCEPT - { - return static_cast(sizeof(uint32_t)); - } - - constexpr void* get_buffer(const long& value) WI_NOEXCEPT - { - return const_cast(&value); - } - - constexpr DWORD get_buffer_size_bytes(long) WI_NOEXCEPT - { - return static_cast(sizeof(long)); - } - - constexpr void* get_buffer(const unsigned long& value) WI_NOEXCEPT - { - return const_cast(&value); - } - - constexpr DWORD get_buffer_size_bytes(unsigned long) WI_NOEXCEPT - { - return static_cast(sizeof(unsigned long)); - } - - constexpr void* get_buffer(const int64_t& value) WI_NOEXCEPT - { - return const_cast(&value); - } - - constexpr DWORD get_buffer_size_bytes(int64_t) WI_NOEXCEPT - { - return static_cast(sizeof(int64_t)); - } - - constexpr void* get_buffer(const uint64_t& value) WI_NOEXCEPT - { - return const_cast(&value); - } - - constexpr DWORD get_buffer_size_bytes(uint64_t) WI_NOEXCEPT - { - return static_cast(sizeof(uint64_t)); - } - - constexpr void* get_buffer(PCWSTR value) WI_NOEXCEPT - { - return const_cast(value); - } - - inline DWORD get_buffer_size_bytes(PCWSTR value) WI_NOEXCEPT - { - if (!value) - { - return 0; - } - // including the last null buffer space in the returned buffer-size-bytes - // as the registry API we call guarantees null termination - return static_cast((::wcslen(value) + 1) * sizeof(wchar_t)); - } - -#if defined(_VECTOR_) && defined(WIL_ENABLE_EXCEPTIONS) - inline void* get_buffer(const ::std::vector& buffer) WI_NOEXCEPT - { - return const_cast(buffer.data()); - } - - inline DWORD get_buffer_size_bytes(const ::std::vector& value) WI_NOEXCEPT - { - return static_cast(value.size()); - } - - template <> - constexpr bool supports_prepare_buffer<::std::vector>() WI_NOEXCEPT - { - return true; - } - inline HRESULT prepare_buffer(::std::vector& value) WI_NOEXCEPT try - { - // resize the initial vector to at least 1 byte - // this is needed so we can detect when the registry value exists - // but the value has zero-bytes - if (value.empty()) - { - value.resize(1); - } - // zero out the buffer if pre-allocated - for (auto& string_char : value) - { - string_char = 0x00; - } - return S_OK; - } - CATCH_RETURN(); - - template <> - constexpr bool supports_resize_buffer<::std::vector>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer(::std::vector& buffer, DWORD byteSize) WI_NOEXCEPT try - { - buffer.resize(byteSize); - return S_OK; - } - CATCH_RETURN(); - - // std::vector does not implement resize_buffer - // because these support functions are only needed for set_value - // from the return of get_multistring_from_wstrings - inline void* get_buffer(const ::std::vector& value) WI_NOEXCEPT - { - return const_cast(value.data()); - } - - inline DWORD get_buffer_size_bytes(const ::std::vector& value) WI_NOEXCEPT - { - return static_cast(value.size()) * sizeof(wchar_t); - } - - template <> - constexpr bool supports_prepare_buffer<::std::vector>() WI_NOEXCEPT - { - return true; - } - inline HRESULT prepare_buffer(::std::vector& value) WI_NOEXCEPT - { - // zero out the buffer if pre-allocated - for (auto& string_char : value) - { - string_char = L'\0'; - } - return S_OK; - } -#endif // #if defined(_VECTOR_) && defined(WIL_ENABLE_EXCEPTIONS) - -#if defined(_STRING_) && defined(WIL_ENABLE_EXCEPTIONS) - inline void* get_buffer(const ::std::wstring& string) WI_NOEXCEPT - { - return const_cast(string.data()); - } - - inline DWORD get_buffer_size_bytes(const ::std::wstring& string) WI_NOEXCEPT - { - // including the last null buffer space in the returned buffer-size-bytes - // as the registry API we call guarantees null termination - return static_cast((string.size() + 1) * sizeof(wchar_t)); - } - - template <> - constexpr bool supports_prepare_buffer<::std::wstring>() WI_NOEXCEPT - { - return true; - } - inline HRESULT prepare_buffer(::std::wstring& string) WI_NOEXCEPT - { - // zero out the buffer if pre-allocated - for (auto& string_char : string) - { - string_char = L'\0'; - } - return S_OK; - } - - template <> - constexpr bool supports_resize_buffer<::std::wstring>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer(::std::wstring& string, DWORD byteSize) WI_NOEXCEPT try - { - string.resize(byteSize / sizeof(wchar_t)); - return S_OK; - } - CATCH_RETURN(); - - template <> - constexpr bool supports_trim_buffer<::std::wstring>() WI_NOEXCEPT - { - return true; - } - inline void trim_buffer(::std::wstring& buffer) WI_NOEXCEPT - { - // remove any embedded null characters - const auto offset = buffer.find_first_of(L'\0'); - if (offset != ::std::wstring::npos) - { - buffer.resize(offset); - } - } -#endif // #if defined(_STRING_) && defined(WIL_ENABLE_EXCEPTIONS) - -#if defined(__WIL_OLEAUTO_H_) - inline void* get_buffer(const BSTR& value) WI_NOEXCEPT - { - return value; - } - - inline DWORD get_buffer_size_bytes(const BSTR& value) WI_NOEXCEPT - { - auto length = ::SysStringLen(value); - if (length > 0) - { - // SysStringLen does not count the null-terminator - // including the last null buffer space in the returned buffer-size-bytes - // as the registry API we call guarantees null termination - length += 1; - } - return length * sizeof(wchar_t); - } - - template <> - constexpr bool supports_prepare_buffer() WI_NOEXCEPT - { - return true; - } - inline HRESULT prepare_buffer(const BSTR& value) WI_NOEXCEPT - { - if (value) - { - // zero out the buffer if pre-allocated - for (auto& string_char : ::wil::make_range(value, get_buffer_size_bytes(value) / sizeof(WCHAR))) - { - string_char = L'\0'; - } - } - return S_OK; - } - - template <> - constexpr bool supports_resize_buffer() WI_NOEXCEPT - { - return true; - } - // transferringOwnership is only set to false if this is a 'shallow' copy of the BSTR - // and the caller maintained ownership of the original BSTR. - inline HRESULT resize_buffer(BSTR& string, DWORD byteSize, bool transferringOwnership = true) WI_NOEXCEPT - { - // convert bytes to length (number of WCHAR's) - DWORD length = byteSize / sizeof(WCHAR); - // SysAllocStringLen adds a null, so subtract a wchar_t from the input length - length = length > 0 ? length - 1 : length; - const BSTR new_bstr{ ::SysAllocStringLen(string, length) }; - RETURN_IF_NULL_ALLOC(new_bstr); - - // if not transferring ownership, the caller will still own the original BSTR - if (transferringOwnership) - { - ::SysFreeString(string); - } - - string = new_bstr; - return S_OK; - } - - inline void* get_buffer(const ::wil::unique_bstr& value) WI_NOEXCEPT - { - return value.get(); - } - - inline DWORD get_buffer_size_bytes(const ::wil::unique_bstr& value) WI_NOEXCEPT - { - return get_buffer_size_bytes(value.get()); - } - - template <> - constexpr bool supports_prepare_buffer<::wil::unique_bstr>() WI_NOEXCEPT - { - return true; - } - inline HRESULT prepare_buffer(const ::wil::unique_bstr& value) WI_NOEXCEPT - { - if (value) - { - // zero out the buffer if pre-allocated - for (auto& string_char : ::wil::make_range(value.get(), get_buffer_size_bytes(value) / sizeof(WCHAR))) - { - string_char = L'\0'; - } - } - return S_OK; - } - - template<> - constexpr bool supports_resize_buffer<::wil::unique_bstr>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer(::wil::unique_bstr& string, DWORD byteSize) WI_NOEXCEPT - { - BSTR temp_bstr = string.get(); - - // not transferring ownership of the BSTR within 'string' to resize_buffer() - // resize_buffer() will overwrite temp_bstr with a newly-allocated BSTR - constexpr bool transferringOwnership = false; - RETURN_IF_FAILED(resize_buffer(temp_bstr, byteSize, transferringOwnership)); - - // if succeeded in creating a new BSTR, move ownership of the new BSTR into string - string.reset(temp_bstr); - return S_OK; - } -#endif // #if defined(__WIL_OLEAUTO_H_) - -#if defined(__WIL_OLEAUTO_H_STL) - inline void* get_buffer(const ::wil::shared_bstr& value) WI_NOEXCEPT - { - return value.get(); - } - - inline DWORD get_buffer_size_bytes(const ::wil::shared_bstr& value) WI_NOEXCEPT - { - return get_buffer_size_bytes(value.get()); - } - - template <> - constexpr bool supports_prepare_buffer<::wil::shared_bstr>() WI_NOEXCEPT - { - return true; - } - inline HRESULT prepare_buffer(const ::wil::shared_bstr& value) WI_NOEXCEPT - { - if (value) - { - // zero out the buffer if pre-allocated - for (auto& string_char : ::wil::make_range(value.get(), get_buffer_size_bytes(value) / sizeof(WCHAR))) - { - string_char = L'\0'; - } - } - return S_OK; - } - - template<> - constexpr bool supports_resize_buffer<::wil::shared_bstr>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer(::wil::shared_bstr& string, DWORD byteSize) WI_NOEXCEPT - { - BSTR temp_bstr = string.get(); - - // not transferring ownership of the BSTR within 'string' to resize_buffer() - // resize_buffer() will overwrite temp_bstr with a newly-allocated BSTR - constexpr bool transferringOwnership = false; - RETURN_IF_FAILED(resize_buffer(temp_bstr, byteSize, transferringOwnership)); - - // if succeeded in creating a new BSTR, move ownership of the new BSTR into string - string.reset(temp_bstr); - return S_OK; - } -#endif // #if defined(__WIL_OLEAUTO_H_STL) - -#if defined(__WIL_OBJBASE_H_) - inline void* get_buffer(const ::wil::unique_cotaskmem_string& value) WI_NOEXCEPT - { - return value.get(); - } - - constexpr DWORD get_buffer_size_bytes(const ::wil::unique_cotaskmem_string&) WI_NOEXCEPT - { - // wil::unique_cotaskmem_string does not intrinsically track its internal buffer size - // thus the caller must track the buffer size it requested to be allocated - return 0; - } - - template<> - constexpr bool supports_resize_buffer<::wil::unique_cotaskmem_string>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer(::wil::unique_cotaskmem_string& string, DWORD byteSize) WI_NOEXCEPT - { - // convert bytes to length (number of WCHAR's) - size_t length = byteSize / sizeof(wchar_t); - // ::wil::make_unique_string_nothrow adds one to the length when it allocates, so subtracting 1 from the input length - length = length > 0 ? length - 1 : length; - auto new_string = ::wil::make_unique_string_nothrow<::wil::unique_cotaskmem_string>(string.get(), length); - RETURN_IF_NULL_ALLOC(new_string.get()); - - string = ::wistd::move(new_string); - return S_OK; - } - - inline void* get_buffer(const ::wil::unique_cotaskmem_array_ptr& value) WI_NOEXCEPT - { - return value.get(); - } - - inline DWORD get_buffer_size_bytes(const ::wil::unique_cotaskmem_array_ptr& value) WI_NOEXCEPT - { - return static_cast(value.size()); - } - - template<> - constexpr bool supports_resize_buffer<::wil::unique_cotaskmem_array_ptr>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer(::wil::unique_cotaskmem_array_ptr& arrayValue, DWORD byteSize) WI_NOEXCEPT - { - ::wil::unique_cotaskmem_array_ptr tempValue; - *tempValue.addressof() = static_cast(::CoTaskMemAlloc(byteSize)); - RETURN_IF_NULL_ALLOC(tempValue.get()); - *tempValue.size_address() = byteSize; - - const auto bytesToCopy = arrayValue.size() < byteSize ? arrayValue.size() : byteSize; - CopyMemory(tempValue.get(), arrayValue.get(), bytesToCopy); - - arrayValue = ::wistd::move(tempValue); - return S_OK; - } -#endif // #if defined(__WIL_OBJBASE_H_) - -#if defined(__WIL_OBJBASE_H_STL) - inline void* get_buffer(const ::wil::shared_cotaskmem_string& value) WI_NOEXCEPT - { - return value.get(); - } - - constexpr DWORD get_buffer_size_bytes(const ::wil::shared_cotaskmem_string&) WI_NOEXCEPT - { - // wil::shared_cotaskmem_string does not intrinsically track its internal buffer size - // thus the caller must track the buffer size it requested to be allocated - return 0; - } - - template<> - constexpr bool supports_resize_buffer<::wil::shared_cotaskmem_string>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer(::wil::shared_cotaskmem_string& string, DWORD byteSize) WI_NOEXCEPT - { - // convert bytes to length (number of WCHAR's) - size_t length = byteSize / sizeof(wchar_t); - // ::wil::make_unique_string_nothrow adds one to the length when it allocates, so subtracting 1 from the input length - length = length > 0 ? length - 1 : length; - auto new_string = ::wil::make_unique_string_nothrow<::wil::unique_cotaskmem_string>(string.get(), length); - RETURN_IF_NULL_ALLOC(new_string.get()); - - string = ::wistd::move(new_string); - return S_OK; - } -#endif // #if defined(__WIL_OBJBASE_H_STL) - - inline void* get_buffer(const ::wil::unique_process_heap_string& value) WI_NOEXCEPT - { - return value.get(); - } - - constexpr DWORD get_buffer_size_bytes(const ::wil::unique_process_heap_string&) WI_NOEXCEPT - { - // wil::unique_process_heap_string does not intrinsically track its internal buffer size - // thus the caller must track the buffer size it requested to be allocated - return 0; - } - - template<> - constexpr bool supports_resize_buffer<::wil::unique_process_heap_string>() WI_NOEXCEPT - { - return true; - } - inline HRESULT resize_buffer(::wil::unique_process_heap_string& string, DWORD byteSize) WI_NOEXCEPT - { - // convert bytes to length (number of WCHAR's) - size_t length = byteSize / sizeof(wchar_t); - // ::wil::make_unique_string_nothrow adds one to the length when it allocates, so subtracting 1 from the input length - length = length > 0 ? length - 1 : length; - auto new_string = ::wil::make_unique_string_nothrow<::wil::unique_process_heap_string>(string.get(), length); - RETURN_IF_NULL_ALLOC(new_string.get()); - - string = ::wistd::move(new_string); - return S_OK; - } - - // constexpr expressions to determining the get* and set* registry value types - // for all supported types T to read/write values - template - DWORD get_value_type() WI_NOEXCEPT - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for get_value_type"); - } - - template - DWORD set_value_type() WI_NOEXCEPT - { - static_assert(sizeof(T) != sizeof(T), "Unsupported type for set_value_type"); - } - - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_DWORD); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_DWORD; - } - - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_DWORD); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_DWORD; - } - - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_DWORD); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_DWORD; - } - - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_DWORD); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_DWORD; - } - - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_QWORD); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_QWORD; - } - - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_QWORD); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_QWORD; - } - - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } - -#if defined(_STRING_) && defined(WIL_ENABLE_EXCEPTIONS) - template <> - constexpr DWORD get_value_type<::std::wstring>() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } - - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } -#endif // #if defined(_STRING_) && defined(WIL_ENABLE_EXCEPTIONS) - -#if defined(__WIL_OLEAUTO_H_) - template <> - constexpr DWORD get_value_type() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } - template <> - constexpr DWORD get_value_type<::wil::unique_bstr>() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } - - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } - - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } -#endif // #if defined(__WIL_OLEAUTO_H_) - -#if defined(__WIL_OLEAUTO_H_STL) - - template <> - constexpr DWORD get_value_type<::wil::shared_bstr>() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } - - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } -#endif // #if defined(__WIL_OLEAUTO_H_STL) - -#if defined(__WIL_OBJBASE_H_) - template <> - constexpr DWORD get_value_type<::wil::unique_cotaskmem_string>() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } - - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } -#endif // defined(__WIL_OBJBASE_H_) - -#if defined(__WIL_OBJBASE_H_STL) - template <> - constexpr DWORD get_value_type<::wil::shared_cotaskmem_string>() WI_NOEXCEPT - { - return get_value_flags_from_value_type(REG_SZ); - } - - template <> - constexpr DWORD set_value_type() WI_NOEXCEPT - { - return REG_SZ; - } -#endif // #if defined(__WIL_OBJBASE_H_STL) - } - - template - class reg_view_t - { - public: - explicit reg_view_t(HKEY key) WI_NOEXCEPT : m_key(key) - { - } - ~reg_view_t() WI_NOEXCEPT = default; - reg_view_t(const reg_view_t&) = delete; - reg_view_t& operator=(const reg_view_t&) = delete; - reg_view_t(reg_view_t&&) = delete; - reg_view_t& operator=(reg_view_t&&) = delete; - - typename err_policy::result open_key(_In_opt_ _In_opt_ PCWSTR subKey, _Out_ HKEY* hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) const - { - constexpr DWORD zero_options{ 0 }; - return err_policy::HResult(HRESULT_FROM_WIN32(::RegOpenKeyExW(m_key, subKey, zero_options, get_access_flags(access), hkey))); - } - - typename err_policy::result create_key(PCWSTR subKey, _Out_ HKEY* hkey, ::wil::reg::key_access access = ::wil::reg::key_access::read) const - { - *hkey = nullptr; - - constexpr DWORD zero_reserved{ 0 }; - constexpr PWSTR null_class{ nullptr }; - constexpr DWORD zero_options{ 0 }; - constexpr SECURITY_ATTRIBUTES* null_security_attributes{ nullptr }; - DWORD disposition{ 0 }; - return err_policy::HResult(HRESULT_FROM_WIN32( - ::RegCreateKeyExW(m_key, subKey, zero_reserved, null_class, zero_options, get_access_flags(access), null_security_attributes, hkey, &disposition))); - } - - typename err_policy::result delete_tree(_In_opt_ PCWSTR sub_key) const - { - auto hr = HRESULT_FROM_WIN32(::RegDeleteTreeW(m_key, sub_key)); - if (::wil::reg::is_registry_not_found(hr)) - { - hr = S_OK; - } - return err_policy::HResult(hr); - } - - typename err_policy::result delete_value(_In_opt_ PCWSTR value_name) const - { - return err_policy::HResult(HRESULT_FROM_WIN32(::RegDeleteValueW(m_key, value_name))); - } - - template - typename err_policy::result get_value(_In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, R& return_value, DWORD type = reg_value_type_info::get_value_type()) const - { - return get_value_with_type(subkey, value_name, return_value, type); - } - - // typename D supports unsigned 32-bit values; i.e. allows the caller to pass a DWORD* as well as uint32_t* - template || wistd::is_same_v>* = nullptr> - typename err_policy::result get_value_char_array(_In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, WCHAR(&return_value)[Length], DWORD type, _Out_opt_ DwordType * requiredBytes) const - { - constexpr DwordType zero_value{ 0ul }; - ::wil::assign_to_opt_param(requiredBytes, zero_value); - DWORD data_size_bytes{ Length * sizeof(WCHAR) }; - const auto hr = HRESULT_FROM_WIN32( - ::RegGetValueW(m_key, subkey, value_name, ::wil::reg::reg_view_details::get_value_flags_from_value_type(type), nullptr, return_value, &data_size_bytes)); - if (SUCCEEDED(hr) || ::wil::reg::is_registry_buffer_too_small(hr)) - { - const DwordType updated_value{ data_size_bytes }; - ::wil::assign_to_opt_param(requiredBytes, updated_value); - } - return err_policy::HResult(hr); - } - -#if defined (_OPTIONAL_) && defined(__cpp_lib_optional) - // intended for err_exception_policy as err_returncode_policy will not get an error code - template - ::std::optional try_get_value(_In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, DWORD type = reg_value_type_info::get_value_type()) const - { - R value{}; - const auto hr = get_value_with_type(subkey, value_name, value, type); - if (SUCCEEDED(hr)) - { - return ::std::optional(::wistd::move(value)); - } - - if (::wil::reg::is_registry_not_found(hr)) - { - return ::std::nullopt; - } - - // throw if exception policy - err_policy::HResult(hr); - return ::std::nullopt; - } -#endif // #if defined (_OPTIONAL_) && defined(__cpp_lib_optional) - - template - typename err_policy::result set_value(_In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const R& value, DWORD type = reg_value_type_info::set_value_type()) const - { - return set_value_with_type(subkey, value_name, value, type); - } - - private: - const HKEY m_key{}; - - template - typename err_policy::result set_value_with_type(_In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, const R& value, DWORD type) const - { - return err_policy::HResult(HRESULT_FROM_WIN32( - ::RegSetKeyValueW( - m_key, - subkey, - value_name, - type, - static_cast(reg_value_type_info::get_buffer(value)), - reg_value_type_info::get_buffer_size_bytes(value)))); - } - - template - typename get_value_with_type_policy::result get_value_with_type(_In_opt_ PCWSTR subkey, _In_opt_ PCWSTR value_name, R& return_value, DWORD type = reg_value_type_info::get_value_type()) const - { - if -#if defined(__cpp_if_constexpr) - constexpr -#endif - (reg_value_type_info::supports_prepare_buffer()) - - { - const auto prepare_buffer_hr = reg_value_type_info::prepare_buffer(return_value); - if (FAILED(prepare_buffer_hr)) - { - return get_value_with_type_policy::HResult(prepare_buffer_hr); - } - } - - // get_buffer_size_bytes should include the null terminator when used for strings. - DWORD bytes_allocated{ reg_value_type_info::get_buffer_size_bytes(return_value) }; - HRESULT get_value_hresult = S_OK; - for (;;) - { - constexpr DWORD* null_type{ nullptr }; - DWORD data_size_bytes{ bytes_allocated }; - get_value_hresult = HRESULT_FROM_WIN32(::RegGetValueW( - m_key, - subkey, - value_name, - get_value_flags_from_value_type(type), - null_type, - reg_value_type_info::get_buffer(return_value), - &data_size_bytes)); - - // some return types we can grow as needed - e.g. when writing to a std::wstring - // only compile and resize_buffer for those types that support dynamically growing the buffer - if -#if defined(__cpp_if_constexpr) - constexpr -#endif - (reg_value_type_info::supports_resize_buffer()) - { - // Attempt to grow the buffer with the data_size_bytes returned from GetRegValueW - // GetRegValueW will indicate the caller allocate the returned number of bytes in one of two cases: - // 1. returns ERROR_MORE_DATA - // 2. returns ERROR_SUCCESS when we gave it a nullptr for the out buffer - const bool shouldReallocate = - (::wil::reg::is_registry_buffer_too_small(get_value_hresult)) || - (SUCCEEDED(get_value_hresult) && (reg_value_type_info::get_buffer(return_value) == nullptr) && (data_size_bytes > 0)); - if (shouldReallocate) - { - // verify if resize_buffer succeeded allocation - const auto resize_buffer_hr = reg_value_type_info::resize_buffer(return_value, data_size_bytes); - if (FAILED(resize_buffer_hr)) - { - // if resize fails, return this error back to the caller - return get_value_with_type_policy::HResult(resize_buffer_hr); - } - - // if it resize succeeds, continue the for loop to try again - bytes_allocated = data_size_bytes; - continue; - } - - // if the RegGetValueW call succeeded with a non-null [out] param, - // and the type supports resize_buffer - // and the bytes we allocated don't match data_size_bytes returned from RegGetValueW - // resize the buffer to match what RegGetValueW returned - if (SUCCEEDED(get_value_hresult)) - { - const auto current_byte_size = reg_value_type_info::get_buffer_size_bytes(return_value); - if (current_byte_size != data_size_bytes) - { - // verify if resize_buffer succeeded allocation - const auto resize_buffer_hr = reg_value_type_info::resize_buffer(return_value, data_size_bytes); - if (FAILED(resize_buffer_hr)) - { - // if resize fails, return this error back to the caller - return get_value_with_type_policy::HResult(resize_buffer_hr); - } - } - } - } - - // we don't need to reallocate and retry the call to RegGetValueW so breaking out of the loop - break; - } - - // some types (generally string types) require trimming its internal buffer after RegGetValueW successfully wrote into its buffer - if -#if defined(__cpp_if_constexpr) - constexpr -#endif - (reg_value_type_info::supports_trim_buffer()) - - { - if (SUCCEEDED(get_value_hresult)) - { - reg_value_type_info::trim_buffer(return_value); - } - } - - return get_value_with_type_policy::HResult(get_value_hresult); - } - }; - - using reg_view_nothrow = ::wil::reg::reg_view_details::reg_view_t<::wil::err_returncode_policy>; -#if defined(WIL_ENABLE_EXCEPTIONS) - using reg_view = ::wil::reg::reg_view_details::reg_view_t<::wil::err_exception_policy>; -#endif // #if defined(WIL_ENABLE_EXCEPTIONS) - } // namespace reg_view_details - - namespace reg_iterator_details - { - constexpr uint32_t iterator_end_offset = 0xffffffff; - constexpr size_t iterator_default_buffer_length = 16; - - // function overloads to allow *_enumerator objects to be constructed from all 3 types of HKEY representatives - inline HKEY get_hkey(HKEY h) WI_NOEXCEPT - { - return h; - } - inline HKEY get_hkey(const ::wil::unique_hkey& h) WI_NOEXCEPT - { - return h.get(); - } -#if defined(__WIL_WINREG_STL) - inline HKEY get_hkey(const ::wil::shared_hkey& h) WI_NOEXCEPT - { - return h.get(); - } -#endif // #if defined(__WIL_WINREG_STL) - -#if defined(WIL_ENABLE_EXCEPTIONS) && defined(_STRING_) - // overloads for some of the below string functions - specific for std::wstring - // these overloads must be declared before the template functions below, as some of those template functions - // reference these overload functions - inline void clear_name(::std::wstring& name, size_t) WI_NOEXCEPT - { - name.assign(name.size(), L'\0'); - } - inline ::std::wstring copy_name(const ::std::wstring& str, size_t length) WI_NOEXCEPT - { - try - { - // guarantee that the copied string has the specified internal length - // i.e., the same length assumptions hold when the string is copied - ::std::wstring tempString(length, L'0'); - tempString.assign(str); - return tempString; - } - catch (...) - { - return {}; - } - } - inline bool is_valid(const ::std::wstring& name) WI_NOEXCEPT - { - return !name.empty(); - } -#endif // #if defined(WIL_ENABLE_EXCEPTIONS) && defined(_STRING_) - - // string manipulation functions needed for iterator functions - template - PWSTR address_of_name(const T& name) WI_NOEXCEPT - { - return static_cast(::wil::reg::reg_view_details::reg_value_type_info::get_buffer(name)); - } - - template - bool is_valid(const T& name) WI_NOEXCEPT - { - return static_cast(address_of_name(name)); - } - - template - bool compare_name(const T& name, PCWSTR comparand) WI_NOEXCEPT - { - if (!is_valid(name) || !comparand) - { - return false; - } - return 0 == wcscmp(address_of_name(name), comparand); - } - - template - void clear_name(const T& name, size_t length) WI_NOEXCEPT - { - if (is_valid(name) && length > 0) - { - memset(address_of_name(name), 0, length * sizeof(wchar_t)); - } - } - - // failure returns zero - template - size_t resize_name(T& name, size_t current_length, size_t new_length) WI_NOEXCEPT - { - if (new_length > current_length) - { - // resize_buffer takes size in bytes - if (FAILED(::wil::reg::reg_view_details::reg_value_type_info::resize_buffer(name, static_cast(new_length * sizeof(wchar_t))))) - { - return 0; - } - return new_length; - } - - // continue to use the existing buffer since the requested length is less than or equals to the current length - clear_name(name, current_length); - return current_length; - } - - template - T copy_name(const T& name, size_t length) WI_NOEXCEPT - { - if (!is_valid(name)) - { - return {}; - - } - return ::wil::make_unique_string_nothrow(address_of_name(name), length); - } - -#if defined(__WIL_OLEAUTO_H_) - // overloads for some of the above string functions - specific for wil::unique_bstr - // these should come after the template functions - as they reference some of those functions - inline size_t resize_name(::wil::unique_bstr& name, size_t current_length, size_t new_length) WI_NOEXCEPT - { - if (new_length > current_length) - { - // SysAllocStringLen adds a null, so subtract a wchar_t from the input length - new_length = new_length > 0 ? new_length - 1 : new_length; - const BSTR new_bstr{ ::SysAllocStringLen(nullptr, static_cast(new_length)) }; - if (!new_bstr) - { - return 0; - } - name.reset(new_bstr); - return new_length; - } - - // continue to use the existing buffer since the requested length is less than or equals to the current length - clear_name(name, current_length); - return current_length; - } - inline ::wil::unique_bstr copy_name(const ::wil::unique_bstr& name, size_t length) WI_NOEXCEPT - { - if (!is_valid(name)) - { - return {}; - } - - // SysAllocStringLen adds a null, so subtract a wchar_t from the input length - length = length > 0 ? length - 1 : length; - return ::wil::unique_bstr{ ::SysAllocStringLen(name.get(), static_cast(length)) }; - } -#endif // #if defined(__WIL_OLEAUTO_H_) - }; - - // forward declaration to allow friend-ing the template iterator class -#if defined(WIL_ENABLE_EXCEPTIONS) - template class iterator_t; -#endif - template - class iterator_nothrow_t; - - // all methods must be noexcept - to be usable with any iterator type (throwing or non-throwing) - template - class key_iterator_data - { - public: - T name{}; - - key_iterator_data(HKEY key = nullptr) WI_NOEXCEPT : m_hkey{ key } - { - } - ~key_iterator_data() WI_NOEXCEPT = default; - - key_iterator_data(const key_iterator_data& rhs) WI_NOEXCEPT - { - // might return null/empty string on failure - name = ::wil::reg::reg_iterator_details::copy_name(rhs.name, rhs.m_name_length); - m_hkey = rhs.m_hkey; - m_index = rhs.m_index; - m_name_length = ::wil::reg::reg_iterator_details::is_valid(name) ? rhs.m_name_length : 0; - } - key_iterator_data& operator=(const key_iterator_data& rhs) WI_NOEXCEPT - { - if (&rhs != this) - { - key_iterator_data temp(rhs); - *this = ::wistd::move(temp); - } - return *this; - } - - key_iterator_data(key_iterator_data&&) WI_NOEXCEPT = default; - key_iterator_data& operator=(key_iterator_data&& rhs) WI_NOEXCEPT = default; - - // Case-sensitive comparison - bool operator==(PCWSTR comparand) const WI_NOEXCEPT - { - return ::wil::reg::reg_iterator_details::compare_name(name, comparand); - } - - private: -#if defined(WIL_ENABLE_EXCEPTIONS) - friend class ::wil::reg::iterator_t; -#endif - friend class ::wil::reg::iterator_nothrow_t; - - bool at_end() const WI_NOEXCEPT - { - return m_index == ::wil::reg::reg_iterator_details::iterator_end_offset; - } - - void make_end_iterator() WI_NOEXCEPT - { - ::wil::reg::reg_iterator_details::clear_name(name, m_name_length); - m_index = ::wil::reg::reg_iterator_details::iterator_end_offset; - } - - bool resize(size_t new_length) WI_NOEXCEPT - { - m_name_length = ::wil::reg::reg_iterator_details::resize_name(name, m_name_length, new_length); - // if failed to resize_name, will return 0 - return m_name_length > 0; - } - - HRESULT enumerate_current_index() WI_NOEXCEPT - { - FAIL_FAST_IF(at_end()); - - for (auto string_length = static_cast(m_name_length);;) - { - if (!resize(string_length)) - { - return E_OUTOFMEMORY; - } - - const auto error = ::RegEnumKeyExW( - m_hkey, // hKey - m_index, // dwIndex - string_length == 0 ? nullptr : ::wil::reg::reg_iterator_details::address_of_name(name), // lpName - &string_length, // lpcchName - nullptr, // lpReserved - nullptr, // lpClass - nullptr, // lpcchClass - nullptr); // lpftLastWriteTime - - if (error == ERROR_SUCCESS) - { - // some types, like std::wstring, cannot have embedded nulls - ::wil::reg::reg_view_details::reg_value_type_info::trim_buffer(name); - break; - } - if (error == ERROR_NO_MORE_ITEMS) - { - make_end_iterator(); - break; - } - if (error == ERROR_MORE_DATA) - { - // resize to iterator_default_buffer_length and try again - string_length += ::wil::reg::reg_iterator_details::iterator_default_buffer_length; - continue; - } - // any other error will fail - RETURN_WIN32(error); - } - return S_OK; - } - - HKEY m_hkey{}; - uint32_t m_index = ::wil::reg::reg_iterator_details::iterator_end_offset; - size_t m_name_length{}; - }; - - // all methods must be noexcept - to be usable with any iterator type (throwing or non-throwing) - template - class value_iterator_data - { - public: - T name{}; - DWORD type = REG_NONE; - - value_iterator_data(HKEY key = nullptr) WI_NOEXCEPT : m_hkey{ key } - { - } - ~value_iterator_data() WI_NOEXCEPT = default; - - value_iterator_data(const value_iterator_data& rhs) WI_NOEXCEPT - { - // might return null/empty string on failure - name = ::wil::reg::reg_iterator_details::copy_name(rhs.name, rhs.m_name_length); - type = rhs.type; - m_hkey = rhs.m_hkey; - m_index = rhs.m_index; - m_name_length = ::wil::reg::reg_iterator_details::is_valid(name) ? rhs.m_name_length : 0; - } - value_iterator_data& operator=(const value_iterator_data& rhs) WI_NOEXCEPT - { - if (&rhs != this) - { - value_iterator_data temp(rhs); - *this = ::wistd::move(temp); - } - return *this; - } - - value_iterator_data(value_iterator_data&&) WI_NOEXCEPT = default; - value_iterator_data& operator=(value_iterator_data&& rhs) WI_NOEXCEPT = default; - - bool at_end() const WI_NOEXCEPT - { - return m_index == ::wil::reg::reg_iterator_details::iterator_end_offset; - } - - private: -#if defined(WIL_ENABLE_EXCEPTIONS) - friend class ::wil::reg::iterator_t; -#endif - friend class ::wil::reg::iterator_nothrow_t; - - void make_end_iterator() WI_NOEXCEPT - { - ::wil::reg::reg_iterator_details::clear_name(name, m_name_length); - m_index = ::wil::reg::reg_iterator_details::iterator_end_offset; - } - - bool resize(size_t new_length) - { - m_name_length = ::wil::reg::reg_iterator_details::resize_name(name, m_name_length, new_length); - // if failed to resize_name, will return 0 - return m_name_length > 0; - } - - HRESULT enumerate_current_index() WI_NOEXCEPT - { - FAIL_FAST_IF(at_end()); - - for (auto string_length = static_cast(m_name_length);;) - { - if (!resize(string_length)) - { - return E_OUTOFMEMORY; - } - - const auto error = ::RegEnumValueW( - m_hkey, // hKey - m_index, // dwIndex - string_length == 0 ? nullptr : ::wil::reg::reg_iterator_details::address_of_name(name), // lpValueName - &string_length, // lpcchValueName - nullptr, // lpReserved - &type, // lpType - nullptr, // lpData - nullptr); // lpcbData - - if (error == ERROR_SUCCESS) - { - // some types, like std::wstring, cannot have embedded nulls - ::wil::reg::reg_view_details::reg_value_type_info::trim_buffer(name); - break; - } - if (error == ERROR_NO_MORE_ITEMS) - { - make_end_iterator(); - break; - } - if (error == ERROR_MORE_DATA) - { - // resize to iterator_default_buffer_length and try again - string_length += ::wil::reg::reg_iterator_details::iterator_default_buffer_length; - continue; - } - - // any other error will fail - RETURN_WIN32(error); - } - return S_OK; - } - - HKEY m_hkey{}; - uint32_t m_index = ::wil::reg::reg_iterator_details::iterator_end_offset; - size_t m_name_length{}; - }; - -#if defined(WIL_ENABLE_EXCEPTIONS) - template - class iterator_t - { - public: - // defining iterator_traits allows STL functions to be used with this iterator class. - // Notice this is a forward_iterator - // - does not support random-access (e.g. vector::iterator) - // - does not support bi-directional access (e.g. list::iterator) -#if defined(_ITERATOR_) - using iterator_category = ::std::forward_iterator_tag; -#endif - using value_type = T; - using difference_type = size_t; - using distance_type = size_t; - using pointer = T*; - using reference = T&; - - iterator_t() WI_NOEXCEPT = default; - ~iterator_t() WI_NOEXCEPT = default; - - iterator_t(HKEY hkey) : m_data(hkey) - { - if (hkey != nullptr) - { - m_data.resize(::wil::reg::reg_iterator_details::iterator_default_buffer_length); - m_data.m_index = 0; - m_data.enumerate_current_index(); - } - } - - iterator_t(const iterator_t&) = default; - iterator_t& operator=(const iterator_t&) = default; - iterator_t(iterator_t&&) WI_NOEXCEPT = default; - iterator_t& operator=(iterator_t&&) WI_NOEXCEPT = default; - - // operator support - const T& operator*() const - { - FAIL_FAST_IF(m_data.at_end()); - return m_data; - } - const T& operator*() - { - FAIL_FAST_IF(m_data.at_end()); - return m_data; - } - const T* operator->() const - { - FAIL_FAST_IF(m_data.at_end()); - return &m_data; - } - const T* operator->() - { - FAIL_FAST_IF(m_data.at_end()); - return &m_data; - } - - bool operator==(const iterator_t& rhs) const WI_NOEXCEPT - { - if (m_data.at_end() || rhs.m_data.at_end()) - { - // if either is not initialized (or end), both must not be initialized (or end) to be equal - return m_data.m_index == rhs.m_data.m_index; - } - return m_data.m_hkey == rhs.m_data.m_hkey && m_data.m_index == rhs.m_data.m_index; - } - - bool operator!=(const iterator_t& rhs) const WI_NOEXCEPT - { - return !(*this == rhs); - } - - // pre-increment - iterator_t& operator++() - { - this->operator +=(1); - return *this; - } - const iterator_t& operator++() const - { - this->operator +=(1); - return *this; - } - - // increment by integer - iterator_t& operator+=(size_t offset) - { - uint32_t newIndex = m_data.m_index + static_cast(offset); - if (newIndex < m_data.m_index) - { - // fail on integer overflow - THROW_HR(E_INVALIDARG); - } - if (newIndex == ::wil::reg::reg_iterator_details::iterator_end_offset) - { - // fail if this creates an end iterator - THROW_HR(E_INVALIDARG); - } - - // iterate by the integer offset - for (size_t count = 0; count < offset; ++count) - { - ++m_data.m_index; - m_data.enumerate_current_index(); - } - return *this; - } - - // not supporting post-increment - which would require copy-construction - iterator_t operator++(int) = delete; - - private: - // container based on the class template type - T m_data{}; - }; -#endif - - template - class iterator_nothrow_t - { - public: - iterator_nothrow_t() WI_NOEXCEPT = default; - ~iterator_nothrow_t() WI_NOEXCEPT = default; - - iterator_nothrow_t(HKEY hkey) WI_NOEXCEPT : m_data(hkey) - { - if (hkey != nullptr) - { - m_data.m_index = 0; - if (!m_data.resize(::wil::reg::reg_iterator_details::iterator_default_buffer_length)) - { - m_last_error = E_OUTOFMEMORY; - } - else - { - m_last_error = m_data.enumerate_current_index(); - } - } - } - - iterator_nothrow_t(const iterator_nothrow_t&) WI_NOEXCEPT = default; - iterator_nothrow_t& operator=(const iterator_nothrow_t&) WI_NOEXCEPT = default; - iterator_nothrow_t(iterator_nothrow_t&&) WI_NOEXCEPT = default; - iterator_nothrow_t& operator=(iterator_nothrow_t&&) WI_NOEXCEPT = default; - - bool at_end() const WI_NOEXCEPT - { - return m_data.at_end(); - } - - HRESULT last_error() const WI_NOEXCEPT - { - return m_last_error; - } - - HRESULT move_next() WI_NOEXCEPT - { - const auto newIndex = m_data.m_index + 1; - if (newIndex < m_data.m_index) - { - // fail on integer overflow - m_last_error = E_INVALIDARG; - } - else if (newIndex == ::wil::reg::reg_iterator_details::iterator_end_offset) - { - // fail if this creates an end iterator - m_last_error = E_INVALIDARG; - } - else - { - m_data.m_index = newIndex; - m_last_error = m_data.enumerate_current_index(); - } - - if (FAILED(m_last_error)) - { - // on failure, set the iterator to an end iterator - m_data.make_end_iterator(); - } - - return m_last_error; - } - - // operator support - const T& operator*() const WI_NOEXCEPT - { - return m_data; - } - const T& operator*() WI_NOEXCEPT - { - return m_data; - } - const T* operator->() const WI_NOEXCEPT - { - return &m_data; - } - const T* operator->() WI_NOEXCEPT - { - return &m_data; - } - bool operator==(const iterator_nothrow_t& rhs) const WI_NOEXCEPT - { - if (m_data.at_end() || rhs.m_data.at_end()) - { - // if either is not initialized (or end), both must not be initialized (or end) to be equal - return m_data.m_index == rhs.m_data.m_index; - } - return m_data.m_hkey == rhs.m_data.m_hkey && m_data.m_index == rhs.m_data.m_index; - } - - bool operator!=(const iterator_nothrow_t& rhs) const WI_NOEXCEPT - { - return !(*this == rhs); - } - - iterator_nothrow_t& operator++() WI_NOEXCEPT - { - move_next(); - return *this; - } - const iterator_nothrow_t& operator++() const WI_NOEXCEPT - { - move_next(); - return *this; - } - - private: - // container based on the class template type - T m_data{}; - HRESULT m_last_error{}; - }; - - } // namespace reg -} // namespace wil -#endif // __WIL_REGISTRY_HELPERS_INCLUDED \ No newline at end of file diff --git a/src/common/dep/wil/resource.h b/src/common/dep/wil/resource.h deleted file mode 100644 index 550a108c8..000000000 --- a/src/common/dep/wil/resource.h +++ /dev/null @@ -1,7103 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* - -#include "result_macros.h" -#include "wistd_functional.h" -#include "wistd_memory.h" - -#pragma warning(push) -#pragma warning(disable:26135 26110) // Missing locking annotation, Caller failing to hold lock -#pragma warning(disable:4714) // __forceinline not honored - -#ifndef __WIL_RESOURCE -#define __WIL_RESOURCE - -// stdint.h and intsafe.h have conflicting definitions, so it's not safe to include either to pick up our dependencies, -// so the definitions we need are copied below -#ifdef _WIN64 -#define __WI_SIZE_MAX 0xffffffffffffffffui64 // UINT64_MAX -#else /* _WIN64 */ -#define __WI_SIZE_MAX 0xffffffffui32 // UINT32_MAX -#endif /* _WIN64 */ - -// Forward declaration -/// @cond -namespace Microsoft -{ - namespace WRL - { - template - class ComPtr; - } -} -/// @endcond - -namespace wil -{ - //! This type copies the current value of GetLastError at construction and resets the last error - //! to that value when it is destroyed. - //! - //! This is useful in library code that runs during a value's destructor. If the library code could - //! inadvertently change the value of GetLastError (by calling a Win32 API or similar), it should - //! instantiate a value of this type before calling the library function in order to preserve the - //! GetLastError value the user would expect. - //! - //! This construct exists to hide kernel mode/user mode differences in wil library code. - //! - //! Example usage: - //! - //! if (!CreateFile(...)) - //! { - //! auto lastError = wil::last_error_context(); - //! WriteFile(g_hlog, logdata); - //! } - //! - class last_error_context - { -#ifndef WIL_KERNEL_MODE - bool m_dismissed = false; - DWORD m_error = 0; - public: - last_error_context() WI_NOEXCEPT : last_error_context(::GetLastError()) - { - } - - explicit last_error_context(DWORD error) WI_NOEXCEPT : - m_error(error) - { - } - - last_error_context(last_error_context&& other) WI_NOEXCEPT - { - operator=(wistd::move(other)); - } - - last_error_context& operator=(last_error_context&& other) WI_NOEXCEPT - { - m_dismissed = wistd::exchange(other.m_dismissed, true); - m_error = other.m_error; - - return *this; - } - - ~last_error_context() WI_NOEXCEPT - { - if (!m_dismissed) - { - ::SetLastError(m_error); - } - } - - //! last_error_context doesn't own a concrete resource, so therefore - //! it just disarms its destructor and returns void. - void release() WI_NOEXCEPT - { - WI_ASSERT(!m_dismissed); - m_dismissed = true; - } - - WI_NODISCARD auto value() const WI_NOEXCEPT - { - return m_error; - } -#else - public: - void release() WI_NOEXCEPT { } -#endif // WIL_KERNEL_MODE - }; - - /// @cond - namespace details - { - typedef wistd::integral_constant pointer_access_all; // get(), release(), addressof(), and '&' are available - typedef wistd::integral_constant pointer_access_noaddress; // get() and release() are available - typedef wistd::integral_constant pointer_access_none; // the raw pointer is not available - - template struct close_invoke_helper - { - __forceinline static void close(pointer_storage_t value) WI_NOEXCEPT { wistd::invoke(close_fn, value); } - inline static void close_reset(pointer_storage_t value) WI_NOEXCEPT - { - auto preserveError = last_error_context(); - wistd::invoke(close_fn, value); - } - }; - - template struct close_invoke_helper - { - __forceinline static void close(pointer_storage_t value) WI_NOEXCEPT { close_fn(value); } - inline static void close_reset(pointer_storage_t value) WI_NOEXCEPT - { - auto preserveError = last_error_context(); - close_fn(value); - } - }; - - template using close_invoker = - close_invoke_helper ? wistd::is_function_v> : false, close_fn_t, close_fn, pointer_storage_t>; - - template // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer - struct resource_policy : close_invoker - { - typedef pointer_storage_t pointer_storage; - typedef pointer_t pointer; - typedef pointer_invalid_t pointer_invalid; - typedef pointer_access_t pointer_access; - __forceinline static pointer_storage invalid_value() { return (pointer)invalid; } - __forceinline static bool is_valid(pointer_storage value) WI_NOEXCEPT { return (static_cast(value) != (pointer)invalid); } - }; - - - // This class provides the pointer storage behind the implementation of unique_any_t utilizing the given - // resource_policy. It is separate from unique_any_t to allow a type-specific specialization class to plug - // into the inheritance chain between unique_any_t and unique_storage. This allows classes like unique_event - // to be a unique_any formed class, but also expose methods like SetEvent directly. - - template - class unique_storage - { - protected: - typedef Policy policy; - typedef typename policy::pointer_storage pointer_storage; - typedef typename policy::pointer pointer; - typedef unique_storage base_storage; - - public: - unique_storage() WI_NOEXCEPT : - m_ptr(policy::invalid_value()) - { - } - - explicit unique_storage(pointer_storage ptr) WI_NOEXCEPT : - m_ptr(ptr) - { - } - - unique_storage(unique_storage &&other) WI_NOEXCEPT : - m_ptr(wistd::move(other.m_ptr)) - { - other.m_ptr = policy::invalid_value(); - } - - ~unique_storage() WI_NOEXCEPT - { - if (policy::is_valid(m_ptr)) - { - policy::close(m_ptr); - } - } - - WI_NODISCARD bool is_valid() const WI_NOEXCEPT - { - return policy::is_valid(m_ptr); - } - - void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT - { - if (policy::is_valid(m_ptr)) - { - policy::close_reset(m_ptr); - } - m_ptr = ptr; - } - - void reset(wistd::nullptr_t) WI_NOEXCEPT - { - static_assert(wistd::is_same::value, "reset(nullptr): valid only for handle types using nullptr as the invalid value"); - reset(); - } - - WI_NODISCARD pointer get() const WI_NOEXCEPT - { - return static_cast(m_ptr); - } - - pointer_storage release() WI_NOEXCEPT - { - static_assert(!wistd::is_same::value, "release(): the raw handle value is not available for this resource class"); - auto ptr = m_ptr; - m_ptr = policy::invalid_value(); - return ptr; - } - - pointer_storage *addressof() WI_NOEXCEPT - { - static_assert(wistd::is_same::value, "addressof(): the address of the raw handle is not available for this resource class"); - return &m_ptr; - } - - protected: - void replace(unique_storage &&other) WI_NOEXCEPT - { - reset(other.m_ptr); - other.m_ptr = policy::invalid_value(); - } - - private: - pointer_storage m_ptr; - }; - } // details - /// @endcond - - - // This class when paired with unique_storage and an optional type-specific specialization class implements - // the same interface as STL's unique_ptr<> for resource handle types. It is a non-copyable, yet movable class - // supporting attach (reset), detach (release), retrieval (get()). - - template - class unique_any_t : public storage_t - { - public: - typedef typename storage_t::policy policy; - typedef typename policy::pointer_storage pointer_storage; - typedef typename policy::pointer pointer; - - unique_any_t(unique_any_t const &) = delete; - unique_any_t& operator=(unique_any_t const &) = delete; - - // Note that the default constructor really shouldn't be needed (taken care of by the forwarding constructor below), but - // the forwarding constructor causes an internal compiler error when the class is used in a C++ array. Defining the default - // constructor independent of the forwarding constructor removes the compiler limitation. - unique_any_t() = default; - - // forwarding constructor: forwards all 'explicit' and multi-arg constructors to the base class - template - explicit unique_any_t(arg1 && first, args_t&&... args) - __WI_NOEXCEPT_((wistd::is_nothrow_constructible_v)) : - storage_t(wistd::forward(first), wistd::forward(args)...) - { - static_assert(wistd::is_same::value || - wistd::is_same::value || - wistd::is_same::value, "pointer_access policy must be a known pointer_access* integral type"); - } - - unique_any_t(wistd::nullptr_t) WI_NOEXCEPT - { - static_assert(wistd::is_same::value, "nullptr constructor: valid only for handle types using nullptr as the invalid value"); - } - - unique_any_t(unique_any_t &&other) WI_NOEXCEPT : - storage_t(wistd::move(other)) - { - } - - unique_any_t& operator=(unique_any_t &&other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - // cast to base_storage to 'skip' calling the (optional) specialization class that provides handle-specific functionality - storage_t::replace(wistd::move(static_cast(other))); - } - return (*this); - } - - unique_any_t& operator=(wistd::nullptr_t) WI_NOEXCEPT - { - static_assert(wistd::is_same::value, "nullptr assignment: valid only for handle types using nullptr as the invalid value"); - storage_t::reset(); - return (*this); - } - - void swap(unique_any_t &other) WI_NOEXCEPT - { - unique_any_t self(wistd::move(*this)); - operator=(wistd::move(other)); - other = wistd::move(self); - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return storage_t::is_valid(); - } - - //! ~~~~ - //! BOOL OpenOrCreateWaffle(PCWSTR name, HWAFFLE* handle); - //! wil::unique_any waffle; - //! RETURN_IF_WIN32_BOOL_FALSE(OpenOrCreateWaffle(L"tasty.yum", waffle.put())); - //! ~~~~ - pointer_storage *put() WI_NOEXCEPT - { - static_assert(wistd::is_same::value, "operator & is not available for this handle"); - storage_t::reset(); - return storage_t::addressof(); - } - - pointer_storage *operator&() WI_NOEXCEPT - { - return put(); - } - - WI_NODISCARD pointer get() const WI_NOEXCEPT - { - static_assert(!wistd::is_same::value, "get(): the raw handle value is not available for this resource class"); - return storage_t::get(); - } - - // The following functions are publicly exposed by their inclusion in the unique_storage base class - - // explicit unique_any_t(pointer_storage ptr) WI_NOEXCEPT - // void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT - // void reset(wistd::nullptr_t) WI_NOEXCEPT - // pointer_storage release() WI_NOEXCEPT // not exposed for some resource types - // pointer_storage *addressof() WI_NOEXCEPT // not exposed for some resource types - }; - - template - void swap(unique_any_t& left, unique_any_t& right) WI_NOEXCEPT - { - left.swap(right); - } - - template - bool operator==(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT - { - return (left.get() == right.get()); - } - - template - bool operator==(const unique_any_t& left, wistd::nullptr_t) WI_NOEXCEPT - { - static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); - return !left; - } - - template - bool operator==(wistd::nullptr_t, const unique_any_t& right) WI_NOEXCEPT - { - static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); - return !right; - } - - template - bool operator!=(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT - { - return (!(left.get() == right.get())); - } - - template - bool operator!=(const unique_any_t& left, wistd::nullptr_t) WI_NOEXCEPT - { - static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); - return !!left; - } - - template - bool operator!=(wistd::nullptr_t, const unique_any_t& right) WI_NOEXCEPT - { - static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); - return !!right; - } - - template - bool operator<(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT - { - return (left.get() < right.get()); - } - - template - bool operator>=(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT - { - return (!(left < right)); - } - - template - bool operator>(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT - { - return (right < left); - } - - template - bool operator<=(const unique_any_t& left, const unique_any_t& right) WI_NOEXCEPT - { - return (!(right < left)); - } - - // unique_any provides a template alias for easily building a unique_any_t from a unique_storage class with the given - // template parameters for resource_policy. - - template // nullptr_t if the invalid handle value is compatible with nullptr, otherwise pointer - using unique_any = unique_any_t>>; - - /// @cond - namespace details - { - template - class lambda_call - { - public: - lambda_call(const lambda_call&) = delete; - lambda_call& operator=(const lambda_call&) = delete; - lambda_call& operator=(lambda_call&& other) = delete; - - explicit lambda_call(TLambda&& lambda) WI_NOEXCEPT : m_lambda(wistd::move(lambda)) - { - static_assert(wistd::is_same::value, "scope_exit lambdas must not have a return value"); - static_assert(!wistd::is_lvalue_reference::value && !wistd::is_rvalue_reference::value, - "scope_exit should only be directly used with a lambda"); - } - - lambda_call(lambda_call&& other) WI_NOEXCEPT : m_lambda(wistd::move(other.m_lambda)), m_call(other.m_call) - { - other.m_call = false; - } - - ~lambda_call() WI_NOEXCEPT - { - reset(); - } - - // Ensures the scope_exit lambda will not be called - void release() WI_NOEXCEPT - { - m_call = false; - } - - // Executes the scope_exit lambda immediately if not yet run; ensures it will not run again - void reset() WI_NOEXCEPT - { - if (m_call) - { - m_call = false; - m_lambda(); - } - } - - // Returns true if the scope_exit lambda is still going to be executed - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return m_call; - } - - protected: - TLambda m_lambda; - bool m_call = true; - }; - -#ifdef WIL_ENABLE_EXCEPTIONS - template - class lambda_call_log - { - public: - lambda_call_log(const lambda_call_log&) = delete; - lambda_call_log& operator=(const lambda_call_log&) = delete; - lambda_call_log& operator=(lambda_call_log&& other) = delete; - - explicit lambda_call_log(void* address, const DiagnosticsInfo& info, TLambda&& lambda) WI_NOEXCEPT : - m_address(address), m_info(info), m_lambda(wistd::move(lambda)) - { - static_assert(wistd::is_same::value, "scope_exit lambdas must return 'void'"); - static_assert(!wistd::is_lvalue_reference::value && !wistd::is_rvalue_reference::value, - "scope_exit should only be directly used with a lambda"); - } - - lambda_call_log(lambda_call_log&& other) WI_NOEXCEPT : - m_address(other.m_address), m_info(other.m_info), m_lambda(wistd::move(other.m_lambda)), m_call(other.m_call) - { - other.m_call = false; - } - - ~lambda_call_log() WI_NOEXCEPT - { - reset(); - } - - // Ensures the scope_exit lambda will not be called - void release() WI_NOEXCEPT - { - m_call = false; - } - - // Executes the scope_exit lambda immediately if not yet run; ensures it will not run again - void reset() WI_NOEXCEPT - { - if (m_call) - { - m_call = false; - try - { - m_lambda(); - } - catch (...) - { - ReportFailure_CaughtException(__R_DIAGNOSTICS(m_info), m_address); - } - } - } - - // Returns true if the scope_exit lambda is still going to be executed - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return m_call; - } - - private: - void* m_address; - DiagnosticsInfo m_info; - TLambda m_lambda; - bool m_call = true; - }; -#endif // WIL_ENABLE_EXCEPTIONS - } - /// @endcond - - /** Returns an object that executes the given lambda when destroyed. - Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid - execution. Exceptions thrown in the lambda will fail-fast; use scope_exit_log to avoid. */ - template - WI_NODISCARD inline auto scope_exit(TLambda&& lambda) WI_NOEXCEPT - { - return details::lambda_call(wistd::forward(lambda)); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - /** Returns an object that executes the given lambda when destroyed; logs exceptions. - Capture the object with 'auto'; use reset() to execute the lambda early or release() to avoid - execution. Exceptions thrown in the lambda will be caught and logged without being propagated. */ - template - WI_NODISCARD inline __declspec(noinline) auto scope_exit_log(const DiagnosticsInfo& diagnostics, TLambda&& lambda) WI_NOEXCEPT - { - return details::lambda_call_log(_ReturnAddress(), diagnostics, wistd::forward(lambda)); - } -#endif - - // Forward declaration... - template - class com_ptr_t; - - //! Type traits class that identifies the inner type of any smart pointer. - template - struct smart_pointer_details - { - typedef typename Ptr::pointer pointer; - }; - - /// @cond - template - struct smart_pointer_details> - { - typedef T* pointer; - }; - /// @endcond - - /** Generically detaches a raw pointer from any smart pointer. - Caller takes ownership of the returned raw pointer; calls the correct release(), detach(), - or Detach() method based on the smart pointer type */ - template - WI_NODISCARD typename TSmartPointer::pointer detach_from_smart_pointer(TSmartPointer& smartPtr) - { - return smartPtr.release(); - } - - /// @cond - // Generically detaches a raw pointer from any smart pointer - template - WI_NODISCARD T* detach_from_smart_pointer(wil::com_ptr_t& smartPtr) - { - return smartPtr.detach(); - } - - // Generically detaches a raw pointer from any smart pointer - template - WI_NODISCARD T* detach_from_smart_pointer(Microsoft::WRL::ComPtr& smartPtr) - { - return smartPtr.Detach(); - } - - template class com_ptr_t; // forward - namespace details - { - // The first two attach_to_smart_pointer() overloads are ambiguous when passed a com_ptr_t. - // To solve that use this functions return type to elminate the reset form for com_ptr_t. - template wistd::false_type use_reset(wil::com_ptr_t*) { return wistd::false_type(); } - template wistd::true_type use_reset(T*) { return wistd::true_type(); } - } - /// @endcond - - /** Generically attach a raw pointer to a compatible smart pointer. - Calls the correct reset(), attach(), or Attach() method based on samrt pointer type. */ - template (nullptr)))::value>> - void attach_to_smart_pointer(TSmartPointer& smartPtr, typename TSmartPointer::pointer rawPtr) - { - smartPtr.reset(rawPtr); - } - - /// @cond - - // Generically attach a raw pointer to a compatible smart pointer. - template - void attach_to_smart_pointer(wil::com_ptr_t& smartPtr, T* rawPtr) - { - smartPtr.attach(rawPtr); - } - - // Generically attach a raw pointer to a compatible smart pointer. - template - void attach_to_smart_pointer(Microsoft::WRL::ComPtr& smartPtr, T* rawPtr) - { - smartPtr.Attach(rawPtr); - } - /// @endcond - - //! @ingroup outparam - /** Detach a smart pointer resource to an optional output pointer parameter. - Avoids cluttering code with nullptr tests; works generically for any smart pointer */ - template - inline void detach_to_opt_param(_Out_opt_ T* outParam, TSmartPointer&& smartPtr) - { - if (outParam) - { - *outParam = detach_from_smart_pointer(smartPtr); - } - } - - /// @cond - namespace details - { - template - struct out_param_t - { - typedef typename wil::smart_pointer_details::pointer pointer; - T &wrapper; - pointer pRaw; - bool replace = true; - - out_param_t(_Inout_ T &output) : - wrapper(output), - pRaw(nullptr) - { - } - - out_param_t(out_param_t&& other) WI_NOEXCEPT : - wrapper(other.wrapper), - pRaw(other.pRaw) - { - WI_ASSERT(other.replace); - other.replace = false; - } - - operator pointer*() - { - WI_ASSERT(replace); - return &pRaw; - } - - ~out_param_t() - { - if (replace) - { - attach_to_smart_pointer(wrapper, pRaw); - } - } - - out_param_t(out_param_t const &other) = delete; - out_param_t &operator=(out_param_t const &other) = delete; - }; - - template - struct out_param_ptr_t - { - typedef typename wil::smart_pointer_details::pointer pointer; - T &wrapper; - pointer pRaw; - bool replace = true; - - out_param_ptr_t(_Inout_ T &output) : - wrapper(output), - pRaw(nullptr) - { - } - - out_param_ptr_t(out_param_ptr_t&& other) WI_NOEXCEPT : - wrapper(other.wrapper), - pRaw(other.pRaw) - { - WI_ASSERT(other.replace); - other.replace = false; - } - - operator Tcast() - { - WI_ASSERT(replace); - return reinterpret_cast(&pRaw); - } - - ~out_param_ptr_t() - { - if (replace) - { - attach_to_smart_pointer(wrapper, pRaw); - } - } - - out_param_ptr_t(out_param_ptr_t const &other) = delete; - out_param_ptr_t &operator=(out_param_ptr_t const &other) = delete; - }; - } // details - /// @endcond - - /** Use to retrieve raw out parameter pointers into smart pointers that do not support the '&' operator. - This avoids multi-step handling of a raw resource to establish the smart pointer. - Example: `GetFoo(out_param(foo));` */ - template - details::out_param_t out_param(T& p) - { - return details::out_param_t(p); - } - - /** Use to retrieve raw out parameter pointers (with a required cast) into smart pointers that do not support the '&' operator. - Use only when the smart pointer's &handle is not equal to the output type a function requires, necessitating a cast. - Example: `wil::out_param_ptr(securityDescriptor)` */ - template - details::out_param_ptr_t out_param_ptr(T& p) - { - return details::out_param_ptr_t(p); - } - - /** Use unique_struct to define an RAII type for a trivial struct that references resources that must be cleaned up. - Unique_struct wraps a trivial struct using a custom clean up function and, optionally, custom initializer function. If no custom initialier function is defined in the template - then ZeroMemory is used. - Unique_struct is modeled off of std::unique_ptr. However, unique_struct inherits from the defined type instead of managing the struct through a private member variable. - - If the type you're wrapping is a system type, you can share the code by declaring it in this file (Resource.h). Send requests to wildisc. - Otherwise, if the type is local to your project, declare it locally. - @tparam struct_t The struct you want to manage - @tparam close_fn_t The type of the function to clean up the struct. Takes one parameter: a pointer of struct_t. Return values are ignored. - @tparam close_fn The function of type close_fn_t. This is called in the destructor and reset functions. - @tparam init_fn_t Optional:The type of the function to initialize the struct. Takes one parameter: a pointer of struct_t. Return values are ignored. - @tparam init_fn Optional:The function of type init_fn_t. This is called in the constructor, reset, and release functions. The default is ZeroMemory to initialize the struct. - - Defined using the default zero memory initializer - ~~~ - typedef wil::unique_struct unique_prop_variant_default_init; - - unique_prop_variant_default_init propvariant; - SomeFunction(&propvariant); - ~~~ - - Defined using a custom initializer - ~~~ - typedef wil::unique_struct unique_prop_variant; - - unique_prop_variant propvariant; - SomeFunction(&propvariant); - ~~~ - */ - template - class unique_struct : public struct_t - { - using closer = details::close_invoker; - public: - //! Initializes the managed struct using the user-provided initialization function, or ZeroMemory if no function is specified - unique_struct() - { - call_init(use_default_init_fn()); - } - - //! Takes ownership of the struct by doing a shallow copy. Must explicitly be type struct_t - explicit unique_struct(const struct_t& other) WI_NOEXCEPT : - struct_t(other) - {} - - //! Initializes the managed struct by taking the ownership of the other managed struct - //! Then resets the other managed struct by calling the custom close function - unique_struct(unique_struct&& other) WI_NOEXCEPT : - struct_t(other.release()) - {} - - //! Resets this managed struct by calling the custom close function and takes ownership of the other managed struct - //! Then resets the other managed struct by calling the custom close function - unique_struct & operator=(unique_struct&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - reset(other.release()); - } - return *this; - } - - //! Calls the custom close function - ~unique_struct() WI_NOEXCEPT - { - closer::close(this); - } - - void reset(const unique_struct&) = delete; - - //! Resets this managed struct by calling the custom close function and begins management of the other struct - void reset(const struct_t& other) WI_NOEXCEPT - { - closer::close_reset(this); - struct_t::operator=(other); - } - - //! Resets this managed struct by calling the custom close function - //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is specified - void reset() WI_NOEXCEPT - { - closer::close(this); - call_init(use_default_init_fn()); - } - - void swap(struct_t&) = delete; - - //! Swaps the managed structs - void swap(unique_struct& other) WI_NOEXCEPT - { - struct_t self(*this); - struct_t::operator=(other); - *(other.addressof()) = self; - } - - //! Returns the managed struct - //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is specified - struct_t release() WI_NOEXCEPT - { - struct_t value(*this); - call_init(use_default_init_fn()); - return value; - } - - //! Returns address of the managed struct - struct_t * addressof() WI_NOEXCEPT - { - return this; - } - - //! Resets this managed struct by calling the custom close function - //! Then initializes this managed struct using the user-provided initialization function, or ZeroMemory if no function is specified - //! Returns address of the managed struct - struct_t * reset_and_addressof() WI_NOEXCEPT - { - reset(); - return this; - } - - unique_struct(const unique_struct&) = delete; - unique_struct& operator=(const unique_struct&) = delete; - unique_struct& operator=(const struct_t&) = delete; - - private: - typedef typename wistd::is_same::type use_default_init_fn; - - void call_init(wistd::true_type) - { - RtlZeroMemory(this, sizeof(*this)); - } - - void call_init(wistd::false_type) - { - init_fn(this); - } - }; - - struct empty_deleter - { - template - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T) const - { - } - }; - - /** unique_any_array_ptr is a RAII type for managing conformant arrays that need to be freed and have elements that may need to be freed. - The intented use for this RAII type would be to capture out params from API like IPropertyValue::GetStringArray. - This class also maintains the size of the array, so it can iterate over the members and deallocate them before it deallocates the base array pointer. - - If the type you're wrapping is a system type, you can share the code by declaring it in this file (Resource.h). Send requests to wildisc. - Otherwise, if the type is local to your project, declare it locally. - - @tparam ValueType: The type of array you want to manage. - @tparam ArrayDeleter: The type of the function to clean up the array. Takes one parameter of type T[] or T*. Return values are ignored. This is called in the destructor and reset functions. - @tparam ElementDeleter: The type of the function to clean up the array elements. Takes one parameter of type T. Return values are ignored. This is called in the destructor and reset functions. - - ~~~ - void GetSomeArray(_Out_ size_t*, _Out_ NOTMYTYPE**); - - struct not_my_deleter - { - void operator()(NOTMYTYPE p) const - { - destroy(p); - } - }; - - wil::unique_any_array_ptr myArray; - GetSomeArray(myArray.size_address(), &myArray); - ~~~ */ - template - class unique_any_array_ptr - { - public: - typedef ValueType value_type; - typedef size_t size_type; - typedef ptrdiff_t difference_type; - typedef ValueType *pointer; - typedef const ValueType *const_pointer; - typedef ValueType& reference; - typedef const ValueType& const_reference; - - typedef ValueType* iterator; - typedef const ValueType* const_iterator; - - unique_any_array_ptr() = default; - unique_any_array_ptr(const unique_any_array_ptr&) = delete; - unique_any_array_ptr& operator=(const unique_any_array_ptr&) = delete; - - unique_any_array_ptr(wistd::nullptr_t) WI_NOEXCEPT - { - } - - unique_any_array_ptr& operator=(wistd::nullptr_t) WI_NOEXCEPT - { - reset(); - return *this; - } - - unique_any_array_ptr(pointer ptr, size_t size) WI_NOEXCEPT : m_ptr(ptr), m_size(size) - { - } - - unique_any_array_ptr(unique_any_array_ptr&& other) WI_NOEXCEPT : m_ptr(other.m_ptr), m_size(other.m_size) - { - other.m_ptr = nullptr; - other.m_size = size_type{}; - } - - unique_any_array_ptr& operator=(unique_any_array_ptr&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - reset(); - swap(other); - } - return *this; - } - - ~unique_any_array_ptr() WI_NOEXCEPT - { - reset(); - } - - void swap(unique_any_array_ptr& other) WI_NOEXCEPT - { - auto ptr = m_ptr; - auto size = m_size; - m_ptr = other.m_ptr; - m_size = other.m_size; - other.m_ptr = ptr; - other.m_size = size; - } - - WI_NODISCARD iterator begin() WI_NOEXCEPT - { - return (iterator(m_ptr)); - } - - WI_NODISCARD const_iterator begin() const WI_NOEXCEPT - { - return (const_iterator(m_ptr)); - } - - WI_NODISCARD iterator end() WI_NOEXCEPT - { - return (iterator(m_ptr + m_size)); - } - - WI_NODISCARD const_iterator end() const WI_NOEXCEPT - { - return (const_iterator(m_ptr + m_size)); - } - - WI_NODISCARD const_iterator cbegin() const WI_NOEXCEPT - { - return (begin()); - } - - WI_NODISCARD const_iterator cend() const WI_NOEXCEPT - { - return (end()); - } - - WI_NODISCARD size_type size() const WI_NOEXCEPT - { - return (m_size); - } - - WI_NODISCARD bool empty() const WI_NOEXCEPT - { - return (size() == size_type{}); - } - - WI_NODISCARD reference operator[](size_type position) - { - WI_ASSERT(position < m_size); - _Analysis_assume_(position < m_size); - return (m_ptr[position]); - } - - WI_NODISCARD const_reference operator[](size_type position) const - { - WI_ASSERT(position < m_size); - _Analysis_assume_(position < m_size); - return (m_ptr[position]); - } - - WI_NODISCARD reference front() - { - WI_ASSERT(!empty()); - return (m_ptr[0]); - } - - WI_NODISCARD const_reference front() const - { - WI_ASSERT(!empty()); - return (m_ptr[0]); - } - - WI_NODISCARD reference back() - { - WI_ASSERT(!empty()); - return (m_ptr[m_size - 1]); - } - - WI_NODISCARD const_reference back() const - { - WI_ASSERT(!empty()); - return (m_ptr[m_size - 1]); - } - - WI_NODISCARD ValueType* data() WI_NOEXCEPT - { - return (m_ptr); - } - - WI_NODISCARD const ValueType* data() const WI_NOEXCEPT - { - return (m_ptr); - } - - WI_NODISCARD pointer get() const WI_NOEXCEPT - { - return m_ptr; - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_ptr != pointer()); - } - - pointer release() WI_NOEXCEPT - { - auto result = m_ptr; - m_ptr = nullptr; - m_size = size_type{}; - return result; - } - - void reset() WI_NOEXCEPT - { - if (m_ptr) - { - reset_array(ElementDeleter()); - ArrayDeleter()(m_ptr); - m_ptr = nullptr; - m_size = size_type{}; - } - } - - void reset(pointer ptr, size_t size) WI_NOEXCEPT - { - reset(); - m_ptr = ptr; - m_size = size; - } - - pointer* addressof() WI_NOEXCEPT - { - return &m_ptr; - } - - pointer* put() WI_NOEXCEPT - { - reset(); - return addressof(); - } - - pointer* operator&() WI_NOEXCEPT - { - return put(); - } - - size_type* size_address() WI_NOEXCEPT - { - return &m_size; - } - - template - struct size_address_ptr - { - unique_any_array_ptr& wrapper; - TSize size{}; - bool replace = true; - - size_address_ptr(_Inout_ unique_any_array_ptr& output) : - wrapper(output) - { - } - - size_address_ptr(size_address_ptr&& other) WI_NOEXCEPT : - wrapper(other.wrapper), - size(other.size) - { - WI_ASSERT(other.replace); - other.replace = false; - } - - operator TSize*() - { - WI_ASSERT(replace); - return &size; - } - - ~size_address_ptr() - { - if (replace) - { - *wrapper.size_address() = static_cast(size); - } - } - - size_address_ptr(size_address_ptr const &other) = delete; - size_address_ptr &operator=(size_address_ptr const &other) = delete; - }; - - template - size_address_ptr size_address() WI_NOEXCEPT - { - return size_address_ptr(*this); - } - - private: - pointer m_ptr = nullptr; - size_type m_size{}; - - void reset_array(const empty_deleter&) - { - } - - template - void reset_array(const T& deleter) - { - for (auto& element : make_range(m_ptr, m_size)) - { - deleter(element); - } - } - }; - - // forward declaration - template - class com_ptr_t; - - /// @cond - namespace details - { - template - struct unique_any_array_deleter - { - template - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const - { - UniqueAnyType::policy::close_reset(p); - } - }; - - template - struct unique_struct_array_deleter - { - template - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T& p) const - { - close_invoker::close(&p); - } - }; - - struct com_unknown_deleter - { - template - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const - { - if (p) - { - p->Release(); - } - } - }; - - template - struct element_traits - { - typedef empty_deleter deleter; - typedef T type; - }; - - template - struct element_traits> - { - typedef unique_any_array_deleter> deleter; - typedef typename unique_any_t::pointer type; - }; - - template - struct element_traits> - { - typedef com_unknown_deleter deleter; - typedef T* type; - }; - - template - struct element_traits> - { - typedef unique_struct_array_deleter deleter; - typedef struct_t type; - }; - } - /// @endcond - - template - using unique_array_ptr = unique_any_array_ptr::type, ArrayDeleter, typename details::element_traits::deleter>; - - /** Adapter for single-parameter 'free memory' for `wistd::unique_ptr`. - This struct provides a standard wrapper for calling a platform function to deallocate memory held by a - `wistd::unique_ptr`, making declaring them as easy as declaring wil::unique_any<>. - - Consider this adapter in preference to `wil::unique_any<>` when the returned type is really a pointer or an - array of items; `wistd::unique_ptr<>` exposes `operator->()` and `operator[]` for array-typed things safely. - ~~~~ - EXTERN_C VOID WINAPI MyDllFreeMemory(void* p); - EXTERN_C HRESULT MyDllGetString(_Outptr_ PWSTR* pString); - EXTERN_C HRESULT MyDllGetThing(_In_ PCWSTR pString, _Outptr_ PMYSTRUCT* ppThing); - template - using unique_mydll_ptr = wistd::unique_ptr>; - HRESULT Test() - { - unique_mydll_ptr dllString; - unique_mydll_ptr thing; - RETURN_IF_FAILED(MyDllGetString(wil::out_param(dllString))); - RETURN_IF_FAILED(MyDllGetThing(dllString.get(), wil::out_param(thing))); - if (thing->Member) - { - // ... - } - return S_OK; - } - ~~~~ */ - template struct function_deleter - { - template void operator()(_Frees_ptr_opt_ T* toFree) const - { - TDeleter(toFree); - } - }; - - /** Use unique_com_token to define an RAII type for a token-based resource that is managed by a COM interface. - By comparison, unique_any_t has the requirement that the close function must be static. This works for functions - such as CloseHandle(), but for any resource cleanup function that relies on a more complex interface, - unique_com_token can be used. - - @tparam interface_t A COM interface pointer that will manage this resource type. - @tparam token_t The token type that relates to the COM interface management functions. - @tparam close_fn_t The type of the function that is called when the resource is destroyed. - @tparam close_fn The function used to destroy the associated resource. This function should have the signature void(interface_t* source, token_t token). - @tparam invalid_token Optional:An invalid token value. Defaults to default-constructed token_t(). - - Example - ~~~ - void __stdcall MyInterfaceCloseFunction(IMyInterface* source, DWORD token) - { - source->MyCloseFunction(token); - } - using unique_my_interface_token = wil::unique_com_token; - ~~~ */ - template - class unique_com_token - { - public: - unique_com_token() = default; - - unique_com_token(_In_opt_ interface_t* source, token_t token = invalid_token) WI_NOEXCEPT - { - reset(source, token); - } - - unique_com_token(unique_com_token&& other) WI_NOEXCEPT : m_source(other.m_source), m_token(other.m_token) - { - other.m_source = nullptr; - other.m_token = invalid_token; - } - - unique_com_token& operator=(unique_com_token&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - reset(); - m_source = other.m_source; - m_token = other.m_token; - - other.m_source = nullptr; - other.m_token = invalid_token; - } - return *this; - } - - ~unique_com_token() WI_NOEXCEPT - { - reset(); - } - - //! Determine if the underlying source and token are valid - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_token != invalid_token) && m_source; - } - - //! Associates a new source and releases the existing token if valid - void associate(_In_opt_ interface_t* source) WI_NOEXCEPT - { - reset(source, invalid_token); - } - - //! Assigns a new source and token - void reset(_In_opt_ interface_t* source, token_t token) WI_NOEXCEPT - { - WI_ASSERT(source || (token == invalid_token)); - - // Determine if we need to call the close function on our previous token. - if (m_token != invalid_token) - { - if ((m_source != source) || (m_token != token)) - { - wistd::invoke(close_fn, m_source, m_token); - } - } - - m_token = token; - - // Assign our new source and manage the reference counts - if (m_source != source) - { - auto oldSource = m_source; - m_source = source; - - if (m_source) - { - m_source->AddRef(); - } - - if (oldSource) - { - oldSource->Release(); - } - } - } - - //! Assigns a new token without modifying the source; associate must be called first - void reset(token_t token) WI_NOEXCEPT - { - reset(m_source, token); - } - - //! Closes the token and the releases the reference to the source - void reset() WI_NOEXCEPT - { - reset(nullptr, invalid_token); - } - - //! Exchanges values with another managed token - void swap(unique_com_token& other) WI_NOEXCEPT - { - wistd::swap_wil(m_source, other.m_source); - wistd::swap_wil(m_token, other.m_token); - } - - //! Releases the held token to the caller without closing it and releases the reference to the source. - //! Requires that the associated COM interface be kept alive externally or the released token may be invalidated - token_t release() WI_NOEXCEPT - { - auto token = m_token; - m_token = invalid_token; - reset(); - return token; - } - - //! Returns address of the managed token; associate must be called first - token_t* addressof() WI_NOEXCEPT - { - WI_ASSERT(m_source); - return &m_token; - } - - //! Releases the held token and allows attaching a new token; associate must be called first - token_t* put() WI_NOEXCEPT - { - reset(invalid_token); - return addressof(); - } - - //! Releases the held token and allows attaching a new token; associate must be called first - token_t* operator&() WI_NOEXCEPT - { - return put(); - } - - //! Retrieves the token - WI_NODISCARD token_t get() const WI_NOEXCEPT - { - return m_token; - } - - unique_com_token(const unique_com_token&) = delete; - unique_com_token& operator=(const unique_com_token&) = delete; - - private: - interface_t* m_source = nullptr; - token_t m_token = invalid_token; - }; - - /** Use unique_com_call to define an RAII type that demands a particular parameter-less method be called on a COM interface. - This allows implementing an RAII type that can call a Close() method (think IClosable) or a SetSite(nullptr) - method (think IObjectWithSite) or some other method when a basic interface call is required as part of the RAII contract. - see wil::com_set_site in wil\com.h for the IObjectWithSite support. - - @tparam interface_t A COM interface pointer that provides context to make the call. - @tparam close_fn_t The type of the function that is called to invoke the method. - @tparam close_fn The function used to invoke the interface method. This function should have the signature void(interface_t* source). - - Example - ~~~ - void __stdcall CloseIClosable(IClosable* source) - { - source->Close(); - } - using unique_closable_call = wil::unique_com_call; - ~~~ */ - template - class unique_com_call - { - public: - unique_com_call() = default; - - explicit unique_com_call(_In_opt_ interface_t* ptr) WI_NOEXCEPT - { - reset(ptr); - } - - unique_com_call(unique_com_call&& other) WI_NOEXCEPT - { - m_ptr = other.m_ptr; - other.m_ptr = nullptr; - } - - unique_com_call& operator=(unique_com_call&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - reset(); - m_ptr = other.m_ptr; - other.m_ptr = nullptr; - } - return *this; - } - - ~unique_com_call() WI_NOEXCEPT - { - reset(); - } - - //! Assigns an interface to make a given call on - void reset(_In_opt_ interface_t* ptr = nullptr) WI_NOEXCEPT - { - if (ptr != m_ptr) - { - auto oldSource = m_ptr; - m_ptr = ptr; - if (m_ptr) - { - m_ptr->AddRef(); - } - if (oldSource) - { - details::close_invoker::close(oldSource); - oldSource->Release(); - } - } - } - - //! Exchanges values with another class - void swap(unique_com_call& other) WI_NOEXCEPT - { - wistd::swap_wil(m_ptr, other.m_ptr); - } - - //! Cancel the interface call that this class was expected to make - void release() WI_NOEXCEPT - { - auto ptr = m_ptr; - m_ptr = nullptr; - if (ptr) - { - ptr->Release(); - } - } - - //! Returns true if the call this class was expected to make is still outstanding - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_ptr != nullptr); - } - - //! Returns address of the internal interface - interface_t** addressof() WI_NOEXCEPT - { - return &m_ptr; - } - - //! Releases the held interface (first performing the interface call if required) - //! and allows attaching a new interface - interface_t** put() WI_NOEXCEPT - { - reset(); - return addressof(); - } - - //! Releases the held interface (first performing the interface call if required) - //! and allows attaching a new interface - interface_t** operator&() WI_NOEXCEPT - { - return put(); - } - - unique_com_call(const unique_com_call&) = delete; - unique_com_call& operator=(const unique_com_call&) = delete; - - private: - interface_t* m_ptr = nullptr; - }; - - - /** Use unique_call to define an RAII type that demands a particular parameter-less global function be called. - This allows implementing a RAII types that can call methods like CoUninitialize. - - @tparam close_fn_t The type of the function that is called to invoke the call. - @tparam close_fn The function used to invoke the call. This function should have the signature void(). - @tparam default_value Determines whether the unique_call is active or inactive when default-constructed or reset. - - Example - ~~~ - void __stdcall CoUninitializeFunction() - { - ::CoUninitialize(); - } - using unique_couninitialize_call = wil::unique_call; - ~~~ */ - template - class unique_call - { - public: - unique_call() = default; - - explicit unique_call(bool call) WI_NOEXCEPT : m_call(call) - { - } - - unique_call(unique_call&& other) WI_NOEXCEPT - { - m_call = other.m_call; - other.m_call = false; - } - - unique_call& operator=(unique_call&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - reset(); - m_call = other.m_call; - other.m_call = false; - } - return *this; - } - - ~unique_call() WI_NOEXCEPT - { - reset(); - } - - //! Assigns a new ptr and token - void reset() WI_NOEXCEPT - { - auto call = m_call; - m_call = false; - if (call) - { - close_fn(); - } - } - - //! Exchanges values with raii class - void swap(unique_call& other) WI_NOEXCEPT - { - wistd::swap_wil(m_call, other.m_call); - } - - //! Make the interface call that was expected of this class - void activate() WI_NOEXCEPT - { - m_call = true; - } - - //! Do not make the interface call that was expected of this class - void release() WI_NOEXCEPT - { - m_call = false; - } - - //! Returns true if the call that was expected is still outstanding - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return m_call; - } - - unique_call(const unique_call&) = delete; - unique_call& operator=(const unique_call&) = delete; - - private: - bool m_call = default_value; - }; - - // str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer. - // Overloads in this file support any string that is implicitly convertible to a PCWSTR, HSTRING, and any unique_any_t - // that points to any other supported type (this covers unique_hstring, unique_cotaskmem_string, and similar). - // An overload for std::wstring is available in stl.h. - inline PCWSTR str_raw_ptr(PCWSTR str) - { - return str; - } - - template - PCWSTR str_raw_ptr(const unique_any_t& ua) - { - return str_raw_ptr(ua.get()); - } - -#if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) - namespace details - { - // Forward declaration - template struct string_maker; - - // Concatenate any number of strings together and store it in an automatically allocated string. If a string is present - // in the input buffer, it is overwritten. - template - HRESULT str_build_nothrow(string_type& result, _In_reads_(strCount) PCWSTR* strList, size_t strCount) - { - size_t lengthRequiredWithoutNull{}; - for (auto& string : make_range(strList, strCount)) - { - lengthRequiredWithoutNull += string ? wcslen(string) : 0; - } - - details::string_maker maker; - RETURN_IF_FAILED(maker.make(nullptr, lengthRequiredWithoutNull)); - - auto buffer = maker.buffer(); - auto bufferEnd = buffer + lengthRequiredWithoutNull + 1; - for (auto& string : make_range(strList, strCount)) - { - if (string) - { - RETURN_IF_FAILED(StringCchCopyExW(buffer, (bufferEnd - buffer), string, &buffer, nullptr, STRSAFE_IGNORE_NULLS)); - } - } - - result = maker.release(); - return S_OK; - } - - // NOTE: 'Strings' must all be PCWSTR, or convertible to PCWSTR, but C++ doesn't allow us to express that cleanly - template - HRESULT str_build_nothrow(string_type& result, Strings... strings) - { - PCWSTR localStrings[] = { strings... }; - return str_build_nothrow(result, localStrings, sizeof...(Strings)); - } - } - - // Concatenate any number of strings together and store it in an automatically allocated string. If a string is present - // in the input buffer, the remaining strings are appended to it. - template - HRESULT str_concat_nothrow(string_type& buffer, const strings&... str) - { - static_assert(sizeof...(str) > 0, "attempting to concatenate no strings"); - return details::str_build_nothrow(buffer, details::string_maker::get(buffer), str_raw_ptr(str)...); - } -#endif // !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) - -#ifdef WIL_ENABLE_EXCEPTIONS - // Concatenate any number of strings together and store it in an automatically allocated string. - template - string_type str_concat(arguments&&... args) - { - string_type result{}; - THROW_IF_FAILED(str_concat_nothrow(result, wistd::forward(args)...)); - return result; - } -#endif // WIL_ENABLE_EXCEPTIONS - - // Concatenate any number of strings together and store it in an automatically allocated string. - template - string_type str_concat_failfast(arguments&&... args) - { - string_type result{}; - FAIL_FAST_IF_FAILED(str_concat_nothrow(result, wistd::forward(args)...)); - return result; - } - -#if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) - namespace details - { - // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format arguments - // that StringCchPrintfExW takes. - template - HRESULT str_vprintf_nothrow(string_type& result, _Printf_format_string_ PCWSTR pszFormat, va_list& argsVL) - { - size_t lengthRequiredWithoutNull = _vscwprintf(pszFormat, argsVL); - - string_maker maker; - RETURN_IF_FAILED(maker.make(nullptr, lengthRequiredWithoutNull)); - - auto buffer = maker.buffer(); - RETURN_IF_FAILED(StringCchVPrintfExW(buffer, lengthRequiredWithoutNull + 1, nullptr, nullptr, STRSAFE_NULL_ON_FAILURE, pszFormat, argsVL)); - - result = maker.release(); - return S_OK; - } - } - - // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format arguments - // that StringCchPrintfExW takes. - template - HRESULT str_printf_nothrow(string_type& result, _Printf_format_string_ PCWSTR pszFormat, ...) - { - va_list argsVL; - va_start(argsVL, pszFormat); - auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); - va_end(argsVL); - return hr; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format arguments - // that StringCchPrintfExW takes. - template - string_type str_printf(_Printf_format_string_ PCWSTR pszFormat, ...) - { - string_type result{}; - va_list argsVL; - va_start(argsVL, pszFormat); - auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); - va_end(argsVL); - THROW_IF_FAILED(hr); - return result; - } -#endif // WIL_ENABLE_EXCEPTIONS - - // Wraps StringCchPrintFExW and stores it in an automatically allocated string. Takes a buffer followed by the same format arguments - // that StringCchPrintfExW takes. - template - string_type str_printf_failfast(_Printf_format_string_ PCWSTR pszFormat, ...) - { - string_type result{}; - va_list argsVL; - va_start(argsVL, pszFormat); - auto hr = details::str_vprintf_nothrow(result, pszFormat, argsVL); - va_end(argsVL); - FAIL_FAST_IF_FAILED(hr); - return result; - } -#endif // !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) - -} // namespace wil -#endif // __WIL_RESOURCE - - - // Hash deferral function for unique_any_t -#if (defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && !defined(__WIL_RESOURCE_UNIQUE_HASH) -#define __WIL_RESOURCE_UNIQUE_HASH -namespace std -{ - template - struct hash> - { - WI_NODISCARD size_t operator()(wil::unique_any_t const &val) const - { - return (hash::pointer>()(val.get())); - } - }; -} -#endif - -// shared_any and weak_any implementation using STL header -#if defined(_MEMORY_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(WIL_RESOURCE_STL) && !defined(RESOURCE_SUPPRESS_STL) -#define WIL_RESOURCE_STL -namespace wil { - - template - class weak_any; - - /// @cond - namespace details - { - // This class provides the pointer storage behind the implementation of shared_any_t utilizing the given - // resource_policy. It is separate from shared_any_t to allow a type-specific specialization class to plug - // into the inheritance chain between shared_any_t and shared_storage. This allows classes like shared_event - // to be a shared_any formed class, but also expose methods like SetEvent directly. - - template - class shared_storage - { - protected: - typedef UniqueT unique_t; - typedef typename unique_t::policy policy; - typedef typename policy::pointer_storage pointer_storage; - typedef typename policy::pointer pointer; - typedef shared_storage base_storage; - - public: - shared_storage() = default; - - explicit shared_storage(pointer_storage ptr) - { - if (policy::is_valid(ptr)) - { - m_ptr = std::make_shared(unique_t(ptr)); // unique_t on the stack to prevent leak on throw - } - } - - shared_storage(unique_t &&other) - { - if (other) - { - m_ptr = std::make_shared(wistd::move(other)); - } - } - - shared_storage(const shared_storage &other) WI_NOEXCEPT : - m_ptr(other.m_ptr) - { - } - - shared_storage& operator=(const shared_storage &other) WI_NOEXCEPT - { - m_ptr = other.m_ptr; - return *this; - } - - shared_storage(shared_storage &&other) WI_NOEXCEPT : - m_ptr(wistd::move(other.m_ptr)) - { - } - - shared_storage(std::shared_ptr const &ptr) : - m_ptr(ptr) - { - } - - WI_NODISCARD bool is_valid() const WI_NOEXCEPT - { - return (m_ptr && m_ptr->is_valid()); - } - - void reset(pointer_storage ptr = policy::invalid_value()) - { - if (policy::is_valid(ptr)) - { - m_ptr = std::make_shared(unique_t(ptr)); // unique_t on the stack to prevent leak on throw - } - else - { - m_ptr = nullptr; - } - } - - void reset(unique_t &&other) - { - m_ptr = std::make_shared(wistd::move(other)); - } - - void reset(wistd::nullptr_t) WI_NOEXCEPT - { - static_assert(wistd::is_same::value, "reset(nullptr): valid only for handle types using nullptr as the invalid value"); - reset(); - } - - template ::value, int>::type = 0> - WI_NODISCARD pointer get() const WI_NOEXCEPT - { - return (m_ptr ? m_ptr->get() : policy::invalid_value()); - } - - template ::value, int>::type = 0> - pointer_storage *addressof() - { - if (!m_ptr) - { - m_ptr = std::make_shared(); - } - return m_ptr->addressof(); - } - - WI_NODISCARD long int use_count() const WI_NOEXCEPT - { - return m_ptr.use_count(); - } - - protected: - void replace(shared_storage &&other) WI_NOEXCEPT - { - m_ptr = wistd::move(other.m_ptr); - } - - private: - template - friend class ::wil::weak_any; - - std::shared_ptr m_ptr; - }; - } - /// @endcond - - // This class when paired with shared_storage and an optional type-specific specialization class implements - // the same interface as STL's shared_ptr<> for resource handle types. It is both copyable and movable, supporting - // weak references and automatic closure of the handle upon release of the last shared_any. - - template - class shared_any_t : public storage_t - { - public: - typedef typename storage_t::policy policy; - typedef typename policy::pointer_storage pointer_storage; - typedef typename policy::pointer pointer; - typedef typename storage_t::unique_t unique_t; - - // default and forwarding constructor: forwards default, all 'explicit' and multi-arg constructors to the base class - template - explicit shared_any_t(args_t&&... args) - __WI_NOEXCEPT_((wistd::is_nothrow_constructible_v)) : - storage_t(wistd::forward(args)...) - { - } - - shared_any_t(wistd::nullptr_t) WI_NOEXCEPT - { - static_assert(wistd::is_same::value, "nullptr constructor: valid only for handle types using nullptr as the invalid value"); - } - - shared_any_t(shared_any_t &&other) WI_NOEXCEPT : - storage_t(wistd::move(other)) - { - } - - shared_any_t(const shared_any_t &other) WI_NOEXCEPT : - storage_t(other) - { - } - - shared_any_t& operator=(shared_any_t &&other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - storage_t::replace(wistd::move(static_cast(other))); - } - return (*this); - } - - shared_any_t& operator=(const shared_any_t& other) WI_NOEXCEPT - { - storage_t::operator=(other); - return (*this); - } - - shared_any_t(unique_t &&other) : - storage_t(wistd::move(other)) - { - } - - shared_any_t& operator=(unique_t &&other) - { - storage_t::reset(wistd::move(other)); - return (*this); - } - - shared_any_t& operator=(wistd::nullptr_t) WI_NOEXCEPT - { - static_assert(wistd::is_same::value, "nullptr assignment: valid only for handle types using nullptr as the invalid value"); - storage_t::reset(); - return (*this); - } - - void swap(shared_any_t &other) WI_NOEXCEPT - { - shared_any_t self(wistd::move(*this)); - operator=(wistd::move(other)); - other = wistd::move(self); - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return storage_t::is_valid(); - } - - pointer_storage *put() - { - static_assert(wistd::is_same::value, "operator & is not available for this handle"); - storage_t::reset(); - return storage_t::addressof(); - } - - pointer_storage *operator&() - { - return put(); - } - - WI_NODISCARD pointer get() const WI_NOEXCEPT - { - static_assert(!wistd::is_same::value, "get(): the raw handle value is not available for this resource class"); - return storage_t::get(); - } - - // The following functions are publicly exposed by their inclusion in the base class - - // void reset(pointer_storage ptr = policy::invalid_value()) WI_NOEXCEPT - // void reset(wistd::nullptr_t) WI_NOEXCEPT - // pointer_storage *addressof() WI_NOEXCEPT // (note: not exposed for opaque resource types) - }; - - template - void swap(shared_any_t& left, shared_any_t& right) WI_NOEXCEPT - { - left.swap(right); - } - - template - bool operator==(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT - { - return (left.get() == right.get()); - } - - template - bool operator==(const shared_any_t& left, wistd::nullptr_t) WI_NOEXCEPT - { - static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); - return !left; - } - - template - bool operator==(wistd::nullptr_t, const shared_any_t& right) WI_NOEXCEPT - { - static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); - return !right; - } - - template - bool operator!=(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT - { - return (!(left.get() == right.get())); - } - - template - bool operator!=(const shared_any_t& left, wistd::nullptr_t) WI_NOEXCEPT - { - static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); - return !!left; - } - - template - bool operator!=(wistd::nullptr_t, const shared_any_t& right) WI_NOEXCEPT - { - static_assert(wistd::is_same::policy::pointer_invalid, wistd::nullptr_t>::value, "the resource class does not use nullptr as an invalid value"); - return !!right; - } - - template - bool operator<(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT - { - return (left.get() < right.get()); - } - - template - bool operator>=(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT - { - return (!(left < right)); - } - - template - bool operator>(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT - { - return (right < left); - } - - template - bool operator<=(const shared_any_t& left, const shared_any_t& right) WI_NOEXCEPT - { - return (!(right < left)); - } - - - // This class provides weak_ptr<> support for shared_any<>, bringing the same weak reference counting and lock() acquire semantics - // to shared_any. - - template - class weak_any - { - public: - typedef SharedT shared_t; - - weak_any() WI_NOEXCEPT - { - } - - weak_any(const shared_t &other) WI_NOEXCEPT : - m_weakPtr(other.m_ptr) - { - } - - weak_any(const weak_any &other) WI_NOEXCEPT : - m_weakPtr(other.m_weakPtr) - { - } - - weak_any& operator=(const weak_any &right) WI_NOEXCEPT - { - m_weakPtr = right.m_weakPtr; - return (*this); - } - - weak_any& operator=(const shared_t &right) WI_NOEXCEPT - { - m_weakPtr = right.m_ptr; - return (*this); - } - - void reset() WI_NOEXCEPT - { - m_weakPtr.reset(); - } - - void swap(weak_any &other) WI_NOEXCEPT - { - m_weakPtr.swap(other.m_weakPtr); - } - - WI_NODISCARD bool expired() const WI_NOEXCEPT - { - return m_weakPtr.expired(); - } - - WI_NODISCARD shared_t lock() const WI_NOEXCEPT - { - return shared_t(m_weakPtr.lock()); - } - - private: - std::weak_ptr m_weakPtr; - }; - - template - void swap(weak_any& left, weak_any& right) WI_NOEXCEPT - { - left.swap(right); - } - - template - using shared_any = shared_any_t>; - -} // namespace wil -#endif - - -#if defined(WIL_RESOURCE_STL) && (defined(_UNORDERED_SET_) || defined(_UNORDERED_MAP_)) && !defined(__WIL_RESOURCE_SHARED_HASH) -#define __WIL_RESOURCE_SHARED_HASH -namespace std -{ - template - struct hash> - { - WI_NODISCARD size_t operator()(wil::shared_any_t const &val) const - { - return (hash::pointer>()(val.get())); - } - }; -} -#endif - - -namespace wil -{ - -#if defined(__NOTHROW_T_DEFINED) && !defined(__WIL__NOTHROW_T_DEFINED) -#define __WIL__NOTHROW_T_DEFINED - /** Provides `std::make_unique()` semantics for resources allocated in a context that may not throw upon allocation failure. - `wil::make_unique_nothrow()` is identical to `std::make_unique()` except for the following: - * It returns `wistd::unique_ptr`, rather than `std::unique_ptr` - * It returns an empty (null) `wistd::unique_ptr` upon allocation failure, rather than throwing an exception - - Note that `wil::make_unique_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an exception-based class that may throw in its constructor. - ~~~ - auto foo = wil::make_unique_nothrow(fooConstructorParam1, fooConstructorParam2); - if (foo) - { - foo->Bar(); - } - ~~~ - */ - template - inline typename wistd::enable_if::value, wistd::unique_ptr<_Ty> >::type make_unique_nothrow(_Types&&... _Args) - { - return (wistd::unique_ptr<_Ty>(new(std::nothrow) _Ty(wistd::forward<_Types>(_Args)...))); - } - - /** Provides `std::make_unique()` semantics for array resources allocated in a context that may not throw upon allocation failure. - See the overload of `wil::make_unique_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_nothrow(size); // the default constructor will be called on each Foo object - if (foos) - { - for (auto& elem : wil::make_range(foos.get(), size)) - { - elem.Bar(); - } - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent<_Ty>::value == 0, wistd::unique_ptr<_Ty> >::type make_unique_nothrow(size_t _Size) - { - typedef typename wistd::remove_extent<_Ty>::type _Elem; - return (wistd::unique_ptr<_Ty>(new(std::nothrow) _Elem[_Size]())); - } - - template - typename wistd::enable_if::value != 0, void>::type make_unique_nothrow(_Types&&...) = delete; - -#if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) - /** Provides `std::make_unique()` semantics for resources allocated in a context that must fail fast upon allocation failure. - See the overload of `wil::make_unique_nothrow()` for non-array types for more details. - ~~~ - auto foo = wil::make_unique_failfast(fooConstructorParam1, fooConstructorParam2); - foo->Bar(); - ~~~ - */ - template - inline typename wistd::enable_if::value, wistd::unique_ptr<_Ty> >::type make_unique_failfast(_Types&&... _Args) - { -#pragma warning(suppress: 28193) // temporary must be inspected (it is within the called function) - return (wistd::unique_ptr<_Ty>(FAIL_FAST_IF_NULL_ALLOC(new(std::nothrow) _Ty(wistd::forward<_Types>(_Args)...)))); - } - - /** Provides `std::make_unique()` semantics for array resources allocated in a context that must fail fast upon allocation failure. - See the overload of `wil::make_unique_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_nothrow(size); // the default constructor will be called on each Foo object - for (auto& elem : wil::make_range(foos.get(), size)) - { - elem.Bar(); - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent<_Ty>::value == 0, wistd::unique_ptr<_Ty> >::type make_unique_failfast(size_t _Size) - { - typedef typename wistd::remove_extent<_Ty>::type _Elem; -#pragma warning(suppress: 28193) // temporary must be inspected (it is within the called function) - return (wistd::unique_ptr<_Ty>(FAIL_FAST_IF_NULL_ALLOC(new(std::nothrow) _Elem[_Size]()))); - } - - template - typename wistd::enable_if::value != 0, void>::type make_unique_failfast(_Types&&...) = delete; -#endif // !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) -#endif // __WIL__NOTHROW_T_DEFINED - -#if defined(_WINBASE_) && !defined(__WIL_WINBASE_) && !defined(WIL_KERNEL_MODE) -#define __WIL_WINBASE_ - /// @cond - namespace details - { - inline void __stdcall SetEvent(HANDLE h) WI_NOEXCEPT - { - __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::SetEvent(h)); - } - - inline void __stdcall ResetEvent(HANDLE h) WI_NOEXCEPT - { - __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ResetEvent(h)); - } - - inline void __stdcall CloseHandle(HANDLE h) WI_NOEXCEPT - { - __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::CloseHandle(h)); - } - - inline void __stdcall ReleaseSemaphore(_In_ HANDLE h) WI_NOEXCEPT - { - __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ReleaseSemaphore(h, 1, nullptr)); - } - - inline void __stdcall ReleaseMutex(_In_ HANDLE h) WI_NOEXCEPT - { - __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::ReleaseMutex(h)); - } - - inline void __stdcall CloseTokenLinkedToken(_In_ TOKEN_LINKED_TOKEN* linkedToken) WI_NOEXCEPT - { - if (linkedToken->LinkedToken && (linkedToken->LinkedToken != INVALID_HANDLE_VALUE)) - { - __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(::CloseHandle(linkedToken->LinkedToken)); - } - } - - enum class PendingCallbackCancellationBehavior - { - Cancel, - Wait, - NoWait, - }; - - template - struct DestroyThreadPoolWait - { - static void Destroy(_In_ PTP_WAIT threadPoolWait) WI_NOEXCEPT - { - ::SetThreadpoolWait(threadPoolWait, nullptr, nullptr); - ::WaitForThreadpoolWaitCallbacks(threadPoolWait, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); - ::CloseThreadpoolWait(threadPoolWait); - } - }; - - template <> - struct DestroyThreadPoolWait - { - static void Destroy(_In_ PTP_WAIT threadPoolWait) WI_NOEXCEPT - { - ::CloseThreadpoolWait(threadPoolWait); - } - }; - - template - struct DestroyThreadPoolWork - { - static void Destroy(_In_ PTP_WORK threadpoolWork) WI_NOEXCEPT - { - ::WaitForThreadpoolWorkCallbacks(threadpoolWork, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); - ::CloseThreadpoolWork(threadpoolWork); - } - }; - - template <> - struct DestroyThreadPoolWork - { - static void Destroy(_In_ PTP_WORK threadpoolWork) WI_NOEXCEPT - { - ::CloseThreadpoolWork(threadpoolWork); - } - }; - - // Non-RTL implementation for threadpool_t parameter of DestroyThreadPoolTimer<> - struct SystemThreadPoolMethods - { - static void WINAPI SetThreadpoolTimer(_Inout_ PTP_TIMER Timer, _In_opt_ PFILETIME DueTime, _In_ DWORD Period, _In_ DWORD WindowLength) WI_NOEXCEPT - { - ::SetThreadpoolTimer(Timer, DueTime, Period, WindowLength); - } - static void WaitForThreadpoolTimerCallbacks(_Inout_ PTP_TIMER Timer, _In_ BOOL CancelPendingCallbacks) WI_NOEXCEPT - { - ::WaitForThreadpoolTimerCallbacks(Timer, CancelPendingCallbacks); - } - static void CloseThreadpoolTimer(_Inout_ PTP_TIMER Timer) WI_NOEXCEPT - { - ::CloseThreadpoolTimer(Timer); - } - }; - - // SetThreadpoolTimer(timer, nullptr, 0, 0) will cancel any pending callbacks, - // then CloseThreadpoolTimer will asynchronusly close the timer if a callback is running. - template - struct DestroyThreadPoolTimer - { - static void Destroy(_In_ PTP_TIMER threadpoolTimer) WI_NOEXCEPT - { - threadpool_t::SetThreadpoolTimer(threadpoolTimer, nullptr, 0, 0); -#pragma warning(suppress:4127) // conditional expression is constant - if (cancellationBehavior != PendingCallbackCancellationBehavior::NoWait) - { - threadpool_t::WaitForThreadpoolTimerCallbacks(threadpoolTimer, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); - } - threadpool_t::CloseThreadpoolTimer(threadpoolTimer); - } - }; - - // PendingCallbackCancellationBehavior::NoWait explicitly does not block waiting for - // callbacks when destructing. - template - struct DestroyThreadPoolTimer - { - static void Destroy(_In_ PTP_TIMER threadpoolTimer) WI_NOEXCEPT - { - threadpool_t::CloseThreadpoolTimer(threadpoolTimer); - } - }; - - template - struct DestroyThreadPoolIo - { - static void Destroy(_In_ PTP_IO threadpoolIo) WI_NOEXCEPT - { - ::WaitForThreadpoolIoCallbacks(threadpoolIo, (cancellationBehavior == PendingCallbackCancellationBehavior::Cancel)); - ::CloseThreadpoolIo(threadpoolIo); - } - }; - - template <> - struct DestroyThreadPoolIo - { - static void Destroy(_In_ PTP_IO threadpoolIo) WI_NOEXCEPT - { - ::CloseThreadpoolIo(threadpoolIo); - } - }; - - template - struct handle_invalid_resource_policy : resource_policy - { - __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT { return ((ptr != INVALID_HANDLE_VALUE) && (ptr != nullptr)); } - }; - - template - struct handle_null_resource_policy : resource_policy - { - __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT { return ((ptr != nullptr) && (ptr != INVALID_HANDLE_VALUE)); } - }; - - template - struct handle_null_only_resource_policy : resource_policy - { - __forceinline static bool is_valid(HANDLE ptr) WI_NOEXCEPT { return (ptr != nullptr); } - }; - - typedef resource_policy handle_resource_policy; - } - /// @endcond - - template - using unique_any_handle_invalid = unique_any_t>>; - - template - using unique_any_handle_null = unique_any_t>>; - - template - using unique_any_handle_null_only = unique_any_t>>; - - typedef unique_any_handle_invalid unique_hfile; - typedef unique_any_handle_null unique_handle; - typedef unique_any_handle_invalid unique_hfind; - typedef unique_any unique_hmodule; - typedef unique_any_handle_null_only unique_process_handle; - - typedef unique_struct unique_token_linked_token; - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) - typedef unique_any unique_sid; - typedef unique_any_handle_null_only unique_boundary_descriptor; - - namespace details - { - template - inline void __stdcall ClosePrivateNamespaceHelper(HANDLE h) WI_NOEXCEPT - { - ::ClosePrivateNamespace(h, flags); - } - } - - template - using unique_private_namespace = unique_any_handle_null_only>; - - using unique_private_namespace_close = unique_private_namespace<>; - using unique_private_namespace_destroy = unique_private_namespace; -#endif - - using unique_tool_help_snapshot = unique_hfile; - - typedef unique_any::Destroy> unique_threadpool_wait; - typedef unique_any::Destroy> unique_threadpool_wait_nocancel; - typedef unique_any::Destroy> unique_threadpool_wait_nowait; - typedef unique_any::Destroy> unique_threadpool_work; - typedef unique_any::Destroy> unique_threadpool_work_nocancel; - typedef unique_any::Destroy> unique_threadpool_work_nowait; - typedef unique_any::Destroy> unique_threadpool_timer; - typedef unique_any::Destroy> unique_threadpool_timer_nocancel; - typedef unique_any::Destroy> unique_threadpool_timer_nowait; - typedef unique_any::Destroy> unique_threadpool_io; - typedef unique_any::Destroy> unique_threadpool_io_nocancel; - typedef unique_any::Destroy> unique_threadpool_io_nowait; - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - typedef unique_any_handle_invalid unique_hfind_change; -#endif - - typedef unique_any event_set_scope_exit; - typedef unique_any event_reset_scope_exit; - - // Guarantees a SetEvent on the given event handle when the returned object goes out of scope - // Note: call SetEvent early with the reset() method on the returned object or abort the call with the release() method - WI_NODISCARD inline event_set_scope_exit SetEvent_scope_exit(HANDLE hEvent) WI_NOEXCEPT - { - __FAIL_FAST_ASSERT__(hEvent != nullptr); - return event_set_scope_exit(hEvent); - } - - // Guarantees a ResetEvent on the given event handle when the returned object goes out of scope - // Note: call ResetEvent early with the reset() method on the returned object or abort the call with the release() method - WI_NODISCARD inline event_reset_scope_exit ResetEvent_scope_exit(HANDLE hEvent) WI_NOEXCEPT - { - __FAIL_FAST_ASSERT__(hEvent != nullptr); - return event_reset_scope_exit(hEvent); - } - - // Checks to see if the given *manual reset* event is currently signaled. The event must not be an auto-reset event. - // Use when the event will only be set once (cancellation-style) or will only be reset by the polling thread - inline bool event_is_signaled(HANDLE hEvent) WI_NOEXCEPT - { - auto status = ::WaitForSingleObjectEx(hEvent, 0, FALSE); - // Fast fail will trip for wait failures, auto-reset events, or when the event is being both Set and Reset - // from a thread other than the polling thread (use event_wait directly for those cases). - __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || ((status == WAIT_OBJECT_0) && (WAIT_OBJECT_0 == ::WaitForSingleObjectEx(hEvent, 0, FALSE)))); - return (status == WAIT_OBJECT_0); - } - - // Waits on the given handle for the specified duration - inline bool handle_wait(HANDLE hEvent, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) WI_NOEXCEPT - { - DWORD status = ::WaitForSingleObjectEx(hEvent, dwMilliseconds, bAlertable); - __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || (bAlertable && (status == WAIT_IO_COMPLETION))); - return (status == WAIT_OBJECT_0); - } - - enum class EventOptions - { - None = 0x0, - ManualReset = 0x1, - Signaled = 0x2 - }; - DEFINE_ENUM_FLAG_OPERATORS(EventOptions); - - template - class event_t : public storage_t - { - public: - // forward all base class constructors... - template - explicit event_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} - - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Exception-based constructor to create an unnamed event - event_t(EventOptions options) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); - create(options); - } - - void ResetEvent() const WI_NOEXCEPT - { - details::ResetEvent(storage_t::get()); - } - - void SetEvent() const WI_NOEXCEPT - { - details::SetEvent(storage_t::get()); - } - - // Guarantees a SetEvent on the given event handle when the returned object goes out of scope - // Note: call SetEvent early with the reset() method on the returned object or abort the call with the release() method - WI_NODISCARD event_set_scope_exit SetEvent_scope_exit() const WI_NOEXCEPT - { - return wil::SetEvent_scope_exit(storage_t::get()); - } - - // Guarantees a ResetEvent on the given event handle when the returned object goes out of scope - // Note: call ResetEvent early with the reset() method on the returned object or abort the call with the release() method - WI_NODISCARD event_reset_scope_exit ResetEvent_scope_exit() const WI_NOEXCEPT - { - return wil::ResetEvent_scope_exit(storage_t::get()); - } - - // Checks if a *manual reset* event is currently signaled. The event must not be an auto-reset event. - // Use when the event will only be set once (cancellation-style) or will only be reset by the polling thread - WI_NODISCARD bool is_signaled() const WI_NOEXCEPT - { - return wil::event_is_signaled(storage_t::get()); - } - - // Basic WaitForSingleObject on the event handle with the given timeout - bool wait(DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) const WI_NOEXCEPT - { - return wil::handle_wait(storage_t::get(), dwMilliseconds, bAlertable); - } - - // Tries to create a named event -- returns false if unable to do so (gle may still be inspected with return=false) - bool try_create(EventOptions options, PCWSTR name, _In_opt_ LPSECURITY_ATTRIBUTES securityAttributes = nullptr, _Out_opt_ bool *alreadyExists = nullptr) - { - auto handle = ::CreateEventExW(securityAttributes, name, (WI_IsFlagSet(options, EventOptions::ManualReset) ? CREATE_EVENT_MANUAL_RESET : 0) | (WI_IsFlagSet(options, EventOptions::Signaled) ? CREATE_EVENT_INITIAL_SET : 0), EVENT_ALL_ACCESS); - if (!handle) - { - assign_to_opt_param(alreadyExists, false); - return false; - } - assign_to_opt_param(alreadyExists, (::GetLastError() == ERROR_ALREADY_EXISTS)); - storage_t::reset(handle); - return true; - } - - // Returns HRESULT for unique_event_nothrow, void with exceptions for shared_event and unique_event - result create(EventOptions options = EventOptions::None, PCWSTR name = nullptr, _In_opt_ LPSECURITY_ATTRIBUTES securityAttributes = nullptr, _Out_opt_ bool *alreadyExists = nullptr) - { - return err_policy::LastErrorIfFalse(try_create(options, name, securityAttributes, alreadyExists)); - } - - // Tries to open the named event -- returns false if unable to do so (gle may still be inspected with return=false) - bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE, bool inheritHandle = false) - { - auto handle = ::OpenEventW(desiredAccess, inheritHandle, name); - if (handle == nullptr) - { - return false; - } - storage_t::reset(handle); - return true; - } - - // Returns HRESULT for unique_event_nothrow, void with exceptions for shared_event and unique_event - result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | EVENT_MODIFY_STATE, bool inheritHandle = false) - { - return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); - } - }; - - typedef unique_any_t, err_returncode_policy>> unique_event_nothrow; - typedef unique_any_t, err_failfast_policy>> unique_event_failfast; -#ifdef WIL_ENABLE_EXCEPTIONS - typedef unique_any_t, err_exception_policy>> unique_event; -#endif - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && ((_WIN32_WINNT >= _WIN32_WINNT_WIN8) || (__WIL_RESOURCE_ENABLE_QUIRKS && (_WIN32_WINNT >= _WIN32_WINNT_WIN7))) - enum class SlimEventType - { - AutoReset, - ManualReset, - }; - - /** A lean and mean event class. - This class provides a very similar API to `wil::unique_event` but doesn't require a kernel object. - - The two variants of this class are: - - `wil::slim_event_auto_reset` - - `wil::slim_event_manual_reset` - - In addition, `wil::slim_event_auto_reset` has the alias `wil::slim_event`. - - Some key differences to `wil::unique_event` include: - - There is no 'create()' function, as initialization occurs in the constructor and can't fail. - - The move functions have been deleted. - - For auto-reset events, the `is_signaled()` function doesn't reset the event. (Use `ResetEvent()` instead.) - - The `ResetEvent()` function returns the previous state of the event. - - To create a manual reset event, use `wil::slim_event_manual_reset'. - ~~~~ - wil::slim_event finished; - std::thread doStuff([&finished] () { - Sleep(10); - finished.SetEvent(); - }); - finished.wait(); - - std::shared_ptr CreateSharedEvent(bool startSignaled) - { - return std::make_shared(startSignaled); - } - ~~~~ */ - template - class slim_event_t - { - public: - slim_event_t() WI_NOEXCEPT = default; - - slim_event_t(bool isSignaled) WI_NOEXCEPT : - m_isSignaled(isSignaled ? TRUE : FALSE) - { - } - - // Cannot change memory location. - slim_event_t(const slim_event_t&) = delete; - slim_event_t(slim_event_t&&) = delete; - slim_event_t& operator=(const slim_event_t&) = delete; - slim_event_t& operator=(slim_event_t&&) = delete; - - // Returns the previous state of the event. - bool ResetEvent() WI_NOEXCEPT - { - return !!InterlockedExchange(&m_isSignaled, FALSE); - } - - void SetEvent() WI_NOEXCEPT - { - // FYI: 'WakeByAddress*' invokes a full memory barrier. - WriteRelease(&m_isSignaled, TRUE); - - #pragma warning(suppress:4127) // conditional expression is constant - if (Type == SlimEventType::AutoReset) - { - WakeByAddressSingle(&m_isSignaled); - } - else - { - WakeByAddressAll(&m_isSignaled); - } - } - - // Checks if the event is currently signaled. - // Note: Unlike Win32 auto-reset event objects, this will not reset the event. - WI_NODISCARD bool is_signaled() const WI_NOEXCEPT - { - return !!ReadAcquire(&m_isSignaled); - } - - bool wait(DWORD timeoutMiliseconds) WI_NOEXCEPT - { - if (timeoutMiliseconds == 0) - { - return TryAcquireEvent(); - } - else if (timeoutMiliseconds == INFINITE) - { - return wait(); - } - - UINT64 startTime{}; - QueryUnbiasedInterruptTime(&startTime); - - UINT64 elapsedTimeMilliseconds = 0; - - while (!TryAcquireEvent()) - { - if (elapsedTimeMilliseconds >= timeoutMiliseconds) - { - return false; - } - - DWORD newTimeout = static_cast(timeoutMiliseconds - elapsedTimeMilliseconds); - - if (!WaitForSignal(newTimeout)) - { - return false; - } - - UINT64 currTime; - QueryUnbiasedInterruptTime(&currTime); - - elapsedTimeMilliseconds = (currTime - startTime) / static_cast(10 * 1000); - } - - return true; - } - - bool wait() WI_NOEXCEPT - { - while (!TryAcquireEvent()) - { - if (!WaitForSignal(INFINITE)) - { - return false; - } - } - - return true; - } - - private: - bool TryAcquireEvent() WI_NOEXCEPT - { - #pragma warning(suppress:4127) // conditional expression is constant - if (Type == SlimEventType::AutoReset) - { - return ResetEvent(); - } - else - { - return is_signaled(); - } - } - - bool WaitForSignal(DWORD timeoutMiliseconds) WI_NOEXCEPT - { - LONG falseValue = FALSE; - BOOL waitResult = WaitOnAddress(&m_isSignaled, &falseValue, sizeof(m_isSignaled), timeoutMiliseconds); - __FAIL_FAST_ASSERT__(waitResult || ::GetLastError() == ERROR_TIMEOUT); - return !!waitResult; - } - - LONG m_isSignaled = FALSE; - }; - - /** An event object that will atomically revert to an unsignaled state anytime a `wait()` call succeeds (i.e. returns true). */ - using slim_event_auto_reset = slim_event_t; - - /** An event object that once signaled remains that way forever, unless `ResetEvent()` is called. */ - using slim_event_manual_reset = slim_event_t; - - /** An alias for `wil::slim_event_auto_reset`. */ - using slim_event = slim_event_auto_reset; - -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - - typedef unique_any mutex_release_scope_exit; - - WI_NODISCARD inline mutex_release_scope_exit ReleaseMutex_scope_exit(_In_ HANDLE hMutex) WI_NOEXCEPT - { - __FAIL_FAST_ASSERT__(hMutex != nullptr); - return mutex_release_scope_exit(hMutex); - } - - // For efficiency, avoid using mutexes when an srwlock or condition variable will do. - template - class mutex_t : public storage_t - { - public: - // forward all base class constructors... - template - explicit mutex_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} - - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Exception-based constructor to create a mutex (prefer unnamed (nullptr) for the name) - mutex_t(_In_opt_ PCWSTR name) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); - create(name); - } - - void ReleaseMutex() const WI_NOEXCEPT - { - details::ReleaseMutex(storage_t::get()); - } - - WI_NODISCARD mutex_release_scope_exit ReleaseMutex_scope_exit() const WI_NOEXCEPT - { - return wil::ReleaseMutex_scope_exit(storage_t::get()); - } - - WI_NODISCARD mutex_release_scope_exit acquire(_Out_opt_ DWORD *pStatus = nullptr, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) const WI_NOEXCEPT - { - auto handle = storage_t::get(); - DWORD status = ::WaitForSingleObjectEx(handle, dwMilliseconds, bAlertable); - assign_to_opt_param(pStatus, status); - __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || (status == WAIT_ABANDONED) || (bAlertable && (status == WAIT_IO_COMPLETION))); - return mutex_release_scope_exit(((status == WAIT_OBJECT_0) || (status == WAIT_ABANDONED)) ? handle : nullptr); - } - - // Tries to create a named mutex -- returns false if unable to do so (gle may still be inspected with return=false) - bool try_create(_In_opt_ PCWSTR name, DWORD dwFlags = 0, DWORD desiredAccess = MUTEX_ALL_ACCESS, - _In_opt_ PSECURITY_ATTRIBUTES mutexAttributes = nullptr, _Out_opt_ bool* alreadyExists = nullptr) - { - auto handle = ::CreateMutexExW(mutexAttributes, name, dwFlags, desiredAccess); - if (handle == nullptr) - { - assign_to_opt_param(alreadyExists, false); - return false; - } - assign_to_opt_param(alreadyExists, (::GetLastError() == ERROR_ALREADY_EXISTS)); - storage_t::reset(handle); - return true; - } - - // Returns HRESULT for unique_mutex_nothrow, void with exceptions for shared_mutex and unique_mutex - result create(_In_opt_ PCWSTR name = nullptr, DWORD dwFlags = 0, DWORD desiredAccess = MUTEX_ALL_ACCESS, - _In_opt_ PSECURITY_ATTRIBUTES mutexAttributes = nullptr, _Out_opt_ bool* alreadyExists = nullptr) - { - return err_policy::LastErrorIfFalse(try_create(name, dwFlags, desiredAccess, mutexAttributes, alreadyExists)); - } - - // Tries to open a named mutex -- returns false if unable to do so (gle may still be inspected with return=false) - bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, bool inheritHandle = false) - { - auto handle = ::OpenMutexW(desiredAccess, inheritHandle, name); - if (handle == nullptr) - { - return false; - } - storage_t::reset(handle); - return true; - } - - // Returns HRESULT for unique_mutex_nothrow, void with exceptions for shared_mutex and unique_mutex - result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, bool inheritHandle = false) - { - return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); - } - }; - - typedef unique_any_t, err_returncode_policy>> unique_mutex_nothrow; - typedef unique_any_t, err_failfast_policy>> unique_mutex_failfast; -#ifdef WIL_ENABLE_EXCEPTIONS - typedef unique_any_t, err_exception_policy>> unique_mutex; -#endif - - typedef unique_any semaphore_release_scope_exit; - - WI_NODISCARD inline semaphore_release_scope_exit ReleaseSemaphore_scope_exit(_In_ HANDLE hSemaphore) WI_NOEXCEPT - { - __FAIL_FAST_ASSERT__(hSemaphore != nullptr); - return semaphore_release_scope_exit(hSemaphore); - } - - template - class semaphore_t : public storage_t - { - public: - // forward all base class constructors... - template - explicit semaphore_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} - - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Note that for custom-constructors the type given the constructor has to match exactly as not all implicit conversions will make it through the - // forwarding constructor. This constructor, for example, uses 'int' instead of 'LONG' as the count to ease that particular issue (const numbers are int by default). - explicit semaphore_t(int initialCount, int maximumCount, _In_opt_ PCWSTR name = nullptr, DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); - create(initialCount, maximumCount, name, desiredAccess, pSemaphoreAttributes); - } - - void ReleaseSemaphore(long nReleaseCount = 1, _In_opt_ long *pnPreviousCount = nullptr) WI_NOEXCEPT - { - long nPreviousCount = 0; - __FAIL_FAST_ASSERT__(::ReleaseSemaphore(storage_t::get(), nReleaseCount, &nPreviousCount)); - assign_to_opt_param(pnPreviousCount, nPreviousCount); - } - - WI_NODISCARD semaphore_release_scope_exit ReleaseSemaphore_scope_exit() WI_NOEXCEPT - { - return wil::ReleaseSemaphore_scope_exit(storage_t::get()); - } - - WI_NODISCARD semaphore_release_scope_exit acquire(_Out_opt_ DWORD *pStatus = nullptr, DWORD dwMilliseconds = INFINITE, BOOL bAlertable = FALSE) WI_NOEXCEPT - { - auto handle = storage_t::get(); - DWORD status = ::WaitForSingleObjectEx(handle, dwMilliseconds, bAlertable); - assign_to_opt_param(pStatus, status); - __FAIL_FAST_ASSERT__((status == WAIT_TIMEOUT) || (status == WAIT_OBJECT_0) || (bAlertable && (status == WAIT_IO_COMPLETION))); - return semaphore_release_scope_exit((status == WAIT_OBJECT_0) ? handle : nullptr); - } - - // Tries to create a named event -- returns false if unable to do so (gle may still be inspected with return=false) - bool try_create(LONG lInitialCount, LONG lMaximumCount, _In_opt_ PCWSTR name, DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr, _Out_opt_ bool *alreadyExists = nullptr) - { - auto handle = ::CreateSemaphoreExW(pSemaphoreAttributes, lInitialCount, lMaximumCount, name, 0, desiredAccess); - if (handle == nullptr) - { - assign_to_opt_param(alreadyExists, false); - return false; - } - assign_to_opt_param(alreadyExists, (::GetLastError() == ERROR_ALREADY_EXISTS)); - storage_t::reset(handle); - return true; - } - - // Returns HRESULT for unique_semaphore_nothrow, void with exceptions for shared_event and unique_event - result create(LONG lInitialCount, LONG lMaximumCount, _In_opt_ PCWSTR name = nullptr, DWORD desiredAccess = SEMAPHORE_ALL_ACCESS, _In_opt_ PSECURITY_ATTRIBUTES pSemaphoreAttributes = nullptr, _Out_opt_ bool *alreadyExists = nullptr) - { - return err_policy::LastErrorIfFalse(try_create(lInitialCount, lMaximumCount, name, desiredAccess, pSemaphoreAttributes, alreadyExists)); - } - - // Tries to open the named semaphore -- returns false if unable to do so (gle may still be inspected with return=false) - bool try_open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, bool inheritHandle = false) - { - auto handle = ::OpenSemaphoreW(desiredAccess, inheritHandle, name); - if (handle == nullptr) - { - return false; - } - storage_t::reset(handle); - return true; - } - - // Returns HRESULT for unique_semaphore_nothrow, void with exceptions for shared_semaphore and unique_semaphore - result open(_In_ PCWSTR name, DWORD desiredAccess = SYNCHRONIZE | SEMAPHORE_MODIFY_STATE, bool inheritHandle = false) - { - return err_policy::LastErrorIfFalse(try_open(name, desiredAccess, inheritHandle)); - } - }; - - typedef unique_any_t, err_returncode_policy>> unique_semaphore_nothrow; - typedef unique_any_t, err_failfast_policy>> unique_semaphore_failfast; -#ifdef WIL_ENABLE_EXCEPTIONS - typedef unique_any_t, err_exception_policy>> unique_semaphore; -#endif - - typedef unique_any rwlock_release_exclusive_scope_exit; - typedef unique_any rwlock_release_shared_scope_exit; - - WI_NODISCARD inline rwlock_release_exclusive_scope_exit AcquireSRWLockExclusive(_Inout_ SRWLOCK *plock) WI_NOEXCEPT - { - ::AcquireSRWLockExclusive(plock); - return rwlock_release_exclusive_scope_exit(plock); - } - - WI_NODISCARD inline rwlock_release_shared_scope_exit AcquireSRWLockShared(_Inout_ SRWLOCK *plock) WI_NOEXCEPT - { - ::AcquireSRWLockShared(plock); - return rwlock_release_shared_scope_exit(plock); - } - - WI_NODISCARD inline rwlock_release_exclusive_scope_exit TryAcquireSRWLockExclusive(_Inout_ SRWLOCK *plock) WI_NOEXCEPT - { - return rwlock_release_exclusive_scope_exit(::TryAcquireSRWLockExclusive(plock) ? plock : nullptr); - } - - WI_NODISCARD inline rwlock_release_shared_scope_exit TryAcquireSRWLockShared(_Inout_ SRWLOCK *plock) WI_NOEXCEPT - { - return rwlock_release_shared_scope_exit(::TryAcquireSRWLockShared(plock) ? plock : nullptr); - } - - class srwlock - { - public: - srwlock(const srwlock&) = delete; - srwlock(srwlock&&) = delete; - srwlock& operator=(const srwlock&) = delete; - srwlock& operator=(srwlock&&) = delete; - - srwlock() = default; - - WI_NODISCARD rwlock_release_exclusive_scope_exit lock_exclusive() WI_NOEXCEPT - { - return wil::AcquireSRWLockExclusive(&m_lock); - } - - WI_NODISCARD rwlock_release_exclusive_scope_exit try_lock_exclusive() WI_NOEXCEPT - { - return wil::TryAcquireSRWLockExclusive(&m_lock); - } - - WI_NODISCARD rwlock_release_shared_scope_exit lock_shared() WI_NOEXCEPT - { - return wil::AcquireSRWLockShared(&m_lock); - } - - WI_NODISCARD rwlock_release_shared_scope_exit try_lock_shared() WI_NOEXCEPT - { - return wil::TryAcquireSRWLockShared(&m_lock); - } - - private: - SRWLOCK m_lock = SRWLOCK_INIT; - }; - - typedef unique_any cs_leave_scope_exit; - - WI_NODISCARD inline cs_leave_scope_exit EnterCriticalSection(_Inout_ CRITICAL_SECTION *pcs) WI_NOEXCEPT - { - ::EnterCriticalSection(pcs); - return cs_leave_scope_exit(pcs); - } - - WI_NODISCARD inline cs_leave_scope_exit TryEnterCriticalSection(_Inout_ CRITICAL_SECTION *pcs) WI_NOEXCEPT - { - return cs_leave_scope_exit(::TryEnterCriticalSection(pcs) ? pcs : nullptr); - } - - // Critical sections are worse than srwlocks in performance and memory usage (their only unique attribute - // being recursive acquisition). Prefer srwlocks over critical sections when you don't need recursive acquisition. - class critical_section - { - public: - critical_section(const critical_section&) = delete; - critical_section(critical_section&&) = delete; - critical_section& operator=(const critical_section&) = delete; - critical_section& operator=(critical_section&&) = delete; - - critical_section(ULONG spincount = 0) WI_NOEXCEPT - { - // Initialization will not fail without invalid params... - ::InitializeCriticalSectionEx(&m_cs, spincount, 0); - } - - ~critical_section() WI_NOEXCEPT - { - ::DeleteCriticalSection(&m_cs); - } - - WI_NODISCARD cs_leave_scope_exit lock() WI_NOEXCEPT - { - return wil::EnterCriticalSection(&m_cs); - } - - WI_NODISCARD cs_leave_scope_exit try_lock() WI_NOEXCEPT - { - return wil::TryEnterCriticalSection(&m_cs); - } - - private: - CRITICAL_SECTION m_cs; - }; - - class condition_variable - { - public: - condition_variable(const condition_variable&) = delete; - condition_variable(condition_variable&&) = delete; - condition_variable& operator=(const condition_variable&) = delete; - condition_variable& operator=(condition_variable&&) = delete; - - condition_variable() = default; - - void notify_one() WI_NOEXCEPT - { - ::WakeConditionVariable(&m_cv); - } - - void notify_all() WI_NOEXCEPT - { - ::WakeAllConditionVariable(&m_cv); - } - - void wait(const cs_leave_scope_exit& lock) WI_NOEXCEPT - { - wait_for(lock, INFINITE); - } - - void wait(const rwlock_release_exclusive_scope_exit& lock) WI_NOEXCEPT - { - wait_for(lock, INFINITE); - } - - void wait(const rwlock_release_shared_scope_exit& lock) WI_NOEXCEPT - { - wait_for(lock, INFINITE); - } - - bool wait_for(const cs_leave_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT - { - bool result = !!::SleepConditionVariableCS(&m_cv, lock.get(), timeoutMs); - __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); - return result; - } - - bool wait_for(const rwlock_release_exclusive_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT - { - bool result = !!::SleepConditionVariableSRW(&m_cv, lock.get(), timeoutMs, 0); - __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); - return result; - } - - bool wait_for(const rwlock_release_shared_scope_exit& lock, DWORD timeoutMs) WI_NOEXCEPT - { - bool result = !!::SleepConditionVariableSRW(&m_cv, lock.get(), timeoutMs, CONDITION_VARIABLE_LOCKMODE_SHARED); - __FAIL_FAST_ASSERT__(result || ::GetLastError() == ERROR_TIMEOUT); - return result; - } - - private: - CONDITION_VARIABLE m_cv = CONDITION_VARIABLE_INIT; - }; - - /// @cond - namespace details - { - template struct string_allocator - { - static void* allocate(size_t /*size*/) WI_NOEXCEPT - { - static_assert(!wistd::is_same::value, "This type did not provide a string_allocator, add a specialization of string_allocator to support your type."); - return nullptr; - } - }; - } - /// @endcond - - // This string helper does not support the ansi wil string helpers - template - PCWSTR string_get_not_null(const string_type& string) - { - return string ? string.get() : L""; - } - -#ifndef MAKE_UNIQUE_STRING_MAX_CCH -#define MAKE_UNIQUE_STRING_MAX_CCH 2147483647 // max buffer size, in characters, that we support (same as INT_MAX) -#endif - - /** Copies a string (up to the given length) into memory allocated with a specified allocator returning null on failure. - Use `wil::make_unique_string_nothrow()` for string resources returned from APIs that must satisfy a memory allocation contract - that requires use of a specific allocator and free function (CoTaskMemAlloc/CoTaskMemFree, LocalAlloc/LocalFree, GlobalAlloc/GlobalFree, etc.). - ~~~ - auto str = wil::make_unique_string_nothrow(L"a string of words", 8); - RETURN_IF_NULL_ALLOC(str); - std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" - - auto str = wil::make_unique_string_nothrow(L"a string"); - RETURN_IF_NULL_ALLOC(str); - std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" - - NOTE: If source is not null terminated, then length MUST be equal to or less than the size - of the buffer pointed to by source. - ~~~ - */ - template string_type make_unique_string_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - const wchar_t* source, size_t length = static_cast(-1)) WI_NOEXCEPT - { - // guard against invalid parameters (null source with -1 length) - FAIL_FAST_IF(!source && (length == static_cast(-1))); - - // When the source string exists, calculate the number of characters to copy up to either - // 1) the length that is given - // 2) the length of the source string. When the source does not exist, use the given length - // for calculating both the size of allocated buffer and the number of characters to copy. - size_t lengthToCopy = length; - if (source) - { - size_t maxLength = length < MAKE_UNIQUE_STRING_MAX_CCH ? length : MAKE_UNIQUE_STRING_MAX_CCH; - PCWSTR endOfSource = source; - while (maxLength && (*endOfSource != L'\0')) - { - endOfSource++; - maxLength--; - } - lengthToCopy = endOfSource - source; - } - - if (length == static_cast(-1)) - { - length = lengthToCopy; - } - const size_t allocatedBytes = (length + 1) * sizeof(*source); - auto result = static_cast(details::string_allocator::allocate(allocatedBytes)); - - if (result) - { - if (source) - { - const size_t bytesToCopy = lengthToCopy * sizeof(*source); - memcpy_s(result, allocatedBytes, source, bytesToCopy); - result[lengthToCopy] = L'\0'; // ensure the copied string is zero terminated - } - else - { - *result = L'\0'; // ensure null terminated in the "reserve space" use case. - } - result[length] = L'\0'; // ensure the final char of the buffer is zero terminated - } - return string_type(result); - } -#ifndef WIL_NO_ANSI_STRINGS - template string_type make_unique_ansistring_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT - { - if (length == static_cast(-1)) - { - // guard against invalid parameters (null source with -1 length) - FAIL_FAST_IF(!source); - length = strlen(source); - } - const size_t cb = (length + 1) * sizeof(*source); - auto result = static_cast(details::string_allocator::allocate(cb)); - if (result) - { - if (source) - { - memcpy_s(result, cb, source, cb - sizeof(*source)); - } - else - { - *result = '\0'; // ensure null terminated in the "reserve space" use case. - } - result[length] = '\0'; // ensure zero terminated - } - return string_type(result); - } -#endif // WIL_NO_ANSI_STRINGS - - /** Copies a given string into memory allocated with a specified allocator that will fail fast on failure. - The use of variadic templates parameters supports the 2 forms of make_unique_string, see those for more details. - */ - template string_type make_unique_string_failfast( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT - { - auto result(make_unique_string_nothrow(source, length)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; - } - -#ifndef WIL_NO_ANSI_STRINGS - template string_type make_unique_ansistring_failfast( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT - { - auto result(make_unique_ansistring_nothrow(source, length)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; - } -#endif // WIL_NO_ANSI_STRINGS - -#ifdef WIL_ENABLE_EXCEPTIONS - /** Copies a given string into memory allocated with a specified allocator that will throw on failure. - The use of variadic templates parameters supports the 2 forms of make_unique_string, see those for more details. - */ - template string_type make_unique_string( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCWSTR source, size_t length = static_cast(-1)) - { - auto result(make_unique_string_nothrow(source, length)); - THROW_IF_NULL_ALLOC(result); - return result; - } -#ifndef WIL_NO_ANSI_STRINGS - template string_type make_unique_ansistring( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCSTR source, size_t length = static_cast(-1)) - { - auto result(make_unique_ansistring_nothrow(source, length)); - THROW_IF_NULL_ALLOC(result); - return result; - } -#endif // WIL_NO_ANSI_STRINGS -#endif // WIL_ENABLE_EXCEPTIONS - - /// @cond - namespace details - { - // string_maker abstracts creating a string for common string types. This form supports the - // wil::unique_xxx_string types. Specializations of other types like HSTRING and std::wstring - // are found in wil\winrt.h and wil\stl.h. - // This design supports creating the string in a single step or using two phase construction. - - template struct string_maker - { - HRESULT make( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - const wchar_t* source, - size_t length) - { - m_value = make_unique_string_nothrow(source, length); - return m_value ? S_OK : E_OUTOFMEMORY; - } - - wchar_t* buffer() { WI_ASSERT(m_value.get()); return m_value.get(); } - - // By default, assume string_type is a null-terminated string and therefore does not require trimming. - HRESULT trim_at_existing_null(size_t /* length */) { return S_OK; } - - string_type release() { return wistd::move(m_value); } - - // Utility to abstract access to the null terminated m_value of all string types. - static PCWSTR get(const string_type& value) { return value.get(); } - - private: - string_type m_value; // a wil::unique_xxx_string type. - }; - - struct SecureZeroData - { - void *pointer; - size_t sizeBytes; - SecureZeroData(void *pointer_, size_t sizeBytes_ = 0) WI_NOEXCEPT { pointer = pointer_; sizeBytes = sizeBytes_; } - WI_NODISCARD operator void*() const WI_NOEXCEPT { return pointer; } - static void Close(SecureZeroData data) WI_NOEXCEPT { ::SecureZeroMemory(data.pointer, data.sizeBytes); } - }; - } - /// @endcond - - typedef unique_any secure_zero_memory_scope_exit; - - WI_NODISCARD inline secure_zero_memory_scope_exit SecureZeroMemory_scope_exit(_In_reads_bytes_(sizeBytes) void* pSource, size_t sizeBytes) - { - return secure_zero_memory_scope_exit(details::SecureZeroData(pSource, sizeBytes)); - } - - WI_NODISCARD inline secure_zero_memory_scope_exit SecureZeroMemory_scope_exit(_In_ PWSTR initializedString) - { - return SecureZeroMemory_scope_exit(static_cast(initializedString), wcslen(initializedString) * sizeof(initializedString[0])); - } - - /// @cond - namespace details - { - inline void __stdcall FreeProcessHeap(_Pre_opt_valid_ _Frees_ptr_opt_ void* p) - { - ::HeapFree(::GetProcessHeap(), 0, p); - } - } - /// @endcond - - struct process_heap_deleter - { - template - void operator()(_Pre_valid_ _Frees_ptr_ T* p) const - { - details::FreeProcessHeap(p); - } - }; - - struct virtualalloc_deleter - { - template - void operator()(_Pre_valid_ _Frees_ptr_ T* p) const - { - ::VirtualFree(p, 0, MEM_RELEASE); - } - }; - - struct mapview_deleter - { - template - void operator()(_Pre_valid_ _Frees_ptr_ T* p) const - { - ::UnmapViewOfFile(p); - } - }; - - template - using unique_process_heap_ptr = wistd::unique_ptr; - - typedef unique_any unique_process_heap_string; - - /// @cond - namespace details - { - template<> struct string_allocator - { - static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT - { - return ::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY, size); - } - }; - } - /// @endcond - - /** Manages a typed pointer allocated with VirtualAlloc - A specialization of wistd::unique_ptr<> that frees via VirtualFree(p, 0, MEM_RELEASE). - */ - template - using unique_virtualalloc_ptr = wistd::unique_ptr; - - /** Manages a typed pointer allocated with MapViewOfFile - A specialization of wistd::unique_ptr<> that frees via UnmapViewOfFile(p). - */ - template - using unique_mapview_ptr = wistd::unique_ptr; - -#endif // __WIL_WINBASE_ - -#if defined(__WIL_WINBASE_) && defined(__NOTHROW_T_DEFINED) && !defined(__WIL_WINBASE_NOTHROW_T_DEFINED) -#define __WIL_WINBASE_NOTHROW_T_DEFINED - // unique_event_watcher, unique_event_watcher_nothrow, unique_event_watcher_failfast - // - // Clients must include or to enable use of this class as it uses new(std::nothrow). - // This is to avoid the dependency on those headers that some clients can't tolerate. - // - // These classes makes it easy to execute a provided function when an event - // is signaled. It will create the event handle for you, take ownership of one - // or duplicate a handle provided. It supports the ability to signal the - // event using SetEvent() and SetEvent_scope_exit(); - // - // This can be used to support producer-consumer pattern - // where a producer updates some state then signals the event when done. - // The consumer will consume that state in the callback provided to unique_event_watcher. - // - // Note, multiple signals may coalesce into a single callback. - // - // Example use of throwing version: - // auto globalStateWatcher = wil::make_event_watcher([] - // { - // currentState = GetGlobalState(); - // }); - // - // UpdateGlobalState(value); - // globalStateWatcher.SetEvent(); // signal observers so they can update - // - // Example use of non-throwing version: - // auto globalStateWatcher = wil::make_event_watcher_nothrow([] - // { - // currentState = GetGlobalState(); - // }); - // RETURN_IF_NULL_ALLOC(globalStateWatcher); - // - // UpdateGlobalState(value); - // globalStateWatcher.SetEvent(); // signal observers so they can update - - /// @cond - namespace details - { - struct event_watcher_state - { - event_watcher_state(unique_event_nothrow &&eventHandle, wistd::function &&callback) - : m_callback(wistd::move(callback)), m_event(wistd::move(eventHandle)) - { - } - wistd::function m_callback; - unique_event_nothrow m_event; - // The thread pool must be last to ensure that the other members are valid - // when it is destructed as it will reference them. - unique_threadpool_wait m_threadPoolWait; - }; - - inline void delete_event_watcher_state(_In_opt_ event_watcher_state *watcherStorage) { delete watcherStorage; } - - typedef resource_policy event_watcher_state_resource_policy; - } - /// @endcond - - template - class event_watcher_t : public storage_t - { - public: - // forward all base class constructors... - template - explicit event_watcher_t(args_t&&... args) WI_NOEXCEPT : storage_t(wistd::forward(args)...) {} - - // HRESULT or void error handling... - typedef typename err_policy::result result; - - // Exception-based constructors - template - event_watcher_t(unique_any_t, from_err_policy>> &&eventHandle, wistd::function &&callback) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); - create(wistd::move(eventHandle), wistd::move(callback)); - } - - event_watcher_t(_In_ HANDLE eventHandle, wistd::function &&callback) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); - create(eventHandle, wistd::move(callback)); - } - - event_watcher_t(wistd::function &&callback) - { - static_assert(wistd::is_same::value, "this constructor requires exceptions or fail fast; use the create method"); - create(wistd::move(callback)); - } - - template - result create(unique_any_t, event_err_policy>> &&eventHandle, - wistd::function &&callback) - { - return err_policy::HResult(create_take_hevent_ownership(eventHandle.release(), wistd::move(callback))); - } - - // Creates the event that you will be watching. - result create(wistd::function &&callback) - { - unique_event_nothrow eventHandle; - HRESULT hr = eventHandle.create(EventOptions::ManualReset); // auto-reset is supported too. - if (FAILED(hr)) - { - return err_policy::HResult(hr); - } - return err_policy::HResult(create_take_hevent_ownership(eventHandle.release(), wistd::move(callback))); - } - - // Input is an event handler that is duplicated into this class. - result create(_In_ HANDLE eventHandle, wistd::function &&callback) - { - unique_event_nothrow ownedHandle; - if (!DuplicateHandle(GetCurrentProcess(), eventHandle, GetCurrentProcess(), &ownedHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) - { - return err_policy::LastError(); - } - return err_policy::HResult(create_take_hevent_ownership(ownedHandle.release(), wistd::move(callback))); - } - - // Provide access to the inner event and the very common SetEvent() method on it. - WI_NODISCARD unique_event_nothrow const& get_event() const WI_NOEXCEPT { return storage_t::get()->m_event; } - void SetEvent() const WI_NOEXCEPT { storage_t::get()->m_event.SetEvent(); } - - private: - - // Had to move this from a Lambda so it would compile in C++/CLI (which thought the Lambda should be a managed function for some reason). - static void CALLBACK wait_callback(PTP_CALLBACK_INSTANCE, void *context, TP_WAIT *pThreadPoolWait, TP_WAIT_RESULT) - { - auto pThis = static_cast(context); - // Manual events must be re-set to avoid missing the last notification. - pThis->m_event.ResetEvent(); - // Call the client before re-arming to ensure that multiple callbacks don't - // run concurrently. - pThis->m_callback(); - SetThreadpoolWait(pThreadPoolWait, pThis->m_event.get(), nullptr); // valid params ensure success - } - - // To avoid template expansion (if unique_event/unique_event_nothrow forms were used) this base - // create function takes a raw handle and assumes its ownership, even on failure. - HRESULT create_take_hevent_ownership(_In_ HANDLE rawHandleOwnershipTaken, wistd::function &&callback) - { - __FAIL_FAST_ASSERT__(rawHandleOwnershipTaken != nullptr); // invalid parameter - unique_event_nothrow eventHandle(rawHandleOwnershipTaken); - wistd::unique_ptr watcherState(new(std::nothrow) details::event_watcher_state(wistd::move(eventHandle), wistd::move(callback))); - RETURN_IF_NULL_ALLOC(watcherState); - - watcherState->m_threadPoolWait.reset(CreateThreadpoolWait(wait_callback, watcherState.get(), nullptr)); - RETURN_LAST_ERROR_IF(!watcherState->m_threadPoolWait); - storage_t::reset(watcherState.release()); // no more failures after this, pass ownership - SetThreadpoolWait(storage_t::get()->m_threadPoolWait.get(), storage_t::get()->m_event.get(), nullptr); - return S_OK; - } - }; - - typedef unique_any_t, err_returncode_policy>> unique_event_watcher_nothrow; - typedef unique_any_t, err_failfast_policy>> unique_event_watcher_failfast; - - template - unique_event_watcher_nothrow make_event_watcher_nothrow(unique_any_t, err_policy>> &&eventHandle, wistd::function &&callback) WI_NOEXCEPT - { - unique_event_watcher_nothrow watcher; - watcher.create(wistd::move(eventHandle), wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) - } - - inline unique_event_watcher_nothrow make_event_watcher_nothrow(_In_ HANDLE eventHandle, wistd::function &&callback) WI_NOEXCEPT - { - unique_event_watcher_nothrow watcher; - watcher.create(eventHandle, wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) - } - - inline unique_event_watcher_nothrow make_event_watcher_nothrow(wistd::function &&callback) WI_NOEXCEPT - { - unique_event_watcher_nothrow watcher; - watcher.create(wistd::move(callback)); - return watcher; // caller must test for success using if (watcher) - } - - template - unique_event_watcher_failfast make_event_watcher_failfast(unique_any_t, err_policy>> &&eventHandle, wistd::function &&callback) - { - return unique_event_watcher_failfast(wistd::move(eventHandle), wistd::move(callback)); - } - - inline unique_event_watcher_failfast make_event_watcher_failfast(_In_ HANDLE eventHandle, wistd::function &&callback) - { - return unique_event_watcher_failfast(eventHandle, wistd::move(callback)); - } - - inline unique_event_watcher_failfast make_event_watcher_failfast(wistd::function &&callback) - { - return unique_event_watcher_failfast(wistd::move(callback)); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - typedef unique_any_t, err_exception_policy>> unique_event_watcher; - - template - unique_event_watcher make_event_watcher(unique_any_t, err_policy>> &&eventHandle, wistd::function &&callback) - { - return unique_event_watcher(wistd::move(eventHandle), wistd::move(callback)); - } - - inline unique_event_watcher make_event_watcher(_In_ HANDLE eventHandle, wistd::function &&callback) - { - return unique_event_watcher(eventHandle, wistd::move(callback)); - } - - inline unique_event_watcher make_event_watcher(wistd::function &&callback) - { - return unique_event_watcher(wistd::move(callback)); - } -#endif // WIL_ENABLE_EXCEPTIONS - -#endif // __WIL_WINBASE_NOTHROW_T_DEFINED - -#if defined(__WIL_WINBASE_) && !defined(__WIL_WINBASE_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_WINBASE_STL - typedef shared_any_t>> shared_event; - typedef shared_any_t>> shared_mutex; - typedef shared_any_t>> shared_semaphore; - typedef shared_any shared_hfile; - typedef shared_any shared_handle; - typedef shared_any shared_hfind; - typedef shared_any shared_hmodule; - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - typedef shared_any shared_threadpool_wait; - typedef shared_any shared_threadpool_wait_nocancel; - typedef shared_any shared_threadpool_work; - typedef shared_any shared_threadpool_work_nocancel; - - typedef shared_any shared_hfind_change; -#endif - - typedef weak_any weak_event; - typedef weak_any weak_mutex; - typedef weak_any weak_semaphore; - typedef weak_any weak_hfile; - typedef weak_any weak_handle; - typedef weak_any weak_hfind; - typedef weak_any weak_hmodule; - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) - typedef weak_any weak_threadpool_wait; - typedef weak_any weak_threadpool_wait_nocancel; - typedef weak_any weak_threadpool_work; - typedef weak_any weak_threadpool_work_nocancel; - - typedef weak_any weak_hfind_change; -#endif - -#endif // __WIL_WINBASE_STL - -#if defined(__WIL_WINBASE_) && defined(__NOTHROW_T_DEFINED) && !defined(__WIL_WINBASE_NOTHROW_T_DEFINED_STL) && defined(WIL_RESOURCE_STL) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_WINBASE_NOTHROW_T_DEFINED_STL - typedef shared_any_t>> shared_event_watcher; - typedef weak_any weak_event_watcher; -#endif // __WIL_WINBASE_NOTHROW_T_DEFINED_STL - -#if defined(__WIL_WINBASE_) && !defined(__WIL_WINBASE_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_WINBASE_DESKTOP - /// @cond - namespace details - { - inline void __stdcall DestroyPrivateObjectSecurity(_Pre_opt_valid_ _Frees_ptr_opt_ PSECURITY_DESCRIPTOR pObjectDescriptor) WI_NOEXCEPT - { - ::DestroyPrivateObjectSecurity(&pObjectDescriptor); - } - } - /// @endcond - - using hlocal_deleter = function_deleter; - - template - using unique_hlocal_ptr = wistd::unique_ptr; - - /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. - Use `wil::make_unique_hlocal_nothrow()` for resources returned from APIs that must satisfy a memory allocation contract that requires the use of `LocalAlloc()` / `LocalFree()`. - Use `wil::make_unique_nothrow()` when `LocalAlloc()` is not required. - - Allocations are initialized with placement new and will call constructors (if present), but this does not guarantee initialization. - - Note that `wil::make_unique_hlocal_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an exception-based class that may throw in its constructor. - ~~~ - auto foo = wil::make_unique_hlocal_nothrow(); - if (foo) - { - // initialize allocated Foo object as appropriate - } - ~~~ - */ - template - inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal_nothrow(Args&&... args) - { - static_assert(wistd::is_trivially_destructible::value, "T has a destructor that won't be run when used with this function; use make_unique instead"); - unique_hlocal_ptr sp(static_cast(::LocalAlloc(LMEM_FIXED, sizeof(T)))); - if (sp) - { - // use placement new to initialize memory from the previous allocation - new (sp.get()) T(wistd::forward(args)...); - } - return sp; - } - - /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. - See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_hlocal_nothrow(size); - if (foos) - { - for (auto& elem : wil::make_range(foos.get(), size)) - { - // initialize allocated Foo objects as appropriate - } - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type make_unique_hlocal_nothrow(size_t size) - { - typedef typename wistd::remove_extent::type E; - static_assert(wistd::is_trivially_destructible::value, "E has a destructor that won't be run when used with this function; use make_unique instead"); - FAIL_FAST_IF((__WI_SIZE_MAX / sizeof(E)) < size); - size_t allocSize = sizeof(E) * size; - unique_hlocal_ptr sp(static_cast(::LocalAlloc(LMEM_FIXED, allocSize))); - if (sp) - { - // use placement new to initialize memory from the previous allocation; - // note that array placement new cannot be used as the standard allows for operator new[] - // to consume overhead in the allocation for internal bookkeeping - for (auto& elem : make_range(static_cast(sp.get()), size)) - { - new (&elem) E(); - } - } - return sp; - } - - /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. - See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. - ~~~ - auto foo = wil::make_unique_hlocal_failfast(); - // initialize allocated Foo object as appropriate - ~~~ - */ - template - inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal_failfast(Args&&... args) - { - unique_hlocal_ptr result(make_unique_hlocal_nothrow(wistd::forward(args)...)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; - } - - /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. - See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_hlocal_failfast(size); - for (auto& elem : wil::make_range(foos.get(), size)) - { - // initialize allocated Foo objects as appropriate - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type make_unique_hlocal_failfast(size_t size) - { - unique_hlocal_ptr result(make_unique_hlocal_nothrow(size)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - /** Provides `std::make_unique()` semantics for resources allocated with `LocalAlloc()`. - See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. - ~~~ - auto foo = wil::make_unique_hlocal(); - // initialize allocated Foo object as appropriate - ~~~ - */ - template - inline typename wistd::enable_if::value, unique_hlocal_ptr>::type make_unique_hlocal(Args&&... args) - { - unique_hlocal_ptr result(make_unique_hlocal_nothrow(wistd::forward(args)...)); - THROW_IF_NULL_ALLOC(result); - return result; - } - - /** Provides `std::make_unique()` semantics for array resources allocated with `LocalAlloc()`. - See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_hlocal(size); - for (auto& elem : wil::make_range(foos.get(), size)) - { - // initialize allocated Foo objects as appropriate - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_ptr>::type make_unique_hlocal(size_t size) - { - unique_hlocal_ptr result(make_unique_hlocal_nothrow(size)); - THROW_IF_NULL_ALLOC(result); - return result; - } -#endif // WIL_ENABLE_EXCEPTIONS - - typedef unique_any unique_hlocal; - typedef unique_any unique_hlocal_string; -#ifndef WIL_NO_ANSI_STRINGS - typedef unique_any unique_hlocal_ansistring; -#endif // WIL_NO_ANSI_STRINGS - - /// @cond - namespace details - { - struct localalloc_allocator - { - static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT - { - return ::LocalAlloc(LMEM_FIXED, size); - } - }; - - template<> struct string_allocator : localalloc_allocator {}; -#ifndef WIL_NO_ANSI_STRINGS - template<> struct string_allocator : localalloc_allocator {}; -#endif // WIL_NO_ANSI_STRINGS - } - /// @endcond - - inline auto make_hlocal_string_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT - { - return make_unique_string_nothrow(source, length); - } - - inline auto make_hlocal_string_failfast( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT - { - return make_unique_string_failfast(source, length); - } - -#ifndef WIL_NO_ANSI_STRINGS - inline auto make_hlocal_ansistring_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT - { - return make_unique_ansistring_nothrow(source, length); - } - - inline auto make_hlocal_ansistring_failfast( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT - { - return make_unique_ansistring_failfast(source, length); - } -#endif - -#ifdef WIL_ENABLE_EXCEPTIONS - inline auto make_hlocal_string( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCWSTR source, size_t length = static_cast(-1)) - { - return make_unique_string(source, length); - } - -#ifndef WIL_NO_ANSI_STRINGS - inline auto make_hlocal_ansistring( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCSTR source, size_t length = static_cast(-1)) - { - return make_unique_ansistring(source, length); - } -#endif // WIL_NO_ANSI_STRINGS -#endif // WIL_ENABLE_EXCEPTIONS - - struct hlocal_secure_deleter - { - template - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const - { - if (p) - { -#pragma warning(suppress: 26006 26007) // LocalSize() ensures proper buffer length - ::SecureZeroMemory(p, ::LocalSize(p)); // this is safe since LocalSize() returns 0 on failure - ::LocalFree(p); - } - } - }; - - template - using unique_hlocal_secure_ptr = wistd::unique_ptr; - - /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. - See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. - ~~~ - auto foo = wil::make_unique_hlocal_secure_nothrow(); - if (foo) - { - // initialize allocated Foo object as appropriate - } - ~~~ - */ - template - inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_nothrow(Args&&... args) - { - return unique_hlocal_secure_ptr(make_unique_hlocal_nothrow(wistd::forward(args)...).release()); - } - - /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. - See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_hlocal_secure_nothrow(size); - if (foos) - { - for (auto& elem : wil::make_range(foos.get(), size)) - { - // initialize allocated Foo objects as appropriate - } - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_nothrow(size_t size) - { - return unique_hlocal_secure_ptr(make_unique_hlocal_nothrow(size).release()); - } - - /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. - See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. - ~~~ - auto foo = wil::make_unique_hlocal_secure_failfast(); - // initialize allocated Foo object as appropriate - ~~~ - */ - template - inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_failfast(Args&&... args) - { - unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(wistd::forward(args)...)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; - } - - /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. - See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_hlocal_secure_failfast(size); - for (auto& elem : wil::make_range(foos.get(), size)) - { - // initialize allocated Foo objects as appropriate - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure_failfast(size_t size) - { - unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(size)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - /** Provides `std::make_unique()` semantics for secure resources allocated with `LocalAlloc()`. - See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. - ~~~ - auto foo = wil::make_unique_hlocal_secure(); - // initialize allocated Foo object as appropriate - ~~~ - */ - template - inline typename wistd::enable_if::value, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure(Args&&... args) - { - unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(wistd::forward(args)...)); - THROW_IF_NULL_ALLOC(result); - return result; - } - - /** Provides `std::make_unique()` semantics for secure array resources allocated with `LocalAlloc()`. - See the overload of `wil::make_unique_hlocal_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_hlocal_secure(size); - for (auto& elem : wil::make_range(foos.get(), size)) - { - // initialize allocated Foo objects as appropriate - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_hlocal_secure_ptr>::type make_unique_hlocal_secure(size_t size) - { - unique_hlocal_secure_ptr result(make_unique_hlocal_secure_nothrow(size)); - THROW_IF_NULL_ALLOC(result); - return result; - } -#endif // WIL_ENABLE_EXCEPTIONS - - typedef unique_hlocal_secure_ptr unique_hlocal_string_secure; - - /** Copies a given string into secure memory allocated with `LocalAlloc()` in a context that may not throw upon allocation failure. - See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. - ~~~ - auto str = wil::make_hlocal_string_secure_nothrow(L"a string"); - RETURN_IF_NULL_ALLOC(str); - std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" - ~~~ - */ - inline auto make_hlocal_string_secure_nothrow(_In_ PCWSTR source) WI_NOEXCEPT - { - return unique_hlocal_string_secure(make_hlocal_string_nothrow(source).release()); - } - - /** Copies a given string into secure memory allocated with `LocalAlloc()` in a context that must fail fast upon allocation failure. - See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. - ~~~ - auto str = wil::make_hlocal_string_secure_failfast(L"a string"); - std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" - ~~~ - */ - inline auto make_hlocal_string_secure_failfast(_In_ PCWSTR source) WI_NOEXCEPT - { - unique_hlocal_string_secure result(make_hlocal_string_secure_nothrow(source)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - /** Copies a given string into secure memory allocated with `LocalAlloc()`. - See the overload of `wil::make_hlocal_string_nothrow()` with supplied length for more details. - ~~~ - auto str = wil::make_hlocal_string_secure(L"a string"); - std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" - ~~~ - */ - inline auto make_hlocal_string_secure(_In_ PCWSTR source) - { - unique_hlocal_string_secure result(make_hlocal_string_secure_nothrow(source)); - THROW_IF_NULL_ALLOC(result); - return result; - } -#endif - - using hglobal_deleter = function_deleter; - - template - using unique_hglobal_ptr = wistd::unique_ptr; - - typedef unique_any unique_hglobal; - typedef unique_any unique_hglobal_string; -#ifndef WIL_NO_ANSI_STRINGS - typedef unique_any unique_hglobal_ansistring; -#endif // WIL_NO_ANSI_STRINGS - - /// @cond - namespace details - { - template<> struct string_allocator - { - static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT - { - return ::GlobalAlloc(GPTR, size); - } - }; - } - /// @endcond - - inline auto make_process_heap_string_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT - { - return make_unique_string_nothrow(source, length); - } - - inline auto make_process_heap_string_failfast( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT - { - return make_unique_string_failfast(source, length); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - inline auto make_process_heap_string( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCWSTR source, size_t length = static_cast(-1)) - { - return make_unique_string(source, length); - } -#endif // WIL_ENABLE_EXCEPTIONS - - typedef unique_any_handle_null unique_hheap; - typedef unique_any unique_tls; - typedef unique_any unique_hlocal_security_descriptor; - typedef unique_any unique_private_security_descriptor; - -#if defined(_WINUSER_) && !defined(__WIL__WINUSER_) -#define __WIL__WINUSER_ - typedef unique_any unique_haccel; - typedef unique_any unique_hcursor; - typedef unique_any unique_hwnd; -#if !defined(NOUSER) && !defined(NOWH) - typedef unique_any unique_hhook; -#endif -#if !defined(NOWINABLE) - typedef unique_any unique_hwineventhook; -#endif -#if !defined(NOCLIPBOARD) - using unique_close_clipboard_call = unique_call; - - inline unique_close_clipboard_call open_clipboard(HWND hwnd) - { - return unique_close_clipboard_call { OpenClipboard(hwnd) != FALSE }; - } -#endif -#endif // __WIL__WINUSER_ - -#if !defined(NOGDI) && !defined(NODESKTOP) - typedef unique_any unique_hdesk; - typedef unique_any unique_hwinsta; -#endif // !defined(NOGDI) && !defined(NODESKTOP) - -#endif -#if defined(__WIL_WINBASE_DESKTOP) && !defined(__WIL_WINBASE_DESKTOP_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_WINBASE_DESKTOP_STL - typedef shared_any shared_hheap; - typedef shared_any shared_hlocal; - typedef shared_any shared_tls; - typedef shared_any shared_hlocal_security_descriptor; - typedef shared_any shared_private_security_descriptor; - typedef shared_any shared_haccel; - typedef shared_any shared_hcursor; -#if !defined(NOGDI) && !defined(NODESKTOP) - typedef shared_any shared_hdesk; - typedef shared_any shared_hwinsta; -#endif // !defined(NOGDI) && !defined(NODESKTOP) - typedef shared_any shared_hwnd; -#if !defined(NOUSER) && !defined(NOWH) - typedef shared_any shared_hhook; -#endif -#if !defined(NOWINABLE) - typedef shared_any shared_hwineventhook; -#endif - - typedef weak_any weak_hheap; - typedef weak_any weak_hlocal; - typedef weak_any weak_tls; - typedef weak_any weak_hlocal_security_descriptor; - typedef weak_any weak_private_security_descriptor; - typedef weak_any weak_haccel; - typedef weak_any weak_hcursor; -#if !defined(NOGDI) && !defined(NODESKTOP) - typedef weak_any weak_hdesk; - typedef weak_any weak_hwinsta; -#endif // !defined(NOGDI) && !defined(NODESKTOP) - typedef weak_any weak_hwnd; -#if !defined(NOUSER) && !defined(NOWH) - typedef weak_any weak_hhook; -#endif -#if !defined(NOWINABLE) - typedef weak_any weak_hwineventhook; -#endif -#endif // __WIL_WINBASE_DESKTOP_STL - -#if defined(_COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE) -#define __WIL__COMBASEAPI_H_ -#if (NTDDI_VERSION >= NTDDI_WIN8) - typedef unique_any unique_mta_usage_cookie; -#endif - - typedef unique_any unique_com_class_object_cookie; - - /// @cond - namespace details - { - inline void __stdcall MultiQiCleanup(_In_ MULTI_QI* multiQi) - { - if (multiQi->pItf) - { - multiQi->pItf->Release(); - multiQi->pItf = nullptr; - } - } - } - /// @endcond - - //! A type that calls CoRevertToSelf on destruction (or reset()). - using unique_coreverttoself_call = unique_call; - - //! Calls CoImpersonateClient and fail-fasts if it fails; returns an RAII object that reverts - WI_NODISCARD inline unique_coreverttoself_call CoImpersonateClient_failfast() - { - FAIL_FAST_IF_FAILED(::CoImpersonateClient()); - return unique_coreverttoself_call(); - } - - typedef unique_struct unique_multi_qi; -#endif // __WIL__COMBASEAPI_H_ -#if defined(__WIL__COMBASEAPI_H_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL__COMBASEAPI_H_EXCEPTIONAL) -#define __WIL__COMBASEAPI_H_EXCEPTIONAL - WI_NODISCARD inline unique_coreverttoself_call CoImpersonateClient() - { - THROW_IF_FAILED(::CoImpersonateClient()); - return unique_coreverttoself_call(); - } -#endif -#if defined(__WIL__COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H__STL) && defined(WIL_RESOURCE_STL) && (NTDDI_VERSION >= NTDDI_WIN8) -#define __WIL__COMBASEAPI_H__STL - typedef shared_any shared_mta_usage_cookie; - typedef weak_any weak_mta_usage_cookie; -#endif // __WIL__COMBASEAPI_H__STL - -#if defined(_COMBASEAPI_H_) && !defined(__WIL__COMBASEAPI_H_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE) -#define __WIL__COMBASEAPI_H_APP - //! A type that calls CoUninitialize on destruction (or reset()). - using unique_couninitialize_call = unique_call; - - //! Calls CoInitializeEx and fail-fasts if it fails; returns an RAII object that reverts - WI_NODISCARD inline unique_couninitialize_call CoInitializeEx_failfast(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/) - { - FAIL_FAST_IF_FAILED(::CoInitializeEx(nullptr, coinitFlags)); - return {}; - } -#endif // __WIL__COMBASEAPI_H_APP -#if defined(__WIL__COMBASEAPI_H_APP) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL__COMBASEAPI_H_APPEXCEPTIONAL) -#define __WIL__COMBASEAPI_H_APPEXCEPTIONAL - WI_NODISCARD inline unique_couninitialize_call CoInitializeEx(DWORD coinitFlags = 0 /*COINIT_MULTITHREADED*/) - { - THROW_IF_FAILED(::CoInitializeEx(nullptr, coinitFlags)); - return {}; - } -#endif - -#if defined(__ROAPI_H_) && !defined(__WIL__ROAPI_H_APP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) && (NTDDI_VERSION >= NTDDI_WIN8) -#define __WIL__ROAPI_H_APP - - typedef unique_any unique_ro_registration_cookie; - - //! A type that calls RoUninitialize on destruction (or reset()). - //! Use as a replacement for Windows::Foundation::Uninitialize. - using unique_rouninitialize_call = unique_call; - - //! Calls RoInitialize and fail-fasts if it fails; returns an RAII object that reverts - //! Use as a replacement for Windows::Foundation::Initialize - WI_NODISCARD inline unique_rouninitialize_call RoInitialize_failfast(RO_INIT_TYPE initType = RO_INIT_MULTITHREADED) - { - FAIL_FAST_IF_FAILED(::RoInitialize(initType)); - return unique_rouninitialize_call(); - } -#endif // __WIL__ROAPI_H_APP -#if defined(__WIL__ROAPI_H_APP) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL__ROAPI_H_APPEXCEPTIONAL) -#define __WIL__ROAPI_H_APPEXCEPTIONAL - //! Calls RoInitialize and throws an exception if it fails; returns an RAII object that reverts - //! Use as a replacement for Windows::Foundation::Initialize - WI_NODISCARD inline unique_rouninitialize_call RoInitialize(RO_INIT_TYPE initType = RO_INIT_MULTITHREADED) - { - THROW_IF_FAILED(::RoInitialize(initType)); - return unique_rouninitialize_call(); - } -#endif - -#if defined(__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) -#define __WIL__WINSTRING_H_ - typedef unique_any unique_hstring; - - template<> inline unique_hstring make_unique_string_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCWSTR source, size_t length) WI_NOEXCEPT - { - WI_ASSERT(source != nullptr); // the HSTRING version of this function does not suport this case - if (length == static_cast(-1)) - { - length = wcslen(source); - } - - unique_hstring result; - ::WindowsCreateString(source, static_cast(length), &result); - return result; - } - - typedef unique_any unique_hstring_buffer; - - /** Promotes an hstring_buffer to an HSTRING. - When an HSTRING_BUFFER object is promoted to a real string it must not be passed to WindowsDeleteString. The caller owns the - HSTRING afterwards. - ~~~ - HRESULT Type::MakePath(_Out_ HSTRING* path) - { - wchar_t* bufferStorage = nullptr; - wil::unique_hstring_buffer theBuffer; - RETURN_IF_FAILED(::WindowsPreallocateStringBuffer(65, &bufferStorage, &theBuffer)); - RETURN_IF_FAILED(::PathCchCombine(bufferStorage, 65, m_foo, m_bar)); - RETURN_IF_FAILED(wil::make_hstring_from_buffer_nothrow(wistd::move(theBuffer), path))); - return S_OK; - } - ~~~ - */ - inline HRESULT make_hstring_from_buffer_nothrow(unique_hstring_buffer&& source, _Out_ HSTRING* promoted) - { - HRESULT hr = ::WindowsPromoteStringBuffer(source.get(), promoted); - if (SUCCEEDED(hr)) - { - source.release(); - } - return hr; - } - - //! A fail-fast variant of `make_hstring_from_buffer_nothrow` - inline unique_hstring make_hstring_from_buffer_failfast(unique_hstring_buffer&& source) - { - unique_hstring result; - FAIL_FAST_IF_FAILED(make_hstring_from_buffer_nothrow(wistd::move(source), &result)); - return result; - } - -#if defined WIL_ENABLE_EXCEPTIONS - /** Promotes an hstring_buffer to an HSTRING. - When an HSTRING_BUFFER object is promoted to a real string it must not be passed to WindowsDeleteString. The caller owns the - HSTRING afterwards. - ~~~ - wil::unique_hstring Type::Make() - { - wchar_t* bufferStorage = nullptr; - wil::unique_hstring_buffer theBuffer; - THROW_IF_FAILED(::WindowsPreallocateStringBuffer(65, &bufferStorage, &theBuffer)); - THROW_IF_FAILED(::PathCchCombine(bufferStorage, 65, m_foo, m_bar)); - return wil::make_hstring_from_buffer(wistd::move(theBuffer)); - } - ~~~ - */ - inline unique_hstring make_hstring_from_buffer(unique_hstring_buffer&& source) - { - unique_hstring result; - THROW_IF_FAILED(make_hstring_from_buffer_nothrow(wistd::move(source), &result)); - return result; - } -#endif - - /// @cond - namespace details - { - template<> struct string_maker - { - string_maker() = default; - string_maker(const string_maker&) = delete; - void operator=(const string_maker&) = delete; - string_maker& operator=(string_maker&& source) WI_NOEXCEPT - { - m_value = wistd::move(source.m_value); - m_bufferHandle = wistd::move(source.m_bufferHandle); - m_charBuffer = wistd::exchange(source.m_charBuffer, nullptr); - return *this; - } - - HRESULT make( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - const wchar_t* source, - size_t length) - { - if (source) - { - RETURN_IF_FAILED(WindowsCreateString(source, static_cast(length), &m_value)); - m_charBuffer = nullptr; - m_bufferHandle.reset(); // do this after WindowsCreateString so we can trim_at_existing_null() from our own buffer - } - else - { - // Need to set it to the empty string to support the empty string case. - m_value.reset(); - RETURN_IF_FAILED(WindowsPreallocateStringBuffer(static_cast(length), &m_charBuffer, &m_bufferHandle)); - } - return S_OK; - } - - WI_NODISCARD wchar_t* buffer() { WI_ASSERT(m_charBuffer != nullptr); return m_charBuffer; } - WI_NODISCARD const wchar_t* buffer() const { return m_charBuffer; } - - HRESULT trim_at_existing_null(size_t length) { return make(buffer(), length); } - - unique_hstring release() - { - m_charBuffer = nullptr; - if (m_bufferHandle) - { - return make_hstring_from_buffer_failfast(wistd::move(m_bufferHandle)); - } - return wistd::move(m_value); - } - - static PCWSTR get(const wil::unique_hstring& value) { return WindowsGetStringRawBuffer(value.get(), nullptr); } - - private: - unique_hstring m_value; - unique_hstring_buffer m_bufferHandle; - wchar_t* m_charBuffer = nullptr; - }; - } - /// @endcond - - // str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer. - // This is the overload for HSTRING. Other overloads available above. - inline PCWSTR str_raw_ptr(HSTRING str) - { - return WindowsGetStringRawBuffer(str, nullptr); - } - - inline PCWSTR str_raw_ptr(const unique_hstring& str) - { - return str_raw_ptr(str.get()); - } - -#endif // __WIL__WINSTRING_H_ -#if defined(__WIL__WINSTRING_H_) && !defined(__WIL__WINSTRING_H_STL) && defined(WIL_RESOURCE_STL) -#define __WIL__WINSTRING_H_STL - typedef shared_any shared_hstring; - typedef shared_any shared_hstring_buffer; - typedef weak_any weak_hstring; - typedef weak_any weak_hstring_buffer; -#endif // __WIL__WINSTRING_H_STL - - -#if defined(_WINREG_) && !defined(__WIL_WINREG_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE) -#define __WIL_WINREG_ - typedef unique_any unique_hkey; -#endif // __WIL_WINREG_ -#if defined(__WIL_WINREG_) && !defined(__WIL_WINREG_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_WINREG_STL - typedef shared_any shared_hkey; - typedef weak_any weak_hkey; -#endif // __WIL_WINREG_STL - -#if defined(__propidl_h__) && !defined(_WIL__propidl_h__) && !defined(WIL_KERNEL_MODE) -#define _WIL__propidl_h__ - // if language extensions (/Za) disabled, PropVariantInit will not exist, PROPVARIANT has forward declaration only -#if defined(_MSC_EXTENSIONS) - using unique_prop_variant = wil::unique_struct; -#endif -#endif // _WIL__propidl_h__ - -#if defined(_OLEAUTO_H_) && !defined(__WIL_OLEAUTO_H_) && !defined(WIL_KERNEL_MODE) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) -#define __WIL_OLEAUTO_H_ - using unique_variant = wil::unique_struct; - typedef unique_any unique_bstr; - - inline wil::unique_bstr make_bstr_nothrow(PCWSTR source) WI_NOEXCEPT - { - return wil::unique_bstr(::SysAllocString(source)); - } - - inline wil::unique_bstr make_bstr_failfast(PCWSTR source) WI_NOEXCEPT - { - return wil::unique_bstr(FAIL_FAST_IF_NULL_ALLOC(::SysAllocString(source))); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - inline wil::unique_bstr make_bstr(PCWSTR source) - { - wil::unique_bstr result(make_bstr_nothrow(source)); - THROW_IF_NULL_ALLOC(result); - return result; - } -#endif // WIL_ENABLE_EXCEPTIONS - - inline wil::unique_variant make_variant_bstr_nothrow(PCWSTR source) WI_NOEXCEPT - { - wil::unique_variant result{}; - V_UNION(result.addressof(), bstrVal) = ::SysAllocString(source); - if (V_UNION(result.addressof(), bstrVal) != nullptr) - { - V_VT(result.addressof()) = VT_BSTR; - } - return result; - } - - inline wil::unique_variant make_variant_bstr_failfast(PCWSTR source) WI_NOEXCEPT - { - auto result{make_variant_bstr_nothrow(source)}; - FAIL_FAST_HR_IF(E_OUTOFMEMORY, V_VT(result.addressof()) == VT_EMPTY); - return result; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - inline wil::unique_variant make_variant_bstr(PCWSTR source) - { - auto result{make_variant_bstr_nothrow(source)}; - THROW_HR_IF(E_OUTOFMEMORY, V_VT(result.addressof()) == VT_EMPTY); - return result; - } -#endif // WIL_ENABLE_EXCEPTIONS - -#endif // __WIL_OLEAUTO_H_ -#if defined(__WIL_OLEAUTO_H_) && !defined(__WIL_OLEAUTO_H_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_OLEAUTO_H_STL - typedef shared_any shared_bstr; - typedef weak_any weak_bstr; -#endif // __WIL_OLEAUTO_H_STL - - -#if (defined(_WININET_) || defined(_DUBINET_)) && !defined(__WIL_WININET_) -#define __WIL_WININET_ - typedef unique_any unique_hinternet; -#endif // __WIL_WININET_ -#if defined(__WIL_WININET_) && !defined(__WIL_WININET_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_WININET_STL - typedef shared_any shared_hinternet; - typedef weak_any weak_hinternet; -#endif // __WIL_WININET_STL - - -#if defined(_WINHTTPX_) && !defined(__WIL_WINHTTP_) -#define __WIL_WINHTTP_ - typedef unique_any unique_winhttp_hinternet; -#endif // __WIL_WINHTTP_ -#if defined(__WIL_WINHTTP_) && !defined(__WIL_WINHTTP_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_WINHTTP_STL - typedef shared_any shared_winhttp_hinternet; - typedef weak_any weak_winhttp_hinternet; -#endif // __WIL_WINHTTP_STL - - -#if defined(_WINSOCKAPI_) && !defined(__WIL_WINSOCKAPI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_WINSOCKAPI_ - typedef unique_any unique_socket; -#endif // __WIL_WINSOCKAPI_ -#if defined(__WIL_WINSOCKAPI_) && !defined(__WIL_WINSOCKAPI_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_WINSOCKAPI_STL - typedef shared_any shared_socket; - typedef weak_any weak_socket; -#endif // __WIL_WINSOCKAPI_STL - - -#if defined(_WINGDI_) && !defined(__WIL_WINGDI_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(NOGDI) && !defined(WIL_KERNEL_MODE) -#define __WIL_WINGDI_ - struct window_dc - { - HDC dc; - HWND hwnd; - window_dc(HDC dc_, HWND hwnd_ = nullptr) WI_NOEXCEPT { dc = dc_; hwnd = hwnd_; } - WI_NODISCARD operator HDC() const WI_NOEXCEPT { return dc; } - static void close(window_dc wdc) WI_NOEXCEPT { ::ReleaseDC(wdc.hwnd, wdc.dc); } - }; - typedef unique_any unique_hdc_window; - - struct paint_dc - { - HWND hwnd; - PAINTSTRUCT ps; - paint_dc(HDC hdc = nullptr) { ::ZeroMemory(this, sizeof(*this)); ps.hdc = hdc; } - WI_NODISCARD operator HDC() const WI_NOEXCEPT { return ps.hdc; } - static void close(paint_dc pdc) WI_NOEXCEPT { ::EndPaint(pdc.hwnd, &pdc.ps); } - }; - typedef unique_any unique_hdc_paint; - - struct select_result - { - HGDIOBJ hgdi; - HDC hdc; - select_result(HGDIOBJ hgdi_, HDC hdc_ = nullptr) WI_NOEXCEPT { hgdi = hgdi_; hdc = hdc_; } - WI_NODISCARD operator HGDIOBJ() const WI_NOEXCEPT { return hgdi; } - static void close(select_result sr) WI_NOEXCEPT { ::SelectObject(sr.hdc, sr.hgdi); } - }; - typedef unique_any unique_select_object; - - inline unique_hdc_window GetDC(HWND hwnd) WI_NOEXCEPT - { - return unique_hdc_window(window_dc(::GetDC(hwnd), hwnd)); - } - - inline unique_hdc_window GetWindowDC(HWND hwnd) WI_NOEXCEPT - { - return unique_hdc_window(window_dc(::GetWindowDC(hwnd), hwnd)); - } - - inline unique_hdc_paint BeginPaint(HWND hwnd, _Out_opt_ PPAINTSTRUCT pPaintStruct = nullptr) WI_NOEXCEPT - { - paint_dc pdc; - pdc.hwnd = hwnd; - HDC hdc = ::BeginPaint(hwnd, &pdc.ps); - assign_to_opt_param(pPaintStruct, pdc.ps); - return (hdc == nullptr) ? unique_hdc_paint() : unique_hdc_paint(pdc); - } - - inline unique_select_object SelectObject(HDC hdc, HGDIOBJ gdiobj) WI_NOEXCEPT - { - return unique_select_object(select_result(::SelectObject(hdc, gdiobj), hdc)); - } - - typedef unique_any unique_hgdiobj; - typedef unique_any unique_hpen; - typedef unique_any unique_hbrush; - typedef unique_any unique_hfont; - typedef unique_any unique_hbitmap; - typedef unique_any unique_hrgn; - typedef unique_any unique_hpalette; - typedef unique_any unique_hdc; - typedef unique_any unique_hicon; -#if !defined(NOMENUS) - typedef unique_any unique_hmenu; -#endif // !defined(NOMENUS) -#endif // __WIL_WINGDI_ -#if defined(__WIL_WINGDI_) && !defined(__WIL_WINGDI_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_WINGDI_STL - typedef shared_any shared_hgdiobj; - typedef shared_any shared_hpen; - typedef shared_any shared_hbrush; - typedef shared_any shared_hfont; - typedef shared_any shared_hbitmap; - typedef shared_any shared_hrgn; - typedef shared_any shared_hpalette; - typedef shared_any shared_hdc; - typedef shared_any shared_hicon; -#if !defined(NOMENUS) - typedef shared_any shared_hmenu; -#endif // !defined(NOMENUS) - - typedef weak_any weak_hgdiobj; - typedef weak_any weak_hpen; - typedef weak_any weak_hbrush; - typedef weak_any weak_hfont; - typedef weak_any weak_hbitmap; - typedef weak_any weak_hrgn; - typedef weak_any weak_hpalette; - typedef weak_any weak_hdc; - typedef weak_any weak_hicon; -#if !defined(NOMENUS) - typedef weak_any weak_hmenu; -#endif // !defined(NOMENUS) -#endif // __WIL_WINGDI_STL - -#if defined(_INC_WTSAPI) && !defined(__WIL_WTSAPI) -#define __WIL_WTSAPI - template - using unique_wtsmem_ptr = wistd::unique_ptr>; -#endif // __WIL_WTSAPI - -#if defined(_WINSCARD_H_) && !defined(__WIL_WINSCARD_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_WINSCARD_H_ - typedef unique_any unique_scardctx; -#endif // __WIL_WINSCARD_H_ -#if defined(__WIL_WINSCARD_H_) && !defined(__WIL_WINSCARD_H_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_WINSCARD_H_STL - typedef shared_any shared_scardctx; - typedef weak_any weak_scardctx; -#endif // __WIL_WINSCARD_H_STL - - -#if defined(__WINCRYPT_H__) && !defined(__WIL__WINCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL__WINCRYPT_H__ - /// @cond - namespace details - { - inline void __stdcall CertCloseStoreNoParam(_Pre_opt_valid_ _Frees_ptr_opt_ HCERTSTORE hCertStore) WI_NOEXCEPT - { - ::CertCloseStore(hCertStore, 0); - } - - inline void __stdcall CryptReleaseContextNoParam(_Pre_opt_valid_ _Frees_ptr_opt_ HCRYPTPROV hCryptCtx) WI_NOEXCEPT - { - ::CryptReleaseContext(hCryptCtx, 0); - } - } - /// @endcond - - struct cert_context_t : details::unique_storage> - { - // forward all base class constructors... - template - explicit cert_context_t(args_t&&... args) WI_NOEXCEPT : unique_storage(wistd::forward(args)...) {} - - /** A wrapper around CertEnumCertificatesInStore. - CertEnumCertificatesInStore takes ownership of its second paramter in an unclear fashion, - making it error-prone to use in combination with unique_cert_context. This wrapper helps - manage the resource correctly while ensuring the GetLastError state set by CertEnumCertificatesInStore. - is not lost. See MSDN for more information on `CertEnumCertificatesInStore`. - ~~~~ - void MyMethod(HCERTSTORE certStore) - { - wil::unique_cert_context enumCert; - while (enumCert.CertEnumCertificatesInStore(certStore)) - { - UseTheCertToDoTheThing(enumCert); - } - } - ~~~~ - @param certStore A handle of a certificate store. - @param 'true' if a certificate was enumerated by this call, false otherwise. - */ - bool CertEnumCertificatesInStore(HCERTSTORE certStore) WI_NOEXCEPT - { - reset(::CertEnumCertificatesInStore(certStore, release())); - return is_valid(); - } - }; - - // Warning - ::CertEnumCertificatesInStore takes ownership of its parameter. Prefer the - // .CertEnumCertificatesInStore method of the unique_cert_context or else use .release - // when calling ::CertEnumCertificatesInStore directly. - typedef unique_any_t unique_cert_context; - typedef unique_any unique_cert_chain_context; - typedef unique_any unique_hcertstore; - typedef unique_any unique_hcryptprov; - typedef unique_any unique_hcryptkey; - typedef unique_any unique_hcrypthash; - typedef unique_any unique_hcryptmsg; -#endif // __WIL__WINCRYPT_H__ -#if defined(__WIL__WINCRYPT_H__) && !defined(__WIL__WINCRYPT_H__STL) && defined(WIL_RESOURCE_STL) -#define __WIL__WINCRYPT_H__STL - typedef shared_any shared_cert_context; - typedef shared_any shared_cert_chain_context; - typedef shared_any shared_hcertstore; - typedef shared_any shared_hcryptprov; - typedef shared_any shared_hcryptkey; - typedef shared_any shared_hcrypthash; - typedef shared_any shared_hcryptmsg; - - typedef weak_any weak_cert_context; - typedef weak_any weak_cert_chain_context; - typedef weak_any weak_hcertstore; - typedef weak_any weak_hcryptprov; - typedef weak_any weak_hcryptkey; - typedef weak_any weak_hcrypthash; - typedef weak_any weak_hcryptmsg; -#endif // __WIL__WINCRYPT_H__STL - - -#if defined(__NCRYPT_H__) && !defined(__WIL_NCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_NCRYPT_H__ - using ncrypt_deleter = function_deleter; - - template - using unique_ncrypt_ptr = wistd::unique_ptr; - - typedef unique_any unique_ncrypt_prov; - typedef unique_any unique_ncrypt_key; - typedef unique_any unique_ncrypt_secret; -#endif // __WIL_NCRYPT_H__ -#if defined(__WIL_NCRYPT_H__) && !defined(__WIL_NCRYPT_H_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_NCRYPT_H_STL - typedef shared_any shared_ncrypt_prov; - typedef shared_any shared_ncrypt_key; - typedef shared_any shared_ncrypt_secret; - - typedef weak_any weak_ncrypt_prov; - typedef weak_any weak_ncrypt_key; - typedef weak_any weak_ncrypt_secret; -#endif // __WIL_NCRYPT_H_STL - -#if defined(__BCRYPT_H__) && !defined(__WIL_BCRYPT_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_BCRYPT_H__ - /// @cond - namespace details - { - inline void __stdcall BCryptCloseAlgorithmProviderNoFlags(_Pre_opt_valid_ _Frees_ptr_opt_ BCRYPT_ALG_HANDLE hAlgorithm) WI_NOEXCEPT - { - if (hAlgorithm) - { - ::BCryptCloseAlgorithmProvider(hAlgorithm, 0); - } - } - } - /// @endcond - - using bcrypt_deleter = function_deleter; - - template - using unique_bcrypt_ptr = wistd::unique_ptr; - - typedef unique_any unique_bcrypt_algorithm; - typedef unique_any unique_bcrypt_hash; - typedef unique_any unique_bcrypt_key; - typedef unique_any unique_bcrypt_secret; -#endif // __WIL_BCRYPT_H__ -#if defined(__WIL_BCRYPT_H__) && !defined(__WIL_BCRYPT_H_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_BCRYPT_H_STL - typedef shared_any shared_bcrypt_algorithm; - typedef shared_any shared_bcrypt_hash; - typedef shared_any shared_bcrypt_key; - typedef shared_any shared_bcrypt_secret; - - typedef weak_any weak_bcrypt_algorithm; - typedef weak_any weak_bcrypt_hash; - typedef weak_any weak_bcrypt_key; - typedef weak_any weak_bcrypt_secret; -#endif // __WIL_BCRYPT_H_STL - - -#if defined(__RPCNDR_H__) && !defined(__WIL__RPCNDR_H__) && !defined(WIL_KERNEL_MODE) -#define __WIL__RPCNDR_H__ - - //! Function deleter for use with pointers allocated by MIDL_user_allocate - using midl_deleter = function_deleter; - - //! Unique-ptr holding a type allocated by MIDL_user_alloc or returned from an RPC invocation - template using unique_midl_ptr = wistd::unique_ptr; - - //! Unique-ptr for strings allocated by MIDL_user_alloc - using unique_midl_string = unique_midl_ptr; -#ifndef WIL_NO_ANSI_STRINGS - using unique_midl_ansistring = unique_midl_ptr; -#endif - - namespace details - { - struct midl_allocator - { - static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT - { - return ::MIDL_user_allocate(size); - } - }; - - // Specialization to support construction of unique_midl_string instances - template<> struct string_allocator : midl_allocator {}; - -#ifndef WIL_NO_ANSI_STRINGS - template<> struct string_allocator : midl_allocator {}; -#endif - } -#endif // __WIL__RPCNDR_H__ - -#if defined(_OBJBASE_H_) && !defined(__WIL_OBJBASE_H_) && !defined(WIL_KERNEL_MODE) -#define __WIL_OBJBASE_H_ - using cotaskmem_deleter = function_deleter; - - template - using unique_cotaskmem_ptr = wistd::unique_ptr; - - template - using unique_cotaskmem_array_ptr = unique_array_ptr; - - /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. - Use `wil::make_unique_cotaskmem_nothrow()` for resources returned from APIs that must satisfy a memory allocation contract that requires the use of `CoTaskMemAlloc()` / `CoTaskMemFree()`. - Use `wil::make_unique_nothrow()` when `CoTaskMemAlloc()` is not required. - - Allocations are initialized with placement new and will call constructors (if present), but this does not guarantee initialization. - - Note that `wil::make_unique_cotaskmem_nothrow()` is not marked WI_NOEXCEPT as it may be used to create an exception-based class that may throw in its constructor. - ~~~ - auto foo = wil::make_unique_cotaskmem_nothrow(); - if (foo) - { - // initialize allocated Foo object as appropriate - } - ~~~ - */ - template - inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type make_unique_cotaskmem_nothrow(Args&&... args) - { - static_assert(wistd::is_trivially_destructible::value, "T has a destructor that won't be run when used with this function; use make_unique instead"); - unique_cotaskmem_ptr sp(static_cast(::CoTaskMemAlloc(sizeof(T)))); - if (sp) - { - // use placement new to initialize memory from the previous allocation - new (sp.get()) T(wistd::forward(args)...); - } - return sp; - } - - /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. - See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_cotaskmem_nothrow(size); - if (foos) - { - for (auto& elem : wil::make_range(foos.get(), size)) - { - // initialize allocated Foo objects as appropriate - } - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_ptr>::type make_unique_cotaskmem_nothrow(size_t size) - { - typedef typename wistd::remove_extent::type E; - static_assert(wistd::is_trivially_destructible::value, "E has a destructor that won't be run when used with this function; use make_unique instead"); - FAIL_FAST_IF((__WI_SIZE_MAX / sizeof(E)) < size); - size_t allocSize = sizeof(E) * size; - unique_cotaskmem_ptr sp(static_cast(::CoTaskMemAlloc(allocSize))); - if (sp) - { - // use placement new to initialize memory from the previous allocation; - // note that array placement new cannot be used as the standard allows for operator new[] - // to consume overhead in the allocation for internal bookkeeping - for (auto& elem : make_range(static_cast(sp.get()), size)) - { - new (&elem) E(); - } - } - return sp; - } - - /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. - See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. - ~~~ - auto foo = wil::make_unique_cotaskmem_failfast(); - // initialize allocated Foo object as appropriate - ~~~ - */ - template - inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type make_unique_cotaskmem_failfast(Args&&... args) - { - unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(wistd::forward(args)...)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; - } - - /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. - See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_cotaskmem_failfast(size); - for (auto& elem : wil::make_range(foos.get(), size)) - { - // initialize allocated Foo objects as appropriate - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_ptr>::type make_unique_cotaskmem_failfast(size_t size) - { - unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(size)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - /** Provides `std::make_unique()` semantics for resources allocated with `CoTaskMemAlloc()`. - See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. - ~~~ - auto foo = wil::make_unique_cotaskmem(); - // initialize allocated Foo object as appropriate - ~~~ - */ - template - inline typename wistd::enable_if::value, unique_cotaskmem_ptr>::type make_unique_cotaskmem(Args&&... args) - { - unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(wistd::forward(args)...)); - THROW_IF_NULL_ALLOC(result); - return result; - } - - /** Provides `std::make_unique()` semantics for array resources allocated with `CoTaskMemAlloc()`. - See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_cotaskmem(size); - for (auto& elem : wil::make_range(foos.get(), size)) - { - // initialize allocated Foo objects as appropriate - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_ptr>::type make_unique_cotaskmem(size_t size) - { - unique_cotaskmem_ptr result(make_unique_cotaskmem_nothrow(size)); - THROW_IF_NULL_ALLOC(result); - return result; - } -#endif // WIL_ENABLE_EXCEPTIONS - - typedef unique_any unique_cotaskmem; - typedef unique_any unique_cotaskmem_string; -#ifndef WIL_NO_ANSI_STRINGS - typedef unique_any unique_cotaskmem_ansistring; -#endif // WIL_NO_ANSI_STRINGS - - /// @cond - namespace details - { - struct cotaskmem_allocator - { - static _Ret_opt_bytecap_(size) void* allocate(size_t size) WI_NOEXCEPT - { - return ::CoTaskMemAlloc(size); - } - }; - - template<> struct string_allocator : cotaskmem_allocator {}; - -#ifndef WIL_NO_ANSI_STRINGS - template<> struct string_allocator : cotaskmem_allocator {}; -#endif // WIL_NO_ANSI_STRINGS - } - /// @endcond - - inline auto make_cotaskmem_string_nothrow( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT - { - return make_unique_string_nothrow(source, length); - } - - inline auto make_cotaskmem_string_failfast( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCWSTR source, size_t length = static_cast(-1)) WI_NOEXCEPT - { - return make_unique_string_failfast(source, length); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - inline auto make_cotaskmem_string( - _When_((source != nullptr) && length != static_cast(-1), _In_reads_(length)) - _When_((source != nullptr) && length == static_cast(-1), _In_z_) - PCWSTR source, size_t length = static_cast(-1)) - { - return make_unique_string(source, length); - } - -#endif // WIL_ENABLE_EXCEPTIONS -#endif // __WIL_OBJBASE_H_ -#if defined(__WIL_OBJBASE_H_) && !defined(__WIL_OBJBASE_H_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_OBJBASE_H_STL - typedef shared_any shared_cotaskmem; - typedef weak_any weak_cotaskmem; - typedef shared_any shared_cotaskmem_string; - typedef weak_any weak_cotaskmem_string; -#endif // __WIL_OBJBASE_H_STL - -#if defined(__WIL_OBJBASE_H_) && defined(__WIL_WINBASE_) && !defined(__WIL_OBJBASE_AND_WINBASE_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_OBJBASE_AND_WINBASE_H_ - - struct cotaskmem_secure_deleter - { - template - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ T* p) const - { - if (p) - { - IMalloc* malloc; - if (SUCCEEDED(::CoGetMalloc(1, &malloc))) - { - size_t const size = malloc->GetSize(p); - if (size != static_cast(-1)) - { - ::SecureZeroMemory(p, size); - } - malloc->Release(); - } - ::CoTaskMemFree(p); - } - } - }; - - template - using unique_cotaskmem_secure_ptr = wistd::unique_ptr; - - /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. - See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. - ~~~ - auto foo = wil::make_unique_cotaskmem_secure_nothrow(); - if (foo) - { - // initialize allocated Foo object as appropriate - } - ~~~ - */ - template - inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_nothrow(Args&&... args) - { - return unique_cotaskmem_secure_ptr(make_unique_cotaskmem_nothrow(wistd::forward(args)...).release()); - } - - /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. - See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_cotaskmem_secure_nothrow(size); - if (foos) - { - for (auto& elem : wil::make_range(foos.get(), size)) - { - // initialize allocated Foo objects as appropriate - } - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_nothrow(size_t size) - { - return unique_cotaskmem_secure_ptr(make_unique_cotaskmem_nothrow(size).release()); - } - - /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. - See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. - ~~~ - auto foo = wil::make_unique_cotaskmem_secure_failfast(); - // initialize allocated Foo object as appropriate - ~~~ - */ - template - inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_failfast(Args&&... args) - { - unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(wistd::forward(args)...)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; - } - - /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. - See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_cotaskmem_secure_failfast(size); - for (auto& elem : wil::make_range(foos.get(), size)) - { - // initialize allocated Foo objects as appropriate - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure_failfast(size_t size) - { - unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(size)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - /** Provides `std::make_unique()` semantics for secure resources allocated with `CoTaskMemAlloc()`. - See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. - ~~~ - auto foo = wil::make_unique_cotaskmem_secure(); - // initialize allocated Foo object as appropriate - ~~~ - */ - template - inline typename wistd::enable_if::value, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure(Args&&... args) - { - unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(wistd::forward(args)...)); - THROW_IF_NULL_ALLOC(result); - return result; - } - - /** Provides `std::make_unique()` semantics for secure array resources allocated with `CoTaskMemAlloc()`. - See the overload of `wil::make_unique_cotaskmem_nothrow()` for non-array types for more details. - ~~~ - const size_t size = 42; - auto foos = wil::make_unique_cotaskmem_secure(size); - for (auto& elem : wil::make_range(foos.get(), size)) - { - // initialize allocated Foo objects as appropriate - } - ~~~ - */ - template - inline typename wistd::enable_if::value && wistd::extent::value == 0, unique_cotaskmem_secure_ptr>::type make_unique_cotaskmem_secure(size_t size) - { - unique_cotaskmem_secure_ptr result(make_unique_cotaskmem_secure_nothrow(size)); - THROW_IF_NULL_ALLOC(result); - return result; - } -#endif // WIL_ENABLE_EXCEPTIONS - - typedef unique_cotaskmem_secure_ptr unique_cotaskmem_string_secure; - - /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()` in a context that may not throw upon allocation failure. - See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details. - ~~~ - auto str = wil::make_cotaskmem_string_secure_nothrow(L"a string"); - if (str) - { - std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" - } - ~~~ - */ - inline unique_cotaskmem_string_secure make_cotaskmem_string_secure_nothrow(_In_ PCWSTR source) WI_NOEXCEPT - { - return unique_cotaskmem_string_secure(make_cotaskmem_string_nothrow(source).release()); - } - - /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()` in a context that must fail fast upon allocation failure. - See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details. - ~~~ - auto str = wil::make_cotaskmem_string_secure_failfast(L"a string"); - std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" - ~~~ - */ - inline unique_cotaskmem_string_secure make_cotaskmem_string_secure_failfast(_In_ PCWSTR source) WI_NOEXCEPT - { - unique_cotaskmem_string_secure result(make_cotaskmem_string_secure_nothrow(source)); - FAIL_FAST_IF_NULL_ALLOC(result); - return result; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - /** Copies a given string into secure memory allocated with `CoTaskMemAlloc()`. - See the overload of `wil::make_cotaskmem_string_nothrow()` with supplied length for more details. - ~~~ - auto str = wil::make_cotaskmem_string_secure(L"a string"); - std::wcout << L"This is " << str.get() << std::endl; // prints "This is a string" - ~~~ - */ - inline unique_cotaskmem_string_secure make_cotaskmem_string_secure(_In_ PCWSTR source) - { - unique_cotaskmem_string_secure result(make_cotaskmem_string_secure_nothrow(source)); - THROW_IF_NULL_ALLOC(result); - return result; - } -#endif -#endif // __WIL_OBJBASE_AND_WINBASE_H_ - -#if defined(_OLE2_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIL_OLE2_H_) && !defined(WIL_KERNEL_MODE) -#define __WIL_OLE2_H_ - typedef unique_struct unique_stg_medium; - struct unique_hglobal_locked : public unique_any - { - unique_hglobal_locked() = delete; - - explicit unique_hglobal_locked(HGLOBAL global) : unique_any(global) - { - // GlobalLock returns a pointer to the associated global memory block and that's what callers care about. - m_globalMemory = GlobalLock(global); - if (!m_globalMemory) - { - release(); - } - } - - explicit unique_hglobal_locked(STGMEDIUM& medium) : unique_hglobal_locked(medium.hGlobal) - { - } - - WI_NODISCARD pointer get() const - { - return m_globalMemory; - } - - private: - pointer m_globalMemory; - }; - - //! A type that calls OleUninitialize on destruction (or reset()). - //! Use as a replacement for Windows::Foundation::Uninitialize. - using unique_oleuninitialize_call = unique_call; - - //! Calls RoInitialize and fail-fasts if it fails; returns an RAII object that reverts - //! Use as a replacement for Windows::Foundation::Initialize - _Check_return_ inline unique_oleuninitialize_call OleInitialize_failfast() - { - FAIL_FAST_IF_FAILED(::OleInitialize(nullptr)); - return unique_oleuninitialize_call(); - } -#endif // __WIL_OLE2_H_ - -#if defined(__WIL_OLE2_H_) && defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WIL_OLE2_H_EXCEPTIONAL) -#define __WIL_OLE2_H_EXCEPTIONAL - //! Calls RoInitialize and throws an exception if it fails; returns an RAII object that reverts - //! Use as a replacement for Windows::Foundation::Initialize - _Check_return_ inline unique_oleuninitialize_call OleInitialize() - { - THROW_IF_FAILED(::OleInitialize(nullptr)); - return unique_oleuninitialize_call(); - } -#endif - -#if defined(_INC_COMMCTRL) && !defined(__WIL_INC_COMMCTRL) && !defined(WIL_KERNEL_MODE) -#define __WIL_INC_COMMCTRL - typedef unique_any unique_himagelist; -#endif // __WIL_INC_COMMCTRL -#if defined(__WIL_INC_COMMCTRL) && !defined(__WIL_INC_COMMCTRL_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_INC_COMMCTRL_STL - typedef shared_any shared_himagelist; - typedef weak_any weak_himagelist; -#endif // __WIL_INC_COMMCTRL_STL - -#if defined(_UXTHEME_H_) && !defined(__WIL_INC_UXTHEME) && !defined(WIL_KERNEL_MODE) -#define __WIL_INC_UXTHEME - typedef unique_any unique_htheme; -#endif // __WIL_INC_UXTHEME - -#pragma warning(push) -#pragma warning(disable:4995) -#if defined(_INC_USERENV) && !defined(__WIL_INC_USERENV) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE) -#define __WIL_INC_USERENV - typedef unique_any unique_environment_block; -#endif // __WIL_INC_USERENV -#pragma warning(pop) - -#if defined(__WINEVT_H__) && !defined(__WIL_INC_EVT_HANDLE) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_PKG_EVENTLOGSERVICE) && !defined(WIL_KERNEL_MODE) -#define __WIL_INC_EVT_HANDLE - typedef unique_any unique_evt_handle; -#endif // __WIL_INC_EVT_HANDLE - -#if defined(_WINSVC_) && !defined(__WIL_HANDLE_H_WINSVC) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE) -#define __WIL_HANDLE_H_WINSVC - typedef unique_any unique_schandle; -#endif // __WIL_HANDLE_H_WINSVC -#if defined(__WIL_HANDLE_H_WINSVC) && !defined(__WIL_HANDLE_H_WINSVC_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_HANDLE_H_WINSVC_STL - typedef shared_any shared_schandle; - typedef weak_any weak_schandle; -#endif // __WIL_HANDLE_H_WINSVC_STL - -#if defined(_INC_STDIO) && !defined(__WIL_INC_STDIO) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(WIL_KERNEL_MODE) -#define __WIL_INC_STDIO - typedef unique_any unique_pipe; - typedef unique_any unique_file; -#endif // __WIL_INC_STDIO -#if defined(__WIL_INC_STDIO) && !defined(__WIL__INC_STDIO_STL) && defined(WIL_RESOURCE_STL) -#define __WIL__INC_STDIO_STL - typedef shared_any shared_pipe; - typedef weak_any weak_pipe; - typedef shared_any shared_file; - typedef weak_any weak_file; -#endif // __WIL__INC_STDIO_STL - -#if defined(_INC_LOCALE) && !defined(__WIL_INC_LOCALE) && !defined(WIL_KERNEL_MODE) -#define __WIL_INC_LOCALE - typedef unique_any<_locale_t, decltype(&::_free_locale), ::_free_locale> unique_locale; -#endif // __WIL_INC_LOCALE -#if defined(__WIL_INC_LOCALE) && !defined(__WIL__INC_LOCALE_STL) && defined(WIL_RESOURCE_STL) -#define __WIL__INC_LOCALE_STL - typedef shared_any shared_locale; - typedef weak_any weak_locale; -#endif // __WIL__INC_LOCALE_STL - -#if defined(_NTLSA_) && !defined(__WIL_NTLSA_) && !defined(WIL_KERNEL_MODE) -#define __WIL_NTLSA_ - typedef unique_any unique_hlsa; - - using lsa_freemem_deleter = function_deleter; - - template - using unique_lsamem_ptr = wistd::unique_ptr; -#endif // _NTLSA_ -#if defined(_NTLSA_) && !defined(__WIL_NTLSA_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_NTLSA_STL - typedef shared_any shared_hlsa; - typedef weak_any weak_hlsa; -#endif // _NTLSA_ - -#if defined(_LSALOOKUP_) && !defined(__WIL_LSALOOKUP_) -#define __WIL_LSALOOKUP_ - typedef unique_any unique_hlsalookup; - - using lsalookup_freemem_deleter = function_deleter; - - template - using unique_lsalookupmem_ptr = wistd::unique_ptr; -#endif // _LSALOOKUP_ -#if defined(_LSALOOKUP_) && !defined(__WIL_LSALOOKUP_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_LSALOOKUP_STL - typedef shared_any shared_hlsalookup; - typedef weak_any weak_hlsalookup; -#endif // _LSALOOKUP_ - -#if defined(_NTLSA_IFS_) && !defined(__WIL_HANDLE_H_NTLSA_IFS_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_HANDLE_H_NTLSA_IFS_ - using lsa_deleter = function_deleter; - - template - using unique_lsa_ptr = wistd::unique_ptr; -#endif // __WIL_HANDLE_H_NTLSA_IFS_ - -#if defined(__WERAPI_H__) && !defined(__WIL_WERAPI_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_WERAPI_H__ - typedef unique_any unique_wer_report; -#endif - -#if defined(__MIDLES_H__) && !defined(__WIL_MIDLES_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_MIDLES_H__ - typedef unique_any unique_rpc_pickle; -#endif -#if defined(__WIL_MIDLES_H__) && !defined(__WIL_MIDLES_H_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_MIDLES_H_STL - typedef shared_any shared_rpc_pickle; - typedef weak_any weak_rpc_pickle; -#endif - -#if defined(__RPCDCE_H__) && !defined(__WIL_RPCDCE_H__) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_RPCDCE_H__ - /// @cond - namespace details - { - inline void __stdcall WpRpcBindingFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_BINDING_HANDLE binding) - { - ::RpcBindingFree(&binding); - } - - inline void __stdcall WpRpcBindingVectorFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_BINDING_VECTOR* bindingVector) - { - ::RpcBindingVectorFree(&bindingVector); - } - - inline void __stdcall WpRpcStringFree(_Pre_opt_valid_ _Frees_ptr_opt_ RPC_WSTR wstr) - { - ::RpcStringFreeW(&wstr); - } - } - /// @endcond - - typedef unique_any unique_rpc_binding; - typedef unique_any unique_rpc_binding_vector; - typedef unique_any unique_rpc_wstr; -#endif -#if defined(__WIL_RPCDCE_H__) && !defined(__WIL_RPCDCE_H_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_RPCDCE_H_STL - typedef shared_any shared_rpc_binding; - typedef weak_any weak_rpc_binding; - typedef shared_any shared_rpc_binding_vector; - typedef weak_any weak_rpc_binding_vector; - typedef shared_any shared_rpc_wstr; - typedef weak_any weak_rpc_wstr; -#endif - -#if defined(_WCMAPI_H) && !defined(__WIL_WCMAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_WCMAPI_H_ - using wcm_deleter = function_deleter; - - template - using unique_wcm_ptr = wistd::unique_ptr; -#endif - -#if defined(_NETIOAPI_H_) && defined(_WS2IPDEF_) && defined(MIB_INVALID_TEREDO_PORT_NUMBER) && !defined(__WIL_NETIOAPI_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_NETIOAPI_H_ - typedef unique_any unique_mib_iftable; -#endif -#if defined(__WIL_NETIOAPI_H_) && !defined(__WIL_NETIOAPI_H_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_NETIOAPI_H_STL - typedef shared_any shared_mib_iftable; - typedef weak_any weak_mib_iftable; -#endif - -#if defined(_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_WLAN_WLANAPI_H - using wlan_deleter = function_deleter; - - template - using unique_wlan_ptr = wistd::unique_ptr < T, wlan_deleter >; - - /// @cond - namespace details - { - inline void __stdcall CloseWlanHandle(_Frees_ptr_ HANDLE hClientHandle) - { - ::WlanCloseHandle(hClientHandle, nullptr); - } - } - /// @endcond - - typedef unique_any unique_wlan_handle; -#endif -#if defined(__WIL_WLAN_WLANAPI_H) && !defined(__WIL_WLAN_WLANAPI_H_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_WLAN_WLANAPI_H_STL - typedef shared_any shared_wlan_handle; - typedef weak_any weak_wlan_handle; -#endif - -#if defined(_HPOWERNOTIFY_DEF_) && !defined(__WIL_HPOWERNOTIFY_DEF_H_) && !defined(WIL_KERNEL_MODE) -#define __WIL_HPOWERNOTIFY_DEF_H_ - typedef unique_any unique_hpowernotify; -#endif - -#if defined(__WIL_WINBASE_DESKTOP) && defined(SID_DEFINED) && !defined(__WIL_PSID_DEF_H_) -#define __WIL_PSID_DEF_H_ - typedef unique_any unique_any_psid; -#if defined(_OBJBASE_H_) - typedef unique_any unique_cotaskmem_psid; -#endif -#endif - -#if defined(_PROCESSTHREADSAPI_H_) && !defined(__WIL_PROCESSTHREADSAPI_H_DESK_SYS) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && !defined(WIL_KERNEL_MODE) -#define __WIL_PROCESSTHREADSAPI_H_DESK_SYS - /// @cond - namespace details - { - inline void __stdcall CloseProcessInformation(_In_ PROCESS_INFORMATION* p) - { - if (p->hProcess) - { - CloseHandle(p->hProcess); - } - - if (p->hThread) - { - CloseHandle(p->hThread); - } - } - } - /// @endcond - - /** Manages the outbound parameter containing handles returned by `CreateProcess()` and related methods. - ~~~ - unique_process_information process; - CreateProcessW(..., CREATE_SUSPENDED, ..., &process); - THROW_LAST_ERROR_IF(ResumeThread(process.hThread) == -1); - THROW_LAST_ERROR_IF(WaitForSingleObject(process.hProcess, INFINITE) != WAIT_OBJECT_0); - ~~~ - */ - using unique_process_information = unique_struct; -#endif - -#if defined(_PROCESSENV_) && !defined(__WIL__PROCESSENV_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) -#define __WIL__PROCESSENV_ - /** Manages lifecycle of an environment-strings block - ~~~ - wil::unique_environstrings_ptr env { ::GetEnvironmentStringsW() }; - const wchar_t *nextVar = env.get(); - while (nextVar && *nextVar) - { - // consume 'nextVar' - nextVar += wcslen(nextVar) + 1; - } - ~~~ - */ - using unique_environstrings_ptr = wistd::unique_ptr>; - -#ifndef WIL_NO_ANSI_STRINGS - //! ANSI equivalent to unique_environstrings_ptr; - using unique_environansistrings_ptr = wistd::unique_ptr>; -#endif -#endif - -#if defined(_APPMODEL_H_) && !defined(__WIL_APPMODEL_H_) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) -#define __WIL_APPMODEL_H_ - typedef unique_any unique_package_info_reference; -#endif // __WIL_APPMODEL_H_ -#if defined(__WIL_APPMODEL_H_) && !defined(__WIL_APPMODEL_H_STL) && defined(WIL_RESOURCE_STL) -#define __WIL_APPMODEL_H_STL - typedef shared_any shared_package_info_reference; - typedef weak_any weak_package_info_reference; -#endif // __WIL_APPMODEL_H_STL - -#if defined(WDFAPI) && !defined(__WIL_WDFAPI) -#define __WIL_WDFAPI - - namespace details - { - template - using wdf_object_resource_policy = resource_policy; - } - - template - using unique_wdf_any = unique_any_t>>; - - using unique_wdf_object = unique_wdf_any; - - using unique_wdf_timer = unique_wdf_any; - using unique_wdf_work_item = unique_wdf_any; - - using unique_wdf_memory = unique_wdf_any; - - using unique_wdf_dma_enabler = unique_wdf_any; - using unique_wdf_dma_transaction = unique_wdf_any; - using unique_wdf_common_buffer = unique_wdf_any; - - using unique_wdf_key = unique_wdf_any; - using unique_wdf_string = unique_wdf_any; - using unique_wdf_collection = unique_wdf_any; - - using wdf_wait_lock_release_scope_exit = - unique_any< - WDFWAITLOCK, - decltype(&::WdfWaitLockRelease), - ::WdfWaitLockRelease, - details::pointer_access_none>; - -#if defined(WIL_KERNEL_MODE) - using unique_wdf_device_init = - unique_any< - WDFDEVICE_INIT *, - decltype(&::WdfDeviceInitFree), - ::WdfDeviceInitFree>; -#endif - - inline - WI_NODISCARD - _IRQL_requires_max_(PASSIVE_LEVEL) - _Acquires_lock_(lock) - wdf_wait_lock_release_scope_exit - acquire_wdf_wait_lock(WDFWAITLOCK lock) WI_NOEXCEPT - { - ::WdfWaitLockAcquire(lock, nullptr); - return wdf_wait_lock_release_scope_exit(lock); - } - - inline - WI_NODISCARD - _IRQL_requires_max_(APC_LEVEL) - _When_(return, _Acquires_lock_(lock)) - wdf_wait_lock_release_scope_exit - try_acquire_wdf_wait_lock(WDFWAITLOCK lock) WI_NOEXCEPT - { - LONGLONG timeout = 0; - NTSTATUS status = ::WdfWaitLockAcquire(lock, &timeout); - if (status == STATUS_SUCCESS) - { - return wdf_wait_lock_release_scope_exit(lock); - } - else - { - return wdf_wait_lock_release_scope_exit(); - } - } - - using wdf_spin_lock_release_scope_exit = - unique_any< - WDFSPINLOCK, - decltype(&::WdfSpinLockRelease), - ::WdfSpinLockRelease, - details::pointer_access_none>; - - inline - WI_NODISCARD - _IRQL_requires_max_(DISPATCH_LEVEL) - _IRQL_raises_(DISPATCH_LEVEL) - _Acquires_lock_(lock) - wdf_spin_lock_release_scope_exit - acquire_wdf_spin_lock(WDFSPINLOCK lock) WI_NOEXCEPT - { - ::WdfSpinLockAcquire(lock); - return wdf_spin_lock_release_scope_exit(lock); - } - - namespace details - { - template - using unique_wdf_lock_storage = unique_storage>; - - class unique_wdf_spin_lock_storage : public unique_wdf_lock_storage - { - using wdf_lock_storage_t = unique_wdf_lock_storage; - - public: - using pointer = wdf_lock_storage_t::pointer; - - // Forward all base class constructors, but have it be explicit. - template - explicit unique_wdf_spin_lock_storage(args_t&& ... args) WI_NOEXCEPT : wdf_lock_storage_t(wistd::forward(args)...) {} - - NTSTATUS create(_In_opt_ WDF_OBJECT_ATTRIBUTES* attributes = WDF_NO_OBJECT_ATTRIBUTES) - { - return ::WdfSpinLockCreate(attributes, out_param(*this)); - } - - WI_NODISCARD - _IRQL_requires_max_(DISPATCH_LEVEL) - _IRQL_raises_(DISPATCH_LEVEL) - wdf_spin_lock_release_scope_exit acquire() WI_NOEXCEPT - { - return wil::acquire_wdf_spin_lock(wdf_lock_storage_t::get()); - } - }; - - class unique_wdf_wait_lock_storage : public unique_wdf_lock_storage - { - using wdf_lock_storage_t = unique_wdf_lock_storage; - - public: - using pointer = wdf_lock_storage_t::pointer; - - // Forward all base class constructors, but have it be explicit. - template - explicit unique_wdf_wait_lock_storage(args_t&& ... args) WI_NOEXCEPT : wdf_lock_storage_t(wistd::forward(args)...) {} - - NTSTATUS create(_In_opt_ WDF_OBJECT_ATTRIBUTES* attributes = WDF_NO_OBJECT_ATTRIBUTES) - { - return ::WdfWaitLockCreate(attributes, out_param(*this)); - } - - WI_NODISCARD - _IRQL_requires_max_(PASSIVE_LEVEL) - wdf_wait_lock_release_scope_exit acquire() WI_NOEXCEPT - { - return wil::acquire_wdf_wait_lock(wdf_lock_storage_t::get()); - } - - WI_NODISCARD - _IRQL_requires_max_(APC_LEVEL) - wdf_wait_lock_release_scope_exit try_acquire() WI_NOEXCEPT - { - return wil::try_acquire_wdf_wait_lock(wdf_lock_storage_t::get()); - } - }; - } - - using unique_wdf_wait_lock = unique_any_t; - using unique_wdf_spin_lock = unique_any_t; - - //! unique_wdf_object_reference is a RAII type for managing WDF object references acquired using - //! the WdfObjectReference* family of APIs. The behavior of this class is exactly identical to - //! wil::unique_any but a few methods have some WDF-object-reference-specific enhancements. - //! - //! * The constructor takes not only a WDFOBJECT-compatible type or a wil::unique_wdf_any, but - //! optionally also a tag with which the reference was acquired. - //! * A get_tag() method is provided to retrieve the tag. - //! * reset() is similar to the constructor in that it also optionally takes a tag. - //! * release() optionally takes an out-param that returns the tag. - //! - //! These subtle differences make it impossible to reuse the wil::unique_any_t template for its implementation. - template - class unique_wdf_object_reference - { - public: - unique_wdf_object_reference() WI_NOEXCEPT = default; - - //! Wrap a WDF object reference that has already been acquired into this RAII type. If you - //! want to acquire a new reference instead, use WI_WdfObjectReferenceIncrement. - explicit unique_wdf_object_reference(wdf_object_t wdfObject, void* tag = nullptr) WI_NOEXCEPT - : m_wdfObject(wdfObject), m_tag(tag) - { - } - - //! This is similar to the constructor that takes a raw WDF handle but is enlightened to - //! take a const-ref to a wil::unique_wdf_any<> instead, obviating the need to call .get() - //! on it. As with the other constructor, the expectation is that the raw reference has - //! already been acquired and ownership is being transferred into this RAII object. - explicit unique_wdf_object_reference(const wil::unique_wdf_any& wdfObject, void* tag = nullptr) WI_NOEXCEPT - : unique_wdf_object_reference(wdfObject.get(), tag) - { - } - - unique_wdf_object_reference(const unique_wdf_object_reference&) = delete; - unique_wdf_object_reference& operator=(const unique_wdf_object_reference&) = delete; - - unique_wdf_object_reference(unique_wdf_object_reference&& other) - : m_wdfObject(other.m_wdfObject), m_tag(other.m_tag) - { - other.m_wdfObject = WDF_NO_HANDLE; - other.m_tag = nullptr; - } - - unique_wdf_object_reference& operator=(unique_wdf_object_reference&& other) - { - if (this != wistd::addressof(other)) - { - reset(other.m_wdfObject, other.m_tag); - other.m_wdfObject = WDF_NO_HANDLE; - other.m_tag = nullptr; - } - - return *this; - } - - ~unique_wdf_object_reference() WI_NOEXCEPT - { - reset(); - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return m_wdfObject != WDF_NO_HANDLE; - } - - WI_NODISCARD wdf_object_t get() const WI_NOEXCEPT - { - return m_wdfObject; - } - - WI_NODISCARD void* get_tag() const WI_NOEXCEPT - { - return m_tag; - } - - //! Replaces the current instance (releasing it if it exists) with a new WDF object - //! reference that has already been acquired by the caller. - void reset(wdf_object_t wdfObject = WDF_NO_HANDLE, void* tag = nullptr) WI_NOEXCEPT - { - if (m_wdfObject != WDF_NO_HANDLE) - { - // We don't use WdfObjectDereferenceActual because there is no way to provide the - // correct __LINE__ and __FILE__, but if you use RAII all the way, you shouldn't have to - // worry about where it was released, only where it was acquired. - WdfObjectDereferenceWithTag(m_wdfObject, m_tag); - } - - m_wdfObject = wdfObject; - m_tag = tag; - } - - void reset(const wil::unique_wdf_any& wdfObject, void* tag = nullptr) WI_NOEXCEPT - { - reset(wdfObject.get(), tag); - } - - wdf_object_t release(_Outptr_opt_ void** tag = nullptr) WI_NOEXCEPT - { - const auto wdfObject = m_wdfObject; - wil::assign_to_opt_param(tag, m_tag); - m_wdfObject = WDF_NO_HANDLE; - m_tag = nullptr; - return wdfObject; - } - - void swap(unique_wdf_object_reference& other) WI_NOEXCEPT - { - wistd::swap_wil(m_wdfObject, other.m_wdfObject); - wistd::swap_wil(m_tag, other.m_tag); - } - - //! Drops the current reference if any, and returns a pointer to a WDF handle which can - //! receive a newly referenced WDF handle. The tag is assumed to be nullptr. If a different - //! tag needs to be used, a temporary variable will need to be used to receive the WDF - //! handle and a unique_wdf_object_reference will need to be constructed with it. - //! - //! The quintessential use-case for this method is WdfIoQueueFindRequest. - wdf_object_t* put() WI_NOEXCEPT - { - reset(); - return &m_wdfObject; - } - - wdf_object_t* operator&() WI_NOEXCEPT - { - return put(); - } - - private: - wdf_object_t m_wdfObject = WDF_NO_HANDLE; - void* m_tag = nullptr; - }; - - // Increment the ref-count on a WDF object and return a unique_wdf_object_reference for it. Use - // WI_WdfObjectReferenceIncrement to automatically use the call-site source location. Use this - // function only if the call-site source location is obtained from elsewhere (i.e., plumbed - // through other abstractions). - template - inline WI_NODISCARD unique_wdf_object_reference wdf_object_reference_increment( - wdf_object_t wdfObject, PVOID tag, LONG lineNumber, PCSTR fileName) WI_NOEXCEPT - { - // Parameter is incorrectly marked as non-const, so the const-cast is required. - ::WdfObjectReferenceActual(wdfObject, tag, lineNumber, const_cast(fileName)); - return unique_wdf_object_reference{ wdfObject, tag }; - } - - template - inline WI_NODISCARD unique_wdf_object_reference wdf_object_reference_increment( - const wil::unique_wdf_any& wdfObject, PVOID tag, LONG lineNumber, PCSTR fileName) WI_NOEXCEPT - { - return wdf_object_reference_increment(wdfObject.get(), tag, lineNumber, fileName); - } - -// A macro so that we can capture __LINE__ and __FILE__. -#define WI_WdfObjectReferenceIncrement(wdfObject, tag) \ - wil::wdf_object_reference_increment(wdfObject, tag, __LINE__, __FILE__) - - //! wdf_request_completer is a unique_any-like RAII class for managing completion of a - //! WDFREQUEST. On destruction or explicit reset() it completes the WDFREQUEST with parameters - //! (status, information, priority boost) previously set using methods on this class. - //! - //! This class does not use the unique_any_t template primarily because the release() and put() - //! methods need to return a WDFREQUEST/WDFREQUEST*, as opposed to the internal storage type. - class wdf_request_completer - { - public: - - explicit wdf_request_completer(WDFREQUEST wdfRequest = WDF_NO_HANDLE) WI_NOEXCEPT - : m_wdfRequest(wdfRequest) - { - } - - wdf_request_completer(const wdf_request_completer&) = delete; - wdf_request_completer& operator=(const wdf_request_completer&) = delete; - - wdf_request_completer(wdf_request_completer&& other) WI_NOEXCEPT - : m_wdfRequest(other.m_wdfRequest), m_status(other.m_status), m_information(other.m_information), -#if defined(WIL_KERNEL_MODE) - m_priorityBoost(other.m_priorityBoost), -#endif - m_completionFlags(other.m_completionFlags) - { - clear_state(other); - } - - wdf_request_completer& operator=(wdf_request_completer&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - reset(); - m_wdfRequest = other.m_wdfRequest; - m_status = other.m_status; - m_information = other.m_information; -#if defined(WIL_KERNEL_MODE) - m_priorityBoost = other.m_priorityBoost; -#endif - m_completionFlags = other.m_completionFlags; - clear_state(other); - } - - return *this; - } - - ~wdf_request_completer() WI_NOEXCEPT - { - reset(); - } - - WI_NODISCARD WDFREQUEST get() const WI_NOEXCEPT - { - return m_wdfRequest; - } - - //! Set the NTSTATUS value with with the WDFREQUEST will be completed when the RAII object - //! goes out of scope or .reset() is called explicitly. Calling this method does *not* - //! complete the request right away. No effect if this object currently does not have - //! ownership of a WDFREQUEST. The expected usage pattern is that set_status() is called - //! only after ownership of a WDFREQUEST is transferred to this object. - void set_status(NTSTATUS status) WI_NOEXCEPT - { - // The contract is that this method has no effect if we currently do not have a - // m_wdfRequest. But that is enforced by discarding all state when a WDFREQUEST is - // attached, not by explicitly checking for that condition here. - - m_status = status; - } - - //! Set the IO_STATUS_BLOCK.Information value with which the WDFREQUEST will be completed. - //! Note that the Information value is not stored directly in the WDFREQUEST using - //! WdfRequestSetInformation. It is only used at the time of completion. No effect if this - //! object currently does not have ownership of a WDFREQUEST. The expected usage pattern is - //! that set_information() is called only after ownership of a WDFREQUEST is transferred to - //! this object. - void set_information(ULONG_PTR information) WI_NOEXCEPT - { - // The contract is that this method has no effect if we currently do not have a - // m_wdfRequest. But that is enforced by discarding all state when a WDFREQUEST is - // attached, not by explicitly checking for that condition here. - - m_completionFlags.informationSet = 1; - m_information = information; - } - -#if defined(WIL_KERNEL_MODE) - //! Set the priority boost with which the WDFREQUEST will be completed. If this method is - //! called, the WDFREQUEST will eventually be completed with - //! WdfRequestCompleteWithPriorityBoost. No effect if this object currently does not have - //! ownership of a WDFREQUEST. The expected usage pattern is that set_priority_boost() is - //! called only after ownership of a WDFREQUEST is transferred to this object. - void set_priority_boost(CCHAR priorityBoost) WI_NOEXCEPT - { - // The contract is that this method has no effect if we currently do not have a - // m_wdfRequest. But that is enforced by discarding all state when a WDFREQUEST is - // attached, not by explicitly checking for that condition here. - - m_completionFlags.priorityBoostSet = 1; - m_priorityBoost = priorityBoost; - } -#endif - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return m_wdfRequest != WDF_NO_HANDLE; - } - - WDFREQUEST* put() WI_NOEXCEPT - { - reset(); - return &m_wdfRequest; - } - - WDFREQUEST* operator&() WI_NOEXCEPT - { - return put(); - } - - //! Relinquishes completion responsibility for the WDFREQUEST. Note that any state - //! (information, priority boost, status) set on this object is lost. This design choice was - //! made because it is atypical to set an information or priority boost value upfront; they - //! are typically set at the point where the request is going to be completed. Hence a - //! use-case wherein release() is called will typically not have set an information or - //! priority boost. - WDFREQUEST release() WI_NOEXCEPT - { - const auto wdfRequest = m_wdfRequest; - clear_state(*this); - return wdfRequest; - } - - void swap(wdf_request_completer& other) WI_NOEXCEPT - { - wistd::swap_wil(m_wdfRequest, other.m_wdfRequest); - wistd::swap_wil(m_information, other.m_information); - wistd::swap_wil(m_status, other.m_status); -#if defined(WIL_KERNEL_MODE) - wistd::swap_wil(m_priorityBoost, other.m_priorityBoost); -#endif - wistd::swap_wil(m_completionFlags, other.m_completionFlags); - } - - void reset(WDFREQUEST newWdfRequest = WDF_NO_HANDLE) - { - if (m_wdfRequest != WDF_NO_HANDLE) - { - // We try to match the usage patterns that the driver would have typically used in the - // various scenarios. For instance, if the driver has set the information field, we'll - // call WdfRequestCompleteWithInformation instead of calling WdfRequestSetInformation - // followed by WdfRequestComplete. - -#if defined(WIL_KERNEL_MODE) - if (m_completionFlags.priorityBoostSet) - { - if (m_completionFlags.informationSet) - { - WdfRequestSetInformation(m_wdfRequest, m_information); - } - - WdfRequestCompleteWithPriorityBoost(m_wdfRequest, m_status, m_priorityBoost); - } - else -#endif - if (m_completionFlags.informationSet) - { - WdfRequestCompleteWithInformation(m_wdfRequest, m_status, m_information); - } - else - { - WdfRequestComplete(m_wdfRequest, m_status); - } - } - - // We call clear_state unconditionally just in case some parameters (status, - // information, etc.) were set prior to attaching a WDFREQUEST to this object. Those - // parameters are not considered relevant to the WDFREQUEST being attached to this - // object now. - clear_state(*this, newWdfRequest); - } - - private: - - static void clear_state(wdf_request_completer& completer, WDFREQUEST newWdfRequest = WDF_NO_HANDLE) WI_NOEXCEPT - { - completer.m_wdfRequest = newWdfRequest; - completer.m_status = STATUS_UNSUCCESSFUL; - completer.m_information = 0; -#if defined(WIL_KERNEL_MODE) - completer.m_priorityBoost = 0; -#endif - completer.m_completionFlags = {}; - } - - // Members are ordered in decreasing size to minimize padding. - - WDFREQUEST m_wdfRequest = WDF_NO_HANDLE; - - // This will not be used unless m_completionFlags.informationSet is set. - ULONG_PTR m_information = 0; - - // There is no reasonably default NTSTATUS value. Callers are expected to explicitly set a - // status value at the point where it is decided that the request needs to be completed. - NTSTATUS m_status = STATUS_UNSUCCESSFUL; - -// UMDF does not support WdfRequestCompleteWithPriorityBoost. -#if defined(WIL_KERNEL_MODE) - // This will not be used unless m_completionFlags.priorityBoostSet is set. - CCHAR m_priorityBoost = 0; -#endif - - struct - { - UINT8 informationSet : 1; -#if defined(WIL_KERNEL_MODE) - UINT8 priorityBoostSet : 1; -#endif - } m_completionFlags = {}; - }; -#endif - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && \ - defined(_CFGMGR32_H_) && \ - (WINVER >= _WIN32_WINNT_WIN8) && \ - !defined(__WIL_CFGMGR32_H_) -#define __WIL_CFGMGR32_H_ - typedef unique_any unique_hcmnotification; -#endif - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) && \ - defined(_SWDEVICE_H_) && \ - (WINVER >= _WIN32_WINNT_WIN8) && \ - !defined(__WIL_SWDEVICE_H_) -#define __WIL_SWDEVICE_H_ - typedef unique_any unique_hswdevice; -#endif - -#if defined(WIL_KERNEL_MODE) && (defined(_WDMDDK_) || defined(_NTDDK_)) && !defined(__WIL_RESOURCE_WDM) -#define __WIL_RESOURCE_WDM - - namespace details - { - struct kspin_lock_saved_irql - { - PKSPIN_LOCK spinLock = nullptr; - KIRQL savedIrql = PASSIVE_LEVEL; - - kspin_lock_saved_irql() = default; - - kspin_lock_saved_irql(PKSPIN_LOCK /* spinLock */) - { - // This constructor exists simply to allow conversion of the pointer type to - // pointer_storage type when constructing an invalid instance. The spinLock pointer - // is expected to be nullptr. - } - - // Exists to satisfy the interconvertibility requirement for pointer_storage and - // pointer. - WI_NODISCARD explicit operator PKSPIN_LOCK() const - { - return spinLock; - } - - _IRQL_requires_(DISPATCH_LEVEL) - static - void Release(_In_ _IRQL_restores_ const kspin_lock_saved_irql& spinLockSavedIrql) - { - KeReleaseSpinLock(spinLockSavedIrql.spinLock, spinLockSavedIrql.savedIrql); - } - }; - - // On some architectures KeReleaseSpinLockFromDpcLevel is a macro, and we need a thunk - // function we can take the address of. - inline - _IRQL_requires_min_(DISPATCH_LEVEL) - void __stdcall ReleaseSpinLockFromDpcLevel(_Inout_ PKSPIN_LOCK spinLock) WI_NOEXCEPT - { - KeReleaseSpinLockFromDpcLevel(spinLock); - } - } - - using kspin_lock_guard = unique_any; - - using kspin_lock_at_dpc_guard = unique_any; - - WI_NODISCARD - inline - _IRQL_requires_max_(DISPATCH_LEVEL) - _IRQL_saves_ - _IRQL_raises_(DISPATCH_LEVEL) - kspin_lock_guard - acquire_kspin_lock(_In_ PKSPIN_LOCK spinLock) - { - details::kspin_lock_saved_irql spinLockSavedIrql; - KeAcquireSpinLock(spinLock, &spinLockSavedIrql.savedIrql); - spinLockSavedIrql.spinLock = spinLock; - return kspin_lock_guard(spinLockSavedIrql); - } - - WI_NODISCARD - inline - _IRQL_requires_min_(DISPATCH_LEVEL) - kspin_lock_at_dpc_guard - acquire_kspin_lock_at_dpc(_In_ PKSPIN_LOCK spinLock) - { - KeAcquireSpinLockAtDpcLevel(spinLock); - return kspin_lock_at_dpc_guard(spinLock); - } - - class kernel_spin_lock - { - public: - kernel_spin_lock() WI_NOEXCEPT - { - ::KeInitializeSpinLock(&m_kSpinLock); - } - - ~kernel_spin_lock() = default; - - // Cannot change memory location. - kernel_spin_lock(const kernel_spin_lock&) = delete; - kernel_spin_lock& operator=(const kernel_spin_lock&) = delete; - kernel_spin_lock(kernel_spin_lock&&) = delete; - kernel_spin_lock& operator=(kernel_spin_lock&&) = delete; - - WI_NODISCARD - _IRQL_requires_max_(DISPATCH_LEVEL) - _IRQL_saves_ - _IRQL_raises_(DISPATCH_LEVEL) - kspin_lock_guard acquire() WI_NOEXCEPT - { - return acquire_kspin_lock(&m_kSpinLock); - } - - WI_NODISCARD - _IRQL_requires_min_(DISPATCH_LEVEL) - kspin_lock_at_dpc_guard acquire_at_dpc() WI_NOEXCEPT - { - return acquire_kspin_lock_at_dpc(&m_kSpinLock); - } - - private: - KSPIN_LOCK m_kSpinLock; - }; - - namespace details - { - template - class kernel_event_t - { - public: - explicit kernel_event_t(bool isSignaled = false) WI_NOEXCEPT - { - ::KeInitializeEvent(&m_kernelEvent, static_cast(eventType), isSignaled ? TRUE : FALSE); - } - - // Cannot change memory location. - kernel_event_t(const kernel_event_t&) = delete; - kernel_event_t(kernel_event_t&&) = delete; - kernel_event_t& operator=(const kernel_event_t&) = delete; - kernel_event_t& operator=(kernel_event_t&&) = delete; - - // Get the underlying KEVENT structure for more advanced usages like - // KeWaitForMultipleObjects or KeWaitForSingleObject with non-default parameters. - PRKEVENT get() WI_NOEXCEPT - { - return &m_kernelEvent; - } - - void clear() WI_NOEXCEPT - { - // The most common use-case is to clear the event with no interest in its previous - // value. Hence, that is the functionality we provide by default. If the previous - // value is required, one may .get() the underlying event object and call - // ::KeResetEvent(). - ::KeClearEvent(&m_kernelEvent); - } - - // Returns the previous state of the event. - bool set(KPRIORITY increment = IO_NO_INCREMENT) WI_NOEXCEPT - { - return ::KeSetEvent(&m_kernelEvent, increment, FALSE) ? true : false; - } - - // Checks if the event is currently signaled. Does not change the state of the event. - WI_NODISCARD bool is_signaled() const WI_NOEXCEPT - { - return ::KeReadStateEvent(const_cast(&m_kernelEvent)) ? true : false; - } - - // Return true if the wait was satisfied. Time is specified in 100ns units, relative - // (negative) or absolute (positive). For more details, see the documentation of - // KeWaitForSingleObject. - bool wait(LONGLONG waitTime) WI_NOEXCEPT - { - LARGE_INTEGER duration; - duration.QuadPart = waitTime; - return wait_for_single_object(&duration); - } - - // Waits indefinitely for the event to be signaled. - void wait() WI_NOEXCEPT - { - wait_for_single_object(nullptr); - } - - private: - bool wait_for_single_object(_In_opt_ LARGE_INTEGER* waitDuration) WI_NOEXCEPT - { - auto status = ::KeWaitForSingleObject(&m_kernelEvent, Executive, KernelMode, FALSE, waitDuration); - - // We specified Executive and non-alertable, which means some of the return values are - // not possible. - WI_ASSERT((status == STATUS_SUCCESS) || (status == STATUS_TIMEOUT)); - return (status == STATUS_SUCCESS); - } - - KEVENT m_kernelEvent; - }; - } - - using kernel_event_auto_reset = details::kernel_event_t; - using kernel_event_manual_reset = details::kernel_event_t; - using kernel_event = kernel_event_auto_reset; // For parity with the default for other WIL event types. - - /** - RAII class and lock-guards for a kernel FAST_MUTEX. - */ - - using fast_mutex_guard = unique_any; - - WI_NODISCARD - inline - _IRQL_requires_max_(APC_LEVEL) - fast_mutex_guard acquire_fast_mutex(FAST_MUTEX* fastMutex) WI_NOEXCEPT - { - ::ExAcquireFastMutex(fastMutex); - return fast_mutex_guard(fastMutex); - } - - WI_NODISCARD - inline - _IRQL_requires_max_(APC_LEVEL) - fast_mutex_guard try_acquire_fast_mutex(FAST_MUTEX* fastMutex) WI_NOEXCEPT - { - if (::ExTryToAcquireFastMutex(fastMutex)) - { - return fast_mutex_guard(fastMutex); - } - else - { - return fast_mutex_guard(); - } - } - - class fast_mutex - { - public: - fast_mutex() WI_NOEXCEPT - { - ::ExInitializeFastMutex(&m_fastMutex); - } - - ~fast_mutex() WI_NOEXCEPT = default; - - // Cannot change memory location. - fast_mutex(const fast_mutex&) = delete; - fast_mutex& operator=(const fast_mutex&) = delete; - fast_mutex(fast_mutex&&) = delete; - fast_mutex& operator=(fast_mutex&&) = delete; - - // Calls ExAcquireFastMutex. Returned wil::unique_any object calls ExReleaseFastMutex on - // destruction. - WI_NODISCARD - _IRQL_requires_max_(APC_LEVEL) - fast_mutex_guard acquire() WI_NOEXCEPT - { - return acquire_fast_mutex(&m_fastMutex); - } - - // Calls ExTryToAcquireFastMutex. Returned wil::unique_any may be empty. If non-empty, it - // calls ExReleaseFastMutex on destruction. - WI_NODISCARD - _IRQL_requires_max_(APC_LEVEL) - fast_mutex_guard try_acquire() WI_NOEXCEPT - { - return try_acquire_fast_mutex(&m_fastMutex); - } - - private: - FAST_MUTEX m_fastMutex; - }; - - namespace details - { - _IRQL_requires_max_(APC_LEVEL) - inline void release_fast_mutex_with_critical_region(FAST_MUTEX* fastMutex) WI_NOEXCEPT - { - ::ExReleaseFastMutexUnsafe(fastMutex); - ::KeLeaveCriticalRegion(); - } - } - - using fast_mutex_with_critical_region_guard = - unique_any; - - WI_NODISCARD - inline - _IRQL_requires_max_(APC_LEVEL) - fast_mutex_with_critical_region_guard acquire_fast_mutex_with_critical_region(FAST_MUTEX* fastMutex) WI_NOEXCEPT - { - ::KeEnterCriticalRegion(); - ::ExAcquireFastMutexUnsafe(fastMutex); - return fast_mutex_with_critical_region_guard(fastMutex); - } - - // A FAST_MUTEX lock class that calls KeEnterCriticalRegion and then ExAcquireFastMutexUnsafe. - // Returned wil::unique_any lock-guard calls ExReleaseFastMutexUnsafe and KeLeaveCriticalRegion - // on destruction. This is useful if calling code wants to stay at PASSIVE_LEVEL. - class fast_mutex_with_critical_region - { - public: - fast_mutex_with_critical_region() WI_NOEXCEPT - { - ::ExInitializeFastMutex(&m_fastMutex); - } - - ~fast_mutex_with_critical_region() WI_NOEXCEPT = default; - - // Cannot change memory location. - fast_mutex_with_critical_region(const fast_mutex_with_critical_region&) = delete; - fast_mutex_with_critical_region& operator=(const fast_mutex_with_critical_region&) = delete; - fast_mutex_with_critical_region(fast_mutex_with_critical_region&&) = delete; - fast_mutex_with_critical_region& operator=(fast_mutex_with_critical_region&&) = delete; - - WI_NODISCARD - _IRQL_requires_max_(APC_LEVEL) - fast_mutex_with_critical_region_guard acquire() WI_NOEXCEPT - { - return acquire_fast_mutex_with_critical_region(&m_fastMutex); - } - - private: - FAST_MUTEX m_fastMutex; - }; - - //! A type that calls KeLeaveCriticalRegion on destruction (or reset()). - using unique_leave_critical_region_call = unique_call; - - //! Disables user APCs and normal kernel APCs; returns an RAII object that reverts - WI_NODISCARD inline unique_leave_critical_region_call enter_critical_region() - { - KeEnterCriticalRegion(); - return{}; - } - - //! A type that calls KeLeaveGuardedRegion on destruction (or reset()). - using unique_leave_guarded_region_call = unique_call; - - //! Disables all APCs; returns an RAII object that reverts - WI_NODISCARD inline unique_leave_guarded_region_call enter_guarded_region() - { - KeEnterGuardedRegion(); - return{}; - } - -//! WDM version of EX_PUSH_LOCK is available starting with Windows 10 1809 -#if (NTDDI_VERSION >= NTDDI_WIN10_RS5) - namespace details - { - _IRQL_requires_max_(APC_LEVEL) - inline void release_push_lock_exclusive(EX_PUSH_LOCK* pushLock) WI_NOEXCEPT - { - ::ExReleasePushLockExclusive(pushLock); - ::KeLeaveCriticalRegion(); - } - - _IRQL_requires_max_(APC_LEVEL) - inline void release_push_lock_shared(EX_PUSH_LOCK* pushLock) WI_NOEXCEPT - { - ::ExReleasePushLockShared(pushLock); - ::KeLeaveCriticalRegion(); - } - } - - using push_lock_exclusive_guard = - unique_any; - - using push_lock_shared_guard = - unique_any; - - WI_NODISCARD - inline - _IRQL_requires_max_(APC_LEVEL) - push_lock_exclusive_guard acquire_push_lock_exclusive(EX_PUSH_LOCK* pushLock) WI_NOEXCEPT - { - ::KeEnterCriticalRegion(); - ::ExAcquirePushLockExclusive(pushLock); - return push_lock_exclusive_guard(pushLock); - } - - WI_NODISCARD - inline - _IRQL_requires_max_(APC_LEVEL) - push_lock_shared_guard acquire_push_lock_shared(EX_PUSH_LOCK* pushLock) WI_NOEXCEPT - { - ::KeEnterCriticalRegion(); - ::ExAcquirePushLockShared(pushLock); - return push_lock_shared_guard(pushLock); - } - - class push_lock - { - public: - push_lock() WI_NOEXCEPT - { - ::ExInitializePushLock(&m_pushLock); - } - - ~push_lock() WI_NOEXCEPT = default; - - // Cannot change memory location. - push_lock(const push_lock&) = delete; - push_lock& operator=(const push_lock&) = delete; - push_lock(push_lock&&) = delete; - push_lock& operator=(push_lock&&) = delete; - - WI_NODISCARD - _IRQL_requires_max_(APC_LEVEL) - push_lock_exclusive_guard acquire_exclusive() WI_NOEXCEPT - { - return acquire_push_lock_exclusive(&m_pushLock); - } - - WI_NODISCARD - _IRQL_requires_max_(APC_LEVEL) - push_lock_shared_guard acquire_shared() WI_NOEXCEPT - { - return acquire_push_lock_shared(&m_pushLock); - } - - private: - EX_PUSH_LOCK m_pushLock; - }; -#endif - - namespace details - { - // Define a templated type for pool functions in order to satisfy overload resolution below - template - struct pool_helpers - { - static inline - _IRQL_requires_max_(DISPATCH_LEVEL) - void __stdcall FreePoolWithTag(pointer value) WI_NOEXCEPT - { - if (value) - { - ExFreePoolWithTag(value, tag); - } - } - }; - } - - template - using unique_tagged_pool_ptr = unique_any::FreePoolWithTag), &details::pool_helpers::FreePoolWithTag>; - - // For use with IRPs that need to be IoFreeIrp'ed when done, typically allocated using IoAllocateIrp. - using unique_allocated_irp = wil::unique_any; - using unique_io_workitem = wil::unique_any; - -#endif // __WIL_RESOURCE_WDM - -#if defined(WIL_KERNEL_MODE) && (defined(_WDMDDK_) || defined(_ZWAPI_)) && !defined(__WIL_RESOURCE_ZWAPI) -#define __WIL_RESOURCE_ZWAPI - - using unique_kernel_handle = wil::unique_any; - -#endif // __WIL_RESOURCE_ZWAPI - -#if defined(WINTRUST_H) && defined(SOFTPUB_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIL_WINTRUST) -#define __WIL_WINTRUST - namespace details - { - inline void __stdcall CloseWintrustData(_Inout_ WINTRUST_DATA* wtData) WI_NOEXCEPT - { - GUID guidV2 = WINTRUST_ACTION_GENERIC_VERIFY_V2; - wtData->dwStateAction = WTD_STATEACTION_CLOSE; - WinVerifyTrust(static_cast(INVALID_HANDLE_VALUE), &guidV2, wtData); - } - } - typedef wil::unique_struct unique_wintrust_data; -#endif // __WIL_WINTRUST - -#if defined(MSCAT_H) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && !defined(__WIL_MSCAT) -#define __WIL_MSCAT - namespace details - { - inline void __stdcall CryptCATAdminReleaseContextNoFlags(_Pre_opt_valid_ _Frees_ptr_opt_ HCATADMIN handle) WI_NOEXCEPT - { - CryptCATAdminReleaseContext(handle, 0); - } - } - typedef wil::unique_any unique_hcatadmin; - -#if defined(WIL_RESOURCE_STL) - typedef shared_any shared_hcatadmin; - struct hcatinfo_deleter - { - hcatinfo_deleter(wil::shared_hcatadmin handle) WI_NOEXCEPT : m_hCatAdmin(wistd::move(handle)) {} - void operator()(_Pre_opt_valid_ _Frees_ptr_opt_ HCATINFO handle) const WI_NOEXCEPT - { - CryptCATAdminReleaseCatalogContext(m_hCatAdmin.get(), handle, 0); - } - wil::shared_hcatadmin m_hCatAdmin; - }; - // This stores HCATINFO, i.e. HANDLE (void *) - typedef wistd::unique_ptr unique_hcatinfo; - - namespace details - { - class crypt_catalog_enumerator - { - wil::unique_hcatinfo m_hCatInfo; - const BYTE* m_hash; - DWORD m_hashLen; - bool m_initialized = false; - - struct ref - { - explicit ref(crypt_catalog_enumerator &r) WI_NOEXCEPT : - m_r(r) - {} - - WI_NODISCARD operator HCATINFO() const WI_NOEXCEPT - { - return m_r.current(); - } - - wil::unique_hcatinfo move_from_unique_hcatinfo() WI_NOEXCEPT - { - wil::unique_hcatinfo info(wistd::move(m_r.m_hCatInfo)); - return info; - } - - WI_NODISCARD bool operator==(wistd::nullptr_t) const WI_NOEXCEPT - { - return m_r.m_hCatInfo == nullptr; - } - - WI_NODISCARD bool operator!=(wistd::nullptr_t) const WI_NOEXCEPT - { - return !(*this == nullptr); - } - - private: - crypt_catalog_enumerator &m_r; - }; - - struct iterator - { -#ifdef _XUTILITY_ - // muse be input_iterator_tag as use of one instance invalidates the other. - typedef ::std::input_iterator_tag iterator_category; -#endif - - explicit iterator(crypt_catalog_enumerator *r) WI_NOEXCEPT : - m_r(r) - {} - - iterator(const iterator &) = default; - iterator(iterator &&) = default; - iterator &operator=(const iterator &) = default; - iterator &operator=(iterator &&) = default; - - WI_NODISCARD bool operator==(const iterator &rhs) const WI_NOEXCEPT - { - if (rhs.m_r == m_r) - { - return true; - } - - return (*this == nullptr) && (rhs == nullptr); - } - - WI_NODISCARD bool operator!=(const iterator &rhs) const WI_NOEXCEPT - { - return !(rhs == *this); - } - - WI_NODISCARD bool operator==(wistd::nullptr_t) const WI_NOEXCEPT - { - return nullptr == m_r || nullptr == m_r->current(); - } - - WI_NODISCARD bool operator!=(wistd::nullptr_t) const WI_NOEXCEPT - { - return !(*this == nullptr); - } - - iterator &operator++() WI_NOEXCEPT - { - if (m_r != nullptr) - { - m_r->next(); - } - - return *this; - } - - WI_NODISCARD ref operator*() const WI_NOEXCEPT - { - return ref(*m_r); - } - - private: - crypt_catalog_enumerator *m_r; - }; - - shared_hcatadmin &hcatadmin() WI_NOEXCEPT - { - return m_hCatInfo.get_deleter().m_hCatAdmin; - } - - bool move_next() WI_NOEXCEPT - { - HCATINFO prevCatInfo = m_hCatInfo.release(); - m_hCatInfo.reset( - ::CryptCATAdminEnumCatalogFromHash( - hcatadmin().get(), - const_cast(m_hash), - m_hashLen, - 0, - &prevCatInfo)); - return !!m_hCatInfo; - } - - HCATINFO next() WI_NOEXCEPT - { - if (m_initialized && m_hCatInfo) - { - move_next(); - } - - return current(); - } - - HCATINFO init() WI_NOEXCEPT - { - if (!m_initialized) - { - m_initialized = true; - move_next(); - } - - return current(); - } - - HCATINFO current() WI_NOEXCEPT - { - return m_hCatInfo.get(); - } - - public: - crypt_catalog_enumerator(wil::shared_hcatadmin &hCatAdmin, - const BYTE *hash, - DWORD hashLen) WI_NOEXCEPT : - m_hCatInfo(nullptr, hCatAdmin), - m_hash(hash), - m_hashLen(hashLen) - // , m_initialized(false) // redundant - {} - - WI_NODISCARD iterator begin() WI_NOEXCEPT - { - init(); - return iterator(this); - } - - WI_NODISCARD iterator end() const WI_NOEXCEPT - { - return iterator(nullptr); - } - - crypt_catalog_enumerator(crypt_catalog_enumerator &&) = default; - crypt_catalog_enumerator &operator=(crypt_catalog_enumerator &&) = default; - - crypt_catalog_enumerator(const crypt_catalog_enumerator &) = delete; - crypt_catalog_enumerator &operator=(const crypt_catalog_enumerator &) = delete; - }; - } - - /** Use to enumerate catalogs containing a hash with a range-based for. - This avoids handling a raw resource to call CryptCATAdminEnumCatalogFromHash correctly. - Example: - `for (auto&& cat : wil::make_catalog_enumerator(hCatAdmin, hash, hashLen)) - { CryptCATCatalogInfoFromContext(cat, &catInfo, 0); }` */ - inline details::crypt_catalog_enumerator make_crypt_catalog_enumerator(wil::shared_hcatadmin &hCatAdmin, - _In_count_(hashLen) const BYTE *hash, DWORD hashLen) WI_NOEXCEPT - { - return details::crypt_catalog_enumerator(hCatAdmin, hash, hashLen); - } - - template - details::crypt_catalog_enumerator make_crypt_catalog_enumerator(wil::shared_hcatadmin &hCatAdmin, - const BYTE (&hash)[Size]) WI_NOEXCEPT - { - static_assert(Size <= static_cast(0xffffffffUL), "Array size truncated"); - return details::crypt_catalog_enumerator(hCatAdmin, hash, static_cast(Size)); - } - -#endif // WI_RESOURCE_STL - -#endif // __WIL_MSCAT - - -#if !defined(__WIL_RESOURCE_LOCK_ENFORCEMENT) -#define __WIL_RESOURCE_LOCK_ENFORCEMENT - - /** - Functions that need an exclusive lock use can use write_lock_required as a parameter to enforce lock - safety at compile time. Similarly, read_lock_required may stand as a parameter where shared ownership - of a lock is required. These are empty structs that will never be used, other than passing them on to - another function that requires them. - - These types are implicitly convertible from various lock holding types, enabling callers to provide them as - proof of the lock that they hold. - - The following example is intentially contrived to demonstrate multiple use cases: - - Methods that require only shared/read access - - Methods that require only exclusive write access - - Methods that pass their proof-of-lock to a helper - ~~~ - class RemoteControl - { - public: - void VolumeUp(); - int GetVolume(); - private: - int GetCurrentVolume(wil::read_lock_required); - void AdjustVolume(int delta, wil::write_lock_required); - void SetNewVolume(int newVolume, wil::write_lock_required); - - int m_currentVolume = 0; - wil::srwlock m_lock; - }; - - void RemoteControl::VolumeUp() - { - auto writeLock = m_lock.lock_exclusive(); - AdjustVolume(1, writeLock); - } - - int RemoteControl::GetVolume() - { - auto readLock = m_lock.lock_shared(); - return GetCurrentVolume(readLock); - } - - int RemoteControl::GetCurrentVolume(wil::read_lock_required) - { - return m_currentVolume; - } - - void AdjustVolume(int delta, wil::write_lock_required lockProof) - { - const auto currentVolume = GetCurrentVolume(lockProof); - SetNewVolume(currentVolume + delta, lockProof); - } - - void RemoteControl::SetNewVolume(int newVolume, wil::write_lock_required) - { - m_currentVolume = newVolume; - } - ~~~ - - In this design it is impossible to not meet the "lock must be held" precondition and the function parameter types - help you understand which one. - - Cases not handled: - - Functions that need the lock held, but fail to specify this fact by requiring a lock required parameter need - to be found via code inspection. - - Recursively taking a lock, when it is already held, is not avoided in this pattern - - Readers will learn to be suspicious of acquiring a lock in functions with lock required parameters. - - Designs with multiple locks, that must be careful to take them in the same order every time, are not helped - by this pattern. - - Locking the wrong object - - Use of a std::lock type that has not actually be secured yet (such as by std::try_to_lock or std::defer_lock) - - or use of a lock type that had been acquired but has since been released, reset, or otherwise unlocked - - These utility types are not fool-proof against all lock misuse, anti-patterns, or other complex yet valid - scenarios. However on the net, their usage in typical cases can assist in creating clearer, self-documenting - code that catches the common issues of forgetting to hold a lock or forgetting whether a lock is required to - call another method safely. - */ - struct write_lock_required; - - /** - Stands as proof that a shared lock has been acquired. See write_lock_required for more information. - */ - struct read_lock_required; - - namespace details - { - // Only those lock types specialized by lock_proof_traits will allow either a write_lock_required or - // read_lock_required to be constructed. The allows_exclusive value indicates if the type represents an exclusive, - // write-safe lock aquisition, or a shared, read-only lock acquisition. - template - struct lock_proof_traits { }; - - // Base for specializing lock_proof_traits where the lock type is shared - struct shared_lock_proof - { - static constexpr bool allows_shared = true; - }; - - // Base for specializing lock_proof_traits where the lock type is exclusive (super-set of shared_lock_proof) - struct exclusive_lock_proof : shared_lock_proof - { - static constexpr bool allows_exclusive = true; - }; - } - - struct write_lock_required - { - /** - Construct a new write_lock_required object for use as proof that an exclusive lock has been acquired. - */ - template - write_lock_required(const TLockProof&, wistd::enable_if_t::allows_exclusive, int> = 0) {} - - write_lock_required() = delete; // No default construction - }; - - struct read_lock_required - { - /** - Construct a new read_lock_required object for use as proof that a shared lock has been acquired. - */ - template - read_lock_required(const TLockProof&, wistd::enable_if_t::allows_shared, int> = 0) {} - - /** - Uses a prior write_lock_required object to construct a read_lock_required object as proof that at shared lock - has been acquired. (Exclusive locks held are presumed to suffice for proof of a read lock) - */ - read_lock_required(const write_lock_required&) {} - - read_lock_required() = delete; // No default construction - }; -#endif // __WIL_RESOURCE_LOCK_ENFORCEMENT - -#if defined(__WIL_WINBASE_) && !defined(__WIL__RESOURCE_LOCKPROOF_WINBASE) && defined(__WIL_RESOURCE_LOCK_ENFORCEMENT) -#define __WIL__RESOURCE_LOCKPROOF_WINBASE - - namespace details - { - // Specializations for srwlock - template<> - struct lock_proof_traits : shared_lock_proof {}; - - template<> - struct lock_proof_traits : exclusive_lock_proof {}; - - // Specialization for critical_section - template<> - struct lock_proof_traits : exclusive_lock_proof {}; - } - -#endif //__WIL__RESOURCE_LOCKPROOF_WINBASE - -#if defined(_MUTEX_) && !defined(__WIL__RESOURCE_LOCKPROOF_MUTEX) && defined(__WIL_RESOURCE_LOCK_ENFORCEMENT) -#define __WIL__RESOURCE_LOCKPROOF_MUTEX - - namespace details - { - template - struct lock_proof_traits> : exclusive_lock_proof {}; - - template - struct lock_proof_traits> : exclusive_lock_proof {}; - } - -#endif //__WIL__RESOURCE_LOCKPROOF_MUTEX - -#if defined(_SHARED_MUTEX_) && !defined(__WIL__RESOURCE_LOCKPROOF_SHAREDMUTEX) && defined(__WIL_RESOURCE_LOCK_ENFORCEMENT) -#define __WIL__RESOURCE_LOCKPROOF_SHAREDMUTEX - - namespace details - { - template - struct lock_proof_traits> : shared_lock_proof {}; - } - -#endif //__WIL__RESOURCE_LOCKPROOF_SHAREDMUTEX - -} // namespace wil - -#pragma warning(pop) diff --git a/src/common/dep/wil/result.h b/src/common/dep/wil/result.h deleted file mode 100644 index 8d5f26c07..000000000 --- a/src/common/dep/wil/result.h +++ /dev/null @@ -1,1280 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_RESULT_INCLUDED -#define __WIL_RESULT_INCLUDED - -// Most functionality is picked up from result_macros.h. This file specifically provides higher level processing of errors when -// they are encountered by the underlying macros. -#include "result_macros.h" - -// Note that we avoid pulling in STL's memory header from Result.h through Resource.h as we have -// Result.h customers who are still on older versions of STL (without std::shared_ptr<>). -#ifndef RESOURCE_SUPPRESS_STL -#define RESOURCE_SUPPRESS_STL -#include "resource.h" -#undef RESOURCE_SUPPRESS_STL -#else -#include "resource.h" -#endif - -#ifdef WIL_KERNEL_MODE -#error This header is not supported in kernel-mode. -#endif - -// The updated behavior of running init-list ctors during placement new is proper & correct, disable the warning that requests developers verify they want it -#pragma warning(push) -#pragma warning(disable : 4351) - -namespace wil -{ - // WARNING: EVERYTHING in this namespace must be handled WITH CARE as the entities defined within - // are used as an in-proc ABI contract between binaries that utilize WIL. Making changes - // that add v-tables or change the storage semantics of anything herein needs to be done - // with care and respect to versioning. - ///@cond - namespace details_abi - { - #define __WI_SEMAHPORE_VERSION L"_p0" - - // This class uses named semaphores to be able to stash a numeric value (including a pointer - // for retrieval from within any module in a process). This is a very specific need of a - // header-based library that should not be generally used. - // - // Notes for use: - // * Data members must be stable unless __WI_SEMAHPORE_VERSION is changed - // * The class must not reference module code (v-table, function pointers, etc) - // * Use of this class REQUIRES that there be a MUTEX held around the semaphore manipulation - // and tests as it doesn't attempt to handle thread contention on the semaphore while manipulating - // the count. - // * This class supports storing a 31-bit number of a single semaphore or a 62-bit number across - // two semaphores and directly supports pointers. - - class SemaphoreValue - { - public: - SemaphoreValue() = default; - SemaphoreValue(const SemaphoreValue&) = delete; - SemaphoreValue& operator=(const SemaphoreValue&) = delete; - - SemaphoreValue(SemaphoreValue&& other) WI_NOEXCEPT : - m_semaphore(wistd::move(other.m_semaphore)), - m_semaphoreHigh(wistd::move(other.m_semaphoreHigh)) - { - static_assert(sizeof(m_semaphore) == sizeof(HANDLE), "unique_any must be a direct representation of the HANDLE to be used across module"); - } - - void Destroy() - { - m_semaphore.reset(); - m_semaphoreHigh.reset(); - } - - template - HRESULT CreateFromValue(PCWSTR name, T value) - { - return CreateFromValueInternal(name, (sizeof(value) > sizeof(unsigned long)), static_cast(value)); - } - - HRESULT CreateFromPointer(PCWSTR name, void* pointer) - { - ULONG_PTR value = reinterpret_cast(pointer); - FAIL_FAST_IMMEDIATE_IF(WI_IsAnyFlagSet(value, 0x3)); - return CreateFromValue(name, value >> 2); - } - - template - static HRESULT TryGetValue(PCWSTR name, _Out_ T* value, _Out_opt_ bool *retrieved = nullptr) - { - *value = static_cast(0); - unsigned __int64 value64 = 0; - __WIL_PRIVATE_RETURN_IF_FAILED(TryGetValueInternal(name, (sizeof(T) > sizeof(unsigned long)), &value64, retrieved)); - *value = static_cast(value64); - return S_OK; - } - - static HRESULT TryGetPointer(PCWSTR name, _Outptr_result_maybenull_ void** pointer) - { - *pointer = nullptr; - ULONG_PTR value = 0; - __WIL_PRIVATE_RETURN_IF_FAILED(TryGetValue(name, &value)); - *pointer = reinterpret_cast(value << 2); - return S_OK; - } - - private: - HRESULT CreateFromValueInternal(PCWSTR name, bool is64Bit, unsigned __int64 value) - { - WI_ASSERT(!m_semaphore && !m_semaphoreHigh); // call Destroy first - - // This routine only supports 31 bits when semahporeHigh is not supplied or 62 bits when the value - // is supplied. It's a programming error to use it when either of these conditions are not true. - - FAIL_FAST_IMMEDIATE_IF((!is64Bit && WI_IsAnyFlagSet(value, 0xFFFFFFFF80000000)) || - (is64Bit && WI_IsAnyFlagSet(value, 0xC000000000000000))); - - wchar_t localName[MAX_PATH]; - WI_VERIFY_SUCCEEDED(StringCchCopyW(localName, ARRAYSIZE(localName), name)); - WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), __WI_SEMAHPORE_VERSION)); - - const unsigned long highPart = static_cast(value >> 31); - const unsigned long lowPart = static_cast(value & 0x000000007FFFFFFF); - - // We set the count of the semaphore equal to the max (the value we're storing). The only exception to that - // is ZERO, where you can't create a semaphore of value ZERO, where we push the max to one and use a count of ZERO. - - __WIL_PRIVATE_RETURN_IF_FAILED(m_semaphore.create(static_cast(lowPart), static_cast((lowPart > 0) ? lowPart : 1), localName)); - if (is64Bit) - { - WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), L"h")); - __WIL_PRIVATE_RETURN_IF_FAILED(m_semaphoreHigh.create(static_cast(highPart), static_cast((highPart > 0) ? highPart : 1), localName)); - } - - return S_OK; - } - - static HRESULT GetValueFromSemaphore(HANDLE semaphore, _Out_ LONG* count) - { - // First we consume a single count from the semaphore. This will work in all cases other - // than the case where the count we've recorded is ZERO which will TIMEOUT. - - DWORD result = ::WaitForSingleObject(semaphore, 0); - __WIL_PRIVATE_RETURN_LAST_ERROR_IF(result == WAIT_FAILED); - __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, !((result == WAIT_OBJECT_0) || (result == WAIT_TIMEOUT))); - - LONG value = 0; - if (result == WAIT_OBJECT_0) - { - // We were able to wait. To establish our count, all we have to do is release that count - // back to the semaphore and observe the value that we released. - - __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(::ReleaseSemaphore(semaphore, 1, &value)); - value++; // we waited first, so our actual value is one more than the old value - - // Make sure the value is correct by validating that we have no more posts. - BOOL expectedFailure = ::ReleaseSemaphore(semaphore, 1, nullptr); - __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, expectedFailure || (::GetLastError() != ERROR_TOO_MANY_POSTS)); - } - else - { - WI_ASSERT(result == WAIT_TIMEOUT); - - // We know at this point that the value is ZERO. We'll do some verification to ensure that - // this address is right by validating that we have one and only one more post that we could use. - - LONG expected = 0; - __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(::ReleaseSemaphore(semaphore, 1, &expected)); - __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, expected != 0); - - const BOOL expectedFailure = ::ReleaseSemaphore(semaphore, 1, nullptr); - __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, expectedFailure || (::GetLastError() != ERROR_TOO_MANY_POSTS)); - - result = ::WaitForSingleObject(semaphore, 0); - __WIL_PRIVATE_RETURN_LAST_ERROR_IF(result == WAIT_FAILED); - __WIL_PRIVATE_RETURN_HR_IF(E_UNEXPECTED, result != WAIT_OBJECT_0); - } - - *count = value; - return S_OK; - } - - static HRESULT TryGetValueInternal(PCWSTR name, bool is64Bit, _Out_ unsigned __int64* value, _Out_opt_ bool* retrieved) - { - assign_to_opt_param(retrieved, false); - *value = 0; - - wchar_t localName[MAX_PATH]; - WI_VERIFY_SUCCEEDED(StringCchCopyW(localName, ARRAYSIZE(localName), name)); - WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), __WI_SEMAHPORE_VERSION)); - - wil::unique_semaphore_nothrow semaphoreLow(::OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, localName)); - if (!semaphoreLow) - { - __WIL_PRIVATE_RETURN_HR_IF(S_OK, (::GetLastError() == ERROR_FILE_NOT_FOUND)); - __WIL_PRIVATE_RETURN_LAST_ERROR(); - } - - LONG countLow = 0; - LONG countHigh = 0; - - __WIL_PRIVATE_RETURN_IF_FAILED(GetValueFromSemaphore(semaphoreLow.get(), &countLow)); - - if (is64Bit) - { - WI_VERIFY_SUCCEEDED(StringCchCatW(localName, ARRAYSIZE(localName), L"h")); - wil::unique_semaphore_nothrow semaphoreHigh(::OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, localName)); - __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(semaphoreHigh); - - __WIL_PRIVATE_RETURN_IF_FAILED(GetValueFromSemaphore(semaphoreHigh.get(), &countHigh)); - } - - WI_ASSERT((countLow >= 0) && (countHigh >= 0)); - - const unsigned __int64 newValueHigh = (static_cast(countHigh) << 31); - const unsigned __int64 newValueLow = static_cast(countLow); - - assign_to_opt_param(retrieved, true); - *value = (newValueHigh | newValueLow); - return S_OK; - } - - wil::unique_semaphore_nothrow m_semaphore; - wil::unique_semaphore_nothrow m_semaphoreHigh; - }; - - template - class ProcessLocalStorageData - { - public: - ProcessLocalStorageData(unique_mutex_nothrow&& mutex, SemaphoreValue&& value) : - m_mutex(wistd::move(mutex)), - m_value(wistd::move(value)), - m_data() - { - static_assert(sizeof(m_mutex) == sizeof(HANDLE), "unique_any must be equivalent to the handle size to safely use across module"); - } - - T* GetData() - { - WI_ASSERT(m_mutex); - return &m_data; - } - - void Release() - { - if (ProcessShutdownInProgress()) - { - // There are no other threads to contend with. - m_refCount = m_refCount - 1; - if (m_refCount == 0) - { - m_data.ProcessShutdown(); - } - } - else - { - auto lock = m_mutex.acquire(); - m_refCount = m_refCount - 1; - if (m_refCount == 0) - { - // We must explicitly destroy our semaphores while holding the mutex - m_value.Destroy(); - lock.reset(); - - this->~ProcessLocalStorageData(); - ::HeapFree(::GetProcessHeap(), 0, this); - } - } - } - - static HRESULT Acquire(PCSTR staticNameWithVersion, _Outptr_result_nullonfailure_ ProcessLocalStorageData** data) - { - *data = nullptr; - - // NOTE: the '0' in SM0 below is intended as the VERSION number. Changes to this class require - // that this value be revised. - - const DWORD size = static_cast(sizeof(ProcessLocalStorageData)); - wchar_t name[MAX_PATH]; - WI_VERIFY(SUCCEEDED(StringCchPrintfW(name, ARRAYSIZE(name), L"Local\\SM0:%lu:%lu:%hs", ::GetCurrentProcessId(), size, staticNameWithVersion))); - - unique_mutex_nothrow mutex; - mutex.reset(::CreateMutexExW(nullptr, name, 0, MUTEX_ALL_ACCESS)); - - // This will fail in some environments and will be fixed with deliverable 12394134 - RETURN_LAST_ERROR_IF_EXPECTED(!mutex); - auto lock = mutex.acquire(); - - void* pointer = nullptr; - __WIL_PRIVATE_RETURN_IF_FAILED(SemaphoreValue::TryGetPointer(name, &pointer)); - if (pointer) - { - *data = reinterpret_cast*>(pointer); - (*data)->m_refCount = (*data)->m_refCount + 1; - } - else - { - __WIL_PRIVATE_RETURN_IF_FAILED(MakeAndInitialize(name, wistd::move(mutex), data)); // Assumes mutex handle ownership on success ('lock' will still be released) - } - - return S_OK; - } - - private: - - volatile long m_refCount = 1; - unique_mutex_nothrow m_mutex; - SemaphoreValue m_value; - T m_data; - - static HRESULT MakeAndInitialize(PCWSTR name, unique_mutex_nothrow&& mutex, _Outptr_result_nullonfailure_ ProcessLocalStorageData** data) - { - *data = nullptr; - - const DWORD size = static_cast(sizeof(ProcessLocalStorageData)); - - unique_process_heap_ptr> dataAlloc(static_cast*>(details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, size))); - __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(dataAlloc); - - SemaphoreValue semaphoreValue; - __WIL_PRIVATE_RETURN_IF_FAILED(semaphoreValue.CreateFromPointer(name, dataAlloc.get())); - - new(dataAlloc.get()) ProcessLocalStorageData(wistd::move(mutex), wistd::move(semaphoreValue)); - *data = dataAlloc.release(); - - return S_OK; - } - }; - - template - class ProcessLocalStorage - { - public: - ProcessLocalStorage(PCSTR staticNameWithVersion) WI_NOEXCEPT : - m_staticNameWithVersion(staticNameWithVersion) - { - } - - ~ProcessLocalStorage() WI_NOEXCEPT - { - if (m_data) - { - m_data->Release(); - } - } - - T* GetShared() WI_NOEXCEPT - { - if (!m_data) - { - ProcessLocalStorageData* localTemp = nullptr; - if (SUCCEEDED(ProcessLocalStorageData::Acquire(m_staticNameWithVersion, &localTemp)) && !m_data) - { - m_data = localTemp; - } - } - return m_data ? m_data->GetData() : nullptr; - } - - private: - PCSTR m_staticNameWithVersion = nullptr; - ProcessLocalStorageData* m_data = nullptr; - }; - - template - class ThreadLocalStorage - { - public: - ThreadLocalStorage(const ThreadLocalStorage&) = delete; - ThreadLocalStorage& operator=(const ThreadLocalStorage&) = delete; - - ThreadLocalStorage() = default; - - ~ThreadLocalStorage() WI_NOEXCEPT - { - for (auto &entry : m_hashArray) - { - Node *pNode = entry; - while (pNode != nullptr) - { - auto pCurrent = pNode; -#pragma warning(push) -#pragma warning(disable:6001) // https://github.com/microsoft/wil/issues/164 - pNode = pNode->pNext; -#pragma warning(pop) - pCurrent->~Node(); - ::HeapFree(::GetProcessHeap(), 0, pCurrent); - } - entry = nullptr; - } - } - - // Note: Can return nullptr even when (shouldAllocate == true) upon allocation failure - T* GetLocal(bool shouldAllocate = false) WI_NOEXCEPT - { - DWORD const threadId = ::GetCurrentThreadId(); - size_t const index = (threadId % ARRAYSIZE(m_hashArray)); - for (auto pNode = m_hashArray[index]; pNode != nullptr; pNode = pNode->pNext) - { - if (pNode->threadId == threadId) - { - return &pNode->value; - } - } - - if (shouldAllocate) - { - if (auto pNewRaw = details::ProcessHeapAlloc(0, sizeof(Node))) - { - auto pNew = new (pNewRaw) Node{ threadId }; - - Node *pFirst; - do - { - pFirst = m_hashArray[index]; - pNew->pNext = pFirst; - } while (::InterlockedCompareExchangePointer(reinterpret_cast(m_hashArray + index), pNew, pFirst) != pFirst); - - return &pNew->value; - } - } - return nullptr; - } - - private: - - struct Node - { - DWORD threadId = ULONG_MAX; - Node* pNext = nullptr; - T value{}; - }; - - Node * volatile m_hashArray[10]{}; - }; - - struct ThreadLocalFailureInfo - { - // ABI contract (carry size to facilitate additive change without re-versioning) - unsigned short size; - unsigned char reserved1[2]; // packing, reserved - // When this failure was seen - unsigned int sequenceId; - - // Information about the failure - HRESULT hr; - PCSTR fileName; - unsigned short lineNumber; - unsigned char failureType; // FailureType - unsigned char reserved2; // packing, reserved - PCSTR modulePath; - void* returnAddress; - void* callerReturnAddress; - PCWSTR message; - - // The allocation (LocalAlloc) where structure strings point - void* stringBuffer; - size_t stringBufferSize; - - // NOTE: Externally Managed: Must not have constructor or destructor - - void Clear() - { - ::HeapFree(::GetProcessHeap(), 0, stringBuffer); - stringBuffer = nullptr; - stringBufferSize = 0; - } - - void Set(const FailureInfo& info, unsigned int newSequenceId) - { - sequenceId = newSequenceId; - - hr = info.hr; - fileName = nullptr; - lineNumber = static_cast(info.uLineNumber); - failureType = static_cast(info.type); - modulePath = nullptr; - returnAddress = info.returnAddress; - callerReturnAddress = info.callerReturnAddress; - message = nullptr; - - size_t neededSize = details::ResultStringSize(info.pszFile) + - details::ResultStringSize(info.pszModule) + - details::ResultStringSize(info.pszMessage); - - if (!stringBuffer || (stringBufferSize < neededSize)) - { - auto newBuffer = details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, neededSize); - if (newBuffer) - { - ::HeapFree(::GetProcessHeap(), 0, stringBuffer); - stringBuffer = newBuffer; - stringBufferSize = neededSize; - } - } - - if (stringBuffer) - { - unsigned char *pBuffer = static_cast(stringBuffer); - unsigned char *pBufferEnd = pBuffer + stringBufferSize; - - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, info.pszFile, &fileName); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, info.pszModule, &modulePath); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, info.pszMessage, &message); - ZeroMemory(pBuffer, pBufferEnd - pBuffer); - } - } - - void Get(FailureInfo& info) const - { - ::ZeroMemory(&info, sizeof(info)); - - info.failureId = sequenceId; - info.hr = hr; - info.pszFile = fileName; - info.uLineNumber = lineNumber; - info.type = static_cast(failureType); - info.pszModule = modulePath; - info.returnAddress = returnAddress; - info.callerReturnAddress = callerReturnAddress; - info.pszMessage = message; - } - }; - - struct ThreadLocalData - { - // ABI contract (carry size to facilitate additive change without re-versioning) - unsigned short size = sizeof(ThreadLocalData); - - // Subscription information - unsigned int threadId = 0; - volatile long* failureSequenceId = nullptr; // backpointer to the global ID - - // Information about thread errors - unsigned int latestSubscribedFailureSequenceId = 0; - - // The last (N) observed errors - ThreadLocalFailureInfo* errors = nullptr; - unsigned short errorAllocCount = 0; - unsigned short errorCurrentIndex = 0; - - // NOTE: Externally Managed: Must allow ZERO init construction - - ~ThreadLocalData() - { - Clear(); - } - - void Clear() - { - for (auto& error : make_range(errors, errorAllocCount)) - { - error.Clear(); - } - ::HeapFree(::GetProcessHeap(), 0, errors); - errorAllocCount = 0; - errorCurrentIndex = 0; - errors = nullptr; - } - - bool EnsureAllocated(bool create = true) - { - if (!errors && create) - { - const unsigned short errorCount = 5; - errors = reinterpret_cast(details::ProcessHeapAlloc(HEAP_ZERO_MEMORY, errorCount * sizeof(ThreadLocalFailureInfo))); - if (errors) - { - errorAllocCount = errorCount; - errorCurrentIndex = 0; - for (auto& error : make_range(errors, errorAllocCount)) - { - error.size = sizeof(ThreadLocalFailureInfo); - } - } - } - return (errors != nullptr); - } - - void SetLastError(const wil::FailureInfo& info) - { - const bool hasListener = (latestSubscribedFailureSequenceId > 0); - - if (!EnsureAllocated(hasListener)) - { - // We either couldn't allocate or we haven't yet allocated and nobody - // was listening, so we ignore. - return; - } - - if (hasListener) - { - // When we have listeners, we can throw away any updates to the last seen error - // code within the same listening context presuming it's an update of the existing - // error with the same code. - - for (auto& error : make_range(errors, errorAllocCount)) - { - if ((error.sequenceId > latestSubscribedFailureSequenceId) && (error.hr == info.hr)) - { - return; - } - } - } - - // Otherwise we create a new failure... - - errorCurrentIndex = (errorCurrentIndex + 1) % errorAllocCount; - errors[errorCurrentIndex].Set(info, ::InterlockedIncrementNoFence(failureSequenceId)); - } - - WI_NODISCARD bool GetLastError(_Inout_ wil::FailureInfo& info, unsigned int minSequenceId, HRESULT matchRequirement) const - { - if (!errors) - { - return false; - } - - // If the last error we saw doesn't meet the filter requirement or if the last error was never - // set, then we couldn't return a result at all... - auto& lastFailure = errors[errorCurrentIndex]; - if (minSequenceId >= lastFailure.sequenceId) - { - return false; - } - - // With no result filter, we just go to the last error and report it - if (matchRequirement == S_OK) - { - lastFailure.Get(info); - return true; - } - - // Find the oldest result matching matchRequirement and passing minSequenceId - ThreadLocalFailureInfo* find = nullptr; - for (auto& error : make_range(errors, errorAllocCount)) - { - if ((error.hr == matchRequirement) && (error.sequenceId > minSequenceId)) - { - if (!find || (error.sequenceId < find->sequenceId)) - { - find = &error; - } - } - } - if (find) - { - find->Get(info); - return true; - } - - return false; - } - - bool GetCaughtExceptionError(_Inout_ wil::FailureInfo& info, unsigned int minSequenceId, _In_opt_ const DiagnosticsInfo* diagnostics, HRESULT matchRequirement, void* returnAddress) - { - // First attempt to get the last error and then see if it matches the error returned from - // the last caught exception. If it does, then we're good to go and we return that last error. - - FailureInfo last = {}; - if (GetLastError(last, minSequenceId, matchRequirement) && (last.hr == ResultFromCaughtException())) - { - info = last; - return true; - } - - // The last error didn't match or we never had one... we need to create one -- we do so by logging - // our current request and then using the last error. - - DiagnosticsInfo source; - if (diagnostics) - { - source = *diagnostics; - } - - // NOTE: FailureType::Log as it's only informative (no action) and SupportedExceptions::All as it's not a barrier, only recognition. - wchar_t message[2048]{}; - const HRESULT hr = details::ReportFailure_CaughtExceptionCommon(__R_DIAGNOSTICS_RA(source, returnAddress), message, ARRAYSIZE(message), SupportedExceptions::All).hr; - - // Now that the exception was logged, we should be able to fetch it. - return GetLastError(info, minSequenceId, hr); - } - }; - - struct ProcessLocalData - { - // ABI contract (carry size to facilitate additive change without re-versioning) - unsigned short size = sizeof(ProcessLocalData); - - // Failure Information - volatile long failureSequenceId = 1; // process global variable - ThreadLocalStorage threads; // list of allocated threads - - void ProcessShutdown() {} - }; - - __declspec(selectany) ProcessLocalStorage* g_pProcessLocalData = nullptr; - - __declspec(noinline) inline ThreadLocalData* GetThreadLocalDataCache(bool allocate = true) - { - ThreadLocalData* result = nullptr; - if (g_pProcessLocalData) - { - auto processData = g_pProcessLocalData->GetShared(); - if (processData) - { - result = processData->threads.GetLocal(allocate); - if (result && !result->failureSequenceId) - { - result->failureSequenceId = &(processData->failureSequenceId); - } - } - } - return result; - } - - __forceinline ThreadLocalData* GetThreadLocalData(bool allocate = true) - { - return GetThreadLocalDataCache(allocate); - } - - } // details_abi - /// @endcond - - - /** Returns a sequence token that can be used with wil::GetLastError to limit errors to those that occur after this token was retrieved. - General usage pattern: use wil::GetCurrentErrorSequenceId to cache a token, execute your code, on failure use wil::GetLastError with the token - to provide information on the error that occurred while executing your code. Prefer to use wil::ThreadErrorContext over this approach when - possible. */ - inline long GetCurrentErrorSequenceId() - { - auto data = details_abi::GetThreadLocalData(); - if (data) - { - // someone is interested -- make sure we can store errors - data->EnsureAllocated(); - return *data->failureSequenceId; - } - - return 0; - } - - /** Caches failure information for later retrieval from GetLastError. - Most people will never need to do this explicitly as failure information is automatically made available per-thread across a process when - errors are encountered naturally through the WIL macros. */ - inline void SetLastError(const wil::FailureInfo& info) - { - static volatile unsigned int lastThread = 0; - auto threadId = ::GetCurrentThreadId(); - if (lastThread != threadId) - { - static volatile long depth = 0; - if (::InterlockedIncrementNoFence(&depth) < 4) - { - lastThread = threadId; - auto data = details_abi::GetThreadLocalData(false); // false = avoids allocation if not already present - if (data) - { - data->SetLastError(info); - } - lastThread = 0; - } - ::InterlockedDecrementNoFence(&depth); - } - } - - /** Retrieves failure information for the current thread with the given filters. - This API can be used to retrieve information about the last WIL failure that occurred on the current thread. - This error crosses DLL boundaries as long as the error occurred in the current process. Passing a minSequenceId - restricts the error returned to one that occurred after the given sequence ID. Passing matchRequirement also filters - the returned result to the given error code. */ - inline bool GetLastError(_Inout_ wil::FailureInfo& info, unsigned int minSequenceId = 0, HRESULT matchRequirement = S_OK) - { - auto data = details_abi::GetThreadLocalData(false); // false = avoids allocation if not already present - if (data) - { - return data->GetLastError(info, minSequenceId, matchRequirement); - } - return false; - } - - /** Retrieves failure information when within a catch block for the current thread with the given filters. - When unable to retrieve the exception information (when WIL hasn't yet seen it), this will attempt (best effort) to - discover information about the exception and will attribute that information to the given DiagnosticsInfo position. - See GetLastError for capabilities and filtering. */ - inline __declspec(noinline) bool GetCaughtExceptionError(_Inout_ wil::FailureInfo& info, unsigned int minSequenceId = 0, const DiagnosticsInfo* diagnostics = nullptr, HRESULT matchRequirement = S_OK) - { - auto data = details_abi::GetThreadLocalData(); - if (data) - { - return data->GetCaughtExceptionError(info, minSequenceId, diagnostics, matchRequirement, _ReturnAddress()); - } - return false; - } - - /** Use this class to manage retrieval of information about an error occurring in the requested code. - Construction of this class sets a point in time after which you can use the GetLastError class method to retrieve - the origination of the last error that occurred on this thread since the class was created. */ - class ThreadErrorContext - { - public: - ThreadErrorContext() : - m_data(details_abi::GetThreadLocalData()) - { - if (m_data) - { - m_sequenceIdLast = m_data->latestSubscribedFailureSequenceId; - m_sequenceIdStart = *m_data->failureSequenceId; - m_data->latestSubscribedFailureSequenceId = m_sequenceIdStart; - } - } - - ~ThreadErrorContext() - { - if (m_data) - { - m_data->latestSubscribedFailureSequenceId = m_sequenceIdLast; - } - } - - /** Retrieves the origination of the last error that occurred since this class was constructed. - The optional parameter allows the failure information returned to be filtered to a specific - result. */ - inline bool GetLastError(FailureInfo& info, HRESULT matchRequirement = S_OK) - { - if (m_data) - { - return m_data->GetLastError(info, m_sequenceIdStart, matchRequirement); - } - return false; - } - - /** Retrieves the origin of the current exception (within a catch block) since this class was constructed. - See @ref GetCaughtExceptionError for more information */ - inline __declspec(noinline) bool GetCaughtExceptionError(_Inout_ wil::FailureInfo& info, const DiagnosticsInfo* diagnostics = nullptr, HRESULT matchRequirement = S_OK) - { - if (m_data) - { - return m_data->GetCaughtExceptionError(info, m_sequenceIdStart, diagnostics, matchRequirement, _ReturnAddress()); - } - return false; - } - - private: - details_abi::ThreadLocalData* m_data; - unsigned long m_sequenceIdStart{}; - unsigned long m_sequenceIdLast{}; - }; - - - enum class WilInitializeCommand - { - Create, - Destroy, - }; - - - /// @cond - namespace details - { - struct IFailureCallback - { - virtual bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT = 0; - }; - - class ThreadFailureCallbackHolder; - - __declspec(selectany) details_abi::ThreadLocalStorage* g_pThreadFailureCallbacks = nullptr; - - class ThreadFailureCallbackHolder - { - public: - ThreadFailureCallbackHolder(_In_opt_ IFailureCallback *pCallbackParam, _In_opt_ CallContextInfo *pCallContext = nullptr, bool watchNow = true) WI_NOEXCEPT : - m_ppThreadList(nullptr), - m_pCallback(pCallbackParam), - m_pNext(nullptr), - m_threadId(0), - m_pCallContext(pCallContext) - { - if (watchNow) - { - StartWatching(); - } - } - - ThreadFailureCallbackHolder(ThreadFailureCallbackHolder &&other) WI_NOEXCEPT : - m_ppThreadList(nullptr), - m_pCallback(other.m_pCallback), - m_pNext(nullptr), - m_threadId(0), - m_pCallContext(other.m_pCallContext) - { - if (other.m_threadId != 0) - { - other.StopWatching(); - StartWatching(); - } - } - - ~ThreadFailureCallbackHolder() WI_NOEXCEPT - { - if (m_threadId != 0) - { - StopWatching(); - } - } - - void SetCallContext(_In_opt_ CallContextInfo *pCallContext) - { - m_pCallContext = pCallContext; - } - - CallContextInfo *CallContextInfo() - { - return m_pCallContext; - } - - void StartWatching() - { - // out-of balance Start/Stop calls? - __FAIL_FAST_IMMEDIATE_ASSERT__(m_threadId == 0); - - m_ppThreadList = g_pThreadFailureCallbacks ? g_pThreadFailureCallbacks->GetLocal(true) : nullptr; // true = allocate thread list if missing - if (m_ppThreadList) - { - m_pNext = *m_ppThreadList; - *m_ppThreadList = this; - m_threadId = ::GetCurrentThreadId(); - } - } - - void StopWatching() - { - if (m_threadId != ::GetCurrentThreadId()) - { - // The thread-specific failure holder cannot be stopped on a different thread than it was started on or the - // internal book-keeping list will be corrupted. To fix this change the telemetry pattern in the calling code - // to match one of the patterns available here: - // https://microsoft.sharepoint.com/teams/osg_development/Shared%20Documents/Windows%20TraceLogging%20Helpers.docx - - WI_USAGE_ERROR("MEMORY CORRUPTION: Calling code is leaking an activity thread-watcher and releasing it on another thread"); - } - - m_threadId = 0; - - while (*m_ppThreadList != nullptr) - { - if (*m_ppThreadList == this) - { - *m_ppThreadList = m_pNext; - break; - } - m_ppThreadList = &((*m_ppThreadList)->m_pNext); - } - m_ppThreadList = nullptr; - } - - WI_NODISCARD bool IsWatching() const - { - return (m_threadId != 0); - } - - void SetWatching(bool shouldWatch) - { - if (shouldWatch && !IsWatching()) - { - StartWatching(); - } - else if (!shouldWatch && IsWatching()) - { - StopWatching(); - } - } - - static bool GetThreadContext(_Inout_ FailureInfo *pFailure, _In_opt_ ThreadFailureCallbackHolder *pCallback, _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) - { - *callContextString = '\0'; - bool foundContext = false; - if (pCallback != nullptr) - { - foundContext = GetThreadContext(pFailure, pCallback->m_pNext, callContextString, callContextStringLength); - - if (pCallback->m_pCallContext != nullptr) - { - auto &context = *pCallback->m_pCallContext; - - // We generate the next telemetry ID only when we've found an error (avoid always incrementing) - if (context.contextId == 0) - { - context.contextId = ::InterlockedIncrementNoFence(&s_telemetryId); - } - - if (pFailure->callContextOriginating.contextId == 0) - { - pFailure->callContextOriginating = context; - } - - pFailure->callContextCurrent = context; - - auto callContextStringEnd = callContextString + callContextStringLength; - callContextString += strlen(callContextString); - - if ((callContextStringEnd - callContextString) > 2) // room for at least the slash + null - { - *callContextString++ = '\\'; - auto nameSizeBytes = strlen(context.contextName) + 1; - size_t remainingBytes = static_cast(callContextStringEnd - callContextString); - auto copyBytes = (nameSizeBytes < remainingBytes) ? nameSizeBytes : remainingBytes; - memcpy_s(callContextString, remainingBytes, context.contextName, copyBytes); - *(callContextString + (copyBytes - 1)) = '\0'; - } - - return true; - } - } - return foundContext; - } - - static void GetContextAndNotifyFailure(_Inout_ FailureInfo *pFailure, _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) WI_NOEXCEPT - { - *callContextString = '\0'; - bool reportedTelemetry = false; - - ThreadFailureCallbackHolder **ppListeners = g_pThreadFailureCallbacks ? g_pThreadFailureCallbacks->GetLocal() : nullptr; - if ((ppListeners != nullptr) && (*ppListeners != nullptr)) - { - callContextString[0] = '\0'; - if (GetThreadContext(pFailure, *ppListeners, callContextString, callContextStringLength)) - { - pFailure->pszCallContext = callContextString; - } - - auto pNode = *ppListeners; - do - { - reportedTelemetry |= pNode->m_pCallback->NotifyFailure(*pFailure); - pNode = pNode->m_pNext; - } - while (pNode != nullptr); - } - - if (g_pfnTelemetryCallback != nullptr) - { - // If the telemetry was requested to be suppressed, - // pretend like it has already been reported to the fallback callback - g_pfnTelemetryCallback(reportedTelemetry || WI_IsFlagSet(pFailure->flags, FailureFlags::RequestSuppressTelemetry), *pFailure); - } - } - - ThreadFailureCallbackHolder(ThreadFailureCallbackHolder const &) = delete; - ThreadFailureCallbackHolder& operator=(ThreadFailureCallbackHolder const &) = delete; - - private: - static long volatile s_telemetryId; - - ThreadFailureCallbackHolder **m_ppThreadList; - IFailureCallback *m_pCallback; - ThreadFailureCallbackHolder *m_pNext; - DWORD m_threadId; - wil::CallContextInfo *m_pCallContext; - }; - - __declspec(selectany) long volatile ThreadFailureCallbackHolder::s_telemetryId = 1; - - template - class ThreadFailureCallbackFn final : public IFailureCallback - { - public: - explicit ThreadFailureCallbackFn(_In_opt_ CallContextInfo *pContext, _Inout_ TLambda &&errorFunction) WI_NOEXCEPT : - m_errorFunction(wistd::move(errorFunction)), - m_callbackHolder(this, pContext) - { - } - - ThreadFailureCallbackFn(_Inout_ ThreadFailureCallbackFn && other) WI_NOEXCEPT : - m_errorFunction(wistd::move(other.m_errorFunction)), - m_callbackHolder(this, other.m_callbackHolder.CallContextInfo()) - { - } - - bool NotifyFailure(FailureInfo const &failure) WI_NOEXCEPT override - { - return m_errorFunction(failure); - } - - private: - ThreadFailureCallbackFn(_In_ ThreadFailureCallbackFn const &); - ThreadFailureCallbackFn & operator=(_In_ ThreadFailureCallbackFn const &); - - TLambda m_errorFunction; - ThreadFailureCallbackHolder m_callbackHolder; - }; - - - // returns true if telemetry was reported for this error - inline void __stdcall GetContextAndNotifyFailure(_Inout_ FailureInfo *pFailure, _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) WI_NOEXCEPT - { - ThreadFailureCallbackHolder::GetContextAndNotifyFailure(pFailure, callContextString, callContextStringLength); - - // Update the process-wide failure cache - wil::SetLastError(*pFailure); - } - - template void InitGlobalWithStorage(WilInitializeCommand state, void* storage, T*& global, TCtorArgs&&... args) - { - if ((state == WilInitializeCommand::Create) && !global) - { - global = ::new (storage) T(wistd::forward(args)...); - } - else if ((state == WilInitializeCommand::Destroy) && global) - { - global->~T(); - global = nullptr; - } - } - } - /// @endcond - - /** Modules that cannot use CRT-based static initialization may call this method from their entrypoint - instead. Disable the use of CRT-based initializers by defining RESULT_SUPPRESS_STATIC_INITIALIZERS - while compiling this header. Linking together libraries that disagree on this setting and calling - this method will behave correctly. It may be necessary to recompile all statically linked libraries - with the RESULT_SUPPRESS_... setting to eliminate all "LNK4201 - CRT section exists, but..." errors. - */ - inline void WilInitialize_Result(WilInitializeCommand state) - { - static unsigned char s_processLocalData[sizeof(*details_abi::g_pProcessLocalData)]; - static unsigned char s_threadFailureCallbacks[sizeof(*details::g_pThreadFailureCallbacks)]; - - details::InitGlobalWithStorage(state, s_processLocalData, details_abi::g_pProcessLocalData, "WilError_03"); - details::InitGlobalWithStorage(state, s_threadFailureCallbacks, details::g_pThreadFailureCallbacks); - - if (state == WilInitializeCommand::Create) - { - details::g_pfnGetContextAndNotifyFailure = details::GetContextAndNotifyFailure; - } - } - - /// @cond - namespace details - { -#ifndef RESULT_SUPPRESS_STATIC_INITIALIZERS - __declspec(selectany) ::wil::details_abi::ProcessLocalStorage<::wil::details_abi::ProcessLocalData> g_processLocalData("WilError_03"); - __declspec(selectany) ::wil::details_abi::ThreadLocalStorage g_threadFailureCallbacks; - - WI_HEADER_INITITALIZATION_FUNCTION(InitializeResultHeader, [] - { - g_pfnGetContextAndNotifyFailure = GetContextAndNotifyFailure; - ::wil::details_abi::g_pProcessLocalData = &g_processLocalData; - g_pThreadFailureCallbacks = &g_threadFailureCallbacks; - return 1; - }); -#endif - } - /// @endcond - - - // This helper functions much like scope_exit -- give it a lambda and get back a local object that can be used to - // catch all errors happening in your module through all WIL error handling mechanisms. The lambda will be called - // once for each error throw, error return, or error catch that is handled while the returned object is still in - // scope. Usage: - // - // auto monitor = wil::ThreadFailureCallback([](wil::FailureInfo const &failure) - // { - // // Write your code that logs or cares about failure details here... - // // It has access to HRESULT, filename, line number, etc through the failure param. - // }); - // - // As long as the returned 'monitor' object remains in scope, the lambda will continue to receive callbacks for any - // failures that occur in this module on the calling thread. Note that this will guarantee that the lambda will run - // for any failure that is through any of the WIL macros (THROW_XXX, RETURN_XXX, LOG_XXX, etc). - - template - inline wil::details::ThreadFailureCallbackFn ThreadFailureCallback(_Inout_ TLambda &&fnAtExit) WI_NOEXCEPT - { - return wil::details::ThreadFailureCallbackFn(nullptr, wistd::forward(fnAtExit)); - } - - - // Much like ThreadFailureCallback, this class will receive WIL failure notifications from the time it's instantiated - // until the time that it's destroyed. At any point during that time you can ask for the last failure that was seen - // by any of the WIL macros (RETURN_XXX, THROW_XXX, LOG_XXX, etc) on the current thread. - // - // This class is most useful when utilized as a member of an RAII class that's dedicated to providing logging or - // telemetry. In the destructor of that class, if the operation had not been completed successfully (it goes out of - // scope due to early return or exception unwind before success is acknowledged) then details about the last failure - // can be retrieved and appropriately logged. - // - // Usage: - // - // class MyLogger - // { - // public: - // MyLogger() : m_fComplete(false) {} - // ~MyLogger() - // { - // if (!m_fComplete) - // { - // FailureInfo *pFailure = m_cache.GetFailure(); - // if (pFailure != nullptr) - // { - // // Log information about pFailure (pFileure->hr, pFailure->pszFile, pFailure->uLineNumber, etc) - // } - // else - // { - // // It's possible that you get stack unwind from an exception that did NOT come through WIL - // // like (std::bad_alloc from the STL). Use a reasonable default like: HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION). - // } - // } - // } - // void Complete() { m_fComplete = true; } - // private: - // bool m_fComplete; - // ThreadFailureCache m_cache; - // }; - - class ThreadFailureCache final : - public details::IFailureCallback - { - public: - ThreadFailureCache() : - m_callbackHolder(this) - { - } - - ThreadFailureCache(ThreadFailureCache && rhs) WI_NOEXCEPT : - m_failure(wistd::move(rhs.m_failure)), - m_callbackHolder(this) - { - } - - ThreadFailureCache& operator=(ThreadFailureCache && rhs) WI_NOEXCEPT - { - m_failure = wistd::move(rhs.m_failure); - return *this; - } - - void WatchCurrentThread() - { - m_callbackHolder.StartWatching(); - } - - void IgnoreCurrentThread() - { - m_callbackHolder.StopWatching(); - } - - FailureInfo const* GetFailure() - { - return (FAILED(m_failure.GetFailureInfo().hr) ? &(m_failure.GetFailureInfo()) : nullptr); - } - - bool NotifyFailure(FailureInfo const& failure) WI_NOEXCEPT override - { - // When we "cache" a failure, we bias towards trying to find the origin of the last HRESULT - // generated, so we ignore subsequent failures on the same error code (assuming propagation). - - if (failure.hr != m_failure.GetFailureInfo().hr) - { - m_failure.SetFailureInfo(failure); - } - return false; - } - - private: - StoredFailureInfo m_failure; - details::ThreadFailureCallbackHolder m_callbackHolder; - }; - -} // wil - -#pragma warning(pop) - -#endif diff --git a/src/common/dep/wil/result_macros.h b/src/common/dep/wil/result_macros.h deleted file mode 100644 index 4f8229743..000000000 --- a/src/common/dep/wil/result_macros.h +++ /dev/null @@ -1,6249 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_RESULTMACROS_INCLUDED -#define __WIL_RESULTMACROS_INCLUDED - -// WARNING: -// Code within this scope must satisfy both C99 and C++ - -#include "common.h" - -#if !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) -#include -#endif - -// Setup the debug behavior. For kernel-mode, we ignore NDEBUG because that gets set automatically -// for driver projects. We mimic the behavior of NT_ASSERT which checks only for DBG. -// RESULT_NO_DEBUG is provided as an opt-out mechanism. -#ifndef RESULT_DEBUG -#if (DBG || defined(DEBUG) || defined(_DEBUG)) && !defined(RESULT_NO_DEBUG) && (defined(WIL_KERNEL_MODE) || !defined(NDEBUG)) -#define RESULT_DEBUG -#endif -#endif - -/// @cond -#if defined(_PREFAST_) -#define __WI_ANALYSIS_ASSUME(_exp) _Analysis_assume_(_exp) -#else -#ifdef RESULT_DEBUG -#define __WI_ANALYSIS_ASSUME(_exp) ((void) 0) -#else -// NOTE: Clang does not currently handle __noop correctly and will fail to compile if the argument is not copy -// constructible. Therefore, use 'sizeof' for syntax validation. We don't do this universally for all compilers -// since lambdas are not allowed in unevaluated contexts prior to C++20, which does not appear to affect __noop -#if !defined(_MSC_VER) || defined(__clang__) -#define __WI_ANALYSIS_ASSUME(_exp) ((void)sizeof(!(_exp))) // Validate syntax on non-debug builds -#else -#define __WI_ANALYSIS_ASSUME(_exp) __noop(_exp) -#endif -#endif -#endif // _PREFAST_ - -//***************************************************************************** -// Assert Macros -//***************************************************************************** - -#ifdef RESULT_DEBUG -// FINE_PATCH: This macro can be already defined if using WIL2Trace.h or WIL2Console.h -#ifndef __WI_ASSERT_FAIL_ANNOTATION -#if defined(__clang__) && defined(_WIN32) -// Clang currently mis-handles '__annotation' for 32-bit - https://bugs.llvm.org/show_bug.cgi?id=41890 -#define __WI_ASSERT_FAIL_ANNOTATION(msg) (void)0 -#else -#define __WI_ASSERT_FAIL_ANNOTATION(msg) __annotation(L"Debug", L"AssertFail", msg) -#endif -#endif // FINE_PATCH - -#define WI_ASSERT(condition) (__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (__WI_ASSERT_FAIL_ANNOTATION(L"" #condition), DbgRaiseAssertionFailure(), FALSE) : TRUE)) -#define WI_ASSERT_MSG(condition, msg) (__WI_ANALYSIS_ASSUME(condition), ((!(condition)) ? (__WI_ASSERT_FAIL_ANNOTATION(L##msg), DbgRaiseAssertionFailure(), FALSE) : TRUE)) -#define WI_ASSERT_NOASSUME WI_ASSERT -#define WI_ASSERT_MSG_NOASSUME WI_ASSERT_MSG -#define WI_VERIFY WI_ASSERT -#define WI_VERIFY_MSG WI_ASSERT_MSG -#define WI_VERIFY_SUCCEEDED(condition) WI_ASSERT(SUCCEEDED(condition)) -#else -#define WI_ASSERT(condition) (__WI_ANALYSIS_ASSUME(condition), 0) -#define WI_ASSERT_MSG(condition, msg) (__WI_ANALYSIS_ASSUME(condition), 0) -#define WI_ASSERT_NOASSUME(condition) ((void) 0) -#define WI_ASSERT_MSG_NOASSUME(condition, msg) ((void) 0) -#define WI_VERIFY(condition) (__WI_ANALYSIS_ASSUME(condition), ((condition) ? TRUE : FALSE)) -#define WI_VERIFY_MSG(condition, msg) (__WI_ANALYSIS_ASSUME(condition), ((condition) ? TRUE : FALSE)) -#define WI_VERIFY_SUCCEEDED(condition) (__WI_ANALYSIS_ASSUME(SUCCEEDED(condition)), ((SUCCEEDED(condition)) ? TRUE : FALSE)) -#endif // RESULT_DEBUG - -#if !defined(_NTDEF_) -typedef _Return_type_success_(return >= 0) LONG NTSTATUS; -#endif -#ifndef STATUS_SUCCESS -#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) -#endif -#ifndef STATUS_UNSUCCESSFUL -#define STATUS_UNSUCCESSFUL ((NTSTATUS)0xC0000001L) -#endif -#ifndef __NTSTATUS_FROM_WIN32 -#define __NTSTATUS_FROM_WIN32(x) ((NTSTATUS)(x) <= 0 ? ((NTSTATUS)(x)) : ((NTSTATUS) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | ERROR_SEVERITY_ERROR))) -#endif - -#ifndef WIL_AllocateMemory -#ifdef _KERNEL_MODE -#define WIL_AllocateMemory(SIZE) ExAllocatePoolWithTag(NonPagedPoolNx, SIZE, 'LIW') -WI_ODR_PRAGMA("WIL_AllocateMemory", "2") -#else -#define WIL_AllocateMemory(SIZE) HeapAlloc(GetProcessHeap(), 0, SIZE) -WI_ODR_PRAGMA("WIL_AllocateMemory", "1") -#endif -#else -WI_ODR_PRAGMA("WIL_AllocateMemory", "0") -#endif - -#ifndef WIL_FreeMemory -#ifdef _KERNEL_MODE -#define WIL_FreeMemory(MEM) ExFreePoolWithTag(MEM, 'LIW') -WI_ODR_PRAGMA("WIL_FreeMemory", "2") -#else -#define WIL_FreeMemory(MEM) HeapFree(GetProcessHeap(), 0, MEM) -WI_ODR_PRAGMA("WIL_FreeMemory", "1") -#endif -#else -WI_ODR_PRAGMA("WIL_FreeMemory", "0") -#endif - -// It would appear as though the C++17 "noexcept is part of the type system" update in MSVC has "infected" the behavior -// when compiling with C++14 (the default...), however the updated behavior for decltype understanding noexcept is _not_ -// present... So, work around it -#if __WI_LIBCPP_STD_VER >= 17 -#define WI_PFN_NOEXCEPT WI_NOEXCEPT -#else -#define WI_PFN_NOEXCEPT -#endif -/// @endcond - -#if defined(__cplusplus) && !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) - -#include -#include // provides the _ReturnAddress() intrinsic -#include // provides 'operator new', 'std::nothrow', etc. -#if defined(WIL_ENABLE_EXCEPTIONS) && !defined(WIL_SUPPRESS_NEW) -#include // provides std::bad_alloc in the windows and public CRT headers -#endif - -#pragma warning(push) -#pragma warning(disable:4714 6262) // __forceinline not honored, stack size - -//***************************************************************************** -// Behavioral setup (error handling macro configuration) -//***************************************************************************** -// Set any of the following macros to the values given below before including Result.h to -// control the error handling macro's trade-offs between diagnostics and performance - -// RESULT_DIAGNOSTICS_LEVEL -// This define controls the level of diagnostic instrumentation that is built into the binary as a -// byproduct of using the macros. The amount of diagnostic instrumentation that is supplied is -// a trade-off between diagnosibility of issues and code size and performance. The modes are: -// 0 - No diagnostics, smallest & fastest (subject to tail-merge) -// 1 - No diagnostics, unique call sites for each macro (defeat's tail-merge) -// 2 - Line number -// 3 - Line number + source filename -// 4 - Line number + source filename + function name -// 5 - Line number + source filename + function name + code within the macro -// By default, mode 3 is used in free builds and mode 5 is used in checked builds. Note that the -// _ReturnAddress() will always be available through all modes when possible. - -// RESULT_INCLUDE_CALLER_RETURNADDRESS -// This controls whether or not the _ReturnAddress() of the function that includes the macro will -// be reported to telemetry. Note that this is in addition to the _ReturnAddress() of the actual -// macro position (which is always reported). The values are: -// 0 - The address is not included -// 1 - The address is included -// The default value is '1'. - -// RESULT_INLINE_ERROR_TESTS -// For conditional macros (other than RETURN_XXX), this controls whether branches will be evaluated -// within the call containing the macro or will be forced into the function called by the macros. -// Pushing branching into the called function reduces code size and the number of unique branches -// evaluated, but increases the instruction count executed per macro. -// 0 - Branching will not happen inline to the macros -// 1 - Branching is pushed into the calling function via __forceinline -// The default value is '1'. Note that XXX_MSG functions are always effectively mode '0' due to the -// compiler's unwillingness to inline var-arg functions. - -// RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST -// RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST -// RESULT_INLINE_ERROR_TESTS_FAIL_FAST -// These defines are identical to those above in form/function, but only applicable to fail fast error -// handling allowing a process to have different diagnostic information and performance characteristics -// for fail fast than for other error handling given the different reporting infrastructure (Watson -// vs Telemetry). - -// Set the default diagnostic mode -// Note that RESULT_DEBUG_INFO and RESULT_SUPPRESS_DEBUG_INFO are older deprecated models of controlling mode -#ifndef RESULT_DIAGNOSTICS_LEVEL -#if (defined(RESULT_DEBUG) || defined(RESULT_DEBUG_INFO)) && !defined(RESULT_SUPPRESS_DEBUG_INFO) -#define RESULT_DIAGNOSTICS_LEVEL 5 -#else -#define RESULT_DIAGNOSTICS_LEVEL 3 -#endif -#endif -#ifndef RESULT_INCLUDE_CALLER_RETURNADDRESS -#define RESULT_INCLUDE_CALLER_RETURNADDRESS 1 -#endif -#ifndef RESULT_INLINE_ERROR_TESTS -#define RESULT_INLINE_ERROR_TESTS 1 -#endif -#ifndef RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST -#define RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST RESULT_DIAGNOSTICS_LEVEL -#endif -#ifndef RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST -#define RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST RESULT_INCLUDE_CALLER_RETURNADDRESS -#endif -#ifndef RESULT_INLINE_ERROR_TESTS_FAIL_FAST -#define RESULT_INLINE_ERROR_TESTS_FAIL_FAST RESULT_INLINE_ERROR_TESTS -#endif - - -//***************************************************************************** -// Win32 specific error macros -//***************************************************************************** - -#define FAILED_WIN32(win32err) ((win32err) != 0) -#define SUCCEEDED_WIN32(win32err) ((win32err) == 0) - - -//***************************************************************************** -// NT_STATUS specific error macros -//***************************************************************************** - -#define FAILED_NTSTATUS(status) (((NTSTATUS)(status)) < 0) -#define SUCCEEDED_NTSTATUS(status) (((NTSTATUS)(status)) >= 0) - - -//***************************************************************************** -// Testing helpers - redefine to run unit tests against fail fast -//***************************************************************************** - -#ifndef RESULT_NORETURN -#define RESULT_NORETURN __declspec(noreturn) -#endif -#ifndef RESULT_NORETURN_NULL -#define RESULT_NORETURN_NULL _Ret_notnull_ -#endif -#ifndef RESULT_NORETURN_RESULT -#define RESULT_NORETURN_RESULT(expr) (void)(expr); -#endif - -//***************************************************************************** -// Helpers to setup the macros and functions used below... do not directly use. -//***************************************************************************** - -/// @cond -#define __R_DIAGNOSTICS(diagnostics) diagnostics.returnAddress, diagnostics.line, diagnostics.file, nullptr, nullptr -#define __R_DIAGNOSTICS_RA(diagnostics, address) diagnostics.returnAddress, diagnostics.line, diagnostics.file, nullptr, nullptr, address -#define __R_FN_PARAMS_FULL _In_opt_ void* callerReturnAddress, unsigned int lineNumber, _In_opt_ PCSTR fileName, _In_opt_ PCSTR functionName, _In_opt_ PCSTR code, void* returnAddress -#define __R_FN_LOCALS_FULL_RA void* callerReturnAddress = nullptr; unsigned int lineNumber = 0; PCSTR fileName = nullptr; PCSTR functionName = nullptr; PCSTR code = nullptr; void* returnAddress = _ReturnAddress(); -// NOTE: This BEGINs the common macro handling (__R_ prefix) for non-fail fast handled cases -// This entire section will be repeated below for fail fast (__RFF_ prefix). -#define __R_COMMA , -#define __R_FN_CALL_FULL callerReturnAddress, lineNumber, fileName, functionName, code, returnAddress -#define __R_FN_CALL_FULL_RA callerReturnAddress, lineNumber, fileName, functionName, code, _ReturnAddress() -// The following macros assemble the varying amount of data we want to collect from the macros, treating it uniformly -#if (RESULT_DIAGNOSTICS_LEVEL >= 2) // line number -#define __R_IF_LINE(term) term -#define __R_IF_NOT_LINE(term) -#define __R_IF_COMMA , -#define __R_LINE_VALUE static_cast(__LINE__) -#else -#define __R_IF_LINE(term) -#define __R_IF_NOT_LINE(term) term -#define __R_IF_COMMA -#define __R_LINE_VALUE static_cast(0) -#endif -#if (RESULT_DIAGNOSTICS_LEVEL >= 3) // line number + file name -#define __R_IF_FILE(term) term -#define __R_IF_NOT_FILE(term) -#define __R_FILE_VALUE __FILE__ -#else -#define __R_IF_FILE(term) -#define __R_IF_NOT_FILE(term) term -#define __R_FILE_VALUE nullptr -#endif -#if (RESULT_DIAGNOSTICS_LEVEL >= 4) // line number + file name + function name -#define __R_IF_FUNCTION(term) term -#define __R_IF_NOT_FUNCTION(term) -#else -#define __R_IF_FUNCTION(term) -#define __R_IF_NOT_FUNCTION(term) term -#endif -#if (RESULT_DIAGNOSTICS_LEVEL >= 5) // line number + file name + function name + macro code -#define __R_IF_CODE(term) term -#define __R_IF_NOT_CODE(term) -#else -#define __R_IF_CODE(term) -#define __R_IF_NOT_CODE(term) term -#endif -#if (RESULT_INCLUDE_CALLER_RETURNADDRESS == 1) -#define __R_IF_CALLERADDRESS(term) term -#define __R_IF_NOT_CALLERADDRESS(term) -#define __R_CALLERADDRESS_VALUE _ReturnAddress() -#else -#define __R_IF_CALLERADDRESS(term) -#define __R_IF_NOT_CALLERADDRESS(term) term -#define __R_CALLERADDRESS_VALUE nullptr -#endif -#if (RESULT_INCLUDE_CALLER_RETURNADDRESS == 1) || (RESULT_DIAGNOSTICS_LEVEL >= 2) -#define __R_IF_TRAIL_COMMA , -#else -#define __R_IF_TRAIL_COMMA -#endif -// Assemble the varying amounts of data into a single macro -#define __R_INFO_ONLY(CODE) __R_IF_CALLERADDRESS(_ReturnAddress() __R_IF_COMMA) __R_IF_LINE(__R_LINE_VALUE) __R_IF_FILE(__R_COMMA __R_FILE_VALUE) __R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE) -#define __R_INFO(CODE) __R_INFO_ONLY(CODE) __R_IF_TRAIL_COMMA -#define __R_INFO_NOFILE_ONLY(CODE) __R_IF_CALLERADDRESS(_ReturnAddress() __R_IF_COMMA) __R_IF_LINE(__R_LINE_VALUE) __R_IF_FILE(__R_COMMA "wil") __R_IF_FUNCTION(__R_COMMA __FUNCTION__) __R_IF_CODE(__R_COMMA CODE) -#define __R_INFO_NOFILE(CODE) __R_INFO_NOFILE_ONLY(CODE) __R_IF_TRAIL_COMMA -#define __R_FN_PARAMS_ONLY __R_IF_CALLERADDRESS(void* callerReturnAddress __R_IF_COMMA) __R_IF_LINE(unsigned int lineNumber) __R_IF_FILE(__R_COMMA _In_opt_ PCSTR fileName) __R_IF_FUNCTION(__R_COMMA _In_opt_ PCSTR functionName) __R_IF_CODE(__R_COMMA _In_opt_ PCSTR code) -#define __R_FN_PARAMS __R_FN_PARAMS_ONLY __R_IF_TRAIL_COMMA -#define __R_FN_CALL_ONLY __R_IF_CALLERADDRESS(callerReturnAddress __R_IF_COMMA) __R_IF_LINE(lineNumber) __R_IF_FILE(__R_COMMA fileName) __R_IF_FUNCTION(__R_COMMA functionName) __R_IF_CODE(__R_COMMA code) -#define __R_FN_CALL __R_FN_CALL_ONLY __R_IF_TRAIL_COMMA -#define __R_FN_LOCALS __R_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) __R_IF_NOT_LINE(unsigned int lineNumber = 0;) __R_IF_NOT_FILE(PCSTR fileName = nullptr;) __R_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) __R_IF_NOT_CODE(PCSTR code = nullptr;) -#define __R_FN_LOCALS_RA __R_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) __R_IF_NOT_LINE(unsigned int lineNumber = 0;) __R_IF_NOT_FILE(PCSTR fileName = nullptr;) __R_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) __R_IF_NOT_CODE(PCSTR code = nullptr;) void* returnAddress = _ReturnAddress(); -#define __R_FN_UNREFERENCED __R_IF_CALLERADDRESS((void)callerReturnAddress;) __R_IF_LINE((void)lineNumber;) __R_IF_FILE((void)fileName;) __R_IF_FUNCTION((void)functionName;) __R_IF_CODE((void)code;) -// 1) Direct Methods -// * Called Directly by Macros -// * Always noinline -// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1) -#if (RESULT_DIAGNOSTICS_LEVEL == 1) -#define __R_DIRECT_METHOD(RetType, MethodName) template inline __declspec(noinline) RetType MethodName -#define __R_DIRECT_NORET_METHOD(RetType, MethodName) template inline __declspec(noinline) RESULT_NORETURN RetType MethodName -#else -#define __R_DIRECT_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName -#define __R_DIRECT_NORET_METHOD(RetType, MethodName) inline __declspec(noinline) RESULT_NORETURN RetType MethodName -#endif -#define __R_DIRECT_FN_PARAMS __R_FN_PARAMS -#define __R_DIRECT_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY -#define __R_DIRECT_FN_CALL __R_FN_CALL_FULL_RA __R_COMMA -#define __R_DIRECT_FN_CALL_ONLY __R_FN_CALL_FULL_RA -// 2) Internal Methods -// * Only called by Conditional routines -// * 'inline' when (RESULT_INLINE_ERROR_TESTS = 0 and RESULT_DIAGNOSTICS_LEVEL != 1), otherwise noinline (directly called by code when branching is forceinlined) -// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1 and RESULT_INLINE_ERROR_TESTS = 1) -#if (RESULT_DIAGNOSTICS_LEVEL == 1) -#define __R_INTERNAL_NOINLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName -#define __R_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName -#define __R_INTERNAL_INLINE_METHOD(MethodName) template inline __declspec(noinline) void MethodName -#define __R_INTERNAL_INLINE_NORET_METHOD(MethodName) template inline __declspec(noinline) RESULT_NORETURN void MethodName -#define __R_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName -#else -#define __R_INTERNAL_NOINLINE_METHOD(MethodName) inline void MethodName -#define __R_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline RESULT_NORETURN void MethodName -#define __R_INTERNAL_INLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName -#define __R_INTERNAL_INLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName -#define __R_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName -#endif -#define __R_CALL_INTERNAL_NOINLINE_METHOD(MethodName) MethodName -#define __R_INTERNAL_NOINLINE_FN_PARAMS __R_FN_PARAMS void* returnAddress __R_COMMA -#define __R_INTERNAL_NOINLINE_FN_PARAMS_ONLY __R_FN_PARAMS void* returnAddress -#define __R_INTERNAL_NOINLINE_FN_CALL __R_FN_CALL_FULL __R_COMMA -#define __R_INTERNAL_NOINLINE_FN_CALL_ONLY __R_FN_CALL_FULL -#define __R_INTERNAL_INLINE_FN_PARAMS __R_FN_PARAMS -#define __R_INTERNAL_INLINE_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY -#define __R_INTERNAL_INLINE_FN_CALL __R_FN_CALL_FULL_RA __R_COMMA -#define __R_INTERNAL_INLINE_FN_CALL_ONLY __R_FN_CALL_FULL_RA -#if (RESULT_INLINE_ERROR_TESTS == 0) -#define __R_INTERNAL_METHOD __R_INTERNAL_NOINLINE_METHOD -#define __R_INTERNAL_NORET_METHOD __R_INTERNAL_NOINLINE_NORET_METHOD -#define __R_CALL_INTERNAL_METHOD __R_CALL_INTERNAL_NOINLINE_METHOD -#define __R_INTERNAL_FN_PARAMS __R_INTERNAL_NOINLINE_FN_PARAMS -#define __R_INTERNAL_FN_PARAMS_ONLY __R_INTERNAL_NOINLINE_FN_PARAMS_ONLY -#define __R_INTERNAL_FN_CALL __R_INTERNAL_NOINLINE_FN_CALL -#define __R_INTERNAL_FN_CALL_ONLY __R_INTERNAL_NOINLINE_FN_CALL_ONLY -#else -#define __R_INTERNAL_METHOD __R_INTERNAL_INLINE_METHOD -#define __R_INTERNAL_NORET_METHOD __R_INTERNAL_INLINE_NORET_METHOD -#define __R_CALL_INTERNAL_METHOD __R_CALL_INTERNAL_INLINE_METHOD -#define __R_INTERNAL_FN_PARAMS __R_INTERNAL_INLINE_FN_PARAMS -#define __R_INTERNAL_FN_PARAMS_ONLY __R_INTERNAL_INLINE_FN_PARAMS_ONLY -#define __R_INTERNAL_FN_CALL __R_INTERNAL_INLINE_FN_CALL -#define __R_INTERNAL_FN_CALL_ONLY __R_INTERNAL_INLINE_FN_CALL_ONLY -#endif -// 3) Conditional Methods -// * Called Directly by Macros -// * May be noinline or __forceinline depending upon (RESULT_INLINE_ERROR_TESTS) -// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL == 1) -#if (RESULT_DIAGNOSTICS_LEVEL == 1) -#define __R_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) template inline __declspec(noinline) RetType MethodName -#define __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName -#define __R_CONDITIONAL_INLINE_METHOD(RetType, MethodName) template __forceinline RetType MethodName -#define __R_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName -#define __R_CONDITIONAL_PARTIAL_TEMPLATE unsigned int optimizerCounter __R_COMMA -#else -#define __R_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName -#define __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName -#define __R_CONDITIONAL_INLINE_METHOD(RetType, MethodName) __forceinline RetType MethodName -#define __R_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName -#define __R_CONDITIONAL_PARTIAL_TEMPLATE -#endif -#define __R_CONDITIONAL_NOINLINE_FN_CALL __R_FN_CALL _ReturnAddress() __R_COMMA -#define __R_CONDITIONAL_NOINLINE_FN_CALL_ONLY __R_FN_CALL _ReturnAddress() -#define __R_CONDITIONAL_INLINE_FN_CALL __R_FN_CALL -#define __R_CONDITIONAL_INLINE_FN_CALL_ONLY __R_FN_CALL_ONLY -#if (RESULT_INLINE_ERROR_TESTS == 0) -#define __R_CONDITIONAL_METHOD __R_CONDITIONAL_NOINLINE_METHOD -#define __R_CONDITIONAL_TEMPLATE_METHOD __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD -#define __R_CONDITIONAL_FN_CALL __R_CONDITIONAL_NOINLINE_FN_CALL -#define __R_CONDITIONAL_FN_CALL_ONLY __R_CONDITIONAL_NOINLINE_FN_CALL_ONLY -#else -#define __R_CONDITIONAL_METHOD __R_CONDITIONAL_INLINE_METHOD -#define __R_CONDITIONAL_TEMPLATE_METHOD __R_CONDITIONAL_INLINE_TEMPLATE_METHOD -#define __R_CONDITIONAL_FN_CALL __R_CONDITIONAL_INLINE_FN_CALL -#define __R_CONDITIONAL_FN_CALL_ONLY __R_CONDITIONAL_INLINE_FN_CALL_ONLY -#endif -#define __R_CONDITIONAL_FN_PARAMS __R_FN_PARAMS -#define __R_CONDITIONAL_FN_PARAMS_ONLY __R_FN_PARAMS_ONLY -// Macro call-site helpers -#define __R_NS_ASSEMBLE2(ri, rd) in##ri##diag##rd // Differing internal namespaces eliminate ODR violations between modes -#define __R_NS_ASSEMBLE(ri, rd) __R_NS_ASSEMBLE2(ri, rd) -#define __R_NS_NAME __R_NS_ASSEMBLE(RESULT_INLINE_ERROR_TESTS, RESULT_DIAGNOSTICS_LEVEL) -#define __R_NS wil::details::__R_NS_NAME -#if (RESULT_DIAGNOSTICS_LEVEL == 1) -#define __R_FN(MethodName) __R_NS:: MethodName <__COUNTER__> -#else -#define __R_FN(MethodName) __R_NS:: MethodName -#endif -// NOTE: This ENDs the common macro handling (__R_ prefix) for non-fail fast handled cases -// This entire section is repeated below for fail fast (__RFF_ prefix). For ease of editing this section, the -// process is to copy/paste, and search and replace (__R_ -> __RFF_), (RESULT_DIAGNOSTICS_LEVEL -> RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST), -// (RESULT_INLINE_ERROR_TESTS -> RESULT_INLINE_ERROR_TESTS_FAIL_FAST) and (RESULT_INCLUDE_CALLER_RETURNADDRESS -> RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST) -#define __RFF_COMMA , -#define __RFF_FN_CALL_FULL callerReturnAddress, lineNumber, fileName, functionName, code, returnAddress -#define __RFF_FN_CALL_FULL_RA callerReturnAddress, lineNumber, fileName, functionName, code, _ReturnAddress() -// The following macros assemble the varying amount of data we want to collect from the macros, treating it uniformly -#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 2) // line number -#define __RFF_IF_LINE(term) term -#define __RFF_IF_NOT_LINE(term) -#define __RFF_IF_COMMA , -#else -#define __RFF_IF_LINE(term) -#define __RFF_IF_NOT_LINE(term) term -#define __RFF_IF_COMMA -#endif -#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 3) // line number + file name -#define __RFF_IF_FILE(term) term -#define __RFF_IF_NOT_FILE(term) -#else -#define __RFF_IF_FILE(term) -#define __RFF_IF_NOT_FILE(term) term -#endif -#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 4) // line number + file name + function name -#define __RFF_IF_FUNCTION(term) term -#define __RFF_IF_NOT_FUNCTION(term) -#else -#define __RFF_IF_FUNCTION(term) -#define __RFF_IF_NOT_FUNCTION(term) term -#endif -#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 5) // line number + file name + function name + macro code -#define __RFF_IF_CODE(term) term -#define __RFF_IF_NOT_CODE(term) -#else -#define __RFF_IF_CODE(term) -#define __RFF_IF_NOT_CODE(term) term -#endif -#if (RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST == 1) -#define __RFF_IF_CALLERADDRESS(term) term -#define __RFF_IF_NOT_CALLERADDRESS(term) -#else -#define __RFF_IF_CALLERADDRESS(term) -#define __RFF_IF_NOT_CALLERADDRESS(term) term -#endif -#if (RESULT_INCLUDE_CALLER_RETURNADDRESS_FAIL_FAST == 1) || (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST >= 2) -#define __RFF_IF_TRAIL_COMMA , -#else -#define __RFF_IF_TRAIL_COMMA -#endif -// Assemble the varying amounts of data into a single macro -#define __RFF_INFO_ONLY(CODE) __RFF_IF_CALLERADDRESS(_ReturnAddress() __RFF_IF_COMMA) __RFF_IF_LINE(__R_LINE_VALUE) __RFF_IF_FILE(__RFF_COMMA __R_FILE_VALUE) __RFF_IF_FUNCTION(__RFF_COMMA __FUNCTION__) __RFF_IF_CODE(__RFF_COMMA CODE) -#define __RFF_INFO(CODE) __RFF_INFO_ONLY(CODE) __RFF_IF_TRAIL_COMMA -#define __RFF_INFO_NOFILE_ONLY(CODE) __RFF_IF_CALLERADDRESS(_ReturnAddress() __RFF_IF_COMMA) __RFF_IF_LINE(__R_LINE_VALUE) __RFF_IF_FILE(__RFF_COMMA "wil") __RFF_IF_FUNCTION(__RFF_COMMA __FUNCTION__) __RFF_IF_CODE(__RFF_COMMA CODE) -#define __RFF_INFO_NOFILE(CODE) __RFF_INFO_NOFILE_ONLY(CODE) __RFF_IF_TRAIL_COMMA -#define __RFF_FN_PARAMS_ONLY __RFF_IF_CALLERADDRESS(void* callerReturnAddress __RFF_IF_COMMA) __RFF_IF_LINE(unsigned int lineNumber) __RFF_IF_FILE(__RFF_COMMA _In_opt_ PCSTR fileName) __RFF_IF_FUNCTION(__RFF_COMMA _In_opt_ PCSTR functionName) __RFF_IF_CODE(__RFF_COMMA _In_opt_ PCSTR code) -#define __RFF_FN_PARAMS __RFF_FN_PARAMS_ONLY __RFF_IF_TRAIL_COMMA -#define __RFF_FN_CALL_ONLY __RFF_IF_CALLERADDRESS(callerReturnAddress __RFF_IF_COMMA) __RFF_IF_LINE(lineNumber) __RFF_IF_FILE(__RFF_COMMA fileName) __RFF_IF_FUNCTION(__RFF_COMMA functionName) __RFF_IF_CODE(__RFF_COMMA code) -#define __RFF_FN_CALL __RFF_FN_CALL_ONLY __RFF_IF_TRAIL_COMMA -#define __RFF_FN_LOCALS __RFF_IF_NOT_CALLERADDRESS(void* callerReturnAddress = nullptr;) __RFF_IF_NOT_LINE(unsigned int lineNumber = 0;) __RFF_IF_NOT_FILE(PCSTR fileName = nullptr;) __RFF_IF_NOT_FUNCTION(PCSTR functionName = nullptr;) __RFF_IF_NOT_CODE(PCSTR code = nullptr;) -#define __RFF_FN_UNREFERENCED __RFF_IF_CALLERADDRESS(callerReturnAddress;) __RFF_IF_LINE(lineNumber;) __RFF_IF_FILE(fileName;) __RFF_IF_FUNCTION(functionName;) __RFF_IF_CODE(code;) -// 1) Direct Methods -// * Called Directly by Macros -// * Always noinline -// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) -#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) -#define __RFF_DIRECT_METHOD(RetType, MethodName) template inline __declspec(noinline) RetType MethodName -#define __RFF_DIRECT_NORET_METHOD(RetType, MethodName) template inline __declspec(noinline) RESULT_NORETURN RetType MethodName -#else -#define __RFF_DIRECT_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName -#define __RFF_DIRECT_NORET_METHOD(RetType, MethodName) inline __declspec(noinline) RESULT_NORETURN RetType MethodName -#endif -#define __RFF_DIRECT_FN_PARAMS __RFF_FN_PARAMS -#define __RFF_DIRECT_FN_PARAMS_ONLY __RFF_FN_PARAMS_ONLY -#define __RFF_DIRECT_FN_CALL __RFF_FN_CALL_FULL_RA __RFF_COMMA -#define __RFF_DIRECT_FN_CALL_ONLY __RFF_FN_CALL_FULL_RA -// 2) Internal Methods -// * Only called by Conditional routines -// * 'inline' when (RESULT_INLINE_ERROR_TESTS_FAIL_FAST = 0 and RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST != 1), otherwise noinline (directly called by code when branching is forceinlined) -// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1 and RESULT_INLINE_ERROR_TESTS_FAIL_FAST = 1) -#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) -#define __RFF_INTERNAL_NOINLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName -#define __RFF_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName -#define __RFF_INTERNAL_INLINE_METHOD(MethodName) template inline __declspec(noinline) void MethodName -#define __RFF_INTERNAL_INLINE_NORET_METHOD(MethodName) template inline __declspec(noinline) RESULT_NORETURN void MethodName -#define __RFF_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName -#else -#define __RFF_INTERNAL_NOINLINE_METHOD(MethodName) inline void MethodName -#define __RFF_INTERNAL_NOINLINE_NORET_METHOD(MethodName) inline RESULT_NORETURN void MethodName -#define __RFF_INTERNAL_INLINE_METHOD(MethodName) inline __declspec(noinline) void MethodName -#define __RFF_INTERNAL_INLINE_NORET_METHOD(MethodName) inline __declspec(noinline) RESULT_NORETURN void MethodName -#define __RFF_CALL_INTERNAL_INLINE_METHOD(MethodName) MethodName -#endif -#define __RFF_CALL_INTERNAL_NOINLINE_METHOD(MethodName) MethodName -#define __RFF_INTERNAL_NOINLINE_FN_PARAMS __RFF_FN_PARAMS void* returnAddress __RFF_COMMA -#define __RFF_INTERNAL_NOINLINE_FN_PARAMS_ONLY __RFF_FN_PARAMS void* returnAddress -#define __RFF_INTERNAL_NOINLINE_FN_CALL __RFF_FN_CALL_FULL __RFF_COMMA -#define __RFF_INTERNAL_NOINLINE_FN_CALL_ONLY __RFF_FN_CALL_FULL -#define __RFF_INTERNAL_INLINE_FN_PARAMS __RFF_FN_PARAMS -#define __RFF_INTERNAL_INLINE_FN_PARAMS_ONLY __RFF_FN_PARAMS_ONLY -#define __RFF_INTERNAL_INLINE_FN_CALL __RFF_FN_CALL_FULL_RA __RFF_COMMA -#define __RFF_INTERNAL_INLINE_FN_CALL_ONLY __RFF_FN_CALL_FULL_RA -#if (RESULT_INLINE_ERROR_TESTS_FAIL_FAST == 0) -#define __RFF_INTERNAL_METHOD __RFF_INTERNAL_NOINLINE_METHOD -#define __RFF_INTERNAL_NORET_METHOD __RFF_INTERNAL_NOINLINE_NORET_METHOD -#define __RFF_CALL_INTERNAL_METHOD __RFF_CALL_INTERNAL_NOINLINE_METHOD -#define __RFF_INTERNAL_FN_PARAMS __RFF_INTERNAL_NOINLINE_FN_PARAMS -#define __RFF_INTERNAL_FN_PARAMS_ONLY __RFF_INTERNAL_NOINLINE_FN_PARAMS_ONLY -#define __RFF_INTERNAL_FN_CALL __RFF_INTERNAL_NOINLINE_FN_CALL -#define __RFF_INTERNAL_FN_CALL_ONLY __RFF_INTERNAL_NOINLINE_FN_CALL_ONLY -#else -#define __RFF_INTERNAL_METHOD __RFF_INTERNAL_INLINE_METHOD -#define __RFF_INTERNAL_NORET_METHOD __RFF_INTERNAL_INLINE_NORET_METHOD -#define __RFF_CALL_INTERNAL_METHOD __RFF_CALL_INTERNAL_INLINE_METHOD -#define __RFF_INTERNAL_FN_PARAMS __RFF_INTERNAL_INLINE_FN_PARAMS -#define __RFF_INTERNAL_FN_PARAMS_ONLY __RFF_INTERNAL_INLINE_FN_PARAMS_ONLY -#define __RFF_INTERNAL_FN_CALL __RFF_INTERNAL_INLINE_FN_CALL -#define __RFF_INTERNAL_FN_CALL_ONLY __RFF_INTERNAL_INLINE_FN_CALL_ONLY -#endif -// 3) Conditional Methods -// * Called Directly by Macros -// * May be noinline or __forceinline depending upon (RESULT_INLINE_ERROR_TESTS_FAIL_FAST) -// * May be template-driven to create unique call sites if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) -#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) -#define __RFF_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) template inline __declspec(noinline) RetType MethodName -#define __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName -#define __RFF_CONDITIONAL_INLINE_METHOD(RetType, MethodName) template __forceinline RetType MethodName -#define __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName -#define __RFF_CONDITIONAL_PARTIAL_TEMPLATE unsigned int optimizerCounter __RFF_COMMA -#else -#define __RFF_CONDITIONAL_NOINLINE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName -#define __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RetType, MethodName) inline __declspec(noinline) RetType MethodName -#define __RFF_CONDITIONAL_INLINE_METHOD(RetType, MethodName) __forceinline RetType MethodName -#define __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD(RetType, MethodName) __forceinline RetType MethodName -#define __RFF_CONDITIONAL_PARTIAL_TEMPLATE -#endif -#define __RFF_CONDITIONAL_NOINLINE_FN_CALL __RFF_FN_CALL _ReturnAddress() __RFF_COMMA -#define __RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY __RFF_FN_CALL _ReturnAddress() -#define __RFF_CONDITIONAL_INLINE_FN_CALL __RFF_FN_CALL -#define __RFF_CONDITIONAL_INLINE_FN_CALL_ONLY __RFF_FN_CALL_ONLY -#if (RESULT_INLINE_ERROR_TESTS_FAIL_FAST == 0) -#define __RFF_CONDITIONAL_METHOD __RFF_CONDITIONAL_NOINLINE_METHOD -#define __RFF_CONDITIONAL_TEMPLATE_METHOD __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD -#define __RFF_CONDITIONAL_FN_CALL __RFF_CONDITIONAL_NOINLINE_FN_CALL -#define __RFF_CONDITIONAL_FN_CALL_ONLY __RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY -#else -#define __RFF_CONDITIONAL_METHOD __RFF_CONDITIONAL_INLINE_METHOD -#define __RFF_CONDITIONAL_TEMPLATE_METHOD __RFF_CONDITIONAL_INLINE_TEMPLATE_METHOD -#define __RFF_CONDITIONAL_FN_CALL __RFF_CONDITIONAL_INLINE_FN_CALL -#define __RFF_CONDITIONAL_FN_CALL_ONLY __RFF_CONDITIONAL_INLINE_FN_CALL_ONLY -#endif -#define __RFF_CONDITIONAL_FN_PARAMS __RFF_FN_PARAMS -#define __RFF_CONDITIONAL_FN_PARAMS_ONLY __RFF_FN_PARAMS_ONLY -// Macro call-site helpers -#define __RFF_NS_ASSEMBLE2(ri, rd) in##ri##diag##rd // Differing internal namespaces eliminate ODR violations between modes -#define __RFF_NS_ASSEMBLE(ri, rd) __RFF_NS_ASSEMBLE2(ri, rd) -#define __RFF_NS_NAME __RFF_NS_ASSEMBLE(RESULT_INLINE_ERROR_TESTS_FAIL_FAST, RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST) -#define __RFF_NS wil::details::__RFF_NS_NAME -#if (RESULT_DIAGNOSTICS_LEVEL_FAIL_FAST == 1) -#define __RFF_FN(MethodName) __RFF_NS:: MethodName <__COUNTER__> -#else -#define __RFF_FN(MethodName) __RFF_NS:: MethodName -#endif -// end-of-repeated fail-fast handling macros - -// Force the compiler to evaluate a call to 'wprintf' to verify the format string & args and produce warnings if there -// are any issues. The short-circuit 'and' will prevent the call and strings used from making it into the binary. -// Note that this requires using a string literal for the format string. If you don't, you'll get the following compiler -// error: error C2146: syntax error: missing ')' before identifier '...' -#if !defined(wprintf) && !defined(WIL_NO_MSG_FORMAT_CHECKS) -#define __WI_CHECK_MSG_FMT(fmt, ...) (0 && ::wprintf(L"" fmt, ##__VA_ARGS__)) ? nullptr : fmt, ##__VA_ARGS__ -#else -#define __WI_CHECK_MSG_FMT(fmt, ...) fmt, ##__VA_ARGS__ -#endif - -// Helpers for return macros -#define __RETURN_HR_MSG(hr, str, fmt, ...) __WI_SUPPRESS_4127_S do { const HRESULT __hr = (hr); if (FAILED(__hr)) { __R_FN(Return_HrMsg)(__R_INFO(str) __hr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); } return __hr; } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __RETURN_HR_MSG_FAIL(hr, str, fmt, ...) __WI_SUPPRESS_4127_S do { const HRESULT __hr = (hr); __R_FN(Return_HrMsg)(__R_INFO(str) __hr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); return __hr; } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __RETURN_WIN32_MSG(err, str, fmt, ...) __WI_SUPPRESS_4127_S do { const DWORD __err = (err); if (FAILED_WIN32(__err)) { return __R_FN(Return_Win32Msg)(__R_INFO(str) __err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); } return S_OK; } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __RETURN_WIN32_MSG_FAIL(err, str, fmt, ...) __WI_SUPPRESS_4127_S do { const DWORD __err = (err); return __R_FN(Return_Win32Msg)(__R_INFO(str) __err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __RETURN_GLE_MSG_FAIL(str, fmt, ...) return __R_FN(Return_GetLastErrorMsg)(__R_INFO(str) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define __RETURN_NTSTATUS_MSG(status, str, fmt, ...) __WI_SUPPRESS_4127_S do { const NTSTATUS __status = (status); if (FAILED_NTSTATUS(__status)) { return __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); } return S_OK; } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __RETURN_NTSTATUS_MSG_FAIL(status, str, fmt, ...) __WI_SUPPRESS_4127_S do { const NTSTATUS __status = (status); return __R_FN(Return_NtStatusMsg)(__R_INFO(str) __status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)); } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __RETURN_HR(hr, str) __WI_SUPPRESS_4127_S do { const HRESULT __hr = (hr); if (FAILED(__hr)) { __R_FN(Return_Hr)(__R_INFO(str) __hr); } return __hr; } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __RETURN_HR_NOFILE(hr, str) __WI_SUPPRESS_4127_S do { const HRESULT __hr = (hr); if (FAILED(__hr)) { __R_FN(Return_Hr)(__R_INFO_NOFILE(str) __hr); } return __hr; } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __RETURN_HR_FAIL(hr, str) __WI_SUPPRESS_4127_S do { const HRESULT __hr = (hr); __R_FN(Return_Hr)(__R_INFO(str) __hr); return __hr; } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __RETURN_HR_FAIL_NOFILE(hr, str) __WI_SUPPRESS_4127_S do { const HRESULT __hr = (hr); __R_FN(Return_Hr)(__R_INFO_NOFILE(str) __hr); return __hr; } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __RETURN_WIN32(err, str) __WI_SUPPRESS_4127_S do { const DWORD __err = (err); if (FAILED_WIN32(__err)) { return __R_FN(Return_Win32)(__R_INFO(str) __err); } return S_OK; } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __RETURN_WIN32_FAIL(err, str) __WI_SUPPRESS_4127_S do { const DWORD __err = (err); return __R_FN(Return_Win32)(__R_INFO(str) __err); } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __RETURN_GLE_FAIL(str) return __R_FN(Return_GetLastError)(__R_INFO_ONLY(str)) -#define __RETURN_GLE_FAIL_NOFILE(str) return __R_FN(Return_GetLastError)(__R_INFO_NOFILE_ONLY(str)) -#define __RETURN_NTSTATUS(status, str) __WI_SUPPRESS_4127_S do { const NTSTATUS __status = (status); if (FAILED_NTSTATUS(__status)) { return __R_FN(Return_NtStatus)(__R_INFO(str) __status); } return S_OK; } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __RETURN_NTSTATUS_FAIL(status, str) __WI_SUPPRESS_4127_S do { const NTSTATUS __status = (status); return __R_FN(Return_NtStatus)(__R_INFO(str) __status); } __WI_SUPPRESS_4127_E while ((void)0, 0) -/// @endcond - -//***************************************************************************** -// Macros for returning failures as HRESULTs -//***************************************************************************** - -// Always returns a known result (HRESULT) - always logs failures -#define RETURN_HR(hr) __RETURN_HR(wil::verify_hresult(hr), #hr) -#define RETURN_LAST_ERROR() __RETURN_GLE_FAIL(nullptr) -#define RETURN_WIN32(win32err) __RETURN_WIN32(win32err, #win32err) -#define RETURN_NTSTATUS(status) __RETURN_NTSTATUS(status, #status) - -// Conditionally returns failures (HRESULT) - always logs failures -#define RETURN_IF_FAILED(hr) __WI_SUPPRESS_4127_S do { const auto __hrRet = wil::verify_hresult(hr); if (FAILED(__hrRet)) { __RETURN_HR_FAIL(__hrRet, #hr); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) __WI_SUPPRESS_4127_S do { const auto __boolRet = wil::verify_BOOL(win32BOOL); if (!__boolRet) { __RETURN_GLE_FAIL(#win32BOOL); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define RETURN_IF_WIN32_ERROR(win32err) __WI_SUPPRESS_4127_S do { const DWORD __errRet = (win32err); if (FAILED_WIN32(__errRet)) { __RETURN_WIN32_FAIL(__errRet, #win32err); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define RETURN_IF_NULL_ALLOC(ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __RETURN_HR_FAIL(E_OUTOFMEMORY, #ptr); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define RETURN_HR_IF(hr, condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { __RETURN_HR(wil::verify_hresult(hr), #condition); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define RETURN_HR_IF_NULL(hr, ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __RETURN_HR(wil::verify_hresult(hr), #ptr); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define RETURN_LAST_ERROR_IF(condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { __RETURN_GLE_FAIL(#condition); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define RETURN_LAST_ERROR_IF_NULL(ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __RETURN_GLE_FAIL(#ptr); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define RETURN_IF_NTSTATUS_FAILED(status) __WI_SUPPRESS_4127_S do { const NTSTATUS __statusRet = (status); if (FAILED_NTSTATUS(__statusRet)) { __RETURN_NTSTATUS_FAIL(__statusRet, #status); }} __WI_SUPPRESS_4127_E while ((void)0, 0) - -// Always returns a known failure (HRESULT) - always logs a var-arg message on failure -#define RETURN_HR_MSG(hr, fmt, ...) __RETURN_HR_MSG(wil::verify_hresult(hr), #hr, fmt, ##__VA_ARGS__) -#define RETURN_LAST_ERROR_MSG(fmt, ...) __RETURN_GLE_MSG_FAIL(nullptr, fmt, ##__VA_ARGS__) -#define RETURN_WIN32_MSG(win32err, fmt, ...) __RETURN_WIN32_MSG(win32err, #win32err, fmt, ##__VA_ARGS__) -#define RETURN_NTSTATUS_MSG(status, fmt, ...) __RETURN_NTSTATUS_MSG(status, #status, fmt, ##__VA_ARGS__) - -// Conditionally returns failures (HRESULT) - always logs a var-arg message on failure -#define RETURN_IF_FAILED_MSG(hr, fmt, ...) __WI_SUPPRESS_4127_S do { const auto __hrRet = wil::verify_hresult(hr); if (FAILED(__hrRet)) { __RETURN_HR_MSG_FAIL(__hrRet, #hr, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) __WI_SUPPRESS_4127_S do { if (!wil::verify_BOOL(win32BOOL)) { __RETURN_GLE_MSG_FAIL(#win32BOOL, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_IF_WIN32_ERROR_MSG(win32err, fmt, ...) __WI_SUPPRESS_4127_S do { const DWORD __errRet = (win32err); if (FAILED_WIN32(__errRet)) { __RETURN_WIN32_MSG_FAIL(__errRet, #win32err, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_IF_NULL_ALLOC_MSG(ptr, fmt, ...) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __RETURN_HR_MSG_FAIL(E_OUTOFMEMORY, #ptr, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_HR_IF_MSG(hr, condition, fmt, ...) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { __RETURN_HR_MSG(wil::verify_hresult(hr), #condition, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_HR_IF_NULL_MSG(hr, ptr, fmt, ...) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __RETURN_HR_MSG(wil::verify_hresult(hr), #ptr, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_LAST_ERROR_IF_MSG(condition, fmt, ...) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { __RETURN_GLE_MSG_FAIL(#condition, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __RETURN_GLE_MSG_FAIL(#ptr, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) __WI_SUPPRESS_4127_S do { const NTSTATUS __statusRet = (status); if (FAILED_NTSTATUS(__statusRet)) { __RETURN_NTSTATUS_MSG_FAIL(__statusRet, #status, fmt, ##__VA_ARGS__); }} __WI_SUPPRESS_4127_E while((void)0, 0) - -// Conditionally returns failures (HRESULT) - use for failures that are expected in common use - failures are not logged - macros are only for control flow pattern -#define RETURN_IF_FAILED_EXPECTED(hr) __WI_SUPPRESS_4127_S do { const auto __hrRet = wil::verify_hresult(hr); if (FAILED(__hrRet)) { return __hrRet; }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(win32BOOL) __WI_SUPPRESS_4127_S do { if (!wil::verify_BOOL(win32BOOL)) { return wil::details::GetLastErrorFailHr(); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_IF_WIN32_ERROR_EXPECTED(win32err) __WI_SUPPRESS_4127_S do { const DWORD __errRet = (win32err); if (FAILED_WIN32(__errRet)) { return __HRESULT_FROM_WIN32(__errRet); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_IF_NULL_ALLOC_EXPECTED(ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { return E_OUTOFMEMORY; }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_HR_IF_EXPECTED(hr, condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { return wil::verify_hresult(hr); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_HR_IF_NULL_EXPECTED(hr, ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { return wil::verify_hresult(hr); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_LAST_ERROR_IF_EXPECTED(condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { return wil::details::GetLastErrorFailHr(); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_LAST_ERROR_IF_NULL_EXPECTED(ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { return wil::details::GetLastErrorFailHr(); }} __WI_SUPPRESS_4127_E while((void)0, 0) -#define RETURN_IF_NTSTATUS_FAILED_EXPECTED(status) __WI_SUPPRESS_4127_S do { const NTSTATUS __statusRet = (status); if (FAILED_NTSTATUS(__statusRet)) { return wil::details::NtStatusToHr(__statusRet); }} __WI_SUPPRESS_4127_E while((void)0, 0) - -#define __WI_OR_IS_EXPECTED_HRESULT(e) || (__hrRet == wil::verify_hresult(e)) -#define RETURN_IF_FAILED_WITH_EXPECTED(hr, hrExpected, ...) \ - do \ - { \ - const auto __hrRet = wil::verify_hresult(hr); \ - if (FAILED(__hrRet)) \ - { \ - if ((__hrRet == wil::verify_hresult(hrExpected)) WI_FOREACH(__WI_OR_IS_EXPECTED_HRESULT, ##__VA_ARGS__)) \ - { \ - return __hrRet; \ - } \ - __RETURN_HR_FAIL(__hrRet, #hr); \ - } \ - } \ - while ((void)0, 0) - -//***************************************************************************** -// Macros for logging failures (ignore or pass-through) -//***************************************************************************** - -// Always logs a known failure -#define LOG_HR(hr) __R_FN(Log_Hr)(__R_INFO(#hr) wil::verify_hresult(hr)) -#define LOG_LAST_ERROR() __R_FN(Log_GetLastError)(__R_INFO_ONLY(nullptr)) -#define LOG_WIN32(win32err) __R_FN(Log_Win32)(__R_INFO(#win32err) win32err) -#define LOG_NTSTATUS(status) __R_FN(Log_NtStatus)(__R_INFO(#status) status) - -// Conditionally logs failures - returns parameter value -#define LOG_IF_FAILED(hr) __R_FN(Log_IfFailed)(__R_INFO(#hr) wil::verify_hresult(hr)) -#define LOG_IF_WIN32_BOOL_FALSE(win32BOOL) __R_FN(Log_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) -#define LOG_IF_WIN32_ERROR(win32err) __R_FN(Log_IfWin32Error)(__R_INFO(#win32err) win32err) -#define LOG_IF_NULL_ALLOC(ptr) __R_FN(Log_IfNullAlloc)(__R_INFO(#ptr) ptr) -#define LOG_HR_IF(hr, condition) __R_FN(Log_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) -#define LOG_HR_IF_NULL(hr, ptr) __R_FN(Log_HrIfNull)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr) -#define LOG_LAST_ERROR_IF(condition) __R_FN(Log_GetLastErrorIf)(__R_INFO(#condition) wil::verify_bool(condition)) -#define LOG_LAST_ERROR_IF_NULL(ptr) __R_FN(Log_GetLastErrorIfNull)(__R_INFO(#ptr) ptr) -#define LOG_IF_NTSTATUS_FAILED(status) __R_FN(Log_IfNtStatusFailed)(__R_INFO(#status) status) - -// Alternatives for SUCCEEDED(hr) and FAILED(hr) that conditionally log failures -#define SUCCEEDED_LOG(hr) SUCCEEDED(LOG_IF_FAILED(hr)) -#define FAILED_LOG(hr) FAILED(LOG_IF_FAILED(hr)) -#define SUCCEEDED_WIN32_LOG(win32err) SUCCEEDED_WIN32(LOG_IF_WIN32_ERROR(win32err)) -#define FAILED_WIN32_LOG(win32err) FAILED_WIN32(LOG_IF_WIN32_ERROR(win32err)) -#define SUCCEEDED_NTSTATUS_LOG(status) SUCCEEDED_NTSTATUS(LOG_IF_NTSTATUS_FAILED(status)) -#define FAILED_NTSTATUS_LOG(status) FAILED_NTSTATUS(LOG_IF_NTSTATUS_FAILED(status)) - -// Alternatives for NT_SUCCESS(x) that conditionally logs failures -#define NT_SUCCESS_LOG(status) NT_SUCCESS(LOG_IF_NTSTATUS_FAILED(status)) - -// Always logs a known failure - logs a var-arg message on failure -#define LOG_HR_MSG(hr, fmt, ...) __R_FN(Log_HrMsg)(__R_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_LAST_ERROR_MSG(fmt, ...) __R_FN(Log_GetLastErrorMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_WIN32_MSG(win32err, fmt, ...) __R_FN(Log_Win32Msg)(__R_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_NTSTATUS_MSG(status, fmt, ...) __R_FN(Log_NtStatusMsg)(__R_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) - -// Conditionally logs failures - returns parameter value - logs a var-arg message on failure -#define LOG_IF_FAILED_MSG(hr, fmt, ...) __R_FN(Log_IfFailedMsg)(__R_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) __R_FN(Log_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_IF_WIN32_ERROR_MSG(win32err, fmt, ...) __R_FN(Log_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_IF_NULL_ALLOC_MSG(ptr, fmt, ...) __R_FN(Log_IfNullAllocMsg)(__R_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_HR_IF_MSG(hr, condition, fmt, ...) __R_FN(Log_HrIfMsg)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_HR_IF_NULL_MSG(hr, ptr, fmt, ...) __R_FN(Log_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_LAST_ERROR_IF_MSG(condition, fmt, ...) __R_FN(Log_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) __R_FN(Log_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define LOG_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) __R_FN(Log_IfNtStatusFailedMsg)(__R_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) - -#define __WI_COMMA_EXPECTED_HRESULT(e) , wil::verify_hresult(e) -#define LOG_IF_FAILED_WITH_EXPECTED(hr, hrExpected, ...) __R_FN(Log_IfFailedWithExpected)(__R_INFO(#hr) wil::verify_hresult(hr), WI_ARGS_COUNT(__VA_ARGS__) + 1, wil::verify_hresult(hrExpected) WI_FOREACH(__WI_COMMA_EXPECTED_HRESULT, ##__VA_ARGS__)) - -//***************************************************************************** -// Macros to fail fast the process on failures -//***************************************************************************** - -// Always fail fast a known failure -#define FAIL_FAST_HR(hr) __RFF_FN(FailFast_Hr)(__RFF_INFO(#hr) wil::verify_hresult(hr)) -#define FAIL_FAST_LAST_ERROR() __RFF_FN(FailFast_GetLastError)(__RFF_INFO_ONLY(nullptr)) -#define FAIL_FAST_WIN32(win32err) __RFF_FN(FailFast_Win32)(__RFF_INFO(#win32err) win32err) -#define FAIL_FAST_NTSTATUS(status) __RFF_FN(FailFast_NtStatus)(__RFF_INFO(#status) status) - -// Conditionally fail fast failures - returns parameter value -#define FAIL_FAST_IF_FAILED(hr) __RFF_FN(FailFast_IfFailed)(__RFF_INFO(#hr) wil::verify_hresult(hr)) -#define FAIL_FAST_IF_WIN32_BOOL_FALSE(win32BOOL) __RFF_FN(FailFast_IfWin32BoolFalse)(__RFF_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) -#define FAIL_FAST_IF_WIN32_ERROR(win32err) __RFF_FN(FailFast_IfWin32Error)(__RFF_INFO(#win32err) win32err) -#define FAIL_FAST_IF_NULL_ALLOC(ptr) __RFF_FN(FailFast_IfNullAlloc)(__RFF_INFO(#ptr) ptr) -#define FAIL_FAST_HR_IF(hr, condition) __RFF_FN(FailFast_HrIf)(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) -#define FAIL_FAST_HR_IF_NULL(hr, ptr) __RFF_FN(FailFast_HrIfNull)(__RFF_INFO(#ptr) wil::verify_hresult(hr), ptr) -#define FAIL_FAST_LAST_ERROR_IF(condition) __RFF_FN(FailFast_GetLastErrorIf)(__RFF_INFO(#condition) wil::verify_bool(condition)) -#define FAIL_FAST_LAST_ERROR_IF_NULL(ptr) __RFF_FN(FailFast_GetLastErrorIfNull)(__RFF_INFO(#ptr) ptr) -#define FAIL_FAST_IF_NTSTATUS_FAILED(status) __RFF_FN(FailFast_IfNtStatusFailed)(__RFF_INFO(#status) status) - -// Always fail fast a known failure - fail fast a var-arg message on failure -#define FAIL_FAST_HR_MSG(hr, fmt, ...) __RFF_FN(FailFast_HrMsg)(__RFF_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_LAST_ERROR_MSG(fmt, ...) __RFF_FN(FailFast_GetLastErrorMsg)(__RFF_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_WIN32_MSG(win32err, fmt, ...) __RFF_FN(FailFast_Win32Msg)(__RFF_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_NTSTATUS_MSG(status, fmt, ...) __RFF_FN(FailFast_NtStatusMsg)(__RFF_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) - -// Conditionally fail fast failures - returns parameter value - fail fast a var-arg message on failure -#define FAIL_FAST_IF_FAILED_MSG(hr, fmt, ...) __RFF_FN(FailFast_IfFailedMsg)(__RFF_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) __RFF_FN(FailFast_IfWin32BoolFalseMsg)(__RFF_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_IF_WIN32_ERROR_MSG(win32err, fmt, ...) __RFF_FN(FailFast_IfWin32ErrorMsg)(__RFF_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_IF_NULL_ALLOC_MSG(ptr, fmt, ...) __RFF_FN(FailFast_IfNullAllocMsg)(__RFF_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_HR_IF_MSG(hr, condition, fmt, ...) __RFF_FN(FailFast_HrIfMsg)(__RFF_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_HR_IF_NULL_MSG(hr, ptr, fmt, ...) __RFF_FN(FailFast_HrIfNullMsg)(__RFF_INFO(#ptr) wil::verify_hresult(hr), ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_LAST_ERROR_IF_MSG(condition, fmt, ...) __RFF_FN(FailFast_GetLastErrorIfMsg)(__RFF_INFO(#condition) wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) __RFF_FN(FailFast_GetLastErrorIfNullMsg)(__RFF_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) __RFF_FN(FailFast_IfNtStatusFailedMsg)(__RFF_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) - -// Always fail fast a known failure -#ifndef FAIL_FAST -#define FAIL_FAST() __RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(nullptr)) -#endif - -// Conditionally fail fast failures - returns parameter value -#define FAIL_FAST_IF(condition) __RFF_FN(FailFast_If)(__RFF_INFO(#condition) wil::verify_bool(condition)) -#define FAIL_FAST_IF_NULL(ptr) __RFF_FN(FailFast_IfNull)(__RFF_INFO(#ptr) ptr) - -// Always fail fast a known failure - fail fast a var-arg message on failure -#define FAIL_FAST_MSG(fmt, ...) __RFF_FN(FailFast_UnexpectedMsg)(__RFF_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) - -// Conditionally fail fast failures - returns parameter value - fail fast a var-arg message on failure -#define FAIL_FAST_IF_MSG(condition, fmt, ...) __RFF_FN(FailFast_IfMsg)(__RFF_INFO(#condition) wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_IF_NULL_MSG(ptr, fmt, ...) __RFF_FN(FailFast_IfNullMsg)(__RFF_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) - -// Immediate fail fast (no telemetry - use rarely / only when *already* in an undefined state) -#define FAIL_FAST_IMMEDIATE() __RFF_FN(FailFastImmediate_Unexpected)() - -// Conditional immediate fail fast (no telemetry - use rarely / only when *already* in an undefined state) -#define FAIL_FAST_IMMEDIATE_IF_FAILED(hr) __RFF_FN(FailFastImmediate_IfFailed)(wil::verify_hresult(hr)) -#define FAIL_FAST_IMMEDIATE_IF(condition) __RFF_FN(FailFastImmediate_If)(wil::verify_bool(condition)) -#define FAIL_FAST_IMMEDIATE_IF_NULL(ptr) __RFF_FN(FailFastImmediate_IfNull)(ptr) -#define FAIL_FAST_IMMEDIATE_IF_NTSTATUS_FAILED(status) __RFF_FN(FailFastImmediate_IfNtStatusFailed)(status) - -// Specializations -#define FAIL_FAST_IMMEDIATE_IF_IN_LOADER_CALLOUT() do { if (wil::details::g_pfnFailFastInLoaderCallout != nullptr) { wil::details::g_pfnFailFastInLoaderCallout(); } } while ((void)0, 0) - - -//***************************************************************************** -// Macros to throw exceptions on failure -//***************************************************************************** - -#ifdef WIL_ENABLE_EXCEPTIONS - -// Always throw a known failure -#define THROW_HR(hr) __R_FN(Throw_Hr)(__R_INFO(#hr) wil::verify_hresult(hr)) -#define THROW_LAST_ERROR() __R_FN(Throw_GetLastError)(__R_INFO_ONLY(nullptr)) -#define THROW_WIN32(win32err) __R_FN(Throw_Win32)(__R_INFO(#win32err) win32err) -#define THROW_EXCEPTION(exception) wil::details::ReportFailure_CustomException(__R_INFO(#exception) exception) -#define THROW_NTSTATUS(status) __R_FN(Throw_NtStatus)(__R_INFO(#status) status) - -// Conditionally throw failures - returns parameter value -#define THROW_IF_FAILED(hr) __R_FN(Throw_IfFailed)(__R_INFO(#hr) wil::verify_hresult(hr)) -#define THROW_IF_WIN32_BOOL_FALSE(win32BOOL) __R_FN(Throw_IfWin32BoolFalse)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL)) -#define THROW_IF_WIN32_ERROR(win32err) __R_FN(Throw_IfWin32Error)(__R_INFO(#win32err) win32err) -#define THROW_IF_NULL_ALLOC(ptr) __R_FN(Throw_IfNullAlloc)(__R_INFO(#ptr) ptr) -#define THROW_HR_IF(hr, condition) __R_FN(Throw_HrIf)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) -#define THROW_HR_IF_NULL(hr, ptr) __R_FN(Throw_HrIfNull)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr) -#define THROW_WIN32_IF(win32err, condition) __R_FN(Throw_Win32If)(__R_INFO(#condition) wil::verify_win32(win32err), wil::verify_bool(condition)) -#define THROW_LAST_ERROR_IF(condition) __R_FN(Throw_GetLastErrorIf)(__R_INFO(#condition) wil::verify_bool(condition)) -#define THROW_LAST_ERROR_IF_NULL(ptr) __R_FN(Throw_GetLastErrorIfNull)(__R_INFO(#ptr) ptr) -#define THROW_IF_NTSTATUS_FAILED(status) __R_FN(Throw_IfNtStatusFailed)(__R_INFO(#status) status) - -// Always throw a known failure - throw a var-arg message on failure -#define THROW_HR_MSG(hr, fmt, ...) __R_FN(Throw_HrMsg)(__R_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_LAST_ERROR_MSG(fmt, ...) __R_FN(Throw_GetLastErrorMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_WIN32_MSG(win32err, fmt, ...) __R_FN(Throw_Win32Msg)(__R_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_EXCEPTION_MSG(exception, fmt, ...) wil::details::ReportFailure_CustomExceptionMsg(__R_INFO(#exception) exception, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_NTSTATUS_MSG(status, fmt, ...) __R_FN(Throw_NtStatusMsg)(__R_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) - -// Conditionally throw failures - returns parameter value - throw a var-arg message on failure -#define THROW_IF_FAILED_MSG(hr, fmt, ...) __R_FN(Throw_IfFailedMsg)(__R_INFO(#hr) wil::verify_hresult(hr), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_IF_WIN32_BOOL_FALSE_MSG(win32BOOL, fmt, ...) __R_FN(Throw_IfWin32BoolFalseMsg)(__R_INFO(#win32BOOL) wil::verify_BOOL(win32BOOL), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_IF_WIN32_ERROR_MSG(win32err, fmt, ...) __R_FN(Throw_IfWin32ErrorMsg)(__R_INFO(#win32err) win32err, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_IF_NULL_ALLOC_MSG(ptr, fmt, ...) __R_FN(Throw_IfNullAllocMsg)(__R_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_HR_IF_MSG(hr, condition, fmt, ...) __R_FN(Throw_HrIfMsg)(__R_INFO(#condition) wil::verify_hresult(hr), wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_HR_IF_NULL_MSG(hr, ptr, fmt, ...) __R_FN(Throw_HrIfNullMsg)(__R_INFO(#ptr) wil::verify_hresult(hr), ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_WIN32_IF_MSG(win32err, condition, fmt, ...) __R_FN(Throw_Win32IfMsg)(__R_INFO(#condition) wil::verify_win32(win32err), wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_LAST_ERROR_IF_MSG(condition, fmt, ...) __R_FN(Throw_GetLastErrorIfMsg)(__R_INFO(#condition) wil::verify_bool(condition), __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_LAST_ERROR_IF_NULL_MSG(ptr, fmt, ...) __R_FN(Throw_GetLastErrorIfNullMsg)(__R_INFO(#ptr) ptr, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_IF_NTSTATUS_FAILED_MSG(status, fmt, ...) __R_FN(Throw_IfNtStatusFailedMsg)(__R_INFO(#status) status, __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) - - -//***************************************************************************** -// Macros to catch and convert exceptions on failure -//***************************************************************************** - -// Use these macros *within* a catch (...) block to handle exceptions -#define RETURN_CAUGHT_EXCEPTION() return __R_FN(Return_CaughtException)(__R_INFO_ONLY(nullptr)) -#define RETURN_CAUGHT_EXCEPTION_MSG(fmt, ...) return __R_FN(Return_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define RETURN_CAUGHT_EXCEPTION_EXPECTED() return wil::ResultFromCaughtException() -#define LOG_CAUGHT_EXCEPTION() __R_FN(Log_CaughtException)(__R_INFO_ONLY(nullptr)) -#define LOG_CAUGHT_EXCEPTION_MSG(fmt, ...) __R_FN(Log_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define FAIL_FAST_CAUGHT_EXCEPTION() __R_FN(FailFast_CaughtException)(__R_INFO_ONLY(nullptr)) -#define FAIL_FAST_CAUGHT_EXCEPTION_MSG(fmt, ...) __R_FN(FailFast_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) -#define THROW_NORMALIZED_CAUGHT_EXCEPTION() __R_FN(Throw_CaughtException)(__R_INFO_ONLY(nullptr)) -#define THROW_NORMALIZED_CAUGHT_EXCEPTION_MSG(fmt, ...) __R_FN(Throw_CaughtExceptionMsg)(__R_INFO(nullptr) __WI_CHECK_MSG_FMT(fmt, ##__VA_ARGS__)) - -// Use these macros in place of a catch block to handle exceptions -#define CATCH_RETURN() catch (...) { RETURN_CAUGHT_EXCEPTION(); } -#define CATCH_RETURN_MSG(fmt, ...) catch (...) { RETURN_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); } -#define CATCH_RETURN_EXPECTED() catch (...) { RETURN_CAUGHT_EXCEPTION_EXPECTED(); } -#define CATCH_LOG() catch (...) { LOG_CAUGHT_EXCEPTION(); } -// Use CATCH_LOG_RETURN instead of CATCH_LOG in a function-try block around a destructor. CATCH_LOG in this specific case has an implicit throw at the end of scope. -// Due to a bug (DevDiv 441931), Warning 4297 (function marked noexcept throws exception) is detected even when the throwing code is unreachable, such as the end of scope after a return, in function-level catch. -#define CATCH_LOG_RETURN() catch (...) { __pragma(warning(suppress : 4297)); LOG_CAUGHT_EXCEPTION(); return; } -#define CATCH_LOG_MSG(fmt, ...) catch (...) { LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); } -// Likewise use CATCH_LOG_RETURN_MSG instead of CATCH_LOG_MSG in function-try blocks around destructors. -#define CATCH_LOG_RETURN_MSG(fmt, ...) catch (...) { __pragma(warning(suppress : 4297)); LOG_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); return; } -#define CATCH_FAIL_FAST() catch (...) { FAIL_FAST_CAUGHT_EXCEPTION(); } -#define CATCH_FAIL_FAST_MSG(fmt, ...) catch (...) { FAIL_FAST_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); } -#define CATCH_THROW_NORMALIZED() catch (...) { THROW_NORMALIZED_CAUGHT_EXCEPTION(); } -#define CATCH_THROW_NORMALIZED_MSG(fmt, ...) catch (...) { THROW_NORMALIZED_CAUGHT_EXCEPTION_MSG(fmt, ##__VA_ARGS__); } -#define CATCH_LOG_RETURN_HR(hr) catch (...) { LOG_CAUGHT_EXCEPTION(); return hr; } - -#endif // WIL_ENABLE_EXCEPTIONS - -// Use this macro to supply diagnostics information to wil::ResultFromException -#define WI_DIAGNOSTICS_INFO wil::DiagnosticsInfo(__R_CALLERADDRESS_VALUE, __R_LINE_VALUE, __R_FILE_VALUE) -#define WI_DIAGNOSTICS_NAME(name) wil::DiagnosticsInfo(__R_CALLERADDRESS_VALUE, __R_LINE_VALUE, __R_FILE_VALUE, name) - - - -//***************************************************************************** -// Usage Error Macros -//***************************************************************************** - -#ifndef WI_USAGE_ASSERT_STOP -#define WI_USAGE_ASSERT_STOP(condition) WI_ASSERT(condition) -#endif -#ifdef RESULT_DEBUG -#define WI_USAGE_ERROR(msg, ...) do { LOG_HR_MSG(HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE), msg, ##__VA_ARGS__); WI_USAGE_ASSERT_STOP(false); } while ((void)0, 0) -#define WI_USAGE_ERROR_FORWARD(msg, ...) do { ReportFailure_ReplaceMsg(__R_FN_CALL_FULL, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE), msg, ##__VA_ARGS__); WI_USAGE_ASSERT_STOP(false); } while ((void)0, 0) -#else -#define WI_USAGE_ERROR(msg, ...) do { LOG_HR(HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); WI_USAGE_ASSERT_STOP(false); } while ((void)0, 0) -#define WI_USAGE_ERROR_FORWARD(msg, ...) do { ReportFailure_Hr(__R_FN_CALL_FULL, HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE)); WI_USAGE_ASSERT_STOP(false); } while ((void)0, 0) -#endif -#define WI_USAGE_VERIFY(condition, msg, ...) do { const auto __passed = wil::verify_bool(condition); if (!__passed) { WI_USAGE_ERROR(msg, ##__VA_ARGS__); }} while ((void)0, 0) -#define WI_USAGE_VERIFY_FORWARD(condition, msg, ...) do { const auto __passed = wil::verify_bool(condition); if (!__passed) { WI_USAGE_ERROR_FORWARD(msg, ##__VA_ARGS__); }} while ((void)0, 0) -#ifdef RESULT_DEBUG -#define WI_USAGE_ASSERT(condition, msg, ...) WI_USAGE_VERIFY(condition, msg, ##__VA_ARGS__) -#else -#define WI_USAGE_ASSERT(condition, msg, ...) -#endif - -//***************************************************************************** -// Internal Error Macros - DO NOT USE - these are for internal WIL use only to reduce sizes of binaries that use WIL -//***************************************************************************** -#ifdef RESULT_DEBUG -#define __WIL_PRIVATE_RETURN_IF_FAILED(hr) RETURN_IF_FAILED(hr) -#define __WIL_PRIVATE_RETURN_HR_IF(hr, cond) RETURN_HR_IF(hr, cond) -#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF(cond) RETURN_LAST_ERROR_IF(cond) -#define __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) -#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(ptr) RETURN_LAST_ERROR_IF_NULL(ptr) -#define __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(ptr) RETURN_IF_NULL_ALLOC(ptr) -#define __WIL_PRIVATE_RETURN_LAST_ERROR() RETURN_LAST_ERROR() -#define __WIL_PRIVATE_FAIL_FAST_HR_IF(hr, condition) FAIL_FAST_HR_IF(hr, condition) -#define __WIL_PRIVATE_FAIL_FAST_HR(hr) FAIL_FAST_HR(hr) -#define __WIL_PRIVATE_LOG_HR(hr) LOG_HR(hr) -#else -#define __WIL_PRIVATE_RETURN_IF_FAILED(hr) do { const auto __hrRet = wil::verify_hresult(hr); if (FAILED(__hrRet)) { __RETURN_HR_FAIL_NOFILE(__hrRet, #hr); }} while ((void)0, 0) -#define __WIL_PRIVATE_RETURN_HR_IF(hr, cond) do { if (wil::verify_bool(cond)) { __RETURN_HR_NOFILE(wil::verify_hresult(hr), #cond); }} while ((void)0, 0) -#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF(cond) do { if (wil::verify_bool(cond)) { __RETURN_GLE_FAIL_NOFILE(#cond); }} while ((void)0, 0) -#define __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(win32BOOL) do { const BOOL __boolRet = wil::verify_BOOL(win32BOOL); if (!__boolRet) { __RETURN_GLE_FAIL_NOFILE(#win32BOOL); }} while ((void)0, 0) -#define __WIL_PRIVATE_RETURN_LAST_ERROR_IF_NULL(ptr) do { if ((ptr) == nullptr) { __RETURN_GLE_FAIL_NOFILE(#ptr); }} while ((void)0, 0) -#define __WIL_PRIVATE_RETURN_IF_NULL_ALLOC(ptr) do { if ((ptr) == nullptr) { __RETURN_HR_FAIL_NOFILE(E_OUTOFMEMORY, #ptr); }} while ((void)0, 0) -#define __WIL_PRIVATE_RETURN_LAST_ERROR() __RETURN_GLE_FAIL_NOFILE(nullptr) -#define __WIL_PRIVATE_FAIL_FAST_HR_IF(hr, condition) __RFF_FN(FailFast_HrIf)(__RFF_INFO_NOFILE(#condition) wil::verify_hresult(hr), wil::verify_bool(condition)) -#define __WIL_PRIVATE_FAIL_FAST_HR(hr) __RFF_FN(FailFast_Hr)(__RFF_INFO_NOFILE(#hr) wil::verify_hresult(hr)) -#define __WIL_PRIVATE_LOG_HR(hr) __R_FN(Log_Hr)(__R_INFO_NOFILE(#hr) wil::verify_hresult(hr)) -#endif - -namespace wil -{ - // Indicates the kind of message / failure type that was used to produce a given error - enum class FailureType - { - Exception, // THROW_... - Return, // RETURN_..._LOG or RETURN_..._MSG - Log, // LOG_... - FailFast // FAIL_FAST_... - }; - - enum class FailureFlags - { - None = 0x00, - RequestFailFast = 0x01, - RequestSuppressTelemetry = 0x02, - RequestDebugBreak = 0x04, - NtStatus = 0x08, - }; - DEFINE_ENUM_FLAG_OPERATORS(FailureFlags); - - /** Use with functions and macros that allow customizing which kinds of exceptions are handled. - This is used with methods like wil::ResultFromException and wil::ResultFromExceptionDebug. */ - enum class SupportedExceptions - { - Default, //!< [Default] all well known exceptions (honors g_fResultFailFastUnknownExceptions). - Known, //!< [Known] all well known exceptions (including std::exception). - All, //!< [All] all exceptions, known or otherwise. - None, //!< [None] no exceptions at all, an exception will fail-fast where thrown. - Thrown, //!< [Thrown] exceptions thrown by wil only (Platform::Exception^ or ResultException). - ThrownOrAlloc //!< [ThrownOrAlloc] exceptions thrown by wil (Platform::Exception^ or ResultException) or std::bad_alloc. - }; - - // Represents the call context information about a given failure - // No constructors, destructors or virtual members should be contained within - struct CallContextInfo - { - long contextId; // incrementing ID for this call context (unique across an individual module load within process) - PCSTR contextName; // the explicit name given to this context - PCWSTR contextMessage; // [optional] Message that can be associated with the call context - }; - - // Represents all context information about a given failure - // No constructors, destructors or virtual members should be contained within - struct FailureInfo - { - FailureType type; - FailureFlags flags; - HRESULT hr; - NTSTATUS status; - long failureId; // incrementing ID for this specific failure (unique across an individual module load within process) - PCWSTR pszMessage; // Message is only present for _MSG logging (it's the Sprintf message) - DWORD threadId; // the thread this failure was originally encountered on - PCSTR pszCode; // [debug only] Capture code from the macro - PCSTR pszFunction; // [debug only] The function name - PCSTR pszFile; - unsigned int uLineNumber; - int cFailureCount; // How many failures of 'type' have been reported in this module so far - PCSTR pszCallContext; // General breakdown of the call context stack that generated this failure - CallContextInfo callContextOriginating; // The outermost (first seen) call context - CallContextInfo callContextCurrent; // The most recently seen call context - PCSTR pszModule; // The module where the failure originated - void* returnAddress; // The return address to the point that called the macro - void* callerReturnAddress; // The return address of the function that includes the macro - }; - - //! Created automatically from using WI_DIAGNOSTICS_INFO to provide diagnostics to functions. - //! Note that typically wil hides diagnostics from users under the covers by passing them automatically to functions as - //! parameters hidden behind a macro. In some cases, the user needs to directly supply these, so this class provides - //! the mechanism for that. We only use this for user-passed content as it can't be directly controlled by RESULT_DIAGNOSTICS_LEVEL - //! to ensure there are no ODR violations (though that variable still controls what parameters within this structure would be available). - struct DiagnosticsInfo - { - void* returnAddress = nullptr; - PCSTR file = nullptr; - PCSTR name = nullptr; - unsigned short line = 0; - - DiagnosticsInfo() = default; - - __forceinline DiagnosticsInfo(void* returnAddress_, unsigned short line_, PCSTR file_) : - returnAddress(returnAddress_), - file(file_), - line(line_) - { - } - - __forceinline DiagnosticsInfo(void* returnAddress_, unsigned short line_, PCSTR file_, PCSTR name_) : - returnAddress(returnAddress_), - file(file_), - name(name_), - line(line_) - { - } - }; - - enum class ErrorReturn - { - Auto, - None - }; - - // [optionally] Plug in error logging - // Note: This callback is deprecated. Please use SetResultTelemetryFallback for telemetry or - // SetResultLoggingCallback for observation. - extern "C" __declspec(selectany) void(__stdcall *g_pfnResultLoggingCallback)(_Inout_ wil::FailureInfo *pFailure, _Inout_updates_opt_z_(cchDebugMessage) PWSTR pszDebugMessage, _Pre_satisfies_(cchDebugMessage > 0) size_t cchDebugMessage) WI_PFN_NOEXCEPT = nullptr; - - // [optional] - // This can be explicitly set to control whether or not error messages will be output to OutputDebugString. It can also - // be set directly from within the debugger to force console logging for debugging purposes. - __declspec(selectany) bool g_fResultOutputDebugString = true; - - // [optionally] Allows application to specify a debugger to detect whether a debugger is present. - // Useful for processes that can only be debugged under kernel debuggers where IsDebuggerPresent returns - // false. - __declspec(selectany) bool(__stdcall *g_pfnIsDebuggerPresent)() WI_PFN_NOEXCEPT = nullptr; - - // [optionally] Allows forcing WIL to believe a debugger is present. Useful for when a kernel debugger is attached and ::IsDebuggerPresent returns false - __declspec(selectany) bool g_fIsDebuggerPresent = false; - - // [optionally] Plug in additional exception-type support (return S_OK when *unable* to remap the exception) - __declspec(selectany) HRESULT(__stdcall *g_pfnResultFromCaughtException)() WI_PFN_NOEXCEPT = nullptr; - - // [optionally] Use to configure fast fail of unknown exceptions (turn them off). - __declspec(selectany) bool g_fResultFailFastUnknownExceptions = true; - - // [optionally] Set to false to a configure all THROW_XXX macros in C++/CX to throw ResultException rather than Platform::Exception^ - __declspec(selectany) bool g_fResultThrowPlatformException = true; - - // [optionally] Set to false to a configure all CATCH_ and CAUGHT_ macros to NOT support (fail-fast) std::exception based exceptions (other than std::bad_alloc and wil::ResultException) - __declspec(selectany) bool g_fResultSupportStdException = true; - - // [optionally] Set to true to cause a debug break to occur on a result failure - __declspec(selectany) bool g_fBreakOnFailure = false; - - // [optionally] customize failfast behavior - __declspec(selectany) bool(__stdcall *g_pfnWilFailFast)(const wil::FailureInfo& info) WI_PFN_NOEXCEPT = nullptr; - - /// @cond - namespace details - { - // True if g_pfnResultLoggingCallback is set (allows cutting off backwards compat calls to the function) - __declspec(selectany) bool g_resultMessageCallbackSet = false; - - // On Desktop/System WINAPI family: convert NTSTATUS error codes to friendly name strings. - __declspec(selectany) void(__stdcall *g_pfnFormatNtStatusMsg)(NTSTATUS, PWSTR, DWORD) = nullptr; - - _Success_(true) _Ret_range_(dest, destEnd) - inline PWSTR LogStringPrintf(_Out_writes_to_ptr_(destEnd) _Always_(_Post_z_) PWSTR dest, _Pre_satisfies_(destEnd >= dest) PCWSTR destEnd, _In_ _Printf_format_string_ PCWSTR format, ...) - { - va_list argList; - va_start(argList, format); - StringCchVPrintfW(dest, (destEnd - dest), format, argList); - return (destEnd == dest) ? dest : (dest + wcslen(dest)); - } - } - /// @endcond - - // This call generates the default logging string that makes its way to OutputDebugString for - // any particular failure. This string is also used to associate a failure with a PlatformException^ which - // only allows a single string to be associated with the exception. - inline HRESULT GetFailureLogString(_Out_writes_(cchDest) _Always_(_Post_z_) PWSTR pszDest, _Pre_satisfies_(cchDest > 0) _In_ size_t cchDest, _In_ FailureInfo const &failure) WI_NOEXCEPT - { - // This function was lenient to empty strings at one point and some callers became dependent on this beahvior - if ((cchDest == 0) || (pszDest == nullptr)) - { - return S_OK; - } - - pszDest[0] = L'\0'; - - // Call the logging callback (if present) to allow them to generate the debug string that will be pushed to the console - // or the platform exception object if the caller desires it. - if ((g_pfnResultLoggingCallback != nullptr) && details::g_resultMessageCallbackSet) - { - // older-form callback was a non-const FailureInfo*; conceptually this is const as callers should not be modifying - g_pfnResultLoggingCallback(const_cast(&failure), pszDest, cchDest); - } - - // The callback only optionally needs to supply the debug string -- if the callback didn't populate it, yet we still want - // it for OutputDebugString or exception message, then generate the default string. - if (pszDest[0] == L'\0') - { - PCSTR pszType = ""; - switch (failure.type) - { - case FailureType::Exception: - pszType = "Exception"; - break; - case FailureType::Return: - if (WI_IsFlagSet(failure.flags, FailureFlags::NtStatus)) - { - pszType = "ReturnNt"; - } - else - { - pszType = "ReturnHr"; - } - break; - case FailureType::Log: - if (WI_IsFlagSet(failure.flags, FailureFlags::NtStatus)) - { - pszType = "LogNt"; - } - else - { - pszType = "LogHr"; - } - break; - case FailureType::FailFast: - pszType = "FailFast"; - break; - } - - wchar_t szErrorText[256]{}; - LONG errorCode = 0; - - if (WI_IsFlagSet(failure.flags, FailureFlags::NtStatus)) - { - errorCode = failure.status; - if (wil::details::g_pfnFormatNtStatusMsg) - { - wil::details::g_pfnFormatNtStatusMsg(failure.status, szErrorText, ARRAYSIZE(szErrorText)); - } - } - else - { - errorCode = failure.hr; - FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, failure.hr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), szErrorText, ARRAYSIZE(szErrorText), nullptr); - } - - // %FILENAME(%LINE): %TYPE(%count) tid(%threadid) %HRESULT %SystemMessage - // %Caller_MSG [%CODE(%FUNCTION)] - - PWSTR dest = pszDest; - PCWSTR destEnd = (pszDest + cchDest); - - if (failure.pszFile != nullptr) - { - dest = details::LogStringPrintf(dest, destEnd, L"%hs(%u)\\%hs!%p: ", failure.pszFile, failure.uLineNumber, failure.pszModule, failure.returnAddress); - } - else - { - dest = details::LogStringPrintf(dest, destEnd, L"%hs!%p: ", failure.pszModule, failure.returnAddress); - } - - if (failure.callerReturnAddress != nullptr) - { - dest = details::LogStringPrintf(dest, destEnd, L"(caller: %p) ", failure.callerReturnAddress); - } - - dest = details::LogStringPrintf(dest, destEnd, L"%hs(%d) tid(%x) %08X %ws", pszType, failure.cFailureCount, ::GetCurrentThreadId(), errorCode, szErrorText); - - if ((failure.pszMessage != nullptr) || (failure.pszCallContext != nullptr) || (failure.pszFunction != nullptr)) - { - dest = details::LogStringPrintf(dest, destEnd, L" "); - if (failure.pszMessage != nullptr) - { - dest = details::LogStringPrintf(dest, destEnd, L"Msg:[%ws] ", failure.pszMessage); - } - if (failure.pszCallContext != nullptr) - { - dest = details::LogStringPrintf(dest, destEnd, L"CallContext:[%hs] ", failure.pszCallContext); - } - - if (failure.pszCode != nullptr) - { - dest = details::LogStringPrintf(dest, destEnd, L"[%hs(%hs)]\n", failure.pszFunction, failure.pszCode); - } - else if (failure.pszFunction != nullptr) - { - dest = details::LogStringPrintf(dest, destEnd, L"[%hs]\n", failure.pszFunction); - } - else - { - dest = details::LogStringPrintf(dest, destEnd, L"\n"); - } - } - } - - // Explicitly choosing to return success in the event of truncation... Current callers - // depend upon it or it would be eliminated. - return S_OK; - } - - /// @cond - namespace details - { - //! Interface used to wrap up code (generally a lambda or other functor) to run in an exception-managed context where - //! exceptions or errors can be observed and logged. - struct IFunctor - { - virtual HRESULT Run() = 0; - }; - - //! Used to provide custom behavior when an exception is encountered while executing IFunctor - struct IFunctorHost - { - virtual HRESULT Run(IFunctor& functor) = 0; - virtual HRESULT ExceptionThrown(void* returnAddress) = 0; - }; - - __declspec(noinline) inline HRESULT NtStatusToHr(NTSTATUS status) WI_NOEXCEPT; - __declspec(noinline) inline NTSTATUS HrToNtStatus(HRESULT) WI_NOEXCEPT; - - struct ResultStatus - { - enum Kind : unsigned int { HResult, NtStatus }; - - static ResultStatus FromResult(const HRESULT _hr) - { - return { _hr, wil::details::HrToNtStatus(_hr), Kind::HResult }; - } - static ResultStatus FromStatus(const NTSTATUS _status) - { - return { wil::details::NtStatusToHr(_status), _status, Kind::NtStatus }; - } - static ResultStatus FromFailureInfo(const FailureInfo& _failure) - { - return { _failure.hr, _failure.status, WI_IsFlagSet(_failure.flags, FailureFlags::NtStatus) ? Kind::NtStatus : Kind::HResult }; - } - HRESULT hr = S_OK; - NTSTATUS status = STATUS_SUCCESS; - Kind kind = Kind::NtStatus; - }; - - // Fallback telemetry provider callback (set with wil::SetResultTelemetryFallback) - __declspec(selectany) void(__stdcall *g_pfnTelemetryCallback)(bool alreadyReported, wil::FailureInfo const &failure) WI_PFN_NOEXCEPT = nullptr; - - // Result.h plug-in (WIL use only) - __declspec(selectany) void(__stdcall* g_pfnNotifyFailure)(_Inout_ FailureInfo* pFailure) WI_PFN_NOEXCEPT = nullptr; - __declspec(selectany) void(__stdcall *g_pfnGetContextAndNotifyFailure)(_Inout_ FailureInfo *pFailure, _Out_writes_(callContextStringLength) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringLength > 0) size_t callContextStringLength) WI_PFN_NOEXCEPT = nullptr; - - // Observe all errors flowing through the system with this callback (set with wil::SetResultLoggingCallback); use with custom logging - __declspec(selectany) void(__stdcall *g_pfnLoggingCallback)(wil::FailureInfo const &failure) WI_PFN_NOEXCEPT = nullptr; - - // Desktop/System Only: Module fetch function (automatically setup) - __declspec(selectany) PCSTR(__stdcall *g_pfnGetModuleName)() WI_PFN_NOEXCEPT = nullptr; - - // Desktop/System Only: Retrieve address offset and modulename - __declspec(selectany) bool(__stdcall *g_pfnGetModuleInformation)(void* address, _Out_opt_ unsigned int* addressOffset, _Out_writes_bytes_opt_(size) char* name, size_t size) WI_PFN_NOEXCEPT = nullptr; - - // Called with the expectation that the program will terminate when called inside of a loader callout. - // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined) - __declspec(selectany) void(__stdcall *g_pfnFailFastInLoaderCallout)() WI_PFN_NOEXCEPT = nullptr; - - // Called to translate an NTSTATUS value to a Win32 error code - // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined) - __declspec(selectany) ULONG(__stdcall *g_pfnRtlNtStatusToDosErrorNoTeb)(NTSTATUS) WI_PFN_NOEXCEPT = nullptr; - - // Desktop/System Only: Call to DebugBreak - __declspec(selectany) void(__stdcall *g_pfnDebugBreak)() WI_PFN_NOEXCEPT = nullptr; - - // Called to determine whether or not termination is happening - // Desktop/System Only: Automatically setup when building Windows (BUILD_WINDOWS defined) - __declspec(selectany) BOOLEAN(__stdcall *g_pfnDllShutdownInProgress)() WI_PFN_NOEXCEPT = nullptr; - __declspec(selectany) bool g_processShutdownInProgress = false; - - // On Desktop/System WINAPI family: dynalink RaiseFailFastException because we may encounter modules - // that do not have RaiseFailFastException in kernelbase. UWP apps will directly link. - __declspec(selectany) void (__stdcall *g_pfnRaiseFailFastException)(PEXCEPTION_RECORD,PCONTEXT,DWORD) = nullptr; - - // Exception-based compiled additions - __declspec(selectany) HRESULT(__stdcall *g_pfnRunFunctorWithExceptionFilter)(IFunctor& functor, IFunctorHost& host, void* returnAddress) = nullptr; - __declspec(selectany) void(__stdcall *g_pfnRethrow)() = nullptr; - __declspec(selectany) void(__stdcall *g_pfnThrowResultException)(const FailureInfo& failure) = nullptr; - extern "C" __declspec(selectany) ResultStatus(__stdcall *g_pfnResultFromCaughtExceptionInternal)(_Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, _Out_ bool* isNormalized) WI_PFN_NOEXCEPT = nullptr; - - // C++/WinRT additions - extern "C" __declspec(selectany) HRESULT(__stdcall *g_pfnResultFromCaughtException_CppWinRt)(_Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, _Out_ bool* isNormalized) WI_PFN_NOEXCEPT = nullptr; - - // C++/cx compiled additions - extern "C" __declspec(selectany) void(__stdcall *g_pfnThrowPlatformException)(FailureInfo const &failure, PCWSTR debugString) = nullptr; - extern "C" __declspec(selectany) _Always_(_Post_satisfies_(return < 0)) HRESULT(__stdcall *g_pfnResultFromCaughtException_WinRt)(_Inout_updates_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, _Out_ bool* isNormalized) WI_PFN_NOEXCEPT = nullptr; - __declspec(selectany) _Always_(_Post_satisfies_(return < 0)) HRESULT(__stdcall *g_pfnResultFromKnownExceptions_WinRt)(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) = nullptr; - - // Plugin to call RoOriginateError (WIL use only) - __declspec(selectany) void(__stdcall *g_pfnOriginateCallback)(wil::FailureInfo const& failure) WI_PFN_NOEXCEPT = nullptr; - - // Plugin to call RoFailFastWithErrorContext (WIL use only) - __declspec(selectany) void(__stdcall* g_pfnFailfastWithContextCallback)(wil::FailureInfo const& failure) WI_PFN_NOEXCEPT = nullptr; - - - // Allocate and disown the allocation so that Appverifier does not complain about a false leak - inline PVOID ProcessHeapAlloc(_In_ DWORD flags, _In_ size_t size) WI_NOEXCEPT - { - const HANDLE processHeap = ::GetProcessHeap(); - const PVOID allocation = ::HeapAlloc(processHeap, flags, size); - - static bool fetchedRtlDisownModuleHeapAllocation = false; - static NTSTATUS (__stdcall *pfnRtlDisownModuleHeapAllocation)(HANDLE, PVOID) WI_PFN_NOEXCEPT = nullptr; - - if (pfnRtlDisownModuleHeapAllocation) - { - (void)pfnRtlDisownModuleHeapAllocation(processHeap, allocation); - } - else if (!fetchedRtlDisownModuleHeapAllocation) - { - if (auto ntdllModule = ::GetModuleHandleW(L"ntdll.dll")) - { - pfnRtlDisownModuleHeapAllocation = reinterpret_cast(::GetProcAddress(ntdllModule, "RtlDisownModuleHeapAllocation")); - } - fetchedRtlDisownModuleHeapAllocation = true; - - if (pfnRtlDisownModuleHeapAllocation) - { - (void)pfnRtlDisownModuleHeapAllocation(processHeap, allocation); - } - } - - return allocation; - } - - enum class ReportFailureOptions - { - None = 0x00, - ForcePlatformException = 0x01, - MayRethrow = 0x02, - }; - DEFINE_ENUM_FLAG_OPERATORS(ReportFailureOptions); - - template - using functor_return_type = decltype((*static_cast(nullptr))()); - - template - struct functor_wrapper_void : public IFunctor - { - TFunctor&& functor; - functor_wrapper_void(TFunctor&& functor_) : functor(wistd::forward(functor_)) { } - #pragma warning(push) - #pragma warning(disable:4702) // https://github.com/Microsoft/wil/issues/2 - HRESULT Run() override - { - functor(); - return S_OK; - } - #pragma warning(pop) - }; - - template - struct functor_wrapper_HRESULT : public IFunctor - { - TFunctor&& functor; - functor_wrapper_HRESULT(TFunctor& functor_) : functor(wistd::forward(functor_)) { } - HRESULT Run() override - { - return functor(); - } - }; - - template - struct functor_wrapper_other : public IFunctor - { - TFunctor&& functor; - TReturn& retVal; - functor_wrapper_other(TFunctor& functor_, TReturn& retval_) : functor(wistd::forward(functor_)), retVal(retval_) { } - #pragma warning(push) - #pragma warning(disable:4702) // https://github.com/Microsoft/wil/issues/2 - HRESULT Run() override - { - retVal = functor(); - return S_OK; - } - #pragma warning(pop) - }; - - struct tag_return_void : public wistd::integral_constant - { - template - using functor_wrapper = functor_wrapper_void; - }; - - struct tag_return_HRESULT : public wistd::integral_constant - { - template - using functor_wrapper = functor_wrapper_HRESULT; - }; - - struct tag_return_other : public wistd::integral_constant - { - template - using functor_wrapper = functor_wrapper_other; - }; - - // type-trait to help discover the return type of a functor for tag/dispatch. - - template - struct return_type - { - using type = tag_return_other; - }; - - template <> - struct return_type - { - using type = tag_return_HRESULT; - }; - - template <> - struct return_type - { - using type = tag_return_void; - }; - - template <> - struct return_type - { - using type = tag_return_void; - }; - - template - using functor_tag = typename return_type>::type; - - // Forward declarations to enable use of fail fast and reporting internally... - namespace __R_NS_NAME - { - _Post_satisfies_(return == hr) __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT; - _Post_satisfies_(return == hr) __R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT; - _Post_satisfies_(return == err) __R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT; - } - namespace __RFF_NS_NAME - { - __RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT; - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT; - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT; - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD(bool, FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT; - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT; - } - - RESULT_NORETURN inline void __stdcall WilFailFast(const FailureInfo& info); - inline void LogFailure(__R_FN_PARAMS_FULL, FailureType type, const ResultStatus& resultPair, _In_opt_ PCWSTR message, - bool fWantDebugString, _Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString, _Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars, - _Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars, - _Out_ FailureInfo *failure) WI_NOEXCEPT; - - __declspec(noinline) inline void ReportFailure(__R_FN_PARAMS_FULL, FailureType type, const ResultStatus& resultPair, _In_opt_ PCWSTR message = nullptr, ReportFailureOptions options = ReportFailureOptions::None); - template - __declspec(noinline) inline void ReportFailure_Base(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, _In_opt_ PCWSTR message = nullptr, ReportFailureOptions options = ReportFailureOptions::None); - template - inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, ...); - __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr); - template - __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr); - template - __declspec(noinline) inline HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported = SupportedExceptions::Default); - - //***************************************************************************** - // Fail fast helpers (for use only internally to WIL) - //***************************************************************************** - - /// @cond - #define __FAIL_FAST_ASSERT__(condition) do { if (!(condition)) { __RFF_FN(FailFast_Unexpected)(__RFF_INFO_ONLY(#condition)); } } while ((void)0, 0) - #define __FAIL_FAST_IMMEDIATE_ASSERT__(condition) do { if (!(condition)) { wil::FailureInfo failure {}; wil::details::WilFailFast(failure); } } while ((void)0, 0) - #define __FAIL_FAST_ASSERT_WIN32_BOOL_FALSE__(condition) __RFF_FN(FailFast_IfWin32BoolFalse)(__RFF_INFO(#condition) wil::verify_BOOL(condition)) - - // A simple ref-counted buffer class. The interface is very similar to shared_ptr<>, only it manages - // an allocated buffer and maintains the size. - - class shared_buffer - { - public: - shared_buffer() WI_NOEXCEPT : m_pCopy(nullptr), m_size(0) - { - } - - shared_buffer(shared_buffer const &other) WI_NOEXCEPT : m_pCopy(nullptr), m_size(0) - { - assign(other.m_pCopy, other.m_size); - } - - shared_buffer(shared_buffer &&other) WI_NOEXCEPT : - m_pCopy(other.m_pCopy), - m_size(other.m_size) - { - other.m_pCopy = nullptr; - other.m_size = 0; - } - - ~shared_buffer() WI_NOEXCEPT - { - reset(); - } - - shared_buffer& operator=(shared_buffer const &other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - assign(other.m_pCopy, other.m_size); - } - return *this; - } - - shared_buffer& operator=(shared_buffer &&other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - reset(); - m_pCopy = other.m_pCopy; - m_size = other.m_size; - other.m_pCopy = nullptr; - other.m_size = 0; - } - return *this; - } - - void reset() WI_NOEXCEPT - { - if (m_pCopy != nullptr) - { - if (0 == ::InterlockedDecrementRelease(m_pCopy)) - { - WIL_FreeMemory(m_pCopy); - } - m_pCopy = nullptr; - m_size = 0; - } - } - - bool create(_In_reads_bytes_opt_(cbData) void const *pData, size_t cbData) WI_NOEXCEPT - { - if (cbData == 0) - { - reset(); - return true; - } - - long *pCopyRefCount = reinterpret_cast(WIL_AllocateMemory(sizeof(long)+cbData)); - if (pCopyRefCount == nullptr) - { - return false; - } - - *pCopyRefCount = 0; - if (pData != nullptr) - { - memcpy_s(pCopyRefCount + 1, cbData, pData, cbData); // +1 to advance past sizeof(long) counter - } - assign(pCopyRefCount, cbData); - return true; - } - - bool create(size_t cbData) WI_NOEXCEPT - { - return create(nullptr, cbData); - } - - WI_NODISCARD void* get(_Out_opt_ size_t *pSize = nullptr) const WI_NOEXCEPT - { - if (pSize != nullptr) - { - *pSize = m_size; - } - return (m_pCopy == nullptr) ? nullptr : (m_pCopy + 1); - } - - WI_NODISCARD size_t size() const WI_NOEXCEPT - { - return m_size; - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_pCopy != nullptr); - } - - WI_NODISCARD bool unique() const WI_NOEXCEPT - { - return ((m_pCopy != nullptr) && (*m_pCopy == 1)); - } - - private: - long *m_pCopy; // pointer to allocation: refcount + data - size_t m_size; // size of the data from m_pCopy - - void assign(_In_opt_ long *pCopy, size_t cbSize) WI_NOEXCEPT - { - reset(); - if (pCopy != nullptr) - { - m_pCopy = pCopy; - m_size = cbSize; - ::InterlockedIncrementNoFence(m_pCopy); - } - } - }; - - inline shared_buffer make_shared_buffer_nothrow(_In_reads_bytes_opt_(countBytes) void *pData, size_t countBytes) WI_NOEXCEPT - { - shared_buffer buffer; - buffer.create(pData, countBytes); - return buffer; - } - - inline shared_buffer make_shared_buffer_nothrow(size_t countBytes) WI_NOEXCEPT - { - shared_buffer buffer; - buffer.create(countBytes); - return buffer; - } - - // A small mimic of the STL shared_ptr class, but unlike shared_ptr, a pointer is not attached to the class, but is - // always simply contained within (it cannot be attached or detached). - - template - class shared_object - { - public: - shared_object() WI_NOEXCEPT : m_pCopy(nullptr) - { - } - - shared_object(shared_object const &other) WI_NOEXCEPT : - m_pCopy(other.m_pCopy) - { - if (m_pCopy != nullptr) - { - ::InterlockedIncrementNoFence(&m_pCopy->m_refCount); - } - } - - shared_object(shared_object &&other) WI_NOEXCEPT : - m_pCopy(other.m_pCopy) - { - other.m_pCopy = nullptr; - } - - ~shared_object() WI_NOEXCEPT - { - reset(); - } - - shared_object& operator=(shared_object const &other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - reset(); - m_pCopy = other.m_pCopy; - if (m_pCopy != nullptr) - { - ::InterlockedIncrementNoFence(&m_pCopy->m_refCount); - } - } - return *this; - } - - shared_object& operator=(shared_object &&other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - reset(); - m_pCopy = other.m_pCopy; - other.m_pCopy = nullptr; - } - return *this; - } - - void reset() WI_NOEXCEPT - { - if (m_pCopy != nullptr) - { - if (0 == ::InterlockedDecrementRelease(&m_pCopy->m_refCount)) - { - delete m_pCopy; - } - m_pCopy = nullptr; - } - } - - bool create() - { - RefAndObject *pObject = new(std::nothrow) RefAndObject(); - if (pObject == nullptr) - { - return false; - } - reset(); - m_pCopy = pObject; - return true; - } - - template - bool create(param_t &¶m1) - { - RefAndObject *pObject = new(std::nothrow) RefAndObject(wistd::forward(param1)); - if (pObject == nullptr) - { - return false; - } - reset(); - m_pCopy = pObject; - return true; - } - - WI_NODISCARD object_t* get() const WI_NOEXCEPT - { - return (m_pCopy == nullptr) ? nullptr : &m_pCopy->m_object; - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_pCopy != nullptr); - } - - WI_NODISCARD bool unique() const WI_NOEXCEPT - { - return ((m_pCopy != nullptr) && (m_pCopy->m_refCount == 1)); - } - - WI_NODISCARD object_t* operator->() const WI_NOEXCEPT - { - return get(); - } - - private: - struct RefAndObject - { - long m_refCount; - object_t m_object; - - RefAndObject() : - m_refCount(1), - m_object() - { - } - - template - RefAndObject(param_t &¶m1) : - m_refCount(1), - m_object(wistd::forward(param1)) - { - } - }; - - RefAndObject *m_pCopy; - }; - - // The following functions are basically the same, but are kept separated to: - // 1) Provide a unique count and last error code per-type - // 2) Avoid merging the types to allow easy debugging (breakpoints, conditional breakpoints based - // upon count of errors from a particular type, etc) -__WI_PUSH_WARNINGS -#if __clang_major__ >= 13 -__WI_CLANG_DISABLE_WARNING(-Wunused-but-set-variable) // s_hrErrorLast used for debugging. We intentionally only assign to it -#endif - __declspec(noinline) inline int RecordException(HRESULT hr) WI_NOEXCEPT - { - static HRESULT volatile s_hrErrorLast = S_OK; - static long volatile s_cErrorCount = 0; - s_hrErrorLast = hr; - return ::InterlockedIncrementNoFence(&s_cErrorCount); - } - - __declspec(noinline) inline int RecordReturn(HRESULT hr) WI_NOEXCEPT - { - static HRESULT volatile s_hrErrorLast = S_OK; - static long volatile s_cErrorCount = 0; - s_hrErrorLast = hr; - return ::InterlockedIncrementNoFence(&s_cErrorCount); - } - - __declspec(noinline) inline int RecordLog(HRESULT hr) WI_NOEXCEPT - { - static HRESULT volatile s_hrErrorLast = S_OK; - static long volatile s_cErrorCount = 0; - s_hrErrorLast = hr; - return ::InterlockedIncrementNoFence(&s_cErrorCount); - } - - __declspec(noinline) inline int RecordFailFast(HRESULT hr) WI_NOEXCEPT - { - static HRESULT volatile s_hrErrorLast = S_OK; - s_hrErrorLast = hr; - return 1; - } -__WI_POP_WARNINGS - - inline RESULT_NORETURN void __stdcall WilRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_opt_ PCONTEXT cr, _In_ DWORD flags) - { - // if we managed to load the pointer either through WilDynamicRaiseFailFastException (PARTITION_DESKTOP etc.) - // or via direct linkage (e.g. UWP apps), then use it. - if (g_pfnRaiseFailFastException) - { - g_pfnRaiseFailFastException(er, cr, flags); - } - // if not, as a best effort, we are just going to call the intrinsic. - __fastfail(FAST_FAIL_FATAL_APP_EXIT); - } - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) - inline bool __stdcall GetModuleInformation(_In_opt_ void* address, _Out_opt_ unsigned int* addressOffset, _Out_writes_bytes_opt_(size) char* name, size_t size) WI_NOEXCEPT - { - HMODULE hModule = nullptr; - if (address && !GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, reinterpret_cast(address), &hModule)) - { - assign_to_opt_param(addressOffset, 0U); - return false; - } - if (addressOffset) - { - *addressOffset = address ? static_cast(static_cast(address) - reinterpret_cast(hModule)) : 0; - } - if (name) - { - char modulePath[MAX_PATH]; - if (!GetModuleFileNameA(hModule, modulePath, ARRAYSIZE(modulePath))) - { - return false; - } - - PCSTR start = modulePath + strlen(modulePath); - while ((start > modulePath) && (*(start - 1) != '\\')) - { - start--; - } - StringCchCopyA(name, size, start); - } - return true; - } - - inline PCSTR __stdcall GetCurrentModuleName() WI_NOEXCEPT - { - static char s_szModule[64] = {}; - static volatile bool s_fModuleValid = false; - if (!s_fModuleValid) // Races are acceptable - { - GetModuleInformation(reinterpret_cast(&RecordFailFast), nullptr, s_szModule, ARRAYSIZE(s_szModule)); - s_fModuleValid = true; - } - return s_szModule; - } - - inline void __stdcall DebugBreak() WI_NOEXCEPT - { - ::DebugBreak(); - } - - inline void __stdcall WilDynamicLoadRaiseFailFastException(_In_ PEXCEPTION_RECORD er, _In_ PCONTEXT cr, _In_ DWORD flags) - { - auto k32handle = GetModuleHandleW(L"kernelbase.dll"); - _Analysis_assume_(k32handle != nullptr); - auto pfnRaiseFailFastException = reinterpret_cast(GetProcAddress(k32handle, "RaiseFailFastException")); - if (pfnRaiseFailFastException) - { - pfnRaiseFailFastException(er, cr, flags); - } - } -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) - - inline bool __stdcall GetModuleInformationFromAddress(_In_opt_ void* address, _Out_opt_ unsigned int* addressOffset, _Out_writes_bytes_opt_(size) char* buffer, size_t size) WI_NOEXCEPT - { - if (size > 0) - { - assign_to_opt_param(buffer, '\0'); - } - if (addressOffset) - { - *addressOffset = 0; - } - if (g_pfnGetModuleInformation) - { - return g_pfnGetModuleInformation(address, addressOffset, buffer, size); - } - return false; - } - - __declspec(noinline) inline HRESULT NtStatusToHr(NTSTATUS status) WI_NOEXCEPT - { - // The following conversions are the only known incorrect mappings in RtlNtStatusToDosErrorNoTeb - if (SUCCEEDED_NTSTATUS(status)) - { - // All successful status codes have only one hresult equivalent, S_OK - return S_OK; - } - if (status == static_cast(STATUS_NO_MEMORY)) - { - // RtlNtStatusToDosErrorNoTeb maps STATUS_NO_MEMORY to the less popular of two Win32 no memory error codes resulting in an unexpected mapping - return E_OUTOFMEMORY; - } - - if (g_pfnRtlNtStatusToDosErrorNoTeb != nullptr) - { - DWORD err = g_pfnRtlNtStatusToDosErrorNoTeb(status); - - // ERROR_MR_MID_NOT_FOUND indicates a bug in the originator of the error (failure to add a mapping to the Win32 error codes). - // There are known instances of this bug which are unlikely to be fixed soon, and it's always possible that additional instances - // could be added in the future. In these cases, it's better to use HRESULT_FROM_NT rather than returning a meaningless error. - if ((err != 0) && (err != ERROR_MR_MID_NOT_FOUND)) - { - return __HRESULT_FROM_WIN32(err); - } - } - - return HRESULT_FROM_NT(status); - } - - __declspec(noinline) inline NTSTATUS HrToNtStatus(HRESULT hr) WI_NOEXCEPT - { - // Constants taken from ntstatus.h - static constexpr NTSTATUS WIL_STATUS_INVALID_PARAMETER = 0xC000000D; - static constexpr NTSTATUS WIL_STATUS_INTERNAL_ERROR = 0xC00000E5; - static constexpr NTSTATUS WIL_STATUS_INTEGER_OVERFLOW = 0xC0000095; - static constexpr NTSTATUS WIL_STATUS_OBJECT_PATH_NOT_FOUND = 0xC000003A; - static constexpr NTSTATUS WIL_STATUS_OBJECT_NAME_NOT_FOUND = 0xC0000034; - static constexpr NTSTATUS WIL_STATUS_NOT_IMPLEMENTED = 0xC0000002; - static constexpr NTSTATUS WIL_STATUS_BUFFER_OVERFLOW = 0x80000005; - static constexpr NTSTATUS WIL_STATUS_IMPLEMENTATION_LIMIT = 0xC000042B; - static constexpr NTSTATUS WIL_STATUS_NO_MORE_MATCHES = 0xC0000273; - static constexpr NTSTATUS WIL_STATUS_ILLEGAL_CHARACTER = 0xC0000161; - static constexpr NTSTATUS WIL_STATUS_UNDEFINED_CHARACTER = 0xC0000163; - static constexpr NTSTATUS WIL_STATUS_BUFFER_TOO_SMALL = 0xC0000023; - static constexpr NTSTATUS WIL_STATUS_DISK_FULL = 0xC000007F; - static constexpr NTSTATUS WIL_STATUS_OBJECT_NAME_INVALID = 0xC0000033; - static constexpr NTSTATUS WIL_STATUS_DLL_NOT_FOUND = 0xC0000135; - static constexpr NTSTATUS WIL_STATUS_REVISION_MISMATCH = 0xC0000059; - static constexpr NTSTATUS WIL_STATUS_XML_PARSE_ERROR = 0xC000A083; - static constexpr HRESULT WIL_E_FAIL = 0x80004005; - - NTSTATUS status = STATUS_SUCCESS; - - switch (hr) - { - case S_OK: - status = STATUS_SUCCESS; - break; - case E_INVALIDARG: - status = WIL_STATUS_INVALID_PARAMETER; - break; - case __HRESULT_FROM_WIN32(ERROR_INTERNAL_ERROR): - status = WIL_STATUS_INTERNAL_ERROR; - break; - case E_OUTOFMEMORY: - status = STATUS_NO_MEMORY; - break; - case __HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW): - status = WIL_STATUS_INTEGER_OVERFLOW; - break; - case __HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND): - status = WIL_STATUS_OBJECT_PATH_NOT_FOUND; - break; - case __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND): - status = WIL_STATUS_OBJECT_NAME_NOT_FOUND; - break; - case __HRESULT_FROM_WIN32(ERROR_INVALID_FUNCTION): - status = WIL_STATUS_NOT_IMPLEMENTED; - break; - case __HRESULT_FROM_WIN32(ERROR_MORE_DATA): - status = WIL_STATUS_BUFFER_OVERFLOW; - break; - case __HRESULT_FROM_WIN32(ERROR_IMPLEMENTATION_LIMIT): - status = WIL_STATUS_IMPLEMENTATION_LIMIT; - break; - case __HRESULT_FROM_WIN32(ERROR_NO_MORE_MATCHES): - status = WIL_STATUS_NO_MORE_MATCHES; - break; - case __HRESULT_FROM_WIN32(ERROR_ILLEGAL_CHARACTER): - status = WIL_STATUS_ILLEGAL_CHARACTER; - break; - case __HRESULT_FROM_WIN32(ERROR_UNDEFINED_CHARACTER): - status = WIL_STATUS_UNDEFINED_CHARACTER; - break; - case __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER): - status = WIL_STATUS_BUFFER_TOO_SMALL; - break; - case __HRESULT_FROM_WIN32(ERROR_DISK_FULL): - status = WIL_STATUS_DISK_FULL; - break; - case __HRESULT_FROM_WIN32(ERROR_INVALID_NAME): - status = WIL_STATUS_OBJECT_NAME_INVALID; - break; - case __HRESULT_FROM_WIN32(ERROR_MOD_NOT_FOUND): - status = WIL_STATUS_DLL_NOT_FOUND; - break; - case __HRESULT_FROM_WIN32(ERROR_OLD_WIN_VERSION): - status = WIL_STATUS_REVISION_MISMATCH; - break; - case WIL_E_FAIL: - status = STATUS_UNSUCCESSFUL; - break; - case __HRESULT_FROM_WIN32(ERROR_XML_PARSE_ERROR): - status = WIL_STATUS_XML_PARSE_ERROR; - break; - case __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION): - status = STATUS_NONCONTINUABLE_EXCEPTION; - break; - default: - if ((hr & FACILITY_NT_BIT) != 0) - { - status = (hr & ~FACILITY_NT_BIT); - } - else if (HRESULT_FACILITY(hr) == FACILITY_WIN32) - { - status = __NTSTATUS_FROM_WIN32(HRESULT_CODE(hr)); - } - else if (HRESULT_FACILITY(hr) == FACILITY_SSPI) - { - status = ((NTSTATUS)(hr) <= 0 ? ((NTSTATUS)(hr)) : ((NTSTATUS)(((hr) & 0x0000FFFF) | (FACILITY_SSPI << 16) | ERROR_SEVERITY_ERROR))); - } - else - { - status = WIL_STATUS_INTERNAL_ERROR; - } - break; - } - return status; - } - - // The following set of functions all differ only based upon number of arguments. They are unified in their handling - // of data from each of the various error-handling types (fast fail, exceptions, etc.). - _Post_equals_last_error_ - inline DWORD GetLastErrorFail(__R_FN_PARAMS_FULL) WI_NOEXCEPT - { - __R_FN_UNREFERENCED; - auto err = ::GetLastError(); - if (SUCCEEDED_WIN32(err)) - { - // This function should only be called when GetLastError() is set to a FAILURE. - // If you hit this assert (or are reviewing this failure telemetry), then there are one of three issues: - // 1) Your code is using a macro (such as RETURN_IF_WIN32_BOOL_FALSE()) on a function that does not actually - // set the last error (consult MSDN). - // 2) Your macro check against the error is not immediately after the API call. Pushing it later can result - // in another API call between the previous one and the check resetting the last error. - // 3) The API you're calling has a bug in it and does not accurately set the last error (there are a few - // examples here, such as SendMessageTimeout() that don't accurately set the last error). For these, - // please send mail to 'wildisc' when found and work-around with win32errorhelpers. - - WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected. GetLastError() does not have an error."); - return ERROR_ASSERTION_FAILURE; - } - return err; - } - - inline __declspec(noinline) DWORD GetLastErrorFail() WI_NOEXCEPT - { - __R_FN_LOCALS_FULL_RA; - return GetLastErrorFail(__R_FN_CALL_FULL); - } - - _Translates_last_error_to_HRESULT_ - inline HRESULT GetLastErrorFailHr(__R_FN_PARAMS_FULL) WI_NOEXCEPT - { - return HRESULT_FROM_WIN32(GetLastErrorFail(__R_FN_CALL_FULL)); - } - - _Translates_last_error_to_HRESULT_ - inline __declspec(noinline) HRESULT GetLastErrorFailHr() WI_NOEXCEPT - { - __R_FN_LOCALS_FULL_RA; - return GetLastErrorFailHr(__R_FN_CALL_FULL); - } - - inline void PrintLoggingMessage(_Out_writes_(cchDest) _Post_z_ PWSTR pszDest, _Pre_satisfies_(cchDest > 0) size_t cchDest, _In_opt_ _Printf_format_string_ PCSTR formatString, _In_opt_ va_list argList) WI_NOEXCEPT - { - if (formatString == nullptr) - { - pszDest[0] = L'\0'; - } - else if (argList == nullptr) - { - StringCchPrintfW(pszDest, cchDest, L"%hs", formatString); - } - else - { - wchar_t szFormatWide[2048]; - StringCchPrintfW(szFormatWide, ARRAYSIZE(szFormatWide), L"%hs", formatString); - StringCchVPrintfW(pszDest, cchDest, szFormatWide, argList); - } - } - -#pragma warning(push) -#pragma warning(disable:__WARNING_RETURNING_BAD_RESULT) - // NOTE: The following two functions are unfortunate copies of strsafe.h functions that have been copied to reduce the friction associated with using - // Result.h and ResultException.h in a build that does not have WINAPI_PARTITION_DESKTOP defined (where these are conditionally enabled). - - static STRSAFEAPI WilStringLengthWorkerA(_In_reads_or_z_(cchMax) STRSAFE_PCNZCH psz, _In_ _In_range_(<= , STRSAFE_MAX_CCH) size_t cchMax, _Out_opt_ _Deref_out_range_(< , cchMax) _Deref_out_range_(<= , _String_length_(psz)) size_t* pcchLength) - { - HRESULT hr = S_OK; - size_t cchOriginalMax = cchMax; - while (cchMax && (*psz != '\0')) - { - psz++; - cchMax--; - } - if (cchMax == 0) - { - // the string is longer than cchMax - hr = STRSAFE_E_INVALID_PARAMETER; - } - if (pcchLength) - { - if (SUCCEEDED(hr)) - { - *pcchLength = cchOriginalMax - cchMax; - } - else - { - *pcchLength = 0; - } - } - return hr; - } - - _Must_inspect_result_ STRSAFEAPI StringCchLengthA(_In_reads_or_z_(cchMax) STRSAFE_PCNZCH psz, _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchMax, _Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<= , _String_length_(psz)) size_t* pcchLength) - { - HRESULT hr = S_OK; - if ((psz == nullptr) || (cchMax > STRSAFE_MAX_CCH)) - { - hr = STRSAFE_E_INVALID_PARAMETER; - } - else - { - hr = WilStringLengthWorkerA(psz, cchMax, pcchLength); - } - if (FAILED(hr) && pcchLength) - { - *pcchLength = 0; - } - return hr; - } -#pragma warning(pop) - - _Post_satisfies_(cchDest > 0 && cchDest <= cchMax) static STRSAFEAPI WilStringValidateDestA(_In_reads_opt_(cchDest) STRSAFE_PCNZCH /*pszDest*/, _In_ size_t cchDest, _In_ const size_t cchMax) - { - HRESULT hr = S_OK; - if ((cchDest == 0) || (cchDest > cchMax)) - { - hr = STRSAFE_E_INVALID_PARAMETER; - } - return hr; - } - - static STRSAFEAPI WilStringVPrintfWorkerA(_Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest, _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest, _Always_(_Out_opt_ _Deref_out_range_(<=, cchDest - 1)) size_t* pcchNewDestLength, _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat, _In_ va_list argList) - { - HRESULT hr = S_OK; - int iRet{}; - - // leave the last space for the null terminator - size_t cchMax = cchDest - 1; - size_t cchNewDestLength = 0; -#undef STRSAFE_USE_SECURE_CRT -#define STRSAFE_USE_SECURE_CRT 1 - #if (STRSAFE_USE_SECURE_CRT == 1) && !defined(STRSAFE_LIB_IMPL) - iRet = _vsnprintf_s(pszDest, cchDest, cchMax, pszFormat, argList); - #else - #pragma warning(push) - #pragma warning(disable: __WARNING_BANNED_API_USAGE)// "STRSAFE not included" - iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList); - #pragma warning(pop) - #endif - // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax)); - - if ((iRet < 0) || (((size_t)iRet) > cchMax)) - { - // need to null terminate the string - pszDest += cchMax; - *pszDest = '\0'; - - cchNewDestLength = cchMax; - - // we have truncated pszDest - hr = STRSAFE_E_INSUFFICIENT_BUFFER; - } - else if (((size_t)iRet) == cchMax) - { - // need to null terminate the string - pszDest += cchMax; - *pszDest = '\0'; - - cchNewDestLength = cchMax; - } - else - { - cchNewDestLength = (size_t)iRet; - } - - if (pcchNewDestLength) - { - *pcchNewDestLength = cchNewDestLength; - } - - return hr; - } - - __inline HRESULT StringCchPrintfA( _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest, _In_ size_t cchDest, _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat, ...) - { - HRESULT hr; - hr = wil::details::WilStringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH); - if (SUCCEEDED(hr)) - { - va_list argList; - va_start(argList, pszFormat); - hr = wil::details::WilStringVPrintfWorkerA(pszDest, cchDest, nullptr, pszFormat, argList); - va_end(argList); - } - else if (cchDest > 0) - { - *pszDest = '\0'; - } - return hr; - } - - _Ret_range_(sizeof(char), (psz == nullptr) ? sizeof(char) : (_String_length_(psz) + sizeof(char))) - inline size_t ResultStringSize(_In_opt_ PCSTR psz) - { return (psz == nullptr) ? sizeof(char) : (strlen(psz) + sizeof(char)); } - - _Ret_range_(sizeof(wchar_t), (psz == nullptr) ? sizeof(wchar_t) : ((_String_length_(psz) + 1) * sizeof(wchar_t))) - inline size_t ResultStringSize(_In_opt_ PCWSTR psz) - { return (psz == nullptr) ? sizeof(wchar_t) : (wcslen(psz) + 1) * sizeof(wchar_t); } - - template - _Ret_range_(pStart, pEnd) inline unsigned char* WriteResultString( - _Pre_satisfies_(pStart <= pEnd) - _When_((pStart == pEnd) || (pszString == nullptr) || (pszString[0] == 0), _In_opt_) - _When_((pStart != pEnd) && (pszString != nullptr) && (pszString[0] != 0), _Out_writes_bytes_opt_(_String_length_(pszString) * sizeof(pszString[0]))) - unsigned char* pStart, _Pre_satisfies_(pEnd >= pStart) unsigned char* pEnd, _In_opt_z_ TString pszString, _Outptr_result_maybenull_z_ TString* ppszBufferString) - { - // No space? Null string? Do nothing. - if ((pStart == pEnd) || !pszString || !*pszString) - { - assign_null_to_opt_param(ppszBufferString); - return pStart; - } - - // Treats the range pStart--pEnd as a memory buffer into which pszString is copied. A pointer to - // the start of the copied string is placed into ppszStringBuffer. If the buffer isn't big enough, - // do nothing, and tell the caller nothing was written. - size_t const stringSize = ResultStringSize(pszString); - size_t const bufferSize = pEnd - pStart; - if (bufferSize < stringSize) - { - assign_null_to_opt_param(ppszBufferString); - return pStart; - } - - memcpy_s(pStart, bufferSize, pszString, stringSize); - assign_to_opt_param(ppszBufferString, reinterpret_cast(pStart));// lgtm[cpp/incorrect-string-type-conversion] False positive - The query is misinterpreting a buffer (char *) with a MBS string, the cast to TString is expected. - return pStart + stringSize; - } - - _Ret_range_(0, (cchMax > 0) ? cchMax - 1 : 0) inline size_t UntrustedStringLength(_In_ PCSTR psz, _In_ size_t cchMax) { size_t cbLength; return SUCCEEDED(wil::details::StringCchLengthA(psz, cchMax, &cbLength)) ? cbLength : 0; } - _Ret_range_(0, (cchMax > 0) ? cchMax - 1 : 0) inline size_t UntrustedStringLength(_In_ PCWSTR psz, _In_ size_t cchMax) { size_t cbLength; return SUCCEEDED(::StringCchLengthW(psz, cchMax, &cbLength)) ? cbLength : 0; } - - template - _Ret_range_(pStart, pEnd) inline unsigned char *GetResultString(_In_reads_to_ptr_opt_(pEnd) unsigned char *pStart, _Pre_satisfies_(pEnd >= pStart) unsigned char *pEnd, _Out_ TString *ppszBufferString) - { - size_t cchLen = UntrustedStringLength(reinterpret_cast(pStart), (pEnd - pStart) / sizeof((*ppszBufferString)[0])); - *ppszBufferString = (cchLen > 0) ? reinterpret_cast(pStart) : nullptr; - auto pReturn = (wistd::min)(pEnd, pStart + ((cchLen + 1) * sizeof((*ppszBufferString)[0]))); - __analysis_assume((pReturn >= pStart) && (pReturn <= pEnd)); - return pReturn; - } - } // details namespace - /// @endcond - - //***************************************************************************** - // WIL result handling initializers - // - // Generally, callers do not need to manually initialize WIL. This header creates - // the appropriate .CRT init section pieces through global objects to ensure that - // WilInitialize... is called before DllMain or main(). - // - // Certain binaries do not link with the CRT or do not support .CRT-section based - // initializers. Those binaries must link only with other static libraries that - // also set RESULT_SUPPRESS_STATIC_INITIALIZERS to ensure no .CRT inits are left, - // and they should call one of the WilInitialize_ResultMacros_??? methods during - // their initialization phase. Skipping this initialization path is OK as well, - // but results in a slightly degraded experience with result reporting. - // - // Calling WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse provides: - // - The name of the current module in wil::FailureInfo::pszModule - // - The name of the returning-to module during wil\staging.h failures - //***************************************************************************** - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) - //! Call this method to initialize WIL manually in a module where RESULT_SUPPRESS_STATIC_INITIALIZERS is required. WIL will - //! only use publicly documented APIs. - inline void WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse() - { - details::g_pfnGetModuleName = details::GetCurrentModuleName; - details::g_pfnGetModuleInformation = details::GetModuleInformation; - details::g_pfnDebugBreak = details::DebugBreak; - details::g_pfnRaiseFailFastException = wil::details::WilDynamicLoadRaiseFailFastException; - } - - /// @cond - namespace details - { -#ifndef RESULT_SUPPRESS_STATIC_INITIALIZERS -#if !defined(BUILD_WINDOWS) || defined(WIL_SUPPRESS_PRIVATE_API_USE) - WI_HEADER_INITITALIZATION_FUNCTION(WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse, [] - { - ::wil::WilInitialize_ResultMacros_DesktopOrSystem_SuppressPrivateApiUse(); - return 1; - }); -#endif -#endif - } - /// @endcond -#else // !WINAPI_PARTITION_DESKTOP, !WINAPI_PARTITION_SYSTEM, explicitly assume these modules can direct link - namespace details - { - WI_HEADER_INITITALIZATION_FUNCTION(WilInitialize_ResultMacros_AppOnly, [] - { - g_pfnRaiseFailFastException = ::RaiseFailFastException; - return 1; - }); - } -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) - - //***************************************************************************** - // Public Error Handling Helpers - //***************************************************************************** - - //! Call this method to determine if process shutdown is in progress (allows avoiding work during dll unload). - inline bool ProcessShutdownInProgress() - { - return (details::g_processShutdownInProgress || (details::g_pfnDllShutdownInProgress ? details::g_pfnDllShutdownInProgress() : false)); - } - - /** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down, - but the hosting DLL doesn't support CRT initializers (such as kernelbase.dll). The hosting DLL is responsible for calling - Construct() and Destroy() to manually run the constructor and destructor during DLL load & unload. - Upon process shutdown a method (ProcessShutdown()) is called that must be implemented on the object, otherwise the destructor is - called as is typical. */ - template - class manually_managed_shutdown_aware_object - { - public: - manually_managed_shutdown_aware_object() = default; - manually_managed_shutdown_aware_object(manually_managed_shutdown_aware_object const&) = delete; - void operator=(manually_managed_shutdown_aware_object const&) = delete; - - void construct() - { - void* var = &m_raw; - ::new(var) T(); - } - - void destroy() - { - if (ProcessShutdownInProgress()) - { - get().ProcessShutdown(); - } - else - { - (&get())->~T(); - } - } - - //! Retrieves a reference to the contained object - T& get() WI_NOEXCEPT - { - return *reinterpret_cast(&m_raw); - } - - private: - alignas(T) unsigned char m_raw[sizeof(T)]; - }; - - /** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down. - Upon process shutdown a method (ProcessShutdown()) is called that must be implemented on the object, otherwise the destructor is - called as is typical. */ - template - class shutdown_aware_object - { - public: - shutdown_aware_object() - { - m_object.construct(); - } - - ~shutdown_aware_object() - { - m_object.destroy(); - } - - shutdown_aware_object(shutdown_aware_object const&) = delete; - void operator=(shutdown_aware_object const&) = delete; - - //! Retrieves a reference to the contained object - T& get() WI_NOEXCEPT - { - return m_object.get(); - } - - private: - manually_managed_shutdown_aware_object m_object; - }; - - /** Use this object to wrap an object that wants to prevent its destructor from being run when the process is shutting down. */ - template - class object_without_destructor_on_shutdown - { - public: - object_without_destructor_on_shutdown() - { - void* var = &m_raw; - ::new(var) T(); - } - - ~object_without_destructor_on_shutdown() - { - if (!ProcessShutdownInProgress()) - { - get().~T(); - } - } - - object_without_destructor_on_shutdown(object_without_destructor_on_shutdown const&) = delete; - void operator=(object_without_destructor_on_shutdown const&) = delete; - - //! Retrieves a reference to the contained object - T& get() WI_NOEXCEPT - { - return *reinterpret_cast(&m_raw); - } - - private: - alignas(T) unsigned char m_raw[sizeof(T)]{}; - }; - - /** Forward your DLLMain to this function so that WIL can have visibility into whether a DLL unload is because - of termination or normal unload. Note that when g_pfnDllShutdownInProgress is set, WIL attempts to make this - determination on its own without this callback. Suppressing private APIs requires use of this. */ - inline void DLLMain(HINSTANCE, DWORD reason, _In_opt_ LPVOID reserved) - { - if (!details::g_processShutdownInProgress) - { - if ((reason == DLL_PROCESS_DETACH) && (reserved != nullptr)) - { - details::g_processShutdownInProgress = true; - } - } - } - - // [optionally] Plug in fallback telemetry reporting - // Normally, the callback is owned by including ResultLogging.h in the including module. Alternatively a module - // could re-route fallback telemetry to any ONE specific provider by calling this method. - inline void SetResultTelemetryFallback(_In_opt_ decltype(details::g_pfnTelemetryCallback) callbackFunction) - { - // Only ONE telemetry provider can own the fallback telemetry callback. - __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnTelemetryCallback == nullptr) || (callbackFunction == nullptr) || (details::g_pfnTelemetryCallback == callbackFunction)); - details::g_pfnTelemetryCallback = callbackFunction; - } - - // [optionally] Plug in result logging (do not use for telemetry) - // This provides the ability for a module to hook all failures flowing through the system for inspection - // and/or logging. - inline void SetResultLoggingCallback(_In_opt_ decltype(details::g_pfnLoggingCallback) callbackFunction) - { - // Only ONE function can own the result logging callback - __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnLoggingCallback == nullptr) || (callbackFunction == nullptr) || (details::g_pfnLoggingCallback == callbackFunction)); - details::g_pfnLoggingCallback = callbackFunction; - } - - // [optionally] Plug in custom result messages - // There are some purposes that require translating the full information that is known about a failure - // into a message to be logged (either through the console for debugging OR as the message attached - // to a Platform::Exception^). This callback allows a module to format the string itself away from the - // default. - inline void SetResultMessageCallback(_In_opt_ decltype(wil::g_pfnResultLoggingCallback) callbackFunction) - { - // Only ONE function can own the result message callback - __FAIL_FAST_IMMEDIATE_ASSERT__((g_pfnResultLoggingCallback == nullptr) || (callbackFunction == nullptr) || (g_pfnResultLoggingCallback == callbackFunction)); - details::g_resultMessageCallbackSet = true; - g_pfnResultLoggingCallback = callbackFunction; - } - - // [optionally] Plug in exception remapping - // A module can plug a callback in using this function to setup custom exception handling to allow any - // exception type to be converted into an HRESULT from exception barriers. - inline void SetResultFromCaughtExceptionCallback(_In_opt_ decltype(wil::g_pfnResultFromCaughtException) callbackFunction) - { - // Only ONE function can own the exception conversion - __FAIL_FAST_IMMEDIATE_ASSERT__((g_pfnResultFromCaughtException == nullptr) || (callbackFunction == nullptr) || (g_pfnResultFromCaughtException == callbackFunction)); - g_pfnResultFromCaughtException = callbackFunction; - } - - // [optionally] Plug in exception remapping - // This provides the ability for a module to call RoOriginateError in case of a failure. - // Normally, the callback is owned by including result_originate.h in the including module. Alternatively a module - // could re-route error origination callback to its own implementation. - inline void SetOriginateErrorCallback(_In_opt_ decltype(details::g_pfnOriginateCallback) callbackFunction) - { - // Only ONE function can own the error origination callback - __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnOriginateCallback == nullptr) || (callbackFunction == nullptr) || (details::g_pfnOriginateCallback == callbackFunction)); - details::g_pfnOriginateCallback = callbackFunction; - } - - // [optionally] Plug in failfast callback - // This provides the ability for a module to call RoFailFastWithErrorContext in the failfast handler -if- there is stowed - // exception data available. Normally, the callback is owned by including result_originate.h in the including module. - // Alternatively a module could re-route to its own implementation. - inline void SetFailfastWithContextCallback(_In_opt_ decltype(details::g_pfnFailfastWithContextCallback) callbackFunction) - { - // Only ONE function can own the failfast with context callback - __FAIL_FAST_IMMEDIATE_ASSERT__((details::g_pfnFailfastWithContextCallback == nullptr) || (callbackFunction == nullptr) || (details::g_pfnFailfastWithContextCallback == callbackFunction)); - details::g_pfnFailfastWithContextCallback = callbackFunction; - } - - // A RAII wrapper around the storage of a FailureInfo struct (which is normally meant to be consumed - // on the stack or from the caller). The storage of FailureInfo needs to copy some data internally - // for lifetime purposes. - - class StoredFailureInfo - { - public: - StoredFailureInfo() WI_NOEXCEPT - { - ::ZeroMemory(&m_failureInfo, sizeof(m_failureInfo)); - } - - StoredFailureInfo(FailureInfo const &other) WI_NOEXCEPT - { - SetFailureInfo(other); - } - - WI_NODISCARD FailureInfo const& GetFailureInfo() const WI_NOEXCEPT - { - return m_failureInfo; - } - - void SetFailureInfo(FailureInfo const &failure) WI_NOEXCEPT - { - m_failureInfo = failure; - - size_t const cbNeed = details::ResultStringSize(failure.pszMessage) + - details::ResultStringSize(failure.pszCode) + - details::ResultStringSize(failure.pszFunction) + - details::ResultStringSize(failure.pszFile) + - details::ResultStringSize(failure.pszCallContext) + - details::ResultStringSize(failure.pszModule) + - details::ResultStringSize(failure.callContextCurrent.contextName) + - details::ResultStringSize(failure.callContextCurrent.contextMessage) + - details::ResultStringSize(failure.callContextOriginating.contextName) + - details::ResultStringSize(failure.callContextOriginating.contextMessage); - - if (!m_spStrings.unique() || (m_spStrings.size() < cbNeed)) - { - m_spStrings.reset(); - m_spStrings.create(cbNeed); - } - - size_t cbAlloc; - unsigned char *pBuffer = static_cast(m_spStrings.get(&cbAlloc)); - unsigned char *pBufferEnd = (pBuffer != nullptr) ? pBuffer + cbAlloc : nullptr; - - if (pBuffer) - { - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszMessage, &m_failureInfo.pszMessage); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCode, &m_failureInfo.pszCode); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszFunction, &m_failureInfo.pszFunction); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszFile, &m_failureInfo.pszFile); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszCallContext, &m_failureInfo.pszCallContext); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.pszModule, &m_failureInfo.pszModule); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextCurrent.contextName, &m_failureInfo.callContextCurrent.contextName); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextCurrent.contextMessage, &m_failureInfo.callContextCurrent.contextMessage); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextOriginating.contextName, &m_failureInfo.callContextOriginating.contextName); - pBuffer = details::WriteResultString(pBuffer, pBufferEnd, failure.callContextOriginating.contextMessage, &m_failureInfo.callContextOriginating.contextMessage); - ZeroMemory(pBuffer, pBufferEnd - pBuffer); - } - } - - // Relies upon generated copy constructor and assignment operator - - protected: - FailureInfo m_failureInfo; - details::shared_buffer m_spStrings; - }; - -#if defined(WIL_ENABLE_EXCEPTIONS) || defined(WIL_FORCE_INCLUDE_RESULT_EXCEPTION) - - //! This is WIL's default exception class thrown from all THROW_XXX macros (outside of c++/cx). - //! This class stores all of the FailureInfo context that is available when the exception is thrown. It's also caught by - //! exception guards for automatic conversion to HRESULT. - //! - //! In c++/cx, Platform::Exception^ is used instead of this class (unless @ref wil::g_fResultThrowPlatformException has been changed). - class ResultException : public std::exception - { - public: - //! Constructs a new ResultException from an existing FailureInfo. - ResultException(const FailureInfo& failure) WI_NOEXCEPT : - m_failure(failure) - { - } - - //! Constructs a new exception type from a given HRESULT (use only for constructing custom exception types). - ResultException(_Pre_satisfies_(hr < 0) HRESULT hr) WI_NOEXCEPT : - m_failure(CustomExceptionFailureInfo(hr)) - { - } - - //! Returns the failed HRESULT that this exception represents. - _Always_(_Post_satisfies_(return < 0)) WI_NODISCARD HRESULT GetErrorCode() const WI_NOEXCEPT - { - HRESULT const hr = m_failure.GetFailureInfo().hr; - __analysis_assume(hr < 0); - return hr; - } - - //! Returns the failed NTSTATUS that this exception represents. - _Always_(_Post_satisfies_(return < 0)) WI_NODISCARD NTSTATUS GetStatusCode() const WI_NOEXCEPT - { - NTSTATUS const status = m_failure.GetFailureInfo().status; - __analysis_assume(status < 0); - return status; - } - - //! Get a reference to the stored FailureInfo. - WI_NODISCARD FailureInfo const& GetFailureInfo() const WI_NOEXCEPT - { - return m_failure.GetFailureInfo(); - } - - //! Sets the stored FailureInfo (use primarily only when constructing custom exception types). - void SetFailureInfo(FailureInfo const &failure) WI_NOEXCEPT - { - m_failure.SetFailureInfo(failure); - } - - //! Provides a string representing the FailureInfo from this exception. - WI_NODISCARD inline const char* __CLR_OR_THIS_CALL what() const WI_NOEXCEPT override - { -#if !defined(NONLS) && !defined(NOAPISET) - if (!m_what) - { - wchar_t message[2048]; - GetFailureLogString(message, ARRAYSIZE(message), m_failure.GetFailureInfo()); - - int len = WideCharToMultiByte(CP_ACP, 0, message, -1, nullptr, 0, nullptr, nullptr); - if (!m_what.create(len)) - { - // Allocation failed, return placeholder string. - return "WIL Exception"; - } - - WideCharToMultiByte(CP_ACP, 0, message, -1, static_cast(m_what.get()), len, nullptr, nullptr); - } - return static_cast(m_what.get()); -#else - if (!m_what) - { - wchar_t message[2048]; - GetFailureLogString(message, ARRAYSIZE(message), m_failure.GetFailureInfo()); - - char messageA[1024]; - wil::details::StringCchPrintfA(messageA, ARRAYSIZE(messageA), "%ws", message); - m_what.create(messageA, strlen(messageA) + sizeof(*messageA)); - } - return static_cast(m_what.get()); -#endif - } - - // Relies upon auto-generated copy constructor and assignment operator - protected: - StoredFailureInfo m_failure; //!< The failure information for this exception - mutable details::shared_buffer m_what; //!< The on-demand generated what() string - - //! Use to produce a custom FailureInfo from an HRESULT (use only when constructing custom exception types). - static FailureInfo CustomExceptionFailureInfo(HRESULT hr) WI_NOEXCEPT - { - FailureInfo fi = {}; - fi.type = FailureType::Exception; - fi.hr = hr; - return fi; - } - }; -#endif - - - //***************************************************************************** - // Public Helpers that catch -- mostly only enabled when exceptions are enabled - //***************************************************************************** - - // ResultFromCaughtException is a function that is meant to be called from within a catch(...) block. Internally - // it re-throws and catches the exception to convert it to an HRESULT. If an exception is of an unrecognized type - // the function will fail fast. - // - // try - // { - // // Code - // } - // catch (...) - // { - // hr = wil::ResultFromCaughtException(); - // } - _Always_(_Post_satisfies_(return < 0)) - __declspec(noinline) inline HRESULT ResultFromCaughtException() WI_NOEXCEPT - { - bool isNormalized = false; - HRESULT hr = S_OK; - if (details::g_pfnResultFromCaughtExceptionInternal) - { - hr = details::g_pfnResultFromCaughtExceptionInternal(nullptr, 0, &isNormalized).hr; - } - if (FAILED(hr)) - { - return hr; - } - - // Caller bug: an unknown exception was thrown - __WIL_PRIVATE_FAIL_FAST_HR_IF(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION), g_fResultFailFastUnknownExceptions); - return __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); - } - - //! Identical to 'throw;', but can be called from error-code neutral code to rethrow in code that *may* be running under an exception context - inline void RethrowCaughtException() - { - // We always want to rethrow the exception under normal circumstances. Ordinarily, we could actually guarantee - // this as we should be able to rethrow if we caught an exception, but if we got here in the middle of running - // dynamic initializers, then it's possible that we haven't yet setup the rethrow function pointer, thus the - // runtime check without the noreturn annotation. - - if (details::g_pfnRethrow) - { - details::g_pfnRethrow(); - } - } - - //! Identical to 'throw ResultException(failure);', but can be referenced from error-code neutral code - inline void ThrowResultException(const FailureInfo& failure) - { - if (details::g_pfnThrowResultException) - { - details::g_pfnThrowResultException(failure); - } - } - - //! @cond - namespace details - { -#ifdef WIL_ENABLE_EXCEPTIONS - //***************************************************************************** - // Private helpers to catch and propagate exceptions - //***************************************************************************** - - RESULT_NORETURN inline void TerminateAndReportError(_In_opt_ PEXCEPTION_POINTERS) - { - // This is an intentional fail-fast that was caught by an exception guard with WIL. Look back up the callstack to determine - // the source of the actual exception being thrown. The exception guard used by the calling code did not expect this - // exception type to be thrown or is specifically requesting fail-fast for this class of exception. - - FailureInfo failure{}; - WilFailFast(failure); - } - - inline void MaybeGetExceptionString(const ResultException& exception, _Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) - { - if (debugString) - { - GetFailureLogString(debugString, debugStringChars, exception.GetFailureInfo()); - } - } - - inline void MaybeGetExceptionString(const std::exception& exception, _Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) - { - if (debugString) - { - StringCchPrintfW(debugString, debugStringChars, L"std::exception: %hs", exception.what()); - } - } - - inline HRESULT ResultFromKnownException(const ResultException& exception, const DiagnosticsInfo& diagnostics, void* returnAddress) - { - wchar_t message[2048]{}; - MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); - auto hr = exception.GetErrorCode(); - wil::details::ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message); - return hr; - } - - inline HRESULT ResultFromKnownException(const std::bad_alloc& exception, const DiagnosticsInfo& diagnostics, void* returnAddress) - { - wchar_t message[2048]{}; - MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); - constexpr auto hr = E_OUTOFMEMORY; - wil::details::ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message); - return hr; - } - - inline HRESULT ResultFromKnownException(const std::exception& exception, const DiagnosticsInfo& diagnostics, void* returnAddress) - { - wchar_t message[2048]{}; - MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); - constexpr auto hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); - ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message); - return hr; - } - - inline HRESULT ResultFromKnownException_CppWinRT(const DiagnosticsInfo& diagnostics, void* returnAddress) - { - if (g_pfnResultFromCaughtException_CppWinRt) - { - wchar_t message[2048]{}; - bool ignored; - auto hr = g_pfnResultFromCaughtException_CppWinRt(message, ARRAYSIZE(message), &ignored); - if (FAILED(hr)) - { - ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message); - return hr; - } - } - - // Indicate that this either isn't a C++/WinRT exception or a handler isn't configured by returning success - return S_OK; - } - - inline HRESULT RecognizeCaughtExceptionFromCallback(_Inout_updates_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) - { - HRESULT hr = g_pfnResultFromCaughtException(); - - // If we still don't know the error -- or we would like to get the debug string for the error (if possible) we - // rethrow and catch std::exception. - - if (SUCCEEDED(hr) || debugString) - { - try - { - throw; - } - catch (std::exception& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - if (SUCCEEDED(hr)) - { - hr = __HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); - } - } - catch (...) - { - // Fall through to returning 'hr' below - } - } - - return hr; - } - -#ifdef __cplusplus_winrt - inline Platform::String^ GetPlatformExceptionMessage(Platform::Exception^ exception) - { - struct RawExceptionData_Partial - { - PCWSTR description; - PCWSTR restrictedErrorString; - }; - - auto exceptionPtr = reinterpret_cast(static_cast<::Platform::Object^>(exception)); - auto exceptionInfoPtr = reinterpret_cast(exceptionPtr) - 1; - auto partial = reinterpret_cast(*exceptionInfoPtr); - - Platform::String^ message = exception->Message; - - PCWSTR errorString = partial->restrictedErrorString; - PCWSTR messageString = reinterpret_cast(message ? message->Data() : nullptr); - - // An old Platform::Exception^ bug that did not actually expose the error string out of the exception - // message. We do it by hand here if the message associated with the strong does not contain the - // message that was originally attached to the string (in the fixed version it will). - - if ((errorString && *errorString && messageString) && - (wcsstr(messageString, errorString) == nullptr)) - { - return ref new Platform::String(reinterpret_cast<_Null_terminated_ const __wchar_t *>(errorString)); - } - return message; - } - - inline void MaybeGetExceptionString(_In_ Platform::Exception^ exception, _Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars) - { - if (debugString) - { - auto message = GetPlatformExceptionMessage(exception); - auto messageString = !message ? L"(null Message)" : reinterpret_cast(message->Data()); - StringCchPrintfW(debugString, debugStringChars, L"Platform::Exception^: %ws", messageString); - } - } - - inline HRESULT ResultFromKnownException(Platform::Exception^ exception, const DiagnosticsInfo& diagnostics, void* returnAddress) - { - wchar_t message[2048]; - message[0] = L'\0'; - MaybeGetExceptionString(exception, message, ARRAYSIZE(message)); - auto hr = exception->HResult; - wil::details::ReportFailure_Base(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), ResultStatus::FromResult(hr), message); - return hr; - } - - inline HRESULT __stdcall ResultFromCaughtException_WinRt(_Inout_updates_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, _Inout_ bool* isNormalized) WI_NOEXCEPT - { - if (g_pfnResultFromCaughtException) - { - try - { - throw; - } - catch (const ResultException& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return exception.GetErrorCode(); - } - catch (Platform::Exception^ exception) - { - *isNormalized = true; - // We need to call __abi_translateCurrentException so that the CX runtime will pull the originated error information - // out of the exception object and place it back into thread-local storage. - __abi_translateCurrentException(false); - MaybeGetExceptionString(exception, debugString, debugStringChars); - return exception->HResult; - } - catch (const std::bad_alloc& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return E_OUTOFMEMORY; - } - catch (...) - { - auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars); - if (FAILED(hr)) - { - return hr; - } - } - } - else - { - try - { - throw; - } - catch (const ResultException& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return exception.GetErrorCode(); - } - catch (Platform::Exception^ exception) - { - *isNormalized = true; - // We need to call __abi_translateCurrentException so that the CX runtime will pull the originated error information - // out of the exception object and place it back into thread-local storage. - __abi_translateCurrentException(false); - MaybeGetExceptionString(exception, debugString, debugStringChars); - return exception->HResult; - } - catch (const std::bad_alloc& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return E_OUTOFMEMORY; - } - catch (std::exception& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION); - } - catch (...) - { - // Fall through to returning 'S_OK' below - } - } - - // Tell the caller that we were unable to map the exception by succeeding... - return S_OK; - } - - // WinRT supporting version to execute a functor and catch known exceptions. - inline HRESULT __stdcall ResultFromKnownExceptions_WinRt(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) - { - WI_ASSERT(supported != SupportedExceptions::Default); - - switch (supported) - { - case SupportedExceptions::Known: - try - { - return functor.Run(); - } - catch (const ResultException& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (Platform::Exception^ exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (const std::bad_alloc& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (std::exception& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (...) - { - auto hr = ResultFromKnownException_CppWinRT(diagnostics, returnAddress); - if (FAILED(hr)) - { - return hr; - } - - // Unknown exception - throw; - } - break; - - case SupportedExceptions::ThrownOrAlloc: - try - { - return functor.Run(); - } - catch (const ResultException& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (Platform::Exception^ exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (const std::bad_alloc& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - break; - - case SupportedExceptions::Thrown: - try - { - return functor.Run(); - } - catch (const ResultException& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (Platform::Exception^ exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - break; - } - - WI_ASSERT(false); - return S_OK; - } - - inline void __stdcall ThrowPlatformException(FailureInfo const &failure, LPCWSTR debugString) - { - throw Platform::Exception::CreateException(failure.hr, ref new Platform::String(reinterpret_cast<_Null_terminated_ const __wchar_t *>(debugString))); - } - -#if !defined(RESULT_SUPPRESS_STATIC_INITIALIZERS) - WI_HEADER_INITITALIZATION_FUNCTION(InitializeWinRt, [] - { - g_pfnResultFromCaughtException_WinRt = ResultFromCaughtException_WinRt; - g_pfnResultFromKnownExceptions_WinRt = ResultFromKnownExceptions_WinRt; - g_pfnThrowPlatformException = ThrowPlatformException; - return 1; - }); -#endif -#endif - - inline void __stdcall Rethrow() - { - throw; - } - - inline void __stdcall ThrowResultExceptionInternal(const FailureInfo& failure) - { - throw ResultException(failure); - } - - __declspec(noinline) inline ResultStatus __stdcall ResultFromCaughtExceptionInternal(_Out_writes_opt_(debugStringChars) PWSTR debugString, _When_(debugString != nullptr, _Pre_satisfies_(debugStringChars > 0)) size_t debugStringChars, _Out_ bool* isNormalized) WI_NOEXCEPT - { - if (debugString) - { - *debugString = L'\0'; - } - *isNormalized = false; - - if (details::g_pfnResultFromCaughtException_CppWinRt != nullptr) - { - const auto hr = details::g_pfnResultFromCaughtException_CppWinRt(debugString, debugStringChars, isNormalized); - if (FAILED(hr)) - { - return ResultStatus::FromResult(hr); - } - } - - if (details::g_pfnResultFromCaughtException_WinRt != nullptr) - { - const auto hr = details::g_pfnResultFromCaughtException_WinRt(debugString, debugStringChars, isNormalized); - return ResultStatus::FromResult(hr); - } - - if (g_pfnResultFromCaughtException) - { - try - { - throw; - } - catch (const ResultException& exception) - { - *isNormalized = true; - MaybeGetExceptionString(exception, debugString, debugStringChars); - return ResultStatus::FromFailureInfo(exception.GetFailureInfo()); - } - catch (const std::bad_alloc& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return ResultStatus::FromResult(E_OUTOFMEMORY); - } - catch (...) - { - auto hr = RecognizeCaughtExceptionFromCallback(debugString, debugStringChars); - if (FAILED(hr)) - { - return ResultStatus::FromResult(hr); - } - } - } - else - { - try - { - throw; - } - catch (const ResultException& exception) - { - *isNormalized = true; - MaybeGetExceptionString(exception, debugString, debugStringChars); - return ResultStatus::FromFailureInfo(exception.GetFailureInfo()); - } - catch (const std::bad_alloc& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return ResultStatus::FromResult(E_OUTOFMEMORY); - } - catch (std::exception& exception) - { - MaybeGetExceptionString(exception, debugString, debugStringChars); - return ResultStatus::FromResult(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); - } - catch (...) - { - // Fall through to returning 'S_OK' below - } - } - - // Tell the caller that we were unable to map the exception by succeeding... - return ResultStatus::FromResult(S_OK); - } - - // Runs the given functor, converting any exceptions of the supported types that are known to HRESULTs and returning - // that HRESULT. Does NOT attempt to catch unknown exceptions (which propagate). Primarily used by SEH exception - // handling techniques to stop at the point the exception is thrown. - inline HRESULT ResultFromKnownExceptions(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) - { - if (supported == SupportedExceptions::Default) - { - supported = g_fResultSupportStdException ? SupportedExceptions::Known : SupportedExceptions::ThrownOrAlloc; - } - - if ((details::g_pfnResultFromKnownExceptions_WinRt != nullptr) && - ((supported == SupportedExceptions::Known) || (supported == SupportedExceptions::Thrown) || (supported == SupportedExceptions::ThrownOrAlloc))) - { - return details::g_pfnResultFromKnownExceptions_WinRt(diagnostics, returnAddress, supported, functor); - } - - switch (supported) - { - case SupportedExceptions::Known: - try - { - return functor.Run(); - } - catch (const ResultException& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (const std::bad_alloc& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (std::exception& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (...) - { - auto hr = ResultFromKnownException_CppWinRT(diagnostics, returnAddress); - if (FAILED(hr)) - { - return hr; - } - - // Unknown exception - throw; - } - - case SupportedExceptions::ThrownOrAlloc: - try - { - return functor.Run(); - } - catch (const ResultException& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - catch (const std::bad_alloc& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - - case SupportedExceptions::Thrown: - try - { - return functor.Run(); - } - catch (const ResultException& exception) - { - return ResultFromKnownException(exception, diagnostics, returnAddress); - } - - case SupportedExceptions::All: - try - { - return functor.Run(); - } - catch (...) - { - return wil::details::ReportFailure_CaughtException(__R_DIAGNOSTICS_RA(diagnostics, returnAddress), supported); - } - - case SupportedExceptions::None: - return functor.Run(); - - case SupportedExceptions::Default: - WI_ASSERT(false); - } - - WI_ASSERT(false); - return S_OK; - } - - inline HRESULT ResultFromExceptionSeh(const DiagnosticsInfo& diagnostics, void* returnAddress, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT - { - __try - { - return wil::details::ResultFromKnownExceptions(diagnostics, returnAddress, supported, functor); - } - __except (wil::details::TerminateAndReportError(GetExceptionInformation()), EXCEPTION_CONTINUE_SEARCH) - { - WI_ASSERT(false); - RESULT_NORETURN_RESULT(HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); - } - } - - __declspec(noinline) inline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT - { -#ifdef RESULT_DEBUG - // We can't do debug SEH handling if the caller also wants a shot at mapping the exceptions - // themselves or if the caller doesn't want to fail-fast unknown exceptions - if ((g_pfnResultFromCaughtException == nullptr) && g_fResultFailFastUnknownExceptions) - { - return wil::details::ResultFromExceptionSeh(diagnostics, _ReturnAddress(), supported, functor); - } -#endif - try - { - return functor.Run(); - } - catch (...) - { - return wil::details::ReportFailure_CaughtException(__R_DIAGNOSTICS(diagnostics), _ReturnAddress(), supported); - } - } - - __declspec(noinline) inline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, IFunctor& functor) WI_NOEXCEPT - { - return wil::details::ResultFromExceptionSeh(diagnostics, _ReturnAddress(), supported, functor); - } - - // Exception guard -- catch exceptions and log them (or handle them with a custom callback) - // WARNING: may throw an exception... - inline HRESULT __stdcall RunFunctorWithExceptionFilter(IFunctor& functor, IFunctorHost& host, void* returnAddress) - { - try - { - return host.Run(functor); - } - catch (...) - { - // Note that the host may choose to re-throw, throw a normalized exception, return S_OK and eat the exception or - // return the remapped failure. - return host.ExceptionThrown(returnAddress); - } - } - - WI_HEADER_INITITALIZATION_FUNCTION(InitializeResultExceptions, [] - { - g_pfnRunFunctorWithExceptionFilter = RunFunctorWithExceptionFilter; - g_pfnRethrow = Rethrow; - g_pfnThrowResultException = ThrowResultExceptionInternal; - g_pfnResultFromCaughtExceptionInternal = ResultFromCaughtExceptionInternal; - return 1; - }); - - } - - //! A lambda-based exception guard that can vary the supported exception types. - //! This function accepts a lambda and diagnostics information as its parameters and executes that lambda - //! under a try/catch(...) block. All exceptions are caught and the function reports the exception information - //! and diagnostics to telemetry on failure. An HRESULT is returned that maps to the exception. - //! - //! Note that an overload exists that does not report failures to telemetry at all. This version should be preferred - //! to that version. Also note that neither of these versions are preferred over using try catch blocks to accomplish - //! the same thing as they will be more efficient. - //! - //! See @ref page_exception_guards for more information and examples on exception guards. - //! ~~~~ - //! return wil::ResultFromException(WI_DIAGNOSTICS_INFO, [&] - //! { - //! // exception-based code - //! // telemetry is reported with full exception information - //! }); - //! ~~~~ - //! @param diagnostics Always pass WI_DIAGNOSTICS_INFO as the first parameter - //! @param supported What kind of exceptions you want to support - //! @param functor A lambda that accepts no parameters; any return value is ignored - //! @return S_OK on success (no exception thrown) or an error based upon the exception thrown - template - __forceinline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, Functor&& functor) WI_NOEXCEPT - { - static_assert(details::functor_tag::value != details::tag_return_other::value, "Functor must return void or HRESULT"); - typename details::functor_tag::template functor_wrapper functorObject(wistd::forward(functor)); - - return wil::details::ResultFromException(diagnostics, supported, functorObject); - } - - //! A lambda-based exception guard. - //! This overload uses SupportedExceptions::Known by default. See @ref ResultFromException for more detailed information. - template - __forceinline HRESULT ResultFromException(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT - { - return ResultFromException(diagnostics, SupportedExceptions::Known, wistd::forward(functor)); - } - - //! A lambda-based exception guard that does not report failures to telemetry. - //! This function accepts a lambda as it's only parameter and executes that lambda under a try/catch(...) block. - //! All exceptions are caught and the function returns an HRESULT mapping to the exception. - //! - //! This version (taking only a lambda) does not report failures to telemetry. An overload with the same name - //! can be utilized by passing `WI_DIAGNOSTICS_INFO` as the first parameter and the lambda as the second parameter - //! to report failure information to telemetry. - //! - //! See @ref page_exception_guards for more information and examples on exception guards. - //! ~~~~ - //! hr = wil::ResultFromException([&] - //! { - //! // exception-based code - //! // the conversion of exception to HRESULT doesn't report telemetry - //! }); - //! - //! hr = wil::ResultFromException(WI_DIAGNOSTICS_INFO, [&] - //! { - //! // exception-based code - //! // telemetry is reported with full exception information - //! }); - //! ~~~~ - //! @param functor A lambda that accepts no parameters; any return value is ignored - //! @return S_OK on success (no exception thrown) or an error based upon the exception thrown - template - inline HRESULT ResultFromException(Functor&& functor) WI_NOEXCEPT try - { - static_assert(details::functor_tag::value == details::tag_return_void::value, "Functor must return void"); - typename details::functor_tag::template functor_wrapper functorObject(wistd::forward(functor)); - - functorObject.Run(); - return S_OK; - } - catch (...) - { - return ResultFromCaughtException(); - } - - - //! A lambda-based exception guard that can identify the origin of unknown exceptions and can vary the supported exception types. - //! Functionally this is nearly identical to the corresponding @ref ResultFromException function with the exception - //! that it utilizes structured exception handling internally to be able to terminate at the point where a unknown - //! exception is thrown, rather than after that unknown exception has been unwound. Though less efficient, this leads - //! to a better debugging experience when analyzing unknown exceptions. - //! - //! For example: - //! ~~~~ - //! hr = wil::ResultFromExceptionDebug(WI_DIAGNOSTICS_INFO, [&] - //! { - //! FunctionWhichMayThrow(); - //! }); - //! ~~~~ - //! Assume FunctionWhichMayThrow() has a bug in it where it accidentally does a `throw E_INVALIDARG;`. This ends up - //! throwing a `long` as an exception object which is not what the caller intended. The normal @ref ResultFromException - //! would fail-fast when this is encountered, but it would do so AFTER FunctionWhichMayThrow() is already off of the - //! stack and has been unwound. Because SEH is used for ResultFromExceptionDebug, the fail-fast occurs with everything - //! leading up to and including the `throw INVALIDARG;` still on the stack (and easily debuggable). - //! - //! The penalty paid for using this, however, is efficiency. It's far less efficient as a general pattern than either - //! using ResultFromException directly or especially using try with CATCH_ macros directly. Still it's helpful to deploy - //! selectively to isolate issues a component may be having with unknown/unhandled exceptions. - //! - //! The ability to vary the SupportedExceptions that this routine provides adds the ability to track down unexpected - //! exceptions not falling into the supported category easily through fail-fast. For example, by not supporting any - //! exception, you can use this function to quickly add an exception guard that will fail-fast any exception at the point - //! the exception occurs (the throw) in a codepath where the origination of unknown exceptions need to be tracked down. - //! - //! Also see @ref ResultFromExceptionDebugNoStdException. It functions almost identically, but also will fail-fast and stop - //! on std::exception based exceptions (but not Platform::Exception^ or wil::ResultException). Using this can help isolate - //! where an unexpected exception is being generated from. - //! @param diagnostics Always pass WI_DIAGNOSTICS_INFO as the first parameter - //! @param supported What kind of exceptions you want to support - //! @param functor A lambda that accepts no parameters; any return value is ignored - //! @return S_OK on success (no exception thrown) or an error based upon the exception thrown - template - __forceinline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, SupportedExceptions supported, Functor&& functor) WI_NOEXCEPT - { - static_assert(details::functor_tag::value == details::tag_return_void::value, "Functor must return void"); - typename details::functor_tag::template functor_wrapper functorObject(wistd::forward(functor)); - - return wil::details::ResultFromExceptionDebug(diagnostics, supported, functorObject); - } - - //! A lambda-based exception guard that can identify the origin of unknown exceptions. - //! This overload uses SupportedExceptions::Known by default. See @ref ResultFromExceptionDebug for more detailed information. - template - __forceinline HRESULT ResultFromExceptionDebug(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT - { - static_assert(details::functor_tag::value == details::tag_return_void::value, "Functor must return void"); - typename details::functor_tag::template functor_wrapper functorObject(wistd::forward(functor)); - - return wil::details::ResultFromExceptionDebug(diagnostics, SupportedExceptions::Known, functorObject); - } - - //! A fail-fast based exception guard. - //! Technically this is an overload of @ref ResultFromExceptionDebug that uses SupportedExceptions::None by default. Any uncaught - //! exception that makes it back to this guard would result in a fail-fast at the point the exception is thrown. - template - __forceinline void FailFastException(const DiagnosticsInfo& diagnostics, Functor&& functor) WI_NOEXCEPT - { - static_assert(details::functor_tag::value == details::tag_return_void::value, "Functor must return void"); - typename details::functor_tag::template functor_wrapper functorObject(wistd::forward(functor)); - - wil::details::ResultFromExceptionDebug(diagnostics, SupportedExceptions::None, functorObject); - } - - namespace details { - -#endif // WIL_ENABLE_EXCEPTIONS - - // Exception guard -- catch exceptions and log them (or handle them with a custom callback) - // WARNING: may throw an exception... - inline __declspec(noinline) HRESULT RunFunctor(IFunctor& functor, IFunctorHost& host) - { - if (g_pfnRunFunctorWithExceptionFilter) - { - return g_pfnRunFunctorWithExceptionFilter(functor, host, _ReturnAddress()); - } - - return host.Run(functor); - } - - // Returns true if a debugger should be considered to be connected. - // Modules can force this on through setting g_fIsDebuggerPresent explicitly (useful for live debugging), - // they can provide a callback function by setting g_pfnIsDebuggerPresent (useful for kernel debbugging), - // and finally the user-mode check (IsDebuggerPrsent) is checked. IsDebuggerPresent is a fast call - inline bool IsDebuggerPresent() - { - return g_fIsDebuggerPresent || ((g_pfnIsDebuggerPresent != nullptr) ? g_pfnIsDebuggerPresent() : (::IsDebuggerPresent() != FALSE)); - } - - //***************************************************************************** - // Shared Reporting -- all reporting macros bubble up through this codepath - //***************************************************************************** - - inline void LogFailure(__R_FN_PARAMS_FULL, FailureType type, const ResultStatus& resultPair, _In_opt_ PCWSTR message, - bool fWantDebugString, _Out_writes_(debugStringSizeChars) _Post_z_ PWSTR debugString, _Pre_satisfies_(debugStringSizeChars > 0) size_t debugStringSizeChars, - _Out_writes_(callContextStringSizeChars) _Post_z_ PSTR callContextString, _Pre_satisfies_(callContextStringSizeChars > 0) size_t callContextStringSizeChars, - _Out_ FailureInfo *failure) WI_NOEXCEPT - { - debugString[0] = L'\0'; - callContextString[0] = L'\0'; - - static long volatile s_failureId = 0; - - failure->hr = resultPair.hr; - failure->status = resultPair.status; - - int failureCount = 0; - switch (type) - { - case FailureType::Exception: - failureCount = RecordException(failure->hr); - break; - case FailureType::Return: - failureCount = RecordReturn(failure->hr); - break; - case FailureType::Log: - if (SUCCEEDED(failure->hr)) - { - // If you hit this assert (or are reviewing this failure telemetry), then most likely you are trying to log success - // using one of the WIL macros. Example: - // LOG_HR(S_OK); - // Instead, use one of the forms that conditionally logs based upon the error condition: - // LOG_IF_FAILED(hr); - - WI_USAGE_ERROR_FORWARD("CALLER BUG: Macro usage error detected. Do not LOG_XXX success."); - failure->hr = __HRESULT_FROM_WIN32(ERROR_ASSERTION_FAILURE); - failure->status = wil::details::HrToNtStatus(failure->hr); - } - failureCount = RecordLog(failure->hr); - break; - case FailureType::FailFast: - failureCount = RecordFailFast(failure->hr); - break; - }; - - failure->type = type; - failure->flags = FailureFlags::None; - WI_SetFlagIf(failure->flags, FailureFlags::NtStatus, resultPair.kind == ResultStatus::Kind::NtStatus); - failure->failureId = ::InterlockedIncrementNoFence(&s_failureId); - failure->pszMessage = ((message != nullptr) && (message[0] != L'\0')) ? message : nullptr; - failure->threadId = ::GetCurrentThreadId(); - failure->pszFile = fileName; - failure->uLineNumber = lineNumber; - failure->cFailureCount = failureCount; - failure->pszCode = code; - failure->pszFunction = functionName; - failure->returnAddress = returnAddress; - failure->callerReturnAddress = callerReturnAddress; - failure->pszCallContext = nullptr; - ::ZeroMemory(&failure->callContextCurrent, sizeof(failure->callContextCurrent)); - ::ZeroMemory(&failure->callContextOriginating, sizeof(failure->callContextOriginating)); - failure->pszModule = (g_pfnGetModuleName != nullptr) ? g_pfnGetModuleName() : nullptr; - - // Process failure notification / adjustments - if (details::g_pfnNotifyFailure) - { - details::g_pfnNotifyFailure(failure); - } - - // Completes filling out failure, notifies thread-based callbacks and the telemetry callback - if (details::g_pfnGetContextAndNotifyFailure) - { - details::g_pfnGetContextAndNotifyFailure(failure, callContextString, callContextStringSizeChars); - } - - // Allow hooks to inspect the failure before acting upon it - if (details::g_pfnLoggingCallback) - { - details::g_pfnLoggingCallback(*failure); - } - - // If the hook is enabled then it will be given the opportunity to call RoOriginateError to greatly improve the diagnostic experience - // for uncaught exceptions. In cases where we will be throwing a C++/CX Platform::Exception we should avoid originating because the - // CX runtime will be doing that for us. fWantDebugString is only set to true when the caller will be throwing a Platform::Exception. - if (details::g_pfnOriginateCallback && !fWantDebugString && WI_IsFlagClear(failure->flags, FailureFlags::RequestSuppressTelemetry)) - { - details::g_pfnOriginateCallback(*failure); - } - - if (SUCCEEDED(failure->hr)) - { - // Caller bug: Leaking a success code into a failure-only function - FAIL_FAST_IMMEDIATE_IF(type != FailureType::FailFast); - failure->hr = E_UNEXPECTED; - failure->status = wil::details::HrToNtStatus(failure->hr); - } - - bool const fUseOutputDebugString = IsDebuggerPresent() && g_fResultOutputDebugString && WI_IsFlagClear(failure->flags, FailureFlags::RequestSuppressTelemetry); - - // We need to generate the logging message if: - // * We're logging to OutputDebugString - // * OR the caller asked us to (generally for attaching to a C++/CX exception) - if (fWantDebugString || fUseOutputDebugString) - { - // Call the logging callback (if present) to allow them to generate the debug string that will be pushed to the console - // or the platform exception object if the caller desires it. - if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet) - { - g_pfnResultLoggingCallback(failure, debugString, debugStringSizeChars); - } - - // The callback only optionally needs to supply the debug string -- if the callback didn't populate it, yet we still want - // it for OutputDebugString or exception message, then generate the default string. - if (debugString[0] == L'\0') - { - GetFailureLogString(debugString, debugStringSizeChars, *failure); - } - - if (fUseOutputDebugString) - { - ::OutputDebugStringW(debugString); - } - } - else - { - // [deprecated behavior] - // This callback was at one point *always* called for all failures, so we continue to call it for failures even when we don't - // need to generate the debug string information (when the callback was supplied directly). We can avoid this if the caller - // used the explicit function (through g_resultMessageCallbackSet) - if ((g_pfnResultLoggingCallback != nullptr) && !g_resultMessageCallbackSet) - { - g_pfnResultLoggingCallback(failure, nullptr, 0); - } - } - - if ((WI_IsFlagSet(failure->flags, FailureFlags::RequestDebugBreak) || g_fBreakOnFailure) && (g_pfnDebugBreak != nullptr)) - { - g_pfnDebugBreak(); - } - } - - inline RESULT_NORETURN void __stdcall WilFailFast(const wil::FailureInfo& failure) - { - if (g_pfnWilFailFast) - { - g_pfnWilFailFast(failure); - } - -#ifdef RESULT_RAISE_FAST_FAIL_EXCEPTION - // Use of this macro is an ODR violation - use the callback instead. This will be removed soon. - RESULT_RAISE_FAST_FAIL_EXCEPTION; -#endif - - // Before we fail fast in this method, give the [optional] RoFailFastWithErrorContext a try. - if (g_pfnFailfastWithContextCallback) - { - g_pfnFailfastWithContextCallback(failure); - } - - // parameter 0 is the !analyze code (FAST_FAIL_FATAL_APP_EXIT) - EXCEPTION_RECORD er{}; - er.NumberParameters = 1; // default to be safe, see below - er.ExceptionCode = static_cast(STATUS_STACK_BUFFER_OVERRUN); // 0xC0000409 - er.ExceptionFlags = EXCEPTION_NONCONTINUABLE; - er.ExceptionInformation[0] = FAST_FAIL_FATAL_APP_EXIT; // see winnt.h, generated from minkernel\published\base\ntrtl_x.w - if (failure.returnAddress == nullptr) // FailureInfo does not have _ReturnAddress, have RaiseFailFastException generate it - { - // passing ExceptionCode 0xC0000409 and one param with FAST_FAIL_APP_EXIT will use existing - // !analyze functionality to crawl the stack looking for the HRESULT - // don't pass a 0 HRESULT in param 1 because that will result in worse bucketing. - WilRaiseFailFastException(&er, nullptr, FAIL_FAST_GENERATE_EXCEPTION_ADDRESS); - } - else // use FailureInfo caller address - { - // parameter 1 is the failing HRESULT - // parameter 2 is the line number. This is never used for bucketing (due to code churn causing re-bucketing) but is available in the dump's - // exception record to aid in failure locality. Putting it here prevents it from being poisoned in triage dumps. - er.NumberParameters = 3; - er.ExceptionInformation[1] = failure.hr; - er.ExceptionInformation[2] = failure.uLineNumber; - er.ExceptionAddress = failure.returnAddress; - WilRaiseFailFastException(&er, nullptr, 0 /* do not generate exception address */); - } - } - - template - inline __declspec(noinline) void ReportFailure_Return(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options) - { - bool needPlatformException = ((T == FailureType::Exception) && - WI_IsFlagClear(options, ReportFailureOptions::MayRethrow) && - (g_pfnThrowPlatformException != nullptr) && - (g_fResultThrowPlatformException || WI_IsFlagSet(options, ReportFailureOptions::ForcePlatformException))); - - FailureInfo failure; - wchar_t debugString[2048]; - char callContextString[1024]; - - LogFailure(__R_FN_CALL_FULL, T, resultPair, message, needPlatformException, - debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), &failure); - - if (WI_IsFlagSet(failure.flags, FailureFlags::RequestFailFast)) - { - WilFailFast(failure); - } - } - - template - inline __declspec(noinline) void ReportFailure_Base(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options) - { - ReportFailure_Return(__R_FN_CALL_FULL, resultPair, message, options); - } - - template - inline __declspec(noinline) RESULT_NORETURN void ReportFailure_NoReturn(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options) - { - bool needPlatformException = ((T == FailureType::Exception) && - WI_IsFlagClear(options, ReportFailureOptions::MayRethrow) && - (g_pfnThrowPlatformException != nullptr) && - (g_fResultThrowPlatformException || WI_IsFlagSet(options, ReportFailureOptions::ForcePlatformException))); - - FailureInfo failure; - wchar_t debugString[2048]; - char callContextString[1024]; - - LogFailure(__R_FN_CALL_FULL, T, resultPair, message, needPlatformException, - debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), &failure); -__WI_SUPPRESS_4127_S - if ((T == FailureType::FailFast) || WI_IsFlagSet(failure.flags, FailureFlags::RequestFailFast)) - { - WilFailFast(const_cast(failure)); - } - else - { - if (needPlatformException) - { - g_pfnThrowPlatformException(failure, debugString); - } - - if (WI_IsFlagSet(options, ReportFailureOptions::MayRethrow)) - { - RethrowCaughtException(); - } - - ThrowResultException(failure); - - // Wil was instructed to throw, but doesn't have any capability to do so (global function pointers are not setup) - WilFailFast(const_cast(failure)); - } -__WI_SUPPRESS_4127_E - } - - template<> - inline __declspec(noinline) RESULT_NORETURN void ReportFailure_Base(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options) - { - ReportFailure_NoReturn(__R_FN_CALL_FULL, resultPair, message, options); - } - - template<> - inline __declspec(noinline) RESULT_NORETURN void ReportFailure_Base(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, PCWSTR message, ReportFailureOptions options) - { - ReportFailure_NoReturn(__R_FN_CALL_FULL, resultPair, message, options); - } - - __declspec(noinline) inline void ReportFailure(__R_FN_PARAMS_FULL, FailureType type, const ResultStatus& resultPair, _In_opt_ PCWSTR message, ReportFailureOptions options) - { - switch(type) - { - case FailureType::Exception: - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message, options); - break; - case FailureType::FailFast: - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message, options); - break; - case FailureType::Log: - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message, options); - break; - case FailureType::Return: - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message, options); - break; - } - } - - template - inline ResultStatus ReportFailure_CaughtExceptionCommon(__R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported) - { - bool isNormalized = false; - auto length = wcslen(debugString); - WI_ASSERT(length < debugStringChars); - ResultStatus resultPair; - if (details::g_pfnResultFromCaughtExceptionInternal) - { - resultPair = details::g_pfnResultFromCaughtExceptionInternal(debugString + length, debugStringChars - length, &isNormalized); - } - - const bool known = (FAILED(resultPair.hr)); - if (!known) - { - resultPair = ResultStatus::FromResult(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); - } - - ReportFailureOptions options = ReportFailureOptions::ForcePlatformException; - WI_SetFlagIf(options, ReportFailureOptions::MayRethrow, isNormalized); - - if ((supported == SupportedExceptions::None) || - ((supported == SupportedExceptions::Known) && !known) || - ((supported == SupportedExceptions::Thrown) && !isNormalized) || - ((supported == SupportedExceptions::Default) && !known && g_fResultFailFastUnknownExceptions)) - { - // By default WIL will issue a fail fast for unrecognized exception types. Wil recognizes any std::exception or wil::ResultException based - // types and Platform::Exception^, so there aren't too many valid exception types which could cause this. Those that are valid, should be handled - // by remapping the exception callback. Those that are not valid should be found and fixed (meaningless accidents like 'throw hr;'). - // The caller may also be requesting non-default behavior to fail-fast more frequently (primarily for debugging unknown exceptions). - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, debugString, options); - } - else - { - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, debugString, options); - } - - return resultPair; - } - - template - inline ResultStatus RESULT_NORETURN ReportFailure_CaughtExceptionCommonNoReturnBase(__R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported) - { - bool isNormalized = false; - const auto length = wcslen(debugString); - WI_ASSERT(length < debugStringChars); - ResultStatus resultPair; - if (details::g_pfnResultFromCaughtExceptionInternal) - { - resultPair = details::g_pfnResultFromCaughtExceptionInternal(debugString + length, debugStringChars - length, &isNormalized); - } - - const bool known = (FAILED(resultPair.hr)); - if (!known) - { - resultPair = ResultStatus::FromResult(__HRESULT_FROM_WIN32(ERROR_UNHANDLED_EXCEPTION)); - } - - ReportFailureOptions options = ReportFailureOptions::ForcePlatformException; - WI_SetFlagIf(options, ReportFailureOptions::MayRethrow, isNormalized); - - if ((supported == SupportedExceptions::None) || - ((supported == SupportedExceptions::Known) && !known) || - ((supported == SupportedExceptions::Thrown) && !isNormalized) || - ((supported == SupportedExceptions::Default) && !known && g_fResultFailFastUnknownExceptions)) - { - // By default WIL will issue a fail fast for unrecognized exception types. Wil recognizes any std::exception or wil::ResultException based - // types and Platform::Exception^, so there aren't too many valid exception types which could cause this. Those that are valid, should be handled - // by remapping the exception callback. Those that are not valid should be found and fixed (meaningless accidents like 'throw hr;'). - // The caller may also be requesting non-default behavior to fail-fast more frequently (primarily for debugging unknown exceptions). - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, debugString, options); - } - else - { - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, debugString, options); - } - - RESULT_NORETURN_RESULT(resultPair); - } - - template<> - inline RESULT_NORETURN ResultStatus ReportFailure_CaughtExceptionCommon(__R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported) - { - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommonNoReturnBase(__R_FN_CALL_FULL, debugString, debugStringChars, supported)); - } - - template<> - inline RESULT_NORETURN ResultStatus ReportFailure_CaughtExceptionCommon(__R_FN_PARAMS_FULL, _Inout_updates_(debugStringChars) PWSTR debugString, _Pre_satisfies_(debugStringChars > 0) size_t debugStringChars, SupportedExceptions supported) - { - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommonNoReturnBase(__R_FN_CALL_FULL, debugString, debugStringChars, supported)); - } - - template - inline void ReportFailure_Msg(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, _Printf_format_string_ PCSTR formatString, va_list argList) - { - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message); - } - - template<> - inline RESULT_NORETURN void ReportFailure_Msg(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, _Printf_format_string_ PCSTR formatString, va_list argList) - { - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message); - } - - template<> - inline RESULT_NORETURN void ReportFailure_Msg(__R_FN_PARAMS_FULL, const ResultStatus& resultPair, _Printf_format_string_ PCSTR formatString, va_list argList) - { - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - ReportFailure_Base(__R_FN_CALL_FULL, resultPair, message); - } - - template - inline void ReportFailure_ReplaceMsg(__R_FN_PARAMS_FULL, HRESULT hr, PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - } - - template - __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr) - { - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - } - - template<> - __declspec(noinline) inline RESULT_NORETURN void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr) - { - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - } - - template<> - __declspec(noinline) inline RESULT_NORETURN void ReportFailure_Hr(__R_FN_PARAMS_FULL, HRESULT hr) - { - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - } - - __declspec(noinline) inline void ReportFailure_Hr(__R_FN_PARAMS_FULL, FailureType type, HRESULT hr) - { - switch(type) - { - case FailureType::Exception: - ReportFailure_Hr(__R_FN_CALL_FULL, hr); - break; - case FailureType::FailFast: - ReportFailure_Hr(__R_FN_CALL_FULL, hr); - break; - case FailureType::Log: - ReportFailure_Hr(__R_FN_CALL_FULL, hr); - break; - case FailureType::Return: - ReportFailure_Hr(__R_FN_CALL_FULL, hr); - break; - } - } - - template - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __declspec(noinline) inline HRESULT ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err) - { - const auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - return hr; - } - - template<> - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err) - { - const auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - RESULT_NORETURN_RESULT(hr); - } - - template<> - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32(__R_FN_PARAMS_FULL, DWORD err) - { - const auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - RESULT_NORETURN_RESULT(hr); - } - - template - __declspec(noinline) inline DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL) - { - const auto err = GetLastErrorFail(__R_FN_CALL_FULL); - const auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - ::SetLastError(err); - return err; - } - - template<> - __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL) - { - const auto err = GetLastErrorFail(__R_FN_CALL_FULL); - const auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - RESULT_NORETURN_RESULT(err); - } - - template<> - __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastError(__R_FN_PARAMS_FULL) - { - const auto err = GetLastErrorFail(__R_FN_CALL_FULL); - const auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - RESULT_NORETURN_RESULT(err); - } - - template - _Success_(true) - _Translates_last_error_to_HRESULT_ - __declspec(noinline) inline HRESULT ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL) - { - const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - return hr; - } - - template<> - _Success_(true) - _Translates_last_error_to_HRESULT_ - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL) - { - const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - RESULT_NORETURN_RESULT(hr); - } - - template<> - _Success_(true) - _Translates_last_error_to_HRESULT_ - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHr(__R_FN_PARAMS_FULL) - { - const auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); - ReportFailure_Base(__R_FN_CALL_FULL, ResultStatus::FromResult(hr)); - RESULT_NORETURN_RESULT(hr); - } - - template - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __declspec(noinline) inline HRESULT ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status) - { - const auto resultPair = ResultStatus::FromStatus(status); - ReportFailure_Base(__R_FN_CALL_FULL, resultPair); - return resultPair.hr; - } - - template<> - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status) - { - const auto resultPair = ResultStatus::FromStatus(status); - ReportFailure_Base(__R_FN_CALL_FULL, resultPair); - RESULT_NORETURN_RESULT(resultPair.hr); - } - - template<> - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatus(__R_FN_PARAMS_FULL, NTSTATUS status) - { - const auto resultPair = ResultStatus::FromStatus(status); - ReportFailure_Base(__R_FN_CALL_FULL, resultPair); - RESULT_NORETURN_RESULT(resultPair.hr); - } - - template - __declspec(noinline) inline HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) - { - wchar_t message[2048]{}; - return ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).hr; - } - - template<> - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) - { - wchar_t message[2048]{}; - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).hr); - } - - template<> - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtException(__R_FN_PARAMS_FULL, SupportedExceptions supported) - { - wchar_t message[2048]{}; - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), supported).hr); - } - - template - __declspec(noinline) inline void ReportFailure_HrMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) - { - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - } - - template<> - __declspec(noinline) inline RESULT_NORETURN void ReportFailure_HrMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) - { - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - } - - template<> - __declspec(noinline) inline RESULT_NORETURN void ReportFailure_HrMsg(__R_FN_PARAMS_FULL, HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) - { - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - } - - template - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __declspec(noinline) inline HRESULT ReportFailure_Win32Msg(__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - return hr; - } - - template<> - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32Msg(__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - RESULT_NORETURN_RESULT(hr); - } - - template<> - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_Win32Msg(__R_FN_PARAMS_FULL, DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - RESULT_NORETURN_RESULT(hr); - } - - template - __declspec(noinline) inline DWORD ReportFailure_GetLastErrorMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto err = GetLastErrorFail(__R_FN_CALL_FULL); - auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - ::SetLastError(err); - return err; - } - - template<> - __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastErrorMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto err = GetLastErrorFail(__R_FN_CALL_FULL); - auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - RESULT_NORETURN_RESULT(err); - } - - template<> - __declspec(noinline) inline RESULT_NORETURN DWORD ReportFailure_GetLastErrorMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto err = GetLastErrorFail(__R_FN_CALL_FULL); - auto hr = __HRESULT_FROM_WIN32(err); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - RESULT_NORETURN_RESULT(err); - } - - template - _Success_(true) - _Translates_last_error_to_HRESULT_ - __declspec(noinline) inline HRESULT ReportFailure_GetLastErrorHrMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - return hr; - } - - template<> - _Success_(true) - _Translates_last_error_to_HRESULT_ - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHrMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - RESULT_NORETURN_RESULT(hr); - } - - template<> - _Success_(true) - _Translates_last_error_to_HRESULT_ - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_GetLastErrorHrMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - auto hr = GetLastErrorFailHr(__R_FN_CALL_FULL); - ReportFailure_Msg(__R_FN_CALL_FULL, ResultStatus::FromResult(hr), formatString, argList); - RESULT_NORETURN_RESULT(hr); - } - - template - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __declspec(noinline) inline HRESULT ReportFailure_NtStatusMsg(__R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) - { - const auto resultPair = ResultStatus::FromStatus(status); - ReportFailure_Msg(__R_FN_CALL_FULL, resultPair, formatString, argList); - return resultPair.hr; - } - - template<> - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatusMsg(__R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) - { - const auto resultPair = ResultStatus::FromStatus(status); - ReportFailure_Msg(__R_FN_CALL_FULL, resultPair, formatString, argList); - RESULT_NORETURN_RESULT(resultPair.hr); - } - - template<> - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_NtStatusMsg(__R_FN_PARAMS_FULL, NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) - { - const auto resultPair = ResultStatus::FromStatus(status); - ReportFailure_Msg(__R_FN_CALL_FULL, resultPair, formatString, argList); - RESULT_NORETURN_RESULT(resultPair.hr); - } - - template - __declspec(noinline) inline HRESULT ReportFailure_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - // Pre-populate the buffer with our message, the exception message will be added to it... - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - StringCchCatW(message, ARRAYSIZE(message), L" -- "); - return ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).hr; - } - - template<> - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - // Pre-populate the buffer with our message, the exception message will be added to it... - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - StringCchCatW(message, ARRAYSIZE(message), L" -- "); - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).hr); - } - - template<> - __declspec(noinline) inline RESULT_NORETURN HRESULT ReportFailure_CaughtExceptionMsg(__R_FN_PARAMS_FULL, _Printf_format_string_ PCSTR formatString, va_list argList) - { - // Pre-populate the buffer with our message, the exception message will be added to it... - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - StringCchCatW(message, ARRAYSIZE(message), L" -- "); - RESULT_NORETURN_RESULT(ReportFailure_CaughtExceptionCommon(__R_FN_CALL_FULL, message, ARRAYSIZE(message), SupportedExceptions::Default).hr); - } - - - //***************************************************************************** - // Support for throwing custom exception types - //***************************************************************************** - -#ifdef WIL_ENABLE_EXCEPTIONS - inline HRESULT GetErrorCode(_In_ ResultException &exception) WI_NOEXCEPT - { - return exception.GetErrorCode(); - } - - inline void SetFailureInfo(_In_ FailureInfo const &failure, _Inout_ ResultException &exception) WI_NOEXCEPT - { - return exception.SetFailureInfo(failure); - } - -#ifdef __cplusplus_winrt - inline HRESULT GetErrorCode(_In_ Platform::Exception^ exception) WI_NOEXCEPT - { - return exception->HResult; - } - - inline void SetFailureInfo(_In_ FailureInfo const &, _Inout_ Platform::Exception^ exception) WI_NOEXCEPT - { - // no-op -- once a PlatformException^ is created, we can't modify the message, but this function must - // exist to distinguish this from ResultException - } -#endif - - template - RESULT_NORETURN inline void ReportFailure_CustomExceptionHelper(_Inout_ T &exception, __R_FN_PARAMS_FULL, _In_opt_ PCWSTR message = nullptr) - { - // When seeing the error: "cannot convert parameter 1 from 'XXX' to 'wil::ResultException &'" - // Custom exceptions must be based upon either ResultException or Platform::Exception^ to be used with ResultException.h. - // This compilation error indicates an attempt to throw an incompatible exception type. - const HRESULT hr = GetErrorCode(exception); - - FailureInfo failure; - wchar_t debugString[2048]; - char callContextString[1024]; - - LogFailure(__R_FN_CALL_FULL, FailureType::Exception, ResultStatus::FromResult(hr), message, false, // false = does not need debug string - debugString, ARRAYSIZE(debugString), callContextString, ARRAYSIZE(callContextString), &failure); - - if (WI_IsFlagSet(failure.flags, FailureFlags::RequestFailFast)) - { - WilFailFast(failure); - } - - // push the failure info context into the custom exception class - SetFailureInfo(failure, exception); - - throw exception; - } - - template - __declspec(noreturn, noinline) inline void ReportFailure_CustomException(__R_FN_PARAMS _In_ T exception) - { - __R_FN_LOCALS_RA; - ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL); - } - - template - __declspec(noreturn, noinline) inline void ReportFailure_CustomExceptionMsg(__R_FN_PARAMS _In_ T exception, _In_ _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - wchar_t message[2048]; - PrintLoggingMessage(message, ARRAYSIZE(message), formatString, argList); - - __R_FN_LOCALS_RA; - ReportFailure_CustomExceptionHelper(exception, __R_FN_CALL_FULL, message); - } -#endif - - namespace __R_NS_NAME - { - //***************************************************************************** - // Return Macros - //***************************************************************************** - - __R_DIRECT_METHOD(void, Return_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr); - } - - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __R_DIRECT_METHOD(HRESULT, Return_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT - { - __R_FN_LOCALS; - return wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL err); - } - - _Success_(true) - _Translates_last_error_to_HRESULT_ - __R_DIRECT_METHOD(HRESULT, Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - return wil::details::ReportFailure_GetLastErrorHr(__R_DIRECT_FN_CALL_ONLY); - } - - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __R_DIRECT_METHOD(HRESULT, Return_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT - { - __R_FN_LOCALS; - return wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL status); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - __R_DIRECT_METHOD(HRESULT, Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - return wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY); - } -#endif - - __R_DIRECT_METHOD(void, Return_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL hr, formatString, argList); - } - - _Success_(true) - _Translates_Win32_to_HRESULT_(err) - __R_DIRECT_METHOD(HRESULT, Return_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - return wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL err, formatString, argList); - } - - _Success_(true) - _Translates_last_error_to_HRESULT_ - __R_DIRECT_METHOD(HRESULT, Return_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - return wil::details::ReportFailure_GetLastErrorHrMsg(__R_DIRECT_FN_CALL formatString, argList); - } - - _Success_(true) - _Translates_NTSTATUS_to_HRESULT_(status) - __R_DIRECT_METHOD(HRESULT, Return_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - return wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL status, formatString, argList); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - __R_DIRECT_METHOD(HRESULT, Return_CaughtExceptionMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - return wil::details::ReportFailure_CaughtExceptionMsg(__R_DIRECT_FN_CALL formatString, argList); - } -#endif - - //***************************************************************************** - // Log Macros - //***************************************************************************** - - _Post_satisfies_(return == hr) - __R_DIRECT_METHOD(HRESULT, Log_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr); - return hr; - } - - _Post_satisfies_(return == err) - __R_DIRECT_METHOD(DWORD, Log_Win32)(__R_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL err); - return err; - } - - __R_DIRECT_METHOD(DWORD, Log_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - return wil::details::ReportFailure_GetLastError(__R_DIRECT_FN_CALL_ONLY); - } - - _Post_satisfies_(return == status) - __R_DIRECT_METHOD(NTSTATUS, Log_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL status); - return status; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - __R_DIRECT_METHOD(HRESULT, Log_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - return wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY); - } -#endif - - __R_INTERNAL_METHOD(_Log_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL hr); - } - - __R_INTERNAL_METHOD(_Log_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_GetLastError(__R_INTERNAL_FN_CALL_ONLY); - } - - __R_INTERNAL_METHOD(_Log_Win32)(__R_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Win32(__R_INTERNAL_FN_CALL err); - } - - __R_INTERNAL_METHOD(_Log_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL E_OUTOFMEMORY); - } - - __R_INTERNAL_METHOD(_Log_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatus(__R_INTERNAL_FN_CALL status); - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == hr) - __R_CONDITIONAL_METHOD(HRESULT, Log_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr) - { - if (FAILED(hr)) - { - __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); - } - return hr; - } - - _Post_satisfies_(return == hr) - __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Log_IfFailedWithExpected)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, unsigned int expectedCount, ...) WI_NOEXCEPT - { - va_list args; - va_start(args, expectedCount); - - if (FAILED(hr)) - { - unsigned int expectedIndex; - for (expectedIndex = 0; expectedIndex < expectedCount; ++expectedIndex) - { - if (hr == va_arg(args, HRESULT)) - { - break; - } - } - - if (expectedIndex == expectedCount) - { - __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); - } - } - - va_end(args); - return hr; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == ret) - __R_CONDITIONAL_METHOD(BOOL, Log_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret) - { - if (!ret) - { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return ret; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == err) - __R_CONDITIONAL_METHOD(DWORD, Log_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err) - { - if (FAILED_WIN32(err)) - { - __R_CALL_INTERNAL_METHOD(_Log_Win32)(__R_CONDITIONAL_FN_CALL err); - } - return err; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == handle) - __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) - { - if (handle == INVALID_HANDLE_VALUE) - { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return handle; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == handle) - __R_CONDITIONAL_METHOD(HANDLE, Log_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) - { - if (handle == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return handle; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) - __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer) WI_NOEXCEPT - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Log_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); - } - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == condition) - __R_CONDITIONAL_METHOD(bool, Log_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) - { - if (condition) - { - __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); - } - return condition; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == condition) - __R_CONDITIONAL_METHOD(bool, Log_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) - { - if (!condition) - { - __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); - } - return condition; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) - __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); - } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) WI_NOEXCEPT - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Log_Hr)(__R_CONDITIONAL_FN_CALL hr); - } - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == condition) - __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition) - { - if (condition) - { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return condition; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == condition) - __R_CONDITIONAL_METHOD(bool, Log_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition) - { - if (!condition) - { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return condition; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) - __R_CONDITIONAL_TEMPLATE_METHOD(PointerT, Log_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) WI_NOEXCEPT - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_TEMPLATE_METHOD(void, Log_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) WI_NOEXCEPT - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Log_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == status) - __R_CONDITIONAL_METHOD(NTSTATUS, Log_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status) - { - if (FAILED_NTSTATUS(status)) - { - __R_CALL_INTERNAL_METHOD(_Log_NtStatus)(__R_CONDITIONAL_FN_CALL status); - } - return status; - } - - _Post_satisfies_(return == hr) - __R_DIRECT_METHOD(HRESULT, Log_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL hr, formatString, argList); - return hr; - } - - _Post_satisfies_(return == err) - __R_DIRECT_METHOD(DWORD, Log_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL err, formatString, argList); - return err; - } - - __R_DIRECT_METHOD(DWORD, Log_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - return wil::details::ReportFailure_GetLastErrorMsg(__R_DIRECT_FN_CALL formatString, argList); - } - - _Post_satisfies_(return == status) - __R_DIRECT_METHOD(NTSTATUS, Log_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL status, formatString, argList); - return status; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - __R_DIRECT_METHOD(HRESULT, Log_CaughtExceptionMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - return wil::details::ReportFailure_CaughtExceptionMsg(__R_DIRECT_FN_CALL formatString, argList); - } -#endif - - __R_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList); - } - - __R_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_GetLastErrorMsg(__R_INTERNAL_NOINLINE_FN_CALL formatString, argList); - } - - __R_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg)(__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_Win32Msg(__R_INTERNAL_NOINLINE_FN_CALL err, formatString, argList); - } - - __R_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList); - } - - __R_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatusMsg(__R_INTERNAL_NOINLINE_FN_CALL status, formatString, argList); - } - - _Post_satisfies_(return == hr) - __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Log_IfFailedMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (FAILED(hr)) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - return hr; - } - - _Post_satisfies_(return == ret) - __R_CONDITIONAL_NOINLINE_METHOD(BOOL, Log_IfWin32BoolFalseMsg)(__R_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!ret) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return ret; - } - - _Post_satisfies_(return == err) - __R_CONDITIONAL_NOINLINE_METHOD(DWORD, Log_IfWin32ErrorMsg)(__R_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (FAILED_WIN32(err)) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); - } - return err; - } - - _Post_satisfies_(return == handle) - __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleInvalidMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (handle == INVALID_HANDLE_VALUE) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return handle; - } - - _Post_satisfies_(return == handle) - __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Log_IfHandleNullMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (handle == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return handle; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); - } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); - } - } - - _Post_satisfies_(return == condition) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (condition) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - return condition; - } - - _Post_satisfies_(return == condition) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_HrIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!condition) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - return condition; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - } - - _Post_satisfies_(return == condition) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (condition) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return condition; - } - - _Post_satisfies_(return == condition) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Log_GetLastErrorIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!condition) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return condition; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(PointerT, Log_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Log_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - } - - _Post_satisfies_(return == status) - __R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, Log_IfNtStatusFailedMsg)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (FAILED_NTSTATUS(status)) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Log_NtStatusMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); - } - return status; - } - } // namespace __R_NS_NAME - - namespace __RFF_NS_NAME - { - //***************************************************************************** - // FailFast Macros - //***************************************************************************** - - __RFF_DIRECT_NORET_METHOD(void, FailFast_Hr)(__RFF_DIRECT_FN_PARAMS HRESULT hr) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Hr(__RFF_DIRECT_FN_CALL hr); - } - - __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32)(__RFF_DIRECT_FN_PARAMS DWORD err) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Win32(__RFF_DIRECT_FN_CALL err); - } - - __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastError)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_GetLastError(__RFF_DIRECT_FN_CALL_ONLY); - } - - __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatus)(__RFF_DIRECT_FN_PARAMS NTSTATUS status) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_NtStatus(__RFF_DIRECT_FN_CALL status); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - __RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtException)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_CaughtException(__RFF_DIRECT_FN_CALL_ONLY); - } -#endif - - __RFF_INTERNAL_NORET_METHOD(_FailFast_Hr)(__RFF_INTERNAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL hr); - } - - __RFF_INTERNAL_NORET_METHOD(_FailFast_GetLastError)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_GetLastError(__RFF_INTERNAL_FN_CALL_ONLY); - } - - __RFF_INTERNAL_NORET_METHOD(_FailFast_Win32)(__RFF_INTERNAL_FN_PARAMS DWORD err) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Win32(__RFF_INTERNAL_FN_CALL err); - } - - __RFF_INTERNAL_NORET_METHOD(_FailFast_NullAlloc)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL E_OUTOFMEMORY); - } - - __RFF_INTERNAL_NORET_METHOD(_FailFast_NtStatus)(__RFF_INTERNAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_NtStatus(__RFF_INTERNAL_FN_CALL status); - } - - _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(HRESULT, FailFast_IfFailed)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr) WI_NOEXCEPT - { - if (FAILED(hr)) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); - } - return hr; - } - - _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(BOOL, FailFast_IfWin32BoolFalse)(__RFF_CONDITIONAL_FN_PARAMS BOOL ret) WI_NOEXCEPT - { - if (!ret) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - return ret; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(DWORD, FailFast_IfWin32Error)(__RFF_CONDITIONAL_FN_PARAMS DWORD err) - { - if (FAILED_WIN32(err)) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Win32)(__RFF_CONDITIONAL_FN_CALL err); - } - return err; - } - - _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(HANDLE, FailFast_IfHandleInvalid)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT - { - if (handle == INVALID_HANDLE_VALUE) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - return handle; - } - - _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, FailFast_IfHandleNull)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle) WI_NOEXCEPT - { - if (handle == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - return handle; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullAlloc)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - return pointer; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_IfNullAlloc)(__RFF_CONDITIONAL_FN_PARAMS const PointerT& pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_NullAlloc)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIf)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT - { - if (condition) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_HrIfFalse)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) WI_NOEXCEPT - { - if (!condition) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); - } - return condition; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_HrIfNull)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); - } - return pointer; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_HrIfNull)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Hr)(__RFF_CONDITIONAL_FN_CALL hr); - } - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_GetLastErrorIf)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT - { - if (condition) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_GetLastErrorIfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT - { - if (!condition) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - return condition; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_GetLastErrorIfNull)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - return pointer; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_GetLastErrorIfNull)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_GetLastError)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - } - - _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(NTSTATUS, FailFast_IfNtStatusFailed)(__RFF_CONDITIONAL_FN_PARAMS NTSTATUS status) WI_NOEXCEPT - { - if (FAILED_NTSTATUS(status)) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_NtStatus)(__RFF_CONDITIONAL_FN_CALL status); - } - return status; - } - - __RFF_DIRECT_NORET_METHOD(void, FailFast_HrMsg)(__RFF_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __RFF_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__RFF_DIRECT_FN_CALL hr, formatString, argList); - } - - __RFF_DIRECT_NORET_METHOD(void, FailFast_Win32Msg)(__RFF_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __RFF_FN_LOCALS; - wil::details::ReportFailure_Win32Msg(__RFF_DIRECT_FN_CALL err, formatString, argList); - } - - __RFF_DIRECT_NORET_METHOD(void, FailFast_GetLastErrorMsg)(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __RFF_FN_LOCALS; - wil::details::ReportFailure_GetLastErrorMsg(__RFF_DIRECT_FN_CALL formatString, argList); - } - - __RFF_DIRECT_NORET_METHOD(void, FailFast_NtStatusMsg)(__RFF_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __RFF_FN_LOCALS; - wil::details::ReportFailure_NtStatusMsg(__RFF_DIRECT_FN_CALL status, formatString, argList); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - __RFF_DIRECT_NORET_METHOD(void, FailFast_CaughtExceptionMsg)(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __RFF_FN_LOCALS; - wil::details::ReportFailure_CaughtExceptionMsg(__RFF_DIRECT_FN_CALL formatString, argList); - } -#endif - - __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_HrMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList); - } - - __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_GetLastErrorMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_GetLastErrorMsg(__RFF_INTERNAL_NOINLINE_FN_CALL formatString, argList); - } - - __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_Win32Msg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Win32Msg(__RFF_INTERNAL_NOINLINE_FN_CALL err, formatString, argList); - } - - __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NullAllocMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList); - } - - __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_NtStatusMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_NtStatusMsg(__RFF_INTERNAL_NOINLINE_FN_CALL status, formatString, argList); - } - - _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(HRESULT, FailFast_IfFailedMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (FAILED(hr)) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - return hr; - } - - _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(BOOL, FailFast_IfWin32BoolFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!ret) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return ret; - } - - _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(DWORD, FailFast_IfWin32ErrorMsg)(__RFF_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (FAILED_WIN32(err)) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_Win32Msg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); - } - return err; - } - - _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(HANDLE, FailFast_IfHandleInvalidMsg)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (handle == INVALID_HANDLE_VALUE) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return handle; - } - - _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, FailFast_IfHandleNullMsg)(__RFF_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (handle == nullptr) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return handle; - } - - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullAllocMsg)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); - } - return pointer; - } - - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_IfNullAllocMsg)(__RFF_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NullAllocMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); - } - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_HrIfMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (condition) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_HrIfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!condition) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - return condition; - } - - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_HrIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - return pointer; - } - - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_HrIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_HrMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (condition) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_GetLastErrorIfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!condition) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return condition; - } - - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_GetLastErrorIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return pointer; - } - - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_GetLastErrorIfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_GetLastErrorMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - } - - _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, FailFast_IfNtStatusFailedMsg)(__RFF_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (FAILED_NTSTATUS(status)) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_NtStatusMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); - } - return status; - } - - __RFF_DIRECT_NORET_METHOD(void, FailFast_Unexpected)(__RFF_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Hr(__RFF_DIRECT_FN_CALL E_UNEXPECTED); - } - - __RFF_INTERNAL_NORET_METHOD(_FailFast_Unexpected)(__RFF_INTERNAL_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_Hr(__RFF_INTERNAL_FN_CALL E_UNEXPECTED); - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_If)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT - { - if (condition) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFast_IfFalse)(__RFF_CONDITIONAL_FN_PARAMS bool condition) WI_NOEXCEPT - { - if (!condition) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - return condition; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - __WI_SUPPRESS_NULLPTR_ANALYSIS - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNull)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - return pointer; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __WI_SUPPRESS_NULLPTR_ANALYSIS - __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFast_IfNull)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFast_Unexpected)(__RFF_CONDITIONAL_FN_CALL_ONLY); - } - } - - __RFF_DIRECT_NORET_METHOD(void, FailFast_UnexpectedMsg)(__RFF_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - va_list argList; - va_start(argList, formatString); - __RFF_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__RFF_DIRECT_FN_CALL E_UNEXPECTED, formatString, argList); - } - - __RFF_INTERNAL_NOINLINE_NORET_METHOD(_FailFast_UnexpectedMsg)(__RFF_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) WI_NOEXCEPT - { - __RFF_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__RFF_INTERNAL_NOINLINE_FN_CALL E_UNEXPECTED, formatString, argList); - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (condition) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_METHOD(bool, FailFast_IfFalseMsg)(__RFF_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (!condition) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return condition; - } - - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFast_IfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return pointer; - } - - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, FailFast_IfNullMsg)(__RFF_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) WI_NOEXCEPT - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __RFF_CALL_INTERNAL_NOINLINE_METHOD(_FailFast_UnexpectedMsg)(__RFF_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - } - - //***************************************************************************** - // FailFast Immediate Macros - //***************************************************************************** - - __RFF_DIRECT_NORET_METHOD(void, FailFastImmediate_Unexpected)() WI_NOEXCEPT - { - __fastfail(FAST_FAIL_FATAL_APP_EXIT); - } - - __RFF_INTERNAL_NORET_METHOD(_FailFastImmediate_Unexpected)() WI_NOEXCEPT - { - __fastfail(FAST_FAIL_FATAL_APP_EXIT); - } - - _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(HRESULT, FailFastImmediate_IfFailed)(HRESULT hr) WI_NOEXCEPT - { - if (FAILED(hr)) - { - __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); - } - return hr; - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_If)(bool condition) WI_NOEXCEPT - { - if (condition) - { - __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(bool, FailFastImmediate_IfFalse)(bool condition) WI_NOEXCEPT - { - if (!condition) - { - __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); - } - return condition; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __RFF_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, FailFastImmediate_IfNull)(_Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); - } - return pointer; - } - - // Should be decorated WI_NOEXCEPT, but conflicts with forceinline. - template <__RFF_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __RFF_CONDITIONAL_TEMPLATE_METHOD(void, FailFastImmediate_IfNull)(_In_opt_ const PointerT& pointer) - { - if (pointer == nullptr) - { - __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); - } - } - - _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) - __RFF_CONDITIONAL_METHOD(NTSTATUS, FailFastImmediate_IfNtStatusFailed)(NTSTATUS status) WI_NOEXCEPT - { - if (FAILED_NTSTATUS(status)) - { - __RFF_CALL_INTERNAL_METHOD(_FailFastImmediate_Unexpected)(); - } - return status; - } - } // namespace __RFF_NS_NAME - - namespace __R_NS_NAME - { - //***************************************************************************** - // Exception Macros - //***************************************************************************** - -#ifdef WIL_ENABLE_EXCEPTIONS - __R_DIRECT_NORET_METHOD(void, Throw_Hr)(__R_DIRECT_FN_PARAMS HRESULT hr) - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_DIRECT_FN_CALL hr); - } - - __R_DIRECT_NORET_METHOD(void, Throw_Win32)(__R_DIRECT_FN_PARAMS DWORD err) - { - __R_FN_LOCALS; - wil::details::ReportFailure_Win32(__R_DIRECT_FN_CALL err); - } - - __R_DIRECT_NORET_METHOD(void, Throw_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) - { - __R_FN_LOCALS; - wil::details::ReportFailure_GetLastError(__R_DIRECT_FN_CALL_ONLY); - } - - __R_DIRECT_NORET_METHOD(void, Throw_NtStatus)(__R_DIRECT_FN_PARAMS NTSTATUS status) - { - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatus(__R_DIRECT_FN_CALL status); - } - - __R_DIRECT_NORET_METHOD(void, Throw_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) - { - __R_FN_LOCALS; - wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY); - } - - __R_INTERNAL_NORET_METHOD(_Throw_Hr)(__R_INTERNAL_FN_PARAMS HRESULT hr) - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL hr); - } - - __R_INTERNAL_NORET_METHOD(_Throw_GetLastError)(__R_INTERNAL_FN_PARAMS_ONLY) - { - __R_FN_LOCALS; - wil::details::ReportFailure_GetLastError(__R_INTERNAL_FN_CALL_ONLY); - } - - __R_INTERNAL_NORET_METHOD(_Throw_Win32)(__R_INTERNAL_FN_PARAMS DWORD err) - { - __R_FN_LOCALS; - wil::details::ReportFailure_Win32(__R_INTERNAL_FN_CALL err); - } - - __R_INTERNAL_NORET_METHOD(_Throw_NullAlloc)(__R_INTERNAL_FN_PARAMS_ONLY) - { - __R_FN_LOCALS; - wil::details::ReportFailure_Hr(__R_INTERNAL_FN_CALL E_OUTOFMEMORY); - } - - __R_INTERNAL_NORET_METHOD(_Throw_NtStatus)(__R_INTERNAL_FN_PARAMS NTSTATUS status) - { - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatus(__R_INTERNAL_FN_CALL status); - } - - _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(HRESULT, Throw_IfFailed)(__R_CONDITIONAL_FN_PARAMS HRESULT hr) - { - if (FAILED(hr)) - { - __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); - } - return hr; - } - - _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(BOOL, Throw_IfWin32BoolFalse)(__R_CONDITIONAL_FN_PARAMS BOOL ret) - { - if (!ret) - { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return ret; - } - - _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(DWORD, Throw_IfWin32Error)(__R_CONDITIONAL_FN_PARAMS DWORD err) - { - if (FAILED_WIN32(err)) - { - __R_CALL_INTERNAL_METHOD(_Throw_Win32)(__R_CONDITIONAL_FN_CALL err); - } - return err; - } - - _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(HANDLE, Throw_IfHandleInvalid)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) - { - if (handle == INVALID_HANDLE_VALUE) - { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return handle; - } - - _Post_satisfies_(return == handle) _When_(handle == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(RESULT_NORETURN_NULL HANDLE, Throw_IfHandleNull)(__R_CONDITIONAL_FN_PARAMS HANDLE handle) - { - if (handle == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return handle; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_IfNullAlloc)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer) - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Throw_NullAlloc)(__R_CONDITIONAL_FN_CALL_ONLY); - } - } - - _Post_satisfies_(return == condition) - _When_(condition, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(bool, Throw_HrIf)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) - { - if (condition) - { - __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); - } - return condition; - } - - _Post_satisfies_(return == condition) - _When_(!condition, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(bool, Throw_HrIfFalse)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition) - { - if (!condition) - { - __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); - } - return condition; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); - } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_HrIfNull)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer) - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Throw_Hr)(__R_CONDITIONAL_FN_CALL hr); - } - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(bool, Throw_Win32If)(__R_CONDITIONAL_FN_PARAMS DWORD err, bool condition) - { - if (condition) - { - __R_CALL_INTERNAL_METHOD(_Throw_Win32)(__R_CONDITIONAL_FN_CALL err); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIf)(__R_CONDITIONAL_FN_PARAMS bool condition) - { - if (condition) - { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(bool, Throw_GetLastErrorIfFalse)(__R_CONDITIONAL_FN_PARAMS bool condition) - { - if (!condition) - { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return condition; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer) - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __R_CONDITIONAL_TEMPLATE_METHOD(void, Throw_GetLastErrorIfNull)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer) - { - if (pointer == nullptr) - { - __R_CALL_INTERNAL_METHOD(_Throw_GetLastError)(__R_CONDITIONAL_FN_CALL_ONLY); - } - } - - _Post_satisfies_(return == status) - _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) - __R_CONDITIONAL_METHOD(NTSTATUS, Throw_IfNtStatusFailed)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status) - { - if (FAILED_NTSTATUS(status)) - { - __R_CALL_INTERNAL_METHOD(_Throw_NtStatus)(__R_CONDITIONAL_FN_CALL status); - } - return status; - } - - __R_DIRECT_NORET_METHOD(void, Throw_HrMsg)(__R_DIRECT_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_DIRECT_FN_CALL hr, formatString, argList); - } - - __R_DIRECT_NORET_METHOD(void, Throw_Win32Msg)(__R_DIRECT_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_Win32Msg(__R_DIRECT_FN_CALL err, formatString, argList); - } - - __R_DIRECT_NORET_METHOD(void, Throw_GetLastErrorMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_GetLastErrorMsg(__R_DIRECT_FN_CALL formatString, argList); - } - - __R_DIRECT_NORET_METHOD(void, Throw_NtStatusMsg)(__R_DIRECT_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatusMsg(__R_DIRECT_FN_CALL status, formatString, argList); - } - - __R_DIRECT_NORET_METHOD(void, Throw_CaughtExceptionMsg)(__R_DIRECT_FN_PARAMS _Printf_format_string_ PCSTR formatString, ...) - { - va_list argList; - va_start(argList, formatString); - __R_FN_LOCALS; - wil::details::ReportFailure_CaughtExceptionMsg(__R_DIRECT_FN_CALL formatString, argList); - } - - __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_HrMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, va_list argList) - { - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL hr, formatString, argList); - } - - __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_GetLastErrorMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) - { - __R_FN_LOCALS; - wil::details::ReportFailure_GetLastErrorMsg(__R_INTERNAL_NOINLINE_FN_CALL formatString, argList); - } - - __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_Win32Msg)(__R_INTERNAL_NOINLINE_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, va_list argList) - { - __R_FN_LOCALS; - wil::details::ReportFailure_Win32Msg(__R_INTERNAL_NOINLINE_FN_CALL err, formatString, argList); - } - - __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_NullAllocMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS _Printf_format_string_ PCSTR formatString, va_list argList) - { - __R_FN_LOCALS; - wil::details::ReportFailure_HrMsg(__R_INTERNAL_NOINLINE_FN_CALL E_OUTOFMEMORY, formatString, argList); - } - - __R_INTERNAL_NOINLINE_NORET_METHOD(_Throw_NtStatusMsg)(__R_INTERNAL_NOINLINE_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, va_list argList) - { - __R_FN_LOCALS; - wil::details::ReportFailure_NtStatusMsg(__R_INTERNAL_NOINLINE_FN_CALL status, formatString, argList); - } - - _Post_satisfies_(return == hr) _When_(FAILED(hr), _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(HRESULT, Throw_IfFailedMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Printf_format_string_ PCSTR formatString, ...) - { - if (FAILED(hr)) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - return hr; - } - - _Post_satisfies_(return == ret) _When_(!ret, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(BOOL, Throw_IfWin32BoolFalseMsg)(__R_CONDITIONAL_FN_PARAMS BOOL ret, _Printf_format_string_ PCSTR formatString, ...) - { - if (!ret) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return ret; - } - - _Post_satisfies_(return == err) _When_(FAILED_WIN32(err), _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(DWORD, Throw_IfWin32ErrorMsg)(__R_CONDITIONAL_FN_PARAMS DWORD err, _Printf_format_string_ PCSTR formatString, ...) - { - if (FAILED_WIN32(err)) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); - } - return err; - } - - _Post_satisfies_(return == handle) _When_(handle == INVALID_HANDLE_VALUE, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(HANDLE, Throw_IfHandleInvalidMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) - { - if (handle == INVALID_HANDLE_VALUE) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return handle; - } - - _Post_satisfies_(return == handle) _When_(handle == 0, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(RESULT_NORETURN_NULL HANDLE, Throw_IfHandleNullMsg)(__R_CONDITIONAL_FN_PARAMS HANDLE handle, _Printf_format_string_ PCSTR formatString, ...) - { - if (handle == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return handle; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); - } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __WI_SUPPRESS_NULLPTR_ANALYSIS - _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_IfNullAllocMsg)(__R_CONDITIONAL_FN_PARAMS const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NullAllocMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL_ONLY, formatString, argList); - } - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) - { - if (condition) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_HrIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, bool condition, _Printf_format_string_ PCSTR formatString, ...) - { - if (!condition) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - return condition; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - __WI_SUPPRESS_NULLPTR_ANALYSIS - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __WI_SUPPRESS_NULLPTR_ANALYSIS - _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_HrIfNullMsg)(__R_CONDITIONAL_FN_PARAMS HRESULT hr, _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_HrMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL hr, formatString, argList); - } - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_Win32IfMsg)(__R_CONDITIONAL_FN_PARAMS DWORD err, bool condition, _Printf_format_string_ PCSTR formatString, ...) - { - if (condition) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_Win32Msg)(__R_CONDITIONAL_NOINLINE_FN_CALL err, formatString, argList); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(condition, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_GetLastErrorIfMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) - { - if (condition) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return condition; - } - - _Post_satisfies_(return == condition) _When_(!condition, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(bool, Throw_GetLastErrorIfFalseMsg)(__R_CONDITIONAL_FN_PARAMS bool condition, _Printf_format_string_ PCSTR formatString, ...) - { - if (!condition) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return condition; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_NOT_CLASS(PointerT)> - _Post_satisfies_(return == pointer) _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(RESULT_NORETURN_NULL PointerT, Throw_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _Pre_maybenull_ PointerT pointer, _Printf_format_string_ PCSTR formatString, ...) - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - return pointer; - } - - template <__R_CONDITIONAL_PARTIAL_TEMPLATE typename PointerT, __R_ENABLE_IF_IS_CLASS(PointerT)> - __WI_SUPPRESS_NULLPTR_ANALYSIS - _When_(pointer == nullptr, _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_TEMPLATE_METHOD(void, Throw_GetLastErrorIfNullMsg)(__R_CONDITIONAL_FN_PARAMS _In_opt_ const PointerT& pointer, _Printf_format_string_ PCSTR formatString, ...) - { - if (pointer == nullptr) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_GetLastErrorMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL formatString, argList); - } - } - - _Post_satisfies_(return == status) _When_(FAILED_NTSTATUS(status), _Analysis_noreturn_) - __R_CONDITIONAL_NOINLINE_METHOD(NTSTATUS, Throw_IfNtStatusFailedMsg)(__R_CONDITIONAL_FN_PARAMS NTSTATUS status, _Printf_format_string_ PCSTR formatString, ...) - { - if (FAILED_NTSTATUS(status)) - { - va_list argList; - va_start(argList, formatString); - __R_CALL_INTERNAL_NOINLINE_METHOD(_Throw_NtStatusMsg)(__R_CONDITIONAL_NOINLINE_FN_CALL status, formatString, argList); - } - return status; - } -#endif // WIL_ENABLE_EXCEPTIONS - - } // __R_NS_NAME namespace - } // details namespace - /// @endcond - - - //***************************************************************************** - // Error Handling Policies to switch between error-handling style - //***************************************************************************** - // The following policies are used as template policies for components that can support exception, fail-fast, and - // error-code based modes. - - // Use for classes which should return HRESULTs as their error-handling policy - // Intentionally removed logging from this policy as logging is more useful at the caller. - struct err_returncode_policy - { - using result = HRESULT; - - __forceinline static HRESULT Win32BOOL(BOOL fReturn) { RETURN_IF_WIN32_BOOL_FALSE_EXPECTED(fReturn); return S_OK; } - __forceinline static HRESULT Win32Handle(HANDLE h, _Out_ HANDLE *ph) { *ph = h; RETURN_LAST_ERROR_IF_NULL_EXPECTED(h); return S_OK; } - _Post_satisfies_(return == hr) - __forceinline static HRESULT HResult(HRESULT hr) { return hr; } - __forceinline static HRESULT LastError() { return wil::details::GetLastErrorFailHr(); } - __forceinline static HRESULT LastErrorIfFalse(bool condition) { RETURN_LAST_ERROR_IF_EXPECTED(!condition); return S_OK; } - _Post_satisfies_(return == S_OK) - __forceinline static HRESULT OK() { return S_OK; } - }; - - // Use for classes which fail-fast on errors - struct err_failfast_policy - { - typedef _Return_type_success_(true) void result; - __forceinline static result Win32BOOL(BOOL fReturn) { FAIL_FAST_IF_WIN32_BOOL_FALSE(fReturn); } - __forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE *ph) { *ph = h; FAIL_FAST_LAST_ERROR_IF_NULL(h); } - _When_(FAILED(hr), _Analysis_noreturn_) - __forceinline static result HResult(HRESULT hr) { FAIL_FAST_IF_FAILED(hr); } - __forceinline static result LastError() { FAIL_FAST_LAST_ERROR(); } - __forceinline static result LastErrorIfFalse(bool condition) { if (!condition) { FAIL_FAST_LAST_ERROR(); } } - __forceinline static result OK() {} - }; - -#ifdef WIL_ENABLE_EXCEPTIONS - // Use for classes which should return through exceptions as their error-handling policy - struct err_exception_policy - { - typedef _Return_type_success_(true) void result; - __forceinline static result Win32BOOL(BOOL fReturn) { THROW_IF_WIN32_BOOL_FALSE(fReturn); } - __forceinline static result Win32Handle(HANDLE h, _Out_ HANDLE *ph) { *ph = h; THROW_LAST_ERROR_IF_NULL(h); } - _When_(FAILED(hr), _Analysis_noreturn_) - __forceinline static result HResult(HRESULT hr) { THROW_IF_FAILED(hr); } - __forceinline static result LastError() { THROW_LAST_ERROR(); } - __forceinline static result LastErrorIfFalse(bool condition) { if (!condition) { THROW_LAST_ERROR(); } } - __forceinline static result OK() {} - }; -#else - // NOTE: A lot of types use 'err_exception_policy' as a default template argument and therefore it must be defined - // (MSVC is permissive about this, but other compilers are not). This will still cause compilation errors at - // template instantiation time since this type lacks required member functions. An alternative would be to have some - // 'default_err_policy' alias that would be something like 'err_failfast_policy' when exceptions are not available, - // but that may have unexpected side effects when compiling code that expects to be using exceptions - struct err_exception_policy - { - }; -#endif - -} // namespace wil - -#pragma warning(pop) - -#endif // defined(__cplusplus) && !defined(__WIL_MIN_KERNEL) && !defined(WIL_KERNEL_MODE) -#endif // __WIL_RESULTMACROS_INCLUDED diff --git a/src/common/dep/wil/result_originate.h b/src/common/dep/wil/result_originate.h deleted file mode 100644 index 02badba54..000000000 --- a/src/common/dep/wil/result_originate.h +++ /dev/null @@ -1,126 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* - -// Note: When origination is enabled by including this file, origination is done as part of the RETURN_* and THROW_* macros. Before originating -// a new error we will observe whether there is already an error payload associated with the current thread. If there is, and the HRESULTs match, -// then a new error will not be originated. Otherwise we will overwrite it with a new origination. The ABI boundary for WinRT APIs will check the -// per-thread error information. The act of checking the error clears it, so there should be minimal risk of failing to originate distinct errors -// simply because the HRESULTs match. -// -// For THROW_ macros we will examine the thread-local error storage once per throw. So typically once, with additional calls if the exception is -// caught and re-thrown. -// -// For RETURN_ macros we will have to examine the thread-local error storage once per frame as the call stack unwinds. Because error conditions -// -should- be uncommon the performance impact of checking TLS should be minimal. The more expensive part is originating the error because it must -// capture the entire stack and some additional data. - -#ifndef __WIL_RESULT_ORIGINATE_INCLUDED -#define __WIL_RESULT_ORIGINATE_INCLUDED - -#include "result.h" -#include // RestrictedErrorInfo uses BSTRs :( -#include -#include "resource.h" -#include "com.h" -#include - -namespace wil -{ - namespace details - { - // Note: The name must begin with "Raise" so that the !analyze auto-bucketing will ignore this stack frame. Otherwise this line of code gets all the blame. - inline void __stdcall RaiseRoOriginateOnWilExceptions(wil::FailureInfo const& failure) WI_NOEXCEPT - { - if ((failure.type == FailureType::Return) || (failure.type == FailureType::Exception)) - { - bool shouldOriginate = true; - - wil::com_ptr_nothrow restrictedErrorInformation; - if (GetRestrictedErrorInfo(&restrictedErrorInformation) == S_OK) - { - // This thread already has an error origination payload. Don't originate again if it has the same HRESULT that we are - // observing right now. - wil::unique_bstr descriptionUnused; - HRESULT existingHr = failure.hr; - wil::unique_bstr restrictedDescriptionUnused; - wil::unique_bstr capabilitySidUnused; - if (SUCCEEDED(restrictedErrorInformation->GetErrorDetails(&descriptionUnused, &existingHr, &restrictedDescriptionUnused, &capabilitySidUnused))) - { - shouldOriginate = (failure.hr != existingHr); - } - } - - if (shouldOriginate) - { -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) - wil::unique_hmodule errorModule; - if (GetModuleHandleExW(0, L"api-ms-win-core-winrt-error-l1-1-1.dll", &errorModule)) - { - auto pfn = reinterpret_cast(GetProcAddress(errorModule.get(), "RoOriginateErrorW")); - if (pfn != nullptr) - { - pfn(failure.hr, 0, failure.pszMessage); - } - } -#else // DESKTOP | SYSTEM - ::RoOriginateErrorW(failure.hr, 0, failure.pszMessage); -#endif // DESKTOP | SYSTEM - } - else if (restrictedErrorInformation) - { - // GetRestrictedErrorInfo returns ownership of the error information. If we aren't originating, and an error was already present, - // then we need to restore the error information for later observation. - SetRestrictedErrorInfo(restrictedErrorInformation.get()); - } - } - } - - // This method will check for the presence of stowed exception data on the current thread. If such data exists, and the HRESULT - // matches the current failure, then we will call RoFailFastWithErrorContext. RoFailFastWithErrorContext in this situation will - // result in -VASTLY- improved crash bucketing. It is hard to express just how much better. In other cases we just return and - // the calling method fails fast the same way it always has. - inline void __stdcall FailfastWithContextCallback(wil::FailureInfo const& failure) WI_NOEXCEPT - { - wil::com_ptr_nothrow restrictedErrorInformation; - if (GetRestrictedErrorInfo(&restrictedErrorInformation) == S_OK) - { - wil::unique_bstr descriptionUnused; - HRESULT existingHr = failure.hr; - wil::unique_bstr restrictedDescriptionUnused; - wil::unique_bstr capabilitySidUnused; - if (SUCCEEDED(restrictedErrorInformation->GetErrorDetails(&descriptionUnused, &existingHr, &restrictedDescriptionUnused, &capabilitySidUnused)) && - (existingHr == failure.hr)) - { - // GetRestrictedErrorInfo returns ownership of the error information. We want it to be available for RoFailFastWithErrorContext - // so we must restore it via SetRestrictedErrorInfo first. - SetRestrictedErrorInfo(restrictedErrorInformation.get()); - RoFailFastWithErrorContext(existingHr); - } - else - { - // The error didn't match the current failure. Put it back in thread-local storage even though we aren't failing fast - // in this method, so it is available in the debugger just-in-case. - SetRestrictedErrorInfo(restrictedErrorInformation.get()); - } - } - } - } // namespace details -} // namespace wil - -// Automatically call RoOriginateError upon error origination by including this file -WI_HEADER_INITITALIZATION_FUNCTION(ResultStowedExceptionInitialize, [] -{ - ::wil::SetOriginateErrorCallback(::wil::details::RaiseRoOriginateOnWilExceptions); - ::wil::SetFailfastWithContextCallback(::wil::details::FailfastWithContextCallback); - return 1; -}) - -#endif // __WIL_RESULT_ORIGINATE_INCLUDED diff --git a/src/common/dep/wil/rpc_helpers.h b/src/common/dep/wil/rpc_helpers.h deleted file mode 100644 index 63fd97b5d..000000000 --- a/src/common/dep/wil/rpc_helpers.h +++ /dev/null @@ -1,206 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_RPC_HELPERS_INCLUDED -#define __WIL_RPC_HELPERS_INCLUDED - -#include "result.h" -#include "resource.h" -#include "wistd_functional.h" -#include "wistd_type_traits.h" - -namespace wil -{ - - /// @cond - namespace details - { - // This call-adapter template converts a void-returning 'wistd::invoke' into - // an HRESULT-returning 'wistd::invoke' that emits S_OK. It can be eliminated - // with 'if constexpr' when C++17 is in wide use. - template struct call_adapter - { - template static HRESULT call(TArgs&& ... args) - { - return wistd::invoke(wistd::forward(args)...); - } - }; - - template<> struct call_adapter - { - template static HRESULT call(TArgs&& ... args) - { - wistd::invoke(wistd::forward(args)...); - return S_OK; - } - }; - - // Some RPC exceptions are already HRESULTs. Others are in the regular Win32 - // error space. If the incoming exception code isn't an HRESULT, wrap it. - constexpr HRESULT map_rpc_exception(DWORD code) - { - return IS_ERROR(code) ? code : __HRESULT_FROM_WIN32(code); - } - } - /// @endcond - - /** Invokes an RPC method, mapping structured exceptions to HRESULTs - Failures encountered by the RPC infrastructure (such as server crashes, authentication - errors, client parameter issues, etc.) are emitted by raising a structured exception from - within the RPC machinery. This method wraps the requested call in the usual RpcTryExcept, - RpcTryCatch, and RpcEndExcept sequence then maps the exceptions to HRESULTs for the usual - flow control machinery to use. - - Many RPC methods are defined as returning HRESULT themselves, where the HRESULT indicates - the result of the _work_. HRESULTs returned by a successful completion of the _call_ are - returned as-is. - - RPC methods that have a return type of 'void' are mapped to returning S_OK when the _call_ - completes successfully. - - For example, consider an RPC interface method defined in idl as: - ~~~ - HRESULT GetKittenState([in, ref, string] const wchar_t* name, [out, retval] KittenState** state); - ~~~ - To call this method, use: - ~~~ - wil::unique_rpc_binding binding = // typically gotten elsewhere; - wil::unique_midl_ptr state; - HRESULT hr = wil::invoke_rpc_nothrow(GetKittenState, binding.get(), L"fluffy", state.put()); - RETURN_IF_FAILED(hr); - ~~~ - */ - template HRESULT invoke_rpc_nothrow(TCall&&... args) WI_NOEXCEPT - { - RpcTryExcept - { - // Note: this helper type can be removed with C++17 enabled via - // 'if constexpr(wistd::is_same_v)' - using result_t = typename wistd::__invoke_of::type; - RETURN_IF_FAILED(details::call_adapter::call(wistd::forward(args)...)); - return S_OK; - } - RpcExcept(RpcExceptionFilter(RpcExceptionCode())) - { - RETURN_HR(details::map_rpc_exception(RpcExceptionCode())); - } - RpcEndExcept - } - - /** Invokes an RPC method, mapping structured exceptions to HRESULTs - Failures encountered by the RPC infrastructure (such as server crashes, authentication - errors, client parameter issues, etc.) are emitted by raising a structured exception from - within the RPC machinery. This method wraps the requested call in the usual RpcTryExcept, - RpcTryCatch, and RpcEndExcept sequence then maps the exceptions to HRESULTs for the usual - flow control machinery to use. - - Some RPC methods return results (such as a state enumeration or other value) directly in - their signature. This adapter writes that result into a caller-provided object then - returns S_OK. - - For example, consider an RPC interface method defined in idl as: - ~~~ - GUID GetKittenId([in, ref, string] const wchar_t* name); - ~~~ - To call this method, use: - ~~~ - wil::unique_rpc_binding binding = // typically gotten elsewhere; - GUID id; - HRESULT hr = wil::invoke_rpc_result_nothrow(id, GetKittenId, binding.get(), L"fluffy"); - RETURN_IF_FAILED(hr); - ~~~ - */ - template HRESULT invoke_rpc_result_nothrow(TResult& result, TCall&&... args) WI_NOEXCEPT - { - RpcTryExcept - { - result = wistd::invoke(wistd::forward(args)...); - return S_OK; - } - RpcExcept(RpcExceptionFilter(RpcExceptionCode())) - { - RETURN_HR(details::map_rpc_exception(RpcExceptionCode())); - } - RpcEndExcept - } - - namespace details - { - // Provides an adapter around calling the context-handle-close method on an - // RPC interface, which itself is an RPC call. - template - struct rpc_closer_t - { - static void Close(TStorage arg) WI_NOEXCEPT - { - LOG_IF_FAILED(invoke_rpc_nothrow(close_fn, &arg)); - } - }; - } - - /** Manages explicit RPC context handles - Explicit RPC context handles are used in many RPC interfaces. Most interfaces with - context handles have an explicit `FooClose([in, out] CONTEXT*)` method that lets - the server close out the context handle. As the close method itself is an RPC call, - it can fail and raise a structured exception. - - This type routes the context-handle-specific `Close` call through the `invoke_rpc_nothrow` - helper, ensuring correct cleanup and lifecycle management. - ~~~ - // Assume the interface has two methods: - // HRESULT OpenFoo([in] handle_t binding, [out] FOO_CONTEXT*); - // HRESULT UseFoo([in] FOO_CONTEXT context; - // void CloseFoo([in, out] PFOO_CONTEXT); - using unique_foo_context = wil::unique_rpc_context_handle; - unique_foo_context context; - RETURN_IF_FAILED(wil::invoke_rpc_nothrow(OpenFoo, m_binding.get(), context.put())); - RETURN_IF_FAILED(wil::invoke_rpc_nothrow(UseFoo, context.get())); - context.reset(); - ~~~ - */ - template - using unique_rpc_context_handle = unique_any::Close), details::rpc_closer_t::Close>; - -#ifdef WIL_ENABLE_EXCEPTIONS - /** Invokes an RPC method, mapping structured exceptions to C++ exceptions - See `wil::invoke_rpc_nothrow` for additional information. Failures during the _call_ - and those returned by the _method_ are mapped to HRESULTs and thrown inside a - wil::ResultException. Using the example RPC method provided above: - ~~~ - wil::unique_midl_ptr state; - wil::invoke_rpc(GetKittenState, binding.get(), L"fluffy", state.put()); - // use 'state' - ~~~ - */ - template void invoke_rpc(TCall&& ... args) - { - THROW_IF_FAILED(invoke_rpc_nothrow(wistd::forward(args)...)); - } - - /** Invokes an RPC method, mapping structured exceptions to C++ exceptions - See `wil::invoke_rpc_result_nothrow` for additional information. Failures during the - _call_ are mapped to HRESULTs and thrown inside a `wil::ResultException`. Using the - example RPC method provided above: - ~~~ - GUID id = wil::invoke_rpc_result(GetKittenId, binding.get()); - // use 'id' - ~~~ - */ - template auto invoke_rpc_result(TCall&& ... args) - { - using result_t = typename wistd::__invoke_of::type; - result_t result{}; - THROW_IF_FAILED(invoke_rpc_result_nothrow(result, wistd::forward(args)...)); - return result; - } -#endif -} - -#endif diff --git a/src/common/dep/wil/safecast.h b/src/common/dep/wil/safecast.h deleted file mode 100644 index 3fa6d7e61..000000000 --- a/src/common/dep/wil/safecast.h +++ /dev/null @@ -1,369 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_SAFECAST_INCLUDED -#define __WIL_SAFECAST_INCLUDED - -#include "result_macros.h" -#include -#include "wistd_config.h" -#include "wistd_type_traits.h" - -namespace wil -{ - namespace details - { - // Default error case for undefined conversions in intsafe.h - template constexpr wistd::nullptr_t intsafe_conversion = nullptr; - - // is_known_safe_static_cast_v determines if a conversion is known to be safe or not. Known - // safe conversions can be handled by static_cast, this includes conversions between the same - // type, when the new type is larger than the old type but is not a signed to unsigned - // conversion, and when the two types are the same size and signed/unsigned. All other - // conversions will be assumed to be potentially unsafe, and the conversion must be handled - // by intsafe and checked. - template - constexpr bool is_known_safe_static_cast_v = - (sizeof(NewT) > sizeof(OldT) && !(wistd::is_signed_v && wistd::is_unsigned_v)) || - (sizeof(NewT) == sizeof(OldT) && ((wistd::is_signed_v && wistd::is_signed_v) || (wistd::is_unsigned_v && wistd::is_unsigned_v))); - - // Helper template to determine that NewT and OldT are both integral types. The safe_cast - // operation only supports conversions between integral types. - template - constexpr bool both_integral_v = wistd::is_integral::value && wistd::is_integral::value; - - // Note on native wchar_t (__wchar_t): - // Intsafe.h does not currently handle native wchar_t. When compiling with /Zc:wchar_t-, this is fine as wchar_t is - // typedef'd to unsigned short. However, when compiling with /Zc:wchar_t or wchar_t as a native type, the lack of - // support for native wchar_t in intsafe.h becomes an issue. To work around this, we treat native wchar_t as an - // unsigned short when passing it to intsafe.h, because the two on the Windows platform are the same size and - // share the same range according to MSDN. If the cast is to a native wchar_t, the result from intsafe.h is cast - // to a native wchar_t. - - // Intsafe does not have a defined conversion for native wchar_t - template - constexpr bool neither_native_wchar_v = !wistd::is_same::value && !wistd::is_same::value; - - // Check to see if the cast is a conversion to native wchar_t - template - constexpr bool is_cast_to_wchar_v = wistd::is_same::value && !wistd::is_same::value; - - // Check to see if the cast is a conversion from native wchar_t - template - constexpr bool is_cast_from_wchar_v = !wistd::is_same::value && wistd::is_same::value; - - // Validate the conversion to be performed has a defined mapping to an intsafe conversion - template - constexpr bool is_supported_intsafe_cast_v = intsafe_conversion != nullptr; - - // True when the conversion is between integral types and can be handled by static_cast - template - constexpr bool is_supported_safe_static_cast_v = both_integral_v && is_known_safe_static_cast_v; - - // True when the conversion is between integral types, does not involve native wchar, has - // a mapped intsafe conversion, and is unsafe. - template - constexpr bool is_supported_unsafe_cast_no_wchar_v = - both_integral_v && - !is_known_safe_static_cast_v && - neither_native_wchar_v && - is_supported_intsafe_cast_v; - - // True when the conversion is between integral types, is a cast to native wchar_t, has - // a mapped intsafe conversion, and is unsafe. - template - constexpr bool is_supported_unsafe_cast_to_wchar_v = - both_integral_v && - !is_known_safe_static_cast_v && - is_cast_to_wchar_v && - is_supported_intsafe_cast_v; - - // True when the conversion is between integral types, is a cast from native wchar_t, has - // a mapped intsafe conversion, and is unsafe. - template - constexpr bool is_supported_unsafe_cast_from_wchar_v = - both_integral_v && - !is_known_safe_static_cast_v && - is_cast_from_wchar_v && - is_supported_intsafe_cast_v; - - // True when the conversion is supported and unsafe, and may or may not involve - // native wchar_t. - template - constexpr bool is_supported_unsafe_cast_v = - is_supported_unsafe_cast_no_wchar_v || - is_supported_unsafe_cast_to_wchar_v || - is_supported_unsafe_cast_from_wchar_v; - - // True when T is any one of the primitive types that the variably sized types are defined as. - template - constexpr bool is_potentially_variably_sized_type_v = - wistd::is_same::value || - wistd::is_same::value || - wistd::is_same::value || - wistd::is_same::value || - wistd::is_same::value || - wistd::is_same::value; - - // True when either type is potentialy variably sized (e.g. size_t, ptrdiff_t) - template - constexpr bool is_potentially_variably_sized_cast_v = - is_potentially_variably_sized_type_v || - is_potentially_variably_sized_type_v; - - // Mappings of all conversions defined in intsafe.h to intsafe_conversion - // Note: Uppercase types (UINT, DWORD, SIZE_T, etc) and architecture dependent types resolve - // to the base types. The base types are used since they do not vary based on architecture. - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, char> = LongLongToChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, int> = LongLongToInt; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, long> = LongLongToLong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, short> = LongLongToShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, signed char> = LongLongToInt8; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned __int64> = LongLongToULongLong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned char> = LongLongToUChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned int> = LongLongToUInt; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned long> = LongLongToULong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion<__int64, unsigned short> = LongLongToUShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToInt8; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToULongLong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToUChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToUInt; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToULong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = IntToUShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToInt; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToInt8; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToULongLong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToUChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToUInt; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToULong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = LongToUShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToInt8; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToULongLong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToUChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToUInt; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToULong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ShortToUShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToULongLong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToUChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToUInt; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToULong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = Int8ToUShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToLongLong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToInt; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToLong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToInt8; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToUChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToUInt; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToULong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongLongToUShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UInt8ToChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToInt8; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToInt; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToLong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToInt8; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToUChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UIntToUShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToInt; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToLong; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToInt8; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToUChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToUInt; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = ULongToUShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UShortToChar; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UShortToShort; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UShortToInt8; - template<> __WI_LIBCPP_INLINE_VAR constexpr auto intsafe_conversion = UShortToUChar; - } - - // Unsafe conversion where failure results in fail fast. - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - NewT safe_cast_failfast(const OldT var) - { - NewT newVar; - FAIL_FAST_IF_FAILED((details::intsafe_conversion(var, &newVar))); - return newVar; - } - - // Unsafe conversion where failure results in fail fast. - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - NewT safe_cast_failfast(const OldT var) - { - NewT newVar; - FAIL_FAST_IF_FAILED((details::intsafe_conversion(static_cast(var), &newVar))); - return newVar; - } - - // Unsafe conversion where failure results in fail fast. - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - NewT safe_cast_failfast(const OldT var) - { - unsigned short newVar; - FAIL_FAST_IF_FAILED((details::intsafe_conversion(var, &newVar))); - return static_cast<__wchar_t>(newVar); - } - - // This conversion is always safe, therefore a static_cast is fine. - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - NewT safe_cast_failfast(const OldT var) - { - return static_cast(var); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - // Unsafe conversion where failure results in a thrown exception. - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - NewT safe_cast(const OldT var) - { - NewT newVar; - THROW_IF_FAILED((details::intsafe_conversion(var, &newVar))); - return newVar; - } - - // Unsafe conversion where failure results in a thrown exception. - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - NewT safe_cast(const OldT var) - { - NewT newVar; - THROW_IF_FAILED((details::intsafe_conversion(static_cast(var), &newVar))); - return newVar; - } - - // Unsafe conversion where failure results in a thrown exception. - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - NewT safe_cast(const OldT var) - { - unsigned short newVar; - THROW_IF_FAILED((details::intsafe_conversion(var, &newVar))); - return static_cast<__wchar_t>(newVar); - } - - // This conversion is always safe, therefore a static_cast is fine. - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - NewT safe_cast(const OldT var) - { - return static_cast(var); - } -#endif - - // This conversion is unsafe, therefore the two parameter version of safe_cast_nothrow must be used - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - NewT safe_cast_nothrow(const OldT /*var*/) - { - static_assert(!wistd::is_same_v, "This cast has the potential to fail, use the two parameter safe_cast_nothrow instead"); - } - - // This conversion is always safe, therefore a static_cast is fine. - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - NewT safe_cast_nothrow(const OldT var) - { - return static_cast(var); - } - - // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) - { - return details::intsafe_conversion(var, newTResult); - } - - // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) - { - return details::intsafe_conversion(static_cast(var), newTResult); - } - - // Unsafe conversion where an HRESULT is returned. It is up to the callee to check and handle the HRESULT - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) - { - return details::intsafe_conversion(var, reinterpret_cast(newTResult)); - } - - // This conversion is always safe, therefore a static_cast is fine. If it can be determined the conversion - // does not involve a variably sized type, then the compilation will fail and say the single parameter version - // of safe_cast_nothrow should be used instead. - template < - typename NewT, - typename OldT, - wistd::enable_if_t, int> = 0 - > - HRESULT safe_cast_nothrow(const OldT var, NewT* newTResult) - { - static_assert(details::is_potentially_variably_sized_cast_v, "This cast is always safe; use safe_cast_nothrow(value) to avoid unnecessary error handling."); - *newTResult = static_cast(var); - return S_OK; - } -} - -#endif // __WIL_SAFECAST_INCLUDED diff --git a/src/common/dep/wil/stl.h b/src/common/dep/wil/stl.h deleted file mode 100644 index dd50530d9..000000000 --- a/src/common/dep/wil/stl.h +++ /dev/null @@ -1,196 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_STL_INCLUDED -#define __WIL_STL_INCLUDED - -#include "common.h" -#include "resource.h" -#include -#include -#include -#include -#if _HAS_CXX17 -#include -#endif - -#ifndef WI_STL_FAIL_FAST_IF -#define WI_STL_FAIL_FAST_IF FAIL_FAST_IF -#endif - -#if defined(WIL_ENABLE_EXCEPTIONS) - -namespace wil -{ - /** Secure allocator for STL containers. - The `wil::secure_allocator` allocator calls `SecureZeroMemory` before deallocating - memory. This provides a mechanism for secure STL containers such as `wil::secure_vector`, - `wil::secure_string`, and `wil::secure_wstring`. */ - template - struct secure_allocator - : public std::allocator - { - template - struct rebind - { - using other = secure_allocator; - }; - - secure_allocator() - : std::allocator() - { - } - - ~secure_allocator() = default; - - secure_allocator(const secure_allocator& a) - : std::allocator(a) - { - } - - template - secure_allocator(const secure_allocator& a) - : std::allocator(a) - { - } - - T* allocate(size_t n) - { - return std::allocator::allocate(n); - } - - void deallocate(T* p, size_t n) - { - SecureZeroMemory(p, sizeof(T) * n); - std::allocator::deallocate(p, n); - } - }; - - //! `wil::secure_vector` will be securely zeroed before deallocation. - template - using secure_vector = std::vector>; - //! `wil::secure_wstring` will be securely zeroed before deallocation. - using secure_wstring = std::basic_string, wil::secure_allocator>; - //! `wil::secure_string` will be securely zeroed before deallocation. - using secure_string = std::basic_string, wil::secure_allocator>; - - /// @cond - namespace details - { - template<> struct string_maker - { - HRESULT make(_In_reads_opt_(length) PCWSTR source, size_t length) WI_NOEXCEPT try - { - m_value = source ? std::wstring(source, length) : std::wstring(length, L'\0'); - return S_OK; - } - catch (...) - { - return E_OUTOFMEMORY; - } - - wchar_t* buffer() { return &m_value[0]; } - - HRESULT trim_at_existing_null(size_t length) { m_value.erase(length); return S_OK; } - - std::wstring release() { return std::wstring(std::move(m_value)); } - - static PCWSTR get(const std::wstring& value) { return value.c_str(); } - - private: - std::wstring m_value; - }; - } - /// @endcond - - // str_raw_ptr is an overloaded function that retrieves a const pointer to the first character in a string's buffer. - // This is the overload for std::wstring. Other overloads available in resource.h. - inline PCWSTR str_raw_ptr(const std::wstring& str) - { - return str.c_str(); - } - -#if _HAS_CXX17 - /** - zstring_view. A zstring_view is identical to a std::string_view except it is always nul-terminated (unless empty). - * zstring_view can be used for storing string literals without "forgetting" the length or that it is nul-terminated. - * A zstring_view can be converted implicitly to a std::string_view because it is always safe to use a nul-terminated - string_view as a plain string view. - * A zstring_view can be constructed from a std::string because the data in std::string is nul-terminated. - */ - template - class basic_zstring_view : public std::basic_string_view - { - using size_type = typename std::basic_string_view::size_type; - - public: - constexpr basic_zstring_view() noexcept = default; - constexpr basic_zstring_view(const basic_zstring_view&) noexcept = default; - constexpr basic_zstring_view& operator=(const basic_zstring_view&) noexcept = default; - - constexpr basic_zstring_view(const TChar* pStringData, size_type stringLength) noexcept - : std::basic_string_view(pStringData, stringLength) - { - if (pStringData[stringLength] != 0) { WI_STL_FAIL_FAST_IF(true); } - } - - template - constexpr basic_zstring_view(const TChar(&stringArray)[stringArrayLength]) noexcept - : std::basic_string_view(&stringArray[0], length_n(&stringArray[0], stringArrayLength)) - { - } - - // Construct from nul-terminated char ptr. To prevent this from overshadowing array construction, - // we disable this constructor if the value is an array (including string literal). - template::value && !std::is_array::value>* = nullptr> - constexpr basic_zstring_view(TPtr&& pStr) noexcept - : std::basic_string_view(std::forward(pStr)) {} - - constexpr basic_zstring_view(const std::basic_string& str) noexcept - : std::basic_string_view(&str[0], str.size()) {} - - // basic_string_view [] precondition won't let us read view[view.size()]; so we define our own. - WI_NODISCARD constexpr const TChar& operator[](size_type idx) const noexcept - { - WI_ASSERT(idx <= this->size() && this->data() != nullptr); - return this->data()[idx]; - } - - WI_NODISCARD constexpr const TChar* c_str() const noexcept - { - WI_ASSERT(this->data() == nullptr || this->data()[this->size()] == 0); - return this->data(); - } - - private: - // Bounds-checked version of char_traits::length, like strnlen. Requires that the input contains a null terminator. - static constexpr size_type length_n(_In_reads_opt_(buf_size) const TChar* str, size_type buf_size) noexcept - { - const std::basic_string_view view(str, buf_size); - auto pos = view.find_first_of(TChar()); - if (pos == view.npos) { WI_STL_FAIL_FAST_IF(true); } - return pos; - } - - // The following basic_string_view methods must not be allowed because they break the nul-termination. - using std::basic_string_view::swap; - using std::basic_string_view::remove_suffix; - }; - - using zstring_view = basic_zstring_view; - using zwstring_view = basic_zstring_view; -#endif // _HAS_CXX17 - -} // namespace wil - -#endif // WIL_ENABLE_EXCEPTIONS - -#endif // __WIL_STL_INCLUDED diff --git a/src/common/dep/wil/token_helpers.h b/src/common/dep/wil/token_helpers.h deleted file mode 100644 index 624f6ee08..000000000 --- a/src/common/dep/wil/token_helpers.h +++ /dev/null @@ -1,613 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_TOKEN_HELPERS_INCLUDED -#define __WIL_TOKEN_HELPERS_INCLUDED - -#ifdef _KERNEL_MODE -#error This header is not supported in kernel-mode. -#endif - -#include "resource.h" -#include -#include // for UNLEN and DNLEN -#include - -// for GetUserNameEx() -#ifndef SECURITY_WIN32 -#define SECURITY_WIN32 -#endif -#include - -namespace wil -{ - /// @cond - namespace details - { - // Template specialization for TOKEN_INFORMATION_CLASS, add more mappings here as needed - // TODO: The mapping should be reversed to be MapTokenInfoClassToStruct since there may - // be an info class value that uses the same structure. That is the case for the file - // system information. - template struct MapTokenStructToInfoClass; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenAccessInformation; static constexpr bool FixedSize = false; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenAppContainerSid; static constexpr bool FixedSize = false; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenDefaultDacl; static constexpr bool FixedSize = false; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenGroupsAndPrivileges; static constexpr bool FixedSize = false; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenIntegrityLevel; static constexpr bool FixedSize = false; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenOwner; static constexpr bool FixedSize = false; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenPrimaryGroup; static constexpr bool FixedSize = false; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenPrivileges; static constexpr bool FixedSize = false; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenUser; static constexpr bool FixedSize = false; }; - - // fixed size cases - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenElevationType; static constexpr bool FixedSize = true; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenMandatoryPolicy; static constexpr bool FixedSize = true; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenOrigin; static constexpr bool FixedSize = true; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenSource; static constexpr bool FixedSize = true; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenStatistics; static constexpr bool FixedSize = true; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenType; static constexpr bool FixedSize = true; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenImpersonationLevel; static constexpr bool FixedSize = true; }; - template<> struct MapTokenStructToInfoClass { static constexpr TOKEN_INFORMATION_CLASS infoClass = TokenElevation; static constexpr bool FixedSize = true; }; - - struct token_info_deleter - { - template void operator()(T* p) const - { - static_assert(wistd::is_trivially_destructible_v, "do not use with nontrivial types"); - ::operator delete(p); - } - }; - } - /// @endcond - - enum class OpenThreadTokenAs - { - Current, - Self - }; - - /** Open the active token. - Opens either the current thread token (if impersonating) or the current process token. Returns a token the caller - can use with methods like get_token_information<> below. By default, the token is opened for TOKEN_QUERY and as the - effective user. - - Consider using GetCurrentThreadEffectiveToken() instead of this method when eventually calling get_token_information. - This method returns a real handle to the effective token, but GetCurrentThreadEffectiveToken() is a Pseudo-handle - and much easier to manage. - ~~~~ - wil::unique_handle theToken; - RETURN_IF_FAILED(wil::open_current_access_token_nothrow(&theToken)); - ~~~~ - Callers who want more access to the token (such as to duplicate or modify the token) can pass - any mask of the token rights. - ~~~~ - wil::unique_handle theToken; - RETURN_IF_FAILED(wil::open_current_access_token_nothrow(&theToken, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES)); - ~~~~ - Services impersonating their clients may need to request that the active token is opened on the - behalf of the service process to perform certain operations. Opening a token for impersonation access - or privilege-adjustment are examples of uses. - ~~~~ - wil::unique_handle callerToken; - RETURN_IF_FAILED(wil::open_current_access_token_nothrow(&theToken, TOKEN_QUERY | TOKEN_IMPERSONATE, OpenThreadTokenAs::Self)); - ~~~~ - @param tokenHandle Receives the token opened during the operation. Must be CloseHandle'd by the caller, or - (preferably) stored in a wil::unique_handle - @param access Bits from the TOKEN_* access mask which are passed to OpenThreadToken/OpenProcessToken - @param openAs Current to use current thread security context, or Self to use process security context. - */ - inline HRESULT open_current_access_token_nothrow(_Out_ HANDLE* tokenHandle, unsigned long access = TOKEN_QUERY, OpenThreadTokenAs openAs = OpenThreadTokenAs::Current) - { - HRESULT hr = (OpenThreadToken(GetCurrentThread(), access, (openAs == OpenThreadTokenAs::Self), tokenHandle) ? S_OK : HRESULT_FROM_WIN32(::GetLastError())); - if (hr == HRESULT_FROM_WIN32(ERROR_NO_TOKEN)) - { - hr = (OpenProcessToken(GetCurrentProcess(), access, tokenHandle) ? S_OK : HRESULT_FROM_WIN32(::GetLastError())); - } - return hr; - } - - //! Current thread or process token, consider using GetCurrentThreadEffectiveToken() instead. - inline wil::unique_handle open_current_access_token_failfast(unsigned long access = TOKEN_QUERY, OpenThreadTokenAs openAs = OpenThreadTokenAs::Current) - { - HANDLE rawTokenHandle; - FAIL_FAST_IF_FAILED(open_current_access_token_nothrow(&rawTokenHandle, access, openAs)); - return wil::unique_handle(rawTokenHandle); - } - -// Exception based function to open current thread/process access token and acquire pointer to it -#ifdef WIL_ENABLE_EXCEPTIONS - //! Current thread or process token, consider using GetCurrentThreadEffectiveToken() instead. - inline wil::unique_handle open_current_access_token(unsigned long access = TOKEN_QUERY, OpenThreadTokenAs openAs = OpenThreadTokenAs::Current) - { - HANDLE rawTokenHandle; - THROW_IF_FAILED(open_current_access_token_nothrow(&rawTokenHandle, access, openAs)); - return wil::unique_handle(rawTokenHandle); - } -#endif // WIL_ENABLE_EXCEPTIONS - -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - - // Returns tokenHandle or the effective thread token if tokenHandle is null. - // Note, this returns an token handle who's lifetime is managed independently - // and it may be a pseudo token, don't free it! - inline HANDLE GetCurrentThreadEffectiveTokenWithOverride(HANDLE tokenHandle) - { - return tokenHandle ? tokenHandle : GetCurrentThreadEffectiveToken(); - } - - /** Fetches information about a token. - See GetTokenInformation on MSDN for what this method can return. For variable sized structs the information - is returned to the caller as a wil::unique_tokeninfo_ptr (like TOKEN_ORIGIN, TOKEN_USER, TOKEN_ELEVATION, etc.). For - fixed sized, the struct is returned directly. - The caller must have access to read the information from the provided token. This method works with both real - (e.g. OpenCurrentAccessToken) and pseudo (e.g. GetCurrentThreadToken) token handles. - ~~~~ - // Retrieve the TOKEN_USER structure for the current process - wil::unique_tokeninfo_ptr user; - RETURN_IF_FAILED(wil::get_token_information_nothrow(user, GetCurrentProcessToken())); - RETURN_IF_FAILED(ConsumeSid(user->User.Sid)); - ~~~~ - Not specifying the token handle is the same as specifying 'nullptr' and retrieves information about the effective token. - ~~~~ - wil::unique_tokeninfo_ptr privileges; - RETURN_IF_FAILED(wil::get_token_information_nothrow(privileges)); - for (auto const& privilege : wil::GetRange(privileges->Privileges, privileges->PrivilegeCount)) - { - RETURN_IF_FAILED(ConsumePrivilege(privilege)); - } - ~~~~ - @param tokenInfo Receives a pointer to a structure containing the results of GetTokenInformation for the requested - type. The type of selects which TOKEN_INFORMATION_CLASS will be used. - @param tokenHandle Specifies which token will be queried. When nullptr, the thread's effective current token is used. - @return S_OK on success, a FAILED hresult containing the win32 error from querying the token otherwise. - */ - - template using unique_tokeninfo_ptr = wistd::unique_ptr; - - template ::FixedSize>* = nullptr> - inline HRESULT get_token_information_nothrow(unique_tokeninfo_ptr& tokenInfo, HANDLE tokenHandle = nullptr) - { - tokenInfo.reset(); - tokenHandle = GetCurrentThreadEffectiveTokenWithOverride(tokenHandle); - - DWORD tokenInfoSize = 0; - const auto infoClass = details::MapTokenStructToInfoClass::infoClass; - RETURN_LAST_ERROR_IF(!((!GetTokenInformation(tokenHandle, infoClass, nullptr, 0, &tokenInfoSize)) && - (::GetLastError() == ERROR_INSUFFICIENT_BUFFER))); - unique_tokeninfo_ptr tokenInfoClose{ static_cast(::operator new(tokenInfoSize, std::nothrow)) }; - RETURN_IF_NULL_ALLOC(tokenInfoClose); - RETURN_IF_WIN32_BOOL_FALSE(GetTokenInformation(tokenHandle, infoClass, tokenInfoClose.get(), tokenInfoSize, &tokenInfoSize)); - tokenInfo = wistd::move(tokenInfoClose); - - return S_OK; - } - - template ::FixedSize>* = nullptr> - inline HRESULT get_token_information_nothrow(_Out_ T* tokenInfo, HANDLE tokenHandle = nullptr) - { - *tokenInfo = {}; - tokenHandle = GetCurrentThreadEffectiveTokenWithOverride(tokenHandle); - - DWORD tokenInfoSize = sizeof(T); - const auto infoClass = details::MapTokenStructToInfoClass::infoClass; - RETURN_IF_WIN32_BOOL_FALSE(GetTokenInformation(tokenHandle, infoClass, tokenInfo, tokenInfoSize, &tokenInfoSize)); - - return S_OK; - } - - namespace details - { - template::FixedSize>* = nullptr> - unique_tokeninfo_ptr GetTokenInfoWrap(HANDLE token = nullptr) - { - unique_tokeninfo_ptr temp; - policy::HResult(get_token_information_nothrow(temp, token)); - return temp; - } - - template::FixedSize>* = nullptr> - T GetTokenInfoWrap(HANDLE token = nullptr) - { - T temp{}; - policy::HResult(get_token_information_nothrow(&temp, token)); - return temp; - } - } - - //! A variant of get_token_information that fails-fast on errors retrieving the token - template - inline auto get_token_information_failfast(HANDLE token = nullptr) - { - return details::GetTokenInfoWrap(token); - } - - //! Overload of GetTokenInformationNoThrow that retrieves a token linked from the provided token - inline HRESULT get_token_information_nothrow(unique_token_linked_token& tokenInfo, HANDLE tokenHandle = nullptr) - { - static_assert(sizeof(tokenInfo) == sizeof(TOKEN_LINKED_TOKEN), "confusing size mismatch"); - tokenHandle = GetCurrentThreadEffectiveTokenWithOverride(tokenHandle); - - DWORD tokenInfoSize = 0; - RETURN_IF_WIN32_BOOL_FALSE(::GetTokenInformation(tokenHandle, TokenLinkedToken, - tokenInfo.reset_and_addressof(), sizeof(tokenInfo), &tokenInfoSize)); - return S_OK; - } - - /** Retrieves the linked-token information for a token. - Fails-fast if the link information cannot be retrieved. - ~~~~ - auto link = get_linked_token_information_failfast(GetCurrentThreadToken()); - auto tokenUser = get_token_information(link.LinkedToken); - ~~~~ - @param token Specifies the token to query. Pass nullptr to use the current effective thread token - @return unique_token_linked_token containing a handle to the linked token - */ - inline unique_token_linked_token get_linked_token_information_failfast(HANDLE token = nullptr) - { - unique_token_linked_token tokenInfo; - FAIL_FAST_IF_FAILED(get_token_information_nothrow(tokenInfo, token)); - return tokenInfo; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - /** Fetches information about a token. - See get_token_information_nothrow for full details. - ~~~~ - auto user = wil::get_token_information(GetCurrentProcessToken()); - ConsumeSid(user->User.Sid); - ~~~~ - Pass 'nullptr' (or omit the parameter) as tokenHandle to retrieve information about the effective token. - ~~~~ - auto privs = wil::get_token_information(privileges); - for (auto& priv : wil::make_range(privs->Privileges, privs->Privilieges + privs->PrivilegeCount)) - { - if (priv.Attributes & SE_PRIVILEGE_ENABLED) - { - // ... - } - } - ~~~~ - @return A pointer to a structure containing the results of GetTokenInformation for the requested type. The type of - selects which TOKEN_INFORMATION_CLASS will be used. - @param token Specifies which token will be queried. When nullptr or not set, the thread's effective current token is used. - */ - template - inline auto get_token_information(HANDLE token = nullptr) - { - return details::GetTokenInfoWrap(token); - } - - /** Retrieves the linked-token information for a token. - Throws an exception if the link information cannot be retrieved. - ~~~~ - auto link = get_linked_token_information(GetCurrentThreadToken()); - auto tokenUser = get_token_information(link.LinkedToken); - ~~~~ - @param token Specifies the token to query. Pass nullptr to use the current effective thread token - @return unique_token_linked_token containing a handle to the linked token - */ - inline unique_token_linked_token get_linked_token_information(HANDLE token = nullptr) - { - unique_token_linked_token tokenInfo; - THROW_IF_FAILED(get_token_information_nothrow(tokenInfo, token)); - return tokenInfo; - } -#endif -#endif // _WIN32_WINNT >= _WIN32_WINNT_WIN8 - - /// @cond - namespace details - { - inline void RevertImpersonateToken(_In_ _Post_ptr_invalid_ HANDLE oldToken) - { - FAIL_FAST_IMMEDIATE_IF(!::SetThreadToken(nullptr, oldToken)); - - if (oldToken) - { - ::CloseHandle(oldToken); - } - } - } - /// @endcond - - using unique_token_reverter = wil::unique_any< - HANDLE, - decltype(&details::RevertImpersonateToken), - details::RevertImpersonateToken, - details::pointer_access_none, - HANDLE, - INT_PTR, - -1, - HANDLE>; - - /** Temporarily impersonates a token on this thread. - This method sets a new token on a thread, restoring the current token when the returned object - is destroyed. Useful for impersonating other tokens or running as 'self,' especially in services. - ~~~~ - HRESULT OpenFileAsSessionuser(PCWSTR filePath, DWORD session, _Out_ HANDLE* opened) - { - wil::unique_handle userToken; - RETURN_IF_WIN32_BOOL_FALSE(QueryUserToken(session, &userToken)); - - wil::unique_token_reverter reverter; - RETURN_IF_FAILED(wil::impersonate_token_nothrow(userToken.get(), reverter)); - - wil::unique_hfile userFile(::CreateFile(filePath, ...)); - RETURN_LAST_ERROR_IF(!userFile && (::GetLastError() != ERROR_FILE_NOT_FOUND)); - - *opened = userFile.release(); - return S_OK; - } - ~~~~ - @param token A token to impersonate, or 'nullptr' to run as the process identity. - */ - inline HRESULT impersonate_token_nothrow(HANDLE token, unique_token_reverter& reverter) - { - wil::unique_handle currentToken; - - // Get the token for the current thread. If there wasn't one, the reset will clear it as well - if (!OpenThreadToken(GetCurrentThread(), TOKEN_ALL_ACCESS, TRUE, ¤tToken)) - { - RETURN_LAST_ERROR_IF(::GetLastError() != ERROR_NO_TOKEN); - } - - // Update the current token - RETURN_IF_WIN32_BOOL_FALSE(::SetThreadToken(nullptr, token)); - - reverter.reset(currentToken.release()); // Ownership passed - return S_OK; - } - - /** Temporarily clears any impersonation on this thread. - This method resets the current thread's token to nullptr, indicating that it is not impersonating - any user. Useful for elevating to whatever identity a service or higher-privilege process might - be capable of running under. - ~~~~ - HRESULT DeleteFileRetryAsSelf(PCWSTR filePath) - { - if (!::DeleteFile(filePath)) - { - RETURN_LAST_ERROR_IF(::GetLastError() != ERROR_ACCESS_DENIED); - wil::unique_token_reverter reverter; - RETURN_IF_FAILED(wil::run_as_self_nothrow(reverter)); - RETURN_IF_FAILED(TakeOwnershipOfFile(filePath)); - RETURN_IF_FAILED(GrantDeleteAccess(filePath)); - RETURN_IF_WIN32_BOOL_FALSE(::DeleteFile(filePath)); - } - return S_OK; - } - ~~~~ - */ - inline HRESULT run_as_self_nothrow(unique_token_reverter& reverter) - { - return impersonate_token_nothrow(nullptr, reverter); - } - - inline unique_token_reverter impersonate_token_failfast(HANDLE token) - { - unique_token_reverter oldToken; - FAIL_FAST_IF_FAILED(impersonate_token_nothrow(token, oldToken)); - return oldToken; - } - - inline unique_token_reverter run_as_self_failfast() - { - return impersonate_token_failfast(nullptr); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - /** Temporarily impersonates a token on this thread. - This method sets a new token on a thread, restoring the current token when the returned object - is destroyed. Useful for impersonating other tokens or running as 'self,' especially in services. - ~~~~ - wil::unique_hfile OpenFileAsSessionuser(_In_z_ const wchar_t* filePath, DWORD session) - { - wil::unique_handle userToken; - THROW_IF_WIN32_BOOL_FALSE(QueryUserToken(session, &userToken)); - - auto priorToken = wil::impersonate_token(userToken.get()); - - wil::unique_hfile userFile(::CreateFile(filePath, ...)); - THROW_LAST_ERROR_IF(::GetLastError() != ERROR_FILE_NOT_FOUND); - - return userFile; - } - ~~~~ - @param token A token to impersonate, or 'nullptr' to run as the process identity. - */ - inline unique_token_reverter impersonate_token(HANDLE token = nullptr) - { - unique_token_reverter oldToken; - THROW_IF_FAILED(impersonate_token_nothrow(token, oldToken)); - return oldToken; - } - - /** Temporarily clears any impersonation on this thread. - This method resets the current thread's token to nullptr, indicating that it is not impersonating - any user. Useful for elevating to whatever identity a service or higher-privilege process might - be capable of running under. - ~~~~ - void DeleteFileRetryAsSelf(_In_z_ const wchar_t* filePath) - { - if (!::DeleteFile(filePath) && (::GetLastError() == ERROR_ACCESS_DENIED)) - { - auto priorToken = wil::run_as_self(); - TakeOwnershipOfFile(filePath); - GrantDeleteAccess(filePath); - ::DeleteFile(filePath); - } - } - ~~~~ - */ - inline unique_token_reverter run_as_self() - { - return impersonate_token(nullptr); - } -#endif // WIL_ENABLE_EXCEPTIONS - - namespace details - { - template struct static_sid_t - { - BYTE Revision; - BYTE SubAuthorityCount; - SID_IDENTIFIER_AUTHORITY IdentifierAuthority; - DWORD SubAuthority[AuthorityCount]; - - PSID get() - { - return reinterpret_cast(this); - } - - template static_sid_t& operator=(const static_sid_t& source) - { - static_assert(other <= AuthorityCount, "Cannot assign from a larger static sid to a smaller one"); - - if (&this->Revision != &source.Revision) - { - memcpy(this, &source, sizeof(source)); - } - - return *this; - } - }; - } - - /** Returns a structure containing a Revision 1 SID initialized with the authorities provided - Replaces AllocateAndInitializeSid by constructing a structure laid out like a PSID, but - returned like a value. The resulting object is suitable for use with any method taking PSID, - passed by "&the_sid" or via "the_sid.get()" - ~~~~ - // Change the owner of the key to administrators - auto systemSid = wil::make_static_sid(SECURITY_NT_AUTHORITY, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS); - RETURN_IF_WIN32_ERROR(SetNamedSecurityInfo(keyPath, SE_REGISTRY_KEY, OWNER_SECURITY_INFORMATION, &systemSid, nullptr, nullptr, nullptr)); - ~~~~ - */ - template constexpr auto make_static_sid(const SID_IDENTIFIER_AUTHORITY& authority, Ts&&... subAuthorities) - { - using sid_t = details::static_sid_t; - - static_assert(sizeof...(subAuthorities) <= SID_MAX_SUB_AUTHORITIES, "too many sub authorities"); - static_assert(offsetof(sid_t, Revision) == offsetof(_SID, Revision), "layout mismatch"); - static_assert(offsetof(sid_t, SubAuthorityCount) == offsetof(_SID, SubAuthorityCount), "layout mismatch"); - static_assert(offsetof(sid_t, IdentifierAuthority) == offsetof(_SID, IdentifierAuthority), "layout mismatch"); - static_assert(offsetof(sid_t, SubAuthority) == offsetof(_SID, SubAuthority), "layout mismatch"); - - return sid_t { SID_REVISION, sizeof...(subAuthorities), authority, { static_cast(subAuthorities)... } }; - } - - //! Variant of static_sid that defaults to the NT authority - template constexpr auto make_static_nt_sid(Ts&& ... subAuthorities) - { - return make_static_sid(SECURITY_NT_AUTHORITY, wistd::forward(subAuthorities)...); - } - - /** Determines whether a specified security identifier (SID) is enabled in an access token. - This function determines whether a security identifier, described by a given set of subauthorities, is enabled - in the given access token. Note that only up to eight subauthorities can be passed to this function. - ~~~~ - bool IsGuest() - { - return wil::test_token_membership(nullptr, SECURITY_NT_AUTHORITY, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_GUESTS)); - } - ~~~~ - @param result This will be set to true if and only if a security identifier described by the given set of subauthorities is enabled in the given access token. - @param token A handle to an access token. The handle must have TOKEN_QUERY access to the token, and must be an impersonation token. If token is nullptr, test_token_membership - uses the impersonation token of the calling thread. If the thread is not impersonating, the function duplicates the thread's primary token to create an impersonation token. - @param sidAuthority A reference to a SID_IDENTIFIER_AUTHORITY structure. This structure provides the top-level identifier authority value to set in the SID. - @param subAuthorities Up to 15 subauthority values to place in the SID (this is a systemwide limit) - @return S_OK on success, a FAILED hresult containing the win32 error from creating the SID or querying the token otherwise. - */ - template HRESULT test_token_membership_nothrow(_Out_ bool* result, _In_opt_ HANDLE token, - const SID_IDENTIFIER_AUTHORITY& sidAuthority, Ts&&... subAuthorities) - { - *result = false; - auto tempSid = make_static_sid(sidAuthority, wistd::forward(subAuthorities)...); - BOOL isMember; - RETURN_IF_WIN32_BOOL_FALSE(CheckTokenMembership(token, &tempSid, &isMember)); - - *result = (isMember != FALSE); - - return S_OK; - } - -#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) - /** Determine whether a token represents an app container - This method uses the passed in token and emits a boolean indicating that - whether TokenIsAppContainer is true. - ~~~~ - HRESULT OnlyIfAppContainer() - { - bool isAppContainer; - RETURN_IF_FAILED(wil::get_token_is_app_container_nothrow(nullptr, isAppContainer)); - RETURN_HR_IF(E_ACCESSDENIED, !isAppContainer); - RETURN_HR(...); - } - ~~~~ - @param token A token to get info about, or 'nullptr' to run as the current thread. - */ - inline HRESULT get_token_is_app_container_nothrow(_In_opt_ HANDLE token, bool& value) - { - DWORD isAppContainer = 0; - DWORD returnLength = 0; - RETURN_IF_WIN32_BOOL_FALSE(::GetTokenInformation( - token ? token : GetCurrentThreadEffectiveToken(), - TokenIsAppContainer, - &isAppContainer, - sizeof(isAppContainer), - &returnLength)); - - value = (isAppContainer != 0); - - return S_OK; - } - - //! A variant of get_token_is_app_container_nothrow that fails-fast on errors retrieving the token information - inline bool get_token_is_app_container_failfast(HANDLE token = nullptr) - { - bool value = false; - FAIL_FAST_IF_FAILED(get_token_is_app_container_nothrow(token, value)); - - return value; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - //! A variant of get_token_is_app_container_nothrow that throws on errors retrieving the token information - inline bool get_token_is_app_container(HANDLE token = nullptr) - { - bool value = false; - THROW_IF_FAILED(get_token_is_app_container_nothrow(token, value)); - - return value; - } -#endif // WIL_ENABLE_EXCEPTIONS -#endif // _WIN32_WINNT >= _WIN32_WINNT_WIN8 - - template bool test_token_membership_failfast(_In_opt_ HANDLE token, - const SID_IDENTIFIER_AUTHORITY& sidAuthority, Ts&&... subAuthorities) - { - bool result; - FAIL_FAST_IF_FAILED(test_token_membership_nothrow(&result, token, sidAuthority, wistd::forward(subAuthorities)...)); - return result; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - template bool test_token_membership(_In_opt_ HANDLE token, const SID_IDENTIFIER_AUTHORITY& sidAuthority, - Ts&&... subAuthorities) - { - bool result; - THROW_IF_FAILED(test_token_membership_nothrow(&result, token, sidAuthority, wistd::forward(subAuthorities)...)); - return result; - } -#endif - -} //namespace wil - -#endif // __WIL_TOKEN_HELPERS_INCLUDED diff --git a/src/common/dep/wil/traceloggingconfig.h b/src/common/dep/wil/traceloggingconfig.h deleted file mode 100644 index 33e3e9c88..000000000 --- a/src/common/dep/wil/traceloggingconfig.h +++ /dev/null @@ -1,71 +0,0 @@ -#pragma once -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* - -#ifndef __WIL_TRACELOGGING_CONFIG_H -#define __WIL_TRACELOGGING_CONFIG_H - -// Configuration macro for use in TRACELOGGING_DEFINE_PROVIDER. The definition -// in this file configures the provider as a normal (non-telemetry) provider. -#define TraceLoggingOptionMicrosoftTelemetry() \ - // Empty definition for TraceLoggingOptionMicrosoftTelemetry - -// Configuration macro for use in TRACELOGGING_DEFINE_PROVIDER. The definition -// in this file configures the provider as a normal (non-telemetry) provider. -#define TraceLoggingOptionWindowsCoreTelemetry() \ - // Empty definition for TraceLoggingOptionWindowsCoreTelemetry - -// Event privacy tags. Use the PDT macro values for the tag parameter, e.g.: -// TraceLoggingWrite(..., -// TelemetryPrivacyDataTag(PDT_BrowsingHistory | PDT_ProductAndServiceUsage), -// ...); -#define TelemetryPrivacyDataTag(tag) TraceLoggingUInt64((tag), "PartA_PrivTags") -#define PDT_BrowsingHistory 0x0000000000000002u -#define PDT_DeviceConnectivityAndConfiguration 0x0000000000000800u -#define PDT_InkingTypingAndSpeechUtterance 0x0000000000020000u -#define PDT_ProductAndServicePerformance 0x0000000001000000u -#define PDT_ProductAndServiceUsage 0x0000000002000000u -#define PDT_SoftwareSetupAndInventory 0x0000000080000000u - -// Event categories specified via keywords, e.g.: -// TraceLoggingWrite(..., -// TraceLoggingKeyword(MICROSOFT_KEYWORD_MEASURES), -// ...); -#define MICROSOFT_KEYWORD_CRITICAL_DATA 0x0000800000000000 // Bit 47 -#define MICROSOFT_KEYWORD_MEASURES 0x0000400000000000 // Bit 46 -#define MICROSOFT_KEYWORD_TELEMETRY 0x0000200000000000 // Bit 45 -#define MICROSOFT_KEYWORD_RESERVED_44 0x0000100000000000 // Bit 44 (reserved for future assignment) - -// Event categories specified via event tags, e.g.: -// TraceLoggingWrite(..., -// TraceLoggingEventTag(MICROSOFT_EVENTTAG_REALTIME_LATENCY), -// ...); -#define MICROSOFT_EVENTTAG_DROP_USER_IDS 0x00008000 -#define MICROSOFT_EVENTTAG_AGGREGATE 0x00010000 -#define MICROSOFT_EVENTTAG_DROP_PII_EXCEPT_IP 0x00020000 -#define MICROSOFT_EVENTTAG_COSTDEFERRED_LATENCY 0x00040000 -#define MICROSOFT_EVENTTAG_CORE_DATA 0x00080000 -#define MICROSOFT_EVENTTAG_INJECT_XTOKEN 0x00100000 -#define MICROSOFT_EVENTTAG_REALTIME_LATENCY 0x00200000 -#define MICROSOFT_EVENTTAG_NORMAL_LATENCY 0x00400000 -#define MICROSOFT_EVENTTAG_CRITICAL_PERSISTENCE 0x00800000 -#define MICROSOFT_EVENTTAG_NORMAL_PERSISTENCE 0x01000000 -#define MICROSOFT_EVENTTAG_DROP_PII 0x02000000 -#define MICROSOFT_EVENTTAG_HASH_PII 0x04000000 -#define MICROSOFT_EVENTTAG_MARK_PII 0x08000000 - -// Field categories specified via field tags, e.g.: -// TraceLoggingWrite(..., -// TraceLoggingString(szUser, "UserName", "User's name", MICROSOFT_FIELDTAG_HASH_PII), -// ...); -#define MICROSOFT_FIELDTAG_DROP_PII 0x04000000 -#define MICROSOFT_FIELDTAG_HASH_PII 0x08000000 -#endif // __WIL_TRACELOGGING_CONFIG_H \ No newline at end of file diff --git a/src/common/dep/wil/wil.natvis b/src/common/dep/wil/wil.natvis deleted file mode 100644 index 2eac65f5f..000000000 --- a/src/common/dep/wil/wil.natvis +++ /dev/null @@ -1,170 +0,0 @@ - - - - - default_delete - - - - - - {get()} - - get() - - - - - - {get()} - - get() - - - - - - - ({first()}, {second()}) - - first() - second() - - - - - {__f_} - - - - - - empty - {*__f_} - - *__f_ - - - - - __ptr_.first() - empty - {*__ptr_.first()} - - __ptr_.first() - __ptr_.second() - - - - - empty - {__ptr_.first(),su} - __ptr_.first() - - __ptr_.first() - wcslen(__ptr_.first()) - __ptr_.second() - - - - - empty - {__ptr_.first(),su} - __ptr_.first() - - __ptr_.first() - wcslen(__ptr_.first()) - __ptr_.second() - - - - - empty - {__ptr_.first(),s} - __ptr_.first() - - __ptr_.first() - strlen(__ptr_.first()) - __ptr_.second() - - - - - empty - {__ptr_.first(),s} - __ptr_.first() - - __ptr_.first() - strlen(__ptr_.first()) - __ptr_.second() - - - - - empty - {*m_ptr} - m_ptr - - m_ptr - - - - - empty - {m_ptr} - - - - - empty - {m_ptr} - - - - - empty - {m_ptr} - m_ptr - - - - - empty - {m_ptr,su} - m_ptr - - wcslen(m_ptr) - - - - empty - {m_ptr,s} - m_ptr - - strlen(m_ptr) - - - - - {m_ptr} - - m_ptr - - - - - - - {_Mydata,[_Mysize]} - - size() - - - \ No newline at end of file diff --git a/src/common/dep/wil/win32_helpers.h b/src/common/dep/wil/win32_helpers.h deleted file mode 100644 index 9eeb666eb..000000000 --- a/src/common/dep/wil/win32_helpers.h +++ /dev/null @@ -1,897 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_WIN32_HELPERS_INCLUDED -#define __WIL_WIN32_HELPERS_INCLUDED - -#include // FILETIME, HINSTANCE -#include // GetSystemTimeAsFileTime -#include // GetProcAddress -#include // GetModuleFileNameExW (macro), K32GetModuleFileNameExW -#include -#include - -// detect std::bit_cast -#ifdef __has_include -# if (__cplusplus >= 202002L || _MSVC_LANG >= 202002L) && __has_include() -# include -# endif -#endif - -#if __cpp_lib_bit_cast >= 201806L -# define __WI_CONSTEXPR_BIT_CAST constexpr -#else -# define __WI_CONSTEXPR_BIT_CAST inline -#endif - -#include "result.h" -#include "resource.h" -#include "wistd_functional.h" -#include "wistd_type_traits.h" - -#if _HAS_CXX20 && defined(_STRING_VIEW_) && defined(_COMPARE_) -// If we're using c++20, then must be included to use the string ordinal functions -# define __WI_DEFINE_STRING_ORDINAL_FUNCTIONS -#elif !_HAS_CXX20 && defined(_STRING_VIEW_) -# define __WI_DEFINE_STRING_ORDINAL_FUNCTIONS -#endif - -namespace wistd -{ -#if defined(__WI_DEFINE_STRING_ORDINAL_FUNCTIONS) - -#if _HAS_CXX20 - - using weak_ordering = std::weak_ordering; - -#else // _HAS_CXX20 - - struct weak_ordering - { - static const weak_ordering less; - static const weak_ordering equivalent; - static const weak_ordering greater; - - [[nodiscard]] friend constexpr bool operator==(const weak_ordering left, std::nullptr_t) noexcept - { - return left.m_value == 0; - } - - [[nodiscard]] friend constexpr bool operator!=(const weak_ordering left, std::nullptr_t) noexcept - { - return left.m_value != 0; - } - - [[nodiscard]] friend constexpr bool operator<(const weak_ordering left, std::nullptr_t) noexcept - { - return left.m_value < 0; - } - - [[nodiscard]] friend constexpr bool operator>(const weak_ordering left, std::nullptr_t) noexcept - { - return left.m_value > 0; - } - - [[nodiscard]] friend constexpr bool operator<=(const weak_ordering left, std::nullptr_t) noexcept - { - return left.m_value <= 0; - } - - [[nodiscard]] friend constexpr bool operator>=(const weak_ordering left, std::nullptr_t) noexcept - { - return left.m_value >= 0; - } - - [[nodiscard]] friend constexpr bool operator==(std::nullptr_t, const weak_ordering right) noexcept - { - return right == 0; - } - - [[nodiscard]] friend constexpr bool operator!=(std::nullptr_t, const weak_ordering right) noexcept - { - return right != 0; - } - - [[nodiscard]] friend constexpr bool operator<(std::nullptr_t, const weak_ordering right) noexcept - { - return right > 0; - } - - [[nodiscard]] friend constexpr bool operator>(std::nullptr_t, const weak_ordering right) noexcept - { - return right < 0; - } - - [[nodiscard]] friend constexpr bool operator<=(std::nullptr_t, const weak_ordering right) noexcept - { - return right >= 0; - } - - [[nodiscard]] friend constexpr bool operator>=(std::nullptr_t, const weak_ordering right) noexcept - { - return right <= 0; - } - - signed char m_value; - }; - - inline constexpr weak_ordering weak_ordering::less{static_cast(-1)}; - inline constexpr weak_ordering weak_ordering::equivalent{static_cast(0)}; - inline constexpr weak_ordering weak_ordering::greater{static_cast(1)}; - -#endif // !_HAS_CXX20 - -#endif // defined(__WI_DEFINE_STRING_ORDINAL_FUNCTIONS) - -} - -namespace wil -{ - //! Strictly a function of the file system but this is the value for all known file system, NTFS, FAT. - //! CDFs has a limit of 254. - constexpr size_t max_path_segment_length = 255; - - //! Character length not including the null, MAX_PATH (260) includes the null. - constexpr size_t max_path_length = 259; - - //! 32743 Character length not including the null. This is a system defined limit. - //! The 24 is for the expansion of the roots from "C:" to "\Device\HarddiskVolume4" - //! It will be 25 when there are more than 9 disks. - constexpr size_t max_extended_path_length = 0x7FFF - 24; - - //! For {guid} string form. Includes space for the null terminator. - constexpr size_t guid_string_buffer_length = 39; - - //! For {guid} string form. Not including the null terminator. - constexpr size_t guid_string_length = 38; - -#pragma region String and identifier comparisons - // Using CompareStringOrdinal functions: - // - // Indentifiers require a locale-less (ordinal), and often case-insensitive, comparison (filenames, registry keys, XML node names, etc). - // DO NOT use locale-sensitive (lexical) comparisons for resource identifiers (e.g.wcs*() functions in the CRT). - -#if defined(__WI_DEFINE_STRING_ORDINAL_FUNCTIONS) - - namespace details - { - [[nodiscard]] inline int CompareStringOrdinal(std::wstring_view left, std::wstring_view right, bool caseInsensitive) WI_NOEXCEPT - { - // Casting from size_t (unsigned) to int (signed) should be safe from overrun to a negative, - // merely truncating the string. CompareStringOrdinal should be resilient to negatives. - return ::CompareStringOrdinal(left.data(), static_cast(left.size()), right.data(), static_cast(right.size()), caseInsensitive); - } - } - - [[nodiscard]] inline wistd::weak_ordering compare_string_ordinal(std::wstring_view left, std::wstring_view right, bool caseInsensitive) WI_NOEXCEPT - { - switch (wil::details::CompareStringOrdinal(left, right, caseInsensitive)) - { - case CSTR_LESS_THAN: - return wistd::weak_ordering::less; - case CSTR_GREATER_THAN: - return wistd::weak_ordering::greater; - default: - return wistd::weak_ordering::equivalent; - } - } - -#endif // defined(__WI_DEFINE_STRING_ORDINAL_FUNCTIONS) - -#pragma endregion - -#pragma region FILETIME helpers - // FILETIME duration values. FILETIME is in 100 nanosecond units. - namespace filetime_duration - { - long long const one_millisecond = 10000LL; - long long const one_second = 10000000LL; - long long const one_minute = 10000000LL * 60; // 600000000 or 600000000LL - long long const one_hour = 10000000LL * 60 * 60; // 36000000000 or 36000000000LL - long long const one_day = 10000000LL * 60 * 60 * 24; // 864000000000 or 864000000000LL - }; - - namespace filetime - { - constexpr unsigned long long to_int64(const FILETIME &ft) WI_NOEXCEPT - { -#if __cpp_lib_bit_cast >= 201806L - return std::bit_cast(ft); -#else - // Cannot reinterpret_cast FILETIME* to unsigned long long* - // due to alignment differences. - return (static_cast(ft.dwHighDateTime) << 32) + ft.dwLowDateTime; -#endif - } - - __WI_CONSTEXPR_BIT_CAST FILETIME from_int64(unsigned long long i64) WI_NOEXCEPT - { -#if __cpp_lib_bit_cast >= 201806L - return std::bit_cast(i64); -#else - static_assert(sizeof(i64) == sizeof(FILETIME), "sizes don't match"); - static_assert(__alignof(unsigned long long) >= __alignof(FILETIME), "alignment not compatible with type pun"); - return *reinterpret_cast(&i64); -#endif - } - - __WI_CONSTEXPR_BIT_CAST FILETIME add(_In_ FILETIME const &ft, long long delta100ns) WI_NOEXCEPT - { - return from_int64(to_int64(ft) + delta100ns); - } - - constexpr bool is_empty(const FILETIME &ft) WI_NOEXCEPT - { - return (ft.dwHighDateTime == 0) && (ft.dwLowDateTime == 0); - } - - inline FILETIME get_system_time() WI_NOEXCEPT - { - FILETIME ft; - GetSystemTimeAsFileTime(&ft); - return ft; - } - - /// Convert time as units of 100 nanoseconds to milliseconds. Fractional milliseconds are truncated. - constexpr unsigned long long convert_100ns_to_msec(unsigned long long time100ns) WI_NOEXCEPT - { - return time100ns / filetime_duration::one_millisecond; - } - - /// Convert time as milliseconds to units of 100 nanoseconds. - constexpr unsigned long long convert_msec_to_100ns(unsigned long long timeMsec) WI_NOEXCEPT - { - return timeMsec * filetime_duration::one_millisecond; - } - -#if defined(_APISETREALTIME_) && (_WIN32_WINNT >= _WIN32_WINNT_WIN7) - /// Returns the current unbiased interrupt-time count, in units of 100 nanoseconds. The unbiased interrupt-time count does not include time the system spends in sleep or hibernation. - /// - /// This API avoids prematurely shortcircuiting timing loops due to system sleep/hibernation. - /// - /// This is equivalent to GetTickCount64() except it returns units of 100 nanoseconds instead of milliseconds, and it doesn't include time the system spends in sleep or hibernation. - /// For example - /// - /// start = GetTickCount64(); - /// hibernate(); - /// ...wake from hibernation 30 minutes later...; - /// elapsed = GetTickCount64() - start; - /// // elapsed = 30min - /// - /// Do the same using unbiased interrupt-time and elapsed is 0 (or nearly so). - /// - /// @note This is identical to QueryUnbiasedInterruptTime() but returns the value as a return value (rather than an out parameter). - /// @see https://msdn.microsoft.com/en-us/library/windows/desktop/ee662307(v=vs.85).aspx - inline unsigned long long QueryUnbiasedInterruptTimeAs100ns() WI_NOEXCEPT - { - ULONGLONG now{}; - QueryUnbiasedInterruptTime(&now); - return now; - } - - /// Returns the current unbiased interrupt-time count, in units of milliseconds. The unbiased interrupt-time count does not include time the system spends in sleep or hibernation. - /// @see QueryUnbiasedInterruptTimeAs100ns - inline unsigned long long QueryUnbiasedInterruptTimeAsMSec() WI_NOEXCEPT - { - return convert_100ns_to_msec(QueryUnbiasedInterruptTimeAs100ns()); - } -#endif // _APISETREALTIME_ - } -#pragma endregion - -#pragma region RECT helpers - template - constexpr auto rect_width(rect_type const& rect) - { - return rect.right - rect.left; - } - - template - constexpr auto rect_height(rect_type const& rect) - { - return rect.bottom - rect.top; - } - - template - constexpr auto rect_is_empty(rect_type const& rect) - { - return (rect.left >= rect.right) || (rect.top >= rect.bottom); - } - - template - constexpr auto rect_contains_point(rect_type const& rect, point_type const& point) - { - return (point.x >= rect.left) && (point.x < rect.right) && (point.y >= rect.top) && (point.y < rect.bottom); - } - - template - constexpr rect_type rect_from_size(length_type x, length_type y, length_type width, length_type height) - { - rect_type rect; - rect.left = x; - rect.top = y; - rect.right = x + width; - rect.bottom = y + height; - return rect; - } -#pragma endregion - - // Use to adapt Win32 APIs that take a fixed size buffer into forms that return - // an allocated buffer. Supports many types of string representation. - // See comments below on the expected behavior of the callback. - // Adjust stackBufferLength based on typical result sizes to optimize use and - // to test the boundary cases. - template - HRESULT AdaptFixedSizeToAllocatedResult(string_type& result, wistd::function callback) WI_NOEXCEPT - { - details::string_maker maker; - - wchar_t value[stackBufferLength]{}; - size_t valueLengthNeededWithNull{}; // callback returns the number of characters needed including the null terminator. - RETURN_IF_FAILED_EXPECTED(callback(value, ARRAYSIZE(value), &valueLengthNeededWithNull)); - WI_ASSERT(valueLengthNeededWithNull > 0); - if (valueLengthNeededWithNull <= ARRAYSIZE(value)) - { - // Success case as described above, make() adds the space for the null. - RETURN_IF_FAILED(maker.make(value, valueLengthNeededWithNull - 1)); - } - else - { - // Did not fit in the stack allocated buffer, need to do 2 phase construction. - // May need to loop more than once if external conditions cause the value to change. - size_t bufferLength; - do - { - bufferLength = valueLengthNeededWithNull; - // bufferLength includes the null so subtract that as make() will add space for it. - RETURN_IF_FAILED(maker.make(nullptr, bufferLength - 1)); - - RETURN_IF_FAILED_EXPECTED(callback(maker.buffer(), bufferLength, &valueLengthNeededWithNull)); - WI_ASSERT(valueLengthNeededWithNull > 0); - - // If the value shrunk, then adjust the string to trim off the excess buffer. - if (valueLengthNeededWithNull < bufferLength) - { - RETURN_IF_FAILED(maker.trim_at_existing_null(valueLengthNeededWithNull - 1)); - } - } - while (valueLengthNeededWithNull > bufferLength); - } - result = maker.release(); - return S_OK; - } - - /** Expands the '%' quoted environment variables in 'input' using ExpandEnvironmentStringsW(); */ - template - HRESULT ExpandEnvironmentStringsW(_In_ PCWSTR input, string_type& result) WI_NOEXCEPT - { - return wil::AdaptFixedSizeToAllocatedResult(result, - [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT - { - *valueLengthNeededWithNul = ::ExpandEnvironmentStringsW(input, value, static_cast(valueLength)); - RETURN_LAST_ERROR_IF(*valueLengthNeededWithNul == 0); - return S_OK; - }); - } - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) - /** Searches for a specified file in a specified path using ExpandEnvironmentStringsW(); */ - template - HRESULT SearchPathW(_In_opt_ PCWSTR path, _In_ PCWSTR fileName, _In_opt_ PCWSTR extension, string_type& result) WI_NOEXCEPT - { - return wil::AdaptFixedSizeToAllocatedResult(result, - [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT - { - *valueLengthNeededWithNul = ::SearchPathW(path, fileName, extension, static_cast(valueLength), value, nullptr); - - if (*valueLengthNeededWithNul == 0) - { - // ERROR_FILE_NOT_FOUND is an expected return value for SearchPathW - const HRESULT searchResult = HRESULT_FROM_WIN32(::GetLastError()); - RETURN_HR_IF_EXPECTED(searchResult, searchResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); - RETURN_IF_FAILED(searchResult); - } - - // AdaptFixedSizeToAllocatedResult expects that the length will always include the NUL. - // If the result is copied to the buffer, SearchPathW returns the length of copied string, WITHOUT the NUL. - // If the buffer is too small to hold the result, SearchPathW returns the length of the required buffer WITH the nul. - if (*valueLengthNeededWithNul < valueLength) - { - (*valueLengthNeededWithNul)++; // It fit, account for the null. - } - return S_OK; - }); - } - - template - HRESULT QueryFullProcessImageNameW(HANDLE processHandle, _In_ DWORD flags, string_type& result) WI_NOEXCEPT - { - return wil::AdaptFixedSizeToAllocatedResult(result, - [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT - { - DWORD lengthToUse = static_cast(valueLength); - BOOL const success = ::QueryFullProcessImageNameW(processHandle, flags, value, &lengthToUse); - RETURN_LAST_ERROR_IF((success == FALSE) && (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)); - - // On success, return the amount used; on failure, try doubling - *valueLengthNeededWithNul = success ? (static_cast(lengthToUse) + 1) : (static_cast(lengthToUse) * 2); - return S_OK; - }); - } - - /** Expands environment strings and checks path existence with SearchPathW */ - template - HRESULT ExpandEnvAndSearchPath(_In_ PCWSTR input, string_type& result) WI_NOEXCEPT - { - wil::unique_cotaskmem_string expandedName; - RETURN_IF_FAILED((wil::ExpandEnvironmentStringsW(input, expandedName))); - - // ERROR_FILE_NOT_FOUND is an expected return value for SearchPathW - const HRESULT searchResult = (wil::SearchPathW(nullptr, expandedName.get(), nullptr, result)); - RETURN_HR_IF_EXPECTED(searchResult, searchResult == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)); - RETURN_IF_FAILED(searchResult); - - return S_OK; - } -#endif - - /** Looks up the environment variable 'key' and fails if it is not found. */ - template - inline HRESULT GetEnvironmentVariableW(_In_ PCWSTR key, string_type& result) WI_NOEXCEPT - { - return wil::AdaptFixedSizeToAllocatedResult(result, - [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT - { - // If the function succeeds, the return value is the number of characters stored in the buffer - // pointed to by lpBuffer, not including the terminating null character. - // - // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in - // characters, required to hold the string and its terminating null character and the contents of - // lpBuffer are undefined. - // - // If the function fails, the return value is zero. If the specified environment variable was not - // found in the environment block, GetLastError returns ERROR_ENVVAR_NOT_FOUND. - - ::SetLastError(ERROR_SUCCESS); - - *valueLengthNeededWithNul = ::GetEnvironmentVariableW(key, value, static_cast(valueLength)); - RETURN_LAST_ERROR_IF_EXPECTED((*valueLengthNeededWithNul == 0) && (::GetLastError() != ERROR_SUCCESS)); - if (*valueLengthNeededWithNul < valueLength) - { - (*valueLengthNeededWithNul)++; // It fit, account for the null. - } - return S_OK; - }); - } - - /** Looks up the environment variable 'key' and returns null if it is not found. */ - template - HRESULT TryGetEnvironmentVariableW(_In_ PCWSTR key, string_type& result) WI_NOEXCEPT - { - const auto hr = wil::GetEnvironmentVariableW(key, result); - RETURN_HR_IF(hr, FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_ENVVAR_NOT_FOUND))); - return S_OK; - } - - /** Retrieves the fully qualified path for the file containing the specified module loaded - by a given process. Note GetModuleFileNameExW is a macro.*/ - template - HRESULT GetModuleFileNameExW(_In_opt_ HANDLE process, _In_opt_ HMODULE module, string_type& path) WI_NOEXCEPT - { - auto adapter = [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT - { - DWORD copiedCount{}; - size_t valueUsedWithNul{}; - bool copyFailed{}; - bool copySucceededWithNoTruncation{}; - if (process != nullptr) - { - // GetModuleFileNameExW truncates and provides no error or other indication it has done so. - // The only way to be sure it didn't truncate is if it didn't need the whole buffer. The - // count copied to the buffer includes the nul-character as well. - copiedCount = ::GetModuleFileNameExW(process, module, value, static_cast(valueLength)); - valueUsedWithNul = static_cast(copiedCount) + 1; - copyFailed = (0 == copiedCount); - copySucceededWithNoTruncation = !copyFailed && (copiedCount < valueLength - 1); - } - else - { - // In cases of insufficient buffer, GetModuleFileNameW will return a value equal to lengthWithNull - // and set the last error to ERROR_INSUFFICIENT_BUFFER. The count returned does not include - // the nul-character - copiedCount = ::GetModuleFileNameW(module, value, static_cast(valueLength)); - valueUsedWithNul = static_cast(copiedCount) + 1; - copyFailed = (0 == copiedCount); - copySucceededWithNoTruncation = !copyFailed && (copiedCount < valueLength); - } - - RETURN_LAST_ERROR_IF(copyFailed); - - // When the copy truncated, request another try with more space. - *valueLengthNeededWithNul = copySucceededWithNoTruncation ? valueUsedWithNul : (valueLength * 2); - - return S_OK; - }; - - return wil::AdaptFixedSizeToAllocatedResult(path, wistd::move(adapter)); - } - - /** Retrieves the fully qualified path for the file that contains the specified module. - The module must have been loaded by the current process. The path returned will use the - same format that was specified when the module was loaded. Therefore, the path can be a - long or short file name, and can have the prefix '\\?\'. */ - template - HRESULT GetModuleFileNameW(HMODULE module, string_type& path) WI_NOEXCEPT - { - return wil::GetModuleFileNameExW(nullptr, module, path); - } - - template - HRESULT GetSystemDirectoryW(string_type& result) WI_NOEXCEPT - { - return wil::AdaptFixedSizeToAllocatedResult(result, - [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT - { - *valueLengthNeededWithNul = ::GetSystemDirectoryW(value, static_cast(valueLength)); - RETURN_LAST_ERROR_IF(*valueLengthNeededWithNul == 0); - if (*valueLengthNeededWithNul < valueLength) - { - (*valueLengthNeededWithNul)++; // it fit, account for the null - } - return S_OK; - }); - } - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) - template - HRESULT GetWindowsDirectoryW(string_type& result) WI_NOEXCEPT - { - return wil::AdaptFixedSizeToAllocatedResult(result, - [&](_Out_writes_(valueLength) PWSTR value, size_t valueLength, _Out_ size_t* valueLengthNeededWithNul) -> HRESULT - { - *valueLengthNeededWithNul = ::GetWindowsDirectoryW(value, static_cast(valueLength)); - RETURN_LAST_ERROR_IF(*valueLengthNeededWithNul == 0); - if (*valueLengthNeededWithNul < valueLength) - { - (*valueLengthNeededWithNul)++; // it fit, account for the null - } - return S_OK; - }); - } -#endif - -#ifdef WIL_ENABLE_EXCEPTIONS - /** Expands the '%' quoted environment variables in 'input' using ExpandEnvironmentStringsW(); */ - template - string_type ExpandEnvironmentStringsW(_In_ PCWSTR input) - { - string_type result{}; - THROW_IF_FAILED((wil::ExpandEnvironmentStringsW(input, result))); - return result; - } - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) - /** Searches for a specified file in a specified path using SearchPathW*/ - template - string_type TrySearchPathW(_In_opt_ PCWSTR path, _In_ PCWSTR fileName, PCWSTR _In_opt_ extension) - { - string_type result{}; - HRESULT searchHR = wil::SearchPathW(path, fileName, extension, result); - THROW_HR_IF(searchHR, FAILED(searchHR) && (searchHR != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))); - return result; - } -#endif - - /** Looks up the environment variable 'key' and fails if it is not found. */ - template - string_type GetEnvironmentVariableW(_In_ PCWSTR key) - { - string_type result{}; - THROW_IF_FAILED((wil::GetEnvironmentVariableW(key, result))); - return result; - } - - /** Looks up the environment variable 'key' and returns null if it is not found. */ - template - string_type TryGetEnvironmentVariableW(_In_ PCWSTR key) - { - string_type result{}; - THROW_IF_FAILED((wil::TryGetEnvironmentVariableW(key, result))); - return result; - } - - template - string_type GetModuleFileNameW(HMODULE module = nullptr /* current process module */) - { - string_type result{}; - THROW_IF_FAILED((wil::GetModuleFileNameW(module, result))); - return result; - } - - template - string_type GetModuleFileNameExW(HANDLE process, HMODULE module) - { - string_type result{}; - THROW_IF_FAILED((wil::GetModuleFileNameExW(process, module, result))); - return result; - } - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) - template - string_type GetWindowsDirectoryW() - { - string_type result; - THROW_IF_FAILED((wil::GetWindowsDirectoryW(result))); - return result; - } -#endif - - template - string_type GetSystemDirectoryW() - { - string_type result; - THROW_IF_FAILED((wil::GetSystemDirectoryW(result))); - return result; - } - - template - string_type QueryFullProcessImageNameW(HANDLE processHandle = GetCurrentProcess(), DWORD flags = 0) - { - string_type result{}; - THROW_IF_FAILED((wil::QueryFullProcessImageNameW(processHandle, flags, result))); - return result; - } - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) - - // Lookup a DWORD value under HKLM\...\Image File Execution Options\ - inline DWORD GetCurrentProcessExecutionOption(PCWSTR valueName, DWORD defaultValue = 0) - { - auto filePath = wil::GetModuleFileNameW(); - if (auto lastSlash = wcsrchr(filePath.get(), L'\\')) - { - const auto fileName = lastSlash + 1; - auto keyPath = wil::str_concat(LR"(SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\)", - fileName); - DWORD value{}, sizeofValue = sizeof(value); - if (::RegGetValueW(HKEY_LOCAL_MACHINE, keyPath.get(), valueName, -#ifdef RRF_SUBKEY_WOW6464KEY - RRF_RT_REG_DWORD | RRF_SUBKEY_WOW6464KEY, -#else - RRF_RT_REG_DWORD, -#endif - nullptr, &value, &sizeofValue) == ERROR_SUCCESS) - { - return value; - } - } - return defaultValue; - } - - // Waits for a debugger to attach to the current process based on registry configuration. - // - // Example: - // HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\explorer.exe - // WaitForDebuggerPresent=1 - // - // REG_DWORD value of - // missing or 0 -> don't break - // 1 -> wait for the debugger, continue execution once it is attached - // 2 -> wait for the debugger, break here once attached. - inline void WaitForDebuggerPresent(bool checkRegistryConfig = true) - { - for (;;) - { - auto configValue = checkRegistryConfig ? GetCurrentProcessExecutionOption(L"WaitForDebuggerPresent") : 1; - if (configValue == 0) - { - return; // not configured, don't wait - } - - if (IsDebuggerPresent()) - { - if (configValue == 2) - { - DebugBreak(); // debugger attached, SHIFT+F11 to return to the caller - } - return; // debugger now attached, continue executing - } - Sleep(500); - } - } -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) - -#endif - - /** Retrieve the HINSTANCE for the current DLL or EXE using this symbol that - the linker provides for every module. This avoids the need for a global HINSTANCE variable - and provides access to this value for static libraries. */ - EXTERN_C IMAGE_DOS_HEADER __ImageBase; - inline HINSTANCE GetModuleInstanceHandle() WI_NOEXCEPT { return reinterpret_cast(&__ImageBase); } - - // GetModuleHandleExW was added to the app partition in version 22000 of the SDK -#if defined(NTDDI_WIN10_CO) ? \ - WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) : \ - WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) - // Use this in threads that can outlive the object or API call that created them. - // Without this COM, or the API caller, can unload the DLL, resulting in a crash. - // It is very important that this be the first object created in the thread proc - // as when this runs down the thread exits and no destructors of objects created before - // it will run. - [[nodiscard]] inline auto get_module_reference_for_thread() noexcept - { - HMODULE thisModule{}; - FAIL_FAST_IF(!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, L"", &thisModule)); - return wil::scope_exit([thisModule] - { - FreeLibraryAndExitThread(thisModule, 0); - }); - } -#endif - - /// @cond - namespace details - { - class init_once_completer - { - INIT_ONCE& m_once; - unsigned long m_flags = INIT_ONCE_INIT_FAILED; - public: - init_once_completer(_In_ INIT_ONCE& once) WI_NOEXCEPT : m_once(once) - { - } - - #pragma warning(push) - #pragma warning(disable:4702) // https://github.com/Microsoft/wil/issues/2 - void success() WI_NOEXCEPT - { - m_flags = 0; - } - #pragma warning(pop) - - ~init_once_completer() WI_NOEXCEPT - { - ::InitOnceComplete(&m_once, m_flags, nullptr); - } - }; - } - /// @endcond - - /** Performs one-time initialization - Simplifies using the Win32 INIT_ONCE structure to perform one-time initialization. The provided `func` is invoked - at most once. - ~~~~ - INIT_ONCE g_init{}; - ComPtr g_foo; - HRESULT MyMethod() - { - bool winner = false; - RETURN_IF_FAILED(wil::init_once_nothrow(g_init, [] - { - ComPtr foo; - RETURN_IF_FAILED(::CoCreateInstance(..., IID_PPV_ARGS(&foo)); - RETURN_IF_FAILED(foo->Startup()); - g_foo = foo; - }, &winner); - if (winner) - { - RETURN_IF_FAILED(g_foo->Another()); - } - return S_OK; - } - ~~~~ - See MSDN for more information on `InitOnceExecuteOnce`. - @param initOnce The INIT_ONCE structure to use as context for initialization. - @param func A function that will be invoked to perform initialization. If this fails, the init call - fails and the once-init is not marked as initialized. A later caller could attempt to - initialize it a second time. - @param callerCompleted Set to 'true' if this was the call that caused initialization, false otherwise. - */ - template HRESULT init_once_nothrow(_Inout_ INIT_ONCE& initOnce, T func, _Out_opt_ bool* callerCompleted = nullptr) WI_NOEXCEPT - { - BOOL pending = FALSE; - wil::assign_to_opt_param(callerCompleted, false); - - __WIL_PRIVATE_RETURN_IF_WIN32_BOOL_FALSE(InitOnceBeginInitialize(&initOnce, 0, &pending, nullptr)); - - if (pending) - { - details::init_once_completer completion(initOnce); - __WIL_PRIVATE_RETURN_IF_FAILED(func()); - completion.success(); - wil::assign_to_opt_param(callerCompleted, true); - } - - return S_OK; - } - - //! Similar to init_once_nothrow, but fails-fast if the initialization step failed. The 'callerComplete' value is - //! returned to the caller instead of being an out-parameter. - template bool init_once_failfast(_Inout_ INIT_ONCE& initOnce, T&& func) WI_NOEXCEPT - { - bool callerCompleted; - - FAIL_FAST_IF_FAILED(init_once_nothrow(initOnce, wistd::forward(func), &callerCompleted)); - - return callerCompleted; - }; - - //! Returns 'true' if this `init_once` structure has finished initialization, false otherwise. - inline bool init_once_initialized(_Inout_ INIT_ONCE& initOnce) WI_NOEXCEPT - { - BOOL pending = FALSE; - return ::InitOnceBeginInitialize(&initOnce, INIT_ONCE_CHECK_ONLY, &pending, nullptr) && !pending; - } - -#ifdef WIL_ENABLE_EXCEPTIONS - /** Performs one-time initialization - Simplifies using the Win32 INIT_ONCE structure to perform one-time initialization. The provided `func` is invoked - at most once. - ~~~~ - INIT_ONCE g_init{}; - ComPtr g_foo; - void MyMethod() - { - bool winner = wil::init_once(g_init, [] - { - ComPtr foo; - THROW_IF_FAILED(::CoCreateInstance(..., IID_PPV_ARGS(&foo)); - THROW_IF_FAILED(foo->Startup()); - g_foo = foo; - }); - if (winner) - { - THROW_IF_FAILED(g_foo->Another()); - } - } - ~~~~ - See MSDN for more information on `InitOnceExecuteOnce`. - @param initOnce The INIT_ONCE structure to use as context for initialization. - @param func A function that will be invoked to perform initialization. If this fails, the init call - fails and the once-init is not marked as initialized. A later caller could attempt to - initialize it a second time. - @returns 'true' if this was the call that caused initialization, false otherwise. - */ - template bool init_once(_Inout_ INIT_ONCE& initOnce, T func) - { - BOOL pending = FALSE; - - THROW_IF_WIN32_BOOL_FALSE(::InitOnceBeginInitialize(&initOnce, 0, &pending, nullptr)); - - if (pending) - { - details::init_once_completer completion(initOnce); - func(); - completion.success(); - return true; - } - else - { - return false; - } - } -#endif // WIL_ENABLE_EXCEPTIONS -} - -// Macro for calling GetProcAddress(), with type safety for C++ clients -// using the type information from the specified function. -// The return value is automatically cast to match the function prototype of the input function. -// -// Sample usage: -// -// auto sendMail = GetProcAddressByFunctionDeclaration(hinstMAPI, MAPISendMailW); -// if (sendMail) -// { -// sendMail(0, 0, pmm, MAPI_USE_DEFAULT, 0); -// } -// Declaration -#define GetProcAddressByFunctionDeclaration(hinst, fn) reinterpret_cast(GetProcAddress(hinst, #fn)) - -#endif // __WIL_WIN32_HELPERS_INCLUDED diff --git a/src/common/dep/wil/win32_result_macros.h b/src/common/dep/wil/win32_result_macros.h deleted file mode 100644 index 664f4b986..000000000 --- a/src/common/dep/wil/win32_result_macros.h +++ /dev/null @@ -1,104 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_WIN32_RESULTMACROS_INCLUDED -#define __WIL_WIN32_RESULTMACROS_INCLUDED - -#include "result_macros.h" - -// Helpers for return macros -#define __WIN32_RETURN_WIN32(error, str) __WI_SUPPRESS_4127_S do { const auto __error = (error); if (FAILED_WIN32(__error)) { __R_FN(Return_Win32)(__R_INFO(str) __error); } return __error; } __WI_SUPPRESS_4127_E while ((void)0, 0) -#define __WIN32_RETURN_GLE_FAIL(str) return __R_FN(Win32_Return_GetLastError)(__R_INFO_ONLY(str)) - -FORCEINLINE long __WIN32_FROM_HRESULT(HRESULT hr) -{ - if (SUCCEEDED(hr)) - { - return ERROR_SUCCESS; - } - return HRESULT_FACILITY(hr) == FACILITY_WIN32 ? HRESULT_CODE(hr) : hr; -} - -//***************************************************************************** -// Macros for returning failures as WIN32 error codes -//***************************************************************************** - -// Always returns a known result (WIN32 error code) - always logs failures -#define WIN32_RETURN_WIN32(error) __WIN32_RETURN_WIN32(wil::verify_win32(error), #error) -#define WIN32_RETURN_LAST_ERROR() __WIN32_RETURN_GLE_FAIL(nullptr) - -// Conditionally returns failures (WIN32 error code) - always logs failures -#define WIN32_RETURN_IF_WIN32_ERROR(error) __WI_SUPPRESS_4127_S do { const auto __errorRet = wil::verify_win32(error); if (FAILED_WIN32(__errorRet)) { __WIN32_RETURN_WIN32(__errorRet, #error); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define WIN32_RETURN_WIN32_IF(error, condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { __WIN32_RETURN_WIN32(wil::verify_win32(error), #condition); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define WIN32_RETURN_WIN32_IF_NULL(error, ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __WIN32_RETURN_WIN32(wil::verify_win32(error), #ptr); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define WIN32_RETURN_LAST_ERROR_IF(condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { __WIN32_RETURN_GLE_FAIL(#condition); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define WIN32_RETURN_LAST_ERROR_IF_NULL(ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { __WIN32_RETURN_GLE_FAIL(#ptr); }} __WI_SUPPRESS_4127_E while ((void)0, 0) - -// Conditionally returns failures (WIN32 error code) - use for failures that are expected in common use - failures are not logged - macros are only for control flow pattern -#define WIN32_RETURN_IF_WIN32_ERROR_EXPECTED(error) __WI_SUPPRESS_4127_S do { const auto __errorRet = wil::verify_win32(error); if (FAILED_WIN32(__errorRet)) { return __errorRet; }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define WIN32_RETURN_WIN32_IF_EXPECTED(error, condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { return wil::verify_win32(error); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define WIN32_RETURN_WIN32_IF_NULL_EXPECTED(error, ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { return wil::verify_win32(error); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define WIN32_RETURN_LAST_ERROR_IF_EXPECTED(condition) __WI_SUPPRESS_4127_S do { if (wil::verify_bool(condition)) { return wil::verify_win32(wil::details::GetLastErrorFail()); }} __WI_SUPPRESS_4127_E while ((void)0, 0) -#define WIN32_RETURN_LAST_ERROR_IF_NULL_EXPECTED(ptr) __WI_SUPPRESS_4127_S do { if ((ptr) == nullptr) { return wil::verify_win32(wil::details::GetLastErrorFail()); }} __WI_SUPPRESS_4127_E while ((void)0, 0) - - -//***************************************************************************** -// Macros to catch and convert exceptions on failure -//***************************************************************************** - -// Use these macros *within* a catch (...) block to handle exceptions -#define WIN32_RETURN_CAUGHT_EXCEPTION() return __R_FN(Win32_Return_CaughtException)(__R_INFO_ONLY(nullptr)) - -// Use these macros in place of a catch block to handle exceptions -#define WIN32_CATCH_RETURN() catch (...) { WIN32_RETURN_CAUGHT_EXCEPTION(); } - -namespace wil -{ - //***************************************************************************** - // Public Helpers that catch -- mostly only enabled when exceptions are enabled - //***************************************************************************** - - // Win32ErrorFromCaughtException is a function that is meant to be called from within a catch(...) block. Internally - // it re-throws and catches the exception to convert it to a WIN32 error code. If an exception is of an unrecognized type - // the function will fail fast. - // - // try - // { - // // Code - // } - // catch (...) - // { - // status = wil::Win32ErrorFromCaughtException(); - // } - _Always_(_Post_satisfies_(return > 0)) - __declspec(noinline) inline long Win32ErrorFromCaughtException() WI_NOEXCEPT - { - return __WIN32_FROM_HRESULT(ResultFromCaughtException()); - } - - namespace details::__R_NS_NAME - { -#ifdef WIL_ENABLE_EXCEPTIONS - __R_DIRECT_METHOD(long, Win32_Return_CaughtException)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - return __WIN32_FROM_HRESULT(wil::details::ReportFailure_CaughtException(__R_DIRECT_FN_CALL_ONLY)); - } -#endif - - __R_DIRECT_METHOD(long, Win32_Return_GetLastError)(__R_DIRECT_FN_PARAMS_ONLY) WI_NOEXCEPT - { - __R_FN_LOCALS; - return __WIN32_FROM_HRESULT(wil::details::ReportFailure_GetLastErrorHr(__R_DIRECT_FN_CALL_ONLY)); - } - } -} - -#endif // __WIL_WIN32_RESULTMACROS_INCLUDED diff --git a/src/common/dep/wil/winrt.h b/src/common/dep/wil/winrt.h deleted file mode 100644 index 37249893d..000000000 --- a/src/common/dep/wil/winrt.h +++ /dev/null @@ -1,2334 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_WINRT_INCLUDED -#define __WIL_WINRT_INCLUDED - -#include -#include -#include -#include -#include -#include "result.h" -#include "com.h" -#include "resource.h" -#include -#include - -#ifdef __cplusplus_winrt -#include // bring in the CRT iterator for support for C++ CX code -#endif - -/// @cond -#if defined(WIL_ENABLE_EXCEPTIONS) && !defined(__WI_HAS_STD_LESS) -#ifdef __has_include -#if __has_include() -#define __WI_HAS_STD_LESS 1 -#include -#endif // Otherwise, not using STL; don't specialize std::less -#else -// Fall back to the old way of forward declaring std::less -#define __WI_HAS_STD_LESS 1 -#pragma warning(push) -#pragma warning(disable:4643) // Forward declaring '...' in namespace std is not permitted by the C++ Standard. -namespace std -{ - template - struct less; -} -#pragma warning(pop) -#endif -#endif -#if defined(WIL_ENABLE_EXCEPTIONS) && defined(__has_include) -#if __has_include() -#define __WI_HAS_STD_VECTOR 1 -#include -#endif -#endif -/// @endcond - -// This enables this code to be used in code that uses the ABI prefix or not. -// Code using the public SDK and C++ CX code has the ABI prefix, windows internal -// is built in a way that does not. -#if !defined(MIDL_NS_PREFIX) && !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) -// Internal .idl files use the namespace without the ABI prefix. Macro out ABI for that case -#pragma push_macro("ABI") -#undef ABI -#define ABI -#endif - -namespace wil -{ - // time_t is the number of 1 - second intervals since January 1, 1970. - constexpr long long SecondsToStartOf1970 = 0x2b6109100; - constexpr long long HundredNanoSecondsInSecond = 10000000LL; - - inline __time64_t DateTime_to_time_t(ABI::Windows::Foundation::DateTime dateTime) - { - // DateTime is the number of 100 - nanosecond intervals since January 1, 1601. - return (dateTime.UniversalTime / HundredNanoSecondsInSecond - SecondsToStartOf1970); - } - - inline ABI::Windows::Foundation::DateTime time_t_to_DateTime(__time64_t timeT) - { - ABI::Windows::Foundation::DateTime dateTime; - dateTime.UniversalTime = (timeT + SecondsToStartOf1970) * HundredNanoSecondsInSecond; - return dateTime; - } - -#pragma region HSTRING Helpers - /// @cond - namespace details - { - // hstring_compare is used to assist in HSTRING comparison of two potentially non-similar string types. E.g. - // comparing a raw HSTRING with WRL's HString/HStringReference/etc. The consumer can optionally inhibit the - // deduction of array sizes by providing 'true' for the 'InhibitStringArrays' template argument. This is - // generally done in scenarios where the consumer cannot guarantee that the input argument types are perfectly - // preserved from end-to-end. E.g. if a single function in the execution path captures an array as const T&, - // then it is impossible to differentiate const arrays (where we generally do want to deduce length) from - // non-const arrays (where we generally do not want to deduce length). The consumer can also optionally choose - // to perform case-insensitive comparison by providing 'true' for the 'IgnoreCase' template argument. - template - struct hstring_compare - { - // get_buffer returns the string buffer and length for the supported string types - static const wchar_t* get_buffer(HSTRING hstr, UINT32* length) WI_NOEXCEPT - { - return ::WindowsGetStringRawBuffer(hstr, length); - } - - static const wchar_t* get_buffer(const Microsoft::WRL::Wrappers::HString& hstr, UINT32* length) WI_NOEXCEPT - { - return hstr.GetRawBuffer(length); - } - - static const wchar_t* get_buffer( - const Microsoft::WRL::Wrappers::HStringReference& hstr, - UINT32* length) WI_NOEXCEPT - { - return hstr.GetRawBuffer(length); - } - - static const wchar_t* get_buffer(const unique_hstring& str, UINT32* length) WI_NOEXCEPT - { - return ::WindowsGetStringRawBuffer(str.get(), length); - } - - template - static wistd::enable_if_t get_buffer(const wchar_t* str, UINT32* length) WI_NOEXCEPT - { - str = (str != nullptr) ? str : L""; - *length = static_cast(wcslen(str)); - return str; - } - - template - static wistd::enable_if_t< - wistd::conjunction< - wistd::is_pointer, - wistd::is_same>, wchar_t>, - wistd::bool_constant - >::value, - const wchar_t*> get_buffer(StringT str, UINT32* length) WI_NOEXCEPT - { - str = (str != nullptr) ? str : L""; - *length = static_cast(wcslen(str)); - return str; - } - - template - static wistd::enable_if_t get_buffer( - const wchar_t (&str)[Size], - UINT32* length) WI_NOEXCEPT - { - *length = Size - 1; - return str; - } - - template - static wistd::enable_if_t get_buffer(wchar_t (&str)[Size], UINT32* length) WI_NOEXCEPT - { - *length = static_cast(wcslen(str)); - return str; - } - - // Overload for std::wstring, or at least things that behave like std::wstring, without adding a dependency - // on STL headers - template - static wistd::enable_if_t, - wistd::is_convertible().data()), const wchar_t*>, - wistd::is_same().size())>>, - const wchar_t*> get_buffer(const StringT& str, UINT32* length) WI_NOEXCEPT - { - *length = static_cast(str.size()); - const wchar_t* ret = str.data(); - return ret ? ret : L""; - } - - template - static auto compare(LhsT&& lhs, RhsT&& rhs) -> - decltype(get_buffer(lhs, wistd::declval()), get_buffer(rhs, wistd::declval()), int()) - { - UINT32 lhsLength; - UINT32 rhsLength; - auto lhsBuffer = get_buffer(wistd::forward(lhs), &lhsLength); - auto rhsBuffer = get_buffer(wistd::forward(rhs), &rhsLength); - - const auto result = ::CompareStringOrdinal( - lhsBuffer, - lhsLength, - rhsBuffer, - rhsLength, - IgnoreCase ? TRUE : FALSE); - WI_ASSERT(result != 0); - - return result; - } - - template - static auto equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT -> - decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) - { - return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_EQUAL; - } - - template - static auto not_equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT -> - decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) - { - return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_EQUAL; - } - - template - static auto less(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT -> - decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) - { - return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_LESS_THAN; - } - - template - static auto less_equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT -> - decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) - { - return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_GREATER_THAN; - } - - template - static auto greater(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT -> - decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) - { - return compare(wistd::forward(lhs), wistd::forward(rhs)) == CSTR_GREATER_THAN; - } - - template - static auto greater_equals(LhsT&& lhs, RhsT&& rhs) WI_NOEXCEPT -> - decltype(compare(wistd::forward(lhs), wistd::forward(rhs)), bool()) - { - return compare(wistd::forward(lhs), wistd::forward(rhs)) != CSTR_LESS_THAN; - } - }; - } - /// @endcond - - //! Detects if one or more embedded null is present in an HSTRING. - inline bool HasEmbeddedNull(_In_opt_ HSTRING value) - { - BOOL hasEmbeddedNull = FALSE; - (void)WindowsStringHasEmbeddedNull(value, &hasEmbeddedNull); - return hasEmbeddedNull != FALSE; - } - - /** TwoPhaseHStringConstructor help using the 2 phase constructor pattern for HSTRINGs. - ~~~ - auto stringConstructor = wil::TwoPhaseHStringConstructor::Preallocate(size); - RETURN_IF_NULL_ALLOC(stringConstructor.Get()); - - RETURN_IF_FAILED(stream->Read(stringConstructor.Get(), stringConstructor.ByteSize(), &bytesRead)); - - // Validate stream contents, sizes must match, string must be null terminated. - RETURN_IF_FAILED(stringConstructor.Validate(bytesRead)); - - wil::unique_hstring string { stringConstructor.Promote() }; - ~~~ - - See also wil::unique_hstring_buffer. - */ - struct TwoPhaseHStringConstructor - { - TwoPhaseHStringConstructor() = delete; - TwoPhaseHStringConstructor(const TwoPhaseHStringConstructor&) = delete; - void operator=(const TwoPhaseHStringConstructor&) = delete; - - TwoPhaseHStringConstructor(TwoPhaseHStringConstructor&& other) WI_NOEXCEPT - { - m_characterLength = other.m_characterLength; - other.m_characterLength = 0; - m_maker = wistd::move(other.m_maker); - } - - static TwoPhaseHStringConstructor Preallocate(UINT32 characterLength) - { - return TwoPhaseHStringConstructor{ characterLength }; - } - - //! Returns the HSTRING after it has been populated like Detatch() or release(); be sure to put this in a RAII type to manage its lifetime. - HSTRING Promote() - { - m_characterLength = 0; - return m_maker.release().release(); - } - - ~TwoPhaseHStringConstructor() = default; - - WI_NODISCARD explicit operator PCWSTR() const - { - // This is set by WindowsPromoteStringBuffer() which must be called to - // construct this object via the static method Preallocate(). - return m_maker.buffer(); - } - - //! Returns a pointer for the buffer so it can be populated - WI_NODISCARD wchar_t* Get() const { return const_cast(m_maker.buffer()); } - //! Used to validate range of buffer when populating. - WI_NODISCARD ULONG ByteSize() const { return m_characterLength * sizeof(wchar_t); } - - /** Ensure that the size of the data provided is consistent with the pre-allocated buffer. - It seems that WindowsPreallocateStringBuffer() provides the null terminator in the buffer - (based on testing) so this can be called before populating the buffer. - */ - WI_NODISCARD HRESULT Validate(ULONG bytesRead) const - { - // Null termination is required for the buffer before calling WindowsPromoteStringBuffer(). - RETURN_HR_IF(HRESULT_FROM_WIN32(ERROR_INVALID_DATA), - (bytesRead != ByteSize()) || - (Get()[m_characterLength] != L'\0')); - return S_OK; - } - - private: - TwoPhaseHStringConstructor(UINT32 characterLength) : m_characterLength(characterLength) - { - (void)m_maker.make(nullptr, characterLength); - } - - UINT32 m_characterLength; - details::string_maker m_maker; - }; - - //! A transparent less-than comparison function object that enables comparison of various string types intended for - //! use with associative containers (such as `std::set`, `std::map`, etc.) that use - //! `Microsoft::WRL::Wrappers::HString` as the key type. This removes the need for the consumer to explicitly - //! create an `HString` object when using lookup functions such as `find`, `lower_bound`, etc. For example, the - //! following scenarios would all work exactly as you would expect them to: - //! ~~~ - //! std::map map; - //! const wchar_t constArray[] = L"foo"; - //! wchar_t nonConstArray[MAX_PATH] = L"foo"; - //! - //! HString key; - //! THROW_IF_FAILED(key.Set(constArray)); - //! map.emplace(std::move(key), 42); - //! - //! HString str; - //! wil::unique_hstring uniqueStr; - //! THROW_IF_FAILED(str.Set(L"foo")); - //! THROW_IF_FAILED(str.CopyTo(&uniqueStr)); - //! - //! // All of the following return an iterator to the pair { L"foo", 42 } - //! map.find(str); - //! map.find(str.Get()); - //! map.find(HStringReference(constArray)); - //! map.find(uniqueStr); - //! map.find(std::wstring(constArray)); - //! map.find(constArray); - //! map.find(nonConstArray); - //! map.find(static_cast(constArray)); - //! ~~~ - //! The first four calls in the example above use `WindowsGetStringRawBuffer` (or equivalent) to get the string - //! buffer and length for the comparison. The fifth example uses `std::wstring::c_str` and `std::wstring::length` - //! for getting these two values. The remaining three examples use only the string buffer and call `wcslen` for the - //! length. That is, the length is *not* deduced for either array. This is because argument types are not always - //! perfectly preserved by container functions and in fact are often captured as const references making it - //! impossible to differentiate const arrays - where we can safely deduce length - from non const arrays - where we - //! cannot safely deduce length since the buffer may be larger than actually needed (e.g. creating a - //! `char[MAX_PATH]` array, but only filling it with 10 characters). The implications of this behavior is that - //! string literals that contain embedded null characters will only include the part of the buffer up to the first - //! null character. For example, the following example will result in all calls to `find` returning an end - //! iterator. - //! ~~~ - //! std::map map; - //! const wchar_t constArray[] = L"foo\0bar"; - //! wchar_t nonConstArray[MAX_PATH] = L"foo\0bar"; - //! - //! // Create the key with the embedded null character - //! HString key; - //! THROW_IF_FAILED(key.Set(constArray)); - //! map.emplace(std::move(key), 42); - //! - //! // All of the following return map.end() since they look for the string "foo" - //! map.find(constArray); - //! map.find(nonConstArray); - //! map.find(static_cast(constArray)); - //! ~~~ - //! In order to search using a string literal that contains embedded null characters, a simple alternative is to - //! first create an `HStringReference` and use that for the function call: - //! ~~~ - //! // HStringReference's constructor *will* deduce the length of const arrays - //! map.find(HStringReference(constArray)); - //! ~~~ - struct hstring_less - { - using is_transparent = void; - - template - WI_NODISCARD auto operator()(const LhsT& lhs, const RhsT& rhs) const WI_NOEXCEPT -> - decltype(details::hstring_compare::less(lhs, rhs)) - { - return details::hstring_compare::less(lhs, rhs); - } - }; - - //! A transparent less-than comparison function object whose behavior is equivalent to that of @ref hstring_less - //! with the one difference that comparisons are case-insensitive. That is, the following example will correctly - //! find the inserted value: - //! ~~~ - //! std::map map; - //! - //! HString key; - //! THROW_IF_FAILED(key.Set(L"foo")); - //! map.emplace(std::move(key), 42); - //! - //! // All of the following return an iterator to the pair { L"foo", 42 } - //! map.find(L"FOo"); - //! map.find(HStringReference(L"fOo")); - //! map.find(HStringReference(L"fOO").Get()); - //! ~~~ - struct hstring_insensitive_less - { - using is_transparent = void; - - template - WI_NODISCARD auto operator()(const LhsT& lhs, const RhsT& rhs) const WI_NOEXCEPT -> - decltype(details::hstring_compare::less(lhs, rhs)) - { - return details::hstring_compare::less(lhs, rhs); - } - }; - -#pragma endregion - - /// @cond - namespace details - { - // MapToSmartType::type is used to map a raw type into an RAII expression - // of it. This is needed when lifetime management of the type is needed, for example - // when holding them as a value produced in an iterator. - // This type has a common set of methods used to abstract the access to the value - // that is similar to ComPtr<> and the WRL Wrappers: Get(), GetAddressOf() and other operators. - // Clients of the smart type must use those to access the value. - - // TODO: Having the base definition defined will result in creating leaks if a type - // that needs resource management (e.g. PROPVARIANT) that has not specialized is used. - // - // One fix is to use std::is_enum to cover that case and leave the base definition undefined. - // That base should use static_assert to inform clients how to fix the lack of specialization. - template struct MapToSmartType - { - #pragma warning(push) - #pragma warning(disable:4702) // https://github.com/Microsoft/wil/issues/2 - struct type // T holder - { - type() = default; - type(T&& value) : m_value(wistd::forward(value)) {} - WI_NODISCARD operator T() const { return m_value; } - type& operator=(T&& value) { m_value = wistd::forward(value); return *this; } - WI_NODISCARD T Get() const { return m_value; } - - // Returning T&& to support move only types - // In case of absence of T::operator=(T&&) a call to T::operator=(const T&) will happen - T&& Get() { return wistd::move(m_value); } - - WI_NODISCARD HRESULT CopyTo(T* result) const { *result = m_value; return S_OK; } - T* GetAddressOf() { return &m_value; } - T* ReleaseAndGetAddressOf() { return &m_value; } - T* operator&() { return &m_value; } - T m_value{}; - }; - #pragma warning(pop) - }; - - // IUnknown * derived -> Microsoft::WRL::ComPtr<> - template - struct MapToSmartType::type>::value>::type> - { - typedef Microsoft::WRL::ComPtr::type> type; - }; - - // HSTRING -> Microsoft::WRL::Wrappers::HString - template <> struct MapToSmartType - { - class HStringWithRelease : public Microsoft::WRL::Wrappers::HString - { - public: - // Unlike all other WRL types HString does not have ReleaseAndGetAddressOf and - // GetAddressOf() has non-standard behavior, calling Release(). - HSTRING* ReleaseAndGetAddressOf() WI_NOEXCEPT - { - Release(); - return &hstr_; - } - }; - typedef HStringWithRelease type; - }; - - // WinRT interfaces like IVector<>, IAsyncOperation<> and IIterable<> can be templated - // on a runtime class (instead of an interface or primitive type). In these cases the objects - // produced by those interfaces implement an interface defined by the runtime class default interface. - // - // These templates deduce the type of the produced interface or pass through - // the type unmodified in the non runtime class case. - // - // for example: - // IAsyncOperation -> IAsyncOperation - - // For IVector, IVectorView. - template struct MapVectorResultType - { - template - static TResult PeekGetAtType(HRESULT(STDMETHODCALLTYPE TVector::*)(unsigned, TResult*)); - typedef decltype(PeekGetAtType(&VectorType::GetAt)) type; - }; - - // For IIterator. - template struct MapIteratorResultType - { - template - static TResult PeekCurrentType(HRESULT(STDMETHODCALLTYPE TIterable::*)(TResult*)); - typedef decltype(PeekCurrentType(&ABI::Windows::Foundation::Collections::IIterator::get_Current)) type; - }; - - // For IAsyncOperation. - template struct MapAsyncOpResultType - { - template - static TResult PeekGetResultsType(HRESULT(STDMETHODCALLTYPE TAsyncOperation::*)(TResult*)); - typedef decltype(PeekGetResultsType(&ABI::Windows::Foundation::IAsyncOperation::GetResults)) type; - }; - - // For IAsyncOperationWithProgress. - template struct MapAsyncOpProgressResultType - { - template - static TResult PeekGetResultsType(HRESULT(STDMETHODCALLTYPE TAsyncOperation::*)(TResult*)); - typedef decltype(PeekGetResultsType(&ABI::Windows::Foundation::IAsyncOperationWithProgress::GetResults)) type; - }; - - // No support for IAsyncActionWithProgress

none of these (currently) use - // a runtime class for the progress type. - } - /// @endcond -#pragma region C++ iterators for WinRT collections for use with range based for and STL algorithms - - /** Range base for and STL algorithms support for WinRT ABI collection types, IVector, IVectorView, IIterable - similar to support provided by for C++ CX. Three error handling policies are supported. - ~~~ - ComPtr collection = GetCollection(); // can be IVector, IVectorView or IIterable - - for (auto const& element : wil::get_range(collection.Get())) // exceptions - for (auto const& element : wil::get_range_nothrow(collection.Get(), &hr)) // error code - for (auto const& element : wil::get_range_failfast(collection.Get())) // fail fast - { - // use element - } - ~~~ - Standard algorithm example: - ~~~ - ComPtr> files = GetFiles(); - auto fileRange = wil::get_range_nothrow(files.Get()); - auto itFound = std::find_if(fileRange.begin(), fileRange.end(), [](ComPtr file) -> bool - { - return true; // first element in range - }); - ~~~ - */ -#pragma region exception and fail fast based IVector<>/IVectorView<> - - template - class vector_range - { - public: - typedef typename details::MapVectorResultType::type TResult; - typedef typename details::MapToSmartType::type TSmart; - - vector_range() = delete; - - explicit vector_range(_In_ VectorType *vector) : m_v(vector) - { - } - - class vector_iterator - { - public: -#ifdef _XUTILITY_ - // could be random_access_iterator_tag but missing some features - typedef ::std::bidirectional_iterator_tag iterator_category; -#endif - typedef TSmart value_type; - typedef ptrdiff_t difference_type; - typedef const TSmart* pointer; - typedef const TSmart& reference; - - // for begin() - vector_iterator(VectorType* v, unsigned int pos) - : m_v(v), m_i(pos) - { - } - - // for end() - vector_iterator() : m_v(nullptr), m_i(-1) {} - - vector_iterator(const vector_iterator& other) - { - m_v = other.m_v; - m_i = other.m_i; - err_policy::HResult(other.m_element.CopyTo(m_element.GetAddressOf())); - } - - vector_iterator& operator=(const vector_iterator& other) - { - if (this != wistd::addressof(other)) - { - m_v = other.m_v; - m_i = other.m_i; - err_policy::HResult(other.m_element.CopyTo(m_element.ReleaseAndGetAddressOf())); - } - return *this; - } - - reference operator*() - { - err_policy::HResult(m_v->GetAt(m_i, m_element.ReleaseAndGetAddressOf())); - return m_element; - } - - pointer operator->() - { - err_policy::HResult(m_v->GetAt(m_i, m_element.ReleaseAndGetAddressOf())); - return wistd::addressof(m_element); - } - - vector_iterator& operator++() - { - ++m_i; - return *this; - } - - vector_iterator& operator--() - { - --m_i; - return *this; - } - - vector_iterator operator++(int) - { - vector_iterator old(*this); - ++*this; - return old; - } - - vector_iterator operator--(int) - { - vector_iterator old(*this); - --*this; - return old; - } - - vector_iterator& operator+=(int n) - { - m_i += n; - return *this; - } - - vector_iterator& operator-=(int n) - { - m_i -= n; - return *this; - } - - WI_NODISCARD vector_iterator operator+(int n) const - { - vector_iterator ret(*this); - ret += n; - return ret; - } - - WI_NODISCARD vector_iterator operator-(int n) const - { - vector_iterator ret(*this); - ret -= n; - return ret; - } - - WI_NODISCARD ptrdiff_t operator-(const vector_iterator& other) const - { - return m_i - other.m_i; - } - - WI_NODISCARD bool operator==(const vector_iterator& other) const - { - return m_i == other.m_i; - } - - WI_NODISCARD bool operator!=(const vector_iterator& other) const - { - return m_i != other.m_i; - } - - WI_NODISCARD bool operator<(const vector_iterator& other) const - { - return m_i < other.m_i; - } - - WI_NODISCARD bool operator>(const vector_iterator& other) const - { - return m_i > other.m_i; - } - - WI_NODISCARD bool operator<=(const vector_iterator& other) const - { - return m_i <= other.m_i; - } - - WI_NODISCARD bool operator>=(const vector_iterator& other) const - { - return m_i >= other.m_i; - } - - private: - VectorType* m_v; // weak, collection must outlive iterators. - unsigned int m_i; - TSmart m_element; - }; - - vector_iterator begin() - { - return vector_iterator(m_v, 0); - } - - vector_iterator end() - { - unsigned int size; - err_policy::HResult(m_v->get_Size(&size)); - return vector_iterator(m_v, size); - } - private: - VectorType* m_v; // weak, collection must outlive iterators. - }; -#pragma endregion - -#pragma region error code based IVector<>/IVectorView<> - - template - class vector_range_nothrow - { - public: - typedef typename details::MapVectorResultType::type TResult; - typedef typename details::MapToSmartType::type TSmart; - - vector_range_nothrow() = delete; - vector_range_nothrow(const vector_range_nothrow&) = delete; - vector_range_nothrow& operator=(const vector_range_nothrow&) = delete; - - vector_range_nothrow(vector_range_nothrow&& other) WI_NOEXCEPT : - m_v(other.m_v), m_size(other.m_size), m_result(other.m_result), m_resultStorage(other.m_resultStorage), - m_currentElement(wistd::move(other.m_currentElement)) - { - } - - vector_range_nothrow(_In_ VectorType *vector, HRESULT* result = nullptr) - : m_v(vector), m_result(result ? result : &m_resultStorage) - { - *m_result = m_v->get_Size(&m_size); - } - - class vector_iterator_nothrow - { - public: -#ifdef _XUTILITY_ - // must be input_iterator_tag as use (via ++, --, etc.) of one invalidates the other. - typedef ::std::input_iterator_tag iterator_category; -#endif - typedef TSmart value_type; - typedef ptrdiff_t difference_type; - typedef const TSmart* pointer; - typedef const TSmart& reference; - - vector_iterator_nothrow() = delete; - vector_iterator_nothrow(vector_range_nothrow* range, unsigned int pos) - : m_range(range), m_i(pos) - { - } - - WI_NODISCARD reference operator*() const - { - return m_range->m_currentElement; - } - - WI_NODISCARD pointer operator->() const - { - return wistd::addressof(m_range->m_currentElement); - } - - vector_iterator_nothrow& operator++() - { - ++m_i; - m_range->get_at_current(m_i); - return *this; - } - - vector_iterator_nothrow& operator--() - { - --m_i; - m_range->get_at_current(m_i); - return *this; - } - - vector_iterator_nothrow operator++(int) - { - vector_iterator_nothrow old(*this); - ++*this; - return old; - } - - vector_iterator_nothrow operator--(int) - { - vector_iterator_nothrow old(*this); - --*this; - return old; - } - - vector_iterator_nothrow& operator+=(int n) - { - m_i += n; - m_range->get_at_current(m_i); - return *this; - } - - vector_iterator_nothrow& operator-=(int n) - { - m_i -= n; - m_range->get_at_current(m_i); - return *this; - } - - WI_NODISCARD bool operator==(vector_iterator_nothrow const& other) const - { - return FAILED(*m_range->m_result) || (m_i == other.m_i); - } - - WI_NODISCARD bool operator!=(vector_iterator_nothrow const& other) const - { - return !operator==(other); - } - - private: - vector_range_nothrow* m_range; - unsigned int m_i = 0; - }; - - vector_iterator_nothrow begin() - { - get_at_current(0); - return vector_iterator_nothrow(this, 0); - } - - vector_iterator_nothrow end() - { - return vector_iterator_nothrow(this, m_size); - } - - // Note, the error code is observed in operator!= and operator==, it always - // returns "equal" in the failed state to force the compare to the end - // iterator to return false and stop the loop. - // - // Is this ok for the general case? - void get_at_current(unsigned int i) - { - if (SUCCEEDED(*m_result) && (i < m_size)) - { - *m_result = m_v->GetAt(i, m_currentElement.ReleaseAndGetAddressOf()); - } - } - - private: - VectorType* m_v; // weak, collection must outlive iterators. - unsigned int m_size; - - // This state is shared by vector_iterator_nothrow instances. this means - // use of one iterator invalidates the other. - HRESULT* m_result; - HRESULT m_resultStorage = S_OK; // for the case where the caller does not provide the location to store the result - TSmart m_currentElement; - }; - -#pragma endregion - -#pragma region exception and fail fast based IIterable<> - - template - class iterable_range - { - public: - typedef typename details::MapIteratorResultType::type TResult; - typedef typename details::MapToSmartType::type TSmart; - - explicit iterable_range(_In_ ABI::Windows::Foundation::Collections::IIterable* iterable) - : m_iterable(iterable) - { - } - - class iterable_iterator - { - public: -#ifdef _XUTILITY_ - typedef ::std::forward_iterator_tag iterator_category; -#endif - typedef TSmart value_type; - typedef ptrdiff_t difference_type; - typedef const TSmart* pointer; - typedef const TSmart& reference; - - iterable_iterator() : m_i(-1) {} - - // for begin() - explicit iterable_iterator(_In_ ABI::Windows::Foundation::Collections::IIterable* iterable) - { - err_policy::HResult(iterable->First(&m_iterator)); - boolean hasCurrent; - err_policy::HResult(m_iterator->get_HasCurrent(&hasCurrent)); - m_i = hasCurrent ? 0 : -1; - } - - // for end() - iterable_iterator(int /*currentIndex*/) : m_i(-1) - { - } - - iterable_iterator(const iterable_iterator& other) - { - m_iterator = other.m_iterator; - m_i = other.m_i; - err_policy::HResult(other.m_element.CopyTo(m_element.GetAddressOf())); - } - - iterable_iterator& operator=(const iterable_iterator& other) - { - m_iterator = other.m_iterator; - m_i = other.m_i; - err_policy::HResult(other.m_element.CopyTo(m_element.ReleaseAndGetAddressOf())); - return *this; - } - - WI_NODISCARD bool operator==(iterable_iterator const& other) const - { - return m_i == other.m_i; - } - - WI_NODISCARD bool operator!=(iterable_iterator const& other) const - { - return !operator==(other); - } - - reference operator*() - { - err_policy::HResult(m_iterator->get_Current(m_element.ReleaseAndGetAddressOf())); - return m_element; - } - - pointer operator->() - { - err_policy::HResult(m_iterator->get_Current(m_element.ReleaseAndGetAddressOf())); - return wistd::addressof(m_element); - } - - iterable_iterator& operator++() - { - boolean hasCurrent; - err_policy::HResult(m_iterator->MoveNext(&hasCurrent)); - if (hasCurrent) - { - m_i++; - } - else - { - m_i = -1; - } - return *this; - } - - iterable_iterator operator++(int) - { - iterable_iterator old(*this); - ++*this; - return old; - } - - private: - Microsoft::WRL::ComPtr> m_iterator; - int m_i; - TSmart m_element; - }; - - iterable_iterator begin() - { - return iterable_iterator(m_iterable); - } - - iterable_iterator end() - { - return iterable_iterator(); - } - private: - // weak, collection must outlive iterators. - ABI::Windows::Foundation::Collections::IIterable* m_iterable; - }; -#pragma endregion - -#if defined(__WI_HAS_STD_VECTOR) - /** Converts WinRT vectors to std::vector by requesting the collection's data in a single - operation. This can be more efficient in terms of IPC cost than iteratively processing it. - ~~~ - ComPtr> values = GetValues(); - std::vector> allData = wil::to_vector(values); - for (ComPtr const& item : allData) - { - // use item - } - Can be used for ABI::Windows::Foundation::Collections::IVector and - ABI::Windows::Foundation::Collections::IVectorView - */ - template auto to_vector(VectorType* src) - { - using TResult = typename details::MapVectorResultType::type; - using TSmart = typename details::MapToSmartType::type; - static_assert(sizeof(TResult) == sizeof(TSmart), "result and smart sizes are different"); - std::vector output; - UINT32 expected = 0; - THROW_IF_FAILED(src->get_Size(&expected)); - if (expected > 0) - { - output.resize(expected + 1); - UINT32 fetched = 0; - THROW_IF_FAILED(src->GetMany(0, static_cast(output.size()), reinterpret_cast(output.data()), &fetched)); - THROW_HR_IF(E_CHANGED_STATE, fetched > expected); - output.resize(fetched); - } - return output; - } -#endif - -#pragma region error code base IIterable<> - template - class iterable_range_nothrow - { - public: - typedef typename details::MapIteratorResultType::type TResult; - typedef typename details::MapToSmartType::type TSmart; - - iterable_range_nothrow() = delete; - iterable_range_nothrow(const iterable_range_nothrow&) = delete; - iterable_range_nothrow& operator=(const iterable_range_nothrow&) = delete; - iterable_range_nothrow& operator=(iterable_range_nothrow &&) = delete; - - iterable_range_nothrow(iterable_range_nothrow&& other) WI_NOEXCEPT : - m_iterator(wistd::move(other.m_iterator)), m_element(wistd::move(other.m_element)), - m_resultStorage(other.m_resultStorage) - { - if (other.m_result == &other.m_resultStorage) - { - m_result = &m_resultStorage; - } - else - { - m_result = other.m_result; - } - } - - iterable_range_nothrow(_In_ ABI::Windows::Foundation::Collections::IIterable* iterable, HRESULT* result = nullptr) - : m_result(result ? result : &m_resultStorage) - { - *m_result = iterable->First(&m_iterator); - if (SUCCEEDED(*m_result)) - { - boolean hasCurrent; - *m_result = m_iterator->get_HasCurrent(&hasCurrent); - if (SUCCEEDED(*m_result) && hasCurrent) - { - *m_result = m_iterator->get_Current(m_element.ReleaseAndGetAddressOf()); - if (FAILED(*m_result)) - { - m_iterator = nullptr; // release the iterator if no elements are found - } - } - else - { - m_iterator = nullptr; // release the iterator if no elements are found - } - } - } - - class iterable_iterator_nothrow - { - public: -#ifdef _XUTILITY_ - // muse be input_iterator_tag as use of one instance invalidates the other. - typedef ::std::input_iterator_tag iterator_category; -#endif - typedef TSmart value_type; - typedef ptrdiff_t difference_type; - typedef const TSmart* pointer; - typedef const TSmart& reference; - - iterable_iterator_nothrow(_In_ iterable_range_nothrow* range, int currentIndex) : - m_range(range), m_i(currentIndex) - { - } - - WI_NODISCARD bool operator==(iterable_iterator_nothrow const& other) const - { - return FAILED(*m_range->m_result) || (m_i == other.m_i); - } - - WI_NODISCARD bool operator!=(iterable_iterator_nothrow const& other) const - { - return !operator==(other); - } - - WI_NODISCARD reference operator*() const WI_NOEXCEPT - { - return m_range->m_element; - } - - WI_NODISCARD pointer operator->() const WI_NOEXCEPT - { - return wistd::addressof(m_range->m_element); - } - - iterable_iterator_nothrow& operator++() - { - boolean hasCurrent; - *m_range->m_result = m_range->m_iterator->MoveNext(&hasCurrent); - if (SUCCEEDED(*m_range->m_result) && hasCurrent) - { - *m_range->m_result = m_range->m_iterator->get_Current(m_range->m_element.ReleaseAndGetAddressOf()); - if (SUCCEEDED(*m_range->m_result)) - { - m_i++; - } - else - { - m_i = -1; - } - } - else - { - m_i = -1; - } - return *this; - } - - iterable_range_nothrow operator++(int) - { - iterable_range_nothrow old(*this); - ++*this; - return old; - } - - private: - iterable_range_nothrow* m_range; - int m_i; - }; - - iterable_iterator_nothrow begin() - { - return iterable_iterator_nothrow(this, this->m_iterator ? 0 : -1); - } - - iterable_iterator_nothrow end() - { - return iterable_iterator_nothrow(this, -1); - } - - private: - Microsoft::WRL::ComPtr> m_iterator; - // This state is shared by all iterator instances - // so use of one iterator can invalidate another's ability to dereference - // that is allowed for input iterators. - TSmart m_element; - HRESULT* m_result; - HRESULT m_resultStorage = S_OK; - }; - -#pragma endregion - -#ifdef WIL_ENABLE_EXCEPTIONS - template vector_range> get_range(ABI::Windows::Foundation::Collections::IVector *v) - { - return vector_range>(v); - } - - template vector_range> get_range(ABI::Windows::Foundation::Collections::IVectorView *v) - { - return vector_range>(v); - } -#endif // WIL_ENABLE_EXCEPTIONS - - template vector_range, err_failfast_policy> get_range_failfast(ABI::Windows::Foundation::Collections::IVector *v) - { - return vector_range, err_failfast_policy>(v); - } - - template vector_range, err_failfast_policy> get_range_failfast(ABI::Windows::Foundation::Collections::IVectorView *v) - { - return vector_range, err_failfast_policy>(v); - } - - template vector_range_nothrow> get_range_nothrow(ABI::Windows::Foundation::Collections::IVector *v, HRESULT* result = nullptr) - { - return vector_range_nothrow>(v, result); - } - - template vector_range_nothrow> get_range_nothrow(ABI::Windows::Foundation::Collections::IVectorView *v, HRESULT* result = nullptr) - { - return vector_range_nothrow>(v, result); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - template iterable_range get_range(ABI::Windows::Foundation::Collections::IIterable *v) - { - return iterable_range(v); - } -#endif // WIL_ENABLE_EXCEPTIONS - - template iterable_range get_range_failfast(ABI::Windows::Foundation::Collections::IIterable *v) - { - return iterable_range(v); - } - - template iterable_range_nothrow get_range_nothrow(ABI::Windows::Foundation::Collections::IIterable *v, HRESULT* result = nullptr) - { - return iterable_range_nothrow(v, result); - } -} - -#pragma endregion - -#ifdef WIL_ENABLE_EXCEPTIONS - -#pragma region Global operator functions -#if defined(MIDL_NS_PREFIX) || defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) -namespace ABI { -#endif - namespace Windows { - namespace Foundation { - namespace Collections { - template typename wil::vector_range>::vector_iterator begin(IVector* v) - { - return typename wil::vector_range>::vector_iterator(v, 0); - } - - template typename wil::vector_range>::vector_iterator end(IVector* v) - { - unsigned int size; - THROW_IF_FAILED(v->get_Size(&size)); - return typename wil::vector_range>::vector_iterator(v, size); - } - - template typename wil::vector_range>::vector_iterator begin(IVectorView* v) - { - return typename wil::vector_range>::vector_iterator(v, 0); - } - - template typename wil::vector_range>::vector_iterator end(IVectorView* v) - { - unsigned int size; - THROW_IF_FAILED(v->get_Size(&size)); - return typename wil::vector_range>::vector_iterator(v, size); - } - - template typename wil::iterable_range::iterable_iterator begin(IIterable* i) - { - return typename wil::iterable_range::iterable_iterator(i); - } - - template typename wil::iterable_range::iterable_iterator end(IIterable*) - { - return typename wil::iterable_range::iterable_iterator(); - } - } // namespace Collections - } // namespace Foundation - } // namespace Windows -#if defined(MIDL_NS_PREFIX) || defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) -} // namespace ABI -#endif - -#endif // WIL_ENABLE_EXCEPTIONS - -#pragma endregion - -namespace wil -{ -#pragma region WinRT Async API helpers - -/// @cond -namespace details -{ - template ::value, int>::type = 0> - HRESULT CallAndHandleErrorsWithReturnType(TFunc&& func, Args&&... args) - { - return wistd::forward(func)(wistd::forward(args)...); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - template ::value, int>::type = 0> - HRESULT CallAndHandleErrorsWithReturnType(TFunc&& func, Args&&... args) - { - try - { - wistd::forward(func)(wistd::forward(args)...); - } - CATCH_RETURN(); - return S_OK; - } -#endif - - template - HRESULT CallAndHandleErrors(TFunc&& func, Args&&... args) - { - return CallAndHandleErrorsWithReturnType(func)(wistd::forward(args)...))>( - wistd::forward(func), wistd::forward(args)...); - } - - // Get the last type of a template parameter pack. - // usage: - // LastType::type boolValue; - template struct LastType - { - template struct LastTypeOfTs - { - typedef typename LastTypeOfTs::type type; - }; - - template struct LastTypeOfTs - { - typedef T type; - }; - - template - static typename LastTypeOfTs::type LastTypeOfTsFunc() {} - typedef decltype(LastTypeOfTsFunc()) type; - }; - - // Takes a member function that has an out param like F(..., IAsyncAction**) or F(..., IAsyncOperation**) - // and returns IAsyncAction* or IAsyncOperation*. - template - typename wistd::remove_pointer::type>::type GetReturnParamPointerType(HRESULT(STDMETHODCALLTYPE I::*)(P...)); - - // Use to determine the result type of the async action/operation interfaces or example - // decltype(GetAsyncResultType(action.get())) returns void - void GetAsyncResultType(ABI::Windows::Foundation::IAsyncAction*); - template void GetAsyncResultType(ABI::Windows::Foundation::IAsyncActionWithProgress

*); - template typename wil::details::MapAsyncOpResultType::type GetAsyncResultType(ABI::Windows::Foundation::IAsyncOperation*); - template typename wil::details::MapAsyncOpProgressResultType::type GetAsyncResultType(ABI::Windows::Foundation::IAsyncOperationWithProgress*); - - // Use to determine the result type of the async action/operation interfaces or example - // decltype(GetAsyncDelegateType(action.get())) returns void - ABI::Windows::Foundation::IAsyncActionCompletedHandler* GetAsyncDelegateType(ABI::Windows::Foundation::IAsyncAction*); - template ABI::Windows::Foundation::IAsyncActionWithProgressCompletedHandler

* GetAsyncDelegateType(ABI::Windows::Foundation::IAsyncActionWithProgress

*); - template ABI::Windows::Foundation::IAsyncOperationCompletedHandler* GetAsyncDelegateType(ABI::Windows::Foundation::IAsyncOperation*); - template ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler* GetAsyncDelegateType(ABI::Windows::Foundation::IAsyncOperationWithProgress*); - - template - HRESULT RunWhenCompleteAction(_In_ TIOperation operation, TFunction&& func) WI_NOEXCEPT - { - using namespace Microsoft::WRL; - typedef wistd::remove_pointer_t TIDelegate; - - auto callback = Callback, TIDelegate, TBaseAgility>>( - [func = wistd::forward(func)](TIOperation operation, ABI::Windows::Foundation::AsyncStatus status) mutable -> HRESULT - { - HRESULT hr = S_OK; - if (status != ABI::Windows::Foundation::AsyncStatus::Completed) // avoid a potentially costly marshaled QI / call if we completed successfully - { - // QI to the IAsyncInfo interface. While all operations implement this, it is - // possible that the stub has disconnected, causing the QI to fail. - ComPtr asyncInfo; - hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); - if (SUCCEEDED(hr)) - { - // Save the error code result in a temporary variable to allow us - // to also retrieve the result of the COM call. If the stub has - // disconnected, this call may fail. - HRESULT errorCode = E_UNEXPECTED; - hr = asyncInfo->get_ErrorCode(&errorCode); - if (SUCCEEDED(hr)) - { - // Return the operations error code to the caller. - hr = errorCode; - } - } - } - - return CallAndHandleErrors(func, hr); - }); - RETURN_IF_NULL_ALLOC(callback); - return operation->put_Completed(callback.Get()); - } - - template - HRESULT RunWhenComplete(_In_ TIOperation operation, TFunction&& func) WI_NOEXCEPT - { - using namespace Microsoft::WRL; - using namespace ABI::Windows::Foundation::Internal; - - typedef wistd::remove_pointer_t TIDelegate; - - auto callback = Callback, TIDelegate, TBaseAgility>>( - [func = wistd::forward(func)](TIOperation operation, ABI::Windows::Foundation::AsyncStatus status) mutable -> HRESULT - { - typename details::MapToSmartType::type::TResult_complex>::type>::type result; - - HRESULT hr = S_OK; - // avoid a potentially costly marshaled QI / call if we completed successfully - if (status == ABI::Windows::Foundation::AsyncStatus::Completed) - { - hr = operation->GetResults(result.GetAddressOf()); - } - else - { - // QI to the IAsyncInfo interface. While all operations implement this, it is - // possible that the stub has disconnected, causing the QI to fail. - ComPtr asyncInfo; - hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); - if (SUCCEEDED(hr)) - { - // Save the error code result in a temporary variable to allow us - // to also retrieve the result of the COM call. If the stub has - // disconnected, this call may fail. - HRESULT errorCode = E_UNEXPECTED; - hr = asyncInfo->get_ErrorCode(&errorCode); - if (SUCCEEDED(hr)) - { - // Return the operations error code to the caller. - hr = errorCode; - } - } - } - - return CallAndHandleErrors(func, hr, result.Get()); - }); - RETURN_IF_NULL_ALLOC(callback); - return operation->put_Completed(callback.Get()); - } - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) - template - HRESULT WaitForCompletion(_In_ TIOperation operation, COWAIT_FLAGS flags, DWORD timeoutValue, _Out_opt_ bool* timedOut) WI_NOEXCEPT - { - typedef wistd::remove_pointer_t TIDelegate; - - class CompletionDelegate : public Microsoft::WRL::RuntimeClass, - TIDelegate, Microsoft::WRL::FtmBase> - { - public: - HRESULT RuntimeClassInitialize() - { - RETURN_HR(m_completedEventHandle.create()); - } - - HRESULT STDMETHODCALLTYPE Invoke(_In_ TIOperation, ABI::Windows::Foundation::AsyncStatus status) override - { - m_status = status; - m_completedEventHandle.SetEvent(); - return S_OK; - } - - WI_NODISCARD HANDLE GetEvent() const - { - return m_completedEventHandle.get(); - } - - WI_NODISCARD ABI::Windows::Foundation::AsyncStatus GetStatus() const - { - return m_status; - } - - private: - volatile ABI::Windows::Foundation::AsyncStatus m_status = ABI::Windows::Foundation::AsyncStatus::Started; - wil::unique_event_nothrow m_completedEventHandle; - }; - - WI_ASSERT(timedOut || (timeoutValue == INFINITE)); - assign_to_opt_param(timedOut, false); - - Microsoft::WRL::ComPtr completedDelegate; - RETURN_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&completedDelegate)); - RETURN_IF_FAILED(operation->put_Completed(completedDelegate.Get())); - - HANDLE handles[] = { completedDelegate->GetEvent() }; - DWORD dwHandleIndex; - HRESULT hr = CoWaitForMultipleHandles(flags, timeoutValue, ARRAYSIZE(handles), handles, &dwHandleIndex); - - // If the caller is listening for timedOut, and we actually timed out, set the bool and return S_OK. Otherwise, fail. - if (timedOut && (hr == RPC_S_CALLPENDING)) - { - *timedOut = true; - return S_OK; - } - RETURN_IF_FAILED(hr); - - if (completedDelegate->GetStatus() != ABI::Windows::Foundation::AsyncStatus::Completed) - { - // QI to the IAsyncInfo interface. While all operations implement this, it is - // possible that the stub has disconnected, causing the QI to fail. - Microsoft::WRL::ComPtr asyncInfo; - hr = operation->QueryInterface(IID_PPV_ARGS(&asyncInfo)); - if (SUCCEEDED(hr)) - { - // Save the error code result in a temporary variable to allow us - // to also retrieve the result of the COM call. If the stub has - // disconnected, this call may fail. - HRESULT errorCode = E_UNEXPECTED; - hr = asyncInfo->get_ErrorCode(&errorCode); - if (SUCCEEDED(hr)) - { - // Return the operations error code to the caller. - hr = errorCode; - } - } - return hr; // leave it to the caller to log failures. - } - return S_OK; - } - - template - HRESULT WaitForCompletion(_In_ TIOperation operation, _Out_ TIResults result, COWAIT_FLAGS flags, - DWORD timeoutValue, _Out_opt_ bool* timedOut) WI_NOEXCEPT - { - RETURN_IF_FAILED_EXPECTED(details::WaitForCompletion(operation, flags, timeoutValue, timedOut)); - return operation->GetResults(result); - } -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) -} -/// @endcond - -/** Set the completion callback for an async operation to run a caller provided function. -Once complete the function is called with the error code result of the operation -and the async operation result (if applicable). -The function parameter list must be (HRESULT hr) for actions, -(HRESULT hr, IResultInterface* object) for operations that produce interfaces, -and (HRESULT hr, TResult value) for operations that produce value types. -~~~ -run_when_complete(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> void -{ - -}); -~~~ -for an agile callback use Microsoft::WRL::FtmBase -~~~ -run_when_complete(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> void -{ - -}); -~~~ -Using the non throwing form: -~~~ -hr = run_when_complete_nothrow(getFileOp.Get(), [](HRESULT hr, IStorageFile* file) -> HRESULT -{ - -}); -~~~ -*/ - -//! Run a fuction when an async operation completes. Use Microsoft::WRL::FtmBase for TAgility to make the completion handler agile and run on the async thread. -template -HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncAction* operation, TFunc&& func) WI_NOEXCEPT -{ - return details::RunWhenCompleteAction(operation, wistd::forward(func)); -} - -template::type> -HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, TFunc&& func) WI_NOEXCEPT -{ - return details::RunWhenComplete(operation, wistd::forward(func)); -} - -template::type> -HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, TFunc&& func) WI_NOEXCEPT -{ - return details::RunWhenComplete(operation, wistd::forward(func)); -} - -template -HRESULT run_when_complete_nothrow(_In_ ABI::Windows::Foundation::IAsyncActionWithProgress* operation, TFunc&& func) WI_NOEXCEPT -{ - return details::RunWhenCompleteAction(operation, wistd::forward(func)); -} - -#ifdef WIL_ENABLE_EXCEPTIONS -//! Run a fuction when an async operation completes. Use Microsoft::WRL::FtmBase for TAgility to make the completion handler agile and run on the async thread. -template -void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncAction* operation, TFunc&& func) -{ - THROW_IF_FAILED((details::RunWhenCompleteAction(operation, wistd::forward(func)))); -} - -template::type> -void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, TFunc&& func) -{ - THROW_IF_FAILED((details::RunWhenComplete(operation, wistd::forward(func)))); -} - -template::type> -void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, TFunc&& func) -{ - THROW_IF_FAILED((details::RunWhenComplete(operation, wistd::forward(func)))); -} - -template -void run_when_complete(_In_ ABI::Windows::Foundation::IAsyncActionWithProgress* operation, TFunc&& func) -{ - THROW_IF_FAILED((details::RunWhenCompleteAction(operation, wistd::forward(func)))); -} -#endif - -#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) -/** Wait for an asynchronous operation to complete (or be canceled). -Use to synchronously wait on async operations on background threads. -Do not call from UI threads or STA threads as reentrancy will result. -~~~ -ComPtr> op; -THROW_IF_FAILED(storageFileStatics->GetFileFromPathAsync(HStringReference(path).Get(), &op)); -auto file = wil::wait_for_completion(op.Get()); -~~~ -*/ -template -inline HRESULT wait_for_completion_nothrow(_In_ TAsync* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT -{ - return details::WaitForCompletion(operation, flags, INFINITE, nullptr); -} - -// These forms return the result from the async operation - -template -HRESULT wait_for_completion_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, - _Out_ typename wil::details::MapAsyncOpResultType::type* result, - COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT -{ - return details::WaitForCompletion(operation, result, flags, INFINITE, nullptr); -} - -template -HRESULT wait_for_completion_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, - _Out_ typename wil::details::MapAsyncOpProgressResultType::type* result, - COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT -{ - return details::WaitForCompletion(operation, result, flags, INFINITE, nullptr); -} - -// Same as above, but allows caller to specify a timeout value. -// On timeout, S_OK is returned, with timedOut set to true. - -template -inline HRESULT wait_for_completion_or_timeout_nothrow(_In_ TAsync* operation, - DWORD timeoutValue, _Out_ bool* timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT -{ - return details::WaitForCompletion(operation, flags, timeoutValue, timedOut); -} - -template -HRESULT wait_for_completion_or_timeout_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, - _Out_ typename wil::details::MapAsyncOpResultType::type* result, - DWORD timeoutValue, _Out_ bool* timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT -{ - return details::WaitForCompletion(operation, result, flags, timeoutValue, timedOut); -} - -template -HRESULT wait_for_completion_or_timeout_nothrow(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, - _Out_ typename wil::details::MapAsyncOpProgressResultType::type* result, - DWORD timeoutValue, _Out_ bool* timedOut, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) WI_NOEXCEPT -{ - return details::WaitForCompletion(operation, result, flags, timeoutValue, timedOut); -} - -#ifdef WIL_ENABLE_EXCEPTIONS -//! Wait for an asynchronous operation to complete (or be canceled). -template -inline void wait_for_completion(_In_ TAsync* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) -{ - THROW_IF_FAILED(details::WaitForCompletion(operation, flags, INFINITE, nullptr)); -} - -template ::type>::type> -TReturn -wait_for_completion(_In_ ABI::Windows::Foundation::IAsyncOperation* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) -{ - TReturn result; - THROW_IF_FAILED(details::WaitForCompletion(operation, result.GetAddressOf(), flags, INFINITE, nullptr)); - return result; -} - -template ::type>::type> -TReturn -wait_for_completion(_In_ ABI::Windows::Foundation::IAsyncOperationWithProgress* operation, COWAIT_FLAGS flags = COWAIT_DISPATCH_CALLS) -{ - TReturn result; - THROW_IF_FAILED(details::WaitForCompletion(operation, result.GetAddressOf(), flags, INFINITE, nullptr)); - return result; -} - -/** Similar to WaitForCompletion but this function encapsulates the creation of the async operation -making usage simpler. -~~~ -ComPtr launcher; // inited somewhere -auto result = call_and_wait_for_completion(launcher.Get(), &ILauncherStatics::LaunchUriAsync, uri.Get()); -~~~ -*/ -template -auto call_and_wait_for_completion(I* object, HRESULT(STDMETHODCALLTYPE I::*func)(P...), Args&&... args) -{ - Microsoft::WRL::ComPtr::type>::type>::type> op; - THROW_IF_FAILED((object->*func)(wistd::forward(args)..., &op)); - return wil::wait_for_completion(op.Get()); -} -#endif -#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) - -#pragma endregion - -#pragma region WinRT object construction -#ifdef WIL_ENABLE_EXCEPTIONS -//! Get a WinRT activation factory object, usually using a IXXXStatics interface. -template -com_ptr GetActivationFactory(PCWSTR runtimeClass) -{ - com_ptr result; - THROW_IF_FAILED(RoGetActivationFactory(Microsoft::WRL::Wrappers::HStringReference(runtimeClass).Get(), IID_PPV_ARGS(&result))); - return result; -} - -//! Get a WinRT object. -template -com_ptr ActivateInstance(PCWSTR runtimeClass) -{ - com_ptr result; - THROW_IF_FAILED(RoActivateInstance(Microsoft::WRL::Wrappers::HStringReference(runtimeClass).Get(), &result)); - return result.query(); -} -#endif -#pragma endregion - -#pragma region Async production helpers - -/// @cond -namespace details -{ - template - class SyncAsyncOp WrlFinal : public Microsoft::WRL::RuntimeClass, - Microsoft::WRL::AsyncBase>> - { - // typedef typename MapToSmartType::type TSmart; - using RuntimeClassT = typename SyncAsyncOp::RuntimeClassT; - InspectableClass(__super::z_get_rc_name_impl(), TrustLevel::BaseTrust); - public: - HRESULT RuntimeClassInitialize(const TResult& op) - { - m_result = op; - return S_OK; - } - - IFACEMETHODIMP put_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler* competed) override - { - competed->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); - return S_OK; - } - - IFACEMETHODIMP get_Completed(ABI::Windows::Foundation::IAsyncOperationCompletedHandler** competed) override - { - *competed = nullptr; - return S_OK; - } - - IFACEMETHODIMP GetResults(TResult* result) override - { - *result = m_result; - return S_OK; - } - - HRESULT OnStart() override { return S_OK; } - void OnClose() override { } - void OnCancel() override { } - private: - // needs to be MapToSmartType::type to hold non trial types - TResult m_result{}; - }; - - extern const __declspec(selectany) wchar_t SyncAsyncActionName[] = L"SyncActionAction"; - - class SyncAsyncActionOp WrlFinal : public Microsoft::WRL::RuntimeClass -#endif - >> - { - InspectableClass(InterfaceName_Windows_Foundation_IAsyncAction, TrustLevel::BaseTrust); - public: - IFACEMETHODIMP put_Completed(ABI::Windows::Foundation::IAsyncActionCompletedHandler* competed) override - { - competed->Invoke(this, ABI::Windows::Foundation::AsyncStatus::Completed); - return S_OK; - } - - IFACEMETHODIMP get_Completed(ABI::Windows::Foundation::IAsyncActionCompletedHandler** competed) override - { - *competed = nullptr; - return S_OK; - } - - IFACEMETHODIMP GetResults() override - { - return S_OK; - } - - HRESULT OnStart() override { return S_OK; } - void OnClose() override { } - void OnCancel() override { } - }; -} - -/// @endcond -//! Creates a WinRT async operation object that implements IAsyncOperation. Use mostly for testing and for mocking APIs. -template -HRESULT make_synchronous_async_operation_nothrow(ABI::Windows::Foundation::IAsyncOperation** result, const TResult& value) -{ - return Microsoft::WRL::MakeAndInitialize>(result, value); -} - -//! Creates a WinRT async operation object that implements IAsyncAction. Use mostly for testing and for mocking APIs. -inline HRESULT make_synchronous_async_action_nothrow(ABI::Windows::Foundation::IAsyncAction** result) -{ - return Microsoft::WRL::MakeAndInitialize(result); -} - -#ifdef WIL_ENABLE_EXCEPTIONS -//! Creates a WinRT async operation object that implements IAsyncOperation. Use mostly for testing and for mocking APIs. -// TODO: map TRealResult and TSmartResult into SyncAsyncOp. -template ::type, typename TSmartResult = typename details::MapToSmartType::type> -void make_synchronous_async_operation(ABI::Windows::Foundation::IAsyncOperation** result, const TResult& value) -{ - THROW_IF_FAILED((Microsoft::WRL::MakeAndInitialize>(result, value))); -} - -//! Creates a WinRT async operation object that implements IAsyncAction. Use mostly for testing and for mocking APIs. -inline void make_synchronous_async_action(ABI::Windows::Foundation::IAsyncAction** result) -{ - THROW_IF_FAILED((Microsoft::WRL::MakeAndInitialize(result))); -} -#endif -#pragma endregion - -#pragma region EventRegistrationToken RAII wrapper - -// unique_winrt_event_token[_cx] is an RAII wrapper around EventRegistrationToken. When the unique_winrt_event_token[_cx] is -// destroyed, the event is automatically unregistered. Declare a wil::unique_winrt_event_token[_cx] at the scope the event -// should be registered for (often they are tied to object lifetime), where T is the type of the event sender -// wil::unique_winrt_event_token_cx m_token; -// -// Macros have been defined to register for handling the event and then returning an unique_winrt_event_token[_cx]. These -// macros simply hide the function references for adding and removing the event. -// C++/CX m_token = WI_MakeUniqueWinRtEventTokenCx(ExampleEventName, sender, handler); -// ABI m_token = WI_MakeUniqueWinRtEventToken(ExampleEventName, sender, handler, &m_token); // Exception and failfast -// ABI RETURN_IF_FAILED(WI_MakeUniqueWinRtEventTokenNoThrow(ExampleEventName, sender, handler, &m_token)); // No throw variant -// -// When the wrapper is destroyed, the handler will be unregistered. You can explicitly unregister the handler prior. -// m_token.reset(); -// -// You can release the EventRegistrationToken from being managed by the wrapper by calling .release() -// m_token.release(); // DANGER: no longer being managed -// -// If you just need the value of the EventRegistrationToken you can call .get() -// m_token.get(); -// -// See "onecore\shell\tests\wil\UniqueWinRTEventTokenTests.cpp" for more examples of usage in ABI and C++/CX. - -#ifdef __cplusplus_winrt -namespace details -{ - template struct remove_reference { typedef T type; }; - template struct remove_reference { typedef T type; }; -} - -template -class unique_winrt_event_token_cx -{ - using removal_func = void(T::*)(Windows::Foundation::EventRegistrationToken); - using static_removal_func = void(__cdecl *)(Windows::Foundation::EventRegistrationToken); - -public: - unique_winrt_event_token_cx() = default; - - unique_winrt_event_token_cx(Windows::Foundation::EventRegistrationToken token, T^ sender, removal_func removalFunction) WI_NOEXCEPT : - m_token(token), - m_weakSender(sender), - m_removalFunction(removalFunction) - {} - - unique_winrt_event_token_cx(Windows::Foundation::EventRegistrationToken token, static_removal_func removalFunction) WI_NOEXCEPT : - m_token(token), - m_staticRemovalFunction(removalFunction) - {} - - unique_winrt_event_token_cx(const unique_winrt_event_token_cx&) = delete; - unique_winrt_event_token_cx& operator=(const unique_winrt_event_token_cx&) = delete; - - unique_winrt_event_token_cx(unique_winrt_event_token_cx&& other) WI_NOEXCEPT : - m_token(other.m_token), - m_weakSender(wistd::move(other.m_weakSender)), - m_removalFunction(other.m_removalFunction), - m_staticRemovalFunction(other.m_staticRemovalFunction) - { - other.m_token = {}; - other.m_weakSender = nullptr; - other.m_removalFunction = nullptr; - other.m_staticRemovalFunction = nullptr; - } - - unique_winrt_event_token_cx& operator=(unique_winrt_event_token_cx&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - reset(); - - wistd::swap_wil(m_token, other.m_token); - wistd::swap_wil(m_weakSender, other.m_weakSender); - wistd::swap_wil(m_removalFunction, other.m_removalFunction); - wistd::swap_wil(m_staticRemovalFunction, other.m_staticRemovalFunction); - } - - return *this; - } - - ~unique_winrt_event_token_cx() WI_NOEXCEPT - { - reset(); - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_token.Value != 0); - } - - WI_NODISCARD Windows::Foundation::EventRegistrationToken get() const WI_NOEXCEPT - { - return m_token; - } - - void reset() noexcept - { - if (m_token.Value != 0) - { - if (m_staticRemovalFunction) - { - (*m_staticRemovalFunction)(m_token); - } - else - { - auto resolvedSender = [&]() - { - try - { - return m_weakSender.Resolve(); - } - catch (...) - { - // Ignore RPC or other failures that are unavoidable in some cases - // matching wil::unique_winrt_event_token and winrt::event_revoker - return static_cast(nullptr); - } - }(); - if (resolvedSender) - { - (resolvedSender->*m_removalFunction)(m_token); - } - } - release(); - } - } - - // Stops the wrapper from managing resource and returns the EventRegistrationToken. - Windows::Foundation::EventRegistrationToken release() WI_NOEXCEPT - { - auto token = m_token; - m_token = {}; - m_weakSender = nullptr; - m_removalFunction = nullptr; - m_staticRemovalFunction = nullptr; - return token; - } - -private: - Windows::Foundation::EventRegistrationToken m_token = {}; - Platform::WeakReference m_weakSender; - removal_func m_removalFunction = nullptr; - static_removal_func m_staticRemovalFunction = nullptr; -}; - -#endif - -template -class unique_winrt_event_token -{ - using removal_func = HRESULT(__stdcall T::*)(::EventRegistrationToken); - -public: - unique_winrt_event_token() = default; - - unique_winrt_event_token(::EventRegistrationToken token, T* sender, removal_func removalFunction) WI_NOEXCEPT : - m_token(token), - m_removalFunction(removalFunction) - { - m_weakSender = wil::com_weak_query_failfast(sender); - } - - unique_winrt_event_token(const unique_winrt_event_token&) = delete; - unique_winrt_event_token& operator=(const unique_winrt_event_token&) = delete; - - unique_winrt_event_token(unique_winrt_event_token&& other) WI_NOEXCEPT : - m_token(other.m_token), - m_weakSender(wistd::move(other.m_weakSender)), - m_removalFunction(other.m_removalFunction) - { - other.m_token = {}; - other.m_removalFunction = nullptr; - } - - unique_winrt_event_token& operator=(unique_winrt_event_token&& other) WI_NOEXCEPT - { - if (this != wistd::addressof(other)) - { - reset(); - - wistd::swap_wil(m_token, other.m_token); - wistd::swap_wil(m_weakSender, other.m_weakSender); - wistd::swap_wil(m_removalFunction, other.m_removalFunction); - } - - return *this; - } - - ~unique_winrt_event_token() WI_NOEXCEPT - { - reset(); - } - - WI_NODISCARD explicit operator bool() const WI_NOEXCEPT - { - return (m_token.value != 0); - } - - WI_NODISCARD ::EventRegistrationToken get() const WI_NOEXCEPT - { - return m_token; - } - - void reset() WI_NOEXCEPT - { - if (m_token.value != 0) - { - // If T cannot be QI'ed from the weak object then T is not a COM interface. - auto resolvedSender = m_weakSender.try_query(); - if (resolvedSender) - { - FAIL_FAST_IF_FAILED((resolvedSender.get()->*m_removalFunction)(m_token)); - } - release(); - } - } - - // Stops the wrapper from managing resource and returns the EventRegistrationToken. - ::EventRegistrationToken release() WI_NOEXCEPT - { - auto token = m_token; - m_token = {}; - m_weakSender = nullptr; - m_removalFunction = nullptr; - return token; - } - -private: - ::EventRegistrationToken m_token = {}; - wil::com_weak_ref_failfast m_weakSender; - removal_func m_removalFunction = nullptr; -}; - -namespace details -{ -#ifdef __cplusplus_winrt - - // Handles registration of the event handler to the subscribing object and then wraps the EventRegistrationToken in unique_winrt_event_token. - // Not intended to be directly called. Use the WI_MakeUniqueWinRtEventTokenCx macro to abstract away specifying the functions that handle addition and removal. - template - inline wil::unique_winrt_event_token_cx make_unique_winrt_event_token_cx(T^ sender, addition_func additionFunc, removal_func removalFunc, handler^ h) - { - auto rawToken = (sender->*additionFunc)(h); - wil::unique_winrt_event_token_cx temp(rawToken, sender, removalFunc); - return temp; - } - - template - inline wil::unique_winrt_event_token_cx make_unique_winrt_static_event_token_cx(addition_func additionFunc, removal_func removalFunc, handler^ h) - { - auto rawToken = (*additionFunc)(h); - wil::unique_winrt_event_token_cx temp(rawToken, removalFunc); - return temp; - } - -#endif // __cplusplus_winrt - - // Handles registration of the event handler to the subscribing object and then wraps the EventRegistrationToken in unique_winrt_event_token. - // Not intended to be directly called. Use the WI_MakeUniqueWinRtEventToken macro to abstract away specifying the functions that handle addition and removal. - template - inline auto make_unique_winrt_event_token(T* sender, addition_func additionFunc, removal_func removalFunc, handler h, wil::unique_winrt_event_token* token_reference) - { - ::EventRegistrationToken rawToken; - err_policy::HResult((sender->*additionFunc)(h, &rawToken)); - *token_reference = wil::unique_winrt_event_token(rawToken, sender, removalFunc); - return err_policy::OK(); - } - - // Overload make function to allow for returning the constructed object when not using HRESULT based code. - template - inline typename wistd::enable_if::value, wil::unique_winrt_event_token>::type - make_unique_winrt_event_token(T* sender, addition_func additionFunc, removal_func removalFunc, handler h) - { - ::EventRegistrationToken rawToken; - err_policy::HResult((sender->*additionFunc)(h, &rawToken)); - return wil::unique_winrt_event_token(rawToken, sender, removalFunc); - } - -} // namespace details - -// Helper macros to abstract function names for event addition and removal. -#ifdef __cplusplus_winrt - -#define WI_MakeUniqueWinRtEventTokenCx(_event, _object, _handler) \ - wil::details::make_unique_winrt_event_token_cx( \ - _object, \ - &wil::details::remove_reference::type::##_event##::add, \ - &wil::details::remove_reference::type::##_event##::remove, \ - _handler) - -#define WI_MakeUniqueWinRtStaticEventTokenCx(_event, _baseType, _handler) \ - wil::details::make_unique_winrt_static_event_token_cx<_baseType>( \ - &##_baseType##::##_event##::add, \ - &##_baseType##::##_event##::remove, \ - _handler) - -#endif // __cplusplus_winrt - -#ifdef WIL_ENABLE_EXCEPTIONS - -#define WI_MakeUniqueWinRtEventToken(_event, _object, _handler) \ - wil::details::make_unique_winrt_event_token( \ - _object, \ - &wistd::remove_pointer::type::add_##_event, \ - &wistd::remove_pointer::type::remove_##_event, \ - _handler) - -#endif // WIL_ENABLE_EXCEPTIONS - -#define WI_MakeUniqueWinRtEventTokenNoThrow(_event, _object, _handler, _token_reference) \ - wil::details::make_unique_winrt_event_token( \ - _object, \ - &wistd::remove_pointer::type::add_##_event, \ - &wistd::remove_pointer::type::remove_##_event, \ - _handler, \ - _token_reference) - -#define WI_MakeUniqueWinRtEventTokenFailFast(_event, _object, _handler) \ - wil::details::make_unique_winrt_event_token( \ - _object, \ - &wistd::remove_pointer::type::add_##_event, \ - &wistd::remove_pointer::type::remove_##_event, \ - _handler) - -#pragma endregion // EventRegistrationToken RAII wrapper - -} // namespace wil - -#if (NTDDI_VERSION >= NTDDI_WINBLUE) - -template <> -struct ABI::Windows::Foundation::IAsyncOperation : - ABI::Windows::Foundation::IAsyncOperation_impl -{ - static const wchar_t* z_get_rc_name_impl() - { - return L"IAsyncOperation"; - } -}; - -template -struct ABI::Windows::Foundation::IAsyncOperationWithProgress : - ABI::Windows::Foundation::IAsyncOperationWithProgress_impl -{ - static const wchar_t* z_get_rc_name_impl() - { - return L"IAsyncOperationWithProgress"; - } -}; - -template -struct ABI::Windows::Foundation::IAsyncOperation*> : - ABI::Windows::Foundation::IAsyncOperation_impl*> -{ - static const wchar_t* z_get_rc_name_impl() - { - return L"IAsyncOperation*>"; - } -}; - -template -struct ABI::Windows::Foundation::IAsyncOperationWithProgress*, P> : - ABI::Windows::Foundation::IAsyncOperationWithProgress_impl*, P> -{ - static const wchar_t* z_get_rc_name_impl() - { - return L"IAsyncOperationWithProgress*,P>"; - } -}; - -template -struct ABI::Windows::Foundation::IAsyncOperation*> : - ABI::Windows::Foundation::IAsyncOperation_impl*> -{ - static const wchar_t* z_get_rc_name_impl() - { - return L"IAsyncOperation*>"; - } -}; - -template -struct ABI::Windows::Foundation::IAsyncOperationWithProgress*, Z> : - ABI::Windows::Foundation::IAsyncOperationWithProgress_impl*, Z> -{ - static const wchar_t* z_get_rc_name_impl() - { - return L"IAsyncOperationWithProgress*,Z>"; - } -}; - -template <> -struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler : - ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl -{ - static const wchar_t* z_get_rc_name_impl() - { - return L"IAsyncOperationCompletedHandler"; - } -}; - -template -struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler : - ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl -{ - static const wchar_t* z_get_rc_name_impl() - { - return L"IAsyncOperationWithProgressCompletedHandler"; - } -}; - -template -struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler*> : - ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl*> -{ - static const wchar_t* z_get_rc_name_impl() - { - return L"IAsyncOperationCompletedHandler*>"; - } -}; - -template -struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler*, P> : - ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl*, P> -{ - static const wchar_t* z_get_rc_name_impl() - { - return L"IAsyncOperationWithProgressCompletedHandler*,P>"; - } -}; - -template -struct ABI::Windows::Foundation::IAsyncOperationCompletedHandler*> : - ABI::Windows::Foundation::IAsyncOperationCompletedHandler_impl*> -{ - static const wchar_t* z_get_rc_name_impl() - { - return L"IAsyncOperationCompletedHandler*>"; - } -}; - -template -struct ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler*, Z> : - ABI::Windows::Foundation::IAsyncOperationWithProgressCompletedHandler_impl*, Z> -{ - static const wchar_t* z_get_rc_name_impl() - { - return L"IAsyncOperationWithProgressCompletedHandler*,Z>"; - } -}; -#endif // NTDDI_VERSION >= NTDDI_WINBLUE - -#if !defined(MIDL_NS_PREFIX) && !defined(____x_ABI_CWindows_CFoundation_CIClosable_FWD_DEFINED__) -// Internal .idl files use the namespace without the ABI prefix. Macro out ABI for that case -#pragma pop_macro("ABI") -#endif - -#if __WI_HAS_STD_LESS - -namespace std -{ - //! Specialization of `std::less` for `Microsoft::WRL::Wrappers::HString` that uses `hstring_less` for the - //! comparison function object. - template <> - struct less : - public wil::hstring_less - { - }; - - //! Specialization of `std::less` for `wil::unique_hstring` that uses `hstring_less` for the comparison function - //! object. - template <> - struct less : - public wil::hstring_less - { - }; -} - -#endif - -#endif // __WIL_WINRT_INCLUDED diff --git a/src/common/dep/wil/wistd_config.h b/src/common/dep/wil/wistd_config.h deleted file mode 100644 index 820e0601c..000000000 --- a/src/common/dep/wil/wistd_config.h +++ /dev/null @@ -1,571 +0,0 @@ -// -*- C++ -*- -//===--------------------------- __config ---------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// STL common functionality -// -// Some aspects of STL are core language concepts that should be used from all C++ code, regardless -// of whether exceptions are enabled in the component. Common library code that expects to be used -// from exception-free components want these concepts, but including STL headers directly introduces -// friction as it requires components not using STL to declare their STL version. Doing so creates -// ambiguity around whether STL use is safe in a particular component and implicitly brings in -// a long list of headers (including ) which can create further ambiguity around throwing new -// support (some routines pulled in may expect it). Secondarily, pulling in these headers also has -// the potential to create naming conflicts or other implied dependencies. -// -// To promote the use of these core language concepts outside of STL-based binaries, this file is -// selectively pulling those concepts *directly* from corresponding STL headers. The corresponding -// "std::" namespace STL functions and types should be preferred over these in code that is bound to -// STL. The implementation and naming of all functions are taken directly from STL, instead using -// "wistd" (Windows Implementation std) as the namespace. -// -// Routines in this namespace should always be considered a reflection of the *current* STL implementation -// of those routines. Updates from STL should be taken, but no "bugs" should be fixed here. -// -// New, exception-based code should not use this namespace, but instead should prefer the std:: implementation. -// Only code that is not exception-based and libraries that expect to be utilized across both exception -// and non-exception based code should utilize this functionality. - -// This header mimics libc++'s '__config' header to the extent necessary to get the wistd::* definitions compiling. Note -// that this has a few key differences since libc++'s MSVC compatability is currently not functional and a bit behind - -#ifndef _WISTD_CONFIG_H_ -#define _WISTD_CONFIG_H_ - -// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage -#include // For size_t and other necessary types - -/// @cond -#if defined(_MSC_VER) && !defined(__clang__) -# if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -# define __WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -# endif -#endif - -#ifndef __WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER -#pragma GCC system_header -#endif - -#ifdef __GNUC__ -# define __WI_GNUC_VER (__GNUC__ * 100 + __GNUC_MINOR__) -// The __WI_GNUC_VER_NEW macro better represents the new GCC versioning scheme -// introduced in GCC 5.0. -# define __WI_GNUC_VER_NEW (__WI_GNUC_VER * 10 + __GNUC_PATCHLEVEL__) -#else -# define __WI_GNUC_VER 0 -# define __WI_GNUC_VER_NEW 0 -#endif - -// _MSVC_LANG is the more accurate way to get the C++ version in MSVC -#if defined(_MSVC_LANG) && (_MSVC_LANG > __cplusplus) -#define __WI_CPLUSPLUS _MSVC_LANG -#else -#define __WI_CPLUSPLUS __cplusplus -#endif - -#ifndef __WI_LIBCPP_STD_VER -# if __WI_CPLUSPLUS <= 201103L -# define __WI_LIBCPP_STD_VER 11 -# elif __WI_CPLUSPLUS <= 201402L -# define __WI_LIBCPP_STD_VER 14 -# elif __WI_CPLUSPLUS <= 201703L -# define __WI_LIBCPP_STD_VER 17 -# else -# define __WI_LIBCPP_STD_VER 18 // current year, or date of c++2a ratification -# endif -#endif // __WI_LIBCPP_STD_VER - -#if __WI_CPLUSPLUS < 201103L -#define __WI_LIBCPP_CXX03_LANG -#endif - -#if defined(__ELF__) -# define __WI_LIBCPP_OBJECT_FORMAT_ELF 1 -#elif defined(__MACH__) -# define __WI_LIBCPP_OBJECT_FORMAT_MACHO 1 -#elif defined(_WIN32) -# define __WI_LIBCPP_OBJECT_FORMAT_COFF 1 -#elif defined(__wasm__) -# define __WI_LIBCPP_OBJECT_FORMAT_WASM 1 -#else -# error Unknown object file format -#endif - -#if defined(__clang__) -# define __WI_LIBCPP_COMPILER_CLANG -#elif defined(__GNUC__) -# define __WI_LIBCPP_COMPILER_GCC -#elif defined(_MSC_VER) -# define __WI_LIBCPP_COMPILER_MSVC -#elif defined(__IBMCPP__) -# define __WI_LIBCPP_COMPILER_IBM -#endif - -#if defined(__WI_LIBCPP_COMPILER_MSVC) -#define __WI_PUSH_WARNINGS __pragma(warning(push)) -#define __WI_POP_WARNINGS __pragma(warning(pop)) -#elif defined(__WI_LIBCPP_COMPILER_CLANG) -#define __WI_PUSH_WARNINGS __pragma(clang diagnostic push) -#define __WI_POP_WARNINGS __pragma(clang diagnostic pop) -#else -#define __WI_PUSH_WARNINGS -#define __WI_POP_WARNINGS -#endif - -#ifdef __WI_LIBCPP_COMPILER_MSVC -#define __WI_MSVC_DISABLE_WARNING(id) __pragma(warning(disable: id)) -#else -#define __WI_MSVC_DISABLE_WARNING(id) -#endif - -#ifdef __WI_LIBCPP_COMPILER_CLANG -#define __WI_CLANG_DISABLE_WARNING(warning) __pragma(clang diagnostic ignored #warning) -#else -#define __WI_CLANG_DISABLE_WARNING(warning) -#endif - -// NOTE: MSVC, which is what we primarily target, is severly underrepresented in libc++ and checks such as -// __has_feature(...) are always false for MSVC, even when the feature being tested _is_ present in MSVC. Therefore, we -// instead modify all checks to be __WI_HAS_FEATURE_IS_UNION, etc., which provides the correct value for MSVC and falls -// back to the __has_feature(...), etc. value otherwise. We intentionally leave '__has_feature', etc. undefined for MSVC -// so that we don't accidentally use the incorrect behavior -#ifndef __WI_LIBCPP_COMPILER_MSVC - -#ifndef __has_feature -#define __has_feature(__x) 0 -#endif - -// '__is_identifier' returns '0' if '__x' is a reserved identifier provided by -// the compiler and '1' otherwise. -#ifndef __is_identifier -#define __is_identifier(__x) 1 -#endif - -#ifndef __has_cpp_attribute -#define __has_cpp_attribute(__x) 0 -#endif - -#ifndef __has_attribute -#define __has_attribute(__x) 0 -#endif - -#ifndef __has_builtin -#define __has_builtin(__x) 0 -#endif - -#if __has_feature(cxx_alignas) -# define __WI_ALIGNAS_TYPE(x) alignas(x) -# define __WI_ALIGNAS(x) alignas(x) -#else -# define __WI_ALIGNAS_TYPE(x) __attribute__((__aligned__(__alignof(x)))) -# define __WI_ALIGNAS(x) __attribute__((__aligned__(x))) -#endif - -#if __has_feature(cxx_explicit_conversions) || defined(__IBMCPP__) || \ - (!defined(__WI_LIBCPP_CXX03_LANG) && defined(__GNUC__)) // All supported GCC versions -# define __WI_LIBCPP_EXPLICIT explicit -#else -# define __WI_LIBCPP_EXPLICIT -#endif - -#if __has_feature(cxx_attributes) -# define __WI_LIBCPP_NORETURN [[noreturn]] -#else -# define __WI_LIBCPP_NORETURN __attribute__ ((noreturn)) -#endif - -#define __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS -#define __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS - -// The __WI_LIBCPP_NODISCARD_ATTRIBUTE should only be used to define other -// NODISCARD macros to the correct attribute. -#if __has_cpp_attribute(nodiscard) -# define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[nodiscard]] -#elif defined(__WI_LIBCPP_COMPILER_CLANG) && !defined(__WI_LIBCPP_CXX03_LANG) -# define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[clang::warn_unused_result]] -#else -// We can't use GCC's [[gnu::warn_unused_result]] and -// __attribute__((warn_unused_result)), because GCC does not silence them via -// (void) cast. -# define __WI_LIBCPP_NODISCARD_ATTRIBUTE -#endif - -#define __WI_HAS_FEATURE_IS_UNION __has_feature(is_union) -#define __WI_HAS_FEATURE_IS_CLASS __has_feature(is_class) -#define __WI_HAS_FEATURE_IS_ENUM __has_feature(is_enum) -#define __WI_HAS_FEATURE_IS_CONVERTIBLE_TO __has_feature(is_convertible_to) -#define __WI_HAS_FEATURE_IS_EMPTY __has_feature(is_empty) -#define __WI_HAS_FEATURE_IS_POLYMORPHIC __has_feature(is_polymorphic) -#define __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR __has_feature(has_virtual_destructor) -#define __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS __has_feature(cxx_reference_qualified_functions) -#define __WI_HAS_FEATURE_IS_CONSTRUCTIBLE __has_feature(is_constructible) -#define __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE __has_feature(is_trivially_constructible) -#define __WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE __has_feature(is_trivially_assignable) -#define __WI_HAS_FEATURE_HAS_TRIVIAL_DESTRUCTOR __has_feature(has_trivial_destructor) -#define __WI_HAS_FEATURE_NOEXCEPT __has_feature(cxx_noexcept) -#define __WI_HAS_FEATURE_IS_POD __has_feature(is_pod) -#define __WI_HAS_FEATURE_IS_STANDARD_LAYOUT __has_feature(is_standard_layout) -#define __WI_HAS_FEATURE_IS_TRIVIALLY_COPYABLE __has_feature(is_trivially_copyable) -#define __WI_HAS_FEATURE_IS_TRIVIAL __has_feature(is_trivial) -#define __WI_HAS_FEATURE_HAS_TRIVIAL_CONSTRUCTOR __has_feature(has_trivial_constructor) || (__WI_GNUC_VER >= 403) -#define __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR __has_feature(has_nothrow_constructor) || (__WI_GNUC_VER >= 403) -#define __WI_HAS_FEATURE_HAS_NOTHROW_COPY __has_feature(has_nothrow_copy) || (__WI_GNUC_VER >= 403) -#define __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN __has_feature(has_nothrow_assign) || (__WI_GNUC_VER >= 403) - -#if !(__has_feature(cxx_noexcept)) -#define __WI_LIBCPP_HAS_NO_NOEXCEPT -#endif - -#if !__is_identifier(__has_unique_object_representations) || __WI_GNUC_VER >= 700 -#define __WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS -#endif - -#if !(__has_feature(cxx_variadic_templates)) -#define __WI_LIBCPP_HAS_NO_VARIADICS -#endif - -#if __has_feature(is_literal) || __WI_GNUC_VER >= 407 -#define __WI_LIBCPP_IS_LITERAL(T) __is_literal(T) -#endif - -#if __has_feature(underlying_type) || __WI_GNUC_VER >= 407 -#define __WI_LIBCPP_UNDERLYING_TYPE(T) __underlying_type(T) -#endif - -#if __has_feature(is_final) || __WI_GNUC_VER >= 407 -#define __WI_LIBCPP_HAS_IS_FINAL -#endif - -#if __has_feature(is_base_of) || defined(__GNUC__) && __WI_GNUC_VER >= 403 -#define __WI_LIBCPP_HAS_IS_BASE_OF -#endif - -#if __is_identifier(__is_aggregate) && (__WI_GNUC_VER_NEW < 7001) -#define __WI_LIBCPP_HAS_NO_IS_AGGREGATE -#endif - -#if !(__has_feature(cxx_rtti)) && !defined(__WI_LIBCPP_NO_RTTI) -#define __WI_LIBCPP_NO_RTTI -#endif - -#if !(__has_feature(cxx_variable_templates)) -#define __WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES -#endif - -#if !(__has_feature(cxx_relaxed_constexpr)) -#define __WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR -#endif - -#if !__has_builtin(__builtin_addressof) && _GNUC_VER < 700 -#define __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF -#endif - -#if __has_attribute(__no_sanitize__) && !defined(__WI_LIBCPP_COMPILER_GCC) -# define __WI_LIBCPP_NO_CFI __attribute__((__no_sanitize__("cfi"))) -#else -# define __WI_LIBCPP_NO_CFI -#endif - -#define __WI_LIBCPP_ALWAYS_INLINE __attribute__ ((__always_inline__)) - -#if __has_attribute(internal_linkage) -# define __WI_LIBCPP_INTERNAL_LINKAGE __attribute__ ((internal_linkage)) -#else -# define __WI_LIBCPP_INTERNAL_LINKAGE __WI_LIBCPP_ALWAYS_INLINE -#endif - -#else - -// NOTE: Much of the following assumes a decently recent version of MSVC. Past versions can be supported, but will need -// to be updated to contain the proper _MSC_VER check -#define __WI_ALIGNAS_TYPE(x) alignas(x) -#define __WI_ALIGNAS(x) alignas(x) -#define __alignof__ __alignof - -#define __WI_LIBCPP_EXPLICIT explicit -#define __WI_LIBCPP_NORETURN [[noreturn]] -#define __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS __pragma(warning(suppress:26495)) -#define __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS __pragma(warning(suppress:26439)) - - -#if __WI_LIBCPP_STD_VER > 14 -#define __WI_LIBCPP_NODISCARD_ATTRIBUTE [[nodiscard]] -#else -#define __WI_LIBCPP_NODISCARD_ATTRIBUTE _Check_return_ -#endif - -#define __WI_HAS_FEATURE_IS_UNION 1 -#define __WI_HAS_FEATURE_IS_CLASS 1 -#define __WI_HAS_FEATURE_IS_ENUM 1 -#define __WI_HAS_FEATURE_IS_CONVERTIBLE_TO 1 -#define __WI_HAS_FEATURE_IS_EMPTY 1 -#define __WI_HAS_FEATURE_IS_POLYMORPHIC 1 -#define __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR 1 -#define __WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS 1 -#define __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS 1 -#define __WI_HAS_FEATURE_IS_CONSTRUCTIBLE 1 -#define __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE 1 -#define __WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE 1 -#define __WI_HAS_FEATURE_HAS_TRIVIAL_DESTRUCTOR 1 -#define __WI_HAS_FEATURE_NOEXCEPT 1 -#define __WI_HAS_FEATURE_IS_POD 1 -#define __WI_HAS_FEATURE_IS_STANDARD_LAYOUT 1 -#define __WI_HAS_FEATURE_IS_TRIVIALLY_COPYABLE 1 -#define __WI_HAS_FEATURE_IS_TRIVIAL 1 -#define __WI_HAS_FEATURE_HAS_TRIVIAL_CONSTRUCTOR 1 -#define __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR 1 -#define __WI_HAS_FEATURE_HAS_NOTHROW_COPY 1 -#define __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN 1 -#define __WI_HAS_FEATURE_IS_DESTRUCTIBLE 1 - -#if !defined(_CPPRTTI) && !defined(__WI_LIBCPP_NO_RTTI) -#define __WI_LIBCPP_NO_RTTI -#endif - -#define __WI_LIBCPP_IS_LITERAL(T) __is_literal_type(T) -#define __WI_LIBCPP_UNDERLYING_TYPE(T) __underlying_type(T) -#define __WI_LIBCPP_HAS_IS_FINAL -#define __WI_LIBCPP_HAS_IS_BASE_OF - -#if __WI_LIBCPP_STD_VER < 14 -#define __WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES -#endif - -#define __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF -#define __WI_LIBCPP_NO_CFI - -#define __WI_LIBCPP_ALWAYS_INLINE __forceinline -#define __WI_LIBCPP_INTERNAL_LINKAGE - -#endif - -#ifndef _WIN32 - -#ifdef __LITTLE_ENDIAN__ -# if __LITTLE_ENDIAN__ -# define __WI_LIBCPP_LITTLE_ENDIAN -# endif // __LITTLE_ENDIAN__ -#endif // __LITTLE_ENDIAN__ - -#ifdef __BIG_ENDIAN__ -# if __BIG_ENDIAN__ -# define __WI_LIBCPP_BIG_ENDIAN -# endif // __BIG_ENDIAN__ -#endif // __BIG_ENDIAN__ - -#ifdef __BYTE_ORDER__ -# if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ -# define __WI_LIBCPP_LITTLE_ENDIAN -# elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -# define __WI_LIBCPP_BIG_ENDIAN -# endif // __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ -#endif // __BYTE_ORDER__ - -#if !defined(__WI_LIBCPP_LITTLE_ENDIAN) && !defined(__WI_LIBCPP_BIG_ENDIAN) -# include -# if __BYTE_ORDER == __LITTLE_ENDIAN -# define __WI_LIBCPP_LITTLE_ENDIAN -# elif __BYTE_ORDER == __BIG_ENDIAN -# define __WI_LIBCPP_BIG_ENDIAN -# else // __BYTE_ORDER == __BIG_ENDIAN -# error unable to determine endian -# endif -#endif // !defined(__WI_LIBCPP_LITTLE_ENDIAN) && !defined(__WI_LIBCPP_BIG_ENDIAN) - -#else // _WIN32 - -#define __WI_LIBCPP_LITTLE_ENDIAN - -#endif // _WIN32 - -#ifdef __WI_LIBCPP_HAS_NO_CONSTEXPR -# define __WI_LIBCPP_CONSTEXPR -#else -# define __WI_LIBCPP_CONSTEXPR constexpr -#endif - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR) -# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 constexpr -#else -# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 -#endif - -#if __WI_LIBCPP_STD_VER > 14 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR) -# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX14 constexpr -#else -# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX14 -#endif - -#if __WI_LIBCPP_STD_VER > 17 && !defined(__WI_LIBCPP_HAS_NO_CXX14_CONSTEXPR) -# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX17 constexpr -#else -# define __WI_LIBCPP_CONSTEXPR_AFTER_CXX17 -#endif - -#if !defined(__WI_LIBCPP_DISABLE_NODISCARD_AFTER_CXX17) && \ - (__WI_LIBCPP_STD_VER > 17 || defined(__WI_LIBCPP_ENABLE_NODISCARD)) -# define __WI_LIBCPP_NODISCARD_AFTER_CXX17 __WI_LIBCPP_NODISCARD_ATTRIBUTE -#else -# define __WI_LIBCPP_NODISCARD_AFTER_CXX17 -#endif - -#if __WI_LIBCPP_STD_VER > 14 && defined(__cpp_inline_variables) && (__cpp_inline_variables >= 201606L) -# define __WI_LIBCPP_INLINE_VAR inline -#else -# define __WI_LIBCPP_INLINE_VAR -#endif - -#ifdef __WI_LIBCPP_CXX03_LANG -#define __WI_LIBCPP_HAS_NO_UNICODE_CHARS -#define __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES -#endif - -#ifndef __SIZEOF_INT128__ -#define __WI_LIBCPP_HAS_NO_INT128 -#endif - -#if !__WI_HAS_FEATURE_NOEXCEPT && !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) -#define __WI_LIBCPP_HAS_NO_NOEXCEPT -#endif - -#ifndef __WI_LIBCPP_HAS_NO_NOEXCEPT -# define WI_NOEXCEPT noexcept -# define __WI_NOEXCEPT_(x) noexcept(x) -#else -# define WI_NOEXCEPT throw() -# define __WI_NOEXCEPT_(x) -#endif - -#if defined(__WI_LIBCPP_OBJECT_FORMAT_COFF) -#define __WI_LIBCPP_HIDDEN -#define __WI_LIBCPP_TEMPLATE_VIS -#endif // defined(__WI_LIBCPP_OBJECT_FORMAT_COFF) - -#ifndef __WI_LIBCPP_HIDDEN -# if !defined(__WI_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) -# define __WI_LIBCPP_HIDDEN __attribute__ ((__visibility__("hidden"))) -# else -# define __WI_LIBCPP_HIDDEN -# endif -#endif - -#ifndef __WI_LIBCPP_TEMPLATE_VIS -# if !defined(__WI_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS) && !defined(__WI_LIBCPP_COMPILER_MSVC) -# if __has_attribute(__type_visibility__) -# define __WI_LIBCPP_TEMPLATE_VIS __attribute__ ((__type_visibility__("default"))) -# else -# define __WI_LIBCPP_TEMPLATE_VIS __attribute__ ((__visibility__("default"))) -# endif -# else -# define __WI_LIBCPP_TEMPLATE_VIS -# endif -#endif - -#define __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_HIDDEN __WI_LIBCPP_INTERNAL_LINKAGE - -namespace wistd // ("Windows Implementation" std) -{ - using nullptr_t = decltype(__nullptr); - - template - struct __less - { - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 - bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;} - - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 - bool operator()(const _T1& __x, const _T2& __y) const {return __x < __y;} - - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 - bool operator()(const _T2& __x, const _T1& __y) const {return __x < __y;} - - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 - bool operator()(const _T2& __x, const _T2& __y) const {return __x < __y;} - }; - - template - struct __less<_T1, _T1> - { - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 - bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;} - }; - - template - struct __less - { - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 - bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;} - }; - - template - struct __less<_T1, const _T1> - { - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 - bool operator()(const _T1& __x, const _T1& __y) const {return __x < __y;} - }; - - // These are added to wistd to enable use of min/max without having to use the windows.h min/max - // macros that some clients might not have access to. Note: the STL versions of these have debug - // checking for the less than operator and support for iterators that these implementations lack. - // Use the STL versions when you require use of those features. - - // min - - template - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 - const _Tp& - (min)(const _Tp& __a, const _Tp& __b, _Compare __comp) - { - return __comp(__b, __a) ? __b : __a; - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 - const _Tp& - (min)(const _Tp& __a, const _Tp& __b) - { - return (min)(__a, __b, __less<_Tp>()); - } - - // max - - template - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 - const _Tp& - (max)(const _Tp& __a, const _Tp& __b, _Compare __comp) - { - return __comp(__a, __b) ? __b : __a; - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 - const _Tp& - (max)(const _Tp& __a, const _Tp& __b) - { - return (max)(__a, __b, __less<_Tp>()); - } - - template - struct __WI_LIBCPP_TEMPLATE_VIS unary_function - { - using argument_type = _Arg; - using result_type = _Result; - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS binary_function - { - using first_argument_type = _Arg1; - using second_argument_type = _Arg2; - using result_type = _Result; - }; -} -/// @endcond - -#endif // _WISTD_CONFIG_H_ diff --git a/src/common/dep/wil/wistd_functional.h b/src/common/dep/wil/wistd_functional.h deleted file mode 100644 index c112057e5..000000000 --- a/src/common/dep/wil/wistd_functional.h +++ /dev/null @@ -1,548 +0,0 @@ -// -*- C++ -*- -//===------------------------ functional ----------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// STL common functionality -// -// Some aspects of STL are core language concepts that should be used from all C++ code, regardless -// of whether exceptions are enabled in the component. Common library code that expects to be used -// from exception-free components want these concepts, but including STL headers directly introduces -// friction as it requires components not using STL to declare their STL version. Doing so creates -// ambiguity around whether STL use is safe in a particular component and implicitly brings in -// a long list of headers (including ) which can create further ambiguity around throwing new -// support (some routines pulled in may expect it). Secondarily, pulling in these headers also has -// the potential to create naming conflicts or other implied dependencies. -// -// To promote the use of these core language concepts outside of STL-based binaries, this file is -// selectively pulling those concepts *directly* from corresponding STL headers. The corresponding -// "std::" namespace STL functions and types should be preferred over these in code that is bound to -// STL. The implementation and naming of all functions are taken directly from STL, instead using -// "wistd" (Windows Implementation std) as the namespace. -// -// Routines in this namespace should always be considered a reflection of the *current* STL implementation -// of those routines. Updates from STL should be taken, but no "bugs" should be fixed here. -// -// New, exception-based code should not use this namespace, but instead should prefer the std:: implementation. -// Only code that is not exception-based and libraries that expect to be utilized across both exception -// and non-exception based code should utilize this functionality. - -#ifndef _WISTD_FUNCTIONAL_H_ -#define _WISTD_FUNCTIONAL_H_ - -// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage -#include "wistd_memory.h" -#include // For __fastfail -#include // For placement new - -#if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -#pragma GCC system_header -#endif - -#pragma warning(push) -#pragma warning(disable: 4324) -#pragma warning(disable: 4800) - -/// @cond -namespace wistd // ("Windows Implementation" std) -{ - // wistd::function - // - // All of the code below is in direct support of wistd::function. This class is identical to std::function - // with the following exceptions: - // - // 1) It never allocates and is safe to use from exception-free code (custom allocators are not supported) - // 2) It's slightly bigger on the stack (64 bytes, rather than 24 for 32bit) - // 3) There is an explicit static-assert if a lambda becomes too large to hold in the internal buffer (rather than an allocation) - - template - struct __invoke_void_return_wrapper - { -#ifndef __WI_LIBCPP_CXX03_LANG - template - static _Ret __call(_Args&&... __args) { - return __invoke(wistd::forward<_Args>(__args)...); - } -#else - template - static _Ret __call(_Fn __f) { - return __invoke(__f); - } - - template - static _Ret __call(_Fn __f, _A0& __a0) { - return __invoke(__f, __a0); - } - - template - static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1) { - return __invoke(__f, __a0, __a1); - } - - template - static _Ret __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2){ - return __invoke(__f, __a0, __a1, __a2); - } -#endif - }; - - template <> - struct __invoke_void_return_wrapper - { -#ifndef __WI_LIBCPP_CXX03_LANG - template - static void __call(_Args&&... __args) { - (void)__invoke(wistd::forward<_Args>(__args)...); - } -#else - template - static void __call(_Fn __f) { - __invoke(__f); - } - - template - static void __call(_Fn __f, _A0& __a0) { - __invoke(__f, __a0); - } - - template - static void __call(_Fn __f, _A0& __a0, _A1& __a1) { - __invoke(__f, __a0, __a1); - } - - template - static void __call(_Fn __f, _A0& __a0, _A1& __a1, _A2& __a2) { - __invoke(__f, __a0, __a1, __a2); - } -#endif - }; - - //////////////////////////////////////////////////////////////////////////////// - // FUNCTION - //============================================================================== - - // bad_function_call - - __WI_LIBCPP_NORETURN inline __WI_LIBCPP_INLINE_VISIBILITY - void __throw_bad_function_call() - { - __fastfail(7); // FAST_FAIL_FATAL_APP_EXIT - } - - template class __WI_LIBCPP_TEMPLATE_VIS function; // undefined - - namespace __function - { - - template - struct __maybe_derive_from_unary_function - { - }; - - template - struct __maybe_derive_from_unary_function<_Rp(_A1)> - : public unary_function<_A1, _Rp> - { - }; - - template - struct __maybe_derive_from_binary_function - { - }; - - template - struct __maybe_derive_from_binary_function<_Rp(_A1, _A2)> - : public binary_function<_A1, _A2, _Rp> - { - }; - - template - __WI_LIBCPP_INLINE_VISIBILITY - bool __not_null(_Fp const&) { return true; } - - template - __WI_LIBCPP_INLINE_VISIBILITY - bool __not_null(_Fp* __ptr) { return __ptr; } - - template - __WI_LIBCPP_INLINE_VISIBILITY - bool __not_null(_Ret _Class::*__ptr) { return __ptr; } - - template - __WI_LIBCPP_INLINE_VISIBILITY - bool __not_null(function<_Fp> const& __f) { return !!__f; } - - } // namespace __function - -#ifndef __WI_LIBCPP_CXX03_LANG - - namespace __function { - - template class __base; - - template - class __base<_Rp(_ArgTypes...)> - { - __base(const __base&); - __base& operator=(const __base&); - public: - __WI_LIBCPP_INLINE_VISIBILITY __base() {} - __WI_LIBCPP_INLINE_VISIBILITY virtual ~__base() {} - virtual void __clone(__base*) const = 0; - virtual void __move(__base*) = 0; - virtual void destroy() WI_NOEXCEPT = 0; - virtual _Rp operator()(_ArgTypes&& ...) = 0; - }; - - template class __func; - - template - class __func<_Fp, _Rp(_ArgTypes...)> - : public __base<_Rp(_ArgTypes...)> - { - _Fp __f_; - public: - __WI_LIBCPP_INLINE_VISIBILITY - explicit __func(_Fp&& __f) - : __f_(wistd::move(__f)) {} - - __WI_LIBCPP_INLINE_VISIBILITY - explicit __func(const _Fp& __f) - : __f_(__f) {} - - virtual void __clone(__base<_Rp(_ArgTypes...)>*) const; - virtual void __move(__base<_Rp(_ArgTypes...)>*); - virtual void destroy() WI_NOEXCEPT; - virtual _Rp operator()(_ArgTypes&& ... __arg); - }; - - template - void - __func<_Fp, _Rp(_ArgTypes...)>::__clone(__base<_Rp(_ArgTypes...)>* __p) const - { - ::new (__p) __func(__f_); - } - - template - void - __func<_Fp, _Rp(_ArgTypes...)>::__move(__base<_Rp(_ArgTypes...)>* __p) - { - ::new (__p) __func(wistd::move(__f_)); - } - - template - void - __func<_Fp, _Rp(_ArgTypes...)>::destroy() WI_NOEXCEPT - { - __f_.~_Fp(); - } - - template - _Rp - __func<_Fp, _Rp(_ArgTypes...)>::operator()(_ArgTypes&& ... __arg) - { - typedef __invoke_void_return_wrapper<_Rp> _Invoker; - return _Invoker::__call(__f_, wistd::forward<_ArgTypes>(__arg)...); - } - - // 'wistd::function' is most similar to 'inplace_function' in that it _only_ permits holding function objects - // that can fit within its internal buffer. Therefore, we expand this size to accommodate space for at least 12 - // pointers (__base vtable takes an additional one). - constexpr const size_t __buffer_size = 13 * sizeof(void*); - - } // __function - - // NOTE: The extra 'alignas' here is to work around the x86 compiler bug mentioned in - // https://github.com/microsoft/STL/issues/1533 to force alignment on the stack - template - class __WI_LIBCPP_TEMPLATE_VIS __WI_ALIGNAS(typename aligned_storage<__function::__buffer_size>::type) - function<_Rp(_ArgTypes...)> - : public __function::__maybe_derive_from_unary_function<_Rp(_ArgTypes...)>, - public __function::__maybe_derive_from_binary_function<_Rp(_ArgTypes...)> - { - using __base = __function::__base<_Rp(_ArgTypes...)>; - __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS - typename aligned_storage<__function::__buffer_size>::type __buf_; - __base* __f_; - - __WI_LIBCPP_NO_CFI static __base *__as_base(void *p) { - return static_cast<__base*>(p); - } - - template - struct __callable_imp - { - static const bool value = is_same::value || - is_convertible::type, - _Rp>::value; - }; - - template - struct __callable_imp<_Fp, false> - { - static constexpr bool value = false; - }; - - template - struct __callable - { - static const bool value = __callable_imp<_Fp, __lazy_and< - integral_constant, function>::value>, - __invokable<_Fp&, _ArgTypes...> - >::value>::value; - }; - - template - using _EnableIfCallable = typename enable_if<__callable<_Fp>::value>::type; - public: - using result_type = _Rp; - - // construct/copy/destroy: - __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS - function() WI_NOEXCEPT : __f_(0) {} - - __WI_LIBCPP_INLINE_VISIBILITY - function(nullptr_t) WI_NOEXCEPT : __f_(0) {} - function(const function&); - function(function&&); - template> - function(_Fp); - - function& operator=(const function&); - function& operator=(function&&); - function& operator=(nullptr_t) WI_NOEXCEPT; - template> - function& operator=(_Fp&&); - - ~function(); - - // function modifiers: - void swap(function&); - - // function capacity: - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - __WI_LIBCPP_EXPLICIT operator bool() const WI_NOEXCEPT {return __f_;} - - // deleted overloads close possible hole in the type system - template - bool operator==(const function<_R2(_ArgTypes2...)>&) const = delete; - template - bool operator!=(const function<_R2(_ArgTypes2...)>&) const = delete; - public: - // function invocation: - _Rp operator()(_ArgTypes...) const; - - // NOTE: type_info is very compiler specific, and on top of that, we're operating in a namespace other than - // 'std' so all functions requiring RTTI have been removed - }; - - template - __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS - function<_Rp(_ArgTypes...)>::function(const function& __f) - { - if (__f.__f_ == nullptr) - __f_ = 0; - else - { - __f_ = __as_base(&__buf_); - __f.__f_->__clone(__f_); - } - } - - template - __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS __WI_LIBCPP_SUPPRESS_NOEXCEPT_ANALYSIS - function<_Rp(_ArgTypes...)>::function(function&& __f) - { - if (__f.__f_ == nullptr) - __f_ = 0; - else - { - __f_ = __as_base(&__buf_); - __f.__f_->__move(__f_); - __f.__f_->destroy(); - __f.__f_ = 0; - } - } - - template - template - __WI_LIBCPP_SUPPRESS_NONINIT_ANALYSIS - function<_Rp(_ArgTypes...)>::function(_Fp __f) - : __f_(nullptr) - { - if (__function::__not_null(__f)) - { - typedef __function::__func<_Fp, _Rp(_ArgTypes...)> _FF; - static_assert(sizeof(_FF) <= sizeof(__buf_), - "The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). Refactor to reduce size of the capture."); - __f_ = ::new(static_cast(&__buf_)) _FF(wistd::move(__f)); - } - } - - template - function<_Rp(_ArgTypes...)>& - function<_Rp(_ArgTypes...)>::operator=(const function& __f) - { - *this = nullptr; - if (__f.__f_) - { - __f_ = __as_base(&__buf_); - __f.__f_->__clone(__f_); - } - return *this; - } - - template - function<_Rp(_ArgTypes...)>& - function<_Rp(_ArgTypes...)>::operator=(function&& __f) - { - *this = nullptr; - if (__f.__f_) - { - __f_ = __as_base(&__buf_); - __f.__f_->__move(__f_); - __f.__f_->destroy(); - __f.__f_ = 0; - } - return *this; - } - - template - function<_Rp(_ArgTypes...)>& - function<_Rp(_ArgTypes...)>::operator=(nullptr_t) WI_NOEXCEPT - { - __base* __t = __f_; - __f_ = 0; - if (__t) - __t->destroy(); - return *this; - } - - template - template - function<_Rp(_ArgTypes...)>& - function<_Rp(_ArgTypes...)>::operator=(_Fp&& __f) - { - *this = nullptr; - if (__function::__not_null(__f)) - { - typedef __function::__func::type, _Rp(_ArgTypes...)> _FF; - static_assert(sizeof(_FF) <= sizeof(__buf_), - "The sizeof(wistd::function) has grown too large for the reserved buffer (12 pointers). Refactor to reduce size of the capture."); - __f_ = ::new(static_cast(&__buf_)) _FF(wistd::move(__f)); - } - - return *this; - } - - template - function<_Rp(_ArgTypes...)>::~function() - { - if (__f_) - __f_->destroy(); - } - - template - void - function<_Rp(_ArgTypes...)>::swap(function& __f) - { - if (wistd::addressof(__f) == this) - return; - if (__f_ && __f.__f_) - { - typename aligned_storage::type __tempbuf; - __base* __t = __as_base(&__tempbuf); - __f_->__move(__t); - __f_->destroy(); - __f_ = 0; - __f.__f_->__move(__as_base(&__buf_)); - __f.__f_->destroy(); - __f.__f_ = 0; - __f_ = __as_base(&__buf_); - __t->__move(__as_base(&__f.__buf_)); - __t->destroy(); - __f.__f_ = __as_base(&__f.__buf_); - } - else if (__f_) - { - __f_->__move(__as_base(&__f.__buf_)); - __f_->destroy(); - __f_ = 0; - __f.__f_ = __as_base(&__f.__buf_); - } - else if (__f.__f_) - { - __f.__f_->__move(__as_base(&__buf_)); - __f.__f_->destroy(); - __f.__f_ = 0; - __f_ = __as_base(&__buf_); - } - } - - template - _Rp - function<_Rp(_ArgTypes...)>::operator()(_ArgTypes... __arg) const - { - if (__f_ == nullptr) - __throw_bad_function_call(); - return (*__f_)(wistd::forward<_ArgTypes>(__arg)...); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator==(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) WI_NOEXCEPT {return !__f;} - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator==(nullptr_t, const function<_Rp(_ArgTypes...)>& __f) WI_NOEXCEPT {return !__f;} - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator!=(const function<_Rp(_ArgTypes...)>& __f, nullptr_t) WI_NOEXCEPT {return (bool)__f;} - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator!=(nullptr_t, const function<_Rp(_ArgTypes...)>& __f) WI_NOEXCEPT {return (bool)__f;} - - // Provide both 'swap_wil' and 'swap' since we now have two ADL scenarios that we need to work - template - inline __WI_LIBCPP_INLINE_VISIBILITY - void - swap(function<_Rp(_ArgTypes...)>& __x, function<_Rp(_ArgTypes...)>& __y) - {return __x.swap(__y);} - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - void - swap_wil(function<_Rp(_ArgTypes...)>& __x, function<_Rp(_ArgTypes...)>& __y) - {return __x.swap(__y);} - - // std::invoke - template - typename __invoke_of<_Fn, _Args...>::type - invoke(_Fn&& __f, _Args&&... __args) - __WI_NOEXCEPT_((__nothrow_invokable<_Fn, _Args...>::value)) - { - return wistd::__invoke(wistd::forward<_Fn>(__f), wistd::forward<_Args>(__args)...); - } - -#else // __WI_LIBCPP_CXX03_LANG - -#error wistd::function and wistd::invoke not implemented for pre-C++11 - -#endif -} -/// @endcond - -#pragma warning(pop) - -#endif // _WISTD_FUNCTIONAL_H_ diff --git a/src/common/dep/wil/wistd_memory.h b/src/common/dep/wil/wistd_memory.h deleted file mode 100644 index 5730f2fd6..000000000 --- a/src/common/dep/wil/wistd_memory.h +++ /dev/null @@ -1,1038 +0,0 @@ -// -*- C++ -*- -//===-------------------------- memory ------------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// STL common functionality -// -// Some aspects of STL are core language concepts that should be used from all C++ code, regardless -// of whether exceptions are enabled in the component. Common library code that expects to be used -// from exception-free components want these concepts, but including STL headers directly introduces -// friction as it requires components not using STL to declare their STL version. Doing so creates -// ambiguity around whether STL use is safe in a particular component and implicitly brings in -// a long list of headers (including ) which can create further ambiguity around throwing new -// support (some routines pulled in may expect it). Secondarily, pulling in these headers also has -// the potential to create naming conflicts or other implied dependencies. -// -// To promote the use of these core language concepts outside of STL-based binaries, this file is -// selectively pulling those concepts *directly* from corresponding STL headers. The corresponding -// "std::" namespace STL functions and types should be preferred over these in code that is bound to -// STL. The implementation and naming of all functions are taken directly from STL, instead using -// "wistd" (Windows Implementation std) as the namespace. -// -// Routines in this namespace should always be considered a reflection of the *current* STL implementation -// of those routines. Updates from STL should be taken, but no "bugs" should be fixed here. -// -// New, exception-based code should not use this namespace, but instead should prefer the std:: implementation. -// Only code that is not exception-based and libraries that expect to be utilized across both exception -// and non-exception based code should utilize this functionality. - -#ifndef _WISTD_MEMORY_H_ -#define _WISTD_MEMORY_H_ - -// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage -#include "wistd_type_traits.h" - -#if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -#pragma GCC system_header -#endif - -/// @cond -namespace wistd // ("Windows Implementation" std) -{ - // allocator_traits - - template - struct __has_pointer_type : false_type {}; - - template - struct __has_pointer_type<_Tp, - typename __void_t::type> : true_type {}; - - namespace __pointer_type_imp - { - - template ::value> - struct __pointer_type - { - using type = typename _Dp::pointer; - }; - - template - struct __pointer_type<_Tp, _Dp, false> - { - using type = _Tp*; - }; - - } // __pointer_type_imp - - template - struct __pointer_type - { - using type = typename __pointer_type_imp::__pointer_type<_Tp, typename remove_reference<_Dp>::type>::type; - }; - - template ::value && !__libcpp_is_final<_Tp>::value> - struct __compressed_pair_elem { - using _ParamT = _Tp; - using reference = _Tp&; - using const_reference = const _Tp&; - -#ifndef __WI_LIBCPP_CXX03_LANG - __WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem() : __value_() {} - - template ::type>::value - >::type> - __WI_LIBCPP_INLINE_VISIBILITY - constexpr explicit - __compressed_pair_elem(_Up&& __u) - : __value_(wistd::forward<_Up>(__u)) - { - } - - // NOTE: Since we have not added 'tuple' to 'wistd', the 'piecewise' constructor has been removed -#else - __WI_LIBCPP_INLINE_VISIBILITY __compressed_pair_elem() : __value_() {} - __WI_LIBCPP_INLINE_VISIBILITY - __compressed_pair_elem(_ParamT __p) : __value_(wistd::forward<_ParamT>(__p)) {} -#endif - - __WI_LIBCPP_INLINE_VISIBILITY reference __get() WI_NOEXCEPT { return __value_; } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - const_reference __get() const WI_NOEXCEPT { return __value_; } - - private: - _Tp __value_; - }; - - template - struct __compressed_pair_elem<_Tp, _Idx, true> : private _Tp { - using _ParamT = _Tp; - using reference = _Tp&; - using const_reference = const _Tp&; - using __value_type = _Tp; - -#ifndef __WI_LIBCPP_CXX03_LANG - __WI_LIBCPP_INLINE_VISIBILITY constexpr __compressed_pair_elem() = default; - - template ::type>::value - >::type> - __WI_LIBCPP_INLINE_VISIBILITY - constexpr explicit - __compressed_pair_elem(_Up&& __u) - : __value_type(wistd::forward<_Up>(__u)) - {} - - // NOTE: Since we have not added 'tuple' to 'wistd', the 'piecewise' constructor has been removed -#else - __WI_LIBCPP_INLINE_VISIBILITY __compressed_pair_elem() : __value_type() {} - __WI_LIBCPP_INLINE_VISIBILITY - __compressed_pair_elem(_ParamT __p) - : __value_type(wistd::forward<_ParamT>(__p)) {} -#endif - - __WI_LIBCPP_INLINE_VISIBILITY reference __get() WI_NOEXCEPT { return *this; } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - const_reference __get() const WI_NOEXCEPT { return *this; } - }; - - // Tag used to construct the second element of the compressed pair. - struct __second_tag {}; - - template - class __declspec(empty_bases) __compressed_pair : private __compressed_pair_elem<_T1, 0>, - private __compressed_pair_elem<_T2, 1> { - using _Base1 = __compressed_pair_elem<_T1, 0>; - using _Base2 = __compressed_pair_elem<_T2, 1>; - - // NOTE: This static assert should never fire because __compressed_pair - // is *almost never* used in a scenario where it's possible for T1 == T2. - // (The exception is wistd::function where it is possible that the function - // object and the allocator have the same type). - static_assert((!is_same<_T1, _T2>::value), - "__compressed_pair cannot be instantated when T1 and T2 are the same type; " - "The current implementation is NOT ABI-compatible with the previous " - "implementation for this configuration"); - - public: -#ifndef __WI_LIBCPP_CXX03_LANG - template , _Dummy>::value && - __dependent_type, _Dummy>::value - >::type - > - __WI_LIBCPP_INLINE_VISIBILITY - constexpr __compressed_pair() {} - - template ::type, - __compressed_pair>::value, - bool>::type = true> - __WI_LIBCPP_INLINE_VISIBILITY constexpr explicit - __compressed_pair(_Tp&& __t) - : _Base1(wistd::forward<_Tp>(__t)), _Base2() {} - - template - __WI_LIBCPP_INLINE_VISIBILITY constexpr - __compressed_pair(__second_tag, _Tp&& __t) - : _Base1(), _Base2(wistd::forward<_Tp>(__t)) {} - - template - __WI_LIBCPP_INLINE_VISIBILITY constexpr - __compressed_pair(_U1&& __t1, _U2&& __t2) - : _Base1(wistd::forward<_U1>(__t1)), _Base2(wistd::forward<_U2>(__t2)) {} - - // NOTE: Since we have not added 'tuple' to 'wistd', the 'piecewise' constructor has been removed -#else - __WI_LIBCPP_INLINE_VISIBILITY - __compressed_pair() {} - - __WI_LIBCPP_INLINE_VISIBILITY explicit - __compressed_pair(_T1 __t1) : _Base1(wistd::forward<_T1>(__t1)) {} - - __WI_LIBCPP_INLINE_VISIBILITY - __compressed_pair(__second_tag, _T2 __t2) - : _Base1(), _Base2(wistd::forward<_T2>(__t2)) {} - - __WI_LIBCPP_INLINE_VISIBILITY - __compressed_pair(_T1 __t1, _T2 __t2) - : _Base1(wistd::forward<_T1>(__t1)), _Base2(wistd::forward<_T2>(__t2)) {} -#endif - - __WI_LIBCPP_INLINE_VISIBILITY - typename _Base1::reference first() WI_NOEXCEPT { - return static_cast<_Base1&>(*this).__get(); - } - - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - typename _Base1::const_reference first() const WI_NOEXCEPT { - return static_cast<_Base1 const&>(*this).__get(); - } - - __WI_LIBCPP_INLINE_VISIBILITY - typename _Base2::reference second() WI_NOEXCEPT { - return static_cast<_Base2&>(*this).__get(); - } - - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - typename _Base2::const_reference second() const WI_NOEXCEPT { - return static_cast<_Base2 const&>(*this).__get(); - } - - __WI_LIBCPP_INLINE_VISIBILITY - void swap(__compressed_pair& __x) - __WI_NOEXCEPT_(__is_nothrow_swappable<_T1>::value && - __is_nothrow_swappable<_T2>::value) - { - using wistd::swap_wil; - swap_wil(first(), __x.first()); - swap_wil(second(), __x.second()); - } - }; - - // Provide both 'swap_wil' and 'swap' since we now have two ADL scenarios that we need to work - template - inline __WI_LIBCPP_INLINE_VISIBILITY - void swap(__compressed_pair<_T1, _T2>& __x, __compressed_pair<_T1, _T2>& __y) - __WI_NOEXCEPT_(__is_nothrow_swappable<_T1>::value && - __is_nothrow_swappable<_T2>::value) { - __x.swap(__y); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - void swap_wil(__compressed_pair<_T1, _T2>& __x, __compressed_pair<_T1, _T2>& __y) - __WI_NOEXCEPT_(__is_nothrow_swappable<_T1>::value && - __is_nothrow_swappable<_T2>::value) { - __x.swap(__y); - } - - // default_delete - - template - struct __WI_LIBCPP_TEMPLATE_VIS default_delete { - static_assert(!is_function<_Tp>::value, - "default_delete cannot be instantiated for function types"); -#ifndef __WI_LIBCPP_CXX03_LANG - __WI_LIBCPP_INLINE_VISIBILITY constexpr default_delete() WI_NOEXCEPT = default; -#else - __WI_LIBCPP_INLINE_VISIBILITY default_delete() {} -#endif - template - __WI_LIBCPP_INLINE_VISIBILITY - default_delete(const default_delete<_Up>&, - typename enable_if::value>::type* = - nullptr) WI_NOEXCEPT {} - - __WI_LIBCPP_INLINE_VISIBILITY void operator()(_Tp* __ptr) const WI_NOEXCEPT { - static_assert(sizeof(_Tp) > 0, - "default_delete can not delete incomplete type"); - static_assert(!is_void<_Tp>::value, - "default_delete can not delete incomplete type"); - delete __ptr; - } - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS default_delete<_Tp[]> { - private: - template - struct _EnableIfConvertible - : enable_if::value> {}; - - public: -#ifndef __WI_LIBCPP_CXX03_LANG - __WI_LIBCPP_INLINE_VISIBILITY constexpr default_delete() WI_NOEXCEPT = default; -#else - __WI_LIBCPP_INLINE_VISIBILITY default_delete() {} -#endif - - template - __WI_LIBCPP_INLINE_VISIBILITY - default_delete(const default_delete<_Up[]>&, - typename _EnableIfConvertible<_Up>::type* = nullptr) WI_NOEXCEPT {} - - template - __WI_LIBCPP_INLINE_VISIBILITY - typename _EnableIfConvertible<_Up>::type - operator()(_Up* __ptr) const WI_NOEXCEPT { - static_assert(sizeof(_Tp) > 0, - "default_delete can not delete incomplete type"); - static_assert(!is_void<_Tp>::value, - "default_delete can not delete void type"); - delete[] __ptr; - } - }; - - - -#ifndef __WI_LIBCPP_CXX03_LANG - template - struct __unique_ptr_deleter_sfinae { - static_assert(!is_reference<_Deleter>::value, "incorrect specialization"); - using __lval_ref_type = const _Deleter&; - using __good_rval_ref_type = _Deleter&&; - using __enable_rval_overload = true_type; - }; - - template - struct __unique_ptr_deleter_sfinae<_Deleter const&> { - using __lval_ref_type = const _Deleter&; - using __bad_rval_ref_type = const _Deleter&&; - using __enable_rval_overload = false_type; - }; - - template - struct __unique_ptr_deleter_sfinae<_Deleter&> { - using __lval_ref_type = _Deleter&; - using __bad_rval_ref_type = _Deleter&&; - using __enable_rval_overload = false_type; - }; -#endif // !defined(__WI_LIBCPP_CXX03_LANG) - - template > - class __WI_LIBCPP_TEMPLATE_VIS unique_ptr { - public: - using element_type = _Tp; - using deleter_type = _Dp; - using pointer = typename __pointer_type<_Tp, deleter_type>::type; - - static_assert(!is_rvalue_reference::value, - "the specified deleter type cannot be an rvalue reference"); - - private: - __compressed_pair __ptr_; - - struct __nat { int __for_bool_; }; - -#ifndef __WI_LIBCPP_CXX03_LANG - using _DeleterSFINAE = __unique_ptr_deleter_sfinae<_Dp>; - - template - using _LValRefType = - typename __dependent_type<_DeleterSFINAE, _Dummy>::__lval_ref_type; - - template - using _GoodRValRefType = - typename __dependent_type<_DeleterSFINAE, _Dummy>::__good_rval_ref_type; - - template - using _BadRValRefType = - typename __dependent_type<_DeleterSFINAE, _Dummy>::__bad_rval_ref_type; - - template , _Dummy>::type> - using _EnableIfDeleterDefaultConstructible = - typename enable_if::value && - !is_pointer<_Deleter>::value>::type; - - template - using _EnableIfDeleterConstructible = - typename enable_if::value>::type; - - template - using _EnableIfMoveConvertible = typename enable_if< - is_convertible::value && - !is_array<_Up>::value - >::type; - - template - using _EnableIfDeleterConvertible = typename enable_if< - (is_reference<_Dp>::value && is_same<_Dp, _UDel>::value) || - (!is_reference<_Dp>::value && is_convertible<_UDel, _Dp>::value) - >::type; - - template - using _EnableIfDeleterAssignable = typename enable_if< - is_assignable<_Dp&, _UDel&&>::value - >::type; - - public: - template > - __WI_LIBCPP_INLINE_VISIBILITY - constexpr unique_ptr() WI_NOEXCEPT : __ptr_(pointer()) {} - - template > - __WI_LIBCPP_INLINE_VISIBILITY - constexpr unique_ptr(nullptr_t) WI_NOEXCEPT : __ptr_(pointer()) {} - - template > - __WI_LIBCPP_INLINE_VISIBILITY - explicit unique_ptr(pointer __p) WI_NOEXCEPT : __ptr_(__p) {} - - template >> - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(pointer __p, _LValRefType<_Dummy> __d) WI_NOEXCEPT - : __ptr_(__p, __d) {} - - template >> - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(pointer __p, _GoodRValRefType<_Dummy> __d) WI_NOEXCEPT - : __ptr_(__p, wistd::move(__d)) { - static_assert(!is_reference::value, - "rvalue deleter bound to reference"); - } - - template >> - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(pointer __p, _BadRValRefType<_Dummy> __d) = delete; - - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(unique_ptr&& __u) WI_NOEXCEPT - : __ptr_(__u.release(), wistd::forward(__u.get_deleter())) { - } - - template , _Up>, - class = _EnableIfDeleterConvertible<_Ep> - > - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(unique_ptr<_Up, _Ep>&& __u) WI_NOEXCEPT - : __ptr_(__u.release(), wistd::forward<_Ep>(__u.get_deleter())) {} - - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr& operator=(unique_ptr&& __u) WI_NOEXCEPT { - reset(__u.release()); - __ptr_.second() = wistd::forward(__u.get_deleter()); - return *this; - } - - template , _Up>, - class = _EnableIfDeleterAssignable<_Ep> - > - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) WI_NOEXCEPT { - reset(__u.release()); - __ptr_.second() = wistd::forward<_Ep>(__u.get_deleter()); - return *this; - } - -#else // __WI_LIBCPP_CXX03_LANG - private: - unique_ptr(unique_ptr&); - template unique_ptr(unique_ptr<_Up, _Ep>&); - - unique_ptr& operator=(unique_ptr&); - template unique_ptr& operator=(unique_ptr<_Up, _Ep>&); - - public: - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr() : __ptr_(pointer()) - { - static_assert(!is_pointer::value, - "unique_ptr constructed with null function pointer deleter"); - static_assert(is_default_constructible::value, - "unique_ptr::deleter_type is not default constructible"); - } - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(nullptr_t) : __ptr_(pointer()) - { - static_assert(!is_pointer::value, - "unique_ptr constructed with null function pointer deleter"); - } - __WI_LIBCPP_INLINE_VISIBILITY - explicit unique_ptr(pointer __p) - : __ptr_(wistd::move(__p)) { - static_assert(!is_pointer::value, - "unique_ptr constructed with null function pointer deleter"); - } - - __WI_LIBCPP_INLINE_VISIBILITY - operator __rv() { - return __rv(*this); - } - - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(__rv __u) - : __ptr_(__u->release(), - wistd::forward(__u->get_deleter())) {} - - template - __WI_LIBCPP_INLINE_VISIBILITY - typename enable_if< - !is_array<_Up>::value && - is_convertible::pointer, - pointer>::value && - is_assignable::value, - unique_ptr&>::type - operator=(unique_ptr<_Up, _Ep> __u) { - reset(__u.release()); - __ptr_.second() = wistd::forward<_Ep>(__u.get_deleter()); - return *this; - } - - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(pointer __p, deleter_type __d) - : __ptr_(wistd::move(__p), wistd::move(__d)) {} -#endif // __WI_LIBCPP_CXX03_LANG - - __WI_LIBCPP_INLINE_VISIBILITY - ~unique_ptr() { reset(); } - - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr& operator=(nullptr_t) WI_NOEXCEPT { - reset(); - return *this; - } - - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - typename add_lvalue_reference<_Tp>::type - operator*() const { - return *__ptr_.first(); - } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - pointer operator->() const WI_NOEXCEPT { - return __ptr_.first(); - } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - pointer get() const WI_NOEXCEPT { - return __ptr_.first(); - } - __WI_LIBCPP_INLINE_VISIBILITY - deleter_type& get_deleter() WI_NOEXCEPT { - return __ptr_.second(); - } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - const deleter_type& get_deleter() const WI_NOEXCEPT { - return __ptr_.second(); - } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - __WI_LIBCPP_EXPLICIT operator bool() const WI_NOEXCEPT { - return __ptr_.first() != nullptr; - } - - __WI_LIBCPP_INLINE_VISIBILITY - pointer release() WI_NOEXCEPT { - pointer __t = __ptr_.first(); - __ptr_.first() = pointer(); - return __t; - } - - __WI_LIBCPP_INLINE_VISIBILITY - void reset(pointer __p = pointer()) WI_NOEXCEPT { - pointer __tmp = __ptr_.first(); - __ptr_.first() = __p; - if (__tmp) - __ptr_.second()(__tmp); - } - - __WI_LIBCPP_INLINE_VISIBILITY - void swap(unique_ptr& __u) WI_NOEXCEPT { - __ptr_.swap(__u.__ptr_); - } - }; - - - template - class __WI_LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> { - public: - using element_type = _Tp; - using deleter_type = _Dp; - using pointer = typename __pointer_type<_Tp, deleter_type>::type; - - private: - __compressed_pair __ptr_; - - template - struct _CheckArrayPointerConversion : is_same<_From, pointer> {}; - - template - struct _CheckArrayPointerConversion<_FromElem*> - : integral_constant::value || - (is_same::value && - is_convertible<_FromElem(*)[], element_type(*)[]>::value) - > - {}; - -#ifndef __WI_LIBCPP_CXX03_LANG - using _DeleterSFINAE = __unique_ptr_deleter_sfinae<_Dp>; - - template - using _LValRefType = - typename __dependent_type<_DeleterSFINAE, _Dummy>::__lval_ref_type; - - template - using _GoodRValRefType = - typename __dependent_type<_DeleterSFINAE, _Dummy>::__good_rval_ref_type; - - template - using _BadRValRefType = - typename __dependent_type<_DeleterSFINAE, _Dummy>::__bad_rval_ref_type; - - template , _Dummy>::type> - using _EnableIfDeleterDefaultConstructible = - typename enable_if::value && - !is_pointer<_Deleter>::value>::type; - - template - using _EnableIfDeleterConstructible = - typename enable_if::value>::type; - - template - using _EnableIfPointerConvertible = typename enable_if< - _CheckArrayPointerConversion<_Pp>::value - >::type; - - template - using _EnableIfMoveConvertible = typename enable_if< - is_array<_Up>::value && - is_same::value && - is_same::value && - is_convertible<_ElemT(*)[], element_type(*)[]>::value - >::type; - - template - using _EnableIfDeleterConvertible = typename enable_if< - (is_reference<_Dp>::value && is_same<_Dp, _UDel>::value) || - (!is_reference<_Dp>::value && is_convertible<_UDel, _Dp>::value) - >::type; - - template - using _EnableIfDeleterAssignable = typename enable_if< - is_assignable<_Dp&, _UDel&&>::value - >::type; - - public: - template > - __WI_LIBCPP_INLINE_VISIBILITY - constexpr unique_ptr() WI_NOEXCEPT : __ptr_(pointer()) {} - - template > - __WI_LIBCPP_INLINE_VISIBILITY - constexpr unique_ptr(nullptr_t) WI_NOEXCEPT : __ptr_(pointer()) {} - - template , - class = _EnableIfPointerConvertible<_Pp>> - __WI_LIBCPP_INLINE_VISIBILITY - explicit unique_ptr(_Pp __p) WI_NOEXCEPT - : __ptr_(__p) {} - - template >, - class = _EnableIfPointerConvertible<_Pp>> - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(_Pp __p, _LValRefType<_Dummy> __d) WI_NOEXCEPT - : __ptr_(__p, __d) {} - - template >> - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(nullptr_t, _LValRefType<_Dummy> __d) WI_NOEXCEPT - : __ptr_(nullptr, __d) {} - - template >, - class = _EnableIfPointerConvertible<_Pp>> - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(_Pp __p, _GoodRValRefType<_Dummy> __d) WI_NOEXCEPT - : __ptr_(__p, wistd::move(__d)) { - static_assert(!is_reference::value, - "rvalue deleter bound to reference"); - } - - template >> - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(nullptr_t, _GoodRValRefType<_Dummy> __d) WI_NOEXCEPT - : __ptr_(nullptr, wistd::move(__d)) { - static_assert(!is_reference::value, - "rvalue deleter bound to reference"); - } - - template >, - class = _EnableIfPointerConvertible<_Pp>> - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(_Pp __p, _BadRValRefType<_Dummy> __d) = delete; - - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(unique_ptr&& __u) WI_NOEXCEPT - : __ptr_(__u.release(), wistd::forward(__u.get_deleter())) { - } - - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr& operator=(unique_ptr&& __u) WI_NOEXCEPT { - reset(__u.release()); - __ptr_.second() = wistd::forward(__u.get_deleter()); - return *this; - } - - template , _Up>, - class = _EnableIfDeleterConvertible<_Ep> - > - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(unique_ptr<_Up, _Ep>&& __u) WI_NOEXCEPT - : __ptr_(__u.release(), wistd::forward<_Ep>(__u.get_deleter())) { - } - - template , _Up>, - class = _EnableIfDeleterAssignable<_Ep> - > - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr& - operator=(unique_ptr<_Up, _Ep>&& __u) WI_NOEXCEPT { - reset(__u.release()); - __ptr_.second() = wistd::forward<_Ep>(__u.get_deleter()); - return *this; - } - -#else // __WI_LIBCPP_CXX03_LANG - private: - template explicit unique_ptr(_Up); - - unique_ptr(unique_ptr&); - template unique_ptr(unique_ptr<_Up>&); - - unique_ptr& operator=(unique_ptr&); - template unique_ptr& operator=(unique_ptr<_Up>&); - - template - unique_ptr(_Up __u, - typename conditional< - is_reference::value, deleter_type, - typename add_lvalue_reference::type>::type, - typename enable_if::value, - __nat>::type = __nat()); - public: - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr() : __ptr_(pointer()) { - static_assert(!is_pointer::value, - "unique_ptr constructed with null function pointer deleter"); - } - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(nullptr_t) : __ptr_(pointer()) { - static_assert(!is_pointer::value, - "unique_ptr constructed with null function pointer deleter"); - } - - __WI_LIBCPP_INLINE_VISIBILITY - explicit unique_ptr(pointer __p) : __ptr_(__p) { - static_assert(!is_pointer::value, - "unique_ptr constructed with null function pointer deleter"); - } - - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(pointer __p, deleter_type __d) - : __ptr_(__p, wistd::forward(__d)) {} - - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(nullptr_t, deleter_type __d) - : __ptr_(pointer(), wistd::forward(__d)) {} - - __WI_LIBCPP_INLINE_VISIBILITY - operator __rv() { - return __rv(*this); - } - - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr(__rv __u) - : __ptr_(__u->release(), - wistd::forward(__u->get_deleter())) {} - - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr& operator=(__rv __u) { - reset(__u->release()); - __ptr_.second() = wistd::forward(__u->get_deleter()); - return *this; - } - -#endif // __WI_LIBCPP_CXX03_LANG - - public: - __WI_LIBCPP_INLINE_VISIBILITY - ~unique_ptr() { reset(); } - - __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr& operator=(nullptr_t) WI_NOEXCEPT { - reset(); - return *this; - } - - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - typename add_lvalue_reference<_Tp>::type - operator[](size_t __i) const { - return __ptr_.first()[__i]; - } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - pointer get() const WI_NOEXCEPT { - return __ptr_.first(); - } - - __WI_LIBCPP_INLINE_VISIBILITY - deleter_type& get_deleter() WI_NOEXCEPT { - return __ptr_.second(); - } - - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - const deleter_type& get_deleter() const WI_NOEXCEPT { - return __ptr_.second(); - } - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - __WI_LIBCPP_EXPLICIT operator bool() const WI_NOEXCEPT { - return __ptr_.first() != nullptr; - } - - __WI_LIBCPP_INLINE_VISIBILITY - pointer release() WI_NOEXCEPT { - pointer __t = __ptr_.first(); - __ptr_.first() = pointer(); - return __t; - } - - template - __WI_LIBCPP_INLINE_VISIBILITY - typename enable_if< - _CheckArrayPointerConversion<_Pp>::value - >::type - reset(_Pp __p) WI_NOEXCEPT { - pointer __tmp = __ptr_.first(); - __ptr_.first() = __p; - if (__tmp) - __ptr_.second()(__tmp); - } - - __WI_LIBCPP_INLINE_VISIBILITY - void reset(nullptr_t = nullptr) WI_NOEXCEPT { - pointer __tmp = __ptr_.first(); - __ptr_.first() = nullptr; - if (__tmp) - __ptr_.second()(__tmp); - } - - __WI_LIBCPP_INLINE_VISIBILITY - void swap(unique_ptr& __u) WI_NOEXCEPT { - __ptr_.swap(__u.__ptr_); - } - - }; - - // Provide both 'swap_wil' and 'swap' since we now have two ADL scenarios that we need to work - template - inline __WI_LIBCPP_INLINE_VISIBILITY - typename enable_if< - __is_swappable<_Dp>::value, - void - >::type - swap(unique_ptr<_Tp, _Dp>& __x, unique_ptr<_Tp, _Dp>& __y) WI_NOEXCEPT {__x.swap(__y);} - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - typename enable_if< - __is_swappable<_Dp>::value, - void - >::type - swap_wil(unique_ptr<_Tp, _Dp>& __x, unique_ptr<_Tp, _Dp>& __y) WI_NOEXCEPT {__x.swap(__y);} - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator==(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return __x.get() == __y.get();} - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator!=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return !(__x == __y);} - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator< (const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) - { - typedef typename unique_ptr<_T1, _D1>::pointer _P1; - typedef typename unique_ptr<_T2, _D2>::pointer _P2; - typedef typename common_type<_P1, _P2>::type _Vp; - return less<_Vp>()(__x.get(), __y.get()); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator> (const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return __y < __x;} - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator<=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return !(__y < __x);} - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator>=(const unique_ptr<_T1, _D1>& __x, const unique_ptr<_T2, _D2>& __y) {return !(__x < __y);} - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator==(const unique_ptr<_T1, _D1>& __x, nullptr_t) WI_NOEXCEPT - { - return !__x; - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator==(nullptr_t, const unique_ptr<_T1, _D1>& __x) WI_NOEXCEPT - { - return !__x; - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator!=(const unique_ptr<_T1, _D1>& __x, nullptr_t) WI_NOEXCEPT - { - return static_cast(__x); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator!=(nullptr_t, const unique_ptr<_T1, _D1>& __x) WI_NOEXCEPT - { - return static_cast(__x); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator<(const unique_ptr<_T1, _D1>& __x, nullptr_t) - { - typedef typename unique_ptr<_T1, _D1>::pointer _P1; - return less<_P1>()(__x.get(), nullptr); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator<(nullptr_t, const unique_ptr<_T1, _D1>& __x) - { - typedef typename unique_ptr<_T1, _D1>::pointer _P1; - return less<_P1>()(nullptr, __x.get()); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator>(const unique_ptr<_T1, _D1>& __x, nullptr_t) - { - return nullptr < __x; - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator>(nullptr_t, const unique_ptr<_T1, _D1>& __x) - { - return __x < nullptr; - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator<=(const unique_ptr<_T1, _D1>& __x, nullptr_t) - { - return !(nullptr < __x); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator<=(nullptr_t, const unique_ptr<_T1, _D1>& __x) - { - return !(__x < nullptr); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator>=(const unique_ptr<_T1, _D1>& __x, nullptr_t) - { - return !(__x < nullptr); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - bool - operator>=(nullptr_t, const unique_ptr<_T1, _D1>& __x) - { - return !(nullptr < __x); - } - -#ifdef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - unique_ptr<_Tp, _Dp> - move(unique_ptr<_Tp, _Dp>& __t) - { - return unique_ptr<_Tp, _Dp>(__rv >(__t)); - } - -#endif -} -/// @endcond - -#endif // _WISTD_MEMORY_H_ diff --git a/src/common/dep/wil/wistd_type_traits.h b/src/common/dep/wil/wistd_type_traits.h deleted file mode 100644 index ab81fbdfe..000000000 --- a/src/common/dep/wil/wistd_type_traits.h +++ /dev/null @@ -1,4504 +0,0 @@ -// -*- C++ -*- -//===------------------------ type_traits ---------------------------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is dual licensed under the MIT and the University of Illinois Open -// Source Licenses. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -// STL common functionality -// -// Some aspects of STL are core language concepts that should be used from all C++ code, regardless -// of whether exceptions are enabled in the component. Common library code that expects to be used -// from exception-free components want these concepts, but including directly introduces -// friction as it requires components not using STL to declare their STL version. Doing so creates -// ambiguity around whether STL use is safe in a particular component and implicitly brings in -// a long list of headers (including ) which can create further ambiguity around throwing new -// support (some routines pulled in may expect it). Secondarily, pulling in these headers also has -// the potential to create naming conflicts or other implied dependencies. -// -// To promote the use of these core language concepts outside of STL-based binaries, this file is -// selectively pulling those concepts *directly* from corresponding STL headers. The corresponding -// "std::" namespace STL functions and types should be preferred over these in code that is bound to -// STL. The implementation and naming of all functions are taken directly from STL, instead using -// "wistd" (Windows Implementation std) as the namespace. -// -// Routines in this namespace should always be considered a reflection of the *current* STL implementation -// of those routines. Updates from STL should be taken, but no "bugs" should be fixed here. -// -// New, exception-based code should not use this namespace, but instead should prefer the std:: implementation. -// Only code that is not exception-based and libraries that expect to be utilized across both exception -// and non-exception based code should utilize this functionality. - -#ifndef _WISTD_TYPE_TRAITS_H_ -#define _WISTD_TYPE_TRAITS_H_ - -// DO NOT add *any* additional includes to this file -- there should be no dependencies from its usage -#include "wistd_config.h" - -#if !defined(__WI_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -#pragma GCC system_header -#endif - -/// @cond -namespace wistd // ("Windows Implementation" std) -{ - template struct __WI_LIBCPP_TEMPLATE_VIS pair; - template class __WI_LIBCPP_TEMPLATE_VIS reference_wrapper; - template struct __WI_LIBCPP_TEMPLATE_VIS hash; - - template - struct __void_t { typedef void type; }; - - template - struct __identity { typedef _Tp type; }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS __dependent_type : public _Tp {}; - - template - struct __WI_LIBCPP_TEMPLATE_VIS conditional {typedef _If type;}; - template - struct __WI_LIBCPP_TEMPLATE_VIS conditional {typedef _Then type;}; - -#if __WI_LIBCPP_STD_VER > 11 - template using conditional_t = typename conditional<_Bp, _If, _Then>::type; -#endif - - template struct __WI_LIBCPP_TEMPLATE_VIS __lazy_enable_if {}; - template struct __WI_LIBCPP_TEMPLATE_VIS __lazy_enable_if {typedef typename _Tp::type type;}; - - template struct __WI_LIBCPP_TEMPLATE_VIS enable_if {}; - template struct __WI_LIBCPP_TEMPLATE_VIS enable_if {typedef _Tp type;}; - -#if __WI_LIBCPP_STD_VER > 11 - template using enable_if_t = typename enable_if<_Bp, _Tp>::type; -#endif - - // addressof -#ifndef __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF - - template - inline __WI_LIBCPP_CONSTEXPR_AFTER_CXX14 - __WI_LIBCPP_NO_CFI __WI_LIBCPP_INLINE_VISIBILITY - _Tp* - addressof(_Tp& __x) WI_NOEXCEPT - { - return __builtin_addressof(__x); - } - -#else - - template - inline __WI_LIBCPP_NO_CFI __WI_LIBCPP_INLINE_VISIBILITY - _Tp* - addressof(_Tp& __x) WI_NOEXCEPT - { - return reinterpret_cast<_Tp *>( - const_cast(&reinterpret_cast(__x))); - } - -#endif // __WI_LIBCPP_HAS_NO_BUILTIN_ADDRESSOF - -#if !defined(__WI_LIBCPP_CXX03_LANG) - template _Tp* addressof(const _Tp&&) WI_NOEXCEPT = delete; -#endif - - struct __two {char __lx[2];}; - - // helper class: - - template - struct __WI_LIBCPP_TEMPLATE_VIS integral_constant - { - static __WI_LIBCPP_CONSTEXPR const _Tp value = __v; - typedef _Tp value_type; - typedef integral_constant type; - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - __WI_LIBCPP_CONSTEXPR operator value_type() const WI_NOEXCEPT {return value;} -#if __WI_LIBCPP_STD_VER > 11 - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_INLINE_VISIBILITY - constexpr value_type operator ()() const WI_NOEXCEPT {return value;} -#endif - }; - - template - __WI_LIBCPP_CONSTEXPR const _Tp integral_constant<_Tp, __v>::value; - -#if !defined(__WI_LIBCPP_CXX03_LANG) - template - using bool_constant = integral_constant; -#define __WI_LIBCPP_BOOL_CONSTANT(__b) bool_constant<(__b)> -#else -#define __WI_LIBCPP_BOOL_CONSTANT(__b) integral_constant -#endif - - typedef __WI_LIBCPP_BOOL_CONSTANT(true) true_type; - typedef __WI_LIBCPP_BOOL_CONSTANT(false) false_type; - -#if !defined(__WI_LIBCPP_CXX03_LANG) - - // __lazy_and - - template - struct __lazy_and_impl; - - template - struct __lazy_and_impl : false_type {}; - - template <> - struct __lazy_and_impl : true_type {}; - - template - struct __lazy_and_impl : integral_constant {}; - - template - struct __lazy_and_impl : __lazy_and_impl<_Hp::type::value, _Tp...> {}; - - template - struct __lazy_and : __lazy_and_impl<_P1::type::value, _Pr...> {}; - - // __lazy_or - - template - struct __lazy_or_impl; - - template - struct __lazy_or_impl : true_type {}; - - template <> - struct __lazy_or_impl : false_type {}; - - template - struct __lazy_or_impl - : __lazy_or_impl<_Hp::type::value, _Tp...> {}; - - template - struct __lazy_or : __lazy_or_impl<_P1::type::value, _Pr...> {}; - - // __lazy_not - - template - struct __lazy_not : integral_constant {}; - - // __and_ - template struct __and_; - template<> struct __and_<> : true_type {}; - - template struct __and_<_B0> : _B0 {}; - - template - struct __and_<_B0, _B1> : conditional<_B0::value, _B1, _B0>::type {}; - - template - struct __and_<_B0, _B1, _B2, _Bn...> - : conditional<_B0::value, __and_<_B1, _B2, _Bn...>, _B0>::type {}; - - // __or_ - template struct __or_; - template<> struct __or_<> : false_type {}; - - template struct __or_<_B0> : _B0 {}; - - template - struct __or_<_B0, _B1> : conditional<_B0::value, _B0, _B1>::type {}; - - template - struct __or_<_B0, _B1, _B2, _Bn...> - : conditional<_B0::value, _B0, __or_<_B1, _B2, _Bn...> >::type {}; - - // __not_ - template - struct __not_ : conditional<_Tp::value, false_type, true_type>::type {}; - -#endif // !defined(__WI_LIBCPP_CXX03_LANG) - - // is_const - - template struct __WI_LIBCPP_TEMPLATE_VIS is_const : public false_type {}; - template struct __WI_LIBCPP_TEMPLATE_VIS is_const<_Tp const> : public true_type {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_const_v - = is_const<_Tp>::value; -#endif - - // is_volatile - - template struct __WI_LIBCPP_TEMPLATE_VIS is_volatile : public false_type {}; - template struct __WI_LIBCPP_TEMPLATE_VIS is_volatile<_Tp volatile> : public true_type {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_volatile_v - = is_volatile<_Tp>::value; -#endif - - // remove_const - - template struct __WI_LIBCPP_TEMPLATE_VIS remove_const {typedef _Tp type;}; - template struct __WI_LIBCPP_TEMPLATE_VIS remove_const {typedef _Tp type;}; -#if __WI_LIBCPP_STD_VER > 11 - template using remove_const_t = typename remove_const<_Tp>::type; -#endif - - // remove_volatile - - template struct __WI_LIBCPP_TEMPLATE_VIS remove_volatile {typedef _Tp type;}; - template struct __WI_LIBCPP_TEMPLATE_VIS remove_volatile {typedef _Tp type;}; -#if __WI_LIBCPP_STD_VER > 11 - template using remove_volatile_t = typename remove_volatile<_Tp>::type; -#endif - - // remove_cv - - template struct __WI_LIBCPP_TEMPLATE_VIS remove_cv - {typedef typename remove_volatile::type>::type type;}; -#if __WI_LIBCPP_STD_VER > 11 - template using remove_cv_t = typename remove_cv<_Tp>::type; -#endif - - // is_void - - template struct __libcpp_is_void : public false_type {}; - template <> struct __libcpp_is_void : public true_type {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_void - : public __libcpp_is_void::type> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_void_v - = is_void<_Tp>::value; -#endif - - // __is_nullptr_t - - template struct __is_nullptr_t_impl : public false_type {}; - template <> struct __is_nullptr_t_impl : public true_type {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS __is_nullptr_t - : public __is_nullptr_t_impl::type> {}; - -#if __WI_LIBCPP_STD_VER > 11 - template struct __WI_LIBCPP_TEMPLATE_VIS is_null_pointer - : public __is_nullptr_t_impl::type> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_null_pointer_v - = is_null_pointer<_Tp>::value; -#endif -#endif - - // is_integral - - template struct __libcpp_is_integral : public false_type {}; - template <> struct __libcpp_is_integral : public true_type {}; - template <> struct __libcpp_is_integral : public true_type {}; - template <> struct __libcpp_is_integral : public true_type {}; - template <> struct __libcpp_is_integral : public true_type {}; -#ifdef _MSC_VER - template <> struct __libcpp_is_integral<__wchar_t> : public true_type {}; -#else - template <> struct __libcpp_is_integral : public true_type {}; -#endif -#ifndef __WI_LIBCPP_HAS_NO_UNICODE_CHARS - template <> struct __libcpp_is_integral : public true_type {}; - template <> struct __libcpp_is_integral : public true_type {}; -#endif // __WI_LIBCPP_HAS_NO_UNICODE_CHARS - template <> struct __libcpp_is_integral : public true_type {}; - template <> struct __libcpp_is_integral : public true_type {}; - template <> struct __libcpp_is_integral : public true_type {}; - template <> struct __libcpp_is_integral : public true_type {}; - template <> struct __libcpp_is_integral : public true_type {}; - template <> struct __libcpp_is_integral : public true_type {}; - template <> struct __libcpp_is_integral : public true_type {}; - template <> struct __libcpp_is_integral : public true_type {}; -#ifndef __WI_LIBCPP_HAS_NO_INT128 - template <> struct __libcpp_is_integral<__int128_t> : public true_type {}; - template <> struct __libcpp_is_integral<__uint128_t> : public true_type {}; -#endif - - template struct __WI_LIBCPP_TEMPLATE_VIS is_integral - : public __libcpp_is_integral::type> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_integral_v - = is_integral<_Tp>::value; -#endif - - // is_floating_point - - template struct __libcpp_is_floating_point : public false_type {}; - template <> struct __libcpp_is_floating_point : public true_type {}; - template <> struct __libcpp_is_floating_point : public true_type {}; - template <> struct __libcpp_is_floating_point : public true_type {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_floating_point - : public __libcpp_is_floating_point::type> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_floating_point_v - = is_floating_point<_Tp>::value; -#endif - - // is_array - - template struct __WI_LIBCPP_TEMPLATE_VIS is_array - : public false_type {}; - template struct __WI_LIBCPP_TEMPLATE_VIS is_array<_Tp[]> - : public true_type {}; - template struct __WI_LIBCPP_TEMPLATE_VIS is_array<_Tp[_Np]> - : public true_type {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_array_v - = is_array<_Tp>::value; -#endif - - // is_pointer - - template struct __libcpp_is_pointer : public false_type {}; - template struct __libcpp_is_pointer<_Tp*> : public true_type {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_pointer - : public __libcpp_is_pointer::type> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_pointer_v - = is_pointer<_Tp>::value; -#endif - - // is_reference - - template struct __WI_LIBCPP_TEMPLATE_VIS is_lvalue_reference : public false_type {}; - template struct __WI_LIBCPP_TEMPLATE_VIS is_lvalue_reference<_Tp&> : public true_type {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_rvalue_reference : public false_type {}; -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - template struct __WI_LIBCPP_TEMPLATE_VIS is_rvalue_reference<_Tp&&> : public true_type {}; -#endif - - template struct __WI_LIBCPP_TEMPLATE_VIS is_reference : public false_type {}; - template struct __WI_LIBCPP_TEMPLATE_VIS is_reference<_Tp&> : public true_type {}; -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - template struct __WI_LIBCPP_TEMPLATE_VIS is_reference<_Tp&&> : public true_type {}; -#endif - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_reference_v - = is_reference<_Tp>::value; - - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_lvalue_reference_v - = is_lvalue_reference<_Tp>::value; - - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_rvalue_reference_v - = is_rvalue_reference<_Tp>::value; -#endif - // is_union - -#if __WI_HAS_FEATURE_IS_UNION || (__WI_GNUC_VER >= 403) - - template struct __WI_LIBCPP_TEMPLATE_VIS is_union - : public integral_constant {}; - -#else - - template struct __libcpp_union : public false_type {}; - template struct __WI_LIBCPP_TEMPLATE_VIS is_union - : public __libcpp_union::type> {}; - -#endif - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_union_v - = is_union<_Tp>::value; -#endif - - // is_class - -#if __WI_HAS_FEATURE_IS_CLASS || (__WI_GNUC_VER >= 403) - - template struct __WI_LIBCPP_TEMPLATE_VIS is_class - : public integral_constant {}; - -#else - - namespace __is_class_imp - { - template char __test(int _Tp::*); - template __two __test(...); - } - - template struct __WI_LIBCPP_TEMPLATE_VIS is_class - : public integral_constant(0)) == 1 && !is_union<_Tp>::value> {}; - -#endif - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_class_v - = is_class<_Tp>::value; -#endif - - // is_same - - template struct __WI_LIBCPP_TEMPLATE_VIS is_same : public false_type {}; - template struct __WI_LIBCPP_TEMPLATE_VIS is_same<_Tp, _Tp> : public true_type {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_same_v - = is_same<_Tp, _Up>::value; -#endif - - // is_function - - namespace __libcpp_is_function_imp - { - struct __dummy_type {}; - template char __test(_Tp*); - template char __test(__dummy_type); - template __two __test(...); - template _Tp& __source(int); - template __dummy_type __source(...); - } - - template ::value || - is_union<_Tp>::value || - is_void<_Tp>::value || - is_reference<_Tp>::value || - __is_nullptr_t<_Tp>::value > - struct __libcpp_is_function - : public integral_constant(__libcpp_is_function_imp::__source<_Tp>(0))) == 1> - {}; - template struct __libcpp_is_function<_Tp, true> : public false_type {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_function - : public __libcpp_is_function<_Tp> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_function_v - = is_function<_Tp>::value; -#endif - - // is_member_function_pointer - - // template struct __libcpp_is_member_function_pointer : public false_type {}; - // template struct __libcpp_is_member_function_pointer<_Tp _Up::*> : public is_function<_Tp> {}; - // - - template - struct __member_pointer_traits_imp - { // forward declaration; specializations later - }; - - - template struct __libcpp_is_member_function_pointer - : public false_type {}; - - template - struct __libcpp_is_member_function_pointer<_Ret _Class::*> - : public is_function<_Ret> {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_member_function_pointer - : public __libcpp_is_member_function_pointer::type>::type {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_member_function_pointer_v - = is_member_function_pointer<_Tp>::value; -#endif - - // is_member_pointer - - template struct __libcpp_is_member_pointer : public false_type {}; - template struct __libcpp_is_member_pointer<_Tp _Up::*> : public true_type {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_member_pointer - : public __libcpp_is_member_pointer::type> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_member_pointer_v - = is_member_pointer<_Tp>::value; -#endif - - // is_member_object_pointer - - template struct __WI_LIBCPP_TEMPLATE_VIS is_member_object_pointer - : public integral_constant::value && - !is_member_function_pointer<_Tp>::value> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_member_object_pointer_v - = is_member_object_pointer<_Tp>::value; -#endif - - // is_enum - -#if __WI_HAS_FEATURE_IS_ENUM || (__WI_GNUC_VER >= 403) - - template struct __WI_LIBCPP_TEMPLATE_VIS is_enum - : public integral_constant {}; - -#else - - template struct __WI_LIBCPP_TEMPLATE_VIS is_enum - : public integral_constant::value && - !is_integral<_Tp>::value && - !is_floating_point<_Tp>::value && - !is_array<_Tp>::value && - !is_pointer<_Tp>::value && - !is_reference<_Tp>::value && - !is_member_pointer<_Tp>::value && - !is_union<_Tp>::value && - !is_class<_Tp>::value && - !is_function<_Tp>::value > {}; - -#endif - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_enum_v - = is_enum<_Tp>::value; -#endif - - // is_arithmetic - - template struct __WI_LIBCPP_TEMPLATE_VIS is_arithmetic - : public integral_constant::value || - is_floating_point<_Tp>::value> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_arithmetic_v - = is_arithmetic<_Tp>::value; -#endif - - // is_fundamental - - template struct __WI_LIBCPP_TEMPLATE_VIS is_fundamental - : public integral_constant::value || - __is_nullptr_t<_Tp>::value || - is_arithmetic<_Tp>::value> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_fundamental_v - = is_fundamental<_Tp>::value; -#endif - - // is_scalar - - template struct __WI_LIBCPP_TEMPLATE_VIS is_scalar - : public integral_constant::value || - is_member_pointer<_Tp>::value || - is_pointer<_Tp>::value || - __is_nullptr_t<_Tp>::value || - is_enum<_Tp>::value > {}; - - template <> struct __WI_LIBCPP_TEMPLATE_VIS is_scalar : public true_type {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_scalar_v - = is_scalar<_Tp>::value; -#endif - - // is_object - - template struct __WI_LIBCPP_TEMPLATE_VIS is_object - : public integral_constant::value || - is_array<_Tp>::value || - is_union<_Tp>::value || - is_class<_Tp>::value > {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_object_v - = is_object<_Tp>::value; -#endif - - // is_compound - - template struct __WI_LIBCPP_TEMPLATE_VIS is_compound - : public integral_constant::value> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_compound_v - = is_compound<_Tp>::value; -#endif - - - // __is_referenceable [defns.referenceable] - - struct __is_referenceable_impl { - template static _Tp& __test(int); - template static __two __test(...); - }; - - template - struct __is_referenceable : integral_constant(0)), __two>::value> {}; - - - // add_const - - template ::value || - is_function<_Tp>::value || - is_const<_Tp>::value > - struct __add_const {typedef _Tp type;}; - - template - struct __add_const<_Tp, false> {typedef const _Tp type;}; - - template struct __WI_LIBCPP_TEMPLATE_VIS add_const - {typedef typename __add_const<_Tp>::type type;}; - -#if __WI_LIBCPP_STD_VER > 11 - template using add_const_t = typename add_const<_Tp>::type; -#endif - - // add_volatile - - template ::value || - is_function<_Tp>::value || - is_volatile<_Tp>::value > - struct __add_volatile {typedef _Tp type;}; - - template - struct __add_volatile<_Tp, false> {typedef volatile _Tp type;}; - - template struct __WI_LIBCPP_TEMPLATE_VIS add_volatile - {typedef typename __add_volatile<_Tp>::type type;}; - -#if __WI_LIBCPP_STD_VER > 11 - template using add_volatile_t = typename add_volatile<_Tp>::type; -#endif - - // add_cv - - template struct __WI_LIBCPP_TEMPLATE_VIS add_cv - {typedef typename add_const::type>::type type;}; - -#if __WI_LIBCPP_STD_VER > 11 - template using add_cv_t = typename add_cv<_Tp>::type; -#endif - - // remove_reference - - template struct __WI_LIBCPP_TEMPLATE_VIS remove_reference {typedef _Tp type;}; - template struct __WI_LIBCPP_TEMPLATE_VIS remove_reference<_Tp&> {typedef _Tp type;}; -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - template struct __WI_LIBCPP_TEMPLATE_VIS remove_reference<_Tp&&> {typedef _Tp type;}; -#endif - -#if __WI_LIBCPP_STD_VER > 11 - template using remove_reference_t = typename remove_reference<_Tp>::type; -#endif - - // add_lvalue_reference - - template ::value> struct __add_lvalue_reference_impl { typedef _Tp type; }; - template struct __add_lvalue_reference_impl<_Tp, true> { typedef _Tp& type; }; - - template struct __WI_LIBCPP_TEMPLATE_VIS add_lvalue_reference - {typedef typename __add_lvalue_reference_impl<_Tp>::type type;}; - -#if __WI_LIBCPP_STD_VER > 11 - template using add_lvalue_reference_t = typename add_lvalue_reference<_Tp>::type; -#endif - -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - - template ::value> struct __add_rvalue_reference_impl { typedef _Tp type; }; - template struct __add_rvalue_reference_impl<_Tp, true> { typedef _Tp&& type; }; - - template struct __WI_LIBCPP_TEMPLATE_VIS add_rvalue_reference - {typedef typename __add_rvalue_reference_impl<_Tp>::type type;}; - -#if __WI_LIBCPP_STD_VER > 11 - template using add_rvalue_reference_t = typename add_rvalue_reference<_Tp>::type; -#endif - -#endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - - // MSVC has issues compiling some source code that uses the libc++ definition of 'declval' -#ifdef _MSC_VER - template - typename add_rvalue_reference<_Tp>::type declval() WI_NOEXCEPT; -#else - template _Tp&& __declval(int); - template _Tp __declval(long); - - template - decltype(__declval<_Tp>(0)) - declval() WI_NOEXCEPT; -#endif - -#else // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - - template - typename add_lvalue_reference<_Tp>::type - declval(); - -#endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - - // __uncvref - - template - struct __uncvref { - typedef typename remove_cv::type>::type type; - }; - - template - struct __unconstref { - typedef typename remove_const::type>::type type; - }; - -#ifndef __WI_LIBCPP_CXX03_LANG - template - using __uncvref_t = typename __uncvref<_Tp>::type; -#endif - - // __is_same_uncvref - - template - struct __is_same_uncvref : is_same::type, - typename __uncvref<_Up>::type> {}; - -#if __WI_LIBCPP_STD_VER > 17 - // remove_cvref - same as __uncvref - template - struct remove_cvref : public __uncvref<_Tp> {}; - - template using remove_cvref_t = typename remove_cvref<_Tp>::type; -#endif - - - struct __any - { - __any(...); - }; - - // remove_pointer - - template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer {typedef _Tp type;}; - template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp*> {typedef _Tp type;}; - template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp* const> {typedef _Tp type;}; - template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp* volatile> {typedef _Tp type;}; - template struct __WI_LIBCPP_TEMPLATE_VIS remove_pointer<_Tp* const volatile> {typedef _Tp type;}; - -#if __WI_LIBCPP_STD_VER > 11 - template using remove_pointer_t = typename remove_pointer<_Tp>::type; -#endif - - // add_pointer - - template ::value || - is_same::type, void>::value> - struct __add_pointer_impl - {typedef typename remove_reference<_Tp>::type* type;}; - template struct __add_pointer_impl<_Tp, false> - {typedef _Tp type;}; - - template struct __WI_LIBCPP_TEMPLATE_VIS add_pointer - {typedef typename __add_pointer_impl<_Tp>::type type;}; - -#if __WI_LIBCPP_STD_VER > 11 - template using add_pointer_t = typename add_pointer<_Tp>::type; -#endif - - // type_identity -#if __WI_LIBCPP_STD_VER > 17 - template struct type_identity { typedef _Tp type; }; - template using type_identity_t = typename type_identity<_Tp>::type; -#endif - - // is_signed - - template ::value> - struct __libcpp_is_signed_impl : public __WI_LIBCPP_BOOL_CONSTANT(_Tp(-1) < _Tp(0)) {}; - - template - struct __libcpp_is_signed_impl<_Tp, false> : public true_type {}; // floating point - - template ::value> - struct __libcpp_is_signed : public __libcpp_is_signed_impl<_Tp> {}; - - template struct __libcpp_is_signed<_Tp, false> : public false_type {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_signed : public __libcpp_is_signed<_Tp> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_signed_v - = is_signed<_Tp>::value; -#endif - - // is_unsigned - - template ::value> - struct __libcpp_is_unsigned_impl : public __WI_LIBCPP_BOOL_CONSTANT(_Tp(0) < _Tp(-1)) {}; - - template - struct __libcpp_is_unsigned_impl<_Tp, false> : public false_type {}; // floating point - - template ::value> - struct __libcpp_is_unsigned : public __libcpp_is_unsigned_impl<_Tp> {}; - - template struct __libcpp_is_unsigned<_Tp, false> : public false_type {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_unsigned : public __libcpp_is_unsigned<_Tp> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_unsigned_v - = is_unsigned<_Tp>::value; -#endif - - // rank - - template struct __WI_LIBCPP_TEMPLATE_VIS rank - : public integral_constant {}; - template struct __WI_LIBCPP_TEMPLATE_VIS rank<_Tp[]> - : public integral_constant::value + 1> {}; - template struct __WI_LIBCPP_TEMPLATE_VIS rank<_Tp[_Np]> - : public integral_constant::value + 1> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR size_t rank_v - = rank<_Tp>::value; -#endif - - // extent - - template struct __WI_LIBCPP_TEMPLATE_VIS extent - : public integral_constant {}; - template struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[], 0> - : public integral_constant {}; - template struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[], _Ip> - : public integral_constant::value> {}; - template struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[_Np], 0> - : public integral_constant {}; - template struct __WI_LIBCPP_TEMPLATE_VIS extent<_Tp[_Np], _Ip> - : public integral_constant::value> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR size_t extent_v - = extent<_Tp, _Ip>::value; -#endif - - // remove_extent - - template struct __WI_LIBCPP_TEMPLATE_VIS remove_extent - {typedef _Tp type;}; - template struct __WI_LIBCPP_TEMPLATE_VIS remove_extent<_Tp[]> - {typedef _Tp type;}; - template struct __WI_LIBCPP_TEMPLATE_VIS remove_extent<_Tp[_Np]> - {typedef _Tp type;}; - -#if __WI_LIBCPP_STD_VER > 11 - template using remove_extent_t = typename remove_extent<_Tp>::type; -#endif - - // remove_all_extents - - template struct __WI_LIBCPP_TEMPLATE_VIS remove_all_extents - {typedef _Tp type;}; - template struct __WI_LIBCPP_TEMPLATE_VIS remove_all_extents<_Tp[]> - {typedef typename remove_all_extents<_Tp>::type type;}; - template struct __WI_LIBCPP_TEMPLATE_VIS remove_all_extents<_Tp[_Np]> - {typedef typename remove_all_extents<_Tp>::type type;}; - -#if __WI_LIBCPP_STD_VER > 11 - template using remove_all_extents_t = typename remove_all_extents<_Tp>::type; -#endif - - // decay - - template - struct __decay { - typedef typename remove_cv<_Up>::type type; - }; - - template - struct __decay<_Up, true> { - public: - typedef typename conditional - < - is_array<_Up>::value, - typename remove_extent<_Up>::type*, - typename conditional - < - is_function<_Up>::value, - typename add_pointer<_Up>::type, - typename remove_cv<_Up>::type - >::type - >::type type; - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS decay - { - private: - typedef typename remove_reference<_Tp>::type _Up; - public: - typedef typename __decay<_Up, __is_referenceable<_Up>::value>::type type; - }; - -#if __WI_LIBCPP_STD_VER > 11 - template using decay_t = typename decay<_Tp>::type; -#endif - - // is_abstract - - template struct __WI_LIBCPP_TEMPLATE_VIS is_abstract - : public integral_constant {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_abstract_v - = is_abstract<_Tp>::value; -#endif - - // is_final - -#if defined(__WI_LIBCPP_HAS_IS_FINAL) - template struct __WI_LIBCPP_TEMPLATE_VIS - __libcpp_is_final : public integral_constant {}; -#else - template struct __WI_LIBCPP_TEMPLATE_VIS - __libcpp_is_final : public false_type {}; -#endif - -#if defined(__WI_LIBCPP_HAS_IS_FINAL) && __WI_LIBCPP_STD_VER > 11 - template struct __WI_LIBCPP_TEMPLATE_VIS - is_final : public integral_constant {}; -#endif - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_final_v - = is_final<_Tp>::value; -#endif - - // is_aggregate -#if __WI_LIBCPP_STD_VER > 14 && !defined(__WI_LIBCPP_HAS_NO_IS_AGGREGATE) - - template struct __WI_LIBCPP_TEMPLATE_VIS - is_aggregate : public integral_constant {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR constexpr bool is_aggregate_v - = is_aggregate<_Tp>::value; -#endif - -#endif // __WI_LIBCPP_STD_VER > 14 && !defined(__WI_LIBCPP_HAS_NO_IS_AGGREGATE) - - // is_base_of - -#ifdef __WI_LIBCPP_HAS_IS_BASE_OF - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_base_of - : public integral_constant {}; - -#else // __WI_LIBCPP_HAS_IS_BASE_OF - - namespace __is_base_of_imp - { - template - struct _Dst - { - _Dst(const volatile _Tp &); - }; - template - struct _Src - { - operator const volatile _Tp &(); - template operator const _Dst<_Up> &(); - }; - template struct __one { typedef char type; }; - template typename __one(declval<_Src<_Dp> >()))>::type __test(int); - template __two __test(...); - } - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_base_of - : public integral_constant::value && - sizeof(__is_base_of_imp::__test<_Bp, _Dp>(0)) == 2> {}; - -#endif // __WI_LIBCPP_HAS_IS_BASE_OF - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_base_of_v - = is_base_of<_Bp, _Dp>::value; -#endif - - // is_convertible - -#if __WI_HAS_FEATURE_IS_CONVERTIBLE_TO && !defined(__WI_LIBCPP_USE_IS_CONVERTIBLE_FALLBACK) - - template struct __WI_LIBCPP_TEMPLATE_VIS is_convertible - : public integral_constant::value> {}; - -#else // __WI_HAS_FEATURE_IS_CONVERTIBLE_TO - - namespace __is_convertible_imp - { - template void __test_convert(_Tp); - - template - struct __is_convertible_test : public false_type {}; - - template - struct __is_convertible_test<_From, _To, - decltype(__is_convertible_imp::__test_convert<_To>(declval<_From>()))> : public true_type - {}; - - template ::value, - bool _IsFunction = is_function<_Tp>::value, - bool _IsVoid = is_void<_Tp>::value> - struct __is_array_function_or_void {enum {value = 0};}; - template struct __is_array_function_or_void<_Tp, true, false, false> {enum {value = 1};}; - template struct __is_array_function_or_void<_Tp, false, true, false> {enum {value = 2};}; - template struct __is_array_function_or_void<_Tp, false, false, true> {enum {value = 3};}; - } - - template ::type>::value> - struct __is_convertible_check - { - static const size_t __v = 0; - }; - - template - struct __is_convertible_check<_Tp, 0> - { - static const size_t __v = sizeof(_Tp); - }; - - template ::value, - unsigned _T2_is_array_function_or_void = __is_convertible_imp::__is_array_function_or_void<_T2>::value> - struct __is_convertible - : public integral_constant::value -#if defined(__WI_LIBCPP_HAS_NO_RVALUE_REFERENCES) - && !(!is_function<_T1>::value && !is_reference<_T1>::value && is_reference<_T2>::value - && (!is_const::type>::value - || is_volatile::type>::value) - && (is_same::type, - typename remove_cv::type>::type>::value - || is_base_of::type, _T1>::value)) -#endif - > - {}; - - template struct __is_convertible<_T1, _T2, 0, 1> : public false_type {}; - template struct __is_convertible<_T1, _T2, 1, 1> : public false_type {}; - template struct __is_convertible<_T1, _T2, 2, 1> : public false_type {}; - template struct __is_convertible<_T1, _T2, 3, 1> : public false_type {}; - - template struct __is_convertible<_T1, _T2, 0, 2> : public false_type {}; - template struct __is_convertible<_T1, _T2, 1, 2> : public false_type {}; - template struct __is_convertible<_T1, _T2, 2, 2> : public false_type {}; - template struct __is_convertible<_T1, _T2, 3, 2> : public false_type {}; - - template struct __is_convertible<_T1, _T2, 0, 3> : public false_type {}; - template struct __is_convertible<_T1, _T2, 1, 3> : public false_type {}; - template struct __is_convertible<_T1, _T2, 2, 3> : public false_type {}; - template struct __is_convertible<_T1, _T2, 3, 3> : public true_type {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_convertible - : public __is_convertible<_T1, _T2> - { - static const size_t __complete_check1 = __is_convertible_check<_T1>::__v; - static const size_t __complete_check2 = __is_convertible_check<_T2>::__v; - }; - -#endif // __WI_HAS_FEATURE_IS_CONVERTIBLE_TO - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_convertible_v - = is_convertible<_From, _To>::value; -#endif - - // is_empty - -#if __WI_HAS_FEATURE_IS_EMPTY || (__WI_GNUC_VER >= 407) - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_empty - : public integral_constant {}; - -#else // __WI_HAS_FEATURE_IS_EMPTY - - template - struct __is_empty1 - : public _Tp - { - double __lx; - }; - - struct __is_empty2 - { - double __lx; - }; - - template ::value> - struct __libcpp_empty : public integral_constant) == sizeof(__is_empty2)> {}; - - template struct __libcpp_empty<_Tp, false> : public false_type {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_empty : public __libcpp_empty<_Tp> {}; - -#endif // __WI_HAS_FEATURE_IS_EMPTY - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_empty_v - = is_empty<_Tp>::value; -#endif - - // is_polymorphic - -#if __WI_HAS_FEATURE_IS_POLYMORPHIC - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_polymorphic - : public integral_constant {}; - -#else - - template char &__is_polymorphic_impl( - typename enable_if(declval<_Tp*>())) != 0, - int>::type); - template __two &__is_polymorphic_impl(...); - - template struct __WI_LIBCPP_TEMPLATE_VIS is_polymorphic - : public integral_constant(0)) == 1> {}; - -#endif // __WI_HAS_FEATURE_IS_POLYMORPHIC - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_polymorphic_v - = is_polymorphic<_Tp>::value; -#endif - - // has_virtual_destructor - -#if __WI_HAS_FEATURE_HAS_VIRTUAL_DESTRUCTOR || (__WI_GNUC_VER >= 403) - - template struct __WI_LIBCPP_TEMPLATE_VIS has_virtual_destructor - : public integral_constant {}; - -#else - - template struct __WI_LIBCPP_TEMPLATE_VIS has_virtual_destructor - : public false_type {}; - -#endif - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool has_virtual_destructor_v - = has_virtual_destructor<_Tp>::value; -#endif - - // has_unique_object_representations - -#if __WI_LIBCPP_STD_VER > 14 && defined(__WI_LIBCPP_HAS_UNIQUE_OBJECT_REPRESENTATIONS) - - template struct __WI_LIBCPP_TEMPLATE_VIS has_unique_object_representations - : public integral_constant>)> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool has_unique_object_representations_v - = has_unique_object_representations<_Tp>::value; -#endif - -#endif - - // alignment_of - - template struct __WI_LIBCPP_TEMPLATE_VIS alignment_of - : public integral_constant {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR size_t alignment_of_v - = alignment_of<_Tp>::value; -#endif - - // aligned_storage - - template - struct __type_list - { - typedef _Hp _Head; - typedef _Tp _Tail; - }; - - struct __nat - { -#ifndef __WI_LIBCPP_CXX03_LANG - __nat() = delete; - __nat(const __nat&) = delete; - __nat& operator=(const __nat&) = delete; - ~__nat() = delete; -#endif - }; - - template - struct __align_type - { - static const size_t value = alignment_of<_Tp>::value; - typedef _Tp type; - }; - - struct __struct_double {long double __lx;}; - struct __struct_double4 {double __lx[4];}; - - typedef - __type_list<__align_type, - __type_list<__align_type, - __type_list<__align_type, - __type_list<__align_type, - __type_list<__align_type, - __type_list<__align_type, - __type_list<__align_type, - __type_list<__align_type<__struct_double>, - __type_list<__align_type<__struct_double4>, - __type_list<__align_type, - __nat - > > > > > > > > > > __all_types; - - template struct __find_pod; - - template - struct __find_pod<__type_list<_Hp, __nat>, _Align> - { - typedef typename conditional< - _Align == _Hp::value, - typename _Hp::type, - void - >::type type; - }; - - template - struct __find_pod<__type_list<_Hp, _Tp>, _Align> - { - typedef typename conditional< - _Align == _Hp::value, - typename _Hp::type, - typename __find_pod<_Tp, _Align>::type - >::type type; - }; - - template - struct __has_pod_with_align : public integral_constant::type, void>::value> {}; - - template struct __find_max_align; - - template - struct __find_max_align<__type_list<_Hp, __nat>, _Len> : public integral_constant {}; - - template - struct __select_align - { - private: - static const size_t __min = _A2 < _A1 ? _A2 : _A1; - static const size_t __max = _A1 < _A2 ? _A2 : _A1; - public: - static const size_t value = _Len < __max ? __min : __max; - }; - - template - struct __find_max_align<__type_list<_Hp, _Tp>, _Len> - : public integral_constant::value>::value> {}; - - template ::value> - struct __aligned_storage - { - typedef typename __find_pod<__all_types, _Align>::type _Aligner; - static_assert(!is_void<_Aligner>::value, ""); - union type - { - _Aligner __align; - unsigned char __data[(_Len + _Align - 1)/_Align * _Align]; - }; - }; - -#define __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(n) \ - template \ - struct __aligned_storage<_Len, n, false>\ - {\ - struct __WI_ALIGNAS(n) type\ - {\ - unsigned char __lx[(_Len + n - 1)/n * n];\ - };\ - } - - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x1); - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x2); - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x4); - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x8); - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x10); - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x20); - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x40); - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x80); - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x100); - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x200); - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x400); - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x800); - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x1000); - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x2000); - // PE/COFF does not support alignment beyond 8192 (=0x2000) -#if !defined(__WI_LIBCPP_OBJECT_FORMAT_COFF) - __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION(0x4000); -#endif // !defined(__WI_LIBCPP_OBJECT_FORMAT_COFF) - -#undef __WI_CREATE_ALIGNED_STORAGE_SPECIALIZATION - - template ::value> - struct __WI_LIBCPP_TEMPLATE_VIS aligned_storage : public __aligned_storage<_Len, _Align> {}; - -#if __WI_LIBCPP_STD_VER > 11 - template ::value> - using aligned_storage_t = typename aligned_storage<_Len, _Align>::type; -#endif - -#ifndef __WI_LIBCPP_HAS_NO_VARIADICS - - // aligned_union - - template - struct __static_max; - - template - struct __static_max<_I0> - { - static const size_t value = _I0; - }; - - template - struct __static_max<_I0, _I1, _In...> - { - static const size_t value = _I0 >= _I1 ? __static_max<_I0, _In...>::value : - __static_max<_I1, _In...>::value; - }; - - template - struct aligned_union - { - static const size_t alignment_value = __static_max<__alignof__(_Type0), - __alignof__(_Types)...>::value; - static const size_t __len = __static_max<_Len, sizeof(_Type0), - sizeof(_Types)...>::value; - typedef typename aligned_storage<__len, alignment_value>::type type; - }; - -#if __WI_LIBCPP_STD_VER > 11 - template using aligned_union_t = typename aligned_union<_Len, _Types...>::type; -#endif - -#endif // __WI_LIBCPP_HAS_NO_VARIADICS - - template - struct __numeric_type - { - static void __test(...); - static float __test(float); - static double __test(char); - static double __test(int); - static double __test(unsigned); - static double __test(long); - static double __test(unsigned long); - static double __test(long long); - static double __test(unsigned long long); - static double __test(double); - static long double __test(long double); - - typedef decltype(__test(declval<_Tp>())) type; - static const bool value = !is_same::value; - }; - - template <> - struct __numeric_type - { - static const bool value = true; - }; - - // __promote - - template ::value && - __numeric_type<_A2>::value && - __numeric_type<_A3>::value> - class __promote_imp - { - public: - static const bool value = false; - }; - - template - class __promote_imp<_A1, _A2, _A3, true> - { - private: - typedef typename __promote_imp<_A1>::type __type1; - typedef typename __promote_imp<_A2>::type __type2; - typedef typename __promote_imp<_A3>::type __type3; - public: - typedef decltype(__type1() + __type2() + __type3()) type; - static const bool value = true; - }; - - template - class __promote_imp<_A1, _A2, void, true> - { - private: - typedef typename __promote_imp<_A1>::type __type1; - typedef typename __promote_imp<_A2>::type __type2; - public: - typedef decltype(__type1() + __type2()) type; - static const bool value = true; - }; - - template - class __promote_imp<_A1, void, void, true> - { - public: - typedef typename __numeric_type<_A1>::type type; - static const bool value = true; - }; - - template - class __promote : public __promote_imp<_A1, _A2, _A3> {}; - - // make_signed / make_unsigned - - typedef - __type_list -#endif - > > > > > __signed_types; - - typedef - __type_list -#endif - > > > > > __unsigned_types; - - template struct __find_first; - - template - struct __find_first<__type_list<_Hp, _Tp>, _Size, true> - { - typedef _Hp type; - }; - - template - struct __find_first<__type_list<_Hp, _Tp>, _Size, false> - { - typedef typename __find_first<_Tp, _Size>::type type; - }; - - template ::type>::value, - bool = is_volatile::type>::value> - struct __apply_cv - { - typedef _Up type; - }; - - template - struct __apply_cv<_Tp, _Up, true, false> - { - typedef const _Up type; - }; - - template - struct __apply_cv<_Tp, _Up, false, true> - { - typedef volatile _Up type; - }; - - template - struct __apply_cv<_Tp, _Up, true, true> - { - typedef const volatile _Up type; - }; - - template - struct __apply_cv<_Tp&, _Up, false, false> - { - typedef _Up& type; - }; - - template - struct __apply_cv<_Tp&, _Up, true, false> - { - typedef const _Up& type; - }; - - template - struct __apply_cv<_Tp&, _Up, false, true> - { - typedef volatile _Up& type; - }; - - template - struct __apply_cv<_Tp&, _Up, true, true> - { - typedef const volatile _Up& type; - }; - - template ::value || is_enum<_Tp>::value> - struct __make_signed {}; - - template - struct __make_signed<_Tp, true> - { - typedef typename __find_first<__signed_types, sizeof(_Tp)>::type type; - }; - - template <> struct __make_signed {}; - template <> struct __make_signed< signed short, true> {typedef short type;}; - template <> struct __make_signed {typedef short type;}; - template <> struct __make_signed< signed int, true> {typedef int type;}; - template <> struct __make_signed {typedef int type;}; - template <> struct __make_signed< signed long, true> {typedef long type;}; - template <> struct __make_signed {typedef long type;}; - template <> struct __make_signed< signed long long, true> {typedef long long type;}; - template <> struct __make_signed {typedef long long type;}; -#ifndef __WI_LIBCPP_HAS_NO_INT128 - template <> struct __make_signed<__int128_t, true> {typedef __int128_t type;}; - template <> struct __make_signed<__uint128_t, true> {typedef __int128_t type;}; -#endif - - template - struct __WI_LIBCPP_TEMPLATE_VIS make_signed - { - typedef typename __apply_cv<_Tp, typename __make_signed::type>::type>::type type; - }; - -#if __WI_LIBCPP_STD_VER > 11 - template using make_signed_t = typename make_signed<_Tp>::type; -#endif - - template ::value || is_enum<_Tp>::value> - struct __make_unsigned {}; - - template - struct __make_unsigned<_Tp, true> - { - typedef typename __find_first<__unsigned_types, sizeof(_Tp)>::type type; - }; - - template <> struct __make_unsigned {}; - template <> struct __make_unsigned< signed short, true> {typedef unsigned short type;}; - template <> struct __make_unsigned {typedef unsigned short type;}; - template <> struct __make_unsigned< signed int, true> {typedef unsigned int type;}; - template <> struct __make_unsigned {typedef unsigned int type;}; - template <> struct __make_unsigned< signed long, true> {typedef unsigned long type;}; - template <> struct __make_unsigned {typedef unsigned long type;}; - template <> struct __make_unsigned< signed long long, true> {typedef unsigned long long type;}; - template <> struct __make_unsigned {typedef unsigned long long type;}; -#ifndef __WI_LIBCPP_HAS_NO_INT128 - template <> struct __make_unsigned<__int128_t, true> {typedef __uint128_t type;}; - template <> struct __make_unsigned<__uint128_t, true> {typedef __uint128_t type;}; -#endif - - template - struct __WI_LIBCPP_TEMPLATE_VIS make_unsigned - { - typedef typename __apply_cv<_Tp, typename __make_unsigned::type>::type>::type type; - }; - -#if __WI_LIBCPP_STD_VER > 11 - template using make_unsigned_t = typename make_unsigned<_Tp>::type; -#endif - -#ifdef __WI_LIBCPP_HAS_NO_VARIADICS - - template - struct __WI_LIBCPP_TEMPLATE_VIS common_type - { - public: - typedef typename common_type::type, _Vp>::type type; - }; - - template <> - struct __WI_LIBCPP_TEMPLATE_VIS common_type - { - public: - typedef void type; - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, void, void> - { - public: - typedef typename common_type<_Tp, _Tp>::type type; - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up, void> - { - typedef typename decay() : declval<_Up>() - )>::type type; - }; - -#else // __WI_LIBCPP_HAS_NO_VARIADICS - - // bullet 1 - sizeof...(Tp) == 0 - - template - struct __WI_LIBCPP_TEMPLATE_VIS common_type {}; - - // bullet 2 - sizeof...(Tp) == 1 - - template - struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp> - : public common_type<_Tp, _Tp> {}; - - // bullet 3 - sizeof...(Tp) == 2 - - template - struct __common_type2_imp {}; - - template - struct __common_type2_imp<_Tp, _Up, - typename __void_t() : declval<_Up>() - )>::type> - { - typedef typename decay() : declval<_Up>() - )>::type type; - }; - - template ::type, - class _DUp = typename decay<_Up>::type> - using __common_type2 = - typename conditional< - is_same<_Tp, _DTp>::value && is_same<_Up, _DUp>::value, - __common_type2_imp<_Tp, _Up>, - common_type<_DTp, _DUp> - >::type; - - template - struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up> - : __common_type2<_Tp, _Up> {}; - - // bullet 4 - sizeof...(Tp) > 2 - - template struct __common_types; - - template - struct __common_type_impl {}; - - template - struct __common_type_impl< - __common_types<_Tp, _Up>, - typename __void_t::type>::type> - { - typedef typename common_type<_Tp, _Up>::type type; - }; - - template - struct __common_type_impl<__common_types<_Tp, _Up, _Vp...>, - typename __void_t::type>::type> - : __common_type_impl< - __common_types::type, _Vp...> > - { - - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS common_type<_Tp, _Up, _Vp...> - : __common_type_impl<__common_types<_Tp, _Up, _Vp...> > {}; - -#if __WI_LIBCPP_STD_VER > 11 - template using common_type_t = typename common_type<_Tp...>::type; -#endif - -#endif // __WI_LIBCPP_HAS_NO_VARIADICS - - // is_assignable - - template struct __select_2nd { typedef _Tp type; }; - - template - typename __select_2nd() = declval<_Arg>())), true_type>::type - __is_assignable_test(int); - - template - false_type __is_assignable_test(...); - - - template ::value || is_void<_Arg>::value> - struct __is_assignable_imp - : public decltype((__is_assignable_test<_Tp, _Arg>(0))) {}; - - template - struct __is_assignable_imp<_Tp, _Arg, true> - : public false_type - { - }; - - template - struct is_assignable - : public __is_assignable_imp<_Tp, _Arg> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_assignable_v - = is_assignable<_Tp, _Arg>::value; -#endif - - // is_copy_assignable - - template struct __WI_LIBCPP_TEMPLATE_VIS is_copy_assignable - : public is_assignable::type, - typename add_lvalue_reference::type>::type> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_copy_assignable_v - = is_copy_assignable<_Tp>::value; -#endif - - // is_move_assignable - - template struct __WI_LIBCPP_TEMPLATE_VIS is_move_assignable -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - : public is_assignable::type, - typename add_rvalue_reference<_Tp>::type> {}; -#else - : public is_copy_assignable<_Tp> {}; -#endif - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_move_assignable_v - = is_move_assignable<_Tp>::value; -#endif - - // is_destructible - -#if __WI_HAS_FEATURE_IS_DESTRUCTIBLE - - template - struct is_destructible - : public integral_constant {}; - -#else - - // if it's a reference, return true - // if it's a function, return false - // if it's void, return false - // if it's an array of unknown bound, return false - // Otherwise, return "std::declval<_Up&>().~_Up()" is well-formed - // where _Up is remove_all_extents<_Tp>::type - - template - struct __is_destructible_apply { typedef int type; }; - - template - struct __is_destructor_wellformed { - template - static char __test ( - typename __is_destructible_apply().~_Tp1())>::type - ); - - template - static __two __test (...); - - static const bool value = sizeof(__test<_Tp>(12)) == sizeof(char); - }; - - template - struct __destructible_imp; - - template - struct __destructible_imp<_Tp, false> - : public integral_constant::type>::value> {}; - - template - struct __destructible_imp<_Tp, true> - : public true_type {}; - - template - struct __destructible_false; - - template - struct __destructible_false<_Tp, false> : public __destructible_imp<_Tp, is_reference<_Tp>::value> {}; - - template - struct __destructible_false<_Tp, true> : public false_type {}; - - template - struct is_destructible - : public __destructible_false<_Tp, is_function<_Tp>::value> {}; - - template - struct is_destructible<_Tp[]> - : public false_type {}; - - template <> - struct is_destructible - : public false_type {}; - -#endif // __WI_HAS_FEATURE_IS_DESTRUCTIBLE - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_destructible_v - = is_destructible<_Tp>::value; -#endif - - // move - -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - - template - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - typename remove_reference<_Tp>::type&& - move(_Tp&& __t) WI_NOEXCEPT - { - typedef typename remove_reference<_Tp>::type _Up; - return static_cast<_Up&&>(__t); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - _Tp&& - forward(typename remove_reference<_Tp>::type& __t) WI_NOEXCEPT - { - return static_cast<_Tp&&>(__t); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - _Tp&& - forward(typename remove_reference<_Tp>::type&& __t) WI_NOEXCEPT - { - static_assert(!is_lvalue_reference<_Tp>::value, - "can not forward an rvalue as an lvalue"); - return static_cast<_Tp&&>(__t); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR_AFTER_CXX17 - _T1 exchange(_T1& __obj, _T2 && __new_value) - { - _T1 __old_value = wistd::move(__obj); - __obj = wistd::forward<_T2>(__new_value); - return __old_value; - } - -#else // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - _Tp& - move(_Tp& __t) - { - return __t; - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - const _Tp& - move(const _Tp& __t) - { - return __t; - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - _Tp& - forward(typename remove_reference<_Tp>::type& __t) WI_NOEXCEPT - { - return __t; - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - _T1 exchange(_T1& __obj, const _T2& __new_value) - { - _T1 __old_value = __obj; - __obj = __new_value; - return __old_value; - } - - template - class __rv - { - typedef typename remove_reference<_Tp>::type _Trr; - _Trr& t_; - public: - __WI_LIBCPP_INLINE_VISIBILITY - _Trr* operator->() {return &t_;} - __WI_LIBCPP_INLINE_VISIBILITY - explicit __rv(_Trr& __t) : t_(__t) {} - }; - -#endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - -#if __WI_LIBCPP_STD_VER > 11 - template -#else - template -#endif - struct __WI_LIBCPP_TEMPLATE_VIS less : binary_function<_Tp, _Tp, bool> - { - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 __WI_LIBCPP_INLINE_VISIBILITY - bool operator()(const _Tp& __x, const _Tp& __y) const - {return __x < __y;} - }; - -#if __WI_LIBCPP_STD_VER > 11 - template <> - struct __WI_LIBCPP_TEMPLATE_VIS less - { - template - __WI_LIBCPP_NODISCARD_ATTRIBUTE __WI_LIBCPP_CONSTEXPR_AFTER_CXX11 __WI_LIBCPP_INLINE_VISIBILITY - auto operator()(_T1&& __t, _T2&& __u) const - __WI_NOEXCEPT_(noexcept(wistd::forward<_T1>(__t) < wistd::forward<_T2>(__u))) - -> decltype (wistd::forward<_T1>(__t) < wistd::forward<_T2>(__u)) - { return wistd::forward<_T1>(__t) < wistd::forward<_T2>(__u); } - typedef void is_transparent; - }; -#endif - -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - typename decay<_Tp>::type - __decay_copy(_Tp&& __t) - { - return wistd::forward<_Tp>(__t); - } - -#else - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - typename decay<_Tp>::type - __decay_copy(const _Tp& __t) - { - return wistd::forward<_Tp>(__t); - } - -#endif - -#ifndef __WI_LIBCPP_HAS_NO_VARIADICS - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...), true, false> - { - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...), true, false> - { - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param..., ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const, true, false> - { - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const, true, false> - { - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param..., ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) volatile, true, false> - { - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) volatile, true, false> - { - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param..., ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const volatile, true, false> - { - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const volatile, true, false> - { - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param..., ...); - }; - -#if __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS || \ - (defined(__WI_GNUC_VER) && __WI_GNUC_VER >= 409) - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) &, true, false> - { - typedef _Class& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) &, true, false> - { - typedef _Class& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param..., ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const&, true, false> - { - typedef _Class const& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const&, true, false> - { - typedef _Class const& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param..., ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) volatile&, true, false> - { - typedef _Class volatile& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) volatile&, true, false> - { - typedef _Class volatile& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param..., ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const volatile&, true, false> - { - typedef _Class const volatile& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const volatile&, true, false> - { - typedef _Class const volatile& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param..., ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) &&, true, false> - { - typedef _Class&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) &&, true, false> - { - typedef _Class&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param..., ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const&&, true, false> - { - typedef _Class const&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const&&, true, false> - { - typedef _Class const&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param..., ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) volatile&&, true, false> - { - typedef _Class volatile&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) volatile&&, true, false> - { - typedef _Class volatile&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param..., ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param...) const volatile&&, true, false> - { - typedef _Class const volatile&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_Param..., ...) const volatile&&, true, false> - { - typedef _Class const volatile&& _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_Param..., ...); - }; - -#endif // __WI_HAS_FEATURE_REFERENCE_QUALIFIED_FUNCTIONS || __WI_GNUC_VER >= 409 - -#else // __WI_LIBCPP_HAS_NO_VARIADICS - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(), true, false> - { - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(...), true, false> - { - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0), true, false> - { - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...), true, false> - { - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1), true, false> - { - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...), true, false> - { - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1, ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2), true, false> - { - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1, _P2); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...), true, false> - { - typedef _Class _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1, _P2, ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)() const, true, false> - { - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(...) const, true, false> - { - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0) const, true, false> - { - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...) const, true, false> - { - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1) const, true, false> - { - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...) const, true, false> - { - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1, ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2) const, true, false> - { - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1, _P2); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...) const, true, false> - { - typedef _Class const _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1, _P2, ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)() volatile, true, false> - { - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(...) volatile, true, false> - { - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0) volatile, true, false> - { - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...) volatile, true, false> - { - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1) volatile, true, false> - { - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...) volatile, true, false> - { - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1, ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2) volatile, true, false> - { - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1, _P2); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...) volatile, true, false> - { - typedef _Class volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1, _P2, ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)() const volatile, true, false> - { - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(...) const volatile, true, false> - { - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0) const volatile, true, false> - { - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, ...) const volatile, true, false> - { - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1) const volatile, true, false> - { - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, ...) const volatile, true, false> - { - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1, ...); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2) const volatile, true, false> - { - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1, _P2); - }; - - template - struct __member_pointer_traits_imp<_Rp (_Class::*)(_P0, _P1, _P2, ...) const volatile, true, false> - { - typedef _Class const volatile _ClassType; - typedef _Rp _ReturnType; - typedef _Rp (_FnType) (_P0, _P1, _P2, ...); - }; - -#endif // __WI_LIBCPP_HAS_NO_VARIADICS - - template - struct __member_pointer_traits_imp<_Rp _Class::*, false, true> - { - typedef _Class _ClassType; - typedef _Rp _ReturnType; - }; - - template - struct __member_pointer_traits - : public __member_pointer_traits_imp::type, - is_member_function_pointer<_Mp>::value, - is_member_object_pointer<_Mp>::value> - { - // typedef ... _ClassType; - // typedef ... _ReturnType; - // typedef ... _FnType; - }; - - - template - struct __member_pointer_class_type {}; - - template - struct __member_pointer_class_type<_Ret _ClassType::*> { - typedef _ClassType type; - }; - - // result_of - - template class result_of; - -#ifdef __WI_LIBCPP_HAS_NO_VARIADICS - - template - class __result_of - { - }; - - template - class __result_of<_Fn(), true, false> - { - public: - typedef decltype(declval<_Fn>()()) type; - }; - - template - class __result_of<_Fn(_A0), true, false> - { - public: - typedef decltype(declval<_Fn>()(declval<_A0>())) type; - }; - - template - class __result_of<_Fn(_A0, _A1), true, false> - { - public: - typedef decltype(declval<_Fn>()(declval<_A0>(), declval<_A1>())) type; - }; - - template - class __result_of<_Fn(_A0, _A1, _A2), true, false> - { - public: - typedef decltype(declval<_Fn>()(declval<_A0>(), declval<_A1>(), declval<_A2>())) type; - }; - - template - struct __result_of_mp; - - // member function pointer - - template - struct __result_of_mp<_Mp, _Tp, true> - : public __identity::_ReturnType> - { - }; - - // member data pointer - - template - struct __result_of_mdp; - - template - struct __result_of_mdp<_Rp _Class::*, _Tp, false> - { - typedef typename __apply_cv()), _Rp>::type& type; - }; - - template - struct __result_of_mdp<_Rp _Class::*, _Tp, true> - { - typedef typename __apply_cv<_Tp, _Rp>::type& type; - }; - - template - struct __result_of_mp<_Rp _Class::*, _Tp, false> - : public __result_of_mdp<_Rp _Class::*, _Tp, - is_base_of<_Class, typename remove_reference<_Tp>::type>::value> - { - }; - - - - template - class __result_of<_Fn(_Tp), false, true> // _Fn must be member pointer - : public __result_of_mp::type, - _Tp, - is_member_function_pointer::type>::value> - { - }; - - template - class __result_of<_Fn(_Tp, _A0), false, true> // _Fn must be member pointer - : public __result_of_mp::type, - _Tp, - is_member_function_pointer::type>::value> - { - }; - - template - class __result_of<_Fn(_Tp, _A0, _A1), false, true> // _Fn must be member pointer - : public __result_of_mp::type, - _Tp, - is_member_function_pointer::type>::value> - { - }; - - template - class __result_of<_Fn(_Tp, _A0, _A1, _A2), false, true> // _Fn must be member pointer - : public __result_of_mp::type, - _Tp, - is_member_function_pointer::type>::value> - { - }; - - // result_of - - template - class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn()> - : public __result_of<_Fn(), - is_class::type>::value || - is_function::type>::type>::value, - is_member_pointer::type>::value - > - { - }; - - template - class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn(_A0)> - : public __result_of<_Fn(_A0), - is_class::type>::value || - is_function::type>::type>::value, - is_member_pointer::type>::value - > - { - }; - - template - class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn(_A0, _A1)> - : public __result_of<_Fn(_A0, _A1), - is_class::type>::value || - is_function::type>::type>::value, - is_member_pointer::type>::value - > - { - }; - - template - class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fn(_A0, _A1, _A2)> - : public __result_of<_Fn(_A0, _A1, _A2), - is_class::type>::value || - is_function::type>::type>::value, - is_member_pointer::type>::value - > - { - }; - -#endif // __WI_LIBCPP_HAS_NO_VARIADICS - - // template struct is_constructible; - - namespace __is_construct - { - struct __nat {}; - } - -#if !defined(__WI_LIBCPP_CXX03_LANG) && (!__WI_HAS_FEATURE_IS_CONSTRUCTIBLE || \ - defined(__WI_LIBCPP_TESTING_FALLBACK_IS_CONSTRUCTIBLE)) - - template - struct __libcpp_is_constructible; - - template - struct __is_invalid_base_to_derived_cast { - static_assert(is_reference<_To>::value, "Wrong specialization"); - using _RawFrom = __uncvref_t<_From>; - using _RawTo = __uncvref_t<_To>; - static const bool value = __lazy_and< - __lazy_not>, - is_base_of<_RawFrom, _RawTo>, - __lazy_not<__libcpp_is_constructible<_RawTo, _From>> - >::value; - }; - - template - struct __is_invalid_lvalue_to_rvalue_cast : false_type { - static_assert(is_reference<_To>::value, "Wrong specialization"); - }; - - template - struct __is_invalid_lvalue_to_rvalue_cast<_ToRef&&, _FromRef&> { - using _RawFrom = __uncvref_t<_FromRef>; - using _RawTo = __uncvref_t<_ToRef>; - static const bool value = __lazy_and< - __lazy_not>, - __lazy_or< - is_same<_RawFrom, _RawTo>, - is_base_of<_RawTo, _RawFrom>> - >::value; - }; - - struct __is_constructible_helper - { - template - static void __eat(_To); - - // This overload is needed to work around a Clang bug that disallows - // static_cast(e) for non-reference-compatible types. - // Example: static_cast(declval()); - // NOTE: The static_cast implementation below is required to support - // classes with explicit conversion operators. - template (declval<_From>()))> - static true_type __test_cast(int); - - template (declval<_From>()))> - static integral_constant::value && - !__is_invalid_lvalue_to_rvalue_cast<_To, _From>::value - > __test_cast(long); - - template - static false_type __test_cast(...); - - template ()...))> - static true_type __test_nary(int); - template - static false_type __test_nary(...); - - template ()))> - static is_destructible<_Tp> __test_unary(int); - template - static false_type __test_unary(...); - }; - - template ::value> - struct __is_default_constructible - : decltype(__is_constructible_helper::__test_nary<_Tp>(0)) - {}; - - template - struct __is_default_constructible<_Tp, true> : false_type {}; - - template - struct __is_default_constructible<_Tp[], false> : false_type {}; - - template - struct __is_default_constructible<_Tp[_Nx], false> - : __is_default_constructible::type> {}; - - template - struct __libcpp_is_constructible - { - static_assert(sizeof...(_Args) > 1, "Wrong specialization"); - typedef decltype(__is_constructible_helper::__test_nary<_Tp, _Args...>(0)) - type; - }; - - template - struct __libcpp_is_constructible<_Tp> : __is_default_constructible<_Tp> {}; - - template - struct __libcpp_is_constructible<_Tp, _A0> - : public decltype(__is_constructible_helper::__test_unary<_Tp, _A0>(0)) - {}; - - template - struct __libcpp_is_constructible<_Tp&, _A0> - : public decltype(__is_constructible_helper:: - __test_cast<_Tp&, _A0>(0)) - {}; - - template - struct __libcpp_is_constructible<_Tp&&, _A0> - : public decltype(__is_constructible_helper:: - __test_cast<_Tp&&, _A0>(0)) - {}; - -#endif - -#if __WI_HAS_FEATURE_IS_CONSTRUCTIBLE - template - struct __WI_LIBCPP_TEMPLATE_VIS is_constructible - : public integral_constant - {}; -#elif !defined(__WI_LIBCPP_CXX03_LANG) - template - struct __WI_LIBCPP_TEMPLATE_VIS is_constructible - : public __libcpp_is_constructible<_Tp, _Args...>::type {}; -#else - // template struct is_constructible0; - - // main is_constructible0 test - - template - decltype((_Tp(), true_type())) - __is_constructible0_test(_Tp&); - - false_type - __is_constructible0_test(__any); - - template - decltype((_Tp(declval<_A0>()), true_type())) - __is_constructible1_test(_Tp&, _A0&); - - template - false_type - __is_constructible1_test(__any, _A0&); - - template - decltype((_Tp(declval<_A0>(), declval<_A1>()), true_type())) - __is_constructible2_test(_Tp&, _A0&, _A1&); - - template - false_type - __is_constructible2_test(__any, _A0&, _A1&); - - template - decltype((_Tp(declval<_A0>(), declval<_A1>(), declval<_A2>()), true_type())) - __is_constructible3_test(_Tp&, _A0&, _A1&, _A2&); - - template - false_type - __is_constructible3_test(__any, _A0&, _A1&, _A2&); - - template - struct __is_constructible0_imp // false, _Tp is not a scalar - : public common_type - < - decltype(__is_constructible0_test(declval<_Tp&>())) - >::type - {}; - - template - struct __is_constructible1_imp // false, _Tp is not a scalar - : public common_type - < - decltype(__is_constructible1_test(declval<_Tp&>(), declval<_A0&>())) - >::type - {}; - - template - struct __is_constructible2_imp // false, _Tp is not a scalar - : public common_type - < - decltype(__is_constructible2_test(declval<_Tp&>(), declval<_A0>(), declval<_A1>())) - >::type - {}; - - template - struct __is_constructible3_imp // false, _Tp is not a scalar - : public common_type - < - decltype(__is_constructible3_test(declval<_Tp&>(), declval<_A0>(), declval<_A1>(), declval<_A2>())) - >::type - {}; - - // handle scalars and reference types - - // Scalars are default constructible, references are not - - template - struct __is_constructible0_imp - : public is_scalar<_Tp> - {}; - - template - struct __is_constructible1_imp - : public is_convertible<_A0, _Tp> - {}; - - template - struct __is_constructible2_imp - : public false_type - {}; - - template - struct __is_constructible3_imp - : public false_type - {}; - - // Treat scalars and reference types separately - - template - struct __is_constructible0_void_check - : public __is_constructible0_imp::value || is_reference<_Tp>::value, - _Tp> - {}; - - template - struct __is_constructible1_void_check - : public __is_constructible1_imp::value || is_reference<_Tp>::value, - _Tp, _A0> - {}; - - template - struct __is_constructible2_void_check - : public __is_constructible2_imp::value || is_reference<_Tp>::value, - _Tp, _A0, _A1> - {}; - - template - struct __is_constructible3_void_check - : public __is_constructible3_imp::value || is_reference<_Tp>::value, - _Tp, _A0, _A1, _A2> - {}; - - // If any of T or Args is void, is_constructible should be false - - template - struct __is_constructible0_void_check - : public false_type - {}; - - template - struct __is_constructible1_void_check - : public false_type - {}; - - template - struct __is_constructible2_void_check - : public false_type - {}; - - template - struct __is_constructible3_void_check - : public false_type - {}; - - // is_constructible entry point - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_constructible - : public __is_constructible3_void_check::value - || is_abstract<_Tp>::value - || is_function<_Tp>::value - || is_void<_A0>::value - || is_void<_A1>::value - || is_void<_A2>::value, - _Tp, _A0, _A1, _A2> - {}; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_constructible<_Tp, __is_construct::__nat, __is_construct::__nat> - : public __is_constructible0_void_check::value - || is_abstract<_Tp>::value - || is_function<_Tp>::value, - _Tp> - {}; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_constructible<_Tp, _A0, __is_construct::__nat> - : public __is_constructible1_void_check::value - || is_abstract<_Tp>::value - || is_function<_Tp>::value - || is_void<_A0>::value, - _Tp, _A0> - {}; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_constructible<_Tp, _A0, _A1, __is_construct::__nat> - : public __is_constructible2_void_check::value - || is_abstract<_Tp>::value - || is_function<_Tp>::value - || is_void<_A0>::value - || is_void<_A1>::value, - _Tp, _A0, _A1> - {}; - - // Array types are default constructible if their element type - // is default constructible - - template - struct __is_constructible0_imp - : public is_constructible::type> - {}; - - template - struct __is_constructible1_imp - : public false_type - {}; - - template - struct __is_constructible2_imp - : public false_type - {}; - - template - struct __is_constructible3_imp - : public false_type - {}; - - // Incomplete array types are not constructible - - template - struct __is_constructible0_imp - : public false_type - {}; - - template - struct __is_constructible1_imp - : public false_type - {}; - - template - struct __is_constructible2_imp - : public false_type - {}; - - template - struct __is_constructible3_imp - : public false_type - {}; - -#endif // __WI_HAS_FEATURE_IS_CONSTRUCTIBLE - - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) && !defined(__WI_LIBCPP_HAS_NO_VARIADICS) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_constructible_v - = is_constructible<_Tp, _Args...>::value; -#endif - - // is_default_constructible - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_default_constructible - : public is_constructible<_Tp> - {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_default_constructible_v - = is_default_constructible<_Tp>::value; -#endif - - // is_copy_constructible - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_copy_constructible - : public is_constructible<_Tp, - typename add_lvalue_reference::type>::type> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_copy_constructible_v - = is_copy_constructible<_Tp>::value; -#endif - - // is_move_constructible - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_move_constructible -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - : public is_constructible<_Tp, typename add_rvalue_reference<_Tp>::type> -#else - : public is_copy_constructible<_Tp> -#endif - {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_move_constructible_v - = is_move_constructible<_Tp>::value; -#endif - - // is_trivially_constructible - -#ifndef __WI_LIBCPP_HAS_NO_VARIADICS - -#if __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE || __WI_GNUC_VER >= 501 - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible - : integral_constant - { - }; - -#else // !__WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible - : false_type - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp> -#if __WI_HAS_FEATURE_HAS_TRIVIAL_CONSTRUCTOR - : integral_constant -#else - : integral_constant::value> -#endif - { - }; - - template -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp&&> -#else - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp> -#endif - : integral_constant::value> - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, const _Tp&> - : integral_constant::value> - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp&> - : integral_constant::value> - { - }; - -#endif // !__WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE - -#else // __WI_LIBCPP_HAS_NO_VARIADICS - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible - : false_type - { - }; - -#if __WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE || __WI_GNUC_VER >= 501 - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, __is_construct::__nat, - __is_construct::__nat> - : integral_constant - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp, - __is_construct::__nat> - : integral_constant - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, const _Tp&, - __is_construct::__nat> - : integral_constant - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp&, - __is_construct::__nat> - : integral_constant - { - }; - -#else // !__WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, __is_construct::__nat, - __is_construct::__nat> - : integral_constant::value> - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp, - __is_construct::__nat> - : integral_constant::value> - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, const _Tp&, - __is_construct::__nat> - : integral_constant::value> - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_constructible<_Tp, _Tp&, - __is_construct::__nat> - : integral_constant::value> - { - }; - -#endif // !__WI_HAS_FEATURE_IS_TRIVIALLY_CONSTRUCTIBLE - -#endif // __WI_LIBCPP_HAS_NO_VARIADICS - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) && !defined(__WI_LIBCPP_HAS_NO_VARIADICS) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_constructible_v - = is_trivially_constructible<_Tp, _Args...>::value; -#endif - - // is_trivially_default_constructible - - template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_default_constructible - : public is_trivially_constructible<_Tp> - {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_default_constructible_v - = is_trivially_default_constructible<_Tp>::value; -#endif - - // is_trivially_copy_constructible - - template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_copy_constructible - : public is_trivially_constructible<_Tp, typename add_lvalue_reference::type> - {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_copy_constructible_v - = is_trivially_copy_constructible<_Tp>::value; -#endif - - // is_trivially_move_constructible - - template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_move_constructible -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - : public is_trivially_constructible<_Tp, typename add_rvalue_reference<_Tp>::type> -#else - : public is_trivially_copy_constructible<_Tp> -#endif - {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_move_constructible_v - = is_trivially_move_constructible<_Tp>::value; -#endif - - // is_trivially_assignable - -#if __WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE || __WI_GNUC_VER >= 501 - - template - struct is_trivially_assignable - : integral_constant - { - }; - -#else // !__WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE - - template - struct is_trivially_assignable - : public false_type {}; - - template - struct is_trivially_assignable<_Tp&, _Tp> - : integral_constant::value> {}; - - template - struct is_trivially_assignable<_Tp&, _Tp&> - : integral_constant::value> {}; - - template - struct is_trivially_assignable<_Tp&, const _Tp&> - : integral_constant::value> {}; - -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - - template - struct is_trivially_assignable<_Tp&, _Tp&&> - : integral_constant::value> {}; - -#endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - -#endif // !__WI_HAS_FEATURE_IS_TRIVIALLY_ASSIGNABLE - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_assignable_v - = is_trivially_assignable<_Tp, _Arg>::value; -#endif - - // is_trivially_copy_assignable - - template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_copy_assignable - : public is_trivially_assignable::type, - typename add_lvalue_reference::type>::type> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_copy_assignable_v - = is_trivially_copy_assignable<_Tp>::value; -#endif - - // is_trivially_move_assignable - - template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_move_assignable - : public is_trivially_assignable::type, -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - typename add_rvalue_reference<_Tp>::type> -#else - typename add_lvalue_reference<_Tp>::type> -#endif - {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_move_assignable_v - = is_trivially_move_assignable<_Tp>::value; -#endif - - // is_trivially_destructible - -#if __WI_HAS_FEATURE_HAS_TRIVIAL_DESTRUCTOR || (__WI_GNUC_VER >= 403) - - template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_destructible - : public integral_constant::value && __has_trivial_destructor(_Tp)> {}; - -#else - - template struct __libcpp_trivial_destructor - : public integral_constant::value || - is_reference<_Tp>::value> {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_destructible - : public __libcpp_trivial_destructor::type> {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_destructible<_Tp[]> - : public false_type {}; - -#endif - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_destructible_v - = is_trivially_destructible<_Tp>::value; -#endif - - // is_nothrow_constructible - -#if 0 - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible - : public integral_constant - { - }; - -#else - -#ifndef __WI_LIBCPP_HAS_NO_VARIADICS - -#if !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) || (__WI_GNUC_VER >= 407 && __cplusplus >= 201103L) - - template struct __libcpp_is_nothrow_constructible; - - template - struct __libcpp_is_nothrow_constructible - : public integral_constant()...))> - { - }; - - template - void __implicit_conversion_to(_Tp) noexcept { } - - template - struct __libcpp_is_nothrow_constructible - : public integral_constant(declval<_Arg>()))> - { - }; - - template - struct __libcpp_is_nothrow_constructible - : public false_type - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible - : __libcpp_is_nothrow_constructible::value, is_reference<_Tp>::value, _Tp, _Args...> - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp[_Ns]> - : __libcpp_is_nothrow_constructible::value, is_reference<_Tp>::value, _Tp> - { - }; - -#else // !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible - : false_type - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp> -#if __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR - : integral_constant -#else - : integral_constant::value> -#endif - { - }; - - template -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp&&> -#else - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp> -#endif -#if __WI_HAS_FEATURE_HAS_NOTHROW_COPY - : integral_constant -#else - : integral_constant::value> -#endif - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, const _Tp&> -#if __WI_HAS_FEATURE_HAS_NOTHROW_COPY - : integral_constant -#else - : integral_constant::value> -#endif - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp&> -#if __WI_HAS_FEATURE_HAS_NOTHROW_COPY - : integral_constant -#else - : integral_constant::value> -#endif - { - }; - -#endif // !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) - -#else // __WI_LIBCPP_HAS_NO_VARIADICS - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible - : false_type - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, __is_construct::__nat, - __is_construct::__nat> -#if __WI_HAS_FEATURE_HAS_NOTHROW_CONSTRUCTOR - : integral_constant -#else - : integral_constant::value> -#endif - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp, - __is_construct::__nat> -#if __WI_HAS_FEATURE_HAS_NOTHROW_COPY - : integral_constant -#else - : integral_constant::value> -#endif - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, const _Tp&, - __is_construct::__nat> -#if __WI_HAS_FEATURE_HAS_NOTHROW_COPY - : integral_constant -#else - : integral_constant::value> -#endif - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_constructible<_Tp, _Tp&, - __is_construct::__nat> -#if __WI_HAS_FEATURE_HAS_NOTHROW_COPY - : integral_constant -#else - : integral_constant::value> -#endif - { - }; - -#endif // __WI_LIBCPP_HAS_NO_VARIADICS -#endif // __has_feature(is_nothrow_constructible) - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) && !defined(__WI_LIBCPP_HAS_NO_VARIADICS) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_constructible_v - = is_nothrow_constructible<_Tp, _Args...>::value; -#endif - - // is_nothrow_default_constructible - - template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_default_constructible - : public is_nothrow_constructible<_Tp> - {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_default_constructible_v - = is_nothrow_default_constructible<_Tp>::value; -#endif - - // is_nothrow_copy_constructible - - template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_copy_constructible - : public is_nothrow_constructible<_Tp, - typename add_lvalue_reference::type>::type> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_copy_constructible_v - = is_nothrow_copy_constructible<_Tp>::value; -#endif - - // is_nothrow_move_constructible - - template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_move_constructible -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - : public is_nothrow_constructible<_Tp, typename add_rvalue_reference<_Tp>::type> -#else - : public is_nothrow_copy_constructible<_Tp> -#endif - {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_move_constructible_v - = is_nothrow_move_constructible<_Tp>::value; -#endif - - // is_nothrow_assignable - -#if !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) || (__WI_GNUC_VER >= 407 && __cplusplus >= 201103L) - - template struct __libcpp_is_nothrow_assignable; - - template - struct __libcpp_is_nothrow_assignable - : public false_type - { - }; - - template - struct __libcpp_is_nothrow_assignable - : public integral_constant() = declval<_Arg>()) > - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable - : public __libcpp_is_nothrow_assignable::value, _Tp, _Arg> - { - }; - -#else // !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable - : public false_type {}; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable<_Tp&, _Tp> -#if __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN - : integral_constant {}; -#else - : integral_constant::value> {}; -#endif - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable<_Tp&, _Tp&> -#if __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN - : integral_constant {}; -#else - : integral_constant::value> {}; -#endif - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_assignable<_Tp&, const _Tp&> -#if __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN - : integral_constant {}; -#else - : integral_constant::value> {}; -#endif - -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - - template - struct is_nothrow_assignable<_Tp&, _Tp&&> -#if __WI_HAS_FEATURE_HAS_NOTHROW_ASSIGN - : integral_constant {}; -#else - : integral_constant::value> {}; -#endif - -#endif // __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - -#endif // !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_assignable_v - = is_nothrow_assignable<_Tp, _Arg>::value; -#endif - - // is_nothrow_copy_assignable - - template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_copy_assignable - : public is_nothrow_assignable::type, - typename add_lvalue_reference::type>::type> {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_copy_assignable_v - = is_nothrow_copy_assignable<_Tp>::value; -#endif - - // is_nothrow_move_assignable - - template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_move_assignable - : public is_nothrow_assignable::type, -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - typename add_rvalue_reference<_Tp>::type> -#else - typename add_lvalue_reference<_Tp>::type> -#endif - {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_move_assignable_v - = is_nothrow_move_assignable<_Tp>::value; -#endif - - // is_nothrow_destructible - -#if !defined(__WI_LIBCPP_HAS_NO_NOEXCEPT) || (__WI_GNUC_VER >= 407 && __cplusplus >= 201103L) - - template struct __libcpp_is_nothrow_destructible; - - template - struct __libcpp_is_nothrow_destructible - : public false_type - { - }; - - template - struct __libcpp_is_nothrow_destructible - : public integral_constant().~_Tp()) > - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible - : public __libcpp_is_nothrow_destructible::value, _Tp> - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp[_Ns]> - : public is_nothrow_destructible<_Tp> - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp&> - : public true_type - { - }; - -#ifndef __WI_LIBCPP_HAS_NO_RVALUE_REFERENCES - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp&&> - : public true_type - { - }; - -#endif - -#else - - template struct __libcpp_nothrow_destructor - : public integral_constant::value || - is_reference<_Tp>::value> {}; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible - : public __libcpp_nothrow_destructor::type> {}; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_destructible<_Tp[]> - : public false_type {}; - -#endif - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_nothrow_destructible_v - = is_nothrow_destructible<_Tp>::value; -#endif - - // is_pod - -#if __WI_HAS_FEATURE_IS_POD || (__WI_GNUC_VER >= 403) - - template struct __WI_LIBCPP_TEMPLATE_VIS is_pod - : public integral_constant {}; - -#else - - template struct __WI_LIBCPP_TEMPLATE_VIS is_pod - : public integral_constant::value && - is_trivially_copy_constructible<_Tp>::value && - is_trivially_copy_assignable<_Tp>::value && - is_trivially_destructible<_Tp>::value> {}; - -#endif - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_pod_v - = is_pod<_Tp>::value; -#endif - - // is_literal_type; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_literal_type -#ifdef __WI_LIBCPP_IS_LITERAL - : public integral_constant -#else - : integral_constant::type>::value || - is_reference::type>::value> -#endif - {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_literal_type_v - = is_literal_type<_Tp>::value; -#endif - - // is_standard_layout; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_standard_layout -#if __WI_HAS_FEATURE_IS_STANDARD_LAYOUT || (__WI_GNUC_VER >= 407) - : public integral_constant -#else - : integral_constant::type>::value> -#endif - {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_standard_layout_v - = is_standard_layout<_Tp>::value; -#endif - - // is_trivially_copyable; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_trivially_copyable -#if __WI_HAS_FEATURE_IS_TRIVIALLY_COPYABLE - : public integral_constant -#elif __WI_GNUC_VER >= 501 - : public integral_constant::value && __is_trivially_copyable(_Tp)> -#else - : integral_constant::type>::value> -#endif - {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivially_copyable_v - = is_trivially_copyable<_Tp>::value; -#endif - - // is_trivial; - - template struct __WI_LIBCPP_TEMPLATE_VIS is_trivial -#if __WI_HAS_FEATURE_IS_TRIVIAL || __WI_GNUC_VER >= 407 - : public integral_constant -#else - : integral_constant::value && - is_trivially_default_constructible<_Tp>::value> -#endif - {}; - -#if __WI_LIBCPP_STD_VER > 11 && !defined(__WI_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) - template - __WI_LIBCPP_INLINE_VAR __WI_LIBCPP_CONSTEXPR bool is_trivial_v - = is_trivial<_Tp>::value; -#endif - - template struct __is_reference_wrapper_impl : public false_type {}; - template struct __is_reference_wrapper_impl > : public true_type {}; - template struct __is_reference_wrapper - : public __is_reference_wrapper_impl::type> {}; - -#ifndef __WI_LIBCPP_CXX03_LANG - - template ::type, - class _DecayA0 = typename decay<_A0>::type, - class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> - using __enable_if_bullet1 = typename enable_if - < - is_member_function_pointer<_DecayFp>::value - && is_base_of<_ClassT, _DecayA0>::value - >::type; - - template ::type, - class _DecayA0 = typename decay<_A0>::type> - using __enable_if_bullet2 = typename enable_if - < - is_member_function_pointer<_DecayFp>::value - && __is_reference_wrapper<_DecayA0>::value - >::type; - - template ::type, - class _DecayA0 = typename decay<_A0>::type, - class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> - using __enable_if_bullet3 = typename enable_if - < - is_member_function_pointer<_DecayFp>::value - && !is_base_of<_ClassT, _DecayA0>::value - && !__is_reference_wrapper<_DecayA0>::value - >::type; - - template ::type, - class _DecayA0 = typename decay<_A0>::type, - class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> - using __enable_if_bullet4 = typename enable_if - < - is_member_object_pointer<_DecayFp>::value - && is_base_of<_ClassT, _DecayA0>::value - >::type; - - template ::type, - class _DecayA0 = typename decay<_A0>::type> - using __enable_if_bullet5 = typename enable_if - < - is_member_object_pointer<_DecayFp>::value - && __is_reference_wrapper<_DecayA0>::value - >::type; - - template ::type, - class _DecayA0 = typename decay<_A0>::type, - class _ClassT = typename __member_pointer_class_type<_DecayFp>::type> - using __enable_if_bullet6 = typename enable_if - < - is_member_object_pointer<_DecayFp>::value - && !is_base_of<_ClassT, _DecayA0>::value - && !__is_reference_wrapper<_DecayA0>::value - >::type; - - // __invoke forward declarations - - // fall back - none of the bullets - -#define __WI_LIBCPP_INVOKE_RETURN(...) \ - __WI_NOEXCEPT_(__WI_NOEXCEPT_(__VA_ARGS__)) -> decltype(__VA_ARGS__) \ - { return __VA_ARGS__; } - - template - auto __invoke(__any, _Args&& ...__args) -> __nat; - - template - auto __invoke_constexpr(__any, _Args&& ...__args) -> __nat; - - // bullets 1, 2 and 3 - - template > - inline __WI_LIBCPP_INLINE_VISIBILITY - auto - __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args) - __WI_LIBCPP_INVOKE_RETURN((wistd::forward<_A0>(__a0).*__f)(wistd::forward<_Args>(__args)...)) - - template > - inline __WI_LIBCPP_INLINE_VISIBILITY - __WI_LIBCPP_CONSTEXPR auto - __invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&& ...__args) - __WI_LIBCPP_INVOKE_RETURN((wistd::forward<_A0>(__a0).*__f)(wistd::forward<_Args>(__args)...)) - - template > - inline __WI_LIBCPP_INLINE_VISIBILITY - auto - __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args) - __WI_LIBCPP_INVOKE_RETURN((__a0.get().*__f)(wistd::forward<_Args>(__args)...)) - - template > - inline __WI_LIBCPP_INLINE_VISIBILITY - __WI_LIBCPP_CONSTEXPR auto - __invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&& ...__args) - __WI_LIBCPP_INVOKE_RETURN((__a0.get().*__f)(wistd::forward<_Args>(__args)...)) - - template > - inline __WI_LIBCPP_INLINE_VISIBILITY - auto - __invoke(_Fp&& __f, _A0&& __a0, _Args&& ...__args) - __WI_LIBCPP_INVOKE_RETURN(((*wistd::forward<_A0>(__a0)).*__f)(wistd::forward<_Args>(__args)...)) - - template > - inline __WI_LIBCPP_INLINE_VISIBILITY - __WI_LIBCPP_CONSTEXPR auto - __invoke_constexpr(_Fp&& __f, _A0&& __a0, _Args&& ...__args) - __WI_LIBCPP_INVOKE_RETURN(((*wistd::forward<_A0>(__a0)).*__f)(wistd::forward<_Args>(__args)...)) - - // bullets 4, 5 and 6 - - template > - inline __WI_LIBCPP_INLINE_VISIBILITY - auto - __invoke(_Fp&& __f, _A0&& __a0) - __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_A0>(__a0).*__f) - - template > - inline __WI_LIBCPP_INLINE_VISIBILITY - __WI_LIBCPP_CONSTEXPR auto - __invoke_constexpr(_Fp&& __f, _A0&& __a0) - __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_A0>(__a0).*__f) - - template > - inline __WI_LIBCPP_INLINE_VISIBILITY - auto - __invoke(_Fp&& __f, _A0&& __a0) - __WI_LIBCPP_INVOKE_RETURN(__a0.get().*__f) - - template > - inline __WI_LIBCPP_INLINE_VISIBILITY - __WI_LIBCPP_CONSTEXPR auto - __invoke_constexpr(_Fp&& __f, _A0&& __a0) - __WI_LIBCPP_INVOKE_RETURN(__a0.get().*__f) - - template > - inline __WI_LIBCPP_INLINE_VISIBILITY - auto - __invoke(_Fp&& __f, _A0&& __a0) - __WI_LIBCPP_INVOKE_RETURN((*wistd::forward<_A0>(__a0)).*__f) - - template > - inline __WI_LIBCPP_INLINE_VISIBILITY - __WI_LIBCPP_CONSTEXPR auto - __invoke_constexpr(_Fp&& __f, _A0&& __a0) - __WI_LIBCPP_INVOKE_RETURN((*wistd::forward<_A0>(__a0)).*__f) - - // bullet 7 - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - auto - __invoke(_Fp&& __f, _Args&& ...__args) - __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_Fp>(__f)(wistd::forward<_Args>(__args)...)) - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - __WI_LIBCPP_CONSTEXPR auto - __invoke_constexpr(_Fp&& __f, _Args&& ...__args) - __WI_LIBCPP_INVOKE_RETURN(wistd::forward<_Fp>(__f)(wistd::forward<_Args>(__args)...)) - -#undef __WI_LIBCPP_INVOKE_RETURN - - // __invokable - - template - struct __invokable_r - { - // FIXME: Check that _Ret, _Fp, and _Args... are all complete types, cv void, - // or incomplete array types as required by the standard. - using _Result = decltype( - __invoke(declval<_Fp>(), declval<_Args>()...)); - - using type = - typename conditional< - !is_same<_Result, __nat>::value, - typename conditional< - is_void<_Ret>::value, - true_type, - is_convertible<_Result, _Ret> - >::type, - false_type - >::type; - static const bool value = type::value; - }; - - template - using __invokable = __invokable_r; - - template - struct __nothrow_invokable_r_imp { - static const bool value = false; - }; - - template - struct __nothrow_invokable_r_imp - { - typedef __nothrow_invokable_r_imp _ThisT; - - template - static void __test_noexcept(_Tp) noexcept; - - static const bool value = noexcept(_ThisT::__test_noexcept<_Ret>( - __invoke(declval<_Fp>(), declval<_Args>()...))); - }; - - template - struct __nothrow_invokable_r_imp - { - static const bool value = noexcept( - __invoke(declval<_Fp>(), declval<_Args>()...)); - }; - - template - using __nothrow_invokable_r = - __nothrow_invokable_r_imp< - __invokable_r<_Ret, _Fp, _Args...>::value, - is_void<_Ret>::value, - _Ret, _Fp, _Args... - >; - - template - using __nothrow_invokable = - __nothrow_invokable_r_imp< - __invokable<_Fp, _Args...>::value, - true, void, _Fp, _Args... - >; - - template - struct __invoke_of - : public enable_if< - __invokable<_Fp, _Args...>::value, - typename __invokable_r::_Result> - { - }; - - // result_of - - template - class __WI_LIBCPP_TEMPLATE_VIS result_of<_Fp(_Args...)> - : public __invoke_of<_Fp, _Args...> - { - }; - -#if __WI_LIBCPP_STD_VER > 11 - template using result_of_t = typename result_of<_Tp>::type; -#endif - -#if __WI_LIBCPP_STD_VER > 14 - - // invoke_result - - template - struct __WI_LIBCPP_TEMPLATE_VIS invoke_result - : __invoke_of<_Fn, _Args...> - { - }; - - template - using invoke_result_t = typename invoke_result<_Fn, _Args...>::type; - - // is_invocable - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_invocable - : integral_constant::value> {}; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_invocable_r - : integral_constant::value> {}; - - template - __WI_LIBCPP_INLINE_VAR constexpr bool is_invocable_v - = is_invocable<_Fn, _Args...>::value; - - template - __WI_LIBCPP_INLINE_VAR constexpr bool is_invocable_r_v - = is_invocable_r<_Ret, _Fn, _Args...>::value; - - // is_nothrow_invocable - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_invocable - : integral_constant::value> {}; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_invocable_r - : integral_constant::value> {}; - - template - __WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_invocable_v - = is_nothrow_invocable<_Fn, _Args...>::value; - - template - __WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_invocable_r_v - = is_nothrow_invocable_r<_Ret, _Fn, _Args...>::value; - -#endif // __WI_LIBCPP_STD_VER > 14 - -#endif // !defined(__WI_LIBCPP_CXX03_LANG) - - template struct __is_swappable; - template struct __is_nothrow_swappable; - - template - inline __WI_LIBCPP_INLINE_VISIBILITY -#ifndef __WI_LIBCPP_CXX03_LANG - typename enable_if - < - is_move_constructible<_Tp>::value && - is_move_assignable<_Tp>::value - >::type -#else - void -#endif - swap_wil(_Tp& __x, _Tp& __y) __WI_NOEXCEPT_(is_nothrow_move_constructible<_Tp>::value && - is_nothrow_move_assignable<_Tp>::value) - { - _Tp __t(wistd::move(__x)); - __x = wistd::move(__y); - __y = wistd::move(__t); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - _ForwardIterator2 - swap_ranges_wil(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2) - { - for(; __first1 != __last1; ++__first1, (void) ++__first2) - swap_wil(*__first1, *__first2); - return __first2; - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - typename enable_if< - __is_swappable<_Tp>::value - >::type - swap_wil(_Tp (&__a)[_Np], _Tp (&__b)[_Np]) __WI_NOEXCEPT_(__is_nothrow_swappable<_Tp>::value) - { - wistd::swap_ranges_wil(__a, __a + _Np, __b); - } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY - void - iter_swap_wil(_ForwardIterator1 __a, _ForwardIterator2 __b) - // __WI_NOEXCEPT_(__WI_NOEXCEPT_(swap_wil(*__a, *__b))) - __WI_NOEXCEPT_(__WI_NOEXCEPT_(swap_wil(*declval<_ForwardIterator1>(), - *declval<_ForwardIterator2>()))) - { - swap_wil(*__a, *__b); - } - - // __swappable - - namespace __detail - { - // ALL generic swap overloads MUST already have a declaration available at this point. - - template ::value && !is_void<_Up>::value> - struct __swappable_with - { - template - static decltype(swap_wil(declval<_LHS>(), declval<_RHS>())) - __test_swap(int); - template - static __nat __test_swap(long); - - // Extra parens are needed for the C++03 definition of decltype. - typedef decltype((__test_swap<_Tp, _Up>(0))) __swap1; - typedef decltype((__test_swap<_Up, _Tp>(0))) __swap2; - - static const bool value = !is_same<__swap1, __nat>::value - && !is_same<__swap2, __nat>::value; - }; - - template - struct __swappable_with<_Tp, _Up, false> : false_type {}; - - template ::value> - struct __nothrow_swappable_with { - static const bool value = -#ifndef __WI_LIBCPP_HAS_NO_NOEXCEPT - noexcept(swap_wil(declval<_Tp>(), declval<_Up>())) - && noexcept(swap_wil(declval<_Up>(), declval<_Tp>())); -#else - false; -#endif - }; - - template - struct __nothrow_swappable_with<_Tp, _Up, false> : false_type {}; - - } // __detail - - template - struct __is_swappable - : public integral_constant::value> - { - }; - - template - struct __is_nothrow_swappable - : public integral_constant::value> - { - }; - -#if __WI_LIBCPP_STD_VER > 14 - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_swappable_with - : public integral_constant::value> - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_swappable - : public conditional< - __is_referenceable<_Tp>::value, - is_swappable_with< - typename add_lvalue_reference<_Tp>::type, - typename add_lvalue_reference<_Tp>::type>, - false_type - >::type - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_swappable_with - : public integral_constant::value> - { - }; - - template - struct __WI_LIBCPP_TEMPLATE_VIS is_nothrow_swappable - : public conditional< - __is_referenceable<_Tp>::value, - is_nothrow_swappable_with< - typename add_lvalue_reference<_Tp>::type, - typename add_lvalue_reference<_Tp>::type>, - false_type - >::type - { - }; - - template - __WI_LIBCPP_INLINE_VAR constexpr bool is_swappable_with_v - = is_swappable_with<_Tp, _Up>::value; - - template - __WI_LIBCPP_INLINE_VAR constexpr bool is_swappable_v - = is_swappable<_Tp>::value; - - template - __WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_swappable_with_v - = is_nothrow_swappable_with<_Tp, _Up>::value; - - template - __WI_LIBCPP_INLINE_VAR constexpr bool is_nothrow_swappable_v - = is_nothrow_swappable<_Tp>::value; - -#endif // __WI_LIBCPP_STD_VER > 14 - -#ifdef __WI_LIBCPP_UNDERLYING_TYPE - - template - struct underlying_type - { - typedef __WI_LIBCPP_UNDERLYING_TYPE(_Tp) type; - }; - -#if __WI_LIBCPP_STD_VER > 11 - template using underlying_type_t = typename underlying_type<_Tp>::type; -#endif - -#else // __WI_LIBCPP_UNDERLYING_TYPE - - template - struct underlying_type - { - static_assert(_Support, "The underyling_type trait requires compiler " - "support. Either no such support exists or " - "libc++ does not know how to use it."); - }; - -#endif // __WI_LIBCPP_UNDERLYING_TYPE - - - template ::value> - struct __sfinae_underlying_type - { - typedef typename underlying_type<_Tp>::type type; - typedef decltype(((type)1) + 0) __promoted_type; - }; - - template - struct __sfinae_underlying_type<_Tp, false> {}; - - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - int __convert_to_integral(int __val) { return __val; } - - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - unsigned __convert_to_integral(unsigned __val) { return __val; } - - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - long __convert_to_integral(long __val) { return __val; } - - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - unsigned long __convert_to_integral(unsigned long __val) { return __val; } - - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - long long __convert_to_integral(long long __val) { return __val; } - - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - unsigned long long __convert_to_integral(unsigned long long __val) {return __val; } - - template - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - typename enable_if::value, long long>::type - __convert_to_integral(_Fp __val) { return __val; } - -#ifndef __WI_LIBCPP_HAS_NO_INT128 - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - __int128_t __convert_to_integral(__int128_t __val) { return __val; } - - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - __uint128_t __convert_to_integral(__uint128_t __val) { return __val; } -#endif - - template - inline __WI_LIBCPP_INLINE_VISIBILITY __WI_LIBCPP_CONSTEXPR - typename __sfinae_underlying_type<_Tp>::__promoted_type - __convert_to_integral(_Tp __val) { return __val; } - -#ifndef __WI_LIBCPP_CXX03_LANG - - template - struct __has_operator_addressof_member_imp - { - template - static auto __test(int) - -> typename __select_2nd().operator&()), true_type>::type; - template - static auto __test(long) -> false_type; - - static const bool value = decltype(__test<_Tp>(0))::value; - }; - - template - struct __has_operator_addressof_free_imp - { - template - static auto __test(int) - -> typename __select_2nd())), true_type>::type; - template - static auto __test(long) -> false_type; - - static const bool value = decltype(__test<_Tp>(0))::value; - }; - - template - struct __has_operator_addressof - : public integral_constant::value - || __has_operator_addressof_free_imp<_Tp>::value> - {}; - -#endif // __WI_LIBCPP_CXX03_LANG - -#ifndef __WI_LIBCPP_CXX03_LANG - - template using void_t = void; - -# ifndef __WI_LIBCPP_HAS_NO_VARIADICS - template - struct conjunction : __and_<_Args...> {}; - template - __WI_LIBCPP_INLINE_VAR constexpr bool conjunction_v - = conjunction<_Args...>::value; - - template - struct disjunction : __or_<_Args...> {}; - template - __WI_LIBCPP_INLINE_VAR constexpr bool disjunction_v - = disjunction<_Args...>::value; - - template - struct negation : __not_<_Tp> {}; - template - __WI_LIBCPP_INLINE_VAR constexpr bool negation_v - = negation<_Tp>::value; -# endif // __WI_LIBCPP_HAS_NO_VARIADICS -#endif // __WI_LIBCPP_CXX03_LANG - - // These traits are used in __tree and __hash_table -#ifndef __WI_LIBCPP_CXX03_LANG - struct __extract_key_fail_tag {}; - struct __extract_key_self_tag {}; - struct __extract_key_first_tag {}; - - template ::type> - struct __can_extract_key - : conditional::value, __extract_key_self_tag, - __extract_key_fail_tag>::type {}; - - template - struct __can_extract_key<_Pair, _Key, pair<_First, _Second>> - : conditional::type, _Key>::value, - __extract_key_first_tag, __extract_key_fail_tag>::type {}; - - // __can_extract_map_key uses true_type/false_type instead of the tags. - // It returns true if _Key != _ContainerValueTy (the container is a map not a set) - // and _ValTy == _Key. - template ::type> - struct __can_extract_map_key - : integral_constant::value> {}; - - // This specialization returns __extract_key_fail_tag for non-map containers - // because _Key == _ContainerValueTy - template - struct __can_extract_map_key<_ValTy, _Key, _Key, _RawValTy> - : false_type {}; - -#endif - -#if __WI_LIBCPP_STD_VER > 17 - enum class endian - { - little = 0xDEAD, - big = 0xFACE, -#if defined(__WI_LIBCPP_LITTLE_ENDIAN) - native = little -#elif defined(__WI_LIBCPP_BIG_ENDIAN) - native = big -#else - native = 0xCAFE -#endif - }; -#endif -} -/// @endcond - -#endif // _WISTD_TYPE_TRAITS_H_ diff --git a/src/common/dep/wil/wrl.h b/src/common/dep/wil/wrl.h deleted file mode 100644 index 1106cab67..000000000 --- a/src/common/dep/wil/wrl.h +++ /dev/null @@ -1,127 +0,0 @@ -//********************************************************* -// -// Copyright (c) Microsoft. All rights reserved. -// This code is licensed under the MIT License. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF -// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED -// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A -// PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -//********************************************************* -#ifndef __WIL_WRL_INCLUDED -#define __WIL_WRL_INCLUDED - -#include -#include "result.h" -#include "common.h" // wistd type_traits helpers -#include // GetModuleHandleW - -/// @cond -EXTERN_C IMAGE_DOS_HEADER __ImageBase; -/// @endcond - -namespace wil -{ - -#ifdef WIL_ENABLE_EXCEPTIONS -#pragma region Object construction helpers that throw exceptions - - /** Used to construct a RuntimeClass based object that uses 2 phase construction. - Construct a RuntimeClass based object that uses 2 phase construction (by implementing - RuntimeClassInitialize() and returning error codes for failures. - ~~~~ - // SomeClass uses 2 phase initialization by implementing RuntimeClassInitialize() - auto someClass = MakeAndInitializeOrThrow(L"input", true); - ~~~~ */ - - template - Microsoft::WRL::ComPtr MakeAndInitializeOrThrow(TArgs&&... args) - { - Microsoft::WRL::ComPtr obj; - THROW_IF_FAILED(Microsoft::WRL::MakeAndInitialize(&obj, Microsoft::WRL::Details::Forward(args)...)); - return obj; - } - - /** Used to construct an RuntimeClass based object that uses exceptions in its constructor (and does - not require 2 phase construction). - ~~~~ - // SomeClass uses exceptions for error handling in its constructor. - auto someClass = MakeOrThrow(L"input", true); - ~~~~ */ - - template - Microsoft::WRL::ComPtr MakeOrThrow(TArgs&&... args) - { - // This is how you can detect the presence of RuntimeClassInitialize() and find dangerous use. - // Unfortunately this produces false positives as all RuntimeClass derived classes have - // a RuntimeClassInitialize() method from their base class. - // static_assert(!std::is_member_function_pointer::value, - // "class has a RuntimeClassInitialize member, use MakeAndInitializeOrThrow instead"); - auto obj = Microsoft::WRL::Make(Microsoft::WRL::Details::Forward(args)...); - THROW_IF_NULL_ALLOC(obj.Get()); - return obj; - } -#pragma endregion - -#endif // WIL_ENABLE_EXCEPTIONS - - /** By default WRL Callback objects are not agile, use this to make an agile one. Replace use of Callback<> with MakeAgileCallback<>. - Will return null on failure, translate that into E_OUTOFMEMORY using XXX_IF_NULL_ALLOC() - from wil\result.h to test the result. */ - template - ::Microsoft::WRL::ComPtr MakeAgileCallbackNoThrow(Args&&... args) WI_NOEXCEPT - { - using namespace Microsoft::WRL; - return Callback, TDelegateInterface, FtmBase>>(wistd::forward(args)...); - } - -#ifdef WIL_ENABLE_EXCEPTIONS - template - ::Microsoft::WRL::ComPtr MakeAgileCallback(Args&&... args) - { - auto result = MakeAgileCallbackNoThrow(wistd::forward(args)...); - THROW_IF_NULL_ALLOC(result); - return result; - } -#endif // WIL_ENABLE_EXCEPTIONS - - /** Holds a reference to the host WRL module to prevent it from being unloaded. - Normally, the reference is held implicitly because you are a member function - of a DLL-hosted COM object, or because you retain a strong reference - to some DLL-hosted COM object, but if those do not apply to you, then you - will need to hold a reference explicitly. For examples (and for the C++/WinRT - equivalent), see winrt_module_reference. - */ - struct [[nodiscard]] wrl_module_reference - { - wrl_module_reference() - { - if (auto modulePtr = ::Microsoft::WRL::GetModuleBase()) - { - modulePtr->IncrementObjectCount(); - } - else - { -#ifdef GET_MODULE_HANDLE_EX_FLAG_PIN - // If this assertion fails, then you are using wrl_module_reference - // from a DLL that does not host WRL objects, and the module reference - // has no effect. - WI_ASSERT(reinterpret_cast(&__ImageBase) == GetModuleHandleW(nullptr)); -#endif - } - } - - wrl_module_reference(wrl_module_reference const&) : wrl_module_reference() {} - - ~wrl_module_reference() - { - if (auto modulePtr = ::Microsoft::WRL::GetModuleBase()) - { - modulePtr->DecrementObjectCount(); - } - } - }; - -} // namespace wil - -#endif // __WIL_WRL_INCLUDED diff --git a/src/vcpkg.json b/src/vcpkg.json index dbf24b1f0..8c257b672 100644 --- a/src/vcpkg.json +++ b/src/vcpkg.json @@ -1,6 +1,7 @@ { "dependencies": [ "bzip2", + "wil", "zlib" ], "builtin-baseline": "6f29f12e82a8293156836ad81cc9bf5af41fe836" From b4204a6538475638bd7991cccea987321cf5ef24 Mon Sep 17 00:00:00 2001 From: Viliam Lejcik Date: Sat, 15 Mar 2025 13:54:56 +0100 Subject: [PATCH 55/65] moved fmt dependency to vcpkg --- src/common/dep/fmt/ChangeLog.rst | 5922 ------------------------------ src/common/dep/fmt/args.h | 234 -- src/common/dep/fmt/chrono.h | 2208 ----------- src/common/dep/fmt/color.h | 632 ---- src/common/dep/fmt/compile.h | 534 --- src/common/dep/fmt/core.h | 2922 --------------- src/common/dep/fmt/fmt.cc | 110 - src/common/dep/fmt/format-inl.h | 1662 --------- src/common/dep/fmt/format.cc | 43 - src/common/dep/fmt/format.h | 4510 ----------------------- src/common/dep/fmt/os.cc | 398 -- src/common/dep/fmt/os.h | 451 --- src/common/dep/fmt/ostream.h | 209 -- src/common/dep/fmt/printf.h | 667 ---- src/common/dep/fmt/ranges.h | 735 ---- src/common/dep/fmt/std.h | 465 --- src/common/dep/fmt/xchar.h | 258 -- 17 files changed, 21960 deletions(-) delete mode 100644 src/common/dep/fmt/ChangeLog.rst delete mode 100644 src/common/dep/fmt/args.h delete mode 100644 src/common/dep/fmt/chrono.h delete mode 100644 src/common/dep/fmt/color.h delete mode 100644 src/common/dep/fmt/compile.h delete mode 100644 src/common/dep/fmt/core.h delete mode 100644 src/common/dep/fmt/fmt.cc delete mode 100644 src/common/dep/fmt/format-inl.h delete mode 100644 src/common/dep/fmt/format.cc delete mode 100644 src/common/dep/fmt/format.h delete mode 100644 src/common/dep/fmt/os.cc delete mode 100644 src/common/dep/fmt/os.h delete mode 100644 src/common/dep/fmt/ostream.h delete mode 100644 src/common/dep/fmt/printf.h delete mode 100644 src/common/dep/fmt/ranges.h delete mode 100644 src/common/dep/fmt/std.h delete mode 100644 src/common/dep/fmt/xchar.h diff --git a/src/common/dep/fmt/ChangeLog.rst b/src/common/dep/fmt/ChangeLog.rst deleted file mode 100644 index 62fc8a8b0..000000000 --- a/src/common/dep/fmt/ChangeLog.rst +++ /dev/null @@ -1,5922 +0,0 @@ -10.1.1 - 2023-08-28 -------------------- - -* Added formatters for ``std::atomic`` and ``atomic_flag`` - (`#3574 `_, - `#3594 `_). - Thanks `@wangzw (Zhanwei Wang) `_ and - `@AlexGuteniev (Alex Guteniev) `_. - -* Fixed an error about partial specialization of ``formatter`` - after instantiation when compiled with gcc and C++20 - (`#3584 `_). - -* Fixed compilation as a C++20 module with gcc and clang - (`#3587 `_, - `#3597 `_, - `#3605 `_). Thanks - `@MathewBensonCode (Mathew Benson) `_. - -* Made ``fmt::to_string`` work with types that have ``format_as`` overloads - (`#3575 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Made ``formatted_size`` work with integral format specifiers at compile time - (`#3591 `_). - Thanks `@elbeno (Ben Deane) `_. - -* Fixed a warning about the ``no_unique_address`` attribute on clang-cl - (`#3599 `_). - Thanks `@lukester1975 `_. - -* Improved compatibility with the legacy GBK encoding - (`#3598 `_, - `#3599 `_). - Thanks `@YuHuanTin `_. - -* Added OpenSSF Scorecard analysis - (`#3530 `_, - `#3571 `_). - Thanks `@joycebrum (Joyce) `_. - -* Updated CI dependencies - (`#3591 `_, - `#3592 `_, - `#3593 `_, - `#3602 `_). - -10.1.0 - 2023-08-12 -------------------- - -* Optimized format string compilation resulting in up to 40% speed up in - compiled ``format_to`` and ~4x speed up in compiled ``format_to_n`` on a - concatenation benchmark (`#3133 `_, - `#3484 `_). - - {fmt} 10.0:: - - --------------------------------------------------------- - Benchmark Time CPU Iterations - --------------------------------------------------------- - BM_format_to 78.9 ns 78.9 ns 8881746 - BM_format_to_n 568 ns 568 ns 1232089 - - {fmt} 10.1:: - - --------------------------------------------------------- - Benchmark Time CPU Iterations - --------------------------------------------------------- - BM_format_to 54.9 ns 54.9 ns 12727944 - BM_format_to_n 133 ns 133 ns 5257795 - -* Optimized storage of an empty allocator in ``basic_memory_buffer`` - (`#3485 `_). - Thanks `@Minty-Meeo `_. - -* Added formatters for proxy references to elements of ``std::vector`` and - ``std::bitset`` (`#3567 `_, - `#3570 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - #include - - int main() { - auto v = std::vector{true}; - fmt::print("{}", v[0]); - } - - Thanks `@phprus (Vladislav Shchapov) `_ and - `@felix642 (Félix-Antoine Constantin) `_. - -* Fixed an ambiguous formatter specialization for containers that look like - container adaptors such as ``boost::flat_set`` - (`#3556 `_, - `#3561 `_). - Thanks `@5chmidti `_. - -* Fixed compilation when formatting durations not convertible from - ``std::chrono::seconds`` (`#3430 `_). - Thanks `@patlkli (Patrick Geltinger) `_. - -* Made the ``formatter`` specialization for ``char*`` const-correct - (`#3432 `_). - Thanks `@timsong-cpp `_. - -* Made ``{}`` and ``{:}`` handled consistently during compile-time checks - (`#3526 `_). - -* Disallowed passing temporaries to ``make_format_args`` to improve API safety - by preventing dangling references. - -* Improved the compile-time error for unformattable types - (`#3478 `_). - Thanks `@BRevzin (Barry Revzin) `_. - -* Improved the floating-point formatter - (`#3448 `_, - `#3450 `_). - Thanks `@florimond-collette (Florimond Collette) - `_. - -* Fixed handling of precision for ``long double`` larger than 64 bits. - (`#3539 `_, - `#3564 `_). - -* Made floating-point and chrono tests less platform-dependent - (`#3337 `_, - `#3433 `_, - `#3434 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Removed the remnants of the Grisu floating-point formatter that has been - replaced by Dragonbox in earlier versions. - -* Added ``throw_format_error`` to the public API - (`#3551 `_). - Thanks `@mjerabek (Martin Jeřábek) `_. - -* Made ``FMT_THROW`` assert even if assertions are disabled when compiling with - exceptions disabled (`#3418 `_, - `#3439 `_). - Thanks `@BRevzin (Barry Revzin) `_. - -* Made ``format_as`` and ``std::filesystem::path`` formatter work with exotic - code unit types. - (`#3457 `_, - `#3476 `_). - Thanks `@gix (Nico Rieck) `_, - `@hmbj (Hans-Martin B. Jensen) `_. - -* Added support for the ``?`` format specifier to ``std::filesystem::path`` and - made the default unescaped for consistency with strings. - -* Deprecated the wide stream overload of ``printf``. - -* Removed unused ``basic_printf_parse_context``. - -* Improved RTTI detection used when formatting exceptions - (`#3468 `_). - Thanks `@danakj (Dana Jansens) `_. - -* Improved compatibility with VxWorks7 - (`#3467 `_). - Thanks `@wenshan1 (Bin Lan) `_. - -* Improved documentation - (`#3174 `_, - `#3423 `_, - `#3454 `_, - `#3458 `_, - `#3461 `_, - `#3487 `_, - `#3515 `_). - Thanks `@zencatalyst (Kasra Hashemi) `_, - `@rlalik `_, - `@mikecrowe (Mike Crowe) `_. - -* Improved build and CI configurations - (`#3449 `_, - `#3451 `_, - `#3452 `_, - `#3453 `_, - `#3459 `_, - `#3481 `_, - `#3486 `_, - `#3489 `_, - `#3496 `_, - `#3517 `_, - `#3523 `_, - `#3563 `_). - Thanks `@joycebrum (Joyce) `_, - `@glebm (Gleb Mazovetskiy) `_, - `@phprus (Vladislav Shchapov) `_, - `@petrmanek (Petr Mánek) `_, - `@setoye (Alta) `_, - `@abouvier (Alexandre Bouvier) `_. - -* Fixed various warnings and compilation issues - (`#3408 `_, - `#3424 `_, - `#3444 `_, - `#3446 `_, - `#3475 `_, - `#3482 `_, - `#3492 `_, - `#3493 `_, - `#3508 `_, - `#3509 `_, - `#3533 `_, - `#3542 `_, - `#3543 `_, - `#3540 `_, - `#3544 `_, - `#3548 `_, - `#3549 `_, - `#3550 `_, - `#3552 `_). - Thanks `@adesitter (Arnaud Desitter) `_, - `@hmbj (Hans-Martin B. Jensen) `_, - `@Minty-Meeo `_, - `@phprus (Vladislav Shchapov) `_, - `@TobiSchluter (Tobias Schlüter) `_, - `@kieranclancy (Kieran Clancy) `_, - `@alexeedm (Dmitry Alexeev) `_, - `@jurihock (Jürgen Hock) `_, - `@Ozomahtli `_, - `@razaqq `_. - -10.0.0 - 2023-05-09 -------------------- - -* Replaced Grisu with a new floating-point formatting algorithm for given - precision (`#3262 `_, - `#2750 `_, - `#3269 `_, - `#3276 `_). - The new algorithm is based on Dragonbox already used for the - shortest representation and gives substantial performance improvement: - - .. image:: https://user-images.githubusercontent.com/33922675/ - 211956670-84891a09-6867-47d9-82fc-3230da7abe0f.png - - * Red: new algorithm - * Green: new algorithm with ``FMT_USE_FULL_CACHE_DRAGONBOX`` defined to 1 - * Blue: old algorithm - - Thanks `@jk-jeon (Junekey Jeon) `_. - -* Replaced ``snprintf``-based hex float formatter with an internal - implementation (`#3179 `_, - `#3203 `_). - This removes the last usage of ``s(n)printf`` in {fmt}. - Thanks `@phprus (Vladislav Shchapov) `_. - -* Fixed alignment of floating-point numbers with localization - (`#3263 `_, - `#3272 `_). - Thanks `@ShawnZhong (Shawn Zhong) `_. - -* Made handling of ``#`` consistent with ``std::format``. - -* Improved C++20 module support - (`#3134 `_, - `#3254 `_, - `#3386 `_, - `#3387 `_, - `#3388 `_, - `#3392 `_, - `#3397 `_, - `#3399 `_, - `#3400 `_). - Thanks `@laitingsheng (Tinson Lai) `_, - `@Orvid (Orvid King) `_, - `@DanielaE (Daniela Engert) `_. - Switched to the `modules CMake library `_ - which allows building {fmt} as a C++20 module with clang:: - - CXX=clang++ cmake -DFMT_MODULE=ON . - make - -* Made ``format_as`` work with any user-defined type and not just enums. - For example (`godbolt `__): - - .. code:: c++ - - #include - - struct floaty_mc_floatface { - double value; - }; - - auto format_as(floaty_mc_floatface f) { return f.value; } - - int main() { - fmt::print("{:8}\n", floaty_mc_floatface{0.42}); // prints " 0.42" - } - -* Removed deprecated implicit conversions for enums and conversions to primitive - types for compatibility with ``std::format`` and to prevent potential ODR - violations. Use ``format_as`` instead. - -* Added support for fill, align and width to the time point formatter - (`#3237 `_, - `#3260 `_, - `#3275 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - // prints " 2023" - fmt::print("{:>8%Y}\n", std::chrono::system_clock::now()); - } - - Thanks `@ShawnZhong (Shawn Zhong) `_. - -* Implemented formatting of subseconds - (`#2207 `_, - `#3117 `_, - `#3115 `_, - `#3143 `_, - `#3144 `_, - `#3349 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - // prints 01.234567 - fmt::print("{:%S}\n", std::chrono::microseconds(1234567)); - } - - Thanks `@patrickroocks (Patrick Roocks) `_ - `@phprus (Vladislav Shchapov) `_, - `@BRevzin (Barry Revzin) `_. - -* Added precision support to ``%S`` - (`#3148 `_). - Thanks `@SappyJoy (Stepan Ponomaryov) `_ - -* Added support for ``std::utc_time`` - (`#3098 `_, - `#3110 `_). - Thanks `@patrickroocks (Patrick Roocks) `_. - -* Switched formatting of ``std::chrono::system_clock`` from local time to UTC - for compatibility with the standard - (`#3199 `_, - `#3230 `_). - Thanks `@ned14 (Niall Douglas) `_. - -* Added support for ``%Ez`` and ``%Oz`` to chrono formatters. - (`#3220 `_, - `#3222 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Improved validation of format specifiers for ``std::chrono::duration`` - (`#3219 `_, - `#3232 `_). - Thanks `@ShawnZhong (Shawn Zhong) `_. - -* Fixed formatting of time points before the epoch - (`#3117 `_, - `#3261 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - auto t = std::chrono::system_clock::from_time_t(0) - - std::chrono::milliseconds(250); - fmt::print("{:%S}\n", t); // prints 59.750000000 - } - - Thanks `@ShawnZhong (Shawn Zhong) `_. - -* Experimental: implemented glibc extension for padding seconds, minutes and - hours (`#2959 `_, - `#3271 `_). - Thanks `@ShawnZhong (Shawn Zhong) `_. - -* Added a formatter for ``std::exception`` - (`#2977 `_, - `#3012 `_, - `#3062 `_, - `#3076 `_, - `#3119 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - #include - - int main() { - try { - std::vector().at(0); - } catch(const std::exception& e) { - fmt::print("{}", e); - } - } - - prints:: - - vector::_M_range_check: __n (which is 0) >= this->size() (which is 0) - - on libstdc++. - Thanks `@zach2good (Zach Toogood) `_ and - `@phprus (Vladislav Shchapov) `_. - -* Moved ``std::error_code`` formatter from ``fmt/os.h`` to ``fmt/std.h``. - (`#3125 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Added formatters for standard container adapters: ``std::priority_queue``, - ``std::queue`` and ``std::stack`` - (`#3215 `_, - `#3279 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - #include - #include - - int main() { - auto s = std::stack>(); - for (auto b: {true, false, true}) s.push(b); - fmt::print("{}\n", s); // prints [true, false, true] - } - - Thanks `@ShawnZhong (Shawn Zhong) `_. - -* Added a formatter for ``std::optional`` to ``fmt/std.h``. - Thanks `@tom-huntington `_. - -* Fixed formatting of valueless by exception variants - (`#3347 `_). - Thanks `@TheOmegaCarrot `_. - -* Made ``fmt::ptr`` accept ``unique_ptr`` with a custom deleter - (`#3177 `_). - Thanks `@hmbj (Hans-Martin B. Jensen) `_. - -* Fixed formatting of noncopyable ranges and nested ranges of chars - (`#3158 `_ - `#3286 `_, - `#3290 `_). - Thanks `@BRevzin (Barry Revzin) `_. - -* Fixed issues with formatting of paths and ranges of paths - (`#3319 `_, - `#3321 `_ - `#3322 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Improved handling of invalid Unicode in paths. - -* Enabled compile-time checks on Apple clang 14 and later - (`#3331 `_). - Thanks `@cloyce (Cloyce D. Spradling) `_. - -* Improved compile-time checks of named arguments - (`#3105 `_, - `#3214 `_). - Thanks `@rbrich (Radek Brich) `_. - -* Fixed formatting when both alignment and ``0`` are given - (`#3236 `_, - `#3248 `_). - Thanks `@ShawnZhong (Shawn Zhong) `_. - -* Improved Unicode support in the experimental file API on Windows - (`#3234 `_, - `#3293 `_). - Thanks `@Fros1er (Froster) `_. - -* Unified UTF transcoding - (`#3416 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Added support for UTF-8 digit separators via an experimental locale facet - (`#1861 `_). - For example (`godbolt `__): - - .. code:: c++ - - auto loc = std::locale( - std::locale(), new fmt::format_facet("’")); - auto s = fmt::format(loc, "{:L}", 1000); - - where ``’`` is U+2019 used as a digit separator in the de_CH locale. - -* Added an overload of ``formatted_size`` that takes a locale - (`#3084 `_, - `#3087 `_). - Thanks `@gerboengels `_. - -* Removed the deprecated ``FMT_DEPRECATED_OSTREAM``. - -* Fixed a UB when using a null ``std::string_view`` with ``fmt::to_string`` - or format string compilation - (`#3241 `_, - `#3244 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Added ``starts_with`` to the fallback ``string_view`` implementation - (`#3080 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Added ``fmt::basic_format_string::get()`` for compatibility with - ``basic_format_string`` (`#3111 `_). - Thanks `@huangqinjin `_. - -* Added ``println`` for compatibility with C++23 - (`#3267 `_). - Thanks `@ShawnZhong (Shawn Zhong) `_. - -* Renamed the ``FMT_EXPORT`` macro for shared library usage to - ``FMT_LIB_EXPORT``. - -* Improved documentation - (`#3108 `_, - `#3169 `_, - `#3243 `_). - `#3404 `_). - Thanks `@Cleroth `_ and - `@Vertexwahn `_. - -* Improved build configuration and tests - (`#3118 `_, - `#3120 `_, - `#3188 `_, - `#3189 `_, - `#3198 `_, - `#3205 `_, - `#3207 `_, - `#3210 `_, - `#3240 `_, - `#3256 `_, - `#3264 `_, - `#3299 `_, - `#3302 `_, - `#3312 `_, - `#3317 `_, - `#3328 `_, - `#3333 `_, - `#3369 `_, - `#3373 `_, - `#3395 `_, - `#3406 `_, - `#3411 `_). - Thanks `@dimztimz (Dimitrij Mijoski) `_, - `@phprus (Vladislav Shchapov) `_, - `@DavidKorczynski `_, - `@ChrisThrasher (Chris Thrasher) `_, - `@FrancoisCarouge (François Carouge) `_, - `@kennyweiss (Kenny Weiss) `_, - `@luzpaz `_, - `@codeinred (Alecto Irene Perez) `_, - `@Mixaill (Mikhail Paulyshka) `_, - `@joycebrum (Joyce) `_, - `@kevinhwang (Kevin Hwang) `_, - `@Vertexwahn `_. - -* Fixed a regression in handling empty format specifiers after a colon (``{:}``) - (`#3086 `_). - Thanks `@oxidase (Michael Krasnyk) `_. - -* Worked around a broken implementation of ``std::is_constant_evaluated`` in - some versions of libstdc++ on clang - (`#3247 `_, - `#3281 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Fixed formatting of volatile variables - (`#3068 `_). - -* Fixed various warnings and compilation issues - (`#3057 `_, - `#3066 `_, - `#3072 `_, - `#3082 `_, - `#3091 `_, - `#3092 `_, - `#3093 `_, - `#3095 `_, - `#3096 `_, - `#3097 `_, - `#3128 `_, - `#3129 `_, - `#3137 `_, - `#3139 `_, - `#3140 `_, - `#3142 `_, - `#3149 `_, - `#3150 `_, - `#3154 `_, - `#3163 `_, - `#3178 `_, - `#3184 `_, - `#3196 `_, - `#3204 `_, - `#3206 `_, - `#3208 `_, - `#3213 `_, - `#3216 `_, - `#3224 `_, - `#3226 `_, - `#3228 `_, - `#3229 `_, - `#3259 `_, - `#3274 `_, - `#3287 `_, - `#3288 `_, - `#3292 `_, - `#3295 `_, - `#3296 `_, - `#3298 `_, - `#3325 `_, - `#3326 `_, - `#3334 `_, - `#3342 `_, - `#3343 `_, - `#3351 `_, - `#3352 `_, - `#3362 `_, - `#3365 `_, - `#3366 `_, - `#3374 `_, - `#3377 `_, - `#3378 `_, - `#3381 `_, - `#3398 `_, - `#3413 `_, - `#3415 `_). - Thanks `@phprus (Vladislav Shchapov) `_, - `@gsjaardema (Greg Sjaardema) `_, - `@NewbieOrange `_, - `@EngineLessCC (VivyaCC) `_, - `@asmaloney (Andy Maloney) `_, - `@HazardyKnusperkeks (Björn Schäpers) - `_, - `@sergiud (Sergiu Deitsch) `_, - `@Youw (Ihor Dutchak) `_, - `@thesmurph `_, - `@czudziakm (Maksymilian Czudziak) `_, - `@Roman-Koshelev `_, - `@chronoxor (Ivan Shynkarenka) `_, - `@ShawnZhong (Shawn Zhong) `_, - `@russelltg (Russell Greene) `_, - `@glebm (Gleb Mazovetskiy) `_, - `@tmartin-gh `_, - `@Zhaojun-Liu (June Liu) `_, - `@louiswins (Louis Wilson) `_, - `@mogemimi `_. - -9.1.0 - 2022-08-27 ------------------- - -* ``fmt::formatted_size`` now works at compile time - (`#3026 `_). For example - (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - using namespace fmt::literals; - constexpr size_t n = fmt::formatted_size("{}"_cf, 42); - fmt::print("{}\n", n); // prints 2 - } - - Thanks `@marksantaniello (Mark Santaniello) - `_. - -* Fixed handling of invalid UTF-8 - (`#3038 `_, - `#3044 `_, - `#3056 `_). - Thanks `@phprus (Vladislav Shchapov) `_ and - `@skeeto (Christopher Wellons) `_. - -* Improved Unicode support in ``ostream`` overloads of ``print`` - (`#2994 `_, - `#3001 `_, - `#3025 `_). - Thanks `@dimztimz (Dimitrij Mijoski) `_. - -* Fixed handling of the sign specifier in localized formatting on systems with - 32-bit ``wchar_t`` (`#3041 `_). - -* Added support for wide streams to ``fmt::streamed`` - (`#2994 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Added the ``n`` specifier that disables the output of delimiters when - formatting ranges (`#2981 `_, - `#2983 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - #include - - int main() { - auto v = std::vector{1, 2, 3}; - fmt::print("{:n}\n", v); // prints 1, 2, 3 - } - - Thanks `@BRevzin (Barry Revzin) `_. - -* Worked around problematic ``std::string_view`` constructors introduced in - C++23 (`#3030 `_, - `#3050 `_). - Thanks `@strega-nil-ms (nicole mazzuca) `_. - -* Improve handling (exclusion) of recursive ranges - (`#2968 `_, - `#2974 `_). - Thanks `@Dani-Hub (Daniel Krügler) `_. - -* Improved error reporting in format string compilation - (`#3055 `_). - -* Improved the implementation of - `Dragonbox `_, the algorithm used for - the default floating-point formatting - (`#2984 `_). - Thanks `@jk-jeon (Junekey Jeon) `_. - -* Fixed issues with floating-point formatting on exotic platforms. - -* Improved the implementation of chrono formatting - (`#3010 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Improved documentation - (`#2966 `_, - `#3009 `_, - `#3020 `_, - `#3037 `_). - Thanks `@mwinterb `_, - `@jcelerier (Jean-Michaël Celerier) `_ - and `@remiburtin (Rémi Burtin) `_. - -* Improved build configuration - (`#2991 `_, - `#2995 `_, - `#3004 `_, - `#3007 `_, - `#3040 `_). - Thanks `@dimztimz (Dimitrij Mijoski) `_ and - `@hwhsu1231 (Haowei Hsu) `_. - -* Fixed various warnings and compilation issues - (`#2969 `_, - `#2971 `_, - `#2975 `_, - `#2982 `_, - `#2985 `_, - `#2988 `_, - `#2989 `_, - `#3000 `_, - `#3006 `_, - `#3014 `_, - `#3015 `_, - `#3021 `_, - `#3023 `_, - `#3024 `_, - `#3029 `_, - `#3043 `_, - `#3052 `_, - `#3053 `_, - `#3054 `_). - Thanks `@h-friederich (Hannes Friederich) `_, - `@dimztimz (Dimitrij Mijoski) `_, - `@olupton (Olli Lupton) `_, - `@bernhardmgruber (Bernhard Manfred Gruber) - `_, - `@phprus (Vladislav Shchapov) `_. - -9.0.0 - 2022-07-04 ------------------- - -* Switched to the internal floating point formatter for all decimal presentation - formats. In particular this results in consistent rounding on all platforms - and removing the ``s[n]printf`` fallback for decimal FP formatting. - -* Compile-time floating point formatting no longer requires the header-only - mode. For example (`godbolt `__): - - .. code:: c++ - - #include - #include - - consteval auto compile_time_dtoa(double value) -> std::array { - auto result = std::array(); - fmt::format_to(result.data(), FMT_COMPILE("{}"), value); - return result; - } - - constexpr auto answer = compile_time_dtoa(0.42); - - works with the default settings. - -* Improved the implementation of - `Dragonbox `_, the algorithm used for - the default floating-point formatting - (`#2713 `_, - `#2750 `_). - Thanks `@jk-jeon (Junekey Jeon) `_. - -* Made ``fmt::to_string`` work with ``__float128``. This uses the internal - FP formatter and works even on system without ``__float128`` support in - ``[s]printf``. - -* Disabled automatic ``std::ostream`` insertion operator (``operator<<``) - discovery when ``fmt/ostream.h`` is included to prevent ODR violations. - You can get the old behavior by defining ``FMT_DEPRECATED_OSTREAM`` but this - will be removed in the next major release. Use ``fmt::streamed`` or - ``fmt::ostream_formatter`` to enable formatting via ``std::ostream`` instead. - -* Added ``fmt::ostream_formatter`` that can be used to write ``formatter`` - specializations that perform formatting via ``std::ostream``. - For example (`godbolt `__): - - .. code:: c++ - - #include - - struct date { - int year, month, day; - - friend std::ostream& operator<<(std::ostream& os, const date& d) { - return os << d.year << '-' << d.month << '-' << d.day; - } - }; - - template <> struct fmt::formatter : ostream_formatter {}; - - std::string s = fmt::format("The date is {}", date{2012, 12, 9}); - // s == "The date is 2012-12-9" - -* Added the ``fmt::streamed`` function that takes an object and formats it - via ``std::ostream``. - For example (`godbolt `__): - - .. code:: c++ - - #include - #include - - int main() { - fmt::print("Current thread id: {}\n", - fmt::streamed(std::this_thread::get_id())); - } - - Note that ``fmt/std.h`` provides a ``formatter`` specialization for - ``std::thread::id`` so you don't need to format it via ``std::ostream``. - -* Deprecated implicit conversions of unscoped enums to integers for consistency - with scoped enums. - -* Added an argument-dependent lookup based ``format_as`` extension API to - simplify formatting of enums. - -* Added experimental ``std::variant`` formatting support - (`#2941 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - #include - - int main() { - auto v = std::variant(42); - fmt::print("{}\n", v); - } - - prints:: - - variant(42) - - Thanks `@jehelset `_. - -* Added experimental ``std::filesystem::path`` formatting support - (`#2865 `_, - `#2902 `_, - `#2917 `_, - `#2918 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - #include - - int main() { - fmt::print("There is no place like {}.", std::filesystem::path("/home")); - } - - prints:: - - There is no place like "/home". - - Thanks `@phprus (Vladislav Shchapov) `_. - -* Added a ``std::thread::id`` formatter to ``fmt/std.h``. - For example (`godbolt `__): - - .. code:: c++ - - #include - #include - - int main() { - fmt::print("Current thread id: {}\n", std::this_thread::get_id()); - } - -* Added ``fmt::styled`` that applies a text style to an individual argument - (`#2793 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - #include - - int main() { - auto now = std::chrono::system_clock::now(); - fmt::print( - "[{}] {}: {}\n", - fmt::styled(now, fmt::emphasis::bold), - fmt::styled("error", fg(fmt::color::red)), - "something went wrong"); - } - - prints - - .. image:: https://user-images.githubusercontent.com/576385/ - 175071215-12809244-dab0-4005-96d8-7cd911c964d5.png - - Thanks `@rbrugo (Riccardo Brugo) `_. - -* Made ``fmt::print`` overload for text styles correctly handle UTF-8 - (`#2681 `_, - `#2701 `_). - Thanks `@AlexGuteniev (Alex Guteniev) `_. - -* Fixed Unicode handling when writing to an ostream. - -* Added support for nested specifiers to range formatting - (`#2673 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - #include - - int main() { - fmt::print("{::#x}\n", std::vector{10, 20, 30}); - } - - prints ``[0xa, 0x14, 0x1e]``. - - Thanks `@BRevzin (Barry Revzin) `_. - -* Implemented escaping of wide strings in ranges - (`#2904 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Added support for ranges with ``begin`` / ``end`` found via the - argument-dependent lookup - (`#2807 `_). - Thanks `@rbrugo (Riccardo Brugo) `_. - -* Fixed formatting of certain kinds of ranges of ranges - (`#2787 `_). - Thanks `@BRevzin (Barry Revzin) `_. - -* Fixed handling of maps with element types other than ``std::pair`` - (`#2944 `_). - Thanks `@BrukerJWD (Jonathan W) `_. - -* Made tuple formatter enabled only if elements are formattable - (`#2939 `_, - `#2940 `_). - Thanks `@jehelset `_. - -* Made ``fmt::join`` compatible with format string compilation - (`#2719 `_, - `#2720 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Made compile-time checks work with named arguments of custom types and - ``std::ostream`` ``print`` overloads - (`#2816 `_, - `#2817 `_, - `#2819 `_). - Thanks `@timsong-cpp `_. - -* Removed ``make_args_checked`` because it is no longer needed for compile-time - checks (`#2760 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Removed the following deprecated APIs: ``_format``, ``arg_join``, - the ``format_to`` overload that takes a memory buffer, - ``[v]fprintf`` that takes an ``ostream``. - -* Removed the deprecated implicit conversion of ``[const] signed char*`` and - ``[const] unsigned char*`` to C strings. - -* Removed the deprecated ``fmt/locale.h``. - -* Replaced the deprecated ``fileno()`` with ``descriptor()`` in - ``buffered_file``. - -* Moved ``to_string_view`` to the ``detail`` namespace since it's an - implementation detail. - -* Made access mode of a created file consistent with ``fopen`` by setting - ``S_IWGRP`` and ``S_IWOTH`` - (`#2733 `_). - Thanks `@arogge (Andreas Rogge) `_. - -* Removed a redundant buffer resize when formatting to ``std::ostream`` - (`#2842 `_, - `#2843 `_). - Thanks `@jcelerier (Jean-Michaël Celerier) `_. - -* Made precision computation for strings consistent with width - (`#2888 `_). - -* Fixed handling of locale separators in floating point formatting - (`#2830 `_). - -* Made sign specifiers work with ``__int128_t`` - (`#2773 `_). - -* Improved support for systems such as CHERI with extra data stored in pointers - (`#2932 `_). - Thanks `@davidchisnall (David Chisnall) `_. - -* Improved documentation - (`#2706 `_, - `#2712 `_, - `#2789 `_, - `#2803 `_, - `#2805 `_, - `#2815 `_, - `#2924 `_). - Thanks `@BRevzin (Barry Revzin) `_, - `@Pokechu22 `_, - `@setoye (Alta) `_, - `@rtobar `_, - `@rbrugo (Riccardo Brugo) `_, - `@anoonD (cre) `_, - `@leha-bot (Alex) `_. - -* Improved build configuration - (`#2766 `_, - `#2772 `_, - `#2836 `_, - `#2852 `_, - `#2907 `_, - `#2913 `_, - `#2914 `_). - Thanks `@kambala-decapitator (Andrey Filipenkov) - `_, - `@mattiasljungstrom (Mattias Ljungström) - `_, - `@kieselnb (Nick Kiesel) `_, - `@nathannaveen `_, - `@Vertexwahn `_. - -* Fixed various warnings and compilation issues - (`#2408 `_, - `#2507 `_, - `#2697 `_, - `#2715 `_, - `#2717 `_, - `#2722 `_, - `#2724 `_, - `#2725 `_, - `#2726 `_, - `#2728 `_, - `#2732 `_, - `#2738 `_, - `#2742 `_, - `#2744 `_, - `#2745 `_, - `#2746 `_, - `#2754 `_, - `#2755 `_, - `#2757 `_, - `#2758 `_, - `#2761 `_, - `#2762 `_, - `#2763 `_, - `#2765 `_, - `#2769 `_, - `#2770 `_, - `#2771 `_, - `#2777 `_, - `#2779 `_, - `#2782 `_, - `#2783 `_, - `#2794 `_, - `#2796 `_, - `#2797 `_, - `#2801 `_, - `#2802 `_, - `#2808 `_, - `#2818 `_, - `#2819 `_, - `#2829 `_, - `#2835 `_, - `#2848 `_, - `#2860 `_, - `#2861 `_, - `#2882 `_, - `#2886 `_, - `#2891 `_, - `#2892 `_, - `#2895 `_, - `#2896 `_, - `#2903 `_, - `#2906 `_, - `#2908 `_, - `#2909 `_, - `#2920 `_, - `#2922 `_, - `#2927 `_, - `#2929 `_, - `#2936 `_, - `#2937 `_, - `#2938 `_, - `#2951 `_, - `#2954 `_, - `#2957 `_, - `#2958 `_, - `#2960 `_). - Thanks `@matrackif `_ - `@Tobi823 (Tobias Hellmann) `_, - `@ivan-volnov (Ivan Volnov) `_, - `@VasiliPupkin256 `_, - `@federico-busato (Federico) `_, - `@barcharcraz (Charlie Barto) `_, - `@jk-jeon (Junekey Jeon) `_, - `@HazardyKnusperkeks (Björn Schäpers) - `_, - `@dalboris (Boris Dalstein) `_, - `@seanm (Sean McBride) `_, - `@gsjaardema (Greg Sjaardema) `_, - `@timsong-cpp `_, - `@seanm (Sean McBride) `_, - `@frithrah `_, - `@chronoxor (Ivan Shynkarenka) `_, - `@Agga `_, - `@madmaxoft (Mattes D) `_, - `@JurajX (Juraj) `_, - `@phprus (Vladislav Shchapov) `_, - `@Dani-Hub (Daniel Krügler) `_. - -8.1.1 - 2022-01-06 ------------------- - -* Restored ABI compatibility with version 8.0.x - (`#2695 `_, - `#2696 `_). - Thanks `@saraedum (Julian Rüth) `_. - -* Fixed chrono formatting on big endian systems - (`#2698 `_, - `#2699 `_). - Thanks `@phprus (Vladislav Shchapov) `_ and - `@xvitaly (Vitaly Zaitsev) `_. - -* Fixed a linkage error with mingw - (`#2691 `_, - `#2692 `_). - Thanks `@rbberger (Richard Berger) `_. - -8.1.0 - 2022-01-02 ------------------- - -* Optimized chrono formatting - (`#2500 `_, - `#2537 `_, - `#2541 `_, - `#2544 `_, - `#2550 `_, - `#2551 `_, - `#2576 `_, - `#2577 `_, - `#2586 `_, - `#2591 `_, - `#2594 `_, - `#2602 `_, - `#2617 `_, - `#2628 `_, - `#2633 `_, - `#2670 `_, - `#2671 `_). - - Processing of some specifiers such as ``%z`` and ``%Y`` is now up to 10-20 - times faster, for example on GCC 11 with libstdc++:: - - ---------------------------------------------------------------------------- - Benchmark Before After - ---------------------------------------------------------------------------- - FMTFormatter_z 261 ns 26.3 ns - FMTFormatterCompile_z 246 ns 11.6 ns - FMTFormatter_Y 263 ns 26.1 ns - FMTFormatterCompile_Y 244 ns 10.5 ns - ---------------------------------------------------------------------------- - - Thanks `@phprus (Vladislav Shchapov) `_ and - `@toughengineer (Pavel Novikov) `_. - -* Implemented subsecond formatting for chrono durations - (`#2623 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - fmt::print("{:%S}", std::chrono::milliseconds(1234)); - } - - prints "01.234". - - Thanks `@matrackif `_. - -* Fixed handling of precision 0 when formatting chrono durations - (`#2587 `_, - `#2588 `_). - Thanks `@lukester1975 `_. - -* Fixed an overflow on invalid inputs in the ``tm`` formatter - (`#2564 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Added ``fmt::group_digits`` that formats integers with a non-localized digit - separator (comma) for groups of three digits. - For example (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - fmt::print("{} dollars", fmt::group_digits(1000000)); - } - - prints "1,000,000 dollars". - -* Added support for faint, conceal, reverse and blink text styles - (`#2394 `_): - - https://user-images.githubusercontent.com/576385/147710227-c68f5317-f8fa-42c3-9123-7c4ba3c398cb.mp4 - - Thanks `@benit8 (Benoît Lormeau) `_ and - `@data-man (Dmitry Atamanov) `_. - -* Added experimental support for compile-time floating point formatting - (`#2426 `_, - `#2470 `_). - It is currently limited to the header-only mode. - Thanks `@alexezeder (Alexey Ochapov) `_. - -* Added UDL-based named argument support to compile-time format string checks - (`#2640 `_, - `#2649 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - using namespace fmt::literals; - fmt::print("{answer:s}", "answer"_a=42); - } - - gives a compile-time error on compilers with C++20 ``consteval`` and non-type - template parameter support (gcc 10+) because ``s`` is not a valid format - specifier for an integer. - - Thanks `@alexezeder (Alexey Ochapov) `_. - -* Implemented escaping of string range elements. - For example (`godbolt `__): - - .. code:: c++ - - #include - #include - - int main() { - fmt::print("{}", std::vector{"\naan"}); - } - - is now printed as:: - - ["\naan"] - - instead of:: - - [" - aan"] - -* Added an experimental ``?`` specifier for escaping strings. - (`#2674 `_). - Thanks `@BRevzin (Barry Revzin) `_. - -* Switched to JSON-like representation of maps and sets for consistency with - Python's ``str.format``. - For example (`godbolt `__): - - .. code:: c++ - - #include - #include - - int main() { - fmt::print("{}", std::map{{"answer", 42}}); - } - - is now printed as:: - - {"answer": 42} - -* Extended ``fmt::join`` to support C++20-only ranges - (`#2549 `_). - Thanks `@BRevzin (Barry Revzin) `_. - -* Optimized handling of non-const-iterable ranges and implemented initial - support for non-const-formattable types. - -* Disabled implicit conversions of scoped enums to integers that was - accidentally introduced in earlier versions - (`#1841 `_). - -* Deprecated implicit conversion of ``[const] signed char*`` and - ``[const] unsigned char*`` to C strings. - -* Deprecated ``_format``, a legacy UDL-based format API - (`#2646 `_). - Thanks `@alexezeder (Alexey Ochapov) `_. - -* Marked ``format``, ``formatted_size`` and ``to_string`` as ``[[nodiscard]]`` - (`#2612 `_). - `@0x8000-0000 (Florin Iucha) `_. - -* Added missing diagnostic when trying to format function and member pointers - as well as objects convertible to pointers which is explicitly disallowed - (`#2598 `_, - `#2609 `_, - `#2610 `_). - Thanks `@AlexGuteniev (Alex Guteniev) `_. - -* Optimized writing to a contiguous buffer with ``format_to_n`` - (`#2489 `_). - Thanks `@Roman-Koshelev `_. - -* Optimized writing to non-``char`` buffers - (`#2477 `_). - Thanks `@Roman-Koshelev `_. - -* Decimal point is now localized when using the ``L`` specifier. - -* Improved floating point formatter implementation - (`#2498 `_, - `#2499 `_). - Thanks `@Roman-Koshelev `_. - -* Fixed handling of very large precision in fixed format - (`#2616 `_). - -* Made a table of cached powers used in FP formatting static - (`#2509 `_). - Thanks `@jk-jeon (Junekey Jeon) `_. - -* Resolved a lookup ambiguity with C++20 format-related functions due to ADL - (`#2639 `_, - `#2641 `_). - Thanks `@mkurdej (Marek Kurdej) `_. - -* Removed unnecessary inline namespace qualification - (`#2642 `_, - `#2643 `_). - Thanks `@mkurdej (Marek Kurdej) `_. - -* Implemented argument forwarding in ``format_to_n`` - (`#2462 `_, - `#2463 `_). - Thanks `@owent (WenTao Ou) `_. - -* Fixed handling of implicit conversions in ``fmt::to_string`` and format string - compilation (`#2565 `_). - -* Changed the default access mode of files created by ``fmt::output_file`` to - ``-rw-r--r--`` for consistency with ``fopen`` - (`#2530 `_). - -* Make ``fmt::ostream::flush`` public - (`#2435 `_). - -* Improved C++14/17 attribute detection - (`#2615 `_). - Thanks `@AlexGuteniev (Alex Guteniev) `_. - -* Improved ``consteval`` detection for MSVC - (`#2559 `_). - Thanks `@DanielaE (Daniela Engert) `_. - -* Improved documentation - (`#2406 `_, - `#2446 `_, - `#2493 `_, - `#2513 `_, - `#2515 `_, - `#2522 `_, - `#2562 `_, - `#2575 `_, - `#2606 `_, - `#2620 `_, - `#2676 `_). - Thanks `@sobolevn (Nikita Sobolev) `_, - `@UnePierre (Max FERGER) `_, - `@zhsj `_, - `@phprus (Vladislav Shchapov) `_, - `@ericcurtin (Eric Curtin) `_, - `@Lounarok `_. - -* Improved fuzzers and added a fuzzer for chrono timepoint formatting - (`#2461 `_, - `#2469 `_). - `@pauldreik (Paul Dreik) `_, - -* Added the ``FMT_SYSTEM_HEADERS`` CMake option setting which marks {fmt}'s - headers as system. It can be used to suppress warnings - (`#2644 `_, - `#2651 `_). - Thanks `@alexezeder (Alexey Ochapov) `_. - -* Added the Bazel build system support - (`#2505 `_, - `#2516 `_). - Thanks `@Vertexwahn `_. - -* Improved build configuration and tests - (`#2437 `_, - `#2558 `_, - `#2648 `_, - `#2650 `_, - `#2663 `_, - `#2677 `_). - Thanks `@DanielaE (Daniela Engert) `_, - `@alexezeder (Alexey Ochapov) `_, - `@phprus (Vladislav Shchapov) `_. - -* Fixed various warnings and compilation issues - (`#2353 `_, - `#2356 `_, - `#2399 `_, - `#2408 `_, - `#2414 `_, - `#2427 `_, - `#2432 `_, - `#2442 `_, - `#2434 `_, - `#2439 `_, - `#2447 `_, - `#2450 `_, - `#2455 `_, - `#2465 `_, - `#2472 `_, - `#2474 `_, - `#2476 `_, - `#2478 `_, - `#2479 `_, - `#2481 `_, - `#2482 `_, - `#2483 `_, - `#2490 `_, - `#2491 `_, - `#2510 `_, - `#2518 `_, - `#2528 `_, - `#2529 `_, - `#2539 `_, - `#2540 `_, - `#2545 `_, - `#2555 `_, - `#2557 `_, - `#2570 `_, - `#2573 `_, - `#2582 `_, - `#2605 `_, - `#2611 `_, - `#2647 `_, - `#2627 `_, - `#2630 `_, - `#2635 `_, - `#2638 `_, - `#2653 `_, - `#2654 `_, - `#2661 `_, - `#2664 `_, - `#2684 `_). - Thanks `@DanielaE (Daniela Engert) `_, - `@mwinterb `_, - `@cdacamar (Cameron DaCamara) `_, - `@TrebledJ (Johnathan) `_, - `@bodomartin (brm) `_, - `@cquammen (Cory Quammen) `_, - `@white238 (Chris White) `_, - `@mmarkeloff (Max) `_, - `@palacaze (Pierre-Antoine Lacaze) `_, - `@jcelerier (Jean-Michaël Celerier) `_, - `@mborn-adi (Mathias Born) `_, - `@BrukerJWD (Jonathan W) `_, - `@spyridon97 (Spiros Tsalikis) `_, - `@phprus (Vladislav Shchapov) `_, - `@oliverlee (Oliver Lee) `_, - `@joshessman-llnl (Josh Essman) `_, - `@akohlmey (Axel Kohlmeyer) `_, - `@timkalu `_, - `@olupton (Olli Lupton) `_, - `@Acretock `_, - `@alexezeder (Alexey Ochapov) `_, - `@andrewcorrigan (Andrew Corrigan) `_, - `@lucpelletier `_, - `@HazardyKnusperkeks (Björn Schäpers) - `_. - -8.0.1 - 2021-07-02 ------------------- - -* Fixed the version number in the inline namespace - (`#2374 `_). - -* Added a missing presentation type check for ``std::string`` - (`#2402 `_). - -* Fixed a linkage error when mixing code built with clang and gcc - (`#2377 `_). - -* Fixed documentation issues - (`#2396 `_, - `#2403 `_, - `#2406 `_). - Thanks `@mkurdej (Marek Kurdej) `_. - -* Removed dead code in FP formatter ( - `#2398 `_). - Thanks `@javierhonduco (Javier Honduvilla Coto) - `_. - -* Fixed various warnings and compilation issues - (`#2351 `_, - `#2359 `_, - `#2365 `_, - `#2368 `_, - `#2370 `_, - `#2376 `_, - `#2381 `_, - `#2382 `_, - `#2386 `_, - `#2389 `_, - `#2395 `_, - `#2397 `_, - `#2400 `_, - `#2401 `_, - `#2407 `_). - Thanks `@zx2c4 (Jason A. Donenfeld) `_, - `@AidanSun05 (Aidan Sun) `_, - `@mattiasljungstrom (Mattias Ljungström) - `_, - `@joemmett (Jonathan Emmett) `_, - `@erengy (Eren Okka) `_, - `@patlkli (Patrick Geltinger) `_, - `@gsjaardema (Greg Sjaardema) `_, - `@phprus (Vladislav Shchapov) `_. - -8.0.0 - 2021-06-21 ------------------- - -* Enabled compile-time format string checks by default. - For example (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - fmt::print("{:d}", "I am not a number"); - } - - gives a compile-time error on compilers with C++20 ``consteval`` support - (gcc 10+, clang 11+) because ``d`` is not a valid format specifier for a - string. - - To pass a runtime string wrap it in ``fmt::runtime``: - - .. code:: c++ - - fmt::print(fmt::runtime("{:d}"), "I am not a number"); - -* Added compile-time formatting - (`#2019 `_, - `#2044 `_, - `#2056 `_, - `#2072 `_, - `#2075 `_, - `#2078 `_, - `#2129 `_, - `#2326 `_). - For example (`godbolt `__): - - .. code:: c++ - - #include - - consteval auto compile_time_itoa(int value) -> std::array { - auto result = std::array(); - fmt::format_to(result.data(), FMT_COMPILE("{}"), value); - return result; - } - - constexpr auto answer = compile_time_itoa(42); - - Most of the formatting functionality is available at compile time with a - notable exception of floating-point numbers and pointers. - Thanks `@alexezeder (Alexey Ochapov) `_. - -* Optimized handling of format specifiers during format string compilation. - For example, hexadecimal formatting (``"{:x}"``) is now 3-7x faster than - before when using ``format_to`` with format string compilation and a - stack-allocated buffer (`#1944 `_). - - Before (7.1.3):: - - ---------------------------------------------------------------------------- - Benchmark Time CPU Iterations - ---------------------------------------------------------------------------- - FMTCompileOld/0 15.5 ns 15.5 ns 43302898 - FMTCompileOld/42 16.6 ns 16.6 ns 43278267 - FMTCompileOld/273123 18.7 ns 18.6 ns 37035861 - FMTCompileOld/9223372036854775807 19.4 ns 19.4 ns 35243000 - ---------------------------------------------------------------------------- - - After (8.x):: - - ---------------------------------------------------------------------------- - Benchmark Time CPU Iterations - ---------------------------------------------------------------------------- - FMTCompileNew/0 1.99 ns 1.99 ns 360523686 - FMTCompileNew/42 2.33 ns 2.33 ns 279865664 - FMTCompileNew/273123 3.72 ns 3.71 ns 190230315 - FMTCompileNew/9223372036854775807 5.28 ns 5.26 ns 130711631 - ---------------------------------------------------------------------------- - - It is even faster than ``std::to_chars`` from libc++ compiled with clang on - macOS:: - - ---------------------------------------------------------------------------- - Benchmark Time CPU Iterations - ---------------------------------------------------------------------------- - ToChars/0 4.42 ns 4.41 ns 160196630 - ToChars/42 5.00 ns 4.98 ns 140735201 - ToChars/273123 7.26 ns 7.24 ns 95784130 - ToChars/9223372036854775807 8.77 ns 8.75 ns 75872534 - ---------------------------------------------------------------------------- - - In other cases, especially involving ``std::string`` construction, the - speed up is usually lower because handling format specifiers takes a smaller - fraction of the total time. - -* Added the ``_cf`` user-defined literal to represent a compiled format string. - It can be used instead of the ``FMT_COMPILE`` macro - (`#2043 `_, - `#2242 `_): - - .. code:: c++ - - #include - - using namespace fmt::literals; - auto s = fmt::format(FMT_COMPILE("{}"), 42); // 🙁 not modern - auto s = fmt::format("{}"_cf, 42); // 🙂 modern as hell - - It requires compiler support for class types in non-type template parameters - (a C++20 feature) which is available in GCC 9.3+. - Thanks `@alexezeder (Alexey Ochapov) `_. - -* Format string compilation now requires ``format`` functions of ``formatter`` - specializations for user-defined types to be ``const``: - - .. code:: c++ - - template <> struct fmt::formatter: formatter { - template - auto format(my_type obj, FormatContext& ctx) const { // Note const here. - // ... - } - }; - -* Added UDL-based named argument support to format string compilation - (`#2243 `_, - `#2281 `_). For example: - - .. code:: c++ - - #include - - using namespace fmt::literals; - auto s = fmt::format(FMT_COMPILE("{answer}"), "answer"_a = 42); - - Here the argument named "answer" is resolved at compile time with no - runtime overhead. - Thanks `@alexezeder (Alexey Ochapov) `_. - -* Added format string compilation support to ``fmt::print`` - (`#2280 `_, - `#2304 `_). - Thanks `@alexezeder (Alexey Ochapov) `_. - -* Added initial support for compiling {fmt} as a C++20 module - (`#2235 `_, - `#2240 `_, - `#2260 `_, - `#2282 `_, - `#2283 `_, - `#2288 `_, - `#2298 `_, - `#2306 `_, - `#2307 `_, - `#2309 `_, - `#2318 `_, - `#2324 `_, - `#2332 `_, - `#2340 `_). - Thanks `@DanielaE (Daniela Engert) `_. - -* Made symbols private by default reducing shared library size - (`#2301 `_). For example there was - a ~15% reported reduction on one platform. - Thanks `@sergiud (Sergiu Deitsch) `_. - -* Optimized includes making the result of preprocessing ``fmt/format.h`` - ~20% smaller with libstdc++/C++20 and slightly improving build times - (`#1998 `_). - -* Added support of ranges with non-const ``begin`` / ``end`` - (`#1953 `_). - Thanks `@kitegi (sarah) `_. - -* Added support of ``std::byte`` and other formattable types to ``fmt::join`` - (`#1981 `_, - `#2040 `_, - `#2050 `_, - `#2262 `_). For example: - - .. code:: c++ - - #include - #include - #include - - int main() { - auto bytes = std::vector{std::byte(4), std::byte(2)}; - fmt::print("{}", fmt::join(bytes, "")); - } - - prints "42". - - Thanks `@kamibo (Camille Bordignon) `_. - -* Implemented the default format for ``std::chrono::system_clock`` - (`#2319 `_, - `#2345 `_). For example: - - .. code:: c++ - - #include - - int main() { - fmt::print("{}", std::chrono::system_clock::now()); - } - - prints "2021-06-18 15:22:00" (the output depends on the current date and - time). Thanks `@sunmy2019 `_. - -* Made more chrono specifiers locale independent by default. Use the ``'L'`` - specifier to get localized formatting. For example: - - .. code:: c++ - - #include - - int main() { - std::locale::global(std::locale("ru_RU.UTF-8")); - auto monday = std::chrono::weekday(1); - fmt::print("{}\n", monday); // prints "Mon" - fmt::print("{:L}\n", monday); // prints "пн" - } - -* Improved locale handling in chrono formatting - (`#2337 `_, - `#2349 `_, - `#2350 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Deprecated ``fmt/locale.h`` moving the formatting functions that take a - locale to ``fmt/format.h`` (``char``) and ``fmt/xchar`` (other overloads). - This doesn't introduce a dependency on ```` so there is virtually no - compile time effect. - -* Deprecated an undocumented ``format_to`` overload that takes - ``basic_memory_buffer``. - -* Made parameter order in ``vformat_to`` consistent with ``format_to`` - (`#2327 `_). - -* Added support for time points with arbitrary durations - (`#2208 `_). For example: - - .. code:: c++ - - #include - - int main() { - using tp = std::chrono::time_point< - std::chrono::system_clock, std::chrono::seconds>; - fmt::print("{:%S}", tp(std::chrono::seconds(42))); - } - - prints "42". - -* Formatting floating-point numbers no longer produces trailing zeros by default - for consistency with ``std::format``. For example: - - .. code:: c++ - - #include - - int main() { - fmt::print("{0:.3}", 1.1); - } - - prints "1.1". Use the ``'#'`` specifier to keep trailing zeros. - -* Dropped a limit on the number of elements in a range and replaced ``{}`` with - ``[]`` as range delimiters for consistency with Python's ``str.format``. - -* The ``'L'`` specifier for locale-specific numeric formatting can now be - combined with presentation specifiers as in ``std::format``. For example: - - .. code:: c++ - - #include - #include - - int main() { - std::locale::global(std::locale("fr_FR.UTF-8")); - fmt::print("{0:.2Lf}", 0.42); - } - - prints "0,42". The deprecated ``'n'`` specifier has been removed. - -* Made the ``0`` specifier ignored for infinity and NaN - (`#2305 `_, - `#2310 `_). - Thanks `@Liedtke (Matthias Liedtke) `_. - -* Made the hexfloat formatting use the right alignment by default - (`#2308 `_, - `#2317 `_). - Thanks `@Liedtke (Matthias Liedtke) `_. - -* Removed the deprecated numeric alignment (``'='``). Use the ``'0'`` specifier - instead. - -* Removed the deprecated ``fmt/posix.h`` header that has been replaced with - ``fmt/os.h``. - -* Removed the deprecated ``format_to_n_context``, ``format_to_n_args`` and - ``make_format_to_n_args``. They have been replaced with ``format_context``, - ``format_args` and ``make_format_args`` respectively. - -* Moved ``wchar_t``-specific functions and types to ``fmt/xchar.h``. - You can define ``FMT_DEPRECATED_INCLUDE_XCHAR`` to automatically include - ``fmt/xchar.h`` from ``fmt/format.h`` but this will be disabled in the next - major release. - -* Fixed handling of the ``'+'`` specifier in localized formatting - (`#2133 `_). - -* Added support for the ``'s'`` format specifier that gives textual - representation of ``bool`` - (`#2094 `_, - `#2109 `_). For example: - - .. code:: c++ - - #include - - int main() { - fmt::print("{:s}", true); - } - - prints "true". - Thanks `@powercoderlol (Ivan Polyakov) `_. - -* Made ``fmt::ptr`` work with function pointers - (`#2131 `_). For example: - - .. code:: c++ - - #include - - int main() { - fmt::print("My main: {}\n", fmt::ptr(main)); - } - - Thanks `@mikecrowe (Mike Crowe) `_. - -* The undocumented support for specializing ``formatter`` for pointer types - has been removed. - -* Fixed ``fmt::formatted_size`` with format string compilation - (`#2141 `_, - `#2161 `_). - Thanks `@alexezeder (Alexey Ochapov) `_. - -* Fixed handling of empty format strings during format string compilation - (`#2042 `_): - - .. code:: c++ - - auto s = fmt::format(FMT_COMPILE("")); - - Thanks `@alexezeder (Alexey Ochapov) `_. - -* Fixed handling of enums in ``fmt::to_string`` - (`#2036 `_). - -* Improved width computation - (`#2033 `_, - `#2091 `_). For example: - - .. code:: c++ - - #include - - int main() { - fmt::print("{:-<10}{}\n", "你好", "世界"); - fmt::print("{:-<10}{}\n", "hello", "world"); - } - - prints - - .. image:: https://user-images.githubusercontent.com/576385/ - 119840373-cea3ca80-beb9-11eb-91e0-54266c48e181.png - - on a modern terminal. - -* The experimental fast output stream (``fmt::ostream``) is now truncated by - default for consistency with ``fopen`` - (`#2018 `_). For example: - - .. code:: c++ - - #include - - int main() { - fmt::ostream out1 = fmt::output_file("guide"); - out1.print("Zaphod"); - out1.close(); - fmt::ostream out2 = fmt::output_file("guide"); - out2.print("Ford"); - } - - writes "Ford" to the file "guide". To preserve the old file content if any - pass ``fmt::file::WRONLY | fmt::file::CREATE`` flags to ``fmt::output_file``. - -* Fixed moving of ``fmt::ostream`` that holds buffered data - (`#2197 `_, - `#2198 `_). - Thanks `@vtta `_. - -* Replaced the ``fmt::system_error`` exception with a function of the same - name that constructs ``std::system_error`` - (`#2266 `_). - -* Replaced the ``fmt::windows_error`` exception with a function of the same - name that constructs ``std::system_error`` with the category returned by - ``fmt::system_category()`` - (`#2274 `_, - `#2275 `_). - The latter is similar to ``std::sytem_category`` but correctly handles UTF-8. - Thanks `@phprus (Vladislav Shchapov) `_. - -* Replaced ``fmt::error_code`` with ``std::error_code`` and made it formattable - (`#2269 `_, - `#2270 `_, - `#2273 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Added speech synthesis support - (`#2206 `_). - -* Made ``format_to`` work with a memory buffer that has a custom allocator - (`#2300 `_). - Thanks `@voxmea `_. - -* Added ``Allocator::max_size`` support to ``basic_memory_buffer``. - (`#1960 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Added wide string support to ``fmt::join`` - (`#2236 `_). - Thanks `@crbrz `_. - -* Made iterators passed to ``formatter`` specializations via a format context - satisfy C++20 ``std::output_iterator`` requirements - (`#2156 `_, - `#2158 `_, - `#2195 `_, - `#2204 `_). - Thanks `@randomnetcat (Jason Cobb) `_. - -* Optimized the ``printf`` implementation - (`#1982 `_, - `#1984 `_, - `#2016 `_, - `#2164 `_). - Thanks `@rimathia `_ and - `@moiwi `_. - -* Improved detection of ``constexpr`` ``char_traits`` - (`#2246 `_, - `#2257 `_). - Thanks `@phprus (Vladislav Shchapov) `_. - -* Fixed writing to ``stdout`` when it is redirected to ``NUL`` on Windows - (`#2080 `_). - -* Fixed exception propagation from iterators - (`#2097 `_). - -* Improved ``strftime`` error handling - (`#2238 `_, - `#2244 `_). - Thanks `@yumeyao `_. - -* Stopped using deprecated GCC UDL template extension. - -* Added ``fmt/args.h`` to the install target - (`#2096 `_). - -* Error messages are now passed to assert when exceptions are disabled - (`#2145 `_). - Thanks `@NobodyXu (Jiahao XU) `_. - -* Added the ``FMT_MASTER_PROJECT`` CMake option to control build and install - targets when {fmt} is included via ``add_subdirectory`` - (`#2098 `_, - `#2100 `_). - Thanks `@randomizedthinking `_. - -* Improved build configuration - (`#2026 `_, - `#2122 `_). - Thanks `@luncliff (Park DongHa) `_ and - `@ibaned (Dan Ibanez) `_. - -* Fixed various warnings and compilation issues - (`#1947 `_, - `#1959 `_, - `#1963 `_, - `#1965 `_, - `#1966 `_, - `#1974 `_, - `#1975 `_, - `#1990 `_, - `#2000 `_, - `#2001 `_, - `#2002 `_, - `#2004 `_, - `#2006 `_, - `#2009 `_, - `#2010 `_, - `#2038 `_, - `#2039 `_, - `#2047 `_, - `#2053 `_, - `#2059 `_, - `#2065 `_, - `#2067 `_, - `#2068 `_, - `#2073 `_, - `#2103 `_, - `#2105 `_, - `#2106 `_, - `#2107 `_, - `#2116 `_, - `#2117 `_, - `#2118 `_, - `#2119 `_, - `#2127 `_, - `#2128 `_, - `#2140 `_, - `#2142 `_, - `#2143 `_, - `#2144 `_, - `#2147 `_, - `#2148 `_, - `#2149 `_, - `#2152 `_, - `#2160 `_, - `#2170 `_, - `#2175 `_, - `#2176 `_, - `#2177 `_, - `#2178 `_, - `#2179 `_, - `#2180 `_, - `#2181 `_, - `#2183 `_, - `#2184 `_, - `#2185 `_, - `#2186 `_, - `#2187 `_, - `#2190 `_, - `#2192 `_, - `#2194 `_, - `#2205 `_, - `#2210 `_, - `#2211 `_, - `#2215 `_, - `#2216 `_, - `#2218 `_, - `#2220 `_, - `#2228 `_, - `#2229 `_, - `#2230 `_, - `#2233 `_, - `#2239 `_, - `#2248 `_, - `#2252 `_, - `#2253 `_, - `#2255 `_, - `#2261 `_, - `#2278 `_, - `#2284 `_, - `#2287 `_, - `#2289 `_, - `#2290 `_, - `#2293 `_, - `#2295 `_, - `#2296 `_, - `#2297 `_, - `#2311 `_, - `#2313 `_, - `#2315 `_, - `#2320 `_, - `#2321 `_, - `#2323 `_, - `#2328 `_, - `#2329 `_, - `#2333 `_, - `#2338 `_, - `#2341 `_). - Thanks `@darklukee `_, - `@fagg (Ashton Fagg) `_, - `@killerbot242 (Lieven de Cock) `_, - `@jgopel (Jonathan Gopel) `_, - `@yeswalrus (Walter Gray) `_, - `@Finkman `_, - `@HazardyKnusperkeks (Björn Schäpers) `_, - `@dkavolis (Daumantas Kavolis) `_, - `@concatime (Issam Maghni) `_, - `@chronoxor (Ivan Shynkarenka) `_, - `@summivox (Yin Zhong) `_, - `@yNeo `_, - `@Apache-HB (Elliot) `_, - `@alexezeder (Alexey Ochapov) `_, - `@toojays (John Steele Scott) `_, - `@Brainy0207 `_, - `@vadz (VZ) `_, - `@imsherlock (Ryan Sherlock) `_, - `@phprus (Vladislav Shchapov) `_, - `@white238 (Chris White) `_, - `@yafshar (Yaser Afshar) `_, - `@BillyDonahue (Billy Donahue) `_, - `@jstaahl `_, - `@denchat `_, - `@DanielaE (Daniela Engert) `_, - `@ilyakurdyukov (Ilya Kurdyukov) `_, - `@ilmai `_, - `@JessyDL (Jessy De Lannoit) `_, - `@sergiud (Sergiu Deitsch) `_, - `@mwinterb `_, - `@sven-herrmann `_, - `@jmelas (John Melas) `_, - `@twoixter (Jose Miguel Pérez) `_, - `@crbrz `_, - `@upsj (Tobias Ribizel) `_. - -* Improved documentation - (`#1986 `_, - `#2051 `_, - `#2057 `_, - `#2081 `_, - `#2084 `_, - `#2312 `_). - Thanks `@imba-tjd (谭九鼎) `_, - `@0x416c69 (AlιAѕѕaѕѕιN) `_, - `@mordante `_. - -* Continuous integration and test improvements - (`#1969 `_, - `#1991 `_, - `#2020 `_, - `#2110 `_, - `#2114 `_, - `#2196 `_, - `#2217 `_, - `#2247 `_, - `#2256 `_, - `#2336 `_, - `#2346 `_). - Thanks `@jgopel (Jonathan Gopel) `_, - `@alexezeder (Alexey Ochapov) `_ and - `@DanielaE (Daniela Engert) `_. - -7.1.3 - 2020-11-24 ------------------- - -* Fixed handling of buffer boundaries in ``format_to_n`` - (`#1996 `_, - `#2029 `_). - -* Fixed linkage errors when linking with a shared library - (`#2011 `_). - -* Reintroduced ostream support to range formatters - (`#2014 `_). - -* Worked around an issue with mixing std versions in gcc - (`#2017 `_). - -7.1.2 - 2020-11-04 ------------------- - -* Fixed floating point formatting with large precision - (`#1976 `_). - -7.1.1 - 2020-11-01 ------------------- - -* Fixed ABI compatibility with 7.0.x - (`#1961 `_). - -* Added the ``FMT_ARM_ABI_COMPATIBILITY`` macro to work around ABI - incompatibility between GCC and Clang on ARM - (`#1919 `_). - -* Worked around a SFINAE bug in GCC 8 - (`#1957 `_). - -* Fixed linkage errors when building with GCC's LTO - (`#1955 `_). - -* Fixed a compilation error when building without ``__builtin_clz`` or equivalent - (`#1968 `_). - Thanks `@tohammer (Tobias Hammer) `_. - -* Fixed a sign conversion warning - (`#1964 `_). - Thanks `@OptoCloud `_. - -7.1.0 - 2020-10-25 ------------------- - -* Switched from `Grisu3 - `_ - to `Dragonbox `_ for the default - floating-point formatting which gives the shortest decimal representation - with round-trip guarantee and correct rounding - (`#1882 `_, - `#1887 `_, - `#1894 `_). This makes {fmt} up to - 20-30x faster than common implementations of ``std::ostringstream`` and - ``sprintf`` on `dtoa-benchmark `_ - and faster than double-conversion and Ryū: - - .. image:: https://user-images.githubusercontent.com/576385/ - 95684665-11719600-0ba8-11eb-8e5b-972ff4e49428.png - - It is possible to get even better performance at the cost of larger binary - size by compiling with the ``FMT_USE_FULL_CACHE_DRAGONBOX`` macro set to 1. - - Thanks `@jk-jeon (Junekey Jeon) `_. - -* Added an experimental unsynchronized file output API which, together with - `format string compilation `_, - can give `5-9 times speed up compared to fprintf - `_ - on common platforms (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - auto f = fmt::output_file("guide"); - f.print("The answer is {}.", 42); - } - -* Added a formatter for ``std::chrono::time_point`` - (`#1819 `_, - `#1837 `_). For example - (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - auto now = std::chrono::system_clock::now(); - fmt::print("The time is {:%H:%M:%S}.\n", now); - } - - Thanks `@adamburgess (Adam Burgess) `_. - -* Added support for ranges with non-const ``begin``/``end`` to ``fmt::join`` - (`#1784 `_, - `#1786 `_). For example - (`godbolt `__): - - .. code:: c++ - - #include - #include - - int main() { - using std::literals::string_literals::operator""s; - auto strs = std::array{"a"s, "bb"s, "ccc"s}; - auto range = strs | ranges::views::filter( - [] (const std::string &x) { return x.size() != 2; } - ); - fmt::print("{}\n", fmt::join(range, "")); - } - - prints "accc". - - Thanks `@tonyelewis (Tony E Lewis) `_. - -* Added a ``memory_buffer::append`` overload that takes a range - (`#1806 `_). - Thanks `@BRevzin (Barry Revzin) `_. - -* Improved handling of single code units in ``FMT_COMPILE``. For example: - - .. code:: c++ - - #include - - char* f(char* buf) { - return fmt::format_to(buf, FMT_COMPILE("x{}"), 42); - } - - compiles to just (`godbolt `__): - - .. code:: asm - - _Z1fPc: - movb $120, (%rdi) - xorl %edx, %edx - cmpl $42, _ZN3fmt2v76detail10basic_dataIvE23zero_or_powers_of_10_32E+8(%rip) - movl $3, %eax - seta %dl - subl %edx, %eax - movzwl _ZN3fmt2v76detail10basic_dataIvE6digitsE+84(%rip), %edx - cltq - addq %rdi, %rax - movw %dx, -2(%rax) - ret - - Here a single ``mov`` instruction writes ``'x'`` (``$120``) to the output - buffer. - -* Added dynamic width support to format string compilation - (`#1809 `_). - -* Improved error reporting for unformattable types: now you'll get the type name - directly in the error message instead of the note: - - .. code:: c++ - - #include - - struct how_about_no {}; - - int main() { - fmt::print("{}", how_about_no()); - } - - Error (`godbolt `__): - - ``fmt/core.h:1438:3: error: static_assert failed due to requirement - 'fmt::v7::formattable()' "Cannot format an argument. - To make type T formattable provide a formatter specialization: - https://fmt.dev/latest/api.html#udt" - ...`` - -* Added the `make_args_checked `_ - function template that allows you to write formatting functions with - compile-time format string checks and avoid binary code bloat - (`godbolt `__): - - .. code:: c++ - - void vlog(const char* file, int line, fmt::string_view format, - fmt::format_args args) { - fmt::print("{}: {}: ", file, line); - fmt::vprint(format, args); - } - - template - void log(const char* file, int line, const S& format, Args&&... args) { - vlog(file, line, format, - fmt::make_args_checked(format, args...)); - } - - #define MY_LOG(format, ...) \ - log(__FILE__, __LINE__, FMT_STRING(format), __VA_ARGS__) - - MY_LOG("invalid squishiness: {}", 42); - -* Replaced ``snprintf`` fallback with a faster internal IEEE 754 ``float`` and - ``double`` formatter for arbitrary precision. For example - (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - fmt::print("{:.500}\n", 4.9406564584124654E-324); - } - - prints - - ``4.9406564584124654417656879286822137236505980261432476442558568250067550727020875186529983636163599237979656469544571773092665671035593979639877479601078187812630071319031140452784581716784898210368871863605699873072305000638740915356498438731247339727316961514003171538539807412623856559117102665855668676818703956031062493194527159149245532930545654440112748012970999954193198940908041656332452475714786901472678015935523861155013480352649347201937902681071074917033322268447533357208324319360923829e-324``. - -* Made ``format_to_n`` and ``formatted_size`` part of the `core API - `__ - (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - char buffer[10]; - auto result = fmt::format_to_n(buffer, sizeof(buffer), "{}", 42); - } - -* Added ``fmt::format_to_n`` overload with format string compilation - (`#1764 `_, - `#1767 `_, - `#1869 `_). For example - (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - char buffer[8]; - fmt::format_to_n(buffer, sizeof(buffer), FMT_COMPILE("{}"), 42); - } - - Thanks `@Kurkin (Dmitry Kurkin) `_, - `@alexezeder (Alexey Ochapov) `_. - -* Added ``fmt::format_to`` overload that take ``text_style`` - (`#1593 `_, - `#1842 `_, - `#1843 `_). For example - (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - std::string out; - fmt::format_to(std::back_inserter(out), - fmt::emphasis::bold | fg(fmt::color::red), - "The answer is {}.", 42); - } - - Thanks `@Naios (Denis Blank) `_. - -* Made the ``'#'`` specifier emit trailing zeros in addition to the decimal - point (`#1797 `_). For example - (`godbolt `__): - - .. code:: c++ - - #include - - int main() { - fmt::print("{:#.2g}", 0.5); - } - - prints ``0.50``. - -* Changed the default floating point format to not include ``.0`` for - consistency with ``std::format`` and ``std::to_chars`` - (`#1893 `_, - `#1943 `_). It is possible to get - the decimal point and trailing zero with the ``#`` specifier. - -* Fixed an issue with floating-point formatting that could result in addition of - a non-significant trailing zero in rare cases e.g. ``1.00e-34`` instead of - ``1.0e-34`` (`#1873 `_, - `#1917 `_). - -* Made ``fmt::to_string`` fallback on ``ostream`` insertion operator if - the ``formatter`` specialization is not provided - (`#1815 `_, - `#1829 `_). - Thanks `@alexezeder (Alexey Ochapov) `_. - -* Added support for the append mode to the experimental file API and - improved ``fcntl.h`` detection. - (`#1847 `_, - `#1848 `_). - Thanks `@t-wiser `_. - -* Fixed handling of types that have both an implicit conversion operator and - an overloaded ``ostream`` insertion operator - (`#1766 `_). - -* Fixed a slicing issue in an internal iterator type - (`#1822 `_). - Thanks `@BRevzin (Barry Revzin) `_. - -* Fixed an issue in locale-specific integer formatting - (`#1927 `_). - -* Fixed handling of exotic code unit types - (`#1870 `_, - `#1932 `_). - -* Improved ``FMT_ALWAYS_INLINE`` - (`#1878 `_). - Thanks `@jk-jeon (Junekey Jeon) `_. - -* Removed dependency on ``windows.h`` - (`#1900 `_). - Thanks `@bernd5 (Bernd Baumanns) `_. - -* Optimized counting of decimal digits on MSVC - (`#1890 `_). - Thanks `@mwinterb `_. - -* Improved documentation - (`#1772 `_, - `#1775 `_, - `#1792 `_, - `#1838 `_, - `#1888 `_, - `#1918 `_, - `#1939 `_). - Thanks `@leolchat (Léonard Gérard) `_, - `@pepsiman (Malcolm Parsons) `_, - `@Klaim (Joël Lamotte) `_, - `@ravijanjam (Ravi J) `_, - `@francesco-st `_, - `@udnaan (Adnan) `_. - -* Added the ``FMT_REDUCE_INT_INSTANTIATIONS`` CMake option that reduces the - binary code size at the cost of some integer formatting performance. This can - be useful for extremely memory-constrained embedded systems - (`#1778 `_, - `#1781 `_). - Thanks `@kammce (Khalil Estell) `_. - -* Added the ``FMT_USE_INLINE_NAMESPACES`` macro to control usage of inline - namespaces (`#1945 `_). - Thanks `@darklukee `_. - -* Improved build configuration - (`#1760 `_, - `#1770 `_, - `#1779 `_, - `#1783 `_, - `#1823 `_). - Thanks `@dvetutnev (Dmitriy Vetutnev) `_, - `@xvitaly (Vitaly Zaitsev) `_, - `@tambry (Raul Tambre) `_, - `@medithe `_, - `@martinwuehrer (Martin Wührer) `_. - -* Fixed various warnings and compilation issues - (`#1790 `_, - `#1802 `_, - `#1808 `_, - `#1810 `_, - `#1811 `_, - `#1812 `_, - `#1814 `_, - `#1816 `_, - `#1817 `_, - `#1818 `_, - `#1825 `_, - `#1836 `_, - `#1855 `_, - `#1856 `_, - `#1860 `_, - `#1877 `_, - `#1879 `_, - `#1880 `_, - `#1896 `_, - `#1897 `_, - `#1898 `_, - `#1904 `_, - `#1908 `_, - `#1911 `_, - `#1912 `_, - `#1928 `_, - `#1929 `_, - `#1935 `_, - `#1937 `_, - `#1942 `_, - `#1949 `_). - Thanks `@TheQwertiest `_, - `@medithe `_, - `@martinwuehrer (Martin Wührer) `_, - `@n16h7hunt3r `_, - `@Othereum (Seokjin Lee) `_, - `@gsjaardema (Greg Sjaardema) `_, - `@AlexanderLanin (Alexander Lanin) `_, - `@gcerretani (Giovanni Cerretani) `_, - `@chronoxor (Ivan Shynkarenka) `_, - `@noizefloor (Jan Schwers) `_, - `@akohlmey (Axel Kohlmeyer) `_, - `@jk-jeon (Junekey Jeon) `_, - `@rimathia `_, - `@rglarix (Riccardo Ghetta (larix)) `_, - `@moiwi `_, - `@heckad (Kazantcev Andrey) `_, - `@MarcDirven `_. - `@BartSiwek (Bart Siwek) `_, - `@darklukee `_. - -7.0.3 - 2020-08-06 ------------------- - -* Worked around broken ``numeric_limits`` for 128-bit integers - (`#1787 `_). - -* Added error reporting on missing named arguments - (`#1796 `_). - -* Stopped using 128-bit integers with clang-cl - (`#1800 `_). - Thanks `@Kingcom `_. - -* Fixed issues in locale-specific integer formatting - (`#1782 `_, - `#1801 `_). - -7.0.2 - 2020-07-29 ------------------- - -* Worked around broken ``numeric_limits`` for 128-bit integers - (`#1725 `_). - -* Fixed compatibility with CMake 3.4 - (`#1779 `_). - -* Fixed handling of digit separators in locale-specific formatting - (`#1782 `_). - -7.0.1 - 2020-07-07 ------------------- - -* Updated the inline version namespace name. - -* Worked around a gcc bug in mangling of alias templates - (`#1753 `_). - -* Fixed a linkage error on Windows - (`#1757 `_). - Thanks `@Kurkin (Dmitry Kurkin) `_. - -* Fixed minor issues with the documentation. - -7.0.0 - 2020-07-05 ------------------- - -* Reduced the library size. For example, on macOS a stripped test binary - statically linked with {fmt} `shrank from ~368k to less than 100k - `_. - -* Added a simpler and more efficient `format string compilation API - `_: - - .. code:: c++ - - #include - - // Converts 42 into std::string using the most efficient method and no - // runtime format string processing. - std::string s = fmt::format(FMT_COMPILE("{}"), 42); - - The old ``fmt::compile`` API is now deprecated. - -* Optimized integer formatting: ``format_to`` with format string compilation - and a stack-allocated buffer is now `faster than to_chars on both - libc++ and libstdc++ - `_. - -* Optimized handling of small format strings. For example, - - .. code:: c++ - - fmt::format("Result: {}: ({},{},{},{})", str1, str2, str3, str4, str5) - - is now ~40% faster (`#1685 `_). - -* Applied extern templates to improve compile times when using the core API - and ``fmt/format.h`` (`#1452 `_). - For example, on macOS with clang the compile time of a test translation unit - dropped from 2.3s to 0.3s with ``-O2`` and from 0.6s to 0.3s with the default - settings (``-O0``). - - Before (``-O2``):: - - % time c++ -c test.cc -I include -std=c++17 -O2 - c++ -c test.cc -I include -std=c++17 -O2 2.22s user 0.08s system 99% cpu 2.311 total - - After (``-O2``):: - - % time c++ -c test.cc -I include -std=c++17 -O2 - c++ -c test.cc -I include -std=c++17 -O2 0.26s user 0.04s system 98% cpu 0.303 total - - Before (default):: - - % time c++ -c test.cc -I include -std=c++17 - c++ -c test.cc -I include -std=c++17 0.53s user 0.06s system 98% cpu 0.601 total - - After (default):: - - % time c++ -c test.cc -I include -std=c++17 - c++ -c test.cc -I include -std=c++17 0.24s user 0.06s system 98% cpu 0.301 total - - It is still recommended to use ``fmt/core.h`` instead of ``fmt/format.h`` but - the compile time difference is now smaller. Thanks - `@alex3d `_ for the suggestion. - -* Named arguments are now stored on stack (no dynamic memory allocations) and - the compiled code is more compact and efficient. For example - - .. code:: c++ - - #include - - int main() { - fmt::print("The answer is {answer}\n", fmt::arg("answer", 42)); - } - - compiles to just (`godbolt `__) - - .. code:: asm - - .LC0: - .string "answer" - .LC1: - .string "The answer is {answer}\n" - main: - sub rsp, 56 - mov edi, OFFSET FLAT:.LC1 - mov esi, 23 - movabs rdx, 4611686018427387905 - lea rax, [rsp+32] - lea rcx, [rsp+16] - mov QWORD PTR [rsp+8], 1 - mov QWORD PTR [rsp], rax - mov DWORD PTR [rsp+16], 42 - mov QWORD PTR [rsp+32], OFFSET FLAT:.LC0 - mov DWORD PTR [rsp+40], 0 - call fmt::v6::vprint(fmt::v6::basic_string_view, - fmt::v6::format_args) - xor eax, eax - add rsp, 56 - ret - - .L.str.1: - .asciz "answer" - -* Implemented compile-time checks for dynamic width and precision - (`#1614 `_): - - .. code:: c++ - - #include - - int main() { - fmt::print(FMT_STRING("{0:{1}}"), 42); - } - - now gives a compilation error because argument 1 doesn't exist:: - - In file included from test.cc:1: - include/fmt/format.h:2726:27: error: constexpr variable 'invalid_format' must be - initialized by a constant expression - FMT_CONSTEXPR_DECL bool invalid_format = - ^ - ... - include/fmt/core.h:569:26: note: in call to - '&checker(s, {}).context_->on_error(&"argument not found"[0])' - if (id >= num_args_) on_error("argument not found"); - ^ - -* Added sentinel support to ``fmt::join`` - (`#1689 `_) - - .. code:: c++ - - struct zstring_sentinel {}; - bool operator==(const char* p, zstring_sentinel) { return *p == '\0'; } - bool operator!=(const char* p, zstring_sentinel) { return *p != '\0'; } - - struct zstring { - const char* p; - const char* begin() const { return p; } - zstring_sentinel end() const { return {}; } - }; - - auto s = fmt::format("{}", fmt::join(zstring{"hello"}, "_")); - // s == "h_e_l_l_o" - - Thanks `@BRevzin (Barry Revzin) `_. - -* Added support for named arguments, ``clear`` and ``reserve`` to - ``dynamic_format_arg_store`` - (`#1655 `_, - `#1663 `_, - `#1674 `_, - `#1677 `_). - Thanks `@vsolontsov-ll (Vladimir Solontsov) - `_. - -* Added support for the ``'c'`` format specifier to integral types for - compatibility with ``std::format`` - (`#1652 `_). - -* Replaced the ``'n'`` format specifier with ``'L'`` for compatibility with - ``std::format`` (`#1624 `_). - The ``'n'`` specifier can be enabled via the ``FMT_DEPRECATED_N_SPECIFIER`` - macro. - -* The ``'='`` format specifier is now disabled by default for compatibility with - ``std::format``. It can be enabled via the ``FMT_DEPRECATED_NUMERIC_ALIGN`` - macro. - -* Removed the following deprecated APIs: - - * ``FMT_STRING_ALIAS`` and ``fmt`` macros - replaced by ``FMT_STRING`` - * ``fmt::basic_string_view::char_type`` - replaced by - ``fmt::basic_string_view::value_type`` - * ``convert_to_int`` - * ``format_arg_store::types`` - * ``*parse_context`` - replaced by ``*format_parse_context`` - * ``FMT_DEPRECATED_INCLUDE_OS`` - * ``FMT_DEPRECATED_PERCENT`` - incompatible with ``std::format`` - * ``*writer`` - replaced by compiled format API - -* Renamed the ``internal`` namespace to ``detail`` - (`#1538 `_). The former is still - provided as an alias if the ``FMT_USE_INTERNAL`` macro is defined. - -* Improved compatibility between ``fmt::printf`` with the standard specs - (`#1595 `_, - `#1682 `_, - `#1683 `_, - `#1687 `_, - `#1699 `_). - Thanks `@rimathia `_. - -* Fixed handling of ``operator<<`` overloads that use ``copyfmt`` - (`#1666 `_). - -* Added the ``FMT_OS`` CMake option to control inclusion of OS-specific APIs - in the fmt target. This can be useful for embedded platforms - (`#1654 `_, - `#1656 `_). - Thanks `@kwesolowski (Krzysztof Wesolowski) - `_. - -* Replaced ``FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION`` with the ``FMT_FUZZ`` - macro to prevent interfering with fuzzing of projects using {fmt} - (`#1650 `_). - Thanks `@asraa (Asra Ali) `_. - -* Fixed compatibility with emscripten - (`#1636 `_, - `#1637 `_). - Thanks `@ArthurSonzogni (Arthur Sonzogni) - `_. - -* Improved documentation - (`#704 `_, - `#1643 `_, - `#1660 `_, - `#1681 `_, - `#1691 `_, - `#1706 `_, - `#1714 `_, - `#1721 `_, - `#1739 `_, - `#1740 `_, - `#1741 `_, - `#1751 `_). - Thanks `@senior7515 (Alexander Gallego) `_, - `@lsr0 (Lindsay Roberts) `_, - `@puetzk (Kevin Puetz) `_, - `@fpelliccioni (Fernando Pelliccioni) `_, - Alexey Kuzmenko, `@jelly (jelle van der Waa) `_, - `@claremacrae (Clare Macrae) `_, - `@jiapengwen (文佳鹏) `_, - `@gsjaardema (Greg Sjaardema) `_, - `@alexey-milovidov `_. - -* Implemented various build configuration fixes and improvements - (`#1603 `_, - `#1657 `_, - `#1702 `_, - `#1728 `_). - Thanks `@scramsby (Scott Ramsby) `_, - `@jtojnar (Jan Tojnar) `_, - `@orivej (Orivej Desh) `_, - `@flagarde `_. - -* Fixed various warnings and compilation issues - (`#1616 `_, - `#1620 `_, - `#1622 `_, - `#1625 `_, - `#1627 `_, - `#1628 `_, - `#1629 `_, - `#1631 `_, - `#1633 `_, - `#1649 `_, - `#1658 `_, - `#1661 `_, - `#1667 `_, - `#1668 `_, - `#1669 `_, - `#1692 `_, - `#1696 `_, - `#1697 `_, - `#1707 `_, - `#1712 `_, - `#1716 `_, - `#1722 `_, - `#1724 `_, - `#1729 `_, - `#1738 `_, - `#1742 `_, - `#1743 `_, - `#1744 `_, - `#1747 `_, - `#1750 `_). - Thanks `@gsjaardema (Greg Sjaardema) `_, - `@gabime (Gabi Melman) `_, - `@johnor (Johan) `_, - `@Kurkin (Dmitry Kurkin) `_, - `@invexed (James Beach) `_, - `@peterbell10 `_, - `@daixtrose (Markus Werle) `_, - `@petrutlucian94 (Lucian Petrut) `_, - `@Neargye (Daniil Goncharov) `_, - `@ambitslix (Attila M. Szilagyi) `_, - `@gabime (Gabi Melman) `_, - `@erthink (Leonid Yuriev) `_, - `@tohammer (Tobias Hammer) `_, - `@0x8000-0000 (Florin Iucha) `_. - -6.2.1 - 2020-05-09 ------------------- - -* Fixed ostream support in ``sprintf`` - (`#1631 `_). - -* Fixed type detection when using implicit conversion to ``string_view`` and - ostream ``operator<<`` inconsistently - (`#1662 `_). - -6.2.0 - 2020-04-05 ------------------- - -* Improved error reporting when trying to format an object of a non-formattable - type: - - .. code:: c++ - - fmt::format("{}", S()); - - now gives:: - - include/fmt/core.h:1015:5: error: static_assert failed due to requirement - 'formattable' "Cannot format argument. To make type T formattable provide a - formatter specialization: - https://fmt.dev/latest/api.html#formatting-user-defined-types" - static_assert( - ^ - ... - note: in instantiation of function template specialization - 'fmt::v6::format' requested here - fmt::format("{}", S()); - ^ - - if ``S`` is not formattable. - -* Reduced the library size by ~10%. - -* Always print decimal point if ``#`` is specified - (`#1476 `_, - `#1498 `_): - - .. code:: c++ - - fmt::print("{:#.0f}", 42.0); - - now prints ``42.`` - -* Implemented the ``'L'`` specifier for locale-specific numeric formatting to - improve compatibility with ``std::format``. The ``'n'`` specifier is now - deprecated and will be removed in the next major release. - -* Moved OS-specific APIs such as ``windows_error`` from ``fmt/format.h`` to - ``fmt/os.h``. You can define ``FMT_DEPRECATED_INCLUDE_OS`` to automatically - include ``fmt/os.h`` from ``fmt/format.h`` for compatibility but this will be - disabled in the next major release. - -* Added precision overflow detection in floating-point formatting. - -* Implemented detection of invalid use of ``fmt::arg``. - -* Used ``type_identity`` to block unnecessary template argument deduction. - Thanks Tim Song. - -* Improved UTF-8 handling - (`#1109 `_): - - .. code:: c++ - - fmt::print("┌{0:─^{2}}┐\n" - "│{1: ^{2}}│\n" - "└{0:─^{2}}┘\n", "", "Привет, мир!", 20); - - now prints:: - - ┌────────────────────┐ - │ Привет, мир! │ - └────────────────────┘ - - on systems that support Unicode. - -* Added experimental dynamic argument storage - (`#1170 `_, - `#1584 `_): - - .. code:: c++ - - fmt::dynamic_format_arg_store store; - store.push_back("answer"); - store.push_back(42); - fmt::vprint("The {} is {}.\n", store); - - prints:: - - The answer is 42. - - Thanks `@vsolontsov-ll (Vladimir Solontsov) - `_. - -* Made ``fmt::join`` accept ``initializer_list`` - (`#1591 `_). - Thanks `@Rapotkinnik (Nikolay Rapotkin) `_. - -* Fixed handling of empty tuples - (`#1588 `_). - -* Fixed handling of output iterators in ``format_to_n`` - (`#1506 `_). - -* Fixed formatting of ``std::chrono::duration`` types to wide output - (`#1533 `_). - Thanks `@zeffy (pilao) `_. - -* Added const ``begin`` and ``end`` overload to buffers - (`#1553 `_). - Thanks `@dominicpoeschko `_. - -* Added the ability to disable floating-point formatting via ``FMT_USE_FLOAT``, - ``FMT_USE_DOUBLE`` and ``FMT_USE_LONG_DOUBLE`` macros for extremely - memory-constrained embedded system - (`#1590 `_). - Thanks `@albaguirre (Alberto Aguirre) `_. - -* Made ``FMT_STRING`` work with ``constexpr`` ``string_view`` - (`#1589 `_). - Thanks `@scramsby (Scott Ramsby) `_. - -* Implemented a minor optimization in the format string parser - (`#1560 `_). - Thanks `@IkarusDeveloper `_. - -* Improved attribute detection - (`#1469 `_, - `#1475 `_, - `#1576 `_). - Thanks `@federico-busato (Federico) `_, - `@chronoxor (Ivan Shynkarenka) `_, - `@refnum `_. - -* Improved documentation - (`#1481 `_, - `#1523 `_). - Thanks `@JackBoosY (Jack·Boos·Yu) `_, - `@imba-tjd (谭九鼎) `_. - -* Fixed symbol visibility on Linux when compiling with ``-fvisibility=hidden`` - (`#1535 `_). - Thanks `@milianw (Milian Wolff) `_. - -* Implemented various build configuration fixes and improvements - (`#1264 `_, - `#1460 `_, - `#1534 `_, - `#1536 `_, - `#1545 `_, - `#1546 `_, - `#1566 `_, - `#1582 `_, - `#1597 `_, - `#1598 `_). - Thanks `@ambitslix (Attila M. Szilagyi) `_, - `@jwillikers (Jordan Williams) `_, - `@stac47 (Laurent Stacul) `_. - -* Fixed various warnings and compilation issues - (`#1433 `_, - `#1461 `_, - `#1470 `_, - `#1480 `_, - `#1485 `_, - `#1492 `_, - `#1493 `_, - `#1504 `_, - `#1505 `_, - `#1512 `_, - `#1515 `_, - `#1516 `_, - `#1518 `_, - `#1519 `_, - `#1520 `_, - `#1521 `_, - `#1522 `_, - `#1524 `_, - `#1530 `_, - `#1531 `_, - `#1532 `_, - `#1539 `_, - `#1547 `_, - `#1548 `_, - `#1554 `_, - `#1567 `_, - `#1568 `_, - `#1569 `_, - `#1571 `_, - `#1573 `_, - `#1575 `_, - `#1581 `_, - `#1583 `_, - `#1586 `_, - `#1587 `_, - `#1594 `_, - `#1596 `_, - `#1604 `_, - `#1606 `_, - `#1607 `_, - `#1609 `_). - Thanks `@marti4d (Chris Martin) `_, - `@iPherian `_, - `@parkertomatoes `_, - `@gsjaardema (Greg Sjaardema) `_, - `@chronoxor (Ivan Shynkarenka) `_, - `@DanielaE (Daniela Engert) `_, - `@torsten48 `_, - `@tohammer (Tobias Hammer) `_, - `@lefticus (Jason Turner) `_, - `@ryusakki (Haise) `_, - `@adnsv (Alex Denisov) `_, - `@fghzxm `_, - `@refnum `_, - `@pramodk (Pramod Kumbhar) `_, - `@Spirrwell `_, - `@scramsby (Scott Ramsby) `_. - -6.1.2 - 2019-12-11 ------------------- - -* Fixed ABI compatibility with ``libfmt.so.6.0.0`` - (`#1471 `_). - -* Fixed handling types convertible to ``std::string_view`` - (`#1451 `_). - Thanks `@denizevrenci (Deniz Evrenci) `_. - -* Made CUDA test an opt-in enabled via the ``FMT_CUDA_TEST`` CMake option. - -* Fixed sign conversion warnings - (`#1440 `_). - Thanks `@0x8000-0000 (Florin Iucha) `_. - -6.1.1 - 2019-12-04 ------------------- - -* Fixed shared library build on Windows - (`#1443 `_, - `#1445 `_, - `#1446 `_, - `#1450 `_). - Thanks `@egorpugin (Egor Pugin) `_, - `@bbolli (Beat Bolli) `_. - -* Added a missing decimal point in exponent notation with trailing zeros. - -* Removed deprecated ``format_arg_store::TYPES``. - -6.1.0 - 2019-12-01 ------------------- - -* {fmt} now formats IEEE 754 ``float`` and ``double`` using the shortest decimal - representation with correct rounding by default: - - .. code:: c++ - - #include - #include - - int main() { - fmt::print("{}", M_PI); - } - - prints ``3.141592653589793``. - -* Made the fast binary to decimal floating-point formatter the default, - simplified it and improved performance. {fmt} is now 15 times faster than - libc++'s ``std::ostringstream``, 11 times faster than ``printf`` and 10% - faster than double-conversion on `dtoa-benchmark - `_: - - ================== ========= ======= - Function Time (ns) Speedup - ================== ========= ======= - ostringstream 1,346.30 1.00x - ostrstream 1,195.74 1.13x - sprintf 995.08 1.35x - doubleconv 99.10 13.59x - fmt 88.34 15.24x - ================== ========= ======= - - .. image:: https://user-images.githubusercontent.com/576385/ - 69767160-cdaca400-112f-11ea-9fc5-347c9f83caad.png - -* {fmt} no longer converts ``float`` arguments to ``double``. In particular this - improves the default (shortest) representation of floats and makes - ``fmt::format`` consistent with ``std::format`` specs - (`#1336 `_, - `#1353 `_, - `#1360 `_, - `#1361 `_): - - .. code:: c++ - - fmt::print("{}", 0.1f); - - prints ``0.1`` instead of ``0.10000000149011612``. - - Thanks `@orivej (Orivej Desh) `_. - -* Made floating-point formatting output consistent with ``printf``/iostreams - (`#1376 `_, - `#1417 `_). - -* Added support for 128-bit integers - (`#1287 `_): - - .. code:: c++ - - fmt::print("{}", std::numeric_limits<__int128_t>::max()); - - prints ``170141183460469231731687303715884105727``. - - Thanks `@denizevrenci (Deniz Evrenci) `_. - -* The overload of ``print`` that takes ``text_style`` is now atomic, i.e. the - output from different threads doesn't interleave - (`#1351 `_). - Thanks `@tankiJong (Tanki Zhang) `_. - -* Made compile time in the header-only mode ~20% faster by reducing the number - of template instantiations. ``wchar_t`` overload of ``vprint`` was moved from - ``fmt/core.h`` to ``fmt/format.h``. - -* Added an overload of ``fmt::join`` that works with tuples - (`#1322 `_, - `#1330 `_): - - .. code:: c++ - - #include - #include - - int main() { - std::tuple t{'a', 1, 2.0f}; - fmt::print("{}", t); - } - - prints ``('a', 1, 2.0)``. - - Thanks `@jeremyong (Jeremy Ong) `_. - -* Changed formatting of octal zero with prefix from "00" to "0": - - .. code:: c++ - - fmt::print("{:#o}", 0); - - prints ``0``. - -* The locale is now passed to ostream insertion (``<<``) operators - (`#1406 `_): - - .. code:: c++ - - #include - #include - - struct S { - double value; - }; - - std::ostream& operator<<(std::ostream& os, S s) { - return os << s.value; - } - - int main() { - auto s = fmt::format(std::locale("fr_FR.UTF-8"), "{}", S{0.42}); - // s == "0,42" - } - - Thanks `@dlaugt (Daniel Laügt) `_. - -* Locale-specific number formatting now uses grouping - (`#1393 `_ - `#1394 `_). - Thanks `@skrdaniel `_. - -* Fixed handling of types with deleted implicit rvalue conversion to - ``const char**`` (`#1421 `_): - - .. code:: c++ - - struct mystring { - operator const char*() const&; - operator const char*() &; - operator const char*() const&& = delete; - operator const char*() && = delete; - }; - mystring str; - fmt::print("{}", str); // now compiles - -* Enums are now mapped to correct underlying types instead of ``int`` - (`#1286 `_). - Thanks `@agmt (Egor Seredin) `_. - -* Enum classes are no longer implicitly converted to ``int`` - (`#1424 `_). - -* Added ``basic_format_parse_context`` for consistency with C++20 - ``std::format`` and deprecated ``basic_parse_context``. - -* Fixed handling of UTF-8 in precision - (`#1389 `_, - `#1390 `_). - Thanks `@tajtiattila (Attila Tajti) `_. - -* {fmt} can now be installed on Linux, macOS and Windows with - `Conda `__ using its - `conda-forge `__ - `package `__ - (`#1410 `_):: - - conda install -c conda-forge fmt - - Thanks `@tdegeus (Tom de Geus) `_. - -* Added a CUDA test (`#1285 `_, - `#1317 `_). - Thanks `@luncliff (Park DongHa) `_ and - `@risa2000 `_. - -* Improved documentation (`#1276 `_, - `#1291 `_, - `#1296 `_, - `#1315 `_, - `#1332 `_, - `#1337 `_, - `#1395 `_ - `#1418 `_). - Thanks - `@waywardmonkeys (Bruce Mitchener) `_, - `@pauldreik (Paul Dreik) `_, - `@jackoalan (Jack Andersen) `_. - -* Various code improvements - (`#1358 `_, - `#1407 `_). - Thanks `@orivej (Orivej Desh) `_, - `@dpacbach (David P. Sicilia) `_, - -* Fixed compile-time format string checks for user-defined types - (`#1292 `_). - -* Worked around a false positive in ``unsigned-integer-overflow`` sanitizer - (`#1377 `_). - -* Fixed various warnings and compilation issues - (`#1273 `_, - `#1278 `_, - `#1280 `_, - `#1281 `_, - `#1288 `_, - `#1290 `_, - `#1301 `_, - `#1305 `_, - `#1306 `_, - `#1309 `_, - `#1312 `_, - `#1313 `_, - `#1316 `_, - `#1319 `_, - `#1320 `_, - `#1326 `_, - `#1328 `_, - `#1344 `_, - `#1345 `_, - `#1347 `_, - `#1349 `_, - `#1354 `_, - `#1362 `_, - `#1366 `_, - `#1364 `_, - `#1370 `_, - `#1371 `_, - `#1385 `_, - `#1388 `_, - `#1397 `_, - `#1414 `_, - `#1416 `_, - `#1422 `_ - `#1427 `_, - `#1431 `_, - `#1433 `_). - Thanks `@hhb `_, - `@gsjaardema (Greg Sjaardema) `_, - `@gabime (Gabi Melman) `_, - `@neheb (Rosen Penev) `_, - `@vedranmiletic (Vedran Miletić) `_, - `@dkavolis (Daumantas Kavolis) `_, - `@mwinterb `_, - `@orivej (Orivej Desh) `_, - `@denizevrenci (Deniz Evrenci) `_ - `@leonklingele `_, - `@chronoxor (Ivan Shynkarenka) `_, - `@kent-tri `_, - `@0x8000-0000 (Florin Iucha) `_, - `@marti4d (Chris Martin) `_. - -6.0.0 - 2019-08-26 ------------------- - -* Switched to the `MIT license - `_ - with an optional exception that allows distributing binary code without - attribution. - -* Floating-point formatting is now locale-independent by default: - - .. code:: c++ - - #include - #include - - int main() { - std::locale::global(std::locale("ru_RU.UTF-8")); - fmt::print("value = {}", 4.2); - } - - prints "value = 4.2" regardless of the locale. - - For locale-specific formatting use the ``n`` specifier: - - .. code:: c++ - - std::locale::global(std::locale("ru_RU.UTF-8")); - fmt::print("value = {:n}", 4.2); - - prints "value = 4,2". - -* Added an experimental Grisu floating-point formatting algorithm - implementation (disabled by default). To enable it compile with the - ``FMT_USE_GRISU`` macro defined to 1: - - .. code:: c++ - - #define FMT_USE_GRISU 1 - #include - - auto s = fmt::format("{}", 4.2); // formats 4.2 using Grisu - - With Grisu enabled, {fmt} is 13x faster than ``std::ostringstream`` (libc++) - and 10x faster than ``sprintf`` on `dtoa-benchmark - `_ (`full results - `_): - - .. image:: https://user-images.githubusercontent.com/576385/ - 54883977-9fe8c000-4e28-11e9-8bde-272d122e7c52.jpg - -* Separated formatting and parsing contexts for consistency with - `C++20 std::format `_, removing the - undocumented ``basic_format_context::parse_context()`` function. - -* Added `oss-fuzz `_ support - (`#1199 `_). - Thanks `@pauldreik (Paul Dreik) `_. - -* ``formatter`` specializations now always take precedence over ``operator<<`` - (`#952 `_): - - .. code:: c++ - - #include - #include - - struct S {}; - - std::ostream& operator<<(std::ostream& os, S) { - return os << 1; - } - - template <> - struct fmt::formatter : fmt::formatter { - auto format(S, format_context& ctx) { - return formatter::format(2, ctx); - } - }; - - int main() { - std::cout << S() << "\n"; // prints 1 using operator<< - fmt::print("{}\n", S()); // prints 2 using formatter - } - -* Introduced the experimental ``fmt::compile`` function that does format string - compilation (`#618 `_, - `#1169 `_, - `#1171 `_): - - .. code:: c++ - - #include - - auto f = fmt::compile("{}"); - std::string s = fmt::format(f, 42); // can be called multiple times to - // format different values - // s == "42" - - It moves the cost of parsing a format string outside of the format function - which can be beneficial when identically formatting many objects of the same - types. Thanks `@stryku (Mateusz Janek) `_. - -* Added experimental ``%`` format specifier that formats floating-point values - as percentages (`#1060 `_, - `#1069 `_, - `#1071 `_): - - .. code:: c++ - - auto s = fmt::format("{:.1%}", 0.42); // s == "42.0%" - - Thanks `@gawain-bolton (Gawain Bolton) `_. - -* Implemented precision for floating-point durations - (`#1004 `_, - `#1012 `_): - - .. code:: c++ - - auto s = fmt::format("{:.1}", std::chrono::duration(1.234)); - // s == 1.2s - - Thanks `@DanielaE (Daniela Engert) `_. - -* Implemented ``chrono`` format specifiers ``%Q`` and ``%q`` that give the value - and the unit respectively (`#1019 `_): - - .. code:: c++ - - auto value = fmt::format("{:%Q}", 42s); // value == "42" - auto unit = fmt::format("{:%q}", 42s); // unit == "s" - - Thanks `@DanielaE (Daniela Engert) `_. - -* Fixed handling of dynamic width in chrono formatter: - - .. code:: c++ - - auto s = fmt::format("{0:{1}%H:%M:%S}", std::chrono::seconds(12345), 12); - // ^ width argument index ^ width - // s == "03:25:45 " - - Thanks Howard Hinnant. - -* Removed deprecated ``fmt/time.h``. Use ``fmt/chrono.h`` instead. - -* Added ``fmt::format`` and ``fmt::vformat`` overloads that take ``text_style`` - (`#993 `_, - `#994 `_): - - .. code:: c++ - - #include - - std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), - "The answer is {}.", 42); - - Thanks `@Naios (Denis Blank) `_. - -* Removed the deprecated color API (``print_colored``). Use the new API, namely - ``print`` overloads that take ``text_style`` instead. - -* Made ``std::unique_ptr`` and ``std::shared_ptr`` formattable as pointers via - ``fmt::ptr`` (`#1121 `_): - - .. code:: c++ - - std::unique_ptr p = ...; - fmt::print("{}", fmt::ptr(p)); // prints p as a pointer - - Thanks `@sighingnow (Tao He) `_. - -* Made ``print`` and ``vprint`` report I/O errors - (`#1098 `_, - `#1099 `_). - Thanks `@BillyDonahue (Billy Donahue) `_. - -* Marked deprecated APIs with the ``[[deprecated]]`` attribute and removed - internal uses of deprecated APIs - (`#1022 `_). - Thanks `@eliaskosunen (Elias Kosunen) `_. - -* Modernized the codebase using more C++11 features and removing workarounds. - Most importantly, ``buffer_context`` is now an alias template, so - use ``buffer_context`` instead of ``buffer_context::type``. - These features require GCC 4.8 or later. - -* ``formatter`` specializations now always take precedence over implicit - conversions to ``int`` and the undocumented ``convert_to_int`` trait - is now deprecated. - -* Moved the undocumented ``basic_writer``, ``writer``, and ``wwriter`` types - to the ``internal`` namespace. - -* Removed deprecated ``basic_format_context::begin()``. Use ``out()`` instead. - -* Disallowed passing the result of ``join`` as an lvalue to prevent misuse. - -* Refactored the undocumented structs that represent parsed format specifiers - to simplify the API and allow multibyte fill. - -* Moved SFINAE to template parameters to reduce symbol sizes. - -* Switched to ``fputws`` for writing wide strings so that it's no longer - required to call ``_setmode`` on Windows - (`#1229 `_, - `#1243 `_). - Thanks `@jackoalan (Jack Andersen) `_. - -* Improved literal-based API - (`#1254 `_). - Thanks `@sylveon (Charles Milette) `_. - -* Added support for exotic platforms without ``uintptr_t`` such as IBM i - (AS/400) which has 128-bit pointers and only 64-bit integers - (`#1059 `_). - -* Added `Sublime Text syntax highlighting config - `_ - (`#1037 `_). - Thanks `@Kronuz (Germán Méndez Bravo) `_. - -* Added the ``FMT_ENFORCE_COMPILE_STRING`` macro to enforce the use of - compile-time format strings - (`#1231 `_). - Thanks `@jackoalan (Jack Andersen) `_. - -* Stopped setting ``CMAKE_BUILD_TYPE`` if {fmt} is a subproject - (`#1081 `_). - -* Various build improvements - (`#1039 `_, - `#1078 `_, - `#1091 `_, - `#1103 `_, - `#1177 `_). - Thanks `@luncliff (Park DongHa) `_, - `@jasonszang (Jason Shuo Zang) `_, - `@olafhering (Olaf Hering) `_, - `@Lecetem `_, - `@pauldreik (Paul Dreik) `_. - -* Improved documentation - (`#1049 `_, - `#1051 `_, - `#1083 `_, - `#1113 `_, - `#1114 `_, - `#1146 `_, - `#1180 `_, - `#1250 `_, - `#1252 `_, - `#1265 `_). - Thanks `@mikelui (Michael Lui) `_, - `@foonathan (Jonathan Müller) `_, - `@BillyDonahue (Billy Donahue) `_, - `@jwakely (Jonathan Wakely) `_, - `@kaisbe (Kais Ben Salah) `_, - `@sdebionne (Samuel Debionne) `_. - -* Fixed ambiguous formatter specialization in ``fmt/ranges.h`` - (`#1123 `_). - -* Fixed formatting of a non-empty ``std::filesystem::path`` which is an - infinitely deep range of its components - (`#1268 `_). - -* Fixed handling of general output iterators when formatting characters - (`#1056 `_, - `#1058 `_). - Thanks `@abolz (Alexander Bolz) `_. - -* Fixed handling of output iterators in ``formatter`` specialization for - ranges (`#1064 `_). - -* Fixed handling of exotic character types - (`#1188 `_). - -* Made chrono formatting work with exceptions disabled - (`#1062 `_). - -* Fixed DLL visibility issues - (`#1134 `_, - `#1147 `_). - Thanks `@denchat `_. - -* Disabled the use of UDL template extension on GCC 9 - (`#1148 `_). - -* Removed misplaced ``format`` compile-time checks from ``printf`` - (`#1173 `_). - -* Fixed issues in the experimental floating-point formatter - (`#1072 `_, - `#1129 `_, - `#1153 `_, - `#1155 `_, - `#1210 `_, - `#1222 `_). - Thanks `@alabuzhev (Alex Alabuzhev) `_. - -* Fixed bugs discovered by fuzzing or during fuzzing integration - (`#1124 `_, - `#1127 `_, - `#1132 `_, - `#1135 `_, - `#1136 `_, - `#1141 `_, - `#1142 `_, - `#1178 `_, - `#1179 `_, - `#1194 `_). - Thanks `@pauldreik (Paul Dreik) `_. - -* Fixed building tests on FreeBSD and Hurd - (`#1043 `_). - Thanks `@jackyf (Eugene V. Lyubimkin) `_. - -* Fixed various warnings and compilation issues - (`#998 `_, - `#1006 `_, - `#1008 `_, - `#1011 `_, - `#1025 `_, - `#1027 `_, - `#1028 `_, - `#1029 `_, - `#1030 `_, - `#1031 `_, - `#1054 `_, - `#1063 `_, - `#1068 `_, - `#1074 `_, - `#1075 `_, - `#1079 `_, - `#1086 `_, - `#1088 `_, - `#1089 `_, - `#1094 `_, - `#1101 `_, - `#1102 `_, - `#1105 `_, - `#1107 `_, - `#1115 `_, - `#1117 `_, - `#1118 `_, - `#1120 `_, - `#1123 `_, - `#1139 `_, - `#1140 `_, - `#1143 `_, - `#1144 `_, - `#1150 `_, - `#1151 `_, - `#1152 `_, - `#1154 `_, - `#1156 `_, - `#1159 `_, - `#1175 `_, - `#1181 `_, - `#1186 `_, - `#1187 `_, - `#1191 `_, - `#1197 `_, - `#1200 `_, - `#1203 `_, - `#1205 `_, - `#1206 `_, - `#1213 `_, - `#1214 `_, - `#1217 `_, - `#1228 `_, - `#1230 `_, - `#1232 `_, - `#1235 `_, - `#1236 `_, - `#1240 `_). - Thanks `@DanielaE (Daniela Engert) `_, - `@mwinterb `_, - `@eliaskosunen (Elias Kosunen) `_, - `@morinmorin `_, - `@ricco19 (Brian Ricciardelli) `_, - `@waywardmonkeys (Bruce Mitchener) `_, - `@chronoxor (Ivan Shynkarenka) `_, - `@remyabel `_, - `@pauldreik (Paul Dreik) `_, - `@gsjaardema (Greg Sjaardema) `_, - `@rcane (Ronny Krüger) `_, - `@mocabe `_, - `@denchat `_, - `@cjdb (Christopher Di Bella) `_, - `@HazardyKnusperkeks (Björn Schäpers) `_, - `@vedranmiletic (Vedran Miletić) `_, - `@jackoalan (Jack Andersen) `_, - `@DaanDeMeyer (Daan De Meyer) `_, - `@starkmapper (Mark Stapper) `_. - -5.3.0 - 2018-12-28 ------------------- - -* Introduced experimental chrono formatting support: - - .. code:: c++ - - #include - - int main() { - using namespace std::literals::chrono_literals; - fmt::print("Default format: {} {}\n", 42s, 100ms); - fmt::print("strftime-like format: {:%H:%M:%S}\n", 3h + 15min + 30s); - } - - prints:: - - Default format: 42s 100ms - strftime-like format: 03:15:30 - -* Added experimental support for emphasis (bold, italic, underline, - strikethrough), colored output to a file stream, and improved colored - formatting API - (`#961 `_, - `#967 `_, - `#973 `_): - - .. code:: c++ - - #include - - int main() { - print(fg(fmt::color::crimson) | fmt::emphasis::bold, - "Hello, {}!\n", "world"); - print(fg(fmt::color::floral_white) | bg(fmt::color::slate_gray) | - fmt::emphasis::underline, "Hello, {}!\n", "мир"); - print(fg(fmt::color::steel_blue) | fmt::emphasis::italic, - "Hello, {}!\n", "世界"); - } - - prints the following on modern terminals with RGB color support: - - .. image:: https://user-images.githubusercontent.com/576385/ - 50405788-b66e7500-076e-11e9-9592-7324d1f951d8.png - - Thanks `@Rakete1111 (Nicolas) `_. - -* Added support for 4-bit terminal colors - (`#968 `_, - `#974 `_) - - .. code:: c++ - - #include - - int main() { - print(fg(fmt::terminal_color::red), "stop\n"); - } - - Note that these colors vary by terminal: - - .. image:: https://user-images.githubusercontent.com/576385/ - 50405925-dbfc7e00-0770-11e9-9b85-333fab0af9ac.png - - Thanks `@Rakete1111 (Nicolas) `_. - -* Parameterized formatting functions on the type of the format string - (`#880 `_, - `#881 `_, - `#883 `_, - `#885 `_, - `#897 `_, - `#920 `_). - Any object of type ``S`` that has an overloaded ``to_string_view(const S&)`` - returning ``fmt::string_view`` can be used as a format string: - - .. code:: c++ - - namespace my_ns { - inline string_view to_string_view(const my_string& s) { - return {s.data(), s.length()}; - } - } - - std::string message = fmt::format(my_string("The answer is {}."), 42); - - Thanks `@DanielaE (Daniela Engert) `_. - -* Made ``std::string_view`` work as a format string - (`#898 `_): - - .. code:: c++ - - auto message = fmt::format(std::string_view("The answer is {}."), 42); - - Thanks `@DanielaE (Daniela Engert) `_. - -* Added wide string support to compile-time format string checks - (`#924 `_): - - .. code:: c++ - - print(fmt(L"{:f}"), 42); // compile-time error: invalid type specifier - - Thanks `@XZiar `_. - -* Made colored print functions work with wide strings - (`#867 `_): - - .. code:: c++ - - #include - - int main() { - print(fg(fmt::color::red), L"{}\n", 42); - } - - Thanks `@DanielaE (Daniela Engert) `_. - -* Introduced experimental Unicode support - (`#628 `_, - `#891 `_): - - .. code:: c++ - - using namespace fmt::literals; - auto s = fmt::format("{:*^5}"_u, "🤡"_u); // s == "**🤡**"_u - -* Improved locale support: - - .. code:: c++ - - #include - - struct numpunct : std::numpunct { - protected: - char do_thousands_sep() const override { return '~'; } - }; - - std::locale loc; - auto s = fmt::format(std::locale(loc, new numpunct()), "{:n}", 1234567); - // s == "1~234~567" - -* Constrained formatting functions on proper iterator types - (`#921 `_). - Thanks `@DanielaE (Daniela Engert) `_. - -* Added ``make_printf_args`` and ``make_wprintf_args`` functions - (`#934 `_). - Thanks `@tnovotny `_. - -* Deprecated ``fmt::visit``, ``parse_context``, and ``wparse_context``. - Use ``fmt::visit_format_arg``, ``format_parse_context``, and - ``wformat_parse_context`` instead. - -* Removed undocumented ``basic_fixed_buffer`` which has been superseded by the - iterator-based API - (`#873 `_, - `#902 `_). - Thanks `@superfunc (hollywood programmer) `_. - -* Disallowed repeated leading zeros in an argument ID: - - .. code:: c++ - - fmt::print("{000}", 42); // error - -* Reintroduced support for gcc 4.4. - -* Fixed compilation on platforms with exotic ``double`` - (`#878 `_). - -* Improved documentation - (`#164 `_, - `#877 `_, - `#901 `_, - `#906 `_, - `#979 `_). - Thanks `@kookjr (Mathew Cucuzella) `_, - `@DarkDimius (Dmitry Petrashko) `_, - `@HecticSerenity `_. - -* Added pkgconfig support which makes it easier to consume the library from - meson and other build systems - (`#916 `_). - Thanks `@colemickens (Cole Mickens) `_. - -* Various build improvements - (`#909 `_, - `#926 `_, - `#937 `_, - `#953 `_, - `#959 `_). - Thanks `@tchaikov (Kefu Chai) `_, - `@luncliff (Park DongHa) `_, - `@AndreasSchoenle (Andreas Schönle) `_, - `@hotwatermorning `_, - `@Zefz (JohanJansen) `_. - -* Improved ``string_view`` construction performance - (`#914 `_). - Thanks `@gabime (Gabi Melman) `_. - -* Fixed non-matching char types - (`#895 `_). - Thanks `@DanielaE (Daniela Engert) `_. - -* Fixed ``format_to_n`` with ``std::back_insert_iterator`` - (`#913 `_). - Thanks `@DanielaE (Daniela Engert) `_. - -* Fixed locale-dependent formatting - (`#905 `_). - -* Fixed various compiler warnings and errors - (`#882 `_, - `#886 `_, - `#933 `_, - `#941 `_, - `#931 `_, - `#943 `_, - `#954 `_, - `#956 `_, - `#962 `_, - `#965 `_, - `#977 `_, - `#983 `_, - `#989 `_). - Thanks `@Luthaf (Guillaume Fraux) `_, - `@stevenhoving (Steven Hoving) `_, - `@christinaa (Kristina Brooks) `_, - `@lgritz (Larry Gritz) `_, - `@DanielaE (Daniela Engert) `_, - `@0x8000-0000 (Sign Bit) `_, - `@liuping1997 `_. - -5.2.1 - 2018-09-21 ------------------- - -* Fixed ``visit`` lookup issues on gcc 7 & 8 - (`#870 `_). - Thanks `@medithe `_. - -* Fixed linkage errors on older gcc. - -* Prevented ``fmt/range.h`` from specializing ``fmt::basic_string_view`` - (`#865 `_, - `#868 `_). - Thanks `@hhggit (dual) `_. - -* Improved error message when formatting unknown types - (`#872 `_). - Thanks `@foonathan (Jonathan Müller) `_, - -* Disabled templated user-defined literals when compiled under nvcc - (`#875 `_). - Thanks `@CandyGumdrop (Candy Gumdrop) `_, - -* Fixed ``format_to`` formatting to ``wmemory_buffer`` - (`#874 `_). - -5.2.0 - 2018-09-13 ------------------- - -* Optimized format string parsing and argument processing which resulted in up - to 5x speed up on long format strings and significant performance boost on - various benchmarks. For example, version 5.2 is 2.22x faster than 5.1 on - decimal integer formatting with ``format_to`` (macOS, clang-902.0.39.2): - - ================== ======= ======= - Method Time, s Speedup - ================== ======= ======= - fmt::format 5.1 0.58 - fmt::format 5.2 0.35 1.66x - fmt::format_to 5.1 0.51 - fmt::format_to 5.2 0.23 2.22x - sprintf 0.71 - std::to_string 1.01 - std::stringstream 1.73 - ================== ======= ======= - -* Changed the ``fmt`` macro from opt-out to opt-in to prevent name collisions. - To enable it define the ``FMT_STRING_ALIAS`` macro to 1 before including - ``fmt/format.h``: - - .. code:: c++ - - #define FMT_STRING_ALIAS 1 - #include - std::string answer = format(fmt("{}"), 42); - -* Added compile-time format string checks to ``format_to`` overload that takes - ``fmt::memory_buffer`` (`#783 `_): - - .. code:: c++ - - fmt::memory_buffer buf; - // Compile-time error: invalid type specifier. - fmt::format_to(buf, fmt("{:d}"), "foo"); - -* Moved experimental color support to ``fmt/color.h`` and enabled the - new API by default. The old API can be enabled by defining the - ``FMT_DEPRECATED_COLORS`` macro. - -* Added formatting support for types explicitly convertible to - ``fmt::string_view``: - - .. code:: c++ - - struct foo { - explicit operator fmt::string_view() const { return "foo"; } - }; - auto s = format("{}", foo()); - - In particular, this makes formatting function work with - ``folly::StringPiece``. - -* Implemented preliminary support for ``char*_t`` by replacing the ``format`` - function overloads with a single function template parameterized on the string - type. - -* Added support for dynamic argument lists - (`#814 `_, - `#819 `_). - Thanks `@MikePopoloski (Michael Popoloski) - `_. - -* Reduced executable size overhead for embedded targets using newlib nano by - making locale dependency optional - (`#839 `_). - Thanks `@teajay-fr (Thomas Benard) `_. - -* Keep ``noexcept`` specifier when exceptions are disabled - (`#801 `_, - `#810 `_). - Thanks `@qis (Alexej Harm) `_. - -* Fixed formatting of user-defined types providing ``operator<<`` with - ``format_to_n`` - (`#806 `_). - Thanks `@mkurdej (Marek Kurdej) `_. - -* Fixed dynamic linkage of new symbols - (`#808 `_). - -* Fixed global initialization issue - (`#807 `_): - - .. code:: c++ - - // This works on compilers with constexpr support. - static const std::string answer = fmt::format("{}", 42); - -* Fixed various compiler warnings and errors - (`#804 `_, - `#809 `_, - `#811 `_, - `#822 `_, - `#827 `_, - `#830 `_, - `#838 `_, - `#843 `_, - `#844 `_, - `#851 `_, - `#852 `_, - `#854 `_). - Thanks `@henryiii (Henry Schreiner) `_, - `@medithe `_, and - `@eliasdaler (Elias Daler) `_. - -5.1.0 - 2018-07-05 ------------------- - -* Added experimental support for RGB color output enabled with - the ``FMT_EXTENDED_COLORS`` macro: - - .. code:: c++ - - #define FMT_EXTENDED_COLORS - #define FMT_HEADER_ONLY // or compile fmt with FMT_EXTENDED_COLORS defined - #include - - fmt::print(fmt::color::steel_blue, "Some beautiful text"); - - The old API (the ``print_colored`` and ``vprint_colored`` functions and the - ``color`` enum) is now deprecated. - (`#762 `_ - `#767 `_). - thanks `@Remotion (Remo) `_. - -* Added quotes to strings in ranges and tuples - (`#766 `_). - Thanks `@Remotion (Remo) `_. - -* Made ``format_to`` work with ``basic_memory_buffer`` - (`#776 `_). - -* Added ``vformat_to_n`` and ``wchar_t`` overload of ``format_to_n`` - (`#764 `_, - `#769 `_). - -* Made ``is_range`` and ``is_tuple_like`` part of public (experimental) API - to allow specialization for user-defined types - (`#751 `_, - `#759 `_). - Thanks `@drrlvn (Dror Levin) `_. - -* Added more compilers to continuous integration and increased ``FMT_PEDANTIC`` - warning levels - (`#736 `_). - Thanks `@eliaskosunen (Elias Kosunen) `_. - -* Fixed compilation with MSVC 2013. - -* Fixed handling of user-defined types in ``format_to`` - (`#793 `_). - -* Forced linking of inline ``vformat`` functions into the library - (`#795 `_). - -* Fixed incorrect call to on_align in ``'{:}='`` - (`#750 `_). - -* Fixed floating-point formatting to a non-back_insert_iterator with sign & - numeric alignment specified - (`#756 `_). - -* Fixed formatting to an array with ``format_to_n`` - (`#778 `_). - -* Fixed formatting of more than 15 named arguments - (`#754 `_). - -* Fixed handling of compile-time strings when including ``fmt/ostream.h``. - (`#768 `_). - -* Fixed various compiler warnings and errors - (`#742 `_, - `#748 `_, - `#752 `_, - `#770 `_, - `#775 `_, - `#779 `_, - `#780 `_, - `#790 `_, - `#792 `_, - `#800 `_). - Thanks `@Remotion (Remo) `_, - `@gabime (Gabi Melman) `_, - `@foonathan (Jonathan Müller) `_, - `@Dark-Passenger (Dhruv Paranjape) `_, and - `@0x8000-0000 (Sign Bit) `_. - -5.0.0 - 2018-05-21 ------------------- - -* Added a requirement for partial C++11 support, most importantly variadic - templates and type traits, and dropped ``FMT_VARIADIC_*`` emulation macros. - Variadic templates are available since GCC 4.4, Clang 2.9 and MSVC 18.0 (2013). - For older compilers use {fmt} `version 4.x - `_ which continues to be - maintained and works with C++98 compilers. - -* Renamed symbols to follow standard C++ naming conventions and proposed a subset - of the library for standardization in `P0645R2 Text Formatting - `_. - -* Implemented ``constexpr`` parsing of format strings and `compile-time format - string checks - `_. For - example - - .. code:: c++ - - #include - - std::string s = format(fmt("{:d}"), "foo"); - - gives a compile-time error because ``d`` is an invalid specifier for strings - (`godbolt `__):: - - ... - :4:19: note: in instantiation of function template specialization 'fmt::v5::format' requested here - std::string s = format(fmt("{:d}"), "foo"); - ^ - format.h:1337:13: note: non-constexpr function 'on_error' cannot be used in a constant expression - handler.on_error("invalid type specifier"); - - Compile-time checks require relaxed ``constexpr`` (C++14 feature) support. If - the latter is not available, checks will be performed at runtime. - -* Separated format string parsing and formatting in the extension API to enable - compile-time format string processing. For example - - .. code:: c++ - - struct Answer {}; - - namespace fmt { - template <> - struct formatter { - constexpr auto parse(parse_context& ctx) { - auto it = ctx.begin(); - spec = *it; - if (spec != 'd' && spec != 's') - throw format_error("invalid specifier"); - return ++it; - } - - template - auto format(Answer, FormatContext& ctx) { - return spec == 's' ? - format_to(ctx.begin(), "{}", "fourty-two") : - format_to(ctx.begin(), "{}", 42); - } - - char spec = 0; - }; - } - - std::string s = format(fmt("{:x}"), Answer()); - - gives a compile-time error due to invalid format specifier (`godbolt - `__):: - - ... - :12:45: error: expression '' is not a constant expression - throw format_error("invalid specifier"); - -* Added `iterator support - `_: - - .. code:: c++ - - #include - #include - - std::vector out; - fmt::format_to(std::back_inserter(out), "{}", 42); - -* Added the `format_to_n - `_ - function that restricts the output to the specified number of characters - (`#298 `_): - - .. code:: c++ - - char out[4]; - fmt::format_to_n(out, sizeof(out), "{}", 12345); - // out == "1234" (without terminating '\0') - -* Added the `formatted_size - `_ - function for computing the output size: - - .. code:: c++ - - #include - - auto size = fmt::formatted_size("{}", 12345); // size == 5 - -* Improved compile times by reducing dependencies on standard headers and - providing a lightweight `core API `_: - - .. code:: c++ - - #include - - fmt::print("The answer is {}.", 42); - - See `Compile time and code bloat - `_. - -* Added the `make_format_args - `_ - function for capturing formatting arguments: - - .. code:: c++ - - // Prints formatted error message. - void vreport_error(const char *format, fmt::format_args args) { - fmt::print("Error: "); - fmt::vprint(format, args); - } - template - void report_error(const char *format, const Args & ... args) { - vreport_error(format, fmt::make_format_args(args...)); - } - -* Added the ``make_printf_args`` function for capturing ``printf`` arguments - (`#687 `_, - `#694 `_). - Thanks `@Kronuz (Germán Méndez Bravo) `_. - -* Added prefix ``v`` to non-variadic functions taking ``format_args`` to - distinguish them from variadic ones: - - .. code:: c++ - - std::string vformat(string_view format_str, format_args args); - - template - std::string format(string_view format_str, const Args & ... args); - -* Added experimental support for formatting ranges, containers and tuple-like - types in ``fmt/ranges.h`` (`#735 `_): - - .. code:: c++ - - #include - - std::vector v = {1, 2, 3}; - fmt::print("{}", v); // prints {1, 2, 3} - - Thanks `@Remotion (Remo) `_. - -* Implemented ``wchar_t`` date and time formatting - (`#712 `_): - - .. code:: c++ - - #include - - std::time_t t = std::time(nullptr); - auto s = fmt::format(L"The date is {:%Y-%m-%d}.", *std::localtime(&t)); - - Thanks `@DanielaE (Daniela Engert) `_. - -* Provided more wide string overloads - (`#724 `_). - Thanks `@DanielaE (Daniela Engert) `_. - -* Switched from a custom null-terminated string view class to ``string_view`` - in the format API and provided ``fmt::string_view`` which implements a subset - of ``std::string_view`` API for pre-C++17 systems. - -* Added support for ``std::experimental::string_view`` - (`#607 `_): - - .. code:: c++ - - #include - #include - - fmt::print("{}", std::experimental::string_view("foo")); - - Thanks `@virgiliofornazin (Virgilio Alexandre Fornazin) - `__. - -* Allowed mixing named and automatic arguments: - - .. code:: c++ - - fmt::format("{} {two}", 1, fmt::arg("two", 2)); - -* Removed the write API in favor of the `format API - `_ with compile-time handling of - format strings. - -* Disallowed formatting of multibyte strings into a wide character target - (`#606 `_). - -* Improved documentation - (`#515 `_, - `#614 `_, - `#617 `_, - `#661 `_, - `#680 `_). - Thanks `@ibell (Ian Bell) `_, - `@mihaitodor (Mihai Todor) `_, and - `@johnthagen `_. - -* Implemented more efficient handling of large number of format arguments. - -* Introduced an inline namespace for symbol versioning. - -* Added debug postfix ``d`` to the ``fmt`` library name - (`#636 `_). - -* Removed unnecessary ``fmt/`` prefix in includes - (`#397 `_). - Thanks `@chronoxor (Ivan Shynkarenka) `_. - -* Moved ``fmt/*.h`` to ``include/fmt/*.h`` to prevent irrelevant files and - directories appearing on the include search paths when fmt is used as a - subproject and moved source files to the ``src`` directory. - -* Added qmake project file ``support/fmt.pro`` - (`#641 `_). - Thanks `@cowo78 (Giuseppe Corbelli) `_. - -* Added Gradle build file ``support/build.gradle`` - (`#649 `_). - Thanks `@luncliff (Park DongHa) `_. - -* Removed ``FMT_CPPFORMAT`` CMake option. - -* Fixed a name conflict with the macro ``CHAR_WIDTH`` in glibc - (`#616 `_). - Thanks `@aroig (Abdó Roig-Maranges) `_. - -* Fixed handling of nested braces in ``fmt::join`` - (`#638 `_). - -* Added ``SOURCELINK_SUFFIX`` for compatibility with Sphinx 1.5 - (`#497 `_). - Thanks `@ginggs (Graham Inggs) `_. - -* Added a missing ``inline`` in the header-only mode - (`#626 `_). - Thanks `@aroig (Abdó Roig-Maranges) `_. - -* Fixed various compiler warnings - (`#640 `_, - `#656 `_, - `#679 `_, - `#681 `_, - `#705 `__, - `#715 `_, - `#717 `_, - `#720 `_, - `#723 `_, - `#726 `_, - `#730 `_, - `#739 `_). - Thanks `@peterbell10 `_, - `@LarsGullik `_, - `@foonathan (Jonathan Müller) `_, - `@eliaskosunen (Elias Kosunen) `_, - `@christianparpart (Christian Parpart) `_, - `@DanielaE (Daniela Engert) `_, - and `@mwinterb `_. - -* Worked around an MSVC bug and fixed several warnings - (`#653 `_). - Thanks `@alabuzhev (Alex Alabuzhev) `_. - -* Worked around GCC bug 67371 - (`#682 `_). - -* Fixed compilation with ``-fno-exceptions`` - (`#655 `_). - Thanks `@chenxiaolong (Andrew Gunnerson) `_. - -* Made ``constexpr remove_prefix`` gcc version check tighter - (`#648 `_). - -* Renamed internal type enum constants to prevent collision with poorly written - C libraries (`#644 `_). - -* Added detection of ``wostream operator<<`` - (`#650 `_). - -* Fixed compilation on OpenBSD - (`#660 `_). - Thanks `@hubslave `_. - -* Fixed compilation on FreeBSD 12 - (`#732 `_). - Thanks `@dankm `_. - -* Fixed compilation when there is a mismatch between ``-std`` options between - the library and user code - (`#664 `_). - -* Fixed compilation with GCC 7 and ``-std=c++11`` - (`#734 `_). - -* Improved generated binary code on GCC 7 and older - (`#668 `_). - -* Fixed handling of numeric alignment with no width - (`#675 `_). - -* Fixed handling of empty strings in UTF8/16 converters - (`#676 `_). - Thanks `@vgalka-sl (Vasili Galka) `_. - -* Fixed formatting of an empty ``string_view`` - (`#689 `_). - -* Fixed detection of ``string_view`` on libc++ - (`#686 `_). - -* Fixed DLL issues (`#696 `_). - Thanks `@sebkoenig `_. - -* Fixed compile checks for mixing narrow and wide strings - (`#690 `_). - -* Disabled unsafe implicit conversion to ``std::string`` - (`#729 `_). - -* Fixed handling of reused format specs (as in ``fmt::join``) for pointers - (`#725 `_). - Thanks `@mwinterb `_. - -* Fixed installation of ``fmt/ranges.h`` - (`#738 `_). - Thanks `@sv1990 `_. - -4.1.0 - 2017-12-20 ------------------- - -* Added ``fmt::to_wstring()`` in addition to ``fmt::to_string()`` - (`#559 `_). - Thanks `@alabuzhev (Alex Alabuzhev) `_. - -* Added support for C++17 ``std::string_view`` - (`#571 `_ and - `#578 `_). - Thanks `@thelostt (Mário Feroldi) `_ and - `@mwinterb `_. - -* Enabled stream exceptions to catch errors - (`#581 `_). - Thanks `@crusader-mike `_. - -* Allowed formatting of class hierarchies with ``fmt::format_arg()`` - (`#547 `_). - Thanks `@rollbear (Björn Fahller) `_. - -* Removed limitations on character types - (`#563 `_). - Thanks `@Yelnats321 (Elnar Dakeshov) `_. - -* Conditionally enabled use of ``std::allocator_traits`` - (`#583 `_). - Thanks `@mwinterb `_. - -* Added support for ``const`` variadic member function emulation with - ``FMT_VARIADIC_CONST`` (`#591 `_). - Thanks `@ludekvodicka (Ludek Vodicka) `_. - -* Various bugfixes: bad overflow check, unsupported implicit type conversion - when determining formatting function, test segfaults - (`#551 `_), ill-formed macros - (`#542 `_) and ambiguous overloads - (`#580 `_). - Thanks `@xylosper (Byoung-young Lee) `_. - -* Prevented warnings on MSVC (`#605 `_, - `#602 `_, and - `#545 `_), - clang (`#582 `_), - GCC (`#573 `_), - various conversion warnings (`#609 `_, - `#567 `_, - `#553 `_ and - `#553 `_), and added ``override`` and - ``[[noreturn]]`` (`#549 `_ and - `#555 `_). - Thanks `@alabuzhev (Alex Alabuzhev) `_, - `@virgiliofornazin (Virgilio Alexandre Fornazin) - `_, - `@alexanderbock (Alexander Bock) `_, - `@yumetodo `_, - `@VaderY (Császár Mátyás) `_, - `@jpcima (JP Cimalando) `_, - `@thelostt (Mário Feroldi) `_, and - `@Manu343726 (Manu Sánchez) `_. - -* Improved CMake: Used ``GNUInstallDirs`` to set installation location - (`#610 `_) and fixed warnings - (`#536 `_ and - `#556 `_). - Thanks `@mikecrowe (Mike Crowe) `_, - `@evgen231 `_ and - `@henryiii (Henry Schreiner) `_. - -4.0.0 - 2017-06-27 ------------------- - -* Removed old compatibility headers ``cppformat/*.h`` and CMake options - (`#527 `_). - Thanks `@maddinat0r (Alex Martin) `_. - -* Added ``string.h`` containing ``fmt::to_string()`` as alternative to - ``std::to_string()`` as well as other string writer functionality - (`#326 `_ and - `#441 `_): - - .. code:: c++ - - #include "fmt/string.h" - - std::string answer = fmt::to_string(42); - - Thanks to `@glebov-andrey (Andrey Glebov) - `_. - -* Moved ``fmt::printf()`` to new ``printf.h`` header and allowed ``%s`` as - generic specifier (`#453 `_), - made ``%.f`` more conformant to regular ``printf()`` - (`#490 `_), added custom writer - support (`#476 `_) and implemented - missing custom argument formatting - (`#339 `_ and - `#340 `_): - - .. code:: c++ - - #include "fmt/printf.h" - - // %s format specifier can be used with any argument type. - fmt::printf("%s", 42); - - Thanks `@mojoBrendan `_, - `@manylegged (Arthur Danskin) `_ and - `@spacemoose (Glen Stark) `_. - See also `#360 `_, - `#335 `_ and - `#331 `_. - -* Added ``container.h`` containing a ``BasicContainerWriter`` - to write to containers like ``std::vector`` - (`#450 `_). - Thanks `@polyvertex (Jean-Charles Lefebvre) `_. - -* Added ``fmt::join()`` function that takes a range and formats - its elements separated by a given string - (`#466 `_): - - .. code:: c++ - - #include "fmt/format.h" - - std::vector v = {1.2, 3.4, 5.6}; - // Prints "(+01.20, +03.40, +05.60)". - fmt::print("({:+06.2f})", fmt::join(v.begin(), v.end(), ", ")); - - Thanks `@olivier80 `_. - -* Added support for custom formatting specifications to simplify customization - of built-in formatting (`#444 `_). - Thanks `@polyvertex (Jean-Charles Lefebvre) `_. - See also `#439 `_. - -* Added ``fmt::format_system_error()`` for error code formatting - (`#323 `_ and - `#526 `_). - Thanks `@maddinat0r (Alex Martin) `_. - -* Added thread-safe ``fmt::localtime()`` and ``fmt::gmtime()`` - as replacement for the standard version to ``time.h`` - (`#396 `_). - Thanks `@codicodi `_. - -* Internal improvements to ``NamedArg`` and ``ArgLists`` - (`#389 `_ and - `#390 `_). - Thanks `@chronoxor `_. - -* Fixed crash due to bug in ``FormatBuf`` - (`#493 `_). - Thanks `@effzeh `_. See also - `#480 `_ and - `#491 `_. - -* Fixed handling of wide strings in ``fmt::StringWriter``. - -* Improved compiler error messages - (`#357 `_). - -* Fixed various warnings and issues with various compilers - (`#494 `_, - `#499 `_, - `#483 `_, - `#485 `_, - `#482 `_, - `#475 `_, - `#473 `_ and - `#414 `_). - Thanks `@chronoxor `_, - `@zhaohuaxishi `_, - `@pkestene (Pierre Kestener) `_, - `@dschmidt (Dominik Schmidt) `_ and - `@0x414c (Alexey Gorishny) `_ . - -* Improved CMake: targets are now namespaced - (`#511 `_ and - `#513 `_), supported header-only - ``printf.h`` (`#354 `_), fixed issue - with minimal supported library subset - (`#418 `_, - `#419 `_ and - `#420 `_). - Thanks `@bjoernthiel (Bjoern Thiel) `_, - `@niosHD (Mario Werner) `_, - `@LogicalKnight (Sean LK) `_ and - `@alabuzhev (Alex Alabuzhev) `_. - -* Improved documentation. Thanks to - `@pwm1234 (Phil) `_ for - `#393 `_. - -3.0.2 - 2017-06-14 ------------------- - -* Added ``FMT_VERSION`` macro - (`#411 `_). - -* Used ``FMT_NULL`` instead of literal ``0`` - (`#409 `_). - Thanks `@alabuzhev (Alex Alabuzhev) `_. - -* Added extern templates for ``format_float`` - (`#413 `_). - -* Fixed implicit conversion issue - (`#507 `_). - -* Fixed signbit detection (`#423 `_). - -* Fixed naming collision (`#425 `_). - -* Fixed missing intrinsic for C++/CLI - (`#457 `_). - Thanks `@calumr (Calum Robinson) `_ - -* Fixed Android detection (`#458 `_). - Thanks `@Gachapen (Magnus Bjerke Vik) `_. - -* Use lean ``windows.h`` if not in header-only mode - (`#503 `_). - Thanks `@Quentin01 (Quentin Buathier) `_. - -* Fixed issue with CMake exporting C++11 flag - (`#445 `_). - Thanks `@EricWF (Eric) `_. - -* Fixed issue with nvcc and MSVC compiler bug and MinGW - (`#505 `_). - -* Fixed DLL issues (`#469 `_ and - `#502 `_). - Thanks `@richardeakin (Richard Eakin) `_ and - `@AndreasSchoenle (Andreas Schönle) `_. - -* Fixed test compilation under FreeBSD - (`#433 `_). - -* Fixed various warnings (`#403 `_, - `#410 `_ and - `#510 `_). - Thanks `@Lecetem `_, - `@chenhayat (Chen Hayat) `_ and - `@trozen `_. - -* Worked around a broken ``__builtin_clz`` in clang with MS codegen - (`#519 `_). - -* Removed redundant include - (`#479 `_). - -* Fixed documentation issues. - -3.0.1 - 2016-11-01 ------------------- -* Fixed handling of thousands separator - (`#353 `_). - -* Fixed handling of ``unsigned char`` strings - (`#373 `_). - -* Corrected buffer growth when formatting time - (`#367 `_). - -* Removed warnings under MSVC and clang - (`#318 `_, - `#250 `_, also merged - `#385 `_ and - `#361 `_). - Thanks `@jcelerier (Jean-Michaël Celerier) `_ - and `@nmoehrle (Nils Moehrle) `_. - -* Fixed compilation issues under Android - (`#327 `_, - `#345 `_ and - `#381 `_), - FreeBSD (`#358 `_), - Cygwin (`#388 `_), - MinGW (`#355 `_) as well as other - issues (`#350 `_, - `#366 `_, - `#348 `_, - `#402 `_, - `#405 `_). - Thanks to `@dpantele (Dmitry) `_, - `@hghwng (Hugh Wang) `_, - `@arvedarved (Tilman Keskinöz) `_, - `@LogicalKnight (Sean) `_ and - `@JanHellwig (Jan Hellwig) `_. - -* Fixed some documentation issues and extended specification - (`#320 `_, - `#333 `_, - `#347 `_, - `#362 `_). - Thanks to `@smellman (Taro Matsuzawa aka. btm) - `_. - -3.0.0 - 2016-05-07 ------------------- - -* The project has been renamed from C++ Format (cppformat) to fmt for - consistency with the used namespace and macro prefix - (`#307 `_). - Library headers are now located in the ``fmt`` directory: - - .. code:: c++ - - #include "fmt/format.h" - - Including ``format.h`` from the ``cppformat`` directory is deprecated - but works via a proxy header which will be removed in the next major version. - - The documentation is now available at https://fmt.dev. - -* Added support for `strftime `_-like - `date and time formatting `_ - (`#283 `_): - - .. code:: c++ - - #include "fmt/time.h" - - std::time_t t = std::time(nullptr); - // Prints "The date is 2016-04-29." (with the current date) - fmt::print("The date is {:%Y-%m-%d}.", *std::localtime(&t)); - -* ``std::ostream`` support including formatting of user-defined types that provide - overloaded ``operator<<`` has been moved to ``fmt/ostream.h``: - - .. code:: c++ - - #include "fmt/ostream.h" - - class Date { - int year_, month_, day_; - public: - Date(int year, int month, int day) : year_(year), month_(month), day_(day) {} - - friend std::ostream &operator<<(std::ostream &os, const Date &d) { - return os << d.year_ << '-' << d.month_ << '-' << d.day_; - } - }; - - std::string s = fmt::format("The date is {}", Date(2012, 12, 9)); - // s == "The date is 2012-12-9" - -* Added support for `custom argument formatters - `_ - (`#235 `_). - -* Added support for locale-specific integer formatting with the ``n`` specifier - (`#305 `_): - - .. code:: c++ - - std::setlocale(LC_ALL, "en_US.utf8"); - fmt::print("cppformat: {:n}\n", 1234567); // prints 1,234,567 - -* Sign is now preserved when formatting an integer with an incorrect ``printf`` - format specifier (`#265 `_): - - .. code:: c++ - - fmt::printf("%lld", -42); // prints -42 - - Note that it would be an undefined behavior in ``std::printf``. - -* Length modifiers such as ``ll`` are now optional in printf formatting - functions and the correct type is determined automatically - (`#255 `_): - - .. code:: c++ - - fmt::printf("%d", std::numeric_limits::max()); - - Note that it would be an undefined behavior in ``std::printf``. - -* Added initial support for custom formatters - (`#231 `_). - -* Fixed detection of user-defined literal support on Intel C++ compiler - (`#311 `_, - `#312 `_). - Thanks to `@dean0x7d (Dean Moldovan) `_ and - `@speth (Ray Speth) `_. - -* Reduced compile time - (`#243 `_, - `#249 `_, - `#317 `_): - - .. image:: https://cloud.githubusercontent.com/assets/4831417/11614060/ - b9e826d2-9c36-11e5-8666-d4131bf503ef.png - - .. image:: https://cloud.githubusercontent.com/assets/4831417/11614080/ - 6ac903cc-9c37-11e5-8165-26df6efae364.png - - Thanks to `@dean0x7d (Dean Moldovan) `_. - -* Compile test fixes (`#313 `_). - Thanks to `@dean0x7d (Dean Moldovan) `_. - -* Documentation fixes (`#239 `_, - `#248 `_, - `#252 `_, - `#258 `_, - `#260 `_, - `#301 `_, - `#309 `_). - Thanks to `@ReadmeCritic `_ - `@Gachapen (Magnus Bjerke Vik) `_ and - `@jwilk (Jakub Wilk) `_. - -* Fixed compiler and sanitizer warnings - (`#244 `_, - `#256 `_, - `#259 `_, - `#263 `_, - `#274 `_, - `#277 `_, - `#286 `_, - `#291 `_, - `#296 `_, - `#308 `_) - Thanks to `@mwinterb `_, - `@pweiskircher (Patrik Weiskircher) `_, - `@Naios `_. - -* Improved compatibility with Windows Store apps - (`#280 `_, - `#285 `_) - Thanks to `@mwinterb `_. - -* Added tests of compatibility with older C++ standards - (`#273 `_). - Thanks to `@niosHD `_. - -* Fixed Android build (`#271 `_). - Thanks to `@newnon `_. - -* Changed ``ArgMap`` to be backed by a vector instead of a map. - (`#261 `_, - `#262 `_). - Thanks to `@mwinterb `_. - -* Added ``fprintf`` overload that writes to a ``std::ostream`` - (`#251 `_). - Thanks to `nickhutchinson (Nicholas Hutchinson) `_. - -* Export symbols when building a Windows DLL - (`#245 `_). - Thanks to `macdems (Maciek Dems) `_. - -* Fixed compilation on Cygwin (`#304 `_). - -* Implemented a workaround for a bug in Apple LLVM version 4.2 of clang - (`#276 `_). - -* Implemented a workaround for Google Test bug - `#705 `_ on gcc 6 - (`#268 `_). - Thanks to `octoploid `_. - -* Removed Biicode support because the latter has been discontinued. - -2.1.1 - 2016-04-11 ------------------- - -* The install location for generated CMake files is now configurable via - the ``FMT_CMAKE_DIR`` CMake variable - (`#299 `_). - Thanks to `@niosHD `_. - -* Documentation fixes (`#252 `_). - -2.1.0 - 2016-03-21 ------------------- - -* Project layout and build system improvements - (`#267 `_): - - * The code have been moved to the ``cppformat`` directory. - Including ``format.h`` from the top-level directory is deprecated - but works via a proxy header which will be removed in the next - major version. - - * C++ Format CMake targets now have proper interface definitions. - - * Installed version of the library now supports the header-only - configuration. - - * Targets ``doc``, ``install``, and ``test`` are now disabled if C++ Format - is included as a CMake subproject. They can be enabled by setting - ``FMT_DOC``, ``FMT_INSTALL``, and ``FMT_TEST`` in the parent project. - - Thanks to `@niosHD `_. - -2.0.1 - 2016-03-13 ------------------- - -* Improved CMake find and package support - (`#264 `_). - Thanks to `@niosHD `_. - -* Fix compile error with Android NDK and mingw32 - (`#241 `_). - Thanks to `@Gachapen (Magnus Bjerke Vik) `_. - -* Documentation fixes - (`#248 `_, - `#260 `_). - -2.0.0 - 2015-12-01 ------------------- - -General -~~~~~~~ - -* [Breaking] Named arguments - (`#169 `_, - `#173 `_, - `#174 `_): - - .. code:: c++ - - fmt::print("The answer is {answer}.", fmt::arg("answer", 42)); - - Thanks to `@jamboree `_. - -* [Experimental] User-defined literals for format and named arguments - (`#204 `_, - `#206 `_, - `#207 `_): - - .. code:: c++ - - using namespace fmt::literals; - fmt::print("The answer is {answer}.", "answer"_a=42); - - Thanks to `@dean0x7d (Dean Moldovan) `_. - -* [Breaking] Formatting of more than 16 arguments is now supported when using - variadic templates - (`#141 `_). - Thanks to `@Shauren `_. - -* Runtime width specification - (`#168 `_): - - .. code:: c++ - - fmt::format("{0:{1}}", 42, 5); // gives " 42" - - Thanks to `@jamboree `_. - -* [Breaking] Enums are now formatted with an overloaded ``std::ostream`` insertion - operator (``operator<<``) if available - (`#232 `_). - -* [Breaking] Changed default ``bool`` format to textual, "true" or "false" - (`#170 `_): - - .. code:: c++ - - fmt::print("{}", true); // prints "true" - - To print ``bool`` as a number use numeric format specifier such as ``d``: - - .. code:: c++ - - fmt::print("{:d}", true); // prints "1" - -* ``fmt::printf`` and ``fmt::sprintf`` now support formatting of ``bool`` with the - ``%s`` specifier giving textual output, "true" or "false" - (`#223 `_): - - .. code:: c++ - - fmt::printf("%s", true); // prints "true" - - Thanks to `@LarsGullik `_. - -* [Breaking] ``signed char`` and ``unsigned char`` are now formatted as integers by default - (`#217 `_). - -* [Breaking] Pointers to C strings can now be formatted with the ``p`` specifier - (`#223 `_): - - .. code:: c++ - - fmt::print("{:p}", "test"); // prints pointer value - - Thanks to `@LarsGullik `_. - -* [Breaking] ``fmt::printf`` and ``fmt::sprintf`` now print null pointers as ``(nil)`` - and null strings as ``(null)`` for consistency with glibc - (`#226 `_). - Thanks to `@LarsGullik `_. - -* [Breaking] ``fmt::(s)printf`` now supports formatting of objects of user-defined types - that provide an overloaded ``std::ostream`` insertion operator (``operator<<``) - (`#201 `_): - - .. code:: c++ - - fmt::printf("The date is %s", Date(2012, 12, 9)); - -* [Breaking] The ``Buffer`` template is now part of the public API and can be used - to implement custom memory buffers - (`#140 `_). - Thanks to `@polyvertex (Jean-Charles Lefebvre) `_. - -* [Breaking] Improved compatibility between ``BasicStringRef`` and - `std::experimental::basic_string_view - `_ - (`#100 `_, - `#159 `_, - `#183 `_): - - - Comparison operators now compare string content, not pointers - - ``BasicStringRef::c_str`` replaced by ``BasicStringRef::data`` - - ``BasicStringRef`` is no longer assumed to be null-terminated - - References to null-terminated strings are now represented by a new class, - ``BasicCStringRef``. - -* Dependency on pthreads introduced by Google Test is now optional - (`#185 `_). - -* New CMake options ``FMT_DOC``, ``FMT_INSTALL`` and ``FMT_TEST`` to control - generation of ``doc``, ``install`` and ``test`` targets respectively, on by default - (`#197 `_, - `#198 `_, - `#200 `_). - Thanks to `@maddinat0r (Alex Martin) `_. - -* ``noexcept`` is now used when compiling with MSVC2015 - (`#215 `_). - Thanks to `@dmkrepo (Dmitriy) `_. - -* Added an option to disable use of ``windows.h`` when ``FMT_USE_WINDOWS_H`` - is defined as 0 before including ``format.h`` - (`#171 `_). - Thanks to `@alfps (Alf P. Steinbach) `_. - -* [Breaking] ``windows.h`` is now included with ``NOMINMAX`` unless - ``FMT_WIN_MINMAX`` is defined. This is done to prevent breaking code using - ``std::min`` and ``std::max`` and only affects the header-only configuration - (`#152 `_, - `#153 `_, - `#154 `_). - Thanks to `@DevO2012 `_. - -* Improved support for custom character types - (`#171 `_). - Thanks to `@alfps (Alf P. Steinbach) `_. - -* Added an option to disable use of IOStreams when ``FMT_USE_IOSTREAMS`` - is defined as 0 before including ``format.h`` - (`#205 `_, - `#208 `_). - Thanks to `@JodiTheTigger `_. - -* Improved detection of ``isnan``, ``isinf`` and ``signbit``. - -Optimization -~~~~~~~~~~~~ - -* Made formatting of user-defined types more efficient with a custom stream buffer - (`#92 `_, - `#230 `_). - Thanks to `@NotImplemented `_. - -* Further improved performance of ``fmt::Writer`` on integer formatting - and fixed a minor regression. Now it is ~7% faster than ``karma::generate`` - on Karma's benchmark - (`#186 `_). - -* [Breaking] Reduced `compiled code size - `_ - (`#143 `_, - `#149 `_). - -Distribution -~~~~~~~~~~~~ - -* [Breaking] Headers are now installed in - ``${CMAKE_INSTALL_PREFIX}/include/cppformat`` - (`#178 `_). - Thanks to `@jackyf (Eugene V. Lyubimkin) `_. - -* [Breaking] Changed the library name from ``format`` to ``cppformat`` - for consistency with the project name and to avoid potential conflicts - (`#178 `_). - Thanks to `@jackyf (Eugene V. Lyubimkin) `_. - -* C++ Format is now available in `Debian `_ GNU/Linux - (`stretch `_, - `sid `_) and - derived distributions such as - `Ubuntu `_ 15.10 and later - (`#155 `_):: - - $ sudo apt-get install libcppformat1-dev - - Thanks to `@jackyf (Eugene V. Lyubimkin) `_. - -* `Packages for Fedora and RHEL `_ - are now available. Thanks to Dave Johansen. - -* C++ Format can now be installed via `Homebrew `_ on OS X - (`#157 `_):: - - $ brew install cppformat - - Thanks to `@ortho `_, Anatoliy Bulukin. - -Documentation -~~~~~~~~~~~~~ - -* Migrated from ReadTheDocs to GitHub Pages for better responsiveness - and reliability - (`#128 `_). - New documentation address is http://cppformat.github.io/. - - -* Added `Building the documentation - `_ - section to the documentation. - -* Documentation build script is now compatible with Python 3 and newer pip versions. - (`#189 `_, - `#209 `_). - Thanks to `@JodiTheTigger `_ and - `@xentec `_. - -* Documentation fixes and improvements - (`#36 `_, - `#75 `_, - `#125 `_, - `#160 `_, - `#161 `_, - `#162 `_, - `#165 `_, - `#210 `_). - Thanks to `@syohex (Syohei YOSHIDA) `_ and - bug reporters. - -* Fixed out-of-tree documentation build - (`#177 `_). - Thanks to `@jackyf (Eugene V. Lyubimkin) `_. - -Fixes -~~~~~ - -* Fixed ``initializer_list`` detection - (`#136 `_). - Thanks to `@Gachapen (Magnus Bjerke Vik) `_. - -* [Breaking] Fixed formatting of enums with numeric format specifiers in - ``fmt::(s)printf`` - (`#131 `_, - `#139 `_): - - .. code:: c++ - - enum { ANSWER = 42 }; - fmt::printf("%d", ANSWER); - - Thanks to `@Naios `_. - -* Improved compatibility with old versions of MinGW - (`#129 `_, - `#130 `_, - `#132 `_). - Thanks to `@cstamford (Christopher Stamford) `_. - -* Fixed a compile error on MSVC with disabled exceptions - (`#144 `_). - -* Added a workaround for broken implementation of variadic templates in MSVC2012 - (`#148 `_). - -* Placed the anonymous namespace within ``fmt`` namespace for the header-only - configuration - (`#171 `_). - Thanks to `@alfps (Alf P. Steinbach) `_. - -* Fixed issues reported by Coverity Scan - (`#187 `_, - `#192 `_). - -* Implemented a workaround for a name lookup bug in MSVC2010 - (`#188 `_). - -* Fixed compiler warnings - (`#95 `_, - `#96 `_, - `#114 `_, - `#135 `_, - `#142 `_, - `#145 `_, - `#146 `_, - `#158 `_, - `#163 `_, - `#175 `_, - `#190 `_, - `#191 `_, - `#194 `_, - `#196 `_, - `#216 `_, - `#218 `_, - `#220 `_, - `#229 `_, - `#233 `_, - `#234 `_, - `#236 `_, - `#281 `_, - `#289 `_). - Thanks to `@seanmiddleditch (Sean Middleditch) `_, - `@dixlorenz (Dix Lorenz) `_, - `@CarterLi (李通洲) `_, - `@Naios `_, - `@fmatthew5876 (Matthew Fioravante) `_, - `@LevskiWeng (Levski Weng) `_, - `@rpopescu `_, - `@gabime (Gabi Melman) `_, - `@cubicool (Jeremy Moles) `_, - `@jkflying (Julian Kent) `_, - `@LogicalKnight (Sean L) `_, - `@inguin (Ingo van Lil) `_ and - `@Jopie64 (Johan) `_. - -* Fixed portability issues (mostly causing test failures) on ARM, ppc64, ppc64le, - s390x and SunOS 5.11 i386 - (`#138 `_, - `#179 `_, - `#180 `_, - `#202 `_, - `#225 `_, - `Red Hat Bugzilla Bug 1260297 `_). - Thanks to `@Naios `_, - `@jackyf (Eugene V. Lyubimkin) `_ and Dave Johansen. - -* Fixed a name conflict with macro ``free`` defined in - ``crtdbg.h`` when ``_CRTDBG_MAP_ALLOC`` is set - (`#211 `_). - -* Fixed shared library build on OS X - (`#212 `_). - Thanks to `@dean0x7d (Dean Moldovan) `_. - -* Fixed an overload conflict on MSVC when ``/Zc:wchar_t-`` option is specified - (`#214 `_). - Thanks to `@slavanap (Vyacheslav Napadovsky) `_. - -* Improved compatibility with MSVC 2008 - (`#236 `_). - Thanks to `@Jopie64 (Johan) `_. - -* Improved compatibility with bcc32 - (`#227 `_). - -* Fixed ``static_assert`` detection on Clang - (`#228 `_). - Thanks to `@dean0x7d (Dean Moldovan) `_. - -1.1.0 - 2015-03-06 ------------------- - -* Added ``BasicArrayWriter``, a class template that provides operations for - formatting and writing data into a fixed-size array - (`#105 `_ and - `#122 `_): - - .. code:: c++ - - char buffer[100]; - fmt::ArrayWriter w(buffer); - w.write("The answer is {}", 42); - -* Added `0 A.D. `_ and `PenUltima Online (POL) - `_ to the list of notable projects using C++ Format. - -* C++ Format now uses MSVC intrinsics for better formatting performance - (`#115 `_, - `#116 `_, - `#118 `_ and - `#121 `_). - Previously these optimizations where only used on GCC and Clang. - Thanks to `@CarterLi `_ and - `@objectx `_. - -* CMake install target (`#119 `_). - Thanks to `@TrentHouliston `_. - - You can now install C++ Format with ``make install`` command. - -* Improved `Biicode `_ support - (`#98 `_ and - `#104 `_). Thanks to - `@MariadeAnton `_ and - `@franramirez688 `_. - -* Improved support for building with `Android NDK - `_ - (`#107 `_). - Thanks to `@newnon `_. - - The `android-ndk-example `_ - repository provides and example of using C++ Format with Android NDK: - - .. image:: https://raw.githubusercontent.com/fmtlib/android-ndk-example/ - master/screenshot.png - -* Improved documentation of ``SystemError`` and ``WindowsError`` - (`#54 `_). - -* Various code improvements - (`#110 `_, - `#111 `_ - `#112 `_). - Thanks to `@CarterLi `_. - -* Improved compile-time errors when formatting wide into narrow strings - (`#117 `_). - -* Fixed ``BasicWriter::write`` without formatting arguments when C++11 support - is disabled (`#109 `_). - -* Fixed header-only build on OS X with GCC 4.9 - (`#124 `_). - -* Fixed packaging issues (`#94 `_). - -* Added `changelog `_ - (`#103 `_). - -1.0.0 - 2015-02-05 ------------------- - -* Add support for a header-only configuration when ``FMT_HEADER_ONLY`` is - defined before including ``format.h``: - - .. code:: c++ - - #define FMT_HEADER_ONLY - #include "format.h" - -* Compute string length in the constructor of ``BasicStringRef`` - instead of the ``size`` method - (`#79 `_). - This eliminates size computation for string literals on reasonable optimizing - compilers. - -* Fix formatting of types with overloaded ``operator <<`` for ``std::wostream`` - (`#86 `_): - - .. code:: c++ - - fmt::format(L"The date is {0}", Date(2012, 12, 9)); - -* Fix linkage of tests on Arch Linux - (`#89 `_). - -* Allow precision specifier for non-float arguments - (`#90 `_): - - .. code:: c++ - - fmt::print("{:.3}\n", "Carpet"); // prints "Car" - -* Fix build on Android NDK - (`#93 `_) - -* Improvements to documentation build procedure. - -* Remove ``FMT_SHARED`` CMake variable in favor of standard `BUILD_SHARED_LIBS - `_. - -* Fix error handling in ``fmt::fprintf``. - -* Fix a number of warnings. - -0.12.0 - 2014-10-25 -------------------- - -* [Breaking] Improved separation between formatting and buffer management. - ``Writer`` is now a base class that cannot be instantiated directly. - The new ``MemoryWriter`` class implements the default buffer management - with small allocations done on stack. So ``fmt::Writer`` should be replaced - with ``fmt::MemoryWriter`` in variable declarations. - - Old code: - - .. code:: c++ - - fmt::Writer w; - - New code: - - .. code:: c++ - - fmt::MemoryWriter w; - - If you pass ``fmt::Writer`` by reference, you can continue to do so: - - .. code:: c++ - - void f(fmt::Writer &w); - - This doesn't affect the formatting API. - -* Support for custom memory allocators - (`#69 `_) - -* Formatting functions now accept `signed char` and `unsigned char` strings as - arguments (`#73 `_): - - .. code:: c++ - - auto s = format("GLSL version: {}", glGetString(GL_VERSION)); - -* Reduced code bloat. According to the new `benchmark results - `_, - cppformat is close to ``printf`` and by the order of magnitude better than - Boost Format in terms of compiled code size. - -* Improved appearance of the documentation on mobile by using the `Sphinx - Bootstrap theme `_: - - .. |old| image:: https://cloud.githubusercontent.com/assets/576385/4792130/ - cd256436-5de3-11e4-9a62-c077d0c2b003.png - - .. |new| image:: https://cloud.githubusercontent.com/assets/576385/4792131/ - cd29896c-5de3-11e4-8f59-cac952942bf0.png - - +-------+-------+ - | Old | New | - +-------+-------+ - | |old| | |new| | - +-------+-------+ - -0.11.0 - 2014-08-21 -------------------- - -* Safe printf implementation with a POSIX extension for positional arguments: - - .. code:: c++ - - fmt::printf("Elapsed time: %.2f seconds", 1.23); - fmt::printf("%1$s, %3$d %2$s", weekday, month, day); - -* Arguments of ``char`` type can now be formatted as integers - (Issue `#55 `_): - - .. code:: c++ - - fmt::format("0x{0:02X}", 'a'); - -* Deprecated parts of the API removed. - -* The library is now built and tested on MinGW with Appveyor in addition to - existing test platforms Linux/GCC, OS X/Clang, Windows/MSVC. - -0.10.0 - 2014-07-01 -------------------- - -**Improved API** - -* All formatting methods are now implemented as variadic functions instead - of using ``operator<<`` for feeding arbitrary arguments into a temporary - formatter object. This works both with C++11 where variadic templates are - used and with older standards where variadic functions are emulated by - providing lightweight wrapper functions defined with the ``FMT_VARIADIC`` - macro. You can use this macro for defining your own portable variadic - functions: - - .. code:: c++ - - void report_error(const char *format, const fmt::ArgList &args) { - fmt::print("Error: {}"); - fmt::print(format, args); - } - FMT_VARIADIC(void, report_error, const char *) - - report_error("file not found: {}", path); - - Apart from a more natural syntax, this also improves performance as there - is no need to construct temporary formatter objects and control arguments' - lifetimes. Because the wrapper functions are very lightweight, this doesn't - cause code bloat even in pre-C++11 mode. - -* Simplified common case of formatting an ``std::string``. Now it requires a - single function call: - - .. code:: c++ - - std::string s = format("The answer is {}.", 42); - - Previously it required 2 function calls: - - .. code:: c++ - - std::string s = str(Format("The answer is {}.") << 42); - - Instead of unsafe ``c_str`` function, ``fmt::Writer`` should be used directly - to bypass creation of ``std::string``: - - .. code:: c++ - - fmt::Writer w; - w.write("The answer is {}.", 42); - w.c_str(); // returns a C string - - This doesn't do dynamic memory allocation for small strings and is less error - prone as the lifetime of the string is the same as for ``std::string::c_str`` - which is well understood (hopefully). - -* Improved consistency in naming functions that are a part of the public API. - Now all public functions are lowercase following the standard library - conventions. Previously it was a combination of lowercase and - CapitalizedWords. - Issue `#50 `_. - -* Old functions are marked as deprecated and will be removed in the next - release. - -**Other Changes** - -* Experimental support for printf format specifications (work in progress): - - .. code:: c++ - - fmt::printf("The answer is %d.", 42); - std::string s = fmt::sprintf("Look, a %s!", "string"); - -* Support for hexadecimal floating point format specifiers ``a`` and ``A``: - - .. code:: c++ - - print("{:a}", -42.0); // Prints -0x1.5p+5 - print("{:A}", -42.0); // Prints -0X1.5P+5 - -* CMake option ``FMT_SHARED`` that specifies whether to build format as a - shared library (off by default). - -0.9.0 - 2014-05-13 ------------------- - -* More efficient implementation of variadic formatting functions. - -* ``Writer::Format`` now has a variadic overload: - - .. code:: c++ - - Writer out; - out.Format("Look, I'm {}!", "variadic"); - -* For efficiency and consistency with other overloads, variadic overload of - the ``Format`` function now returns ``Writer`` instead of ``std::string``. - Use the ``str`` function to convert it to ``std::string``: - - .. code:: c++ - - std::string s = str(Format("Look, I'm {}!", "variadic")); - -* Replaced formatter actions with output sinks: ``NoAction`` -> ``NullSink``, - ``Write`` -> ``FileSink``, ``ColorWriter`` -> ``ANSITerminalSink``. - This improves naming consistency and shouldn't affect client code unless - these classes are used directly which should be rarely needed. - -* Added ``ThrowSystemError`` function that formats a message and throws - ``SystemError`` containing the formatted message and system-specific error - description. For example, the following code - - .. code:: c++ - - FILE *f = fopen(filename, "r"); - if (!f) - ThrowSystemError(errno, "Failed to open file '{}'") << filename; - - will throw ``SystemError`` exception with description - "Failed to open file '': No such file or directory" if file - doesn't exist. - -* Support for AppVeyor continuous integration platform. - -* ``Format`` now throws ``SystemError`` in case of I/O errors. - -* Improve test infrastructure. Print functions are now tested by redirecting - the output to a pipe. - -0.8.0 - 2014-04-14 ------------------- - -* Initial release diff --git a/src/common/dep/fmt/args.h b/src/common/dep/fmt/args.h deleted file mode 100644 index 2d684e7cc..000000000 --- a/src/common/dep/fmt/args.h +++ /dev/null @@ -1,234 +0,0 @@ -// Formatting library for C++ - dynamic argument lists -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_ARGS_H_ -#define FMT_ARGS_H_ - -#include // std::reference_wrapper -#include // std::unique_ptr -#include - -#include "core.h" - -FMT_BEGIN_NAMESPACE - -namespace detail { - -template struct is_reference_wrapper : std::false_type {}; -template -struct is_reference_wrapper> : std::true_type {}; - -template const T& unwrap(const T& v) { return v; } -template const T& unwrap(const std::reference_wrapper& v) { - return static_cast(v); -} - -class dynamic_arg_list { - // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for - // templates it doesn't complain about inability to deduce single translation - // unit for placing vtable. So storage_node_base is made a fake template. - template struct node { - virtual ~node() = default; - std::unique_ptr> next; - }; - - template struct typed_node : node<> { - T value; - - template - FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {} - - template - FMT_CONSTEXPR typed_node(const basic_string_view& arg) - : value(arg.data(), arg.size()) {} - }; - - std::unique_ptr> head_; - - public: - template const T& push(const Arg& arg) { - auto new_node = std::unique_ptr>(new typed_node(arg)); - auto& value = new_node->value; - new_node->next = std::move(head_); - head_ = std::move(new_node); - return value; - } -}; -} // namespace detail - -/** - \rst - A dynamic version of `fmt::format_arg_store`. - It's equipped with a storage to potentially temporary objects which lifetimes - could be shorter than the format arguments object. - - It can be implicitly converted into `~fmt::basic_format_args` for passing - into type-erased formatting functions such as `~fmt::vformat`. - \endrst - */ -template -class dynamic_format_arg_store -#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 - // Workaround a GCC template argument substitution bug. - : public basic_format_args -#endif -{ - private: - using char_type = typename Context::char_type; - - template struct need_copy { - static constexpr detail::type mapped_type = - detail::mapped_type_constant::value; - - enum { - value = !(detail::is_reference_wrapper::value || - std::is_same>::value || - std::is_same>::value || - (mapped_type != detail::type::cstring_type && - mapped_type != detail::type::string_type && - mapped_type != detail::type::custom_type)) - }; - }; - - template - using stored_type = conditional_t< - std::is_convertible>::value && - !detail::is_reference_wrapper::value, - std::basic_string, T>; - - // Storage of basic_format_arg must be contiguous. - std::vector> data_; - std::vector> named_info_; - - // Storage of arguments not fitting into basic_format_arg must grow - // without relocation because items in data_ refer to it. - detail::dynamic_arg_list dynamic_args_; - - friend class basic_format_args; - - unsigned long long get_types() const { - return detail::is_unpacked_bit | data_.size() | - (named_info_.empty() - ? 0ULL - : static_cast(detail::has_named_args_bit)); - } - - const basic_format_arg* data() const { - return named_info_.empty() ? data_.data() : data_.data() + 1; - } - - template void emplace_arg(const T& arg) { - data_.emplace_back(detail::make_arg(arg)); - } - - template - void emplace_arg(const detail::named_arg& arg) { - if (named_info_.empty()) { - constexpr const detail::named_arg_info* zero_ptr{nullptr}; - data_.insert(data_.begin(), {zero_ptr, 0}); - } - data_.emplace_back(detail::make_arg(detail::unwrap(arg.value))); - auto pop_one = [](std::vector>* data) { - data->pop_back(); - }; - std::unique_ptr>, decltype(pop_one)> - guard{&data_, pop_one}; - named_info_.push_back({arg.name, static_cast(data_.size() - 2u)}); - data_[0].value_.named_args = {named_info_.data(), named_info_.size()}; - guard.release(); - } - - public: - constexpr dynamic_format_arg_store() = default; - - /** - \rst - Adds an argument into the dynamic store for later passing to a formatting - function. - - Note that custom types and string types (but not string views) are copied - into the store dynamically allocating memory if necessary. - - **Example**:: - - fmt::dynamic_format_arg_store store; - store.push_back(42); - store.push_back("abc"); - store.push_back(1.5f); - std::string result = fmt::vformat("{} and {} and {}", store); - \endrst - */ - template void push_back(const T& arg) { - if (detail::const_check(need_copy::value)) - emplace_arg(dynamic_args_.push>(arg)); - else - emplace_arg(detail::unwrap(arg)); - } - - /** - \rst - Adds a reference to the argument into the dynamic store for later passing to - a formatting function. - - **Example**:: - - fmt::dynamic_format_arg_store store; - char band[] = "Rolling Stones"; - store.push_back(std::cref(band)); - band[9] = 'c'; // Changing str affects the output. - std::string result = fmt::vformat("{}", store); - // result == "Rolling Scones" - \endrst - */ - template void push_back(std::reference_wrapper arg) { - static_assert( - need_copy::value, - "objects of built-in types and string views are always copied"); - emplace_arg(arg.get()); - } - - /** - Adds named argument into the dynamic store for later passing to a formatting - function. ``std::reference_wrapper`` is supported to avoid copying of the - argument. The name is always copied into the store. - */ - template - void push_back(const detail::named_arg& arg) { - const char_type* arg_name = - dynamic_args_.push>(arg.name).c_str(); - if (detail::const_check(need_copy::value)) { - emplace_arg( - fmt::arg(arg_name, dynamic_args_.push>(arg.value))); - } else { - emplace_arg(fmt::arg(arg_name, arg.value)); - } - } - - /** Erase all elements from the store */ - void clear() { - data_.clear(); - named_info_.clear(); - dynamic_args_ = detail::dynamic_arg_list(); - } - - /** - \rst - Reserves space to store at least *new_cap* arguments including - *new_cap_named* named arguments. - \endrst - */ - void reserve(size_t new_cap, size_t new_cap_named) { - FMT_ASSERT(new_cap >= new_cap_named, - "Set of arguments includes set of named arguments"); - data_.reserve(new_cap); - named_info_.reserve(new_cap_named); - } -}; - -FMT_END_NAMESPACE - -#endif // FMT_ARGS_H_ diff --git a/src/common/dep/fmt/chrono.h b/src/common/dep/fmt/chrono.h deleted file mode 100644 index ff3e1445b..000000000 --- a/src/common/dep/fmt/chrono.h +++ /dev/null @@ -1,2208 +0,0 @@ -// Formatting library for C++ - chrono support -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_CHRONO_H_ -#define FMT_CHRONO_H_ - -#include -#include -#include // std::isfinite -#include // std::memcpy -#include -#include -#include -#include -#include - -#include "format.h" - -FMT_BEGIN_NAMESPACE - -// Check if std::chrono::local_t is available. -#ifndef FMT_USE_LOCAL_TIME -# ifdef __cpp_lib_chrono -# define FMT_USE_LOCAL_TIME (__cpp_lib_chrono >= 201907L) -# else -# define FMT_USE_LOCAL_TIME 0 -# endif -#endif - -// Check if std::chrono::utc_timestamp is available. -#ifndef FMT_USE_UTC_TIME -# ifdef __cpp_lib_chrono -# define FMT_USE_UTC_TIME (__cpp_lib_chrono >= 201907L) -# else -# define FMT_USE_UTC_TIME 0 -# endif -#endif - -// Enable tzset. -#ifndef FMT_USE_TZSET -// UWP doesn't provide _tzset. -# if FMT_HAS_INCLUDE("winapifamily.h") -# include -# endif -# if defined(_WIN32) && (!defined(WINAPI_FAMILY) || \ - (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) -# define FMT_USE_TZSET 1 -# else -# define FMT_USE_TZSET 0 -# endif -#endif - -// Enable safe chrono durations, unless explicitly disabled. -#ifndef FMT_SAFE_DURATION_CAST -# define FMT_SAFE_DURATION_CAST 1 -#endif -#if FMT_SAFE_DURATION_CAST - -// For conversion between std::chrono::durations without undefined -// behaviour or erroneous results. -// This is a stripped down version of duration_cast, for inclusion in fmt. -// See https://github.com/pauldreik/safe_duration_cast -// -// Copyright Paul Dreik 2019 -namespace safe_duration_cast { - -template ::value && - std::numeric_limits::is_signed == - std::numeric_limits::is_signed)> -FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { - ec = 0; - using F = std::numeric_limits; - using T = std::numeric_limits; - static_assert(F::is_integer, "From must be integral"); - static_assert(T::is_integer, "To must be integral"); - - // A and B are both signed, or both unsigned. - if (detail::const_check(F::digits <= T::digits)) { - // From fits in To without any problem. - } else { - // From does not always fit in To, resort to a dynamic check. - if (from < (T::min)() || from > (T::max)()) { - // outside range. - ec = 1; - return {}; - } - } - return static_cast(from); -} - -/** - * converts From to To, without loss. If the dynamic value of from - * can't be converted to To without loss, ec is set. - */ -template ::value && - std::numeric_limits::is_signed != - std::numeric_limits::is_signed)> -FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { - ec = 0; - using F = std::numeric_limits; - using T = std::numeric_limits; - static_assert(F::is_integer, "From must be integral"); - static_assert(T::is_integer, "To must be integral"); - - if (detail::const_check(F::is_signed && !T::is_signed)) { - // From may be negative, not allowed! - if (fmt::detail::is_negative(from)) { - ec = 1; - return {}; - } - // From is positive. Can it always fit in To? - if (detail::const_check(F::digits > T::digits) && - from > static_cast(detail::max_value())) { - ec = 1; - return {}; - } - } - - if (detail::const_check(!F::is_signed && T::is_signed && - F::digits >= T::digits) && - from > static_cast(detail::max_value())) { - ec = 1; - return {}; - } - return static_cast(from); // Lossless conversion. -} - -template ::value)> -FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) { - ec = 0; - return from; -} // function - -// clang-format off -/** - * converts From to To if possible, otherwise ec is set. - * - * input | output - * ---------------------------------|--------------- - * NaN | NaN - * Inf | Inf - * normal, fits in output | converted (possibly lossy) - * normal, does not fit in output | ec is set - * subnormal | best effort - * -Inf | -Inf - */ -// clang-format on -template ::value)> -FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) { - ec = 0; - using T = std::numeric_limits; - static_assert(std::is_floating_point::value, "From must be floating"); - static_assert(std::is_floating_point::value, "To must be floating"); - - // catch the only happy case - if (std::isfinite(from)) { - if (from >= T::lowest() && from <= (T::max)()) { - return static_cast(from); - } - // not within range. - ec = 1; - return {}; - } - - // nan and inf will be preserved - return static_cast(from); -} // function - -template ::value)> -FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) { - ec = 0; - static_assert(std::is_floating_point::value, "From must be floating"); - return from; -} - -/** - * safe duration cast between integral durations - */ -template ::value), - FMT_ENABLE_IF(std::is_integral::value)> -To safe_duration_cast(std::chrono::duration from, - int& ec) { - using From = std::chrono::duration; - ec = 0; - // the basic idea is that we need to convert from count() in the from type - // to count() in the To type, by multiplying it with this: - struct Factor - : std::ratio_divide {}; - - static_assert(Factor::num > 0, "num must be positive"); - static_assert(Factor::den > 0, "den must be positive"); - - // the conversion is like this: multiply from.count() with Factor::num - // /Factor::den and convert it to To::rep, all this without - // overflow/underflow. let's start by finding a suitable type that can hold - // both To, From and Factor::num - using IntermediateRep = - typename std::common_type::type; - - // safe conversion to IntermediateRep - IntermediateRep count = - lossless_integral_conversion(from.count(), ec); - if (ec) return {}; - // multiply with Factor::num without overflow or underflow - if (detail::const_check(Factor::num != 1)) { - const auto max1 = detail::max_value() / Factor::num; - if (count > max1) { - ec = 1; - return {}; - } - const auto min1 = - (std::numeric_limits::min)() / Factor::num; - if (detail::const_check(!std::is_unsigned::value) && - count < min1) { - ec = 1; - return {}; - } - count *= Factor::num; - } - - if (detail::const_check(Factor::den != 1)) count /= Factor::den; - auto tocount = lossless_integral_conversion(count, ec); - return ec ? To() : To(tocount); -} - -/** - * safe duration_cast between floating point durations - */ -template ::value), - FMT_ENABLE_IF(std::is_floating_point::value)> -To safe_duration_cast(std::chrono::duration from, - int& ec) { - using From = std::chrono::duration; - ec = 0; - if (std::isnan(from.count())) { - // nan in, gives nan out. easy. - return To{std::numeric_limits::quiet_NaN()}; - } - // maybe we should also check if from is denormal, and decide what to do about - // it. - - // +-inf should be preserved. - if (std::isinf(from.count())) { - return To{from.count()}; - } - - // the basic idea is that we need to convert from count() in the from type - // to count() in the To type, by multiplying it with this: - struct Factor - : std::ratio_divide {}; - - static_assert(Factor::num > 0, "num must be positive"); - static_assert(Factor::den > 0, "den must be positive"); - - // the conversion is like this: multiply from.count() with Factor::num - // /Factor::den and convert it to To::rep, all this without - // overflow/underflow. let's start by finding a suitable type that can hold - // both To, From and Factor::num - using IntermediateRep = - typename std::common_type::type; - - // force conversion of From::rep -> IntermediateRep to be safe, - // even if it will never happen be narrowing in this context. - IntermediateRep count = - safe_float_conversion(from.count(), ec); - if (ec) { - return {}; - } - - // multiply with Factor::num without overflow or underflow - if (detail::const_check(Factor::num != 1)) { - constexpr auto max1 = detail::max_value() / - static_cast(Factor::num); - if (count > max1) { - ec = 1; - return {}; - } - constexpr auto min1 = std::numeric_limits::lowest() / - static_cast(Factor::num); - if (count < min1) { - ec = 1; - return {}; - } - count *= static_cast(Factor::num); - } - - // this can't go wrong, right? den>0 is checked earlier. - if (detail::const_check(Factor::den != 1)) { - using common_t = typename std::common_type::type; - count /= static_cast(Factor::den); - } - - // convert to the to type, safely - using ToRep = typename To::rep; - - const ToRep tocount = safe_float_conversion(count, ec); - if (ec) { - return {}; - } - return To{tocount}; -} -} // namespace safe_duration_cast -#endif - -// Prevents expansion of a preceding token as a function-style macro. -// Usage: f FMT_NOMACRO() -#define FMT_NOMACRO - -namespace detail { -template struct null {}; -inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); } -inline null<> localtime_s(...) { return null<>(); } -inline null<> gmtime_r(...) { return null<>(); } -inline null<> gmtime_s(...) { return null<>(); } - -inline const std::locale& get_classic_locale() { - static const auto& locale = std::locale::classic(); - return locale; -} - -template struct codecvt_result { - static constexpr const size_t max_size = 32; - CodeUnit buf[max_size]; - CodeUnit* end; -}; -template -constexpr const size_t codecvt_result::max_size; - -template -void write_codecvt(codecvt_result& out, string_view in_buf, - const std::locale& loc) { -#if FMT_CLANG_VERSION -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wdeprecated" - auto& f = std::use_facet>(loc); -# pragma clang diagnostic pop -#else - auto& f = std::use_facet>(loc); -#endif - auto mb = std::mbstate_t(); - const char* from_next = nullptr; - auto result = f.in(mb, in_buf.begin(), in_buf.end(), from_next, - std::begin(out.buf), std::end(out.buf), out.end); - if (result != std::codecvt_base::ok) - FMT_THROW(format_error("failed to format time")); -} - -template -auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc) - -> OutputIt { - if (detail::is_utf8() && loc != get_classic_locale()) { - // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and - // gcc-4. -#if FMT_MSC_VERSION != 0 || \ - (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI)) - // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5 - // and newer. - using code_unit = wchar_t; -#else - using code_unit = char32_t; -#endif - - using unit_t = codecvt_result; - unit_t unit; - write_codecvt(unit, in, loc); - // In UTF-8 is used one to four one-byte code units. - auto u = - to_utf8>(); - if (!u.convert({unit.buf, to_unsigned(unit.end - unit.buf)})) - FMT_THROW(format_error("failed to format time")); - return copy_str(u.c_str(), u.c_str() + u.size(), out); - } - return copy_str(in.data(), in.data() + in.size(), out); -} - -template ::value)> -auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) - -> OutputIt { - codecvt_result unit; - write_codecvt(unit, sv, loc); - return copy_str(unit.buf, unit.end, out); -} - -template ::value)> -auto write_tm_str(OutputIt out, string_view sv, const std::locale& loc) - -> OutputIt { - return write_encoded_tm_str(out, sv, loc); -} - -template -inline void do_write(buffer& buf, const std::tm& time, - const std::locale& loc, char format, char modifier) { - auto&& format_buf = formatbuf>(buf); - auto&& os = std::basic_ostream(&format_buf); - os.imbue(loc); - using iterator = std::ostreambuf_iterator; - const auto& facet = std::use_facet>(loc); - auto end = facet.put(os, os, Char(' '), &time, format, modifier); - if (end.failed()) FMT_THROW(format_error("failed to format time")); -} - -template ::value)> -auto write(OutputIt out, const std::tm& time, const std::locale& loc, - char format, char modifier = 0) -> OutputIt { - auto&& buf = get_buffer(out); - do_write(buf, time, loc, format, modifier); - return get_iterator(buf, out); -} - -template ::value)> -auto write(OutputIt out, const std::tm& time, const std::locale& loc, - char format, char modifier = 0) -> OutputIt { - auto&& buf = basic_memory_buffer(); - do_write(buf, time, loc, format, modifier); - return write_encoded_tm_str(out, string_view(buf.data(), buf.size()), loc); -} - -} // namespace detail - -FMT_BEGIN_EXPORT - -/** - Converts given time since epoch as ``std::time_t`` value into calendar time, - expressed in local time. Unlike ``std::localtime``, this function is - thread-safe on most platforms. - */ -inline std::tm localtime(std::time_t time) { - struct dispatcher { - std::time_t time_; - std::tm tm_; - - dispatcher(std::time_t t) : time_(t) {} - - bool run() { - using namespace fmt::detail; - return handle(localtime_r(&time_, &tm_)); - } - - bool handle(std::tm* tm) { return tm != nullptr; } - - bool handle(detail::null<>) { - using namespace fmt::detail; - return fallback(localtime_s(&tm_, &time_)); - } - - bool fallback(int res) { return res == 0; } - -#if !FMT_MSC_VERSION - bool fallback(detail::null<>) { - using namespace fmt::detail; - std::tm* tm = std::localtime(&time_); - if (tm) tm_ = *tm; - return tm != nullptr; - } -#endif - }; - dispatcher lt(time); - // Too big time values may be unsupported. - if (!lt.run()) FMT_THROW(format_error("time_t value out of range")); - return lt.tm_; -} - -#if FMT_USE_LOCAL_TIME -template -inline auto localtime(std::chrono::local_time time) -> std::tm { - return localtime(std::chrono::system_clock::to_time_t( - std::chrono::current_zone()->to_sys(time))); -} -#endif - -/** - Converts given time since epoch as ``std::time_t`` value into calendar time, - expressed in Coordinated Universal Time (UTC). Unlike ``std::gmtime``, this - function is thread-safe on most platforms. - */ -inline std::tm gmtime(std::time_t time) { - struct dispatcher { - std::time_t time_; - std::tm tm_; - - dispatcher(std::time_t t) : time_(t) {} - - bool run() { - using namespace fmt::detail; - return handle(gmtime_r(&time_, &tm_)); - } - - bool handle(std::tm* tm) { return tm != nullptr; } - - bool handle(detail::null<>) { - using namespace fmt::detail; - return fallback(gmtime_s(&tm_, &time_)); - } - - bool fallback(int res) { return res == 0; } - -#if !FMT_MSC_VERSION - bool fallback(detail::null<>) { - std::tm* tm = std::gmtime(&time_); - if (tm) tm_ = *tm; - return tm != nullptr; - } -#endif - }; - auto gt = dispatcher(time); - // Too big time values may be unsupported. - if (!gt.run()) FMT_THROW(format_error("time_t value out of range")); - return gt.tm_; -} - -inline std::tm gmtime( - std::chrono::time_point time_point) { - return gmtime(std::chrono::system_clock::to_time_t(time_point)); -} - -namespace detail { - -// Writes two-digit numbers a, b and c separated by sep to buf. -// The method by Pavel Novikov based on -// https://johnnylee-sde.github.io/Fast-unsigned-integer-to-time-string/. -inline void write_digit2_separated(char* buf, unsigned a, unsigned b, - unsigned c, char sep) { - unsigned long long digits = - a | (b << 24) | (static_cast(c) << 48); - // Convert each value to BCD. - // We have x = a * 10 + b and we want to convert it to BCD y = a * 16 + b. - // The difference is - // y - x = a * 6 - // a can be found from x: - // a = floor(x / 10) - // then - // y = x + a * 6 = x + floor(x / 10) * 6 - // floor(x / 10) is (x * 205) >> 11 (needs 16 bits). - digits += (((digits * 205) >> 11) & 0x000f00000f00000f) * 6; - // Put low nibbles to high bytes and high nibbles to low bytes. - digits = ((digits & 0x00f00000f00000f0) >> 4) | - ((digits & 0x000f00000f00000f) << 8); - auto usep = static_cast(sep); - // Add ASCII '0' to each digit byte and insert separators. - digits |= 0x3030003030003030 | (usep << 16) | (usep << 40); - - constexpr const size_t len = 8; - if (const_check(is_big_endian())) { - char tmp[len]; - std::memcpy(tmp, &digits, len); - std::reverse_copy(tmp, tmp + len, buf); - } else { - std::memcpy(buf, &digits, len); - } -} - -template FMT_CONSTEXPR inline const char* get_units() { - if (std::is_same::value) return "as"; - if (std::is_same::value) return "fs"; - if (std::is_same::value) return "ps"; - if (std::is_same::value) return "ns"; - if (std::is_same::value) return "µs"; - if (std::is_same::value) return "ms"; - if (std::is_same::value) return "cs"; - if (std::is_same::value) return "ds"; - if (std::is_same>::value) return "s"; - if (std::is_same::value) return "das"; - if (std::is_same::value) return "hs"; - if (std::is_same::value) return "ks"; - if (std::is_same::value) return "Ms"; - if (std::is_same::value) return "Gs"; - if (std::is_same::value) return "Ts"; - if (std::is_same::value) return "Ps"; - if (std::is_same::value) return "Es"; - if (std::is_same>::value) return "m"; - if (std::is_same>::value) return "h"; - return nullptr; -} - -enum class numeric_system { - standard, - // Alternative numeric system, e.g. 十二 instead of 12 in ja_JP locale. - alternative -}; - -// Glibc extensions for formatting numeric values. -enum class pad_type { - unspecified, - // Do not pad a numeric result string. - none, - // Pad a numeric result string with zeros even if the conversion specifier - // character uses space-padding by default. - zero, - // Pad a numeric result string with spaces. - space, -}; - -template -auto write_padding(OutputIt out, pad_type pad, int width) -> OutputIt { - if (pad == pad_type::none) return out; - return std::fill_n(out, width, pad == pad_type::space ? ' ' : '0'); -} - -template -auto write_padding(OutputIt out, pad_type pad) -> OutputIt { - if (pad != pad_type::none) *out++ = pad == pad_type::space ? ' ' : '0'; - return out; -} - -// Parses a put_time-like format string and invokes handler actions. -template -FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin, - const Char* end, - Handler&& handler) { - if (begin == end || *begin == '}') return begin; - if (*begin != '%') FMT_THROW(format_error("invalid format")); - auto ptr = begin; - pad_type pad = pad_type::unspecified; - while (ptr != end) { - auto c = *ptr; - if (c == '}') break; - if (c != '%') { - ++ptr; - continue; - } - if (begin != ptr) handler.on_text(begin, ptr); - ++ptr; // consume '%' - if (ptr == end) FMT_THROW(format_error("invalid format")); - c = *ptr; - switch (c) { - case '_': - pad = pad_type::space; - ++ptr; - break; - case '-': - pad = pad_type::none; - ++ptr; - break; - case '0': - pad = pad_type::zero; - ++ptr; - break; - } - if (ptr == end) FMT_THROW(format_error("invalid format")); - c = *ptr++; - switch (c) { - case '%': - handler.on_text(ptr - 1, ptr); - break; - case 'n': { - const Char newline[] = {'\n'}; - handler.on_text(newline, newline + 1); - break; - } - case 't': { - const Char tab[] = {'\t'}; - handler.on_text(tab, tab + 1); - break; - } - // Year: - case 'Y': - handler.on_year(numeric_system::standard); - break; - case 'y': - handler.on_short_year(numeric_system::standard); - break; - case 'C': - handler.on_century(numeric_system::standard); - break; - case 'G': - handler.on_iso_week_based_year(); - break; - case 'g': - handler.on_iso_week_based_short_year(); - break; - // Day of the week: - case 'a': - handler.on_abbr_weekday(); - break; - case 'A': - handler.on_full_weekday(); - break; - case 'w': - handler.on_dec0_weekday(numeric_system::standard); - break; - case 'u': - handler.on_dec1_weekday(numeric_system::standard); - break; - // Month: - case 'b': - case 'h': - handler.on_abbr_month(); - break; - case 'B': - handler.on_full_month(); - break; - case 'm': - handler.on_dec_month(numeric_system::standard); - break; - // Day of the year/month: - case 'U': - handler.on_dec0_week_of_year(numeric_system::standard); - break; - case 'W': - handler.on_dec1_week_of_year(numeric_system::standard); - break; - case 'V': - handler.on_iso_week_of_year(numeric_system::standard); - break; - case 'j': - handler.on_day_of_year(); - break; - case 'd': - handler.on_day_of_month(numeric_system::standard); - break; - case 'e': - handler.on_day_of_month_space(numeric_system::standard); - break; - // Hour, minute, second: - case 'H': - handler.on_24_hour(numeric_system::standard, pad); - break; - case 'I': - handler.on_12_hour(numeric_system::standard, pad); - break; - case 'M': - handler.on_minute(numeric_system::standard, pad); - break; - case 'S': - handler.on_second(numeric_system::standard, pad); - break; - // Other: - case 'c': - handler.on_datetime(numeric_system::standard); - break; - case 'x': - handler.on_loc_date(numeric_system::standard); - break; - case 'X': - handler.on_loc_time(numeric_system::standard); - break; - case 'D': - handler.on_us_date(); - break; - case 'F': - handler.on_iso_date(); - break; - case 'r': - handler.on_12_hour_time(); - break; - case 'R': - handler.on_24_hour_time(); - break; - case 'T': - handler.on_iso_time(); - break; - case 'p': - handler.on_am_pm(); - break; - case 'Q': - handler.on_duration_value(); - break; - case 'q': - handler.on_duration_unit(); - break; - case 'z': - handler.on_utc_offset(numeric_system::standard); - break; - case 'Z': - handler.on_tz_name(); - break; - // Alternative representation: - case 'E': { - if (ptr == end) FMT_THROW(format_error("invalid format")); - c = *ptr++; - switch (c) { - case 'Y': - handler.on_year(numeric_system::alternative); - break; - case 'y': - handler.on_offset_year(); - break; - case 'C': - handler.on_century(numeric_system::alternative); - break; - case 'c': - handler.on_datetime(numeric_system::alternative); - break; - case 'x': - handler.on_loc_date(numeric_system::alternative); - break; - case 'X': - handler.on_loc_time(numeric_system::alternative); - break; - case 'z': - handler.on_utc_offset(numeric_system::alternative); - break; - default: - FMT_THROW(format_error("invalid format")); - } - break; - } - case 'O': - if (ptr == end) FMT_THROW(format_error("invalid format")); - c = *ptr++; - switch (c) { - case 'y': - handler.on_short_year(numeric_system::alternative); - break; - case 'm': - handler.on_dec_month(numeric_system::alternative); - break; - case 'U': - handler.on_dec0_week_of_year(numeric_system::alternative); - break; - case 'W': - handler.on_dec1_week_of_year(numeric_system::alternative); - break; - case 'V': - handler.on_iso_week_of_year(numeric_system::alternative); - break; - case 'd': - handler.on_day_of_month(numeric_system::alternative); - break; - case 'e': - handler.on_day_of_month_space(numeric_system::alternative); - break; - case 'w': - handler.on_dec0_weekday(numeric_system::alternative); - break; - case 'u': - handler.on_dec1_weekday(numeric_system::alternative); - break; - case 'H': - handler.on_24_hour(numeric_system::alternative, pad); - break; - case 'I': - handler.on_12_hour(numeric_system::alternative, pad); - break; - case 'M': - handler.on_minute(numeric_system::alternative, pad); - break; - case 'S': - handler.on_second(numeric_system::alternative, pad); - break; - case 'z': - handler.on_utc_offset(numeric_system::alternative); - break; - default: - FMT_THROW(format_error("invalid format")); - } - break; - default: - FMT_THROW(format_error("invalid format")); - } - begin = ptr; - } - if (begin != ptr) handler.on_text(begin, ptr); - return ptr; -} - -template struct null_chrono_spec_handler { - FMT_CONSTEXPR void unsupported() { - static_cast(this)->unsupported(); - } - FMT_CONSTEXPR void on_year(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_short_year(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_offset_year() { unsupported(); } - FMT_CONSTEXPR void on_century(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_iso_week_based_year() { unsupported(); } - FMT_CONSTEXPR void on_iso_week_based_short_year() { unsupported(); } - FMT_CONSTEXPR void on_abbr_weekday() { unsupported(); } - FMT_CONSTEXPR void on_full_weekday() { unsupported(); } - FMT_CONSTEXPR void on_dec0_weekday(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_dec1_weekday(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_abbr_month() { unsupported(); } - FMT_CONSTEXPR void on_full_month() { unsupported(); } - FMT_CONSTEXPR void on_dec_month(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_day_of_year() { unsupported(); } - FMT_CONSTEXPR void on_day_of_month(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_day_of_month_space(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_24_hour(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_12_hour(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_minute(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_second(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_datetime(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_loc_date(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_loc_time(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_us_date() { unsupported(); } - FMT_CONSTEXPR void on_iso_date() { unsupported(); } - FMT_CONSTEXPR void on_12_hour_time() { unsupported(); } - FMT_CONSTEXPR void on_24_hour_time() { unsupported(); } - FMT_CONSTEXPR void on_iso_time() { unsupported(); } - FMT_CONSTEXPR void on_am_pm() { unsupported(); } - FMT_CONSTEXPR void on_duration_value() { unsupported(); } - FMT_CONSTEXPR void on_duration_unit() { unsupported(); } - FMT_CONSTEXPR void on_utc_offset(numeric_system) { unsupported(); } - FMT_CONSTEXPR void on_tz_name() { unsupported(); } -}; - -struct tm_format_checker : null_chrono_spec_handler { - FMT_NORETURN void unsupported() { FMT_THROW(format_error("no format")); } - - template - FMT_CONSTEXPR void on_text(const Char*, const Char*) {} - FMT_CONSTEXPR void on_year(numeric_system) {} - FMT_CONSTEXPR void on_short_year(numeric_system) {} - FMT_CONSTEXPR void on_offset_year() {} - FMT_CONSTEXPR void on_century(numeric_system) {} - FMT_CONSTEXPR void on_iso_week_based_year() {} - FMT_CONSTEXPR void on_iso_week_based_short_year() {} - FMT_CONSTEXPR void on_abbr_weekday() {} - FMT_CONSTEXPR void on_full_weekday() {} - FMT_CONSTEXPR void on_dec0_weekday(numeric_system) {} - FMT_CONSTEXPR void on_dec1_weekday(numeric_system) {} - FMT_CONSTEXPR void on_abbr_month() {} - FMT_CONSTEXPR void on_full_month() {} - FMT_CONSTEXPR void on_dec_month(numeric_system) {} - FMT_CONSTEXPR void on_dec0_week_of_year(numeric_system) {} - FMT_CONSTEXPR void on_dec1_week_of_year(numeric_system) {} - FMT_CONSTEXPR void on_iso_week_of_year(numeric_system) {} - FMT_CONSTEXPR void on_day_of_year() {} - FMT_CONSTEXPR void on_day_of_month(numeric_system) {} - FMT_CONSTEXPR void on_day_of_month_space(numeric_system) {} - FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_second(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_datetime(numeric_system) {} - FMT_CONSTEXPR void on_loc_date(numeric_system) {} - FMT_CONSTEXPR void on_loc_time(numeric_system) {} - FMT_CONSTEXPR void on_us_date() {} - FMT_CONSTEXPR void on_iso_date() {} - FMT_CONSTEXPR void on_12_hour_time() {} - FMT_CONSTEXPR void on_24_hour_time() {} - FMT_CONSTEXPR void on_iso_time() {} - FMT_CONSTEXPR void on_am_pm() {} - FMT_CONSTEXPR void on_utc_offset(numeric_system) {} - FMT_CONSTEXPR void on_tz_name() {} -}; - -inline const char* tm_wday_full_name(int wday) { - static constexpr const char* full_name_list[] = { - "Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday"}; - return wday >= 0 && wday <= 6 ? full_name_list[wday] : "?"; -} -inline const char* tm_wday_short_name(int wday) { - static constexpr const char* short_name_list[] = {"Sun", "Mon", "Tue", "Wed", - "Thu", "Fri", "Sat"}; - return wday >= 0 && wday <= 6 ? short_name_list[wday] : "???"; -} - -inline const char* tm_mon_full_name(int mon) { - static constexpr const char* full_name_list[] = { - "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December"}; - return mon >= 0 && mon <= 11 ? full_name_list[mon] : "?"; -} -inline const char* tm_mon_short_name(int mon) { - static constexpr const char* short_name_list[] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - }; - return mon >= 0 && mon <= 11 ? short_name_list[mon] : "???"; -} - -template -struct has_member_data_tm_gmtoff : std::false_type {}; -template -struct has_member_data_tm_gmtoff> - : std::true_type {}; - -template -struct has_member_data_tm_zone : std::false_type {}; -template -struct has_member_data_tm_zone> - : std::true_type {}; - -#if FMT_USE_TZSET -inline void tzset_once() { - static bool init = []() -> bool { - _tzset(); - return true; - }(); - ignore_unused(init); -} -#endif - -// Converts value to Int and checks that it's in the range [0, upper). -template ::value)> -inline Int to_nonnegative_int(T value, Int upper) { - FMT_ASSERT(std::is_unsigned::value || - (value >= 0 && to_unsigned(value) <= to_unsigned(upper)), - "invalid value"); - (void)upper; - return static_cast(value); -} -template ::value)> -inline Int to_nonnegative_int(T value, Int upper) { - if (value < 0 || value > static_cast(upper)) - FMT_THROW(format_error("invalid value")); - return static_cast(value); -} - -constexpr long long pow10(std::uint32_t n) { - return n == 0 ? 1 : 10 * pow10(n - 1); -} - -// Counts the number of fractional digits in the range [0, 18] according to the -// C++20 spec. If more than 18 fractional digits are required then returns 6 for -// microseconds precision. -template () / 10)> -struct count_fractional_digits { - static constexpr int value = - Num % Den == 0 ? N : count_fractional_digits::value; -}; - -// Base case that doesn't instantiate any more templates -// in order to avoid overflow. -template -struct count_fractional_digits { - static constexpr int value = (Num % Den == 0) ? N : 6; -}; - -// Format subseconds which are given as an integer type with an appropriate -// number of digits. -template -void write_fractional_seconds(OutputIt& out, Duration d, int precision = -1) { - constexpr auto num_fractional_digits = - count_fractional_digits::value; - - using subsecond_precision = std::chrono::duration< - typename std::common_type::type, - std::ratio<1, detail::pow10(num_fractional_digits)>>; - - const auto fractional = - d - std::chrono::duration_cast(d); - const auto subseconds = - std::chrono::treat_as_floating_point< - typename subsecond_precision::rep>::value - ? fractional.count() - : std::chrono::duration_cast(fractional).count(); - auto n = static_cast>(subseconds); - const int num_digits = detail::count_digits(n); - - int leading_zeroes = (std::max)(0, num_fractional_digits - num_digits); - if (precision < 0) { - FMT_ASSERT(!std::is_floating_point::value, ""); - if (std::ratio_less::value) { - *out++ = '.'; - out = std::fill_n(out, leading_zeroes, '0'); - out = format_decimal(out, n, num_digits).end; - } - } else { - *out++ = '.'; - leading_zeroes = (std::min)(leading_zeroes, precision); - out = std::fill_n(out, leading_zeroes, '0'); - int remaining = precision - leading_zeroes; - if (remaining != 0 && remaining < num_digits) { - n /= to_unsigned(detail::pow10(to_unsigned(num_digits - remaining))); - out = format_decimal(out, n, remaining).end; - return; - } - out = format_decimal(out, n, num_digits).end; - remaining -= num_digits; - out = std::fill_n(out, remaining, '0'); - } -} - -// Format subseconds which are given as a floating point type with an -// appropriate number of digits. We cannot pass the Duration here, as we -// explicitly need to pass the Rep value in the chrono_formatter. -template -void write_floating_seconds(memory_buffer& buf, Duration duration, - int num_fractional_digits = -1) { - using rep = typename Duration::rep; - FMT_ASSERT(std::is_floating_point::value, ""); - - auto val = duration.count(); - - if (num_fractional_digits < 0) { - // For `std::round` with fallback to `round`: - // On some toolchains `std::round` is not available (e.g. GCC 6). - using namespace std; - num_fractional_digits = - count_fractional_digits::value; - if (num_fractional_digits < 6 && static_cast(round(val)) != val) - num_fractional_digits = 6; - } - - format_to(std::back_inserter(buf), FMT_STRING("{:.{}f}"), - std::fmod(val * static_cast(Duration::period::num) / - static_cast(Duration::period::den), - static_cast(60)), - num_fractional_digits); -} - -template -class tm_writer { - private: - static constexpr int days_per_week = 7; - - const std::locale& loc_; - const bool is_classic_; - OutputIt out_; - const Duration* subsecs_; - const std::tm& tm_; - - auto tm_sec() const noexcept -> int { - FMT_ASSERT(tm_.tm_sec >= 0 && tm_.tm_sec <= 61, ""); - return tm_.tm_sec; - } - auto tm_min() const noexcept -> int { - FMT_ASSERT(tm_.tm_min >= 0 && tm_.tm_min <= 59, ""); - return tm_.tm_min; - } - auto tm_hour() const noexcept -> int { - FMT_ASSERT(tm_.tm_hour >= 0 && tm_.tm_hour <= 23, ""); - return tm_.tm_hour; - } - auto tm_mday() const noexcept -> int { - FMT_ASSERT(tm_.tm_mday >= 1 && tm_.tm_mday <= 31, ""); - return tm_.tm_mday; - } - auto tm_mon() const noexcept -> int { - FMT_ASSERT(tm_.tm_mon >= 0 && tm_.tm_mon <= 11, ""); - return tm_.tm_mon; - } - auto tm_year() const noexcept -> long long { return 1900ll + tm_.tm_year; } - auto tm_wday() const noexcept -> int { - FMT_ASSERT(tm_.tm_wday >= 0 && tm_.tm_wday <= 6, ""); - return tm_.tm_wday; - } - auto tm_yday() const noexcept -> int { - FMT_ASSERT(tm_.tm_yday >= 0 && tm_.tm_yday <= 365, ""); - return tm_.tm_yday; - } - - auto tm_hour12() const noexcept -> int { - const auto h = tm_hour(); - const auto z = h < 12 ? h : h - 12; - return z == 0 ? 12 : z; - } - - // POSIX and the C Standard are unclear or inconsistent about what %C and %y - // do if the year is negative or exceeds 9999. Use the convention that %C - // concatenated with %y yields the same output as %Y, and that %Y contains at - // least 4 characters, with more only if necessary. - auto split_year_lower(long long year) const noexcept -> int { - auto l = year % 100; - if (l < 0) l = -l; // l in [0, 99] - return static_cast(l); - } - - // Algorithm: - // https://en.wikipedia.org/wiki/ISO_week_date#Calculating_the_week_number_from_a_month_and_day_of_the_month_or_ordinal_date - auto iso_year_weeks(long long curr_year) const noexcept -> int { - const auto prev_year = curr_year - 1; - const auto curr_p = - (curr_year + curr_year / 4 - curr_year / 100 + curr_year / 400) % - days_per_week; - const auto prev_p = - (prev_year + prev_year / 4 - prev_year / 100 + prev_year / 400) % - days_per_week; - return 52 + ((curr_p == 4 || prev_p == 3) ? 1 : 0); - } - auto iso_week_num(int tm_yday, int tm_wday) const noexcept -> int { - return (tm_yday + 11 - (tm_wday == 0 ? days_per_week : tm_wday)) / - days_per_week; - } - auto tm_iso_week_year() const noexcept -> long long { - const auto year = tm_year(); - const auto w = iso_week_num(tm_yday(), tm_wday()); - if (w < 1) return year - 1; - if (w > iso_year_weeks(year)) return year + 1; - return year; - } - auto tm_iso_week_of_year() const noexcept -> int { - const auto year = tm_year(); - const auto w = iso_week_num(tm_yday(), tm_wday()); - if (w < 1) return iso_year_weeks(year - 1); - if (w > iso_year_weeks(year)) return 1; - return w; - } - - void write1(int value) { - *out_++ = static_cast('0' + to_unsigned(value) % 10); - } - void write2(int value) { - const char* d = digits2(to_unsigned(value) % 100); - *out_++ = *d++; - *out_++ = *d; - } - void write2(int value, pad_type pad) { - unsigned int v = to_unsigned(value) % 100; - if (v >= 10) { - const char* d = digits2(v); - *out_++ = *d++; - *out_++ = *d; - } else { - out_ = detail::write_padding(out_, pad); - *out_++ = static_cast('0' + v); - } - } - - void write_year_extended(long long year) { - // At least 4 characters. - int width = 4; - if (year < 0) { - *out_++ = '-'; - year = 0 - year; - --width; - } - uint32_or_64_or_128_t n = to_unsigned(year); - const int num_digits = count_digits(n); - if (width > num_digits) out_ = std::fill_n(out_, width - num_digits, '0'); - out_ = format_decimal(out_, n, num_digits).end; - } - void write_year(long long year) { - if (year >= 0 && year < 10000) { - write2(static_cast(year / 100)); - write2(static_cast(year % 100)); - } else { - write_year_extended(year); - } - } - - void write_utc_offset(long offset, numeric_system ns) { - if (offset < 0) { - *out_++ = '-'; - offset = -offset; - } else { - *out_++ = '+'; - } - offset /= 60; - write2(static_cast(offset / 60)); - if (ns != numeric_system::standard) *out_++ = ':'; - write2(static_cast(offset % 60)); - } - template ::value)> - void format_utc_offset_impl(const T& tm, numeric_system ns) { - write_utc_offset(tm.tm_gmtoff, ns); - } - template ::value)> - void format_utc_offset_impl(const T& tm, numeric_system ns) { -#if defined(_WIN32) && defined(_UCRT) -# if FMT_USE_TZSET - tzset_once(); -# endif - long offset = 0; - _get_timezone(&offset); - if (tm.tm_isdst) { - long dstbias = 0; - _get_dstbias(&dstbias); - offset += dstbias; - } - write_utc_offset(-offset, ns); -#else - if (ns == numeric_system::standard) return format_localized('z'); - - // Extract timezone offset from timezone conversion functions. - std::tm gtm = tm; - std::time_t gt = std::mktime(>m); - std::tm ltm = gmtime(gt); - std::time_t lt = std::mktime(<m); - long offset = gt - lt; - write_utc_offset(offset, ns); -#endif - } - - template ::value)> - void format_tz_name_impl(const T& tm) { - if (is_classic_) - out_ = write_tm_str(out_, tm.tm_zone, loc_); - else - format_localized('Z'); - } - template ::value)> - void format_tz_name_impl(const T&) { - format_localized('Z'); - } - - void format_localized(char format, char modifier = 0) { - out_ = write(out_, tm_, loc_, format, modifier); - } - - public: - tm_writer(const std::locale& loc, OutputIt out, const std::tm& tm, - const Duration* subsecs = nullptr) - : loc_(loc), - is_classic_(loc_ == get_classic_locale()), - out_(out), - subsecs_(subsecs), - tm_(tm) {} - - OutputIt out() const { return out_; } - - FMT_CONSTEXPR void on_text(const Char* begin, const Char* end) { - out_ = copy_str(begin, end, out_); - } - - void on_abbr_weekday() { - if (is_classic_) - out_ = write(out_, tm_wday_short_name(tm_wday())); - else - format_localized('a'); - } - void on_full_weekday() { - if (is_classic_) - out_ = write(out_, tm_wday_full_name(tm_wday())); - else - format_localized('A'); - } - void on_dec0_weekday(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) return write1(tm_wday()); - format_localized('w', 'O'); - } - void on_dec1_weekday(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) { - auto wday = tm_wday(); - write1(wday == 0 ? days_per_week : wday); - } else { - format_localized('u', 'O'); - } - } - - void on_abbr_month() { - if (is_classic_) - out_ = write(out_, tm_mon_short_name(tm_mon())); - else - format_localized('b'); - } - void on_full_month() { - if (is_classic_) - out_ = write(out_, tm_mon_full_name(tm_mon())); - else - format_localized('B'); - } - - void on_datetime(numeric_system ns) { - if (is_classic_) { - on_abbr_weekday(); - *out_++ = ' '; - on_abbr_month(); - *out_++ = ' '; - on_day_of_month_space(numeric_system::standard); - *out_++ = ' '; - on_iso_time(); - *out_++ = ' '; - on_year(numeric_system::standard); - } else { - format_localized('c', ns == numeric_system::standard ? '\0' : 'E'); - } - } - void on_loc_date(numeric_system ns) { - if (is_classic_) - on_us_date(); - else - format_localized('x', ns == numeric_system::standard ? '\0' : 'E'); - } - void on_loc_time(numeric_system ns) { - if (is_classic_) - on_iso_time(); - else - format_localized('X', ns == numeric_system::standard ? '\0' : 'E'); - } - void on_us_date() { - char buf[8]; - write_digit2_separated(buf, to_unsigned(tm_mon() + 1), - to_unsigned(tm_mday()), - to_unsigned(split_year_lower(tm_year())), '/'); - out_ = copy_str(std::begin(buf), std::end(buf), out_); - } - void on_iso_date() { - auto year = tm_year(); - char buf[10]; - size_t offset = 0; - if (year >= 0 && year < 10000) { - copy2(buf, digits2(static_cast(year / 100))); - } else { - offset = 4; - write_year_extended(year); - year = 0; - } - write_digit2_separated(buf + 2, static_cast(year % 100), - to_unsigned(tm_mon() + 1), to_unsigned(tm_mday()), - '-'); - out_ = copy_str(std::begin(buf) + offset, std::end(buf), out_); - } - - void on_utc_offset(numeric_system ns) { format_utc_offset_impl(tm_, ns); } - void on_tz_name() { format_tz_name_impl(tm_); } - - void on_year(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) - return write_year(tm_year()); - format_localized('Y', 'E'); - } - void on_short_year(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) - return write2(split_year_lower(tm_year())); - format_localized('y', 'O'); - } - void on_offset_year() { - if (is_classic_) return write2(split_year_lower(tm_year())); - format_localized('y', 'E'); - } - - void on_century(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) { - auto year = tm_year(); - auto upper = year / 100; - if (year >= -99 && year < 0) { - // Zero upper on negative year. - *out_++ = '-'; - *out_++ = '0'; - } else if (upper >= 0 && upper < 100) { - write2(static_cast(upper)); - } else { - out_ = write(out_, upper); - } - } else { - format_localized('C', 'E'); - } - } - - void on_dec_month(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) - return write2(tm_mon() + 1); - format_localized('m', 'O'); - } - - void on_dec0_week_of_year(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) - return write2((tm_yday() + days_per_week - tm_wday()) / days_per_week); - format_localized('U', 'O'); - } - void on_dec1_week_of_year(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) { - auto wday = tm_wday(); - write2((tm_yday() + days_per_week - - (wday == 0 ? (days_per_week - 1) : (wday - 1))) / - days_per_week); - } else { - format_localized('W', 'O'); - } - } - void on_iso_week_of_year(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) - return write2(tm_iso_week_of_year()); - format_localized('V', 'O'); - } - - void on_iso_week_based_year() { write_year(tm_iso_week_year()); } - void on_iso_week_based_short_year() { - write2(split_year_lower(tm_iso_week_year())); - } - - void on_day_of_year() { - auto yday = tm_yday() + 1; - write1(yday / 100); - write2(yday % 100); - } - void on_day_of_month(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) return write2(tm_mday()); - format_localized('d', 'O'); - } - void on_day_of_month_space(numeric_system ns) { - if (is_classic_ || ns == numeric_system::standard) { - auto mday = to_unsigned(tm_mday()) % 100; - const char* d2 = digits2(mday); - *out_++ = mday < 10 ? ' ' : d2[0]; - *out_++ = d2[1]; - } else { - format_localized('e', 'O'); - } - } - - void on_24_hour(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) - return write2(tm_hour(), pad); - format_localized('H', 'O'); - } - void on_12_hour(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) - return write2(tm_hour12(), pad); - format_localized('I', 'O'); - } - void on_minute(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) - return write2(tm_min(), pad); - format_localized('M', 'O'); - } - - void on_second(numeric_system ns, pad_type pad) { - if (is_classic_ || ns == numeric_system::standard) { - write2(tm_sec(), pad); - if (subsecs_) { - if (std::is_floating_point::value) { - auto buf = memory_buffer(); - write_floating_seconds(buf, *subsecs_); - if (buf.size() > 1) { - // Remove the leading "0", write something like ".123". - out_ = std::copy(buf.begin() + 1, buf.end(), out_); - } - } else { - write_fractional_seconds(out_, *subsecs_); - } - } - } else { - // Currently no formatting of subseconds when a locale is set. - format_localized('S', 'O'); - } - } - - void on_12_hour_time() { - if (is_classic_) { - char buf[8]; - write_digit2_separated(buf, to_unsigned(tm_hour12()), - to_unsigned(tm_min()), to_unsigned(tm_sec()), ':'); - out_ = copy_str(std::begin(buf), std::end(buf), out_); - *out_++ = ' '; - on_am_pm(); - } else { - format_localized('r'); - } - } - void on_24_hour_time() { - write2(tm_hour()); - *out_++ = ':'; - write2(tm_min()); - } - void on_iso_time() { - on_24_hour_time(); - *out_++ = ':'; - on_second(numeric_system::standard, pad_type::unspecified); - } - - void on_am_pm() { - if (is_classic_) { - *out_++ = tm_hour() < 12 ? 'A' : 'P'; - *out_++ = 'M'; - } else { - format_localized('p'); - } - } - - // These apply to chrono durations but not tm. - void on_duration_value() {} - void on_duration_unit() {} -}; - -struct chrono_format_checker : null_chrono_spec_handler { - bool has_precision_integral = false; - - FMT_NORETURN void unsupported() { FMT_THROW(format_error("no date")); } - - template - FMT_CONSTEXPR void on_text(const Char*, const Char*) {} - FMT_CONSTEXPR void on_24_hour(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_12_hour(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_minute(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_second(numeric_system, pad_type) {} - FMT_CONSTEXPR void on_12_hour_time() {} - FMT_CONSTEXPR void on_24_hour_time() {} - FMT_CONSTEXPR void on_iso_time() {} - FMT_CONSTEXPR void on_am_pm() {} - FMT_CONSTEXPR void on_duration_value() const { - if (has_precision_integral) { - FMT_THROW(format_error("precision not allowed for this argument type")); - } - } - FMT_CONSTEXPR void on_duration_unit() {} -}; - -template ::value&& has_isfinite::value)> -inline bool isfinite(T) { - return true; -} - -template ::value)> -inline T mod(T x, int y) { - return x % static_cast(y); -} -template ::value)> -inline T mod(T x, int y) { - return std::fmod(x, static_cast(y)); -} - -// If T is an integral type, maps T to its unsigned counterpart, otherwise -// leaves it unchanged (unlike std::make_unsigned). -template ::value> -struct make_unsigned_or_unchanged { - using type = T; -}; - -template struct make_unsigned_or_unchanged { - using type = typename std::make_unsigned::type; -}; - -#if FMT_SAFE_DURATION_CAST -// throwing version of safe_duration_cast -template -To fmt_safe_duration_cast(std::chrono::duration from) { - int ec; - To to = safe_duration_cast::safe_duration_cast(from, ec); - if (ec) FMT_THROW(format_error("cannot format duration")); - return to; -} -#endif - -template ::value)> -inline std::chrono::duration get_milliseconds( - std::chrono::duration d) { - // this may overflow and/or the result may not fit in the - // target type. -#if FMT_SAFE_DURATION_CAST - using CommonSecondsType = - typename std::common_type::type; - const auto d_as_common = fmt_safe_duration_cast(d); - const auto d_as_whole_seconds = - fmt_safe_duration_cast(d_as_common); - // this conversion should be nonproblematic - const auto diff = d_as_common - d_as_whole_seconds; - const auto ms = - fmt_safe_duration_cast>(diff); - return ms; -#else - auto s = std::chrono::duration_cast(d); - return std::chrono::duration_cast(d - s); -#endif -} - -template ::value)> -OutputIt format_duration_value(OutputIt out, Rep val, int) { - return write(out, val); -} - -template ::value)> -OutputIt format_duration_value(OutputIt out, Rep val, int precision) { - auto specs = format_specs(); - specs.precision = precision; - specs.type = precision >= 0 ? presentation_type::fixed_lower - : presentation_type::general_lower; - return write(out, val, specs); -} - -template -OutputIt copy_unit(string_view unit, OutputIt out, Char) { - return std::copy(unit.begin(), unit.end(), out); -} - -template -OutputIt copy_unit(string_view unit, OutputIt out, wchar_t) { - // This works when wchar_t is UTF-32 because units only contain characters - // that have the same representation in UTF-16 and UTF-32. - utf8_to_utf16 u(unit); - return std::copy(u.c_str(), u.c_str() + u.size(), out); -} - -template -OutputIt format_duration_unit(OutputIt out) { - if (const char* unit = get_units()) - return copy_unit(string_view(unit), out, Char()); - *out++ = '['; - out = write(out, Period::num); - if (const_check(Period::den != 1)) { - *out++ = '/'; - out = write(out, Period::den); - } - *out++ = ']'; - *out++ = 's'; - return out; -} - -class get_locale { - private: - union { - std::locale locale_; - }; - bool has_locale_ = false; - - public: - get_locale(bool localized, locale_ref loc) : has_locale_(localized) { - if (localized) - ::new (&locale_) std::locale(loc.template get()); - } - ~get_locale() { - if (has_locale_) locale_.~locale(); - } - operator const std::locale&() const { - return has_locale_ ? locale_ : get_classic_locale(); - } -}; - -template -struct chrono_formatter { - FormatContext& context; - OutputIt out; - int precision; - bool localized = false; - // rep is unsigned to avoid overflow. - using rep = - conditional_t::value && sizeof(Rep) < sizeof(int), - unsigned, typename make_unsigned_or_unchanged::type>; - rep val; - using seconds = std::chrono::duration; - seconds s; - using milliseconds = std::chrono::duration; - bool negative; - - using char_type = typename FormatContext::char_type; - using tm_writer_type = tm_writer; - - chrono_formatter(FormatContext& ctx, OutputIt o, - std::chrono::duration d) - : context(ctx), - out(o), - val(static_cast(d.count())), - negative(false) { - if (d.count() < 0) { - val = 0 - val; - negative = true; - } - - // this may overflow and/or the result may not fit in the - // target type. -#if FMT_SAFE_DURATION_CAST - // might need checked conversion (rep!=Rep) - auto tmpval = std::chrono::duration(val); - s = fmt_safe_duration_cast(tmpval); -#else - s = std::chrono::duration_cast( - std::chrono::duration(val)); -#endif - } - - // returns true if nan or inf, writes to out. - bool handle_nan_inf() { - if (isfinite(val)) { - return false; - } - if (isnan(val)) { - write_nan(); - return true; - } - // must be +-inf - if (val > 0) { - write_pinf(); - } else { - write_ninf(); - } - return true; - } - - Rep hour() const { return static_cast(mod((s.count() / 3600), 24)); } - - Rep hour12() const { - Rep hour = static_cast(mod((s.count() / 3600), 12)); - return hour <= 0 ? 12 : hour; - } - - Rep minute() const { return static_cast(mod((s.count() / 60), 60)); } - Rep second() const { return static_cast(mod(s.count(), 60)); } - - std::tm time() const { - auto time = std::tm(); - time.tm_hour = to_nonnegative_int(hour(), 24); - time.tm_min = to_nonnegative_int(minute(), 60); - time.tm_sec = to_nonnegative_int(second(), 60); - return time; - } - - void write_sign() { - if (negative) { - *out++ = '-'; - negative = false; - } - } - - void write(Rep value, int width, pad_type pad = pad_type::unspecified) { - write_sign(); - if (isnan(value)) return write_nan(); - uint32_or_64_or_128_t n = - to_unsigned(to_nonnegative_int(value, max_value())); - int num_digits = detail::count_digits(n); - if (width > num_digits) { - out = detail::write_padding(out, pad, width - num_digits); - } - out = format_decimal(out, n, num_digits).end; - } - - void write_nan() { std::copy_n("nan", 3, out); } - void write_pinf() { std::copy_n("inf", 3, out); } - void write_ninf() { std::copy_n("-inf", 4, out); } - - template - void format_tm(const tm& time, Callback cb, Args... args) { - if (isnan(val)) return write_nan(); - get_locale loc(localized, context.locale()); - auto w = tm_writer_type(loc, out, time); - (w.*cb)(args...); - out = w.out(); - } - - void on_text(const char_type* begin, const char_type* end) { - std::copy(begin, end, out); - } - - // These are not implemented because durations don't have date information. - void on_abbr_weekday() {} - void on_full_weekday() {} - void on_dec0_weekday(numeric_system) {} - void on_dec1_weekday(numeric_system) {} - void on_abbr_month() {} - void on_full_month() {} - void on_datetime(numeric_system) {} - void on_loc_date(numeric_system) {} - void on_loc_time(numeric_system) {} - void on_us_date() {} - void on_iso_date() {} - void on_utc_offset(numeric_system) {} - void on_tz_name() {} - void on_year(numeric_system) {} - void on_short_year(numeric_system) {} - void on_offset_year() {} - void on_century(numeric_system) {} - void on_iso_week_based_year() {} - void on_iso_week_based_short_year() {} - void on_dec_month(numeric_system) {} - void on_dec0_week_of_year(numeric_system) {} - void on_dec1_week_of_year(numeric_system) {} - void on_iso_week_of_year(numeric_system) {} - void on_day_of_year() {} - void on_day_of_month(numeric_system) {} - void on_day_of_month_space(numeric_system) {} - - void on_24_hour(numeric_system ns, pad_type pad) { - if (handle_nan_inf()) return; - - if (ns == numeric_system::standard) return write(hour(), 2, pad); - auto time = tm(); - time.tm_hour = to_nonnegative_int(hour(), 24); - format_tm(time, &tm_writer_type::on_24_hour, ns, pad); - } - - void on_12_hour(numeric_system ns, pad_type pad) { - if (handle_nan_inf()) return; - - if (ns == numeric_system::standard) return write(hour12(), 2, pad); - auto time = tm(); - time.tm_hour = to_nonnegative_int(hour12(), 12); - format_tm(time, &tm_writer_type::on_12_hour, ns, pad); - } - - void on_minute(numeric_system ns, pad_type pad) { - if (handle_nan_inf()) return; - - if (ns == numeric_system::standard) return write(minute(), 2, pad); - auto time = tm(); - time.tm_min = to_nonnegative_int(minute(), 60); - format_tm(time, &tm_writer_type::on_minute, ns, pad); - } - - void on_second(numeric_system ns, pad_type pad) { - if (handle_nan_inf()) return; - - if (ns == numeric_system::standard) { - if (std::is_floating_point::value) { - auto buf = memory_buffer(); - write_floating_seconds(buf, std::chrono::duration(val), - precision); - if (negative) *out++ = '-'; - if (buf.size() < 2 || buf[1] == '.') { - out = detail::write_padding(out, pad); - } - out = std::copy(buf.begin(), buf.end(), out); - } else { - write(second(), 2, pad); - write_fractional_seconds( - out, std::chrono::duration(val), precision); - } - return; - } - auto time = tm(); - time.tm_sec = to_nonnegative_int(second(), 60); - format_tm(time, &tm_writer_type::on_second, ns, pad); - } - - void on_12_hour_time() { - if (handle_nan_inf()) return; - format_tm(time(), &tm_writer_type::on_12_hour_time); - } - - void on_24_hour_time() { - if (handle_nan_inf()) { - *out++ = ':'; - handle_nan_inf(); - return; - } - - write(hour(), 2); - *out++ = ':'; - write(minute(), 2); - } - - void on_iso_time() { - on_24_hour_time(); - *out++ = ':'; - if (handle_nan_inf()) return; - on_second(numeric_system::standard, pad_type::unspecified); - } - - void on_am_pm() { - if (handle_nan_inf()) return; - format_tm(time(), &tm_writer_type::on_am_pm); - } - - void on_duration_value() { - if (handle_nan_inf()) return; - write_sign(); - out = format_duration_value(out, val, precision); - } - - void on_duration_unit() { - out = format_duration_unit(out); - } -}; - -} // namespace detail - -#if defined(__cpp_lib_chrono) && __cpp_lib_chrono >= 201907 -using weekday = std::chrono::weekday; -#else -// A fallback version of weekday. -class weekday { - private: - unsigned char value; - - public: - weekday() = default; - explicit constexpr weekday(unsigned wd) noexcept - : value(static_cast(wd != 7 ? wd : 0)) {} - constexpr unsigned c_encoding() const noexcept { return value; } -}; - -class year_month_day {}; -#endif - -// A rudimentary weekday formatter. -template struct formatter { - private: - bool localized = false; - - public: - FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) - -> decltype(ctx.begin()) { - auto begin = ctx.begin(), end = ctx.end(); - if (begin != end && *begin == 'L') { - ++begin; - localized = true; - } - return begin; - } - - template - auto format(weekday wd, FormatContext& ctx) const -> decltype(ctx.out()) { - auto time = std::tm(); - time.tm_wday = static_cast(wd.c_encoding()); - detail::get_locale loc(localized, ctx.locale()); - auto w = detail::tm_writer(loc, ctx.out(), time); - w.on_abbr_weekday(); - return w.out(); - } -}; - -template -struct formatter, Char> { - private: - format_specs specs_; - detail::arg_ref width_ref_; - detail::arg_ref precision_ref_; - bool localized_ = false; - basic_string_view format_str_; - - public: - FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) - -> decltype(ctx.begin()) { - auto it = ctx.begin(), end = ctx.end(); - if (it == end || *it == '}') return it; - - it = detail::parse_align(it, end, specs_); - if (it == end) return it; - - it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); - if (it == end) return it; - - auto checker = detail::chrono_format_checker(); - if (*it == '.') { - checker.has_precision_integral = !std::is_floating_point::value; - it = detail::parse_precision(it, end, specs_.precision, precision_ref_, - ctx); - } - if (it != end && *it == 'L') { - localized_ = true; - ++it; - } - end = detail::parse_chrono_format(it, end, checker); - format_str_ = {it, detail::to_unsigned(end - it)}; - return end; - } - - template - auto format(std::chrono::duration d, FormatContext& ctx) const - -> decltype(ctx.out()) { - auto specs = specs_; - auto precision = specs.precision; - specs.precision = -1; - auto begin = format_str_.begin(), end = format_str_.end(); - // As a possible future optimization, we could avoid extra copying if width - // is not specified. - auto buf = basic_memory_buffer(); - auto out = std::back_inserter(buf); - detail::handle_dynamic_spec(specs.width, width_ref_, - ctx); - detail::handle_dynamic_spec(precision, - precision_ref_, ctx); - if (begin == end || *begin == '}') { - out = detail::format_duration_value(out, d.count(), precision); - detail::format_duration_unit(out); - } else { - using chrono_formatter = - detail::chrono_formatter; - auto f = chrono_formatter(ctx, out, d); - f.precision = precision; - f.localized = localized_; - detail::parse_chrono_format(begin, end, f); - } - return detail::write( - ctx.out(), basic_string_view(buf.data(), buf.size()), specs); - } -}; - -template -struct formatter, - Char> : formatter { - FMT_CONSTEXPR formatter() { - this->format_str_ = detail::string_literal{}; - } - - template - auto format(std::chrono::time_point val, - FormatContext& ctx) const -> decltype(ctx.out()) { - using period = typename Duration::period; - if (detail::const_check( - period::num != 1 || period::den != 1 || - std::is_floating_point::value)) { - const auto epoch = val.time_since_epoch(); - auto subsecs = std::chrono::duration_cast( - epoch - std::chrono::duration_cast(epoch)); - - if (subsecs.count() < 0) { - auto second = - std::chrono::duration_cast(std::chrono::seconds(1)); - if (epoch.count() < ((Duration::min)() + second).count()) - FMT_THROW(format_error("duration is too small")); - subsecs += second; - val -= second; - } - - return formatter::do_format( - gmtime(std::chrono::time_point_cast(val)), ctx, - &subsecs); - } - - return formatter::format( - gmtime(std::chrono::time_point_cast(val)), ctx); - } -}; - -#if FMT_USE_LOCAL_TIME -template -struct formatter, Char> - : formatter { - FMT_CONSTEXPR formatter() { - this->format_str_ = detail::string_literal{}; - } - - template - auto format(std::chrono::local_time val, FormatContext& ctx) const - -> decltype(ctx.out()) { - using period = typename Duration::period; - if (period::num != 1 || period::den != 1 || - std::is_floating_point::value) { - const auto epoch = val.time_since_epoch(); - const auto subsecs = std::chrono::duration_cast( - epoch - std::chrono::duration_cast(epoch)); - - return formatter::do_format( - localtime(std::chrono::time_point_cast(val)), - ctx, &subsecs); - } - - return formatter::format( - localtime(std::chrono::time_point_cast(val)), - ctx); - } -}; -#endif - -#if FMT_USE_UTC_TIME -template -struct formatter, - Char> - : formatter, - Char> { - template - auto format(std::chrono::time_point val, - FormatContext& ctx) const -> decltype(ctx.out()) { - return formatter< - std::chrono::time_point, - Char>::format(std::chrono::utc_clock::to_sys(val), ctx); - } -}; -#endif - -template struct formatter { - private: - format_specs specs_; - detail::arg_ref width_ref_; - - protected: - basic_string_view format_str_; - - template - auto do_format(const std::tm& tm, FormatContext& ctx, - const Duration* subsecs) const -> decltype(ctx.out()) { - auto specs = specs_; - auto buf = basic_memory_buffer(); - auto out = std::back_inserter(buf); - detail::handle_dynamic_spec(specs.width, width_ref_, - ctx); - - auto loc_ref = ctx.locale(); - detail::get_locale loc(static_cast(loc_ref), loc_ref); - auto w = - detail::tm_writer(loc, out, tm, subsecs); - detail::parse_chrono_format(format_str_.begin(), format_str_.end(), w); - return detail::write( - ctx.out(), basic_string_view(buf.data(), buf.size()), specs); - } - - public: - FMT_CONSTEXPR auto parse(basic_format_parse_context& ctx) - -> decltype(ctx.begin()) { - auto it = ctx.begin(), end = ctx.end(); - if (it == end || *it == '}') return it; - - it = detail::parse_align(it, end, specs_); - if (it == end) return it; - - it = detail::parse_dynamic_spec(it, end, specs_.width, width_ref_, ctx); - if (it == end) return it; - - end = detail::parse_chrono_format(it, end, detail::tm_format_checker()); - // Replace the default format_str only if the new spec is not empty. - if (end != it) format_str_ = {it, detail::to_unsigned(end - it)}; - return end; - } - - template - auto format(const std::tm& tm, FormatContext& ctx) const - -> decltype(ctx.out()) { - return do_format(tm, ctx, nullptr); - } -}; - -FMT_END_EXPORT -FMT_END_NAMESPACE - -#endif // FMT_CHRONO_H_ diff --git a/src/common/dep/fmt/color.h b/src/common/dep/fmt/color.h deleted file mode 100644 index 8697e1ca0..000000000 --- a/src/common/dep/fmt/color.h +++ /dev/null @@ -1,632 +0,0 @@ -// Formatting library for C++ - color support -// -// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_COLOR_H_ -#define FMT_COLOR_H_ - -#include "format.h" - -FMT_BEGIN_NAMESPACE -FMT_BEGIN_EXPORT - -enum class color : uint32_t { - alice_blue = 0xF0F8FF, // rgb(240,248,255) - antique_white = 0xFAEBD7, // rgb(250,235,215) - aqua = 0x00FFFF, // rgb(0,255,255) - aquamarine = 0x7FFFD4, // rgb(127,255,212) - azure = 0xF0FFFF, // rgb(240,255,255) - beige = 0xF5F5DC, // rgb(245,245,220) - bisque = 0xFFE4C4, // rgb(255,228,196) - black = 0x000000, // rgb(0,0,0) - blanched_almond = 0xFFEBCD, // rgb(255,235,205) - blue = 0x0000FF, // rgb(0,0,255) - blue_violet = 0x8A2BE2, // rgb(138,43,226) - brown = 0xA52A2A, // rgb(165,42,42) - burly_wood = 0xDEB887, // rgb(222,184,135) - cadet_blue = 0x5F9EA0, // rgb(95,158,160) - chartreuse = 0x7FFF00, // rgb(127,255,0) - chocolate = 0xD2691E, // rgb(210,105,30) - coral = 0xFF7F50, // rgb(255,127,80) - cornflower_blue = 0x6495ED, // rgb(100,149,237) - cornsilk = 0xFFF8DC, // rgb(255,248,220) - crimson = 0xDC143C, // rgb(220,20,60) - cyan = 0x00FFFF, // rgb(0,255,255) - dark_blue = 0x00008B, // rgb(0,0,139) - dark_cyan = 0x008B8B, // rgb(0,139,139) - dark_golden_rod = 0xB8860B, // rgb(184,134,11) - dark_gray = 0xA9A9A9, // rgb(169,169,169) - dark_green = 0x006400, // rgb(0,100,0) - dark_khaki = 0xBDB76B, // rgb(189,183,107) - dark_magenta = 0x8B008B, // rgb(139,0,139) - dark_olive_green = 0x556B2F, // rgb(85,107,47) - dark_orange = 0xFF8C00, // rgb(255,140,0) - dark_orchid = 0x9932CC, // rgb(153,50,204) - dark_red = 0x8B0000, // rgb(139,0,0) - dark_salmon = 0xE9967A, // rgb(233,150,122) - dark_sea_green = 0x8FBC8F, // rgb(143,188,143) - dark_slate_blue = 0x483D8B, // rgb(72,61,139) - dark_slate_gray = 0x2F4F4F, // rgb(47,79,79) - dark_turquoise = 0x00CED1, // rgb(0,206,209) - dark_violet = 0x9400D3, // rgb(148,0,211) - deep_pink = 0xFF1493, // rgb(255,20,147) - deep_sky_blue = 0x00BFFF, // rgb(0,191,255) - dim_gray = 0x696969, // rgb(105,105,105) - dodger_blue = 0x1E90FF, // rgb(30,144,255) - fire_brick = 0xB22222, // rgb(178,34,34) - floral_white = 0xFFFAF0, // rgb(255,250,240) - forest_green = 0x228B22, // rgb(34,139,34) - fuchsia = 0xFF00FF, // rgb(255,0,255) - gainsboro = 0xDCDCDC, // rgb(220,220,220) - ghost_white = 0xF8F8FF, // rgb(248,248,255) - gold = 0xFFD700, // rgb(255,215,0) - golden_rod = 0xDAA520, // rgb(218,165,32) - gray = 0x808080, // rgb(128,128,128) - green = 0x008000, // rgb(0,128,0) - green_yellow = 0xADFF2F, // rgb(173,255,47) - honey_dew = 0xF0FFF0, // rgb(240,255,240) - hot_pink = 0xFF69B4, // rgb(255,105,180) - indian_red = 0xCD5C5C, // rgb(205,92,92) - indigo = 0x4B0082, // rgb(75,0,130) - ivory = 0xFFFFF0, // rgb(255,255,240) - khaki = 0xF0E68C, // rgb(240,230,140) - lavender = 0xE6E6FA, // rgb(230,230,250) - lavender_blush = 0xFFF0F5, // rgb(255,240,245) - lawn_green = 0x7CFC00, // rgb(124,252,0) - lemon_chiffon = 0xFFFACD, // rgb(255,250,205) - light_blue = 0xADD8E6, // rgb(173,216,230) - light_coral = 0xF08080, // rgb(240,128,128) - light_cyan = 0xE0FFFF, // rgb(224,255,255) - light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210) - light_gray = 0xD3D3D3, // rgb(211,211,211) - light_green = 0x90EE90, // rgb(144,238,144) - light_pink = 0xFFB6C1, // rgb(255,182,193) - light_salmon = 0xFFA07A, // rgb(255,160,122) - light_sea_green = 0x20B2AA, // rgb(32,178,170) - light_sky_blue = 0x87CEFA, // rgb(135,206,250) - light_slate_gray = 0x778899, // rgb(119,136,153) - light_steel_blue = 0xB0C4DE, // rgb(176,196,222) - light_yellow = 0xFFFFE0, // rgb(255,255,224) - lime = 0x00FF00, // rgb(0,255,0) - lime_green = 0x32CD32, // rgb(50,205,50) - linen = 0xFAF0E6, // rgb(250,240,230) - magenta = 0xFF00FF, // rgb(255,0,255) - maroon = 0x800000, // rgb(128,0,0) - medium_aquamarine = 0x66CDAA, // rgb(102,205,170) - medium_blue = 0x0000CD, // rgb(0,0,205) - medium_orchid = 0xBA55D3, // rgb(186,85,211) - medium_purple = 0x9370DB, // rgb(147,112,219) - medium_sea_green = 0x3CB371, // rgb(60,179,113) - medium_slate_blue = 0x7B68EE, // rgb(123,104,238) - medium_spring_green = 0x00FA9A, // rgb(0,250,154) - medium_turquoise = 0x48D1CC, // rgb(72,209,204) - medium_violet_red = 0xC71585, // rgb(199,21,133) - midnight_blue = 0x191970, // rgb(25,25,112) - mint_cream = 0xF5FFFA, // rgb(245,255,250) - misty_rose = 0xFFE4E1, // rgb(255,228,225) - moccasin = 0xFFE4B5, // rgb(255,228,181) - navajo_white = 0xFFDEAD, // rgb(255,222,173) - navy = 0x000080, // rgb(0,0,128) - old_lace = 0xFDF5E6, // rgb(253,245,230) - olive = 0x808000, // rgb(128,128,0) - olive_drab = 0x6B8E23, // rgb(107,142,35) - orange = 0xFFA500, // rgb(255,165,0) - orange_red = 0xFF4500, // rgb(255,69,0) - orchid = 0xDA70D6, // rgb(218,112,214) - pale_golden_rod = 0xEEE8AA, // rgb(238,232,170) - pale_green = 0x98FB98, // rgb(152,251,152) - pale_turquoise = 0xAFEEEE, // rgb(175,238,238) - pale_violet_red = 0xDB7093, // rgb(219,112,147) - papaya_whip = 0xFFEFD5, // rgb(255,239,213) - peach_puff = 0xFFDAB9, // rgb(255,218,185) - peru = 0xCD853F, // rgb(205,133,63) - pink = 0xFFC0CB, // rgb(255,192,203) - plum = 0xDDA0DD, // rgb(221,160,221) - powder_blue = 0xB0E0E6, // rgb(176,224,230) - purple = 0x800080, // rgb(128,0,128) - rebecca_purple = 0x663399, // rgb(102,51,153) - red = 0xFF0000, // rgb(255,0,0) - rosy_brown = 0xBC8F8F, // rgb(188,143,143) - royal_blue = 0x4169E1, // rgb(65,105,225) - saddle_brown = 0x8B4513, // rgb(139,69,19) - salmon = 0xFA8072, // rgb(250,128,114) - sandy_brown = 0xF4A460, // rgb(244,164,96) - sea_green = 0x2E8B57, // rgb(46,139,87) - sea_shell = 0xFFF5EE, // rgb(255,245,238) - sienna = 0xA0522D, // rgb(160,82,45) - silver = 0xC0C0C0, // rgb(192,192,192) - sky_blue = 0x87CEEB, // rgb(135,206,235) - slate_blue = 0x6A5ACD, // rgb(106,90,205) - slate_gray = 0x708090, // rgb(112,128,144) - snow = 0xFFFAFA, // rgb(255,250,250) - spring_green = 0x00FF7F, // rgb(0,255,127) - steel_blue = 0x4682B4, // rgb(70,130,180) - tan = 0xD2B48C, // rgb(210,180,140) - teal = 0x008080, // rgb(0,128,128) - thistle = 0xD8BFD8, // rgb(216,191,216) - tomato = 0xFF6347, // rgb(255,99,71) - turquoise = 0x40E0D0, // rgb(64,224,208) - violet = 0xEE82EE, // rgb(238,130,238) - wheat = 0xF5DEB3, // rgb(245,222,179) - white = 0xFFFFFF, // rgb(255,255,255) - white_smoke = 0xF5F5F5, // rgb(245,245,245) - yellow = 0xFFFF00, // rgb(255,255,0) - yellow_green = 0x9ACD32 // rgb(154,205,50) -}; // enum class color - -enum class terminal_color : uint8_t { - black = 30, - red, - green, - yellow, - blue, - magenta, - cyan, - white, - bright_black = 90, - bright_red, - bright_green, - bright_yellow, - bright_blue, - bright_magenta, - bright_cyan, - bright_white -}; - -enum class emphasis : uint8_t { - bold = 1, - faint = 1 << 1, - italic = 1 << 2, - underline = 1 << 3, - blink = 1 << 4, - reverse = 1 << 5, - conceal = 1 << 6, - strikethrough = 1 << 7, -}; - -// rgb is a struct for red, green and blue colors. -// Using the name "rgb" makes some editors show the color in a tooltip. -struct rgb { - FMT_CONSTEXPR rgb() : r(0), g(0), b(0) {} - FMT_CONSTEXPR rgb(uint8_t r_, uint8_t g_, uint8_t b_) : r(r_), g(g_), b(b_) {} - FMT_CONSTEXPR rgb(uint32_t hex) - : r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b(hex & 0xFF) {} - FMT_CONSTEXPR rgb(color hex) - : r((uint32_t(hex) >> 16) & 0xFF), - g((uint32_t(hex) >> 8) & 0xFF), - b(uint32_t(hex) & 0xFF) {} - uint8_t r; - uint8_t g; - uint8_t b; -}; - -namespace detail { - -// color is a struct of either a rgb color or a terminal color. -struct color_type { - FMT_CONSTEXPR color_type() noexcept : is_rgb(), value{} {} - FMT_CONSTEXPR color_type(color rgb_color) noexcept : is_rgb(true), value{} { - value.rgb_color = static_cast(rgb_color); - } - FMT_CONSTEXPR color_type(rgb rgb_color) noexcept : is_rgb(true), value{} { - value.rgb_color = (static_cast(rgb_color.r) << 16) | - (static_cast(rgb_color.g) << 8) | rgb_color.b; - } - FMT_CONSTEXPR color_type(terminal_color term_color) noexcept - : is_rgb(), value{} { - value.term_color = static_cast(term_color); - } - bool is_rgb; - union color_union { - uint8_t term_color; - uint32_t rgb_color; - } value; -}; -} // namespace detail - -/** A text style consisting of foreground and background colors and emphasis. */ -class text_style { - public: - FMT_CONSTEXPR text_style(emphasis em = emphasis()) noexcept - : set_foreground_color(), set_background_color(), ems(em) {} - - FMT_CONSTEXPR text_style& operator|=(const text_style& rhs) { - if (!set_foreground_color) { - set_foreground_color = rhs.set_foreground_color; - foreground_color = rhs.foreground_color; - } else if (rhs.set_foreground_color) { - if (!foreground_color.is_rgb || !rhs.foreground_color.is_rgb) - FMT_THROW(format_error("can't OR a terminal color")); - foreground_color.value.rgb_color |= rhs.foreground_color.value.rgb_color; - } - - if (!set_background_color) { - set_background_color = rhs.set_background_color; - background_color = rhs.background_color; - } else if (rhs.set_background_color) { - if (!background_color.is_rgb || !rhs.background_color.is_rgb) - FMT_THROW(format_error("can't OR a terminal color")); - background_color.value.rgb_color |= rhs.background_color.value.rgb_color; - } - - ems = static_cast(static_cast(ems) | - static_cast(rhs.ems)); - return *this; - } - - friend FMT_CONSTEXPR text_style operator|(text_style lhs, - const text_style& rhs) { - return lhs |= rhs; - } - - FMT_CONSTEXPR bool has_foreground() const noexcept { - return set_foreground_color; - } - FMT_CONSTEXPR bool has_background() const noexcept { - return set_background_color; - } - FMT_CONSTEXPR bool has_emphasis() const noexcept { - return static_cast(ems) != 0; - } - FMT_CONSTEXPR detail::color_type get_foreground() const noexcept { - FMT_ASSERT(has_foreground(), "no foreground specified for this style"); - return foreground_color; - } - FMT_CONSTEXPR detail::color_type get_background() const noexcept { - FMT_ASSERT(has_background(), "no background specified for this style"); - return background_color; - } - FMT_CONSTEXPR emphasis get_emphasis() const noexcept { - FMT_ASSERT(has_emphasis(), "no emphasis specified for this style"); - return ems; - } - - private: - FMT_CONSTEXPR text_style(bool is_foreground, - detail::color_type text_color) noexcept - : set_foreground_color(), set_background_color(), ems() { - if (is_foreground) { - foreground_color = text_color; - set_foreground_color = true; - } else { - background_color = text_color; - set_background_color = true; - } - } - - friend FMT_CONSTEXPR text_style fg(detail::color_type foreground) noexcept; - - friend FMT_CONSTEXPR text_style bg(detail::color_type background) noexcept; - - detail::color_type foreground_color; - detail::color_type background_color; - bool set_foreground_color; - bool set_background_color; - emphasis ems; -}; - -/** Creates a text style from the foreground (text) color. */ -FMT_CONSTEXPR inline text_style fg(detail::color_type foreground) noexcept { - return text_style(true, foreground); -} - -/** Creates a text style from the background color. */ -FMT_CONSTEXPR inline text_style bg(detail::color_type background) noexcept { - return text_style(false, background); -} - -FMT_CONSTEXPR inline text_style operator|(emphasis lhs, emphasis rhs) noexcept { - return text_style(lhs) | rhs; -} - -namespace detail { - -template struct ansi_color_escape { - FMT_CONSTEXPR ansi_color_escape(detail::color_type text_color, - const char* esc) noexcept { - // If we have a terminal color, we need to output another escape code - // sequence. - if (!text_color.is_rgb) { - bool is_background = esc == string_view("\x1b[48;2;"); - uint32_t value = text_color.value.term_color; - // Background ASCII codes are the same as the foreground ones but with - // 10 more. - if (is_background) value += 10u; - - size_t index = 0; - buffer[index++] = static_cast('\x1b'); - buffer[index++] = static_cast('['); - - if (value >= 100u) { - buffer[index++] = static_cast('1'); - value %= 100u; - } - buffer[index++] = static_cast('0' + value / 10u); - buffer[index++] = static_cast('0' + value % 10u); - - buffer[index++] = static_cast('m'); - buffer[index++] = static_cast('\0'); - return; - } - - for (int i = 0; i < 7; i++) { - buffer[i] = static_cast(esc[i]); - } - rgb color(text_color.value.rgb_color); - to_esc(color.r, buffer + 7, ';'); - to_esc(color.g, buffer + 11, ';'); - to_esc(color.b, buffer + 15, 'm'); - buffer[19] = static_cast(0); - } - FMT_CONSTEXPR ansi_color_escape(emphasis em) noexcept { - uint8_t em_codes[num_emphases] = {}; - if (has_emphasis(em, emphasis::bold)) em_codes[0] = 1; - if (has_emphasis(em, emphasis::faint)) em_codes[1] = 2; - if (has_emphasis(em, emphasis::italic)) em_codes[2] = 3; - if (has_emphasis(em, emphasis::underline)) em_codes[3] = 4; - if (has_emphasis(em, emphasis::blink)) em_codes[4] = 5; - if (has_emphasis(em, emphasis::reverse)) em_codes[5] = 7; - if (has_emphasis(em, emphasis::conceal)) em_codes[6] = 8; - if (has_emphasis(em, emphasis::strikethrough)) em_codes[7] = 9; - - size_t index = 0; - for (size_t i = 0; i < num_emphases; ++i) { - if (!em_codes[i]) continue; - buffer[index++] = static_cast('\x1b'); - buffer[index++] = static_cast('['); - buffer[index++] = static_cast('0' + em_codes[i]); - buffer[index++] = static_cast('m'); - } - buffer[index++] = static_cast(0); - } - FMT_CONSTEXPR operator const Char*() const noexcept { return buffer; } - - FMT_CONSTEXPR const Char* begin() const noexcept { return buffer; } - FMT_CONSTEXPR_CHAR_TRAITS const Char* end() const noexcept { - return buffer + std::char_traits::length(buffer); - } - - private: - static constexpr size_t num_emphases = 8; - Char buffer[7u + 3u * num_emphases + 1u]; - - static FMT_CONSTEXPR void to_esc(uint8_t c, Char* out, - char delimiter) noexcept { - out[0] = static_cast('0' + c / 100); - out[1] = static_cast('0' + c / 10 % 10); - out[2] = static_cast('0' + c % 10); - out[3] = static_cast(delimiter); - } - static FMT_CONSTEXPR bool has_emphasis(emphasis em, emphasis mask) noexcept { - return static_cast(em) & static_cast(mask); - } -}; - -template -FMT_CONSTEXPR ansi_color_escape make_foreground_color( - detail::color_type foreground) noexcept { - return ansi_color_escape(foreground, "\x1b[38;2;"); -} - -template -FMT_CONSTEXPR ansi_color_escape make_background_color( - detail::color_type background) noexcept { - return ansi_color_escape(background, "\x1b[48;2;"); -} - -template -FMT_CONSTEXPR ansi_color_escape make_emphasis(emphasis em) noexcept { - return ansi_color_escape(em); -} - -template inline void reset_color(buffer& buffer) { - auto reset_color = string_view("\x1b[0m"); - buffer.append(reset_color.begin(), reset_color.end()); -} - -template struct styled_arg { - const T& value; - text_style style; -}; - -template -void vformat_to(buffer& buf, const text_style& ts, - basic_string_view format_str, - basic_format_args>> args) { - bool has_style = false; - if (ts.has_emphasis()) { - has_style = true; - auto emphasis = detail::make_emphasis(ts.get_emphasis()); - buf.append(emphasis.begin(), emphasis.end()); - } - if (ts.has_foreground()) { - has_style = true; - auto foreground = detail::make_foreground_color(ts.get_foreground()); - buf.append(foreground.begin(), foreground.end()); - } - if (ts.has_background()) { - has_style = true; - auto background = detail::make_background_color(ts.get_background()); - buf.append(background.begin(), background.end()); - } - detail::vformat_to(buf, format_str, args, {}); - if (has_style) detail::reset_color(buf); -} - -} // namespace detail - -inline void vprint(std::FILE* f, const text_style& ts, string_view fmt, - format_args args) { - // Legacy wide streams are not supported. - auto buf = memory_buffer(); - detail::vformat_to(buf, ts, fmt, args); - if (detail::is_utf8()) { - detail::print(f, string_view(buf.begin(), buf.size())); - return; - } - buf.push_back('\0'); - int result = std::fputs(buf.data(), f); - if (result < 0) - FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); -} - -/** - \rst - Formats a string and prints it to the specified file stream using ANSI - escape sequences to specify text formatting. - - **Example**:: - - fmt::print(fmt::emphasis::bold | fg(fmt::color::red), - "Elapsed time: {0:.2f} seconds", 1.23); - \endrst - */ -template ::value)> -void print(std::FILE* f, const text_style& ts, const S& format_str, - const Args&... args) { - vprint(f, ts, format_str, - fmt::make_format_args>>(args...)); -} - -/** - \rst - Formats a string and prints it to stdout using ANSI escape sequences to - specify text formatting. - - **Example**:: - - fmt::print(fmt::emphasis::bold | fg(fmt::color::red), - "Elapsed time: {0:.2f} seconds", 1.23); - \endrst - */ -template ::value)> -void print(const text_style& ts, const S& format_str, const Args&... args) { - return print(stdout, ts, format_str, args...); -} - -template > -inline std::basic_string vformat( - const text_style& ts, const S& format_str, - basic_format_args>> args) { - basic_memory_buffer buf; - detail::vformat_to(buf, ts, detail::to_string_view(format_str), args); - return fmt::to_string(buf); -} - -/** - \rst - Formats arguments and returns the result as a string using ANSI - escape sequences to specify text formatting. - - **Example**:: - - #include - std::string message = fmt::format(fmt::emphasis::bold | fg(fmt::color::red), - "The answer is {}", 42); - \endrst -*/ -template > -inline std::basic_string format(const text_style& ts, const S& format_str, - const Args&... args) { - return fmt::vformat(ts, detail::to_string_view(format_str), - fmt::make_format_args>(args...)); -} - -/** - Formats a string with the given text_style and writes the output to ``out``. - */ -template ::value)> -OutputIt vformat_to( - OutputIt out, const text_style& ts, basic_string_view format_str, - basic_format_args>> args) { - auto&& buf = detail::get_buffer(out); - detail::vformat_to(buf, ts, format_str, args); - return detail::get_iterator(buf, out); -} - -/** - \rst - Formats arguments with the given text_style, writes the result to the output - iterator ``out`` and returns the iterator past the end of the output range. - - **Example**:: - - std::vector out; - fmt::format_to(std::back_inserter(out), - fmt::emphasis::bold | fg(fmt::color::red), "{}", 42); - \endrst -*/ -template >::value&& - detail::is_string::value> -inline auto format_to(OutputIt out, const text_style& ts, const S& format_str, - Args&&... args) -> - typename std::enable_if::type { - return vformat_to(out, ts, detail::to_string_view(format_str), - fmt::make_format_args>>(args...)); -} - -template -struct formatter, Char> : formatter { - template - auto format(const detail::styled_arg& arg, FormatContext& ctx) const - -> decltype(ctx.out()) { - const auto& ts = arg.style; - const auto& value = arg.value; - auto out = ctx.out(); - - bool has_style = false; - if (ts.has_emphasis()) { - has_style = true; - auto emphasis = detail::make_emphasis(ts.get_emphasis()); - out = std::copy(emphasis.begin(), emphasis.end(), out); - } - if (ts.has_foreground()) { - has_style = true; - auto foreground = - detail::make_foreground_color(ts.get_foreground()); - out = std::copy(foreground.begin(), foreground.end(), out); - } - if (ts.has_background()) { - has_style = true; - auto background = - detail::make_background_color(ts.get_background()); - out = std::copy(background.begin(), background.end(), out); - } - out = formatter::format(value, ctx); - if (has_style) { - auto reset_color = string_view("\x1b[0m"); - out = std::copy(reset_color.begin(), reset_color.end(), out); - } - return out; - } -}; - -/** - \rst - Returns an argument that will be formatted using ANSI escape sequences, - to be used in a formatting function. - - **Example**:: - - fmt::print("Elapsed time: {0:.2f} seconds", - fmt::styled(1.23, fmt::fg(fmt::color::green) | - fmt::bg(fmt::color::blue))); - \endrst - */ -template -FMT_CONSTEXPR auto styled(const T& value, text_style ts) - -> detail::styled_arg> { - return detail::styled_arg>{value, ts}; -} - -FMT_END_EXPORT -FMT_END_NAMESPACE - -#endif // FMT_COLOR_H_ diff --git a/src/common/dep/fmt/compile.h b/src/common/dep/fmt/compile.h deleted file mode 100644 index a4c7e4956..000000000 --- a/src/common/dep/fmt/compile.h +++ /dev/null @@ -1,534 +0,0 @@ -// Formatting library for C++ - experimental format string compilation -// -// Copyright (c) 2012 - present, Victor Zverovich and fmt contributors -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_COMPILE_H_ -#define FMT_COMPILE_H_ - -#include "format.h" - -FMT_BEGIN_NAMESPACE -namespace detail { - -template -FMT_CONSTEXPR inline counting_iterator copy_str(InputIt begin, InputIt end, - counting_iterator it) { - return it + (end - begin); -} - -// A compile-time string which is compiled into fast formatting code. -class compiled_string {}; - -template -struct is_compiled_string : std::is_base_of {}; - -/** - \rst - Converts a string literal *s* into a format string that will be parsed at - compile time and converted into efficient formatting code. Requires C++17 - ``constexpr if`` compiler support. - - **Example**:: - - // Converts 42 into std::string using the most efficient method and no - // runtime format string processing. - std::string s = fmt::format(FMT_COMPILE("{}"), 42); - \endrst - */ -#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) -# define FMT_COMPILE(s) \ - FMT_STRING_IMPL(s, fmt::detail::compiled_string, explicit) -#else -# define FMT_COMPILE(s) FMT_STRING(s) -#endif - -#if FMT_USE_NONTYPE_TEMPLATE_ARGS -template Str> -struct udl_compiled_string : compiled_string { - using char_type = Char; - explicit constexpr operator basic_string_view() const { - return {Str.data, N - 1}; - } -}; -#endif - -template -const T& first(const T& value, const Tail&...) { - return value; -} - -#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) -template struct type_list {}; - -// Returns a reference to the argument at index N from [first, rest...]. -template -constexpr const auto& get([[maybe_unused]] const T& first, - [[maybe_unused]] const Args&... rest) { - static_assert(N < 1 + sizeof...(Args), "index is out of bounds"); - if constexpr (N == 0) - return first; - else - return detail::get(rest...); -} - -template -constexpr int get_arg_index_by_name(basic_string_view name, - type_list) { - return get_arg_index_by_name(name); -} - -template struct get_type_impl; - -template struct get_type_impl> { - using type = - remove_cvref_t(std::declval()...))>; -}; - -template -using get_type = typename get_type_impl::type; - -template struct is_compiled_format : std::false_type {}; - -template struct text { - basic_string_view data; - using char_type = Char; - - template - constexpr OutputIt format(OutputIt out, const Args&...) const { - return write(out, data); - } -}; - -template -struct is_compiled_format> : std::true_type {}; - -template -constexpr text make_text(basic_string_view s, size_t pos, - size_t size) { - return {{&s[pos], size}}; -} - -template struct code_unit { - Char value; - using char_type = Char; - - template - constexpr OutputIt format(OutputIt out, const Args&...) const { - *out++ = value; - return out; - } -}; - -// This ensures that the argument type is convertible to `const T&`. -template -constexpr const T& get_arg_checked(const Args&... args) { - const auto& arg = detail::get(args...); - if constexpr (detail::is_named_arg>()) { - return arg.value; - } else { - return arg; - } -} - -template -struct is_compiled_format> : std::true_type {}; - -// A replacement field that refers to argument N. -template struct field { - using char_type = Char; - - template - constexpr OutputIt format(OutputIt out, const Args&... args) const { - const T& arg = get_arg_checked(args...); - if constexpr (std::is_convertible_v>) { - auto s = basic_string_view(arg); - return copy_str(s.begin(), s.end(), out); - } - return write(out, arg); - } -}; - -template -struct is_compiled_format> : std::true_type {}; - -// A replacement field that refers to argument with name. -template struct runtime_named_field { - using char_type = Char; - basic_string_view name; - - template - constexpr static bool try_format_argument( - OutputIt& out, - // [[maybe_unused]] due to unused-but-set-parameter warning in GCC 7,8,9 - [[maybe_unused]] basic_string_view arg_name, const T& arg) { - if constexpr (is_named_arg::type>::value) { - if (arg_name == arg.name) { - out = write(out, arg.value); - return true; - } - } - return false; - } - - template - constexpr OutputIt format(OutputIt out, const Args&... args) const { - bool found = (try_format_argument(out, name, args) || ...); - if (!found) { - FMT_THROW(format_error("argument with specified name is not found")); - } - return out; - } -}; - -template -struct is_compiled_format> : std::true_type {}; - -// A replacement field that refers to argument N and has format specifiers. -template struct spec_field { - using char_type = Char; - formatter fmt; - - template - constexpr FMT_INLINE OutputIt format(OutputIt out, - const Args&... args) const { - const auto& vargs = - fmt::make_format_args>(args...); - basic_format_context ctx(out, vargs); - return fmt.format(get_arg_checked(args...), ctx); - } -}; - -template -struct is_compiled_format> : std::true_type {}; - -template struct concat { - L lhs; - R rhs; - using char_type = typename L::char_type; - - template - constexpr OutputIt format(OutputIt out, const Args&... args) const { - out = lhs.format(out, args...); - return rhs.format(out, args...); - } -}; - -template -struct is_compiled_format> : std::true_type {}; - -template -constexpr concat make_concat(L lhs, R rhs) { - return {lhs, rhs}; -} - -struct unknown_format {}; - -template -constexpr size_t parse_text(basic_string_view str, size_t pos) { - for (size_t size = str.size(); pos != size; ++pos) { - if (str[pos] == '{' || str[pos] == '}') break; - } - return pos; -} - -template -constexpr auto compile_format_string(S format_str); - -template -constexpr auto parse_tail(T head, S format_str) { - if constexpr (POS != - basic_string_view(format_str).size()) { - constexpr auto tail = compile_format_string(format_str); - if constexpr (std::is_same, - unknown_format>()) - return tail; - else - return make_concat(head, tail); - } else { - return head; - } -} - -template struct parse_specs_result { - formatter fmt; - size_t end; - int next_arg_id; -}; - -enum { manual_indexing_id = -1 }; - -template -constexpr parse_specs_result parse_specs(basic_string_view str, - size_t pos, int next_arg_id) { - str.remove_prefix(pos); - auto ctx = - compile_parse_context(str, max_value(), nullptr, next_arg_id); - auto f = formatter(); - auto end = f.parse(ctx); - return {f, pos + fmt::detail::to_unsigned(end - str.data()), - next_arg_id == 0 ? manual_indexing_id : ctx.next_arg_id()}; -} - -template struct arg_id_handler { - arg_ref arg_id; - - constexpr int on_auto() { - FMT_ASSERT(false, "handler cannot be used with automatic indexing"); - return 0; - } - constexpr int on_index(int id) { - arg_id = arg_ref(id); - return 0; - } - constexpr int on_name(basic_string_view id) { - arg_id = arg_ref(id); - return 0; - } -}; - -template struct parse_arg_id_result { - arg_ref arg_id; - const Char* arg_id_end; -}; - -template -constexpr auto parse_arg_id(const Char* begin, const Char* end) { - auto handler = arg_id_handler{arg_ref{}}; - auto arg_id_end = parse_arg_id(begin, end, handler); - return parse_arg_id_result{handler.arg_id, arg_id_end}; -} - -template struct field_type { - using type = remove_cvref_t; -}; - -template -struct field_type::value>> { - using type = remove_cvref_t; -}; - -template -constexpr auto parse_replacement_field_then_tail(S format_str) { - using char_type = typename S::char_type; - constexpr auto str = basic_string_view(format_str); - constexpr char_type c = END_POS != str.size() ? str[END_POS] : char_type(); - if constexpr (c == '}') { - return parse_tail( - field::type, ARG_INDEX>(), - format_str); - } else if constexpr (c != ':') { - FMT_THROW(format_error("expected ':'")); - } else { - constexpr auto result = parse_specs::type>( - str, END_POS + 1, NEXT_ID == manual_indexing_id ? 0 : NEXT_ID); - if constexpr (result.end >= str.size() || str[result.end] != '}') { - FMT_THROW(format_error("expected '}'")); - return 0; - } else { - return parse_tail( - spec_field::type, ARG_INDEX>{ - result.fmt}, - format_str); - } - } -} - -// Compiles a non-empty format string and returns the compiled representation -// or unknown_format() on unrecognized input. -template -constexpr auto compile_format_string(S format_str) { - using char_type = typename S::char_type; - constexpr auto str = basic_string_view(format_str); - if constexpr (str[POS] == '{') { - if constexpr (POS + 1 == str.size()) - FMT_THROW(format_error("unmatched '{' in format string")); - if constexpr (str[POS + 1] == '{') { - return parse_tail(make_text(str, POS, 1), format_str); - } else if constexpr (str[POS + 1] == '}' || str[POS + 1] == ':') { - static_assert(ID != manual_indexing_id, - "cannot switch from manual to automatic argument indexing"); - constexpr auto next_id = - ID != manual_indexing_id ? ID + 1 : manual_indexing_id; - return parse_replacement_field_then_tail, Args, - POS + 1, ID, next_id>( - format_str); - } else { - constexpr auto arg_id_result = - parse_arg_id(str.data() + POS + 1, str.data() + str.size()); - constexpr auto arg_id_end_pos = arg_id_result.arg_id_end - str.data(); - constexpr char_type c = - arg_id_end_pos != str.size() ? str[arg_id_end_pos] : char_type(); - static_assert(c == '}' || c == ':', "missing '}' in format string"); - if constexpr (arg_id_result.arg_id.kind == arg_id_kind::index) { - static_assert( - ID == manual_indexing_id || ID == 0, - "cannot switch from automatic to manual argument indexing"); - constexpr auto arg_index = arg_id_result.arg_id.val.index; - return parse_replacement_field_then_tail, - Args, arg_id_end_pos, - arg_index, manual_indexing_id>( - format_str); - } else if constexpr (arg_id_result.arg_id.kind == arg_id_kind::name) { - constexpr auto arg_index = - get_arg_index_by_name(arg_id_result.arg_id.val.name, Args{}); - if constexpr (arg_index >= 0) { - constexpr auto next_id = - ID != manual_indexing_id ? ID + 1 : manual_indexing_id; - return parse_replacement_field_then_tail< - decltype(get_type::value), Args, arg_id_end_pos, - arg_index, next_id>(format_str); - } else if constexpr (c == '}') { - return parse_tail( - runtime_named_field{arg_id_result.arg_id.val.name}, - format_str); - } else if constexpr (c == ':') { - return unknown_format(); // no type info for specs parsing - } - } - } - } else if constexpr (str[POS] == '}') { - if constexpr (POS + 1 == str.size()) - FMT_THROW(format_error("unmatched '}' in format string")); - return parse_tail(make_text(str, POS, 1), format_str); - } else { - constexpr auto end = parse_text(str, POS + 1); - if constexpr (end - POS > 1) { - return parse_tail(make_text(str, POS, end - POS), - format_str); - } else { - return parse_tail(code_unit{str[POS]}, - format_str); - } - } -} - -template ::value)> -constexpr auto compile(S format_str) { - constexpr auto str = basic_string_view(format_str); - if constexpr (str.size() == 0) { - return detail::make_text(str, 0, 0); - } else { - constexpr auto result = - detail::compile_format_string, 0, 0>( - format_str); - return result; - } -} -#endif // defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) -} // namespace detail - -FMT_BEGIN_EXPORT - -#if defined(__cpp_if_constexpr) && defined(__cpp_return_type_deduction) - -template ::value)> -FMT_INLINE std::basic_string format(const CompiledFormat& cf, - const Args&... args) { - auto s = std::basic_string(); - cf.format(std::back_inserter(s), args...); - return s; -} - -template ::value)> -constexpr FMT_INLINE OutputIt format_to(OutputIt out, const CompiledFormat& cf, - const Args&... args) { - return cf.format(out, args...); -} - -template ::value)> -FMT_INLINE std::basic_string format(const S&, - Args&&... args) { - if constexpr (std::is_same::value) { - constexpr auto str = basic_string_view(S()); - if constexpr (str.size() == 2 && str[0] == '{' && str[1] == '}') { - const auto& first = detail::first(args...); - if constexpr (detail::is_named_arg< - remove_cvref_t>::value) { - return fmt::to_string(first.value); - } else { - return fmt::to_string(first); - } - } - } - constexpr auto compiled = detail::compile(S()); - if constexpr (std::is_same, - detail::unknown_format>()) { - return fmt::format( - static_cast>(S()), - std::forward(args)...); - } else { - return fmt::format(compiled, std::forward(args)...); - } -} - -template ::value)> -FMT_CONSTEXPR OutputIt format_to(OutputIt out, const S&, Args&&... args) { - constexpr auto compiled = detail::compile(S()); - if constexpr (std::is_same, - detail::unknown_format>()) { - return fmt::format_to( - out, static_cast>(S()), - std::forward(args)...); - } else { - return fmt::format_to(out, compiled, std::forward(args)...); - } -} -#endif - -template ::value)> -format_to_n_result format_to_n(OutputIt out, size_t n, - const S& format_str, Args&&... args) { - using traits = detail::fixed_buffer_traits; - auto buf = detail::iterator_buffer(out, n); - format_to(std::back_inserter(buf), format_str, std::forward(args)...); - return {buf.out(), buf.count()}; -} - -template ::value)> -FMT_CONSTEXPR20 size_t formatted_size(const S& format_str, - const Args&... args) { - return fmt::format_to(detail::counting_iterator(), format_str, args...) - .count(); -} - -template ::value)> -void print(std::FILE* f, const S& format_str, const Args&... args) { - memory_buffer buffer; - fmt::format_to(std::back_inserter(buffer), format_str, args...); - detail::print(f, {buffer.data(), buffer.size()}); -} - -template ::value)> -void print(const S& format_str, const Args&... args) { - print(stdout, format_str, args...); -} - -#if FMT_USE_NONTYPE_TEMPLATE_ARGS -inline namespace literals { -template constexpr auto operator""_cf() { - using char_t = remove_cvref_t; - return detail::udl_compiled_string(); -} -} // namespace literals -#endif - -FMT_END_EXPORT -FMT_END_NAMESPACE - -#endif // FMT_COMPILE_H_ diff --git a/src/common/dep/fmt/core.h b/src/common/dep/fmt/core.h deleted file mode 100644 index f9e3b7d6d..000000000 --- a/src/common/dep/fmt/core.h +++ /dev/null @@ -1,2922 +0,0 @@ -// Formatting library for C++ - the core API for char/UTF-8 -// -// Copyright (c) 2012 - present, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_CORE_H_ -#define FMT_CORE_H_ - -#include // std::byte -#include // std::FILE -#include // std::strlen -#include -#include -#include // std::addressof -#include -#include - -// The fmt library version in the form major * 10000 + minor * 100 + patch. -#define FMT_VERSION 100101 - -#if defined(__clang__) && !defined(__ibmxl__) -# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__) -#else -# define FMT_CLANG_VERSION 0 -#endif - -#if defined(__GNUC__) && !defined(__clang__) && !defined(__INTEL_COMPILER) && \ - !defined(__NVCOMPILER) -# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -#else -# define FMT_GCC_VERSION 0 -#endif - -#ifndef FMT_GCC_PRAGMA -// Workaround _Pragma bug https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59884. -# if FMT_GCC_VERSION >= 504 -# define FMT_GCC_PRAGMA(arg) _Pragma(arg) -# else -# define FMT_GCC_PRAGMA(arg) -# endif -#endif - -#ifdef __ICL -# define FMT_ICC_VERSION __ICL -#elif defined(__INTEL_COMPILER) -# define FMT_ICC_VERSION __INTEL_COMPILER -#else -# define FMT_ICC_VERSION 0 -#endif - -#ifdef _MSC_VER -# define FMT_MSC_VERSION _MSC_VER -# define FMT_MSC_WARNING(...) __pragma(warning(__VA_ARGS__)) -#else -# define FMT_MSC_VERSION 0 -# define FMT_MSC_WARNING(...) -#endif - -#ifdef _MSVC_LANG -# define FMT_CPLUSPLUS _MSVC_LANG -#else -# define FMT_CPLUSPLUS __cplusplus -#endif - -#ifdef __has_feature -# define FMT_HAS_FEATURE(x) __has_feature(x) -#else -# define FMT_HAS_FEATURE(x) 0 -#endif - -#if defined(__has_include) || FMT_ICC_VERSION >= 1600 || FMT_MSC_VERSION > 1900 -# define FMT_HAS_INCLUDE(x) __has_include(x) -#else -# define FMT_HAS_INCLUDE(x) 0 -#endif - -#ifdef __has_cpp_attribute -# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) -#else -# define FMT_HAS_CPP_ATTRIBUTE(x) 0 -#endif - -#define FMT_HAS_CPP14_ATTRIBUTE(attribute) \ - (FMT_CPLUSPLUS >= 201402L && FMT_HAS_CPP_ATTRIBUTE(attribute)) - -#define FMT_HAS_CPP17_ATTRIBUTE(attribute) \ - (FMT_CPLUSPLUS >= 201703L && FMT_HAS_CPP_ATTRIBUTE(attribute)) - -// Check if relaxed C++14 constexpr is supported. -// GCC doesn't allow throw in constexpr until version 6 (bug 67371). -#ifndef FMT_USE_CONSTEXPR -# if (FMT_HAS_FEATURE(cxx_relaxed_constexpr) || FMT_MSC_VERSION >= 1912 || \ - (FMT_GCC_VERSION >= 600 && FMT_CPLUSPLUS >= 201402L)) && \ - !FMT_ICC_VERSION && (!defined(__NVCC__) || FMT_CPLUSPLUS >= 202002L) -# define FMT_USE_CONSTEXPR 1 -# else -# define FMT_USE_CONSTEXPR 0 -# endif -#endif -#if FMT_USE_CONSTEXPR -# define FMT_CONSTEXPR constexpr -#else -# define FMT_CONSTEXPR -#endif - -#if ((FMT_CPLUSPLUS >= 202002L) && \ - (!defined(_GLIBCXX_RELEASE) || _GLIBCXX_RELEASE > 9)) || \ - (FMT_CPLUSPLUS >= 201709L && FMT_GCC_VERSION >= 1002) -# define FMT_CONSTEXPR20 constexpr -#else -# define FMT_CONSTEXPR20 -#endif - -// Check if constexpr std::char_traits<>::{compare,length} are supported. -#if defined(__GLIBCXX__) -# if FMT_CPLUSPLUS >= 201703L && defined(_GLIBCXX_RELEASE) && \ - _GLIBCXX_RELEASE >= 7 // GCC 7+ libstdc++ has _GLIBCXX_RELEASE. -# define FMT_CONSTEXPR_CHAR_TRAITS constexpr -# endif -#elif defined(_LIBCPP_VERSION) && FMT_CPLUSPLUS >= 201703L && \ - _LIBCPP_VERSION >= 4000 -# define FMT_CONSTEXPR_CHAR_TRAITS constexpr -#elif FMT_MSC_VERSION >= 1914 && FMT_CPLUSPLUS >= 201703L -# define FMT_CONSTEXPR_CHAR_TRAITS constexpr -#endif -#ifndef FMT_CONSTEXPR_CHAR_TRAITS -# define FMT_CONSTEXPR_CHAR_TRAITS -#endif - -// Check if exceptions are disabled. -#ifndef FMT_EXCEPTIONS -# if (defined(__GNUC__) && !defined(__EXCEPTIONS)) || \ - (FMT_MSC_VERSION && !_HAS_EXCEPTIONS) -# define FMT_EXCEPTIONS 0 -# else -# define FMT_EXCEPTIONS 1 -# endif -#endif - -// Disable [[noreturn]] on MSVC/NVCC because of bogus unreachable code warnings. -#if FMT_EXCEPTIONS && FMT_HAS_CPP_ATTRIBUTE(noreturn) && !FMT_MSC_VERSION && \ - !defined(__NVCC__) -# define FMT_NORETURN [[noreturn]] -#else -# define FMT_NORETURN -#endif - -#ifndef FMT_NODISCARD -# if FMT_HAS_CPP17_ATTRIBUTE(nodiscard) -# define FMT_NODISCARD [[nodiscard]] -# else -# define FMT_NODISCARD -# endif -#endif - -#ifndef FMT_INLINE -# if FMT_GCC_VERSION || FMT_CLANG_VERSION -# define FMT_INLINE inline __attribute__((always_inline)) -# else -# define FMT_INLINE inline -# endif -#endif - -#ifdef _MSC_VER -# define FMT_UNCHECKED_ITERATOR(It) \ - using _Unchecked_type = It // Mark iterator as checked. -#else -# define FMT_UNCHECKED_ITERATOR(It) using unchecked_type = It -#endif - -#ifndef FMT_BEGIN_NAMESPACE -# define FMT_BEGIN_NAMESPACE \ - namespace fmt { \ - inline namespace v10 { -# define FMT_END_NAMESPACE \ - } \ - } -#endif - -#ifndef FMT_EXPORT -# define FMT_EXPORT -# define FMT_BEGIN_EXPORT -# define FMT_END_EXPORT -#endif - -#if !defined(FMT_HEADER_ONLY) && defined(_WIN32) -# ifdef FMT_LIB_EXPORT -# define FMT_API __declspec(dllexport) -# elif defined(FMT_SHARED) -# define FMT_API __declspec(dllimport) -# endif -#else -# if defined(FMT_LIB_EXPORT) || defined(FMT_SHARED) -# if defined(__GNUC__) || defined(__clang__) -# define FMT_API __attribute__((visibility("default"))) -# endif -# endif -#endif -#ifndef FMT_API -# define FMT_API -#endif - -// libc++ supports string_view in pre-c++17. -#if FMT_HAS_INCLUDE() && \ - (FMT_CPLUSPLUS >= 201703L || defined(_LIBCPP_VERSION)) -# include -# define FMT_USE_STRING_VIEW -#elif FMT_HAS_INCLUDE("experimental/string_view") && FMT_CPLUSPLUS >= 201402L -# include -# define FMT_USE_EXPERIMENTAL_STRING_VIEW -#endif - -#ifndef FMT_UNICODE -# define FMT_UNICODE !FMT_MSC_VERSION -#endif - -#ifndef FMT_CONSTEVAL -# if ((FMT_GCC_VERSION >= 1000 || FMT_CLANG_VERSION >= 1101) && \ - (!defined(__apple_build_version__) || \ - __apple_build_version__ >= 14000029L) && \ - FMT_CPLUSPLUS >= 202002L) || \ - (defined(__cpp_consteval) && \ - (!FMT_MSC_VERSION || _MSC_FULL_VER >= 193030704)) -// consteval is broken in MSVC before VS2022 and Apple clang before 14. -# define FMT_CONSTEVAL consteval -# define FMT_HAS_CONSTEVAL -# else -# define FMT_CONSTEVAL -# endif -#endif - -#ifndef FMT_USE_NONTYPE_TEMPLATE_ARGS -# if defined(__cpp_nontype_template_args) && \ - ((FMT_GCC_VERSION >= 903 && FMT_CPLUSPLUS >= 201709L) || \ - __cpp_nontype_template_args >= 201911L) && \ - !defined(__NVCOMPILER) && !defined(__LCC__) -# define FMT_USE_NONTYPE_TEMPLATE_ARGS 1 -# else -# define FMT_USE_NONTYPE_TEMPLATE_ARGS 0 -# endif -#endif - -// Enable minimal optimizations for more compact code in debug mode. -FMT_GCC_PRAGMA("GCC push_options") -#if !defined(__OPTIMIZE__) && !defined(__NVCOMPILER) && !defined(__LCC__) && \ - !defined(__CUDACC__) -FMT_GCC_PRAGMA("GCC optimize(\"Og\")") -#endif - -FMT_BEGIN_NAMESPACE - -// Implementations of enable_if_t and other metafunctions for older systems. -template -using enable_if_t = typename std::enable_if::type; -template -using conditional_t = typename std::conditional::type; -template using bool_constant = std::integral_constant; -template -using remove_reference_t = typename std::remove_reference::type; -template -using remove_const_t = typename std::remove_const::type; -template -using remove_cvref_t = typename std::remove_cv>::type; -template struct type_identity { using type = T; }; -template using type_identity_t = typename type_identity::type; -template -using underlying_t = typename std::underlying_type::type; - -// Checks whether T is a container with contiguous storage. -template struct is_contiguous : std::false_type {}; -template -struct is_contiguous> : std::true_type {}; - -struct monostate { - constexpr monostate() {} -}; - -// An enable_if helper to be used in template parameters which results in much -// shorter symbols: https://godbolt.org/z/sWw4vP. Extra parentheses are needed -// to workaround a bug in MSVC 2019 (see #1140 and #1186). -#ifdef FMT_DOC -# define FMT_ENABLE_IF(...) -#else -# define FMT_ENABLE_IF(...) fmt::enable_if_t<(__VA_ARGS__), int> = 0 -#endif - -// This is defined in core.h instead of format.h to avoid injecting in std. -// It is a template to avoid undesirable implicit conversions to std::byte. -#ifdef __cpp_lib_byte -template ::value)> -inline auto format_as(T b) -> unsigned char { - return static_cast(b); -} -#endif - -namespace detail { -// Suppresses "unused variable" warnings with the method described in -// https://herbsutter.com/2009/10/18/mailbag-shutting-up-compiler-warnings/. -// (void)var does not work on many Intel compilers. -template FMT_CONSTEXPR void ignore_unused(const T&...) {} - -constexpr FMT_INLINE auto is_constant_evaluated( - bool default_value = false) noexcept -> bool { -// Workaround for incompatibility between libstdc++ consteval-based -// std::is_constant_evaluated() implementation and clang-14. -// https://github.com/fmtlib/fmt/issues/3247 -#if FMT_CPLUSPLUS >= 202002L && defined(_GLIBCXX_RELEASE) && \ - _GLIBCXX_RELEASE >= 12 && \ - (FMT_CLANG_VERSION >= 1400 && FMT_CLANG_VERSION < 1500) - ignore_unused(default_value); - return __builtin_is_constant_evaluated(); -#elif defined(__cpp_lib_is_constant_evaluated) - ignore_unused(default_value); - return std::is_constant_evaluated(); -#else - return default_value; -#endif -} - -// Suppresses "conditional expression is constant" warnings. -template constexpr FMT_INLINE auto const_check(T value) -> T { - return value; -} - -FMT_NORETURN FMT_API void assert_fail(const char* file, int line, - const char* message); - -#ifndef FMT_ASSERT -# ifdef NDEBUG -// FMT_ASSERT is not empty to avoid -Wempty-body. -# define FMT_ASSERT(condition, message) \ - fmt::detail::ignore_unused((condition), (message)) -# else -# define FMT_ASSERT(condition, message) \ - ((condition) /* void() fails with -Winvalid-constexpr on clang 4.0.1 */ \ - ? (void)0 \ - : fmt::detail::assert_fail(__FILE__, __LINE__, (message))) -# endif -#endif - -#if defined(FMT_USE_STRING_VIEW) -template using std_string_view = std::basic_string_view; -#elif defined(FMT_USE_EXPERIMENTAL_STRING_VIEW) -template -using std_string_view = std::experimental::basic_string_view; -#else -template struct std_string_view {}; -#endif - -#ifdef FMT_USE_INT128 -// Do nothing. -#elif defined(__SIZEOF_INT128__) && !defined(__NVCC__) && \ - !(FMT_CLANG_VERSION && FMT_MSC_VERSION) -# define FMT_USE_INT128 1 -using int128_opt = __int128_t; // An optional native 128-bit integer. -using uint128_opt = __uint128_t; -template inline auto convert_for_visit(T value) -> T { - return value; -} -#else -# define FMT_USE_INT128 0 -#endif -#if !FMT_USE_INT128 -enum class int128_opt {}; -enum class uint128_opt {}; -// Reduce template instantiations. -template auto convert_for_visit(T) -> monostate { return {}; } -#endif - -// Casts a nonnegative integer to unsigned. -template -FMT_CONSTEXPR auto to_unsigned(Int value) -> - typename std::make_unsigned::type { - FMT_ASSERT(std::is_unsigned::value || value >= 0, "negative value"); - return static_cast::type>(value); -} - -FMT_CONSTEXPR inline auto is_utf8() -> bool { - FMT_MSC_WARNING(suppress : 4566) constexpr unsigned char section[] = "\u00A7"; - - // Avoid buggy sign extensions in MSVC's constant evaluation mode (#2297). - using uchar = unsigned char; - return FMT_UNICODE || (sizeof(section) == 3 && uchar(section[0]) == 0xC2 && - uchar(section[1]) == 0xA7); -} -} // namespace detail - -/** - An implementation of ``std::basic_string_view`` for pre-C++17. It provides a - subset of the API. ``fmt::basic_string_view`` is used for format strings even - if ``std::string_view`` is available to prevent issues when a library is - compiled with a different ``-std`` option than the client code (which is not - recommended). - */ -FMT_EXPORT -template class basic_string_view { - private: - const Char* data_; - size_t size_; - - public: - using value_type = Char; - using iterator = const Char*; - - constexpr basic_string_view() noexcept : data_(nullptr), size_(0) {} - - /** Constructs a string reference object from a C string and a size. */ - constexpr basic_string_view(const Char* s, size_t count) noexcept - : data_(s), size_(count) {} - - /** - \rst - Constructs a string reference object from a C string computing - the size with ``std::char_traits::length``. - \endrst - */ - FMT_CONSTEXPR_CHAR_TRAITS - FMT_INLINE - basic_string_view(const Char* s) - : data_(s), - size_(detail::const_check(std::is_same::value && - !detail::is_constant_evaluated(true)) - ? std::strlen(reinterpret_cast(s)) - : std::char_traits::length(s)) {} - - /** Constructs a string reference from a ``std::basic_string`` object. */ - template - FMT_CONSTEXPR basic_string_view( - const std::basic_string& s) noexcept - : data_(s.data()), size_(s.size()) {} - - template >::value)> - FMT_CONSTEXPR basic_string_view(S s) noexcept - : data_(s.data()), size_(s.size()) {} - - /** Returns a pointer to the string data. */ - constexpr auto data() const noexcept -> const Char* { return data_; } - - /** Returns the string size. */ - constexpr auto size() const noexcept -> size_t { return size_; } - - constexpr auto begin() const noexcept -> iterator { return data_; } - constexpr auto end() const noexcept -> iterator { return data_ + size_; } - - constexpr auto operator[](size_t pos) const noexcept -> const Char& { - return data_[pos]; - } - - FMT_CONSTEXPR void remove_prefix(size_t n) noexcept { - data_ += n; - size_ -= n; - } - - FMT_CONSTEXPR_CHAR_TRAITS bool starts_with( - basic_string_view sv) const noexcept { - return size_ >= sv.size_ && - std::char_traits::compare(data_, sv.data_, sv.size_) == 0; - } - FMT_CONSTEXPR_CHAR_TRAITS bool starts_with(Char c) const noexcept { - return size_ >= 1 && std::char_traits::eq(*data_, c); - } - FMT_CONSTEXPR_CHAR_TRAITS bool starts_with(const Char* s) const { - return starts_with(basic_string_view(s)); - } - - // Lexicographically compare this string reference to other. - FMT_CONSTEXPR_CHAR_TRAITS auto compare(basic_string_view other) const -> int { - size_t str_size = size_ < other.size_ ? size_ : other.size_; - int result = std::char_traits::compare(data_, other.data_, str_size); - if (result == 0) - result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1); - return result; - } - - FMT_CONSTEXPR_CHAR_TRAITS friend auto operator==(basic_string_view lhs, - basic_string_view rhs) - -> bool { - return lhs.compare(rhs) == 0; - } - friend auto operator!=(basic_string_view lhs, basic_string_view rhs) -> bool { - return lhs.compare(rhs) != 0; - } - friend auto operator<(basic_string_view lhs, basic_string_view rhs) -> bool { - return lhs.compare(rhs) < 0; - } - friend auto operator<=(basic_string_view lhs, basic_string_view rhs) -> bool { - return lhs.compare(rhs) <= 0; - } - friend auto operator>(basic_string_view lhs, basic_string_view rhs) -> bool { - return lhs.compare(rhs) > 0; - } - friend auto operator>=(basic_string_view lhs, basic_string_view rhs) -> bool { - return lhs.compare(rhs) >= 0; - } -}; - -FMT_EXPORT -using string_view = basic_string_view; - -/** Specifies if ``T`` is a character type. Can be specialized by users. */ -FMT_EXPORT -template struct is_char : std::false_type {}; -template <> struct is_char : std::true_type {}; - -namespace detail { - -// A base class for compile-time strings. -struct compile_string {}; - -template -struct is_compile_string : std::is_base_of {}; - -template ::value)> -FMT_INLINE auto to_string_view(const Char* s) -> basic_string_view { - return s; -} -template -inline auto to_string_view(const std::basic_string& s) - -> basic_string_view { - return s; -} -template -constexpr auto to_string_view(basic_string_view s) - -> basic_string_view { - return s; -} -template >::value)> -inline auto to_string_view(std_string_view s) -> basic_string_view { - return s; -} -template ::value)> -constexpr auto to_string_view(const S& s) - -> basic_string_view { - return basic_string_view(s); -} -void to_string_view(...); - -// Specifies whether S is a string type convertible to fmt::basic_string_view. -// It should be a constexpr function but MSVC 2017 fails to compile it in -// enable_if and MSVC 2015 fails to compile it as an alias template. -// ADL is intentionally disabled as to_string_view is not an extension point. -template -struct is_string - : std::is_class()))> {}; - -template struct char_t_impl {}; -template struct char_t_impl::value>> { - using result = decltype(to_string_view(std::declval())); - using type = typename result::value_type; -}; - -enum class type { - none_type, - // Integer types should go first, - int_type, - uint_type, - long_long_type, - ulong_long_type, - int128_type, - uint128_type, - bool_type, - char_type, - last_integer_type = char_type, - // followed by floating-point types. - float_type, - double_type, - long_double_type, - last_numeric_type = long_double_type, - cstring_type, - string_type, - pointer_type, - custom_type -}; - -// Maps core type T to the corresponding type enum constant. -template -struct type_constant : std::integral_constant {}; - -#define FMT_TYPE_CONSTANT(Type, constant) \ - template \ - struct type_constant \ - : std::integral_constant {} - -FMT_TYPE_CONSTANT(int, int_type); -FMT_TYPE_CONSTANT(unsigned, uint_type); -FMT_TYPE_CONSTANT(long long, long_long_type); -FMT_TYPE_CONSTANT(unsigned long long, ulong_long_type); -FMT_TYPE_CONSTANT(int128_opt, int128_type); -FMT_TYPE_CONSTANT(uint128_opt, uint128_type); -FMT_TYPE_CONSTANT(bool, bool_type); -FMT_TYPE_CONSTANT(Char, char_type); -FMT_TYPE_CONSTANT(float, float_type); -FMT_TYPE_CONSTANT(double, double_type); -FMT_TYPE_CONSTANT(long double, long_double_type); -FMT_TYPE_CONSTANT(const Char*, cstring_type); -FMT_TYPE_CONSTANT(basic_string_view, string_type); -FMT_TYPE_CONSTANT(const void*, pointer_type); - -constexpr bool is_integral_type(type t) { - return t > type::none_type && t <= type::last_integer_type; -} -constexpr bool is_arithmetic_type(type t) { - return t > type::none_type && t <= type::last_numeric_type; -} - -constexpr auto set(type rhs) -> int { return 1 << static_cast(rhs); } -constexpr auto in(type t, int set) -> bool { - return ((set >> static_cast(t)) & 1) != 0; -} - -// Bitsets of types. -enum { - sint_set = - set(type::int_type) | set(type::long_long_type) | set(type::int128_type), - uint_set = set(type::uint_type) | set(type::ulong_long_type) | - set(type::uint128_type), - bool_set = set(type::bool_type), - char_set = set(type::char_type), - float_set = set(type::float_type) | set(type::double_type) | - set(type::long_double_type), - string_set = set(type::string_type), - cstring_set = set(type::cstring_type), - pointer_set = set(type::pointer_type) -}; - -FMT_NORETURN FMT_API void throw_format_error(const char* message); - -struct error_handler { - constexpr error_handler() = default; - - // This function is intentionally not constexpr to give a compile-time error. - FMT_NORETURN void on_error(const char* message) { - throw_format_error(message); - } -}; -} // namespace detail - -/** Throws ``format_error`` with a given message. */ -using detail::throw_format_error; - -/** String's character type. */ -template using char_t = typename detail::char_t_impl::type; - -/** - \rst - Parsing context consisting of a format string range being parsed and an - argument counter for automatic indexing. - You can use the ``format_parse_context`` type alias for ``char`` instead. - \endrst - */ -FMT_EXPORT -template class basic_format_parse_context { - private: - basic_string_view format_str_; - int next_arg_id_; - - FMT_CONSTEXPR void do_check_arg_id(int id); - - public: - using char_type = Char; - using iterator = const Char*; - - explicit constexpr basic_format_parse_context( - basic_string_view format_str, int next_arg_id = 0) - : format_str_(format_str), next_arg_id_(next_arg_id) {} - - /** - Returns an iterator to the beginning of the format string range being - parsed. - */ - constexpr auto begin() const noexcept -> iterator { - return format_str_.begin(); - } - - /** - Returns an iterator past the end of the format string range being parsed. - */ - constexpr auto end() const noexcept -> iterator { return format_str_.end(); } - - /** Advances the begin iterator to ``it``. */ - FMT_CONSTEXPR void advance_to(iterator it) { - format_str_.remove_prefix(detail::to_unsigned(it - begin())); - } - - /** - Reports an error if using the manual argument indexing; otherwise returns - the next argument index and switches to the automatic indexing. - */ - FMT_CONSTEXPR auto next_arg_id() -> int { - if (next_arg_id_ < 0) { - detail::throw_format_error( - "cannot switch from manual to automatic argument indexing"); - return 0; - } - int id = next_arg_id_++; - do_check_arg_id(id); - return id; - } - - /** - Reports an error if using the automatic argument indexing; otherwise - switches to the manual indexing. - */ - FMT_CONSTEXPR void check_arg_id(int id) { - if (next_arg_id_ > 0) { - detail::throw_format_error( - "cannot switch from automatic to manual argument indexing"); - return; - } - next_arg_id_ = -1; - do_check_arg_id(id); - } - FMT_CONSTEXPR void check_arg_id(basic_string_view) {} - FMT_CONSTEXPR void check_dynamic_spec(int arg_id); -}; - -FMT_EXPORT -using format_parse_context = basic_format_parse_context; - -namespace detail { -// A parse context with extra data used only in compile-time checks. -template -class compile_parse_context : public basic_format_parse_context { - private: - int num_args_; - const type* types_; - using base = basic_format_parse_context; - - public: - explicit FMT_CONSTEXPR compile_parse_context( - basic_string_view format_str, int num_args, const type* types, - int next_arg_id = 0) - : base(format_str, next_arg_id), num_args_(num_args), types_(types) {} - - constexpr auto num_args() const -> int { return num_args_; } - constexpr auto arg_type(int id) const -> type { return types_[id]; } - - FMT_CONSTEXPR auto next_arg_id() -> int { - int id = base::next_arg_id(); - if (id >= num_args_) throw_format_error("argument not found"); - return id; - } - - FMT_CONSTEXPR void check_arg_id(int id) { - base::check_arg_id(id); - if (id >= num_args_) throw_format_error("argument not found"); - } - using base::check_arg_id; - - FMT_CONSTEXPR void check_dynamic_spec(int arg_id) { - detail::ignore_unused(arg_id); -#if !defined(__LCC__) - if (arg_id < num_args_ && types_ && !is_integral_type(types_[arg_id])) - throw_format_error("width/precision is not integer"); -#endif - } -}; - -// Extracts a reference to the container from back_insert_iterator. -template -inline auto get_container(std::back_insert_iterator it) - -> Container& { - using base = std::back_insert_iterator; - struct accessor : base { - accessor(base b) : base(b) {} - using base::container; - }; - return *accessor(it).container; -} - -template -FMT_CONSTEXPR auto copy_str(InputIt begin, InputIt end, OutputIt out) - -> OutputIt { - while (begin != end) *out++ = static_cast(*begin++); - return out; -} - -template , U>::value&& is_char::value)> -FMT_CONSTEXPR auto copy_str(T* begin, T* end, U* out) -> U* { - if (is_constant_evaluated()) return copy_str(begin, end, out); - auto size = to_unsigned(end - begin); - if (size > 0) memcpy(out, begin, size * sizeof(U)); - return out + size; -} - -/** - \rst - A contiguous memory buffer with an optional growing ability. It is an internal - class and shouldn't be used directly, only via `~fmt::basic_memory_buffer`. - \endrst - */ -template class buffer { - private: - T* ptr_; - size_t size_; - size_t capacity_; - - protected: - // Don't initialize ptr_ since it is not accessed to save a few cycles. - FMT_MSC_WARNING(suppress : 26495) - buffer(size_t sz) noexcept : size_(sz), capacity_(sz) {} - - FMT_CONSTEXPR20 buffer(T* p = nullptr, size_t sz = 0, size_t cap = 0) noexcept - : ptr_(p), size_(sz), capacity_(cap) {} - - FMT_CONSTEXPR20 ~buffer() = default; - buffer(buffer&&) = default; - - /** Sets the buffer data and capacity. */ - FMT_CONSTEXPR void set(T* buf_data, size_t buf_capacity) noexcept { - ptr_ = buf_data; - capacity_ = buf_capacity; - } - - /** Increases the buffer capacity to hold at least *capacity* elements. */ - virtual FMT_CONSTEXPR20 void grow(size_t capacity) = 0; - - public: - using value_type = T; - using const_reference = const T&; - - buffer(const buffer&) = delete; - void operator=(const buffer&) = delete; - - FMT_INLINE auto begin() noexcept -> T* { return ptr_; } - FMT_INLINE auto end() noexcept -> T* { return ptr_ + size_; } - - FMT_INLINE auto begin() const noexcept -> const T* { return ptr_; } - FMT_INLINE auto end() const noexcept -> const T* { return ptr_ + size_; } - - /** Returns the size of this buffer. */ - constexpr auto size() const noexcept -> size_t { return size_; } - - /** Returns the capacity of this buffer. */ - constexpr auto capacity() const noexcept -> size_t { return capacity_; } - - /** Returns a pointer to the buffer data (not null-terminated). */ - FMT_CONSTEXPR auto data() noexcept -> T* { return ptr_; } - FMT_CONSTEXPR auto data() const noexcept -> const T* { return ptr_; } - - /** Clears this buffer. */ - void clear() { size_ = 0; } - - // Tries resizing the buffer to contain *count* elements. If T is a POD type - // the new elements may not be initialized. - FMT_CONSTEXPR20 void try_resize(size_t count) { - try_reserve(count); - size_ = count <= capacity_ ? count : capacity_; - } - - // Tries increasing the buffer capacity to *new_capacity*. It can increase the - // capacity by a smaller amount than requested but guarantees there is space - // for at least one additional element either by increasing the capacity or by - // flushing the buffer if it is full. - FMT_CONSTEXPR20 void try_reserve(size_t new_capacity) { - if (new_capacity > capacity_) grow(new_capacity); - } - - FMT_CONSTEXPR20 void push_back(const T& value) { - try_reserve(size_ + 1); - ptr_[size_++] = value; - } - - /** Appends data to the end of the buffer. */ - template void append(const U* begin, const U* end); - - template FMT_CONSTEXPR auto operator[](Idx index) -> T& { - return ptr_[index]; - } - template - FMT_CONSTEXPR auto operator[](Idx index) const -> const T& { - return ptr_[index]; - } -}; - -struct buffer_traits { - explicit buffer_traits(size_t) {} - auto count() const -> size_t { return 0; } - auto limit(size_t size) -> size_t { return size; } -}; - -class fixed_buffer_traits { - private: - size_t count_ = 0; - size_t limit_; - - public: - explicit fixed_buffer_traits(size_t limit) : limit_(limit) {} - auto count() const -> size_t { return count_; } - auto limit(size_t size) -> size_t { - size_t n = limit_ > count_ ? limit_ - count_ : 0; - count_ += size; - return size < n ? size : n; - } -}; - -// A buffer that writes to an output iterator when flushed. -template -class iterator_buffer final : public Traits, public buffer { - private: - OutputIt out_; - enum { buffer_size = 256 }; - T data_[buffer_size]; - - protected: - FMT_CONSTEXPR20 void grow(size_t) override { - if (this->size() == buffer_size) flush(); - } - - void flush() { - auto size = this->size(); - this->clear(); - out_ = copy_str(data_, data_ + this->limit(size), out_); - } - - public: - explicit iterator_buffer(OutputIt out, size_t n = buffer_size) - : Traits(n), buffer(data_, 0, buffer_size), out_(out) {} - iterator_buffer(iterator_buffer&& other) - : Traits(other), buffer(data_, 0, buffer_size), out_(other.out_) {} - ~iterator_buffer() { flush(); } - - auto out() -> OutputIt { - flush(); - return out_; - } - auto count() const -> size_t { return Traits::count() + this->size(); } -}; - -template -class iterator_buffer final - : public fixed_buffer_traits, - public buffer { - private: - T* out_; - enum { buffer_size = 256 }; - T data_[buffer_size]; - - protected: - FMT_CONSTEXPR20 void grow(size_t) override { - if (this->size() == this->capacity()) flush(); - } - - void flush() { - size_t n = this->limit(this->size()); - if (this->data() == out_) { - out_ += n; - this->set(data_, buffer_size); - } - this->clear(); - } - - public: - explicit iterator_buffer(T* out, size_t n = buffer_size) - : fixed_buffer_traits(n), buffer(out, 0, n), out_(out) {} - iterator_buffer(iterator_buffer&& other) - : fixed_buffer_traits(other), - buffer(std::move(other)), - out_(other.out_) { - if (this->data() != out_) { - this->set(data_, buffer_size); - this->clear(); - } - } - ~iterator_buffer() { flush(); } - - auto out() -> T* { - flush(); - return out_; - } - auto count() const -> size_t { - return fixed_buffer_traits::count() + this->size(); - } -}; - -template class iterator_buffer final : public buffer { - protected: - FMT_CONSTEXPR20 void grow(size_t) override {} - - public: - explicit iterator_buffer(T* out, size_t = 0) : buffer(out, 0, ~size_t()) {} - - auto out() -> T* { return &*this->end(); } -}; - -// A buffer that writes to a container with the contiguous storage. -template -class iterator_buffer, - enable_if_t::value, - typename Container::value_type>> - final : public buffer { - private: - Container& container_; - - protected: - FMT_CONSTEXPR20 void grow(size_t capacity) override { - container_.resize(capacity); - this->set(&container_[0], capacity); - } - - public: - explicit iterator_buffer(Container& c) - : buffer(c.size()), container_(c) {} - explicit iterator_buffer(std::back_insert_iterator out, size_t = 0) - : iterator_buffer(get_container(out)) {} - - auto out() -> std::back_insert_iterator { - return std::back_inserter(container_); - } -}; - -// A buffer that counts the number of code units written discarding the output. -template class counting_buffer final : public buffer { - private: - enum { buffer_size = 256 }; - T data_[buffer_size]; - size_t count_ = 0; - - protected: - FMT_CONSTEXPR20 void grow(size_t) override { - if (this->size() != buffer_size) return; - count_ += this->size(); - this->clear(); - } - - public: - counting_buffer() : buffer(data_, 0, buffer_size) {} - - auto count() -> size_t { return count_ + this->size(); } -}; -} // namespace detail - -template -FMT_CONSTEXPR void basic_format_parse_context::do_check_arg_id(int id) { - // Argument id is only checked at compile-time during parsing because - // formatting has its own validation. - if (detail::is_constant_evaluated() && - (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) { - using context = detail::compile_parse_context; - if (id >= static_cast(this)->num_args()) - detail::throw_format_error("argument not found"); - } -} - -template -FMT_CONSTEXPR void basic_format_parse_context::check_dynamic_spec( - int arg_id) { - if (detail::is_constant_evaluated() && - (!FMT_GCC_VERSION || FMT_GCC_VERSION >= 1200)) { - using context = detail::compile_parse_context; - static_cast(this)->check_dynamic_spec(arg_id); - } -} - -FMT_EXPORT template class basic_format_arg; -FMT_EXPORT template class basic_format_args; -FMT_EXPORT template class dynamic_format_arg_store; - -// A formatter for objects of type T. -FMT_EXPORT -template -struct formatter { - // A deleted default constructor indicates a disabled formatter. - formatter() = delete; -}; - -// Specifies if T has an enabled formatter specialization. A type can be -// formattable even if it doesn't have a formatter e.g. via a conversion. -template -using has_formatter = - std::is_constructible>; - -// An output iterator that appends to a buffer. -// It is used to reduce symbol sizes for the common case. -class appender : public std::back_insert_iterator> { - using base = std::back_insert_iterator>; - - public: - using std::back_insert_iterator>::back_insert_iterator; - appender(base it) noexcept : base(it) {} - FMT_UNCHECKED_ITERATOR(appender); - - auto operator++() noexcept -> appender& { return *this; } - auto operator++(int) noexcept -> appender { return *this; } -}; - -namespace detail { - -template -constexpr auto has_const_formatter_impl(T*) - -> decltype(typename Context::template formatter_type().format( - std::declval(), std::declval()), - true) { - return true; -} -template -constexpr auto has_const_formatter_impl(...) -> bool { - return false; -} -template -constexpr auto has_const_formatter() -> bool { - return has_const_formatter_impl(static_cast(nullptr)); -} - -template -using buffer_appender = conditional_t::value, appender, - std::back_insert_iterator>>; - -// Maps an output iterator to a buffer. -template -auto get_buffer(OutputIt out) -> iterator_buffer { - return iterator_buffer(out); -} -template , Buf>::value)> -auto get_buffer(std::back_insert_iterator out) -> buffer& { - return get_container(out); -} - -template -FMT_INLINE auto get_iterator(Buf& buf, OutputIt) -> decltype(buf.out()) { - return buf.out(); -} -template -auto get_iterator(buffer&, OutputIt out) -> OutputIt { - return out; -} - -struct view {}; - -template struct named_arg : view { - const Char* name; - const T& value; - named_arg(const Char* n, const T& v) : name(n), value(v) {} -}; - -template struct named_arg_info { - const Char* name; - int id; -}; - -template -struct arg_data { - // args_[0].named_args points to named_args_ to avoid bloating format_args. - // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. - T args_[1 + (NUM_ARGS != 0 ? NUM_ARGS : +1)]; - named_arg_info named_args_[NUM_NAMED_ARGS]; - - template - arg_data(const U&... init) : args_{T(named_args_, NUM_NAMED_ARGS), init...} {} - arg_data(const arg_data& other) = delete; - auto args() const -> const T* { return args_ + 1; } - auto named_args() -> named_arg_info* { return named_args_; } -}; - -template -struct arg_data { - // +1 to workaround a bug in gcc 7.5 that causes duplicated-branches warning. - T args_[NUM_ARGS != 0 ? NUM_ARGS : +1]; - - template - FMT_CONSTEXPR FMT_INLINE arg_data(const U&... init) : args_{init...} {} - FMT_CONSTEXPR FMT_INLINE auto args() const -> const T* { return args_; } - FMT_CONSTEXPR FMT_INLINE auto named_args() -> std::nullptr_t { - return nullptr; - } -}; - -template -inline void init_named_args(named_arg_info*, int, int) {} - -template struct is_named_arg : std::false_type {}; -template struct is_statically_named_arg : std::false_type {}; - -template -struct is_named_arg> : std::true_type {}; - -template ::value)> -void init_named_args(named_arg_info* named_args, int arg_count, - int named_arg_count, const T&, const Tail&... args) { - init_named_args(named_args, arg_count + 1, named_arg_count, args...); -} - -template ::value)> -void init_named_args(named_arg_info* named_args, int arg_count, - int named_arg_count, const T& arg, const Tail&... args) { - named_args[named_arg_count++] = {arg.name, arg_count}; - init_named_args(named_args, arg_count + 1, named_arg_count, args...); -} - -template -FMT_CONSTEXPR FMT_INLINE void init_named_args(std::nullptr_t, int, int, - const Args&...) {} - -template constexpr auto count() -> size_t { return B ? 1 : 0; } -template constexpr auto count() -> size_t { - return (B1 ? 1 : 0) + count(); -} - -template constexpr auto count_named_args() -> size_t { - return count::value...>(); -} - -template -constexpr auto count_statically_named_args() -> size_t { - return count::value...>(); -} - -struct unformattable {}; -struct unformattable_char : unformattable {}; -struct unformattable_pointer : unformattable {}; - -template struct string_value { - const Char* data; - size_t size; -}; - -template struct named_arg_value { - const named_arg_info* data; - size_t size; -}; - -template struct custom_value { - using parse_context = typename Context::parse_context_type; - void* value; - void (*format)(void* arg, parse_context& parse_ctx, Context& ctx); -}; - -// A formatting argument value. -template class value { - public: - using char_type = typename Context::char_type; - - union { - monostate no_value; - int int_value; - unsigned uint_value; - long long long_long_value; - unsigned long long ulong_long_value; - int128_opt int128_value; - uint128_opt uint128_value; - bool bool_value; - char_type char_value; - float float_value; - double double_value; - long double long_double_value; - const void* pointer; - string_value string; - custom_value custom; - named_arg_value named_args; - }; - - constexpr FMT_INLINE value() : no_value() {} - constexpr FMT_INLINE value(int val) : int_value(val) {} - constexpr FMT_INLINE value(unsigned val) : uint_value(val) {} - constexpr FMT_INLINE value(long long val) : long_long_value(val) {} - constexpr FMT_INLINE value(unsigned long long val) : ulong_long_value(val) {} - FMT_INLINE value(int128_opt val) : int128_value(val) {} - FMT_INLINE value(uint128_opt val) : uint128_value(val) {} - constexpr FMT_INLINE value(float val) : float_value(val) {} - constexpr FMT_INLINE value(double val) : double_value(val) {} - FMT_INLINE value(long double val) : long_double_value(val) {} - constexpr FMT_INLINE value(bool val) : bool_value(val) {} - constexpr FMT_INLINE value(char_type val) : char_value(val) {} - FMT_CONSTEXPR FMT_INLINE value(const char_type* val) { - string.data = val; - if (is_constant_evaluated()) string.size = {}; - } - FMT_CONSTEXPR FMT_INLINE value(basic_string_view val) { - string.data = val.data(); - string.size = val.size(); - } - FMT_INLINE value(const void* val) : pointer(val) {} - FMT_INLINE value(const named_arg_info* args, size_t size) - : named_args{args, size} {} - - template FMT_CONSTEXPR20 FMT_INLINE value(T& val) { - using value_type = remove_const_t; - custom.value = const_cast(std::addressof(val)); - // Get the formatter type through the context to allow different contexts - // have different extension points, e.g. `formatter` for `format` and - // `printf_formatter` for `printf`. - custom.format = format_custom_arg< - value_type, typename Context::template formatter_type>; - } - value(unformattable); - value(unformattable_char); - value(unformattable_pointer); - - private: - // Formats an argument of a custom type, such as a user-defined class. - template - static void format_custom_arg(void* arg, - typename Context::parse_context_type& parse_ctx, - Context& ctx) { - auto f = Formatter(); - parse_ctx.advance_to(f.parse(parse_ctx)); - using qualified_type = - conditional_t(), const T, T>; - ctx.advance_to(f.format(*static_cast(arg), ctx)); - } -}; - -// To minimize the number of types we need to deal with, long is translated -// either to int or to long long depending on its size. -enum { long_short = sizeof(long) == sizeof(int) }; -using long_type = conditional_t; -using ulong_type = conditional_t; - -template struct format_as_result { - template ::value || std::is_class::value)> - static auto map(U*) -> decltype(format_as(std::declval())); - static auto map(...) -> void; - - using type = decltype(map(static_cast(nullptr))); -}; -template using format_as_t = typename format_as_result::type; - -template -struct has_format_as - : bool_constant, void>::value> {}; - -// Maps formatting arguments to core types. -// arg_mapper reports errors by returning unformattable instead of using -// static_assert because it's used in the is_formattable trait. -template struct arg_mapper { - using char_type = typename Context::char_type; - - FMT_CONSTEXPR FMT_INLINE auto map(signed char val) -> int { return val; } - FMT_CONSTEXPR FMT_INLINE auto map(unsigned char val) -> unsigned { - return val; - } - FMT_CONSTEXPR FMT_INLINE auto map(short val) -> int { return val; } - FMT_CONSTEXPR FMT_INLINE auto map(unsigned short val) -> unsigned { - return val; - } - FMT_CONSTEXPR FMT_INLINE auto map(int val) -> int { return val; } - FMT_CONSTEXPR FMT_INLINE auto map(unsigned val) -> unsigned { return val; } - FMT_CONSTEXPR FMT_INLINE auto map(long val) -> long_type { return val; } - FMT_CONSTEXPR FMT_INLINE auto map(unsigned long val) -> ulong_type { - return val; - } - FMT_CONSTEXPR FMT_INLINE auto map(long long val) -> long long { return val; } - FMT_CONSTEXPR FMT_INLINE auto map(unsigned long long val) - -> unsigned long long { - return val; - } - FMT_CONSTEXPR FMT_INLINE auto map(int128_opt val) -> int128_opt { - return val; - } - FMT_CONSTEXPR FMT_INLINE auto map(uint128_opt val) -> uint128_opt { - return val; - } - FMT_CONSTEXPR FMT_INLINE auto map(bool val) -> bool { return val; } - - template ::value || - std::is_same::value)> - FMT_CONSTEXPR FMT_INLINE auto map(T val) -> char_type { - return val; - } - template ::value || -#ifdef __cpp_char8_t - std::is_same::value || -#endif - std::is_same::value || - std::is_same::value) && - !std::is_same::value, - int> = 0> - FMT_CONSTEXPR FMT_INLINE auto map(T) -> unformattable_char { - return {}; - } - - FMT_CONSTEXPR FMT_INLINE auto map(float val) -> float { return val; } - FMT_CONSTEXPR FMT_INLINE auto map(double val) -> double { return val; } - FMT_CONSTEXPR FMT_INLINE auto map(long double val) -> long double { - return val; - } - - FMT_CONSTEXPR FMT_INLINE auto map(char_type* val) -> const char_type* { - return val; - } - FMT_CONSTEXPR FMT_INLINE auto map(const char_type* val) -> const char_type* { - return val; - } - template ::value && !std::is_pointer::value && - std::is_same>::value)> - FMT_CONSTEXPR FMT_INLINE auto map(const T& val) - -> basic_string_view { - return to_string_view(val); - } - template ::value && !std::is_pointer::value && - !std::is_same>::value)> - FMT_CONSTEXPR FMT_INLINE auto map(const T&) -> unformattable_char { - return {}; - } - - FMT_CONSTEXPR FMT_INLINE auto map(void* val) -> const void* { return val; } - FMT_CONSTEXPR FMT_INLINE auto map(const void* val) -> const void* { - return val; - } - FMT_CONSTEXPR FMT_INLINE auto map(std::nullptr_t val) -> const void* { - return val; - } - - // Use SFINAE instead of a const T* parameter to avoid a conflict with the - // array overload. - template < - typename T, - FMT_ENABLE_IF( - std::is_pointer::value || std::is_member_pointer::value || - std::is_function::type>::value || - (std::is_array::value && - !std::is_convertible::value))> - FMT_CONSTEXPR auto map(const T&) -> unformattable_pointer { - return {}; - } - - template ::value)> - FMT_CONSTEXPR FMT_INLINE auto map(const T (&values)[N]) -> const T (&)[N] { - return values; - } - - // Only map owning types because mapping views can be unsafe. - template , - FMT_ENABLE_IF(std::is_arithmetic::value)> - FMT_CONSTEXPR FMT_INLINE auto map(const T& val) -> decltype(this->map(U())) { - return map(format_as(val)); - } - - template > - struct formattable : bool_constant() || - (has_formatter::value && - !std::is_const::value)> {}; - - template ::value)> - FMT_CONSTEXPR FMT_INLINE auto do_map(T& val) -> T& { - return val; - } - template ::value)> - FMT_CONSTEXPR FMT_INLINE auto do_map(T&) -> unformattable { - return {}; - } - - template , - FMT_ENABLE_IF((std::is_class::value || std::is_enum::value || - std::is_union::value) && - !is_string::value && !is_char::value && - !is_named_arg::value && - !std::is_arithmetic>::value)> - FMT_CONSTEXPR FMT_INLINE auto map(T& val) -> decltype(this->do_map(val)) { - return do_map(val); - } - - template ::value)> - FMT_CONSTEXPR FMT_INLINE auto map(const T& named_arg) - -> decltype(this->map(named_arg.value)) { - return map(named_arg.value); - } - - auto map(...) -> unformattable { return {}; } -}; - -// A type constant after applying arg_mapper. -template -using mapped_type_constant = - type_constant().map(std::declval())), - typename Context::char_type>; - -enum { packed_arg_bits = 4 }; -// Maximum number of arguments with packed types. -enum { max_packed_args = 62 / packed_arg_bits }; -enum : unsigned long long { is_unpacked_bit = 1ULL << 63 }; -enum : unsigned long long { has_named_args_bit = 1ULL << 62 }; - -template -auto copy_str(InputIt begin, InputIt end, appender out) -> appender { - get_container(out).append(begin, end); - return out; -} -template -auto copy_str(InputIt begin, InputIt end, - std::back_insert_iterator out) - -> std::back_insert_iterator { - get_container(out).append(begin, end); - return out; -} - -template -FMT_CONSTEXPR auto copy_str(R&& rng, OutputIt out) -> OutputIt { - return detail::copy_str(rng.begin(), rng.end(), out); -} - -#if FMT_GCC_VERSION && FMT_GCC_VERSION < 500 -// A workaround for gcc 4.8 to make void_t work in a SFINAE context. -template struct void_t_impl { using type = void; }; -template using void_t = typename void_t_impl::type; -#else -template using void_t = void; -#endif - -template -struct is_output_iterator : std::false_type {}; - -template -struct is_output_iterator< - It, T, - void_t::iterator_category, - decltype(*std::declval() = std::declval())>> - : std::true_type {}; - -template struct is_back_insert_iterator : std::false_type {}; -template -struct is_back_insert_iterator> - : std::true_type {}; - -// A type-erased reference to an std::locale to avoid a heavy include. -class locale_ref { - private: - const void* locale_; // A type-erased pointer to std::locale. - - public: - constexpr FMT_INLINE locale_ref() : locale_(nullptr) {} - template explicit locale_ref(const Locale& loc); - - explicit operator bool() const noexcept { return locale_ != nullptr; } - - template auto get() const -> Locale; -}; - -template constexpr auto encode_types() -> unsigned long long { - return 0; -} - -template -constexpr auto encode_types() -> unsigned long long { - return static_cast(mapped_type_constant::value) | - (encode_types() << packed_arg_bits); -} - -#if defined(__cpp_if_constexpr) -// This type is intentionally undefined, only used for errors -template struct type_is_unformattable_for; -#endif - -template -FMT_CONSTEXPR FMT_INLINE auto make_arg(T& val) -> value { - using arg_type = remove_cvref_t().map(val))>; - - constexpr bool formattable_char = - !std::is_same::value; - static_assert(formattable_char, "Mixing character types is disallowed."); - - // Formatting of arbitrary pointers is disallowed. If you want to format a - // pointer cast it to `void*` or `const void*`. In particular, this forbids - // formatting of `[const] volatile char*` printed as bool by iostreams. - constexpr bool formattable_pointer = - !std::is_same::value; - static_assert(formattable_pointer, - "Formatting of non-void pointers is disallowed."); - - constexpr bool formattable = !std::is_same::value; -#if defined(__cpp_if_constexpr) - if constexpr (!formattable) { - type_is_unformattable_for _; - } -#endif - static_assert( - formattable, - "Cannot format an argument. To make type T formattable provide a " - "formatter specialization: https://fmt.dev/latest/api.html#udt"); - return {arg_mapper().map(val)}; -} - -template -FMT_CONSTEXPR auto make_arg(T& val) -> basic_format_arg { - auto arg = basic_format_arg(); - arg.type_ = mapped_type_constant::value; - arg.value_ = make_arg(val); - return arg; -} - -template -FMT_CONSTEXPR inline auto make_arg(T& val) -> basic_format_arg { - return make_arg(val); -} -} // namespace detail -FMT_BEGIN_EXPORT - -// A formatting argument. It is a trivially copyable/constructible type to -// allow storage in basic_memory_buffer. -template class basic_format_arg { - private: - detail::value value_; - detail::type type_; - - template - friend FMT_CONSTEXPR auto detail::make_arg(T& value) - -> basic_format_arg; - - template - friend FMT_CONSTEXPR auto visit_format_arg(Visitor&& vis, - const basic_format_arg& arg) - -> decltype(vis(0)); - - friend class basic_format_args; - friend class dynamic_format_arg_store; - - using char_type = typename Context::char_type; - - template - friend struct detail::arg_data; - - basic_format_arg(const detail::named_arg_info* args, size_t size) - : value_(args, size) {} - - public: - class handle { - public: - explicit handle(detail::custom_value custom) : custom_(custom) {} - - void format(typename Context::parse_context_type& parse_ctx, - Context& ctx) const { - custom_.format(custom_.value, parse_ctx, ctx); - } - - private: - detail::custom_value custom_; - }; - - constexpr basic_format_arg() : type_(detail::type::none_type) {} - - constexpr explicit operator bool() const noexcept { - return type_ != detail::type::none_type; - } - - auto type() const -> detail::type { return type_; } - - auto is_integral() const -> bool { return detail::is_integral_type(type_); } - auto is_arithmetic() const -> bool { - return detail::is_arithmetic_type(type_); - } -}; - -/** - \rst - Visits an argument dispatching to the appropriate visit method based on - the argument type. For example, if the argument type is ``double`` then - ``vis(value)`` will be called with the value of type ``double``. - \endrst - */ -// DEPRECATED! -template -FMT_CONSTEXPR FMT_INLINE auto visit_format_arg( - Visitor&& vis, const basic_format_arg& arg) -> decltype(vis(0)) { - switch (arg.type_) { - case detail::type::none_type: - break; - case detail::type::int_type: - return vis(arg.value_.int_value); - case detail::type::uint_type: - return vis(arg.value_.uint_value); - case detail::type::long_long_type: - return vis(arg.value_.long_long_value); - case detail::type::ulong_long_type: - return vis(arg.value_.ulong_long_value); - case detail::type::int128_type: - return vis(detail::convert_for_visit(arg.value_.int128_value)); - case detail::type::uint128_type: - return vis(detail::convert_for_visit(arg.value_.uint128_value)); - case detail::type::bool_type: - return vis(arg.value_.bool_value); - case detail::type::char_type: - return vis(arg.value_.char_value); - case detail::type::float_type: - return vis(arg.value_.float_value); - case detail::type::double_type: - return vis(arg.value_.double_value); - case detail::type::long_double_type: - return vis(arg.value_.long_double_value); - case detail::type::cstring_type: - return vis(arg.value_.string.data); - case detail::type::string_type: - using sv = basic_string_view; - return vis(sv(arg.value_.string.data, arg.value_.string.size)); - case detail::type::pointer_type: - return vis(arg.value_.pointer); - case detail::type::custom_type: - return vis(typename basic_format_arg::handle(arg.value_.custom)); - } - return vis(monostate()); -} - -// Formatting context. -template class basic_format_context { - private: - OutputIt out_; - basic_format_args args_; - detail::locale_ref loc_; - - public: - using iterator = OutputIt; - using format_arg = basic_format_arg; - using format_args = basic_format_args; - using parse_context_type = basic_format_parse_context; - template using formatter_type = formatter; - - /** The character type for the output. */ - using char_type = Char; - - basic_format_context(basic_format_context&&) = default; - basic_format_context(const basic_format_context&) = delete; - void operator=(const basic_format_context&) = delete; - /** - Constructs a ``basic_format_context`` object. References to the arguments - are stored in the object so make sure they have appropriate lifetimes. - */ - constexpr basic_format_context(OutputIt out, format_args ctx_args, - detail::locale_ref loc = {}) - : out_(out), args_(ctx_args), loc_(loc) {} - - constexpr auto arg(int id) const -> format_arg { return args_.get(id); } - FMT_CONSTEXPR auto arg(basic_string_view name) -> format_arg { - return args_.get(name); - } - FMT_CONSTEXPR auto arg_id(basic_string_view name) -> int { - return args_.get_id(name); - } - auto args() const -> const format_args& { return args_; } - - FMT_CONSTEXPR auto error_handler() -> detail::error_handler { return {}; } - void on_error(const char* message) { error_handler().on_error(message); } - - // Returns an iterator to the beginning of the output range. - FMT_CONSTEXPR auto out() -> iterator { return out_; } - - // Advances the begin iterator to ``it``. - void advance_to(iterator it) { - if (!detail::is_back_insert_iterator()) out_ = it; - } - - FMT_CONSTEXPR auto locale() -> detail::locale_ref { return loc_; } -}; - -template -using buffer_context = - basic_format_context, Char>; -using format_context = buffer_context; - -template -using is_formattable = bool_constant>() - .map(std::declval()))>::value>; - -/** - \rst - An array of references to arguments. It can be implicitly converted into - `~fmt::basic_format_args` for passing into type-erased formatting functions - such as `~fmt::vformat`. - \endrst - */ -template -class format_arg_store -#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 - // Workaround a GCC template argument substitution bug. - : public basic_format_args -#endif -{ - private: - static const size_t num_args = sizeof...(Args); - static constexpr size_t num_named_args = detail::count_named_args(); - static const bool is_packed = num_args <= detail::max_packed_args; - - using value_type = conditional_t, - basic_format_arg>; - - detail::arg_data - data_; - - friend class basic_format_args; - - static constexpr unsigned long long desc = - (is_packed ? detail::encode_types() - : detail::is_unpacked_bit | num_args) | - (num_named_args != 0 - ? static_cast(detail::has_named_args_bit) - : 0); - - public: - template - FMT_CONSTEXPR FMT_INLINE format_arg_store(T&... args) - : -#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 - basic_format_args(*this), -#endif - data_{detail::make_arg(args)...} { - if (detail::const_check(num_named_args != 0)) - detail::init_named_args(data_.named_args(), 0, 0, args...); - } -}; - -/** - \rst - Constructs a `~fmt::format_arg_store` object that contains references to - arguments and can be implicitly converted to `~fmt::format_args`. `Context` - can be omitted in which case it defaults to `~fmt::format_context`. - See `~fmt::arg` for lifetime considerations. - \endrst - */ -// Arguments are taken by lvalue references to avoid some lifetime issues. -template -constexpr auto make_format_args(T&... args) - -> format_arg_store...> { - return {args...}; -} - -/** - \rst - Returns a named argument to be used in a formatting function. - It should only be used in a call to a formatting function or - `dynamic_format_arg_store::push_back`. - - **Example**:: - - fmt::print("Elapsed time: {s:.2f} seconds", fmt::arg("s", 1.23)); - \endrst - */ -template -inline auto arg(const Char* name, const T& arg) -> detail::named_arg { - static_assert(!detail::is_named_arg(), "nested named arguments"); - return {name, arg}; -} -FMT_END_EXPORT - -/** - \rst - A view of a collection of formatting arguments. To avoid lifetime issues it - should only be used as a parameter type in type-erased functions such as - ``vformat``:: - - void vlog(string_view format_str, format_args args); // OK - format_args args = make_format_args(); // Error: dangling reference - \endrst - */ -template class basic_format_args { - public: - using size_type = int; - using format_arg = basic_format_arg; - - private: - // A descriptor that contains information about formatting arguments. - // If the number of arguments is less or equal to max_packed_args then - // argument types are passed in the descriptor. This reduces binary code size - // per formatting function call. - unsigned long long desc_; - union { - // If is_packed() returns true then argument values are stored in values_; - // otherwise they are stored in args_. This is done to improve cache - // locality and reduce compiled code size since storing larger objects - // may require more code (at least on x86-64) even if the same amount of - // data is actually copied to stack. It saves ~10% on the bloat test. - const detail::value* values_; - const format_arg* args_; - }; - - constexpr auto is_packed() const -> bool { - return (desc_ & detail::is_unpacked_bit) == 0; - } - auto has_named_args() const -> bool { - return (desc_ & detail::has_named_args_bit) != 0; - } - - FMT_CONSTEXPR auto type(int index) const -> detail::type { - int shift = index * detail::packed_arg_bits; - unsigned int mask = (1 << detail::packed_arg_bits) - 1; - return static_cast((desc_ >> shift) & mask); - } - - constexpr FMT_INLINE basic_format_args(unsigned long long desc, - const detail::value* values) - : desc_(desc), values_(values) {} - constexpr basic_format_args(unsigned long long desc, const format_arg* args) - : desc_(desc), args_(args) {} - - public: - constexpr basic_format_args() : desc_(0), args_(nullptr) {} - - /** - \rst - Constructs a `basic_format_args` object from `~fmt::format_arg_store`. - \endrst - */ - template - constexpr FMT_INLINE basic_format_args( - const format_arg_store& store) - : basic_format_args(format_arg_store::desc, - store.data_.args()) {} - - /** - \rst - Constructs a `basic_format_args` object from - `~fmt::dynamic_format_arg_store`. - \endrst - */ - constexpr FMT_INLINE basic_format_args( - const dynamic_format_arg_store& store) - : basic_format_args(store.get_types(), store.data()) {} - - /** - \rst - Constructs a `basic_format_args` object from a dynamic set of arguments. - \endrst - */ - constexpr basic_format_args(const format_arg* args, int count) - : basic_format_args(detail::is_unpacked_bit | detail::to_unsigned(count), - args) {} - - /** Returns the argument with the specified id. */ - FMT_CONSTEXPR auto get(int id) const -> format_arg { - format_arg arg; - if (!is_packed()) { - if (id < max_size()) arg = args_[id]; - return arg; - } - if (id >= detail::max_packed_args) return arg; - arg.type_ = type(id); - if (arg.type_ == detail::type::none_type) return arg; - arg.value_ = values_[id]; - return arg; - } - - template - auto get(basic_string_view name) const -> format_arg { - int id = get_id(name); - return id >= 0 ? get(id) : format_arg(); - } - - template - auto get_id(basic_string_view name) const -> int { - if (!has_named_args()) return -1; - const auto& named_args = - (is_packed() ? values_[-1] : args_[-1].value_).named_args; - for (size_t i = 0; i < named_args.size; ++i) { - if (named_args.data[i].name == name) return named_args.data[i].id; - } - return -1; - } - - auto max_size() const -> int { - unsigned long long max_packed = detail::max_packed_args; - return static_cast(is_packed() ? max_packed - : desc_ & ~detail::is_unpacked_bit); - } -}; - -/** An alias to ``basic_format_args``. */ -// A separate type would result in shorter symbols but break ABI compatibility -// between clang and gcc on ARM (#1919). -FMT_EXPORT using format_args = basic_format_args; - -// We cannot use enum classes as bit fields because of a gcc bug, so we put them -// in namespaces instead (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61414). -// Additionally, if an underlying type is specified, older gcc incorrectly warns -// that the type is too small. Both bugs are fixed in gcc 9.3. -#if FMT_GCC_VERSION && FMT_GCC_VERSION < 903 -# define FMT_ENUM_UNDERLYING_TYPE(type) -#else -# define FMT_ENUM_UNDERLYING_TYPE(type) : type -#endif -namespace align { -enum type FMT_ENUM_UNDERLYING_TYPE(unsigned char){none, left, right, center, - numeric}; -} -using align_t = align::type; -namespace sign { -enum type FMT_ENUM_UNDERLYING_TYPE(unsigned char){none, minus, plus, space}; -} -using sign_t = sign::type; - -namespace detail { - -// Workaround an array initialization issue in gcc 4.8. -template struct fill_t { - private: - enum { max_size = 4 }; - Char data_[max_size] = {Char(' '), Char(0), Char(0), Char(0)}; - unsigned char size_ = 1; - - public: - FMT_CONSTEXPR void operator=(basic_string_view s) { - auto size = s.size(); - FMT_ASSERT(size <= max_size, "invalid fill"); - for (size_t i = 0; i < size; ++i) data_[i] = s[i]; - size_ = static_cast(size); - } - - constexpr auto size() const -> size_t { return size_; } - constexpr auto data() const -> const Char* { return data_; } - - FMT_CONSTEXPR auto operator[](size_t index) -> Char& { return data_[index]; } - FMT_CONSTEXPR auto operator[](size_t index) const -> const Char& { - return data_[index]; - } -}; -} // namespace detail - -enum class presentation_type : unsigned char { - none, - dec, // 'd' - oct, // 'o' - hex_lower, // 'x' - hex_upper, // 'X' - bin_lower, // 'b' - bin_upper, // 'B' - hexfloat_lower, // 'a' - hexfloat_upper, // 'A' - exp_lower, // 'e' - exp_upper, // 'E' - fixed_lower, // 'f' - fixed_upper, // 'F' - general_lower, // 'g' - general_upper, // 'G' - chr, // 'c' - string, // 's' - pointer, // 'p' - debug // '?' -}; - -// Format specifiers for built-in and string types. -template struct format_specs { - int width; - int precision; - presentation_type type; - align_t align : 4; - sign_t sign : 3; - bool alt : 1; // Alternate form ('#'). - bool localized : 1; - detail::fill_t fill; - - constexpr format_specs() - : width(0), - precision(-1), - type(presentation_type::none), - align(align::none), - sign(sign::none), - alt(false), - localized(false) {} -}; - -namespace detail { - -enum class arg_id_kind { none, index, name }; - -// An argument reference. -template struct arg_ref { - FMT_CONSTEXPR arg_ref() : kind(arg_id_kind::none), val() {} - - FMT_CONSTEXPR explicit arg_ref(int index) - : kind(arg_id_kind::index), val(index) {} - FMT_CONSTEXPR explicit arg_ref(basic_string_view name) - : kind(arg_id_kind::name), val(name) {} - - FMT_CONSTEXPR auto operator=(int idx) -> arg_ref& { - kind = arg_id_kind::index; - val.index = idx; - return *this; - } - - arg_id_kind kind; - union value { - FMT_CONSTEXPR value(int idx = 0) : index(idx) {} - FMT_CONSTEXPR value(basic_string_view n) : name(n) {} - - int index; - basic_string_view name; - } val; -}; - -// Format specifiers with width and precision resolved at formatting rather -// than parsing time to allow reusing the same parsed specifiers with -// different sets of arguments (precompilation of format strings). -template -struct dynamic_format_specs : format_specs { - arg_ref width_ref; - arg_ref precision_ref; -}; - -// Converts a character to ASCII. Returns '\0' on conversion failure. -template ::value)> -constexpr auto to_ascii(Char c) -> char { - return c <= 0xff ? static_cast(c) : '\0'; -} -template ::value)> -constexpr auto to_ascii(Char c) -> char { - return c <= 0xff ? static_cast(c) : '\0'; -} - -// Returns the number of code units in a code point or 1 on error. -template -FMT_CONSTEXPR auto code_point_length(const Char* begin) -> int { - if (const_check(sizeof(Char) != 1)) return 1; - auto c = static_cast(*begin); - return static_cast((0x3a55000000000000ull >> (2 * (c >> 3))) & 0x3) + 1; -} - -// Return the result via the out param to workaround gcc bug 77539. -template -FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr& out) -> bool { - for (out = first; out != last; ++out) { - if (*out == value) return true; - } - return false; -} - -template <> -inline auto find(const char* first, const char* last, char value, - const char*& out) -> bool { - out = static_cast( - std::memchr(first, value, to_unsigned(last - first))); - return out != nullptr; -} - -// Parses the range [begin, end) as an unsigned integer. This function assumes -// that the range is non-empty and the first character is a digit. -template -FMT_CONSTEXPR auto parse_nonnegative_int(const Char*& begin, const Char* end, - int error_value) noexcept -> int { - FMT_ASSERT(begin != end && '0' <= *begin && *begin <= '9', ""); - unsigned value = 0, prev = 0; - auto p = begin; - do { - prev = value; - value = value * 10 + unsigned(*p - '0'); - ++p; - } while (p != end && '0' <= *p && *p <= '9'); - auto num_digits = p - begin; - begin = p; - if (num_digits <= std::numeric_limits::digits10) - return static_cast(value); - // Check for overflow. - const unsigned max = to_unsigned((std::numeric_limits::max)()); - return num_digits == std::numeric_limits::digits10 + 1 && - prev * 10ull + unsigned(p[-1] - '0') <= max - ? static_cast(value) - : error_value; -} - -FMT_CONSTEXPR inline auto parse_align(char c) -> align_t { - switch (c) { - case '<': - return align::left; - case '>': - return align::right; - case '^': - return align::center; - } - return align::none; -} - -template constexpr auto is_name_start(Char c) -> bool { - return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_'; -} - -template -FMT_CONSTEXPR auto do_parse_arg_id(const Char* begin, const Char* end, - Handler&& handler) -> const Char* { - Char c = *begin; - if (c >= '0' && c <= '9') { - int index = 0; - constexpr int max = (std::numeric_limits::max)(); - if (c != '0') - index = parse_nonnegative_int(begin, end, max); - else - ++begin; - if (begin == end || (*begin != '}' && *begin != ':')) - throw_format_error("invalid format string"); - else - handler.on_index(index); - return begin; - } - if (!is_name_start(c)) { - throw_format_error("invalid format string"); - return begin; - } - auto it = begin; - do { - ++it; - } while (it != end && (is_name_start(*it) || ('0' <= *it && *it <= '9'))); - handler.on_name({begin, to_unsigned(it - begin)}); - return it; -} - -template -FMT_CONSTEXPR FMT_INLINE auto parse_arg_id(const Char* begin, const Char* end, - Handler&& handler) -> const Char* { - FMT_ASSERT(begin != end, ""); - Char c = *begin; - if (c != '}' && c != ':') return do_parse_arg_id(begin, end, handler); - handler.on_auto(); - return begin; -} - -template struct dynamic_spec_id_handler { - basic_format_parse_context& ctx; - arg_ref& ref; - - FMT_CONSTEXPR void on_auto() { - int id = ctx.next_arg_id(); - ref = arg_ref(id); - ctx.check_dynamic_spec(id); - } - FMT_CONSTEXPR void on_index(int id) { - ref = arg_ref(id); - ctx.check_arg_id(id); - ctx.check_dynamic_spec(id); - } - FMT_CONSTEXPR void on_name(basic_string_view id) { - ref = arg_ref(id); - ctx.check_arg_id(id); - } -}; - -// Parses [integer | "{" [arg_id] "}"]. -template -FMT_CONSTEXPR auto parse_dynamic_spec(const Char* begin, const Char* end, - int& value, arg_ref& ref, - basic_format_parse_context& ctx) - -> const Char* { - FMT_ASSERT(begin != end, ""); - if ('0' <= *begin && *begin <= '9') { - int val = parse_nonnegative_int(begin, end, -1); - if (val != -1) - value = val; - else - throw_format_error("number is too big"); - } else if (*begin == '{') { - ++begin; - auto handler = dynamic_spec_id_handler{ctx, ref}; - if (begin != end) begin = parse_arg_id(begin, end, handler); - if (begin != end && *begin == '}') return ++begin; - throw_format_error("invalid format string"); - } - return begin; -} - -template -FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end, - int& value, arg_ref& ref, - basic_format_parse_context& ctx) - -> const Char* { - ++begin; - if (begin == end || *begin == '}') { - throw_format_error("invalid precision"); - return begin; - } - return parse_dynamic_spec(begin, end, value, ref, ctx); -} - -enum class state { start, align, sign, hash, zero, width, precision, locale }; - -// Parses standard format specifiers. -template -FMT_CONSTEXPR FMT_INLINE auto parse_format_specs( - const Char* begin, const Char* end, dynamic_format_specs& specs, - basic_format_parse_context& ctx, type arg_type) -> const Char* { - auto c = '\0'; - if (end - begin > 1) { - auto next = to_ascii(begin[1]); - c = parse_align(next) == align::none ? to_ascii(*begin) : '\0'; - } else { - if (begin == end) return begin; - c = to_ascii(*begin); - } - - struct { - state current_state = state::start; - FMT_CONSTEXPR void operator()(state s, bool valid = true) { - if (current_state >= s || !valid) - throw_format_error("invalid format specifier"); - current_state = s; - } - } enter_state; - - using pres = presentation_type; - constexpr auto integral_set = sint_set | uint_set | bool_set | char_set; - struct { - const Char*& begin; - dynamic_format_specs& specs; - type arg_type; - - FMT_CONSTEXPR auto operator()(pres type, int set) -> const Char* { - if (!in(arg_type, set)) throw_format_error("invalid format specifier"); - specs.type = type; - return begin + 1; - } - } parse_presentation_type{begin, specs, arg_type}; - - for (;;) { - switch (c) { - case '<': - case '>': - case '^': - enter_state(state::align); - specs.align = parse_align(c); - ++begin; - break; - case '+': - case '-': - case ' ': - enter_state(state::sign, in(arg_type, sint_set | float_set)); - switch (c) { - case '+': - specs.sign = sign::plus; - break; - case '-': - specs.sign = sign::minus; - break; - case ' ': - specs.sign = sign::space; - break; - } - ++begin; - break; - case '#': - enter_state(state::hash, is_arithmetic_type(arg_type)); - specs.alt = true; - ++begin; - break; - case '0': - enter_state(state::zero); - if (!is_arithmetic_type(arg_type)) - throw_format_error("format specifier requires numeric argument"); - if (specs.align == align::none) { - // Ignore 0 if align is specified for compatibility with std::format. - specs.align = align::numeric; - specs.fill[0] = Char('0'); - } - ++begin; - break; - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '{': - enter_state(state::width); - begin = parse_dynamic_spec(begin, end, specs.width, specs.width_ref, ctx); - break; - case '.': - enter_state(state::precision, - in(arg_type, float_set | string_set | cstring_set)); - begin = parse_precision(begin, end, specs.precision, specs.precision_ref, - ctx); - break; - case 'L': - enter_state(state::locale, is_arithmetic_type(arg_type)); - specs.localized = true; - ++begin; - break; - case 'd': - return parse_presentation_type(pres::dec, integral_set); - case 'o': - return parse_presentation_type(pres::oct, integral_set); - case 'x': - return parse_presentation_type(pres::hex_lower, integral_set); - case 'X': - return parse_presentation_type(pres::hex_upper, integral_set); - case 'b': - return parse_presentation_type(pres::bin_lower, integral_set); - case 'B': - return parse_presentation_type(pres::bin_upper, integral_set); - case 'a': - return parse_presentation_type(pres::hexfloat_lower, float_set); - case 'A': - return parse_presentation_type(pres::hexfloat_upper, float_set); - case 'e': - return parse_presentation_type(pres::exp_lower, float_set); - case 'E': - return parse_presentation_type(pres::exp_upper, float_set); - case 'f': - return parse_presentation_type(pres::fixed_lower, float_set); - case 'F': - return parse_presentation_type(pres::fixed_upper, float_set); - case 'g': - return parse_presentation_type(pres::general_lower, float_set); - case 'G': - return parse_presentation_type(pres::general_upper, float_set); - case 'c': - return parse_presentation_type(pres::chr, integral_set); - case 's': - return parse_presentation_type(pres::string, - bool_set | string_set | cstring_set); - case 'p': - return parse_presentation_type(pres::pointer, pointer_set | cstring_set); - case '?': - return parse_presentation_type(pres::debug, - char_set | string_set | cstring_set); - case '}': - return begin; - default: { - if (*begin == '}') return begin; - // Parse fill and alignment. - auto fill_end = begin + code_point_length(begin); - if (end - fill_end <= 0) { - throw_format_error("invalid format specifier"); - return begin; - } - if (*begin == '{') { - throw_format_error("invalid fill character '{'"); - return begin; - } - auto align = parse_align(to_ascii(*fill_end)); - enter_state(state::align, align != align::none); - specs.fill = {begin, to_unsigned(fill_end - begin)}; - specs.align = align; - begin = fill_end + 1; - } - } - if (begin == end) return begin; - c = to_ascii(*begin); - } -} - -template -FMT_CONSTEXPR auto parse_replacement_field(const Char* begin, const Char* end, - Handler&& handler) -> const Char* { - struct id_adapter { - Handler& handler; - int arg_id; - - FMT_CONSTEXPR void on_auto() { arg_id = handler.on_arg_id(); } - FMT_CONSTEXPR void on_index(int id) { arg_id = handler.on_arg_id(id); } - FMT_CONSTEXPR void on_name(basic_string_view id) { - arg_id = handler.on_arg_id(id); - } - }; - - ++begin; - if (begin == end) return handler.on_error("invalid format string"), end; - if (*begin == '}') { - handler.on_replacement_field(handler.on_arg_id(), begin); - } else if (*begin == '{') { - handler.on_text(begin, begin + 1); - } else { - auto adapter = id_adapter{handler, 0}; - begin = parse_arg_id(begin, end, adapter); - Char c = begin != end ? *begin : Char(); - if (c == '}') { - handler.on_replacement_field(adapter.arg_id, begin); - } else if (c == ':') { - begin = handler.on_format_specs(adapter.arg_id, begin + 1, end); - if (begin == end || *begin != '}') - return handler.on_error("unknown format specifier"), end; - } else { - return handler.on_error("missing '}' in format string"), end; - } - } - return begin + 1; -} - -template -FMT_CONSTEXPR FMT_INLINE void parse_format_string( - basic_string_view format_str, Handler&& handler) { - auto begin = format_str.data(); - auto end = begin + format_str.size(); - if (end - begin < 32) { - // Use a simple loop instead of memchr for small strings. - const Char* p = begin; - while (p != end) { - auto c = *p++; - if (c == '{') { - handler.on_text(begin, p - 1); - begin = p = parse_replacement_field(p - 1, end, handler); - } else if (c == '}') { - if (p == end || *p != '}') - return handler.on_error("unmatched '}' in format string"); - handler.on_text(begin, p); - begin = ++p; - } - } - handler.on_text(begin, end); - return; - } - struct writer { - FMT_CONSTEXPR void operator()(const Char* from, const Char* to) { - if (from == to) return; - for (;;) { - const Char* p = nullptr; - if (!find(from, to, Char('}'), p)) - return handler_.on_text(from, to); - ++p; - if (p == to || *p != '}') - return handler_.on_error("unmatched '}' in format string"); - handler_.on_text(from, p); - from = p + 1; - } - } - Handler& handler_; - } write = {handler}; - while (begin != end) { - // Doing two passes with memchr (one for '{' and another for '}') is up to - // 2.5x faster than the naive one-pass implementation on big format strings. - const Char* p = begin; - if (*begin != '{' && !find(begin + 1, end, Char('{'), p)) - return write(begin, end); - write(begin, p); - begin = parse_replacement_field(p, end, handler); - } -} - -template ::value> struct strip_named_arg { - using type = T; -}; -template struct strip_named_arg { - using type = remove_cvref_t; -}; - -template -FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx) - -> decltype(ctx.begin()) { - using char_type = typename ParseContext::char_type; - using context = buffer_context; - using mapped_type = conditional_t< - mapped_type_constant::value != type::custom_type, - decltype(arg_mapper().map(std::declval())), - typename strip_named_arg::type>; -#if defined(__cpp_if_constexpr) - if constexpr (std::is_default_constructible_v< - formatter>) { - return formatter().parse(ctx); - } else { - type_is_unformattable_for _; - return ctx.begin(); - } -#else - return formatter().parse(ctx); -#endif -} - -// Checks char specs and returns true iff the presentation type is char-like. -template -FMT_CONSTEXPR auto check_char_specs(const format_specs& specs) -> bool { - if (specs.type != presentation_type::none && - specs.type != presentation_type::chr && - specs.type != presentation_type::debug) { - return false; - } - if (specs.align == align::numeric || specs.sign != sign::none || specs.alt) - throw_format_error("invalid format specifier for char"); - return true; -} - -#if FMT_USE_NONTYPE_TEMPLATE_ARGS -template -constexpr auto get_arg_index_by_name(basic_string_view name) -> int { - if constexpr (is_statically_named_arg()) { - if (name == T::name) return N; - } - if constexpr (sizeof...(Args) > 0) - return get_arg_index_by_name(name); - (void)name; // Workaround an MSVC bug about "unused" parameter. - return -1; -} -#endif - -template -FMT_CONSTEXPR auto get_arg_index_by_name(basic_string_view name) -> int { -#if FMT_USE_NONTYPE_TEMPLATE_ARGS - if constexpr (sizeof...(Args) > 0) - return get_arg_index_by_name<0, Args...>(name); -#endif - (void)name; - return -1; -} - -template class format_string_checker { - private: - using parse_context_type = compile_parse_context; - static constexpr int num_args = sizeof...(Args); - - // Format specifier parsing function. - // In the future basic_format_parse_context will replace compile_parse_context - // here and will use is_constant_evaluated and downcasting to access the data - // needed for compile-time checks: https://godbolt.org/z/GvWzcTjh1. - using parse_func = const Char* (*)(parse_context_type&); - - type types_[num_args > 0 ? static_cast(num_args) : 1]; - parse_context_type context_; - parse_func parse_funcs_[num_args > 0 ? static_cast(num_args) : 1]; - - public: - explicit FMT_CONSTEXPR format_string_checker(basic_string_view fmt) - : types_{mapped_type_constant>::value...}, - context_(fmt, num_args, types_), - parse_funcs_{&parse_format_specs...} {} - - FMT_CONSTEXPR void on_text(const Char*, const Char*) {} - - FMT_CONSTEXPR auto on_arg_id() -> int { return context_.next_arg_id(); } - FMT_CONSTEXPR auto on_arg_id(int id) -> int { - return context_.check_arg_id(id), id; - } - FMT_CONSTEXPR auto on_arg_id(basic_string_view id) -> int { -#if FMT_USE_NONTYPE_TEMPLATE_ARGS - auto index = get_arg_index_by_name(id); - if (index < 0) on_error("named argument is not found"); - return index; -#else - (void)id; - on_error("compile-time checks for named arguments require C++20 support"); - return 0; -#endif - } - - FMT_CONSTEXPR void on_replacement_field(int id, const Char* begin) { - on_format_specs(id, begin, begin); // Call parse() on empty specs. - } - - FMT_CONSTEXPR auto on_format_specs(int id, const Char* begin, const Char*) - -> const Char* { - context_.advance_to(begin); - // id >= 0 check is a workaround for gcc 10 bug (#2065). - return id >= 0 && id < num_args ? parse_funcs_[id](context_) : begin; - } - - FMT_CONSTEXPR void on_error(const char* message) { - throw_format_error(message); - } -}; - -// Reports a compile-time error if S is not a valid format string. -template ::value)> -FMT_INLINE void check_format_string(const S&) { -#ifdef FMT_ENFORCE_COMPILE_STRING - static_assert(is_compile_string::value, - "FMT_ENFORCE_COMPILE_STRING requires all format strings to use " - "FMT_STRING."); -#endif -} -template ::value)> -void check_format_string(S format_str) { - using char_t = typename S::char_type; - FMT_CONSTEXPR auto s = basic_string_view(format_str); - using checker = format_string_checker...>; - FMT_CONSTEXPR bool error = (parse_format_string(s, checker(s)), true); - ignore_unused(error); -} - -template struct vformat_args { - using type = basic_format_args< - basic_format_context>, Char>>; -}; -template <> struct vformat_args { using type = format_args; }; - -// Use vformat_args and avoid type_identity to keep symbols short. -template -void vformat_to(buffer& buf, basic_string_view fmt, - typename vformat_args::type args, locale_ref loc = {}); - -FMT_API void vprint_mojibake(std::FILE*, string_view, format_args); -#ifndef _WIN32 -inline void vprint_mojibake(std::FILE*, string_view, format_args) {} -#endif -} // namespace detail - -FMT_BEGIN_EXPORT - -// A formatter specialization for natively supported types. -template -struct formatter::value != - detail::type::custom_type>> { - private: - detail::dynamic_format_specs specs_; - - public: - template - FMT_CONSTEXPR auto parse(ParseContext& ctx) -> const Char* { - auto type = detail::type_constant::value; - auto end = - detail::parse_format_specs(ctx.begin(), ctx.end(), specs_, ctx, type); - if (type == detail::type::char_type) detail::check_char_specs(specs_); - return end; - } - - template ::value, - FMT_ENABLE_IF(U == detail::type::string_type || - U == detail::type::cstring_type || - U == detail::type::char_type)> - FMT_CONSTEXPR void set_debug_format(bool set = true) { - specs_.type = set ? presentation_type::debug : presentation_type::none; - } - - template - FMT_CONSTEXPR auto format(const T& val, FormatContext& ctx) const - -> decltype(ctx.out()); -}; - -template struct runtime_format_string { - basic_string_view str; -}; - -/** A compile-time format string. */ -template class basic_format_string { - private: - basic_string_view str_; - - public: - template >::value)> - FMT_CONSTEVAL FMT_INLINE basic_format_string(const S& s) : str_(s) { - static_assert( - detail::count< - (std::is_base_of>::value && - std::is_reference::value)...>() == 0, - "passing views as lvalues is disallowed"); -#ifdef FMT_HAS_CONSTEVAL - if constexpr (detail::count_named_args() == - detail::count_statically_named_args()) { - using checker = - detail::format_string_checker...>; - detail::parse_format_string(str_, checker(s)); - } -#else - detail::check_format_string(s); -#endif - } - basic_format_string(runtime_format_string fmt) : str_(fmt.str) {} - - FMT_INLINE operator basic_string_view() const { return str_; } - FMT_INLINE auto get() const -> basic_string_view { return str_; } -}; - -#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409 -// Workaround broken conversion on older gcc. -template using format_string = string_view; -inline auto runtime(string_view s) -> string_view { return s; } -#else -template -using format_string = basic_format_string...>; -/** - \rst - Creates a runtime format string. - - **Example**:: - - // Check format string at runtime instead of compile-time. - fmt::print(fmt::runtime("{:d}"), "I am not a number"); - \endrst - */ -inline auto runtime(string_view s) -> runtime_format_string<> { return {{s}}; } -#endif - -FMT_API auto vformat(string_view fmt, format_args args) -> std::string; - -/** - \rst - Formats ``args`` according to specifications in ``fmt`` and returns the result - as a string. - - **Example**:: - - #include - std::string message = fmt::format("The answer is {}.", 42); - \endrst -*/ -template -FMT_NODISCARD FMT_INLINE auto format(format_string fmt, T&&... args) - -> std::string { - return vformat(fmt, fmt::make_format_args(args...)); -} - -/** Formats a string and writes the output to ``out``. */ -template ::value)> -auto vformat_to(OutputIt out, string_view fmt, format_args args) -> OutputIt { - auto&& buf = detail::get_buffer(out); - detail::vformat_to(buf, fmt, args, {}); - return detail::get_iterator(buf, out); -} - -/** - \rst - Formats ``args`` according to specifications in ``fmt``, writes the result to - the output iterator ``out`` and returns the iterator past the end of the output - range. `format_to` does not append a terminating null character. - - **Example**:: - - auto out = std::vector(); - fmt::format_to(std::back_inserter(out), "{}", 42); - \endrst - */ -template ::value)> -FMT_INLINE auto format_to(OutputIt out, format_string fmt, T&&... args) - -> OutputIt { - return vformat_to(out, fmt, fmt::make_format_args(args...)); -} - -template struct format_to_n_result { - /** Iterator past the end of the output range. */ - OutputIt out; - /** Total (not truncated) output size. */ - size_t size; -}; - -template ::value)> -auto vformat_to_n(OutputIt out, size_t n, string_view fmt, format_args args) - -> format_to_n_result { - using traits = detail::fixed_buffer_traits; - auto buf = detail::iterator_buffer(out, n); - detail::vformat_to(buf, fmt, args, {}); - return {buf.out(), buf.count()}; -} - -/** - \rst - Formats ``args`` according to specifications in ``fmt``, writes up to ``n`` - characters of the result to the output iterator ``out`` and returns the total - (not truncated) output size and the iterator past the end of the output range. - `format_to_n` does not append a terminating null character. - \endrst - */ -template ::value)> -FMT_INLINE auto format_to_n(OutputIt out, size_t n, format_string fmt, - T&&... args) -> format_to_n_result { - return vformat_to_n(out, n, fmt, fmt::make_format_args(args...)); -} - -/** Returns the number of chars in the output of ``format(fmt, args...)``. */ -template -FMT_NODISCARD FMT_INLINE auto formatted_size(format_string fmt, - T&&... args) -> size_t { - auto buf = detail::counting_buffer<>(); - detail::vformat_to(buf, fmt, fmt::make_format_args(args...), {}); - return buf.count(); -} - -FMT_API void vprint(string_view fmt, format_args args); -FMT_API void vprint(std::FILE* f, string_view fmt, format_args args); - -/** - \rst - Formats ``args`` according to specifications in ``fmt`` and writes the output - to ``stdout``. - - **Example**:: - - fmt::print("Elapsed time: {0:.2f} seconds", 1.23); - \endrst - */ -template -FMT_INLINE void print(format_string fmt, T&&... args) { - const auto& vargs = fmt::make_format_args(args...); - return detail::is_utf8() ? vprint(fmt, vargs) - : detail::vprint_mojibake(stdout, fmt, vargs); -} - -/** - \rst - Formats ``args`` according to specifications in ``fmt`` and writes the - output to the file ``f``. - - **Example**:: - - fmt::print(stderr, "Don't {}!", "panic"); - \endrst - */ -template -FMT_INLINE void print(std::FILE* f, format_string fmt, T&&... args) { - const auto& vargs = fmt::make_format_args(args...); - return detail::is_utf8() ? vprint(f, fmt, vargs) - : detail::vprint_mojibake(f, fmt, vargs); -} - -/** - Formats ``args`` according to specifications in ``fmt`` and writes the - output to the file ``f`` followed by a newline. - */ -template -FMT_INLINE void println(std::FILE* f, format_string fmt, T&&... args) { - return fmt::print(f, "{}\n", fmt::format(fmt, std::forward(args)...)); -} - -/** - Formats ``args`` according to specifications in ``fmt`` and writes the output - to ``stdout`` followed by a newline. - */ -template -FMT_INLINE void println(format_string fmt, T&&... args) { - return fmt::println(stdout, fmt, std::forward(args)...); -} - -FMT_END_EXPORT -FMT_GCC_PRAGMA("GCC pop_options") -FMT_END_NAMESPACE - -#ifdef FMT_HEADER_ONLY -# include "format.h" -#endif -#endif // FMT_CORE_H_ diff --git a/src/common/dep/fmt/fmt.cc b/src/common/dep/fmt/fmt.cc deleted file mode 100644 index a02167c65..000000000 --- a/src/common/dep/fmt/fmt.cc +++ /dev/null @@ -1,110 +0,0 @@ -module; - -// Put all implementation-provided headers into the global module fragment -// to prevent attachment to this module. -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if __has_include() -# include -#endif -#if defined(_MSC_VER) || defined(__MINGW32__) -# include -#endif -#if defined __APPLE__ || defined(__FreeBSD__) -# include -#endif -#if __has_include() -# include -#endif -#if (__has_include() || defined(__APPLE__) || \ - defined(__linux__)) && \ - (!defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP)) -# include -# include -# include -# ifndef _WIN32 -# include -# else -# include -# endif -#endif -#ifdef _WIN32 -# if defined(__GLIBCXX__) -# include -# include -# elif defined(_LIBCPP_VERSION) -# include <__std_stream> -# endif -# define WIN32_LEAN_AND_MEAN -# include -#endif - -export module fmt; - -#define FMT_EXPORT export -#define FMT_BEGIN_EXPORT export { -#define FMT_END_EXPORT } - -// If you define FMT_ATTACH_TO_GLOBAL_MODULE -// - all declarations are detached from module 'fmt' -// - the module behaves like a traditional static library, too -// - all library symbols are mangled traditionally -// - you can mix TUs with either importing or #including the {fmt} API -#ifdef FMT_ATTACH_TO_GLOBAL_MODULE -extern "C++" { -#endif - -// All library-provided declarations and definitions must be in the module -// purview to be exported. -#include "fmt/args.h" -#include "fmt/chrono.h" -#include "fmt/color.h" -#include "fmt/compile.h" -#include "fmt/format.h" -#include "fmt/os.h" -#include "fmt/printf.h" -#include "fmt/std.h" -#include "fmt/xchar.h" - -#ifdef FMT_ATTACH_TO_GLOBAL_MODULE -} -#endif - -// gcc doesn't yet implement private module fragments -#if !FMT_GCC_VERSION -module : private; -#endif - -#include "format.cc" -#include "os.cc" diff --git a/src/common/dep/fmt/format-inl.h b/src/common/dep/fmt/format-inl.h deleted file mode 100644 index dac2d437a..000000000 --- a/src/common/dep/fmt/format-inl.h +++ /dev/null @@ -1,1662 +0,0 @@ -// Formatting library for C++ - implementation -// -// Copyright (c) 2012 - 2016, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#ifndef FMT_FORMAT_INL_H_ -#define FMT_FORMAT_INL_H_ - -#include -#include // errno -#include -#include -#include - -#ifndef FMT_STATIC_THOUSANDS_SEPARATOR -# include -#endif - -#ifdef _WIN32 -# include // _isatty -#endif - -#include "format.h" - -FMT_BEGIN_NAMESPACE -namespace detail { - -FMT_FUNC void assert_fail(const char* file, int line, const char* message) { - // Use unchecked std::fprintf to avoid triggering another assertion when - // writing to stderr fails - std::fprintf(stderr, "%s:%d: assertion failed: %s", file, line, message); - // Chosen instead of std::abort to satisfy Clang in CUDA mode during device - // code pass. - std::terminate(); -} - -FMT_FUNC void throw_format_error(const char* message) { - FMT_THROW(format_error(message)); -} - -FMT_FUNC void format_error_code(detail::buffer& out, int error_code, - string_view message) noexcept { - // Report error code making sure that the output fits into - // inline_buffer_size to avoid dynamic memory allocation and potential - // bad_alloc. - out.try_resize(0); - static const char SEP[] = ": "; - static const char ERROR_STR[] = "error "; - // Subtract 2 to account for terminating null characters in SEP and ERROR_STR. - size_t error_code_size = sizeof(SEP) + sizeof(ERROR_STR) - 2; - auto abs_value = static_cast>(error_code); - if (detail::is_negative(error_code)) { - abs_value = 0 - abs_value; - ++error_code_size; - } - error_code_size += detail::to_unsigned(detail::count_digits(abs_value)); - auto it = buffer_appender(out); - if (message.size() <= inline_buffer_size - error_code_size) - format_to(it, FMT_STRING("{}{}"), message, SEP); - format_to(it, FMT_STRING("{}{}"), ERROR_STR, error_code); - FMT_ASSERT(out.size() <= inline_buffer_size, ""); -} - -FMT_FUNC void report_error(format_func func, int error_code, - const char* message) noexcept { - memory_buffer full_message; - func(full_message, error_code, message); - // Don't use fwrite_fully because the latter may throw. - if (std::fwrite(full_message.data(), full_message.size(), 1, stderr) > 0) - std::fputc('\n', stderr); -} - -// A wrapper around fwrite that throws on error. -inline void fwrite_fully(const void* ptr, size_t size, size_t count, - FILE* stream) { - size_t written = std::fwrite(ptr, size, count, stream); - if (written < count) - FMT_THROW(system_error(errno, FMT_STRING("cannot write to file"))); -} - -#ifndef FMT_STATIC_THOUSANDS_SEPARATOR -template -locale_ref::locale_ref(const Locale& loc) : locale_(&loc) { - static_assert(std::is_same::value, ""); -} - -template Locale locale_ref::get() const { - static_assert(std::is_same::value, ""); - return locale_ ? *static_cast(locale_) : std::locale(); -} - -template -FMT_FUNC auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result { - auto& facet = std::use_facet>(loc.get()); - auto grouping = facet.grouping(); - auto thousands_sep = grouping.empty() ? Char() : facet.thousands_sep(); - return {std::move(grouping), thousands_sep}; -} -template FMT_FUNC Char decimal_point_impl(locale_ref loc) { - return std::use_facet>(loc.get()) - .decimal_point(); -} -#else -template -FMT_FUNC auto thousands_sep_impl(locale_ref) -> thousands_sep_result { - return {"\03", FMT_STATIC_THOUSANDS_SEPARATOR}; -} -template FMT_FUNC Char decimal_point_impl(locale_ref) { - return '.'; -} -#endif - -FMT_FUNC auto write_loc(appender out, loc_value value, - const format_specs<>& specs, locale_ref loc) -> bool { -#ifndef FMT_STATIC_THOUSANDS_SEPARATOR - auto locale = loc.get(); - // We cannot use the num_put facet because it may produce output in - // a wrong encoding. - using facet = format_facet; - if (std::has_facet(locale)) - return std::use_facet(locale).put(out, value, specs); - return facet(locale).put(out, value, specs); -#endif - return false; -} -} // namespace detail - -template typename Locale::id format_facet::id; - -#ifndef FMT_STATIC_THOUSANDS_SEPARATOR -template format_facet::format_facet(Locale& loc) { - auto& numpunct = std::use_facet>(loc); - grouping_ = numpunct.grouping(); - if (!grouping_.empty()) separator_ = std::string(1, numpunct.thousands_sep()); -} - -template <> -FMT_API FMT_FUNC auto format_facet::do_put( - appender out, loc_value val, const format_specs<>& specs) const -> bool { - return val.visit( - detail::loc_writer<>{out, specs, separator_, grouping_, decimal_point_}); -} -#endif - -FMT_FUNC std::system_error vsystem_error(int error_code, string_view fmt, - format_args args) { - auto ec = std::error_code(error_code, std::generic_category()); - return std::system_error(ec, vformat(fmt, args)); -} - -namespace detail { - -template inline bool operator==(basic_fp x, basic_fp y) { - return x.f == y.f && x.e == y.e; -} - -// Compilers should be able to optimize this into the ror instruction. -FMT_CONSTEXPR inline uint32_t rotr(uint32_t n, uint32_t r) noexcept { - r &= 31; - return (n >> r) | (n << (32 - r)); -} -FMT_CONSTEXPR inline uint64_t rotr(uint64_t n, uint32_t r) noexcept { - r &= 63; - return (n >> r) | (n << (64 - r)); -} - -// Implementation of Dragonbox algorithm: https://github.com/jk-jeon/dragonbox. -namespace dragonbox { -// Computes upper 64 bits of multiplication of a 32-bit unsigned integer and a -// 64-bit unsigned integer. -inline uint64_t umul96_upper64(uint32_t x, uint64_t y) noexcept { - return umul128_upper64(static_cast(x) << 32, y); -} - -// Computes lower 128 bits of multiplication of a 64-bit unsigned integer and a -// 128-bit unsigned integer. -inline uint128_fallback umul192_lower128(uint64_t x, - uint128_fallback y) noexcept { - uint64_t high = x * y.high(); - uint128_fallback high_low = umul128(x, y.low()); - return {high + high_low.high(), high_low.low()}; -} - -// Computes lower 64 bits of multiplication of a 32-bit unsigned integer and a -// 64-bit unsigned integer. -inline uint64_t umul96_lower64(uint32_t x, uint64_t y) noexcept { - return x * y; -} - -// Various fast log computations. -inline int floor_log10_pow2_minus_log10_4_over_3(int e) noexcept { - FMT_ASSERT(e <= 2936 && e >= -2985, "too large exponent"); - return (e * 631305 - 261663) >> 21; -} - -FMT_INLINE_VARIABLE constexpr struct { - uint32_t divisor; - int shift_amount; -} div_small_pow10_infos[] = {{10, 16}, {100, 16}}; - -// Replaces n by floor(n / pow(10, N)) returning true if and only if n is -// divisible by pow(10, N). -// Precondition: n <= pow(10, N + 1). -template -bool check_divisibility_and_divide_by_pow10(uint32_t& n) noexcept { - // The numbers below are chosen such that: - // 1. floor(n/d) = floor(nm / 2^k) where d=10 or d=100, - // 2. nm mod 2^k < m if and only if n is divisible by d, - // where m is magic_number, k is shift_amount - // and d is divisor. - // - // Item 1 is a common technique of replacing division by a constant with - // multiplication, see e.g. "Division by Invariant Integers Using - // Multiplication" by Granlund and Montgomery (1994). magic_number (m) is set - // to ceil(2^k/d) for large enough k. - // The idea for item 2 originates from Schubfach. - constexpr auto info = div_small_pow10_infos[N - 1]; - FMT_ASSERT(n <= info.divisor * 10, "n is too large"); - constexpr uint32_t magic_number = - (1u << info.shift_amount) / info.divisor + 1; - n *= magic_number; - const uint32_t comparison_mask = (1u << info.shift_amount) - 1; - bool result = (n & comparison_mask) < magic_number; - n >>= info.shift_amount; - return result; -} - -// Computes floor(n / pow(10, N)) for small n and N. -// Precondition: n <= pow(10, N + 1). -template uint32_t small_division_by_pow10(uint32_t n) noexcept { - constexpr auto info = div_small_pow10_infos[N - 1]; - FMT_ASSERT(n <= info.divisor * 10, "n is too large"); - constexpr uint32_t magic_number = - (1u << info.shift_amount) / info.divisor + 1; - return (n * magic_number) >> info.shift_amount; -} - -// Computes floor(n / 10^(kappa + 1)) (float) -inline uint32_t divide_by_10_to_kappa_plus_1(uint32_t n) noexcept { - // 1374389535 = ceil(2^37/100) - return static_cast((static_cast(n) * 1374389535) >> 37); -} -// Computes floor(n / 10^(kappa + 1)) (double) -inline uint64_t divide_by_10_to_kappa_plus_1(uint64_t n) noexcept { - // 2361183241434822607 = ceil(2^(64+7)/1000) - return umul128_upper64(n, 2361183241434822607ull) >> 7; -} - -// Various subroutines using pow10 cache -template struct cache_accessor; - -template <> struct cache_accessor { - using carrier_uint = float_info::carrier_uint; - using cache_entry_type = uint64_t; - - static uint64_t get_cached_power(int k) noexcept { - FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, - "k is out of range"); - static constexpr const uint64_t pow10_significands[] = { - 0x81ceb32c4b43fcf5, 0xa2425ff75e14fc32, 0xcad2f7f5359a3b3f, - 0xfd87b5f28300ca0e, 0x9e74d1b791e07e49, 0xc612062576589ddb, - 0xf79687aed3eec552, 0x9abe14cd44753b53, 0xc16d9a0095928a28, - 0xf1c90080baf72cb2, 0x971da05074da7bef, 0xbce5086492111aeb, - 0xec1e4a7db69561a6, 0x9392ee8e921d5d08, 0xb877aa3236a4b44a, - 0xe69594bec44de15c, 0x901d7cf73ab0acda, 0xb424dc35095cd810, - 0xe12e13424bb40e14, 0x8cbccc096f5088cc, 0xafebff0bcb24aaff, - 0xdbe6fecebdedd5bf, 0x89705f4136b4a598, 0xabcc77118461cefd, - 0xd6bf94d5e57a42bd, 0x8637bd05af6c69b6, 0xa7c5ac471b478424, - 0xd1b71758e219652c, 0x83126e978d4fdf3c, 0xa3d70a3d70a3d70b, - 0xcccccccccccccccd, 0x8000000000000000, 0xa000000000000000, - 0xc800000000000000, 0xfa00000000000000, 0x9c40000000000000, - 0xc350000000000000, 0xf424000000000000, 0x9896800000000000, - 0xbebc200000000000, 0xee6b280000000000, 0x9502f90000000000, - 0xba43b74000000000, 0xe8d4a51000000000, 0x9184e72a00000000, - 0xb5e620f480000000, 0xe35fa931a0000000, 0x8e1bc9bf04000000, - 0xb1a2bc2ec5000000, 0xde0b6b3a76400000, 0x8ac7230489e80000, - 0xad78ebc5ac620000, 0xd8d726b7177a8000, 0x878678326eac9000, - 0xa968163f0a57b400, 0xd3c21bcecceda100, 0x84595161401484a0, - 0xa56fa5b99019a5c8, 0xcecb8f27f4200f3a, 0x813f3978f8940985, - 0xa18f07d736b90be6, 0xc9f2c9cd04674edf, 0xfc6f7c4045812297, - 0x9dc5ada82b70b59e, 0xc5371912364ce306, 0xf684df56c3e01bc7, - 0x9a130b963a6c115d, 0xc097ce7bc90715b4, 0xf0bdc21abb48db21, - 0x96769950b50d88f5, 0xbc143fa4e250eb32, 0xeb194f8e1ae525fe, - 0x92efd1b8d0cf37bf, 0xb7abc627050305ae, 0xe596b7b0c643c71a, - 0x8f7e32ce7bea5c70, 0xb35dbf821ae4f38c, 0xe0352f62a19e306f}; - return pow10_significands[k - float_info::min_k]; - } - - struct compute_mul_result { - carrier_uint result; - bool is_integer; - }; - struct compute_mul_parity_result { - bool parity; - bool is_integer; - }; - - static compute_mul_result compute_mul( - carrier_uint u, const cache_entry_type& cache) noexcept { - auto r = umul96_upper64(u, cache); - return {static_cast(r >> 32), - static_cast(r) == 0}; - } - - static uint32_t compute_delta(const cache_entry_type& cache, - int beta) noexcept { - return static_cast(cache >> (64 - 1 - beta)); - } - - static compute_mul_parity_result compute_mul_parity( - carrier_uint two_f, const cache_entry_type& cache, int beta) noexcept { - FMT_ASSERT(beta >= 1, ""); - FMT_ASSERT(beta < 64, ""); - - auto r = umul96_lower64(two_f, cache); - return {((r >> (64 - beta)) & 1) != 0, - static_cast(r >> (32 - beta)) == 0}; - } - - static carrier_uint compute_left_endpoint_for_shorter_interval_case( - const cache_entry_type& cache, int beta) noexcept { - return static_cast( - (cache - (cache >> (num_significand_bits() + 2))) >> - (64 - num_significand_bits() - 1 - beta)); - } - - static carrier_uint compute_right_endpoint_for_shorter_interval_case( - const cache_entry_type& cache, int beta) noexcept { - return static_cast( - (cache + (cache >> (num_significand_bits() + 1))) >> - (64 - num_significand_bits() - 1 - beta)); - } - - static carrier_uint compute_round_up_for_shorter_interval_case( - const cache_entry_type& cache, int beta) noexcept { - return (static_cast( - cache >> (64 - num_significand_bits() - 2 - beta)) + - 1) / - 2; - } -}; - -template <> struct cache_accessor { - using carrier_uint = float_info::carrier_uint; - using cache_entry_type = uint128_fallback; - - static uint128_fallback get_cached_power(int k) noexcept { - FMT_ASSERT(k >= float_info::min_k && k <= float_info::max_k, - "k is out of range"); - - static constexpr const uint128_fallback pow10_significands[] = { -#if FMT_USE_FULL_CACHE_DRAGONBOX - {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, - {0x9faacf3df73609b1, 0x77b191618c54e9ad}, - {0xc795830d75038c1d, 0xd59df5b9ef6a2418}, - {0xf97ae3d0d2446f25, 0x4b0573286b44ad1e}, - {0x9becce62836ac577, 0x4ee367f9430aec33}, - {0xc2e801fb244576d5, 0x229c41f793cda740}, - {0xf3a20279ed56d48a, 0x6b43527578c11110}, - {0x9845418c345644d6, 0x830a13896b78aaaa}, - {0xbe5691ef416bd60c, 0x23cc986bc656d554}, - {0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa9}, - {0x94b3a202eb1c3f39, 0x7bf7d71432f3d6aa}, - {0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc54}, - {0xe858ad248f5c22c9, 0xd1b3400f8f9cff69}, - {0x91376c36d99995be, 0x23100809b9c21fa2}, - {0xb58547448ffffb2d, 0xabd40a0c2832a78b}, - {0xe2e69915b3fff9f9, 0x16c90c8f323f516d}, - {0x8dd01fad907ffc3b, 0xae3da7d97f6792e4}, - {0xb1442798f49ffb4a, 0x99cd11cfdf41779d}, - {0xdd95317f31c7fa1d, 0x40405643d711d584}, - {0x8a7d3eef7f1cfc52, 0x482835ea666b2573}, - {0xad1c8eab5ee43b66, 0xda3243650005eed0}, - {0xd863b256369d4a40, 0x90bed43e40076a83}, - {0x873e4f75e2224e68, 0x5a7744a6e804a292}, - {0xa90de3535aaae202, 0x711515d0a205cb37}, - {0xd3515c2831559a83, 0x0d5a5b44ca873e04}, - {0x8412d9991ed58091, 0xe858790afe9486c3}, - {0xa5178fff668ae0b6, 0x626e974dbe39a873}, - {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, - {0x80fa687f881c7f8e, 0x7ce66634bc9d0b9a}, - {0xa139029f6a239f72, 0x1c1fffc1ebc44e81}, - {0xc987434744ac874e, 0xa327ffb266b56221}, - {0xfbe9141915d7a922, 0x4bf1ff9f0062baa9}, - {0x9d71ac8fada6c9b5, 0x6f773fc3603db4aa}, - {0xc4ce17b399107c22, 0xcb550fb4384d21d4}, - {0xf6019da07f549b2b, 0x7e2a53a146606a49}, - {0x99c102844f94e0fb, 0x2eda7444cbfc426e}, - {0xc0314325637a1939, 0xfa911155fefb5309}, - {0xf03d93eebc589f88, 0x793555ab7eba27cb}, - {0x96267c7535b763b5, 0x4bc1558b2f3458df}, - {0xbbb01b9283253ca2, 0x9eb1aaedfb016f17}, - {0xea9c227723ee8bcb, 0x465e15a979c1cadd}, - {0x92a1958a7675175f, 0x0bfacd89ec191eca}, - {0xb749faed14125d36, 0xcef980ec671f667c}, - {0xe51c79a85916f484, 0x82b7e12780e7401b}, - {0x8f31cc0937ae58d2, 0xd1b2ecb8b0908811}, - {0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa16}, - {0xdfbdcece67006ac9, 0x67a791e093e1d49b}, - {0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e1}, - {0xaecc49914078536d, 0x58fae9f773886e19}, - {0xda7f5bf590966848, 0xaf39a475506a899f}, - {0x888f99797a5e012d, 0x6d8406c952429604}, - {0xaab37fd7d8f58178, 0xc8e5087ba6d33b84}, - {0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a65}, - {0x855c3be0a17fcd26, 0x5cf2eea09a550680}, - {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, - {0xd0601d8efc57b08b, 0xf13b94daf124da27}, - {0x823c12795db6ce57, 0x76c53d08d6b70859}, - {0xa2cb1717b52481ed, 0x54768c4b0c64ca6f}, - {0xcb7ddcdda26da268, 0xa9942f5dcf7dfd0a}, - {0xfe5d54150b090b02, 0xd3f93b35435d7c4d}, - {0x9efa548d26e5a6e1, 0xc47bc5014a1a6db0}, - {0xc6b8e9b0709f109a, 0x359ab6419ca1091c}, - {0xf867241c8cc6d4c0, 0xc30163d203c94b63}, - {0x9b407691d7fc44f8, 0x79e0de63425dcf1e}, - {0xc21094364dfb5636, 0x985915fc12f542e5}, - {0xf294b943e17a2bc4, 0x3e6f5b7b17b2939e}, - {0x979cf3ca6cec5b5a, 0xa705992ceecf9c43}, - {0xbd8430bd08277231, 0x50c6ff782a838354}, - {0xece53cec4a314ebd, 0xa4f8bf5635246429}, - {0x940f4613ae5ed136, 0x871b7795e136be9a}, - {0xb913179899f68584, 0x28e2557b59846e40}, - {0xe757dd7ec07426e5, 0x331aeada2fe589d0}, - {0x9096ea6f3848984f, 0x3ff0d2c85def7622}, - {0xb4bca50b065abe63, 0x0fed077a756b53aa}, - {0xe1ebce4dc7f16dfb, 0xd3e8495912c62895}, - {0x8d3360f09cf6e4bd, 0x64712dd7abbbd95d}, - {0xb080392cc4349dec, 0xbd8d794d96aacfb4}, - {0xdca04777f541c567, 0xecf0d7a0fc5583a1}, - {0x89e42caaf9491b60, 0xf41686c49db57245}, - {0xac5d37d5b79b6239, 0x311c2875c522ced6}, - {0xd77485cb25823ac7, 0x7d633293366b828c}, - {0x86a8d39ef77164bc, 0xae5dff9c02033198}, - {0xa8530886b54dbdeb, 0xd9f57f830283fdfd}, - {0xd267caa862a12d66, 0xd072df63c324fd7c}, - {0x8380dea93da4bc60, 0x4247cb9e59f71e6e}, - {0xa46116538d0deb78, 0x52d9be85f074e609}, - {0xcd795be870516656, 0x67902e276c921f8c}, - {0x806bd9714632dff6, 0x00ba1cd8a3db53b7}, - {0xa086cfcd97bf97f3, 0x80e8a40eccd228a5}, - {0xc8a883c0fdaf7df0, 0x6122cd128006b2ce}, - {0xfad2a4b13d1b5d6c, 0x796b805720085f82}, - {0x9cc3a6eec6311a63, 0xcbe3303674053bb1}, - {0xc3f490aa77bd60fc, 0xbedbfc4411068a9d}, - {0xf4f1b4d515acb93b, 0xee92fb5515482d45}, - {0x991711052d8bf3c5, 0x751bdd152d4d1c4b}, - {0xbf5cd54678eef0b6, 0xd262d45a78a0635e}, - {0xef340a98172aace4, 0x86fb897116c87c35}, - {0x9580869f0e7aac0e, 0xd45d35e6ae3d4da1}, - {0xbae0a846d2195712, 0x8974836059cca10a}, - {0xe998d258869facd7, 0x2bd1a438703fc94c}, - {0x91ff83775423cc06, 0x7b6306a34627ddd0}, - {0xb67f6455292cbf08, 0x1a3bc84c17b1d543}, - {0xe41f3d6a7377eeca, 0x20caba5f1d9e4a94}, - {0x8e938662882af53e, 0x547eb47b7282ee9d}, - {0xb23867fb2a35b28d, 0xe99e619a4f23aa44}, - {0xdec681f9f4c31f31, 0x6405fa00e2ec94d5}, - {0x8b3c113c38f9f37e, 0xde83bc408dd3dd05}, - {0xae0b158b4738705e, 0x9624ab50b148d446}, - {0xd98ddaee19068c76, 0x3badd624dd9b0958}, - {0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d7}, - {0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4d}, - {0xd47487cc8470652b, 0x7647c32000696720}, - {0x84c8d4dfd2c63f3b, 0x29ecd9f40041e074}, - {0xa5fb0a17c777cf09, 0xf468107100525891}, - {0xcf79cc9db955c2cc, 0x7182148d4066eeb5}, - {0x81ac1fe293d599bf, 0xc6f14cd848405531}, - {0xa21727db38cb002f, 0xb8ada00e5a506a7d}, - {0xca9cf1d206fdc03b, 0xa6d90811f0e4851d}, - {0xfd442e4688bd304a, 0x908f4a166d1da664}, - {0x9e4a9cec15763e2e, 0x9a598e4e043287ff}, - {0xc5dd44271ad3cdba, 0x40eff1e1853f29fe}, - {0xf7549530e188c128, 0xd12bee59e68ef47d}, - {0x9a94dd3e8cf578b9, 0x82bb74f8301958cf}, - {0xc13a148e3032d6e7, 0xe36a52363c1faf02}, - {0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac2}, - {0x96f5600f15a7b7e5, 0x29ab103a5ef8c0ba}, - {0xbcb2b812db11a5de, 0x7415d448f6b6f0e8}, - {0xebdf661791d60f56, 0x111b495b3464ad22}, - {0x936b9fcebb25c995, 0xcab10dd900beec35}, - {0xb84687c269ef3bfb, 0x3d5d514f40eea743}, - {0xe65829b3046b0afa, 0x0cb4a5a3112a5113}, - {0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ac}, - {0xb3f4e093db73a093, 0x59ed216765690f57}, - {0xe0f218b8d25088b8, 0x306869c13ec3532d}, - {0x8c974f7383725573, 0x1e414218c73a13fc}, - {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, - {0xdbac6c247d62a583, 0xdf45f746b74abf3a}, - {0x894bc396ce5da772, 0x6b8bba8c328eb784}, - {0xab9eb47c81f5114f, 0x066ea92f3f326565}, - {0xd686619ba27255a2, 0xc80a537b0efefebe}, - {0x8613fd0145877585, 0xbd06742ce95f5f37}, - {0xa798fc4196e952e7, 0x2c48113823b73705}, - {0xd17f3b51fca3a7a0, 0xf75a15862ca504c6}, - {0x82ef85133de648c4, 0x9a984d73dbe722fc}, - {0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebbb}, - {0xcc963fee10b7d1b3, 0x318df905079926a9}, - {0xffbbcfe994e5c61f, 0xfdf17746497f7053}, - {0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa634}, - {0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc1}, - {0xf9bd690a1b68637b, 0x3dfdce7aa3c673b1}, - {0x9c1661a651213e2d, 0x06bea10ca65c084f}, - {0xc31bfa0fe5698db8, 0x486e494fcff30a63}, - {0xf3e2f893dec3f126, 0x5a89dba3c3efccfb}, - {0x986ddb5c6b3a76b7, 0xf89629465a75e01d}, - {0xbe89523386091465, 0xf6bbb397f1135824}, - {0xee2ba6c0678b597f, 0x746aa07ded582e2d}, - {0x94db483840b717ef, 0xa8c2a44eb4571cdd}, - {0xba121a4650e4ddeb, 0x92f34d62616ce414}, - {0xe896a0d7e51e1566, 0x77b020baf9c81d18}, - {0x915e2486ef32cd60, 0x0ace1474dc1d122f}, - {0xb5b5ada8aaff80b8, 0x0d819992132456bb}, - {0xe3231912d5bf60e6, 0x10e1fff697ed6c6a}, - {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, - {0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb3}, - {0xddd0467c64bce4a0, 0xac7cb3f6d05ddbdf}, - {0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96c}, - {0xad4ab7112eb3929d, 0x86c16c98d2c953c7}, - {0xd89d64d57a607744, 0xe871c7bf077ba8b8}, - {0x87625f056c7c4a8b, 0x11471cd764ad4973}, - {0xa93af6c6c79b5d2d, 0xd598e40d3dd89bd0}, - {0xd389b47879823479, 0x4aff1d108d4ec2c4}, - {0x843610cb4bf160cb, 0xcedf722a585139bb}, - {0xa54394fe1eedb8fe, 0xc2974eb4ee658829}, - {0xce947a3da6a9273e, 0x733d226229feea33}, - {0x811ccc668829b887, 0x0806357d5a3f5260}, - {0xa163ff802a3426a8, 0xca07c2dcb0cf26f8}, - {0xc9bcff6034c13052, 0xfc89b393dd02f0b6}, - {0xfc2c3f3841f17c67, 0xbbac2078d443ace3}, - {0x9d9ba7832936edc0, 0xd54b944b84aa4c0e}, - {0xc5029163f384a931, 0x0a9e795e65d4df12}, - {0xf64335bcf065d37d, 0x4d4617b5ff4a16d6}, - {0x99ea0196163fa42e, 0x504bced1bf8e4e46}, - {0xc06481fb9bcf8d39, 0xe45ec2862f71e1d7}, - {0xf07da27a82c37088, 0x5d767327bb4e5a4d}, - {0x964e858c91ba2655, 0x3a6a07f8d510f870}, - {0xbbe226efb628afea, 0x890489f70a55368c}, - {0xeadab0aba3b2dbe5, 0x2b45ac74ccea842f}, - {0x92c8ae6b464fc96f, 0x3b0b8bc90012929e}, - {0xb77ada0617e3bbcb, 0x09ce6ebb40173745}, - {0xe55990879ddcaabd, 0xcc420a6a101d0516}, - {0x8f57fa54c2a9eab6, 0x9fa946824a12232e}, - {0xb32df8e9f3546564, 0x47939822dc96abfa}, - {0xdff9772470297ebd, 0x59787e2b93bc56f8}, - {0x8bfbea76c619ef36, 0x57eb4edb3c55b65b}, - {0xaefae51477a06b03, 0xede622920b6b23f2}, - {0xdab99e59958885c4, 0xe95fab368e45ecee}, - {0x88b402f7fd75539b, 0x11dbcb0218ebb415}, - {0xaae103b5fcd2a881, 0xd652bdc29f26a11a}, - {0xd59944a37c0752a2, 0x4be76d3346f04960}, - {0x857fcae62d8493a5, 0x6f70a4400c562ddc}, - {0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb953}, - {0xd097ad07a71f26b2, 0x7e2000a41346a7a8}, - {0x825ecc24c873782f, 0x8ed400668c0c28c9}, - {0xa2f67f2dfa90563b, 0x728900802f0f32fb}, - {0xcbb41ef979346bca, 0x4f2b40a03ad2ffba}, - {0xfea126b7d78186bc, 0xe2f610c84987bfa9}, - {0x9f24b832e6b0f436, 0x0dd9ca7d2df4d7ca}, - {0xc6ede63fa05d3143, 0x91503d1c79720dbc}, - {0xf8a95fcf88747d94, 0x75a44c6397ce912b}, - {0x9b69dbe1b548ce7c, 0xc986afbe3ee11abb}, - {0xc24452da229b021b, 0xfbe85badce996169}, - {0xf2d56790ab41c2a2, 0xfae27299423fb9c4}, - {0x97c560ba6b0919a5, 0xdccd879fc967d41b}, - {0xbdb6b8e905cb600f, 0x5400e987bbc1c921}, - {0xed246723473e3813, 0x290123e9aab23b69}, - {0x9436c0760c86e30b, 0xf9a0b6720aaf6522}, - {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, - {0xe7958cb87392c2c2, 0xb60b1d1230b20e05}, - {0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c3}, - {0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af4}, - {0xe2280b6c20dd5232, 0x25c6da63c38de1b1}, - {0x8d590723948a535f, 0x579c487e5a38ad0f}, - {0xb0af48ec79ace837, 0x2d835a9df0c6d852}, - {0xdcdb1b2798182244, 0xf8e431456cf88e66}, - {0x8a08f0f8bf0f156b, 0x1b8e9ecb641b5900}, - {0xac8b2d36eed2dac5, 0xe272467e3d222f40}, - {0xd7adf884aa879177, 0x5b0ed81dcc6abb10}, - {0x86ccbb52ea94baea, 0x98e947129fc2b4ea}, - {0xa87fea27a539e9a5, 0x3f2398d747b36225}, - {0xd29fe4b18e88640e, 0x8eec7f0d19a03aae}, - {0x83a3eeeef9153e89, 0x1953cf68300424ad}, - {0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd8}, - {0xcdb02555653131b6, 0x3792f412cb06794e}, - {0x808e17555f3ebf11, 0xe2bbd88bbee40bd1}, - {0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec5}, - {0xc8de047564d20a8b, 0xf245825a5a445276}, - {0xfb158592be068d2e, 0xeed6e2f0f0d56713}, - {0x9ced737bb6c4183d, 0x55464dd69685606c}, - {0xc428d05aa4751e4c, 0xaa97e14c3c26b887}, - {0xf53304714d9265df, 0xd53dd99f4b3066a9}, - {0x993fe2c6d07b7fab, 0xe546a8038efe402a}, - {0xbf8fdb78849a5f96, 0xde98520472bdd034}, - {0xef73d256a5c0f77c, 0x963e66858f6d4441}, - {0x95a8637627989aad, 0xdde7001379a44aa9}, - {0xbb127c53b17ec159, 0x5560c018580d5d53}, - {0xe9d71b689dde71af, 0xaab8f01e6e10b4a7}, - {0x9226712162ab070d, 0xcab3961304ca70e9}, - {0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d23}, - {0xe45c10c42a2b3b05, 0x8cb89a7db77c506b}, - {0x8eb98a7a9a5b04e3, 0x77f3608e92adb243}, - {0xb267ed1940f1c61c, 0x55f038b237591ed4}, - {0xdf01e85f912e37a3, 0x6b6c46dec52f6689}, - {0x8b61313bbabce2c6, 0x2323ac4b3b3da016}, - {0xae397d8aa96c1b77, 0xabec975e0a0d081b}, - {0xd9c7dced53c72255, 0x96e7bd358c904a22}, - {0x881cea14545c7575, 0x7e50d64177da2e55}, - {0xaa242499697392d2, 0xdde50bd1d5d0b9ea}, - {0xd4ad2dbfc3d07787, 0x955e4ec64b44e865}, - {0x84ec3c97da624ab4, 0xbd5af13bef0b113f}, - {0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58f}, - {0xcfb11ead453994ba, 0x67de18eda5814af3}, - {0x81ceb32c4b43fcf4, 0x80eacf948770ced8}, - {0xa2425ff75e14fc31, 0xa1258379a94d028e}, - {0xcad2f7f5359a3b3e, 0x096ee45813a04331}, - {0xfd87b5f28300ca0d, 0x8bca9d6e188853fd}, - {0x9e74d1b791e07e48, 0x775ea264cf55347e}, - {0xc612062576589dda, 0x95364afe032a819e}, - {0xf79687aed3eec551, 0x3a83ddbd83f52205}, - {0x9abe14cd44753b52, 0xc4926a9672793543}, - {0xc16d9a0095928a27, 0x75b7053c0f178294}, - {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, - {0x971da05074da7bee, 0xd3f6fc16ebca5e04}, - {0xbce5086492111aea, 0x88f4bb1ca6bcf585}, - {0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6}, - {0x9392ee8e921d5d07, 0x3aff322e62439fd0}, - {0xb877aa3236a4b449, 0x09befeb9fad487c3}, - {0xe69594bec44de15b, 0x4c2ebe687989a9b4}, - {0x901d7cf73ab0acd9, 0x0f9d37014bf60a11}, - {0xb424dc35095cd80f, 0x538484c19ef38c95}, - {0xe12e13424bb40e13, 0x2865a5f206b06fba}, - {0x8cbccc096f5088cb, 0xf93f87b7442e45d4}, - {0xafebff0bcb24aafe, 0xf78f69a51539d749}, - {0xdbe6fecebdedd5be, 0xb573440e5a884d1c}, - {0x89705f4136b4a597, 0x31680a88f8953031}, - {0xabcc77118461cefc, 0xfdc20d2b36ba7c3e}, - {0xd6bf94d5e57a42bc, 0x3d32907604691b4d}, - {0x8637bd05af6c69b5, 0xa63f9a49c2c1b110}, - {0xa7c5ac471b478423, 0x0fcf80dc33721d54}, - {0xd1b71758e219652b, 0xd3c36113404ea4a9}, - {0x83126e978d4fdf3b, 0x645a1cac083126ea}, - {0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4}, - {0xcccccccccccccccc, 0xcccccccccccccccd}, - {0x8000000000000000, 0x0000000000000000}, - {0xa000000000000000, 0x0000000000000000}, - {0xc800000000000000, 0x0000000000000000}, - {0xfa00000000000000, 0x0000000000000000}, - {0x9c40000000000000, 0x0000000000000000}, - {0xc350000000000000, 0x0000000000000000}, - {0xf424000000000000, 0x0000000000000000}, - {0x9896800000000000, 0x0000000000000000}, - {0xbebc200000000000, 0x0000000000000000}, - {0xee6b280000000000, 0x0000000000000000}, - {0x9502f90000000000, 0x0000000000000000}, - {0xba43b74000000000, 0x0000000000000000}, - {0xe8d4a51000000000, 0x0000000000000000}, - {0x9184e72a00000000, 0x0000000000000000}, - {0xb5e620f480000000, 0x0000000000000000}, - {0xe35fa931a0000000, 0x0000000000000000}, - {0x8e1bc9bf04000000, 0x0000000000000000}, - {0xb1a2bc2ec5000000, 0x0000000000000000}, - {0xde0b6b3a76400000, 0x0000000000000000}, - {0x8ac7230489e80000, 0x0000000000000000}, - {0xad78ebc5ac620000, 0x0000000000000000}, - {0xd8d726b7177a8000, 0x0000000000000000}, - {0x878678326eac9000, 0x0000000000000000}, - {0xa968163f0a57b400, 0x0000000000000000}, - {0xd3c21bcecceda100, 0x0000000000000000}, - {0x84595161401484a0, 0x0000000000000000}, - {0xa56fa5b99019a5c8, 0x0000000000000000}, - {0xcecb8f27f4200f3a, 0x0000000000000000}, - {0x813f3978f8940984, 0x4000000000000000}, - {0xa18f07d736b90be5, 0x5000000000000000}, - {0xc9f2c9cd04674ede, 0xa400000000000000}, - {0xfc6f7c4045812296, 0x4d00000000000000}, - {0x9dc5ada82b70b59d, 0xf020000000000000}, - {0xc5371912364ce305, 0x6c28000000000000}, - {0xf684df56c3e01bc6, 0xc732000000000000}, - {0x9a130b963a6c115c, 0x3c7f400000000000}, - {0xc097ce7bc90715b3, 0x4b9f100000000000}, - {0xf0bdc21abb48db20, 0x1e86d40000000000}, - {0x96769950b50d88f4, 0x1314448000000000}, - {0xbc143fa4e250eb31, 0x17d955a000000000}, - {0xeb194f8e1ae525fd, 0x5dcfab0800000000}, - {0x92efd1b8d0cf37be, 0x5aa1cae500000000}, - {0xb7abc627050305ad, 0xf14a3d9e40000000}, - {0xe596b7b0c643c719, 0x6d9ccd05d0000000}, - {0x8f7e32ce7bea5c6f, 0xe4820023a2000000}, - {0xb35dbf821ae4f38b, 0xdda2802c8a800000}, - {0xe0352f62a19e306e, 0xd50b2037ad200000}, - {0x8c213d9da502de45, 0x4526f422cc340000}, - {0xaf298d050e4395d6, 0x9670b12b7f410000}, - {0xdaf3f04651d47b4c, 0x3c0cdd765f114000}, - {0x88d8762bf324cd0f, 0xa5880a69fb6ac800}, - {0xab0e93b6efee0053, 0x8eea0d047a457a00}, - {0xd5d238a4abe98068, 0x72a4904598d6d880}, - {0x85a36366eb71f041, 0x47a6da2b7f864750}, - {0xa70c3c40a64e6c51, 0x999090b65f67d924}, - {0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d}, - {0x82818f1281ed449f, 0xbff8f10e7a8921a5}, - {0xa321f2d7226895c7, 0xaff72d52192b6a0e}, - {0xcbea6f8ceb02bb39, 0x9bf4f8a69f764491}, - {0xfee50b7025c36a08, 0x02f236d04753d5b5}, - {0x9f4f2726179a2245, 0x01d762422c946591}, - {0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef6}, - {0xf8ebad2b84e0d58b, 0xd2e0898765a7deb3}, - {0x9b934c3b330c8577, 0x63cc55f49f88eb30}, - {0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fc}, - {0xf316271c7fc3908a, 0x8bef464e3945ef7b}, - {0x97edd871cfda3a56, 0x97758bf0e3cbb5ad}, - {0xbde94e8e43d0c8ec, 0x3d52eeed1cbea318}, - {0xed63a231d4c4fb27, 0x4ca7aaa863ee4bde}, - {0x945e455f24fb1cf8, 0x8fe8caa93e74ef6b}, - {0xb975d6b6ee39e436, 0xb3e2fd538e122b45}, - {0xe7d34c64a9c85d44, 0x60dbbca87196b617}, - {0x90e40fbeea1d3a4a, 0xbc8955e946fe31ce}, - {0xb51d13aea4a488dd, 0x6babab6398bdbe42}, - {0xe264589a4dcdab14, 0xc696963c7eed2dd2}, - {0x8d7eb76070a08aec, 0xfc1e1de5cf543ca3}, - {0xb0de65388cc8ada8, 0x3b25a55f43294bcc}, - {0xdd15fe86affad912, 0x49ef0eb713f39ebf}, - {0x8a2dbf142dfcc7ab, 0x6e3569326c784338}, - {0xacb92ed9397bf996, 0x49c2c37f07965405}, - {0xd7e77a8f87daf7fb, 0xdc33745ec97be907}, - {0x86f0ac99b4e8dafd, 0x69a028bb3ded71a4}, - {0xa8acd7c0222311bc, 0xc40832ea0d68ce0d}, - {0xd2d80db02aabd62b, 0xf50a3fa490c30191}, - {0x83c7088e1aab65db, 0x792667c6da79e0fb}, - {0xa4b8cab1a1563f52, 0x577001b891185939}, - {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, - {0x80b05e5ac60b6178, 0x544f8158315b05b5}, - {0xa0dc75f1778e39d6, 0x696361ae3db1c722}, - {0xc913936dd571c84c, 0x03bc3a19cd1e38ea}, - {0xfb5878494ace3a5f, 0x04ab48a04065c724}, - {0x9d174b2dcec0e47b, 0x62eb0d64283f9c77}, - {0xc45d1df942711d9a, 0x3ba5d0bd324f8395}, - {0xf5746577930d6500, 0xca8f44ec7ee3647a}, - {0x9968bf6abbe85f20, 0x7e998b13cf4e1ecc}, - {0xbfc2ef456ae276e8, 0x9e3fedd8c321a67f}, - {0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101f}, - {0x95d04aee3b80ece5, 0xbba1f1d158724a13}, - {0xbb445da9ca61281f, 0x2a8a6e45ae8edc98}, - {0xea1575143cf97226, 0xf52d09d71a3293be}, - {0x924d692ca61be758, 0x593c2626705f9c57}, - {0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836d}, - {0xe498f455c38b997a, 0x0b6dfb9c0f956448}, - {0x8edf98b59a373fec, 0x4724bd4189bd5ead}, - {0xb2977ee300c50fe7, 0x58edec91ec2cb658}, - {0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ee}, - {0x8b865b215899f46c, 0xbd79e0d20082ee75}, - {0xae67f1e9aec07187, 0xecd8590680a3aa12}, - {0xda01ee641a708de9, 0xe80e6f4820cc9496}, - {0x884134fe908658b2, 0x3109058d147fdcde}, - {0xaa51823e34a7eede, 0xbd4b46f0599fd416}, - {0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91b}, - {0x850fadc09923329e, 0x03e2cf6bc604ddb1}, - {0xa6539930bf6bff45, 0x84db8346b786151d}, - {0xcfe87f7cef46ff16, 0xe612641865679a64}, - {0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07f}, - {0xa26da3999aef7749, 0xe3be5e330f38f09e}, - {0xcb090c8001ab551c, 0x5cadf5bfd3072cc6}, - {0xfdcb4fa002162a63, 0x73d9732fc7c8f7f7}, - {0x9e9f11c4014dda7e, 0x2867e7fddcdd9afb}, - {0xc646d63501a1511d, 0xb281e1fd541501b9}, - {0xf7d88bc24209a565, 0x1f225a7ca91a4227}, - {0x9ae757596946075f, 0x3375788de9b06959}, - {0xc1a12d2fc3978937, 0x0052d6b1641c83af}, - {0xf209787bb47d6b84, 0xc0678c5dbd23a49b}, - {0x9745eb4d50ce6332, 0xf840b7ba963646e1}, - {0xbd176620a501fbff, 0xb650e5a93bc3d899}, - {0xec5d3fa8ce427aff, 0xa3e51f138ab4cebf}, - {0x93ba47c980e98cdf, 0xc66f336c36b10138}, - {0xb8a8d9bbe123f017, 0xb80b0047445d4185}, - {0xe6d3102ad96cec1d, 0xa60dc059157491e6}, - {0x9043ea1ac7e41392, 0x87c89837ad68db30}, - {0xb454e4a179dd1877, 0x29babe4598c311fc}, - {0xe16a1dc9d8545e94, 0xf4296dd6fef3d67b}, - {0x8ce2529e2734bb1d, 0x1899e4a65f58660d}, - {0xb01ae745b101e9e4, 0x5ec05dcff72e7f90}, - {0xdc21a1171d42645d, 0x76707543f4fa1f74}, - {0x899504ae72497eba, 0x6a06494a791c53a9}, - {0xabfa45da0edbde69, 0x0487db9d17636893}, - {0xd6f8d7509292d603, 0x45a9d2845d3c42b7}, - {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, - {0xa7f26836f282b732, 0x8e6cac7768d7141f}, - {0xd1ef0244af2364ff, 0x3207d795430cd927}, - {0x8335616aed761f1f, 0x7f44e6bd49e807b9}, - {0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a7}, - {0xcd036837130890a1, 0x36dba887c37a8c10}, - {0x802221226be55a64, 0xc2494954da2c978a}, - {0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6d}, - {0xc83553c5c8965d3d, 0x6f92829494e5acc8}, - {0xfa42a8b73abbf48c, 0xcb772339ba1f17fa}, - {0x9c69a97284b578d7, 0xff2a760414536efc}, - {0xc38413cf25e2d70d, 0xfef5138519684abb}, - {0xf46518c2ef5b8cd1, 0x7eb258665fc25d6a}, - {0x98bf2f79d5993802, 0xef2f773ffbd97a62}, - {0xbeeefb584aff8603, 0xaafb550ffacfd8fb}, - {0xeeaaba2e5dbf6784, 0x95ba2a53f983cf39}, - {0x952ab45cfa97a0b2, 0xdd945a747bf26184}, - {0xba756174393d88df, 0x94f971119aeef9e5}, - {0xe912b9d1478ceb17, 0x7a37cd5601aab85e}, - {0x91abb422ccb812ee, 0xac62e055c10ab33b}, - {0xb616a12b7fe617aa, 0x577b986b314d600a}, - {0xe39c49765fdf9d94, 0xed5a7e85fda0b80c}, - {0x8e41ade9fbebc27d, 0x14588f13be847308}, - {0xb1d219647ae6b31c, 0x596eb2d8ae258fc9}, - {0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bc}, - {0x8aec23d680043bee, 0x25de7bb9480d5855}, - {0xada72ccc20054ae9, 0xaf561aa79a10ae6b}, - {0xd910f7ff28069da4, 0x1b2ba1518094da05}, - {0x87aa9aff79042286, 0x90fb44d2f05d0843}, - {0xa99541bf57452b28, 0x353a1607ac744a54}, - {0xd3fa922f2d1675f2, 0x42889b8997915ce9}, - {0x847c9b5d7c2e09b7, 0x69956135febada12}, - {0xa59bc234db398c25, 0x43fab9837e699096}, - {0xcf02b2c21207ef2e, 0x94f967e45e03f4bc}, - {0x8161afb94b44f57d, 0x1d1be0eebac278f6}, - {0xa1ba1ba79e1632dc, 0x6462d92a69731733}, - {0xca28a291859bbf93, 0x7d7b8f7503cfdcff}, - {0xfcb2cb35e702af78, 0x5cda735244c3d43f}, - {0x9defbf01b061adab, 0x3a0888136afa64a8}, - {0xc56baec21c7a1916, 0x088aaa1845b8fdd1}, - {0xf6c69a72a3989f5b, 0x8aad549e57273d46}, - {0x9a3c2087a63f6399, 0x36ac54e2f678864c}, - {0xc0cb28a98fcf3c7f, 0x84576a1bb416a7de}, - {0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d6}, - {0x969eb7c47859e743, 0x9f644ae5a4b1b326}, - {0xbc4665b596706114, 0x873d5d9f0dde1fef}, - {0xeb57ff22fc0c7959, 0xa90cb506d155a7eb}, - {0x9316ff75dd87cbd8, 0x09a7f12442d588f3}, - {0xb7dcbf5354e9bece, 0x0c11ed6d538aeb30}, - {0xe5d3ef282a242e81, 0x8f1668c8a86da5fb}, - {0x8fa475791a569d10, 0xf96e017d694487bd}, - {0xb38d92d760ec4455, 0x37c981dcc395a9ad}, - {0xe070f78d3927556a, 0x85bbe253f47b1418}, - {0x8c469ab843b89562, 0x93956d7478ccec8f}, - {0xaf58416654a6babb, 0x387ac8d1970027b3}, - {0xdb2e51bfe9d0696a, 0x06997b05fcc0319f}, - {0x88fcf317f22241e2, 0x441fece3bdf81f04}, - {0xab3c2fddeeaad25a, 0xd527e81cad7626c4}, - {0xd60b3bd56a5586f1, 0x8a71e223d8d3b075}, - {0x85c7056562757456, 0xf6872d5667844e4a}, - {0xa738c6bebb12d16c, 0xb428f8ac016561dc}, - {0xd106f86e69d785c7, 0xe13336d701beba53}, - {0x82a45b450226b39c, 0xecc0024661173474}, - {0xa34d721642b06084, 0x27f002d7f95d0191}, - {0xcc20ce9bd35c78a5, 0x31ec038df7b441f5}, - {0xff290242c83396ce, 0x7e67047175a15272}, - {0x9f79a169bd203e41, 0x0f0062c6e984d387}, - {0xc75809c42c684dd1, 0x52c07b78a3e60869}, - {0xf92e0c3537826145, 0xa7709a56ccdf8a83}, - {0x9bbcc7a142b17ccb, 0x88a66076400bb692}, - {0xc2abf989935ddbfe, 0x6acff893d00ea436}, - {0xf356f7ebf83552fe, 0x0583f6b8c4124d44}, - {0x98165af37b2153de, 0xc3727a337a8b704b}, - {0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5d}, - {0xeda2ee1c7064130c, 0x1162def06f79df74}, - {0x9485d4d1c63e8be7, 0x8addcb5645ac2ba9}, - {0xb9a74a0637ce2ee1, 0x6d953e2bd7173693}, - {0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0438}, - {0x910ab1d4db9914a0, 0x1d9c9892400a22a3}, - {0xb54d5e4a127f59c8, 0x2503beb6d00cab4c}, - {0xe2a0b5dc971f303a, 0x2e44ae64840fd61e}, - {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, - {0xb10d8e1456105dad, 0x7425a83e872c5f48}, - {0xdd50f1996b947518, 0xd12f124e28f7771a}, - {0x8a5296ffe33cc92f, 0x82bd6b70d99aaa70}, - {0xace73cbfdc0bfb7b, 0x636cc64d1001550c}, - {0xd8210befd30efa5a, 0x3c47f7e05401aa4f}, - {0x8714a775e3e95c78, 0x65acfaec34810a72}, - {0xa8d9d1535ce3b396, 0x7f1839a741a14d0e}, - {0xd31045a8341ca07c, 0x1ede48111209a051}, - {0x83ea2b892091e44d, 0x934aed0aab460433}, - {0xa4e4b66b68b65d60, 0xf81da84d56178540}, - {0xce1de40642e3f4b9, 0x36251260ab9d668f}, - {0x80d2ae83e9ce78f3, 0xc1d72b7c6b42601a}, - {0xa1075a24e4421730, 0xb24cf65b8612f820}, - {0xc94930ae1d529cfc, 0xdee033f26797b628}, - {0xfb9b7cd9a4a7443c, 0x169840ef017da3b2}, - {0x9d412e0806e88aa5, 0x8e1f289560ee864f}, - {0xc491798a08a2ad4e, 0xf1a6f2bab92a27e3}, - {0xf5b5d7ec8acb58a2, 0xae10af696774b1dc}, - {0x9991a6f3d6bf1765, 0xacca6da1e0a8ef2a}, - {0xbff610b0cc6edd3f, 0x17fd090a58d32af4}, - {0xeff394dcff8a948e, 0xddfc4b4cef07f5b1}, - {0x95f83d0a1fb69cd9, 0x4abdaf101564f98f}, - {0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f2}, - {0xea53df5fd18d5513, 0x84c86189216dc5ee}, - {0x92746b9be2f8552c, 0x32fd3cf5b4e49bb5}, - {0xb7118682dbb66a77, 0x3fbc8c33221dc2a2}, - {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, - {0x8f05b1163ba6832d, 0x29cb4d87f2a7400f}, - {0xb2c71d5bca9023f8, 0x743e20e9ef511013}, - {0xdf78e4b2bd342cf6, 0x914da9246b255417}, - {0x8bab8eefb6409c1a, 0x1ad089b6c2f7548f}, - {0xae9672aba3d0c320, 0xa184ac2473b529b2}, - {0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741f}, - {0x8865899617fb1871, 0x7e2fa67c7a658893}, - {0xaa7eebfb9df9de8d, 0xddbb901b98feeab8}, - {0xd51ea6fa85785631, 0x552a74227f3ea566}, - {0x8533285c936b35de, 0xd53a88958f872760}, - {0xa67ff273b8460356, 0x8a892abaf368f138}, - {0xd01fef10a657842c, 0x2d2b7569b0432d86}, - {0x8213f56a67f6b29b, 0x9c3b29620e29fc74}, - {0xa298f2c501f45f42, 0x8349f3ba91b47b90}, - {0xcb3f2f7642717713, 0x241c70a936219a74}, - {0xfe0efb53d30dd4d7, 0xed238cd383aa0111}, - {0x9ec95d1463e8a506, 0xf4363804324a40ab}, - {0xc67bb4597ce2ce48, 0xb143c6053edcd0d6}, - {0xf81aa16fdc1b81da, 0xdd94b7868e94050b}, - {0x9b10a4e5e9913128, 0xca7cf2b4191c8327}, - {0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f1}, - {0xf24a01a73cf2dccf, 0xbc633b39673c8ced}, - {0x976e41088617ca01, 0xd5be0503e085d814}, - {0xbd49d14aa79dbc82, 0x4b2d8644d8a74e19}, - {0xec9c459d51852ba2, 0xddf8e7d60ed1219f}, - {0x93e1ab8252f33b45, 0xcabb90e5c942b504}, - {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, - {0xe7109bfba19c0c9d, 0x0cc512670a783ad5}, - {0x906a617d450187e2, 0x27fb2b80668b24c6}, - {0xb484f9dc9641e9da, 0xb1f9f660802dedf7}, - {0xe1a63853bbd26451, 0x5e7873f8a0396974}, - {0x8d07e33455637eb2, 0xdb0b487b6423e1e9}, - {0xb049dc016abc5e5f, 0x91ce1a9a3d2cda63}, - {0xdc5c5301c56b75f7, 0x7641a140cc7810fc}, - {0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9e}, - {0xac2820d9623bf429, 0x546345fa9fbdcd45}, - {0xd732290fbacaf133, 0xa97c177947ad4096}, - {0x867f59a9d4bed6c0, 0x49ed8eabcccc485e}, - {0xa81f301449ee8c70, 0x5c68f256bfff5a75}, - {0xd226fc195c6a2f8c, 0x73832eec6fff3112}, - {0x83585d8fd9c25db7, 0xc831fd53c5ff7eac}, - {0xa42e74f3d032f525, 0xba3e7ca8b77f5e56}, - {0xcd3a1230c43fb26f, 0x28ce1bd2e55f35ec}, - {0x80444b5e7aa7cf85, 0x7980d163cf5b81b4}, - {0xa0555e361951c366, 0xd7e105bcc3326220}, - {0xc86ab5c39fa63440, 0x8dd9472bf3fefaa8}, - {0xfa856334878fc150, 0xb14f98f6f0feb952}, - {0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d4}, - {0xc3b8358109e84f07, 0x0a862f80ec4700c9}, - {0xf4a642e14c6262c8, 0xcd27bb612758c0fb}, - {0x98e7e9cccfbd7dbd, 0x8038d51cb897789d}, - {0xbf21e44003acdd2c, 0xe0470a63e6bd56c4}, - {0xeeea5d5004981478, 0x1858ccfce06cac75}, - {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, - {0xbaa718e68396cffd, 0xd30560258f54e6bb}, - {0xe950df20247c83fd, 0x47c6b82ef32a206a}, - {0x91d28b7416cdd27e, 0x4cdc331d57fa5442}, - {0xb6472e511c81471d, 0xe0133fe4adf8e953}, - {0xe3d8f9e563a198e5, 0x58180fddd97723a7}, - {0x8e679c2f5e44ff8f, 0x570f09eaa7ea7649}, - {0xb201833b35d63f73, 0x2cd2cc6551e513db}, - {0xde81e40a034bcf4f, 0xf8077f7ea65e58d2}, - {0x8b112e86420f6191, 0xfb04afaf27faf783}, - {0xadd57a27d29339f6, 0x79c5db9af1f9b564}, - {0xd94ad8b1c7380874, 0x18375281ae7822bd}, - {0x87cec76f1c830548, 0x8f2293910d0b15b6}, - {0xa9c2794ae3a3c69a, 0xb2eb3875504ddb23}, - {0xd433179d9c8cb841, 0x5fa60692a46151ec}, - {0x849feec281d7f328, 0xdbc7c41ba6bcd334}, - {0xa5c7ea73224deff3, 0x12b9b522906c0801}, - {0xcf39e50feae16bef, 0xd768226b34870a01}, - {0x81842f29f2cce375, 0xe6a1158300d46641}, - {0xa1e53af46f801c53, 0x60495ae3c1097fd1}, - {0xca5e89b18b602368, 0x385bb19cb14bdfc5}, - {0xfcf62c1dee382c42, 0x46729e03dd9ed7b6}, - {0x9e19db92b4e31ba9, 0x6c07a2c26a8346d2}, - {0xc5a05277621be293, 0xc7098b7305241886}, - {0xf70867153aa2db38, 0xb8cbee4fc66d1ea8}, - {0x9a65406d44a5c903, 0x737f74f1dc043329}, - {0xc0fe908895cf3b44, 0x505f522e53053ff3}, - {0xf13e34aabb430a15, 0x647726b9e7c68ff0}, - {0x96c6e0eab509e64d, 0x5eca783430dc19f6}, - {0xbc789925624c5fe0, 0xb67d16413d132073}, - {0xeb96bf6ebadf77d8, 0xe41c5bd18c57e890}, - {0x933e37a534cbaae7, 0x8e91b962f7b6f15a}, - {0xb80dc58e81fe95a1, 0x723627bbb5a4adb1}, - {0xe61136f2227e3b09, 0xcec3b1aaa30dd91d}, - {0x8fcac257558ee4e6, 0x213a4f0aa5e8a7b2}, - {0xb3bd72ed2af29e1f, 0xa988e2cd4f62d19e}, - {0xe0accfa875af45a7, 0x93eb1b80a33b8606}, - {0x8c6c01c9498d8b88, 0xbc72f130660533c4}, - {0xaf87023b9bf0ee6a, 0xeb8fad7c7f8680b5}, - { 0xdb68c2ca82ed2a05, - 0xa67398db9f6820e2 } -#else - {0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7b}, - {0xce5d73ff402d98e3, 0xfb0a3d212dc81290}, - {0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481f}, - {0x86a8d39ef77164bc, 0xae5dff9c02033198}, - {0xd98ddaee19068c76, 0x3badd624dd9b0958}, - {0xafbd2350644eeacf, 0xe5d1929ef90898fb}, - {0x8df5efabc5979c8f, 0xca8d3ffa1ef463c2}, - {0xe55990879ddcaabd, 0xcc420a6a101d0516}, - {0xb94470938fa89bce, 0xf808e40e8d5b3e6a}, - {0x95a8637627989aad, 0xdde7001379a44aa9}, - {0xf1c90080baf72cb1, 0x5324c68b12dd6339}, - {0xc350000000000000, 0x0000000000000000}, - {0x9dc5ada82b70b59d, 0xf020000000000000}, - {0xfee50b7025c36a08, 0x02f236d04753d5b5}, - {0xcde6fd5e09abcf26, 0xed4c0226b55e6f87}, - {0xa6539930bf6bff45, 0x84db8346b786151d}, - {0x865b86925b9bc5c2, 0x0b8a2392ba45a9b3}, - {0xd910f7ff28069da4, 0x1b2ba1518094da05}, - {0xaf58416654a6babb, 0x387ac8d1970027b3}, - {0x8da471a9de737e24, 0x5ceaecfed289e5d3}, - {0xe4d5e82392a40515, 0x0fabaf3feaa5334b}, - {0xb8da1662e7b00a17, 0x3d6a751f3b936244}, - {0x95527a5202df0ccb, 0x0f37801e0c43ebc9}, - {0xf13e34aabb430a15, 0x647726b9e7c68ff0} -#endif - }; - -#if FMT_USE_FULL_CACHE_DRAGONBOX - return pow10_significands[k - float_info::min_k]; -#else - static constexpr const uint64_t powers_of_5_64[] = { - 0x0000000000000001, 0x0000000000000005, 0x0000000000000019, - 0x000000000000007d, 0x0000000000000271, 0x0000000000000c35, - 0x0000000000003d09, 0x000000000001312d, 0x000000000005f5e1, - 0x00000000001dcd65, 0x00000000009502f9, 0x0000000002e90edd, - 0x000000000e8d4a51, 0x0000000048c27395, 0x000000016bcc41e9, - 0x000000071afd498d, 0x0000002386f26fc1, 0x000000b1a2bc2ec5, - 0x000003782dace9d9, 0x00001158e460913d, 0x000056bc75e2d631, - 0x0001b1ae4d6e2ef5, 0x000878678326eac9, 0x002a5a058fc295ed, - 0x00d3c21bcecceda1, 0x0422ca8b0a00a425, 0x14adf4b7320334b9}; - - static const int compression_ratio = 27; - - // Compute base index. - int cache_index = (k - float_info::min_k) / compression_ratio; - int kb = cache_index * compression_ratio + float_info::min_k; - int offset = k - kb; - - // Get base cache. - uint128_fallback base_cache = pow10_significands[cache_index]; - if (offset == 0) return base_cache; - - // Compute the required amount of bit-shift. - int alpha = floor_log2_pow10(kb + offset) - floor_log2_pow10(kb) - offset; - FMT_ASSERT(alpha > 0 && alpha < 64, "shifting error detected"); - - // Try to recover the real cache. - uint64_t pow5 = powers_of_5_64[offset]; - uint128_fallback recovered_cache = umul128(base_cache.high(), pow5); - uint128_fallback middle_low = umul128(base_cache.low(), pow5); - - recovered_cache += middle_low.high(); - - uint64_t high_to_middle = recovered_cache.high() << (64 - alpha); - uint64_t middle_to_low = recovered_cache.low() << (64 - alpha); - - recovered_cache = - uint128_fallback{(recovered_cache.low() >> alpha) | high_to_middle, - ((middle_low.low() >> alpha) | middle_to_low)}; - FMT_ASSERT(recovered_cache.low() + 1 != 0, ""); - return {recovered_cache.high(), recovered_cache.low() + 1}; -#endif - } - - struct compute_mul_result { - carrier_uint result; - bool is_integer; - }; - struct compute_mul_parity_result { - bool parity; - bool is_integer; - }; - - static compute_mul_result compute_mul( - carrier_uint u, const cache_entry_type& cache) noexcept { - auto r = umul192_upper128(u, cache); - return {r.high(), r.low() == 0}; - } - - static uint32_t compute_delta(cache_entry_type const& cache, - int beta) noexcept { - return static_cast(cache.high() >> (64 - 1 - beta)); - } - - static compute_mul_parity_result compute_mul_parity( - carrier_uint two_f, const cache_entry_type& cache, int beta) noexcept { - FMT_ASSERT(beta >= 1, ""); - FMT_ASSERT(beta < 64, ""); - - auto r = umul192_lower128(two_f, cache); - return {((r.high() >> (64 - beta)) & 1) != 0, - ((r.high() << beta) | (r.low() >> (64 - beta))) == 0}; - } - - static carrier_uint compute_left_endpoint_for_shorter_interval_case( - const cache_entry_type& cache, int beta) noexcept { - return (cache.high() - - (cache.high() >> (num_significand_bits() + 2))) >> - (64 - num_significand_bits() - 1 - beta); - } - - static carrier_uint compute_right_endpoint_for_shorter_interval_case( - const cache_entry_type& cache, int beta) noexcept { - return (cache.high() + - (cache.high() >> (num_significand_bits() + 1))) >> - (64 - num_significand_bits() - 1 - beta); - } - - static carrier_uint compute_round_up_for_shorter_interval_case( - const cache_entry_type& cache, int beta) noexcept { - return ((cache.high() >> (64 - num_significand_bits() - 2 - beta)) + - 1) / - 2; - } -}; - -FMT_FUNC uint128_fallback get_cached_power(int k) noexcept { - return cache_accessor::get_cached_power(k); -} - -// Various integer checks -template -bool is_left_endpoint_integer_shorter_interval(int exponent) noexcept { - const int case_shorter_interval_left_endpoint_lower_threshold = 2; - const int case_shorter_interval_left_endpoint_upper_threshold = 3; - return exponent >= case_shorter_interval_left_endpoint_lower_threshold && - exponent <= case_shorter_interval_left_endpoint_upper_threshold; -} - -// Remove trailing zeros from n and return the number of zeros removed (float) -FMT_INLINE int remove_trailing_zeros(uint32_t& n, int s = 0) noexcept { - FMT_ASSERT(n != 0, ""); - // Modular inverse of 5 (mod 2^32): (mod_inv_5 * 5) mod 2^32 = 1. - constexpr uint32_t mod_inv_5 = 0xcccccccd; - constexpr uint32_t mod_inv_25 = 0xc28f5c29; // = mod_inv_5 * mod_inv_5 - - while (true) { - auto q = rotr(n * mod_inv_25, 2); - if (q > max_value() / 100) break; - n = q; - s += 2; - } - auto q = rotr(n * mod_inv_5, 1); - if (q <= max_value() / 10) { - n = q; - s |= 1; - } - return s; -} - -// Removes trailing zeros and returns the number of zeros removed (double) -FMT_INLINE int remove_trailing_zeros(uint64_t& n) noexcept { - FMT_ASSERT(n != 0, ""); - - // This magic number is ceil(2^90 / 10^8). - constexpr uint64_t magic_number = 12379400392853802749ull; - auto nm = umul128(n, magic_number); - - // Is n is divisible by 10^8? - if ((nm.high() & ((1ull << (90 - 64)) - 1)) == 0 && nm.low() < magic_number) { - // If yes, work with the quotient... - auto n32 = static_cast(nm.high() >> (90 - 64)); - // ... and use the 32 bit variant of the function - int s = remove_trailing_zeros(n32, 8); - n = n32; - return s; - } - - // If n is not divisible by 10^8, work with n itself. - constexpr uint64_t mod_inv_5 = 0xcccccccccccccccd; - constexpr uint64_t mod_inv_25 = 0x8f5c28f5c28f5c29; // = mod_inv_5 * mod_inv_5 - - int s = 0; - while (true) { - auto q = rotr(n * mod_inv_25, 2); - if (q > max_value() / 100) break; - n = q; - s += 2; - } - auto q = rotr(n * mod_inv_5, 1); - if (q <= max_value() / 10) { - n = q; - s |= 1; - } - - return s; -} - -// The main algorithm for shorter interval case -template -FMT_INLINE decimal_fp shorter_interval_case(int exponent) noexcept { - decimal_fp ret_value; - // Compute k and beta - const int minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent); - const int beta = exponent + floor_log2_pow10(-minus_k); - - // Compute xi and zi - using cache_entry_type = typename cache_accessor::cache_entry_type; - const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); - - auto xi = cache_accessor::compute_left_endpoint_for_shorter_interval_case( - cache, beta); - auto zi = cache_accessor::compute_right_endpoint_for_shorter_interval_case( - cache, beta); - - // If the left endpoint is not an integer, increase it - if (!is_left_endpoint_integer_shorter_interval(exponent)) ++xi; - - // Try bigger divisor - ret_value.significand = zi / 10; - - // If succeed, remove trailing zeros if necessary and return - if (ret_value.significand * 10 >= xi) { - ret_value.exponent = minus_k + 1; - ret_value.exponent += remove_trailing_zeros(ret_value.significand); - return ret_value; - } - - // Otherwise, compute the round-up of y - ret_value.significand = - cache_accessor::compute_round_up_for_shorter_interval_case(cache, - beta); - ret_value.exponent = minus_k; - - // When tie occurs, choose one of them according to the rule - if (exponent >= float_info::shorter_interval_tie_lower_threshold && - exponent <= float_info::shorter_interval_tie_upper_threshold) { - ret_value.significand = ret_value.significand % 2 == 0 - ? ret_value.significand - : ret_value.significand - 1; - } else if (ret_value.significand < xi) { - ++ret_value.significand; - } - return ret_value; -} - -template decimal_fp to_decimal(T x) noexcept { - // Step 1: integer promotion & Schubfach multiplier calculation. - - using carrier_uint = typename float_info::carrier_uint; - using cache_entry_type = typename cache_accessor::cache_entry_type; - auto br = bit_cast(x); - - // Extract significand bits and exponent bits. - const carrier_uint significand_mask = - (static_cast(1) << num_significand_bits()) - 1; - carrier_uint significand = (br & significand_mask); - int exponent = - static_cast((br & exponent_mask()) >> num_significand_bits()); - - if (exponent != 0) { // Check if normal. - exponent -= exponent_bias() + num_significand_bits(); - - // Shorter interval case; proceed like Schubfach. - // In fact, when exponent == 1 and significand == 0, the interval is - // regular. However, it can be shown that the end-results are anyway same. - if (significand == 0) return shorter_interval_case(exponent); - - significand |= (static_cast(1) << num_significand_bits()); - } else { - // Subnormal case; the interval is always regular. - if (significand == 0) return {0, 0}; - exponent = - std::numeric_limits::min_exponent - num_significand_bits() - 1; - } - - const bool include_left_endpoint = (significand % 2 == 0); - const bool include_right_endpoint = include_left_endpoint; - - // Compute k and beta. - const int minus_k = floor_log10_pow2(exponent) - float_info::kappa; - const cache_entry_type cache = cache_accessor::get_cached_power(-minus_k); - const int beta = exponent + floor_log2_pow10(-minus_k); - - // Compute zi and deltai. - // 10^kappa <= deltai < 10^(kappa + 1) - const uint32_t deltai = cache_accessor::compute_delta(cache, beta); - const carrier_uint two_fc = significand << 1; - - // For the case of binary32, the result of integer check is not correct for - // 29711844 * 2^-82 - // = 6.1442653300000000008655037797566933477355632930994033813476... * 10^-18 - // and 29711844 * 2^-81 - // = 1.2288530660000000001731007559513386695471126586198806762695... * 10^-17, - // and they are the unique counterexamples. However, since 29711844 is even, - // this does not cause any problem for the endpoints calculations; it can only - // cause a problem when we need to perform integer check for the center. - // Fortunately, with these inputs, that branch is never executed, so we are - // fine. - const typename cache_accessor::compute_mul_result z_mul = - cache_accessor::compute_mul((two_fc | 1) << beta, cache); - - // Step 2: Try larger divisor; remove trailing zeros if necessary. - - // Using an upper bound on zi, we might be able to optimize the division - // better than the compiler; we are computing zi / big_divisor here. - decimal_fp ret_value; - ret_value.significand = divide_by_10_to_kappa_plus_1(z_mul.result); - uint32_t r = static_cast(z_mul.result - float_info::big_divisor * - ret_value.significand); - - if (r < deltai) { - // Exclude the right endpoint if necessary. - if (r == 0 && (z_mul.is_integer & !include_right_endpoint)) { - --ret_value.significand; - r = float_info::big_divisor; - goto small_divisor_case_label; - } - } else if (r > deltai) { - goto small_divisor_case_label; - } else { - // r == deltai; compare fractional parts. - const typename cache_accessor::compute_mul_parity_result x_mul = - cache_accessor::compute_mul_parity(two_fc - 1, cache, beta); - - if (!(x_mul.parity | (x_mul.is_integer & include_left_endpoint))) - goto small_divisor_case_label; - } - ret_value.exponent = minus_k + float_info::kappa + 1; - - // We may need to remove trailing zeros. - ret_value.exponent += remove_trailing_zeros(ret_value.significand); - return ret_value; - - // Step 3: Find the significand with the smaller divisor. - -small_divisor_case_label: - ret_value.significand *= 10; - ret_value.exponent = minus_k + float_info::kappa; - - uint32_t dist = r - (deltai / 2) + (float_info::small_divisor / 2); - const bool approx_y_parity = - ((dist ^ (float_info::small_divisor / 2)) & 1) != 0; - - // Is dist divisible by 10^kappa? - const bool divisible_by_small_divisor = - check_divisibility_and_divide_by_pow10::kappa>(dist); - - // Add dist / 10^kappa to the significand. - ret_value.significand += dist; - - if (!divisible_by_small_divisor) return ret_value; - - // Check z^(f) >= epsilon^(f). - // We have either yi == zi - epsiloni or yi == (zi - epsiloni) - 1, - // where yi == zi - epsiloni if and only if z^(f) >= epsilon^(f). - // Since there are only 2 possibilities, we only need to care about the - // parity. Also, zi and r should have the same parity since the divisor - // is an even number. - const auto y_mul = cache_accessor::compute_mul_parity(two_fc, cache, beta); - - // If z^(f) >= epsilon^(f), we might have a tie when z^(f) == epsilon^(f), - // or equivalently, when y is an integer. - if (y_mul.parity != approx_y_parity) - --ret_value.significand; - else if (y_mul.is_integer & (ret_value.significand % 2 != 0)) - --ret_value.significand; - return ret_value; -} -} // namespace dragonbox -} // namespace detail - -template <> struct formatter { - FMT_CONSTEXPR auto parse(format_parse_context& ctx) - -> format_parse_context::iterator { - return ctx.begin(); - } - - auto format(const detail::bigint& n, format_context& ctx) const - -> format_context::iterator { - auto out = ctx.out(); - bool first = true; - for (auto i = n.bigits_.size(); i > 0; --i) { - auto value = n.bigits_[i - 1u]; - if (first) { - out = format_to(out, FMT_STRING("{:x}"), value); - first = false; - continue; - } - out = format_to(out, FMT_STRING("{:08x}"), value); - } - if (n.exp_ > 0) - out = format_to(out, FMT_STRING("p{}"), - n.exp_ * detail::bigint::bigit_bits); - return out; - } -}; - -FMT_FUNC detail::utf8_to_utf16::utf8_to_utf16(string_view s) { - for_each_codepoint(s, [this](uint32_t cp, string_view) { - if (cp == invalid_code_point) FMT_THROW(std::runtime_error("invalid utf8")); - if (cp <= 0xFFFF) { - buffer_.push_back(static_cast(cp)); - } else { - cp -= 0x10000; - buffer_.push_back(static_cast(0xD800 + (cp >> 10))); - buffer_.push_back(static_cast(0xDC00 + (cp & 0x3FF))); - } - return true; - }); - buffer_.push_back(0); -} - -FMT_FUNC void format_system_error(detail::buffer& out, int error_code, - const char* message) noexcept { - FMT_TRY { - auto ec = std::error_code(error_code, std::generic_category()); - write(std::back_inserter(out), std::system_error(ec, message).what()); - return; - } - FMT_CATCH(...) {} - format_error_code(out, error_code, message); -} - -FMT_FUNC void report_system_error(int error_code, - const char* message) noexcept { - report_error(format_system_error, error_code, message); -} - -FMT_FUNC std::string vformat(string_view fmt, format_args args) { - // Don't optimize the "{}" case to keep the binary size small and because it - // can be better optimized in fmt::format anyway. - auto buffer = memory_buffer(); - detail::vformat_to(buffer, fmt, args); - return to_string(buffer); -} - -namespace detail { -#ifndef _WIN32 -FMT_FUNC bool write_console(std::FILE*, string_view) { return false; } -#else -using dword = conditional_t; -extern "C" __declspec(dllimport) int __stdcall WriteConsoleW( // - void*, const void*, dword, dword*, void*); - -FMT_FUNC bool write_console(std::FILE* f, string_view text) { - auto fd = _fileno(f); - if (!_isatty(fd)) return false; - auto u16 = utf8_to_utf16(text); - auto written = dword(); - return WriteConsoleW(reinterpret_cast(_get_osfhandle(fd)), u16.c_str(), - static_cast(u16.size()), &written, nullptr) != 0; -} - -// Print assuming legacy (non-Unicode) encoding. -FMT_FUNC void vprint_mojibake(std::FILE* f, string_view fmt, format_args args) { - auto buffer = memory_buffer(); - detail::vformat_to(buffer, fmt, - basic_format_args>(args)); - fwrite_fully(buffer.data(), 1, buffer.size(), f); -} -#endif - -FMT_FUNC void print(std::FILE* f, string_view text) { - if (!write_console(f, text)) fwrite_fully(text.data(), 1, text.size(), f); -} -} // namespace detail - -FMT_FUNC void vprint(std::FILE* f, string_view fmt, format_args args) { - auto buffer = memory_buffer(); - detail::vformat_to(buffer, fmt, args); - detail::print(f, {buffer.data(), buffer.size()}); -} - -FMT_FUNC void vprint(string_view fmt, format_args args) { - vprint(stdout, fmt, args); -} - -namespace detail { - -struct singleton { - unsigned char upper; - unsigned char lower_count; -}; - -inline auto is_printable(uint16_t x, const singleton* singletons, - size_t singletons_size, - const unsigned char* singleton_lowers, - const unsigned char* normal, size_t normal_size) - -> bool { - auto upper = x >> 8; - auto lower_start = 0; - for (size_t i = 0; i < singletons_size; ++i) { - auto s = singletons[i]; - auto lower_end = lower_start + s.lower_count; - if (upper < s.upper) break; - if (upper == s.upper) { - for (auto j = lower_start; j < lower_end; ++j) { - if (singleton_lowers[j] == (x & 0xff)) return false; - } - } - lower_start = lower_end; - } - - auto xsigned = static_cast(x); - auto current = true; - for (size_t i = 0; i < normal_size; ++i) { - auto v = static_cast(normal[i]); - auto len = (v & 0x80) != 0 ? (v & 0x7f) << 8 | normal[++i] : v; - xsigned -= len; - if (xsigned < 0) break; - current = !current; - } - return current; -} - -// This code is generated by support/printable.py. -FMT_FUNC auto is_printable(uint32_t cp) -> bool { - static constexpr singleton singletons0[] = { - {0x00, 1}, {0x03, 5}, {0x05, 6}, {0x06, 3}, {0x07, 6}, {0x08, 8}, - {0x09, 17}, {0x0a, 28}, {0x0b, 25}, {0x0c, 20}, {0x0d, 16}, {0x0e, 13}, - {0x0f, 4}, {0x10, 3}, {0x12, 18}, {0x13, 9}, {0x16, 1}, {0x17, 5}, - {0x18, 2}, {0x19, 3}, {0x1a, 7}, {0x1c, 2}, {0x1d, 1}, {0x1f, 22}, - {0x20, 3}, {0x2b, 3}, {0x2c, 2}, {0x2d, 11}, {0x2e, 1}, {0x30, 3}, - {0x31, 2}, {0x32, 1}, {0xa7, 2}, {0xa9, 2}, {0xaa, 4}, {0xab, 8}, - {0xfa, 2}, {0xfb, 5}, {0xfd, 4}, {0xfe, 3}, {0xff, 9}, - }; - static constexpr unsigned char singletons0_lower[] = { - 0xad, 0x78, 0x79, 0x8b, 0x8d, 0xa2, 0x30, 0x57, 0x58, 0x8b, 0x8c, 0x90, - 0x1c, 0x1d, 0xdd, 0x0e, 0x0f, 0x4b, 0x4c, 0xfb, 0xfc, 0x2e, 0x2f, 0x3f, - 0x5c, 0x5d, 0x5f, 0xb5, 0xe2, 0x84, 0x8d, 0x8e, 0x91, 0x92, 0xa9, 0xb1, - 0xba, 0xbb, 0xc5, 0xc6, 0xc9, 0xca, 0xde, 0xe4, 0xe5, 0xff, 0x00, 0x04, - 0x11, 0x12, 0x29, 0x31, 0x34, 0x37, 0x3a, 0x3b, 0x3d, 0x49, 0x4a, 0x5d, - 0x84, 0x8e, 0x92, 0xa9, 0xb1, 0xb4, 0xba, 0xbb, 0xc6, 0xca, 0xce, 0xcf, - 0xe4, 0xe5, 0x00, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, - 0x3b, 0x45, 0x46, 0x49, 0x4a, 0x5e, 0x64, 0x65, 0x84, 0x91, 0x9b, 0x9d, - 0xc9, 0xce, 0xcf, 0x0d, 0x11, 0x29, 0x45, 0x49, 0x57, 0x64, 0x65, 0x8d, - 0x91, 0xa9, 0xb4, 0xba, 0xbb, 0xc5, 0xc9, 0xdf, 0xe4, 0xe5, 0xf0, 0x0d, - 0x11, 0x45, 0x49, 0x64, 0x65, 0x80, 0x84, 0xb2, 0xbc, 0xbe, 0xbf, 0xd5, - 0xd7, 0xf0, 0xf1, 0x83, 0x85, 0x8b, 0xa4, 0xa6, 0xbe, 0xbf, 0xc5, 0xc7, - 0xce, 0xcf, 0xda, 0xdb, 0x48, 0x98, 0xbd, 0xcd, 0xc6, 0xce, 0xcf, 0x49, - 0x4e, 0x4f, 0x57, 0x59, 0x5e, 0x5f, 0x89, 0x8e, 0x8f, 0xb1, 0xb6, 0xb7, - 0xbf, 0xc1, 0xc6, 0xc7, 0xd7, 0x11, 0x16, 0x17, 0x5b, 0x5c, 0xf6, 0xf7, - 0xfe, 0xff, 0x80, 0x0d, 0x6d, 0x71, 0xde, 0xdf, 0x0e, 0x0f, 0x1f, 0x6e, - 0x6f, 0x1c, 0x1d, 0x5f, 0x7d, 0x7e, 0xae, 0xaf, 0xbb, 0xbc, 0xfa, 0x16, - 0x17, 0x1e, 0x1f, 0x46, 0x47, 0x4e, 0x4f, 0x58, 0x5a, 0x5c, 0x5e, 0x7e, - 0x7f, 0xb5, 0xc5, 0xd4, 0xd5, 0xdc, 0xf0, 0xf1, 0xf5, 0x72, 0x73, 0x8f, - 0x74, 0x75, 0x96, 0x2f, 0x5f, 0x26, 0x2e, 0x2f, 0xa7, 0xaf, 0xb7, 0xbf, - 0xc7, 0xcf, 0xd7, 0xdf, 0x9a, 0x40, 0x97, 0x98, 0x30, 0x8f, 0x1f, 0xc0, - 0xc1, 0xce, 0xff, 0x4e, 0x4f, 0x5a, 0x5b, 0x07, 0x08, 0x0f, 0x10, 0x27, - 0x2f, 0xee, 0xef, 0x6e, 0x6f, 0x37, 0x3d, 0x3f, 0x42, 0x45, 0x90, 0x91, - 0xfe, 0xff, 0x53, 0x67, 0x75, 0xc8, 0xc9, 0xd0, 0xd1, 0xd8, 0xd9, 0xe7, - 0xfe, 0xff, - }; - static constexpr singleton singletons1[] = { - {0x00, 6}, {0x01, 1}, {0x03, 1}, {0x04, 2}, {0x08, 8}, {0x09, 2}, - {0x0a, 5}, {0x0b, 2}, {0x0e, 4}, {0x10, 1}, {0x11, 2}, {0x12, 5}, - {0x13, 17}, {0x14, 1}, {0x15, 2}, {0x17, 2}, {0x19, 13}, {0x1c, 5}, - {0x1d, 8}, {0x24, 1}, {0x6a, 3}, {0x6b, 2}, {0xbc, 2}, {0xd1, 2}, - {0xd4, 12}, {0xd5, 9}, {0xd6, 2}, {0xd7, 2}, {0xda, 1}, {0xe0, 5}, - {0xe1, 2}, {0xe8, 2}, {0xee, 32}, {0xf0, 4}, {0xf8, 2}, {0xf9, 2}, - {0xfa, 2}, {0xfb, 1}, - }; - static constexpr unsigned char singletons1_lower[] = { - 0x0c, 0x27, 0x3b, 0x3e, 0x4e, 0x4f, 0x8f, 0x9e, 0x9e, 0x9f, 0x06, 0x07, - 0x09, 0x36, 0x3d, 0x3e, 0x56, 0xf3, 0xd0, 0xd1, 0x04, 0x14, 0x18, 0x36, - 0x37, 0x56, 0x57, 0x7f, 0xaa, 0xae, 0xaf, 0xbd, 0x35, 0xe0, 0x12, 0x87, - 0x89, 0x8e, 0x9e, 0x04, 0x0d, 0x0e, 0x11, 0x12, 0x29, 0x31, 0x34, 0x3a, - 0x45, 0x46, 0x49, 0x4a, 0x4e, 0x4f, 0x64, 0x65, 0x5c, 0xb6, 0xb7, 0x1b, - 0x1c, 0x07, 0x08, 0x0a, 0x0b, 0x14, 0x17, 0x36, 0x39, 0x3a, 0xa8, 0xa9, - 0xd8, 0xd9, 0x09, 0x37, 0x90, 0x91, 0xa8, 0x07, 0x0a, 0x3b, 0x3e, 0x66, - 0x69, 0x8f, 0x92, 0x6f, 0x5f, 0xee, 0xef, 0x5a, 0x62, 0x9a, 0x9b, 0x27, - 0x28, 0x55, 0x9d, 0xa0, 0xa1, 0xa3, 0xa4, 0xa7, 0xa8, 0xad, 0xba, 0xbc, - 0xc4, 0x06, 0x0b, 0x0c, 0x15, 0x1d, 0x3a, 0x3f, 0x45, 0x51, 0xa6, 0xa7, - 0xcc, 0xcd, 0xa0, 0x07, 0x19, 0x1a, 0x22, 0x25, 0x3e, 0x3f, 0xc5, 0xc6, - 0x04, 0x20, 0x23, 0x25, 0x26, 0x28, 0x33, 0x38, 0x3a, 0x48, 0x4a, 0x4c, - 0x50, 0x53, 0x55, 0x56, 0x58, 0x5a, 0x5c, 0x5e, 0x60, 0x63, 0x65, 0x66, - 0x6b, 0x73, 0x78, 0x7d, 0x7f, 0x8a, 0xa4, 0xaa, 0xaf, 0xb0, 0xc0, 0xd0, - 0xae, 0xaf, 0x79, 0xcc, 0x6e, 0x6f, 0x93, - }; - static constexpr unsigned char normal0[] = { - 0x00, 0x20, 0x5f, 0x22, 0x82, 0xdf, 0x04, 0x82, 0x44, 0x08, 0x1b, 0x04, - 0x06, 0x11, 0x81, 0xac, 0x0e, 0x80, 0xab, 0x35, 0x28, 0x0b, 0x80, 0xe0, - 0x03, 0x19, 0x08, 0x01, 0x04, 0x2f, 0x04, 0x34, 0x04, 0x07, 0x03, 0x01, - 0x07, 0x06, 0x07, 0x11, 0x0a, 0x50, 0x0f, 0x12, 0x07, 0x55, 0x07, 0x03, - 0x04, 0x1c, 0x0a, 0x09, 0x03, 0x08, 0x03, 0x07, 0x03, 0x02, 0x03, 0x03, - 0x03, 0x0c, 0x04, 0x05, 0x03, 0x0b, 0x06, 0x01, 0x0e, 0x15, 0x05, 0x3a, - 0x03, 0x11, 0x07, 0x06, 0x05, 0x10, 0x07, 0x57, 0x07, 0x02, 0x07, 0x15, - 0x0d, 0x50, 0x04, 0x43, 0x03, 0x2d, 0x03, 0x01, 0x04, 0x11, 0x06, 0x0f, - 0x0c, 0x3a, 0x04, 0x1d, 0x25, 0x5f, 0x20, 0x6d, 0x04, 0x6a, 0x25, 0x80, - 0xc8, 0x05, 0x82, 0xb0, 0x03, 0x1a, 0x06, 0x82, 0xfd, 0x03, 0x59, 0x07, - 0x15, 0x0b, 0x17, 0x09, 0x14, 0x0c, 0x14, 0x0c, 0x6a, 0x06, 0x0a, 0x06, - 0x1a, 0x06, 0x59, 0x07, 0x2b, 0x05, 0x46, 0x0a, 0x2c, 0x04, 0x0c, 0x04, - 0x01, 0x03, 0x31, 0x0b, 0x2c, 0x04, 0x1a, 0x06, 0x0b, 0x03, 0x80, 0xac, - 0x06, 0x0a, 0x06, 0x21, 0x3f, 0x4c, 0x04, 0x2d, 0x03, 0x74, 0x08, 0x3c, - 0x03, 0x0f, 0x03, 0x3c, 0x07, 0x38, 0x08, 0x2b, 0x05, 0x82, 0xff, 0x11, - 0x18, 0x08, 0x2f, 0x11, 0x2d, 0x03, 0x20, 0x10, 0x21, 0x0f, 0x80, 0x8c, - 0x04, 0x82, 0x97, 0x19, 0x0b, 0x15, 0x88, 0x94, 0x05, 0x2f, 0x05, 0x3b, - 0x07, 0x02, 0x0e, 0x18, 0x09, 0x80, 0xb3, 0x2d, 0x74, 0x0c, 0x80, 0xd6, - 0x1a, 0x0c, 0x05, 0x80, 0xff, 0x05, 0x80, 0xdf, 0x0c, 0xee, 0x0d, 0x03, - 0x84, 0x8d, 0x03, 0x37, 0x09, 0x81, 0x5c, 0x14, 0x80, 0xb8, 0x08, 0x80, - 0xcb, 0x2a, 0x38, 0x03, 0x0a, 0x06, 0x38, 0x08, 0x46, 0x08, 0x0c, 0x06, - 0x74, 0x0b, 0x1e, 0x03, 0x5a, 0x04, 0x59, 0x09, 0x80, 0x83, 0x18, 0x1c, - 0x0a, 0x16, 0x09, 0x4c, 0x04, 0x80, 0x8a, 0x06, 0xab, 0xa4, 0x0c, 0x17, - 0x04, 0x31, 0xa1, 0x04, 0x81, 0xda, 0x26, 0x07, 0x0c, 0x05, 0x05, 0x80, - 0xa5, 0x11, 0x81, 0x6d, 0x10, 0x78, 0x28, 0x2a, 0x06, 0x4c, 0x04, 0x80, - 0x8d, 0x04, 0x80, 0xbe, 0x03, 0x1b, 0x03, 0x0f, 0x0d, - }; - static constexpr unsigned char normal1[] = { - 0x5e, 0x22, 0x7b, 0x05, 0x03, 0x04, 0x2d, 0x03, 0x66, 0x03, 0x01, 0x2f, - 0x2e, 0x80, 0x82, 0x1d, 0x03, 0x31, 0x0f, 0x1c, 0x04, 0x24, 0x09, 0x1e, - 0x05, 0x2b, 0x05, 0x44, 0x04, 0x0e, 0x2a, 0x80, 0xaa, 0x06, 0x24, 0x04, - 0x24, 0x04, 0x28, 0x08, 0x34, 0x0b, 0x01, 0x80, 0x90, 0x81, 0x37, 0x09, - 0x16, 0x0a, 0x08, 0x80, 0x98, 0x39, 0x03, 0x63, 0x08, 0x09, 0x30, 0x16, - 0x05, 0x21, 0x03, 0x1b, 0x05, 0x01, 0x40, 0x38, 0x04, 0x4b, 0x05, 0x2f, - 0x04, 0x0a, 0x07, 0x09, 0x07, 0x40, 0x20, 0x27, 0x04, 0x0c, 0x09, 0x36, - 0x03, 0x3a, 0x05, 0x1a, 0x07, 0x04, 0x0c, 0x07, 0x50, 0x49, 0x37, 0x33, - 0x0d, 0x33, 0x07, 0x2e, 0x08, 0x0a, 0x81, 0x26, 0x52, 0x4e, 0x28, 0x08, - 0x2a, 0x56, 0x1c, 0x14, 0x17, 0x09, 0x4e, 0x04, 0x1e, 0x0f, 0x43, 0x0e, - 0x19, 0x07, 0x0a, 0x06, 0x48, 0x08, 0x27, 0x09, 0x75, 0x0b, 0x3f, 0x41, - 0x2a, 0x06, 0x3b, 0x05, 0x0a, 0x06, 0x51, 0x06, 0x01, 0x05, 0x10, 0x03, - 0x05, 0x80, 0x8b, 0x62, 0x1e, 0x48, 0x08, 0x0a, 0x80, 0xa6, 0x5e, 0x22, - 0x45, 0x0b, 0x0a, 0x06, 0x0d, 0x13, 0x39, 0x07, 0x0a, 0x36, 0x2c, 0x04, - 0x10, 0x80, 0xc0, 0x3c, 0x64, 0x53, 0x0c, 0x48, 0x09, 0x0a, 0x46, 0x45, - 0x1b, 0x48, 0x08, 0x53, 0x1d, 0x39, 0x81, 0x07, 0x46, 0x0a, 0x1d, 0x03, - 0x47, 0x49, 0x37, 0x03, 0x0e, 0x08, 0x0a, 0x06, 0x39, 0x07, 0x0a, 0x81, - 0x36, 0x19, 0x80, 0xb7, 0x01, 0x0f, 0x32, 0x0d, 0x83, 0x9b, 0x66, 0x75, - 0x0b, 0x80, 0xc4, 0x8a, 0xbc, 0x84, 0x2f, 0x8f, 0xd1, 0x82, 0x47, 0xa1, - 0xb9, 0x82, 0x39, 0x07, 0x2a, 0x04, 0x02, 0x60, 0x26, 0x0a, 0x46, 0x0a, - 0x28, 0x05, 0x13, 0x82, 0xb0, 0x5b, 0x65, 0x4b, 0x04, 0x39, 0x07, 0x11, - 0x40, 0x05, 0x0b, 0x02, 0x0e, 0x97, 0xf8, 0x08, 0x84, 0xd6, 0x2a, 0x09, - 0xa2, 0xf7, 0x81, 0x1f, 0x31, 0x03, 0x11, 0x04, 0x08, 0x81, 0x8c, 0x89, - 0x04, 0x6b, 0x05, 0x0d, 0x03, 0x09, 0x07, 0x10, 0x93, 0x60, 0x80, 0xf6, - 0x0a, 0x73, 0x08, 0x6e, 0x17, 0x46, 0x80, 0x9a, 0x14, 0x0c, 0x57, 0x09, - 0x19, 0x80, 0x87, 0x81, 0x47, 0x03, 0x85, 0x42, 0x0f, 0x15, 0x85, 0x50, - 0x2b, 0x80, 0xd5, 0x2d, 0x03, 0x1a, 0x04, 0x02, 0x81, 0x70, 0x3a, 0x05, - 0x01, 0x85, 0x00, 0x80, 0xd7, 0x29, 0x4c, 0x04, 0x0a, 0x04, 0x02, 0x83, - 0x11, 0x44, 0x4c, 0x3d, 0x80, 0xc2, 0x3c, 0x06, 0x01, 0x04, 0x55, 0x05, - 0x1b, 0x34, 0x02, 0x81, 0x0e, 0x2c, 0x04, 0x64, 0x0c, 0x56, 0x0a, 0x80, - 0xae, 0x38, 0x1d, 0x0d, 0x2c, 0x04, 0x09, 0x07, 0x02, 0x0e, 0x06, 0x80, - 0x9a, 0x83, 0xd8, 0x08, 0x0d, 0x03, 0x0d, 0x03, 0x74, 0x0c, 0x59, 0x07, - 0x0c, 0x14, 0x0c, 0x04, 0x38, 0x08, 0x0a, 0x06, 0x28, 0x08, 0x22, 0x4e, - 0x81, 0x54, 0x0c, 0x15, 0x03, 0x03, 0x05, 0x07, 0x09, 0x19, 0x07, 0x07, - 0x09, 0x03, 0x0d, 0x07, 0x29, 0x80, 0xcb, 0x25, 0x0a, 0x84, 0x06, - }; - auto lower = static_cast(cp); - if (cp < 0x10000) { - return is_printable(lower, singletons0, - sizeof(singletons0) / sizeof(*singletons0), - singletons0_lower, normal0, sizeof(normal0)); - } - if (cp < 0x20000) { - return is_printable(lower, singletons1, - sizeof(singletons1) / sizeof(*singletons1), - singletons1_lower, normal1, sizeof(normal1)); - } - if (0x2a6de <= cp && cp < 0x2a700) return false; - if (0x2b735 <= cp && cp < 0x2b740) return false; - if (0x2b81e <= cp && cp < 0x2b820) return false; - if (0x2cea2 <= cp && cp < 0x2ceb0) return false; - if (0x2ebe1 <= cp && cp < 0x2f800) return false; - if (0x2fa1e <= cp && cp < 0x30000) return false; - if (0x3134b <= cp && cp < 0xe0100) return false; - if (0xe01f0 <= cp && cp < 0x110000) return false; - return cp < 0x110000; -} - -} // namespace detail - -FMT_END_NAMESPACE - -#endif // FMT_FORMAT_INL_H_ diff --git a/src/common/dep/fmt/format.cc b/src/common/dep/fmt/format.cc deleted file mode 100644 index 391d3a248..000000000 --- a/src/common/dep/fmt/format.cc +++ /dev/null @@ -1,43 +0,0 @@ -// Formatting library for C++ -// -// Copyright (c) 2012 - 2016, Victor Zverovich -// All rights reserved. -// -// For the license information refer to format.h. - -#include "fmt/format-inl.h" - -FMT_BEGIN_NAMESPACE -namespace detail { - -template FMT_API auto dragonbox::to_decimal(float x) noexcept - -> dragonbox::decimal_fp; -template FMT_API auto dragonbox::to_decimal(double x) noexcept - -> dragonbox::decimal_fp; - -#ifndef FMT_STATIC_THOUSANDS_SEPARATOR -template FMT_API locale_ref::locale_ref(const std::locale& loc); -template FMT_API auto locale_ref::get() const -> std::locale; -#endif - -// Explicit instantiations for char. - -template FMT_API auto thousands_sep_impl(locale_ref) - -> thousands_sep_result; -template FMT_API auto decimal_point_impl(locale_ref) -> char; - -template FMT_API void buffer::append(const char*, const char*); - -template FMT_API void vformat_to(buffer&, string_view, - typename vformat_args<>::type, locale_ref); - -// Explicit instantiations for wchar_t. - -template FMT_API auto thousands_sep_impl(locale_ref) - -> thousands_sep_result; -template FMT_API auto decimal_point_impl(locale_ref) -> wchar_t; - -template FMT_API void buffer::append(const wchar_t*, const wchar_t*); - -} // namespace detail -FMT_END_NAMESPACE diff --git a/src/common/dep/fmt/format.h b/src/common/dep/fmt/format.h deleted file mode 100644 index 87a34b972..000000000 --- a/src/common/dep/fmt/format.h +++ /dev/null @@ -1,4510 +0,0 @@ -/* - Formatting library for C++ - - Copyright (c) 2012 - present, Victor Zverovich - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - --- Optional exception to the license --- - - As an exception, if, as a result of your compiling your source code, portions - of this Software are embedded into a machine-executable object form of such - source code, you may redistribute such embedded portions in such object form - without including the above copyright and permission notices. - */ - -#ifndef FMT_FORMAT_H_ -#define FMT_FORMAT_H_ - -#include // std::signbit -#include // uint32_t -#include // std::memcpy -#include // std::initializer_list -#include // std::numeric_limits -#include // std::uninitialized_copy -#include // std::runtime_error -#include // std::system_error - -#ifdef __cpp_lib_bit_cast -# include // std::bitcast -#endif - -#include "core.h" - -#if defined __cpp_inline_variables && __cpp_inline_variables >= 201606L -# define FMT_INLINE_VARIABLE inline -#else -# define FMT_INLINE_VARIABLE -#endif - -#if FMT_HAS_CPP17_ATTRIBUTE(fallthrough) -# define FMT_FALLTHROUGH [[fallthrough]] -#elif defined(__clang__) -# define FMT_FALLTHROUGH [[clang::fallthrough]] -#elif FMT_GCC_VERSION >= 700 && \ - (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= 520) -# define FMT_FALLTHROUGH [[gnu::fallthrough]] -#else -# define FMT_FALLTHROUGH -#endif - -#ifndef FMT_DEPRECATED -# if FMT_HAS_CPP14_ATTRIBUTE(deprecated) || FMT_MSC_VERSION >= 1900 -# define FMT_DEPRECATED [[deprecated]] -# else -# if (defined(__GNUC__) && !defined(__LCC__)) || defined(__clang__) -# define FMT_DEPRECATED __attribute__((deprecated)) -# elif FMT_MSC_VERSION -# define FMT_DEPRECATED __declspec(deprecated) -# else -# define FMT_DEPRECATED /* deprecated */ -# endif -# endif -#endif - -#ifndef FMT_NO_UNIQUE_ADDRESS -# if FMT_CPLUSPLUS >= 202002L -# if FMT_HAS_CPP_ATTRIBUTE(no_unique_address) -# define FMT_NO_UNIQUE_ADDRESS [[no_unique_address]] -// VS2019 v16.10 and later except clang-cl (https://reviews.llvm.org/D110485) -# elif (FMT_MSC_VERSION >= 1929) && !FMT_CLANG_VERSION -# define FMT_NO_UNIQUE_ADDRESS [[msvc::no_unique_address]] -# endif -# endif -#endif -#ifndef FMT_NO_UNIQUE_ADDRESS -# define FMT_NO_UNIQUE_ADDRESS -#endif - -#if FMT_GCC_VERSION || defined(__clang__) -# define FMT_VISIBILITY(value) __attribute__((visibility(value))) -#else -# define FMT_VISIBILITY(value) -#endif - -#ifdef __has_builtin -# define FMT_HAS_BUILTIN(x) __has_builtin(x) -#else -# define FMT_HAS_BUILTIN(x) 0 -#endif - -#if FMT_GCC_VERSION || FMT_CLANG_VERSION -# define FMT_NOINLINE __attribute__((noinline)) -#else -# define FMT_NOINLINE -#endif - -#ifndef FMT_THROW -# if FMT_EXCEPTIONS -# if FMT_MSC_VERSION || defined(__NVCC__) -FMT_BEGIN_NAMESPACE -namespace detail { -template inline void do_throw(const Exception& x) { - // Silence unreachable code warnings in MSVC and NVCC because these - // are nearly impossible to fix in a generic code. - volatile bool b = true; - if (b) throw x; -} -} // namespace detail -FMT_END_NAMESPACE -# define FMT_THROW(x) detail::do_throw(x) -# else -# define FMT_THROW(x) throw x -# endif -# else -# define FMT_THROW(x) \ - ::fmt::detail::assert_fail(__FILE__, __LINE__, (x).what()) -# endif -#endif - -#if FMT_EXCEPTIONS -# define FMT_TRY try -# define FMT_CATCH(x) catch (x) -#else -# define FMT_TRY if (true) -# define FMT_CATCH(x) if (false) -#endif - -#ifndef FMT_MAYBE_UNUSED -# if FMT_HAS_CPP17_ATTRIBUTE(maybe_unused) -# define FMT_MAYBE_UNUSED [[maybe_unused]] -# else -# define FMT_MAYBE_UNUSED -# endif -#endif - -#ifndef FMT_USE_USER_DEFINED_LITERALS -// EDG based compilers (Intel, NVIDIA, Elbrus, etc), GCC and MSVC support UDLs. -# if (FMT_HAS_FEATURE(cxx_user_literals) || FMT_GCC_VERSION >= 407 || \ - FMT_MSC_VERSION >= 1900) && \ - (!defined(__EDG_VERSION__) || __EDG_VERSION__ >= /* UDL feature */ 480) -# define FMT_USE_USER_DEFINED_LITERALS 1 -# else -# define FMT_USE_USER_DEFINED_LITERALS 0 -# endif -#endif - -// Defining FMT_REDUCE_INT_INSTANTIATIONS to 1, will reduce the number of -// integer formatter template instantiations to just one by only using the -// largest integer type. This results in a reduction in binary size but will -// cause a decrease in integer formatting performance. -#if !defined(FMT_REDUCE_INT_INSTANTIATIONS) -# define FMT_REDUCE_INT_INSTANTIATIONS 0 -#endif - -// __builtin_clz is broken in clang with Microsoft CodeGen: -// https://github.com/fmtlib/fmt/issues/519. -#if !FMT_MSC_VERSION -# if FMT_HAS_BUILTIN(__builtin_clz) || FMT_GCC_VERSION || FMT_ICC_VERSION -# define FMT_BUILTIN_CLZ(n) __builtin_clz(n) -# endif -# if FMT_HAS_BUILTIN(__builtin_clzll) || FMT_GCC_VERSION || FMT_ICC_VERSION -# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) -# endif -#endif - -// __builtin_ctz is broken in Intel Compiler Classic on Windows: -// https://github.com/fmtlib/fmt/issues/2510. -#ifndef __ICL -# if FMT_HAS_BUILTIN(__builtin_ctz) || FMT_GCC_VERSION || FMT_ICC_VERSION || \ - defined(__NVCOMPILER) -# define FMT_BUILTIN_CTZ(n) __builtin_ctz(n) -# endif -# if FMT_HAS_BUILTIN(__builtin_ctzll) || FMT_GCC_VERSION || \ - FMT_ICC_VERSION || defined(__NVCOMPILER) -# define FMT_BUILTIN_CTZLL(n) __builtin_ctzll(n) -# endif -#endif - -#if FMT_MSC_VERSION -# include // _BitScanReverse[64], _BitScanForward[64], _umul128 -#endif - -// Some compilers masquerade as both MSVC and GCC-likes or otherwise support -// __builtin_clz and __builtin_clzll, so only define FMT_BUILTIN_CLZ using the -// MSVC intrinsics if the clz and clzll builtins are not available. -#if FMT_MSC_VERSION && !defined(FMT_BUILTIN_CLZLL) && \ - !defined(FMT_BUILTIN_CTZLL) -FMT_BEGIN_NAMESPACE -namespace detail { -// Avoid Clang with Microsoft CodeGen's -Wunknown-pragmas warning. -# if !defined(__clang__) -# pragma intrinsic(_BitScanForward) -# pragma intrinsic(_BitScanReverse) -# if defined(_WIN64) -# pragma intrinsic(_BitScanForward64) -# pragma intrinsic(_BitScanReverse64) -# endif -# endif - -inline auto clz(uint32_t x) -> int { - unsigned long r = 0; - _BitScanReverse(&r, x); - FMT_ASSERT(x != 0, ""); - // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, - // which the callers guarantee to not happen. - FMT_MSC_WARNING(suppress : 6102) - return 31 ^ static_cast(r); -} -# define FMT_BUILTIN_CLZ(n) detail::clz(n) - -inline auto clzll(uint64_t x) -> int { - unsigned long r = 0; -# ifdef _WIN64 - _BitScanReverse64(&r, x); -# else - // Scan the high 32 bits. - if (_BitScanReverse(&r, static_cast(x >> 32))) - return 63 ^ static_cast(r + 32); - // Scan the low 32 bits. - _BitScanReverse(&r, static_cast(x)); -# endif - FMT_ASSERT(x != 0, ""); - FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. - return 63 ^ static_cast(r); -} -# define FMT_BUILTIN_CLZLL(n) detail::clzll(n) - -inline auto ctz(uint32_t x) -> int { - unsigned long r = 0; - _BitScanForward(&r, x); - FMT_ASSERT(x != 0, ""); - FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. - return static_cast(r); -} -# define FMT_BUILTIN_CTZ(n) detail::ctz(n) - -inline auto ctzll(uint64_t x) -> int { - unsigned long r = 0; - FMT_ASSERT(x != 0, ""); - FMT_MSC_WARNING(suppress : 6102) // Suppress a bogus static analysis warning. -# ifdef _WIN64 - _BitScanForward64(&r, x); -# else - // Scan the low 32 bits. - if (_BitScanForward(&r, static_cast(x))) return static_cast(r); - // Scan the high 32 bits. - _BitScanForward(&r, static_cast(x >> 32)); - r += 32; -# endif - return static_cast(r); -} -# define FMT_BUILTIN_CTZLL(n) detail::ctzll(n) -} // namespace detail -FMT_END_NAMESPACE -#endif - -FMT_BEGIN_NAMESPACE - -template struct disjunction : std::false_type {}; -template struct disjunction

: P {}; -template -struct disjunction - : conditional_t> {}; - -template struct conjunction : std::true_type {}; -template struct conjunction

: P {}; -template -struct conjunction - : conditional_t, P1> {}; - -namespace detail { - -FMT_CONSTEXPR inline void abort_fuzzing_if(bool condition) { - ignore_unused(condition); -#ifdef FMT_FUZZ - if (condition) throw std::runtime_error("fuzzing limit reached"); -#endif -} - -template struct string_literal { - static constexpr CharT value[sizeof...(C)] = {C...}; - constexpr operator basic_string_view() const { - return {value, sizeof...(C)}; - } -}; - -#if FMT_CPLUSPLUS < 201703L -template -constexpr CharT string_literal::value[sizeof...(C)]; -#endif - -template class formatbuf : public Streambuf { - private: - using char_type = typename Streambuf::char_type; - using streamsize = decltype(std::declval().sputn(nullptr, 0)); - using int_type = typename Streambuf::int_type; - using traits_type = typename Streambuf::traits_type; - - buffer& buffer_; - - public: - explicit formatbuf(buffer& buf) : buffer_(buf) {} - - protected: - // The put area is always empty. This makes the implementation simpler and has - // the advantage that the streambuf and the buffer are always in sync and - // sputc never writes into uninitialized memory. A disadvantage is that each - // call to sputc always results in a (virtual) call to overflow. There is no - // disadvantage here for sputn since this always results in a call to xsputn. - - auto overflow(int_type ch) -> int_type override { - if (!traits_type::eq_int_type(ch, traits_type::eof())) - buffer_.push_back(static_cast(ch)); - return ch; - } - - auto xsputn(const char_type* s, streamsize count) -> streamsize override { - buffer_.append(s, s + count); - return count; - } -}; - -// Implementation of std::bit_cast for pre-C++20. -template -FMT_CONSTEXPR20 auto bit_cast(const From& from) -> To { -#ifdef __cpp_lib_bit_cast - if (is_constant_evaluated()) return std::bit_cast(from); -#endif - auto to = To(); - // The cast suppresses a bogus -Wclass-memaccess on GCC. - std::memcpy(static_cast(&to), &from, sizeof(to)); - return to; -} - -inline auto is_big_endian() -> bool { -#ifdef _WIN32 - return false; -#elif defined(__BIG_ENDIAN__) - return true; -#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) - return __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__; -#else - struct bytes { - char data[sizeof(int)]; - }; - return bit_cast(1).data[0] == 0; -#endif -} - -class uint128_fallback { - private: - uint64_t lo_, hi_; - - public: - constexpr uint128_fallback(uint64_t hi, uint64_t lo) : lo_(lo), hi_(hi) {} - constexpr uint128_fallback(uint64_t value = 0) : lo_(value), hi_(0) {} - - constexpr uint64_t high() const noexcept { return hi_; } - constexpr uint64_t low() const noexcept { return lo_; } - - template ::value)> - constexpr explicit operator T() const { - return static_cast(lo_); - } - - friend constexpr auto operator==(const uint128_fallback& lhs, - const uint128_fallback& rhs) -> bool { - return lhs.hi_ == rhs.hi_ && lhs.lo_ == rhs.lo_; - } - friend constexpr auto operator!=(const uint128_fallback& lhs, - const uint128_fallback& rhs) -> bool { - return !(lhs == rhs); - } - friend constexpr auto operator>(const uint128_fallback& lhs, - const uint128_fallback& rhs) -> bool { - return lhs.hi_ != rhs.hi_ ? lhs.hi_ > rhs.hi_ : lhs.lo_ > rhs.lo_; - } - friend constexpr auto operator|(const uint128_fallback& lhs, - const uint128_fallback& rhs) - -> uint128_fallback { - return {lhs.hi_ | rhs.hi_, lhs.lo_ | rhs.lo_}; - } - friend constexpr auto operator&(const uint128_fallback& lhs, - const uint128_fallback& rhs) - -> uint128_fallback { - return {lhs.hi_ & rhs.hi_, lhs.lo_ & rhs.lo_}; - } - friend constexpr auto operator~(const uint128_fallback& n) - -> uint128_fallback { - return {~n.hi_, ~n.lo_}; - } - friend auto operator+(const uint128_fallback& lhs, - const uint128_fallback& rhs) -> uint128_fallback { - auto result = uint128_fallback(lhs); - result += rhs; - return result; - } - friend auto operator*(const uint128_fallback& lhs, uint32_t rhs) - -> uint128_fallback { - FMT_ASSERT(lhs.hi_ == 0, ""); - uint64_t hi = (lhs.lo_ >> 32) * rhs; - uint64_t lo = (lhs.lo_ & ~uint32_t()) * rhs; - uint64_t new_lo = (hi << 32) + lo; - return {(hi >> 32) + (new_lo < lo ? 1 : 0), new_lo}; - } - friend auto operator-(const uint128_fallback& lhs, uint64_t rhs) - -> uint128_fallback { - return {lhs.hi_ - (lhs.lo_ < rhs ? 1 : 0), lhs.lo_ - rhs}; - } - FMT_CONSTEXPR auto operator>>(int shift) const -> uint128_fallback { - if (shift == 64) return {0, hi_}; - if (shift > 64) return uint128_fallback(0, hi_) >> (shift - 64); - return {hi_ >> shift, (hi_ << (64 - shift)) | (lo_ >> shift)}; - } - FMT_CONSTEXPR auto operator<<(int shift) const -> uint128_fallback { - if (shift == 64) return {lo_, 0}; - if (shift > 64) return uint128_fallback(lo_, 0) << (shift - 64); - return {hi_ << shift | (lo_ >> (64 - shift)), (lo_ << shift)}; - } - FMT_CONSTEXPR auto operator>>=(int shift) -> uint128_fallback& { - return *this = *this >> shift; - } - FMT_CONSTEXPR void operator+=(uint128_fallback n) { - uint64_t new_lo = lo_ + n.lo_; - uint64_t new_hi = hi_ + n.hi_ + (new_lo < lo_ ? 1 : 0); - FMT_ASSERT(new_hi >= hi_, ""); - lo_ = new_lo; - hi_ = new_hi; - } - FMT_CONSTEXPR void operator&=(uint128_fallback n) { - lo_ &= n.lo_; - hi_ &= n.hi_; - } - - FMT_CONSTEXPR20 uint128_fallback& operator+=(uint64_t n) noexcept { - if (is_constant_evaluated()) { - lo_ += n; - hi_ += (lo_ < n ? 1 : 0); - return *this; - } -#if FMT_HAS_BUILTIN(__builtin_addcll) && !defined(__ibmxl__) - unsigned long long carry; - lo_ = __builtin_addcll(lo_, n, 0, &carry); - hi_ += carry; -#elif FMT_HAS_BUILTIN(__builtin_ia32_addcarryx_u64) && !defined(__ibmxl__) - unsigned long long result; - auto carry = __builtin_ia32_addcarryx_u64(0, lo_, n, &result); - lo_ = result; - hi_ += carry; -#elif defined(_MSC_VER) && defined(_M_X64) - auto carry = _addcarry_u64(0, lo_, n, &lo_); - _addcarry_u64(carry, hi_, 0, &hi_); -#else - lo_ += n; - hi_ += (lo_ < n ? 1 : 0); -#endif - return *this; - } -}; - -using uint128_t = conditional_t; - -#ifdef UINTPTR_MAX -using uintptr_t = ::uintptr_t; -#else -using uintptr_t = uint128_t; -#endif - -// Returns the largest possible value for type T. Same as -// std::numeric_limits::max() but shorter and not affected by the max macro. -template constexpr auto max_value() -> T { - return (std::numeric_limits::max)(); -} -template constexpr auto num_bits() -> int { - return std::numeric_limits::digits; -} -// std::numeric_limits::digits may return 0 for 128-bit ints. -template <> constexpr auto num_bits() -> int { return 128; } -template <> constexpr auto num_bits() -> int { return 128; } - -// A heterogeneous bit_cast used for converting 96-bit long double to uint128_t -// and 128-bit pointers to uint128_fallback. -template sizeof(From))> -inline auto bit_cast(const From& from) -> To { - constexpr auto size = static_cast(sizeof(From) / sizeof(unsigned)); - struct data_t { - unsigned value[static_cast(size)]; - } data = bit_cast(from); - auto result = To(); - if (const_check(is_big_endian())) { - for (int i = 0; i < size; ++i) - result = (result << num_bits()) | data.value[i]; - } else { - for (int i = size - 1; i >= 0; --i) - result = (result << num_bits()) | data.value[i]; - } - return result; -} - -template -FMT_CONSTEXPR20 inline auto countl_zero_fallback(UInt n) -> int { - int lz = 0; - constexpr UInt msb_mask = static_cast(1) << (num_bits() - 1); - for (; (n & msb_mask) == 0; n <<= 1) lz++; - return lz; -} - -FMT_CONSTEXPR20 inline auto countl_zero(uint32_t n) -> int { -#ifdef FMT_BUILTIN_CLZ - if (!is_constant_evaluated()) return FMT_BUILTIN_CLZ(n); -#endif - return countl_zero_fallback(n); -} - -FMT_CONSTEXPR20 inline auto countl_zero(uint64_t n) -> int { -#ifdef FMT_BUILTIN_CLZLL - if (!is_constant_evaluated()) return FMT_BUILTIN_CLZLL(n); -#endif - return countl_zero_fallback(n); -} - -FMT_INLINE void assume(bool condition) { - (void)condition; -#if FMT_HAS_BUILTIN(__builtin_assume) && !FMT_ICC_VERSION - __builtin_assume(condition); -#elif FMT_GCC_VERSION - if (!condition) __builtin_unreachable(); -#endif -} - -// An approximation of iterator_t for pre-C++20 systems. -template -using iterator_t = decltype(std::begin(std::declval())); -template using sentinel_t = decltype(std::end(std::declval())); - -// A workaround for std::string not having mutable data() until C++17. -template -inline auto get_data(std::basic_string& s) -> Char* { - return &s[0]; -} -template -inline auto get_data(Container& c) -> typename Container::value_type* { - return c.data(); -} - -// Attempts to reserve space for n extra characters in the output range. -// Returns a pointer to the reserved range or a reference to it. -template ::value)> -#if FMT_CLANG_VERSION >= 307 && !FMT_ICC_VERSION -__attribute__((no_sanitize("undefined"))) -#endif -inline auto -reserve(std::back_insert_iterator it, size_t n) -> - typename Container::value_type* { - Container& c = get_container(it); - size_t size = c.size(); - c.resize(size + n); - return get_data(c) + size; -} - -template -inline auto reserve(buffer_appender it, size_t n) -> buffer_appender { - buffer& buf = get_container(it); - buf.try_reserve(buf.size() + n); - return it; -} - -template -constexpr auto reserve(Iterator& it, size_t) -> Iterator& { - return it; -} - -template -using reserve_iterator = - remove_reference_t(), 0))>; - -template -constexpr auto to_pointer(OutputIt, size_t) -> T* { - return nullptr; -} -template auto to_pointer(buffer_appender it, size_t n) -> T* { - buffer& buf = get_container(it); - auto size = buf.size(); - if (buf.capacity() < size + n) return nullptr; - buf.try_resize(size + n); - return buf.data() + size; -} - -template ::value)> -inline auto base_iterator(std::back_insert_iterator it, - typename Container::value_type*) - -> std::back_insert_iterator { - return it; -} - -template -constexpr auto base_iterator(Iterator, Iterator it) -> Iterator { - return it; -} - -// is spectacularly slow to compile in C++20 so use a simple fill_n -// instead (#1998). -template -FMT_CONSTEXPR auto fill_n(OutputIt out, Size count, const T& value) - -> OutputIt { - for (Size i = 0; i < count; ++i) *out++ = value; - return out; -} -template -FMT_CONSTEXPR20 auto fill_n(T* out, Size count, char value) -> T* { - if (is_constant_evaluated()) { - return fill_n(out, count, value); - } - std::memset(out, value, to_unsigned(count)); - return out + count; -} - -#ifdef __cpp_char8_t -using char8_type = char8_t; -#else -enum char8_type : unsigned char {}; -#endif - -template -FMT_CONSTEXPR FMT_NOINLINE auto copy_str_noinline(InputIt begin, InputIt end, - OutputIt out) -> OutputIt { - return copy_str(begin, end, out); -} - -// A public domain branchless UTF-8 decoder by Christopher Wellons: -// https://github.com/skeeto/branchless-utf8 -/* Decode the next character, c, from s, reporting errors in e. - * - * Since this is a branchless decoder, four bytes will be read from the - * buffer regardless of the actual length of the next character. This - * means the buffer _must_ have at least three bytes of zero padding - * following the end of the data stream. - * - * Errors are reported in e, which will be non-zero if the parsed - * character was somehow invalid: invalid byte sequence, non-canonical - * encoding, or a surrogate half. - * - * The function returns a pointer to the next character. When an error - * occurs, this pointer will be a guess that depends on the particular - * error, but it will always advance at least one byte. - */ -FMT_CONSTEXPR inline auto utf8_decode(const char* s, uint32_t* c, int* e) - -> const char* { - constexpr const int masks[] = {0x00, 0x7f, 0x1f, 0x0f, 0x07}; - constexpr const uint32_t mins[] = {4194304, 0, 128, 2048, 65536}; - constexpr const int shiftc[] = {0, 18, 12, 6, 0}; - constexpr const int shifte[] = {0, 6, 4, 2, 0}; - - int len = "\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\0\0\0\0\0\0\0\0\2\2\2\2\3\3\4" - [static_cast(*s) >> 3]; - // Compute the pointer to the next character early so that the next - // iteration can start working on the next character. Neither Clang - // nor GCC figure out this reordering on their own. - const char* next = s + len + !len; - - using uchar = unsigned char; - - // Assume a four-byte character and load four bytes. Unused bits are - // shifted out. - *c = uint32_t(uchar(s[0]) & masks[len]) << 18; - *c |= uint32_t(uchar(s[1]) & 0x3f) << 12; - *c |= uint32_t(uchar(s[2]) & 0x3f) << 6; - *c |= uint32_t(uchar(s[3]) & 0x3f) << 0; - *c >>= shiftc[len]; - - // Accumulate the various error conditions. - *e = (*c < mins[len]) << 6; // non-canonical encoding - *e |= ((*c >> 11) == 0x1b) << 7; // surrogate half? - *e |= (*c > 0x10FFFF) << 8; // out of range? - *e |= (uchar(s[1]) & 0xc0) >> 2; - *e |= (uchar(s[2]) & 0xc0) >> 4; - *e |= uchar(s[3]) >> 6; - *e ^= 0x2a; // top two bits of each tail byte correct? - *e >>= shifte[len]; - - return next; -} - -constexpr FMT_INLINE_VARIABLE uint32_t invalid_code_point = ~uint32_t(); - -// Invokes f(cp, sv) for every code point cp in s with sv being the string view -// corresponding to the code point. cp is invalid_code_point on error. -template -FMT_CONSTEXPR void for_each_codepoint(string_view s, F f) { - auto decode = [f](const char* buf_ptr, const char* ptr) { - auto cp = uint32_t(); - auto error = 0; - auto end = utf8_decode(buf_ptr, &cp, &error); - bool result = f(error ? invalid_code_point : cp, - string_view(ptr, error ? 1 : to_unsigned(end - buf_ptr))); - return result ? (error ? buf_ptr + 1 : end) : nullptr; - }; - auto p = s.data(); - const size_t block_size = 4; // utf8_decode always reads blocks of 4 chars. - if (s.size() >= block_size) { - for (auto end = p + s.size() - block_size + 1; p < end;) { - p = decode(p, p); - if (!p) return; - } - } - if (auto num_chars_left = s.data() + s.size() - p) { - char buf[2 * block_size - 1] = {}; - copy_str(p, p + num_chars_left, buf); - const char* buf_ptr = buf; - do { - auto end = decode(buf_ptr, p); - if (!end) return; - p += end - buf_ptr; - buf_ptr = end; - } while (buf_ptr - buf < num_chars_left); - } -} - -template -inline auto compute_width(basic_string_view s) -> size_t { - return s.size(); -} - -// Computes approximate display width of a UTF-8 string. -FMT_CONSTEXPR inline size_t compute_width(string_view s) { - size_t num_code_points = 0; - // It is not a lambda for compatibility with C++14. - struct count_code_points { - size_t* count; - FMT_CONSTEXPR auto operator()(uint32_t cp, string_view) const -> bool { - *count += detail::to_unsigned( - 1 + - (cp >= 0x1100 && - (cp <= 0x115f || // Hangul Jamo init. consonants - cp == 0x2329 || // LEFT-POINTING ANGLE BRACKET - cp == 0x232a || // RIGHT-POINTING ANGLE BRACKET - // CJK ... Yi except IDEOGRAPHIC HALF FILL SPACE: - (cp >= 0x2e80 && cp <= 0xa4cf && cp != 0x303f) || - (cp >= 0xac00 && cp <= 0xd7a3) || // Hangul Syllables - (cp >= 0xf900 && cp <= 0xfaff) || // CJK Compatibility Ideographs - (cp >= 0xfe10 && cp <= 0xfe19) || // Vertical Forms - (cp >= 0xfe30 && cp <= 0xfe6f) || // CJK Compatibility Forms - (cp >= 0xff00 && cp <= 0xff60) || // Fullwidth Forms - (cp >= 0xffe0 && cp <= 0xffe6) || // Fullwidth Forms - (cp >= 0x20000 && cp <= 0x2fffd) || // CJK - (cp >= 0x30000 && cp <= 0x3fffd) || - // Miscellaneous Symbols and Pictographs + Emoticons: - (cp >= 0x1f300 && cp <= 0x1f64f) || - // Supplemental Symbols and Pictographs: - (cp >= 0x1f900 && cp <= 0x1f9ff)))); - return true; - } - }; - // We could avoid branches by using utf8_decode directly. - for_each_codepoint(s, count_code_points{&num_code_points}); - return num_code_points; -} - -inline auto compute_width(basic_string_view s) -> size_t { - return compute_width( - string_view(reinterpret_cast(s.data()), s.size())); -} - -template -inline auto code_point_index(basic_string_view s, size_t n) -> size_t { - size_t size = s.size(); - return n < size ? n : size; -} - -// Calculates the index of the nth code point in a UTF-8 string. -inline auto code_point_index(string_view s, size_t n) -> size_t { - const char* data = s.data(); - size_t num_code_points = 0; - for (size_t i = 0, size = s.size(); i != size; ++i) { - if ((data[i] & 0xc0) != 0x80 && ++num_code_points > n) return i; - } - return s.size(); -} - -inline auto code_point_index(basic_string_view s, size_t n) - -> size_t { - return code_point_index( - string_view(reinterpret_cast(s.data()), s.size()), n); -} - -template struct is_integral : std::is_integral {}; -template <> struct is_integral : std::true_type {}; -template <> struct is_integral : std::true_type {}; - -template -using is_signed = - std::integral_constant::is_signed || - std::is_same::value>; - -template -using is_integer = - bool_constant::value && !std::is_same::value && - !std::is_same::value && - !std::is_same::value>; - -#ifndef FMT_USE_FLOAT -# define FMT_USE_FLOAT 1 -#endif -#ifndef FMT_USE_DOUBLE -# define FMT_USE_DOUBLE 1 -#endif -#ifndef FMT_USE_LONG_DOUBLE -# define FMT_USE_LONG_DOUBLE 1 -#endif - -#ifndef FMT_USE_FLOAT128 -# ifdef __clang__ -// Clang emulates GCC, so it has to appear early. -# if FMT_HAS_INCLUDE() -# define FMT_USE_FLOAT128 1 -# endif -# elif defined(__GNUC__) -// GNU C++: -# if defined(_GLIBCXX_USE_FLOAT128) && !defined(__STRICT_ANSI__) -# define FMT_USE_FLOAT128 1 -# endif -# endif -# ifndef FMT_USE_FLOAT128 -# define FMT_USE_FLOAT128 0 -# endif -#endif - -#if FMT_USE_FLOAT128 -using float128 = __float128; -#else -using float128 = void; -#endif -template using is_float128 = std::is_same; - -template -using is_floating_point = - bool_constant::value || is_float128::value>; - -template ::value> -struct is_fast_float : bool_constant::is_iec559 && - sizeof(T) <= sizeof(double)> {}; -template struct is_fast_float : std::false_type {}; - -template -using is_double_double = bool_constant::digits == 106>; - -#ifndef FMT_USE_FULL_CACHE_DRAGONBOX -# define FMT_USE_FULL_CACHE_DRAGONBOX 0 -#endif - -template -template -void buffer::append(const U* begin, const U* end) { - while (begin != end) { - auto count = to_unsigned(end - begin); - try_reserve(size_ + count); - auto free_cap = capacity_ - size_; - if (free_cap < count) count = free_cap; - std::uninitialized_copy_n(begin, count, ptr_ + size_); - size_ += count; - begin += count; - } -} - -template -struct is_locale : std::false_type {}; -template -struct is_locale> : std::true_type {}; -} // namespace detail - -FMT_BEGIN_EXPORT - -// The number of characters to store in the basic_memory_buffer object itself -// to avoid dynamic memory allocation. -enum { inline_buffer_size = 500 }; - -/** - \rst - A dynamically growing memory buffer for trivially copyable/constructible types - with the first ``SIZE`` elements stored in the object itself. - - You can use the ``memory_buffer`` type alias for ``char`` instead. - - **Example**:: - - auto out = fmt::memory_buffer(); - format_to(std::back_inserter(out), "The answer is {}.", 42); - - This will append the following output to the ``out`` object: - - .. code-block:: none - - The answer is 42. - - The output can be converted to an ``std::string`` with ``to_string(out)``. - \endrst - */ -template > -class basic_memory_buffer final : public detail::buffer { - private: - T store_[SIZE]; - - // Don't inherit from Allocator to avoid generating type_info for it. - FMT_NO_UNIQUE_ADDRESS Allocator alloc_; - - // Deallocate memory allocated by the buffer. - FMT_CONSTEXPR20 void deallocate() { - T* data = this->data(); - if (data != store_) alloc_.deallocate(data, this->capacity()); - } - - protected: - FMT_CONSTEXPR20 void grow(size_t size) override { - detail::abort_fuzzing_if(size > 5000); - const size_t max_size = std::allocator_traits::max_size(alloc_); - size_t old_capacity = this->capacity(); - size_t new_capacity = old_capacity + old_capacity / 2; - if (size > new_capacity) - new_capacity = size; - else if (new_capacity > max_size) - new_capacity = size > max_size ? size : max_size; - T* old_data = this->data(); - T* new_data = - std::allocator_traits::allocate(alloc_, new_capacity); - // Suppress a bogus -Wstringop-overflow in gcc 13.1 (#3481). - detail::assume(this->size() <= new_capacity); - // The following code doesn't throw, so the raw pointer above doesn't leak. - std::uninitialized_copy_n(old_data, this->size(), new_data); - this->set(new_data, new_capacity); - // deallocate must not throw according to the standard, but even if it does, - // the buffer already uses the new storage and will deallocate it in - // destructor. - if (old_data != store_) alloc_.deallocate(old_data, old_capacity); - } - - public: - using value_type = T; - using const_reference = const T&; - - FMT_CONSTEXPR20 explicit basic_memory_buffer( - const Allocator& alloc = Allocator()) - : alloc_(alloc) { - this->set(store_, SIZE); - if (detail::is_constant_evaluated()) detail::fill_n(store_, SIZE, T()); - } - FMT_CONSTEXPR20 ~basic_memory_buffer() { deallocate(); } - - private: - // Move data from other to this buffer. - FMT_CONSTEXPR20 void move(basic_memory_buffer& other) { - alloc_ = std::move(other.alloc_); - T* data = other.data(); - size_t size = other.size(), capacity = other.capacity(); - if (data == other.store_) { - this->set(store_, capacity); - detail::copy_str(other.store_, other.store_ + size, store_); - } else { - this->set(data, capacity); - // Set pointer to the inline array so that delete is not called - // when deallocating. - other.set(other.store_, 0); - other.clear(); - } - this->resize(size); - } - - public: - /** - \rst - Constructs a :class:`fmt::basic_memory_buffer` object moving the content - of the other object to it. - \endrst - */ - FMT_CONSTEXPR20 basic_memory_buffer(basic_memory_buffer&& other) noexcept { - move(other); - } - - /** - \rst - Moves the content of the other ``basic_memory_buffer`` object to this one. - \endrst - */ - auto operator=(basic_memory_buffer&& other) noexcept -> basic_memory_buffer& { - FMT_ASSERT(this != &other, ""); - deallocate(); - move(other); - return *this; - } - - // Returns a copy of the allocator associated with this buffer. - auto get_allocator() const -> Allocator { return alloc_; } - - /** - Resizes the buffer to contain *count* elements. If T is a POD type new - elements may not be initialized. - */ - FMT_CONSTEXPR20 void resize(size_t count) { this->try_resize(count); } - - /** Increases the buffer capacity to *new_capacity*. */ - void reserve(size_t new_capacity) { this->try_reserve(new_capacity); } - - // Directly append data into the buffer - using detail::buffer::append; - template - void append(const ContiguousRange& range) { - append(range.data(), range.data() + range.size()); - } -}; - -using memory_buffer = basic_memory_buffer; - -template -struct is_contiguous> : std::true_type { -}; - -FMT_END_EXPORT -namespace detail { -FMT_API bool write_console(std::FILE* f, string_view text); -FMT_API void print(std::FILE*, string_view); -} // namespace detail - -FMT_BEGIN_EXPORT - -// Suppress a misleading warning in older versions of clang. -#if FMT_CLANG_VERSION -# pragma clang diagnostic ignored "-Wweak-vtables" -#endif - -/** An error reported from a formatting function. */ -class FMT_VISIBILITY("default") format_error : public std::runtime_error { - public: - using std::runtime_error::runtime_error; -}; - -namespace detail_exported { -#if FMT_USE_NONTYPE_TEMPLATE_ARGS -template struct fixed_string { - constexpr fixed_string(const Char (&str)[N]) { - detail::copy_str(static_cast(str), - str + N, data); - } - Char data[N] = {}; -}; -#endif - -// Converts a compile-time string to basic_string_view. -template -constexpr auto compile_string_to_view(const Char (&s)[N]) - -> basic_string_view { - // Remove trailing NUL character if needed. Won't be present if this is used - // with a raw character array (i.e. not defined as a string). - return {s, N - (std::char_traits::to_int_type(s[N - 1]) == 0 ? 1 : 0)}; -} -template -constexpr auto compile_string_to_view(detail::std_string_view s) - -> basic_string_view { - return {s.data(), s.size()}; -} -} // namespace detail_exported - -class loc_value { - private: - basic_format_arg value_; - - public: - template ::value)> - loc_value(T value) : value_(detail::make_arg(value)) {} - - template ::value)> - loc_value(T) {} - - template auto visit(Visitor&& vis) -> decltype(vis(0)) { - return visit_format_arg(vis, value_); - } -}; - -// A locale facet that formats values in UTF-8. -// It is parameterized on the locale to avoid the heavy include. -template class format_facet : public Locale::facet { - private: - std::string separator_; - std::string grouping_; - std::string decimal_point_; - - protected: - virtual auto do_put(appender out, loc_value val, - const format_specs<>& specs) const -> bool; - - public: - static FMT_API typename Locale::id id; - - explicit format_facet(Locale& loc); - explicit format_facet(string_view sep = "", - std::initializer_list g = {3}, - std::string decimal_point = ".") - : separator_(sep.data(), sep.size()), - grouping_(g.begin(), g.end()), - decimal_point_(decimal_point) {} - - auto put(appender out, loc_value val, const format_specs<>& specs) const - -> bool { - return do_put(out, val, specs); - } -}; - -namespace detail { - -// Returns true if value is negative, false otherwise. -// Same as `value < 0` but doesn't produce warnings if T is an unsigned type. -template ::value)> -constexpr auto is_negative(T value) -> bool { - return value < 0; -} -template ::value)> -constexpr auto is_negative(T) -> bool { - return false; -} - -template -FMT_CONSTEXPR auto is_supported_floating_point(T) -> bool { - if (std::is_same()) return FMT_USE_FLOAT; - if (std::is_same()) return FMT_USE_DOUBLE; - if (std::is_same()) return FMT_USE_LONG_DOUBLE; - return true; -} - -// Smallest of uint32_t, uint64_t, uint128_t that is large enough to -// represent all values of an integral type T. -template -using uint32_or_64_or_128_t = - conditional_t() <= 32 && !FMT_REDUCE_INT_INSTANTIATIONS, - uint32_t, - conditional_t() <= 64, uint64_t, uint128_t>>; -template -using uint64_or_128_t = conditional_t() <= 64, uint64_t, uint128_t>; - -#define FMT_POWERS_OF_10(factor) \ - factor * 10, (factor)*100, (factor)*1000, (factor)*10000, (factor)*100000, \ - (factor)*1000000, (factor)*10000000, (factor)*100000000, \ - (factor)*1000000000 - -// Converts value in the range [0, 100) to a string. -constexpr const char* digits2(size_t value) { - // GCC generates slightly better code when value is pointer-size. - return &"0001020304050607080910111213141516171819" - "2021222324252627282930313233343536373839" - "4041424344454647484950515253545556575859" - "6061626364656667686970717273747576777879" - "8081828384858687888990919293949596979899"[value * 2]; -} - -// Sign is a template parameter to workaround a bug in gcc 4.8. -template constexpr Char sign(Sign s) { -#if !FMT_GCC_VERSION || FMT_GCC_VERSION >= 604 - static_assert(std::is_same::value, ""); -#endif - return static_cast("\0-+ "[s]); -} - -template FMT_CONSTEXPR auto count_digits_fallback(T n) -> int { - int count = 1; - for (;;) { - // Integer division is slow so do it for a group of four digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - if (n < 10) return count; - if (n < 100) return count + 1; - if (n < 1000) return count + 2; - if (n < 10000) return count + 3; - n /= 10000u; - count += 4; - } -} -#if FMT_USE_INT128 -FMT_CONSTEXPR inline auto count_digits(uint128_opt n) -> int { - return count_digits_fallback(n); -} -#endif - -#ifdef FMT_BUILTIN_CLZLL -// It is a separate function rather than a part of count_digits to workaround -// the lack of static constexpr in constexpr functions. -inline auto do_count_digits(uint64_t n) -> int { - // This has comparable performance to the version by Kendall Willets - // (https://github.com/fmtlib/format-benchmark/blob/master/digits10) - // but uses smaller tables. - // Maps bsr(n) to ceil(log10(pow(2, bsr(n) + 1) - 1)). - static constexpr uint8_t bsr2log10[] = { - 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, - 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, - 10, 11, 11, 11, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 15, 15, - 15, 16, 16, 16, 16, 17, 17, 17, 18, 18, 18, 19, 19, 19, 19, 20}; - auto t = bsr2log10[FMT_BUILTIN_CLZLL(n | 1) ^ 63]; - static constexpr const uint64_t zero_or_powers_of_10[] = { - 0, 0, FMT_POWERS_OF_10(1U), FMT_POWERS_OF_10(1000000000ULL), - 10000000000000000000ULL}; - return t - (n < zero_or_powers_of_10[t]); -} -#endif - -// Returns the number of decimal digits in n. Leading zeros are not counted -// except for n == 0 in which case count_digits returns 1. -FMT_CONSTEXPR20 inline auto count_digits(uint64_t n) -> int { -#ifdef FMT_BUILTIN_CLZLL - if (!is_constant_evaluated()) { - return do_count_digits(n); - } -#endif - return count_digits_fallback(n); -} - -// Counts the number of digits in n. BITS = log2(radix). -template -FMT_CONSTEXPR auto count_digits(UInt n) -> int { -#ifdef FMT_BUILTIN_CLZ - if (!is_constant_evaluated() && num_bits() == 32) - return (FMT_BUILTIN_CLZ(static_cast(n) | 1) ^ 31) / BITS + 1; -#endif - // Lambda avoids unreachable code warnings from NVHPC. - return [](UInt m) { - int num_digits = 0; - do { - ++num_digits; - } while ((m >>= BITS) != 0); - return num_digits; - }(n); -} - -#ifdef FMT_BUILTIN_CLZ -// It is a separate function rather than a part of count_digits to workaround -// the lack of static constexpr in constexpr functions. -FMT_INLINE auto do_count_digits(uint32_t n) -> int { -// An optimization by Kendall Willets from https://bit.ly/3uOIQrB. -// This increments the upper 32 bits (log10(T) - 1) when >= T is added. -# define FMT_INC(T) (((sizeof(#T) - 1ull) << 32) - T) - static constexpr uint64_t table[] = { - FMT_INC(0), FMT_INC(0), FMT_INC(0), // 8 - FMT_INC(10), FMT_INC(10), FMT_INC(10), // 64 - FMT_INC(100), FMT_INC(100), FMT_INC(100), // 512 - FMT_INC(1000), FMT_INC(1000), FMT_INC(1000), // 4096 - FMT_INC(10000), FMT_INC(10000), FMT_INC(10000), // 32k - FMT_INC(100000), FMT_INC(100000), FMT_INC(100000), // 256k - FMT_INC(1000000), FMT_INC(1000000), FMT_INC(1000000), // 2048k - FMT_INC(10000000), FMT_INC(10000000), FMT_INC(10000000), // 16M - FMT_INC(100000000), FMT_INC(100000000), FMT_INC(100000000), // 128M - FMT_INC(1000000000), FMT_INC(1000000000), FMT_INC(1000000000), // 1024M - FMT_INC(1000000000), FMT_INC(1000000000) // 4B - }; - auto inc = table[FMT_BUILTIN_CLZ(n | 1) ^ 31]; - return static_cast((n + inc) >> 32); -} -#endif - -// Optional version of count_digits for better performance on 32-bit platforms. -FMT_CONSTEXPR20 inline auto count_digits(uint32_t n) -> int { -#ifdef FMT_BUILTIN_CLZ - if (!is_constant_evaluated()) { - return do_count_digits(n); - } -#endif - return count_digits_fallback(n); -} - -template constexpr auto digits10() noexcept -> int { - return std::numeric_limits::digits10; -} -template <> constexpr auto digits10() noexcept -> int { return 38; } -template <> constexpr auto digits10() noexcept -> int { return 38; } - -template struct thousands_sep_result { - std::string grouping; - Char thousands_sep; -}; - -template -FMT_API auto thousands_sep_impl(locale_ref loc) -> thousands_sep_result; -template -inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { - auto result = thousands_sep_impl(loc); - return {result.grouping, Char(result.thousands_sep)}; -} -template <> -inline auto thousands_sep(locale_ref loc) -> thousands_sep_result { - return thousands_sep_impl(loc); -} - -template -FMT_API auto decimal_point_impl(locale_ref loc) -> Char; -template inline auto decimal_point(locale_ref loc) -> Char { - return Char(decimal_point_impl(loc)); -} -template <> inline auto decimal_point(locale_ref loc) -> wchar_t { - return decimal_point_impl(loc); -} - -// Compares two characters for equality. -template auto equal2(const Char* lhs, const char* rhs) -> bool { - return lhs[0] == Char(rhs[0]) && lhs[1] == Char(rhs[1]); -} -inline auto equal2(const char* lhs, const char* rhs) -> bool { - return memcmp(lhs, rhs, 2) == 0; -} - -// Copies two characters from src to dst. -template -FMT_CONSTEXPR20 FMT_INLINE void copy2(Char* dst, const char* src) { - if (!is_constant_evaluated() && sizeof(Char) == sizeof(char)) { - memcpy(dst, src, 2); - return; - } - *dst++ = static_cast(*src++); - *dst = static_cast(*src); -} - -template struct format_decimal_result { - Iterator begin; - Iterator end; -}; - -// Formats a decimal unsigned integer value writing into out pointing to a -// buffer of specified size. The caller must ensure that the buffer is large -// enough. -template -FMT_CONSTEXPR20 auto format_decimal(Char* out, UInt value, int size) - -> format_decimal_result { - FMT_ASSERT(size >= count_digits(value), "invalid digit count"); - out += size; - Char* end = out; - while (value >= 100) { - // Integer division is slow so do it for a group of two digits instead - // of for every digit. The idea comes from the talk by Alexandrescu - // "Three Optimization Tips for C++". See speed-test for a comparison. - out -= 2; - copy2(out, digits2(static_cast(value % 100))); - value /= 100; - } - if (value < 10) { - *--out = static_cast('0' + value); - return {out, end}; - } - out -= 2; - copy2(out, digits2(static_cast(value))); - return {out, end}; -} - -template >::value)> -FMT_CONSTEXPR inline auto format_decimal(Iterator out, UInt value, int size) - -> format_decimal_result { - // Buffer is large enough to hold all digits (digits10 + 1). - Char buffer[digits10() + 1] = {}; - auto end = format_decimal(buffer, value, size).end; - return {out, detail::copy_str_noinline(buffer, end, out)}; -} - -template -FMT_CONSTEXPR auto format_uint(Char* buffer, UInt value, int num_digits, - bool upper = false) -> Char* { - buffer += num_digits; - Char* end = buffer; - do { - const char* digits = upper ? "0123456789ABCDEF" : "0123456789abcdef"; - unsigned digit = static_cast(value & ((1 << BASE_BITS) - 1)); - *--buffer = static_cast(BASE_BITS < 4 ? static_cast('0' + digit) - : digits[digit]); - } while ((value >>= BASE_BITS) != 0); - return end; -} - -template -FMT_CONSTEXPR inline auto format_uint(It out, UInt value, int num_digits, - bool upper = false) -> It { - if (auto ptr = to_pointer(out, to_unsigned(num_digits))) { - format_uint(ptr, value, num_digits, upper); - return out; - } - // Buffer should be large enough to hold all digits (digits / BASE_BITS + 1). - char buffer[num_bits() / BASE_BITS + 1]; - format_uint(buffer, value, num_digits, upper); - return detail::copy_str_noinline(buffer, buffer + num_digits, out); -} - -// A converter from UTF-8 to UTF-16. -class utf8_to_utf16 { - private: - basic_memory_buffer buffer_; - - public: - FMT_API explicit utf8_to_utf16(string_view s); - operator basic_string_view() const { return {&buffer_[0], size()}; } - auto size() const -> size_t { return buffer_.size() - 1; } - auto c_str() const -> const wchar_t* { return &buffer_[0]; } - auto str() const -> std::wstring { return {&buffer_[0], size()}; } -}; - -enum class to_utf8_error_policy { abort, replace }; - -// A converter from UTF-16/UTF-32 (host endian) to UTF-8. -template class to_utf8 { - private: - Buffer buffer_; - - public: - to_utf8() {} - explicit to_utf8(basic_string_view s, - to_utf8_error_policy policy = to_utf8_error_policy::abort) { - static_assert(sizeof(WChar) == 2 || sizeof(WChar) == 4, - "Expect utf16 or utf32"); - if (!convert(s, policy)) - FMT_THROW(std::runtime_error(sizeof(WChar) == 2 ? "invalid utf16" - : "invalid utf32")); - } - operator string_view() const { return string_view(&buffer_[0], size()); } - size_t size() const { return buffer_.size() - 1; } - const char* c_str() const { return &buffer_[0]; } - std::string str() const { return std::string(&buffer_[0], size()); } - - // Performs conversion returning a bool instead of throwing exception on - // conversion error. This method may still throw in case of memory allocation - // error. - bool convert(basic_string_view s, - to_utf8_error_policy policy = to_utf8_error_policy::abort) { - if (!convert(buffer_, s, policy)) return false; - buffer_.push_back(0); - return true; - } - static bool convert( - Buffer& buf, basic_string_view s, - to_utf8_error_policy policy = to_utf8_error_policy::abort) { - for (auto p = s.begin(); p != s.end(); ++p) { - uint32_t c = static_cast(*p); - if (sizeof(WChar) == 2 && c >= 0xd800 && c <= 0xdfff) { - // Handle a surrogate pair. - ++p; - if (p == s.end() || (c & 0xfc00) != 0xd800 || (*p & 0xfc00) != 0xdc00) { - if (policy == to_utf8_error_policy::abort) return false; - buf.append(string_view("\xEF\xBF\xBD")); - --p; - } else { - c = (c << 10) + static_cast(*p) - 0x35fdc00; - } - } else if (c < 0x80) { - buf.push_back(static_cast(c)); - } else if (c < 0x800) { - buf.push_back(static_cast(0xc0 | (c >> 6))); - buf.push_back(static_cast(0x80 | (c & 0x3f))); - } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) { - buf.push_back(static_cast(0xe0 | (c >> 12))); - buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); - buf.push_back(static_cast(0x80 | (c & 0x3f))); - } else if (c >= 0x10000 && c <= 0x10ffff) { - buf.push_back(static_cast(0xf0 | (c >> 18))); - buf.push_back(static_cast(0x80 | ((c & 0x3ffff) >> 12))); - buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6))); - buf.push_back(static_cast(0x80 | (c & 0x3f))); - } else { - return false; - } - } - return true; - } -}; - -// Computes 128-bit result of multiplication of two 64-bit unsigned integers. -inline uint128_fallback umul128(uint64_t x, uint64_t y) noexcept { -#if FMT_USE_INT128 - auto p = static_cast(x) * static_cast(y); - return {static_cast(p >> 64), static_cast(p)}; -#elif defined(_MSC_VER) && defined(_M_X64) - auto hi = uint64_t(); - auto lo = _umul128(x, y, &hi); - return {hi, lo}; -#else - const uint64_t mask = static_cast(max_value()); - - uint64_t a = x >> 32; - uint64_t b = x & mask; - uint64_t c = y >> 32; - uint64_t d = y & mask; - - uint64_t ac = a * c; - uint64_t bc = b * c; - uint64_t ad = a * d; - uint64_t bd = b * d; - - uint64_t intermediate = (bd >> 32) + (ad & mask) + (bc & mask); - - return {ac + (intermediate >> 32) + (ad >> 32) + (bc >> 32), - (intermediate << 32) + (bd & mask)}; -#endif -} - -namespace dragonbox { -// Computes floor(log10(pow(2, e))) for e in [-2620, 2620] using the method from -// https://fmt.dev/papers/Dragonbox.pdf#page=28, section 6.1. -inline int floor_log10_pow2(int e) noexcept { - FMT_ASSERT(e <= 2620 && e >= -2620, "too large exponent"); - static_assert((-1 >> 1) == -1, "right shift is not arithmetic"); - return (e * 315653) >> 20; -} - -inline int floor_log2_pow10(int e) noexcept { - FMT_ASSERT(e <= 1233 && e >= -1233, "too large exponent"); - return (e * 1741647) >> 19; -} - -// Computes upper 64 bits of multiplication of two 64-bit unsigned integers. -inline uint64_t umul128_upper64(uint64_t x, uint64_t y) noexcept { -#if FMT_USE_INT128 - auto p = static_cast(x) * static_cast(y); - return static_cast(p >> 64); -#elif defined(_MSC_VER) && defined(_M_X64) - return __umulh(x, y); -#else - return umul128(x, y).high(); -#endif -} - -// Computes upper 128 bits of multiplication of a 64-bit unsigned integer and a -// 128-bit unsigned integer. -inline uint128_fallback umul192_upper128(uint64_t x, - uint128_fallback y) noexcept { - uint128_fallback r = umul128(x, y.high()); - r += umul128_upper64(x, y.low()); - return r; -} - -FMT_API uint128_fallback get_cached_power(int k) noexcept; - -// Type-specific information that Dragonbox uses. -template struct float_info; - -template <> struct float_info { - using carrier_uint = uint32_t; - static const int exponent_bits = 8; - static const int kappa = 1; - static const int big_divisor = 100; - static const int small_divisor = 10; - static const int min_k = -31; - static const int max_k = 46; - static const int shorter_interval_tie_lower_threshold = -35; - static const int shorter_interval_tie_upper_threshold = -35; -}; - -template <> struct float_info { - using carrier_uint = uint64_t; - static const int exponent_bits = 11; - static const int kappa = 2; - static const int big_divisor = 1000; - static const int small_divisor = 100; - static const int min_k = -292; - static const int max_k = 341; - static const int shorter_interval_tie_lower_threshold = -77; - static const int shorter_interval_tie_upper_threshold = -77; -}; - -// An 80- or 128-bit floating point number. -template -struct float_info::digits == 64 || - std::numeric_limits::digits == 113 || - is_float128::value>> { - using carrier_uint = detail::uint128_t; - static const int exponent_bits = 15; -}; - -// A double-double floating point number. -template -struct float_info::value>> { - using carrier_uint = detail::uint128_t; -}; - -template struct decimal_fp { - using significand_type = typename float_info::carrier_uint; - significand_type significand; - int exponent; -}; - -template FMT_API auto to_decimal(T x) noexcept -> decimal_fp; -} // namespace dragonbox - -// Returns true iff Float has the implicit bit which is not stored. -template constexpr bool has_implicit_bit() { - // An 80-bit FP number has a 64-bit significand an no implicit bit. - return std::numeric_limits::digits != 64; -} - -// Returns the number of significand bits stored in Float. The implicit bit is -// not counted since it is not stored. -template constexpr int num_significand_bits() { - // std::numeric_limits may not support __float128. - return is_float128() ? 112 - : (std::numeric_limits::digits - - (has_implicit_bit() ? 1 : 0)); -} - -template -constexpr auto exponent_mask() -> - typename dragonbox::float_info::carrier_uint { - using float_uint = typename dragonbox::float_info::carrier_uint; - return ((float_uint(1) << dragonbox::float_info::exponent_bits) - 1) - << num_significand_bits(); -} -template constexpr auto exponent_bias() -> int { - // std::numeric_limits may not support __float128. - return is_float128() ? 16383 - : std::numeric_limits::max_exponent - 1; -} - -// Writes the exponent exp in the form "[+-]d{2,3}" to buffer. -template -FMT_CONSTEXPR auto write_exponent(int exp, It it) -> It { - FMT_ASSERT(-10000 < exp && exp < 10000, "exponent out of range"); - if (exp < 0) { - *it++ = static_cast('-'); - exp = -exp; - } else { - *it++ = static_cast('+'); - } - if (exp >= 100) { - const char* top = digits2(to_unsigned(exp / 100)); - if (exp >= 1000) *it++ = static_cast(top[0]); - *it++ = static_cast(top[1]); - exp %= 100; - } - const char* d = digits2(to_unsigned(exp)); - *it++ = static_cast(d[0]); - *it++ = static_cast(d[1]); - return it; -} - -// A floating-point number f * pow(2, e) where F is an unsigned type. -template struct basic_fp { - F f; - int e; - - static constexpr const int num_significand_bits = - static_cast(sizeof(F) * num_bits()); - - constexpr basic_fp() : f(0), e(0) {} - constexpr basic_fp(uint64_t f_val, int e_val) : f(f_val), e(e_val) {} - - // Constructs fp from an IEEE754 floating-point number. - template FMT_CONSTEXPR basic_fp(Float n) { assign(n); } - - // Assigns n to this and return true iff predecessor is closer than successor. - template ::value)> - FMT_CONSTEXPR auto assign(Float n) -> bool { - static_assert(std::numeric_limits::digits <= 113, "unsupported FP"); - // Assume Float is in the format [sign][exponent][significand]. - using carrier_uint = typename dragonbox::float_info::carrier_uint; - const auto num_float_significand_bits = - detail::num_significand_bits(); - const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; - const auto significand_mask = implicit_bit - 1; - auto u = bit_cast(n); - f = static_cast(u & significand_mask); - auto biased_e = static_cast((u & exponent_mask()) >> - num_float_significand_bits); - // The predecessor is closer if n is a normalized power of 2 (f == 0) - // other than the smallest normalized number (biased_e > 1). - auto is_predecessor_closer = f == 0 && biased_e > 1; - if (biased_e == 0) - biased_e = 1; // Subnormals use biased exponent 1 (min exponent). - else if (has_implicit_bit()) - f += static_cast(implicit_bit); - e = biased_e - exponent_bias() - num_float_significand_bits; - if (!has_implicit_bit()) ++e; - return is_predecessor_closer; - } - - template ::value)> - FMT_CONSTEXPR auto assign(Float n) -> bool { - static_assert(std::numeric_limits::is_iec559, "unsupported FP"); - return assign(static_cast(n)); - } -}; - -using fp = basic_fp; - -// Normalizes the value converted from double and multiplied by (1 << SHIFT). -template -FMT_CONSTEXPR basic_fp normalize(basic_fp value) { - // Handle subnormals. - const auto implicit_bit = F(1) << num_significand_bits(); - const auto shifted_implicit_bit = implicit_bit << SHIFT; - while ((value.f & shifted_implicit_bit) == 0) { - value.f <<= 1; - --value.e; - } - // Subtract 1 to account for hidden bit. - const auto offset = basic_fp::num_significand_bits - - num_significand_bits() - SHIFT - 1; - value.f <<= offset; - value.e -= offset; - return value; -} - -// Computes lhs * rhs / pow(2, 64) rounded to nearest with half-up tie breaking. -FMT_CONSTEXPR inline uint64_t multiply(uint64_t lhs, uint64_t rhs) { -#if FMT_USE_INT128 - auto product = static_cast<__uint128_t>(lhs) * rhs; - auto f = static_cast(product >> 64); - return (static_cast(product) & (1ULL << 63)) != 0 ? f + 1 : f; -#else - // Multiply 32-bit parts of significands. - uint64_t mask = (1ULL << 32) - 1; - uint64_t a = lhs >> 32, b = lhs & mask; - uint64_t c = rhs >> 32, d = rhs & mask; - uint64_t ac = a * c, bc = b * c, ad = a * d, bd = b * d; - // Compute mid 64-bit of result and round. - uint64_t mid = (bd >> 32) + (ad & mask) + (bc & mask) + (1U << 31); - return ac + (ad >> 32) + (bc >> 32) + (mid >> 32); -#endif -} - -FMT_CONSTEXPR inline fp operator*(fp x, fp y) { - return {multiply(x.f, y.f), x.e + y.e + 64}; -} - -template struct basic_data { - // For checking rounding thresholds. - // The kth entry is chosen to be the smallest integer such that the - // upper 32-bits of 10^(k+1) times it is strictly bigger than 5 * 10^k. - static constexpr uint32_t fractional_part_rounding_thresholds[8] = { - 2576980378U, // ceil(2^31 + 2^32/10^1) - 2190433321U, // ceil(2^31 + 2^32/10^2) - 2151778616U, // ceil(2^31 + 2^32/10^3) - 2147913145U, // ceil(2^31 + 2^32/10^4) - 2147526598U, // ceil(2^31 + 2^32/10^5) - 2147487943U, // ceil(2^31 + 2^32/10^6) - 2147484078U, // ceil(2^31 + 2^32/10^7) - 2147483691U // ceil(2^31 + 2^32/10^8) - }; -}; -// This is a struct rather than an alias to avoid shadowing warnings in gcc. -struct data : basic_data<> {}; - -#if FMT_CPLUSPLUS < 201703L -template -constexpr uint32_t basic_data::fractional_part_rounding_thresholds[]; -#endif - -template () == num_bits()> -using convert_float_result = - conditional_t::value || doublish, double, T>; - -template -constexpr auto convert_float(T value) -> convert_float_result { - return static_cast>(value); -} - -template -FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, - const fill_t& fill) -> OutputIt { - auto fill_size = fill.size(); - if (fill_size == 1) return detail::fill_n(it, n, fill[0]); - auto data = fill.data(); - for (size_t i = 0; i < n; ++i) - it = copy_str(data, data + fill_size, it); - return it; -} - -// Writes the output of f, padded according to format specifications in specs. -// size: output size in code units. -// width: output display width in (terminal) column positions. -template -FMT_CONSTEXPR auto write_padded(OutputIt out, const format_specs& specs, - size_t size, size_t width, F&& f) -> OutputIt { - static_assert(align == align::left || align == align::right, ""); - unsigned spec_width = to_unsigned(specs.width); - size_t padding = spec_width > width ? spec_width - width : 0; - // Shifts are encoded as string literals because static constexpr is not - // supported in constexpr functions. - auto* shifts = align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01"; - size_t left_padding = padding >> shifts[specs.align]; - size_t right_padding = padding - left_padding; - auto it = reserve(out, size + padding * specs.fill.size()); - if (left_padding != 0) it = fill(it, left_padding, specs.fill); - it = f(it); - if (right_padding != 0) it = fill(it, right_padding, specs.fill); - return base_iterator(out, it); -} - -template -constexpr auto write_padded(OutputIt out, const format_specs& specs, - size_t size, F&& f) -> OutputIt { - return write_padded(out, specs, size, size, f); -} - -template -FMT_CONSTEXPR auto write_bytes(OutputIt out, string_view bytes, - const format_specs& specs) -> OutputIt { - return write_padded( - out, specs, bytes.size(), [bytes](reserve_iterator it) { - const char* data = bytes.data(); - return copy_str(data, data + bytes.size(), it); - }); -} - -template -auto write_ptr(OutputIt out, UIntPtr value, const format_specs* specs) - -> OutputIt { - int num_digits = count_digits<4>(value); - auto size = to_unsigned(num_digits) + size_t(2); - auto write = [=](reserve_iterator it) { - *it++ = static_cast('0'); - *it++ = static_cast('x'); - return format_uint<4, Char>(it, value, num_digits); - }; - return specs ? write_padded(out, *specs, size, write) - : base_iterator(out, write(reserve(out, size))); -} - -// Returns true iff the code point cp is printable. -FMT_API auto is_printable(uint32_t cp) -> bool; - -inline auto needs_escape(uint32_t cp) -> bool { - return cp < 0x20 || cp == 0x7f || cp == '"' || cp == '\\' || - !is_printable(cp); -} - -template struct find_escape_result { - const Char* begin; - const Char* end; - uint32_t cp; -}; - -template -using make_unsigned_char = - typename conditional_t::value, - std::make_unsigned, - type_identity>::type; - -template -auto find_escape(const Char* begin, const Char* end) - -> find_escape_result { - for (; begin != end; ++begin) { - uint32_t cp = static_cast>(*begin); - if (const_check(sizeof(Char) == 1) && cp >= 0x80) continue; - if (needs_escape(cp)) return {begin, begin + 1, cp}; - } - return {begin, nullptr, 0}; -} - -inline auto find_escape(const char* begin, const char* end) - -> find_escape_result { - if (!is_utf8()) return find_escape(begin, end); - auto result = find_escape_result{end, nullptr, 0}; - for_each_codepoint(string_view(begin, to_unsigned(end - begin)), - [&](uint32_t cp, string_view sv) { - if (needs_escape(cp)) { - result = {sv.begin(), sv.end(), cp}; - return false; - } - return true; - }); - return result; -} - -#define FMT_STRING_IMPL(s, base, explicit) \ - [] { \ - /* Use the hidden visibility as a workaround for a GCC bug (#1973). */ \ - /* Use a macro-like name to avoid shadowing warnings. */ \ - struct FMT_VISIBILITY("hidden") FMT_COMPILE_STRING : base { \ - using char_type FMT_MAYBE_UNUSED = fmt::remove_cvref_t; \ - FMT_MAYBE_UNUSED FMT_CONSTEXPR explicit \ - operator fmt::basic_string_view() const { \ - return fmt::detail_exported::compile_string_to_view(s); \ - } \ - }; \ - return FMT_COMPILE_STRING(); \ - }() - -/** - \rst - Constructs a compile-time format string from a string literal *s*. - - **Example**:: - - // A compile-time error because 'd' is an invalid specifier for strings. - std::string s = fmt::format(FMT_STRING("{:d}"), "foo"); - \endrst - */ -#define FMT_STRING(s) FMT_STRING_IMPL(s, fmt::detail::compile_string, ) - -template -auto write_codepoint(OutputIt out, char prefix, uint32_t cp) -> OutputIt { - *out++ = static_cast('\\'); - *out++ = static_cast(prefix); - Char buf[width]; - fill_n(buf, width, static_cast('0')); - format_uint<4>(buf, cp, width); - return copy_str(buf, buf + width, out); -} - -template -auto write_escaped_cp(OutputIt out, const find_escape_result& escape) - -> OutputIt { - auto c = static_cast(escape.cp); - switch (escape.cp) { - case '\n': - *out++ = static_cast('\\'); - c = static_cast('n'); - break; - case '\r': - *out++ = static_cast('\\'); - c = static_cast('r'); - break; - case '\t': - *out++ = static_cast('\\'); - c = static_cast('t'); - break; - case '"': - FMT_FALLTHROUGH; - case '\'': - FMT_FALLTHROUGH; - case '\\': - *out++ = static_cast('\\'); - break; - default: - if (escape.cp < 0x100) { - return write_codepoint<2, Char>(out, 'x', escape.cp); - } - if (escape.cp < 0x10000) { - return write_codepoint<4, Char>(out, 'u', escape.cp); - } - if (escape.cp < 0x110000) { - return write_codepoint<8, Char>(out, 'U', escape.cp); - } - for (Char escape_char : basic_string_view( - escape.begin, to_unsigned(escape.end - escape.begin))) { - out = write_codepoint<2, Char>(out, 'x', - static_cast(escape_char) & 0xFF); - } - return out; - } - *out++ = c; - return out; -} - -template -auto write_escaped_string(OutputIt out, basic_string_view str) - -> OutputIt { - *out++ = static_cast('"'); - auto begin = str.begin(), end = str.end(); - do { - auto escape = find_escape(begin, end); - out = copy_str(begin, escape.begin, out); - begin = escape.end; - if (!begin) break; - out = write_escaped_cp(out, escape); - } while (begin != end); - *out++ = static_cast('"'); - return out; -} - -template -auto write_escaped_char(OutputIt out, Char v) -> OutputIt { - *out++ = static_cast('\''); - if ((needs_escape(static_cast(v)) && v != static_cast('"')) || - v == static_cast('\'')) { - out = write_escaped_cp( - out, find_escape_result{&v, &v + 1, static_cast(v)}); - } else { - *out++ = v; - } - *out++ = static_cast('\''); - return out; -} - -template -FMT_CONSTEXPR auto write_char(OutputIt out, Char value, - const format_specs& specs) -> OutputIt { - bool is_debug = specs.type == presentation_type::debug; - return write_padded(out, specs, 1, [=](reserve_iterator it) { - if (is_debug) return write_escaped_char(it, value); - *it++ = value; - return it; - }); -} -template -FMT_CONSTEXPR auto write(OutputIt out, Char value, - const format_specs& specs, locale_ref loc = {}) - -> OutputIt { - // char is formatted as unsigned char for consistency across platforms. - using unsigned_type = - conditional_t::value, unsigned char, unsigned>; - return check_char_specs(specs) - ? write_char(out, value, specs) - : write(out, static_cast(value), specs, loc); -} - -// Data for write_int that doesn't depend on output iterator type. It is used to -// avoid template code bloat. -template struct write_int_data { - size_t size; - size_t padding; - - FMT_CONSTEXPR write_int_data(int num_digits, unsigned prefix, - const format_specs& specs) - : size((prefix >> 24) + to_unsigned(num_digits)), padding(0) { - if (specs.align == align::numeric) { - auto width = to_unsigned(specs.width); - if (width > size) { - padding = width - size; - size = width; - } - } else if (specs.precision > num_digits) { - size = (prefix >> 24) + to_unsigned(specs.precision); - padding = to_unsigned(specs.precision - num_digits); - } - } -}; - -// Writes an integer in the format -// -// where are written by write_digits(it). -// prefix contains chars in three lower bytes and the size in the fourth byte. -template -FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, int num_digits, - unsigned prefix, - const format_specs& specs, - W write_digits) -> OutputIt { - // Slightly faster check for specs.width == 0 && specs.precision == -1. - if ((specs.width | (specs.precision + 1)) == 0) { - auto it = reserve(out, to_unsigned(num_digits) + (prefix >> 24)); - if (prefix != 0) { - for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) - *it++ = static_cast(p & 0xff); - } - return base_iterator(out, write_digits(it)); - } - auto data = write_int_data(num_digits, prefix, specs); - return write_padded( - out, specs, data.size, [=](reserve_iterator it) { - for (unsigned p = prefix & 0xffffff; p != 0; p >>= 8) - *it++ = static_cast(p & 0xff); - it = detail::fill_n(it, data.padding, static_cast('0')); - return write_digits(it); - }); -} - -template class digit_grouping { - private: - std::string grouping_; - std::basic_string thousands_sep_; - - struct next_state { - std::string::const_iterator group; - int pos; - }; - next_state initial_state() const { return {grouping_.begin(), 0}; } - - // Returns the next digit group separator position. - int next(next_state& state) const { - if (thousands_sep_.empty()) return max_value(); - if (state.group == grouping_.end()) return state.pos += grouping_.back(); - if (*state.group <= 0 || *state.group == max_value()) - return max_value(); - state.pos += *state.group++; - return state.pos; - } - - public: - explicit digit_grouping(locale_ref loc, bool localized = true) { - if (!localized) return; - auto sep = thousands_sep(loc); - grouping_ = sep.grouping; - if (sep.thousands_sep) thousands_sep_.assign(1, sep.thousands_sep); - } - digit_grouping(std::string grouping, std::basic_string sep) - : grouping_(std::move(grouping)), thousands_sep_(std::move(sep)) {} - - bool has_separator() const { return !thousands_sep_.empty(); } - - int count_separators(int num_digits) const { - int count = 0; - auto state = initial_state(); - while (num_digits > next(state)) ++count; - return count; - } - - // Applies grouping to digits and write the output to out. - template - Out apply(Out out, basic_string_view digits) const { - auto num_digits = static_cast(digits.size()); - auto separators = basic_memory_buffer(); - separators.push_back(0); - auto state = initial_state(); - while (int i = next(state)) { - if (i >= num_digits) break; - separators.push_back(i); - } - for (int i = 0, sep_index = static_cast(separators.size() - 1); - i < num_digits; ++i) { - if (num_digits - i == separators[sep_index]) { - out = - copy_str(thousands_sep_.data(), - thousands_sep_.data() + thousands_sep_.size(), out); - --sep_index; - } - *out++ = static_cast(digits[to_unsigned(i)]); - } - return out; - } -}; - -// Writes a decimal integer with digit grouping. -template -auto write_int(OutputIt out, UInt value, unsigned prefix, - const format_specs& specs, - const digit_grouping& grouping) -> OutputIt { - static_assert(std::is_same, UInt>::value, ""); - int num_digits = count_digits(value); - char digits[40]; - format_decimal(digits, value, num_digits); - unsigned size = to_unsigned((prefix != 0 ? 1 : 0) + num_digits + - grouping.count_separators(num_digits)); - return write_padded( - out, specs, size, size, [&](reserve_iterator it) { - if (prefix != 0) { - char sign = static_cast(prefix); - *it++ = static_cast(sign); - } - return grouping.apply(it, string_view(digits, to_unsigned(num_digits))); - }); -} - -// Writes a localized value. -FMT_API auto write_loc(appender out, loc_value value, - const format_specs<>& specs, locale_ref loc) -> bool; -template -inline auto write_loc(OutputIt, loc_value, const format_specs&, - locale_ref) -> bool { - return false; -} - -FMT_CONSTEXPR inline void prefix_append(unsigned& prefix, unsigned value) { - prefix |= prefix != 0 ? value << 8 : value; - prefix += (1u + (value > 0xff ? 1 : 0)) << 24; -} - -template struct write_int_arg { - UInt abs_value; - unsigned prefix; -}; - -template -FMT_CONSTEXPR auto make_write_int_arg(T value, sign_t sign) - -> write_int_arg> { - auto prefix = 0u; - auto abs_value = static_cast>(value); - if (is_negative(value)) { - prefix = 0x01000000 | '-'; - abs_value = 0 - abs_value; - } else { - constexpr const unsigned prefixes[4] = {0, 0, 0x1000000u | '+', - 0x1000000u | ' '}; - prefix = prefixes[sign]; - } - return {abs_value, prefix}; -} - -template struct loc_writer { - buffer_appender out; - const format_specs& specs; - std::basic_string sep; - std::string grouping; - std::basic_string decimal_point; - - template ::value)> - auto operator()(T value) -> bool { - auto arg = make_write_int_arg(value, specs.sign); - write_int(out, static_cast>(arg.abs_value), arg.prefix, - specs, digit_grouping(grouping, sep)); - return true; - } - - template ::value)> - auto operator()(T) -> bool { - return false; - } -}; - -template -FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg arg, - const format_specs& specs, - locale_ref) -> OutputIt { - static_assert(std::is_same>::value, ""); - auto abs_value = arg.abs_value; - auto prefix = arg.prefix; - switch (specs.type) { - case presentation_type::none: - case presentation_type::dec: { - auto num_digits = count_digits(abs_value); - return write_int( - out, num_digits, prefix, specs, [=](reserve_iterator it) { - return format_decimal(it, abs_value, num_digits).end; - }); - } - case presentation_type::hex_lower: - case presentation_type::hex_upper: { - bool upper = specs.type == presentation_type::hex_upper; - if (specs.alt) - prefix_append(prefix, unsigned(upper ? 'X' : 'x') << 8 | '0'); - int num_digits = count_digits<4>(abs_value); - return write_int( - out, num_digits, prefix, specs, [=](reserve_iterator it) { - return format_uint<4, Char>(it, abs_value, num_digits, upper); - }); - } - case presentation_type::bin_lower: - case presentation_type::bin_upper: { - bool upper = specs.type == presentation_type::bin_upper; - if (specs.alt) - prefix_append(prefix, unsigned(upper ? 'B' : 'b') << 8 | '0'); - int num_digits = count_digits<1>(abs_value); - return write_int(out, num_digits, prefix, specs, - [=](reserve_iterator it) { - return format_uint<1, Char>(it, abs_value, num_digits); - }); - } - case presentation_type::oct: { - int num_digits = count_digits<3>(abs_value); - // Octal prefix '0' is counted as a digit, so only add it if precision - // is not greater than the number of digits. - if (specs.alt && specs.precision <= num_digits && abs_value != 0) - prefix_append(prefix, '0'); - return write_int(out, num_digits, prefix, specs, - [=](reserve_iterator it) { - return format_uint<3, Char>(it, abs_value, num_digits); - }); - } - case presentation_type::chr: - return write_char(out, static_cast(abs_value), specs); - default: - throw_format_error("invalid format specifier"); - } - return out; -} -template -FMT_CONSTEXPR FMT_NOINLINE auto write_int_noinline( - OutputIt out, write_int_arg arg, const format_specs& specs, - locale_ref loc) -> OutputIt { - return write_int(out, arg, specs, loc); -} -template ::value && - !std::is_same::value && - std::is_same>::value)> -FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, - const format_specs& specs, - locale_ref loc) -> OutputIt { - if (specs.localized && write_loc(out, value, specs, loc)) return out; - return write_int_noinline(out, make_write_int_arg(value, specs.sign), specs, - loc); -} -// An inlined version of write used in format string compilation. -template ::value && - !std::is_same::value && - !std::is_same>::value)> -FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value, - const format_specs& specs, - locale_ref loc) -> OutputIt { - if (specs.localized && write_loc(out, value, specs, loc)) return out; - return write_int(out, make_write_int_arg(value, specs.sign), specs, loc); -} - -// An output iterator that counts the number of objects written to it and -// discards them. -class counting_iterator { - private: - size_t count_; - - public: - using iterator_category = std::output_iterator_tag; - using difference_type = std::ptrdiff_t; - using pointer = void; - using reference = void; - FMT_UNCHECKED_ITERATOR(counting_iterator); - - struct value_type { - template FMT_CONSTEXPR void operator=(const T&) {} - }; - - FMT_CONSTEXPR counting_iterator() : count_(0) {} - - FMT_CONSTEXPR size_t count() const { return count_; } - - FMT_CONSTEXPR counting_iterator& operator++() { - ++count_; - return *this; - } - FMT_CONSTEXPR counting_iterator operator++(int) { - auto it = *this; - ++*this; - return it; - } - - FMT_CONSTEXPR friend counting_iterator operator+(counting_iterator it, - difference_type n) { - it.count_ += static_cast(n); - return it; - } - - FMT_CONSTEXPR value_type operator*() const { return {}; } -}; - -template -FMT_CONSTEXPR auto write(OutputIt out, basic_string_view s, - const format_specs& specs) -> OutputIt { - auto data = s.data(); - auto size = s.size(); - if (specs.precision >= 0 && to_unsigned(specs.precision) < size) - size = code_point_index(s, to_unsigned(specs.precision)); - bool is_debug = specs.type == presentation_type::debug; - size_t width = 0; - if (specs.width != 0) { - if (is_debug) - width = write_escaped_string(counting_iterator{}, s).count(); - else - width = compute_width(basic_string_view(data, size)); - } - return write_padded(out, specs, size, width, - [=](reserve_iterator it) { - if (is_debug) return write_escaped_string(it, s); - return copy_str(data, data + size, it); - }); -} -template -FMT_CONSTEXPR auto write(OutputIt out, - basic_string_view> s, - const format_specs& specs, locale_ref) - -> OutputIt { - return write(out, s, specs); -} -template -FMT_CONSTEXPR auto write(OutputIt out, const Char* s, - const format_specs& specs, locale_ref) - -> OutputIt { - return specs.type != presentation_type::pointer - ? write(out, basic_string_view(s), specs, {}) - : write_ptr(out, bit_cast(s), &specs); -} - -template ::value && - !std::is_same::value && - !std::is_same::value)> -FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { - auto abs_value = static_cast>(value); - bool negative = is_negative(value); - // Don't do -abs_value since it trips unsigned-integer-overflow sanitizer. - if (negative) abs_value = ~abs_value + 1; - int num_digits = count_digits(abs_value); - auto size = (negative ? 1 : 0) + static_cast(num_digits); - auto it = reserve(out, size); - if (auto ptr = to_pointer(it, size)) { - if (negative) *ptr++ = static_cast('-'); - format_decimal(ptr, abs_value, num_digits); - return out; - } - if (negative) *it++ = static_cast('-'); - it = format_decimal(it, abs_value, num_digits).end; - return base_iterator(out, it); -} - -// DEPRECATED! -template -FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end, - format_specs& specs) -> const Char* { - FMT_ASSERT(begin != end, ""); - auto align = align::none; - auto p = begin + code_point_length(begin); - if (end - p <= 0) p = begin; - for (;;) { - switch (to_ascii(*p)) { - case '<': - align = align::left; - break; - case '>': - align = align::right; - break; - case '^': - align = align::center; - break; - } - if (align != align::none) { - if (p != begin) { - auto c = *begin; - if (c == '}') return begin; - if (c == '{') { - throw_format_error("invalid fill character '{'"); - return begin; - } - specs.fill = {begin, to_unsigned(p - begin)}; - begin = p + 1; - } else { - ++begin; - } - break; - } else if (p == begin) { - break; - } - p = begin; - } - specs.align = align; - return begin; -} - -// A floating-point presentation format. -enum class float_format : unsigned char { - general, // General: exponent notation or fixed point based on magnitude. - exp, // Exponent notation with the default precision of 6, e.g. 1.2e-3. - fixed, // Fixed point with the default precision of 6, e.g. 0.0012. - hex -}; - -struct float_specs { - int precision; - float_format format : 8; - sign_t sign : 8; - bool upper : 1; - bool locale : 1; - bool binary32 : 1; - bool showpoint : 1; -}; - -template -FMT_CONSTEXPR auto parse_float_type_spec(const format_specs& specs, - ErrorHandler&& eh = {}) - -> float_specs { - auto result = float_specs(); - result.showpoint = specs.alt; - result.locale = specs.localized; - switch (specs.type) { - case presentation_type::none: - result.format = float_format::general; - break; - case presentation_type::general_upper: - result.upper = true; - FMT_FALLTHROUGH; - case presentation_type::general_lower: - result.format = float_format::general; - break; - case presentation_type::exp_upper: - result.upper = true; - FMT_FALLTHROUGH; - case presentation_type::exp_lower: - result.format = float_format::exp; - result.showpoint |= specs.precision != 0; - break; - case presentation_type::fixed_upper: - result.upper = true; - FMT_FALLTHROUGH; - case presentation_type::fixed_lower: - result.format = float_format::fixed; - result.showpoint |= specs.precision != 0; - break; - case presentation_type::hexfloat_upper: - result.upper = true; - FMT_FALLTHROUGH; - case presentation_type::hexfloat_lower: - result.format = float_format::hex; - break; - default: - eh.on_error("invalid format specifier"); - break; - } - return result; -} - -template -FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan, - format_specs specs, - const float_specs& fspecs) -> OutputIt { - auto str = - isnan ? (fspecs.upper ? "NAN" : "nan") : (fspecs.upper ? "INF" : "inf"); - constexpr size_t str_size = 3; - auto sign = fspecs.sign; - auto size = str_size + (sign ? 1 : 0); - // Replace '0'-padding with space for non-finite values. - const bool is_zero_fill = - specs.fill.size() == 1 && *specs.fill.data() == static_cast('0'); - if (is_zero_fill) specs.fill[0] = static_cast(' '); - return write_padded(out, specs, size, [=](reserve_iterator it) { - if (sign) *it++ = detail::sign(sign); - return copy_str(str, str + str_size, it); - }); -} - -// A decimal floating-point number significand * pow(10, exp). -struct big_decimal_fp { - const char* significand; - int significand_size; - int exponent; -}; - -constexpr auto get_significand_size(const big_decimal_fp& f) -> int { - return f.significand_size; -} -template -inline auto get_significand_size(const dragonbox::decimal_fp& f) -> int { - return count_digits(f.significand); -} - -template -constexpr auto write_significand(OutputIt out, const char* significand, - int significand_size) -> OutputIt { - return copy_str(significand, significand + significand_size, out); -} -template -inline auto write_significand(OutputIt out, UInt significand, - int significand_size) -> OutputIt { - return format_decimal(out, significand, significand_size).end; -} -template -FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, - int significand_size, int exponent, - const Grouping& grouping) -> OutputIt { - if (!grouping.has_separator()) { - out = write_significand(out, significand, significand_size); - return detail::fill_n(out, exponent, static_cast('0')); - } - auto buffer = memory_buffer(); - write_significand(appender(buffer), significand, significand_size); - detail::fill_n(appender(buffer), exponent, '0'); - return grouping.apply(out, string_view(buffer.data(), buffer.size())); -} - -template ::value)> -inline auto write_significand(Char* out, UInt significand, int significand_size, - int integral_size, Char decimal_point) -> Char* { - if (!decimal_point) - return format_decimal(out, significand, significand_size).end; - out += significand_size + 1; - Char* end = out; - int floating_size = significand_size - integral_size; - for (int i = floating_size / 2; i > 0; --i) { - out -= 2; - copy2(out, digits2(static_cast(significand % 100))); - significand /= 100; - } - if (floating_size % 2 != 0) { - *--out = static_cast('0' + significand % 10); - significand /= 10; - } - *--out = decimal_point; - format_decimal(out - integral_size, significand, integral_size); - return end; -} - -template >::value)> -inline auto write_significand(OutputIt out, UInt significand, - int significand_size, int integral_size, - Char decimal_point) -> OutputIt { - // Buffer is large enough to hold digits (digits10 + 1) and a decimal point. - Char buffer[digits10() + 2]; - auto end = write_significand(buffer, significand, significand_size, - integral_size, decimal_point); - return detail::copy_str_noinline(buffer, end, out); -} - -template -FMT_CONSTEXPR auto write_significand(OutputIt out, const char* significand, - int significand_size, int integral_size, - Char decimal_point) -> OutputIt { - out = detail::copy_str_noinline(significand, - significand + integral_size, out); - if (!decimal_point) return out; - *out++ = decimal_point; - return detail::copy_str_noinline(significand + integral_size, - significand + significand_size, out); -} - -template -FMT_CONSTEXPR20 auto write_significand(OutputIt out, T significand, - int significand_size, int integral_size, - Char decimal_point, - const Grouping& grouping) -> OutputIt { - if (!grouping.has_separator()) { - return write_significand(out, significand, significand_size, integral_size, - decimal_point); - } - auto buffer = basic_memory_buffer(); - write_significand(buffer_appender(buffer), significand, - significand_size, integral_size, decimal_point); - grouping.apply( - out, basic_string_view(buffer.data(), to_unsigned(integral_size))); - return detail::copy_str_noinline(buffer.data() + integral_size, - buffer.end(), out); -} - -template > -FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f, - const format_specs& specs, - float_specs fspecs, locale_ref loc) - -> OutputIt { - auto significand = f.significand; - int significand_size = get_significand_size(f); - const Char zero = static_cast('0'); - auto sign = fspecs.sign; - size_t size = to_unsigned(significand_size) + (sign ? 1 : 0); - using iterator = reserve_iterator; - - Char decimal_point = - fspecs.locale ? detail::decimal_point(loc) : static_cast('.'); - - int output_exp = f.exponent + significand_size - 1; - auto use_exp_format = [=]() { - if (fspecs.format == float_format::exp) return true; - if (fspecs.format != float_format::general) return false; - // Use the fixed notation if the exponent is in [exp_lower, exp_upper), - // e.g. 0.0001 instead of 1e-04. Otherwise use the exponent notation. - const int exp_lower = -4, exp_upper = 16; - return output_exp < exp_lower || - output_exp >= (fspecs.precision > 0 ? fspecs.precision : exp_upper); - }; - if (use_exp_format()) { - int num_zeros = 0; - if (fspecs.showpoint) { - num_zeros = fspecs.precision - significand_size; - if (num_zeros < 0) num_zeros = 0; - size += to_unsigned(num_zeros); - } else if (significand_size == 1) { - decimal_point = Char(); - } - auto abs_output_exp = output_exp >= 0 ? output_exp : -output_exp; - int exp_digits = 2; - if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3; - - size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits); - char exp_char = fspecs.upper ? 'E' : 'e'; - auto write = [=](iterator it) { - if (sign) *it++ = detail::sign(sign); - // Insert a decimal point after the first digit and add an exponent. - it = write_significand(it, significand, significand_size, 1, - decimal_point); - if (num_zeros > 0) it = detail::fill_n(it, num_zeros, zero); - *it++ = static_cast(exp_char); - return write_exponent(output_exp, it); - }; - return specs.width > 0 ? write_padded(out, specs, size, write) - : base_iterator(out, write(reserve(out, size))); - } - - int exp = f.exponent + significand_size; - if (f.exponent >= 0) { - // 1234e5 -> 123400000[.0+] - size += to_unsigned(f.exponent); - int num_zeros = fspecs.precision - exp; - abort_fuzzing_if(num_zeros > 5000); - if (fspecs.showpoint) { - ++size; - if (num_zeros <= 0 && fspecs.format != float_format::fixed) num_zeros = 0; - if (num_zeros > 0) size += to_unsigned(num_zeros); - } - auto grouping = Grouping(loc, fspecs.locale); - size += to_unsigned(grouping.count_separators(exp)); - return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = detail::sign(sign); - it = write_significand(it, significand, significand_size, - f.exponent, grouping); - if (!fspecs.showpoint) return it; - *it++ = decimal_point; - return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; - }); - } else if (exp > 0) { - // 1234e-2 -> 12.34[0+] - int num_zeros = fspecs.showpoint ? fspecs.precision - significand_size : 0; - size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0); - auto grouping = Grouping(loc, fspecs.locale); - size += to_unsigned(grouping.count_separators(exp)); - return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = detail::sign(sign); - it = write_significand(it, significand, significand_size, exp, - decimal_point, grouping); - return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it; - }); - } - // 1234e-6 -> 0.001234 - int num_zeros = -exp; - if (significand_size == 0 && fspecs.precision >= 0 && - fspecs.precision < num_zeros) { - num_zeros = fspecs.precision; - } - bool pointy = num_zeros != 0 || significand_size != 0 || fspecs.showpoint; - size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros); - return write_padded(out, specs, size, [&](iterator it) { - if (sign) *it++ = detail::sign(sign); - *it++ = zero; - if (!pointy) return it; - *it++ = decimal_point; - it = detail::fill_n(it, num_zeros, zero); - return write_significand(it, significand, significand_size); - }); -} - -template class fallback_digit_grouping { - public: - constexpr fallback_digit_grouping(locale_ref, bool) {} - - constexpr bool has_separator() const { return false; } - - constexpr int count_separators(int) const { return 0; } - - template - constexpr Out apply(Out out, basic_string_view) const { - return out; - } -}; - -template -FMT_CONSTEXPR20 auto write_float(OutputIt out, const DecimalFP& f, - const format_specs& specs, - float_specs fspecs, locale_ref loc) - -> OutputIt { - if (is_constant_evaluated()) { - return do_write_float>(out, f, specs, fspecs, - loc); - } else { - return do_write_float(out, f, specs, fspecs, loc); - } -} - -template constexpr bool isnan(T value) { - return !(value >= value); // std::isnan doesn't support __float128. -} - -template -struct has_isfinite : std::false_type {}; - -template -struct has_isfinite> - : std::true_type {}; - -template ::value&& - has_isfinite::value)> -FMT_CONSTEXPR20 bool isfinite(T value) { - constexpr T inf = T(std::numeric_limits::infinity()); - if (is_constant_evaluated()) - return !detail::isnan(value) && value < inf && value > -inf; - return std::isfinite(value); -} -template ::value)> -FMT_CONSTEXPR bool isfinite(T value) { - T inf = T(std::numeric_limits::infinity()); - // std::isfinite doesn't support __float128. - return !detail::isnan(value) && value < inf && value > -inf; -} - -template ::value)> -FMT_INLINE FMT_CONSTEXPR bool signbit(T value) { - if (is_constant_evaluated()) { -#ifdef __cpp_if_constexpr - if constexpr (std::numeric_limits::is_iec559) { - auto bits = detail::bit_cast(static_cast(value)); - return (bits >> (num_bits() - 1)) != 0; - } -#endif - } - return std::signbit(static_cast(value)); -} - -inline FMT_CONSTEXPR20 void adjust_precision(int& precision, int exp10) { - // Adjust fixed precision by exponent because it is relative to decimal - // point. - if (exp10 > 0 && precision > max_value() - exp10) - FMT_THROW(format_error("number is too big")); - precision += exp10; -} - -class bigint { - private: - // A bigint is stored as an array of bigits (big digits), with bigit at index - // 0 being the least significant one. - using bigit = uint32_t; - using double_bigit = uint64_t; - enum { bigits_capacity = 32 }; - basic_memory_buffer bigits_; - int exp_; - - FMT_CONSTEXPR20 bigit operator[](int index) const { - return bigits_[to_unsigned(index)]; - } - FMT_CONSTEXPR20 bigit& operator[](int index) { - return bigits_[to_unsigned(index)]; - } - - static constexpr const int bigit_bits = num_bits(); - - friend struct formatter; - - FMT_CONSTEXPR20 void subtract_bigits(int index, bigit other, bigit& borrow) { - auto result = static_cast((*this)[index]) - other - borrow; - (*this)[index] = static_cast(result); - borrow = static_cast(result >> (bigit_bits * 2 - 1)); - } - - FMT_CONSTEXPR20 void remove_leading_zeros() { - int num_bigits = static_cast(bigits_.size()) - 1; - while (num_bigits > 0 && (*this)[num_bigits] == 0) --num_bigits; - bigits_.resize(to_unsigned(num_bigits + 1)); - } - - // Computes *this -= other assuming aligned bigints and *this >= other. - FMT_CONSTEXPR20 void subtract_aligned(const bigint& other) { - FMT_ASSERT(other.exp_ >= exp_, "unaligned bigints"); - FMT_ASSERT(compare(*this, other) >= 0, ""); - bigit borrow = 0; - int i = other.exp_ - exp_; - for (size_t j = 0, n = other.bigits_.size(); j != n; ++i, ++j) - subtract_bigits(i, other.bigits_[j], borrow); - while (borrow > 0) subtract_bigits(i, 0, borrow); - remove_leading_zeros(); - } - - FMT_CONSTEXPR20 void multiply(uint32_t value) { - const double_bigit wide_value = value; - bigit carry = 0; - for (size_t i = 0, n = bigits_.size(); i < n; ++i) { - double_bigit result = bigits_[i] * wide_value + carry; - bigits_[i] = static_cast(result); - carry = static_cast(result >> bigit_bits); - } - if (carry != 0) bigits_.push_back(carry); - } - - template ::value || - std::is_same::value)> - FMT_CONSTEXPR20 void multiply(UInt value) { - using half_uint = - conditional_t::value, uint64_t, uint32_t>; - const int shift = num_bits() - bigit_bits; - const UInt lower = static_cast(value); - const UInt upper = value >> num_bits(); - UInt carry = 0; - for (size_t i = 0, n = bigits_.size(); i < n; ++i) { - UInt result = lower * bigits_[i] + static_cast(carry); - carry = (upper * bigits_[i] << shift) + (result >> bigit_bits) + - (carry >> bigit_bits); - bigits_[i] = static_cast(result); - } - while (carry != 0) { - bigits_.push_back(static_cast(carry)); - carry >>= bigit_bits; - } - } - - template ::value || - std::is_same::value)> - FMT_CONSTEXPR20 void assign(UInt n) { - size_t num_bigits = 0; - do { - bigits_[num_bigits++] = static_cast(n); - n >>= bigit_bits; - } while (n != 0); - bigits_.resize(num_bigits); - exp_ = 0; - } - - public: - FMT_CONSTEXPR20 bigint() : exp_(0) {} - explicit bigint(uint64_t n) { assign(n); } - - bigint(const bigint&) = delete; - void operator=(const bigint&) = delete; - - FMT_CONSTEXPR20 void assign(const bigint& other) { - auto size = other.bigits_.size(); - bigits_.resize(size); - auto data = other.bigits_.data(); - copy_str(data, data + size, bigits_.data()); - exp_ = other.exp_; - } - - template FMT_CONSTEXPR20 void operator=(Int n) { - FMT_ASSERT(n > 0, ""); - assign(uint64_or_128_t(n)); - } - - FMT_CONSTEXPR20 int num_bigits() const { - return static_cast(bigits_.size()) + exp_; - } - - FMT_NOINLINE FMT_CONSTEXPR20 bigint& operator<<=(int shift) { - FMT_ASSERT(shift >= 0, ""); - exp_ += shift / bigit_bits; - shift %= bigit_bits; - if (shift == 0) return *this; - bigit carry = 0; - for (size_t i = 0, n = bigits_.size(); i < n; ++i) { - bigit c = bigits_[i] >> (bigit_bits - shift); - bigits_[i] = (bigits_[i] << shift) + carry; - carry = c; - } - if (carry != 0) bigits_.push_back(carry); - return *this; - } - - template FMT_CONSTEXPR20 bigint& operator*=(Int value) { - FMT_ASSERT(value > 0, ""); - multiply(uint32_or_64_or_128_t(value)); - return *this; - } - - friend FMT_CONSTEXPR20 int compare(const bigint& lhs, const bigint& rhs) { - int num_lhs_bigits = lhs.num_bigits(), num_rhs_bigits = rhs.num_bigits(); - if (num_lhs_bigits != num_rhs_bigits) - return num_lhs_bigits > num_rhs_bigits ? 1 : -1; - int i = static_cast(lhs.bigits_.size()) - 1; - int j = static_cast(rhs.bigits_.size()) - 1; - int end = i - j; - if (end < 0) end = 0; - for (; i >= end; --i, --j) { - bigit lhs_bigit = lhs[i], rhs_bigit = rhs[j]; - if (lhs_bigit != rhs_bigit) return lhs_bigit > rhs_bigit ? 1 : -1; - } - if (i != j) return i > j ? 1 : -1; - return 0; - } - - // Returns compare(lhs1 + lhs2, rhs). - friend FMT_CONSTEXPR20 int add_compare(const bigint& lhs1, const bigint& lhs2, - const bigint& rhs) { - auto minimum = [](int a, int b) { return a < b ? a : b; }; - auto maximum = [](int a, int b) { return a > b ? a : b; }; - int max_lhs_bigits = maximum(lhs1.num_bigits(), lhs2.num_bigits()); - int num_rhs_bigits = rhs.num_bigits(); - if (max_lhs_bigits + 1 < num_rhs_bigits) return -1; - if (max_lhs_bigits > num_rhs_bigits) return 1; - auto get_bigit = [](const bigint& n, int i) -> bigit { - return i >= n.exp_ && i < n.num_bigits() ? n[i - n.exp_] : 0; - }; - double_bigit borrow = 0; - int min_exp = minimum(minimum(lhs1.exp_, lhs2.exp_), rhs.exp_); - for (int i = num_rhs_bigits - 1; i >= min_exp; --i) { - double_bigit sum = - static_cast(get_bigit(lhs1, i)) + get_bigit(lhs2, i); - bigit rhs_bigit = get_bigit(rhs, i); - if (sum > rhs_bigit + borrow) return 1; - borrow = rhs_bigit + borrow - sum; - if (borrow > 1) return -1; - borrow <<= bigit_bits; - } - return borrow != 0 ? -1 : 0; - } - - // Assigns pow(10, exp) to this bigint. - FMT_CONSTEXPR20 void assign_pow10(int exp) { - FMT_ASSERT(exp >= 0, ""); - if (exp == 0) return *this = 1; - // Find the top bit. - int bitmask = 1; - while (exp >= bitmask) bitmask <<= 1; - bitmask >>= 1; - // pow(10, exp) = pow(5, exp) * pow(2, exp). First compute pow(5, exp) by - // repeated squaring and multiplication. - *this = 5; - bitmask >>= 1; - while (bitmask != 0) { - square(); - if ((exp & bitmask) != 0) *this *= 5; - bitmask >>= 1; - } - *this <<= exp; // Multiply by pow(2, exp) by shifting. - } - - FMT_CONSTEXPR20 void square() { - int num_bigits = static_cast(bigits_.size()); - int num_result_bigits = 2 * num_bigits; - basic_memory_buffer n(std::move(bigits_)); - bigits_.resize(to_unsigned(num_result_bigits)); - auto sum = uint128_t(); - for (int bigit_index = 0; bigit_index < num_bigits; ++bigit_index) { - // Compute bigit at position bigit_index of the result by adding - // cross-product terms n[i] * n[j] such that i + j == bigit_index. - for (int i = 0, j = bigit_index; j >= 0; ++i, --j) { - // Most terms are multiplied twice which can be optimized in the future. - sum += static_cast(n[i]) * n[j]; - } - (*this)[bigit_index] = static_cast(sum); - sum >>= num_bits(); // Compute the carry. - } - // Do the same for the top half. - for (int bigit_index = num_bigits; bigit_index < num_result_bigits; - ++bigit_index) { - for (int j = num_bigits - 1, i = bigit_index - j; i < num_bigits;) - sum += static_cast(n[i++]) * n[j--]; - (*this)[bigit_index] = static_cast(sum); - sum >>= num_bits(); - } - remove_leading_zeros(); - exp_ *= 2; - } - - // If this bigint has a bigger exponent than other, adds trailing zero to make - // exponents equal. This simplifies some operations such as subtraction. - FMT_CONSTEXPR20 void align(const bigint& other) { - int exp_difference = exp_ - other.exp_; - if (exp_difference <= 0) return; - int num_bigits = static_cast(bigits_.size()); - bigits_.resize(to_unsigned(num_bigits + exp_difference)); - for (int i = num_bigits - 1, j = i + exp_difference; i >= 0; --i, --j) - bigits_[j] = bigits_[i]; - std::uninitialized_fill_n(bigits_.data(), exp_difference, 0); - exp_ -= exp_difference; - } - - // Divides this bignum by divisor, assigning the remainder to this and - // returning the quotient. - FMT_CONSTEXPR20 int divmod_assign(const bigint& divisor) { - FMT_ASSERT(this != &divisor, ""); - if (compare(*this, divisor) < 0) return 0; - FMT_ASSERT(divisor.bigits_[divisor.bigits_.size() - 1u] != 0, ""); - align(divisor); - int quotient = 0; - do { - subtract_aligned(divisor); - ++quotient; - } while (compare(*this, divisor) >= 0); - return quotient; - } -}; - -// format_dragon flags. -enum dragon { - predecessor_closer = 1, - fixup = 2, // Run fixup to correct exp10 which can be off by one. - fixed = 4, -}; - -// Formats a floating-point number using a variation of the Fixed-Precision -// Positive Floating-Point Printout ((FPP)^2) algorithm by Steele & White: -// https://fmt.dev/papers/p372-steele.pdf. -FMT_CONSTEXPR20 inline void format_dragon(basic_fp value, - unsigned flags, int num_digits, - buffer& buf, int& exp10) { - bigint numerator; // 2 * R in (FPP)^2. - bigint denominator; // 2 * S in (FPP)^2. - // lower and upper are differences between value and corresponding boundaries. - bigint lower; // (M^- in (FPP)^2). - bigint upper_store; // upper's value if different from lower. - bigint* upper = nullptr; // (M^+ in (FPP)^2). - // Shift numerator and denominator by an extra bit or two (if lower boundary - // is closer) to make lower and upper integers. This eliminates multiplication - // by 2 during later computations. - bool is_predecessor_closer = (flags & dragon::predecessor_closer) != 0; - int shift = is_predecessor_closer ? 2 : 1; - if (value.e >= 0) { - numerator = value.f; - numerator <<= value.e + shift; - lower = 1; - lower <<= value.e; - if (is_predecessor_closer) { - upper_store = 1; - upper_store <<= value.e + 1; - upper = &upper_store; - } - denominator.assign_pow10(exp10); - denominator <<= shift; - } else if (exp10 < 0) { - numerator.assign_pow10(-exp10); - lower.assign(numerator); - if (is_predecessor_closer) { - upper_store.assign(numerator); - upper_store <<= 1; - upper = &upper_store; - } - numerator *= value.f; - numerator <<= shift; - denominator = 1; - denominator <<= shift - value.e; - } else { - numerator = value.f; - numerator <<= shift; - denominator.assign_pow10(exp10); - denominator <<= shift - value.e; - lower = 1; - if (is_predecessor_closer) { - upper_store = 1ULL << 1; - upper = &upper_store; - } - } - int even = static_cast((value.f & 1) == 0); - if (!upper) upper = &lower; - bool shortest = num_digits < 0; - if ((flags & dragon::fixup) != 0) { - if (add_compare(numerator, *upper, denominator) + even <= 0) { - --exp10; - numerator *= 10; - if (num_digits < 0) { - lower *= 10; - if (upper != &lower) *upper *= 10; - } - } - if ((flags & dragon::fixed) != 0) adjust_precision(num_digits, exp10 + 1); - } - // Invariant: value == (numerator / denominator) * pow(10, exp10). - if (shortest) { - // Generate the shortest representation. - num_digits = 0; - char* data = buf.data(); - for (;;) { - int digit = numerator.divmod_assign(denominator); - bool low = compare(numerator, lower) - even < 0; // numerator <[=] lower. - // numerator + upper >[=] pow10: - bool high = add_compare(numerator, *upper, denominator) + even > 0; - data[num_digits++] = static_cast('0' + digit); - if (low || high) { - if (!low) { - ++data[num_digits - 1]; - } else if (high) { - int result = add_compare(numerator, numerator, denominator); - // Round half to even. - if (result > 0 || (result == 0 && (digit % 2) != 0)) - ++data[num_digits - 1]; - } - buf.try_resize(to_unsigned(num_digits)); - exp10 -= num_digits - 1; - return; - } - numerator *= 10; - lower *= 10; - if (upper != &lower) *upper *= 10; - } - } - // Generate the given number of digits. - exp10 -= num_digits - 1; - if (num_digits <= 0) { - denominator *= 10; - auto digit = add_compare(numerator, numerator, denominator) > 0 ? '1' : '0'; - buf.push_back(digit); - return; - } - buf.try_resize(to_unsigned(num_digits)); - for (int i = 0; i < num_digits - 1; ++i) { - int digit = numerator.divmod_assign(denominator); - buf[i] = static_cast('0' + digit); - numerator *= 10; - } - int digit = numerator.divmod_assign(denominator); - auto result = add_compare(numerator, numerator, denominator); - if (result > 0 || (result == 0 && (digit % 2) != 0)) { - if (digit == 9) { - const auto overflow = '0' + 10; - buf[num_digits - 1] = overflow; - // Propagate the carry. - for (int i = num_digits - 1; i > 0 && buf[i] == overflow; --i) { - buf[i] = '0'; - ++buf[i - 1]; - } - if (buf[0] == overflow) { - buf[0] = '1'; - if ((flags & dragon::fixed) != 0) buf.push_back('0'); - else ++exp10; - } - return; - } - ++digit; - } - buf[num_digits - 1] = static_cast('0' + digit); -} - -// Formats a floating-point number using the hexfloat format. -template ::value)> -FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision, - float_specs specs, buffer& buf) { - // float is passed as double to reduce the number of instantiations and to - // simplify implementation. - static_assert(!std::is_same::value, ""); - - using info = dragonbox::float_info; - - // Assume Float is in the format [sign][exponent][significand]. - using carrier_uint = typename info::carrier_uint; - - constexpr auto num_float_significand_bits = - detail::num_significand_bits(); - - basic_fp f(value); - f.e += num_float_significand_bits; - if (!has_implicit_bit()) --f.e; - - constexpr auto num_fraction_bits = - num_float_significand_bits + (has_implicit_bit() ? 1 : 0); - constexpr auto num_xdigits = (num_fraction_bits + 3) / 4; - - constexpr auto leading_shift = ((num_xdigits - 1) * 4); - const auto leading_mask = carrier_uint(0xF) << leading_shift; - const auto leading_xdigit = - static_cast((f.f & leading_mask) >> leading_shift); - if (leading_xdigit > 1) f.e -= (32 - countl_zero(leading_xdigit) - 1); - - int print_xdigits = num_xdigits - 1; - if (precision >= 0 && print_xdigits > precision) { - const int shift = ((print_xdigits - precision - 1) * 4); - const auto mask = carrier_uint(0xF) << shift; - const auto v = static_cast((f.f & mask) >> shift); - - if (v >= 8) { - const auto inc = carrier_uint(1) << (shift + 4); - f.f += inc; - f.f &= ~(inc - 1); - } - - // Check long double overflow - if (!has_implicit_bit()) { - const auto implicit_bit = carrier_uint(1) << num_float_significand_bits; - if ((f.f & implicit_bit) == implicit_bit) { - f.f >>= 4; - f.e += 4; - } - } - - print_xdigits = precision; - } - - char xdigits[num_bits() / 4]; - detail::fill_n(xdigits, sizeof(xdigits), '0'); - format_uint<4>(xdigits, f.f, num_xdigits, specs.upper); - - // Remove zero tail - while (print_xdigits > 0 && xdigits[print_xdigits] == '0') --print_xdigits; - - buf.push_back('0'); - buf.push_back(specs.upper ? 'X' : 'x'); - buf.push_back(xdigits[0]); - if (specs.showpoint || print_xdigits > 0 || print_xdigits < precision) - buf.push_back('.'); - buf.append(xdigits + 1, xdigits + 1 + print_xdigits); - for (; print_xdigits < precision; ++print_xdigits) buf.push_back('0'); - - buf.push_back(specs.upper ? 'P' : 'p'); - - uint32_t abs_e; - if (f.e < 0) { - buf.push_back('-'); - abs_e = static_cast(-f.e); - } else { - buf.push_back('+'); - abs_e = static_cast(f.e); - } - format_decimal(appender(buf), abs_e, detail::count_digits(abs_e)); -} - -template ::value)> -FMT_CONSTEXPR20 void format_hexfloat(Float value, int precision, - float_specs specs, buffer& buf) { - format_hexfloat(static_cast(value), precision, specs, buf); -} - -template -FMT_CONSTEXPR20 auto format_float(Float value, int precision, float_specs specs, - buffer& buf) -> int { - // float is passed as double to reduce the number of instantiations. - static_assert(!std::is_same::value, ""); - FMT_ASSERT(value >= 0, "value is negative"); - auto converted_value = convert_float(value); - - const bool fixed = specs.format == float_format::fixed; - if (value <= 0) { // <= instead of == to silence a warning. - if (precision <= 0 || !fixed) { - buf.push_back('0'); - return 0; - } - buf.try_resize(to_unsigned(precision)); - fill_n(buf.data(), precision, '0'); - return -precision; - } - - int exp = 0; - bool use_dragon = true; - unsigned dragon_flags = 0; - if (!is_fast_float() || is_constant_evaluated()) { - const auto inv_log2_10 = 0.3010299956639812; // 1 / log2(10) - using info = dragonbox::float_info; - const auto f = basic_fp(converted_value); - // Compute exp, an approximate power of 10, such that - // 10^(exp - 1) <= value < 10^exp or 10^exp <= value < 10^(exp + 1). - // This is based on log10(value) == log2(value) / log2(10) and approximation - // of log2(value) by e + num_fraction_bits idea from double-conversion. - auto e = (f.e + count_digits<1>(f.f) - 1) * inv_log2_10 - 1e-10; - exp = static_cast(e); - if (e > exp) ++exp; // Compute ceil. - dragon_flags = dragon::fixup; - } else if (precision < 0) { - // Use Dragonbox for the shortest format. - if (specs.binary32) { - auto dec = dragonbox::to_decimal(static_cast(value)); - write(buffer_appender(buf), dec.significand); - return dec.exponent; - } - auto dec = dragonbox::to_decimal(static_cast(value)); - write(buffer_appender(buf), dec.significand); - return dec.exponent; - } else { - // Extract significand bits and exponent bits. - using info = dragonbox::float_info; - auto br = bit_cast(static_cast(value)); - - const uint64_t significand_mask = - (static_cast(1) << num_significand_bits()) - 1; - uint64_t significand = (br & significand_mask); - int exponent = static_cast((br & exponent_mask()) >> - num_significand_bits()); - - if (exponent != 0) { // Check if normal. - exponent -= exponent_bias() + num_significand_bits(); - significand |= - (static_cast(1) << num_significand_bits()); - significand <<= 1; - } else { - // Normalize subnormal inputs. - FMT_ASSERT(significand != 0, "zeros should not appear here"); - int shift = countl_zero(significand); - FMT_ASSERT(shift >= num_bits() - num_significand_bits(), - ""); - shift -= (num_bits() - num_significand_bits() - 2); - exponent = (std::numeric_limits::min_exponent - - num_significand_bits()) - - shift; - significand <<= shift; - } - - // Compute the first several nonzero decimal significand digits. - // We call the number we get the first segment. - const int k = info::kappa - dragonbox::floor_log10_pow2(exponent); - exp = -k; - const int beta = exponent + dragonbox::floor_log2_pow10(k); - uint64_t first_segment; - bool has_more_segments; - int digits_in_the_first_segment; - { - const auto r = dragonbox::umul192_upper128( - significand << beta, dragonbox::get_cached_power(k)); - first_segment = r.high(); - has_more_segments = r.low() != 0; - - // The first segment can have 18 ~ 19 digits. - if (first_segment >= 1000000000000000000ULL) { - digits_in_the_first_segment = 19; - } else { - // When it is of 18-digits, we align it to 19-digits by adding a bogus - // zero at the end. - digits_in_the_first_segment = 18; - first_segment *= 10; - } - } - - // Compute the actual number of decimal digits to print. - if (fixed) adjust_precision(precision, exp + digits_in_the_first_segment); - - // Use Dragon4 only when there might be not enough digits in the first - // segment. - if (digits_in_the_first_segment > precision) { - use_dragon = false; - - if (precision <= 0) { - exp += digits_in_the_first_segment; - - if (precision < 0) { - // Nothing to do, since all we have are just leading zeros. - buf.try_resize(0); - } else { - // We may need to round-up. - buf.try_resize(1); - if ((first_segment | static_cast(has_more_segments)) > - 5000000000000000000ULL) { - buf[0] = '1'; - } else { - buf[0] = '0'; - } - } - } // precision <= 0 - else { - exp += digits_in_the_first_segment - precision; - - // When precision > 0, we divide the first segment into three - // subsegments, each with 9, 9, and 0 ~ 1 digits so that each fits - // in 32-bits which usually allows faster calculation than in - // 64-bits. Since some compiler (e.g. MSVC) doesn't know how to optimize - // division-by-constant for large 64-bit divisors, we do it here - // manually. The magic number 7922816251426433760 below is equal to - // ceil(2^(64+32) / 10^10). - const uint32_t first_subsegment = static_cast( - dragonbox::umul128_upper64(first_segment, 7922816251426433760ULL) >> - 32); - const uint64_t second_third_subsegments = - first_segment - first_subsegment * 10000000000ULL; - - uint64_t prod; - uint32_t digits; - bool should_round_up; - int number_of_digits_to_print = precision > 9 ? 9 : precision; - - // Print a 9-digits subsegment, either the first or the second. - auto print_subsegment = [&](uint32_t subsegment, char* buffer) { - int number_of_digits_printed = 0; - - // If we want to print an odd number of digits from the subsegment, - if ((number_of_digits_to_print & 1) != 0) { - // Convert to 64-bit fixed-point fractional form with 1-digit - // integer part. The magic number 720575941 is a good enough - // approximation of 2^(32 + 24) / 10^8; see - // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case - // for details. - prod = ((subsegment * static_cast(720575941)) >> 24) + 1; - digits = static_cast(prod >> 32); - *buffer = static_cast('0' + digits); - number_of_digits_printed++; - } - // If we want to print an even number of digits from the - // first_subsegment, - else { - // Convert to 64-bit fixed-point fractional form with 2-digits - // integer part. The magic number 450359963 is a good enough - // approximation of 2^(32 + 20) / 10^7; see - // https://jk-jeon.github.io/posts/2022/12/fixed-precision-formatting/#fixed-length-case - // for details. - prod = ((subsegment * static_cast(450359963)) >> 20) + 1; - digits = static_cast(prod >> 32); - copy2(buffer, digits2(digits)); - number_of_digits_printed += 2; - } - - // Print all digit pairs. - while (number_of_digits_printed < number_of_digits_to_print) { - prod = static_cast(prod) * static_cast(100); - digits = static_cast(prod >> 32); - copy2(buffer + number_of_digits_printed, digits2(digits)); - number_of_digits_printed += 2; - } - }; - - // Print first subsegment. - print_subsegment(first_subsegment, buf.data()); - - // Perform rounding if the first subsegment is the last subsegment to - // print. - if (precision <= 9) { - // Rounding inside the subsegment. - // We round-up if: - // - either the fractional part is strictly larger than 1/2, or - // - the fractional part is exactly 1/2 and the last digit is odd. - // We rely on the following observations: - // - If fractional_part >= threshold, then the fractional part is - // strictly larger than 1/2. - // - If the MSB of fractional_part is set, then the fractional part - // must be at least 1/2. - // - When the MSB of fractional_part is set, either - // second_third_subsegments being nonzero or has_more_segments - // being true means there are further digits not printed, so the - // fractional part is strictly larger than 1/2. - if (precision < 9) { - uint32_t fractional_part = static_cast(prod); - should_round_up = fractional_part >= - data::fractional_part_rounding_thresholds - [8 - number_of_digits_to_print] || - ((fractional_part >> 31) & - ((digits & 1) | (second_third_subsegments != 0) | - has_more_segments)) != 0; - } - // Rounding at the subsegment boundary. - // In this case, the fractional part is at least 1/2 if and only if - // second_third_subsegments >= 5000000000ULL, and is strictly larger - // than 1/2 if we further have either second_third_subsegments > - // 5000000000ULL or has_more_segments == true. - else { - should_round_up = second_third_subsegments > 5000000000ULL || - (second_third_subsegments == 5000000000ULL && - ((digits & 1) != 0 || has_more_segments)); - } - } - // Otherwise, print the second subsegment. - else { - // Compilers are not aware of how to leverage the maximum value of - // second_third_subsegments to find out a better magic number which - // allows us to eliminate an additional shift. 1844674407370955162 = - // ceil(2^64/10) < ceil(2^64*(10^9/(10^10 - 1))). - const uint32_t second_subsegment = - static_cast(dragonbox::umul128_upper64( - second_third_subsegments, 1844674407370955162ULL)); - const uint32_t third_subsegment = - static_cast(second_third_subsegments) - - second_subsegment * 10; - - number_of_digits_to_print = precision - 9; - print_subsegment(second_subsegment, buf.data() + 9); - - // Rounding inside the subsegment. - if (precision < 18) { - // The condition third_subsegment != 0 implies that the segment was - // of 19 digits, so in this case the third segment should be - // consisting of a genuine digit from the input. - uint32_t fractional_part = static_cast(prod); - should_round_up = fractional_part >= - data::fractional_part_rounding_thresholds - [8 - number_of_digits_to_print] || - ((fractional_part >> 31) & - ((digits & 1) | (third_subsegment != 0) | - has_more_segments)) != 0; - } - // Rounding at the subsegment boundary. - else { - // In this case, the segment must be of 19 digits, thus - // the third subsegment should be consisting of a genuine digit from - // the input. - should_round_up = third_subsegment > 5 || - (third_subsegment == 5 && - ((digits & 1) != 0 || has_more_segments)); - } - } - - // Round-up if necessary. - if (should_round_up) { - ++buf[precision - 1]; - for (int i = precision - 1; i > 0 && buf[i] > '9'; --i) { - buf[i] = '0'; - ++buf[i - 1]; - } - if (buf[0] > '9') { - buf[0] = '1'; - if (fixed) - buf[precision++] = '0'; - else - ++exp; - } - } - buf.try_resize(to_unsigned(precision)); - } - } // if (digits_in_the_first_segment > precision) - else { - // Adjust the exponent for its use in Dragon4. - exp += digits_in_the_first_segment - 1; - } - } - if (use_dragon) { - auto f = basic_fp(); - bool is_predecessor_closer = specs.binary32 - ? f.assign(static_cast(value)) - : f.assign(converted_value); - if (is_predecessor_closer) dragon_flags |= dragon::predecessor_closer; - if (fixed) dragon_flags |= dragon::fixed; - // Limit precision to the maximum possible number of significant digits in - // an IEEE754 double because we don't need to generate zeros. - const int max_double_digits = 767; - if (precision > max_double_digits) precision = max_double_digits; - format_dragon(f, dragon_flags, precision, buf, exp); - } - if (!fixed && !specs.showpoint) { - // Remove trailing zeros. - auto num_digits = buf.size(); - while (num_digits > 0 && buf[num_digits - 1] == '0') { - --num_digits; - ++exp; - } - buf.try_resize(num_digits); - } - return exp; -} -template -FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, - format_specs specs, locale_ref loc) - -> OutputIt { - float_specs fspecs = parse_float_type_spec(specs); - fspecs.sign = specs.sign; - if (detail::signbit(value)) { // value < 0 is false for NaN so use signbit. - fspecs.sign = sign::minus; - value = -value; - } else if (fspecs.sign == sign::minus) { - fspecs.sign = sign::none; - } - - if (!detail::isfinite(value)) - return write_nonfinite(out, detail::isnan(value), specs, fspecs); - - if (specs.align == align::numeric && fspecs.sign) { - auto it = reserve(out, 1); - *it++ = detail::sign(fspecs.sign); - out = base_iterator(out, it); - fspecs.sign = sign::none; - if (specs.width != 0) --specs.width; - } - - memory_buffer buffer; - if (fspecs.format == float_format::hex) { - if (fspecs.sign) buffer.push_back(detail::sign(fspecs.sign)); - format_hexfloat(convert_float(value), specs.precision, fspecs, buffer); - return write_bytes(out, {buffer.data(), buffer.size()}, - specs); - } - int precision = specs.precision >= 0 || specs.type == presentation_type::none - ? specs.precision - : 6; - if (fspecs.format == float_format::exp) { - if (precision == max_value()) - throw_format_error("number is too big"); - else - ++precision; - } else if (fspecs.format != float_format::fixed && precision == 0) { - precision = 1; - } - if (const_check(std::is_same())) fspecs.binary32 = true; - int exp = format_float(convert_float(value), precision, fspecs, buffer); - fspecs.precision = precision; - auto f = big_decimal_fp{buffer.data(), static_cast(buffer.size()), exp}; - return write_float(out, f, specs, fspecs, loc); -} - -template ::value)> -FMT_CONSTEXPR20 auto write(OutputIt out, T value, format_specs specs, - locale_ref loc = {}) -> OutputIt { - if (const_check(!is_supported_floating_point(value))) return out; - return specs.localized && write_loc(out, value, specs, loc) - ? out - : write_float(out, value, specs, loc); -} - -template ::value)> -FMT_CONSTEXPR20 auto write(OutputIt out, T value) -> OutputIt { - if (is_constant_evaluated()) return write(out, value, format_specs()); - if (const_check(!is_supported_floating_point(value))) return out; - - auto fspecs = float_specs(); - if (detail::signbit(value)) { - fspecs.sign = sign::minus; - value = -value; - } - - constexpr auto specs = format_specs(); - using floaty = conditional_t::value, double, T>; - using floaty_uint = typename dragonbox::float_info::carrier_uint; - floaty_uint mask = exponent_mask(); - if ((bit_cast(value) & mask) == mask) - return write_nonfinite(out, std::isnan(value), specs, fspecs); - - auto dec = dragonbox::to_decimal(static_cast(value)); - return write_float(out, dec, specs, fspecs, {}); -} - -template ::value && - !is_fast_float::value)> -inline auto write(OutputIt out, T value) -> OutputIt { - return write(out, value, format_specs()); -} - -template -auto write(OutputIt out, monostate, format_specs = {}, locale_ref = {}) - -> OutputIt { - FMT_ASSERT(false, ""); - return out; -} - -template -FMT_CONSTEXPR auto write(OutputIt out, basic_string_view value) - -> OutputIt { - auto it = reserve(out, value.size()); - it = copy_str_noinline(value.begin(), value.end(), it); - return base_iterator(out, it); -} - -template ::value)> -constexpr auto write(OutputIt out, const T& value) -> OutputIt { - return write(out, to_string_view(value)); -} - -// FMT_ENABLE_IF() condition separated to workaround an MSVC bug. -template < - typename Char, typename OutputIt, typename T, - bool check = - std::is_enum::value && !std::is_same::value && - mapped_type_constant>::value != - type::custom_type, - FMT_ENABLE_IF(check)> -FMT_CONSTEXPR auto write(OutputIt out, T value) -> OutputIt { - return write(out, static_cast>(value)); -} - -template ::value)> -FMT_CONSTEXPR auto write(OutputIt out, T value, - const format_specs& specs = {}, locale_ref = {}) - -> OutputIt { - return specs.type != presentation_type::none && - specs.type != presentation_type::string - ? write(out, value ? 1 : 0, specs, {}) - : write_bytes(out, value ? "true" : "false", specs); -} - -template -FMT_CONSTEXPR auto write(OutputIt out, Char value) -> OutputIt { - auto it = reserve(out, 1); - *it++ = value; - return base_iterator(out, it); -} - -template -FMT_CONSTEXPR_CHAR_TRAITS auto write(OutputIt out, const Char* value) - -> OutputIt { - if (value) return write(out, basic_string_view(value)); - throw_format_error("string pointer is null"); - return out; -} - -template ::value)> -auto write(OutputIt out, const T* value, const format_specs& specs = {}, - locale_ref = {}) -> OutputIt { - return write_ptr(out, bit_cast(value), &specs); -} - -// A write overload that handles implicit conversions. -template > -FMT_CONSTEXPR auto write(OutputIt out, const T& value) -> enable_if_t< - std::is_class::value && !is_string::value && - !is_floating_point::value && !std::is_same::value && - !std::is_same().map( - value))>>::value, - OutputIt> { - return write(out, arg_mapper().map(value)); -} - -template > -FMT_CONSTEXPR auto write(OutputIt out, const T& value) - -> enable_if_t::value == type::custom_type, - OutputIt> { - auto ctx = Context(out, {}, {}); - return typename Context::template formatter_type().format(value, ctx); -} - -// An argument visitor that formats the argument and writes it via the output -// iterator. It's a class and not a generic lambda for compatibility with C++11. -template struct default_arg_formatter { - using iterator = buffer_appender; - using context = buffer_context; - - iterator out; - basic_format_args args; - locale_ref loc; - - template auto operator()(T value) -> iterator { - return write(out, value); - } - auto operator()(typename basic_format_arg::handle h) -> iterator { - basic_format_parse_context parse_ctx({}); - context format_ctx(out, args, loc); - h.format(parse_ctx, format_ctx); - return format_ctx.out(); - } -}; - -template struct arg_formatter { - using iterator = buffer_appender; - using context = buffer_context; - - iterator out; - const format_specs& specs; - locale_ref locale; - - template - FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator { - return detail::write(out, value, specs, locale); - } - auto operator()(typename basic_format_arg::handle) -> iterator { - // User-defined types are handled separately because they require access - // to the parse context. - return out; - } -}; - -template struct custom_formatter { - basic_format_parse_context& parse_ctx; - buffer_context& ctx; - - void operator()( - typename basic_format_arg>::handle h) const { - h.format(parse_ctx, ctx); - } - template void operator()(T) const {} -}; - -template class width_checker { - public: - explicit FMT_CONSTEXPR width_checker(ErrorHandler& eh) : handler_(eh) {} - - template ::value)> - FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { - if (is_negative(value)) handler_.on_error("negative width"); - return static_cast(value); - } - - template ::value)> - FMT_CONSTEXPR auto operator()(T) -> unsigned long long { - handler_.on_error("width is not integer"); - return 0; - } - - private: - ErrorHandler& handler_; -}; - -template class precision_checker { - public: - explicit FMT_CONSTEXPR precision_checker(ErrorHandler& eh) : handler_(eh) {} - - template ::value)> - FMT_CONSTEXPR auto operator()(T value) -> unsigned long long { - if (is_negative(value)) handler_.on_error("negative precision"); - return static_cast(value); - } - - template ::value)> - FMT_CONSTEXPR auto operator()(T) -> unsigned long long { - handler_.on_error("precision is not integer"); - return 0; - } - - private: - ErrorHandler& handler_; -}; - -template