From 612dc390ecd90bf4079ad7545f4a4832ce8f702d Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Tue, 27 Apr 2021 22:37:33 -0700 Subject: Move Converters into wix --- src/.editorconfig | 37 + src/Directory.Build.props | 27 - src/Directory.Build.targets | 51 - src/Directory.csproj.props | 13 - src/Directory.csproj.targets | 26 - .../ConvertSymbols.cs | 876 ------- .../WixToolset.Converters.Symbolizer.csproj | 32 - src/WixToolset.Converters/ConvertCommand.cs | 60 - .../ConverterExtensionCommandLine.cs | 46 - .../ConverterExtensionFactory.cs | 30 - src/WixToolset.Converters/FixupCommandBase.cs | 288 --- src/WixToolset.Converters/FormatCommand.cs | 60 - src/WixToolset.Converters/WixConverter.cs | 2435 -------------------- .../WixToolset.Converters.csproj | 24 - .../WixToolsetCoreServiceProviderExtensions.cs | 25 - src/deps/wix.dll | Bin 1753088 -> 0 bytes .../ConvertSymbolsFixture.cs | 606 ----- .../TestData/Integration/test.wixout | Bin 148559 -> 0 bytes .../TestData/Integration/test.wixproj | 47 - .../TestData/Integration/test.wxs | 36 - .../WixToolsetTest.Converters.Symbolizer.csproj | 33 - ...setTest.Converters.Symbolizer.v3.ncrunchproject | 9 - .../BaseConverterFixture.cs | 33 - .../WixToolsetTest.Converters/BitnessFixture.cs | 187 -- .../BootstrapperApplicationFixture.cs | 418 ---- .../WixToolsetTest.Converters/ConditionFixture.cs | 297 --- .../WixToolsetTest.Converters/ConverterFixture.cs | 449 ---- .../ConverterIntegrationFixture.cs | 195 -- .../CustomActionFixture.cs | 88 - .../CustomTableFixture.cs | 363 --- .../WixToolsetTest.Converters/DependencyFixture.cs | 178 -- .../WixToolsetTest.Converters/DirectoryFixture.cs | 92 - .../WixToolsetTest.Converters/ExePackageFixture.cs | 49 - .../WixToolsetTest.Converters/FeatureFixture.cs | 110 - .../FirewallExtensionFixture.cs | 47 - .../WixToolsetTest.Converters/FormatFixture.cs | 117 - .../WixToolsetTest.Converters/IncludeFixture.cs | 68 - .../Mocks/MockCoreServiceProvider.cs | 51 - .../Mocks/MockMessaging.cs | 39 - .../ProductPackageFixture.cs | 278 --- .../WixToolsetTest.Converters/PropertyFixture.cs | 108 - .../WixToolsetTest.Converters/RegistryFixture.cs | 54 - .../RemotePayloadFixture.cs | 104 - .../WixToolsetTest.Converters/SequenceFixture.cs | 49 - src/test/WixToolsetTest.Converters/TagFixture.cs | 111 - .../PackageSummaryInformation/TypicalV3.msi | Bin 32768 -> 0 bytes .../PackageSummaryInformation/TypicalV3.wxs | 37 - .../TestData/PermissionEx/v3.wxs | 26 - .../TestData/PermissionEx/v4_expected.wxs | 26 - .../Preprocessor/ConvertedPreprocessor.wxs | 61 - .../TestData/Preprocessor/Preprocessor.wxs | 63 - .../TestData/Preprocessor/wixcop.settings.xml | 9 - .../TestData/QtExec.bad/v3.wxs | 64 - .../TestData/QtExec.bad/v4_expected.wxs | 63 - .../TestData/QtExec/v3.wxs | 64 - .../TestData/QtExec/v4_expected.wxs | 62 - .../TestData/SingleFile/ConvertedSingleFile.wxs | 59 - .../TestData/SingleFile/SingleFile.wxs | 61 - .../UtilExtensionFixture.cs | 190 -- .../WixToolsetTest.Converters/VariableFixture.cs | 86 - .../Wix4ConversionFixture.cs | 54 - .../WixToolsetTest.Converters.csproj | 31 - src/version.json | 11 + src/wix/Directory.Build.props | 27 + src/wix/Directory.Build.targets | 51 + src/wix/Directory.csproj.props | 13 + src/wix/Directory.csproj.targets | 26 + src/wix/README.md | 2 + .../ConvertSymbols.cs | 876 +++++++ .../WixToolset.Converters.Symbolizer.csproj | 32 + src/wix/WixToolset.Converters.sln | 85 + src/wix/WixToolset.Converters.v3.ncrunchsolution | 6 + src/wix/WixToolset.Converters/ConvertCommand.cs | 60 + .../ConverterExtensionCommandLine.cs | 46 + .../ConverterExtensionFactory.cs | 30 + src/wix/WixToolset.Converters/FixupCommandBase.cs | 288 +++ src/wix/WixToolset.Converters/FormatCommand.cs | 60 + src/wix/WixToolset.Converters/WixConverter.cs | 2435 ++++++++++++++++++++ .../WixToolset.Converters.csproj | 24 + .../WixToolsetCoreServiceProviderExtensions.cs | 25 + src/wix/appveyor.cmd | 20 + src/wix/appveyor.yml | 44 + src/wix/deps/wix.dll | Bin 0 -> 1753088 bytes src/wix/nuget.config | 14 + .../ConvertSymbolsFixture.cs | 606 +++++ .../TestData/Integration/test.wixout | Bin 0 -> 148559 bytes .../TestData/Integration/test.wixproj | 47 + .../TestData/Integration/test.wxs | 36 + .../WixToolsetTest.Converters.Symbolizer.csproj | 33 + ...setTest.Converters.Symbolizer.v3.ncrunchproject | 9 + .../BaseConverterFixture.cs | 33 + .../WixToolsetTest.Converters/BitnessFixture.cs | 187 ++ .../BootstrapperApplicationFixture.cs | 418 ++++ .../WixToolsetTest.Converters/ConditionFixture.cs | 297 +++ .../WixToolsetTest.Converters/ConverterFixture.cs | 449 ++++ .../ConverterIntegrationFixture.cs | 195 ++ .../CustomActionFixture.cs | 88 + .../CustomTableFixture.cs | 363 +++ .../WixToolsetTest.Converters/DependencyFixture.cs | 178 ++ .../WixToolsetTest.Converters/DirectoryFixture.cs | 92 + .../WixToolsetTest.Converters/ExePackageFixture.cs | 49 + .../WixToolsetTest.Converters/FeatureFixture.cs | 110 + .../FirewallExtensionFixture.cs | 47 + .../WixToolsetTest.Converters/FormatFixture.cs | 117 + .../WixToolsetTest.Converters/IncludeFixture.cs | 68 + .../Mocks/MockCoreServiceProvider.cs | 51 + .../Mocks/MockMessaging.cs | 39 + .../ProductPackageFixture.cs | 278 +++ .../WixToolsetTest.Converters/PropertyFixture.cs | 108 + .../WixToolsetTest.Converters/RegistryFixture.cs | 54 + .../RemotePayloadFixture.cs | 104 + .../WixToolsetTest.Converters/SequenceFixture.cs | 49 + .../test/WixToolsetTest.Converters/TagFixture.cs | 111 + .../PackageSummaryInformation/TypicalV3.msi | Bin 0 -> 32768 bytes .../PackageSummaryInformation/TypicalV3.wxs | 37 + .../TestData/PermissionEx/v3.wxs | 26 + .../TestData/PermissionEx/v4_expected.wxs | 26 + .../Preprocessor/ConvertedPreprocessor.wxs | 61 + .../TestData/Preprocessor/Preprocessor.wxs | 63 + .../TestData/Preprocessor/wixcop.settings.xml | 9 + .../TestData/QtExec.bad/v3.wxs | 64 + .../TestData/QtExec.bad/v4_expected.wxs | 63 + .../TestData/QtExec/v3.wxs | 64 + .../TestData/QtExec/v4_expected.wxs | 62 + .../TestData/SingleFile/ConvertedSingleFile.wxs | 59 + .../TestData/SingleFile/SingleFile.wxs | 61 + .../UtilExtensionFixture.cs | 190 ++ .../WixToolsetTest.Converters/VariableFixture.cs | 86 + .../Wix4ConversionFixture.cs | 54 + .../WixToolsetTest.Converters.csproj | 31 + 130 files changed, 9384 insertions(+), 9165 deletions(-) create mode 100644 src/.editorconfig delete mode 100644 src/Directory.Build.props delete mode 100644 src/Directory.Build.targets delete mode 100644 src/Directory.csproj.props delete mode 100644 src/Directory.csproj.targets delete mode 100644 src/WixToolset.Converters.Symbolizer/ConvertSymbols.cs delete mode 100644 src/WixToolset.Converters.Symbolizer/WixToolset.Converters.Symbolizer.csproj delete mode 100644 src/WixToolset.Converters/ConvertCommand.cs delete mode 100644 src/WixToolset.Converters/ConverterExtensionCommandLine.cs delete mode 100644 src/WixToolset.Converters/ConverterExtensionFactory.cs delete mode 100644 src/WixToolset.Converters/FixupCommandBase.cs delete mode 100644 src/WixToolset.Converters/FormatCommand.cs delete mode 100644 src/WixToolset.Converters/WixConverter.cs delete mode 100644 src/WixToolset.Converters/WixToolset.Converters.csproj delete mode 100644 src/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs delete mode 100644 src/deps/wix.dll delete mode 100644 src/test/WixToolsetTest.Converters.Symbolizer/ConvertSymbolsFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixout delete mode 100644 src/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixproj delete mode 100644 src/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wxs delete mode 100644 src/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.csproj delete mode 100644 src/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.v3.ncrunchproject delete mode 100644 src/test/WixToolsetTest.Converters/BaseConverterFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/BitnessFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/BootstrapperApplicationFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/ConditionFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/ConverterFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/ConverterIntegrationFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/CustomActionFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/CustomTableFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/DependencyFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/DirectoryFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/ExePackageFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/FeatureFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/FirewallExtensionFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/FormatFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/IncludeFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/Mocks/MockCoreServiceProvider.cs delete mode 100644 src/test/WixToolsetTest.Converters/Mocks/MockMessaging.cs delete mode 100644 src/test/WixToolsetTest.Converters/ProductPackageFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/PropertyFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/RegistryFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/RemotePayloadFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/SequenceFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/TagFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.msi delete mode 100644 src/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.wxs delete mode 100644 src/test/WixToolsetTest.Converters/TestData/PermissionEx/v3.wxs delete mode 100644 src/test/WixToolsetTest.Converters/TestData/PermissionEx/v4_expected.wxs delete mode 100644 src/test/WixToolsetTest.Converters/TestData/Preprocessor/ConvertedPreprocessor.wxs delete mode 100644 src/test/WixToolsetTest.Converters/TestData/Preprocessor/Preprocessor.wxs delete mode 100644 src/test/WixToolsetTest.Converters/TestData/Preprocessor/wixcop.settings.xml delete mode 100644 src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v3.wxs delete mode 100644 src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v4_expected.wxs delete mode 100644 src/test/WixToolsetTest.Converters/TestData/QtExec/v3.wxs delete mode 100644 src/test/WixToolsetTest.Converters/TestData/QtExec/v4_expected.wxs delete mode 100644 src/test/WixToolsetTest.Converters/TestData/SingleFile/ConvertedSingleFile.wxs delete mode 100644 src/test/WixToolsetTest.Converters/TestData/SingleFile/SingleFile.wxs delete mode 100644 src/test/WixToolsetTest.Converters/UtilExtensionFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/VariableFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/Wix4ConversionFixture.cs delete mode 100644 src/test/WixToolsetTest.Converters/WixToolsetTest.Converters.csproj create mode 100644 src/version.json create mode 100644 src/wix/Directory.Build.props create mode 100644 src/wix/Directory.Build.targets create mode 100644 src/wix/Directory.csproj.props create mode 100644 src/wix/Directory.csproj.targets create mode 100644 src/wix/README.md create mode 100644 src/wix/WixToolset.Converters.Symbolizer/ConvertSymbols.cs create mode 100644 src/wix/WixToolset.Converters.Symbolizer/WixToolset.Converters.Symbolizer.csproj create mode 100644 src/wix/WixToolset.Converters.sln create mode 100644 src/wix/WixToolset.Converters.v3.ncrunchsolution create mode 100644 src/wix/WixToolset.Converters/ConvertCommand.cs create mode 100644 src/wix/WixToolset.Converters/ConverterExtensionCommandLine.cs create mode 100644 src/wix/WixToolset.Converters/ConverterExtensionFactory.cs create mode 100644 src/wix/WixToolset.Converters/FixupCommandBase.cs create mode 100644 src/wix/WixToolset.Converters/FormatCommand.cs create mode 100644 src/wix/WixToolset.Converters/WixConverter.cs create mode 100644 src/wix/WixToolset.Converters/WixToolset.Converters.csproj create mode 100644 src/wix/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs create mode 100644 src/wix/appveyor.cmd create mode 100644 src/wix/appveyor.yml create mode 100644 src/wix/deps/wix.dll create mode 100644 src/wix/nuget.config create mode 100644 src/wix/test/WixToolsetTest.Converters.Symbolizer/ConvertSymbolsFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixout create mode 100644 src/wix/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixproj create mode 100644 src/wix/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wxs create mode 100644 src/wix/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.csproj create mode 100644 src/wix/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.v3.ncrunchproject create mode 100644 src/wix/test/WixToolsetTest.Converters/BaseConverterFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/BitnessFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/BootstrapperApplicationFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/ConditionFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/ConverterFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/ConverterIntegrationFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/CustomActionFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/CustomTableFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/DependencyFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/DirectoryFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/ExePackageFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/FeatureFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/FirewallExtensionFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/FormatFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/IncludeFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/Mocks/MockCoreServiceProvider.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/Mocks/MockMessaging.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/ProductPackageFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/PropertyFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/RegistryFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/RemotePayloadFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/SequenceFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/TagFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.msi create mode 100644 src/wix/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.wxs create mode 100644 src/wix/test/WixToolsetTest.Converters/TestData/PermissionEx/v3.wxs create mode 100644 src/wix/test/WixToolsetTest.Converters/TestData/PermissionEx/v4_expected.wxs create mode 100644 src/wix/test/WixToolsetTest.Converters/TestData/Preprocessor/ConvertedPreprocessor.wxs create mode 100644 src/wix/test/WixToolsetTest.Converters/TestData/Preprocessor/Preprocessor.wxs create mode 100644 src/wix/test/WixToolsetTest.Converters/TestData/Preprocessor/wixcop.settings.xml create mode 100644 src/wix/test/WixToolsetTest.Converters/TestData/QtExec.bad/v3.wxs create mode 100644 src/wix/test/WixToolsetTest.Converters/TestData/QtExec.bad/v4_expected.wxs create mode 100644 src/wix/test/WixToolsetTest.Converters/TestData/QtExec/v3.wxs create mode 100644 src/wix/test/WixToolsetTest.Converters/TestData/QtExec/v4_expected.wxs create mode 100644 src/wix/test/WixToolsetTest.Converters/TestData/SingleFile/ConvertedSingleFile.wxs create mode 100644 src/wix/test/WixToolsetTest.Converters/TestData/SingleFile/SingleFile.wxs create mode 100644 src/wix/test/WixToolsetTest.Converters/UtilExtensionFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/VariableFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/Wix4ConversionFixture.cs create mode 100644 src/wix/test/WixToolsetTest.Converters/WixToolsetTest.Converters.csproj (limited to 'src') diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 00000000..1d72e683 --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,37 @@ +# Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. +# +# Do NOT modify this file. Update the canonical version in Home\repo-template\src\.editorconfig +# then update all of the repos. + +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.{cs,vb}] +dotnet_sort_system_directives_first = true + +[*.cs] +csharp_indent_case_contents = true : error +csharp_indent_switch_labels = true : error +csharp_new_line_before_open_brace = all +csharp_prefer_braces = true : error +csharp_style_expression_bodied_methods = when_on_single_line : suggestion +csharp_style_expression_bodied_constructors = when_on_single_line : suggestion +csharp_style_expression_bodied_operators = when_on_single_line : suggestion +csharp_style_expression_bodied_properties = when_on_single_line : suggestion +csharp_style_expression_bodied_indexers = when_on_single_line : suggestion +csharp_style_expression_bodied_accessors = when_on_single_line : suggestion +csharp_style_var_elsewhere = true : suggestion +csharp_style_var_for_built_in_types = true : suggestion +csharp_style_var_when_type_is_apparent = true : suggestion +dotnet_style_qualification_for_event = true : error +dotnet_style_qualification_for_field = true : error +dotnet_style_qualification_for_method = true : error +dotnet_style_qualification_for_property = true : error + +[*.targets] +indent_size = 2 diff --git a/src/Directory.Build.props b/src/Directory.Build.props deleted file mode 100644 index b3c6287c..00000000 --- a/src/Directory.Build.props +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - Debug - false - MSB3246 - - $(MSBuildProjectName) - $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\build\)) - $(BaseOutputPath)obj\$(ProjectName)\ - $(BaseOutputPath)$(Configuration)\ - - WiX Toolset Team - WiX Toolset - Copyright (c) .NET Foundation and contributors. All rights reserved. - MS-RL - WiX Toolset - - - - - diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets deleted file mode 100644 index 2fcc765a..00000000 --- a/src/Directory.Build.targets +++ /dev/null @@ -1,51 +0,0 @@ - - - - - - - true - $(SolutionPath) - $(NCrunchOriginalSolutionPath) - - - - - - - $([System.IO.File]::ReadAllText($(TheSolutionPath))) - $([System.IO.Path]::GetDirectoryName( $(TheSolutionPath) )) - (?<="[PackageName]", ")(.*)(?=", ") - - - - - - %(Identity) - $(SolutionFileContent.Contains('\%(Identity).csproj')) - - - - - $(RegexPattern.Replace('[PackageName]','%(PackageName)') ) - $([System.Text.RegularExpressions.Regex]::Match('$(SolutionFileContent)', '%(Pattern)')) - - - - - - - - - - - - - - diff --git a/src/Directory.csproj.props b/src/Directory.csproj.props deleted file mode 100644 index 81d24ad1..00000000 --- a/src/Directory.csproj.props +++ /dev/null @@ -1,13 +0,0 @@ - - - - - true - true - $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)wix.snk)) - false - - diff --git a/src/Directory.csproj.targets b/src/Directory.csproj.targets deleted file mode 100644 index c3270426..00000000 --- a/src/Directory.csproj.targets +++ /dev/null @@ -1,26 +0,0 @@ - - - - - false - $(OutputPath)\$(AssemblyName).xml - - - - - $(PrivateRepositoryUrl.Replace('.git','')) - - $(MSBuildProjectName).nuspec - $(OutputPath)..\ - $(NuspecProperties);Id=$(PackageId);Authors=$(Authors);Copyright=$(Copyright);Description=$(Description);Title=$(Title) - $(NuspecProperties);Version=$(PackageVersion);RepositoryCommit=$(SourceRevisionId);RepositoryType=$(RepositoryType);RepositoryUrl=$(PrivateRepositoryUrl);ProjectFolder=$(MSBuildProjectDirectory)\;ProjectUrl=$(ProjectUrl) - true - snupkg - - - - diff --git a/src/WixToolset.Converters.Symbolizer/ConvertSymbols.cs b/src/WixToolset.Converters.Symbolizer/ConvertSymbols.cs deleted file mode 100644 index 6418b2a6..00000000 --- a/src/WixToolset.Converters.Symbolizer/ConvertSymbols.cs +++ /dev/null @@ -1,876 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Converters.Symbolizer -{ - using System; - using System.Collections.Generic; - using System.Linq; - using WixToolset.Data; - using WixToolset.Data.Symbols; - using WixToolset.Data.WindowsInstaller; - using Wix3 = Microsoft.Tools.WindowsInstallerXml; - -#pragma warning disable 1591 // TODO: add documentation - public static class ConvertSymbols - { - public static Intermediate ConvertFile(string path) - { - var output = Wix3.Output.Load(path, suppressVersionCheck: true, suppressSchema: true); - return ConvertOutput(output); - } - - public static Intermediate ConvertOutput(Wix3.Output output) -#pragma warning restore 1591 - { - var section = new IntermediateSection(String.Empty, OutputType3ToSectionType4(output.Type)); - - var wixMediaByDiskId = IndexWixMediaTableByDiskId(output); - var componentsById = IndexById(output, "Component"); - var bindPathsById = IndexById(output, "BindPath"); - var fontsById = IndexById(output, "Font"); - var selfRegById = IndexById(output, "SelfReg"); - var wixDirectoryById = IndexById(output, "WixDirectory"); - var wixFileById = IndexById(output, "WixFile"); - - foreach (Wix3.Table table in output.Tables) - { - foreach (Wix3.Row row in table.Rows) - { - var symbol = GenerateSymbolFromRow(row, wixMediaByDiskId, componentsById, fontsById, bindPathsById, selfRegById, wixFileById, wixDirectoryById); - if (symbol != null) - { - section.AddSymbol(symbol); - } - } - } - - return new Intermediate(String.Empty, new[] { section }, localizationsByCulture: null); - } - - private static Dictionary IndexWixMediaTableByDiskId(Wix3.Output output) - { - var wixMediaByDiskId = new Dictionary(); - var wixMediaTable = output.Tables["WixMedia"]; - - if (wixMediaTable != null) - { - foreach (Wix3.WixMediaRow row in wixMediaTable.Rows) - { - wixMediaByDiskId.Add(FieldAsInt(row, 0), row); - } - } - - return wixMediaByDiskId; - } - - private static Dictionary IndexById(Wix3.Output output, string tableName) where T : Wix3.Row - { - var byId = new Dictionary(); - var table = output.Tables[tableName]; - - if (table != null) - { - foreach (T row in table.Rows) - { - byId.Add(FieldAsString(row, 0), row); - } - } - - return byId; - } - - private static IntermediateSymbol GenerateSymbolFromRow(Wix3.Row row, Dictionary wixMediaByDiskId, Dictionary componentsById, Dictionary fontsById, Dictionary bindPathsById, Dictionary selfRegById, Dictionary wixFileById, Dictionary wixDirectoryById) - { - var name = row.Table.Name; - switch (name) - { - case "_SummaryInformation": - return DefaultSymbolFromRow(typeof(SummaryInformationSymbol), row, columnZeroIsId: false); - case "ActionText": - return DefaultSymbolFromRow(typeof(ActionTextSymbol), row, columnZeroIsId: false); - case "AppId": - return DefaultSymbolFromRow(typeof(AppIdSymbol), row, columnZeroIsId: false); - case "AppSearch": - return DefaultSymbolFromRow(typeof(AppSearchSymbol), row, columnZeroIsId: false); - case "Billboard": - return DefaultSymbolFromRow(typeof(BillboardSymbol), row, columnZeroIsId: true); - case "Binary": - return DefaultSymbolFromRow(typeof(BinarySymbol), row, columnZeroIsId: true); - case "BindPath": - return null; - case "CCPSearch": - return DefaultSymbolFromRow(typeof(CCPSearchSymbol), row, columnZeroIsId: true); - case "Class": - return DefaultSymbolFromRow(typeof(ClassSymbol), row, columnZeroIsId: false); - case "CompLocator": - return DefaultSymbolFromRow(typeof(CompLocatorSymbol), row, columnZeroIsId: false); - case "Component": - { - var attributes = FieldAsNullableInt(row, 3); - - var location = ComponentLocation.LocalOnly; - if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesSourceOnly) == WindowsInstallerConstants.MsidbComponentAttributesSourceOnly) - { - location = ComponentLocation.SourceOnly; - } - else if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesOptional) == WindowsInstallerConstants.MsidbComponentAttributesOptional) - { - location = ComponentLocation.Either; - } - - var keyPath = FieldAsString(row, 5); - var keyPathType = String.IsNullOrEmpty(keyPath) ? ComponentKeyPathType.Directory : ComponentKeyPathType.File; - if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath) == WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath) - { - keyPathType = ComponentKeyPathType.Registry; - } - else if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource) == WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource) - { - keyPathType = ComponentKeyPathType.OdbcDataSource; - } - - return new ComponentSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) - { - ComponentId = FieldAsString(row, 1), - DirectoryRef = FieldAsString(row, 2), - Condition = FieldAsString(row, 4), - KeyPath = keyPath, - Location = location, - DisableRegistryReflection = (attributes & WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection) == WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection, - NeverOverwrite = (attributes & WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite) == WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite, - Permanent = (attributes & WindowsInstallerConstants.MsidbComponentAttributesPermanent) == WindowsInstallerConstants.MsidbComponentAttributesPermanent, - SharedDllRefCount = (attributes & WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount) == WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount, - Shared = (attributes & WindowsInstallerConstants.MsidbComponentAttributesShared) == WindowsInstallerConstants.MsidbComponentAttributesShared, - Transitive = (attributes & WindowsInstallerConstants.MsidbComponentAttributesTransitive) == WindowsInstallerConstants.MsidbComponentAttributesTransitive, - UninstallWhenSuperseded = (attributes & WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence) == WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence, - Win64 = (attributes & WindowsInstallerConstants.MsidbComponentAttributes64bit) == WindowsInstallerConstants.MsidbComponentAttributes64bit, - KeyPathType = keyPathType, - }; - } - - case "Condition": - return DefaultSymbolFromRow(typeof(ConditionSymbol), row, columnZeroIsId: false); - case "CreateFolder": - return DefaultSymbolFromRow(typeof(CreateFolderSymbol), row, columnZeroIsId: false); - case "CustomAction": - { - var caType = FieldAsInt(row, 1); - var executionType = DetermineCustomActionExecutionType(caType); - var sourceType = DetermineCustomActionSourceType(caType); - var targetType = DetermineCustomActionTargetType(caType); - - return new CustomActionSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) - { - ExecutionType = executionType, - SourceType = sourceType, - Source = FieldAsString(row, 2), - TargetType = targetType, - Target = FieldAsString(row, 3), - Win64 = (caType & WindowsInstallerConstants.MsidbCustomActionType64BitScript) == WindowsInstallerConstants.MsidbCustomActionType64BitScript, - TSAware = (caType & WindowsInstallerConstants.MsidbCustomActionTypeTSAware) == WindowsInstallerConstants.MsidbCustomActionTypeTSAware, - Impersonate = (caType & WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate) != WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate, - IgnoreResult = (caType & WindowsInstallerConstants.MsidbCustomActionTypeContinue) == WindowsInstallerConstants.MsidbCustomActionTypeContinue, - Hidden = (caType & WindowsInstallerConstants.MsidbCustomActionTypeHideTarget) == WindowsInstallerConstants.MsidbCustomActionTypeHideTarget, - Async = (caType & WindowsInstallerConstants.MsidbCustomActionTypeAsync) == WindowsInstallerConstants.MsidbCustomActionTypeAsync, - }; - } - - case "Directory": - { - var id = FieldAsString(row, 0); - var splits = SplitDefaultDir(FieldAsString(row, 2)); - - var symbol = new DirectorySymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, id)) - { - ParentDirectoryRef = FieldAsString(row, 1), - Name = splits[0], - ShortName = splits[1], - SourceName = splits[2], - SourceShortName = splits[3] - }; - - if (wixDirectoryById.TryGetValue(id, out var wixDirectoryRow)) - { - symbol.ComponentGuidGenerationSeed = FieldAsString(wixDirectoryRow, 1); - } - - return symbol; - } - case "DrLocator": - return DefaultSymbolFromRow(typeof(DrLocatorSymbol), row, columnZeroIsId: false); - case "DuplicateFile": - { - var splitName = FieldAsString(row, 3)?.Split('|'); - - var symbol = new DuplicateFileSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) - { - ComponentRef = FieldAsString(row, 1), - FileRef = FieldAsString(row, 2), - DestinationName = splitName == null ? null : splitName.Length > 1 ? splitName[1] : splitName[0], - DestinationShortName = splitName == null ? null : splitName.Length > 1 ? splitName[0] : null, - DestinationFolder = FieldAsString(row, 4) - }; - - return symbol; - } - case "Error": - return DefaultSymbolFromRow(typeof(ErrorSymbol), row, columnZeroIsId: false); - case "Extension": - return DefaultSymbolFromRow(typeof(ExtensionSymbol), row, columnZeroIsId: false); - case "Feature": - { - var attributes = FieldAsInt(row, 7); - var installDefault = FeatureInstallDefault.Local; - if ((attributes & WindowsInstallerConstants.MsidbFeatureAttributesFollowParent) == WindowsInstallerConstants.MsidbFeatureAttributesFollowParent) - { - installDefault = FeatureInstallDefault.FollowParent; - } - else if ((attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorSource) == WindowsInstallerConstants.MsidbFeatureAttributesFavorSource) - { - installDefault = FeatureInstallDefault.Source; - } - - return new FeatureSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) - { - ParentFeatureRef = FieldAsString(row, 1), - Title = FieldAsString(row, 2), - Description = FieldAsString(row, 3), - Display = FieldAsInt(row, 4), // BUGBUGBUG: FieldAsNullableInt(row, 4), - Level = FieldAsInt(row, 5), - DirectoryRef = FieldAsString(row, 6), - DisallowAbsent = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent) == WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent, - DisallowAdvertise = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise) == WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise, - InstallDefault = installDefault, - TypicalDefault = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise) == WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise ? FeatureTypicalDefault.Advertise : FeatureTypicalDefault.Install, - }; - } - - case "FeatureComponents": - return DefaultSymbolFromRow(typeof(FeatureComponentsSymbol), row, columnZeroIsId: false); - case "File": - { - var attributes = FieldAsNullableInt(row, 6); - - FileSymbolAttributes symbolAttributes = 0; - symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesReadOnly) == WindowsInstallerConstants.MsidbFileAttributesReadOnly ? FileSymbolAttributes.ReadOnly : 0; - symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesHidden) == WindowsInstallerConstants.MsidbFileAttributesHidden ? FileSymbolAttributes.Hidden : 0; - symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesSystem) == WindowsInstallerConstants.MsidbFileAttributesSystem ? FileSymbolAttributes.System : 0; - symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesVital) == WindowsInstallerConstants.MsidbFileAttributesVital ? FileSymbolAttributes.Vital : 0; - symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesChecksum) == WindowsInstallerConstants.MsidbFileAttributesChecksum ? FileSymbolAttributes.Checksum : 0; - symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) == WindowsInstallerConstants.MsidbFileAttributesNoncompressed ? FileSymbolAttributes.Uncompressed : 0; - symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesCompressed) == WindowsInstallerConstants.MsidbFileAttributesCompressed ? FileSymbolAttributes.Compressed : 0; - - var id = FieldAsString(row, 0); - var splitName = FieldAsString(row, 2).Split('|'); - - var symbol = new FileSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, id)) - { - ComponentRef = FieldAsString(row, 1), - Name = splitName.Length > 1 ? splitName[1] : splitName[0], - ShortName = splitName.Length > 1 ? splitName[0] : null, - FileSize = FieldAsInt(row, 3), - Version = FieldAsString(row, 4), - Language = FieldAsString(row, 5), - Attributes = symbolAttributes - }; - - if (bindPathsById.TryGetValue(id, out var bindPathRow)) - { - symbol.BindPath = FieldAsString(bindPathRow, 1) ?? String.Empty; - } - - if (fontsById.TryGetValue(id, out var fontRow)) - { - symbol.FontTitle = FieldAsString(fontRow, 1) ?? String.Empty; - } - - if (selfRegById.TryGetValue(id, out var selfRegRow)) - { - symbol.SelfRegCost = FieldAsNullableInt(selfRegRow, 1) ?? 0; - } - - if (wixFileById.TryGetValue(id, out var wixFileRow)) - { - symbol.DirectoryRef = FieldAsString(wixFileRow, 4); - symbol.DiskId = FieldAsNullableInt(wixFileRow, 5) ?? 0; - symbol.Source = new IntermediateFieldPathValue { Path = FieldAsString(wixFileRow, 6) }; - symbol.PatchGroup = FieldAsInt(wixFileRow, 8); - symbol.PatchAttributes = (PatchAttributeType)FieldAsInt(wixFileRow, 10); - } - - return symbol; - } - case "Font": - return null; - case "Icon": - return DefaultSymbolFromRow(typeof(IconSymbol), row, columnZeroIsId: true); - case "IniFile": - { - var splitName = FieldAsString(row, 1).Split('|'); - var action = FieldAsInt(row, 6); - - var symbol = new IniFileSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) - { - FileName = splitName.Length > 1 ? splitName[1] : splitName[0], - ShortFileName = splitName.Length > 1 ? splitName[0] : null, - DirProperty = FieldAsString(row, 2), - Section = FieldAsString(row, 3), - Key = FieldAsString(row, 4), - Value = FieldAsString(row, 5), - Action = action == 3 ? IniFileActionType.AddTag : action == 1 ? IniFileActionType.CreateLine : IniFileActionType.AddLine, - ComponentRef = FieldAsString(row, 7), - }; - - return symbol; - } - case "IniLocator": - { - var splitName = FieldAsString(row, 1).Split('|'); - - var symbol = new IniLocatorSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) - { - FileName = splitName.Length > 1 ? splitName[1] : splitName[0], - ShortFileName = splitName.Length > 1 ? splitName[0] : null, - Section = FieldAsString(row, 2), - Key = FieldAsString(row, 3), - Field = FieldAsInt(row, 4), - Type = FieldAsInt(row, 5), - }; - - return symbol; - } - case "LockPermissions": - return DefaultSymbolFromRow(typeof(LockPermissionsSymbol), row, columnZeroIsId: false); - case "Media": - { - var diskId = FieldAsInt(row, 0); - var symbol = new MediaSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, diskId)) - { - DiskId = diskId, - LastSequence = FieldAsNullableInt(row, 1), - DiskPrompt = FieldAsString(row, 2), - Cabinet = FieldAsString(row, 3), - VolumeLabel = FieldAsString(row, 4), - Source = FieldAsString(row, 5) - }; - - if (wixMediaByDiskId.TryGetValue(diskId, out var wixMediaRow)) - { - var compressionLevel = FieldAsString(wixMediaRow, 1); - - symbol.CompressionLevel = String.IsNullOrEmpty(compressionLevel) ? null : (CompressionLevel?)Enum.Parse(typeof(CompressionLevel), compressionLevel, true); - symbol.Layout = wixMediaRow.Layout; - } - - return symbol; - } - case "MIME": - return DefaultSymbolFromRow(typeof(MIMESymbol), row, columnZeroIsId: false); - case "ModuleIgnoreTable": - return DefaultSymbolFromRow(typeof(ModuleIgnoreTableSymbol), row, columnZeroIsId: true); - case "MoveFile": - return DefaultSymbolFromRow(typeof(MoveFileSymbol), row, columnZeroIsId: true); - case "MsiAssembly": - { - var componentId = FieldAsString(row, 0); - if (componentsById.TryGetValue(componentId, out var componentRow)) - { - return new AssemblySymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(componentRow, 5))) - { - ComponentRef = componentId, - FeatureRef = FieldAsString(row, 1), - ManifestFileRef = FieldAsString(row, 2), - ApplicationFileRef = FieldAsString(row, 3), - Type = FieldAsNullableInt(row, 4) == 1 ? AssemblyType.Win32Assembly : AssemblyType.DotNetAssembly, - }; - } - - return null; - } - case "MsiLockPermissionsEx": - return DefaultSymbolFromRow(typeof(MsiLockPermissionsExSymbol), row, columnZeroIsId: true); - case "MsiShortcutProperty": - return DefaultSymbolFromRow(typeof(MsiShortcutPropertySymbol), row, columnZeroIsId: true); - case "ODBCDataSource": - return DefaultSymbolFromRow(typeof(ODBCDataSourceSymbol), row, columnZeroIsId: true); - case "ODBCDriver": - return DefaultSymbolFromRow(typeof(ODBCDriverSymbol), row, columnZeroIsId: true); - case "ODBCTranslator": - return DefaultSymbolFromRow(typeof(ODBCTranslatorSymbol), row, columnZeroIsId: true); - case "ProgId": - return DefaultSymbolFromRow(typeof(ProgIdSymbol), row, columnZeroIsId: false); - case "Property": - return DefaultSymbolFromRow(typeof(PropertySymbol), row, columnZeroIsId: true); - case "PublishComponent": - return DefaultSymbolFromRow(typeof(PublishComponentSymbol), row, columnZeroIsId: false); - case "Registry": - { - var value = FieldAsString(row, 4); - var valueType = RegistryValueType.String; - var valueAction = RegistryValueActionType.Write; - - if (!String.IsNullOrEmpty(value)) - { - if (value.StartsWith("#x", StringComparison.Ordinal)) - { - valueType = RegistryValueType.Binary; - value = value.Substring(2); - } - else if (value.StartsWith("#%", StringComparison.Ordinal)) - { - valueType = RegistryValueType.Expandable; - value = value.Substring(2); - } - else if (value.StartsWith("#", StringComparison.Ordinal)) - { - valueType = RegistryValueType.Integer; - value = value.Substring(1); - } - else if (value.StartsWith("[~]", StringComparison.Ordinal) && value.EndsWith("[~]", StringComparison.Ordinal)) - { - value = value.Substring(3, value.Length - 6); - valueType = RegistryValueType.MultiString; - valueAction = RegistryValueActionType.Write; - } - else if (value.StartsWith("[~]", StringComparison.Ordinal)) - { - value = value.Substring(3); - valueType = RegistryValueType.MultiString; - valueAction = RegistryValueActionType.Append; - } - else if (value.EndsWith("[~]", StringComparison.Ordinal)) - { - value = value.Substring(0, value.Length - 3); - valueType = RegistryValueType.MultiString; - valueAction = RegistryValueActionType.Prepend; - } - } - - return new RegistrySymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) - { - Root = (RegistryRootType)FieldAsInt(row, 1), - Key = FieldAsString(row, 2), - Name = FieldAsString(row, 3), - Value = value, - ComponentRef = FieldAsString(row, 5), - ValueAction = valueAction, - ValueType = valueType, - }; - } - case "RegLocator": - { - var type = FieldAsInt(row, 4); - - return new RegLocatorSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) - { - Root = (RegistryRootType)FieldAsInt(row, 1), - Key = FieldAsString(row, 2), - Name = FieldAsString(row, 3), - Type = (RegLocatorType)(type & 0xF), - Win64 = (type & WindowsInstallerConstants.MsidbLocatorType64bit) == WindowsInstallerConstants.MsidbLocatorType64bit - }; - } - case "RemoveFile": - { - var splitName = FieldAsString(row, 2).Split('|'); - var installMode = FieldAsInt(row, 4); - - return new RemoveFileSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) - { - ComponentRef = FieldAsString(row, 1), - FileName = splitName.Length > 1 ? splitName[1] : splitName[0], - ShortFileName = splitName.Length > 1 ? splitName[0] : null, - DirPropertyRef = FieldAsString(row, 3), - OnInstall = (installMode & WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall) == WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall ? (bool?)true : null, - OnUninstall = (installMode & WindowsInstallerConstants.MsidbRemoveFileInstallModeOnRemove) == WindowsInstallerConstants.MsidbRemoveFileInstallModeOnRemove ? (bool?)true : null - }; - } - case "RemoveRegistry": - { - return new RemoveRegistrySymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) - { - Action = RemoveRegistryActionType.RemoveOnInstall, - Root = (RegistryRootType)FieldAsInt(row, 1), - Key = FieldAsString(row, 2), - Name = FieldAsString(row, 3), - ComponentRef = FieldAsString(row, 4), - }; - } - - case "ReserveCost": - return DefaultSymbolFromRow(typeof(ReserveCostSymbol), row, columnZeroIsId: true); - case "SelfReg": - return null; - case "ServiceControl": - { - var events = FieldAsInt(row, 2); - var wait = FieldAsNullableInt(row, 4); - return new ServiceControlSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) - { - Name = FieldAsString(row, 1), - Arguments = FieldAsString(row, 3), - Wait = !wait.HasValue || wait.Value == 1, - ComponentRef = FieldAsString(row, 5), - InstallRemove = (events & WindowsInstallerConstants.MsidbServiceControlEventDelete) == WindowsInstallerConstants.MsidbServiceControlEventDelete, - UninstallRemove = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete) == WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete, - InstallStart = (events & WindowsInstallerConstants.MsidbServiceControlEventStart) == WindowsInstallerConstants.MsidbServiceControlEventStart, - UninstallStart = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallStart) == WindowsInstallerConstants.MsidbServiceControlEventUninstallStart, - InstallStop = (events & WindowsInstallerConstants.MsidbServiceControlEventStop) == WindowsInstallerConstants.MsidbServiceControlEventStop, - UninstallStop = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallStop) == WindowsInstallerConstants.MsidbServiceControlEventUninstallStop, - }; - } - - case "ServiceInstall": - return DefaultSymbolFromRow(typeof(ServiceInstallSymbol), row, columnZeroIsId: true); - case "Shortcut": - { - var splitName = FieldAsString(row, 2).Split('|'); - - return new ShortcutSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) - { - DirectoryRef = FieldAsString(row, 1), - Name = splitName.Length > 1 ? splitName[1] : splitName[0], - ShortName = splitName.Length > 1 ? splitName[0] : null, - ComponentRef = FieldAsString(row, 3), - Target = FieldAsString(row, 4), - Arguments = FieldAsString(row, 5), - Description = FieldAsString(row, 6), - Hotkey = FieldAsNullableInt(row, 7), - IconRef = FieldAsString(row, 8), - IconIndex = FieldAsNullableInt(row, 9), - Show = (ShortcutShowType?)FieldAsNullableInt(row, 10), - WorkingDirectory = FieldAsString(row, 11), - DisplayResourceDll = FieldAsString(row, 12), - DisplayResourceId = FieldAsNullableInt(row, 13), - DescriptionResourceDll = FieldAsString(row, 14), - DescriptionResourceId= FieldAsNullableInt(row, 15), - }; - } - case "Signature": - return DefaultSymbolFromRow(typeof(SignatureSymbol), row, columnZeroIsId: true); - case "UIText": - return DefaultSymbolFromRow(typeof(UITextSymbol), row, columnZeroIsId: true); - case "Upgrade": - { - var attributes = FieldAsInt(row, 4); - return new UpgradeSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) - { - UpgradeCode = FieldAsString(row, 0), - VersionMin = FieldAsString(row, 1), - VersionMax = FieldAsString(row, 2), - Language = FieldAsString(row, 3), - Remove = FieldAsString(row, 5), - ActionProperty = FieldAsString(row, 6), - MigrateFeatures = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures) == WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures, - OnlyDetect = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect) == WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect, - IgnoreRemoveFailures = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure) == WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure, - VersionMinInclusive = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive, - VersionMaxInclusive = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive, - ExcludeLanguages = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive, - }; - } - case "Verb": - return DefaultSymbolFromRow(typeof(VerbSymbol), row, columnZeroIsId: false); - case "WixAction": - { - var sequenceTable = FieldAsString(row, 0); - return new WixActionSymbol(SourceLineNumber4(row.SourceLineNumbers)) - { - SequenceTable = (SequenceTable)Enum.Parse(typeof(SequenceTable), sequenceTable == "AdvtExecuteSequence" ? nameof(SequenceTable.AdvertiseExecuteSequence) : sequenceTable), - Action = FieldAsString(row, 1), - Condition = FieldAsString(row, 2), - Sequence = FieldAsNullableInt(row, 3), - Before = FieldAsString(row, 4), - After = FieldAsString(row, 5), - Overridable = FieldAsNullableInt(row, 6) != 0, - }; - } - case "WixBootstrapperApplication": - return DefaultSymbolFromRow(typeof(WixBootstrapperApplicationSymbol), row, columnZeroIsId: true); - case "WixBundleContainer": - return DefaultSymbolFromRow(typeof(WixBundleContainerSymbol), row, columnZeroIsId: true); - case "WixBundleVariable": - return DefaultSymbolFromRow(typeof(WixBundleVariableSymbol), row, columnZeroIsId: true); - case "WixChainItem": - return DefaultSymbolFromRow(typeof(WixChainItemSymbol), row, columnZeroIsId: true); - case "WixCustomTable": - return DefaultSymbolFromRow(typeof(WixCustomTableSymbol), row, columnZeroIsId: true); - case "WixDirectory": - return null; - case "WixFile": - return null; - case "WixInstanceTransforms": - return DefaultSymbolFromRow(typeof(WixInstanceTransformsSymbol), row, columnZeroIsId: true); - case "WixMedia": - return null; - case "WixMerge": - return DefaultSymbolFromRow(typeof(WixMergeSymbol), row, columnZeroIsId: true); - case "WixPatchBaseline": - return DefaultSymbolFromRow(typeof(WixPatchBaselineSymbol), row, columnZeroIsId: true); - case "WixProperty": - { - var attributes = FieldAsInt(row, 1); - return new WixPropertySymbol(SourceLineNumber4(row.SourceLineNumbers)) - { - PropertyRef = FieldAsString(row, 0), - Admin = (attributes & 0x1) == 0x1, - Hidden = (attributes & 0x2) == 0x2, - Secure = (attributes & 0x4) == 0x4, - }; - } - case "WixSuppressModularization": - { - return new WixSuppressModularizationSymbol(SourceLineNumber4(row.SourceLineNumbers)) - { - SuppressIdentifier = FieldAsString(row, 0) - }; - } - case "WixUI": - return DefaultSymbolFromRow(typeof(WixUISymbol), row, columnZeroIsId: true); - case "WixVariable": - return DefaultSymbolFromRow(typeof(WixVariableSymbol), row, columnZeroIsId: true); - default: - return GenericSymbolFromCustomRow(row, columnZeroIsId: false); - } - } - - private static CustomActionTargetType DetermineCustomActionTargetType(int type) - { - var targetType = default(CustomActionTargetType); - - if ((type & WindowsInstallerConstants.MsidbCustomActionTypeVBScript) == WindowsInstallerConstants.MsidbCustomActionTypeVBScript) - { - targetType = CustomActionTargetType.VBScript; - } - else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeJScript) == WindowsInstallerConstants.MsidbCustomActionTypeJScript) - { - targetType = CustomActionTargetType.JScript; - } - else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeTextData) == WindowsInstallerConstants.MsidbCustomActionTypeTextData) - { - targetType = CustomActionTargetType.TextData; - } - else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeExe) == WindowsInstallerConstants.MsidbCustomActionTypeExe) - { - targetType = CustomActionTargetType.Exe; - } - else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeDll) == WindowsInstallerConstants.MsidbCustomActionTypeDll) - { - targetType = CustomActionTargetType.Dll; - } - - return targetType; - } - - private static CustomActionSourceType DetermineCustomActionSourceType(int type) - { - var sourceType = CustomActionSourceType.Binary; - - if ((type & WindowsInstallerConstants.MsidbCustomActionTypeProperty) == WindowsInstallerConstants.MsidbCustomActionTypeProperty) - { - sourceType = CustomActionSourceType.Property; - } - else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeDirectory) == WindowsInstallerConstants.MsidbCustomActionTypeDirectory) - { - sourceType = CustomActionSourceType.Directory; - } - else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeSourceFile) == WindowsInstallerConstants.MsidbCustomActionTypeSourceFile) - { - sourceType = CustomActionSourceType.File; - } - - return sourceType; - } - - private static CustomActionExecutionType DetermineCustomActionExecutionType(int type) - { - var executionType = CustomActionExecutionType.Immediate; - - if ((type & (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit)) == (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit)) - { - executionType = CustomActionExecutionType.Commit; - } - else if ((type & (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback)) == (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback)) - { - executionType = CustomActionExecutionType.Rollback; - } - else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeInScript) == WindowsInstallerConstants.MsidbCustomActionTypeInScript) - { - executionType = CustomActionExecutionType.Deferred; - } - else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat) == WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat) - { - executionType = CustomActionExecutionType.ClientRepeat; - } - else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess) == WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess) - { - executionType = CustomActionExecutionType.OncePerProcess; - } - else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence) == WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence) - { - executionType = CustomActionExecutionType.FirstSequence; - } - - return executionType; - } - - private static IntermediateFieldType ColumnType3ToIntermediateFieldType4(Wix3.ColumnType columnType) - { - switch (columnType) - { - case Wix3.ColumnType.Number: - return IntermediateFieldType.Number; - case Wix3.ColumnType.Object: - return IntermediateFieldType.Path; - case Wix3.ColumnType.Unknown: - case Wix3.ColumnType.String: - case Wix3.ColumnType.Localized: - case Wix3.ColumnType.Preserved: - default: - return IntermediateFieldType.String; - } - } - - private static IntermediateSymbol DefaultSymbolFromRow(Type symbolType, Wix3.Row row, bool columnZeroIsId) - { - var id = columnZeroIsId ? GetIdentifierForRow(row) : null; - - var createSymbol = symbolType.GetConstructor(new[] { typeof(SourceLineNumber), typeof(Identifier) }); - var symbol = (IntermediateSymbol)createSymbol.Invoke(new object[] { SourceLineNumber4(row.SourceLineNumbers), id }); - - SetSymbolFieldsFromRow(row, symbol, columnZeroIsId); - - return symbol; - } - - private static IntermediateSymbol GenericSymbolFromCustomRow(Wix3.Row row, bool columnZeroIsId) - { - var columnDefinitions = row.Table.Definition.Columns.Cast(); - var fieldDefinitions = columnDefinitions.Select(columnDefinition => - new IntermediateFieldDefinition(columnDefinition.Name, ColumnType3ToIntermediateFieldType4(columnDefinition.Type))).ToArray(); - var symbolDefinition = new IntermediateSymbolDefinition(row.Table.Name, fieldDefinitions, null); - - var id = columnZeroIsId ? GetIdentifierForRow(row) : null; - - var createSymbol = typeof(IntermediateSymbol).GetConstructor(new[] { typeof(IntermediateSymbolDefinition), typeof(SourceLineNumber), typeof(Identifier) }); - var symbol = (IntermediateSymbol)createSymbol.Invoke(new object[] { symbolDefinition, SourceLineNumber4(row.SourceLineNumbers), id }); - - SetSymbolFieldsFromRow(row, symbol, columnZeroIsId); - - return symbol; - } - - private static void SetSymbolFieldsFromRow(Wix3.Row row, IntermediateSymbol symbol, bool columnZeroIsId) - { - var offset = 0; - if (columnZeroIsId) - { - offset = 1; - } - - for (var i = offset; i < row.Fields.Length; ++i) - { - var column = row.Fields[i].Column; - switch (column.Type) - { - case Wix3.ColumnType.String: - case Wix3.ColumnType.Localized: - case Wix3.ColumnType.Object: - case Wix3.ColumnType.Preserved: - symbol.Set(i - offset, FieldAsString(row, i)); - break; - case Wix3.ColumnType.Number: - int? nullableValue = FieldAsNullableInt(row, i); - // TODO: Consider whether null values should be coerced to their default value when - // a column is not nullable. For now, just pass through the null. - //int value = FieldAsInt(row, i); - //symbol.Set(i - offset, column.IsNullable ? nullableValue : value); - symbol.Set(i - offset, nullableValue); - break; - case Wix3.ColumnType.Unknown: - break; - } - } - } - - private static Identifier GetIdentifierForRow(Wix3.Row row) - { - var column = row.Fields[0].Column; - switch (column.Type) - { - case Wix3.ColumnType.String: - case Wix3.ColumnType.Localized: - case Wix3.ColumnType.Object: - case Wix3.ColumnType.Preserved: - return new Identifier(AccessModifier.Global, (string)row.Fields[0].Data); - case Wix3.ColumnType.Number: - return new Identifier(AccessModifier.Global, FieldAsInt(row, 0)); - default: - return null; - } - } - - private static SectionType OutputType3ToSectionType4(Wix3.OutputType outputType) - { - switch (outputType) - { - case Wix3.OutputType.Bundle: - return SectionType.Bundle; - case Wix3.OutputType.Module: - return SectionType.Module; - case Wix3.OutputType.Patch: - return SectionType.Patch; - case Wix3.OutputType.PatchCreation: - return SectionType.PatchCreation; - case Wix3.OutputType.Product: - return SectionType.Product; - case Wix3.OutputType.Transform: - case Wix3.OutputType.Unknown: - default: - return SectionType.Unknown; - } - } - - private static SourceLineNumber SourceLineNumber4(Wix3.SourceLineNumberCollection source) - { - return String.IsNullOrEmpty(source?.EncodedSourceLineNumbers) ? null : SourceLineNumber.CreateFromEncoded(source.EncodedSourceLineNumbers); - } - - private static string FieldAsString(Wix3.Row row, int column) - { - return (string)row[column]; - } - - private static int FieldAsInt(Wix3.Row row, int column) - { - return Convert.ToInt32(row[column]); - } - - private static int? FieldAsNullableInt(Wix3.Row row, int column) - { - var field = row.Fields[column]; - if (field.Data == null) - { - return null; - } - else - { - return Convert.ToInt32(field.Data); - } - } - - private static string[] SplitDefaultDir(string defaultDir) - { - var split1 = defaultDir.Split(':'); - var targetSplit = split1.Length > 1 ? split1[1].Split('|') : split1[0].Split('|'); - var sourceSplit = split1.Length > 1 ? split1[0].Split('|') : new[] { String.Empty }; - return new[] - { - targetSplit.Length > 1 ? targetSplit[1] : targetSplit[0], - targetSplit.Length > 1 ? targetSplit[0] : null, - sourceSplit.Length > 1 ? sourceSplit[1] : sourceSplit[0], - sourceSplit.Length > 1 ? sourceSplit[0] : null - }; - } - } -} diff --git a/src/WixToolset.Converters.Symbolizer/WixToolset.Converters.Symbolizer.csproj b/src/WixToolset.Converters.Symbolizer/WixToolset.Converters.Symbolizer.csproj deleted file mode 100644 index 445c3500..00000000 --- a/src/WixToolset.Converters.Symbolizer/WixToolset.Converters.Symbolizer.csproj +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - netstandard2.0 - $(TargetFrameworks);net461;net472 - Symbolizer - WiX Toolset Converters Tuplizer - embedded - true - true - - - - - - - - - - - - - - - - - - - diff --git a/src/WixToolset.Converters/ConvertCommand.cs b/src/WixToolset.Converters/ConvertCommand.cs deleted file mode 100644 index b6826f43..00000000 --- a/src/WixToolset.Converters/ConvertCommand.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Converters -{ - using System; - using System.Threading; - using System.Threading.Tasks; - using WixToolset.Extensibility.Services; - - internal class ConvertCommand : FixupCommandBase - { - private const string SettingsFileDefault = "wix.convert.settings.xml"; - - public ConvertCommand(IServiceProvider serviceProvider) - { - this.Messaging = serviceProvider.GetService(); - } - - private IMessaging Messaging { get; } - - public override Task ExecuteAsync(CancellationToken cancellationToken) - { - if (this.ShowHelp) - { - DisplayHelp(); - return Task.FromResult(-1); - } - - this.ParseSettings(SettingsFileDefault); - - var converter = new WixConverter(this.Messaging, this.IndentationAmount, this.ErrorsAsWarnings, this.IgnoreErrors); - - var errors = base.Inspect(Inspector, cancellationToken); - - return Task.FromResult(errors); - - int Inspector(string file, bool fix) - { - return converter.ConvertFile(file, fix); - } - } - - private static void DisplayHelp() - { - Console.WriteLine(); - Console.WriteLine("Usage: wix convert [options] sourceFile [sourceFile ...]"); - Console.WriteLine(); - Console.WriteLine("Options:"); - Console.WriteLine(" -h|--help Show command line help."); - Console.WriteLine(" --nologo Suppress displaying the logo information."); - Console.WriteLine(" -n|--dry-run Only display errors, do not update files."); - Console.WriteLine(" -r|--recurse Search for matching files in current dir and subdirs."); - Console.WriteLine(" -set1 Primary settings file."); - Console.WriteLine(" -set2 Secondary settings file (overrides primary)."); - Console.WriteLine(" -indent: Indentation multiple (overrides default of 4)."); - Console.WriteLine(); - Console.WriteLine(" sourceFile may use wildcards like *.wxs"); - } - } -} diff --git a/src/WixToolset.Converters/ConverterExtensionCommandLine.cs b/src/WixToolset.Converters/ConverterExtensionCommandLine.cs deleted file mode 100644 index 06d3658c..00000000 --- a/src/WixToolset.Converters/ConverterExtensionCommandLine.cs +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Converters -{ - using System; - using System.Collections.Generic; - using WixToolset.Extensibility; - using WixToolset.Extensibility.Data; - using WixToolset.Extensibility.Services; - - /// - /// Parses the "convert" command-line command. See ConvertCommand for - /// the bulk of the command-line processing. - /// - internal class ConverterExtensionCommandLine : BaseExtensionCommandLine - { - public ConverterExtensionCommandLine(IServiceProvider serviceProvider) - { - this.ServiceProvider = serviceProvider; - } - - private IServiceProvider ServiceProvider { get; } - - public override IReadOnlyCollection CommandLineSwitches => new ExtensionCommandLineSwitch[] - { - new ExtensionCommandLineSwitch { Switch = "convert", Description = "Convert v3 source code to v4 source code." }, - new ExtensionCommandLineSwitch { Switch = "format", Description = "Ensures consistent formatting of source code." }, - }; - - public override bool TryParseCommand(ICommandLineParser parser, string argument, out ICommandLineCommand command) - { - command = null; - - if ("convert".Equals(argument, StringComparison.OrdinalIgnoreCase)) - { - command = new ConvertCommand(this.ServiceProvider); - } - else if ("format".Equals(argument, StringComparison.OrdinalIgnoreCase)) - { - command = new FormatCommand(this.ServiceProvider); - } - - return command != null; - } - } -} diff --git a/src/WixToolset.Converters/ConverterExtensionFactory.cs b/src/WixToolset.Converters/ConverterExtensionFactory.cs deleted file mode 100644 index d4f480aa..00000000 --- a/src/WixToolset.Converters/ConverterExtensionFactory.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Converters -{ - using System; - using WixToolset.Extensibility; - using WixToolset.Extensibility.Services; - - internal class ConverterExtensionFactory : IExtensionFactory - { - public ConverterExtensionFactory(IServiceProvider serviceProvider) - { - this.ServiceProvider = serviceProvider; - } - - private IServiceProvider ServiceProvider { get; } - - public bool TryCreateExtension(Type extensionType, out object extension) - { - extension = null; - - if (extensionType == typeof(IExtensionCommandLine)) - { - extension = new ConverterExtensionCommandLine(this.ServiceProvider); - } - - return extension != null; - } - } -} diff --git a/src/WixToolset.Converters/FixupCommandBase.cs b/src/WixToolset.Converters/FixupCommandBase.cs deleted file mode 100644 index 21282d07..00000000 --- a/src/WixToolset.Converters/FixupCommandBase.cs +++ /dev/null @@ -1,288 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Converters -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Threading; - using System.Threading.Tasks; - using System.Xml; - using WixToolset.Extensibility.Data; - using WixToolset.Extensibility.Services; - - internal abstract class FixupCommandBase : ICommandLineCommand - { - protected FixupCommandBase() - { - this.IndentationAmount = 4; // default indentation amount - this.ErrorsAsWarnings = new HashSet(); - this.ExemptFiles = new HashSet(); - this.IgnoreErrors = new HashSet(); - this.SearchPatternResults = new HashSet(); - this.SearchPatterns = new List(); - } - - public bool ShowLogo { get; private set; } - - public bool StopParsing { get; private set; } - - protected bool ShowHelp { get; set; } - - protected CustomTableTarget CustomTableSetting { get; set; } - - protected bool DryRun { get; set; } - - protected HashSet ErrorsAsWarnings { get; } - - protected HashSet IgnoreErrors { get; } - - protected HashSet ExemptFiles { get; } - - protected int IndentationAmount { get; set; } - - protected bool Recurse { get; set; } - - private HashSet SearchPatternResults { get; } - - private List SearchPatterns { get; } - - private string SettingsFile1 { get; set; } - - private string SettingsFile2 { get; set; } - - public bool TryParseArgument(ICommandLineParser parser, string argument) - { - if (!parser.IsSwitch(argument)) - { - this.SearchPatterns.Add(argument); - return true; - } - - var parameter = argument.Substring(1); - switch (parameter.ToLowerInvariant()) - { - case "?": - case "h": - case "-help": - this.ShowHelp = true; - this.ShowLogo = true; - this.StopParsing = true; - return true; - - case "-custom-table": - var customTableSetting = parser.GetNextArgumentOrError(argument); - switch (customTableSetting) - { - case "bundle": - this.CustomTableSetting = CustomTableTarget.Bundle; - break; - case "msi": - this.CustomTableSetting = CustomTableTarget.Msi; - break; - default: - parser.ReportErrorArgument(argument); - break; - } - return true; - - case "n": - case "-dry-run": - this.DryRun = true; - return true; - - case "nologo": - case "-nologo": - this.ShowLogo = false; - return true; - - case "s": - case "r": - case "-recurse": - case "-recursive": - this.Recurse = true; - return true; - - default: // other parameters - if (parameter.StartsWith("set1", StringComparison.Ordinal)) - { - this.SettingsFile1 = parameter.Substring(4); - return true; - } - else if (parameter.StartsWith("set2", StringComparison.Ordinal)) - { - this.SettingsFile2 = parameter.Substring(4); - return true; - } - else if (parameter.StartsWith("indent:", StringComparison.Ordinal)) - { - try - { - this.IndentationAmount = Convert.ToInt32(parameter.Substring(7)); - } - catch - { - parser.ReportErrorArgument(parameter); // $"Invalid numeric argument: {parameter}"; - } - return true; - } - - return false; - } - } - - public abstract Task ExecuteAsync(CancellationToken cancellationToken); - - protected void ParseSettings(string defaultSettingsFile) - { - // parse the settings if any were specified - if (null != this.SettingsFile1 || null != this.SettingsFile2) - { - this.ParseSettingsFiles(this.SettingsFile1, this.SettingsFile2); - } - else - { - if (File.Exists(defaultSettingsFile)) - { - this.ParseSettingsFiles(defaultSettingsFile, null); - } - } - } - - protected int Inspect(Func inspector, CancellationToken cancellationToken) - { - var errors = this.InspectSubDirectories(inspector, Path.GetFullPath("."), cancellationToken); - - foreach (var searchPattern in this.SearchPatterns) - { - if (!this.SearchPatternResults.Contains(searchPattern)) - { - Console.Error.WriteLine("Could not find file \"{0}\"", searchPattern); - errors++; - } - } - - return errors; - } - - /// - /// Inspect sub-directories. - /// - /// - /// The directory whose sub-directories will be inspected. - /// - /// The number of errors that were found. - private int InspectSubDirectories(Func inspector, string directory, CancellationToken cancellationToken) - { - var errors = 0; - - foreach (var searchPattern in this.SearchPatterns) - { - foreach (var sourceFilePath in GetFiles(directory, searchPattern)) - { - cancellationToken.ThrowIfCancellationRequested(); - - var file = new FileInfo(sourceFilePath); - - if (!this.ExemptFiles.Contains(file.Name.ToUpperInvariant())) - { - this.SearchPatternResults.Add(searchPattern); - errors += inspector(file.FullName, !this.DryRun); - } - } - } - - if (this.Recurse) - { - foreach (var childDirectoryPath in Directory.GetDirectories(directory)) - { - errors += this.InspectSubDirectories(inspector, childDirectoryPath, cancellationToken); - } - } - - return errors; - } - - /// - /// Parse the primary and secondary settings files. - /// - /// The primary settings file. - /// The secondary settings file. - private void ParseSettingsFiles(string localSettingsFile1, string localSettingsFile2) - { - if (null == localSettingsFile1 && null != localSettingsFile2) - { - throw new ArgumentException("Cannot specify a secondary settings file (set2) without a primary settings file (set1).", nameof(localSettingsFile2)); - } - - var settingsFile = localSettingsFile1; - while (null != settingsFile) - { - var doc = new XmlDocument(); - doc.Load(settingsFile); - - // get the types of tests that will have their errors displayed as warnings - var testsIgnoredElements = doc.SelectNodes("/Settings/IgnoreErrors/Test"); - foreach (XmlElement test in testsIgnoredElements) - { - var key = test.GetAttribute("Id"); - this.IgnoreErrors.Add(key); - } - - // get the types of tests that will have their errors displayed as warnings - var testsAsWarningsElements = doc.SelectNodes("/Settings/ErrorsAsWarnings/Test"); - foreach (XmlElement test in testsAsWarningsElements) - { - var key = test.GetAttribute("Id"); - this.ErrorsAsWarnings.Add(key); - } - - // get the exempt files - var localExemptFiles = doc.SelectNodes("/Settings/ExemptFiles/File"); - foreach (XmlElement file in localExemptFiles) - { - var key = file.GetAttribute("Name").ToUpperInvariant(); - this.ExemptFiles.Add(key); - } - - settingsFile = localSettingsFile2; - localSettingsFile2 = null; - } - } - - /// - /// Get the files that match a search path pattern. - /// - /// The base directory at which to begin the search. - /// The search path pattern. - /// The files matching the pattern. - private static string[] GetFiles(string baseDir, string searchPath) - { - // convert alternate directory separators to the standard one - var filePath = searchPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); - var lastSeparator = filePath.LastIndexOf(Path.DirectorySeparatorChar); - string[] files = null; - - try - { - if (0 > lastSeparator) - { - files = Directory.GetFiles(baseDir, filePath); - } - else // found directory separator - { - var searchPattern = filePath.Substring(lastSeparator + 1); - - files = Directory.GetFiles(filePath.Substring(0, lastSeparator + 1), searchPattern); - } - } - catch (DirectoryNotFoundException) - { - // don't let this function throw the DirectoryNotFoundException. (this exception - // occurs for non-existant directories and invalid characters in the searchPattern) - } - - return files; - } - } -} diff --git a/src/WixToolset.Converters/FormatCommand.cs b/src/WixToolset.Converters/FormatCommand.cs deleted file mode 100644 index 0861fc51..00000000 --- a/src/WixToolset.Converters/FormatCommand.cs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Converters -{ - using System; - using System.Threading; - using System.Threading.Tasks; - using WixToolset.Extensibility.Services; - - internal class FormatCommand : FixupCommandBase - { - private const string SettingsFileDefault = "wix.format.settings.xml"; - - public FormatCommand(IServiceProvider serviceProvider) - { - this.Messaging = serviceProvider.GetService(); - } - - private IMessaging Messaging { get; } - - public override Task ExecuteAsync(CancellationToken cancellationToken) - { - if (this.ShowHelp) - { - DisplayHelp(); - return Task.FromResult(-1); - } - - var converter = new WixConverter(this.Messaging, this.IndentationAmount, this.ErrorsAsWarnings, this.IgnoreErrors); - - this.ParseSettings(SettingsFileDefault); - - var errors = base.Inspect(Inspector, cancellationToken); - - return Task.FromResult(errors); - - int Inspector(string file, bool fix) - { - return converter.FormatFile(file, fix); - } - } - - private static void DisplayHelp() - { - Console.WriteLine(); - Console.WriteLine("Usage: wix format [options] sourceFile [sourceFile ...]"); - Console.WriteLine(); - Console.WriteLine("Options:"); - Console.WriteLine(" -h|--help Show command line help."); - Console.WriteLine(" --nologo Suppress displaying the logo information."); - Console.WriteLine(" -n|--dry-run Only display errors, do not update files."); - Console.WriteLine(" -r|--recurse Search for matching files in current dir and subdirs."); - Console.WriteLine(" -set1 Primary settings file."); - Console.WriteLine(" -set2 Secondary settings file (overrides primary)."); - Console.WriteLine(" -indent: Indentation multiple (overrides default of 4)."); - Console.WriteLine(); - Console.WriteLine(" sourceFile may use wildcards like *.wxs"); - } - } -} diff --git a/src/WixToolset.Converters/WixConverter.cs b/src/WixToolset.Converters/WixConverter.cs deleted file mode 100644 index e42d0605..00000000 --- a/src/WixToolset.Converters/WixConverter.cs +++ /dev/null @@ -1,2435 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Converters -{ - using System; - using System.Collections.Generic; - using System.Globalization; - using System.IO; - using System.Linq; - using System.Text; - using System.Text.RegularExpressions; - using System.Xml; - using System.Xml.Linq; - using WixToolset.Data; - using WixToolset.Data.WindowsInstaller; - using WixToolset.Extensibility.Services; - - /// - /// How to convert CustomTable elements. - /// - public enum CustomTableTarget - { - /// - /// Ambiguous elements will be left alone. - /// - Unknown, - - /// - /// Use CustomTable, CustomTableRef, and Unreal. - /// - Msi, - - /// - /// Use BundleCustomData and BundleCustomDataRef. - /// - Bundle, - } - - /// - /// WiX source code converter. - /// - public sealed class WixConverter - { - private enum ConvertOperation - { - Convert, - Format, - } - - private static readonly Regex AddPrefix = new Regex(@"^[^a-zA-Z_]", RegexOptions.Compiled); - private static readonly Regex IllegalIdentifierCharacters = new Regex(@"[^A-Za-z0-9_\.]|\.{2,}", RegexOptions.Compiled); // non 'words' and assorted valid characters - - private const char XDocumentNewLine = '\n'; // XDocument normalizes "\r\n" to just "\n". - private static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs"; - private static readonly XNamespace Wix3Namespace = "http://schemas.microsoft.com/wix/2006/wi"; - private static readonly XNamespace WixBalNamespace = "http://wixtoolset.org/schemas/v4/wxs/bal"; - private static readonly XNamespace WixDependencyNamespace = "http://wixtoolset.org/schemas/v4/wxs/dependency"; - private static readonly XNamespace WixUtilNamespace = "http://wixtoolset.org/schemas/v4/wxs/util"; - private static readonly XNamespace WixFirewallNamespace = "http://wixtoolset.org/schemas/v4/wxs/firewall"; - - private static readonly XName AdminExecuteSequenceElementName = WixNamespace + "AdminExecuteSequence"; - private static readonly XName AdminUISequenceSequenceElementName = WixNamespace + "AdminUISequence"; - private static readonly XName AdvertiseExecuteSequenceElementName = WixNamespace + "AdvertiseExecuteSequence"; - private static readonly XName InstallExecuteSequenceElementName = WixNamespace + "InstallExecuteSequence"; - private static readonly XName InstallUISequenceSequenceElementName = WixNamespace + "InstallUISequence"; - private static readonly XName BootstrapperApplicationElementName = WixNamespace + "BootstrapperApplication"; - private static readonly XName BootstrapperApplicationDllElementName = WixNamespace + "BootstrapperApplicationDll"; - private static readonly XName BootstrapperApplicationRefElementName = WixNamespace + "BootstrapperApplicationRef"; - private static readonly XName ApprovedExeForElevationElementName = WixNamespace + "ApprovedExeForElevation"; - private static readonly XName BundleAttributeElementName = WixNamespace + "BundleAttribute"; - private static readonly XName BundleAttributeDefinitionElementName = WixNamespace + "BundleAttributeDefinition"; - private static readonly XName BundleCustomDataElementName = WixNamespace + "BundleCustomData"; - private static readonly XName BundleCustomDataRefElementName = WixNamespace + "BundleCustomDataRef"; - private static readonly XName BundleElementElementName = WixNamespace + "BundleElement"; - private static readonly XName CustomTableElementName = WixNamespace + "CustomTable"; - private static readonly XName CustomTableRefElementName = WixNamespace + "CustomTableRef"; - private static readonly XName CatalogElementName = WixNamespace + "Catalog"; - private static readonly XName ColumnElementName = WixNamespace + "Column"; - private static readonly XName ComponentElementName = WixNamespace + "Component"; - private static readonly XName ControlElementName = WixNamespace + "Control"; - private static readonly XName ConditionElementName = WixNamespace + "Condition"; - private static readonly XName CreateFolderElementName = WixNamespace + "CreateFolder"; - private static readonly XName DataElementName = WixNamespace + "Data"; - private static readonly XName OldProvidesElementName = WixDependencyNamespace + "Provides"; - private static readonly XName OldRequiresElementName = WixDependencyNamespace + "Requires"; - private static readonly XName OldRequiresRefElementName = WixDependencyNamespace + "RequiresRef"; - private static readonly XName DirectoryElementName = WixNamespace + "Directory"; - private static readonly XName EmbeddedChainerElementName = WixNamespace + "EmbeddedChainer"; - private static readonly XName ErrorElementName = WixNamespace + "Error"; - private static readonly XName FeatureElementName = WixNamespace + "Feature"; - private static readonly XName FileElementName = WixNamespace + "File"; - private static readonly XName FragmentElementName = WixNamespace + "Fragment"; - private static readonly XName FirewallRemoteAddressElementName = WixFirewallNamespace + "RemoteAddress"; - private static readonly XName LaunchElementName = WixNamespace + "Launch"; - private static readonly XName LevelElementName = WixNamespace + "Level"; - private static readonly XName ExePackageElementName = WixNamespace + "ExePackage"; - private static readonly XName ExePackagePayloadElementName = WixNamespace + "ExePackagePayload"; - private static readonly XName ModuleElementName = WixNamespace + "Module"; - private static readonly XName MsiPackageElementName = WixNamespace + "MsiPackage"; - private static readonly XName MspPackageElementName = WixNamespace + "MspPackage"; - private static readonly XName MsuPackageElementName = WixNamespace + "MsuPackage"; - private static readonly XName MsuPackagePayloadElementName = WixNamespace + "MsuPackagePayload"; - private static readonly XName PackageElementName = WixNamespace + "Package"; - private static readonly XName PayloadElementName = WixNamespace + "Payload"; - private static readonly XName PermissionExElementName = WixNamespace + "PermissionEx"; - private static readonly XName ProductElementName = WixNamespace + "Product"; - private static readonly XName ProgressTextElementName = WixNamespace + "ProgressText"; - private static readonly XName PropertyRefElementName = WixNamespace + "PropertyRef"; - private static readonly XName PublishElementName = WixNamespace + "Publish"; - private static readonly XName ProvidesElementName = WixNamespace + "Provides"; - private static readonly XName RequiresElementName = WixNamespace + "Requires"; - private static readonly XName RequiresRefElementName = WixNamespace + "RequiresRef"; - private static readonly XName MultiStringValueElementName = WixNamespace + "MultiStringValue"; - private static readonly XName RemotePayloadElementName = WixNamespace + "RemotePayload"; - private static readonly XName RegistryKeyElementName = WixNamespace + "RegistryKey"; - private static readonly XName RegistrySearchElementName = WixNamespace + "RegistrySearch"; - private static readonly XName RequiredPrivilegeElementName = WixNamespace + "RequiredPrivilege"; - private static readonly XName RowElementName = WixNamespace + "Row"; - private static readonly XName ServiceArgumentElementName = WixNamespace + "ServiceArgument"; - private static readonly XName SetDirectoryElementName = WixNamespace + "SetDirectory"; - private static readonly XName SetPropertyElementName = WixNamespace + "SetProperty"; - private static readonly XName ShortcutPropertyElementName = WixNamespace + "ShortcutProperty"; - private static readonly XName SoftwareTagElementName = WixNamespace + "SoftwareTag"; - private static readonly XName SoftwareTagRefElementName = WixNamespace + "SoftwareTagRef"; - private static readonly XName StandardDirectoryElementName = WixNamespace + "StandardDirectory"; - private static readonly XName TagElementName = XNamespace.None + "Tag"; - private static readonly XName TagRefElementName = XNamespace.None + "TagRef"; - private static readonly XName TextElementName = WixNamespace + "Text"; - private static readonly XName UITextElementName = WixNamespace + "UIText"; - private static readonly XName VariableElementName = WixNamespace + "Variable"; - private static readonly XName VerbElementName = WixNamespace + "Verb"; - private static readonly XName BalUseUILanguagesName = WixBalNamespace + "UseUILanguages"; - private static readonly XName BalStandardBootstrapperApplicationName = WixBalNamespace + "WixStandardBootstrapperApplication"; - private static readonly XName BalManagedBootstrapperApplicationHostName = WixBalNamespace + "WixManagedBootstrapperApplicationHost"; - private static readonly XName BalOldDotNetCoreBootstrapperApplicationName = WixBalNamespace + "WixDotNetCoreBootstrapperApplication"; - private static readonly XName BalNewDotNetCoreBootstrapperApplicationName = WixBalNamespace + "WixDotNetCoreBootstrapperApplicationHost"; - private static readonly XName UtilCloseApplicationElementName = WixUtilNamespace + "CloseApplication"; - private static readonly XName UtilPermissionExElementName = WixUtilNamespace + "PermissionEx"; - private static readonly XName UtilRegistrySearchName = WixUtilNamespace + "RegistrySearch"; - private static readonly XName UtilXmlConfigElementName = WixUtilNamespace + "XmlConfig"; - private static readonly XName CustomActionElementName = WixNamespace + "CustomAction"; - private static readonly XName CustomActionRefElementName = WixNamespace + "CustomActionRef"; - private static readonly XName PropertyElementName = WixNamespace + "Property"; - private static readonly XName Wix4ElementName = WixNamespace + "Wix"; - private static readonly XName Wix3ElementName = Wix3Namespace + "Wix"; - private static readonly XName WixElementWithoutNamespaceName = XNamespace.None + "Wix"; - private static readonly XName Include4ElementName = WixNamespace + "Include"; - private static readonly XName Include3ElementName = Wix3Namespace + "Include"; - private static readonly XName IncludeElementWithoutNamespaceName = XNamespace.None + "Include"; - private static readonly XName SummaryInformationElementName = WixNamespace + "SummaryInformation"; - private static readonly XName MediaTemplateElementName = WixNamespace + "MediaTemplate"; - - private static readonly XName DependencyCheckAttributeName = WixDependencyNamespace + "Check"; - private static readonly XName DependencyEnforceAttributeName = WixDependencyNamespace + "Enforce"; - - private static readonly Dictionary OldToNewNamespaceMapping = new Dictionary() - { - { "http://schemas.microsoft.com/wix/BalExtension", "http://wixtoolset.org/schemas/v4/wxs/bal" }, - { "http://schemas.microsoft.com/wix/ComPlusExtension", "http://wixtoolset.org/schemas/v4/wxs/complus" }, - { "http://schemas.microsoft.com/wix/DependencyExtension", WixDependencyNamespace }, - { "http://schemas.microsoft.com/wix/DifxAppExtension", "http://wixtoolset.org/schemas/v4/wxs/difxapp" }, - { "http://schemas.microsoft.com/wix/FirewallExtension", "http://wixtoolset.org/schemas/v4/wxs/firewall" }, - { "http://schemas.microsoft.com/wix/HttpExtension", "http://wixtoolset.org/schemas/v4/wxs/http" }, - { "http://schemas.microsoft.com/wix/IIsExtension", "http://wixtoolset.org/schemas/v4/wxs/iis" }, - { "http://schemas.microsoft.com/wix/MsmqExtension", "http://wixtoolset.org/schemas/v4/wxs/msmq" }, - { "http://schemas.microsoft.com/wix/NetFxExtension", "http://wixtoolset.org/schemas/v4/wxs/netfx" }, - { "http://schemas.microsoft.com/wix/PSExtension", "http://wixtoolset.org/schemas/v4/wxs/powershell" }, - { "http://schemas.microsoft.com/wix/SqlExtension", "http://wixtoolset.org/schemas/v4/wxs/sql" }, - { "http://schemas.microsoft.com/wix/TagExtension", XNamespace.None }, - { "http://schemas.microsoft.com/wix/UtilExtension", WixUtilNamespace }, - { "http://schemas.microsoft.com/wix/VSExtension", "http://wixtoolset.org/schemas/v4/wxs/vs" }, - { "http://wixtoolset.org/schemas/thmutil/2010", "http://wixtoolset.org/schemas/v4/thmutil" }, - { "http://schemas.microsoft.com/wix/2009/Lux", "http://wixtoolset.org/schemas/v4/lux" }, - { "http://schemas.microsoft.com/wix/2006/wi", "http://wixtoolset.org/schemas/v4/wxs" }, - { "http://schemas.microsoft.com/wix/2006/localization", "http://wixtoolset.org/schemas/v4/wxl" }, - { "http://schemas.microsoft.com/wix/2006/libraries", "http://wixtoolset.org/schemas/v4/wixlib" }, - { "http://schemas.microsoft.com/wix/2006/objects", "http://wixtoolset.org/schemas/v4/wixobj" }, - { "http://schemas.microsoft.com/wix/2006/outputs", "http://wixtoolset.org/schemas/v4/wixout" }, - { "http://schemas.microsoft.com/wix/2007/pdbs", "http://wixtoolset.org/schemas/v4/wixpdb" }, - { "http://schemas.microsoft.com/wix/2003/04/actions", "http://wixtoolset.org/schemas/v4/wi/actions" }, - { "http://schemas.microsoft.com/wix/2006/tables", "http://wixtoolset.org/schemas/v4/wi/tables" }, - { "http://schemas.microsoft.com/wix/2006/WixUnit", "http://wixtoolset.org/schemas/v4/wixunit" }, - }; - - private readonly Dictionary> ConvertElementMapping; - private readonly Regex DeprecatedPrefixRegex = new Regex(@"(?<=(^|[^\$])(\$\$)*)\$(?=\(loc\.[^.].*\))", - RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); - - /// - /// Instantiate a new Converter class. - /// - /// - /// Indentation value to use when validating leading whitespace. - /// Test errors to display as warnings. - /// Test errors to ignore. - /// How to convert CustomTable elements. - public WixConverter(IMessaging messaging, int indentationAmount, IEnumerable errorsAsWarnings = null, IEnumerable ignoreErrors = null, CustomTableTarget customTableTarget = CustomTableTarget.Unknown) - { - this.ConvertElementMapping = new Dictionary> - { - { WixConverter.AdminExecuteSequenceElementName, this.ConvertSequenceElement }, - { WixConverter.AdminUISequenceSequenceElementName, this.ConvertSequenceElement }, - { WixConverter.AdvertiseExecuteSequenceElementName, this.ConvertSequenceElement }, - { WixConverter.InstallUISequenceSequenceElementName, this.ConvertSequenceElement }, - { WixConverter.InstallExecuteSequenceElementName, this.ConvertSequenceElement }, - { WixConverter.BootstrapperApplicationElementName, this.ConvertBootstrapperApplicationElement }, - { WixConverter.BootstrapperApplicationRefElementName, this.ConvertBootstrapperApplicationRefElement }, - { WixConverter.ApprovedExeForElevationElementName, this.ConvertApprovedExeForElevationElement }, - { WixConverter.CatalogElementName, this.ConvertCatalogElement }, - { WixConverter.ColumnElementName, this.ConvertColumnElement }, - { WixConverter.ComponentElementName, this.ConvertComponentElement }, - { WixConverter.ControlElementName, this.ConvertControlElement }, - { WixConverter.CustomActionElementName, this.ConvertCustomActionElement }, - { WixConverter.CustomTableElementName, this.ConvertCustomTableElement }, - { WixConverter.DataElementName, this.ConvertDataElement }, - { WixConverter.DirectoryElementName, this.ConvertDirectoryElement }, - { WixConverter.FeatureElementName, this.ConvertFeatureElement }, - { WixConverter.FileElementName, this.ConvertFileElement }, - { WixConverter.FragmentElementName, this.ConvertFragmentElement }, - { WixConverter.FirewallRemoteAddressElementName, this.ConvertFirewallRemoteAddressElement }, - { WixConverter.EmbeddedChainerElementName, this.ConvertEmbeddedChainerElement }, - { WixConverter.ErrorElementName, this.ConvertErrorElement }, - { WixConverter.ExePackageElementName, this.ConvertExePackageElement }, - { WixConverter.ModuleElementName, this.ConvertModuleElement }, - { WixConverter.MsiPackageElementName, this.ConvertWindowsInstallerPackageElement }, - { WixConverter.MspPackageElementName, this.ConvertWindowsInstallerPackageElement }, - { WixConverter.MsuPackageElementName, this.ConvertSuppressSignatureValidation }, - { WixConverter.OldProvidesElementName, this.ConvertProvidesElement }, - { WixConverter.OldRequiresElementName, this.ConvertRequiresElement }, - { WixConverter.OldRequiresRefElementName, this.ConvertRequiresRefElement }, - { WixConverter.PayloadElementName, this.ConvertSuppressSignatureValidation }, - { WixConverter.PermissionExElementName, this.ConvertPermissionExElement }, - { WixConverter.ProductElementName, this.ConvertProductElement }, - { WixConverter.ProgressTextElementName, this.ConvertProgressTextElement }, - { WixConverter.PropertyRefElementName, this.ConvertPropertyRefElement }, - { WixConverter.PublishElementName, this.ConvertPublishElement }, - { WixConverter.MultiStringValueElementName, this.ConvertMultiStringValueElement }, - { WixConverter.RegistryKeyElementName, this.ConvertRegistryKeyElement }, - { WixConverter.RegistrySearchElementName, this.ConvertRegistrySearchElement }, - { WixConverter.RemotePayloadElementName, this.ConvertRemotePayloadElement }, - { WixConverter.RequiredPrivilegeElementName, this.ConvertRequiredPrivilegeElement }, - { WixConverter.CustomActionRefElementName, this.ConvertCustomActionRefElement }, - { WixConverter.ServiceArgumentElementName, this.ConvertServiceArgumentElement }, - { WixConverter.SetDirectoryElementName, this.ConvertSetDirectoryElement }, - { WixConverter.SetPropertyElementName, this.ConvertSetPropertyElement }, - { WixConverter.ShortcutPropertyElementName, this.ConvertShortcutPropertyElement }, - { WixConverter.TagElementName, this.ConvertTagElement }, - { WixConverter.TagRefElementName, this.ConvertTagRefElement }, - { WixConverter.TextElementName, this.ConvertTextElement }, - { WixConverter.UITextElementName, this.ConvertUITextElement }, - { WixConverter.VariableElementName, this.ConvertVariableElement }, - { WixConverter.UtilCloseApplicationElementName, this.ConvertUtilCloseApplicationElementName }, - { WixConverter.UtilPermissionExElementName, this.ConvertUtilPermissionExElement }, - { WixConverter.UtilRegistrySearchName, this.ConvertUtilRegistrySearchElement }, - { WixConverter.UtilXmlConfigElementName, this.ConvertUtilXmlConfigElement }, - { WixConverter.PropertyElementName, this.ConvertPropertyElement }, - { WixConverter.WixElementWithoutNamespaceName, this.ConvertElementWithoutNamespace }, - { WixConverter.IncludeElementWithoutNamespaceName, this.ConvertElementWithoutNamespace }, - { WixConverter.VerbElementName, this.ConvertVerbElement }, - }; - - this.Messaging = messaging; - - this.IndentationAmount = indentationAmount; - - this.ErrorsAsWarnings = new HashSet(this.YieldConverterTypes(errorsAsWarnings)); - - this.IgnoreErrors = new HashSet(this.YieldConverterTypes(ignoreErrors)); - - this.CustomTableSetting = customTableTarget; - } - - private CustomTableTarget CustomTableSetting { get; } - - private int Errors { get; set; } - - private HashSet ErrorsAsWarnings { get; set; } - - private HashSet IgnoreErrors { get; set; } - - private IMessaging Messaging { get; } - - private int IndentationAmount { get; set; } - - private ConvertOperation Operation { get; set; } - - private string SourceFile { get; set; } - - private int SourceVersion { get; set; } - - /// - /// Convert a file. - /// - /// The file to convert. - /// Option to save the converted errors that are found. - /// The number of errors found. - public int ConvertFile(string sourceFile, bool saveConvertedFile) - { - var document = this.OpenSourceFile(sourceFile); - - if (document is null) - { - return 1; - } - - this.ConvertDocument(document); - - // Fix errors if requested and necessary. - if (saveConvertedFile && 0 < this.Errors) - { - this.SaveDocument(document); - } - - return this.Errors; - } - - /// - /// Convert a document. - /// - /// The document to convert. - /// The number of errors found. - public int ConvertDocument(XDocument document) - { - // Reset the instance info. - this.Errors = 0; - this.SourceVersion = 0; - this.Operation = ConvertOperation.Convert; - - // Remove the declaration. - if (null != document.Declaration - && this.OnError(ConverterTestType.DeclarationPresent, null, "This file contains an XML declaration on the first line.")) - { - document.Declaration = null; - TrimLeadingText(document); - } - - // Start converting the nodes at the top. - this.ConvertNodes(document.Nodes(), 0); - this.RemoveUnusedNamespaces(document.Root); - - return this.Errors; - } - - /// - /// Format a file. - /// - /// The file to format. - /// Option to save the format errors that are found. - /// The number of errors found. - public int FormatFile(string sourceFile, bool saveConvertedFile) - { - var document = this.OpenSourceFile(sourceFile); - - if (document is null) - { - return 1; - } - - this.FormatDocument(document); - - // Fix errors if requested and necessary. - if (saveConvertedFile && 0 < this.Errors) - { - this.SaveDocument(document); - } - - return this.Errors; - } - - /// - /// Format a document. - /// - /// The document to format. - /// The number of errors found. - public int FormatDocument(XDocument document) - { - // Reset the instance info. - this.Errors = 0; - this.SourceVersion = 0; - this.Operation = ConvertOperation.Format; - - // Remove the declaration. - if (null != document.Declaration - && this.OnError(ConverterTestType.DeclarationPresent, null, "This file contains an XML declaration on the first line.")) - { - document.Declaration = null; - TrimLeadingText(document); - } - - // Start converting the nodes at the top. - this.ConvertNodes(document.Nodes(), 0); - this.RemoveUnusedNamespaces(document.Root); - - return this.Errors; - } - - private XDocument OpenSourceFile(string sourceFile) - { - this.SourceFile = sourceFile; - - try - { - return XDocument.Load(this.SourceFile, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - } - catch (XmlException e) - { - this.OnError(ConverterTestType.XmlException, null, "The xml is invalid. Detail: '{0}'", e.Message); - } - - return null; - } - - private void SaveDocument(XDocument document) - { - var ignoreDeclarationError = this.IgnoreErrors.Contains(ConverterTestType.DeclarationPresent); - - try - { - using (var writer = XmlWriter.Create(this.SourceFile, new XmlWriterSettings { OmitXmlDeclaration = !ignoreDeclarationError })) - { - document.Save(writer); - } - } - catch (UnauthorizedAccessException) - { - this.OnError(ConverterTestType.UnauthorizedAccessException, null, "Could not write to file."); - } - } - - private void ConvertNodes(IEnumerable nodes, int level) - { - // Note we operate on a copy of the node list since we may - // remove some whitespace nodes during this processing. - foreach (var node in nodes.ToList()) - { - if (node is XText text) - { - if (null != text.Value) - { - if (this.TryFixDeprecatedLocalizationPrefixes(node, text.Value, out var newValue, ConverterTestType.DeprecatedLocalizationVariablePrefixInTextValue)) - { - text.Value = newValue; - } - } - if (!String.IsNullOrWhiteSpace(text.Value)) - { - text.Value = text.Value.Trim(); - } - else if (node.NextNode is XCData cdata) - { - this.EnsurePrecedingWhitespaceRemoved(text, node, ConverterTestType.WhitespacePrecedingNodeWrong); - } - else if (node.NextNode is XElement element) - { - this.EnsurePrecedingWhitespaceCorrect(text, node, level, ConverterTestType.WhitespacePrecedingNodeWrong); - } - else if (node.NextNode is null) // this is the space before the close element - { - if (node.PreviousNode is null || node.PreviousNode is XCData) - { - this.EnsurePrecedingWhitespaceRemoved(text, node.Parent, ConverterTestType.WhitespacePrecedingEndElementWrong); - } - else if (level == 0) // root element's close tag - { - this.EnsurePrecedingWhitespaceCorrect(text, node, 0, ConverterTestType.WhitespacePrecedingEndElementWrong); - } - else - { - this.EnsurePrecedingWhitespaceCorrect(text, node, level - 1, ConverterTestType.WhitespacePrecedingEndElementWrong); - } - } - } - else if (node is XElement element) - { - this.ConvertElement(element); - - var before = element.Nodes().ToList(); - - this.ConvertNodes(before, level + 1); - - // If any nodes were added during the processing of the children, - // ensure those added children get processed as well. - var added = element.Nodes().Except(before).ToList(); - - if (added.Any()) - { - this.ConvertNodes(added, level + 1); - } - } - } - } - - private bool TryFixDeprecatedLocalizationPrefixes(XNode node, string value, out string newValue, ConverterTestType testType) - { - newValue = this.DeprecatedPrefixRegex.Replace(value, "!"); - - if (object.ReferenceEquals(newValue, value)) - { - return false; - } - - var message = testType == ConverterTestType.DeprecatedLocalizationVariablePrefixInTextValue ? "The prefix on the localization variable in the inner text is incorrect." : "The prefix on the localization variable in the attribute value is incorrect."; - - return this.OnError(testType, node, message); - } - - private void EnsurePrecedingWhitespaceCorrect(XText whitespace, XNode node, int level, ConverterTestType testType) - { - if (!WixConverter.LeadingWhitespaceValid(this.IndentationAmount, level, whitespace.Value)) - { - var message = testType == ConverterTestType.WhitespacePrecedingEndElementWrong ? "The whitespace preceding this end element is incorrect." : "The whitespace preceding this node is incorrect."; - - if (this.OnError(testType, node, message)) - { - WixConverter.FixupWhitespace(this.IndentationAmount, level, whitespace); - } - } - } - - private void EnsurePrecedingWhitespaceRemoved(XText whitespace, XNode node, ConverterTestType testType) - { - if (!String.IsNullOrEmpty(whitespace.Value) && whitespace.NodeType != XmlNodeType.CDATA) - { - var message = testType == ConverterTestType.WhitespacePrecedingEndElementWrong ? "The whitespace preceding this end element is incorrect." : "The whitespace preceding this node is incorrect."; - - if (this.OnError(testType, node, message)) - { - whitespace.Remove(); - } - } - } - - private void ConvertElement(XElement element) - { - var deprecatedToUpdatedNamespaces = new Dictionary(); - - foreach (var attribute in element.Attributes()) - { - if (attribute.IsNamespaceDeclaration) - { - // Gather any deprecated namespaces, then update this element tree based on those deprecations. - var declaration = attribute; - - if (element.Name == Wix3ElementName || element.Name == Include3ElementName) - { - this.SourceVersion = 3; - } - else if (element.Name == Wix4ElementName || element.Name == Include4ElementName) - { - this.SourceVersion = 4; - } - - if (WixConverter.OldToNewNamespaceMapping.TryGetValue(declaration.Value, out var ns)) - { - if (this.OnError(ConverterTestType.XmlnsValueWrong, declaration, "The namespace '{0}' is out of date. It must be '{1}'.", declaration.Value, ns.NamespaceName)) - { - deprecatedToUpdatedNamespaces.Add(declaration.Value, ns); - } - } - } - else - { - if (null != attribute.Value) - { - if (this.TryFixDeprecatedLocalizationPrefixes(element, attribute.Value, out var newValue, ConverterTestType.DeprecatedLocalizationVariablePrefixInAttributeValue)) - { - attribute.Value = newValue; - } - } - } - } - - if (deprecatedToUpdatedNamespaces.Any()) - { - WixConverter.UpdateElementsWithDeprecatedNamespaces(element.DescendantsAndSelf(), deprecatedToUpdatedNamespaces); - } - - // Apply any specialized conversion actions. - if (this.ConvertElementMapping.TryGetValue(element.Name, out var convert)) - { - convert(element); - } - } - - private void ConvertBootstrapperApplicationElement(XElement element) - { - var xUseUILanguages = element.Attribute(BalUseUILanguagesName); - if (xUseUILanguages != null && - this.OnError(ConverterTestType.BalUseUILanguagesDeprecated, element, "bal:UseUILanguages is deprecated, 'true' is now the standard behavior.")) - { - xUseUILanguages.Remove(); - } - - var xBADll = element.Elements(BootstrapperApplicationDllElementName).FirstOrDefault(); - if (xBADll == null) - { - xBADll = this.CreateBootstrapperApplicationDllElement(element); - - if (xBADll != null) - { - element.Add(Environment.NewLine); - element.Add(xBADll); - element.Add(Environment.NewLine); - } - } - } - - private XElement CreateBootstrapperApplicationDllElement(XElement element) - { - XElement xBADll = null; - var xSource = element.Attribute("SourceFile"); - var xDpiAwareness = element.Attribute("DpiAwareness"); - - if (xSource != null) - { - if (xBADll != null || CreateBADllElement(element, out xBADll)) - { - MoveAttribute(element, "SourceFile", xBADll); - MoveAttribute(element, "Name", xBADll); - } - } - else if (xDpiAwareness != null || this.SourceVersion < 4) // older code might be relying on old behavior of first Payload element being the BA dll. - { - var xFirstChild = element.Elements().FirstOrDefault(); - if (xFirstChild?.Name == PayloadElementName) - { - if (xBADll != null || CreateBADllElement(element, out xBADll)) - { - var attributes = xFirstChild.Attributes().ToList(); - xFirstChild.Remove(); - - foreach (var attribute in attributes) - { - xBADll.Add(attribute); - } - } - } - else - { - this.OnError(ConverterTestType.BootstrapperApplicationDllRequired, element, "The new BootstrapperApplicationDll element is required but could not be added automatically since the bootstrapper application dll was not directly specified."); - } - } - - if (xDpiAwareness != null) - { - if (xBADll != null || CreateBADllElement(element, out xBADll)) - { - MoveAttribute(element, "DpiAwareness", xBADll); - } - } - else if (this.SourceVersion < 4 && xBADll != null && - this.OnError(ConverterTestType.AssignBootstrapperApplicationDpiAwareness, element, "The BootstrapperApplicationDll DpiAwareness attribute is being set to 'unaware' to ensure it remains the same as the v3 default")) - { - xBADll.Add(new XAttribute("DpiAwareness", "unaware")); - } - - return xBADll; - - bool CreateBADllElement(XObject node, out XElement xCreatedBADll) - { - var create = this.OnError(ConverterTestType.BootstrapperApplicationDll, node, "The bootstrapper application dll is now specified in the BootstrapperApplicationDll element."); - xCreatedBADll = create ? new XElement(BootstrapperApplicationDllElementName) : null; - return create; - } - } - - private void ConvertBootstrapperApplicationRefElement(XElement element) - { - var xUseUILanguages = element.Attribute(BalUseUILanguagesName); - if (xUseUILanguages != null && - this.OnError(ConverterTestType.BalUseUILanguagesDeprecated, element, "bal:UseUILanguages is deprecated, 'true' is now the standard behavior.")) - { - xUseUILanguages.Remove(); - } - - var xId = element.Attribute("Id"); - if (xId != null) - { - XName balBAName = null; - XName oldBalBAName = null; - string theme = null; - - switch (xId.Value) - { - case "WixStandardBootstrapperApplication.RtfLicense": - balBAName = BalStandardBootstrapperApplicationName; - theme = "rtfLicense"; - break; - case "WixStandardBootstrapperApplication.RtfLargeLicense": - balBAName = BalStandardBootstrapperApplicationName; - theme = "rtfLargeLicense"; - break; - case "WixStandardBootstrapperApplication.HyperlinkLicense": - balBAName = BalStandardBootstrapperApplicationName; - theme = "hyperlinkLicense"; - break; - case "WixStandardBootstrapperApplication.HyperlinkLargeLicense": - balBAName = BalStandardBootstrapperApplicationName; - theme = "hyperlinkLargeLicense"; - break; - case "WixStandardBootstrapperApplication.HyperlinkSidebarLicense": - balBAName = BalStandardBootstrapperApplicationName; - theme = "hyperlinkSidebarLicense"; - break; - case "WixStandardBootstrapperApplication.Foundation": - balBAName = BalStandardBootstrapperApplicationName; - theme = "none"; - break; - case "ManagedBootstrapperApplicationHost": - case "ManagedBootstrapperApplicationHost.RtfLicense": - balBAName = BalManagedBootstrapperApplicationHostName; - theme = "standard"; - break; - case "ManagedBootstrapperApplicationHost.Minimal": - case "ManagedBootstrapperApplicationHost.RtfLicense.Minimal": - case "ManagedBootstrapperApplicationHost.Foundation": - balBAName = BalManagedBootstrapperApplicationHostName; - theme = "none"; - break; - case "DotNetCoreBootstrapperApplicationHost": - case "DotNetCoreBootstrapperApplicationHost.RtfLicense": - balBAName = BalNewDotNetCoreBootstrapperApplicationName; - oldBalBAName = BalOldDotNetCoreBootstrapperApplicationName; - theme = "standard"; - break; - case "DotNetCoreBootstrapperApplicationHost.Minimal": - case "DotNetCoreBootstrapperApplicationHost.RtfLicense.Minimal": - case "DotNetCoreBootstrapperApplicationHost.Foundation": - balBAName = BalNewDotNetCoreBootstrapperApplicationName; - oldBalBAName = BalOldDotNetCoreBootstrapperApplicationName; - theme = "none"; - break; - } - - if (balBAName != null && theme != null && - this.OnError(ConverterTestType.BalBootstrapperApplicationRefToElement, element, "Built-in bootstrapper applications must be referenced through their custom element")) - { - element.Name = BootstrapperApplicationElementName; - xId.Remove(); - this.ConvertBalBootstrapperApplicationRef(element, theme, balBAName, oldBalBAName); - } - } - } - - private void ConvertApprovedExeForElevationElement(XElement element) - { - this.RenameWin64ToBitness(element); - } - - private void ConvertBalBootstrapperApplicationRef(XElement element, string theme, XName balBAElementName, XName oldBalBAElementName = null) - { - var xBalBa = element.Element(oldBalBAElementName ?? balBAElementName); - if (xBalBa == null) - { - xBalBa = new XElement(balBAElementName); - element.Add(Environment.NewLine); - element.Add(xBalBa); - element.Add(Environment.NewLine); - } - else if (oldBalBAElementName != null) - { - xBalBa.Name = BalNewDotNetCoreBootstrapperApplicationName; - } - - if (theme != "standard") - { - xBalBa.Add(new XAttribute("Theme", theme)); - } - } - - private void ConvertCatalogElement(XElement element) - { - if (this.OnError(ConverterTestType.BundleSignatureValidationObsolete, element, "The Catalog element is obsolete. Signature validation is no longer supported. The element will be removed.")) - { - element.Remove(); - } - } - - private void ConvertColumnElement(XElement element) - { - var category = element.Attribute("Category"); - if (category != null) - { - var camelCaseValue = LowercaseFirstChar(category.Value); - if (category.Value != camelCaseValue && - this.OnError(ConverterTestType.ColumnCategoryCamelCase, element, "The CustomTable Category attribute contains an incorrectly cased '{0}' value. Lowercase the first character instead.", category.Name)) - { - category.Value = camelCaseValue; - } - } - - var modularization = element.Attribute("Modularize"); - if (modularization != null) - { - var camelCaseValue = LowercaseFirstChar(modularization.Value); - if (modularization.Value != camelCaseValue && - this.OnError(ConverterTestType.ColumnModularizeCamelCase, element, "The CustomTable Modularize attribute contains an incorrectly cased '{0}' value. Lowercase the first character instead.", modularization.Name)) - { - modularization.Value = camelCaseValue; - } - } - } - - private void ConvertCustomTableElement(XElement element) - { - var bootstrapperApplicationData = element.Attribute("BootstrapperApplicationData"); - if (bootstrapperApplicationData?.Value == "no") - { - if (this.OnError(ConverterTestType.BootstrapperApplicationDataDeprecated, element, "The CustomTable element contains deprecated '{0}' attribute. Use the 'Unreal' attribute instead.", bootstrapperApplicationData.Name)) - { - bootstrapperApplicationData.Remove(); - } - } - else - { - if (element.Elements(ColumnElementName).Any() || bootstrapperApplicationData != null) - { - // Table definition - if (bootstrapperApplicationData != null) - { - switch (this.CustomTableSetting) - { - case CustomTableTarget.Bundle: - if (this.OnError(ConverterTestType.BootstrapperApplicationDataDeprecated, element, "The CustomTable element contains deprecated '{0}' attribute. Use the 'BundleCustomData' element for Bundles.", bootstrapperApplicationData.Name)) - { - element.Name = WixConverter.BundleCustomDataElementName; - bootstrapperApplicationData.Remove(); - this.ConvertCustomTableElementToBundle(element); - } - break; - case CustomTableTarget.Msi: - if (this.OnError(ConverterTestType.BootstrapperApplicationDataDeprecated, element, "The CustomTable element contains deprecated '{0}' attribute. Use the 'Unreal' attribute instead.", bootstrapperApplicationData.Name)) - { - element.Add(new XAttribute("Unreal", bootstrapperApplicationData.Value)); - bootstrapperApplicationData.Remove(); - } - break; - default: - this.OnError(ConverterTestType.CustomTableNotAlwaysConvertable, element, "The CustomTable element contains deprecated '{0}' attribute so can't be converted. Use the 'Unreal' attribute for MSI. Use the 'BundleCustomData' element for Bundles. Use the --custom-table argument to force conversion to 'msi' or 'bundle'", bootstrapperApplicationData.Name); - break; - } - } - } - else - { - // Table ref - switch (this.CustomTableSetting) - { - case CustomTableTarget.Bundle: - if (this.OnError(ConverterTestType.CustomTableRef, element, "CustomTable elements that don't contain the table definition are now BundleCustomDataRef for Bundles.")) - { - element.Name = WixConverter.BundleCustomDataRefElementName; - this.ConvertCustomTableElementToBundle(element); - } - break; - case CustomTableTarget.Msi: - if (this.OnError(ConverterTestType.CustomTableRef, element, "CustomTable elements that don't contain the table definition are now CustomTableRef for MSI.")) - { - element.Name = WixConverter.CustomTableRefElementName; - } - break; - default: - this.OnError(ConverterTestType.CustomTableNotAlwaysConvertable, element, "The CustomTable element contains no 'Column' elements so can't be converted. Use the 'CustomTableRef' element for MSI. Use the 'BundleCustomDataRef' element for Bundles. Use the --custom-table argument to force conversion to 'msi' or 'bundle'"); - break; - } - } - } - } - - private void ConvertCustomTableElementToBundle(XElement element) - { - foreach (var xColumn in element.Elements(ColumnElementName)) - { - xColumn.Name = WixConverter.BundleAttributeDefinitionElementName; - - foreach (var xAttribute in xColumn.Attributes().ToList()) - { - if (xAttribute.Name.LocalName != "Id" && - (xAttribute.Name.Namespace == WixConverter.Wix3Namespace || - xAttribute.Name.Namespace == WixConverter.WixNamespace || - String.IsNullOrEmpty(xAttribute.Name.Namespace.NamespaceName))) - { - xAttribute.Remove(); - } - } - } - - foreach (var xRow in element.Elements(RowElementName)) - { - xRow.Name = WixConverter.BundleElementElementName; - - foreach (var xData in xRow.Elements(DataElementName)) - { - xData.Name = WixConverter.BundleAttributeElementName; - - var xColumn = xData.Attribute("Column"); - if (xColumn != null) - { - xData.Add(new XAttribute("Id", xColumn.Value)); - xColumn.Remove(); - } - - this.ConvertInnerTextToAttribute(xData, "Value"); - } - } - } - - private void ConvertControlElement(XElement element) - { - var remove = new List(); - - foreach (var xCondition in element.Elements(ConditionElementName)) - { - var action = UppercaseFirstChar(xCondition.Attribute("Action")?.Value); - if (!String.IsNullOrEmpty(action) && - TryGetInnerText(xCondition, out var text) && - this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the '{1}Condition' attribute instead.", xCondition.Name.LocalName, action)) - { - element.Add(new XAttribute(action + "Condition", text)); - remove.Add(xCondition); - } - } - - for (var i = remove.Count - 1; i >= 0; i--) - { - remove[i].Remove(); - } - } - - private void ConvertComponentElement(XElement element) - { - var guid = element.Attribute("Guid"); - if (guid != null && guid.Value == "*") - { - if (this.OnError(ConverterTestType.AutoGuidUnnecessary, element, "Using '*' for the Component Guid attribute is unnecessary. Remove the attribute to remove the redundancy.")) - { - guid.Remove(); - } - } - - var xCondition = element.Element(ConditionElementName); - if (xCondition != null) - { - if (TryGetInnerText(xCondition, out var text) && - this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Condition' attribute instead.", xCondition.Name.LocalName)) - { - element.Add(new XAttribute("Condition", text)); - xCondition.Remove(); - } - } - - this.RenameWin64ToBitness(element); - } - - private void ConvertDirectoryElement(XElement element) - { - if (null == element.Attribute("Name")) - { - var attribute = element.Attribute("ShortName"); - if (null != attribute) - { - var shortName = attribute.Value; - if (this.OnError(ConverterTestType.AssignDirectoryNameFromShortName, element, "The directory ShortName attribute is being renamed to Name since Name wasn't specified for value '{0}'", shortName)) - { - element.Add(new XAttribute("Name", shortName)); - attribute.Remove(); - } - } - } - - var id = element.Attribute("Id")?.Value; - - if (id == "TARGETDIR" && - this.OnError(ConverterTestType.TargetDirDeprecated, element, "The TARGETDIR directory should not longer be explicitly defined. Remove the Directory element with Id attribute 'TARGETDIR'.")) - { - var parentElement = element.Parent; - - element.Remove(); - - if (parentElement.FirstNode is XText text && String.IsNullOrWhiteSpace(text.Value)) - { - parentElement.FirstNode.Remove(); - } - - foreach (var child in element.Nodes()) - { - parentElement.Add(child); - } - - element.RemoveAll(); - - if (parentElement.FirstNode is XText textAgain && String.IsNullOrWhiteSpace(textAgain.Value)) - { - parentElement.FirstNode.Remove(); - } - } - else if (id != null && - WindowsInstallerStandard.IsStandardDirectory(id) && - this.OnError(ConverterTestType.DefiningStandardDirectoryDeprecated, element, "Standard directories such as '{0}' should no longer be defined using the Directory element. Use the StandardDirectory element instead.", id)) - { - element.Name = StandardDirectoryElementName; - - foreach (var attrib in element.Attributes().Where(a => a.Name.LocalName != "Id").ToList()) - { - attrib.Remove(); - } - } - } - - private void ConvertFeatureElement(XElement element) - { - var xAbsent = element.Attribute("Absent"); - if (xAbsent != null && - this.OnError(ConverterTestType.FeatureAbsentAttributeReplaced, element, "The Feature element's Absent attribute has been replaced with the AllowAbsent attribute. Use the 'AllowAbsent' attribute instead.")) - { - if (xAbsent.Value == "disallow") - { - element.Add(new XAttribute("AllowAbsent", "no")); - } - xAbsent.Remove(); - } - - var xAllowAdvertise = element.Attribute("AllowAdvertise"); - if (xAllowAdvertise != null) - { - if ((xAllowAdvertise.Value == "system" || xAllowAdvertise.Value == "allow") && - this.OnError(ConverterTestType.FeatureAllowAdvertiseValueDeprecated, element, "The AllowAdvertise attribute's '{0}' value is deprecated. Set the value to 'yes' instead.", xAllowAdvertise.Value)) - { - xAllowAdvertise.Value = "yes"; - } - else if (xAllowAdvertise.Value == "disallow" && - this.OnError(ConverterTestType.FeatureAllowAdvertiseValueDeprecated, element, "The AllowAdvertise attribute's '{0}' value is deprecated. Remove the value instead.", xAllowAdvertise.Value)) - { - xAllowAdvertise.Remove(); - } - } - - var xCondition = element.Element(ConditionElementName); - if (xCondition != null) - { - var level = xCondition.Attribute("Level")?.Value; - if (!String.IsNullOrEmpty(level) && - TryGetInnerText(xCondition, out var text) && - this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Level' element instead.", xCondition.Name.LocalName)) - { - xCondition.AddAfterSelf(new XElement(LevelElementName, - new XAttribute("Value", level), - new XAttribute("Condition", text) - )); - xCondition.Remove(); - } - } - } - - private void ConvertFileElement(XElement element) - { - if (this.SourceVersion < 4 && null == element.Attribute("Id")) - { - var attribute = element.Attribute("Name"); - - if (null == attribute) - { - attribute = element.Attribute("Source"); - } - - if (null != attribute) - { - var name = Path.GetFileName(attribute.Value); - - if (this.OnError(ConverterTestType.AssignAnonymousFileId, element, "The file id is being updated to '{0}' to ensure it remains the same as the v3 default", name)) - { - IEnumerable attributes = element.Attributes().ToList(); - element.RemoveAttributes(); - element.Add(new XAttribute("Id", GetIdentifierFromName(name))); - element.Add(attributes); - } - } - } - } - - private void ConvertFragmentElement(XElement element) - { - var remove = new List(); - - foreach (var xCondition in element.Elements(ConditionElementName)) - { - var message = xCondition.Attribute("Message")?.Value; - - if (!String.IsNullOrEmpty(message) && - TryGetInnerText(xCondition, out var text) && - this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Launch' element instead.", xCondition.Name.LocalName)) - { - xCondition.AddAfterSelf(new XElement(LaunchElementName, - new XAttribute("Condition", text), - new XAttribute("Message", message) - )); - remove.Add(xCondition); - } - } - - for (var i = remove.Count - 1; i >= 0; i--) - { - remove[i].Remove(); - } - } - - private void ConvertFirewallRemoteAddressElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); - - private void ConvertEmbeddedChainerElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Condition"); - - private void ConvertErrorElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Message"); - - private void ConvertExePackageElement(XElement element) - { - this.ConvertSuppressSignatureValidation(element); - - foreach (var attributeName in new[] { "InstallCommand", "RepairCommand", "UninstallCommand" }) - { - var newName = attributeName.Replace("Command", "Arguments"); - var attribute = element.Attribute(attributeName); - - if (attribute != null && - this.OnError(ConverterTestType.RenameExePackageCommandToArguments, element, "The {0} element {1} attribute has been renamed {2}.", element.Name.LocalName, attribute.Name.LocalName, newName)) - { - element.Add(new XAttribute(newName, attribute.Value)); - attribute.Remove(); - } - } - } - - private void ConvertPermissionExElement(XElement element) - { - var xCondition = element.Element(ConditionElementName); - if (xCondition != null) - { - if (TryGetInnerText(xCondition, out var text) && - this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Condition' attribute instead.", xCondition.Name.LocalName)) - { - element.Add(new XAttribute("Condition", text)); - xCondition.Remove(); - } - } - } - - private void ConvertProgressTextElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Message"); - - private void ConvertModuleElement(XElement element) - { - if (element.Attribute("Guid") == null // skip already-converted Module elements - && this.OnError(ConverterTestType.ModuleAndPackageRenamed, element, "The Module and Package elements have been renamed and reorganized for simplicity.")) - { - var xModule = element; - - var xSummaryInformation = xModule.Element(PackageElementName); - if (xSummaryInformation != null) - { - xSummaryInformation.Name = SummaryInformationElementName; - - var xInstallerVersion = xSummaryInformation.Attribute("InstallerVersion"); - if (this.SourceVersion < 4 && xInstallerVersion == null) - { - this.OnError(ConverterTestType.InstallerVersionBehaviorChange, element, "Breaking change: The default value for Package/@InstallerVersion has been changed to '500' regardless of build platform. If you need a lower version, set it manually in the Module element."); - } - - RemoveAttribute(xSummaryInformation, "AdminImage"); - RemoveAttribute(xSummaryInformation, "Comments"); - MoveAttribute(xSummaryInformation, "Id", xModule, "Guid"); - MoveAttribute(xSummaryInformation, "InstallerVersion", xModule); - RemoveAttribute(xSummaryInformation, "Languages"); - RemoveAttribute(xSummaryInformation, "Platform"); - RemoveAttribute(xSummaryInformation, "Platforms"); - RemoveAttribute(xSummaryInformation, "ReadOnly"); - MoveAttribute(xSummaryInformation, "SummaryCodepage", xSummaryInformation, "Codepage", defaultValue: "1252"); - - if (!xSummaryInformation.HasAttributes) - { - xSummaryInformation.Remove(); - } - } - } - } - - private void ConvertProductElement(XElement element) - { - var id = element.Attribute("Id"); - if (id != null && id.Value == "*") - { - if (this.OnError(ConverterTestType.AutoGuidUnnecessary, element, "Using '*' for the Product Id attribute is unnecessary. Remove the attribute to remove the redundancy.")) - { - id.Remove(); - } - } - - var xConditions = element.Elements(ConditionElementName).ToList(); - foreach (var xCondition in xConditions) - { - var message = xCondition.Attribute("Message")?.Value; - - if (!String.IsNullOrEmpty(message) && - TryGetInnerText(xCondition, out var text) && - this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Launch' element instead.", xCondition.Name.LocalName)) - { - xCondition.AddAfterSelf(new XElement(LaunchElementName, - new XAttribute("Condition", text), - new XAttribute("Message", message) - )); - xCondition.Remove(); - } - } - - var xMediaTemplate = element.Element(MediaTemplateElementName); - if (xMediaTemplate?.HasAttributes == false - && this.OnError(ConverterTestType.DefaultMediaTemplate, element, "A MediaTemplate with no attributes set is now provided by default. Remove the element.")) - { - xMediaTemplate.Remove(); - } - - if (this.OnError(ConverterTestType.ProductAndPackageRenamed, element, "The Product and Package elements have been renamed and reorganized for simplicity.")) - { - var xPackage = element; - xPackage.Name = PackageElementName; - - var xSummaryInformation = xPackage.Element(PackageElementName); - if (xSummaryInformation != null) - { - xSummaryInformation.Name = SummaryInformationElementName; - - var xInstallerVersion = xSummaryInformation.Attribute("InstallerVersion"); - if (this.SourceVersion < 4 && xInstallerVersion == null) - { - this.OnError(ConverterTestType.InstallerVersionBehaviorChange, element, "Breaking change: The default value for Package/@InstallerVersion has been changed to '500' regardless of build platform. If you need a lower version, set it manually in the Package element."); - } - - if (xSummaryInformation.Attribute("Compressed") == null) - { - xPackage.SetAttributeValue("Compressed", "no"); - } - else - { - MoveAttribute(xSummaryInformation, "Compressed", xPackage, defaultValue: "yes"); - } - - RemoveAttribute(xSummaryInformation, "AdminImage"); - RemoveAttribute(xSummaryInformation, "Comments"); - RemoveAttribute(xSummaryInformation, "Id"); - MoveAttribute(xSummaryInformation, "InstallerVersion", xPackage, defaultValue: "500"); - MoveAttribute(xSummaryInformation, "InstallScope", xPackage, "Scope", defaultValue: "perMachine"); - RemoveAttribute(xSummaryInformation, "Languages"); - RemoveAttribute(xSummaryInformation, "Platform"); - RemoveAttribute(xSummaryInformation, "Platforms"); - RemoveAttribute(xSummaryInformation, "ReadOnly"); - MoveAttribute(xSummaryInformation, "ShortNames", xPackage); - MoveAttribute(xSummaryInformation, "SummaryCodepage", xSummaryInformation, "Codepage", defaultValue: "1252"); - MoveAttribute(xPackage, "Id", xPackage, "ProductCode"); - - var xInstallPrivileges = xSummaryInformation.Attribute("InstallPrivileges"); - switch (xInstallPrivileges?.Value) - { - case "limited": - xPackage.SetAttributeValue("Scope", "perUser"); - break; - case "elevated": - { - var xAllUsers = xPackage.Elements(PropertyElementName).SingleOrDefault(p => p.Attribute("Id")?.Value == "ALLUSERS"); - if (xAllUsers?.Attribute("Value")?.Value == "1") - { - xAllUsers?.Remove(); - } - } - break; - } - - xInstallPrivileges?.Remove(); - - if (!xSummaryInformation.HasAttributes) - { - xSummaryInformation.Remove(); - } - } - } - } - - private static void MoveAttribute(XElement xSource, string attributeName, XElement xDestination, string destinationAttributeName = null, string defaultValue = null) - { - var xAttribute = xSource.Attribute(attributeName); - if (xAttribute != null && (defaultValue == null || xAttribute.Value != defaultValue)) - { - xDestination.SetAttributeValue(destinationAttributeName ?? attributeName, xAttribute.Value); - } - - xAttribute?.Remove(); - } - - private static void RemoveAttribute(XElement xSummaryInformation, string attributeName) - { - var xAttribute = xSummaryInformation.Attribute(attributeName); - xAttribute?.Remove(); - } - - private void ConvertPropertyRefElement(XElement element) - { - var newElementName = String.Empty; - - var id = element.Attribute("Id"); - switch (id?.Value) - { - case "WIX_SUITE_BACKOFFICE": - case "WIX_SUITE_BLADE": - case "WIX_SUITE_COMMUNICATIONS": - case "WIX_SUITE_COMPUTE_SERVER": - case "WIX_SUITE_DATACENTER": - case "WIX_SUITE_EMBEDDED_RESTRICTED": - case "WIX_SUITE_EMBEDDEDNT": - case "WIX_SUITE_ENTERPRISE": - case "WIX_SUITE_MEDIACENTER": - case "WIX_SUITE_PERSONAL": - case "WIX_SUITE_SECURITY_APPLIANCE": - case "WIX_SUITE_SERVERR2": - case "WIX_SUITE_SINGLEUSERTS": - case "WIX_SUITE_SMALLBUSINESS": - case "WIX_SUITE_SMALLBUSINESS_RESTRICTED": - case "WIX_SUITE_STARTER": - case "WIX_SUITE_STORAGE_SERVER": - case "WIX_SUITE_TABLETPC": - case "WIX_SUITE_TERMINAL": - case "WIX_SUITE_WH_SERVER": - newElementName = "QueryWindowsSuiteInfo"; - break; - case "WIX_DIR_ADMINTOOLS": - case "WIX_DIR_ALTSTARTUP": - case "WIX_DIR_CDBURN_AREA": - case "WIX_DIR_COMMON_ADMINTOOLS": - case "WIX_DIR_COMMON_ALTSTARTUP": - case "WIX_DIR_COMMON_DOCUMENTS": - case "WIX_DIR_COMMON_FAVORITES": - case "WIX_DIR_COMMON_MUSIC": - case "WIX_DIR_COMMON_PICTURES": - case "WIX_DIR_COMMON_VIDEO": - case "WIX_DIR_COOKIES": - case "WIX_DIR_DESKTOP": - case "WIX_DIR_HISTORY": - case "WIX_DIR_INTERNET_CACHE": - case "WIX_DIR_MYMUSIC": - case "WIX_DIR_MYPICTURES": - case "WIX_DIR_MYVIDEO": - case "WIX_DIR_NETHOOD": - case "WIX_DIR_PERSONAL": - case "WIX_DIR_PRINTHOOD": - case "WIX_DIR_PROFILE": - case "WIX_DIR_RECENT": - case "WIX_DIR_RESOURCES": - newElementName = "QueryWindowsDirectories"; - break; - case "WIX_DWM_COMPOSITION_ENABLED": - case "WIX_WDDM_DRIVER_PRESENT": - newElementName = "QueryWindowsDriverInfo"; - break; - case "WIX_ACCOUNT_LOCALSYSTEM": - case "WIX_ACCOUNT_LOCALSERVICE": - case "WIX_ACCOUNT_NETWORKSERVICE": - case "WIX_ACCOUNT_ADMINISTRATORS": - case "WIX_ACCOUNT_USERS": - case "WIX_ACCOUNT_GUESTS": - case "WIX_ACCOUNT_PERFLOGUSERS": - case "WIX_ACCOUNT_PERFLOGUSERS_NODOMAIN": - newElementName = "QueryWindowsWellKnownSIDs"; - break; - } - - if (!String.IsNullOrEmpty(newElementName) - && this.OnError(ConverterTestType.UtilReferencesReplaced, element, "Custom action and property reference {0} to WixUtilExtension have been replaced with strongly-typed elements.", id)) - { - element.AddAfterSelf(new XElement(WixUtilNamespace + newElementName)); - element.Remove(); - } - } - - private void ConvertCustomActionRefElement(XElement element) - { - var newElementName = String.Empty; - - var id = element.Attribute("Id"); - switch (id?.Value) - { - case "WixBroadcastSettingChange": - case "WixBroadcastEnvironmentChange": - case "WixCheckRebootRequired": - case "WixExitEarlyWithSuccess": - case "WixFailWhenDeferred": - case "WixWaitForEvent": - case "WixWaitForEventDeferred": - newElementName = id?.Value.Substring(3); // strip leading Wix - break; - } - - if (!String.IsNullOrEmpty(newElementName) - && this.OnError(ConverterTestType.UtilReferencesReplaced, element, "Custom action and property reference {0} to WixUtilExtension have been replaced with strongly-typed elements.", id)) - { - element.AddAfterSelf(new XElement(WixUtilNamespace + newElementName)); - element.Remove(); - } - } - - private void ConvertPublishElement(XElement element) - { - this.ConvertInnerTextToAttribute(element, "Condition"); - - var xCondition = element.Attribute("Condition"); - if (xCondition?.Value == "1" && - this.OnError(ConverterTestType.PublishConditionOneUnnecessary, element, "Adding Condition='1' on {0} elements is no longer necessary. Remove the Condition attribute.", xCondition.Name.LocalName)) - { - xCondition.Remove(); - } - } - - private void ConvertMultiStringValueElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); - - private void ConvertRegistryKeyElement(XElement element) - { - var xAction = element.Attribute("Action"); - - if (xAction != null - && this.OnError(ConverterTestType.RegistryKeyActionObsolete, element, "The RegistryKey element's Action attribute is obsolete. Action='create' will be converted to ForceCreateOnInstall='yes'. Action='createAndRemoveOnUninstall' will be converted to ForceCreateOnInstall='yes' and ForceDeleteOnUninstall='yes'.")) - { - switch (xAction?.Value) - { - case "create": - element.SetAttributeValue("ForceCreateOnInstall", "yes"); - break; - case "createAndRemoveOnUninstall": - element.SetAttributeValue("ForceCreateOnInstall", "yes"); - element.SetAttributeValue("ForceDeleteOnUninstall", "yes"); - break; - } - - xAction.Remove(); - } - } - - private void ConvertRemotePayloadElement(XElement element) - { - var xParent = element.Parent; - - if (xParent.Name == ExePackageElementName && - this.OnError(ConverterTestType.RemotePayloadRenamed, element, "The RemotePayload element has been renamed. Use the 'ExePackagePayload' instead.")) - { - element.Name = ExePackagePayloadElementName; - } - else if (xParent.Name == MsuPackageElementName && - this.OnError(ConverterTestType.RemotePayloadRenamed, element, "The RemotePayload element has been renamed. Use the 'MsuPackagePayload' instead.")) - { - element.Name = MsuPackagePayloadElementName; - } - - var xName = xParent.Attribute("Name"); - if (xName != null && - this.OnError(ConverterTestType.NameAttributeMovedToRemotePayload, xParent, "The Name attribute must be specified on the child XxxPackagePayload element when using a remote payload.")) - { - element.SetAttributeValue("Name", xName.Value); - xName.Remove(); - } - - var xDownloadUrl = xParent.Attribute("DownloadUrl"); - if (xDownloadUrl != null && - this.OnError(ConverterTestType.DownloadUrlAttributeMovedToRemotePayload, xParent, "The DownloadUrl attribute must be specified on the child XxxPackagePayload element when using a remote payload.")) - { - element.SetAttributeValue("DownloadUrl", xDownloadUrl.Value); - xDownloadUrl.Remove(); - } - - var xCompressed = xParent.Attribute("Compressed"); - if (xCompressed != null && - this.OnError(ConverterTestType.CompressedAttributeUnnecessaryForRemotePayload, xParent, "The Compressed attribute should not be specified when using a remote payload.")) - { - xCompressed.Remove(); - } - - this.OnError(ConverterTestType.BurnHashAlgorithmChanged, element, "The hash algorithm for bundles changed from SHA1 to SHA512."); - - this.RemoveAttributeIfPresent(element, "CertificatePublicKey", ConverterTestType.BundleSignatureValidationObsolete, "The {0} element contains obsolete '{1}' attribute. Signature validation is no longer supported. The attribute will be removed."); - this.RemoveAttributeIfPresent(element, "CertificateThumbprint", ConverterTestType.BundleSignatureValidationObsolete, "The {0} element contains obsolete '{1}' attribute. Signature validation is no longer supported. The attribute will be removed."); - } - - private void ConvertRegistrySearchElement(XElement element) - { - this.RenameWin64ToBitness(element); - } - - private void ConvertRequiredPrivilegeElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Name"); - - private void ConvertDataElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); - - private void ConvertSequenceElement(XElement element) - { - foreach (var child in element.Elements()) - { - this.ConvertInnerTextToAttribute(child, "Condition"); - } - } - - private void ConvertServiceArgumentElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); - - private void ConvertSetDirectoryElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Condition"); - - private void ConvertSetPropertyElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Condition"); - - private void ConvertShortcutPropertyElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); - - private void ConvertProvidesElement(XElement element) - { - if (this.OnError(ConverterTestType.IntegratedDependencyNamespace, element, "The Provides element has been integrated into the WiX v4 namespace. Remove the namespace.")) - { - element.Name = ProvidesElementName; - } - - if (element.Parent.Name == ComponentElementName && - this.OnError(ConverterTestType.IntegratedDependencyNamespace, element, "The Provides element has been integrated into the WiX v4 namespace. Add the 'Check' attribute from the WixDependency.wixext to match v3 runtime behavior.")) - { - element.Add(new XAttribute(DependencyCheckAttributeName, "yes")); - } - } - - private void ConvertRequiresElement(XElement element) - { - if (this.OnError(ConverterTestType.IntegratedDependencyNamespace, element, "The Requires element has been integrated into the WiX v4 namespace. Remove the namespace.")) - { - element.Name = RequiresElementName; - } - - if (element.Parent.Name == ProvidesElementName && - element.Parent.Parent?.Name == ComponentElementName && - this.OnError(ConverterTestType.IntegratedDependencyNamespace, element, "The Requires element has been integrated into the WiX v4 namespace. Add the 'Enforce' attribute from the WixDependency.wixext to match v3 runtime behavior.")) - { - element.Add(new XAttribute(DependencyEnforceAttributeName, "yes")); - } - } - - private void ConvertRequiresRefElement(XElement element) - { - if (this.OnError(ConverterTestType.IntegratedDependencyNamespace, element, "The RequiresRef element has been integrated into the WiX v4 namespace. Remove the namespace.")) - { - element.Name = RequiresRefElementName; - } - - if (element.Parent.Name == ProvidesElementName && - element.Parent.Parent?.Name == ComponentElementName && - this.OnError(ConverterTestType.IntegratedDependencyNamespace, element, "The RequiresRef element has been integrated into the WiX v4 namespace. Add the 'Enforce' attribute from the WixDependency.wixext to match v3 runtime behavior.")) - { - element.Add(new XAttribute(DependencyEnforceAttributeName, "yes")); - } - } - - private void ConvertSuppressSignatureValidation(XElement element) - { - var suppressSignatureValidation = element.Attribute("SuppressSignatureValidation"); - - if (null != suppressSignatureValidation - && this.OnError(ConverterTestType.BundleSignatureValidationObsolete, element, "The chain package element contains obsolete '{0}' attribute. Signature validation is no longer supported. The attribute will be removed.", suppressSignatureValidation.Name)) - { - suppressSignatureValidation.Remove(); - } - } - - private void ConvertTagElement(XElement element) - { - if (this.OnError(ConverterTestType.TagElementRenamed, element, "The Tag element has been renamed. Use the 'SoftwareTag' element instead.")) - { - element.Name = SoftwareTagElementName; - } - - this.RemoveAttributeIfPresent(element, "Licensed", ConverterTestType.SoftwareTagLicensedObsolete, "The {0} element contains obsolete '{1}' attribute. The attribute will be removed."); - this.RemoveAttributeIfPresent(element, "Type", ConverterTestType.SoftwareTagLicensedObsolete, "The {0} element contains obsolete '{1}' attribute. The attribute will be removed."); - this.RenameWin64ToBitness(element); - } - - private void ConvertTagRefElement(XElement element) - { - if (this.OnError(ConverterTestType.TagRefElementRenamed, element, "The TagRef element has been renamed. Use the 'SoftwareTagRef' element instead.")) - { - element.Name = SoftwareTagRefElementName; - } - } - - private void ConvertTextElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); - - private void ConvertUITextElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); - - private void ConvertWindowsInstallerPackageElement(XElement element) - { - this.ConvertSuppressSignatureValidation(element); - - if (null != element.Attribute("DisplayInternalUI")) - { - this.OnError(ConverterTestType.DisplayInternalUiNotConvertable, element, "The DisplayInternalUI functionality has fundamentally changed and requires BootstrapperApplication support."); - } - } - - private void ConvertVerbElement(XElement element) - { - if (null != element.Attribute("Target")) - { - this.OnError(ConverterTestType.VerbTargetNotConvertable, element, "The Verb/@Target attribute has been replaced with typed @TargetFile and @TargetProperty attributes."); - } - } - - private void ConvertCustomActionElement(XElement xCustomAction) - { - var xBinaryKey = xCustomAction.Attribute("BinaryKey"); - if (xBinaryKey != null && this.OnError(ConverterTestType.CustomActionKeysAreNowRefs, xCustomAction, "The CustomAction attributes have been renamed from BinaryKey and FileKey to BinaryRef and FileRef.")) - { - xCustomAction.SetAttributeValue("BinaryRef", xBinaryKey.Value); - xBinaryKey.Remove(); - xBinaryKey = xCustomAction.Attribute("BinaryRef"); - } - - var xFileKey = xCustomAction.Attribute("FileKey"); - if (xFileKey != null && this.OnError(ConverterTestType.CustomActionKeysAreNowRefs, xCustomAction, "The CustomAction attributes have been renamed from BinaryKey and FileKey to BinaryRef and FileRef.")) - { - xCustomAction.SetAttributeValue("FileRef", xFileKey.Value); - xFileKey.Remove(); - } - - if (xBinaryKey?.Value == "WixCA" || xBinaryKey?.Value == "UtilCA") - { - if (this.OnError(ConverterTestType.WixCABinaryIdRenamed, xCustomAction, "The WixCA custom action DLL Binary table id has been renamed. Use the id 'Wix4UtilCA_X86' instead.")) - { - xBinaryKey.Value = "Wix4UtilCA_X86"; - } - } - - if (xBinaryKey?.Value == "WixCA_x64" || xBinaryKey?.Value == "UtilCA_x64") - { - if (this.OnError(ConverterTestType.WixCABinaryIdRenamed, xCustomAction, "The WixCA_x64 custom action DLL Binary table id has been renamed. Use the id 'Wix4UtilCA_X64' instead.")) - { - xBinaryKey.Value = "Wix4UtilCA_X64"; - } - } - - var xDllEntry = xCustomAction.Attribute("DllEntry"); - - if (xDllEntry?.Value == "CAQuietExec" || xDllEntry?.Value == "CAQuietExec64") - { - if (this.OnError(ConverterTestType.QuietExecCustomActionsRenamed, xCustomAction, "The CAQuietExec and CAQuietExec64 custom action ids have been renamed. Use the ids 'WixQuietExec' and 'WixQuietExec64' instead.")) - { - xDllEntry.Value = xDllEntry.Value.Replace("CAQuietExec", "WixQuietExec"); - } - } - - var xProperty = xCustomAction.Attribute("Property"); - - if (xProperty?.Value == "QtExecCmdLine" || xProperty?.Value == "QtExec64CmdLine") - { - if (this.OnError(ConverterTestType.QuietExecCustomActionsRenamed, xCustomAction, "The QtExecCmdLine and QtExec64CmdLine property ids have been renamed. Use the ids 'WixQuietExecCmdLine' and 'WixQuietExec64CmdLine' instead.")) - { - xProperty.Value = xProperty.Value.Replace("QtExec", "WixQuietExec"); - } - } - - var xScript = xCustomAction.Attribute("Script"); - - if (xScript != null && TryGetInnerText(xCustomAction, out var scriptText)) - { - if (this.OnError(ConverterTestType.InnerTextDeprecated, xCustomAction, "Using {0} element text is deprecated. Extract the text to a file and use the 'ScriptSourceFile' attribute to reference it.", xCustomAction.Name.LocalName)) - { - var scriptFolder = Path.GetDirectoryName(this.SourceFile) ?? String.Empty; - var id = xCustomAction.Attribute("Id")?.Value ?? Guid.NewGuid().ToString("N"); - var ext = (xScript.Value == "jscript") ? ".js" : (xScript.Value == "vbscript") ? ".vbs" : ".txt"; - - var scriptFile = Path.Combine(scriptFolder, id + ext); - File.WriteAllText(scriptFile, scriptText); - - RemoveChildren(xCustomAction); - xCustomAction.Add(new XAttribute("ScriptSourceFile", scriptFile)); - } - } - } - - private void ConvertVariableElement(XElement xVariable) - { - var xType = xVariable.Attribute("Type"); - var xValue = xVariable.Attribute("Value"); - if (this.SourceVersion < 4) - { - if (xType == null) - { - if (WasImplicitlyStringTyped(xValue?.Value) && - this.OnError(ConverterTestType.AssignVariableTypeFormatted, xVariable, "The \"string\" variable type now denotes a literal string. Use \"formatted\" to keep the previous behavior.")) - { - xVariable.Add(new XAttribute("Type", "formatted")); - } - } - else if (xType.Value == "string" && - this.OnError(ConverterTestType.AssignVariableTypeFormatted, xVariable, "The \"string\" variable type now denotes a literal string. Use \"formatted\" to keep the previous behavior.")) - { - xType.Value = "formatted"; - } - } - } - - private void ConvertPropertyElement(XElement xProperty) - { - var xId = xProperty.Attribute("Id"); - - if (xId.Value == "QtExecCmdTimeout") - { - this.OnError(ConverterTestType.QtExecCmdTimeoutAmbiguous, xProperty, "QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout."); - } - - this.ConvertInnerTextToAttribute(xProperty, "Value"); - } - - private void ConvertUtilCloseApplicationElementName(XElement element) => this.ConvertInnerTextToAttribute(element, "Condition"); - - private void ConvertUtilPermissionExElement(XElement element) - { - if (this.SourceVersion < 4 && null == element.Attribute("Inheritable")) - { - var inheritable = element.Parent.Name == CreateFolderElementName; - if (!inheritable) - { - if (this.OnError(ConverterTestType.AssignPermissionExInheritable, element, "The PermissionEx Inheritable attribute is being set to 'no' to ensure it remains the same as the v3 default.")) - { - element.Add(new XAttribute("Inheritable", "no")); - } - } - } - } - - private void ConvertUtilRegistrySearchElement(XElement element) - { - this.RenameWin64ToBitness(element); - - if (this.SourceVersion < 4) - { - var result = element.Attribute("Result")?.Value; - if (result == null || result == "value") - { - this.OnError(ConverterTestType.UtilRegistryValueSearchBehaviorChange, element, "Breaking change: util:RegistrySearch for a value no longer clears the variable when the key or value is missing."); - } - } - } - - private void ConvertUtilXmlConfigElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); - - /// - /// Converts a Wix element. - /// - /// The Wix element to convert. - /// The converted element. - private void ConvertElementWithoutNamespace(XElement element) - { - if (this.OnError(ConverterTestType.XmlnsMissing, element, "The xmlns attribute is missing. It must be present with a value of '{0}'.", WixNamespace.NamespaceName)) - { - element.Name = WixNamespace.GetName(element.Name.LocalName); - - element.Add(new XAttribute("xmlns", WixNamespace.NamespaceName)); // set the default namespace. - - foreach (var elementWithoutNamespace in element.DescendantsAndSelf().Where(e => XNamespace.None == e.Name.Namespace)) - { - elementWithoutNamespace.Name = WixNamespace.GetName(elementWithoutNamespace.Name.LocalName); - } - } - } - - private void ConvertInnerTextToAttribute(XElement element, string attributeName) - { - if (TryGetInnerText(element, out var text) && - this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the '{1}' attribute instead.", element.Name.LocalName, attributeName)) - { - element.Add(new XAttribute(attributeName, text)); - RemoveChildren(element); - } - } - - void RemoveAttributeIfPresent(XElement element, string attributeName, ConverterTestType type, string format) - { - var xAttribute = element.Attribute(attributeName); - if (null != xAttribute && this.OnError(type, element, format, element.Name.LocalName, xAttribute.Name)) - { - xAttribute.Remove(); - } - } - - private void RenameWin64ToBitness(XElement element) - { - var win64 = element.Attribute("Win64"); - if (win64 != null && this.OnError(ConverterTestType.Win64AttributeRenamed, element, "The {0} element's Win64 attribute has been renamed. Use the Bitness attribute instead.", element.Name.LocalName)) - { - var value = this.UpdateWin64ValueToBitnessValue(win64); - element.Add(new XAttribute("Bitness", value)); - win64.Remove(); - } - } - - private string UpdateWin64ValueToBitnessValue(XAttribute xWin64Attribute) - { - var value = xWin64Attribute.Value ?? String.Empty; - switch (value) - { - case "yes": - return "always64"; - case "no": - return "always32"; - default: - this.OnError(ConverterTestType.Win64AttributeRenameCannotBeAutomatic, xWin64Attribute, "Breaking change: The Win64 attribute's value '{0}' cannot be converted automatically to the new Bitness attribute.", value); - return value; - } - } - - private IEnumerable YieldConverterTypes(IEnumerable types) - { - if (null != types) - { - foreach (var type in types) - { - if (Enum.TryParse(type, true, out var itt)) - { - yield return itt; - } - else // not a known ConverterTestType - { - this.OnError(ConverterTestType.ConverterTestTypeUnknown, null, "Unknown error type: '{0}'.", type); - } - } - } - } - - private static void UpdateElementsWithDeprecatedNamespaces(IEnumerable elements, Dictionary deprecatedToUpdatedNamespaces) - { - foreach (var element in elements) - { - if (deprecatedToUpdatedNamespaces.TryGetValue(element.Name.Namespace, out var ns)) - { - element.Name = ns.GetName(element.Name.LocalName); - } - - // Remove all the attributes and add them back to with their namespace updated (as necessary). - IEnumerable attributes = element.Attributes().ToList(); - element.RemoveAttributes(); - - foreach (var attribute in attributes) - { - var convertedAttribute = attribute; - - if (attribute.IsNamespaceDeclaration) - { - if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Value, out ns)) - { - if (ns == XNamespace.None) - { - continue; - } - - convertedAttribute = ("xmlns" == attribute.Name.LocalName) ? new XAttribute(attribute.Name.LocalName, ns.NamespaceName) : new XAttribute(XNamespace.Xmlns + attribute.Name.LocalName, ns.NamespaceName); - } - } - else if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Name.Namespace, out ns)) - { - convertedAttribute = new XAttribute(ns.GetName(attribute.Name.LocalName), attribute.Value); - } - - element.Add(convertedAttribute); - } - } - } - - /// - /// Determine if the whitespace preceding a node is appropriate for its depth level. - /// - /// Indentation value to use when validating leading whitespace. - /// The depth level that should match this whitespace. - /// The whitespace to validate. - /// true if the whitespace is legal; false otherwise. - private static bool LeadingWhitespaceValid(int indentationAmount, int level, string whitespace) - { - // Strip off leading newlines; there can be an arbitrary number of these. - whitespace = whitespace.TrimStart(XDocumentNewLine); - - var indentation = new string(' ', level * indentationAmount); - - return whitespace == indentation; - } - - /// - /// Fix the whitespace in a whitespace node. - /// - /// Indentation value to use when validating leading whitespace. - /// The depth level of the desired whitespace. - /// The whitespace node to fix. - private static void FixupWhitespace(int indentationAmount, int level, XText whitespace) - { - var value = new StringBuilder(whitespace.Value.Length); - - // Keep any previous preceeding new lines. - var newlines = whitespace.Value.TakeWhile(c => c == XDocumentNewLine).Count(); - - // Ensure there is always at least one new line before the indentation. - value.Append(XDocumentNewLine, newlines == 0 ? 1 : newlines); - - whitespace.Value = value.Append(' ', level * indentationAmount).ToString(); - } - - /// - /// Removes unused namespaces from the element and its children. - /// - /// Root element to start at. - private void RemoveUnusedNamespaces(XElement root) - { - var declarations = new List(); - var namespaces = new HashSet(); - - VisitElement(root, x => - { - if (x is XAttribute a && a.IsNamespaceDeclaration) - { - declarations.Add(a); - namespaces.Add(a.Value); - } - return true; - }); - - foreach (var ns in namespaces.ToList()) - { - VisitElement(root, x => - { - if ((x is XElement e && e.Name.Namespace == ns) || - (x is XAttribute a && !a.IsNamespaceDeclaration && a.Name.Namespace == ns)) - { - namespaces.Remove(ns); - return false; - } - - return true; - }); - } - - foreach (var declaration in declarations) - { - if (namespaces.Contains(declaration.Value) && - this.OnError(ConverterTestType.RemoveUnusedNamespaces, declaration, "The namespace '{0}' is not used. Remove unused namespaces.", declaration.Value)) - { - declaration.Remove(); - } - } - } - - /// - /// Output an error message to the console. - /// - /// The type of converter test. - /// The node that caused the error. - /// Detailed error message. - /// Additional formatted string arguments. - /// Returns true indicating that action should be taken on this error, and false if it should be ignored. - private bool OnError(ConverterTestType converterTestType, XObject node, string message, params object[] args) - { - // Ignore the error if explicitly ignored or outside the range of the current operation. - if (this.IgnoreErrors.Contains(converterTestType) || - (this.Operation == ConvertOperation.Convert && converterTestType < ConverterTestType.EndIgnoreInConvert) || - (this.Operation == ConvertOperation.Format && converterTestType > ConverterTestType.BeginIgnoreInFormat)) - { - return false; - } - - // Increase the error count. - this.Errors++; - - var sourceLine = (null == node) ? new SourceLineNumber(this.SourceFile ?? "wix.exe") : new SourceLineNumber(this.SourceFile, ((IXmlLineInfo)node).LineNumber); - var warning = this.ErrorsAsWarnings.Contains(converterTestType); - var display = String.Format(CultureInfo.CurrentCulture, message, args); - - var msg = new Message(sourceLine, warning ? MessageLevel.Warning : MessageLevel.Error, (int)converterTestType, "{0} ({1})", display, converterTestType.ToString()); - - this.Messaging.Write(msg); - - return true; - } - - /// - /// Return an identifier based on passed file/directory name - /// - /// File/directory name to generate identifer from - /// A version of the name that is a legal identifier. - /// This is duplicated from WiX's Common class. - private static string GetIdentifierFromName(string name) - { - var result = IllegalIdentifierCharacters.Replace(name, "_"); // replace illegal characters with "_". - - // MSI identifiers must begin with an alphabetic character or an - // underscore. Prefix all other values with an underscore. - if (AddPrefix.IsMatch(name)) - { - result = String.Concat("_", result); - } - - return result; - } - - private static string LowercaseFirstChar(string value) - { - if (!String.IsNullOrEmpty(value)) - { - var c = Char.ToLowerInvariant(value[0]); - if (c != value[0]) - { - var remainder = value.Length > 1 ? value.Substring(1) : String.Empty; - return c + remainder; - } - } - - return value; - } - - private static string UppercaseFirstChar(string value) - { - if (!String.IsNullOrEmpty(value)) - { - var c = Char.ToUpperInvariant(value[0]); - if (c != value[0]) - { - var remainder = value.Length > 1 ? value.Substring(1) : String.Empty; - return c + remainder; - } - } - - return value; - } - - private static bool TryGetInnerText(XElement element, out string value) - { - value = null; - - var nodes = element.Nodes(); - - if (nodes.All(e => e.NodeType == XmlNodeType.Text || e.NodeType == XmlNodeType.CDATA)) - { - value = String.Join(String.Empty, nodes.Cast().Select(TrimTextValue)); - } - - return !String.IsNullOrEmpty(value); - } - - private static bool IsTextNode(XNode node, out XText text) - { - text = null; - - if (node.NodeType == XmlNodeType.Text || node.NodeType == XmlNodeType.CDATA) - { - text = (XText)node; - } - - return text != null; - } - - private static void TrimLeadingText(XDocument document) - { - while (IsTextNode(document.Nodes().FirstOrDefault(), out var text)) - { - text.Remove(); - } - } - - private static string TrimTextValue(XText text) - { - var value = text.Value; - - if (String.IsNullOrEmpty(value)) - { - return String.Empty; - } - else if (text.NodeType == XmlNodeType.CDATA && String.IsNullOrWhiteSpace(value)) - { - return " "; - } - - return value.Trim(); - } - - private static void RemoveChildren(XElement element) - { - var nodes = element.Nodes().ToList(); - foreach (var node in nodes) - { - node.Remove(); - } - } - - private static bool VisitElement(XElement element, Func visitor) - { - if (!visitor(element)) - { - return false; - } - - if (!element.Attributes().All(a => visitor(a))) - { - return false; - } - - return element.Elements().All(e => VisitElement(e, visitor)); - } - - private static bool WasImplicitlyStringTyped(string value) - { - if (value == null) - { - return false; - } - else if (value.StartsWith("v", StringComparison.OrdinalIgnoreCase)) - { - if (Int32.TryParse(value.Substring(1), NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out var _)) - { - return false; - } - else if (Version.TryParse(value.Substring(1), out var _)) - { - return false; - } - } - else if (Int64.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture.NumberFormat, out var _)) - { - return false; - } - - return true; - } - - /// - /// Converter test types. These are used to condition error messages down to warnings. - /// - private enum ConverterTestType - { - /// - /// Internal-only: displayed when a string cannot be converted to an ConverterTestType. - /// - ConverterTestTypeUnknown, - - /// - /// Displayed when an XML loading exception has occurred. - /// - XmlException, - - /// - /// Displayed when the whitespace preceding a node is wrong. - /// - WhitespacePrecedingNodeWrong, - - /// - /// Displayed when the whitespace preceding an end element is wrong. - /// - WhitespacePrecedingEndElementWrong, - - /// Before this point, ignore errors on convert operation - EndIgnoreInConvert, - - /// - /// Displayed when the XML declaration is present in the source file. - /// - DeclarationPresent, - - /// - /// Displayed when a file cannot be accessed; typically when trying to save back a fixed file. - /// - UnauthorizedAccessException, - - /// After this point, ignore errors on format operation - BeginIgnoreInFormat, - - /// - /// Displayed when the xmlns attribute is missing from the document element. - /// - XmlnsMissing, - - /// - /// Displayed when the xmlns attribute on the document element is wrong. - /// - XmlnsValueWrong, - - /// - /// Displayed when inner text contains a deprecated $(loc.xxx) reference. - /// - DeprecatedLocalizationVariablePrefixInTextValue, - - /// - /// Displayed when an attribute value contains a deprecated $(loc.xxx) reference. - /// - DeprecatedLocalizationVariablePrefixInAttributeValue, - - /// - /// Assign an identifier to a File element when on Id attribute is specified. - /// - AssignAnonymousFileId, - - /// - /// SuppressSignatureValidation attribute is obsolete and corresponding functionality removed. - /// - BundleSignatureValidationObsolete, - - /// - /// WixCA Binary/@Id has been renamed to UtilCA. - /// - WixCABinaryIdRenamed, - - /// - /// QtExec custom actions have been renamed. - /// - QuietExecCustomActionsRenamed, - - /// - /// QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout. - /// - QtExecCmdTimeoutAmbiguous, - - /// - /// Directory/@ShortName may only be specified with Directory/@Name. - /// - AssignDirectoryNameFromShortName, - - /// - /// BootstrapperApplicationData attribute is deprecated and replaced with Unreal for MSI. Use BundleCustomData element for Bundles. - /// - BootstrapperApplicationDataDeprecated, - - /// - /// Inheritable is new and is now defaulted to 'yes' which is a change in behavior for all but children of CreateFolder. - /// - AssignPermissionExInheritable, - - /// - /// Column element's Category attribute is camel-case. - /// - ColumnCategoryCamelCase, - - /// - /// Column element's Modularize attribute is camel-case. - /// - ColumnModularizeCamelCase, - - /// - /// Inner text value should move to an attribute. - /// - InnerTextDeprecated, - - /// - /// Explicit auto-GUID unnecessary. - /// - AutoGuidUnnecessary, - - /// - /// The Feature Absent attribute renamed to AllowAbsent. - /// - FeatureAbsentAttributeReplaced, - - /// - /// The Feature AllowAdvertise attribute value deprecated. - /// - FeatureAllowAdvertiseValueDeprecated, - - /// - /// The Condition='1' attribute is unnecessary on Publish elements. - /// - PublishConditionOneUnnecessary, - - /// - /// DpiAwareness is new and is defaulted to 'perMonitorV2' which is a change in behavior. - /// - AssignBootstrapperApplicationDpiAwareness, - - /// - /// The string variable type was previously treated as formatted. - /// - AssignVariableTypeFormatted, - - /// - /// The CustomAction attributes have been renamed from BinaryKey and FileKey to BinaryRef and FileRef. - /// - CustomActionKeysAreNowRefs, - - /// - /// The Product and Package elements have been renamed and reorganized. - /// - ProductAndPackageRenamed, - - /// - /// The Module and Package elements have been renamed and reorganized. - /// - ModuleAndPackageRenamed, - - /// - /// A MediaTemplate with no attributes set is now provided by default. - /// - DefaultMediaTemplate, - - /// - /// util:RegistrySearch has breaking change when value is missing. - /// - UtilRegistryValueSearchBehaviorChange, - - /// - /// DisplayInternalUI can't be converted. - /// - DisplayInternalUiNotConvertable, - - /// - /// InstallerVersion has breaking change when missing. - /// - InstallerVersionBehaviorChange, - - /// - /// Verb/@Target can't be converted. - /// - VerbTargetNotConvertable, - - /// - /// The bootstrapper application dll is now specified in its own element. - /// - BootstrapperApplicationDll, - - /// - /// The new bootstrapper application dll element is required. - /// - BootstrapperApplicationDllRequired, - - /// - /// bal:UseUILanguages is deprecated, 'true' is now the standard behavior. - /// - BalUseUILanguagesDeprecated, - - /// - /// The custom elements for built-in BAs are now required. - /// - BalBootstrapperApplicationRefToElement, - - /// - /// The ExePackage elements "XxxCommand" attributes have been renamed to "XxxArguments". - /// - RenameExePackageCommandToArguments, - - /// - /// The Win64 attribute has been renamed. Use the Bitness attribute instead. - /// - Win64AttributeRenamed, - - /// - /// Breaking change: The Win64 attribute's value '{0}' cannot be converted automatically to the new Bitness attribute. - /// - Win64AttributeRenameCannotBeAutomatic, - - /// - /// The Tag element has been renamed. Use the element 'SoftwareTag' name. - /// - TagElementRenamed, - - /// - /// The Dependency namespace has been incorporated into WiX v4 namespace. - /// - IntegratedDependencyNamespace, - - /// - /// Remove unused namespaces. - /// - RemoveUnusedNamespaces, - - /// - /// The Remote element has been renamed. Use the "XxxPackagePayload" element instead. - /// - RemotePayloadRenamed, - - /// - /// The XxxPackage/@Name attribute must be specified on the child XxxPackagePayload element when using a remote payload. - /// - NameAttributeMovedToRemotePayload, - - /// - /// The XxxPackage/@Compressed attribute should not be specified when using a remote payload. - /// - CompressedAttributeUnnecessaryForRemotePayload, - - /// - /// The XxxPackage/@DownloadUrl attribute must be specified on the child XxxPackagePayload element when using a remote payload. - /// - DownloadUrlAttributeMovedToRemotePayload, - - /// - /// The hash algorithm used for bundles changed from SHA1 to SHA512. - /// - BurnHashAlgorithmChanged, - - /// - /// CustomTable elements can't always be converted. - /// - CustomTableNotAlwaysConvertable, - - /// - /// CustomTable elements that don't contain the table definition are now CustomTableRef. - /// - CustomTableRef, - - /// - /// The RegistryKey element's Action attribute is obsolete. - /// - RegistryKeyActionObsolete, - - /// - /// The TagRef element has been renamed. Use the element 'SoftwareTagRef' name. - /// - TagRefElementRenamed, - - /// - /// The SoftwareTag element's Licensed attribute is obsolete. - /// - SoftwareTagLicensedObsolete, - - /// - /// The SoftwareTag element's Type attribute is obsolete. - /// - SoftwareTagTypeObsolete, - - /// - /// TARGETDIR directory should not longer be explicitly defined. - /// - TargetDirDeprecated, - - /// - /// Standard directories should no longer be defined using the Directory element. - /// - DefiningStandardDirectoryDeprecated, - - /// - /// Naked custom action and property references replaced with WixUtilExtension elements. - /// - UtilReferencesReplaced, - } - } -} diff --git a/src/WixToolset.Converters/WixToolset.Converters.csproj b/src/WixToolset.Converters/WixToolset.Converters.csproj deleted file mode 100644 index 7dddefa5..00000000 --- a/src/WixToolset.Converters/WixToolset.Converters.csproj +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - netstandard2.0 - $(TargetFrameworks);net461;net472 - Converter - WiX Toolset Converters - embedded - true - true - - - - - - - - - - - diff --git a/src/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs b/src/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs deleted file mode 100644 index 084d3b92..00000000 --- a/src/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolset.Converters -{ - using WixToolset.Extensibility.Services; - - /// - /// Extension methods for adding Converters services. - /// - public static class WixToolsetCoreServiceProviderExtensions - { - /// - /// Adds Converters services. - /// - /// - /// - public static IWixToolsetCoreServiceProvider AddConverter(this IWixToolsetCoreServiceProvider coreProvider) - { - var extensionManager = coreProvider.GetService(); - extensionManager.Add(typeof(ConverterExtensionFactory).Assembly); - - return coreProvider; - } - } -} diff --git a/src/deps/wix.dll b/src/deps/wix.dll deleted file mode 100644 index 64f70f75..00000000 Binary files a/src/deps/wix.dll and /dev/null differ diff --git a/src/test/WixToolsetTest.Converters.Symbolizer/ConvertSymbolsFixture.cs b/src/test/WixToolsetTest.Converters.Symbolizer/ConvertSymbolsFixture.cs deleted file mode 100644 index 01213524..00000000 --- a/src/test/WixToolsetTest.Converters.Symbolizer/ConvertSymbolsFixture.cs +++ /dev/null @@ -1,606 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters.Symbolizer -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using WixBuildTools.TestSupport; - using Wix3 = Microsoft.Tools.WindowsInstallerXml; - using WixToolset.Converters.Symbolizer; - using WixToolset.Data; - using WixToolset.Data.WindowsInstaller; - using WixToolset.Data.Symbols; - using Xunit; - - public class ConvertSymbolsFixture - { - [Fact] - public void CanLoadWixoutAndConvertToIntermediate() - { - var rootFolder = TestData.Get(); - var dataFolder = TestData.Get(@"TestData\Integration"); - - using (var fs = new DisposableFileSystem()) - { - var intermediateFolder = fs.GetFolder(); - - var path = Path.Combine(dataFolder, "test.wixout"); - - var intermediate = ConvertSymbols.ConvertFile(path); - - Assert.NotNull(intermediate); - Assert.Single(intermediate.Sections); - Assert.Equal(String.Empty, intermediate.Id); - - // Save and load to guarantee round-tripping support. - // - var wixiplFile = Path.Combine(intermediateFolder, "test.wixipl"); - intermediate.Save(wixiplFile); - - intermediate = Intermediate.Load(wixiplFile); - - var output = Wix3.Output.Load(path, suppressVersionCheck: true, suppressSchema: true); - var wixMediaByDiskId = IndexWixMediaTableByDiskId(output); - - // Dump to text for easy diffing, with some massaging to keep v3 and v4 diffable. - // - var tables = output.Tables.Cast(); - var wix3Dump = tables - .SelectMany(table => table.Rows.Cast() - .SelectMany(row => RowToStrings(row, wixMediaByDiskId))) - .Where(s => !String.IsNullOrEmpty(s)) - .OrderBy(s => s) - .ToArray(); - - var symbols = intermediate.Sections.SelectMany(s => s.Symbols); - - var assemblySymbolsByFileId = symbols.OfType().ToDictionary(a => a.Id.Id); - - var wix4Dump = symbols - .SelectMany(symbol => SymbolToStrings(symbol, assemblySymbolsByFileId)) - .OrderBy(s => s) - .ToArray(); - -#if false - Assert.Equal(wix3Dump, wix4Dump); -#else // useful when you want to diff the outputs with another diff tool. - var wix3TextDump = String.Join(Environment.NewLine, wix3Dump); - var wix4TextDump = String.Join(Environment.NewLine, wix4Dump); - - var path3 = Path.Combine(Path.GetTempPath(), "~3.txt"); - var path4 = Path.Combine(Path.GetTempPath(), "~4.txt"); - - File.WriteAllText(path3, wix3TextDump); - File.WriteAllText(path4, wix4TextDump); - - Assert.Equal(wix3TextDump, wix4TextDump); -#endif - } - } - - private static Dictionary IndexWixMediaTableByDiskId(Wix3.Output output) - { - var wixMediaByDiskId = new Dictionary(); - var wixMediaTable = output.Tables["WixMedia"]; - - if (wixMediaTable != null) - { - foreach (Wix3.WixMediaRow row in wixMediaTable.Rows) - { - wixMediaByDiskId.Add((int)row[0], row); - } - } - - return wixMediaByDiskId; - } - - private static IEnumerable RowToStrings(Wix3.Row row, Dictionary wixMediaByDiskId) - { - string fields = null; - - // Massage output to match WiX v3 rows and v4 symbols. - // - switch (row.Table.Name) - { - case "Directory": - var dirs = SplitDefaultDir((string)row[2]); - fields = String.Join(",", row[0], row[1], dirs[0], dirs[1], dirs[2], dirs[3]); - break; - case "File": - { - var fieldValues = row.Fields.Take(7).Select(SafeConvertField).ToArray(); - if (fieldValues[3] == null) - { - // "Somebody" sometimes writes out a null field even when the column definition says - // it's non-nullable. Not naming names or anything. (SWID tags.) - fieldValues[3] = "0"; - } - fields = String.Join(",", fieldValues); - break; - } - case "Media": - var compression = wixMediaByDiskId.TryGetValue((int)row[0], out var wixMedia) ? (CompressionLevel?)Enum.Parse(typeof(CompressionLevel), SafeConvertField(wixMedia.Fields[1]), true) : null; - - fields = String.Join(",", row.Fields.Select(SafeConvertField)); - fields = String.Join(",", fields, (int?)compression, SafeConvertField(wixMedia?.Fields[2])); - break; - case "RegLocator": - var type = (int)row[4]; - fields = String.Join(",", row[0], row[1], row[2], row[3], type & 0xF, (type & 0x10) == 0x10); - break; - case "RemoveFile": - var attributes = (int)row[4]; - var onInstall = (attributes & 1) == 1 ? (bool?)true : null; - var onUninstall = (attributes & 2) == 2 ? (bool?)true : null; - fields = String.Join(",", row.Fields.Take(4).Select(SafeConvertField)); - fields = String.Join(",", fields, onInstall, onUninstall); - break; - case "Shortcut": - var split = ((string)row[2]).Split('|'); - var afterName = String.Join(",", row.Fields.Skip(3).Select(SafeConvertField)); - fields = String.Join(",", row[0], row[1], split.Length > 1 ? split[1] : split[0], split.Length > 1 ? split[0] : String.Empty, afterName); - break; - case "WixAction": - var table = (int)SequenceStringToSequenceTable(row[0]); - fields = String.Join(",", table, row[1], row[2], row[3], row[4], row[5], row[6]); - break; - case "WixFile": - { - var fieldValues = row.Fields.Select(SafeConvertField).ToArray(); - if (fieldValues[8] == null) - { - // "Somebody" sometimes writes out a null field even when the column definition says - // it's non-nullable. Not naming names or anything. (SWID tags.) - fieldValues[8] = "0"; - } - if (fieldValues[10] == null) - { - // WixFile rows that come from merge modules will not have the attributes column set - // so initilaize with 0. - fieldValues[10] = "0"; - } - fields = String.Join(",", fieldValues); - break; - } - case "WixMedia": - break; - default: - fields = String.Join(",", row.Fields.Select(SafeConvertField)); - break; - } - - if (fields != null) - { - yield return $"{row.Table.Name}:{fields}"; - } - } - - private static IEnumerable SymbolToStrings(IntermediateSymbol symbol, Dictionary assemblySymbolsByFileId) - { - var name = symbol.Definition.Type == SymbolDefinitionType.SummaryInformation ? "_SummaryInformation" : symbol.Definition.Name; - var id = symbol.Id?.Id ?? String.Empty; - - string fields; - switch (symbol.Definition.Name) - { - // Massage output to match WiX v3 rows and v4 symbols. - // - case "Component": - { - var componentSymbol = (ComponentSymbol)symbol; - var attributes = ComponentLocation.Either == componentSymbol.Location ? WindowsInstallerConstants.MsidbComponentAttributesOptional : 0; - attributes |= ComponentLocation.SourceOnly == componentSymbol.Location ? WindowsInstallerConstants.MsidbComponentAttributesSourceOnly : 0; - attributes |= ComponentKeyPathType.Registry == componentSymbol.KeyPathType ? WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath : 0; - attributes |= ComponentKeyPathType.OdbcDataSource == componentSymbol.KeyPathType ? WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource : 0; - attributes |= componentSymbol.DisableRegistryReflection ? WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection : 0; - attributes |= componentSymbol.NeverOverwrite ? WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite : 0; - attributes |= componentSymbol.Permanent ? WindowsInstallerConstants.MsidbComponentAttributesPermanent : 0; - attributes |= componentSymbol.SharedDllRefCount ? WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount : 0; - attributes |= componentSymbol.Shared ? WindowsInstallerConstants.MsidbComponentAttributesShared : 0; - attributes |= componentSymbol.Transitive ? WindowsInstallerConstants.MsidbComponentAttributesTransitive : 0; - attributes |= componentSymbol.UninstallWhenSuperseded ? WindowsInstallerConstants.MsidbComponentAttributes64bit : 0; - attributes |= componentSymbol.Win64 ? WindowsInstallerConstants.MsidbComponentAttributes64bit : 0; - - fields = String.Join(",", - componentSymbol.ComponentId, - componentSymbol.DirectoryRef, - attributes.ToString(), - componentSymbol.Condition, - componentSymbol.KeyPath - ); - break; - } - case "CustomAction": - { - var customActionSymbol = (CustomActionSymbol)symbol; - var type = customActionSymbol.Win64 ? WindowsInstallerConstants.MsidbCustomActionType64BitScript : 0; - type |= customActionSymbol.TSAware ? WindowsInstallerConstants.MsidbCustomActionTypeTSAware : 0; - type |= customActionSymbol.Impersonate ? 0 : WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate; - type |= customActionSymbol.IgnoreResult ? WindowsInstallerConstants.MsidbCustomActionTypeContinue : 0; - type |= customActionSymbol.Hidden ? WindowsInstallerConstants.MsidbCustomActionTypeHideTarget : 0; - type |= customActionSymbol.Async ? WindowsInstallerConstants.MsidbCustomActionTypeAsync : 0; - type |= CustomActionExecutionType.FirstSequence == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence : 0; - type |= CustomActionExecutionType.OncePerProcess == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess : 0; - type |= CustomActionExecutionType.ClientRepeat == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat : 0; - type |= CustomActionExecutionType.Deferred == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript : 0; - type |= CustomActionExecutionType.Rollback == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback : 0; - type |= CustomActionExecutionType.Commit == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit : 0; - type |= CustomActionSourceType.File == customActionSymbol.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeSourceFile : 0; - type |= CustomActionSourceType.Directory == customActionSymbol.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeDirectory : 0; - type |= CustomActionSourceType.Property == customActionSymbol.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeProperty : 0; - type |= CustomActionTargetType.Dll == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeDll : 0; - type |= CustomActionTargetType.Exe == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeExe : 0; - type |= CustomActionTargetType.TextData == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeTextData : 0; - type |= CustomActionTargetType.JScript == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeJScript : 0; - type |= CustomActionTargetType.VBScript == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeVBScript : 0; - - fields = String.Join(",", - type.ToString(), - customActionSymbol.Source, - customActionSymbol.Target, - customActionSymbol.PatchUninstall ? WindowsInstallerConstants.MsidbCustomActionTypePatchUninstall.ToString() : null - ); - break; - } - case "Directory": - { - var directorySymbol = (DirectorySymbol)symbol; - - if (!String.IsNullOrEmpty(directorySymbol.ComponentGuidGenerationSeed)) - { - yield return $"WixDirectory:{directorySymbol.Id.Id},{directorySymbol.ComponentGuidGenerationSeed}"; - } - - fields = String.Join(",", directorySymbol.ParentDirectoryRef, directorySymbol.Name, directorySymbol.ShortName, directorySymbol.SourceName, directorySymbol.SourceShortName); - break; - } - case "Feature": - { - var featureSymbol = (FeatureSymbol)symbol; - var attributes = featureSymbol.DisallowAbsent ? WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent : 0; - attributes |= featureSymbol.DisallowAdvertise ? WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise : 0; - attributes |= FeatureInstallDefault.FollowParent == featureSymbol.InstallDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFollowParent : 0; - attributes |= FeatureInstallDefault.Source == featureSymbol.InstallDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFavorSource : 0; - attributes |= FeatureTypicalDefault.Advertise == featureSymbol.TypicalDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise : 0; - - fields = String.Join(",", - featureSymbol.ParentFeatureRef, - featureSymbol.Title, - featureSymbol.Description, - featureSymbol.Display.ToString(), - featureSymbol.Level.ToString(), - featureSymbol.DirectoryRef, - attributes.ToString()); - break; - } - case "File": - { - var fileSymbol = (FileSymbol)symbol; - - if (fileSymbol.BindPath != null) - { - yield return $"BindImage:{fileSymbol.Id.Id},{fileSymbol.BindPath}"; - } - - if (fileSymbol.FontTitle != null) - { - yield return $"Font:{fileSymbol.Id.Id},{fileSymbol.FontTitle}"; - } - - if (fileSymbol.SelfRegCost.HasValue) - { - yield return $"SelfReg:{fileSymbol.Id.Id},{fileSymbol.SelfRegCost}"; - } - - int? assemblyAttributes = null; - if (assemblySymbolsByFileId.TryGetValue(fileSymbol.Id.Id, out var assemblySymbol)) - { - if (assemblySymbol.Type == AssemblyType.DotNetAssembly) - { - assemblyAttributes = 0; - } - else if (assemblySymbol.Type == AssemblyType.Win32Assembly) - { - assemblyAttributes = 1; - } - } - - yield return "WixFile:" + String.Join(",", - fileSymbol.Id.Id, - assemblyAttributes, - assemblySymbol?.ManifestFileRef, - assemblySymbol?.ApplicationFileRef, - fileSymbol.DirectoryRef, - fileSymbol.DiskId, - fileSymbol.Source.Path, - null, // assembly processor arch - fileSymbol.PatchGroup, - 0, - (int)fileSymbol.PatchAttributes, - fileSymbol.RetainLengths, - fileSymbol.IgnoreOffsets, - fileSymbol.IgnoreLengths, - fileSymbol.RetainOffsets - ); - - var fileAttributes = 0; - fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.ReadOnly) != 0 ? WindowsInstallerConstants.MsidbFileAttributesReadOnly : 0; - fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Hidden) != 0 ? WindowsInstallerConstants.MsidbFileAttributesHidden : 0; - fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.System) != 0 ? WindowsInstallerConstants.MsidbFileAttributesSystem : 0; - fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Vital) != 0 ? WindowsInstallerConstants.MsidbFileAttributesVital : 0; - fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Checksum) != 0 ? WindowsInstallerConstants.MsidbFileAttributesChecksum : 0; - fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Compressed) != 0 ? WindowsInstallerConstants.MsidbFileAttributesCompressed : 0; - fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Uncompressed) != 0 ? WindowsInstallerConstants.MsidbFileAttributesNoncompressed : 0; - - fields = String.Join(",", - fileSymbol.ComponentRef, - fileSymbol.Name, - fileSymbol.FileSize.ToString(), - fileSymbol.Version, - fileSymbol.Language, - fileAttributes); - break; - } - - case "Media": - fields = String.Join(",", symbol.Fields.Skip(1).Select(SafeConvertField)); - break; - - case "Assembly": - { - var assemblySymbol = (AssemblySymbol)symbol; - - id = null; - name = "MsiAssembly"; - fields = String.Join(",", assemblySymbol.ComponentRef, assemblySymbol.FeatureRef, assemblySymbol.ManifestFileRef, assemblySymbol.ApplicationFileRef, assemblySymbol.Type == AssemblyType.Win32Assembly ? 1 : 0); - break; - } - case "RegLocator": - { - var locatorSymbol = (RegLocatorSymbol)symbol; - - fields = String.Join(",", (int)locatorSymbol.Root, locatorSymbol.Key, locatorSymbol.Name, (int)locatorSymbol.Type, locatorSymbol.Win64); - break; - } - case "Registry": - { - var registrySymbol = (RegistrySymbol)symbol; - var value = registrySymbol.Value; - - switch (registrySymbol.ValueType) - { - case RegistryValueType.Binary: - value = String.Concat("#x", value); - break; - case RegistryValueType.Expandable: - value = String.Concat("#%", value); - break; - case RegistryValueType.Integer: - value = String.Concat("#", value); - break; - case RegistryValueType.MultiString: - switch (registrySymbol.ValueAction) - { - case RegistryValueActionType.Append: - value = String.Concat("[~]", value); - break; - case RegistryValueActionType.Prepend: - value = String.Concat(value, "[~]"); - break; - case RegistryValueActionType.Write: - default: - if (null != value && -1 == value.IndexOf("[~]", StringComparison.Ordinal)) - { - value = String.Concat("[~]", value, "[~]"); - } - break; - } - break; - case RegistryValueType.String: - // escape the leading '#' character for string registry keys - if (null != value && value.StartsWith("#", StringComparison.Ordinal)) - { - value = String.Concat("#", value); - } - break; - } - - fields = String.Join(",", - ((int)registrySymbol.Root).ToString(), - registrySymbol.Key, - registrySymbol.Name, - value, - registrySymbol.ComponentRef - ); - break; - } - - case "RemoveRegistry": - { - var removeRegistrySymbol = (RemoveRegistrySymbol)symbol; - fields = String.Join(",", - ((int)removeRegistrySymbol.Root).ToString(), - removeRegistrySymbol.Key, - removeRegistrySymbol.Name, - removeRegistrySymbol.ComponentRef - ); - break; - } - - case "ServiceControl": - { - var serviceControlSymbol = (ServiceControlSymbol)symbol; - - var events = serviceControlSymbol.InstallRemove ? WindowsInstallerConstants.MsidbServiceControlEventDelete : 0; - events |= serviceControlSymbol.UninstallRemove ? WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete : 0; - events |= serviceControlSymbol.InstallStart ? WindowsInstallerConstants.MsidbServiceControlEventStart : 0; - events |= serviceControlSymbol.UninstallStart ? WindowsInstallerConstants.MsidbServiceControlEventUninstallStart : 0; - events |= serviceControlSymbol.InstallStop ? WindowsInstallerConstants.MsidbServiceControlEventStop : 0; - events |= serviceControlSymbol.UninstallStop ? WindowsInstallerConstants.MsidbServiceControlEventUninstallStop : 0; - - fields = String.Join(",", - serviceControlSymbol.Name, - events.ToString(), - serviceControlSymbol.Arguments, - serviceControlSymbol.Wait == true ? "1" : "0", - serviceControlSymbol.ComponentRef - ); - break; - } - - case "ServiceInstall": - { - var serviceInstallSymbol = (ServiceInstallSymbol)symbol; - - var errorControl = (int)serviceInstallSymbol.ErrorControl; - errorControl |= serviceInstallSymbol.Vital ? WindowsInstallerConstants.MsidbServiceInstallErrorControlVital : 0; - - var serviceType = (int)serviceInstallSymbol.ServiceType; - serviceType |= serviceInstallSymbol.Interactive ? WindowsInstallerConstants.MsidbServiceInstallInteractive : 0; - - fields = String.Join(",", - serviceInstallSymbol.Name, - serviceInstallSymbol.DisplayName, - serviceType.ToString(), - ((int)serviceInstallSymbol.StartType).ToString(), - errorControl.ToString(), - serviceInstallSymbol.LoadOrderGroup, - serviceInstallSymbol.Dependencies, - serviceInstallSymbol.StartName, - serviceInstallSymbol.Password, - serviceInstallSymbol.Arguments, - serviceInstallSymbol.ComponentRef, - serviceInstallSymbol.Description - ); - break; - } - - case "Upgrade": - { - var upgradeSymbol = (UpgradeSymbol)symbol; - - var attributes = upgradeSymbol.MigrateFeatures ? WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures : 0; - attributes |= upgradeSymbol.OnlyDetect ? WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect : 0; - attributes |= upgradeSymbol.IgnoreRemoveFailures ? WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure : 0; - attributes |= upgradeSymbol.VersionMinInclusive ? WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive : 0; - attributes |= upgradeSymbol.VersionMaxInclusive ? WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive : 0; - attributes |= upgradeSymbol.ExcludeLanguages ? WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive : 0; - - fields = String.Join(",", - upgradeSymbol.VersionMin, - upgradeSymbol.VersionMax, - upgradeSymbol.Language, - attributes.ToString(), - upgradeSymbol.Remove, - upgradeSymbol.ActionProperty - ); - break; - } - - case "WixAction": - { - var wixActionSymbol = (WixActionSymbol)symbol; - var data = wixActionSymbol.Fields[(int)WixActionSymbolFields.SequenceTable].AsObject(); - var sequenceTableAsInt = data is string ? (int)SequenceStringToSequenceTable(data) : (int)wixActionSymbol.SequenceTable; - - fields = String.Join(",", - sequenceTableAsInt, - wixActionSymbol.Action, - wixActionSymbol.Condition, - wixActionSymbol.Sequence?.ToString() ?? String.Empty, - wixActionSymbol.Before, - wixActionSymbol.After, - wixActionSymbol.Overridable == true ? "1" : "0" - ); - break; - } - - case "WixComplexReference": - { - var wixComplexReferenceSymbol = (WixComplexReferenceSymbol)symbol; - fields = String.Join(",", - wixComplexReferenceSymbol.Parent, - (int)wixComplexReferenceSymbol.ParentType, - wixComplexReferenceSymbol.ParentLanguage, - wixComplexReferenceSymbol.Child, - (int)wixComplexReferenceSymbol.ChildType, - wixComplexReferenceSymbol.IsPrimary ? "1" : "0" - ); - break; - } - - case "WixProperty": - { - var wixPropertySymbol = (WixPropertySymbol)symbol; - var attributes = wixPropertySymbol.Admin ? 0x1 : 0; - attributes |= wixPropertySymbol.Hidden ? 0x2 : 0; - attributes |= wixPropertySymbol.Secure ? 0x4 : 0; - - fields = String.Join(",", - wixPropertySymbol.PropertyRef, - attributes.ToString() - ); - break; - } - - default: - fields = String.Join(",", symbol.Fields.Select(SafeConvertField)); - break; - } - - fields = String.IsNullOrEmpty(id) ? fields : String.IsNullOrEmpty(fields) ? id : $"{id},{fields}"; - yield return $"{name}:{fields}"; - } - - private static SequenceTable SequenceStringToSequenceTable(object sequenceString) - { - switch (sequenceString) - { - case "AdminExecuteSequence": - return SequenceTable.AdminExecuteSequence; - case "AdminUISequence": - return SequenceTable.AdminUISequence; - case "AdvtExecuteSequence": - return SequenceTable.AdvertiseExecuteSequence; - case "InstallExecuteSequence": - return SequenceTable.InstallExecuteSequence; - case "InstallUISequence": - return SequenceTable.InstallUISequence; - default: - throw new ArgumentException($"Unknown sequence: {sequenceString}"); - } - } - - private static string SafeConvertField(Wix3.Field field) - { - return field?.Data?.ToString(); - } - - private static string SafeConvertField(IntermediateField field) - { - var data = field.AsObject(); - if (data is IntermediateFieldPathValue path) - { - return path.Path; - } - - return data?.ToString(); - } - - private static string[] SplitDefaultDir(string defaultDir) - { - var split1 = defaultDir.Split(':'); - var targetSplit = split1.Length > 1 ? split1[1].Split('|') : split1[0].Split('|'); - var sourceSplit = split1.Length > 1 ? split1[0].Split('|') : new[] { String.Empty }; - return new[] - { - targetSplit.Length > 1 ? targetSplit[1] : targetSplit[0], - targetSplit.Length > 1 ? targetSplit[0] : String.Empty, - sourceSplit.Length > 1 ? sourceSplit[1] : sourceSplit[0], - sourceSplit.Length > 1 ? sourceSplit[0] : String.Empty - }; - } - } -} diff --git a/src/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixout b/src/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixout deleted file mode 100644 index da64b8af..00000000 Binary files a/src/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixout and /dev/null differ diff --git a/src/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixproj b/src/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixproj deleted file mode 100644 index d7c4e625..00000000 --- a/src/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixproj +++ /dev/null @@ -1,47 +0,0 @@ - - - - Debug - x86 - 3.10 - d59f1c1e-9238-49fa-bfa2-ec1d9c2dda1d - 2.0 - SymbolizerWixout - Package - - - bin\$(Configuration)\ - obj\$(Configuration)\ - Debug - - - bin\$(Configuration)\ - obj\$(Configuration)\ - - - - - - - $(WixExtDir)\WixUtilExtension.dll - WixUtilExtension - - - $(WixExtDir)\WixNetFxExtension.dll - WixNetFxExtension - - - - - - - - - \ No newline at end of file diff --git a/src/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wxs b/src/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wxs deleted file mode 100644 index 46d4fb43..00000000 --- a/src/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wxs +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.csproj b/src/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.csproj deleted file mode 100644 index 995d9297..00000000 --- a/src/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.csproj +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - net461 - false - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.v3.ncrunchproject b/src/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.v3.ncrunchproject deleted file mode 100644 index 18ab4f79..00000000 --- a/src/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.v3.ncrunchproject +++ /dev/null @@ -1,9 +0,0 @@ - - - - - WixToolsetTest.Converters.Symbolizer.ConvertSymbolsFixture.CanLoadWixoutAndConvertToIntermediate - - - - \ No newline at end of file diff --git a/src/test/WixToolsetTest.Converters/BaseConverterFixture.cs b/src/test/WixToolsetTest.Converters/BaseConverterFixture.cs deleted file mode 100644 index 2421d73b..00000000 --- a/src/test/WixToolsetTest.Converters/BaseConverterFixture.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.IO; - using System.Text; - using System.Xml; - using System.Xml.Linq; - using Xunit; - - public abstract class BaseConverterFixture - { - protected static string UnformattedDocumentString(XDocument document, bool omitXmlDeclaration = true) - { - var sb = new StringBuilder(); - - using (var writer = new StringWriter(sb)) - using (var xml = XmlWriter.Create(writer, new XmlWriterSettings { OmitXmlDeclaration = omitXmlDeclaration })) - { - document.Save(xml); - } - - return sb.ToString().TrimStart(); - } - - protected static string[] UnformattedDocumentLines(XDocument document, bool omitXmlDeclaration = true) - { - var unformatted = UnformattedDocumentString(document, omitXmlDeclaration); - return unformatted.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/BitnessFixture.cs b/src/test/WixToolsetTest.Converters/BitnessFixture.cs deleted file mode 100644 index e45a9388..00000000 --- a/src/test/WixToolsetTest.Converters/BitnessFixture.cs +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class BitnessFixture : BaseConverterFixture - { - [Fact] - public void FixComponentBitness() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(10, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixRegistrySearchBitness() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(4, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixUtilRegistrySearchBitness() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(6, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixApprovedExeBitness() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(4, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/BootstrapperApplicationFixture.cs b/src/test/WixToolsetTest.Converters/BootstrapperApplicationFixture.cs deleted file mode 100644 index 158ab3be..00000000 --- a/src/test/WixToolsetTest.Converters/BootstrapperApplicationFixture.cs +++ /dev/null @@ -1,418 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class BootstrapperApplicationFixture : BaseConverterFixture - { - [Fact] - public void CantCreateBootstrapperApplicationDllFromV3PayloadGroupRef() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(2, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void ConvertDotNetCoreBootstrapperApplicationRefWithExistingElement() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(1, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void ConvertDotNetCoreBootstrapperApplicationRefWithoutExistingElement() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - "", - "", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(1, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void ConvertFrameworkBootstrapperApplicationRefWithExistingElement() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void ConvertFrameworkBootstrapperApplicationRefWithoutExistingElement() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - "", - "", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void ConvertStandardBootstrapperApplicationRefWithExistingElement() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void ConvertStandardBootstrapperApplicationRefWithoutExistingElement() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - "", - "", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void CreateBootstrapperApplicationDllFromV3() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - "", - "", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void CreateBootstrapperApplicationDllFromV3Payload() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - "", - "", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void DoesntSetDpiUnawareFromV4() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(0, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void KeepsDpiAwarenessFromV4() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - "", - "", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(1, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void RemovesBalUseUILanguages() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(5, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/ConditionFixture.cs b/src/test/WixToolsetTest.Converters/ConditionFixture.cs deleted file mode 100644 index d3f65aeb..00000000 --- a/src/test/WixToolsetTest.Converters/ConditionFixture.cs +++ /dev/null @@ -1,297 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class ConditionFixture : BaseConverterFixture - { - [Fact] - public void FixControlCondition() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " x=y", - " a<>b", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(4, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixPublishCondition() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " 1<2", - " 1", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(5, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixComponentCondition() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " 1<2", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixFeatureCondition() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " PROP = 1", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixLaunchCondition() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " 1<2", - " ", - " ", - " 1=2", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(4, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixLaunchConditionInProduct() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " 1<2", - " ", - " ", - " 1=2", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(6, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixPermissionExCondition() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " 1<2", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/ConverterFixture.cs b/src/test/WixToolsetTest.Converters/ConverterFixture.cs deleted file mode 100644 index 13df9da7..00000000 --- a/src/test/WixToolsetTest.Converters/ConverterFixture.cs +++ /dev/null @@ -1,449 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class ConverterFixture : BaseConverterFixture - { - private static readonly XNamespace Wix4Namespace = "http://wixtoolset.org/schemas/v4/wxs"; - - [Fact] - public void EnsuresNoDeclaration() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(1, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void EnsuresDeclarationWhenIgnored() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, ignoreErrors: new[] { "DeclarationPresent" } ); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document, omitXmlDeclaration: false); - - Assert.Equal(0, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void CanConvertMainNamespace() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(2, errors); - //Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace()); - Assert.Equal(expected, actual); - } - - [Fact] - public void CanConvertNamedMainNamespace() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(2, errors); - Assert.Equal(expected, actual); - Assert.Equal(Wix4Namespace, document.Root.GetNamespaceOfPrefix("w")); - } - - [Fact] - public void CanConvertNonWixDefaultNamespace() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(expected, actual); - Assert.Equal(3, errors); - Assert.Equal(Wix4Namespace, document.Root.GetNamespaceOfPrefix("w")); - Assert.Equal("http://wixtoolset.org/schemas/v4/wxs/util", document.Root.GetDefaultNamespace()); - } - - [Fact] - public void CanRemoveUnusedNamespaces() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(4, errors); - Assert.Equal(expected, actual); - Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace()); - } - - [Fact] - public void CanConvertMissingWixNamespace() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(2, errors); - Assert.Equal(expected, actual); - Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace()); - } - - [Fact] - public void CanConvertMissingIncludeNamespace() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(2, errors); - Assert.Equal(expected, actual); - Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace()); - } - - [Fact] - public void CanConvertAnonymousFile() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(3, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void CanConvertShortNameDirectoryWithoutName() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(2, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void CanConvertCatalogElement() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(1, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void CanConvertSuppressSignatureValidationNo() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(1, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void CanConvertSuppressSignatureValidationYes() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(1, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void CantConvertVerbTarget() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(2, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void CanConvertDeprecatedPrefix() - { - var parse = String.Join(Environment.NewLine, - "", - "", - "", - "", - "", - "", - "", - "", - ""); - - var expected = String.Join(Environment.NewLine, - "", - "", - "", - "", - "", - "", - "", - "", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(3, errors); - Assert.Equal(expected, actual); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/ConverterIntegrationFixture.cs b/src/test/WixToolsetTest.Converters/ConverterIntegrationFixture.cs deleted file mode 100644 index a39f6243..00000000 --- a/src/test/WixToolsetTest.Converters/ConverterIntegrationFixture.cs +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.IO; - using System.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolset.Core; - using WixToolset.Core.TestPackage; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class ConverterIntegrationFixture - { - [Fact] - public void CanConvertPermissionExFile() - { - const string beforeFileName = "v3.wxs"; - const string afterFileName = "v4_expected.wxs"; - var folder = TestData.Get(@"TestData\PermissionEx"); - - using (var fs = new DisposableFileSystem()) - { - var baseFolder = fs.GetFolder(true); - var targetFile = Path.Combine(baseFolder, beforeFileName); - File.Copy(Path.Combine(folder, beforeFileName), Path.Combine(baseFolder, beforeFileName)); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 4); - var errors = converter.ConvertFile(targetFile, true); - - Assert.Equal(8, errors); - - var expected = File.ReadAllText(Path.Combine(folder, afterFileName)).Replace("\r\n", "\n"); - var actual = File.ReadAllText(targetFile).Replace("\r\n", "\n"); - Assert.Equal(expected, actual); - - EnsureFixed(targetFile); - } - } - - [Fact] - public void CanConvertSingleFile() - { - const string beforeFileName = "SingleFile.wxs"; - const string afterFileName = "ConvertedSingleFile.wxs"; - var folder = TestData.Get(@"TestData\SingleFile"); - - using (var fs = new DisposableFileSystem()) - { - var baseFolder = fs.GetFolder(true); - var targetFile = Path.Combine(baseFolder, beforeFileName); - File.Copy(Path.Combine(folder, beforeFileName), Path.Combine(baseFolder, beforeFileName)); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 4); - var errors = converter.ConvertFile(targetFile, true); - - Assert.Equal(9, errors); - - var expected = File.ReadAllText(Path.Combine(folder, afterFileName)).Replace("\r\n", "\n"); - var actual = File.ReadAllText(targetFile).Replace("\r\n", "\n"); - Assert.Equal(expected, actual); - - EnsureFixed(targetFile); - } - } - - [Fact] - public void CanDetectReadOnlyOutputFile() - { - const string beforeFileName = "SingleFile.wxs"; - var folder = TestData.Get(@"TestData\SingleFile"); - - using (var fs = new DisposableFileSystem()) - { - var baseFolder = fs.GetFolder(true); - var targetFile = Path.Combine(baseFolder, beforeFileName); - File.Copy(Path.Combine(folder, beforeFileName), Path.Combine(baseFolder, beforeFileName)); - - var info = new FileInfo(targetFile); - info.IsReadOnly = true; - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 4); - var errors = converter.ConvertFile(targetFile, true); - - Assert.Single(messaging.Messages.Where(m => m.Id == 5/*WixConverter.ConverterTestType.UnauthorizedAccessException*/)); - } - } - - [Fact] - public void RetainsPreprocessorInstructions() - { - const string beforeFileName = "Preprocessor.wxs"; - const string afterFileName = "ConvertedPreprocessor.wxs"; - var folder = TestData.Get(@"TestData\Preprocessor"); - - using (var fs = new DisposableFileSystem()) - { - var baseFolder = fs.GetFolder(true); - var targetFile = Path.Combine(baseFolder, beforeFileName); - File.Copy(Path.Combine(folder, beforeFileName), Path.Combine(baseFolder, beforeFileName)); - - var settingsFile = Path.Combine(folder, "wixcop.settings.xml"); - - var result = RunConversion(targetFile, settingsFile: settingsFile); - Assert.Equal(9, result.ExitCode); - - var expected = File.ReadAllText(Path.Combine(folder, afterFileName)).Replace("\r\n", "\n"); - var actual = File.ReadAllText(targetFile).Replace("\r\n", "\n"); - Assert.Equal(expected, actual); - - EnsureFixed(targetFile); - } - } - - [Fact] - public void CanConvertQtExec() - { - const string beforeFileName = "v3.wxs"; - const string afterFileName = "v4_expected.wxs"; - var folder = TestData.Get(@"TestData\QtExec"); - - using (var fs = new DisposableFileSystem()) - { - var baseFolder = fs.GetFolder(true); - var targetFile = Path.Combine(baseFolder, beforeFileName); - File.Copy(Path.Combine(folder, beforeFileName), Path.Combine(baseFolder, beforeFileName)); - - var result = RunConversion(targetFile); - Assert.Equal(13, result.ExitCode); - - var expected = File.ReadAllText(Path.Combine(folder, afterFileName)).Replace("\r\n", "\n"); - var actual = File.ReadAllText(targetFile).Replace("\r\n", "\n"); - Assert.Equal(expected, actual); - - EnsureFixed(targetFile); - } - } - - [Fact] - public void DetectUnconvertableQtExecCmdTimeout() - { - const string beforeFileName = "v3.wxs"; - const string afterFileName = "v4_expected.wxs"; - var folder = TestData.Get(@"TestData\QtExec.bad"); - - using (var fs = new DisposableFileSystem()) - { - var baseFolder = fs.GetFolder(true); - var targetFile = Path.Combine(baseFolder, beforeFileName); - File.Copy(Path.Combine(folder, beforeFileName), Path.Combine(baseFolder, beforeFileName)); - - var result = RunConversion(targetFile); - - Assert.Equal(13, result.ExitCode); - Assert.Single(result.Messages.Where(message => message.ToString().EndsWith("(QtExecCmdTimeoutAmbiguous)"))); - - var expected = File.ReadAllText(Path.Combine(folder, afterFileName)).Replace("\r\n", "\n"); - var actual = File.ReadAllText(targetFile).Replace("\r\n", "\n"); - Assert.Equal(expected, actual); - - // still fails because QtExecCmdTimeoutAmbiguous is unfixable - var result2 = RunConversion(targetFile); - Assert.Equal(1, result2.ExitCode); - } - } - - private static WixRunnerResult RunConversion(string targetFile, bool fixErrors = true, string settingsFile = null) - { - var serviceProvider = WixToolsetServiceProviderFactory.CreateServiceProvider().AddConverter(); - - var exitCode = WixRunner.Execute(new[] - { - "convert", - fixErrors ? null : "--dry-run", - String.IsNullOrEmpty(settingsFile) ? null : "-set1" + settingsFile, - targetFile - }, serviceProvider, out var messages); - - return new WixRunnerResult { ExitCode = exitCode.Result, Messages = messages.ToArray() }; - } - - private static void EnsureFixed(string targetFile) - { - var messaging2 = new MockMessaging(); - var converter2 = new WixConverter(messaging2, 4); - var errors2 = converter2.ConvertFile(targetFile, true); - Assert.Equal(0, errors2); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/CustomActionFixture.cs b/src/test/WixToolsetTest.Converters/CustomActionFixture.cs deleted file mode 100644 index eafc171a..00000000 --- a/src/test/WixToolsetTest.Converters/CustomActionFixture.cs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.IO; - using System.Xml.Linq; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class CustomActionFixture : BaseConverterFixture - { - [Fact] - public void CanConvertCustomAction() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(11, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void CanConvertCustomActionScript() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " function() {", - " var x = 0;", - " return x;", - " }", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var expectedScript = String.Join("\n", - "function() {", - " var x = 0;", - " return x;", - " }"); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(2, errors); - Assert.Equal(expected, actual); - - var script = File.ReadAllText("Foo.js"); - Assert.Equal(expectedScript, script); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/CustomTableFixture.cs b/src/test/WixToolsetTest.Converters/CustomTableFixture.cs deleted file mode 100644 index 2b81a863..00000000 --- a/src/test/WixToolsetTest.Converters/CustomTableFixture.cs +++ /dev/null @@ -1,363 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class CustomTableFixture : BaseConverterFixture - { - [Fact] - public void FixCustomTableCategoryAndModularization() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(4, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixCustomRowTextValue() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " Some value", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(4, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixCustomRowCdataValue() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixCustomRowWithoutValue() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void CanConvertBundleCustomTableBootstrapperApplicationData() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " Row1", - " ", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, customTableTarget: CustomTableTarget.Bundle); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(2, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void CanConvertBundleCustomTableRef() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " Row1", - " ", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, customTableTarget: CustomTableTarget.Bundle); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(2, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void CanConvertMsiCustomTableBootstrapperApplicationData() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " Row1", - " ", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, customTableTarget: CustomTableTarget.Msi); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(2, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void CanConvertMsiCustomTableRef() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " Row1", - " ", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, customTableTarget: CustomTableTarget.Msi); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(2, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void CanDetectAmbiguousCustomTableBootstrapperApplicationData() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(1, errors); - Assert.Equal(expected, actual); - } - - [Fact] - public void CanRemoveBootstrapperApplicationDataFromRealCustomTable() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(1, errors); - Assert.Equal(expected, actual); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/DependencyFixture.cs b/src/test/WixToolsetTest.Converters/DependencyFixture.cs deleted file mode 100644 index 41ded927..00000000 --- a/src/test/WixToolsetTest.Converters/DependencyFixture.cs +++ /dev/null @@ -1,178 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class DependencyFixture : BaseConverterFixture - { - [Fact] - public void FixPackageDependencyProvides() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(5, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixPackageDependencyRequires() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(7, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixPackageDependencyRequiresRef() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(7, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixBundleDependencyProvides() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(5, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/DirectoryFixture.cs b/src/test/WixToolsetTest.Converters/DirectoryFixture.cs deleted file mode 100644 index 3c906320..00000000 --- a/src/test/WixToolsetTest.Converters/DirectoryFixture.cs +++ /dev/null @@ -1,92 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class DirectoryFixture : BaseConverterFixture - { - [Fact] - public void RemoveTargetDir() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixStandardDirectory() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(4, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/ExePackageFixture.cs b/src/test/WixToolsetTest.Converters/ExePackageFixture.cs deleted file mode 100644 index 0ee8d065..00000000 --- a/src/test/WixToolsetTest.Converters/ExePackageFixture.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class ExePackageFixture : BaseConverterFixture - { - [Fact] - public void CanConvertExePackageCommandToArguments() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/FeatureFixture.cs b/src/test/WixToolsetTest.Converters/FeatureFixture.cs deleted file mode 100644 index 1df94a81..00000000 --- a/src/test/WixToolsetTest.Converters/FeatureFixture.cs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class FeatureFixture : BaseConverterFixture - { - [Fact] - public void FixAllowAttributes() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(4, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixDisallowAttributes() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void RemoveDeprecatedAllowAdvertiseAttributes() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/FirewallExtensionFixture.cs b/src/test/WixToolsetTest.Converters/FirewallExtensionFixture.cs deleted file mode 100644 index a101019b..00000000 --- a/src/test/WixToolsetTest.Converters/FirewallExtensionFixture.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class FirewallExtensionFixture : BaseConverterFixture - { - [Fact] - public void FixRemoteAddressValue() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " 127.0.0.1", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/FormatFixture.cs b/src/test/WixToolsetTest.Converters/FormatFixture.cs deleted file mode 100644 index 739fba66..00000000 --- a/src/test/WixToolsetTest.Converters/FormatFixture.cs +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class FormatFixture : BaseConverterFixture - { - [Fact] - public void CanFixWhitespace() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 4, null, null); - - var errors = converter.FormatDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(expected, actual); - Assert.Equal(5, errors); - } - - [Fact] - public void CanPreserveNewLines() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - "", - " ", - "", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - "", - " ", - "", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 4, null, null); - - var conversions = converter.FormatDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(expected, actual); - Assert.Equal(4, conversions); - } - - [Fact] - public void CanFormatWithNewLineAtEndOfFile() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - "", - " ", - "", - " ", - "", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - "", - " ", - "", - " ", - "", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 4, null, null); - - var conversions = converter.FormatDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(expected, actual); - Assert.Equal(3, conversions); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/IncludeFixture.cs b/src/test/WixToolsetTest.Converters/IncludeFixture.cs deleted file mode 100644 index 2fd8244f..00000000 --- a/src/test/WixToolsetTest.Converters/IncludeFixture.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class IncludeFixture : BaseConverterFixture - { - [Fact] - public void EnsureNamespace() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - ""); - - var expected = new[] - { - "", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(1, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixNamespace() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - ""); - - var expected = new[] - { - "", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(1, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/Mocks/MockCoreServiceProvider.cs b/src/test/WixToolsetTest.Converters/Mocks/MockCoreServiceProvider.cs deleted file mode 100644 index b6bb8a40..00000000 --- a/src/test/WixToolsetTest.Converters/Mocks/MockCoreServiceProvider.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters.Mocks -{ - using System; - using System.Collections.Generic; - using WixToolset.Extensibility.Services; - - public class MockCoreServiceProvider : IWixToolsetCoreServiceProvider - { - public Dictionary, object>> CreationFunctions { get; } = new Dictionary, object>>(); - - public Dictionary Singletons { get; } = new Dictionary() - { - { typeof(IMessaging), new MockMessaging() } - }; - - public void AddService(Type serviceType, Func, object> creationFunction) => this.CreationFunctions.Add(serviceType, creationFunction); - - public void AddService(Func, T> creationFunction) where T : class => this.AddService(typeof(T), creationFunction); - - public T GetService() where T : class => this.TryGetService(typeof(T), out var obj) ? (T)obj : null; - - public object GetService(Type serviceType) => this.TryGetService(serviceType, out var service) ? service : null; - - public bool TryGetService(Type serviceType, out object service) - { - if (!this.Singletons.TryGetValue(serviceType, out service)) - { - if (this.CreationFunctions.TryGetValue(serviceType, out var creationFunction)) - { - service = creationFunction(this, this.Singletons); - } - } - - return service != null; - } - - public bool TryGetService(out T service) where T : class - { - service = null; - - if (this.TryGetService(typeof(T), out var obj)) - { - service = (T)obj; - } - - return service != null; - } - } -} \ No newline at end of file diff --git a/src/test/WixToolsetTest.Converters/Mocks/MockMessaging.cs b/src/test/WixToolsetTest.Converters/Mocks/MockMessaging.cs deleted file mode 100644 index 77821a1c..00000000 --- a/src/test/WixToolsetTest.Converters/Mocks/MockMessaging.cs +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters.Mocks -{ - using System; - using System.Collections.Generic; - using WixToolset.Data; - using WixToolset.Extensibility; - using WixToolset.Extensibility.Services; - - public class MockMessaging : IMessaging - { - public List Messages { get; } = new List(); - - public bool EncounteredError { get; private set; } - - public int LastErrorNumber { get; } - - public bool ShowVerboseMessages { get; set; } - - public bool SuppressAllWarnings { get; set; } - - public bool WarningsAsError { get; set; } - - public void ElevateWarningMessage(int warningNumber) => throw new NotImplementedException(); - - public void SetListener(IMessageListener listener) => throw new NotImplementedException(); - - public void SuppressWarningMessage(int warningNumber) => throw new NotImplementedException(); - - public void Write(Message message) - { - this.Messages.Add(message); - this.EncounteredError |= message.Level == MessageLevel.Error; - } - - public void Write(string message, bool verbose = false) => throw new NotImplementedException(); - } -} diff --git a/src/test/WixToolsetTest.Converters/ProductPackageFixture.cs b/src/test/WixToolsetTest.Converters/ProductPackageFixture.cs deleted file mode 100644 index e01b9789..00000000 --- a/src/test/WixToolsetTest.Converters/ProductPackageFixture.cs +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.IO; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolset.Core.TestPackage; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class ProductPackageFixture : BaseConverterFixture - { - [Fact] - public void FixesCompressedWhenYes() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - AssertSuccess(parse, 4, expected); - } - - [Fact] - public void FixesCompressedWhenNo() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - AssertSuccess(parse, 4, expected); - } - - [Fact] - public void FixesCompressedWhenOmitted() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - AssertSuccess(parse, 4, expected); - } - - private static void AssertSuccess(string input, int expectedErrorCount, string[] expected) - { - var document = XDocument.Parse(input, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(expectedErrorCount, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixesInstallerVersion() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - AssertSuccess(parse, 3, expected); - } - - [Fact] - public void FixesDefaultInstallerVersion() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - AssertSuccess(parse, 3, expected); - } - - [Fact] - public void FixesImplicitInstallerVersion() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - AssertSuccess(parse, 4, expected); - } - - [Fact] - public void FixesNonDefaultInstallerVersion() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - AssertSuccess(parse, 3, expected); - } - - [Fact] - public void FixesLimitedInstallerPrivileges() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - AssertSuccess(parse, 4, expected); - } - - [Fact] - public void FixesElevatedInstallerPrivileges() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - "" - }; - - AssertSuccess(parse, 4, expected); - } - - [Fact] - public void CanDecompileAndRecompile() - { - using (var fs = new DisposableFileSystem()) - { - var baseFolder = fs.GetFolder(); - var intermediateFolder = Path.Combine(baseFolder, "obj"); - var decompiledWxsPath = Path.Combine(baseFolder, "TypicalV3.wxs"); - - var folder = TestData.Get(@"TestData\PackageSummaryInformation"); - var v3msiPath = Path.Combine(folder, "TypicalV3.msi"); - var result = WixRunner.Execute(new[] - { - "decompile", v3msiPath, - "-intermediateFolder", intermediateFolder, - "-o", decompiledWxsPath - }); - - result.AssertSuccess(); - - var v4msiPath = Path.Combine(intermediateFolder, "TypicalV4.msi"); - result = WixRunner.Execute(new[] - { - "build", decompiledWxsPath, - "-arch", "x64", - "-intermediateFolder", intermediateFolder, - "-o", v4msiPath - }); - - result.AssertSuccess(); - - Assert.True(File.Exists(v4msiPath)); - - var v3results = Query.QueryDatabase(v3msiPath, new[] { "_SummaryInformation", "Property" }); - var v4results = Query.QueryDatabase(v4msiPath, new[] { "_SummaryInformation", "Property" }); - WixAssert.CompareLineByLine(v3results, v4results); - } - } - } -} diff --git a/src/test/WixToolsetTest.Converters/PropertyFixture.cs b/src/test/WixToolsetTest.Converters/PropertyFixture.cs deleted file mode 100644 index e50a6518..00000000 --- a/src/test/WixToolsetTest.Converters/PropertyFixture.cs +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class PropertyFixture : BaseConverterFixture - { - [Fact] - public void CanFixCdataWhitespace() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(expected, actual); - Assert.Equal(1, errors); - } - - [Fact] - public void CanFixCdataWithWhitespace() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(expected, actual); - Assert.Equal(1, errors); - } - - [Fact] - public void CanKeepCdataWithOnlyWhitespace() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var expected = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - var errors = converter.ConvertDocument(document); - - var actual = UnformattedDocumentString(document); - - Assert.Equal(expected, actual); - Assert.Equal(1, errors); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/RegistryFixture.cs b/src/test/WixToolsetTest.Converters/RegistryFixture.cs deleted file mode 100644 index 405f5416..00000000 --- a/src/test/WixToolsetTest.Converters/RegistryFixture.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class RegistryFixture : BaseConverterFixture - { - [Fact] - public void FixRegistryKeyAction() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(5, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/RemotePayloadFixture.cs b/src/test/WixToolsetTest.Converters/RemotePayloadFixture.cs deleted file mode 100644 index b2640e13..00000000 --- a/src/test/WixToolsetTest.Converters/RemotePayloadFixture.cs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class RemotePayloadFixture : BaseConverterFixture - { - [Fact] - public void CanConvertExePackageRemotePayload() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(6, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void CanConvertMsuPackageRemotePayload() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(5, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/SequenceFixture.cs b/src/test/WixToolsetTest.Converters/SequenceFixture.cs deleted file mode 100644 index ec6c709b..00000000 --- a/src/test/WixToolsetTest.Converters/SequenceFixture.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class SequenceFixture : BaseConverterFixture - { - [Fact] - public void FixCondition() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " NOT Installed", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(2, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/TagFixture.cs b/src/test/WixToolsetTest.Converters/TagFixture.cs deleted file mode 100644 index 5e07c83b..00000000 --- a/src/test/WixToolsetTest.Converters/TagFixture.cs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class TagFixture : BaseConverterFixture - { - [Fact] - public void FixTagExtension() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(4, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixTagExtensionDeprecations() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(7, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixTagExtensionTagRef() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.msi b/src/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.msi deleted file mode 100644 index 0d7e1b21..00000000 Binary files a/src/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.msi and /dev/null differ diff --git a/src/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.wxs b/src/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.wxs deleted file mode 100644 index 8c5027b4..00000000 --- a/src/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.wxs +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/test/WixToolsetTest.Converters/TestData/PermissionEx/v3.wxs b/src/test/WixToolsetTest.Converters/TestData/PermissionEx/v3.wxs deleted file mode 100644 index 9a739052..00000000 --- a/src/test/WixToolsetTest.Converters/TestData/PermissionEx/v3.wxs +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Converters/TestData/PermissionEx/v4_expected.wxs b/src/test/WixToolsetTest.Converters/TestData/PermissionEx/v4_expected.wxs deleted file mode 100644 index 6bf3c1ea..00000000 --- a/src/test/WixToolsetTest.Converters/TestData/PermissionEx/v4_expected.wxs +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Converters/TestData/Preprocessor/ConvertedPreprocessor.wxs b/src/test/WixToolsetTest.Converters/TestData/Preprocessor/ConvertedPreprocessor.wxs deleted file mode 100644 index 8188d900..00000000 --- a/src/test/WixToolsetTest.Converters/TestData/Preprocessor/ConvertedPreprocessor.wxs +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Converters/TestData/Preprocessor/Preprocessor.wxs b/src/test/WixToolsetTest.Converters/TestData/Preprocessor/Preprocessor.wxs deleted file mode 100644 index 2eb908c2..00000000 --- a/src/test/WixToolsetTest.Converters/TestData/Preprocessor/Preprocessor.wxs +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Converters/TestData/Preprocessor/wixcop.settings.xml b/src/test/WixToolsetTest.Converters/TestData/Preprocessor/wixcop.settings.xml deleted file mode 100644 index 9d3ad496..00000000 --- a/src/test/WixToolsetTest.Converters/TestData/Preprocessor/wixcop.settings.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v3.wxs b/src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v3.wxs deleted file mode 100644 index b0fcf9c9..00000000 --- a/src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v3.wxs +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v4_expected.wxs b/src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v4_expected.wxs deleted file mode 100644 index 95d2f618..00000000 --- a/src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v4_expected.wxs +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Converters/TestData/QtExec/v3.wxs b/src/test/WixToolsetTest.Converters/TestData/QtExec/v3.wxs deleted file mode 100644 index 8d81a758..00000000 --- a/src/test/WixToolsetTest.Converters/TestData/QtExec/v3.wxs +++ /dev/null @@ -1,64 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Converters/TestData/QtExec/v4_expected.wxs b/src/test/WixToolsetTest.Converters/TestData/QtExec/v4_expected.wxs deleted file mode 100644 index f24d3f8f..00000000 --- a/src/test/WixToolsetTest.Converters/TestData/QtExec/v4_expected.wxs +++ /dev/null @@ -1,62 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Converters/TestData/SingleFile/ConvertedSingleFile.wxs b/src/test/WixToolsetTest.Converters/TestData/SingleFile/ConvertedSingleFile.wxs deleted file mode 100644 index 5bcdaf59..00000000 --- a/src/test/WixToolsetTest.Converters/TestData/SingleFile/ConvertedSingleFile.wxs +++ /dev/null @@ -1,59 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Converters/TestData/SingleFile/SingleFile.wxs b/src/test/WixToolsetTest.Converters/TestData/SingleFile/SingleFile.wxs deleted file mode 100644 index 310ae811..00000000 --- a/src/test/WixToolsetTest.Converters/TestData/SingleFile/SingleFile.wxs +++ /dev/null @@ -1,61 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/test/WixToolsetTest.Converters/UtilExtensionFixture.cs b/src/test/WixToolsetTest.Converters/UtilExtensionFixture.cs deleted file mode 100644 index 10450c68..00000000 --- a/src/test/WixToolsetTest.Converters/UtilExtensionFixture.cs +++ /dev/null @@ -1,190 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class UtilExtensionFixture : BaseConverterFixture - { - [Fact] - public void FixCloseAppsCondition() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " a<>b", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixXmlConfigValue() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " a<>b", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void WarnsOnAllRegistryValueSearches() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(4, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - - [Fact] - public void FixXmlConfigValueCData() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " b]]>", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void FixQueryOsPropertyRefs() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(6, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/VariableFixture.cs b/src/test/WixToolsetTest.Converters/VariableFixture.cs deleted file mode 100644 index b7b7388f..00000000 --- a/src/test/WixToolsetTest.Converters/VariableFixture.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class VariableFixture : BaseConverterFixture - { - [Fact] - public void FixFormattedType() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(3, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - - [Fact] - public void DoesntFixFormattedTypeFromV4() - { - var parse = String.Join(Environment.NewLine, - "", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(0, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/Wix4ConversionFixture.cs b/src/test/WixToolsetTest.Converters/Wix4ConversionFixture.cs deleted file mode 100644 index 16a68895..00000000 --- a/src/test/WixToolsetTest.Converters/Wix4ConversionFixture.cs +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. - -namespace WixToolsetTest.Converters -{ - using System; - using System.Xml.Linq; - using WixBuildTools.TestSupport; - using WixToolset.Converters; - using WixToolsetTest.Converters.Mocks; - using Xunit; - - public class Wix4ConversionFixture : BaseConverterFixture - { - [Fact] - public void DoesNotAddFileId() - { - var parse = String.Join(Environment.NewLine, - "", - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - ""); - - var expected = new[] - { - "", - " ", - " ", - " ", - " ", - " ", - " ", - " ", - "" - }; - - var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); - - var messaging = new MockMessaging(); - var converter = new WixConverter(messaging, 2, null, null); - - var errors = converter.ConvertDocument(document); - Assert.Equal(1, errors); - - var actualLines = UnformattedDocumentLines(document); - WixAssert.CompareLineByLine(expected, actualLines); - } - } -} diff --git a/src/test/WixToolsetTest.Converters/WixToolsetTest.Converters.csproj b/src/test/WixToolsetTest.Converters/WixToolsetTest.Converters.csproj deleted file mode 100644 index 29b02b95..00000000 --- a/src/test/WixToolsetTest.Converters/WixToolsetTest.Converters.csproj +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - netcoreapp3.1 - false - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/version.json b/src/version.json new file mode 100644 index 00000000..5f857771 --- /dev/null +++ b/src/version.json @@ -0,0 +1,11 @@ +{ + "version": "4.0", + "publicReleaseRefSpec": [ + "^refs/heads/master$" + ], + "cloudBuild": { + "buildNumber": { + "enabled": true + } + } +} diff --git a/src/wix/Directory.Build.props b/src/wix/Directory.Build.props new file mode 100644 index 00000000..b3c6287c --- /dev/null +++ b/src/wix/Directory.Build.props @@ -0,0 +1,27 @@ + + + + + + Debug + false + MSB3246 + + $(MSBuildProjectName) + $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)..\build\)) + $(BaseOutputPath)obj\$(ProjectName)\ + $(BaseOutputPath)$(Configuration)\ + + WiX Toolset Team + WiX Toolset + Copyright (c) .NET Foundation and contributors. All rights reserved. + MS-RL + WiX Toolset + + + + + diff --git a/src/wix/Directory.Build.targets b/src/wix/Directory.Build.targets new file mode 100644 index 00000000..2fcc765a --- /dev/null +++ b/src/wix/Directory.Build.targets @@ -0,0 +1,51 @@ + + + + + + + true + $(SolutionPath) + $(NCrunchOriginalSolutionPath) + + + + + + + $([System.IO.File]::ReadAllText($(TheSolutionPath))) + $([System.IO.Path]::GetDirectoryName( $(TheSolutionPath) )) + (?<="[PackageName]", ")(.*)(?=", ") + + + + + + %(Identity) + $(SolutionFileContent.Contains('\%(Identity).csproj')) + + + + + $(RegexPattern.Replace('[PackageName]','%(PackageName)') ) + $([System.Text.RegularExpressions.Regex]::Match('$(SolutionFileContent)', '%(Pattern)')) + + + + + + + + + + + + + + diff --git a/src/wix/Directory.csproj.props b/src/wix/Directory.csproj.props new file mode 100644 index 00000000..81d24ad1 --- /dev/null +++ b/src/wix/Directory.csproj.props @@ -0,0 +1,13 @@ + + + + + true + true + $([System.IO.Path]::GetFullPath($(MSBuildThisFileDirectory)wix.snk)) + false + + diff --git a/src/wix/Directory.csproj.targets b/src/wix/Directory.csproj.targets new file mode 100644 index 00000000..c3270426 --- /dev/null +++ b/src/wix/Directory.csproj.targets @@ -0,0 +1,26 @@ + + + + + false + $(OutputPath)\$(AssemblyName).xml + + + + + $(PrivateRepositoryUrl.Replace('.git','')) + + $(MSBuildProjectName).nuspec + $(OutputPath)..\ + $(NuspecProperties);Id=$(PackageId);Authors=$(Authors);Copyright=$(Copyright);Description=$(Description);Title=$(Title) + $(NuspecProperties);Version=$(PackageVersion);RepositoryCommit=$(SourceRevisionId);RepositoryType=$(RepositoryType);RepositoryUrl=$(PrivateRepositoryUrl);ProjectFolder=$(MSBuildProjectDirectory)\;ProjectUrl=$(ProjectUrl) + true + snupkg + + + + diff --git a/src/wix/README.md b/src/wix/README.md new file mode 100644 index 00000000..f031cf7c --- /dev/null +++ b/src/wix/README.md @@ -0,0 +1,2 @@ +# Converters +WixToolset.Converters, conversion related functionality diff --git a/src/wix/WixToolset.Converters.Symbolizer/ConvertSymbols.cs b/src/wix/WixToolset.Converters.Symbolizer/ConvertSymbols.cs new file mode 100644 index 00000000..6418b2a6 --- /dev/null +++ b/src/wix/WixToolset.Converters.Symbolizer/ConvertSymbols.cs @@ -0,0 +1,876 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Converters.Symbolizer +{ + using System; + using System.Collections.Generic; + using System.Linq; + using WixToolset.Data; + using WixToolset.Data.Symbols; + using WixToolset.Data.WindowsInstaller; + using Wix3 = Microsoft.Tools.WindowsInstallerXml; + +#pragma warning disable 1591 // TODO: add documentation + public static class ConvertSymbols + { + public static Intermediate ConvertFile(string path) + { + var output = Wix3.Output.Load(path, suppressVersionCheck: true, suppressSchema: true); + return ConvertOutput(output); + } + + public static Intermediate ConvertOutput(Wix3.Output output) +#pragma warning restore 1591 + { + var section = new IntermediateSection(String.Empty, OutputType3ToSectionType4(output.Type)); + + var wixMediaByDiskId = IndexWixMediaTableByDiskId(output); + var componentsById = IndexById(output, "Component"); + var bindPathsById = IndexById(output, "BindPath"); + var fontsById = IndexById(output, "Font"); + var selfRegById = IndexById(output, "SelfReg"); + var wixDirectoryById = IndexById(output, "WixDirectory"); + var wixFileById = IndexById(output, "WixFile"); + + foreach (Wix3.Table table in output.Tables) + { + foreach (Wix3.Row row in table.Rows) + { + var symbol = GenerateSymbolFromRow(row, wixMediaByDiskId, componentsById, fontsById, bindPathsById, selfRegById, wixFileById, wixDirectoryById); + if (symbol != null) + { + section.AddSymbol(symbol); + } + } + } + + return new Intermediate(String.Empty, new[] { section }, localizationsByCulture: null); + } + + private static Dictionary IndexWixMediaTableByDiskId(Wix3.Output output) + { + var wixMediaByDiskId = new Dictionary(); + var wixMediaTable = output.Tables["WixMedia"]; + + if (wixMediaTable != null) + { + foreach (Wix3.WixMediaRow row in wixMediaTable.Rows) + { + wixMediaByDiskId.Add(FieldAsInt(row, 0), row); + } + } + + return wixMediaByDiskId; + } + + private static Dictionary IndexById(Wix3.Output output, string tableName) where T : Wix3.Row + { + var byId = new Dictionary(); + var table = output.Tables[tableName]; + + if (table != null) + { + foreach (T row in table.Rows) + { + byId.Add(FieldAsString(row, 0), row); + } + } + + return byId; + } + + private static IntermediateSymbol GenerateSymbolFromRow(Wix3.Row row, Dictionary wixMediaByDiskId, Dictionary componentsById, Dictionary fontsById, Dictionary bindPathsById, Dictionary selfRegById, Dictionary wixFileById, Dictionary wixDirectoryById) + { + var name = row.Table.Name; + switch (name) + { + case "_SummaryInformation": + return DefaultSymbolFromRow(typeof(SummaryInformationSymbol), row, columnZeroIsId: false); + case "ActionText": + return DefaultSymbolFromRow(typeof(ActionTextSymbol), row, columnZeroIsId: false); + case "AppId": + return DefaultSymbolFromRow(typeof(AppIdSymbol), row, columnZeroIsId: false); + case "AppSearch": + return DefaultSymbolFromRow(typeof(AppSearchSymbol), row, columnZeroIsId: false); + case "Billboard": + return DefaultSymbolFromRow(typeof(BillboardSymbol), row, columnZeroIsId: true); + case "Binary": + return DefaultSymbolFromRow(typeof(BinarySymbol), row, columnZeroIsId: true); + case "BindPath": + return null; + case "CCPSearch": + return DefaultSymbolFromRow(typeof(CCPSearchSymbol), row, columnZeroIsId: true); + case "Class": + return DefaultSymbolFromRow(typeof(ClassSymbol), row, columnZeroIsId: false); + case "CompLocator": + return DefaultSymbolFromRow(typeof(CompLocatorSymbol), row, columnZeroIsId: false); + case "Component": + { + var attributes = FieldAsNullableInt(row, 3); + + var location = ComponentLocation.LocalOnly; + if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesSourceOnly) == WindowsInstallerConstants.MsidbComponentAttributesSourceOnly) + { + location = ComponentLocation.SourceOnly; + } + else if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesOptional) == WindowsInstallerConstants.MsidbComponentAttributesOptional) + { + location = ComponentLocation.Either; + } + + var keyPath = FieldAsString(row, 5); + var keyPathType = String.IsNullOrEmpty(keyPath) ? ComponentKeyPathType.Directory : ComponentKeyPathType.File; + if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath) == WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath) + { + keyPathType = ComponentKeyPathType.Registry; + } + else if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource) == WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource) + { + keyPathType = ComponentKeyPathType.OdbcDataSource; + } + + return new ComponentSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) + { + ComponentId = FieldAsString(row, 1), + DirectoryRef = FieldAsString(row, 2), + Condition = FieldAsString(row, 4), + KeyPath = keyPath, + Location = location, + DisableRegistryReflection = (attributes & WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection) == WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection, + NeverOverwrite = (attributes & WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite) == WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite, + Permanent = (attributes & WindowsInstallerConstants.MsidbComponentAttributesPermanent) == WindowsInstallerConstants.MsidbComponentAttributesPermanent, + SharedDllRefCount = (attributes & WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount) == WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount, + Shared = (attributes & WindowsInstallerConstants.MsidbComponentAttributesShared) == WindowsInstallerConstants.MsidbComponentAttributesShared, + Transitive = (attributes & WindowsInstallerConstants.MsidbComponentAttributesTransitive) == WindowsInstallerConstants.MsidbComponentAttributesTransitive, + UninstallWhenSuperseded = (attributes & WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence) == WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence, + Win64 = (attributes & WindowsInstallerConstants.MsidbComponentAttributes64bit) == WindowsInstallerConstants.MsidbComponentAttributes64bit, + KeyPathType = keyPathType, + }; + } + + case "Condition": + return DefaultSymbolFromRow(typeof(ConditionSymbol), row, columnZeroIsId: false); + case "CreateFolder": + return DefaultSymbolFromRow(typeof(CreateFolderSymbol), row, columnZeroIsId: false); + case "CustomAction": + { + var caType = FieldAsInt(row, 1); + var executionType = DetermineCustomActionExecutionType(caType); + var sourceType = DetermineCustomActionSourceType(caType); + var targetType = DetermineCustomActionTargetType(caType); + + return new CustomActionSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) + { + ExecutionType = executionType, + SourceType = sourceType, + Source = FieldAsString(row, 2), + TargetType = targetType, + Target = FieldAsString(row, 3), + Win64 = (caType & WindowsInstallerConstants.MsidbCustomActionType64BitScript) == WindowsInstallerConstants.MsidbCustomActionType64BitScript, + TSAware = (caType & WindowsInstallerConstants.MsidbCustomActionTypeTSAware) == WindowsInstallerConstants.MsidbCustomActionTypeTSAware, + Impersonate = (caType & WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate) != WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate, + IgnoreResult = (caType & WindowsInstallerConstants.MsidbCustomActionTypeContinue) == WindowsInstallerConstants.MsidbCustomActionTypeContinue, + Hidden = (caType & WindowsInstallerConstants.MsidbCustomActionTypeHideTarget) == WindowsInstallerConstants.MsidbCustomActionTypeHideTarget, + Async = (caType & WindowsInstallerConstants.MsidbCustomActionTypeAsync) == WindowsInstallerConstants.MsidbCustomActionTypeAsync, + }; + } + + case "Directory": + { + var id = FieldAsString(row, 0); + var splits = SplitDefaultDir(FieldAsString(row, 2)); + + var symbol = new DirectorySymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, id)) + { + ParentDirectoryRef = FieldAsString(row, 1), + Name = splits[0], + ShortName = splits[1], + SourceName = splits[2], + SourceShortName = splits[3] + }; + + if (wixDirectoryById.TryGetValue(id, out var wixDirectoryRow)) + { + symbol.ComponentGuidGenerationSeed = FieldAsString(wixDirectoryRow, 1); + } + + return symbol; + } + case "DrLocator": + return DefaultSymbolFromRow(typeof(DrLocatorSymbol), row, columnZeroIsId: false); + case "DuplicateFile": + { + var splitName = FieldAsString(row, 3)?.Split('|'); + + var symbol = new DuplicateFileSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) + { + ComponentRef = FieldAsString(row, 1), + FileRef = FieldAsString(row, 2), + DestinationName = splitName == null ? null : splitName.Length > 1 ? splitName[1] : splitName[0], + DestinationShortName = splitName == null ? null : splitName.Length > 1 ? splitName[0] : null, + DestinationFolder = FieldAsString(row, 4) + }; + + return symbol; + } + case "Error": + return DefaultSymbolFromRow(typeof(ErrorSymbol), row, columnZeroIsId: false); + case "Extension": + return DefaultSymbolFromRow(typeof(ExtensionSymbol), row, columnZeroIsId: false); + case "Feature": + { + var attributes = FieldAsInt(row, 7); + var installDefault = FeatureInstallDefault.Local; + if ((attributes & WindowsInstallerConstants.MsidbFeatureAttributesFollowParent) == WindowsInstallerConstants.MsidbFeatureAttributesFollowParent) + { + installDefault = FeatureInstallDefault.FollowParent; + } + else if ((attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorSource) == WindowsInstallerConstants.MsidbFeatureAttributesFavorSource) + { + installDefault = FeatureInstallDefault.Source; + } + + return new FeatureSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) + { + ParentFeatureRef = FieldAsString(row, 1), + Title = FieldAsString(row, 2), + Description = FieldAsString(row, 3), + Display = FieldAsInt(row, 4), // BUGBUGBUG: FieldAsNullableInt(row, 4), + Level = FieldAsInt(row, 5), + DirectoryRef = FieldAsString(row, 6), + DisallowAbsent = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent) == WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent, + DisallowAdvertise = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise) == WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise, + InstallDefault = installDefault, + TypicalDefault = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise) == WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise ? FeatureTypicalDefault.Advertise : FeatureTypicalDefault.Install, + }; + } + + case "FeatureComponents": + return DefaultSymbolFromRow(typeof(FeatureComponentsSymbol), row, columnZeroIsId: false); + case "File": + { + var attributes = FieldAsNullableInt(row, 6); + + FileSymbolAttributes symbolAttributes = 0; + symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesReadOnly) == WindowsInstallerConstants.MsidbFileAttributesReadOnly ? FileSymbolAttributes.ReadOnly : 0; + symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesHidden) == WindowsInstallerConstants.MsidbFileAttributesHidden ? FileSymbolAttributes.Hidden : 0; + symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesSystem) == WindowsInstallerConstants.MsidbFileAttributesSystem ? FileSymbolAttributes.System : 0; + symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesVital) == WindowsInstallerConstants.MsidbFileAttributesVital ? FileSymbolAttributes.Vital : 0; + symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesChecksum) == WindowsInstallerConstants.MsidbFileAttributesChecksum ? FileSymbolAttributes.Checksum : 0; + symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) == WindowsInstallerConstants.MsidbFileAttributesNoncompressed ? FileSymbolAttributes.Uncompressed : 0; + symbolAttributes |= (attributes & WindowsInstallerConstants.MsidbFileAttributesCompressed) == WindowsInstallerConstants.MsidbFileAttributesCompressed ? FileSymbolAttributes.Compressed : 0; + + var id = FieldAsString(row, 0); + var splitName = FieldAsString(row, 2).Split('|'); + + var symbol = new FileSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, id)) + { + ComponentRef = FieldAsString(row, 1), + Name = splitName.Length > 1 ? splitName[1] : splitName[0], + ShortName = splitName.Length > 1 ? splitName[0] : null, + FileSize = FieldAsInt(row, 3), + Version = FieldAsString(row, 4), + Language = FieldAsString(row, 5), + Attributes = symbolAttributes + }; + + if (bindPathsById.TryGetValue(id, out var bindPathRow)) + { + symbol.BindPath = FieldAsString(bindPathRow, 1) ?? String.Empty; + } + + if (fontsById.TryGetValue(id, out var fontRow)) + { + symbol.FontTitle = FieldAsString(fontRow, 1) ?? String.Empty; + } + + if (selfRegById.TryGetValue(id, out var selfRegRow)) + { + symbol.SelfRegCost = FieldAsNullableInt(selfRegRow, 1) ?? 0; + } + + if (wixFileById.TryGetValue(id, out var wixFileRow)) + { + symbol.DirectoryRef = FieldAsString(wixFileRow, 4); + symbol.DiskId = FieldAsNullableInt(wixFileRow, 5) ?? 0; + symbol.Source = new IntermediateFieldPathValue { Path = FieldAsString(wixFileRow, 6) }; + symbol.PatchGroup = FieldAsInt(wixFileRow, 8); + symbol.PatchAttributes = (PatchAttributeType)FieldAsInt(wixFileRow, 10); + } + + return symbol; + } + case "Font": + return null; + case "Icon": + return DefaultSymbolFromRow(typeof(IconSymbol), row, columnZeroIsId: true); + case "IniFile": + { + var splitName = FieldAsString(row, 1).Split('|'); + var action = FieldAsInt(row, 6); + + var symbol = new IniFileSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) + { + FileName = splitName.Length > 1 ? splitName[1] : splitName[0], + ShortFileName = splitName.Length > 1 ? splitName[0] : null, + DirProperty = FieldAsString(row, 2), + Section = FieldAsString(row, 3), + Key = FieldAsString(row, 4), + Value = FieldAsString(row, 5), + Action = action == 3 ? IniFileActionType.AddTag : action == 1 ? IniFileActionType.CreateLine : IniFileActionType.AddLine, + ComponentRef = FieldAsString(row, 7), + }; + + return symbol; + } + case "IniLocator": + { + var splitName = FieldAsString(row, 1).Split('|'); + + var symbol = new IniLocatorSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) + { + FileName = splitName.Length > 1 ? splitName[1] : splitName[0], + ShortFileName = splitName.Length > 1 ? splitName[0] : null, + Section = FieldAsString(row, 2), + Key = FieldAsString(row, 3), + Field = FieldAsInt(row, 4), + Type = FieldAsInt(row, 5), + }; + + return symbol; + } + case "LockPermissions": + return DefaultSymbolFromRow(typeof(LockPermissionsSymbol), row, columnZeroIsId: false); + case "Media": + { + var diskId = FieldAsInt(row, 0); + var symbol = new MediaSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, diskId)) + { + DiskId = diskId, + LastSequence = FieldAsNullableInt(row, 1), + DiskPrompt = FieldAsString(row, 2), + Cabinet = FieldAsString(row, 3), + VolumeLabel = FieldAsString(row, 4), + Source = FieldAsString(row, 5) + }; + + if (wixMediaByDiskId.TryGetValue(diskId, out var wixMediaRow)) + { + var compressionLevel = FieldAsString(wixMediaRow, 1); + + symbol.CompressionLevel = String.IsNullOrEmpty(compressionLevel) ? null : (CompressionLevel?)Enum.Parse(typeof(CompressionLevel), compressionLevel, true); + symbol.Layout = wixMediaRow.Layout; + } + + return symbol; + } + case "MIME": + return DefaultSymbolFromRow(typeof(MIMESymbol), row, columnZeroIsId: false); + case "ModuleIgnoreTable": + return DefaultSymbolFromRow(typeof(ModuleIgnoreTableSymbol), row, columnZeroIsId: true); + case "MoveFile": + return DefaultSymbolFromRow(typeof(MoveFileSymbol), row, columnZeroIsId: true); + case "MsiAssembly": + { + var componentId = FieldAsString(row, 0); + if (componentsById.TryGetValue(componentId, out var componentRow)) + { + return new AssemblySymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(componentRow, 5))) + { + ComponentRef = componentId, + FeatureRef = FieldAsString(row, 1), + ManifestFileRef = FieldAsString(row, 2), + ApplicationFileRef = FieldAsString(row, 3), + Type = FieldAsNullableInt(row, 4) == 1 ? AssemblyType.Win32Assembly : AssemblyType.DotNetAssembly, + }; + } + + return null; + } + case "MsiLockPermissionsEx": + return DefaultSymbolFromRow(typeof(MsiLockPermissionsExSymbol), row, columnZeroIsId: true); + case "MsiShortcutProperty": + return DefaultSymbolFromRow(typeof(MsiShortcutPropertySymbol), row, columnZeroIsId: true); + case "ODBCDataSource": + return DefaultSymbolFromRow(typeof(ODBCDataSourceSymbol), row, columnZeroIsId: true); + case "ODBCDriver": + return DefaultSymbolFromRow(typeof(ODBCDriverSymbol), row, columnZeroIsId: true); + case "ODBCTranslator": + return DefaultSymbolFromRow(typeof(ODBCTranslatorSymbol), row, columnZeroIsId: true); + case "ProgId": + return DefaultSymbolFromRow(typeof(ProgIdSymbol), row, columnZeroIsId: false); + case "Property": + return DefaultSymbolFromRow(typeof(PropertySymbol), row, columnZeroIsId: true); + case "PublishComponent": + return DefaultSymbolFromRow(typeof(PublishComponentSymbol), row, columnZeroIsId: false); + case "Registry": + { + var value = FieldAsString(row, 4); + var valueType = RegistryValueType.String; + var valueAction = RegistryValueActionType.Write; + + if (!String.IsNullOrEmpty(value)) + { + if (value.StartsWith("#x", StringComparison.Ordinal)) + { + valueType = RegistryValueType.Binary; + value = value.Substring(2); + } + else if (value.StartsWith("#%", StringComparison.Ordinal)) + { + valueType = RegistryValueType.Expandable; + value = value.Substring(2); + } + else if (value.StartsWith("#", StringComparison.Ordinal)) + { + valueType = RegistryValueType.Integer; + value = value.Substring(1); + } + else if (value.StartsWith("[~]", StringComparison.Ordinal) && value.EndsWith("[~]", StringComparison.Ordinal)) + { + value = value.Substring(3, value.Length - 6); + valueType = RegistryValueType.MultiString; + valueAction = RegistryValueActionType.Write; + } + else if (value.StartsWith("[~]", StringComparison.Ordinal)) + { + value = value.Substring(3); + valueType = RegistryValueType.MultiString; + valueAction = RegistryValueActionType.Append; + } + else if (value.EndsWith("[~]", StringComparison.Ordinal)) + { + value = value.Substring(0, value.Length - 3); + valueType = RegistryValueType.MultiString; + valueAction = RegistryValueActionType.Prepend; + } + } + + return new RegistrySymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) + { + Root = (RegistryRootType)FieldAsInt(row, 1), + Key = FieldAsString(row, 2), + Name = FieldAsString(row, 3), + Value = value, + ComponentRef = FieldAsString(row, 5), + ValueAction = valueAction, + ValueType = valueType, + }; + } + case "RegLocator": + { + var type = FieldAsInt(row, 4); + + return new RegLocatorSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) + { + Root = (RegistryRootType)FieldAsInt(row, 1), + Key = FieldAsString(row, 2), + Name = FieldAsString(row, 3), + Type = (RegLocatorType)(type & 0xF), + Win64 = (type & WindowsInstallerConstants.MsidbLocatorType64bit) == WindowsInstallerConstants.MsidbLocatorType64bit + }; + } + case "RemoveFile": + { + var splitName = FieldAsString(row, 2).Split('|'); + var installMode = FieldAsInt(row, 4); + + return new RemoveFileSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) + { + ComponentRef = FieldAsString(row, 1), + FileName = splitName.Length > 1 ? splitName[1] : splitName[0], + ShortFileName = splitName.Length > 1 ? splitName[0] : null, + DirPropertyRef = FieldAsString(row, 3), + OnInstall = (installMode & WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall) == WindowsInstallerConstants.MsidbRemoveFileInstallModeOnInstall ? (bool?)true : null, + OnUninstall = (installMode & WindowsInstallerConstants.MsidbRemoveFileInstallModeOnRemove) == WindowsInstallerConstants.MsidbRemoveFileInstallModeOnRemove ? (bool?)true : null + }; + } + case "RemoveRegistry": + { + return new RemoveRegistrySymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) + { + Action = RemoveRegistryActionType.RemoveOnInstall, + Root = (RegistryRootType)FieldAsInt(row, 1), + Key = FieldAsString(row, 2), + Name = FieldAsString(row, 3), + ComponentRef = FieldAsString(row, 4), + }; + } + + case "ReserveCost": + return DefaultSymbolFromRow(typeof(ReserveCostSymbol), row, columnZeroIsId: true); + case "SelfReg": + return null; + case "ServiceControl": + { + var events = FieldAsInt(row, 2); + var wait = FieldAsNullableInt(row, 4); + return new ServiceControlSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) + { + Name = FieldAsString(row, 1), + Arguments = FieldAsString(row, 3), + Wait = !wait.HasValue || wait.Value == 1, + ComponentRef = FieldAsString(row, 5), + InstallRemove = (events & WindowsInstallerConstants.MsidbServiceControlEventDelete) == WindowsInstallerConstants.MsidbServiceControlEventDelete, + UninstallRemove = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete) == WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete, + InstallStart = (events & WindowsInstallerConstants.MsidbServiceControlEventStart) == WindowsInstallerConstants.MsidbServiceControlEventStart, + UninstallStart = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallStart) == WindowsInstallerConstants.MsidbServiceControlEventUninstallStart, + InstallStop = (events & WindowsInstallerConstants.MsidbServiceControlEventStop) == WindowsInstallerConstants.MsidbServiceControlEventStop, + UninstallStop = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallStop) == WindowsInstallerConstants.MsidbServiceControlEventUninstallStop, + }; + } + + case "ServiceInstall": + return DefaultSymbolFromRow(typeof(ServiceInstallSymbol), row, columnZeroIsId: true); + case "Shortcut": + { + var splitName = FieldAsString(row, 2).Split('|'); + + return new ShortcutSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) + { + DirectoryRef = FieldAsString(row, 1), + Name = splitName.Length > 1 ? splitName[1] : splitName[0], + ShortName = splitName.Length > 1 ? splitName[0] : null, + ComponentRef = FieldAsString(row, 3), + Target = FieldAsString(row, 4), + Arguments = FieldAsString(row, 5), + Description = FieldAsString(row, 6), + Hotkey = FieldAsNullableInt(row, 7), + IconRef = FieldAsString(row, 8), + IconIndex = FieldAsNullableInt(row, 9), + Show = (ShortcutShowType?)FieldAsNullableInt(row, 10), + WorkingDirectory = FieldAsString(row, 11), + DisplayResourceDll = FieldAsString(row, 12), + DisplayResourceId = FieldAsNullableInt(row, 13), + DescriptionResourceDll = FieldAsString(row, 14), + DescriptionResourceId= FieldAsNullableInt(row, 15), + }; + } + case "Signature": + return DefaultSymbolFromRow(typeof(SignatureSymbol), row, columnZeroIsId: true); + case "UIText": + return DefaultSymbolFromRow(typeof(UITextSymbol), row, columnZeroIsId: true); + case "Upgrade": + { + var attributes = FieldAsInt(row, 4); + return new UpgradeSymbol(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Global, FieldAsString(row, 0))) + { + UpgradeCode = FieldAsString(row, 0), + VersionMin = FieldAsString(row, 1), + VersionMax = FieldAsString(row, 2), + Language = FieldAsString(row, 3), + Remove = FieldAsString(row, 5), + ActionProperty = FieldAsString(row, 6), + MigrateFeatures = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures) == WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures, + OnlyDetect = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect) == WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect, + IgnoreRemoveFailures = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure) == WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure, + VersionMinInclusive = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive, + VersionMaxInclusive = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive, + ExcludeLanguages = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive, + }; + } + case "Verb": + return DefaultSymbolFromRow(typeof(VerbSymbol), row, columnZeroIsId: false); + case "WixAction": + { + var sequenceTable = FieldAsString(row, 0); + return new WixActionSymbol(SourceLineNumber4(row.SourceLineNumbers)) + { + SequenceTable = (SequenceTable)Enum.Parse(typeof(SequenceTable), sequenceTable == "AdvtExecuteSequence" ? nameof(SequenceTable.AdvertiseExecuteSequence) : sequenceTable), + Action = FieldAsString(row, 1), + Condition = FieldAsString(row, 2), + Sequence = FieldAsNullableInt(row, 3), + Before = FieldAsString(row, 4), + After = FieldAsString(row, 5), + Overridable = FieldAsNullableInt(row, 6) != 0, + }; + } + case "WixBootstrapperApplication": + return DefaultSymbolFromRow(typeof(WixBootstrapperApplicationSymbol), row, columnZeroIsId: true); + case "WixBundleContainer": + return DefaultSymbolFromRow(typeof(WixBundleContainerSymbol), row, columnZeroIsId: true); + case "WixBundleVariable": + return DefaultSymbolFromRow(typeof(WixBundleVariableSymbol), row, columnZeroIsId: true); + case "WixChainItem": + return DefaultSymbolFromRow(typeof(WixChainItemSymbol), row, columnZeroIsId: true); + case "WixCustomTable": + return DefaultSymbolFromRow(typeof(WixCustomTableSymbol), row, columnZeroIsId: true); + case "WixDirectory": + return null; + case "WixFile": + return null; + case "WixInstanceTransforms": + return DefaultSymbolFromRow(typeof(WixInstanceTransformsSymbol), row, columnZeroIsId: true); + case "WixMedia": + return null; + case "WixMerge": + return DefaultSymbolFromRow(typeof(WixMergeSymbol), row, columnZeroIsId: true); + case "WixPatchBaseline": + return DefaultSymbolFromRow(typeof(WixPatchBaselineSymbol), row, columnZeroIsId: true); + case "WixProperty": + { + var attributes = FieldAsInt(row, 1); + return new WixPropertySymbol(SourceLineNumber4(row.SourceLineNumbers)) + { + PropertyRef = FieldAsString(row, 0), + Admin = (attributes & 0x1) == 0x1, + Hidden = (attributes & 0x2) == 0x2, + Secure = (attributes & 0x4) == 0x4, + }; + } + case "WixSuppressModularization": + { + return new WixSuppressModularizationSymbol(SourceLineNumber4(row.SourceLineNumbers)) + { + SuppressIdentifier = FieldAsString(row, 0) + }; + } + case "WixUI": + return DefaultSymbolFromRow(typeof(WixUISymbol), row, columnZeroIsId: true); + case "WixVariable": + return DefaultSymbolFromRow(typeof(WixVariableSymbol), row, columnZeroIsId: true); + default: + return GenericSymbolFromCustomRow(row, columnZeroIsId: false); + } + } + + private static CustomActionTargetType DetermineCustomActionTargetType(int type) + { + var targetType = default(CustomActionTargetType); + + if ((type & WindowsInstallerConstants.MsidbCustomActionTypeVBScript) == WindowsInstallerConstants.MsidbCustomActionTypeVBScript) + { + targetType = CustomActionTargetType.VBScript; + } + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeJScript) == WindowsInstallerConstants.MsidbCustomActionTypeJScript) + { + targetType = CustomActionTargetType.JScript; + } + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeTextData) == WindowsInstallerConstants.MsidbCustomActionTypeTextData) + { + targetType = CustomActionTargetType.TextData; + } + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeExe) == WindowsInstallerConstants.MsidbCustomActionTypeExe) + { + targetType = CustomActionTargetType.Exe; + } + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeDll) == WindowsInstallerConstants.MsidbCustomActionTypeDll) + { + targetType = CustomActionTargetType.Dll; + } + + return targetType; + } + + private static CustomActionSourceType DetermineCustomActionSourceType(int type) + { + var sourceType = CustomActionSourceType.Binary; + + if ((type & WindowsInstallerConstants.MsidbCustomActionTypeProperty) == WindowsInstallerConstants.MsidbCustomActionTypeProperty) + { + sourceType = CustomActionSourceType.Property; + } + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeDirectory) == WindowsInstallerConstants.MsidbCustomActionTypeDirectory) + { + sourceType = CustomActionSourceType.Directory; + } + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeSourceFile) == WindowsInstallerConstants.MsidbCustomActionTypeSourceFile) + { + sourceType = CustomActionSourceType.File; + } + + return sourceType; + } + + private static CustomActionExecutionType DetermineCustomActionExecutionType(int type) + { + var executionType = CustomActionExecutionType.Immediate; + + if ((type & (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit)) == (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit)) + { + executionType = CustomActionExecutionType.Commit; + } + else if ((type & (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback)) == (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback)) + { + executionType = CustomActionExecutionType.Rollback; + } + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeInScript) == WindowsInstallerConstants.MsidbCustomActionTypeInScript) + { + executionType = CustomActionExecutionType.Deferred; + } + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat) == WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat) + { + executionType = CustomActionExecutionType.ClientRepeat; + } + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess) == WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess) + { + executionType = CustomActionExecutionType.OncePerProcess; + } + else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence) == WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence) + { + executionType = CustomActionExecutionType.FirstSequence; + } + + return executionType; + } + + private static IntermediateFieldType ColumnType3ToIntermediateFieldType4(Wix3.ColumnType columnType) + { + switch (columnType) + { + case Wix3.ColumnType.Number: + return IntermediateFieldType.Number; + case Wix3.ColumnType.Object: + return IntermediateFieldType.Path; + case Wix3.ColumnType.Unknown: + case Wix3.ColumnType.String: + case Wix3.ColumnType.Localized: + case Wix3.ColumnType.Preserved: + default: + return IntermediateFieldType.String; + } + } + + private static IntermediateSymbol DefaultSymbolFromRow(Type symbolType, Wix3.Row row, bool columnZeroIsId) + { + var id = columnZeroIsId ? GetIdentifierForRow(row) : null; + + var createSymbol = symbolType.GetConstructor(new[] { typeof(SourceLineNumber), typeof(Identifier) }); + var symbol = (IntermediateSymbol)createSymbol.Invoke(new object[] { SourceLineNumber4(row.SourceLineNumbers), id }); + + SetSymbolFieldsFromRow(row, symbol, columnZeroIsId); + + return symbol; + } + + private static IntermediateSymbol GenericSymbolFromCustomRow(Wix3.Row row, bool columnZeroIsId) + { + var columnDefinitions = row.Table.Definition.Columns.Cast(); + var fieldDefinitions = columnDefinitions.Select(columnDefinition => + new IntermediateFieldDefinition(columnDefinition.Name, ColumnType3ToIntermediateFieldType4(columnDefinition.Type))).ToArray(); + var symbolDefinition = new IntermediateSymbolDefinition(row.Table.Name, fieldDefinitions, null); + + var id = columnZeroIsId ? GetIdentifierForRow(row) : null; + + var createSymbol = typeof(IntermediateSymbol).GetConstructor(new[] { typeof(IntermediateSymbolDefinition), typeof(SourceLineNumber), typeof(Identifier) }); + var symbol = (IntermediateSymbol)createSymbol.Invoke(new object[] { symbolDefinition, SourceLineNumber4(row.SourceLineNumbers), id }); + + SetSymbolFieldsFromRow(row, symbol, columnZeroIsId); + + return symbol; + } + + private static void SetSymbolFieldsFromRow(Wix3.Row row, IntermediateSymbol symbol, bool columnZeroIsId) + { + var offset = 0; + if (columnZeroIsId) + { + offset = 1; + } + + for (var i = offset; i < row.Fields.Length; ++i) + { + var column = row.Fields[i].Column; + switch (column.Type) + { + case Wix3.ColumnType.String: + case Wix3.ColumnType.Localized: + case Wix3.ColumnType.Object: + case Wix3.ColumnType.Preserved: + symbol.Set(i - offset, FieldAsString(row, i)); + break; + case Wix3.ColumnType.Number: + int? nullableValue = FieldAsNullableInt(row, i); + // TODO: Consider whether null values should be coerced to their default value when + // a column is not nullable. For now, just pass through the null. + //int value = FieldAsInt(row, i); + //symbol.Set(i - offset, column.IsNullable ? nullableValue : value); + symbol.Set(i - offset, nullableValue); + break; + case Wix3.ColumnType.Unknown: + break; + } + } + } + + private static Identifier GetIdentifierForRow(Wix3.Row row) + { + var column = row.Fields[0].Column; + switch (column.Type) + { + case Wix3.ColumnType.String: + case Wix3.ColumnType.Localized: + case Wix3.ColumnType.Object: + case Wix3.ColumnType.Preserved: + return new Identifier(AccessModifier.Global, (string)row.Fields[0].Data); + case Wix3.ColumnType.Number: + return new Identifier(AccessModifier.Global, FieldAsInt(row, 0)); + default: + return null; + } + } + + private static SectionType OutputType3ToSectionType4(Wix3.OutputType outputType) + { + switch (outputType) + { + case Wix3.OutputType.Bundle: + return SectionType.Bundle; + case Wix3.OutputType.Module: + return SectionType.Module; + case Wix3.OutputType.Patch: + return SectionType.Patch; + case Wix3.OutputType.PatchCreation: + return SectionType.PatchCreation; + case Wix3.OutputType.Product: + return SectionType.Product; + case Wix3.OutputType.Transform: + case Wix3.OutputType.Unknown: + default: + return SectionType.Unknown; + } + } + + private static SourceLineNumber SourceLineNumber4(Wix3.SourceLineNumberCollection source) + { + return String.IsNullOrEmpty(source?.EncodedSourceLineNumbers) ? null : SourceLineNumber.CreateFromEncoded(source.EncodedSourceLineNumbers); + } + + private static string FieldAsString(Wix3.Row row, int column) + { + return (string)row[column]; + } + + private static int FieldAsInt(Wix3.Row row, int column) + { + return Convert.ToInt32(row[column]); + } + + private static int? FieldAsNullableInt(Wix3.Row row, int column) + { + var field = row.Fields[column]; + if (field.Data == null) + { + return null; + } + else + { + return Convert.ToInt32(field.Data); + } + } + + private static string[] SplitDefaultDir(string defaultDir) + { + var split1 = defaultDir.Split(':'); + var targetSplit = split1.Length > 1 ? split1[1].Split('|') : split1[0].Split('|'); + var sourceSplit = split1.Length > 1 ? split1[0].Split('|') : new[] { String.Empty }; + return new[] + { + targetSplit.Length > 1 ? targetSplit[1] : targetSplit[0], + targetSplit.Length > 1 ? targetSplit[0] : null, + sourceSplit.Length > 1 ? sourceSplit[1] : sourceSplit[0], + sourceSplit.Length > 1 ? sourceSplit[0] : null + }; + } + } +} diff --git a/src/wix/WixToolset.Converters.Symbolizer/WixToolset.Converters.Symbolizer.csproj b/src/wix/WixToolset.Converters.Symbolizer/WixToolset.Converters.Symbolizer.csproj new file mode 100644 index 00000000..445c3500 --- /dev/null +++ b/src/wix/WixToolset.Converters.Symbolizer/WixToolset.Converters.Symbolizer.csproj @@ -0,0 +1,32 @@ + + + + + + + netstandard2.0 + $(TargetFrameworks);net461;net472 + Symbolizer + WiX Toolset Converters Tuplizer + embedded + true + true + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/WixToolset.Converters.sln b/src/wix/WixToolset.Converters.sln new file mode 100644 index 00000000..ae8a3d92 --- /dev/null +++ b/src/wix/WixToolset.Converters.sln @@ -0,0 +1,85 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Converters", "WixToolset.Converters\WixToolset.Converters.csproj", "{6FAF6385-6598-4B89-972B-C31AFCA14538}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolset.Converters.Symbolizer", "WixToolset.Converters.Symbolizer\WixToolset.Converters.Symbolizer.csproj", "{F051BCAF-698C-41D5-8427-164537CE5C5C}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Test", "Test", "{1B16A6C1-2B5D-4F9A-9DD5-FBC89B3CE31E}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.Converters", "test\WixToolsetTest.Converters\WixToolsetTest.Converters.csproj", "{485C5038-97E1-4729-A54D-848CC69569FD}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WixToolsetTest.Converters.Symbolizer", "test\WixToolsetTest.Converters.Symbolizer\WixToolsetTest.Converters.Symbolizer.csproj", "{9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Debug|x64.ActiveCfg = Debug|Any CPU + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Debug|x64.Build.0 = Debug|Any CPU + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Debug|x86.ActiveCfg = Debug|Any CPU + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Debug|x86.Build.0 = Debug|Any CPU + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Release|Any CPU.Build.0 = Release|Any CPU + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Release|x64.ActiveCfg = Release|Any CPU + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Release|x64.Build.0 = Release|Any CPU + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Release|x86.ActiveCfg = Release|Any CPU + {F051BCAF-698C-41D5-8427-164537CE5C5C}.Release|x86.Build.0 = Release|Any CPU + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Debug|x64.ActiveCfg = Debug|Any CPU + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Debug|x64.Build.0 = Debug|Any CPU + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Debug|x86.ActiveCfg = Debug|Any CPU + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Debug|x86.Build.0 = Debug|Any CPU + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Release|Any CPU.Build.0 = Release|Any CPU + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Release|x64.ActiveCfg = Release|Any CPU + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Release|x64.Build.0 = Release|Any CPU + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Release|x86.ActiveCfg = Release|Any CPU + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C}.Release|x86.Build.0 = Release|Any CPU + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Debug|x64.ActiveCfg = Debug|Any CPU + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Debug|x64.Build.0 = Debug|Any CPU + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Debug|x86.ActiveCfg = Debug|Any CPU + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Debug|x86.Build.0 = Debug|Any CPU + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Release|Any CPU.Build.0 = Release|Any CPU + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Release|x64.ActiveCfg = Release|Any CPU + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Release|x64.Build.0 = Release|Any CPU + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Release|x86.ActiveCfg = Release|Any CPU + {6FAF6385-6598-4B89-972B-C31AFCA14538}.Release|x86.Build.0 = Release|Any CPU + {485C5038-97E1-4729-A54D-848CC69569FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {485C5038-97E1-4729-A54D-848CC69569FD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {485C5038-97E1-4729-A54D-848CC69569FD}.Debug|x64.ActiveCfg = Debug|Any CPU + {485C5038-97E1-4729-A54D-848CC69569FD}.Debug|x64.Build.0 = Debug|Any CPU + {485C5038-97E1-4729-A54D-848CC69569FD}.Debug|x86.ActiveCfg = Debug|Any CPU + {485C5038-97E1-4729-A54D-848CC69569FD}.Debug|x86.Build.0 = Debug|Any CPU + {485C5038-97E1-4729-A54D-848CC69569FD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {485C5038-97E1-4729-A54D-848CC69569FD}.Release|Any CPU.Build.0 = Release|Any CPU + {485C5038-97E1-4729-A54D-848CC69569FD}.Release|x64.ActiveCfg = Release|Any CPU + {485C5038-97E1-4729-A54D-848CC69569FD}.Release|x64.Build.0 = Release|Any CPU + {485C5038-97E1-4729-A54D-848CC69569FD}.Release|x86.ActiveCfg = Release|Any CPU + {485C5038-97E1-4729-A54D-848CC69569FD}.Release|x86.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9DB36DB1-24A1-47A7-9E57-D48A2E33C13C} = {1B16A6C1-2B5D-4F9A-9DD5-FBC89B3CE31E} + {485C5038-97E1-4729-A54D-848CC69569FD} = {1B16A6C1-2B5D-4F9A-9DD5-FBC89B3CE31E} + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {2E71F0EC-CF75-44DA-8353-7066EBD06564} + EndGlobalSection +EndGlobal diff --git a/src/wix/WixToolset.Converters.v3.ncrunchsolution b/src/wix/WixToolset.Converters.v3.ncrunchsolution new file mode 100644 index 00000000..f774ab93 --- /dev/null +++ b/src/wix/WixToolset.Converters.v3.ncrunchsolution @@ -0,0 +1,6 @@ + + + False + True + + \ No newline at end of file diff --git a/src/wix/WixToolset.Converters/ConvertCommand.cs b/src/wix/WixToolset.Converters/ConvertCommand.cs new file mode 100644 index 00000000..b6826f43 --- /dev/null +++ b/src/wix/WixToolset.Converters/ConvertCommand.cs @@ -0,0 +1,60 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Converters +{ + using System; + using System.Threading; + using System.Threading.Tasks; + using WixToolset.Extensibility.Services; + + internal class ConvertCommand : FixupCommandBase + { + private const string SettingsFileDefault = "wix.convert.settings.xml"; + + public ConvertCommand(IServiceProvider serviceProvider) + { + this.Messaging = serviceProvider.GetService(); + } + + private IMessaging Messaging { get; } + + public override Task ExecuteAsync(CancellationToken cancellationToken) + { + if (this.ShowHelp) + { + DisplayHelp(); + return Task.FromResult(-1); + } + + this.ParseSettings(SettingsFileDefault); + + var converter = new WixConverter(this.Messaging, this.IndentationAmount, this.ErrorsAsWarnings, this.IgnoreErrors); + + var errors = base.Inspect(Inspector, cancellationToken); + + return Task.FromResult(errors); + + int Inspector(string file, bool fix) + { + return converter.ConvertFile(file, fix); + } + } + + private static void DisplayHelp() + { + Console.WriteLine(); + Console.WriteLine("Usage: wix convert [options] sourceFile [sourceFile ...]"); + Console.WriteLine(); + Console.WriteLine("Options:"); + Console.WriteLine(" -h|--help Show command line help."); + Console.WriteLine(" --nologo Suppress displaying the logo information."); + Console.WriteLine(" -n|--dry-run Only display errors, do not update files."); + Console.WriteLine(" -r|--recurse Search for matching files in current dir and subdirs."); + Console.WriteLine(" -set1 Primary settings file."); + Console.WriteLine(" -set2 Secondary settings file (overrides primary)."); + Console.WriteLine(" -indent: Indentation multiple (overrides default of 4)."); + Console.WriteLine(); + Console.WriteLine(" sourceFile may use wildcards like *.wxs"); + } + } +} diff --git a/src/wix/WixToolset.Converters/ConverterExtensionCommandLine.cs b/src/wix/WixToolset.Converters/ConverterExtensionCommandLine.cs new file mode 100644 index 00000000..06d3658c --- /dev/null +++ b/src/wix/WixToolset.Converters/ConverterExtensionCommandLine.cs @@ -0,0 +1,46 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Converters +{ + using System; + using System.Collections.Generic; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Data; + using WixToolset.Extensibility.Services; + + /// + /// Parses the "convert" command-line command. See ConvertCommand for + /// the bulk of the command-line processing. + /// + internal class ConverterExtensionCommandLine : BaseExtensionCommandLine + { + public ConverterExtensionCommandLine(IServiceProvider serviceProvider) + { + this.ServiceProvider = serviceProvider; + } + + private IServiceProvider ServiceProvider { get; } + + public override IReadOnlyCollection CommandLineSwitches => new ExtensionCommandLineSwitch[] + { + new ExtensionCommandLineSwitch { Switch = "convert", Description = "Convert v3 source code to v4 source code." }, + new ExtensionCommandLineSwitch { Switch = "format", Description = "Ensures consistent formatting of source code." }, + }; + + public override bool TryParseCommand(ICommandLineParser parser, string argument, out ICommandLineCommand command) + { + command = null; + + if ("convert".Equals(argument, StringComparison.OrdinalIgnoreCase)) + { + command = new ConvertCommand(this.ServiceProvider); + } + else if ("format".Equals(argument, StringComparison.OrdinalIgnoreCase)) + { + command = new FormatCommand(this.ServiceProvider); + } + + return command != null; + } + } +} diff --git a/src/wix/WixToolset.Converters/ConverterExtensionFactory.cs b/src/wix/WixToolset.Converters/ConverterExtensionFactory.cs new file mode 100644 index 00000000..d4f480aa --- /dev/null +++ b/src/wix/WixToolset.Converters/ConverterExtensionFactory.cs @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Converters +{ + using System; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Services; + + internal class ConverterExtensionFactory : IExtensionFactory + { + public ConverterExtensionFactory(IServiceProvider serviceProvider) + { + this.ServiceProvider = serviceProvider; + } + + private IServiceProvider ServiceProvider { get; } + + public bool TryCreateExtension(Type extensionType, out object extension) + { + extension = null; + + if (extensionType == typeof(IExtensionCommandLine)) + { + extension = new ConverterExtensionCommandLine(this.ServiceProvider); + } + + return extension != null; + } + } +} diff --git a/src/wix/WixToolset.Converters/FixupCommandBase.cs b/src/wix/WixToolset.Converters/FixupCommandBase.cs new file mode 100644 index 00000000..21282d07 --- /dev/null +++ b/src/wix/WixToolset.Converters/FixupCommandBase.cs @@ -0,0 +1,288 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Converters +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Threading; + using System.Threading.Tasks; + using System.Xml; + using WixToolset.Extensibility.Data; + using WixToolset.Extensibility.Services; + + internal abstract class FixupCommandBase : ICommandLineCommand + { + protected FixupCommandBase() + { + this.IndentationAmount = 4; // default indentation amount + this.ErrorsAsWarnings = new HashSet(); + this.ExemptFiles = new HashSet(); + this.IgnoreErrors = new HashSet(); + this.SearchPatternResults = new HashSet(); + this.SearchPatterns = new List(); + } + + public bool ShowLogo { get; private set; } + + public bool StopParsing { get; private set; } + + protected bool ShowHelp { get; set; } + + protected CustomTableTarget CustomTableSetting { get; set; } + + protected bool DryRun { get; set; } + + protected HashSet ErrorsAsWarnings { get; } + + protected HashSet IgnoreErrors { get; } + + protected HashSet ExemptFiles { get; } + + protected int IndentationAmount { get; set; } + + protected bool Recurse { get; set; } + + private HashSet SearchPatternResults { get; } + + private List SearchPatterns { get; } + + private string SettingsFile1 { get; set; } + + private string SettingsFile2 { get; set; } + + public bool TryParseArgument(ICommandLineParser parser, string argument) + { + if (!parser.IsSwitch(argument)) + { + this.SearchPatterns.Add(argument); + return true; + } + + var parameter = argument.Substring(1); + switch (parameter.ToLowerInvariant()) + { + case "?": + case "h": + case "-help": + this.ShowHelp = true; + this.ShowLogo = true; + this.StopParsing = true; + return true; + + case "-custom-table": + var customTableSetting = parser.GetNextArgumentOrError(argument); + switch (customTableSetting) + { + case "bundle": + this.CustomTableSetting = CustomTableTarget.Bundle; + break; + case "msi": + this.CustomTableSetting = CustomTableTarget.Msi; + break; + default: + parser.ReportErrorArgument(argument); + break; + } + return true; + + case "n": + case "-dry-run": + this.DryRun = true; + return true; + + case "nologo": + case "-nologo": + this.ShowLogo = false; + return true; + + case "s": + case "r": + case "-recurse": + case "-recursive": + this.Recurse = true; + return true; + + default: // other parameters + if (parameter.StartsWith("set1", StringComparison.Ordinal)) + { + this.SettingsFile1 = parameter.Substring(4); + return true; + } + else if (parameter.StartsWith("set2", StringComparison.Ordinal)) + { + this.SettingsFile2 = parameter.Substring(4); + return true; + } + else if (parameter.StartsWith("indent:", StringComparison.Ordinal)) + { + try + { + this.IndentationAmount = Convert.ToInt32(parameter.Substring(7)); + } + catch + { + parser.ReportErrorArgument(parameter); // $"Invalid numeric argument: {parameter}"; + } + return true; + } + + return false; + } + } + + public abstract Task ExecuteAsync(CancellationToken cancellationToken); + + protected void ParseSettings(string defaultSettingsFile) + { + // parse the settings if any were specified + if (null != this.SettingsFile1 || null != this.SettingsFile2) + { + this.ParseSettingsFiles(this.SettingsFile1, this.SettingsFile2); + } + else + { + if (File.Exists(defaultSettingsFile)) + { + this.ParseSettingsFiles(defaultSettingsFile, null); + } + } + } + + protected int Inspect(Func inspector, CancellationToken cancellationToken) + { + var errors = this.InspectSubDirectories(inspector, Path.GetFullPath("."), cancellationToken); + + foreach (var searchPattern in this.SearchPatterns) + { + if (!this.SearchPatternResults.Contains(searchPattern)) + { + Console.Error.WriteLine("Could not find file \"{0}\"", searchPattern); + errors++; + } + } + + return errors; + } + + /// + /// Inspect sub-directories. + /// + /// + /// The directory whose sub-directories will be inspected. + /// + /// The number of errors that were found. + private int InspectSubDirectories(Func inspector, string directory, CancellationToken cancellationToken) + { + var errors = 0; + + foreach (var searchPattern in this.SearchPatterns) + { + foreach (var sourceFilePath in GetFiles(directory, searchPattern)) + { + cancellationToken.ThrowIfCancellationRequested(); + + var file = new FileInfo(sourceFilePath); + + if (!this.ExemptFiles.Contains(file.Name.ToUpperInvariant())) + { + this.SearchPatternResults.Add(searchPattern); + errors += inspector(file.FullName, !this.DryRun); + } + } + } + + if (this.Recurse) + { + foreach (var childDirectoryPath in Directory.GetDirectories(directory)) + { + errors += this.InspectSubDirectories(inspector, childDirectoryPath, cancellationToken); + } + } + + return errors; + } + + /// + /// Parse the primary and secondary settings files. + /// + /// The primary settings file. + /// The secondary settings file. + private void ParseSettingsFiles(string localSettingsFile1, string localSettingsFile2) + { + if (null == localSettingsFile1 && null != localSettingsFile2) + { + throw new ArgumentException("Cannot specify a secondary settings file (set2) without a primary settings file (set1).", nameof(localSettingsFile2)); + } + + var settingsFile = localSettingsFile1; + while (null != settingsFile) + { + var doc = new XmlDocument(); + doc.Load(settingsFile); + + // get the types of tests that will have their errors displayed as warnings + var testsIgnoredElements = doc.SelectNodes("/Settings/IgnoreErrors/Test"); + foreach (XmlElement test in testsIgnoredElements) + { + var key = test.GetAttribute("Id"); + this.IgnoreErrors.Add(key); + } + + // get the types of tests that will have their errors displayed as warnings + var testsAsWarningsElements = doc.SelectNodes("/Settings/ErrorsAsWarnings/Test"); + foreach (XmlElement test in testsAsWarningsElements) + { + var key = test.GetAttribute("Id"); + this.ErrorsAsWarnings.Add(key); + } + + // get the exempt files + var localExemptFiles = doc.SelectNodes("/Settings/ExemptFiles/File"); + foreach (XmlElement file in localExemptFiles) + { + var key = file.GetAttribute("Name").ToUpperInvariant(); + this.ExemptFiles.Add(key); + } + + settingsFile = localSettingsFile2; + localSettingsFile2 = null; + } + } + + /// + /// Get the files that match a search path pattern. + /// + /// The base directory at which to begin the search. + /// The search path pattern. + /// The files matching the pattern. + private static string[] GetFiles(string baseDir, string searchPath) + { + // convert alternate directory separators to the standard one + var filePath = searchPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + var lastSeparator = filePath.LastIndexOf(Path.DirectorySeparatorChar); + string[] files = null; + + try + { + if (0 > lastSeparator) + { + files = Directory.GetFiles(baseDir, filePath); + } + else // found directory separator + { + var searchPattern = filePath.Substring(lastSeparator + 1); + + files = Directory.GetFiles(filePath.Substring(0, lastSeparator + 1), searchPattern); + } + } + catch (DirectoryNotFoundException) + { + // don't let this function throw the DirectoryNotFoundException. (this exception + // occurs for non-existant directories and invalid characters in the searchPattern) + } + + return files; + } + } +} diff --git a/src/wix/WixToolset.Converters/FormatCommand.cs b/src/wix/WixToolset.Converters/FormatCommand.cs new file mode 100644 index 00000000..0861fc51 --- /dev/null +++ b/src/wix/WixToolset.Converters/FormatCommand.cs @@ -0,0 +1,60 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Converters +{ + using System; + using System.Threading; + using System.Threading.Tasks; + using WixToolset.Extensibility.Services; + + internal class FormatCommand : FixupCommandBase + { + private const string SettingsFileDefault = "wix.format.settings.xml"; + + public FormatCommand(IServiceProvider serviceProvider) + { + this.Messaging = serviceProvider.GetService(); + } + + private IMessaging Messaging { get; } + + public override Task ExecuteAsync(CancellationToken cancellationToken) + { + if (this.ShowHelp) + { + DisplayHelp(); + return Task.FromResult(-1); + } + + var converter = new WixConverter(this.Messaging, this.IndentationAmount, this.ErrorsAsWarnings, this.IgnoreErrors); + + this.ParseSettings(SettingsFileDefault); + + var errors = base.Inspect(Inspector, cancellationToken); + + return Task.FromResult(errors); + + int Inspector(string file, bool fix) + { + return converter.FormatFile(file, fix); + } + } + + private static void DisplayHelp() + { + Console.WriteLine(); + Console.WriteLine("Usage: wix format [options] sourceFile [sourceFile ...]"); + Console.WriteLine(); + Console.WriteLine("Options:"); + Console.WriteLine(" -h|--help Show command line help."); + Console.WriteLine(" --nologo Suppress displaying the logo information."); + Console.WriteLine(" -n|--dry-run Only display errors, do not update files."); + Console.WriteLine(" -r|--recurse Search for matching files in current dir and subdirs."); + Console.WriteLine(" -set1 Primary settings file."); + Console.WriteLine(" -set2 Secondary settings file (overrides primary)."); + Console.WriteLine(" -indent: Indentation multiple (overrides default of 4)."); + Console.WriteLine(); + Console.WriteLine(" sourceFile may use wildcards like *.wxs"); + } + } +} diff --git a/src/wix/WixToolset.Converters/WixConverter.cs b/src/wix/WixToolset.Converters/WixConverter.cs new file mode 100644 index 00000000..e42d0605 --- /dev/null +++ b/src/wix/WixToolset.Converters/WixConverter.cs @@ -0,0 +1,2435 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Converters +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.IO; + using System.Linq; + using System.Text; + using System.Text.RegularExpressions; + using System.Xml; + using System.Xml.Linq; + using WixToolset.Data; + using WixToolset.Data.WindowsInstaller; + using WixToolset.Extensibility.Services; + + /// + /// How to convert CustomTable elements. + /// + public enum CustomTableTarget + { + /// + /// Ambiguous elements will be left alone. + /// + Unknown, + + /// + /// Use CustomTable, CustomTableRef, and Unreal. + /// + Msi, + + /// + /// Use BundleCustomData and BundleCustomDataRef. + /// + Bundle, + } + + /// + /// WiX source code converter. + /// + public sealed class WixConverter + { + private enum ConvertOperation + { + Convert, + Format, + } + + private static readonly Regex AddPrefix = new Regex(@"^[^a-zA-Z_]", RegexOptions.Compiled); + private static readonly Regex IllegalIdentifierCharacters = new Regex(@"[^A-Za-z0-9_\.]|\.{2,}", RegexOptions.Compiled); // non 'words' and assorted valid characters + + private const char XDocumentNewLine = '\n'; // XDocument normalizes "\r\n" to just "\n". + private static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs"; + private static readonly XNamespace Wix3Namespace = "http://schemas.microsoft.com/wix/2006/wi"; + private static readonly XNamespace WixBalNamespace = "http://wixtoolset.org/schemas/v4/wxs/bal"; + private static readonly XNamespace WixDependencyNamespace = "http://wixtoolset.org/schemas/v4/wxs/dependency"; + private static readonly XNamespace WixUtilNamespace = "http://wixtoolset.org/schemas/v4/wxs/util"; + private static readonly XNamespace WixFirewallNamespace = "http://wixtoolset.org/schemas/v4/wxs/firewall"; + + private static readonly XName AdminExecuteSequenceElementName = WixNamespace + "AdminExecuteSequence"; + private static readonly XName AdminUISequenceSequenceElementName = WixNamespace + "AdminUISequence"; + private static readonly XName AdvertiseExecuteSequenceElementName = WixNamespace + "AdvertiseExecuteSequence"; + private static readonly XName InstallExecuteSequenceElementName = WixNamespace + "InstallExecuteSequence"; + private static readonly XName InstallUISequenceSequenceElementName = WixNamespace + "InstallUISequence"; + private static readonly XName BootstrapperApplicationElementName = WixNamespace + "BootstrapperApplication"; + private static readonly XName BootstrapperApplicationDllElementName = WixNamespace + "BootstrapperApplicationDll"; + private static readonly XName BootstrapperApplicationRefElementName = WixNamespace + "BootstrapperApplicationRef"; + private static readonly XName ApprovedExeForElevationElementName = WixNamespace + "ApprovedExeForElevation"; + private static readonly XName BundleAttributeElementName = WixNamespace + "BundleAttribute"; + private static readonly XName BundleAttributeDefinitionElementName = WixNamespace + "BundleAttributeDefinition"; + private static readonly XName BundleCustomDataElementName = WixNamespace + "BundleCustomData"; + private static readonly XName BundleCustomDataRefElementName = WixNamespace + "BundleCustomDataRef"; + private static readonly XName BundleElementElementName = WixNamespace + "BundleElement"; + private static readonly XName CustomTableElementName = WixNamespace + "CustomTable"; + private static readonly XName CustomTableRefElementName = WixNamespace + "CustomTableRef"; + private static readonly XName CatalogElementName = WixNamespace + "Catalog"; + private static readonly XName ColumnElementName = WixNamespace + "Column"; + private static readonly XName ComponentElementName = WixNamespace + "Component"; + private static readonly XName ControlElementName = WixNamespace + "Control"; + private static readonly XName ConditionElementName = WixNamespace + "Condition"; + private static readonly XName CreateFolderElementName = WixNamespace + "CreateFolder"; + private static readonly XName DataElementName = WixNamespace + "Data"; + private static readonly XName OldProvidesElementName = WixDependencyNamespace + "Provides"; + private static readonly XName OldRequiresElementName = WixDependencyNamespace + "Requires"; + private static readonly XName OldRequiresRefElementName = WixDependencyNamespace + "RequiresRef"; + private static readonly XName DirectoryElementName = WixNamespace + "Directory"; + private static readonly XName EmbeddedChainerElementName = WixNamespace + "EmbeddedChainer"; + private static readonly XName ErrorElementName = WixNamespace + "Error"; + private static readonly XName FeatureElementName = WixNamespace + "Feature"; + private static readonly XName FileElementName = WixNamespace + "File"; + private static readonly XName FragmentElementName = WixNamespace + "Fragment"; + private static readonly XName FirewallRemoteAddressElementName = WixFirewallNamespace + "RemoteAddress"; + private static readonly XName LaunchElementName = WixNamespace + "Launch"; + private static readonly XName LevelElementName = WixNamespace + "Level"; + private static readonly XName ExePackageElementName = WixNamespace + "ExePackage"; + private static readonly XName ExePackagePayloadElementName = WixNamespace + "ExePackagePayload"; + private static readonly XName ModuleElementName = WixNamespace + "Module"; + private static readonly XName MsiPackageElementName = WixNamespace + "MsiPackage"; + private static readonly XName MspPackageElementName = WixNamespace + "MspPackage"; + private static readonly XName MsuPackageElementName = WixNamespace + "MsuPackage"; + private static readonly XName MsuPackagePayloadElementName = WixNamespace + "MsuPackagePayload"; + private static readonly XName PackageElementName = WixNamespace + "Package"; + private static readonly XName PayloadElementName = WixNamespace + "Payload"; + private static readonly XName PermissionExElementName = WixNamespace + "PermissionEx"; + private static readonly XName ProductElementName = WixNamespace + "Product"; + private static readonly XName ProgressTextElementName = WixNamespace + "ProgressText"; + private static readonly XName PropertyRefElementName = WixNamespace + "PropertyRef"; + private static readonly XName PublishElementName = WixNamespace + "Publish"; + private static readonly XName ProvidesElementName = WixNamespace + "Provides"; + private static readonly XName RequiresElementName = WixNamespace + "Requires"; + private static readonly XName RequiresRefElementName = WixNamespace + "RequiresRef"; + private static readonly XName MultiStringValueElementName = WixNamespace + "MultiStringValue"; + private static readonly XName RemotePayloadElementName = WixNamespace + "RemotePayload"; + private static readonly XName RegistryKeyElementName = WixNamespace + "RegistryKey"; + private static readonly XName RegistrySearchElementName = WixNamespace + "RegistrySearch"; + private static readonly XName RequiredPrivilegeElementName = WixNamespace + "RequiredPrivilege"; + private static readonly XName RowElementName = WixNamespace + "Row"; + private static readonly XName ServiceArgumentElementName = WixNamespace + "ServiceArgument"; + private static readonly XName SetDirectoryElementName = WixNamespace + "SetDirectory"; + private static readonly XName SetPropertyElementName = WixNamespace + "SetProperty"; + private static readonly XName ShortcutPropertyElementName = WixNamespace + "ShortcutProperty"; + private static readonly XName SoftwareTagElementName = WixNamespace + "SoftwareTag"; + private static readonly XName SoftwareTagRefElementName = WixNamespace + "SoftwareTagRef"; + private static readonly XName StandardDirectoryElementName = WixNamespace + "StandardDirectory"; + private static readonly XName TagElementName = XNamespace.None + "Tag"; + private static readonly XName TagRefElementName = XNamespace.None + "TagRef"; + private static readonly XName TextElementName = WixNamespace + "Text"; + private static readonly XName UITextElementName = WixNamespace + "UIText"; + private static readonly XName VariableElementName = WixNamespace + "Variable"; + private static readonly XName VerbElementName = WixNamespace + "Verb"; + private static readonly XName BalUseUILanguagesName = WixBalNamespace + "UseUILanguages"; + private static readonly XName BalStandardBootstrapperApplicationName = WixBalNamespace + "WixStandardBootstrapperApplication"; + private static readonly XName BalManagedBootstrapperApplicationHostName = WixBalNamespace + "WixManagedBootstrapperApplicationHost"; + private static readonly XName BalOldDotNetCoreBootstrapperApplicationName = WixBalNamespace + "WixDotNetCoreBootstrapperApplication"; + private static readonly XName BalNewDotNetCoreBootstrapperApplicationName = WixBalNamespace + "WixDotNetCoreBootstrapperApplicationHost"; + private static readonly XName UtilCloseApplicationElementName = WixUtilNamespace + "CloseApplication"; + private static readonly XName UtilPermissionExElementName = WixUtilNamespace + "PermissionEx"; + private static readonly XName UtilRegistrySearchName = WixUtilNamespace + "RegistrySearch"; + private static readonly XName UtilXmlConfigElementName = WixUtilNamespace + "XmlConfig"; + private static readonly XName CustomActionElementName = WixNamespace + "CustomAction"; + private static readonly XName CustomActionRefElementName = WixNamespace + "CustomActionRef"; + private static readonly XName PropertyElementName = WixNamespace + "Property"; + private static readonly XName Wix4ElementName = WixNamespace + "Wix"; + private static readonly XName Wix3ElementName = Wix3Namespace + "Wix"; + private static readonly XName WixElementWithoutNamespaceName = XNamespace.None + "Wix"; + private static readonly XName Include4ElementName = WixNamespace + "Include"; + private static readonly XName Include3ElementName = Wix3Namespace + "Include"; + private static readonly XName IncludeElementWithoutNamespaceName = XNamespace.None + "Include"; + private static readonly XName SummaryInformationElementName = WixNamespace + "SummaryInformation"; + private static readonly XName MediaTemplateElementName = WixNamespace + "MediaTemplate"; + + private static readonly XName DependencyCheckAttributeName = WixDependencyNamespace + "Check"; + private static readonly XName DependencyEnforceAttributeName = WixDependencyNamespace + "Enforce"; + + private static readonly Dictionary OldToNewNamespaceMapping = new Dictionary() + { + { "http://schemas.microsoft.com/wix/BalExtension", "http://wixtoolset.org/schemas/v4/wxs/bal" }, + { "http://schemas.microsoft.com/wix/ComPlusExtension", "http://wixtoolset.org/schemas/v4/wxs/complus" }, + { "http://schemas.microsoft.com/wix/DependencyExtension", WixDependencyNamespace }, + { "http://schemas.microsoft.com/wix/DifxAppExtension", "http://wixtoolset.org/schemas/v4/wxs/difxapp" }, + { "http://schemas.microsoft.com/wix/FirewallExtension", "http://wixtoolset.org/schemas/v4/wxs/firewall" }, + { "http://schemas.microsoft.com/wix/HttpExtension", "http://wixtoolset.org/schemas/v4/wxs/http" }, + { "http://schemas.microsoft.com/wix/IIsExtension", "http://wixtoolset.org/schemas/v4/wxs/iis" }, + { "http://schemas.microsoft.com/wix/MsmqExtension", "http://wixtoolset.org/schemas/v4/wxs/msmq" }, + { "http://schemas.microsoft.com/wix/NetFxExtension", "http://wixtoolset.org/schemas/v4/wxs/netfx" }, + { "http://schemas.microsoft.com/wix/PSExtension", "http://wixtoolset.org/schemas/v4/wxs/powershell" }, + { "http://schemas.microsoft.com/wix/SqlExtension", "http://wixtoolset.org/schemas/v4/wxs/sql" }, + { "http://schemas.microsoft.com/wix/TagExtension", XNamespace.None }, + { "http://schemas.microsoft.com/wix/UtilExtension", WixUtilNamespace }, + { "http://schemas.microsoft.com/wix/VSExtension", "http://wixtoolset.org/schemas/v4/wxs/vs" }, + { "http://wixtoolset.org/schemas/thmutil/2010", "http://wixtoolset.org/schemas/v4/thmutil" }, + { "http://schemas.microsoft.com/wix/2009/Lux", "http://wixtoolset.org/schemas/v4/lux" }, + { "http://schemas.microsoft.com/wix/2006/wi", "http://wixtoolset.org/schemas/v4/wxs" }, + { "http://schemas.microsoft.com/wix/2006/localization", "http://wixtoolset.org/schemas/v4/wxl" }, + { "http://schemas.microsoft.com/wix/2006/libraries", "http://wixtoolset.org/schemas/v4/wixlib" }, + { "http://schemas.microsoft.com/wix/2006/objects", "http://wixtoolset.org/schemas/v4/wixobj" }, + { "http://schemas.microsoft.com/wix/2006/outputs", "http://wixtoolset.org/schemas/v4/wixout" }, + { "http://schemas.microsoft.com/wix/2007/pdbs", "http://wixtoolset.org/schemas/v4/wixpdb" }, + { "http://schemas.microsoft.com/wix/2003/04/actions", "http://wixtoolset.org/schemas/v4/wi/actions" }, + { "http://schemas.microsoft.com/wix/2006/tables", "http://wixtoolset.org/schemas/v4/wi/tables" }, + { "http://schemas.microsoft.com/wix/2006/WixUnit", "http://wixtoolset.org/schemas/v4/wixunit" }, + }; + + private readonly Dictionary> ConvertElementMapping; + private readonly Regex DeprecatedPrefixRegex = new Regex(@"(?<=(^|[^\$])(\$\$)*)\$(?=\(loc\.[^.].*\))", + RegexOptions.Compiled | RegexOptions.CultureInvariant | RegexOptions.ExplicitCapture); + + /// + /// Instantiate a new Converter class. + /// + /// + /// Indentation value to use when validating leading whitespace. + /// Test errors to display as warnings. + /// Test errors to ignore. + /// How to convert CustomTable elements. + public WixConverter(IMessaging messaging, int indentationAmount, IEnumerable errorsAsWarnings = null, IEnumerable ignoreErrors = null, CustomTableTarget customTableTarget = CustomTableTarget.Unknown) + { + this.ConvertElementMapping = new Dictionary> + { + { WixConverter.AdminExecuteSequenceElementName, this.ConvertSequenceElement }, + { WixConverter.AdminUISequenceSequenceElementName, this.ConvertSequenceElement }, + { WixConverter.AdvertiseExecuteSequenceElementName, this.ConvertSequenceElement }, + { WixConverter.InstallUISequenceSequenceElementName, this.ConvertSequenceElement }, + { WixConverter.InstallExecuteSequenceElementName, this.ConvertSequenceElement }, + { WixConverter.BootstrapperApplicationElementName, this.ConvertBootstrapperApplicationElement }, + { WixConverter.BootstrapperApplicationRefElementName, this.ConvertBootstrapperApplicationRefElement }, + { WixConverter.ApprovedExeForElevationElementName, this.ConvertApprovedExeForElevationElement }, + { WixConverter.CatalogElementName, this.ConvertCatalogElement }, + { WixConverter.ColumnElementName, this.ConvertColumnElement }, + { WixConverter.ComponentElementName, this.ConvertComponentElement }, + { WixConverter.ControlElementName, this.ConvertControlElement }, + { WixConverter.CustomActionElementName, this.ConvertCustomActionElement }, + { WixConverter.CustomTableElementName, this.ConvertCustomTableElement }, + { WixConverter.DataElementName, this.ConvertDataElement }, + { WixConverter.DirectoryElementName, this.ConvertDirectoryElement }, + { WixConverter.FeatureElementName, this.ConvertFeatureElement }, + { WixConverter.FileElementName, this.ConvertFileElement }, + { WixConverter.FragmentElementName, this.ConvertFragmentElement }, + { WixConverter.FirewallRemoteAddressElementName, this.ConvertFirewallRemoteAddressElement }, + { WixConverter.EmbeddedChainerElementName, this.ConvertEmbeddedChainerElement }, + { WixConverter.ErrorElementName, this.ConvertErrorElement }, + { WixConverter.ExePackageElementName, this.ConvertExePackageElement }, + { WixConverter.ModuleElementName, this.ConvertModuleElement }, + { WixConverter.MsiPackageElementName, this.ConvertWindowsInstallerPackageElement }, + { WixConverter.MspPackageElementName, this.ConvertWindowsInstallerPackageElement }, + { WixConverter.MsuPackageElementName, this.ConvertSuppressSignatureValidation }, + { WixConverter.OldProvidesElementName, this.ConvertProvidesElement }, + { WixConverter.OldRequiresElementName, this.ConvertRequiresElement }, + { WixConverter.OldRequiresRefElementName, this.ConvertRequiresRefElement }, + { WixConverter.PayloadElementName, this.ConvertSuppressSignatureValidation }, + { WixConverter.PermissionExElementName, this.ConvertPermissionExElement }, + { WixConverter.ProductElementName, this.ConvertProductElement }, + { WixConverter.ProgressTextElementName, this.ConvertProgressTextElement }, + { WixConverter.PropertyRefElementName, this.ConvertPropertyRefElement }, + { WixConverter.PublishElementName, this.ConvertPublishElement }, + { WixConverter.MultiStringValueElementName, this.ConvertMultiStringValueElement }, + { WixConverter.RegistryKeyElementName, this.ConvertRegistryKeyElement }, + { WixConverter.RegistrySearchElementName, this.ConvertRegistrySearchElement }, + { WixConverter.RemotePayloadElementName, this.ConvertRemotePayloadElement }, + { WixConverter.RequiredPrivilegeElementName, this.ConvertRequiredPrivilegeElement }, + { WixConverter.CustomActionRefElementName, this.ConvertCustomActionRefElement }, + { WixConverter.ServiceArgumentElementName, this.ConvertServiceArgumentElement }, + { WixConverter.SetDirectoryElementName, this.ConvertSetDirectoryElement }, + { WixConverter.SetPropertyElementName, this.ConvertSetPropertyElement }, + { WixConverter.ShortcutPropertyElementName, this.ConvertShortcutPropertyElement }, + { WixConverter.TagElementName, this.ConvertTagElement }, + { WixConverter.TagRefElementName, this.ConvertTagRefElement }, + { WixConverter.TextElementName, this.ConvertTextElement }, + { WixConverter.UITextElementName, this.ConvertUITextElement }, + { WixConverter.VariableElementName, this.ConvertVariableElement }, + { WixConverter.UtilCloseApplicationElementName, this.ConvertUtilCloseApplicationElementName }, + { WixConverter.UtilPermissionExElementName, this.ConvertUtilPermissionExElement }, + { WixConverter.UtilRegistrySearchName, this.ConvertUtilRegistrySearchElement }, + { WixConverter.UtilXmlConfigElementName, this.ConvertUtilXmlConfigElement }, + { WixConverter.PropertyElementName, this.ConvertPropertyElement }, + { WixConverter.WixElementWithoutNamespaceName, this.ConvertElementWithoutNamespace }, + { WixConverter.IncludeElementWithoutNamespaceName, this.ConvertElementWithoutNamespace }, + { WixConverter.VerbElementName, this.ConvertVerbElement }, + }; + + this.Messaging = messaging; + + this.IndentationAmount = indentationAmount; + + this.ErrorsAsWarnings = new HashSet(this.YieldConverterTypes(errorsAsWarnings)); + + this.IgnoreErrors = new HashSet(this.YieldConverterTypes(ignoreErrors)); + + this.CustomTableSetting = customTableTarget; + } + + private CustomTableTarget CustomTableSetting { get; } + + private int Errors { get; set; } + + private HashSet ErrorsAsWarnings { get; set; } + + private HashSet IgnoreErrors { get; set; } + + private IMessaging Messaging { get; } + + private int IndentationAmount { get; set; } + + private ConvertOperation Operation { get; set; } + + private string SourceFile { get; set; } + + private int SourceVersion { get; set; } + + /// + /// Convert a file. + /// + /// The file to convert. + /// Option to save the converted errors that are found. + /// The number of errors found. + public int ConvertFile(string sourceFile, bool saveConvertedFile) + { + var document = this.OpenSourceFile(sourceFile); + + if (document is null) + { + return 1; + } + + this.ConvertDocument(document); + + // Fix errors if requested and necessary. + if (saveConvertedFile && 0 < this.Errors) + { + this.SaveDocument(document); + } + + return this.Errors; + } + + /// + /// Convert a document. + /// + /// The document to convert. + /// The number of errors found. + public int ConvertDocument(XDocument document) + { + // Reset the instance info. + this.Errors = 0; + this.SourceVersion = 0; + this.Operation = ConvertOperation.Convert; + + // Remove the declaration. + if (null != document.Declaration + && this.OnError(ConverterTestType.DeclarationPresent, null, "This file contains an XML declaration on the first line.")) + { + document.Declaration = null; + TrimLeadingText(document); + } + + // Start converting the nodes at the top. + this.ConvertNodes(document.Nodes(), 0); + this.RemoveUnusedNamespaces(document.Root); + + return this.Errors; + } + + /// + /// Format a file. + /// + /// The file to format. + /// Option to save the format errors that are found. + /// The number of errors found. + public int FormatFile(string sourceFile, bool saveConvertedFile) + { + var document = this.OpenSourceFile(sourceFile); + + if (document is null) + { + return 1; + } + + this.FormatDocument(document); + + // Fix errors if requested and necessary. + if (saveConvertedFile && 0 < this.Errors) + { + this.SaveDocument(document); + } + + return this.Errors; + } + + /// + /// Format a document. + /// + /// The document to format. + /// The number of errors found. + public int FormatDocument(XDocument document) + { + // Reset the instance info. + this.Errors = 0; + this.SourceVersion = 0; + this.Operation = ConvertOperation.Format; + + // Remove the declaration. + if (null != document.Declaration + && this.OnError(ConverterTestType.DeclarationPresent, null, "This file contains an XML declaration on the first line.")) + { + document.Declaration = null; + TrimLeadingText(document); + } + + // Start converting the nodes at the top. + this.ConvertNodes(document.Nodes(), 0); + this.RemoveUnusedNamespaces(document.Root); + + return this.Errors; + } + + private XDocument OpenSourceFile(string sourceFile) + { + this.SourceFile = sourceFile; + + try + { + return XDocument.Load(this.SourceFile, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + } + catch (XmlException e) + { + this.OnError(ConverterTestType.XmlException, null, "The xml is invalid. Detail: '{0}'", e.Message); + } + + return null; + } + + private void SaveDocument(XDocument document) + { + var ignoreDeclarationError = this.IgnoreErrors.Contains(ConverterTestType.DeclarationPresent); + + try + { + using (var writer = XmlWriter.Create(this.SourceFile, new XmlWriterSettings { OmitXmlDeclaration = !ignoreDeclarationError })) + { + document.Save(writer); + } + } + catch (UnauthorizedAccessException) + { + this.OnError(ConverterTestType.UnauthorizedAccessException, null, "Could not write to file."); + } + } + + private void ConvertNodes(IEnumerable nodes, int level) + { + // Note we operate on a copy of the node list since we may + // remove some whitespace nodes during this processing. + foreach (var node in nodes.ToList()) + { + if (node is XText text) + { + if (null != text.Value) + { + if (this.TryFixDeprecatedLocalizationPrefixes(node, text.Value, out var newValue, ConverterTestType.DeprecatedLocalizationVariablePrefixInTextValue)) + { + text.Value = newValue; + } + } + if (!String.IsNullOrWhiteSpace(text.Value)) + { + text.Value = text.Value.Trim(); + } + else if (node.NextNode is XCData cdata) + { + this.EnsurePrecedingWhitespaceRemoved(text, node, ConverterTestType.WhitespacePrecedingNodeWrong); + } + else if (node.NextNode is XElement element) + { + this.EnsurePrecedingWhitespaceCorrect(text, node, level, ConverterTestType.WhitespacePrecedingNodeWrong); + } + else if (node.NextNode is null) // this is the space before the close element + { + if (node.PreviousNode is null || node.PreviousNode is XCData) + { + this.EnsurePrecedingWhitespaceRemoved(text, node.Parent, ConverterTestType.WhitespacePrecedingEndElementWrong); + } + else if (level == 0) // root element's close tag + { + this.EnsurePrecedingWhitespaceCorrect(text, node, 0, ConverterTestType.WhitespacePrecedingEndElementWrong); + } + else + { + this.EnsurePrecedingWhitespaceCorrect(text, node, level - 1, ConverterTestType.WhitespacePrecedingEndElementWrong); + } + } + } + else if (node is XElement element) + { + this.ConvertElement(element); + + var before = element.Nodes().ToList(); + + this.ConvertNodes(before, level + 1); + + // If any nodes were added during the processing of the children, + // ensure those added children get processed as well. + var added = element.Nodes().Except(before).ToList(); + + if (added.Any()) + { + this.ConvertNodes(added, level + 1); + } + } + } + } + + private bool TryFixDeprecatedLocalizationPrefixes(XNode node, string value, out string newValue, ConverterTestType testType) + { + newValue = this.DeprecatedPrefixRegex.Replace(value, "!"); + + if (object.ReferenceEquals(newValue, value)) + { + return false; + } + + var message = testType == ConverterTestType.DeprecatedLocalizationVariablePrefixInTextValue ? "The prefix on the localization variable in the inner text is incorrect." : "The prefix on the localization variable in the attribute value is incorrect."; + + return this.OnError(testType, node, message); + } + + private void EnsurePrecedingWhitespaceCorrect(XText whitespace, XNode node, int level, ConverterTestType testType) + { + if (!WixConverter.LeadingWhitespaceValid(this.IndentationAmount, level, whitespace.Value)) + { + var message = testType == ConverterTestType.WhitespacePrecedingEndElementWrong ? "The whitespace preceding this end element is incorrect." : "The whitespace preceding this node is incorrect."; + + if (this.OnError(testType, node, message)) + { + WixConverter.FixupWhitespace(this.IndentationAmount, level, whitespace); + } + } + } + + private void EnsurePrecedingWhitespaceRemoved(XText whitespace, XNode node, ConverterTestType testType) + { + if (!String.IsNullOrEmpty(whitespace.Value) && whitespace.NodeType != XmlNodeType.CDATA) + { + var message = testType == ConverterTestType.WhitespacePrecedingEndElementWrong ? "The whitespace preceding this end element is incorrect." : "The whitespace preceding this node is incorrect."; + + if (this.OnError(testType, node, message)) + { + whitespace.Remove(); + } + } + } + + private void ConvertElement(XElement element) + { + var deprecatedToUpdatedNamespaces = new Dictionary(); + + foreach (var attribute in element.Attributes()) + { + if (attribute.IsNamespaceDeclaration) + { + // Gather any deprecated namespaces, then update this element tree based on those deprecations. + var declaration = attribute; + + if (element.Name == Wix3ElementName || element.Name == Include3ElementName) + { + this.SourceVersion = 3; + } + else if (element.Name == Wix4ElementName || element.Name == Include4ElementName) + { + this.SourceVersion = 4; + } + + if (WixConverter.OldToNewNamespaceMapping.TryGetValue(declaration.Value, out var ns)) + { + if (this.OnError(ConverterTestType.XmlnsValueWrong, declaration, "The namespace '{0}' is out of date. It must be '{1}'.", declaration.Value, ns.NamespaceName)) + { + deprecatedToUpdatedNamespaces.Add(declaration.Value, ns); + } + } + } + else + { + if (null != attribute.Value) + { + if (this.TryFixDeprecatedLocalizationPrefixes(element, attribute.Value, out var newValue, ConverterTestType.DeprecatedLocalizationVariablePrefixInAttributeValue)) + { + attribute.Value = newValue; + } + } + } + } + + if (deprecatedToUpdatedNamespaces.Any()) + { + WixConverter.UpdateElementsWithDeprecatedNamespaces(element.DescendantsAndSelf(), deprecatedToUpdatedNamespaces); + } + + // Apply any specialized conversion actions. + if (this.ConvertElementMapping.TryGetValue(element.Name, out var convert)) + { + convert(element); + } + } + + private void ConvertBootstrapperApplicationElement(XElement element) + { + var xUseUILanguages = element.Attribute(BalUseUILanguagesName); + if (xUseUILanguages != null && + this.OnError(ConverterTestType.BalUseUILanguagesDeprecated, element, "bal:UseUILanguages is deprecated, 'true' is now the standard behavior.")) + { + xUseUILanguages.Remove(); + } + + var xBADll = element.Elements(BootstrapperApplicationDllElementName).FirstOrDefault(); + if (xBADll == null) + { + xBADll = this.CreateBootstrapperApplicationDllElement(element); + + if (xBADll != null) + { + element.Add(Environment.NewLine); + element.Add(xBADll); + element.Add(Environment.NewLine); + } + } + } + + private XElement CreateBootstrapperApplicationDllElement(XElement element) + { + XElement xBADll = null; + var xSource = element.Attribute("SourceFile"); + var xDpiAwareness = element.Attribute("DpiAwareness"); + + if (xSource != null) + { + if (xBADll != null || CreateBADllElement(element, out xBADll)) + { + MoveAttribute(element, "SourceFile", xBADll); + MoveAttribute(element, "Name", xBADll); + } + } + else if (xDpiAwareness != null || this.SourceVersion < 4) // older code might be relying on old behavior of first Payload element being the BA dll. + { + var xFirstChild = element.Elements().FirstOrDefault(); + if (xFirstChild?.Name == PayloadElementName) + { + if (xBADll != null || CreateBADllElement(element, out xBADll)) + { + var attributes = xFirstChild.Attributes().ToList(); + xFirstChild.Remove(); + + foreach (var attribute in attributes) + { + xBADll.Add(attribute); + } + } + } + else + { + this.OnError(ConverterTestType.BootstrapperApplicationDllRequired, element, "The new BootstrapperApplicationDll element is required but could not be added automatically since the bootstrapper application dll was not directly specified."); + } + } + + if (xDpiAwareness != null) + { + if (xBADll != null || CreateBADllElement(element, out xBADll)) + { + MoveAttribute(element, "DpiAwareness", xBADll); + } + } + else if (this.SourceVersion < 4 && xBADll != null && + this.OnError(ConverterTestType.AssignBootstrapperApplicationDpiAwareness, element, "The BootstrapperApplicationDll DpiAwareness attribute is being set to 'unaware' to ensure it remains the same as the v3 default")) + { + xBADll.Add(new XAttribute("DpiAwareness", "unaware")); + } + + return xBADll; + + bool CreateBADllElement(XObject node, out XElement xCreatedBADll) + { + var create = this.OnError(ConverterTestType.BootstrapperApplicationDll, node, "The bootstrapper application dll is now specified in the BootstrapperApplicationDll element."); + xCreatedBADll = create ? new XElement(BootstrapperApplicationDllElementName) : null; + return create; + } + } + + private void ConvertBootstrapperApplicationRefElement(XElement element) + { + var xUseUILanguages = element.Attribute(BalUseUILanguagesName); + if (xUseUILanguages != null && + this.OnError(ConverterTestType.BalUseUILanguagesDeprecated, element, "bal:UseUILanguages is deprecated, 'true' is now the standard behavior.")) + { + xUseUILanguages.Remove(); + } + + var xId = element.Attribute("Id"); + if (xId != null) + { + XName balBAName = null; + XName oldBalBAName = null; + string theme = null; + + switch (xId.Value) + { + case "WixStandardBootstrapperApplication.RtfLicense": + balBAName = BalStandardBootstrapperApplicationName; + theme = "rtfLicense"; + break; + case "WixStandardBootstrapperApplication.RtfLargeLicense": + balBAName = BalStandardBootstrapperApplicationName; + theme = "rtfLargeLicense"; + break; + case "WixStandardBootstrapperApplication.HyperlinkLicense": + balBAName = BalStandardBootstrapperApplicationName; + theme = "hyperlinkLicense"; + break; + case "WixStandardBootstrapperApplication.HyperlinkLargeLicense": + balBAName = BalStandardBootstrapperApplicationName; + theme = "hyperlinkLargeLicense"; + break; + case "WixStandardBootstrapperApplication.HyperlinkSidebarLicense": + balBAName = BalStandardBootstrapperApplicationName; + theme = "hyperlinkSidebarLicense"; + break; + case "WixStandardBootstrapperApplication.Foundation": + balBAName = BalStandardBootstrapperApplicationName; + theme = "none"; + break; + case "ManagedBootstrapperApplicationHost": + case "ManagedBootstrapperApplicationHost.RtfLicense": + balBAName = BalManagedBootstrapperApplicationHostName; + theme = "standard"; + break; + case "ManagedBootstrapperApplicationHost.Minimal": + case "ManagedBootstrapperApplicationHost.RtfLicense.Minimal": + case "ManagedBootstrapperApplicationHost.Foundation": + balBAName = BalManagedBootstrapperApplicationHostName; + theme = "none"; + break; + case "DotNetCoreBootstrapperApplicationHost": + case "DotNetCoreBootstrapperApplicationHost.RtfLicense": + balBAName = BalNewDotNetCoreBootstrapperApplicationName; + oldBalBAName = BalOldDotNetCoreBootstrapperApplicationName; + theme = "standard"; + break; + case "DotNetCoreBootstrapperApplicationHost.Minimal": + case "DotNetCoreBootstrapperApplicationHost.RtfLicense.Minimal": + case "DotNetCoreBootstrapperApplicationHost.Foundation": + balBAName = BalNewDotNetCoreBootstrapperApplicationName; + oldBalBAName = BalOldDotNetCoreBootstrapperApplicationName; + theme = "none"; + break; + } + + if (balBAName != null && theme != null && + this.OnError(ConverterTestType.BalBootstrapperApplicationRefToElement, element, "Built-in bootstrapper applications must be referenced through their custom element")) + { + element.Name = BootstrapperApplicationElementName; + xId.Remove(); + this.ConvertBalBootstrapperApplicationRef(element, theme, balBAName, oldBalBAName); + } + } + } + + private void ConvertApprovedExeForElevationElement(XElement element) + { + this.RenameWin64ToBitness(element); + } + + private void ConvertBalBootstrapperApplicationRef(XElement element, string theme, XName balBAElementName, XName oldBalBAElementName = null) + { + var xBalBa = element.Element(oldBalBAElementName ?? balBAElementName); + if (xBalBa == null) + { + xBalBa = new XElement(balBAElementName); + element.Add(Environment.NewLine); + element.Add(xBalBa); + element.Add(Environment.NewLine); + } + else if (oldBalBAElementName != null) + { + xBalBa.Name = BalNewDotNetCoreBootstrapperApplicationName; + } + + if (theme != "standard") + { + xBalBa.Add(new XAttribute("Theme", theme)); + } + } + + private void ConvertCatalogElement(XElement element) + { + if (this.OnError(ConverterTestType.BundleSignatureValidationObsolete, element, "The Catalog element is obsolete. Signature validation is no longer supported. The element will be removed.")) + { + element.Remove(); + } + } + + private void ConvertColumnElement(XElement element) + { + var category = element.Attribute("Category"); + if (category != null) + { + var camelCaseValue = LowercaseFirstChar(category.Value); + if (category.Value != camelCaseValue && + this.OnError(ConverterTestType.ColumnCategoryCamelCase, element, "The CustomTable Category attribute contains an incorrectly cased '{0}' value. Lowercase the first character instead.", category.Name)) + { + category.Value = camelCaseValue; + } + } + + var modularization = element.Attribute("Modularize"); + if (modularization != null) + { + var camelCaseValue = LowercaseFirstChar(modularization.Value); + if (modularization.Value != camelCaseValue && + this.OnError(ConverterTestType.ColumnModularizeCamelCase, element, "The CustomTable Modularize attribute contains an incorrectly cased '{0}' value. Lowercase the first character instead.", modularization.Name)) + { + modularization.Value = camelCaseValue; + } + } + } + + private void ConvertCustomTableElement(XElement element) + { + var bootstrapperApplicationData = element.Attribute("BootstrapperApplicationData"); + if (bootstrapperApplicationData?.Value == "no") + { + if (this.OnError(ConverterTestType.BootstrapperApplicationDataDeprecated, element, "The CustomTable element contains deprecated '{0}' attribute. Use the 'Unreal' attribute instead.", bootstrapperApplicationData.Name)) + { + bootstrapperApplicationData.Remove(); + } + } + else + { + if (element.Elements(ColumnElementName).Any() || bootstrapperApplicationData != null) + { + // Table definition + if (bootstrapperApplicationData != null) + { + switch (this.CustomTableSetting) + { + case CustomTableTarget.Bundle: + if (this.OnError(ConverterTestType.BootstrapperApplicationDataDeprecated, element, "The CustomTable element contains deprecated '{0}' attribute. Use the 'BundleCustomData' element for Bundles.", bootstrapperApplicationData.Name)) + { + element.Name = WixConverter.BundleCustomDataElementName; + bootstrapperApplicationData.Remove(); + this.ConvertCustomTableElementToBundle(element); + } + break; + case CustomTableTarget.Msi: + if (this.OnError(ConverterTestType.BootstrapperApplicationDataDeprecated, element, "The CustomTable element contains deprecated '{0}' attribute. Use the 'Unreal' attribute instead.", bootstrapperApplicationData.Name)) + { + element.Add(new XAttribute("Unreal", bootstrapperApplicationData.Value)); + bootstrapperApplicationData.Remove(); + } + break; + default: + this.OnError(ConverterTestType.CustomTableNotAlwaysConvertable, element, "The CustomTable element contains deprecated '{0}' attribute so can't be converted. Use the 'Unreal' attribute for MSI. Use the 'BundleCustomData' element for Bundles. Use the --custom-table argument to force conversion to 'msi' or 'bundle'", bootstrapperApplicationData.Name); + break; + } + } + } + else + { + // Table ref + switch (this.CustomTableSetting) + { + case CustomTableTarget.Bundle: + if (this.OnError(ConverterTestType.CustomTableRef, element, "CustomTable elements that don't contain the table definition are now BundleCustomDataRef for Bundles.")) + { + element.Name = WixConverter.BundleCustomDataRefElementName; + this.ConvertCustomTableElementToBundle(element); + } + break; + case CustomTableTarget.Msi: + if (this.OnError(ConverterTestType.CustomTableRef, element, "CustomTable elements that don't contain the table definition are now CustomTableRef for MSI.")) + { + element.Name = WixConverter.CustomTableRefElementName; + } + break; + default: + this.OnError(ConverterTestType.CustomTableNotAlwaysConvertable, element, "The CustomTable element contains no 'Column' elements so can't be converted. Use the 'CustomTableRef' element for MSI. Use the 'BundleCustomDataRef' element for Bundles. Use the --custom-table argument to force conversion to 'msi' or 'bundle'"); + break; + } + } + } + } + + private void ConvertCustomTableElementToBundle(XElement element) + { + foreach (var xColumn in element.Elements(ColumnElementName)) + { + xColumn.Name = WixConverter.BundleAttributeDefinitionElementName; + + foreach (var xAttribute in xColumn.Attributes().ToList()) + { + if (xAttribute.Name.LocalName != "Id" && + (xAttribute.Name.Namespace == WixConverter.Wix3Namespace || + xAttribute.Name.Namespace == WixConverter.WixNamespace || + String.IsNullOrEmpty(xAttribute.Name.Namespace.NamespaceName))) + { + xAttribute.Remove(); + } + } + } + + foreach (var xRow in element.Elements(RowElementName)) + { + xRow.Name = WixConverter.BundleElementElementName; + + foreach (var xData in xRow.Elements(DataElementName)) + { + xData.Name = WixConverter.BundleAttributeElementName; + + var xColumn = xData.Attribute("Column"); + if (xColumn != null) + { + xData.Add(new XAttribute("Id", xColumn.Value)); + xColumn.Remove(); + } + + this.ConvertInnerTextToAttribute(xData, "Value"); + } + } + } + + private void ConvertControlElement(XElement element) + { + var remove = new List(); + + foreach (var xCondition in element.Elements(ConditionElementName)) + { + var action = UppercaseFirstChar(xCondition.Attribute("Action")?.Value); + if (!String.IsNullOrEmpty(action) && + TryGetInnerText(xCondition, out var text) && + this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the '{1}Condition' attribute instead.", xCondition.Name.LocalName, action)) + { + element.Add(new XAttribute(action + "Condition", text)); + remove.Add(xCondition); + } + } + + for (var i = remove.Count - 1; i >= 0; i--) + { + remove[i].Remove(); + } + } + + private void ConvertComponentElement(XElement element) + { + var guid = element.Attribute("Guid"); + if (guid != null && guid.Value == "*") + { + if (this.OnError(ConverterTestType.AutoGuidUnnecessary, element, "Using '*' for the Component Guid attribute is unnecessary. Remove the attribute to remove the redundancy.")) + { + guid.Remove(); + } + } + + var xCondition = element.Element(ConditionElementName); + if (xCondition != null) + { + if (TryGetInnerText(xCondition, out var text) && + this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Condition' attribute instead.", xCondition.Name.LocalName)) + { + element.Add(new XAttribute("Condition", text)); + xCondition.Remove(); + } + } + + this.RenameWin64ToBitness(element); + } + + private void ConvertDirectoryElement(XElement element) + { + if (null == element.Attribute("Name")) + { + var attribute = element.Attribute("ShortName"); + if (null != attribute) + { + var shortName = attribute.Value; + if (this.OnError(ConverterTestType.AssignDirectoryNameFromShortName, element, "The directory ShortName attribute is being renamed to Name since Name wasn't specified for value '{0}'", shortName)) + { + element.Add(new XAttribute("Name", shortName)); + attribute.Remove(); + } + } + } + + var id = element.Attribute("Id")?.Value; + + if (id == "TARGETDIR" && + this.OnError(ConverterTestType.TargetDirDeprecated, element, "The TARGETDIR directory should not longer be explicitly defined. Remove the Directory element with Id attribute 'TARGETDIR'.")) + { + var parentElement = element.Parent; + + element.Remove(); + + if (parentElement.FirstNode is XText text && String.IsNullOrWhiteSpace(text.Value)) + { + parentElement.FirstNode.Remove(); + } + + foreach (var child in element.Nodes()) + { + parentElement.Add(child); + } + + element.RemoveAll(); + + if (parentElement.FirstNode is XText textAgain && String.IsNullOrWhiteSpace(textAgain.Value)) + { + parentElement.FirstNode.Remove(); + } + } + else if (id != null && + WindowsInstallerStandard.IsStandardDirectory(id) && + this.OnError(ConverterTestType.DefiningStandardDirectoryDeprecated, element, "Standard directories such as '{0}' should no longer be defined using the Directory element. Use the StandardDirectory element instead.", id)) + { + element.Name = StandardDirectoryElementName; + + foreach (var attrib in element.Attributes().Where(a => a.Name.LocalName != "Id").ToList()) + { + attrib.Remove(); + } + } + } + + private void ConvertFeatureElement(XElement element) + { + var xAbsent = element.Attribute("Absent"); + if (xAbsent != null && + this.OnError(ConverterTestType.FeatureAbsentAttributeReplaced, element, "The Feature element's Absent attribute has been replaced with the AllowAbsent attribute. Use the 'AllowAbsent' attribute instead.")) + { + if (xAbsent.Value == "disallow") + { + element.Add(new XAttribute("AllowAbsent", "no")); + } + xAbsent.Remove(); + } + + var xAllowAdvertise = element.Attribute("AllowAdvertise"); + if (xAllowAdvertise != null) + { + if ((xAllowAdvertise.Value == "system" || xAllowAdvertise.Value == "allow") && + this.OnError(ConverterTestType.FeatureAllowAdvertiseValueDeprecated, element, "The AllowAdvertise attribute's '{0}' value is deprecated. Set the value to 'yes' instead.", xAllowAdvertise.Value)) + { + xAllowAdvertise.Value = "yes"; + } + else if (xAllowAdvertise.Value == "disallow" && + this.OnError(ConverterTestType.FeatureAllowAdvertiseValueDeprecated, element, "The AllowAdvertise attribute's '{0}' value is deprecated. Remove the value instead.", xAllowAdvertise.Value)) + { + xAllowAdvertise.Remove(); + } + } + + var xCondition = element.Element(ConditionElementName); + if (xCondition != null) + { + var level = xCondition.Attribute("Level")?.Value; + if (!String.IsNullOrEmpty(level) && + TryGetInnerText(xCondition, out var text) && + this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Level' element instead.", xCondition.Name.LocalName)) + { + xCondition.AddAfterSelf(new XElement(LevelElementName, + new XAttribute("Value", level), + new XAttribute("Condition", text) + )); + xCondition.Remove(); + } + } + } + + private void ConvertFileElement(XElement element) + { + if (this.SourceVersion < 4 && null == element.Attribute("Id")) + { + var attribute = element.Attribute("Name"); + + if (null == attribute) + { + attribute = element.Attribute("Source"); + } + + if (null != attribute) + { + var name = Path.GetFileName(attribute.Value); + + if (this.OnError(ConverterTestType.AssignAnonymousFileId, element, "The file id is being updated to '{0}' to ensure it remains the same as the v3 default", name)) + { + IEnumerable attributes = element.Attributes().ToList(); + element.RemoveAttributes(); + element.Add(new XAttribute("Id", GetIdentifierFromName(name))); + element.Add(attributes); + } + } + } + } + + private void ConvertFragmentElement(XElement element) + { + var remove = new List(); + + foreach (var xCondition in element.Elements(ConditionElementName)) + { + var message = xCondition.Attribute("Message")?.Value; + + if (!String.IsNullOrEmpty(message) && + TryGetInnerText(xCondition, out var text) && + this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Launch' element instead.", xCondition.Name.LocalName)) + { + xCondition.AddAfterSelf(new XElement(LaunchElementName, + new XAttribute("Condition", text), + new XAttribute("Message", message) + )); + remove.Add(xCondition); + } + } + + for (var i = remove.Count - 1; i >= 0; i--) + { + remove[i].Remove(); + } + } + + private void ConvertFirewallRemoteAddressElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); + + private void ConvertEmbeddedChainerElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Condition"); + + private void ConvertErrorElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Message"); + + private void ConvertExePackageElement(XElement element) + { + this.ConvertSuppressSignatureValidation(element); + + foreach (var attributeName in new[] { "InstallCommand", "RepairCommand", "UninstallCommand" }) + { + var newName = attributeName.Replace("Command", "Arguments"); + var attribute = element.Attribute(attributeName); + + if (attribute != null && + this.OnError(ConverterTestType.RenameExePackageCommandToArguments, element, "The {0} element {1} attribute has been renamed {2}.", element.Name.LocalName, attribute.Name.LocalName, newName)) + { + element.Add(new XAttribute(newName, attribute.Value)); + attribute.Remove(); + } + } + } + + private void ConvertPermissionExElement(XElement element) + { + var xCondition = element.Element(ConditionElementName); + if (xCondition != null) + { + if (TryGetInnerText(xCondition, out var text) && + this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Condition' attribute instead.", xCondition.Name.LocalName)) + { + element.Add(new XAttribute("Condition", text)); + xCondition.Remove(); + } + } + } + + private void ConvertProgressTextElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Message"); + + private void ConvertModuleElement(XElement element) + { + if (element.Attribute("Guid") == null // skip already-converted Module elements + && this.OnError(ConverterTestType.ModuleAndPackageRenamed, element, "The Module and Package elements have been renamed and reorganized for simplicity.")) + { + var xModule = element; + + var xSummaryInformation = xModule.Element(PackageElementName); + if (xSummaryInformation != null) + { + xSummaryInformation.Name = SummaryInformationElementName; + + var xInstallerVersion = xSummaryInformation.Attribute("InstallerVersion"); + if (this.SourceVersion < 4 && xInstallerVersion == null) + { + this.OnError(ConverterTestType.InstallerVersionBehaviorChange, element, "Breaking change: The default value for Package/@InstallerVersion has been changed to '500' regardless of build platform. If you need a lower version, set it manually in the Module element."); + } + + RemoveAttribute(xSummaryInformation, "AdminImage"); + RemoveAttribute(xSummaryInformation, "Comments"); + MoveAttribute(xSummaryInformation, "Id", xModule, "Guid"); + MoveAttribute(xSummaryInformation, "InstallerVersion", xModule); + RemoveAttribute(xSummaryInformation, "Languages"); + RemoveAttribute(xSummaryInformation, "Platform"); + RemoveAttribute(xSummaryInformation, "Platforms"); + RemoveAttribute(xSummaryInformation, "ReadOnly"); + MoveAttribute(xSummaryInformation, "SummaryCodepage", xSummaryInformation, "Codepage", defaultValue: "1252"); + + if (!xSummaryInformation.HasAttributes) + { + xSummaryInformation.Remove(); + } + } + } + } + + private void ConvertProductElement(XElement element) + { + var id = element.Attribute("Id"); + if (id != null && id.Value == "*") + { + if (this.OnError(ConverterTestType.AutoGuidUnnecessary, element, "Using '*' for the Product Id attribute is unnecessary. Remove the attribute to remove the redundancy.")) + { + id.Remove(); + } + } + + var xConditions = element.Elements(ConditionElementName).ToList(); + foreach (var xCondition in xConditions) + { + var message = xCondition.Attribute("Message")?.Value; + + if (!String.IsNullOrEmpty(message) && + TryGetInnerText(xCondition, out var text) && + this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the 'Launch' element instead.", xCondition.Name.LocalName)) + { + xCondition.AddAfterSelf(new XElement(LaunchElementName, + new XAttribute("Condition", text), + new XAttribute("Message", message) + )); + xCondition.Remove(); + } + } + + var xMediaTemplate = element.Element(MediaTemplateElementName); + if (xMediaTemplate?.HasAttributes == false + && this.OnError(ConverterTestType.DefaultMediaTemplate, element, "A MediaTemplate with no attributes set is now provided by default. Remove the element.")) + { + xMediaTemplate.Remove(); + } + + if (this.OnError(ConverterTestType.ProductAndPackageRenamed, element, "The Product and Package elements have been renamed and reorganized for simplicity.")) + { + var xPackage = element; + xPackage.Name = PackageElementName; + + var xSummaryInformation = xPackage.Element(PackageElementName); + if (xSummaryInformation != null) + { + xSummaryInformation.Name = SummaryInformationElementName; + + var xInstallerVersion = xSummaryInformation.Attribute("InstallerVersion"); + if (this.SourceVersion < 4 && xInstallerVersion == null) + { + this.OnError(ConverterTestType.InstallerVersionBehaviorChange, element, "Breaking change: The default value for Package/@InstallerVersion has been changed to '500' regardless of build platform. If you need a lower version, set it manually in the Package element."); + } + + if (xSummaryInformation.Attribute("Compressed") == null) + { + xPackage.SetAttributeValue("Compressed", "no"); + } + else + { + MoveAttribute(xSummaryInformation, "Compressed", xPackage, defaultValue: "yes"); + } + + RemoveAttribute(xSummaryInformation, "AdminImage"); + RemoveAttribute(xSummaryInformation, "Comments"); + RemoveAttribute(xSummaryInformation, "Id"); + MoveAttribute(xSummaryInformation, "InstallerVersion", xPackage, defaultValue: "500"); + MoveAttribute(xSummaryInformation, "InstallScope", xPackage, "Scope", defaultValue: "perMachine"); + RemoveAttribute(xSummaryInformation, "Languages"); + RemoveAttribute(xSummaryInformation, "Platform"); + RemoveAttribute(xSummaryInformation, "Platforms"); + RemoveAttribute(xSummaryInformation, "ReadOnly"); + MoveAttribute(xSummaryInformation, "ShortNames", xPackage); + MoveAttribute(xSummaryInformation, "SummaryCodepage", xSummaryInformation, "Codepage", defaultValue: "1252"); + MoveAttribute(xPackage, "Id", xPackage, "ProductCode"); + + var xInstallPrivileges = xSummaryInformation.Attribute("InstallPrivileges"); + switch (xInstallPrivileges?.Value) + { + case "limited": + xPackage.SetAttributeValue("Scope", "perUser"); + break; + case "elevated": + { + var xAllUsers = xPackage.Elements(PropertyElementName).SingleOrDefault(p => p.Attribute("Id")?.Value == "ALLUSERS"); + if (xAllUsers?.Attribute("Value")?.Value == "1") + { + xAllUsers?.Remove(); + } + } + break; + } + + xInstallPrivileges?.Remove(); + + if (!xSummaryInformation.HasAttributes) + { + xSummaryInformation.Remove(); + } + } + } + } + + private static void MoveAttribute(XElement xSource, string attributeName, XElement xDestination, string destinationAttributeName = null, string defaultValue = null) + { + var xAttribute = xSource.Attribute(attributeName); + if (xAttribute != null && (defaultValue == null || xAttribute.Value != defaultValue)) + { + xDestination.SetAttributeValue(destinationAttributeName ?? attributeName, xAttribute.Value); + } + + xAttribute?.Remove(); + } + + private static void RemoveAttribute(XElement xSummaryInformation, string attributeName) + { + var xAttribute = xSummaryInformation.Attribute(attributeName); + xAttribute?.Remove(); + } + + private void ConvertPropertyRefElement(XElement element) + { + var newElementName = String.Empty; + + var id = element.Attribute("Id"); + switch (id?.Value) + { + case "WIX_SUITE_BACKOFFICE": + case "WIX_SUITE_BLADE": + case "WIX_SUITE_COMMUNICATIONS": + case "WIX_SUITE_COMPUTE_SERVER": + case "WIX_SUITE_DATACENTER": + case "WIX_SUITE_EMBEDDED_RESTRICTED": + case "WIX_SUITE_EMBEDDEDNT": + case "WIX_SUITE_ENTERPRISE": + case "WIX_SUITE_MEDIACENTER": + case "WIX_SUITE_PERSONAL": + case "WIX_SUITE_SECURITY_APPLIANCE": + case "WIX_SUITE_SERVERR2": + case "WIX_SUITE_SINGLEUSERTS": + case "WIX_SUITE_SMALLBUSINESS": + case "WIX_SUITE_SMALLBUSINESS_RESTRICTED": + case "WIX_SUITE_STARTER": + case "WIX_SUITE_STORAGE_SERVER": + case "WIX_SUITE_TABLETPC": + case "WIX_SUITE_TERMINAL": + case "WIX_SUITE_WH_SERVER": + newElementName = "QueryWindowsSuiteInfo"; + break; + case "WIX_DIR_ADMINTOOLS": + case "WIX_DIR_ALTSTARTUP": + case "WIX_DIR_CDBURN_AREA": + case "WIX_DIR_COMMON_ADMINTOOLS": + case "WIX_DIR_COMMON_ALTSTARTUP": + case "WIX_DIR_COMMON_DOCUMENTS": + case "WIX_DIR_COMMON_FAVORITES": + case "WIX_DIR_COMMON_MUSIC": + case "WIX_DIR_COMMON_PICTURES": + case "WIX_DIR_COMMON_VIDEO": + case "WIX_DIR_COOKIES": + case "WIX_DIR_DESKTOP": + case "WIX_DIR_HISTORY": + case "WIX_DIR_INTERNET_CACHE": + case "WIX_DIR_MYMUSIC": + case "WIX_DIR_MYPICTURES": + case "WIX_DIR_MYVIDEO": + case "WIX_DIR_NETHOOD": + case "WIX_DIR_PERSONAL": + case "WIX_DIR_PRINTHOOD": + case "WIX_DIR_PROFILE": + case "WIX_DIR_RECENT": + case "WIX_DIR_RESOURCES": + newElementName = "QueryWindowsDirectories"; + break; + case "WIX_DWM_COMPOSITION_ENABLED": + case "WIX_WDDM_DRIVER_PRESENT": + newElementName = "QueryWindowsDriverInfo"; + break; + case "WIX_ACCOUNT_LOCALSYSTEM": + case "WIX_ACCOUNT_LOCALSERVICE": + case "WIX_ACCOUNT_NETWORKSERVICE": + case "WIX_ACCOUNT_ADMINISTRATORS": + case "WIX_ACCOUNT_USERS": + case "WIX_ACCOUNT_GUESTS": + case "WIX_ACCOUNT_PERFLOGUSERS": + case "WIX_ACCOUNT_PERFLOGUSERS_NODOMAIN": + newElementName = "QueryWindowsWellKnownSIDs"; + break; + } + + if (!String.IsNullOrEmpty(newElementName) + && this.OnError(ConverterTestType.UtilReferencesReplaced, element, "Custom action and property reference {0} to WixUtilExtension have been replaced with strongly-typed elements.", id)) + { + element.AddAfterSelf(new XElement(WixUtilNamespace + newElementName)); + element.Remove(); + } + } + + private void ConvertCustomActionRefElement(XElement element) + { + var newElementName = String.Empty; + + var id = element.Attribute("Id"); + switch (id?.Value) + { + case "WixBroadcastSettingChange": + case "WixBroadcastEnvironmentChange": + case "WixCheckRebootRequired": + case "WixExitEarlyWithSuccess": + case "WixFailWhenDeferred": + case "WixWaitForEvent": + case "WixWaitForEventDeferred": + newElementName = id?.Value.Substring(3); // strip leading Wix + break; + } + + if (!String.IsNullOrEmpty(newElementName) + && this.OnError(ConverterTestType.UtilReferencesReplaced, element, "Custom action and property reference {0} to WixUtilExtension have been replaced with strongly-typed elements.", id)) + { + element.AddAfterSelf(new XElement(WixUtilNamespace + newElementName)); + element.Remove(); + } + } + + private void ConvertPublishElement(XElement element) + { + this.ConvertInnerTextToAttribute(element, "Condition"); + + var xCondition = element.Attribute("Condition"); + if (xCondition?.Value == "1" && + this.OnError(ConverterTestType.PublishConditionOneUnnecessary, element, "Adding Condition='1' on {0} elements is no longer necessary. Remove the Condition attribute.", xCondition.Name.LocalName)) + { + xCondition.Remove(); + } + } + + private void ConvertMultiStringValueElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); + + private void ConvertRegistryKeyElement(XElement element) + { + var xAction = element.Attribute("Action"); + + if (xAction != null + && this.OnError(ConverterTestType.RegistryKeyActionObsolete, element, "The RegistryKey element's Action attribute is obsolete. Action='create' will be converted to ForceCreateOnInstall='yes'. Action='createAndRemoveOnUninstall' will be converted to ForceCreateOnInstall='yes' and ForceDeleteOnUninstall='yes'.")) + { + switch (xAction?.Value) + { + case "create": + element.SetAttributeValue("ForceCreateOnInstall", "yes"); + break; + case "createAndRemoveOnUninstall": + element.SetAttributeValue("ForceCreateOnInstall", "yes"); + element.SetAttributeValue("ForceDeleteOnUninstall", "yes"); + break; + } + + xAction.Remove(); + } + } + + private void ConvertRemotePayloadElement(XElement element) + { + var xParent = element.Parent; + + if (xParent.Name == ExePackageElementName && + this.OnError(ConverterTestType.RemotePayloadRenamed, element, "The RemotePayload element has been renamed. Use the 'ExePackagePayload' instead.")) + { + element.Name = ExePackagePayloadElementName; + } + else if (xParent.Name == MsuPackageElementName && + this.OnError(ConverterTestType.RemotePayloadRenamed, element, "The RemotePayload element has been renamed. Use the 'MsuPackagePayload' instead.")) + { + element.Name = MsuPackagePayloadElementName; + } + + var xName = xParent.Attribute("Name"); + if (xName != null && + this.OnError(ConverterTestType.NameAttributeMovedToRemotePayload, xParent, "The Name attribute must be specified on the child XxxPackagePayload element when using a remote payload.")) + { + element.SetAttributeValue("Name", xName.Value); + xName.Remove(); + } + + var xDownloadUrl = xParent.Attribute("DownloadUrl"); + if (xDownloadUrl != null && + this.OnError(ConverterTestType.DownloadUrlAttributeMovedToRemotePayload, xParent, "The DownloadUrl attribute must be specified on the child XxxPackagePayload element when using a remote payload.")) + { + element.SetAttributeValue("DownloadUrl", xDownloadUrl.Value); + xDownloadUrl.Remove(); + } + + var xCompressed = xParent.Attribute("Compressed"); + if (xCompressed != null && + this.OnError(ConverterTestType.CompressedAttributeUnnecessaryForRemotePayload, xParent, "The Compressed attribute should not be specified when using a remote payload.")) + { + xCompressed.Remove(); + } + + this.OnError(ConverterTestType.BurnHashAlgorithmChanged, element, "The hash algorithm for bundles changed from SHA1 to SHA512."); + + this.RemoveAttributeIfPresent(element, "CertificatePublicKey", ConverterTestType.BundleSignatureValidationObsolete, "The {0} element contains obsolete '{1}' attribute. Signature validation is no longer supported. The attribute will be removed."); + this.RemoveAttributeIfPresent(element, "CertificateThumbprint", ConverterTestType.BundleSignatureValidationObsolete, "The {0} element contains obsolete '{1}' attribute. Signature validation is no longer supported. The attribute will be removed."); + } + + private void ConvertRegistrySearchElement(XElement element) + { + this.RenameWin64ToBitness(element); + } + + private void ConvertRequiredPrivilegeElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Name"); + + private void ConvertDataElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); + + private void ConvertSequenceElement(XElement element) + { + foreach (var child in element.Elements()) + { + this.ConvertInnerTextToAttribute(child, "Condition"); + } + } + + private void ConvertServiceArgumentElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); + + private void ConvertSetDirectoryElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Condition"); + + private void ConvertSetPropertyElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Condition"); + + private void ConvertShortcutPropertyElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); + + private void ConvertProvidesElement(XElement element) + { + if (this.OnError(ConverterTestType.IntegratedDependencyNamespace, element, "The Provides element has been integrated into the WiX v4 namespace. Remove the namespace.")) + { + element.Name = ProvidesElementName; + } + + if (element.Parent.Name == ComponentElementName && + this.OnError(ConverterTestType.IntegratedDependencyNamespace, element, "The Provides element has been integrated into the WiX v4 namespace. Add the 'Check' attribute from the WixDependency.wixext to match v3 runtime behavior.")) + { + element.Add(new XAttribute(DependencyCheckAttributeName, "yes")); + } + } + + private void ConvertRequiresElement(XElement element) + { + if (this.OnError(ConverterTestType.IntegratedDependencyNamespace, element, "The Requires element has been integrated into the WiX v4 namespace. Remove the namespace.")) + { + element.Name = RequiresElementName; + } + + if (element.Parent.Name == ProvidesElementName && + element.Parent.Parent?.Name == ComponentElementName && + this.OnError(ConverterTestType.IntegratedDependencyNamespace, element, "The Requires element has been integrated into the WiX v4 namespace. Add the 'Enforce' attribute from the WixDependency.wixext to match v3 runtime behavior.")) + { + element.Add(new XAttribute(DependencyEnforceAttributeName, "yes")); + } + } + + private void ConvertRequiresRefElement(XElement element) + { + if (this.OnError(ConverterTestType.IntegratedDependencyNamespace, element, "The RequiresRef element has been integrated into the WiX v4 namespace. Remove the namespace.")) + { + element.Name = RequiresRefElementName; + } + + if (element.Parent.Name == ProvidesElementName && + element.Parent.Parent?.Name == ComponentElementName && + this.OnError(ConverterTestType.IntegratedDependencyNamespace, element, "The RequiresRef element has been integrated into the WiX v4 namespace. Add the 'Enforce' attribute from the WixDependency.wixext to match v3 runtime behavior.")) + { + element.Add(new XAttribute(DependencyEnforceAttributeName, "yes")); + } + } + + private void ConvertSuppressSignatureValidation(XElement element) + { + var suppressSignatureValidation = element.Attribute("SuppressSignatureValidation"); + + if (null != suppressSignatureValidation + && this.OnError(ConverterTestType.BundleSignatureValidationObsolete, element, "The chain package element contains obsolete '{0}' attribute. Signature validation is no longer supported. The attribute will be removed.", suppressSignatureValidation.Name)) + { + suppressSignatureValidation.Remove(); + } + } + + private void ConvertTagElement(XElement element) + { + if (this.OnError(ConverterTestType.TagElementRenamed, element, "The Tag element has been renamed. Use the 'SoftwareTag' element instead.")) + { + element.Name = SoftwareTagElementName; + } + + this.RemoveAttributeIfPresent(element, "Licensed", ConverterTestType.SoftwareTagLicensedObsolete, "The {0} element contains obsolete '{1}' attribute. The attribute will be removed."); + this.RemoveAttributeIfPresent(element, "Type", ConverterTestType.SoftwareTagLicensedObsolete, "The {0} element contains obsolete '{1}' attribute. The attribute will be removed."); + this.RenameWin64ToBitness(element); + } + + private void ConvertTagRefElement(XElement element) + { + if (this.OnError(ConverterTestType.TagRefElementRenamed, element, "The TagRef element has been renamed. Use the 'SoftwareTagRef' element instead.")) + { + element.Name = SoftwareTagRefElementName; + } + } + + private void ConvertTextElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); + + private void ConvertUITextElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); + + private void ConvertWindowsInstallerPackageElement(XElement element) + { + this.ConvertSuppressSignatureValidation(element); + + if (null != element.Attribute("DisplayInternalUI")) + { + this.OnError(ConverterTestType.DisplayInternalUiNotConvertable, element, "The DisplayInternalUI functionality has fundamentally changed and requires BootstrapperApplication support."); + } + } + + private void ConvertVerbElement(XElement element) + { + if (null != element.Attribute("Target")) + { + this.OnError(ConverterTestType.VerbTargetNotConvertable, element, "The Verb/@Target attribute has been replaced with typed @TargetFile and @TargetProperty attributes."); + } + } + + private void ConvertCustomActionElement(XElement xCustomAction) + { + var xBinaryKey = xCustomAction.Attribute("BinaryKey"); + if (xBinaryKey != null && this.OnError(ConverterTestType.CustomActionKeysAreNowRefs, xCustomAction, "The CustomAction attributes have been renamed from BinaryKey and FileKey to BinaryRef and FileRef.")) + { + xCustomAction.SetAttributeValue("BinaryRef", xBinaryKey.Value); + xBinaryKey.Remove(); + xBinaryKey = xCustomAction.Attribute("BinaryRef"); + } + + var xFileKey = xCustomAction.Attribute("FileKey"); + if (xFileKey != null && this.OnError(ConverterTestType.CustomActionKeysAreNowRefs, xCustomAction, "The CustomAction attributes have been renamed from BinaryKey and FileKey to BinaryRef and FileRef.")) + { + xCustomAction.SetAttributeValue("FileRef", xFileKey.Value); + xFileKey.Remove(); + } + + if (xBinaryKey?.Value == "WixCA" || xBinaryKey?.Value == "UtilCA") + { + if (this.OnError(ConverterTestType.WixCABinaryIdRenamed, xCustomAction, "The WixCA custom action DLL Binary table id has been renamed. Use the id 'Wix4UtilCA_X86' instead.")) + { + xBinaryKey.Value = "Wix4UtilCA_X86"; + } + } + + if (xBinaryKey?.Value == "WixCA_x64" || xBinaryKey?.Value == "UtilCA_x64") + { + if (this.OnError(ConverterTestType.WixCABinaryIdRenamed, xCustomAction, "The WixCA_x64 custom action DLL Binary table id has been renamed. Use the id 'Wix4UtilCA_X64' instead.")) + { + xBinaryKey.Value = "Wix4UtilCA_X64"; + } + } + + var xDllEntry = xCustomAction.Attribute("DllEntry"); + + if (xDllEntry?.Value == "CAQuietExec" || xDllEntry?.Value == "CAQuietExec64") + { + if (this.OnError(ConverterTestType.QuietExecCustomActionsRenamed, xCustomAction, "The CAQuietExec and CAQuietExec64 custom action ids have been renamed. Use the ids 'WixQuietExec' and 'WixQuietExec64' instead.")) + { + xDllEntry.Value = xDllEntry.Value.Replace("CAQuietExec", "WixQuietExec"); + } + } + + var xProperty = xCustomAction.Attribute("Property"); + + if (xProperty?.Value == "QtExecCmdLine" || xProperty?.Value == "QtExec64CmdLine") + { + if (this.OnError(ConverterTestType.QuietExecCustomActionsRenamed, xCustomAction, "The QtExecCmdLine and QtExec64CmdLine property ids have been renamed. Use the ids 'WixQuietExecCmdLine' and 'WixQuietExec64CmdLine' instead.")) + { + xProperty.Value = xProperty.Value.Replace("QtExec", "WixQuietExec"); + } + } + + var xScript = xCustomAction.Attribute("Script"); + + if (xScript != null && TryGetInnerText(xCustomAction, out var scriptText)) + { + if (this.OnError(ConverterTestType.InnerTextDeprecated, xCustomAction, "Using {0} element text is deprecated. Extract the text to a file and use the 'ScriptSourceFile' attribute to reference it.", xCustomAction.Name.LocalName)) + { + var scriptFolder = Path.GetDirectoryName(this.SourceFile) ?? String.Empty; + var id = xCustomAction.Attribute("Id")?.Value ?? Guid.NewGuid().ToString("N"); + var ext = (xScript.Value == "jscript") ? ".js" : (xScript.Value == "vbscript") ? ".vbs" : ".txt"; + + var scriptFile = Path.Combine(scriptFolder, id + ext); + File.WriteAllText(scriptFile, scriptText); + + RemoveChildren(xCustomAction); + xCustomAction.Add(new XAttribute("ScriptSourceFile", scriptFile)); + } + } + } + + private void ConvertVariableElement(XElement xVariable) + { + var xType = xVariable.Attribute("Type"); + var xValue = xVariable.Attribute("Value"); + if (this.SourceVersion < 4) + { + if (xType == null) + { + if (WasImplicitlyStringTyped(xValue?.Value) && + this.OnError(ConverterTestType.AssignVariableTypeFormatted, xVariable, "The \"string\" variable type now denotes a literal string. Use \"formatted\" to keep the previous behavior.")) + { + xVariable.Add(new XAttribute("Type", "formatted")); + } + } + else if (xType.Value == "string" && + this.OnError(ConverterTestType.AssignVariableTypeFormatted, xVariable, "The \"string\" variable type now denotes a literal string. Use \"formatted\" to keep the previous behavior.")) + { + xType.Value = "formatted"; + } + } + } + + private void ConvertPropertyElement(XElement xProperty) + { + var xId = xProperty.Attribute("Id"); + + if (xId.Value == "QtExecCmdTimeout") + { + this.OnError(ConverterTestType.QtExecCmdTimeoutAmbiguous, xProperty, "QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout."); + } + + this.ConvertInnerTextToAttribute(xProperty, "Value"); + } + + private void ConvertUtilCloseApplicationElementName(XElement element) => this.ConvertInnerTextToAttribute(element, "Condition"); + + private void ConvertUtilPermissionExElement(XElement element) + { + if (this.SourceVersion < 4 && null == element.Attribute("Inheritable")) + { + var inheritable = element.Parent.Name == CreateFolderElementName; + if (!inheritable) + { + if (this.OnError(ConverterTestType.AssignPermissionExInheritable, element, "The PermissionEx Inheritable attribute is being set to 'no' to ensure it remains the same as the v3 default.")) + { + element.Add(new XAttribute("Inheritable", "no")); + } + } + } + } + + private void ConvertUtilRegistrySearchElement(XElement element) + { + this.RenameWin64ToBitness(element); + + if (this.SourceVersion < 4) + { + var result = element.Attribute("Result")?.Value; + if (result == null || result == "value") + { + this.OnError(ConverterTestType.UtilRegistryValueSearchBehaviorChange, element, "Breaking change: util:RegistrySearch for a value no longer clears the variable when the key or value is missing."); + } + } + } + + private void ConvertUtilXmlConfigElement(XElement element) => this.ConvertInnerTextToAttribute(element, "Value"); + + /// + /// Converts a Wix element. + /// + /// The Wix element to convert. + /// The converted element. + private void ConvertElementWithoutNamespace(XElement element) + { + if (this.OnError(ConverterTestType.XmlnsMissing, element, "The xmlns attribute is missing. It must be present with a value of '{0}'.", WixNamespace.NamespaceName)) + { + element.Name = WixNamespace.GetName(element.Name.LocalName); + + element.Add(new XAttribute("xmlns", WixNamespace.NamespaceName)); // set the default namespace. + + foreach (var elementWithoutNamespace in element.DescendantsAndSelf().Where(e => XNamespace.None == e.Name.Namespace)) + { + elementWithoutNamespace.Name = WixNamespace.GetName(elementWithoutNamespace.Name.LocalName); + } + } + } + + private void ConvertInnerTextToAttribute(XElement element, string attributeName) + { + if (TryGetInnerText(element, out var text) && + this.OnError(ConverterTestType.InnerTextDeprecated, element, "Using {0} element text is deprecated. Use the '{1}' attribute instead.", element.Name.LocalName, attributeName)) + { + element.Add(new XAttribute(attributeName, text)); + RemoveChildren(element); + } + } + + void RemoveAttributeIfPresent(XElement element, string attributeName, ConverterTestType type, string format) + { + var xAttribute = element.Attribute(attributeName); + if (null != xAttribute && this.OnError(type, element, format, element.Name.LocalName, xAttribute.Name)) + { + xAttribute.Remove(); + } + } + + private void RenameWin64ToBitness(XElement element) + { + var win64 = element.Attribute("Win64"); + if (win64 != null && this.OnError(ConverterTestType.Win64AttributeRenamed, element, "The {0} element's Win64 attribute has been renamed. Use the Bitness attribute instead.", element.Name.LocalName)) + { + var value = this.UpdateWin64ValueToBitnessValue(win64); + element.Add(new XAttribute("Bitness", value)); + win64.Remove(); + } + } + + private string UpdateWin64ValueToBitnessValue(XAttribute xWin64Attribute) + { + var value = xWin64Attribute.Value ?? String.Empty; + switch (value) + { + case "yes": + return "always64"; + case "no": + return "always32"; + default: + this.OnError(ConverterTestType.Win64AttributeRenameCannotBeAutomatic, xWin64Attribute, "Breaking change: The Win64 attribute's value '{0}' cannot be converted automatically to the new Bitness attribute.", value); + return value; + } + } + + private IEnumerable YieldConverterTypes(IEnumerable types) + { + if (null != types) + { + foreach (var type in types) + { + if (Enum.TryParse(type, true, out var itt)) + { + yield return itt; + } + else // not a known ConverterTestType + { + this.OnError(ConverterTestType.ConverterTestTypeUnknown, null, "Unknown error type: '{0}'.", type); + } + } + } + } + + private static void UpdateElementsWithDeprecatedNamespaces(IEnumerable elements, Dictionary deprecatedToUpdatedNamespaces) + { + foreach (var element in elements) + { + if (deprecatedToUpdatedNamespaces.TryGetValue(element.Name.Namespace, out var ns)) + { + element.Name = ns.GetName(element.Name.LocalName); + } + + // Remove all the attributes and add them back to with their namespace updated (as necessary). + IEnumerable attributes = element.Attributes().ToList(); + element.RemoveAttributes(); + + foreach (var attribute in attributes) + { + var convertedAttribute = attribute; + + if (attribute.IsNamespaceDeclaration) + { + if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Value, out ns)) + { + if (ns == XNamespace.None) + { + continue; + } + + convertedAttribute = ("xmlns" == attribute.Name.LocalName) ? new XAttribute(attribute.Name.LocalName, ns.NamespaceName) : new XAttribute(XNamespace.Xmlns + attribute.Name.LocalName, ns.NamespaceName); + } + } + else if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Name.Namespace, out ns)) + { + convertedAttribute = new XAttribute(ns.GetName(attribute.Name.LocalName), attribute.Value); + } + + element.Add(convertedAttribute); + } + } + } + + /// + /// Determine if the whitespace preceding a node is appropriate for its depth level. + /// + /// Indentation value to use when validating leading whitespace. + /// The depth level that should match this whitespace. + /// The whitespace to validate. + /// true if the whitespace is legal; false otherwise. + private static bool LeadingWhitespaceValid(int indentationAmount, int level, string whitespace) + { + // Strip off leading newlines; there can be an arbitrary number of these. + whitespace = whitespace.TrimStart(XDocumentNewLine); + + var indentation = new string(' ', level * indentationAmount); + + return whitespace == indentation; + } + + /// + /// Fix the whitespace in a whitespace node. + /// + /// Indentation value to use when validating leading whitespace. + /// The depth level of the desired whitespace. + /// The whitespace node to fix. + private static void FixupWhitespace(int indentationAmount, int level, XText whitespace) + { + var value = new StringBuilder(whitespace.Value.Length); + + // Keep any previous preceeding new lines. + var newlines = whitespace.Value.TakeWhile(c => c == XDocumentNewLine).Count(); + + // Ensure there is always at least one new line before the indentation. + value.Append(XDocumentNewLine, newlines == 0 ? 1 : newlines); + + whitespace.Value = value.Append(' ', level * indentationAmount).ToString(); + } + + /// + /// Removes unused namespaces from the element and its children. + /// + /// Root element to start at. + private void RemoveUnusedNamespaces(XElement root) + { + var declarations = new List(); + var namespaces = new HashSet(); + + VisitElement(root, x => + { + if (x is XAttribute a && a.IsNamespaceDeclaration) + { + declarations.Add(a); + namespaces.Add(a.Value); + } + return true; + }); + + foreach (var ns in namespaces.ToList()) + { + VisitElement(root, x => + { + if ((x is XElement e && e.Name.Namespace == ns) || + (x is XAttribute a && !a.IsNamespaceDeclaration && a.Name.Namespace == ns)) + { + namespaces.Remove(ns); + return false; + } + + return true; + }); + } + + foreach (var declaration in declarations) + { + if (namespaces.Contains(declaration.Value) && + this.OnError(ConverterTestType.RemoveUnusedNamespaces, declaration, "The namespace '{0}' is not used. Remove unused namespaces.", declaration.Value)) + { + declaration.Remove(); + } + } + } + + /// + /// Output an error message to the console. + /// + /// The type of converter test. + /// The node that caused the error. + /// Detailed error message. + /// Additional formatted string arguments. + /// Returns true indicating that action should be taken on this error, and false if it should be ignored. + private bool OnError(ConverterTestType converterTestType, XObject node, string message, params object[] args) + { + // Ignore the error if explicitly ignored or outside the range of the current operation. + if (this.IgnoreErrors.Contains(converterTestType) || + (this.Operation == ConvertOperation.Convert && converterTestType < ConverterTestType.EndIgnoreInConvert) || + (this.Operation == ConvertOperation.Format && converterTestType > ConverterTestType.BeginIgnoreInFormat)) + { + return false; + } + + // Increase the error count. + this.Errors++; + + var sourceLine = (null == node) ? new SourceLineNumber(this.SourceFile ?? "wix.exe") : new SourceLineNumber(this.SourceFile, ((IXmlLineInfo)node).LineNumber); + var warning = this.ErrorsAsWarnings.Contains(converterTestType); + var display = String.Format(CultureInfo.CurrentCulture, message, args); + + var msg = new Message(sourceLine, warning ? MessageLevel.Warning : MessageLevel.Error, (int)converterTestType, "{0} ({1})", display, converterTestType.ToString()); + + this.Messaging.Write(msg); + + return true; + } + + /// + /// Return an identifier based on passed file/directory name + /// + /// File/directory name to generate identifer from + /// A version of the name that is a legal identifier. + /// This is duplicated from WiX's Common class. + private static string GetIdentifierFromName(string name) + { + var result = IllegalIdentifierCharacters.Replace(name, "_"); // replace illegal characters with "_". + + // MSI identifiers must begin with an alphabetic character or an + // underscore. Prefix all other values with an underscore. + if (AddPrefix.IsMatch(name)) + { + result = String.Concat("_", result); + } + + return result; + } + + private static string LowercaseFirstChar(string value) + { + if (!String.IsNullOrEmpty(value)) + { + var c = Char.ToLowerInvariant(value[0]); + if (c != value[0]) + { + var remainder = value.Length > 1 ? value.Substring(1) : String.Empty; + return c + remainder; + } + } + + return value; + } + + private static string UppercaseFirstChar(string value) + { + if (!String.IsNullOrEmpty(value)) + { + var c = Char.ToUpperInvariant(value[0]); + if (c != value[0]) + { + var remainder = value.Length > 1 ? value.Substring(1) : String.Empty; + return c + remainder; + } + } + + return value; + } + + private static bool TryGetInnerText(XElement element, out string value) + { + value = null; + + var nodes = element.Nodes(); + + if (nodes.All(e => e.NodeType == XmlNodeType.Text || e.NodeType == XmlNodeType.CDATA)) + { + value = String.Join(String.Empty, nodes.Cast().Select(TrimTextValue)); + } + + return !String.IsNullOrEmpty(value); + } + + private static bool IsTextNode(XNode node, out XText text) + { + text = null; + + if (node.NodeType == XmlNodeType.Text || node.NodeType == XmlNodeType.CDATA) + { + text = (XText)node; + } + + return text != null; + } + + private static void TrimLeadingText(XDocument document) + { + while (IsTextNode(document.Nodes().FirstOrDefault(), out var text)) + { + text.Remove(); + } + } + + private static string TrimTextValue(XText text) + { + var value = text.Value; + + if (String.IsNullOrEmpty(value)) + { + return String.Empty; + } + else if (text.NodeType == XmlNodeType.CDATA && String.IsNullOrWhiteSpace(value)) + { + return " "; + } + + return value.Trim(); + } + + private static void RemoveChildren(XElement element) + { + var nodes = element.Nodes().ToList(); + foreach (var node in nodes) + { + node.Remove(); + } + } + + private static bool VisitElement(XElement element, Func visitor) + { + if (!visitor(element)) + { + return false; + } + + if (!element.Attributes().All(a => visitor(a))) + { + return false; + } + + return element.Elements().All(e => VisitElement(e, visitor)); + } + + private static bool WasImplicitlyStringTyped(string value) + { + if (value == null) + { + return false; + } + else if (value.StartsWith("v", StringComparison.OrdinalIgnoreCase)) + { + if (Int32.TryParse(value.Substring(1), NumberStyles.None, CultureInfo.InvariantCulture.NumberFormat, out var _)) + { + return false; + } + else if (Version.TryParse(value.Substring(1), out var _)) + { + return false; + } + } + else if (Int64.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture.NumberFormat, out var _)) + { + return false; + } + + return true; + } + + /// + /// Converter test types. These are used to condition error messages down to warnings. + /// + private enum ConverterTestType + { + /// + /// Internal-only: displayed when a string cannot be converted to an ConverterTestType. + /// + ConverterTestTypeUnknown, + + /// + /// Displayed when an XML loading exception has occurred. + /// + XmlException, + + /// + /// Displayed when the whitespace preceding a node is wrong. + /// + WhitespacePrecedingNodeWrong, + + /// + /// Displayed when the whitespace preceding an end element is wrong. + /// + WhitespacePrecedingEndElementWrong, + + /// Before this point, ignore errors on convert operation + EndIgnoreInConvert, + + /// + /// Displayed when the XML declaration is present in the source file. + /// + DeclarationPresent, + + /// + /// Displayed when a file cannot be accessed; typically when trying to save back a fixed file. + /// + UnauthorizedAccessException, + + /// After this point, ignore errors on format operation + BeginIgnoreInFormat, + + /// + /// Displayed when the xmlns attribute is missing from the document element. + /// + XmlnsMissing, + + /// + /// Displayed when the xmlns attribute on the document element is wrong. + /// + XmlnsValueWrong, + + /// + /// Displayed when inner text contains a deprecated $(loc.xxx) reference. + /// + DeprecatedLocalizationVariablePrefixInTextValue, + + /// + /// Displayed when an attribute value contains a deprecated $(loc.xxx) reference. + /// + DeprecatedLocalizationVariablePrefixInAttributeValue, + + /// + /// Assign an identifier to a File element when on Id attribute is specified. + /// + AssignAnonymousFileId, + + /// + /// SuppressSignatureValidation attribute is obsolete and corresponding functionality removed. + /// + BundleSignatureValidationObsolete, + + /// + /// WixCA Binary/@Id has been renamed to UtilCA. + /// + WixCABinaryIdRenamed, + + /// + /// QtExec custom actions have been renamed. + /// + QuietExecCustomActionsRenamed, + + /// + /// QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout. + /// + QtExecCmdTimeoutAmbiguous, + + /// + /// Directory/@ShortName may only be specified with Directory/@Name. + /// + AssignDirectoryNameFromShortName, + + /// + /// BootstrapperApplicationData attribute is deprecated and replaced with Unreal for MSI. Use BundleCustomData element for Bundles. + /// + BootstrapperApplicationDataDeprecated, + + /// + /// Inheritable is new and is now defaulted to 'yes' which is a change in behavior for all but children of CreateFolder. + /// + AssignPermissionExInheritable, + + /// + /// Column element's Category attribute is camel-case. + /// + ColumnCategoryCamelCase, + + /// + /// Column element's Modularize attribute is camel-case. + /// + ColumnModularizeCamelCase, + + /// + /// Inner text value should move to an attribute. + /// + InnerTextDeprecated, + + /// + /// Explicit auto-GUID unnecessary. + /// + AutoGuidUnnecessary, + + /// + /// The Feature Absent attribute renamed to AllowAbsent. + /// + FeatureAbsentAttributeReplaced, + + /// + /// The Feature AllowAdvertise attribute value deprecated. + /// + FeatureAllowAdvertiseValueDeprecated, + + /// + /// The Condition='1' attribute is unnecessary on Publish elements. + /// + PublishConditionOneUnnecessary, + + /// + /// DpiAwareness is new and is defaulted to 'perMonitorV2' which is a change in behavior. + /// + AssignBootstrapperApplicationDpiAwareness, + + /// + /// The string variable type was previously treated as formatted. + /// + AssignVariableTypeFormatted, + + /// + /// The CustomAction attributes have been renamed from BinaryKey and FileKey to BinaryRef and FileRef. + /// + CustomActionKeysAreNowRefs, + + /// + /// The Product and Package elements have been renamed and reorganized. + /// + ProductAndPackageRenamed, + + /// + /// The Module and Package elements have been renamed and reorganized. + /// + ModuleAndPackageRenamed, + + /// + /// A MediaTemplate with no attributes set is now provided by default. + /// + DefaultMediaTemplate, + + /// + /// util:RegistrySearch has breaking change when value is missing. + /// + UtilRegistryValueSearchBehaviorChange, + + /// + /// DisplayInternalUI can't be converted. + /// + DisplayInternalUiNotConvertable, + + /// + /// InstallerVersion has breaking change when missing. + /// + InstallerVersionBehaviorChange, + + /// + /// Verb/@Target can't be converted. + /// + VerbTargetNotConvertable, + + /// + /// The bootstrapper application dll is now specified in its own element. + /// + BootstrapperApplicationDll, + + /// + /// The new bootstrapper application dll element is required. + /// + BootstrapperApplicationDllRequired, + + /// + /// bal:UseUILanguages is deprecated, 'true' is now the standard behavior. + /// + BalUseUILanguagesDeprecated, + + /// + /// The custom elements for built-in BAs are now required. + /// + BalBootstrapperApplicationRefToElement, + + /// + /// The ExePackage elements "XxxCommand" attributes have been renamed to "XxxArguments". + /// + RenameExePackageCommandToArguments, + + /// + /// The Win64 attribute has been renamed. Use the Bitness attribute instead. + /// + Win64AttributeRenamed, + + /// + /// Breaking change: The Win64 attribute's value '{0}' cannot be converted automatically to the new Bitness attribute. + /// + Win64AttributeRenameCannotBeAutomatic, + + /// + /// The Tag element has been renamed. Use the element 'SoftwareTag' name. + /// + TagElementRenamed, + + /// + /// The Dependency namespace has been incorporated into WiX v4 namespace. + /// + IntegratedDependencyNamespace, + + /// + /// Remove unused namespaces. + /// + RemoveUnusedNamespaces, + + /// + /// The Remote element has been renamed. Use the "XxxPackagePayload" element instead. + /// + RemotePayloadRenamed, + + /// + /// The XxxPackage/@Name attribute must be specified on the child XxxPackagePayload element when using a remote payload. + /// + NameAttributeMovedToRemotePayload, + + /// + /// The XxxPackage/@Compressed attribute should not be specified when using a remote payload. + /// + CompressedAttributeUnnecessaryForRemotePayload, + + /// + /// The XxxPackage/@DownloadUrl attribute must be specified on the child XxxPackagePayload element when using a remote payload. + /// + DownloadUrlAttributeMovedToRemotePayload, + + /// + /// The hash algorithm used for bundles changed from SHA1 to SHA512. + /// + BurnHashAlgorithmChanged, + + /// + /// CustomTable elements can't always be converted. + /// + CustomTableNotAlwaysConvertable, + + /// + /// CustomTable elements that don't contain the table definition are now CustomTableRef. + /// + CustomTableRef, + + /// + /// The RegistryKey element's Action attribute is obsolete. + /// + RegistryKeyActionObsolete, + + /// + /// The TagRef element has been renamed. Use the element 'SoftwareTagRef' name. + /// + TagRefElementRenamed, + + /// + /// The SoftwareTag element's Licensed attribute is obsolete. + /// + SoftwareTagLicensedObsolete, + + /// + /// The SoftwareTag element's Type attribute is obsolete. + /// + SoftwareTagTypeObsolete, + + /// + /// TARGETDIR directory should not longer be explicitly defined. + /// + TargetDirDeprecated, + + /// + /// Standard directories should no longer be defined using the Directory element. + /// + DefiningStandardDirectoryDeprecated, + + /// + /// Naked custom action and property references replaced with WixUtilExtension elements. + /// + UtilReferencesReplaced, + } + } +} diff --git a/src/wix/WixToolset.Converters/WixToolset.Converters.csproj b/src/wix/WixToolset.Converters/WixToolset.Converters.csproj new file mode 100644 index 00000000..7dddefa5 --- /dev/null +++ b/src/wix/WixToolset.Converters/WixToolset.Converters.csproj @@ -0,0 +1,24 @@ + + + + + + + netstandard2.0 + $(TargetFrameworks);net461;net472 + Converter + WiX Toolset Converters + embedded + true + true + + + + + + + + + + + diff --git a/src/wix/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs b/src/wix/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs new file mode 100644 index 00000000..084d3b92 --- /dev/null +++ b/src/wix/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs @@ -0,0 +1,25 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Converters +{ + using WixToolset.Extensibility.Services; + + /// + /// Extension methods for adding Converters services. + /// + public static class WixToolsetCoreServiceProviderExtensions + { + /// + /// Adds Converters services. + /// + /// + /// + public static IWixToolsetCoreServiceProvider AddConverter(this IWixToolsetCoreServiceProvider coreProvider) + { + var extensionManager = coreProvider.GetService(); + extensionManager.Add(typeof(ConverterExtensionFactory).Assembly); + + return coreProvider; + } + } +} diff --git a/src/wix/appveyor.cmd b/src/wix/appveyor.cmd new file mode 100644 index 00000000..02db695b --- /dev/null +++ b/src/wix/appveyor.cmd @@ -0,0 +1,20 @@ +@setlocal +@pushd %~dp0 +@set _P=%~dp0build\Release\publish +@set _C=Release +@if /i "%1"=="debug" set _C=Debug + +:: Restore +msbuild -p:Configuration=%_C% -t:Restore || exit /b + +:: Build +msbuild -p:Configuration=%_C% || exit /b + +:: Test +dotnet test -c %_C% --no-build || exit /b + +:: Pack +msbuild -p:Configuration=%_C% -p:NoBuild=true -t:Pack || exit /b + +@popd +@endlocal diff --git a/src/wix/appveyor.yml b/src/wix/appveyor.yml new file mode 100644 index 00000000..364569cf --- /dev/null +++ b/src/wix/appveyor.yml @@ -0,0 +1,44 @@ +# Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. +# +# Do NOT modify this file. Update the canonical version in Home\repo-template\src\appveyor.yml +# then update all of the repos. + +branches: + only: + - master + - develop + +image: Visual Studio 2019 + +version: 0.0.0.{build} +configuration: Release + +environment: + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: 1 + NUGET_XMLDOC_MODE: skip + +build_script: + - appveyor.cmd + +test: off + +pull_requests: + do_not_increment_build_number: true + +nuget: + disable_publish_on_pr: true + +skip_branch_with_pr: true +skip_tags: true + +artifacts: +- path: build\Release\**\*.nupkg + name: nuget +- path: build\Release\**\*.snupkg + name: snupkg + +notifications: +- provider: Slack + incoming_webhook: + secure: p5xuu+4x2JHfwGDMDe5KcG1k7gZxqYc4jWVwvyNZv5cvkubPD2waJs5yXMAXZNN7Z63/3PWHb7q4KoY/99AjauYa1nZ4c5qYqRPFRBKTHfA= diff --git a/src/wix/deps/wix.dll b/src/wix/deps/wix.dll new file mode 100644 index 00000000..64f70f75 Binary files /dev/null and b/src/wix/deps/wix.dll differ diff --git a/src/wix/nuget.config b/src/wix/nuget.config new file mode 100644 index 00000000..31435a21 --- /dev/null +++ b/src/wix/nuget.config @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/wix/test/WixToolsetTest.Converters.Symbolizer/ConvertSymbolsFixture.cs b/src/wix/test/WixToolsetTest.Converters.Symbolizer/ConvertSymbolsFixture.cs new file mode 100644 index 00000000..01213524 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters.Symbolizer/ConvertSymbolsFixture.cs @@ -0,0 +1,606 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters.Symbolizer +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using WixBuildTools.TestSupport; + using Wix3 = Microsoft.Tools.WindowsInstallerXml; + using WixToolset.Converters.Symbolizer; + using WixToolset.Data; + using WixToolset.Data.WindowsInstaller; + using WixToolset.Data.Symbols; + using Xunit; + + public class ConvertSymbolsFixture + { + [Fact] + public void CanLoadWixoutAndConvertToIntermediate() + { + var rootFolder = TestData.Get(); + var dataFolder = TestData.Get(@"TestData\Integration"); + + using (var fs = new DisposableFileSystem()) + { + var intermediateFolder = fs.GetFolder(); + + var path = Path.Combine(dataFolder, "test.wixout"); + + var intermediate = ConvertSymbols.ConvertFile(path); + + Assert.NotNull(intermediate); + Assert.Single(intermediate.Sections); + Assert.Equal(String.Empty, intermediate.Id); + + // Save and load to guarantee round-tripping support. + // + var wixiplFile = Path.Combine(intermediateFolder, "test.wixipl"); + intermediate.Save(wixiplFile); + + intermediate = Intermediate.Load(wixiplFile); + + var output = Wix3.Output.Load(path, suppressVersionCheck: true, suppressSchema: true); + var wixMediaByDiskId = IndexWixMediaTableByDiskId(output); + + // Dump to text for easy diffing, with some massaging to keep v3 and v4 diffable. + // + var tables = output.Tables.Cast(); + var wix3Dump = tables + .SelectMany(table => table.Rows.Cast() + .SelectMany(row => RowToStrings(row, wixMediaByDiskId))) + .Where(s => !String.IsNullOrEmpty(s)) + .OrderBy(s => s) + .ToArray(); + + var symbols = intermediate.Sections.SelectMany(s => s.Symbols); + + var assemblySymbolsByFileId = symbols.OfType().ToDictionary(a => a.Id.Id); + + var wix4Dump = symbols + .SelectMany(symbol => SymbolToStrings(symbol, assemblySymbolsByFileId)) + .OrderBy(s => s) + .ToArray(); + +#if false + Assert.Equal(wix3Dump, wix4Dump); +#else // useful when you want to diff the outputs with another diff tool. + var wix3TextDump = String.Join(Environment.NewLine, wix3Dump); + var wix4TextDump = String.Join(Environment.NewLine, wix4Dump); + + var path3 = Path.Combine(Path.GetTempPath(), "~3.txt"); + var path4 = Path.Combine(Path.GetTempPath(), "~4.txt"); + + File.WriteAllText(path3, wix3TextDump); + File.WriteAllText(path4, wix4TextDump); + + Assert.Equal(wix3TextDump, wix4TextDump); +#endif + } + } + + private static Dictionary IndexWixMediaTableByDiskId(Wix3.Output output) + { + var wixMediaByDiskId = new Dictionary(); + var wixMediaTable = output.Tables["WixMedia"]; + + if (wixMediaTable != null) + { + foreach (Wix3.WixMediaRow row in wixMediaTable.Rows) + { + wixMediaByDiskId.Add((int)row[0], row); + } + } + + return wixMediaByDiskId; + } + + private static IEnumerable RowToStrings(Wix3.Row row, Dictionary wixMediaByDiskId) + { + string fields = null; + + // Massage output to match WiX v3 rows and v4 symbols. + // + switch (row.Table.Name) + { + case "Directory": + var dirs = SplitDefaultDir((string)row[2]); + fields = String.Join(",", row[0], row[1], dirs[0], dirs[1], dirs[2], dirs[3]); + break; + case "File": + { + var fieldValues = row.Fields.Take(7).Select(SafeConvertField).ToArray(); + if (fieldValues[3] == null) + { + // "Somebody" sometimes writes out a null field even when the column definition says + // it's non-nullable. Not naming names or anything. (SWID tags.) + fieldValues[3] = "0"; + } + fields = String.Join(",", fieldValues); + break; + } + case "Media": + var compression = wixMediaByDiskId.TryGetValue((int)row[0], out var wixMedia) ? (CompressionLevel?)Enum.Parse(typeof(CompressionLevel), SafeConvertField(wixMedia.Fields[1]), true) : null; + + fields = String.Join(",", row.Fields.Select(SafeConvertField)); + fields = String.Join(",", fields, (int?)compression, SafeConvertField(wixMedia?.Fields[2])); + break; + case "RegLocator": + var type = (int)row[4]; + fields = String.Join(",", row[0], row[1], row[2], row[3], type & 0xF, (type & 0x10) == 0x10); + break; + case "RemoveFile": + var attributes = (int)row[4]; + var onInstall = (attributes & 1) == 1 ? (bool?)true : null; + var onUninstall = (attributes & 2) == 2 ? (bool?)true : null; + fields = String.Join(",", row.Fields.Take(4).Select(SafeConvertField)); + fields = String.Join(",", fields, onInstall, onUninstall); + break; + case "Shortcut": + var split = ((string)row[2]).Split('|'); + var afterName = String.Join(",", row.Fields.Skip(3).Select(SafeConvertField)); + fields = String.Join(",", row[0], row[1], split.Length > 1 ? split[1] : split[0], split.Length > 1 ? split[0] : String.Empty, afterName); + break; + case "WixAction": + var table = (int)SequenceStringToSequenceTable(row[0]); + fields = String.Join(",", table, row[1], row[2], row[3], row[4], row[5], row[6]); + break; + case "WixFile": + { + var fieldValues = row.Fields.Select(SafeConvertField).ToArray(); + if (fieldValues[8] == null) + { + // "Somebody" sometimes writes out a null field even when the column definition says + // it's non-nullable. Not naming names or anything. (SWID tags.) + fieldValues[8] = "0"; + } + if (fieldValues[10] == null) + { + // WixFile rows that come from merge modules will not have the attributes column set + // so initilaize with 0. + fieldValues[10] = "0"; + } + fields = String.Join(",", fieldValues); + break; + } + case "WixMedia": + break; + default: + fields = String.Join(",", row.Fields.Select(SafeConvertField)); + break; + } + + if (fields != null) + { + yield return $"{row.Table.Name}:{fields}"; + } + } + + private static IEnumerable SymbolToStrings(IntermediateSymbol symbol, Dictionary assemblySymbolsByFileId) + { + var name = symbol.Definition.Type == SymbolDefinitionType.SummaryInformation ? "_SummaryInformation" : symbol.Definition.Name; + var id = symbol.Id?.Id ?? String.Empty; + + string fields; + switch (symbol.Definition.Name) + { + // Massage output to match WiX v3 rows and v4 symbols. + // + case "Component": + { + var componentSymbol = (ComponentSymbol)symbol; + var attributes = ComponentLocation.Either == componentSymbol.Location ? WindowsInstallerConstants.MsidbComponentAttributesOptional : 0; + attributes |= ComponentLocation.SourceOnly == componentSymbol.Location ? WindowsInstallerConstants.MsidbComponentAttributesSourceOnly : 0; + attributes |= ComponentKeyPathType.Registry == componentSymbol.KeyPathType ? WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath : 0; + attributes |= ComponentKeyPathType.OdbcDataSource == componentSymbol.KeyPathType ? WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource : 0; + attributes |= componentSymbol.DisableRegistryReflection ? WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection : 0; + attributes |= componentSymbol.NeverOverwrite ? WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite : 0; + attributes |= componentSymbol.Permanent ? WindowsInstallerConstants.MsidbComponentAttributesPermanent : 0; + attributes |= componentSymbol.SharedDllRefCount ? WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount : 0; + attributes |= componentSymbol.Shared ? WindowsInstallerConstants.MsidbComponentAttributesShared : 0; + attributes |= componentSymbol.Transitive ? WindowsInstallerConstants.MsidbComponentAttributesTransitive : 0; + attributes |= componentSymbol.UninstallWhenSuperseded ? WindowsInstallerConstants.MsidbComponentAttributes64bit : 0; + attributes |= componentSymbol.Win64 ? WindowsInstallerConstants.MsidbComponentAttributes64bit : 0; + + fields = String.Join(",", + componentSymbol.ComponentId, + componentSymbol.DirectoryRef, + attributes.ToString(), + componentSymbol.Condition, + componentSymbol.KeyPath + ); + break; + } + case "CustomAction": + { + var customActionSymbol = (CustomActionSymbol)symbol; + var type = customActionSymbol.Win64 ? WindowsInstallerConstants.MsidbCustomActionType64BitScript : 0; + type |= customActionSymbol.TSAware ? WindowsInstallerConstants.MsidbCustomActionTypeTSAware : 0; + type |= customActionSymbol.Impersonate ? 0 : WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate; + type |= customActionSymbol.IgnoreResult ? WindowsInstallerConstants.MsidbCustomActionTypeContinue : 0; + type |= customActionSymbol.Hidden ? WindowsInstallerConstants.MsidbCustomActionTypeHideTarget : 0; + type |= customActionSymbol.Async ? WindowsInstallerConstants.MsidbCustomActionTypeAsync : 0; + type |= CustomActionExecutionType.FirstSequence == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence : 0; + type |= CustomActionExecutionType.OncePerProcess == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess : 0; + type |= CustomActionExecutionType.ClientRepeat == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat : 0; + type |= CustomActionExecutionType.Deferred == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript : 0; + type |= CustomActionExecutionType.Rollback == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback : 0; + type |= CustomActionExecutionType.Commit == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit : 0; + type |= CustomActionSourceType.File == customActionSymbol.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeSourceFile : 0; + type |= CustomActionSourceType.Directory == customActionSymbol.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeDirectory : 0; + type |= CustomActionSourceType.Property == customActionSymbol.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeProperty : 0; + type |= CustomActionTargetType.Dll == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeDll : 0; + type |= CustomActionTargetType.Exe == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeExe : 0; + type |= CustomActionTargetType.TextData == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeTextData : 0; + type |= CustomActionTargetType.JScript == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeJScript : 0; + type |= CustomActionTargetType.VBScript == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeVBScript : 0; + + fields = String.Join(",", + type.ToString(), + customActionSymbol.Source, + customActionSymbol.Target, + customActionSymbol.PatchUninstall ? WindowsInstallerConstants.MsidbCustomActionTypePatchUninstall.ToString() : null + ); + break; + } + case "Directory": + { + var directorySymbol = (DirectorySymbol)symbol; + + if (!String.IsNullOrEmpty(directorySymbol.ComponentGuidGenerationSeed)) + { + yield return $"WixDirectory:{directorySymbol.Id.Id},{directorySymbol.ComponentGuidGenerationSeed}"; + } + + fields = String.Join(",", directorySymbol.ParentDirectoryRef, directorySymbol.Name, directorySymbol.ShortName, directorySymbol.SourceName, directorySymbol.SourceShortName); + break; + } + case "Feature": + { + var featureSymbol = (FeatureSymbol)symbol; + var attributes = featureSymbol.DisallowAbsent ? WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent : 0; + attributes |= featureSymbol.DisallowAdvertise ? WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise : 0; + attributes |= FeatureInstallDefault.FollowParent == featureSymbol.InstallDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFollowParent : 0; + attributes |= FeatureInstallDefault.Source == featureSymbol.InstallDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFavorSource : 0; + attributes |= FeatureTypicalDefault.Advertise == featureSymbol.TypicalDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise : 0; + + fields = String.Join(",", + featureSymbol.ParentFeatureRef, + featureSymbol.Title, + featureSymbol.Description, + featureSymbol.Display.ToString(), + featureSymbol.Level.ToString(), + featureSymbol.DirectoryRef, + attributes.ToString()); + break; + } + case "File": + { + var fileSymbol = (FileSymbol)symbol; + + if (fileSymbol.BindPath != null) + { + yield return $"BindImage:{fileSymbol.Id.Id},{fileSymbol.BindPath}"; + } + + if (fileSymbol.FontTitle != null) + { + yield return $"Font:{fileSymbol.Id.Id},{fileSymbol.FontTitle}"; + } + + if (fileSymbol.SelfRegCost.HasValue) + { + yield return $"SelfReg:{fileSymbol.Id.Id},{fileSymbol.SelfRegCost}"; + } + + int? assemblyAttributes = null; + if (assemblySymbolsByFileId.TryGetValue(fileSymbol.Id.Id, out var assemblySymbol)) + { + if (assemblySymbol.Type == AssemblyType.DotNetAssembly) + { + assemblyAttributes = 0; + } + else if (assemblySymbol.Type == AssemblyType.Win32Assembly) + { + assemblyAttributes = 1; + } + } + + yield return "WixFile:" + String.Join(",", + fileSymbol.Id.Id, + assemblyAttributes, + assemblySymbol?.ManifestFileRef, + assemblySymbol?.ApplicationFileRef, + fileSymbol.DirectoryRef, + fileSymbol.DiskId, + fileSymbol.Source.Path, + null, // assembly processor arch + fileSymbol.PatchGroup, + 0, + (int)fileSymbol.PatchAttributes, + fileSymbol.RetainLengths, + fileSymbol.IgnoreOffsets, + fileSymbol.IgnoreLengths, + fileSymbol.RetainOffsets + ); + + var fileAttributes = 0; + fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.ReadOnly) != 0 ? WindowsInstallerConstants.MsidbFileAttributesReadOnly : 0; + fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Hidden) != 0 ? WindowsInstallerConstants.MsidbFileAttributesHidden : 0; + fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.System) != 0 ? WindowsInstallerConstants.MsidbFileAttributesSystem : 0; + fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Vital) != 0 ? WindowsInstallerConstants.MsidbFileAttributesVital : 0; + fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Checksum) != 0 ? WindowsInstallerConstants.MsidbFileAttributesChecksum : 0; + fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Compressed) != 0 ? WindowsInstallerConstants.MsidbFileAttributesCompressed : 0; + fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Uncompressed) != 0 ? WindowsInstallerConstants.MsidbFileAttributesNoncompressed : 0; + + fields = String.Join(",", + fileSymbol.ComponentRef, + fileSymbol.Name, + fileSymbol.FileSize.ToString(), + fileSymbol.Version, + fileSymbol.Language, + fileAttributes); + break; + } + + case "Media": + fields = String.Join(",", symbol.Fields.Skip(1).Select(SafeConvertField)); + break; + + case "Assembly": + { + var assemblySymbol = (AssemblySymbol)symbol; + + id = null; + name = "MsiAssembly"; + fields = String.Join(",", assemblySymbol.ComponentRef, assemblySymbol.FeatureRef, assemblySymbol.ManifestFileRef, assemblySymbol.ApplicationFileRef, assemblySymbol.Type == AssemblyType.Win32Assembly ? 1 : 0); + break; + } + case "RegLocator": + { + var locatorSymbol = (RegLocatorSymbol)symbol; + + fields = String.Join(",", (int)locatorSymbol.Root, locatorSymbol.Key, locatorSymbol.Name, (int)locatorSymbol.Type, locatorSymbol.Win64); + break; + } + case "Registry": + { + var registrySymbol = (RegistrySymbol)symbol; + var value = registrySymbol.Value; + + switch (registrySymbol.ValueType) + { + case RegistryValueType.Binary: + value = String.Concat("#x", value); + break; + case RegistryValueType.Expandable: + value = String.Concat("#%", value); + break; + case RegistryValueType.Integer: + value = String.Concat("#", value); + break; + case RegistryValueType.MultiString: + switch (registrySymbol.ValueAction) + { + case RegistryValueActionType.Append: + value = String.Concat("[~]", value); + break; + case RegistryValueActionType.Prepend: + value = String.Concat(value, "[~]"); + break; + case RegistryValueActionType.Write: + default: + if (null != value && -1 == value.IndexOf("[~]", StringComparison.Ordinal)) + { + value = String.Concat("[~]", value, "[~]"); + } + break; + } + break; + case RegistryValueType.String: + // escape the leading '#' character for string registry keys + if (null != value && value.StartsWith("#", StringComparison.Ordinal)) + { + value = String.Concat("#", value); + } + break; + } + + fields = String.Join(",", + ((int)registrySymbol.Root).ToString(), + registrySymbol.Key, + registrySymbol.Name, + value, + registrySymbol.ComponentRef + ); + break; + } + + case "RemoveRegistry": + { + var removeRegistrySymbol = (RemoveRegistrySymbol)symbol; + fields = String.Join(",", + ((int)removeRegistrySymbol.Root).ToString(), + removeRegistrySymbol.Key, + removeRegistrySymbol.Name, + removeRegistrySymbol.ComponentRef + ); + break; + } + + case "ServiceControl": + { + var serviceControlSymbol = (ServiceControlSymbol)symbol; + + var events = serviceControlSymbol.InstallRemove ? WindowsInstallerConstants.MsidbServiceControlEventDelete : 0; + events |= serviceControlSymbol.UninstallRemove ? WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete : 0; + events |= serviceControlSymbol.InstallStart ? WindowsInstallerConstants.MsidbServiceControlEventStart : 0; + events |= serviceControlSymbol.UninstallStart ? WindowsInstallerConstants.MsidbServiceControlEventUninstallStart : 0; + events |= serviceControlSymbol.InstallStop ? WindowsInstallerConstants.MsidbServiceControlEventStop : 0; + events |= serviceControlSymbol.UninstallStop ? WindowsInstallerConstants.MsidbServiceControlEventUninstallStop : 0; + + fields = String.Join(",", + serviceControlSymbol.Name, + events.ToString(), + serviceControlSymbol.Arguments, + serviceControlSymbol.Wait == true ? "1" : "0", + serviceControlSymbol.ComponentRef + ); + break; + } + + case "ServiceInstall": + { + var serviceInstallSymbol = (ServiceInstallSymbol)symbol; + + var errorControl = (int)serviceInstallSymbol.ErrorControl; + errorControl |= serviceInstallSymbol.Vital ? WindowsInstallerConstants.MsidbServiceInstallErrorControlVital : 0; + + var serviceType = (int)serviceInstallSymbol.ServiceType; + serviceType |= serviceInstallSymbol.Interactive ? WindowsInstallerConstants.MsidbServiceInstallInteractive : 0; + + fields = String.Join(",", + serviceInstallSymbol.Name, + serviceInstallSymbol.DisplayName, + serviceType.ToString(), + ((int)serviceInstallSymbol.StartType).ToString(), + errorControl.ToString(), + serviceInstallSymbol.LoadOrderGroup, + serviceInstallSymbol.Dependencies, + serviceInstallSymbol.StartName, + serviceInstallSymbol.Password, + serviceInstallSymbol.Arguments, + serviceInstallSymbol.ComponentRef, + serviceInstallSymbol.Description + ); + break; + } + + case "Upgrade": + { + var upgradeSymbol = (UpgradeSymbol)symbol; + + var attributes = upgradeSymbol.MigrateFeatures ? WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures : 0; + attributes |= upgradeSymbol.OnlyDetect ? WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect : 0; + attributes |= upgradeSymbol.IgnoreRemoveFailures ? WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure : 0; + attributes |= upgradeSymbol.VersionMinInclusive ? WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive : 0; + attributes |= upgradeSymbol.VersionMaxInclusive ? WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive : 0; + attributes |= upgradeSymbol.ExcludeLanguages ? WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive : 0; + + fields = String.Join(",", + upgradeSymbol.VersionMin, + upgradeSymbol.VersionMax, + upgradeSymbol.Language, + attributes.ToString(), + upgradeSymbol.Remove, + upgradeSymbol.ActionProperty + ); + break; + } + + case "WixAction": + { + var wixActionSymbol = (WixActionSymbol)symbol; + var data = wixActionSymbol.Fields[(int)WixActionSymbolFields.SequenceTable].AsObject(); + var sequenceTableAsInt = data is string ? (int)SequenceStringToSequenceTable(data) : (int)wixActionSymbol.SequenceTable; + + fields = String.Join(",", + sequenceTableAsInt, + wixActionSymbol.Action, + wixActionSymbol.Condition, + wixActionSymbol.Sequence?.ToString() ?? String.Empty, + wixActionSymbol.Before, + wixActionSymbol.After, + wixActionSymbol.Overridable == true ? "1" : "0" + ); + break; + } + + case "WixComplexReference": + { + var wixComplexReferenceSymbol = (WixComplexReferenceSymbol)symbol; + fields = String.Join(",", + wixComplexReferenceSymbol.Parent, + (int)wixComplexReferenceSymbol.ParentType, + wixComplexReferenceSymbol.ParentLanguage, + wixComplexReferenceSymbol.Child, + (int)wixComplexReferenceSymbol.ChildType, + wixComplexReferenceSymbol.IsPrimary ? "1" : "0" + ); + break; + } + + case "WixProperty": + { + var wixPropertySymbol = (WixPropertySymbol)symbol; + var attributes = wixPropertySymbol.Admin ? 0x1 : 0; + attributes |= wixPropertySymbol.Hidden ? 0x2 : 0; + attributes |= wixPropertySymbol.Secure ? 0x4 : 0; + + fields = String.Join(",", + wixPropertySymbol.PropertyRef, + attributes.ToString() + ); + break; + } + + default: + fields = String.Join(",", symbol.Fields.Select(SafeConvertField)); + break; + } + + fields = String.IsNullOrEmpty(id) ? fields : String.IsNullOrEmpty(fields) ? id : $"{id},{fields}"; + yield return $"{name}:{fields}"; + } + + private static SequenceTable SequenceStringToSequenceTable(object sequenceString) + { + switch (sequenceString) + { + case "AdminExecuteSequence": + return SequenceTable.AdminExecuteSequence; + case "AdminUISequence": + return SequenceTable.AdminUISequence; + case "AdvtExecuteSequence": + return SequenceTable.AdvertiseExecuteSequence; + case "InstallExecuteSequence": + return SequenceTable.InstallExecuteSequence; + case "InstallUISequence": + return SequenceTable.InstallUISequence; + default: + throw new ArgumentException($"Unknown sequence: {sequenceString}"); + } + } + + private static string SafeConvertField(Wix3.Field field) + { + return field?.Data?.ToString(); + } + + private static string SafeConvertField(IntermediateField field) + { + var data = field.AsObject(); + if (data is IntermediateFieldPathValue path) + { + return path.Path; + } + + return data?.ToString(); + } + + private static string[] SplitDefaultDir(string defaultDir) + { + var split1 = defaultDir.Split(':'); + var targetSplit = split1.Length > 1 ? split1[1].Split('|') : split1[0].Split('|'); + var sourceSplit = split1.Length > 1 ? split1[0].Split('|') : new[] { String.Empty }; + return new[] + { + targetSplit.Length > 1 ? targetSplit[1] : targetSplit[0], + targetSplit.Length > 1 ? targetSplit[0] : String.Empty, + sourceSplit.Length > 1 ? sourceSplit[1] : sourceSplit[0], + sourceSplit.Length > 1 ? sourceSplit[0] : String.Empty + }; + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixout b/src/wix/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixout new file mode 100644 index 00000000..da64b8af Binary files /dev/null and b/src/wix/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixout differ diff --git a/src/wix/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixproj b/src/wix/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixproj new file mode 100644 index 00000000..d7c4e625 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wixproj @@ -0,0 +1,47 @@ + + + + Debug + x86 + 3.10 + d59f1c1e-9238-49fa-bfa2-ec1d9c2dda1d + 2.0 + SymbolizerWixout + Package + + + bin\$(Configuration)\ + obj\$(Configuration)\ + Debug + + + bin\$(Configuration)\ + obj\$(Configuration)\ + + + + + + + $(WixExtDir)\WixUtilExtension.dll + WixUtilExtension + + + $(WixExtDir)\WixNetFxExtension.dll + WixNetFxExtension + + + + + + + + + \ No newline at end of file diff --git a/src/wix/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wxs b/src/wix/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wxs new file mode 100644 index 00000000..46d4fb43 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters.Symbolizer/TestData/Integration/test.wxs @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.csproj b/src/wix/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.csproj new file mode 100644 index 00000000..995d9297 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.csproj @@ -0,0 +1,33 @@ + + + + + + + net461 + false + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.v3.ncrunchproject b/src/wix/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.v3.ncrunchproject new file mode 100644 index 00000000..18ab4f79 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters.Symbolizer/WixToolsetTest.Converters.Symbolizer.v3.ncrunchproject @@ -0,0 +1,9 @@ + + + + + WixToolsetTest.Converters.Symbolizer.ConvertSymbolsFixture.CanLoadWixoutAndConvertToIntermediate + + + + \ No newline at end of file diff --git a/src/wix/test/WixToolsetTest.Converters/BaseConverterFixture.cs b/src/wix/test/WixToolsetTest.Converters/BaseConverterFixture.cs new file mode 100644 index 00000000..2421d73b --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/BaseConverterFixture.cs @@ -0,0 +1,33 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.IO; + using System.Text; + using System.Xml; + using System.Xml.Linq; + using Xunit; + + public abstract class BaseConverterFixture + { + protected static string UnformattedDocumentString(XDocument document, bool omitXmlDeclaration = true) + { + var sb = new StringBuilder(); + + using (var writer = new StringWriter(sb)) + using (var xml = XmlWriter.Create(writer, new XmlWriterSettings { OmitXmlDeclaration = omitXmlDeclaration })) + { + document.Save(xml); + } + + return sb.ToString().TrimStart(); + } + + protected static string[] UnformattedDocumentLines(XDocument document, bool omitXmlDeclaration = true) + { + var unformatted = UnformattedDocumentString(document, omitXmlDeclaration); + return unformatted.Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/BitnessFixture.cs b/src/wix/test/WixToolsetTest.Converters/BitnessFixture.cs new file mode 100644 index 00000000..e45a9388 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/BitnessFixture.cs @@ -0,0 +1,187 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class BitnessFixture : BaseConverterFixture + { + [Fact] + public void FixComponentBitness() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(10, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixRegistrySearchBitness() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(4, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixUtilRegistrySearchBitness() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(6, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixApprovedExeBitness() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(4, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/BootstrapperApplicationFixture.cs b/src/wix/test/WixToolsetTest.Converters/BootstrapperApplicationFixture.cs new file mode 100644 index 00000000..158ab3be --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/BootstrapperApplicationFixture.cs @@ -0,0 +1,418 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class BootstrapperApplicationFixture : BaseConverterFixture + { + [Fact] + public void CantCreateBootstrapperApplicationDllFromV3PayloadGroupRef() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(2, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void ConvertDotNetCoreBootstrapperApplicationRefWithExistingElement() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(1, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void ConvertDotNetCoreBootstrapperApplicationRefWithoutExistingElement() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + "", + "", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(1, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void ConvertFrameworkBootstrapperApplicationRefWithExistingElement() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void ConvertFrameworkBootstrapperApplicationRefWithoutExistingElement() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + "", + "", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void ConvertStandardBootstrapperApplicationRefWithExistingElement() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void ConvertStandardBootstrapperApplicationRefWithoutExistingElement() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + "", + "", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void CreateBootstrapperApplicationDllFromV3() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + "", + "", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void CreateBootstrapperApplicationDllFromV3Payload() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + "", + "", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void DoesntSetDpiUnawareFromV4() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(0, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void KeepsDpiAwarenessFromV4() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + "", + "", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(1, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void RemovesBalUseUILanguages() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(5, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/ConditionFixture.cs b/src/wix/test/WixToolsetTest.Converters/ConditionFixture.cs new file mode 100644 index 00000000..d3f65aeb --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/ConditionFixture.cs @@ -0,0 +1,297 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class ConditionFixture : BaseConverterFixture + { + [Fact] + public void FixControlCondition() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " x=y", + " a<>b", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(4, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixPublishCondition() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " 1<2", + " 1", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(5, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixComponentCondition() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " 1<2", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixFeatureCondition() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " PROP = 1", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixLaunchCondition() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " 1<2", + " ", + " ", + " 1=2", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(4, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixLaunchConditionInProduct() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " 1<2", + " ", + " ", + " 1=2", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(6, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixPermissionExCondition() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " 1<2", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/ConverterFixture.cs b/src/wix/test/WixToolsetTest.Converters/ConverterFixture.cs new file mode 100644 index 00000000..13df9da7 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/ConverterFixture.cs @@ -0,0 +1,449 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class ConverterFixture : BaseConverterFixture + { + private static readonly XNamespace Wix4Namespace = "http://wixtoolset.org/schemas/v4/wxs"; + + [Fact] + public void EnsuresNoDeclaration() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(1, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void EnsuresDeclarationWhenIgnored() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, ignoreErrors: new[] { "DeclarationPresent" } ); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document, omitXmlDeclaration: false); + + Assert.Equal(0, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void CanConvertMainNamespace() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(2, errors); + //Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace()); + Assert.Equal(expected, actual); + } + + [Fact] + public void CanConvertNamedMainNamespace() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(2, errors); + Assert.Equal(expected, actual); + Assert.Equal(Wix4Namespace, document.Root.GetNamespaceOfPrefix("w")); + } + + [Fact] + public void CanConvertNonWixDefaultNamespace() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(expected, actual); + Assert.Equal(3, errors); + Assert.Equal(Wix4Namespace, document.Root.GetNamespaceOfPrefix("w")); + Assert.Equal("http://wixtoolset.org/schemas/v4/wxs/util", document.Root.GetDefaultNamespace()); + } + + [Fact] + public void CanRemoveUnusedNamespaces() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(4, errors); + Assert.Equal(expected, actual); + Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace()); + } + + [Fact] + public void CanConvertMissingWixNamespace() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(2, errors); + Assert.Equal(expected, actual); + Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace()); + } + + [Fact] + public void CanConvertMissingIncludeNamespace() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(2, errors); + Assert.Equal(expected, actual); + Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace()); + } + + [Fact] + public void CanConvertAnonymousFile() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(3, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void CanConvertShortNameDirectoryWithoutName() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(2, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void CanConvertCatalogElement() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(1, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void CanConvertSuppressSignatureValidationNo() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(1, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void CanConvertSuppressSignatureValidationYes() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(1, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void CantConvertVerbTarget() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(2, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void CanConvertDeprecatedPrefix() + { + var parse = String.Join(Environment.NewLine, + "", + "", + "", + "", + "", + "", + "", + "", + ""); + + var expected = String.Join(Environment.NewLine, + "", + "", + "", + "", + "", + "", + "", + "", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(3, errors); + Assert.Equal(expected, actual); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/ConverterIntegrationFixture.cs b/src/wix/test/WixToolsetTest.Converters/ConverterIntegrationFixture.cs new file mode 100644 index 00000000..a39f6243 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/ConverterIntegrationFixture.cs @@ -0,0 +1,195 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.IO; + using System.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolset.Core; + using WixToolset.Core.TestPackage; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class ConverterIntegrationFixture + { + [Fact] + public void CanConvertPermissionExFile() + { + const string beforeFileName = "v3.wxs"; + const string afterFileName = "v4_expected.wxs"; + var folder = TestData.Get(@"TestData\PermissionEx"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(true); + var targetFile = Path.Combine(baseFolder, beforeFileName); + File.Copy(Path.Combine(folder, beforeFileName), Path.Combine(baseFolder, beforeFileName)); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 4); + var errors = converter.ConvertFile(targetFile, true); + + Assert.Equal(8, errors); + + var expected = File.ReadAllText(Path.Combine(folder, afterFileName)).Replace("\r\n", "\n"); + var actual = File.ReadAllText(targetFile).Replace("\r\n", "\n"); + Assert.Equal(expected, actual); + + EnsureFixed(targetFile); + } + } + + [Fact] + public void CanConvertSingleFile() + { + const string beforeFileName = "SingleFile.wxs"; + const string afterFileName = "ConvertedSingleFile.wxs"; + var folder = TestData.Get(@"TestData\SingleFile"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(true); + var targetFile = Path.Combine(baseFolder, beforeFileName); + File.Copy(Path.Combine(folder, beforeFileName), Path.Combine(baseFolder, beforeFileName)); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 4); + var errors = converter.ConvertFile(targetFile, true); + + Assert.Equal(9, errors); + + var expected = File.ReadAllText(Path.Combine(folder, afterFileName)).Replace("\r\n", "\n"); + var actual = File.ReadAllText(targetFile).Replace("\r\n", "\n"); + Assert.Equal(expected, actual); + + EnsureFixed(targetFile); + } + } + + [Fact] + public void CanDetectReadOnlyOutputFile() + { + const string beforeFileName = "SingleFile.wxs"; + var folder = TestData.Get(@"TestData\SingleFile"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(true); + var targetFile = Path.Combine(baseFolder, beforeFileName); + File.Copy(Path.Combine(folder, beforeFileName), Path.Combine(baseFolder, beforeFileName)); + + var info = new FileInfo(targetFile); + info.IsReadOnly = true; + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 4); + var errors = converter.ConvertFile(targetFile, true); + + Assert.Single(messaging.Messages.Where(m => m.Id == 5/*WixConverter.ConverterTestType.UnauthorizedAccessException*/)); + } + } + + [Fact] + public void RetainsPreprocessorInstructions() + { + const string beforeFileName = "Preprocessor.wxs"; + const string afterFileName = "ConvertedPreprocessor.wxs"; + var folder = TestData.Get(@"TestData\Preprocessor"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(true); + var targetFile = Path.Combine(baseFolder, beforeFileName); + File.Copy(Path.Combine(folder, beforeFileName), Path.Combine(baseFolder, beforeFileName)); + + var settingsFile = Path.Combine(folder, "wixcop.settings.xml"); + + var result = RunConversion(targetFile, settingsFile: settingsFile); + Assert.Equal(9, result.ExitCode); + + var expected = File.ReadAllText(Path.Combine(folder, afterFileName)).Replace("\r\n", "\n"); + var actual = File.ReadAllText(targetFile).Replace("\r\n", "\n"); + Assert.Equal(expected, actual); + + EnsureFixed(targetFile); + } + } + + [Fact] + public void CanConvertQtExec() + { + const string beforeFileName = "v3.wxs"; + const string afterFileName = "v4_expected.wxs"; + var folder = TestData.Get(@"TestData\QtExec"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(true); + var targetFile = Path.Combine(baseFolder, beforeFileName); + File.Copy(Path.Combine(folder, beforeFileName), Path.Combine(baseFolder, beforeFileName)); + + var result = RunConversion(targetFile); + Assert.Equal(13, result.ExitCode); + + var expected = File.ReadAllText(Path.Combine(folder, afterFileName)).Replace("\r\n", "\n"); + var actual = File.ReadAllText(targetFile).Replace("\r\n", "\n"); + Assert.Equal(expected, actual); + + EnsureFixed(targetFile); + } + } + + [Fact] + public void DetectUnconvertableQtExecCmdTimeout() + { + const string beforeFileName = "v3.wxs"; + const string afterFileName = "v4_expected.wxs"; + var folder = TestData.Get(@"TestData\QtExec.bad"); + + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(true); + var targetFile = Path.Combine(baseFolder, beforeFileName); + File.Copy(Path.Combine(folder, beforeFileName), Path.Combine(baseFolder, beforeFileName)); + + var result = RunConversion(targetFile); + + Assert.Equal(13, result.ExitCode); + Assert.Single(result.Messages.Where(message => message.ToString().EndsWith("(QtExecCmdTimeoutAmbiguous)"))); + + var expected = File.ReadAllText(Path.Combine(folder, afterFileName)).Replace("\r\n", "\n"); + var actual = File.ReadAllText(targetFile).Replace("\r\n", "\n"); + Assert.Equal(expected, actual); + + // still fails because QtExecCmdTimeoutAmbiguous is unfixable + var result2 = RunConversion(targetFile); + Assert.Equal(1, result2.ExitCode); + } + } + + private static WixRunnerResult RunConversion(string targetFile, bool fixErrors = true, string settingsFile = null) + { + var serviceProvider = WixToolsetServiceProviderFactory.CreateServiceProvider().AddConverter(); + + var exitCode = WixRunner.Execute(new[] + { + "convert", + fixErrors ? null : "--dry-run", + String.IsNullOrEmpty(settingsFile) ? null : "-set1" + settingsFile, + targetFile + }, serviceProvider, out var messages); + + return new WixRunnerResult { ExitCode = exitCode.Result, Messages = messages.ToArray() }; + } + + private static void EnsureFixed(string targetFile) + { + var messaging2 = new MockMessaging(); + var converter2 = new WixConverter(messaging2, 4); + var errors2 = converter2.ConvertFile(targetFile, true); + Assert.Equal(0, errors2); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/CustomActionFixture.cs b/src/wix/test/WixToolsetTest.Converters/CustomActionFixture.cs new file mode 100644 index 00000000..eafc171a --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/CustomActionFixture.cs @@ -0,0 +1,88 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.IO; + using System.Xml.Linq; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class CustomActionFixture : BaseConverterFixture + { + [Fact] + public void CanConvertCustomAction() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(11, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void CanConvertCustomActionScript() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " function() {", + " var x = 0;", + " return x;", + " }", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var expectedScript = String.Join("\n", + "function() {", + " var x = 0;", + " return x;", + " }"); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(2, errors); + Assert.Equal(expected, actual); + + var script = File.ReadAllText("Foo.js"); + Assert.Equal(expectedScript, script); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/CustomTableFixture.cs b/src/wix/test/WixToolsetTest.Converters/CustomTableFixture.cs new file mode 100644 index 00000000..2b81a863 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/CustomTableFixture.cs @@ -0,0 +1,363 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class CustomTableFixture : BaseConverterFixture + { + [Fact] + public void FixCustomTableCategoryAndModularization() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(4, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixCustomRowTextValue() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " Some value", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(4, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixCustomRowCdataValue() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixCustomRowWithoutValue() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void CanConvertBundleCustomTableBootstrapperApplicationData() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " Row1", + " ", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, customTableTarget: CustomTableTarget.Bundle); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(2, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void CanConvertBundleCustomTableRef() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " Row1", + " ", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, customTableTarget: CustomTableTarget.Bundle); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(2, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void CanConvertMsiCustomTableBootstrapperApplicationData() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " Row1", + " ", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, customTableTarget: CustomTableTarget.Msi); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(2, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void CanConvertMsiCustomTableRef() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " Row1", + " ", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, customTableTarget: CustomTableTarget.Msi); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(2, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void CanDetectAmbiguousCustomTableBootstrapperApplicationData() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(1, errors); + Assert.Equal(expected, actual); + } + + [Fact] + public void CanRemoveBootstrapperApplicationDataFromRealCustomTable() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(1, errors); + Assert.Equal(expected, actual); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/DependencyFixture.cs b/src/wix/test/WixToolsetTest.Converters/DependencyFixture.cs new file mode 100644 index 00000000..41ded927 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/DependencyFixture.cs @@ -0,0 +1,178 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class DependencyFixture : BaseConverterFixture + { + [Fact] + public void FixPackageDependencyProvides() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(5, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixPackageDependencyRequires() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(7, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixPackageDependencyRequiresRef() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(7, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixBundleDependencyProvides() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(5, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/DirectoryFixture.cs b/src/wix/test/WixToolsetTest.Converters/DirectoryFixture.cs new file mode 100644 index 00000000..3c906320 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/DirectoryFixture.cs @@ -0,0 +1,92 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class DirectoryFixture : BaseConverterFixture + { + [Fact] + public void RemoveTargetDir() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixStandardDirectory() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(4, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/ExePackageFixture.cs b/src/wix/test/WixToolsetTest.Converters/ExePackageFixture.cs new file mode 100644 index 00000000..0ee8d065 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/ExePackageFixture.cs @@ -0,0 +1,49 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class ExePackageFixture : BaseConverterFixture + { + [Fact] + public void CanConvertExePackageCommandToArguments() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/FeatureFixture.cs b/src/wix/test/WixToolsetTest.Converters/FeatureFixture.cs new file mode 100644 index 00000000..1df94a81 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/FeatureFixture.cs @@ -0,0 +1,110 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class FeatureFixture : BaseConverterFixture + { + [Fact] + public void FixAllowAttributes() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(4, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixDisallowAttributes() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void RemoveDeprecatedAllowAdvertiseAttributes() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/FirewallExtensionFixture.cs b/src/wix/test/WixToolsetTest.Converters/FirewallExtensionFixture.cs new file mode 100644 index 00000000..a101019b --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/FirewallExtensionFixture.cs @@ -0,0 +1,47 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class FirewallExtensionFixture : BaseConverterFixture + { + [Fact] + public void FixRemoteAddressValue() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " 127.0.0.1", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/FormatFixture.cs b/src/wix/test/WixToolsetTest.Converters/FormatFixture.cs new file mode 100644 index 00000000..739fba66 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/FormatFixture.cs @@ -0,0 +1,117 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class FormatFixture : BaseConverterFixture + { + [Fact] + public void CanFixWhitespace() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 4, null, null); + + var errors = converter.FormatDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(expected, actual); + Assert.Equal(5, errors); + } + + [Fact] + public void CanPreserveNewLines() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + "", + " ", + "", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + "", + " ", + "", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 4, null, null); + + var conversions = converter.FormatDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(expected, actual); + Assert.Equal(4, conversions); + } + + [Fact] + public void CanFormatWithNewLineAtEndOfFile() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + "", + " ", + "", + " ", + "", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + "", + " ", + "", + " ", + "", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 4, null, null); + + var conversions = converter.FormatDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(expected, actual); + Assert.Equal(3, conversions); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/IncludeFixture.cs b/src/wix/test/WixToolsetTest.Converters/IncludeFixture.cs new file mode 100644 index 00000000..2fd8244f --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/IncludeFixture.cs @@ -0,0 +1,68 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class IncludeFixture : BaseConverterFixture + { + [Fact] + public void EnsureNamespace() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + ""); + + var expected = new[] + { + "", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(1, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixNamespace() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + ""); + + var expected = new[] + { + "", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(1, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/Mocks/MockCoreServiceProvider.cs b/src/wix/test/WixToolsetTest.Converters/Mocks/MockCoreServiceProvider.cs new file mode 100644 index 00000000..b6bb8a40 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/Mocks/MockCoreServiceProvider.cs @@ -0,0 +1,51 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters.Mocks +{ + using System; + using System.Collections.Generic; + using WixToolset.Extensibility.Services; + + public class MockCoreServiceProvider : IWixToolsetCoreServiceProvider + { + public Dictionary, object>> CreationFunctions { get; } = new Dictionary, object>>(); + + public Dictionary Singletons { get; } = new Dictionary() + { + { typeof(IMessaging), new MockMessaging() } + }; + + public void AddService(Type serviceType, Func, object> creationFunction) => this.CreationFunctions.Add(serviceType, creationFunction); + + public void AddService(Func, T> creationFunction) where T : class => this.AddService(typeof(T), creationFunction); + + public T GetService() where T : class => this.TryGetService(typeof(T), out var obj) ? (T)obj : null; + + public object GetService(Type serviceType) => this.TryGetService(serviceType, out var service) ? service : null; + + public bool TryGetService(Type serviceType, out object service) + { + if (!this.Singletons.TryGetValue(serviceType, out service)) + { + if (this.CreationFunctions.TryGetValue(serviceType, out var creationFunction)) + { + service = creationFunction(this, this.Singletons); + } + } + + return service != null; + } + + public bool TryGetService(out T service) where T : class + { + service = null; + + if (this.TryGetService(typeof(T), out var obj)) + { + service = (T)obj; + } + + return service != null; + } + } +} \ No newline at end of file diff --git a/src/wix/test/WixToolsetTest.Converters/Mocks/MockMessaging.cs b/src/wix/test/WixToolsetTest.Converters/Mocks/MockMessaging.cs new file mode 100644 index 00000000..77821a1c --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/Mocks/MockMessaging.cs @@ -0,0 +1,39 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters.Mocks +{ + using System; + using System.Collections.Generic; + using WixToolset.Data; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Services; + + public class MockMessaging : IMessaging + { + public List Messages { get; } = new List(); + + public bool EncounteredError { get; private set; } + + public int LastErrorNumber { get; } + + public bool ShowVerboseMessages { get; set; } + + public bool SuppressAllWarnings { get; set; } + + public bool WarningsAsError { get; set; } + + public void ElevateWarningMessage(int warningNumber) => throw new NotImplementedException(); + + public void SetListener(IMessageListener listener) => throw new NotImplementedException(); + + public void SuppressWarningMessage(int warningNumber) => throw new NotImplementedException(); + + public void Write(Message message) + { + this.Messages.Add(message); + this.EncounteredError |= message.Level == MessageLevel.Error; + } + + public void Write(string message, bool verbose = false) => throw new NotImplementedException(); + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/ProductPackageFixture.cs b/src/wix/test/WixToolsetTest.Converters/ProductPackageFixture.cs new file mode 100644 index 00000000..e01b9789 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/ProductPackageFixture.cs @@ -0,0 +1,278 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.IO; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolset.Core.TestPackage; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class ProductPackageFixture : BaseConverterFixture + { + [Fact] + public void FixesCompressedWhenYes() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + AssertSuccess(parse, 4, expected); + } + + [Fact] + public void FixesCompressedWhenNo() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + AssertSuccess(parse, 4, expected); + } + + [Fact] + public void FixesCompressedWhenOmitted() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + AssertSuccess(parse, 4, expected); + } + + private static void AssertSuccess(string input, int expectedErrorCount, string[] expected) + { + var document = XDocument.Parse(input, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(expectedErrorCount, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixesInstallerVersion() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + AssertSuccess(parse, 3, expected); + } + + [Fact] + public void FixesDefaultInstallerVersion() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + AssertSuccess(parse, 3, expected); + } + + [Fact] + public void FixesImplicitInstallerVersion() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + AssertSuccess(parse, 4, expected); + } + + [Fact] + public void FixesNonDefaultInstallerVersion() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + AssertSuccess(parse, 3, expected); + } + + [Fact] + public void FixesLimitedInstallerPrivileges() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + AssertSuccess(parse, 4, expected); + } + + [Fact] + public void FixesElevatedInstallerPrivileges() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + "" + }; + + AssertSuccess(parse, 4, expected); + } + + [Fact] + public void CanDecompileAndRecompile() + { + using (var fs = new DisposableFileSystem()) + { + var baseFolder = fs.GetFolder(); + var intermediateFolder = Path.Combine(baseFolder, "obj"); + var decompiledWxsPath = Path.Combine(baseFolder, "TypicalV3.wxs"); + + var folder = TestData.Get(@"TestData\PackageSummaryInformation"); + var v3msiPath = Path.Combine(folder, "TypicalV3.msi"); + var result = WixRunner.Execute(new[] + { + "decompile", v3msiPath, + "-intermediateFolder", intermediateFolder, + "-o", decompiledWxsPath + }); + + result.AssertSuccess(); + + var v4msiPath = Path.Combine(intermediateFolder, "TypicalV4.msi"); + result = WixRunner.Execute(new[] + { + "build", decompiledWxsPath, + "-arch", "x64", + "-intermediateFolder", intermediateFolder, + "-o", v4msiPath + }); + + result.AssertSuccess(); + + Assert.True(File.Exists(v4msiPath)); + + var v3results = Query.QueryDatabase(v3msiPath, new[] { "_SummaryInformation", "Property" }); + var v4results = Query.QueryDatabase(v4msiPath, new[] { "_SummaryInformation", "Property" }); + WixAssert.CompareLineByLine(v3results, v4results); + } + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/PropertyFixture.cs b/src/wix/test/WixToolsetTest.Converters/PropertyFixture.cs new file mode 100644 index 00000000..e50a6518 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/PropertyFixture.cs @@ -0,0 +1,108 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class PropertyFixture : BaseConverterFixture + { + [Fact] + public void CanFixCdataWhitespace() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(expected, actual); + Assert.Equal(1, errors); + } + + [Fact] + public void CanFixCdataWithWhitespace() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(expected, actual); + Assert.Equal(1, errors); + } + + [Fact] + public void CanKeepCdataWithOnlyWhitespace() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var expected = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + var errors = converter.ConvertDocument(document); + + var actual = UnformattedDocumentString(document); + + Assert.Equal(expected, actual); + Assert.Equal(1, errors); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/RegistryFixture.cs b/src/wix/test/WixToolsetTest.Converters/RegistryFixture.cs new file mode 100644 index 00000000..405f5416 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/RegistryFixture.cs @@ -0,0 +1,54 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class RegistryFixture : BaseConverterFixture + { + [Fact] + public void FixRegistryKeyAction() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(5, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/RemotePayloadFixture.cs b/src/wix/test/WixToolsetTest.Converters/RemotePayloadFixture.cs new file mode 100644 index 00000000..b2640e13 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/RemotePayloadFixture.cs @@ -0,0 +1,104 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class RemotePayloadFixture : BaseConverterFixture + { + [Fact] + public void CanConvertExePackageRemotePayload() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(6, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void CanConvertMsuPackageRemotePayload() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(5, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/SequenceFixture.cs b/src/wix/test/WixToolsetTest.Converters/SequenceFixture.cs new file mode 100644 index 00000000..ec6c709b --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/SequenceFixture.cs @@ -0,0 +1,49 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class SequenceFixture : BaseConverterFixture + { + [Fact] + public void FixCondition() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " NOT Installed", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(2, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/TagFixture.cs b/src/wix/test/WixToolsetTest.Converters/TagFixture.cs new file mode 100644 index 00000000..5e07c83b --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TagFixture.cs @@ -0,0 +1,111 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class TagFixture : BaseConverterFixture + { + [Fact] + public void FixTagExtension() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(4, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixTagExtensionDeprecations() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(7, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixTagExtensionTagRef() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.msi b/src/wix/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.msi new file mode 100644 index 00000000..0d7e1b21 Binary files /dev/null and b/src/wix/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.msi differ diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.wxs b/src/wix/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.wxs new file mode 100644 index 00000000..8c5027b4 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TestData/PackageSummaryInformation/TypicalV3.wxs @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/PermissionEx/v3.wxs b/src/wix/test/WixToolsetTest.Converters/TestData/PermissionEx/v3.wxs new file mode 100644 index 00000000..9a739052 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TestData/PermissionEx/v3.wxs @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/PermissionEx/v4_expected.wxs b/src/wix/test/WixToolsetTest.Converters/TestData/PermissionEx/v4_expected.wxs new file mode 100644 index 00000000..6bf3c1ea --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TestData/PermissionEx/v4_expected.wxs @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/Preprocessor/ConvertedPreprocessor.wxs b/src/wix/test/WixToolsetTest.Converters/TestData/Preprocessor/ConvertedPreprocessor.wxs new file mode 100644 index 00000000..8188d900 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TestData/Preprocessor/ConvertedPreprocessor.wxs @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/Preprocessor/Preprocessor.wxs b/src/wix/test/WixToolsetTest.Converters/TestData/Preprocessor/Preprocessor.wxs new file mode 100644 index 00000000..2eb908c2 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TestData/Preprocessor/Preprocessor.wxs @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/Preprocessor/wixcop.settings.xml b/src/wix/test/WixToolsetTest.Converters/TestData/Preprocessor/wixcop.settings.xml new file mode 100644 index 00000000..9d3ad496 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TestData/Preprocessor/wixcop.settings.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/QtExec.bad/v3.wxs b/src/wix/test/WixToolsetTest.Converters/TestData/QtExec.bad/v3.wxs new file mode 100644 index 00000000..b0fcf9c9 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TestData/QtExec.bad/v3.wxs @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/QtExec.bad/v4_expected.wxs b/src/wix/test/WixToolsetTest.Converters/TestData/QtExec.bad/v4_expected.wxs new file mode 100644 index 00000000..95d2f618 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TestData/QtExec.bad/v4_expected.wxs @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/QtExec/v3.wxs b/src/wix/test/WixToolsetTest.Converters/TestData/QtExec/v3.wxs new file mode 100644 index 00000000..8d81a758 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TestData/QtExec/v3.wxs @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/QtExec/v4_expected.wxs b/src/wix/test/WixToolsetTest.Converters/TestData/QtExec/v4_expected.wxs new file mode 100644 index 00000000..f24d3f8f --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TestData/QtExec/v4_expected.wxs @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/SingleFile/ConvertedSingleFile.wxs b/src/wix/test/WixToolsetTest.Converters/TestData/SingleFile/ConvertedSingleFile.wxs new file mode 100644 index 00000000..5bcdaf59 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TestData/SingleFile/ConvertedSingleFile.wxs @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.Converters/TestData/SingleFile/SingleFile.wxs b/src/wix/test/WixToolsetTest.Converters/TestData/SingleFile/SingleFile.wxs new file mode 100644 index 00000000..310ae811 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/TestData/SingleFile/SingleFile.wxs @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.Converters/UtilExtensionFixture.cs b/src/wix/test/WixToolsetTest.Converters/UtilExtensionFixture.cs new file mode 100644 index 00000000..10450c68 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/UtilExtensionFixture.cs @@ -0,0 +1,190 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class UtilExtensionFixture : BaseConverterFixture + { + [Fact] + public void FixCloseAppsCondition() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " a<>b", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixXmlConfigValue() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " a<>b", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void WarnsOnAllRegistryValueSearches() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(4, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + + [Fact] + public void FixXmlConfigValueCData() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " b]]>", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void FixQueryOsPropertyRefs() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(6, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/VariableFixture.cs b/src/wix/test/WixToolsetTest.Converters/VariableFixture.cs new file mode 100644 index 00000000..b7b7388f --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/VariableFixture.cs @@ -0,0 +1,86 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class VariableFixture : BaseConverterFixture + { + [Fact] + public void FixFormattedType() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(3, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + + [Fact] + public void DoesntFixFormattedTypeFromV4() + { + var parse = String.Join(Environment.NewLine, + "", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(0, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/Wix4ConversionFixture.cs b/src/wix/test/WixToolsetTest.Converters/Wix4ConversionFixture.cs new file mode 100644 index 00000000..16a68895 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/Wix4ConversionFixture.cs @@ -0,0 +1,54 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolsetTest.Converters +{ + using System; + using System.Xml.Linq; + using WixBuildTools.TestSupport; + using WixToolset.Converters; + using WixToolsetTest.Converters.Mocks; + using Xunit; + + public class Wix4ConversionFixture : BaseConverterFixture + { + [Fact] + public void DoesNotAddFileId() + { + var parse = String.Join(Environment.NewLine, + "", + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + ""); + + var expected = new[] + { + "", + " ", + " ", + " ", + " ", + " ", + " ", + " ", + "" + }; + + var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); + + var messaging = new MockMessaging(); + var converter = new WixConverter(messaging, 2, null, null); + + var errors = converter.ConvertDocument(document); + Assert.Equal(1, errors); + + var actualLines = UnformattedDocumentLines(document); + WixAssert.CompareLineByLine(expected, actualLines); + } + } +} diff --git a/src/wix/test/WixToolsetTest.Converters/WixToolsetTest.Converters.csproj b/src/wix/test/WixToolsetTest.Converters/WixToolsetTest.Converters.csproj new file mode 100644 index 00000000..29b02b95 --- /dev/null +++ b/src/wix/test/WixToolsetTest.Converters/WixToolsetTest.Converters.csproj @@ -0,0 +1,31 @@ + + + + + + netcoreapp3.1 + false + + + + + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3-55-g6feb