diff options
| author | Rob Mensching <rob@firegiant.com> | 2019-05-15 16:09:26 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2019-05-15 16:12:21 -0700 |
| commit | 6f6c485118796f044a278447722eaf18ac5bf86e (patch) | |
| tree | de580265227abc257ee85a8973367f5cdce09bd9 /src | |
| parent | 8d3f778c61a1a0a576445e8dc7312613363b787d (diff) | |
| download | wix-6f6c485118796f044a278447722eaf18ac5bf86e.tar.gz wix-6f6c485118796f044a278447722eaf18ac5bf86e.tar.bz2 wix-6f6c485118796f044a278447722eaf18ac5bf86e.zip | |
Initial code commit
Diffstat (limited to 'src')
21 files changed, 2930 insertions, 0 deletions
diff --git a/src/WixToolset.Converters.Tupleizer/ConvertTuplesCommand.cs b/src/WixToolset.Converters.Tupleizer/ConvertTuplesCommand.cs new file mode 100644 index 00000000..c07dd42e --- /dev/null +++ b/src/WixToolset.Converters.Tupleizer/ConvertTuplesCommand.cs | |||
| @@ -0,0 +1,609 @@ | |||
| 1 | // 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. | ||
| 2 | |||
| 3 | namespace WixToolset.Converters.Tupleizer | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Linq; | ||
| 7 | using WixToolset.Data; | ||
| 8 | using WixToolset.Data.Tuples; | ||
| 9 | using WixToolset.Data.WindowsInstaller; | ||
| 10 | using Wix3 = Microsoft.Tools.WindowsInstallerXml; | ||
| 11 | |||
| 12 | public class ConvertTuplesCommand | ||
| 13 | { | ||
| 14 | public Intermediate Execute(string path) | ||
| 15 | { | ||
| 16 | var output = Wix3.Output.Load(path, suppressVersionCheck: true, suppressSchema: true); | ||
| 17 | return this.Execute(output); | ||
| 18 | } | ||
| 19 | |||
| 20 | public Intermediate Execute(Wix3.Output output) | ||
| 21 | { | ||
| 22 | var section = new IntermediateSection(String.Empty, OutputType3ToSectionType4(output.Type), output.Codepage); | ||
| 23 | |||
| 24 | foreach (Wix3.Table table in output.Tables) | ||
| 25 | { | ||
| 26 | foreach (Wix3.Row row in table.Rows) | ||
| 27 | { | ||
| 28 | var tuple = GenerateTupleFromRow(row); | ||
| 29 | if (tuple != null) | ||
| 30 | { | ||
| 31 | section.Tuples.Add(tuple); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | } | ||
| 35 | |||
| 36 | return new Intermediate(String.Empty, new[] { section }, localizationsByCulture: null, embedFilePaths: null); | ||
| 37 | } | ||
| 38 | |||
| 39 | private static IntermediateTuple GenerateTupleFromRow(Wix3.Row row) | ||
| 40 | { | ||
| 41 | var name = row.Table.Name; | ||
| 42 | switch (name) | ||
| 43 | { | ||
| 44 | case "_SummaryInformation": | ||
| 45 | return DefaultTupleFromRow(typeof(_SummaryInformationTuple), row, columnZeroIsId: false); | ||
| 46 | case "ActionText": | ||
| 47 | return DefaultTupleFromRow(typeof(ActionTextTuple), row, columnZeroIsId: false); | ||
| 48 | case "AdvtExecuteSequence": | ||
| 49 | return DefaultTupleFromRow(typeof(AdvtExecuteSequenceTuple), row, columnZeroIsId: false); | ||
| 50 | case "AppId": | ||
| 51 | return DefaultTupleFromRow(typeof(AppIdTuple), row, columnZeroIsId: false); | ||
| 52 | case "AppSearch": | ||
| 53 | return DefaultTupleFromRow(typeof(AppSearchTuple), row, columnZeroIsId: false); | ||
| 54 | case "Binary": | ||
| 55 | return DefaultTupleFromRow(typeof(BinaryTuple), row, columnZeroIsId: false); | ||
| 56 | case "Class": | ||
| 57 | return DefaultTupleFromRow(typeof(ClassTuple), row, columnZeroIsId: false); | ||
| 58 | case "CompLocator": | ||
| 59 | return DefaultTupleFromRow(typeof(CompLocatorTuple), row, columnZeroIsId: true); | ||
| 60 | case "Component": | ||
| 61 | { | ||
| 62 | var attributes = FieldAsNullableInt(row, 3); | ||
| 63 | |||
| 64 | var location = ComponentLocation.LocalOnly; | ||
| 65 | if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesSourceOnly) == WindowsInstallerConstants.MsidbComponentAttributesSourceOnly) | ||
| 66 | { | ||
| 67 | location = ComponentLocation.SourceOnly; | ||
| 68 | } | ||
| 69 | else if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesOptional) == WindowsInstallerConstants.MsidbComponentAttributesOptional) | ||
| 70 | { | ||
| 71 | location = ComponentLocation.Either; | ||
| 72 | } | ||
| 73 | |||
| 74 | var keyPathType = ComponentKeyPathType.File; | ||
| 75 | if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath) == WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath) | ||
| 76 | { | ||
| 77 | keyPathType = ComponentKeyPathType.Registry; | ||
| 78 | } | ||
| 79 | else if ((attributes & WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource) == WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource) | ||
| 80 | { | ||
| 81 | keyPathType = ComponentKeyPathType.OdbcDataSource; | ||
| 82 | } | ||
| 83 | |||
| 84 | return new ComponentTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0))) | ||
| 85 | { | ||
| 86 | ComponentId = FieldAsString(row, 1), | ||
| 87 | Directory_ = FieldAsString(row, 2), | ||
| 88 | Condition = FieldAsString(row, 4), | ||
| 89 | KeyPath = FieldAsString(row, 5), | ||
| 90 | Location = location, | ||
| 91 | DisableRegistryReflection = (attributes & WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection) == WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection, | ||
| 92 | NeverOverwrite = (attributes & WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite) == WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite, | ||
| 93 | Permanent = (attributes & WindowsInstallerConstants.MsidbComponentAttributesPermanent) == WindowsInstallerConstants.MsidbComponentAttributesPermanent, | ||
| 94 | SharedDllRefCount = (attributes & WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount) == WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount, | ||
| 95 | Shared = (attributes & WindowsInstallerConstants.MsidbComponentAttributesShared) == WindowsInstallerConstants.MsidbComponentAttributesShared, | ||
| 96 | Transitive = (attributes & WindowsInstallerConstants.MsidbComponentAttributesTransitive) == WindowsInstallerConstants.MsidbComponentAttributesTransitive, | ||
| 97 | UninstallWhenSuperseded = (attributes & WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence) == WindowsInstallerConstants.MsidbComponentAttributesUninstallOnSupersedence, | ||
| 98 | Win64 = (attributes & WindowsInstallerConstants.MsidbComponentAttributes64bit) == WindowsInstallerConstants.MsidbComponentAttributes64bit, | ||
| 99 | KeyPathType = keyPathType, | ||
| 100 | }; | ||
| 101 | } | ||
| 102 | |||
| 103 | case "Condition": | ||
| 104 | return DefaultTupleFromRow(typeof(ConditionTuple), row, columnZeroIsId: false); | ||
| 105 | case "CreateFolder": | ||
| 106 | return DefaultTupleFromRow(typeof(CreateFolderTuple), row, columnZeroIsId: false); | ||
| 107 | case "CustomAction": | ||
| 108 | { | ||
| 109 | var caType = FieldAsInt(row, 1); | ||
| 110 | var executionType = DetermineCustomActionExecutionType(caType); | ||
| 111 | var sourceType = DetermineCustomActionSourceType(caType); | ||
| 112 | var targetType = DetermineCustomActionTargetType(caType); | ||
| 113 | |||
| 114 | return new CustomActionTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0))) | ||
| 115 | { | ||
| 116 | ExecutionType = executionType, | ||
| 117 | SourceType = sourceType, | ||
| 118 | Source = FieldAsString(row, 2), | ||
| 119 | TargetType = targetType, | ||
| 120 | Target = FieldAsString(row, 3), | ||
| 121 | Win64 = (caType & WindowsInstallerConstants.MsidbCustomActionType64BitScript) == WindowsInstallerConstants.MsidbCustomActionType64BitScript, | ||
| 122 | TSAware = (caType & WindowsInstallerConstants.MsidbCustomActionTypeTSAware) == WindowsInstallerConstants.MsidbCustomActionTypeTSAware, | ||
| 123 | Impersonate = (caType & WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate) != WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate, | ||
| 124 | IgnoreResult = (caType & WindowsInstallerConstants.MsidbCustomActionTypeContinue) == WindowsInstallerConstants.MsidbCustomActionTypeContinue, | ||
| 125 | Hidden = (caType & WindowsInstallerConstants.MsidbCustomActionTypeHideTarget) == WindowsInstallerConstants.MsidbCustomActionTypeHideTarget, | ||
| 126 | Async = (caType & WindowsInstallerConstants.MsidbCustomActionTypeAsync) == WindowsInstallerConstants.MsidbCustomActionTypeAsync, | ||
| 127 | }; | ||
| 128 | } | ||
| 129 | |||
| 130 | case "Directory": | ||
| 131 | return DefaultTupleFromRow(typeof(DirectoryTuple), row, columnZeroIsId: false); | ||
| 132 | case "DrLocator": | ||
| 133 | return DefaultTupleFromRow(typeof(DrLocatorTuple), row, columnZeroIsId: false); | ||
| 134 | case "Error": | ||
| 135 | return DefaultTupleFromRow(typeof(ErrorTuple), row, columnZeroIsId: false); | ||
| 136 | case "Extension": | ||
| 137 | return DefaultTupleFromRow(typeof(ExtensionTuple), row, columnZeroIsId: false); | ||
| 138 | case "Feature": | ||
| 139 | { | ||
| 140 | int attributes = FieldAsInt(row, 7); | ||
| 141 | var installDefault = FeatureInstallDefault.Local; | ||
| 142 | if ((attributes & WindowsInstallerConstants.MsidbFeatureAttributesFollowParent) == WindowsInstallerConstants.MsidbFeatureAttributesFollowParent) | ||
| 143 | { | ||
| 144 | installDefault = FeatureInstallDefault.FollowParent; | ||
| 145 | } | ||
| 146 | else | ||
| 147 | if ((attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorSource) == WindowsInstallerConstants.MsidbFeatureAttributesFavorSource) | ||
| 148 | { | ||
| 149 | installDefault = FeatureInstallDefault.Source; | ||
| 150 | } | ||
| 151 | |||
| 152 | return new FeatureTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0))) | ||
| 153 | { | ||
| 154 | Feature_Parent = FieldAsString(row, 1), | ||
| 155 | Title = FieldAsString(row, 2), | ||
| 156 | Description = FieldAsString(row, 3), | ||
| 157 | Display = FieldAsInt(row, 4), // BUGBUGBUG: FieldAsNullableInt(row, 4), | ||
| 158 | Level = FieldAsInt(row, 5), | ||
| 159 | Directory_ = FieldAsString(row, 6), | ||
| 160 | DisallowAbsent = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent) == WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent, | ||
| 161 | DisallowAdvertise = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise) == WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise, | ||
| 162 | InstallDefault = installDefault, | ||
| 163 | TypicalDefault = (attributes & WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise) == WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise ? FeatureTypicalDefault.Advertise : FeatureTypicalDefault.Install, | ||
| 164 | }; | ||
| 165 | } | ||
| 166 | |||
| 167 | case "FeatureComponents": | ||
| 168 | return DefaultTupleFromRow(typeof(FeatureComponentsTuple), row, columnZeroIsId: false); | ||
| 169 | case "File": | ||
| 170 | { | ||
| 171 | var attributes = FieldAsNullableInt(row, 6); | ||
| 172 | var readOnly = (attributes & WindowsInstallerConstants.MsidbFileAttributesReadOnly) == WindowsInstallerConstants.MsidbFileAttributesReadOnly; | ||
| 173 | var hidden = (attributes & WindowsInstallerConstants.MsidbFileAttributesHidden) == WindowsInstallerConstants.MsidbFileAttributesHidden; | ||
| 174 | var system = (attributes & WindowsInstallerConstants.MsidbFileAttributesSystem) == WindowsInstallerConstants.MsidbFileAttributesSystem; | ||
| 175 | var vital = (attributes & WindowsInstallerConstants.MsidbFileAttributesVital) == WindowsInstallerConstants.MsidbFileAttributesVital; | ||
| 176 | var checksum = (attributes & WindowsInstallerConstants.MsidbFileAttributesChecksum) == WindowsInstallerConstants.MsidbFileAttributesChecksum; | ||
| 177 | bool? compressed = null; | ||
| 178 | if ((attributes & WindowsInstallerConstants.MsidbFileAttributesNoncompressed) == WindowsInstallerConstants.MsidbFileAttributesNoncompressed) | ||
| 179 | { | ||
| 180 | compressed = false; | ||
| 181 | } | ||
| 182 | else if ((attributes & WindowsInstallerConstants.MsidbFileAttributesCompressed) == WindowsInstallerConstants.MsidbFileAttributesCompressed) | ||
| 183 | { | ||
| 184 | compressed = true; | ||
| 185 | } | ||
| 186 | |||
| 187 | return new FileTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0))) | ||
| 188 | { | ||
| 189 | Component_ = FieldAsString(row, 1), | ||
| 190 | LongFileName = FieldAsString(row, 2), | ||
| 191 | FileSize = FieldAsInt(row, 3), | ||
| 192 | Version = FieldAsString(row, 4), | ||
| 193 | Language = FieldAsString(row, 5), | ||
| 194 | ReadOnly = readOnly, | ||
| 195 | Hidden = hidden, | ||
| 196 | System = system, | ||
| 197 | Vital = vital, | ||
| 198 | Checksum = checksum, | ||
| 199 | Compressed = compressed, | ||
| 200 | }; | ||
| 201 | } | ||
| 202 | |||
| 203 | case "Font": | ||
| 204 | return DefaultTupleFromRow(typeof(FontTuple), row, columnZeroIsId: false); | ||
| 205 | case "Icon": | ||
| 206 | return DefaultTupleFromRow(typeof(IconTuple), row, columnZeroIsId: false); | ||
| 207 | case "InstallExecuteSequence": | ||
| 208 | return DefaultTupleFromRow(typeof(InstallExecuteSequenceTuple), row, columnZeroIsId: false); | ||
| 209 | case "LockPermissions": | ||
| 210 | return DefaultTupleFromRow(typeof(LockPermissionsTuple), row, columnZeroIsId: false); | ||
| 211 | case "Media": | ||
| 212 | return DefaultTupleFromRow(typeof(MediaTuple), row, columnZeroIsId: false); | ||
| 213 | case "MIME": | ||
| 214 | return DefaultTupleFromRow(typeof(MIMETuple), row, columnZeroIsId: false); | ||
| 215 | case "MoveFile": | ||
| 216 | return DefaultTupleFromRow(typeof(MoveFileTuple), row, columnZeroIsId: false); | ||
| 217 | case "MsiAssembly": | ||
| 218 | return DefaultTupleFromRow(typeof(MsiAssemblyTuple), row, columnZeroIsId: false); | ||
| 219 | case "MsiShortcutProperty": | ||
| 220 | return DefaultTupleFromRow(typeof(MsiShortcutPropertyTuple), row, columnZeroIsId: false); | ||
| 221 | case "ProgId": | ||
| 222 | return DefaultTupleFromRow(typeof(ProgIdTuple), row, columnZeroIsId: false); | ||
| 223 | case "Property": | ||
| 224 | return DefaultTupleFromRow(typeof(PropertyTuple), row, columnZeroIsId: false); | ||
| 225 | case "PublishComponent": | ||
| 226 | return DefaultTupleFromRow(typeof(PublishComponentTuple), row, columnZeroIsId: false); | ||
| 227 | case "Registry": | ||
| 228 | { | ||
| 229 | var value = FieldAsString(row, 4); | ||
| 230 | var valueType = RegistryValueType.String; | ||
| 231 | var valueAction = RegistryValueActionType.Write; | ||
| 232 | |||
| 233 | if (!String.IsNullOrEmpty(value)) | ||
| 234 | { | ||
| 235 | if (value.StartsWith("#x", StringComparison.Ordinal)) | ||
| 236 | { | ||
| 237 | valueType = RegistryValueType.Binary; | ||
| 238 | value = value.Substring(2); | ||
| 239 | } | ||
| 240 | else if (value.StartsWith("#%", StringComparison.Ordinal)) | ||
| 241 | { | ||
| 242 | valueType = RegistryValueType.Expandable; | ||
| 243 | value = value.Substring(2); | ||
| 244 | } | ||
| 245 | else if (value.StartsWith("#", StringComparison.Ordinal)) | ||
| 246 | { | ||
| 247 | valueType = RegistryValueType.Integer; | ||
| 248 | value = value.Substring(1); | ||
| 249 | } | ||
| 250 | else if (value.StartsWith("[~]", StringComparison.Ordinal) && value.EndsWith("[~]", StringComparison.Ordinal)) | ||
| 251 | { | ||
| 252 | value = value.Substring(3, value.Length - 6); | ||
| 253 | valueType = RegistryValueType.MultiString; | ||
| 254 | valueAction = RegistryValueActionType.Write; | ||
| 255 | } | ||
| 256 | else if (value.StartsWith("[~]", StringComparison.Ordinal)) | ||
| 257 | { | ||
| 258 | value = value.Substring(3); | ||
| 259 | valueType = RegistryValueType.MultiString; | ||
| 260 | valueAction = RegistryValueActionType.Append; | ||
| 261 | } | ||
| 262 | else if (value.EndsWith("[~]", StringComparison.Ordinal)) | ||
| 263 | { | ||
| 264 | value = value.Substring(0, value.Length - 3); | ||
| 265 | valueType = RegistryValueType.MultiString; | ||
| 266 | valueAction = RegistryValueActionType.Prepend; | ||
| 267 | } | ||
| 268 | } | ||
| 269 | |||
| 270 | return new RegistryTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0))) | ||
| 271 | { | ||
| 272 | Root = (RegistryRootType)FieldAsInt(row, 1), | ||
| 273 | Key = FieldAsString(row, 2), | ||
| 274 | Name = FieldAsString(row, 3), | ||
| 275 | Value = value, | ||
| 276 | Component_ = FieldAsString(row, 5), | ||
| 277 | ValueAction = valueAction, | ||
| 278 | ValueType = valueType, | ||
| 279 | }; | ||
| 280 | } | ||
| 281 | |||
| 282 | case "RegLocator": | ||
| 283 | return DefaultTupleFromRow(typeof(RegLocatorTuple), row, columnZeroIsId: false); | ||
| 284 | case "RemoveFile": | ||
| 285 | return DefaultTupleFromRow(typeof(RemoveFileTuple), row, columnZeroIsId: false); | ||
| 286 | case "RemoveRegistry": | ||
| 287 | { | ||
| 288 | return new RemoveRegistryTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0))) | ||
| 289 | { | ||
| 290 | Action = RemoveRegistryActionType.RemoveOnInstall, | ||
| 291 | Root = (RegistryRootType)FieldAsInt(row, 1), | ||
| 292 | Key = FieldAsString(row, 2), | ||
| 293 | Name = FieldAsString(row, 3), | ||
| 294 | Component_ = FieldAsString(row, 4), | ||
| 295 | }; | ||
| 296 | } | ||
| 297 | |||
| 298 | case "ReserveCost": | ||
| 299 | return DefaultTupleFromRow(typeof(ReserveCostTuple), row, columnZeroIsId: false); | ||
| 300 | case "ServiceControl": | ||
| 301 | { | ||
| 302 | var events = FieldAsInt(row, 2); | ||
| 303 | var wait = FieldAsNullableInt(row, 4); | ||
| 304 | return new ServiceControlTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0))) | ||
| 305 | { | ||
| 306 | Name = FieldAsString(row, 1), | ||
| 307 | Arguments = FieldAsString(row, 3), | ||
| 308 | Wait = !wait.HasValue || wait.Value == 1, | ||
| 309 | Component_ = FieldAsString(row, 5), | ||
| 310 | InstallRemove = (events & WindowsInstallerConstants.MsidbServiceControlEventDelete) == WindowsInstallerConstants.MsidbServiceControlEventDelete, | ||
| 311 | UninstallRemove = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete) == WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete, | ||
| 312 | InstallStart = (events & WindowsInstallerConstants.MsidbServiceControlEventStart) == WindowsInstallerConstants.MsidbServiceControlEventStart, | ||
| 313 | UninstallStart = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallStart) == WindowsInstallerConstants.MsidbServiceControlEventUninstallStart, | ||
| 314 | InstallStop = (events & WindowsInstallerConstants.MsidbServiceControlEventStop) == WindowsInstallerConstants.MsidbServiceControlEventStop, | ||
| 315 | UninstallStop = (events & WindowsInstallerConstants.MsidbServiceControlEventUninstallStop) == WindowsInstallerConstants.MsidbServiceControlEventUninstallStop, | ||
| 316 | }; | ||
| 317 | } | ||
| 318 | |||
| 319 | case "ServiceInstall": | ||
| 320 | return DefaultTupleFromRow(typeof(ServiceInstallTuple), row, columnZeroIsId: true); | ||
| 321 | case "Shortcut": | ||
| 322 | return DefaultTupleFromRow(typeof(ShortcutTuple), row, columnZeroIsId: true); | ||
| 323 | case "Signature": | ||
| 324 | return DefaultTupleFromRow(typeof(SignatureTuple), row, columnZeroIsId: false); | ||
| 325 | case "Upgrade": | ||
| 326 | { | ||
| 327 | var attributes = FieldAsInt(row, 4); | ||
| 328 | return new UpgradeTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0))) | ||
| 329 | { | ||
| 330 | UpgradeCode = FieldAsString(row, 0), | ||
| 331 | VersionMin = FieldAsString(row, 1), | ||
| 332 | VersionMax = FieldAsString(row, 2), | ||
| 333 | Language = FieldAsString(row, 3), | ||
| 334 | Remove = FieldAsString(row, 5), | ||
| 335 | ActionProperty = FieldAsString(row, 6), | ||
| 336 | MigrateFeatures = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures) == WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures, | ||
| 337 | OnlyDetect = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect) == WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect, | ||
| 338 | IgnoreRemoveFailures = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure) == WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure, | ||
| 339 | VersionMinInclusive = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive, | ||
| 340 | VersionMaxInclusive = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive, | ||
| 341 | ExcludeLanguages = (attributes & WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive) == WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive, | ||
| 342 | }; | ||
| 343 | } | ||
| 344 | |||
| 345 | case "Verb": | ||
| 346 | return DefaultTupleFromRow(typeof(VerbTuple), row, columnZeroIsId: false); | ||
| 347 | //case "WixAction": | ||
| 348 | // return new WixActionTuple(SourceLineNumber4(row.SourceLineNumbers)) | ||
| 349 | // { | ||
| 350 | // SequenceTable = (SequenceTable)Enum.Parse(typeof(SequenceTable), FieldAsString(row, 0)), | ||
| 351 | // Action = FieldAsString(row, 1), | ||
| 352 | // Condition = FieldAsString(row, 2), | ||
| 353 | // Sequence = FieldAsInt(row, 3), | ||
| 354 | // Before = FieldAsString(row, 4), | ||
| 355 | // After = FieldAsString(row, 5), | ||
| 356 | // Overridable = FieldAsNullableInt(row, 6) != 0, | ||
| 357 | // }; | ||
| 358 | case "WixFile": | ||
| 359 | var assemblyAttributes3 = FieldAsNullableInt(row, 1); | ||
| 360 | return new WixFileTuple(SourceLineNumber4(row.SourceLineNumbers), new Identifier(AccessModifier.Public, FieldAsString(row, 0))) | ||
| 361 | { | ||
| 362 | AssemblyType = assemblyAttributes3 == 0 ? FileAssemblyType.DotNetAssembly : assemblyAttributes3 == 1 ? FileAssemblyType.Win32Assembly : FileAssemblyType.NotAnAssembly, | ||
| 363 | File_AssemblyManifest = FieldAsString(row, 2), | ||
| 364 | File_AssemblyApplication = FieldAsString(row, 3), | ||
| 365 | Directory_ = FieldAsString(row, 4), | ||
| 366 | DiskId = FieldAsInt(row, 5), // TODO: BUGBUGBUG: AB#2626: DiskId is nullable in WiX v3. | ||
| 367 | Source = new IntermediateFieldPathValue() { Path = FieldAsString(row, 6) }, | ||
| 368 | ProcessorArchitecture = FieldAsString(row, 7), | ||
| 369 | PatchGroup = FieldAsInt(row, 8), | ||
| 370 | Attributes = FieldAsInt(row, 9), | ||
| 371 | }; | ||
| 372 | case "WixProperty": | ||
| 373 | { | ||
| 374 | var attributes = FieldAsInt(row, 1); | ||
| 375 | return new WixPropertyTuple(SourceLineNumber4(row.SourceLineNumbers)) | ||
| 376 | { | ||
| 377 | Property_ = FieldAsString(row, 0), | ||
| 378 | Admin = (attributes & 0x1) == 0x1, | ||
| 379 | Hidden = (attributes & 0x2) == 0x2, | ||
| 380 | Secure = (attributes & 0x4) == 0x4, | ||
| 381 | }; | ||
| 382 | } | ||
| 383 | |||
| 384 | default: | ||
| 385 | return GenericTupleFromCustomRow(row, columnZeroIsId: false); | ||
| 386 | } | ||
| 387 | } | ||
| 388 | |||
| 389 | private static CustomActionTargetType DetermineCustomActionTargetType(int type) | ||
| 390 | { | ||
| 391 | var targetType = default(CustomActionTargetType); | ||
| 392 | |||
| 393 | if ((type & WindowsInstallerConstants.MsidbCustomActionTypeVBScript) == WindowsInstallerConstants.MsidbCustomActionTypeVBScript) | ||
| 394 | { | ||
| 395 | targetType = CustomActionTargetType.VBScript; | ||
| 396 | } | ||
| 397 | else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeJScript) == WindowsInstallerConstants.MsidbCustomActionTypeJScript) | ||
| 398 | { | ||
| 399 | targetType = CustomActionTargetType.JScript; | ||
| 400 | } | ||
| 401 | else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeTextData) == WindowsInstallerConstants.MsidbCustomActionTypeTextData) | ||
| 402 | { | ||
| 403 | targetType = CustomActionTargetType.TextData; | ||
| 404 | } | ||
| 405 | else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeExe) == WindowsInstallerConstants.MsidbCustomActionTypeExe) | ||
| 406 | { | ||
| 407 | targetType = CustomActionTargetType.Exe; | ||
| 408 | } | ||
| 409 | else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeDll) == WindowsInstallerConstants.MsidbCustomActionTypeDll) | ||
| 410 | { | ||
| 411 | targetType = CustomActionTargetType.Dll; | ||
| 412 | } | ||
| 413 | |||
| 414 | return targetType; | ||
| 415 | } | ||
| 416 | |||
| 417 | private static CustomActionSourceType DetermineCustomActionSourceType(int type) | ||
| 418 | { | ||
| 419 | var sourceType = CustomActionSourceType.Binary; | ||
| 420 | |||
| 421 | if ((type & WindowsInstallerConstants.MsidbCustomActionTypeProperty) == WindowsInstallerConstants.MsidbCustomActionTypeProperty) | ||
| 422 | { | ||
| 423 | sourceType = CustomActionSourceType.Property; | ||
| 424 | } | ||
| 425 | else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeDirectory) == WindowsInstallerConstants.MsidbCustomActionTypeDirectory) | ||
| 426 | { | ||
| 427 | sourceType = CustomActionSourceType.Directory; | ||
| 428 | } | ||
| 429 | else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeSourceFile) == WindowsInstallerConstants.MsidbCustomActionTypeSourceFile) | ||
| 430 | { | ||
| 431 | sourceType = CustomActionSourceType.File; | ||
| 432 | } | ||
| 433 | |||
| 434 | return sourceType; | ||
| 435 | } | ||
| 436 | |||
| 437 | private static CustomActionExecutionType DetermineCustomActionExecutionType(int type) | ||
| 438 | { | ||
| 439 | var executionType = CustomActionExecutionType.Immediate; | ||
| 440 | |||
| 441 | if ((type & (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit)) == (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit)) | ||
| 442 | { | ||
| 443 | executionType = CustomActionExecutionType.Commit; | ||
| 444 | } | ||
| 445 | else if ((type & (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback)) == (WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback)) | ||
| 446 | { | ||
| 447 | executionType = CustomActionExecutionType.Rollback; | ||
| 448 | } | ||
| 449 | else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeInScript) == WindowsInstallerConstants.MsidbCustomActionTypeInScript) | ||
| 450 | { | ||
| 451 | executionType = CustomActionExecutionType.Deferred; | ||
| 452 | } | ||
| 453 | else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat) == WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat) | ||
| 454 | { | ||
| 455 | executionType = CustomActionExecutionType.ClientRepeat; | ||
| 456 | } | ||
| 457 | else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess) == WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess) | ||
| 458 | { | ||
| 459 | executionType = CustomActionExecutionType.OncePerProcess; | ||
| 460 | } | ||
| 461 | else if ((type & WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence) == WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence) | ||
| 462 | { | ||
| 463 | executionType = CustomActionExecutionType.FirstSequence; | ||
| 464 | } | ||
| 465 | |||
| 466 | return executionType; | ||
| 467 | } | ||
| 468 | |||
| 469 | private static IntermediateFieldType ColumnType3ToIntermediateFieldType4(Wix3.ColumnType columnType) | ||
| 470 | { | ||
| 471 | switch (columnType) | ||
| 472 | { | ||
| 473 | case Wix3.ColumnType.Number: | ||
| 474 | return IntermediateFieldType.Number; | ||
| 475 | case Wix3.ColumnType.Object: | ||
| 476 | return IntermediateFieldType.Path; | ||
| 477 | case Wix3.ColumnType.Unknown: | ||
| 478 | case Wix3.ColumnType.String: | ||
| 479 | case Wix3.ColumnType.Localized: | ||
| 480 | case Wix3.ColumnType.Preserved: | ||
| 481 | default: | ||
| 482 | return IntermediateFieldType.String; | ||
| 483 | } | ||
| 484 | } | ||
| 485 | |||
| 486 | private static IntermediateTuple DefaultTupleFromRow(Type tupleType, Wix3.Row row, bool columnZeroIsId) | ||
| 487 | { | ||
| 488 | var tuple = Activator.CreateInstance(tupleType) as IntermediateTuple; | ||
| 489 | |||
| 490 | SetTupleFieldsFromRow(row, tuple, columnZeroIsId); | ||
| 491 | |||
| 492 | tuple.SourceLineNumbers = SourceLineNumber4(row.SourceLineNumbers); | ||
| 493 | return tuple; | ||
| 494 | } | ||
| 495 | |||
| 496 | private static IntermediateTuple GenericTupleFromCustomRow(Wix3.Row row, bool columnZeroIsId) | ||
| 497 | { | ||
| 498 | var columnDefinitions = row.Table.Definition.Columns.Cast<Wix3.ColumnDefinition>(); | ||
| 499 | var fieldDefinitions = columnDefinitions.Select(columnDefinition => | ||
| 500 | new IntermediateFieldDefinition(columnDefinition.Name, ColumnType3ToIntermediateFieldType4(columnDefinition.Type))).ToArray(); | ||
| 501 | var tupleDefinition = new IntermediateTupleDefinition(row.Table.Name, fieldDefinitions, null); | ||
| 502 | var tuple = new IntermediateTuple(tupleDefinition, SourceLineNumber4(row.SourceLineNumbers)); | ||
| 503 | |||
| 504 | SetTupleFieldsFromRow(row, tuple, columnZeroIsId); | ||
| 505 | |||
| 506 | return tuple; | ||
| 507 | } | ||
| 508 | |||
| 509 | private static void SetTupleFieldsFromRow(Wix3.Row row, IntermediateTuple tuple, bool columnZeroIsId) | ||
| 510 | { | ||
| 511 | int offset = 0; | ||
| 512 | if (columnZeroIsId) | ||
| 513 | { | ||
| 514 | tuple.Id = GetIdentifierForRow(row); | ||
| 515 | offset = 1; | ||
| 516 | } | ||
| 517 | |||
| 518 | for (var i = offset; i < row.Fields.Length; ++i) | ||
| 519 | { | ||
| 520 | var column = row.Fields[i].Column; | ||
| 521 | switch (column.Type) | ||
| 522 | { | ||
| 523 | case Wix3.ColumnType.String: | ||
| 524 | case Wix3.ColumnType.Localized: | ||
| 525 | case Wix3.ColumnType.Object: | ||
| 526 | case Wix3.ColumnType.Preserved: | ||
| 527 | tuple.Set(i - offset, FieldAsString(row, i)); | ||
| 528 | break; | ||
| 529 | case Wix3.ColumnType.Number: | ||
| 530 | int? nullableValue = FieldAsNullableInt(row, i); | ||
| 531 | // TODO: Consider whether null values should be coerced to their default value when | ||
| 532 | // a column is not nullable. For now, just pass through the null. | ||
| 533 | //int value = FieldAsInt(row, i); | ||
| 534 | //tuple.Set(i - offset, column.IsNullable ? nullableValue : value); | ||
| 535 | tuple.Set(i - offset, nullableValue); | ||
| 536 | break; | ||
| 537 | case Wix3.ColumnType.Unknown: | ||
| 538 | break; | ||
| 539 | } | ||
| 540 | } | ||
| 541 | } | ||
| 542 | |||
| 543 | private static Identifier GetIdentifierForRow(Wix3.Row row) | ||
| 544 | { | ||
| 545 | var column = row.Fields[0].Column; | ||
| 546 | switch (column.Type) | ||
| 547 | { | ||
| 548 | case Wix3.ColumnType.String: | ||
| 549 | case Wix3.ColumnType.Localized: | ||
| 550 | case Wix3.ColumnType.Object: | ||
| 551 | case Wix3.ColumnType.Preserved: | ||
| 552 | return new Identifier(AccessModifier.Public, (string)row.Fields[0].Data); | ||
| 553 | case Wix3.ColumnType.Number: | ||
| 554 | return new Identifier(AccessModifier.Public, FieldAsInt(row, 0)); | ||
| 555 | default: | ||
| 556 | return null; | ||
| 557 | } | ||
| 558 | } | ||
| 559 | |||
| 560 | private static SectionType OutputType3ToSectionType4(Wix3.OutputType outputType) | ||
| 561 | { | ||
| 562 | switch (outputType) | ||
| 563 | { | ||
| 564 | case Wix3.OutputType.Bundle: | ||
| 565 | return SectionType.Bundle; | ||
| 566 | case Wix3.OutputType.Module: | ||
| 567 | return SectionType.Module; | ||
| 568 | case Wix3.OutputType.Patch: | ||
| 569 | return SectionType.Patch; | ||
| 570 | case Wix3.OutputType.PatchCreation: | ||
| 571 | return SectionType.PatchCreation; | ||
| 572 | case Wix3.OutputType.Product: | ||
| 573 | return SectionType.Product; | ||
| 574 | case Wix3.OutputType.Transform: | ||
| 575 | case Wix3.OutputType.Unknown: | ||
| 576 | default: | ||
| 577 | return SectionType.Unknown; | ||
| 578 | } | ||
| 579 | } | ||
| 580 | |||
| 581 | private static SourceLineNumber SourceLineNumber4(Wix3.SourceLineNumberCollection source) | ||
| 582 | { | ||
| 583 | return String.IsNullOrEmpty(source?.EncodedSourceLineNumbers) ? null : SourceLineNumber.CreateFromEncoded(source.EncodedSourceLineNumbers); | ||
| 584 | } | ||
| 585 | |||
| 586 | private static string FieldAsString(Wix3.Row row, int column) | ||
| 587 | { | ||
| 588 | return (string)row[column]; | ||
| 589 | } | ||
| 590 | |||
| 591 | private static int FieldAsInt(Wix3.Row row, int column) | ||
| 592 | { | ||
| 593 | return Convert.ToInt32(row[column]); | ||
| 594 | } | ||
| 595 | |||
| 596 | private static int? FieldAsNullableInt(Wix3.Row row, int column) | ||
| 597 | { | ||
| 598 | var field = row.Fields[column]; | ||
| 599 | if (field.Data == null) | ||
| 600 | { | ||
| 601 | return null; | ||
| 602 | } | ||
| 603 | else | ||
| 604 | { | ||
| 605 | return Convert.ToInt32(field.Data); | ||
| 606 | } | ||
| 607 | } | ||
| 608 | } | ||
| 609 | } | ||
diff --git a/src/WixToolset.Converters.Tupleizer/WixToolset.Converters.Tupleizer.csproj b/src/WixToolset.Converters.Tupleizer/WixToolset.Converters.Tupleizer.csproj new file mode 100644 index 00000000..a162807a --- /dev/null +++ b/src/WixToolset.Converters.Tupleizer/WixToolset.Converters.Tupleizer.csproj | |||
| @@ -0,0 +1,32 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <!-- 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. --> | ||
| 3 | |||
| 4 | <Project Sdk="Microsoft.NET.Sdk"> | ||
| 5 | |||
| 6 | <PropertyGroup> | ||
| 7 | <TargetFramework>netstandard2.0</TargetFramework> | ||
| 8 | <Description>Tupleizer</Description> | ||
| 9 | <Title>WiX Toolset Converters Tuplizer</Title> | ||
| 10 | <DebugType>embedded</DebugType> | ||
| 11 | <PublishRepositoryUrl>true</PublishRepositoryUrl> | ||
| 12 | </PropertyGroup> | ||
| 13 | |||
| 14 | <PropertyGroup> | ||
| 15 | <NoWarn>NU1701</NoWarn> | ||
| 16 | </PropertyGroup> | ||
| 17 | |||
| 18 | <ItemGroup> | ||
| 19 | <Reference Include="wix" HintPath="..\deps\wix.dll" /> | ||
| 20 | <None Include="..\deps\wix.dll" Pack="true" PackagePath="lib\net461" /> | ||
| 21 | </ItemGroup> | ||
| 22 | |||
| 23 | <ItemGroup> | ||
| 24 | <PackageReference Include="WixToolset.Core" Version="4.0.*" /> | ||
| 25 | <PackageReference Include="WixToolset.Core.WindowsInstaller" Version="4.0.*" /> | ||
| 26 | </ItemGroup> | ||
| 27 | |||
| 28 | <ItemGroup> | ||
| 29 | <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-18618-05" PrivateAssets="All"/> | ||
| 30 | <PackageReference Include="Nerdbank.GitVersioning" Version="2.1.65" PrivateAssets="All" /> | ||
| 31 | </ItemGroup> | ||
| 32 | </Project> | ||
diff --git a/src/WixToolset.Converters/Wix3Converter.cs b/src/WixToolset.Converters/Wix3Converter.cs new file mode 100644 index 00000000..c23930b6 --- /dev/null +++ b/src/WixToolset.Converters/Wix3Converter.cs | |||
| @@ -0,0 +1,652 @@ | |||
| 1 | // 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. | ||
| 2 | |||
| 3 | namespace WixToolset.Converters | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using System.Globalization; | ||
| 8 | using System.IO; | ||
| 9 | using System.Linq; | ||
| 10 | using System.Text; | ||
| 11 | using System.Text.RegularExpressions; | ||
| 12 | using System.Xml; | ||
| 13 | using System.Xml.Linq; | ||
| 14 | using WixToolset.Data; | ||
| 15 | using WixToolset.Extensibility.Services; | ||
| 16 | |||
| 17 | /// <summary> | ||
| 18 | /// WiX source code converter. | ||
| 19 | /// </summary> | ||
| 20 | public class Wix3Converter | ||
| 21 | { | ||
| 22 | private static readonly Regex AddPrefix = new Regex(@"^[^a-zA-Z_]", RegexOptions.Compiled); | ||
| 23 | private static readonly Regex IllegalIdentifierCharacters = new Regex(@"[^A-Za-z0-9_\.]|\.{2,}", RegexOptions.Compiled); // non 'words' and assorted valid characters | ||
| 24 | |||
| 25 | private const char XDocumentNewLine = '\n'; // XDocument normalizes "\r\n" to just "\n". | ||
| 26 | private static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs"; | ||
| 27 | |||
| 28 | private static readonly XName DirectoryElementName = WixNamespace + "Directory"; | ||
| 29 | private static readonly XName FileElementName = WixNamespace + "File"; | ||
| 30 | private static readonly XName ExePackageElementName = WixNamespace + "ExePackage"; | ||
| 31 | private static readonly XName MsiPackageElementName = WixNamespace + "MsiPackage"; | ||
| 32 | private static readonly XName MspPackageElementName = WixNamespace + "MspPackage"; | ||
| 33 | private static readonly XName MsuPackageElementName = WixNamespace + "MsuPackage"; | ||
| 34 | private static readonly XName PayloadElementName = WixNamespace + "Payload"; | ||
| 35 | private static readonly XName CustomActionElementName = WixNamespace + "CustomAction"; | ||
| 36 | private static readonly XName PropertyElementName = WixNamespace + "Property"; | ||
| 37 | private static readonly XName WixElementWithoutNamespaceName = XNamespace.None + "Wix"; | ||
| 38 | |||
| 39 | private static readonly Dictionary<string, XNamespace> OldToNewNamespaceMapping = new Dictionary<string, XNamespace>() | ||
| 40 | { | ||
| 41 | { "http://schemas.microsoft.com/wix/BalExtension", "http://wixtoolset.org/schemas/v4/wxs/bal" }, | ||
| 42 | { "http://schemas.microsoft.com/wix/ComPlusExtension", "http://wixtoolset.org/schemas/v4/wxs/complus" }, | ||
| 43 | { "http://schemas.microsoft.com/wix/DependencyExtension", "http://wixtoolset.org/schemas/v4/wxs/dependency" }, | ||
| 44 | { "http://schemas.microsoft.com/wix/DifxAppExtension", "http://wixtoolset.org/schemas/v4/wxs/difxapp" }, | ||
| 45 | { "http://schemas.microsoft.com/wix/FirewallExtension", "http://wixtoolset.org/schemas/v4/wxs/firewall" }, | ||
| 46 | { "http://schemas.microsoft.com/wix/GamingExtension", "http://wixtoolset.org/schemas/v4/wxs/gaming" }, | ||
| 47 | { "http://schemas.microsoft.com/wix/IIsExtension", "http://wixtoolset.org/schemas/v4/wxs/iis" }, | ||
| 48 | { "http://schemas.microsoft.com/wix/MsmqExtension", "http://wixtoolset.org/schemas/v4/wxs/msmq" }, | ||
| 49 | { "http://schemas.microsoft.com/wix/NetFxExtension", "http://wixtoolset.org/schemas/v4/wxs/netfx" }, | ||
| 50 | { "http://schemas.microsoft.com/wix/PSExtension", "http://wixtoolset.org/schemas/v4/wxs/powershell" }, | ||
| 51 | { "http://schemas.microsoft.com/wix/SqlExtension", "http://wixtoolset.org/schemas/v4/wxs/sql" }, | ||
| 52 | { "http://schemas.microsoft.com/wix/TagExtension", "http://wixtoolset.org/schemas/v4/wxs/tag" }, | ||
| 53 | { "http://schemas.microsoft.com/wix/UtilExtension", "http://wixtoolset.org/schemas/v4/wxs/util" }, | ||
| 54 | { "http://schemas.microsoft.com/wix/VSExtension", "http://wixtoolset.org/schemas/v4/wxs/vs" }, | ||
| 55 | { "http://wixtoolset.org/schemas/thmutil/2010", "http://wixtoolset.org/schemas/v4/thmutil" }, | ||
| 56 | { "http://schemas.microsoft.com/wix/2009/Lux", "http://wixtoolset.org/schemas/v4/lux" }, | ||
| 57 | { "http://schemas.microsoft.com/wix/2006/wi", "http://wixtoolset.org/schemas/v4/wxs" }, | ||
| 58 | { "http://schemas.microsoft.com/wix/2006/localization", "http://wixtoolset.org/schemas/v4/wxl" }, | ||
| 59 | { "http://schemas.microsoft.com/wix/2006/libraries", "http://wixtoolset.org/schemas/v4/wixlib" }, | ||
| 60 | { "http://schemas.microsoft.com/wix/2006/objects", "http://wixtoolset.org/schemas/v4/wixobj" }, | ||
| 61 | { "http://schemas.microsoft.com/wix/2006/outputs", "http://wixtoolset.org/schemas/v4/wixout" }, | ||
| 62 | { "http://schemas.microsoft.com/wix/2007/pdbs", "http://wixtoolset.org/schemas/v4/wixpdb" }, | ||
| 63 | { "http://schemas.microsoft.com/wix/2003/04/actions", "http://wixtoolset.org/schemas/v4/wi/actions" }, | ||
| 64 | { "http://schemas.microsoft.com/wix/2006/tables", "http://wixtoolset.org/schemas/v4/wi/tables" }, | ||
| 65 | { "http://schemas.microsoft.com/wix/2006/WixUnit", "http://wixtoolset.org/schemas/v4/wixunit" }, | ||
| 66 | }; | ||
| 67 | |||
| 68 | private readonly Dictionary<XName, Action<XElement>> ConvertElementMapping; | ||
| 69 | |||
| 70 | /// <summary> | ||
| 71 | /// Instantiate a new Converter class. | ||
| 72 | /// </summary> | ||
| 73 | /// <param name="indentationAmount">Indentation value to use when validating leading whitespace.</param> | ||
| 74 | /// <param name="errorsAsWarnings">Test errors to display as warnings.</param> | ||
| 75 | /// <param name="ignoreErrors">Test errors to ignore.</param> | ||
| 76 | public Wix3Converter(IMessaging messaging, int indentationAmount, IEnumerable<string> errorsAsWarnings = null, IEnumerable<string> ignoreErrors = null) | ||
| 77 | { | ||
| 78 | this.ConvertElementMapping = new Dictionary<XName, Action<XElement>> | ||
| 79 | { | ||
| 80 | { Wix3Converter.DirectoryElementName, this.ConvertDirectoryElement }, | ||
| 81 | { Wix3Converter.FileElementName, this.ConvertFileElement }, | ||
| 82 | { Wix3Converter.ExePackageElementName, this.ConvertSuppressSignatureValidation }, | ||
| 83 | { Wix3Converter.MsiPackageElementName, this.ConvertSuppressSignatureValidation }, | ||
| 84 | { Wix3Converter.MspPackageElementName, this.ConvertSuppressSignatureValidation }, | ||
| 85 | { Wix3Converter.MsuPackageElementName, this.ConvertSuppressSignatureValidation }, | ||
| 86 | { Wix3Converter.PayloadElementName, this.ConvertSuppressSignatureValidation }, | ||
| 87 | { Wix3Converter.CustomActionElementName, this.ConvertCustomActionElement }, | ||
| 88 | { Wix3Converter.PropertyElementName, this.ConvertPropertyElement }, | ||
| 89 | { Wix3Converter.WixElementWithoutNamespaceName, this.ConvertWixElementWithoutNamespace }, | ||
| 90 | }; | ||
| 91 | |||
| 92 | this.Messaging = messaging; | ||
| 93 | |||
| 94 | this.IndentationAmount = indentationAmount; | ||
| 95 | |||
| 96 | this.ErrorsAsWarnings = new HashSet<ConverterTestType>(this.YieldConverterTypes(errorsAsWarnings)); | ||
| 97 | |||
| 98 | this.IgnoreErrors = new HashSet<ConverterTestType>(this.YieldConverterTypes(ignoreErrors)); | ||
| 99 | } | ||
| 100 | |||
| 101 | private int Errors { get; set; } | ||
| 102 | |||
| 103 | private HashSet<ConverterTestType> ErrorsAsWarnings { get; set; } | ||
| 104 | |||
| 105 | private HashSet<ConverterTestType> IgnoreErrors { get; set; } | ||
| 106 | |||
| 107 | private IMessaging Messaging { get; } | ||
| 108 | |||
| 109 | private int IndentationAmount { get; set; } | ||
| 110 | |||
| 111 | private string SourceFile { get; set; } | ||
| 112 | |||
| 113 | /// <summary> | ||
| 114 | /// Convert a file. | ||
| 115 | /// </summary> | ||
| 116 | /// <param name="sourceFile">The file to convert.</param> | ||
| 117 | /// <param name="saveConvertedFile">Option to save the converted errors that are found.</param> | ||
| 118 | /// <returns>The number of errors found.</returns> | ||
| 119 | public int ConvertFile(string sourceFile, bool saveConvertedFile) | ||
| 120 | { | ||
| 121 | XDocument document; | ||
| 122 | |||
| 123 | // Set the instance info. | ||
| 124 | this.Errors = 0; | ||
| 125 | this.SourceFile = sourceFile; | ||
| 126 | |||
| 127 | try | ||
| 128 | { | ||
| 129 | document = XDocument.Load(this.SourceFile, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 130 | } | ||
| 131 | catch (XmlException e) | ||
| 132 | { | ||
| 133 | this.OnError(ConverterTestType.XmlException, null, "The xml is invalid. Detail: '{0}'", e.Message); | ||
| 134 | |||
| 135 | return this.Errors; | ||
| 136 | } | ||
| 137 | |||
| 138 | this.ConvertDocument(document); | ||
| 139 | |||
| 140 | // Fix errors if requested and necessary. | ||
| 141 | if (saveConvertedFile && 0 < this.Errors) | ||
| 142 | { | ||
| 143 | try | ||
| 144 | { | ||
| 145 | using (var writer = File.CreateText(this.SourceFile)) | ||
| 146 | { | ||
| 147 | document.Save(writer, SaveOptions.DisableFormatting | SaveOptions.OmitDuplicateNamespaces); | ||
| 148 | } | ||
| 149 | } | ||
| 150 | catch (UnauthorizedAccessException) | ||
| 151 | { | ||
| 152 | this.OnError(ConverterTestType.UnauthorizedAccessException, null, "Could not write to file."); | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | return this.Errors; | ||
| 157 | } | ||
| 158 | |||
| 159 | /// <summary> | ||
| 160 | /// Convert a document. | ||
| 161 | /// </summary> | ||
| 162 | /// <param name="document">The document to convert.</param> | ||
| 163 | /// <returns>The number of errors found.</returns> | ||
| 164 | public int ConvertDocument(XDocument document) | ||
| 165 | { | ||
| 166 | var declaration = document.Declaration; | ||
| 167 | |||
| 168 | // Convert the declaration. | ||
| 169 | if (null != declaration) | ||
| 170 | { | ||
| 171 | if (!String.Equals("utf-8", declaration.Encoding, StringComparison.OrdinalIgnoreCase)) | ||
| 172 | { | ||
| 173 | if (this.OnError(ConverterTestType.DeclarationEncodingWrong, document.Root, "The XML declaration encoding is not properly set to 'utf-8'.")) | ||
| 174 | { | ||
| 175 | declaration.Encoding = "utf-8"; | ||
| 176 | } | ||
| 177 | } | ||
| 178 | } | ||
| 179 | else // missing declaration | ||
| 180 | { | ||
| 181 | if (this.OnError(ConverterTestType.DeclarationMissing, null, "This file is missing an XML declaration on the first line.")) | ||
| 182 | { | ||
| 183 | document.Declaration = new XDeclaration("1.0", "utf-8", null); | ||
| 184 | document.Root.AddBeforeSelf(new XText(XDocumentNewLine.ToString())); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | // Start converting the nodes at the top. | ||
| 189 | this.ConvertNodes(document.Nodes(), 0); | ||
| 190 | |||
| 191 | return this.Errors; | ||
| 192 | } | ||
| 193 | |||
| 194 | private void ConvertNodes(IEnumerable<XNode> nodes, int level) | ||
| 195 | { | ||
| 196 | // Note we operate on a copy of the node list since we may | ||
| 197 | // remove some whitespace nodes during this processing. | ||
| 198 | foreach (var node in nodes.ToList()) | ||
| 199 | { | ||
| 200 | if (node is XText text) | ||
| 201 | { | ||
| 202 | if (!String.IsNullOrWhiteSpace(text.Value)) | ||
| 203 | { | ||
| 204 | text.Value = text.Value.Trim(); | ||
| 205 | } | ||
| 206 | else if (node.NextNode is XCData cdata) | ||
| 207 | { | ||
| 208 | this.EnsurePrecedingWhitespaceRemoved(text, node, ConverterTestType.WhitespacePrecedingNodeWrong); | ||
| 209 | } | ||
| 210 | else if (node.NextNode is XElement element) | ||
| 211 | { | ||
| 212 | this.EnsurePrecedingWhitespaceCorrect(text, node, level, ConverterTestType.WhitespacePrecedingNodeWrong); | ||
| 213 | } | ||
| 214 | else if (node.NextNode is null) // this is the space before the close element | ||
| 215 | { | ||
| 216 | if (node.PreviousNode is null || node.PreviousNode is XCData) | ||
| 217 | { | ||
| 218 | this.EnsurePrecedingWhitespaceRemoved(text, node.Parent, ConverterTestType.WhitespacePrecedingEndElementWrong); | ||
| 219 | } | ||
| 220 | else if (level == 0) // root element's close tag | ||
| 221 | { | ||
| 222 | this.EnsurePrecedingWhitespaceCorrect(text, node, 0, ConverterTestType.WhitespacePrecedingEndElementWrong); | ||
| 223 | } | ||
| 224 | else | ||
| 225 | { | ||
| 226 | this.EnsurePrecedingWhitespaceCorrect(text, node, level - 1, ConverterTestType.WhitespacePrecedingEndElementWrong); | ||
| 227 | } | ||
| 228 | } | ||
| 229 | } | ||
| 230 | else if (node is XElement element) | ||
| 231 | { | ||
| 232 | this.ConvertElement(element); | ||
| 233 | |||
| 234 | this.ConvertNodes(element.Nodes(), level + 1); | ||
| 235 | } | ||
| 236 | } | ||
| 237 | } | ||
| 238 | |||
| 239 | private void EnsurePrecedingWhitespaceCorrect(XText whitespace, XNode node, int level, ConverterTestType testType) | ||
| 240 | { | ||
| 241 | if (!Wix3Converter.LeadingWhitespaceValid(this.IndentationAmount, level, whitespace.Value)) | ||
| 242 | { | ||
| 243 | var message = testType == ConverterTestType.WhitespacePrecedingEndElementWrong ? "The whitespace preceding this end element is incorrect." : "The whitespace preceding this node is incorrect."; | ||
| 244 | |||
| 245 | if (this.OnError(testType, node, message)) | ||
| 246 | { | ||
| 247 | Wix3Converter.FixupWhitespace(this.IndentationAmount, level, whitespace); | ||
| 248 | } | ||
| 249 | } | ||
| 250 | } | ||
| 251 | |||
| 252 | private void EnsurePrecedingWhitespaceRemoved(XText whitespace, XNode node, ConverterTestType testType) | ||
| 253 | { | ||
| 254 | if (!String.IsNullOrEmpty(whitespace.Value)) | ||
| 255 | { | ||
| 256 | var message = testType == ConverterTestType.WhitespacePrecedingEndElementWrong ? "The whitespace preceding this end element is incorrect." : "The whitespace preceding this node is incorrect."; | ||
| 257 | |||
| 258 | if (this.OnError(testType, node, message)) | ||
| 259 | { | ||
| 260 | whitespace.Remove(); | ||
| 261 | } | ||
| 262 | } | ||
| 263 | } | ||
| 264 | |||
| 265 | private void ConvertElement(XElement element) | ||
| 266 | { | ||
| 267 | // Gather any deprecated namespaces, then update this element tree based on those deprecations. | ||
| 268 | var deprecatedToUpdatedNamespaces = new Dictionary<XNamespace, XNamespace>(); | ||
| 269 | |||
| 270 | foreach (var declaration in element.Attributes().Where(a => a.IsNamespaceDeclaration)) | ||
| 271 | { | ||
| 272 | if (Wix3Converter.OldToNewNamespaceMapping.TryGetValue(declaration.Value, out var ns)) | ||
| 273 | { | ||
| 274 | if (this.OnError(ConverterTestType.XmlnsValueWrong, declaration, "The namespace '{0}' is out of date. It must be '{1}'.", declaration.Value, ns.NamespaceName)) | ||
| 275 | { | ||
| 276 | deprecatedToUpdatedNamespaces.Add(declaration.Value, ns); | ||
| 277 | } | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | if (deprecatedToUpdatedNamespaces.Any()) | ||
| 282 | { | ||
| 283 | Wix3Converter.UpdateElementsWithDeprecatedNamespaces(element.DescendantsAndSelf(), deprecatedToUpdatedNamespaces); | ||
| 284 | } | ||
| 285 | |||
| 286 | // Apply any specialized conversion actions. | ||
| 287 | if (this.ConvertElementMapping.TryGetValue(element.Name, out var convert)) | ||
| 288 | { | ||
| 289 | convert(element); | ||
| 290 | } | ||
| 291 | } | ||
| 292 | |||
| 293 | private void ConvertDirectoryElement(XElement element) | ||
| 294 | { | ||
| 295 | if (null == element.Attribute("Name")) | ||
| 296 | { | ||
| 297 | var attribute = element.Attribute("ShortName"); | ||
| 298 | if (null != attribute) | ||
| 299 | { | ||
| 300 | var shortName = attribute.Value; | ||
| 301 | if (this.OnError(ConverterTestType.AssignDirectoryNameFromShortName, element, "The directory ShortName attribute is being renamed to Name since Name wasn't specified for value '{0}'", shortName)) | ||
| 302 | { | ||
| 303 | element.Add(new XAttribute("Name", shortName)); | ||
| 304 | attribute.Remove(); | ||
| 305 | } | ||
| 306 | } | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | private void ConvertFileElement(XElement element) | ||
| 311 | { | ||
| 312 | if (null == element.Attribute("Id")) | ||
| 313 | { | ||
| 314 | var attribute = element.Attribute("Name"); | ||
| 315 | |||
| 316 | if (null == attribute) | ||
| 317 | { | ||
| 318 | attribute = element.Attribute("Source"); | ||
| 319 | } | ||
| 320 | |||
| 321 | if (null != attribute) | ||
| 322 | { | ||
| 323 | var name = Path.GetFileName(attribute.Value); | ||
| 324 | |||
| 325 | if (this.OnError(ConverterTestType.AssignAnonymousFileId, element, "The file id is being updated to '{0}' to ensure it remains the same as the default", name)) | ||
| 326 | { | ||
| 327 | IEnumerable<XAttribute> attributes = element.Attributes().ToList(); | ||
| 328 | element.RemoveAttributes(); | ||
| 329 | element.Add(new XAttribute("Id", GetIdentifierFromName(name))); | ||
| 330 | element.Add(attributes); | ||
| 331 | } | ||
| 332 | } | ||
| 333 | } | ||
| 334 | } | ||
| 335 | |||
| 336 | private void ConvertSuppressSignatureValidation(XElement element) | ||
| 337 | { | ||
| 338 | var suppressSignatureValidation = element.Attribute("SuppressSignatureValidation"); | ||
| 339 | |||
| 340 | if (null != suppressSignatureValidation) | ||
| 341 | { | ||
| 342 | if (this.OnError(ConverterTestType.SuppressSignatureValidationDeprecated, element, "The chain package element contains deprecated '{0}' attribute. Use the 'EnableSignatureValidation' attribute instead.", suppressSignatureValidation)) | ||
| 343 | { | ||
| 344 | if ("no" == suppressSignatureValidation.Value) | ||
| 345 | { | ||
| 346 | element.Add(new XAttribute("EnableSignatureValidation", "yes")); | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | suppressSignatureValidation.Remove(); | ||
| 351 | } | ||
| 352 | } | ||
| 353 | |||
| 354 | private void ConvertCustomActionElement(XElement xCustomAction) | ||
| 355 | { | ||
| 356 | var xBinaryKey = xCustomAction.Attribute("BinaryKey"); | ||
| 357 | |||
| 358 | if (xBinaryKey?.Value == "WixCA") | ||
| 359 | { | ||
| 360 | if (this.OnError(ConverterTestType.WixCABinaryIdRenamed, xCustomAction, "The WixCA custom action DLL Binary table id has been renamed. Use the id 'UtilCA' instead.")) | ||
| 361 | { | ||
| 362 | xBinaryKey.Value = "UtilCA"; | ||
| 363 | } | ||
| 364 | } | ||
| 365 | |||
| 366 | var xDllEntry = xCustomAction.Attribute("DllEntry"); | ||
| 367 | |||
| 368 | if (xDllEntry?.Value == "CAQuietExec" || xDllEntry?.Value == "CAQuietExec64") | ||
| 369 | { | ||
| 370 | if (this.OnError(ConverterTestType.QuietExecCustomActionsRenamed, xCustomAction, "The CAQuietExec and CAQuietExec64 custom action ids have been renamed. Use the ids 'WixQuietExec' and 'WixQuietExec64' instead.")) | ||
| 371 | { | ||
| 372 | xDllEntry.Value = xDllEntry.Value.Replace("CAQuietExec", "WixQuietExec"); | ||
| 373 | } | ||
| 374 | } | ||
| 375 | |||
| 376 | var xProperty = xCustomAction.Attribute("Property"); | ||
| 377 | |||
| 378 | if (xProperty?.Value == "QtExecCmdLine" || xProperty?.Value == "QtExec64CmdLine") | ||
| 379 | { | ||
| 380 | if (this.OnError(ConverterTestType.QuietExecCustomActionsRenamed, xCustomAction, "The QtExecCmdLine and QtExec64CmdLine property ids have been renamed. Use the ids 'WixQuietExecCmdLine' and 'WixQuietExec64CmdLine' instead.")) | ||
| 381 | { | ||
| 382 | xProperty.Value = xProperty.Value.Replace("QtExec", "WixQuietExec"); | ||
| 383 | } | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | private void ConvertPropertyElement(XElement xProperty) | ||
| 388 | { | ||
| 389 | var xId = xProperty.Attribute("Id"); | ||
| 390 | |||
| 391 | if (xId.Value == "QtExecCmdTimeout") | ||
| 392 | { | ||
| 393 | this.OnError(ConverterTestType.QtExecCmdTimeoutAmbiguous, xProperty, "QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout."); | ||
| 394 | } | ||
| 395 | } | ||
| 396 | |||
| 397 | /// <summary> | ||
| 398 | /// Converts a Wix element. | ||
| 399 | /// </summary> | ||
| 400 | /// <param name="element">The Wix element to convert.</param> | ||
| 401 | /// <returns>The converted element.</returns> | ||
| 402 | private void ConvertWixElementWithoutNamespace(XElement element) | ||
| 403 | { | ||
| 404 | if (this.OnError(ConverterTestType.XmlnsMissing, element, "The xmlns attribute is missing. It must be present with a value of '{0}'.", WixNamespace.NamespaceName)) | ||
| 405 | { | ||
| 406 | element.Name = WixNamespace.GetName(element.Name.LocalName); | ||
| 407 | |||
| 408 | element.Add(new XAttribute("xmlns", WixNamespace.NamespaceName)); // set the default namespace. | ||
| 409 | |||
| 410 | foreach (var elementWithoutNamespace in element.Elements().Where(e => XNamespace.None == e.Name.Namespace)) | ||
| 411 | { | ||
| 412 | elementWithoutNamespace.Name = WixNamespace.GetName(elementWithoutNamespace.Name.LocalName); | ||
| 413 | } | ||
| 414 | } | ||
| 415 | } | ||
| 416 | |||
| 417 | private IEnumerable<ConverterTestType> YieldConverterTypes(IEnumerable<string> types) | ||
| 418 | { | ||
| 419 | if (null != types) | ||
| 420 | { | ||
| 421 | foreach (var type in types) | ||
| 422 | { | ||
| 423 | |||
| 424 | if (Enum.TryParse<ConverterTestType>(type, true, out var itt)) | ||
| 425 | { | ||
| 426 | yield return itt; | ||
| 427 | } | ||
| 428 | else // not a known ConverterTestType | ||
| 429 | { | ||
| 430 | this.OnError(ConverterTestType.ConverterTestTypeUnknown, null, "Unknown error type: '{0}'.", type); | ||
| 431 | } | ||
| 432 | } | ||
| 433 | } | ||
| 434 | } | ||
| 435 | |||
| 436 | private static void UpdateElementsWithDeprecatedNamespaces(IEnumerable<XElement> elements, Dictionary<XNamespace, XNamespace> deprecatedToUpdatedNamespaces) | ||
| 437 | { | ||
| 438 | foreach (var element in elements) | ||
| 439 | { | ||
| 440 | |||
| 441 | if (deprecatedToUpdatedNamespaces.TryGetValue(element.Name.Namespace, out var ns)) | ||
| 442 | { | ||
| 443 | element.Name = ns.GetName(element.Name.LocalName); | ||
| 444 | } | ||
| 445 | |||
| 446 | // Remove all the attributes and add them back to with their namespace updated (as necessary). | ||
| 447 | IEnumerable<XAttribute> attributes = element.Attributes().ToList(); | ||
| 448 | element.RemoveAttributes(); | ||
| 449 | |||
| 450 | foreach (var attribute in attributes) | ||
| 451 | { | ||
| 452 | var convertedAttribute = attribute; | ||
| 453 | |||
| 454 | if (attribute.IsNamespaceDeclaration) | ||
| 455 | { | ||
| 456 | if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Value, out ns)) | ||
| 457 | { | ||
| 458 | convertedAttribute = ("xmlns" == attribute.Name.LocalName) ? new XAttribute(attribute.Name.LocalName, ns.NamespaceName) : new XAttribute(XNamespace.Xmlns + attribute.Name.LocalName, ns.NamespaceName); | ||
| 459 | } | ||
| 460 | } | ||
| 461 | else if (deprecatedToUpdatedNamespaces.TryGetValue(attribute.Name.Namespace, out ns)) | ||
| 462 | { | ||
| 463 | convertedAttribute = new XAttribute(ns.GetName(attribute.Name.LocalName), attribute.Value); | ||
| 464 | } | ||
| 465 | |||
| 466 | element.Add(convertedAttribute); | ||
| 467 | } | ||
| 468 | } | ||
| 469 | } | ||
| 470 | |||
| 471 | /// <summary> | ||
| 472 | /// Determine if the whitespace preceding a node is appropriate for its depth level. | ||
| 473 | /// </summary> | ||
| 474 | /// <param name="indentationAmount">Indentation value to use when validating leading whitespace.</param> | ||
| 475 | /// <param name="level">The depth level that should match this whitespace.</param> | ||
| 476 | /// <param name="whitespace">The whitespace to validate.</param> | ||
| 477 | /// <returns>true if the whitespace is legal; false otherwise.</returns> | ||
| 478 | private static bool LeadingWhitespaceValid(int indentationAmount, int level, string whitespace) | ||
| 479 | { | ||
| 480 | // Strip off leading newlines; there can be an arbitrary number of these. | ||
| 481 | whitespace = whitespace.TrimStart(XDocumentNewLine); | ||
| 482 | |||
| 483 | var indentation = new string(' ', level * indentationAmount); | ||
| 484 | |||
| 485 | return whitespace == indentation; | ||
| 486 | } | ||
| 487 | |||
| 488 | /// <summary> | ||
| 489 | /// Fix the whitespace in a whitespace node. | ||
| 490 | /// </summary> | ||
| 491 | /// <param name="indentationAmount">Indentation value to use when validating leading whitespace.</param> | ||
| 492 | /// <param name="level">The depth level of the desired whitespace.</param> | ||
| 493 | /// <param name="whitespace">The whitespace node to fix.</param> | ||
| 494 | private static void FixupWhitespace(int indentationAmount, int level, XText whitespace) | ||
| 495 | { | ||
| 496 | var value = new StringBuilder(whitespace.Value.Length); | ||
| 497 | |||
| 498 | // Keep any previous preceeding new lines. | ||
| 499 | var newlines = whitespace.Value.TakeWhile(c => c == XDocumentNewLine).Count(); | ||
| 500 | |||
| 501 | // Ensure there is always at least one new line before the indentation. | ||
| 502 | value.Append(XDocumentNewLine, newlines == 0 ? 1 : newlines); | ||
| 503 | |||
| 504 | whitespace.Value = value.Append(' ', level * indentationAmount).ToString(); | ||
| 505 | } | ||
| 506 | |||
| 507 | /// <summary> | ||
| 508 | /// Output an error message to the console. | ||
| 509 | /// </summary> | ||
| 510 | /// <param name="converterTestType">The type of converter test.</param> | ||
| 511 | /// <param name="node">The node that caused the error.</param> | ||
| 512 | /// <param name="message">Detailed error message.</param> | ||
| 513 | /// <param name="args">Additional formatted string arguments.</param> | ||
| 514 | /// <returns>Returns true indicating that action should be taken on this error, and false if it should be ignored.</returns> | ||
| 515 | private bool OnError(ConverterTestType converterTestType, XObject node, string message, params object[] args) | ||
| 516 | { | ||
| 517 | if (this.IgnoreErrors.Contains(converterTestType)) // ignore the error | ||
| 518 | { | ||
| 519 | return false; | ||
| 520 | } | ||
| 521 | |||
| 522 | // Increase the error count. | ||
| 523 | this.Errors++; | ||
| 524 | |||
| 525 | var sourceLine = (null == node) ? new SourceLineNumber(this.SourceFile ?? "wixcop.exe") : new SourceLineNumber(this.SourceFile, ((IXmlLineInfo)node).LineNumber); | ||
| 526 | var warning = this.ErrorsAsWarnings.Contains(converterTestType); | ||
| 527 | var display = String.Format(CultureInfo.CurrentCulture, message, args); | ||
| 528 | |||
| 529 | var msg = new Message(sourceLine, warning ? MessageLevel.Warning : MessageLevel.Error, (int)converterTestType, "{0} ({1})", display, converterTestType.ToString()); | ||
| 530 | |||
| 531 | this.Messaging.Write(msg); | ||
| 532 | |||
| 533 | return true; | ||
| 534 | } | ||
| 535 | |||
| 536 | /// <summary> | ||
| 537 | /// Return an identifier based on passed file/directory name | ||
| 538 | /// </summary> | ||
| 539 | /// <param name="name">File/directory name to generate identifer from</param> | ||
| 540 | /// <returns>A version of the name that is a legal identifier.</returns> | ||
| 541 | /// <remarks>This is duplicated from WiX's Common class.</remarks> | ||
| 542 | private static string GetIdentifierFromName(string name) | ||
| 543 | { | ||
| 544 | string result = IllegalIdentifierCharacters.Replace(name, "_"); // replace illegal characters with "_". | ||
| 545 | |||
| 546 | // MSI identifiers must begin with an alphabetic character or an | ||
| 547 | // underscore. Prefix all other values with an underscore. | ||
| 548 | if (AddPrefix.IsMatch(name)) | ||
| 549 | { | ||
| 550 | result = String.Concat("_", result); | ||
| 551 | } | ||
| 552 | |||
| 553 | return result; | ||
| 554 | } | ||
| 555 | |||
| 556 | /// <summary> | ||
| 557 | /// Converter test types. These are used to condition error messages down to warnings. | ||
| 558 | /// </summary> | ||
| 559 | private enum ConverterTestType | ||
| 560 | { | ||
| 561 | /// <summary> | ||
| 562 | /// Internal-only: displayed when a string cannot be converted to an ConverterTestType. | ||
| 563 | /// </summary> | ||
| 564 | ConverterTestTypeUnknown, | ||
| 565 | |||
| 566 | /// <summary> | ||
| 567 | /// Displayed when an XML loading exception has occurred. | ||
| 568 | /// </summary> | ||
| 569 | XmlException, | ||
| 570 | |||
| 571 | /// <summary> | ||
| 572 | /// Displayed when a file cannot be accessed; typically when trying to save back a fixed file. | ||
| 573 | /// </summary> | ||
| 574 | UnauthorizedAccessException, | ||
| 575 | |||
| 576 | /// <summary> | ||
| 577 | /// Displayed when the encoding attribute in the XML declaration is not 'UTF-8'. | ||
| 578 | /// </summary> | ||
| 579 | DeclarationEncodingWrong, | ||
| 580 | |||
| 581 | /// <summary> | ||
| 582 | /// Displayed when the XML declaration is missing from the source file. | ||
| 583 | /// </summary> | ||
| 584 | DeclarationMissing, | ||
| 585 | |||
| 586 | /// <summary> | ||
| 587 | /// Displayed when the whitespace preceding a CDATA node is wrong. | ||
| 588 | /// </summary> | ||
| 589 | WhitespacePrecedingCDATAWrong, | ||
| 590 | |||
| 591 | /// <summary> | ||
| 592 | /// Displayed when the whitespace preceding a node is wrong. | ||
| 593 | /// </summary> | ||
| 594 | WhitespacePrecedingNodeWrong, | ||
| 595 | |||
| 596 | /// <summary> | ||
| 597 | /// Displayed when an element is not empty as it should be. | ||
| 598 | /// </summary> | ||
| 599 | NotEmptyElement, | ||
| 600 | |||
| 601 | /// <summary> | ||
| 602 | /// Displayed when the whitespace following a CDATA node is wrong. | ||
| 603 | /// </summary> | ||
| 604 | WhitespaceFollowingCDATAWrong, | ||
| 605 | |||
| 606 | /// <summary> | ||
| 607 | /// Displayed when the whitespace preceding an end element is wrong. | ||
| 608 | /// </summary> | ||
| 609 | WhitespacePrecedingEndElementWrong, | ||
| 610 | |||
| 611 | /// <summary> | ||
| 612 | /// Displayed when the xmlns attribute is missing from the document element. | ||
| 613 | /// </summary> | ||
| 614 | XmlnsMissing, | ||
| 615 | |||
| 616 | /// <summary> | ||
| 617 | /// Displayed when the xmlns attribute on the document element is wrong. | ||
| 618 | /// </summary> | ||
| 619 | XmlnsValueWrong, | ||
| 620 | |||
| 621 | /// <summary> | ||
| 622 | /// Assign an identifier to a File element when on Id attribute is specified. | ||
| 623 | /// </summary> | ||
| 624 | AssignAnonymousFileId, | ||
| 625 | |||
| 626 | /// <summary> | ||
| 627 | /// SuppressSignatureValidation attribute is deprecated and replaced with EnableSignatureValidation. | ||
| 628 | /// </summary> | ||
| 629 | SuppressSignatureValidationDeprecated, | ||
| 630 | |||
| 631 | /// <summary> | ||
| 632 | /// WixCA Binary/@Id has been renamed to UtilCA. | ||
| 633 | /// </summary> | ||
| 634 | WixCABinaryIdRenamed, | ||
| 635 | |||
| 636 | /// <summary> | ||
| 637 | /// QtExec custom actions have been renamed. | ||
| 638 | /// </summary> | ||
| 639 | QuietExecCustomActionsRenamed, | ||
| 640 | |||
| 641 | /// <summary> | ||
| 642 | /// QtExecCmdTimeout was previously used for both CAQuietExec and CAQuietExec64. For WixQuietExec, use WixQuietExecCmdTimeout. For WixQuietExec64, use WixQuietExec64CmdTimeout. | ||
| 643 | /// </summary> | ||
| 644 | QtExecCmdTimeoutAmbiguous, | ||
| 645 | |||
| 646 | /// <summary> | ||
| 647 | /// Directory/@ShortName may only be specified with Directory/@Name. | ||
| 648 | /// </summary> | ||
| 649 | AssignDirectoryNameFromShortName, | ||
| 650 | } | ||
| 651 | } | ||
| 652 | } | ||
diff --git a/src/WixToolset.Converters/WixToolset.Converters.csproj b/src/WixToolset.Converters/WixToolset.Converters.csproj new file mode 100644 index 00000000..94a956d5 --- /dev/null +++ b/src/WixToolset.Converters/WixToolset.Converters.csproj | |||
| @@ -0,0 +1,26 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <!-- 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. --> | ||
| 3 | |||
| 4 | <Project Sdk="Microsoft.NET.Sdk"> | ||
| 5 | |||
| 6 | <PropertyGroup> | ||
| 7 | <TargetFramework>netstandard2.0</TargetFramework> | ||
| 8 | <Description>Converter</Description> | ||
| 9 | <Title>WiX Toolset Converters</Title> | ||
| 10 | <DebugType>embedded</DebugType> | ||
| 11 | <PublishRepositoryUrl>true</PublishRepositoryUrl> | ||
| 12 | </PropertyGroup> | ||
| 13 | |||
| 14 | <PropertyGroup> | ||
| 15 | <NoWarn>NU1701</NoWarn> | ||
| 16 | </PropertyGroup> | ||
| 17 | |||
| 18 | <ItemGroup> | ||
| 19 | <PackageReference Include="WixToolset.Core" Version="4.0.*" /> | ||
| 20 | </ItemGroup> | ||
| 21 | |||
| 22 | <ItemGroup> | ||
| 23 | <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0-beta2-18618-05" PrivateAssets="All"/> | ||
| 24 | <PackageReference Include="Nerdbank.GitVersioning" Version="2.1.65" PrivateAssets="All" /> | ||
| 25 | </ItemGroup> | ||
| 26 | </Project> | ||
diff --git a/src/deps/wix.dll b/src/deps/wix.dll new file mode 100644 index 00000000..64f70f75 --- /dev/null +++ b/src/deps/wix.dll | |||
| Binary files differ | |||
diff --git a/src/test/WixToolsetTest.Converters.Tupleizer/ConvertTuplesFixture.cs b/src/test/WixToolsetTest.Converters.Tupleizer/ConvertTuplesFixture.cs new file mode 100644 index 00000000..ae33d6b1 --- /dev/null +++ b/src/test/WixToolsetTest.Converters.Tupleizer/ConvertTuplesFixture.cs | |||
| @@ -0,0 +1,391 @@ | |||
| 1 | // 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. | ||
| 2 | |||
| 3 | namespace WixToolsetTest.Converters.Tupleizer | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.IO; | ||
| 7 | using System.Linq; | ||
| 8 | using WixBuildTools.TestSupport; | ||
| 9 | using Wix3 = Microsoft.Tools.WindowsInstallerXml; | ||
| 10 | using WixToolset.Converters.Tupleizer; | ||
| 11 | using WixToolset.Data; | ||
| 12 | using WixToolset.Data.WindowsInstaller; | ||
| 13 | using WixToolset.Data.Tuples; | ||
| 14 | using Xunit; | ||
| 15 | |||
| 16 | public class ConvertTuplesFixture | ||
| 17 | { | ||
| 18 | [Fact] | ||
| 19 | public void CanLoadWixoutAndConvertToIntermediate() | ||
| 20 | { | ||
| 21 | var rootFolder = TestData.Get(); | ||
| 22 | var dataFolder = TestData.Get(@"TestData\Integration"); | ||
| 23 | |||
| 24 | using (var fs = new DisposableFileSystem()) | ||
| 25 | { | ||
| 26 | var intermediateFolder = fs.GetFolder(); | ||
| 27 | |||
| 28 | var path = Path.Combine(dataFolder, "test.wixout"); | ||
| 29 | var output = Wix3.Output.Load(path, suppressVersionCheck: true, suppressSchema: true); | ||
| 30 | |||
| 31 | var command = new ConvertTuplesCommand(); | ||
| 32 | var intermediate = command.Execute(output); | ||
| 33 | |||
| 34 | Assert.NotNull(intermediate); | ||
| 35 | Assert.Single(intermediate.Sections); | ||
| 36 | Assert.Equal(String.Empty, intermediate.Id); | ||
| 37 | |||
| 38 | // Save and load to guarantee round-tripping support. | ||
| 39 | // | ||
| 40 | var wixiplFile = Path.Combine(intermediateFolder, "test.wixipl"); | ||
| 41 | intermediate.Save(wixiplFile); | ||
| 42 | |||
| 43 | intermediate = Intermediate.Load(wixiplFile); | ||
| 44 | |||
| 45 | // Dump to text for easy diffing, with some massaging to keep v3 and v4 diffable. | ||
| 46 | // | ||
| 47 | var tables = output.Tables.Cast<Wix3.Table>(); | ||
| 48 | var wix3Dump = tables | ||
| 49 | .SelectMany(table => table.Rows.Cast<Wix3.Row>() | ||
| 50 | .Select(row => RowToString(row))) | ||
| 51 | .ToArray(); | ||
| 52 | |||
| 53 | var tuples = intermediate.Sections.SelectMany(s => s.Tuples); | ||
| 54 | var wix4Dump = tuples.Select(tuple => TupleToString(tuple)).ToArray(); | ||
| 55 | |||
| 56 | Assert.Equal(wix3Dump, wix4Dump); | ||
| 57 | |||
| 58 | // Useful when you want to diff the outputs with another diff tool... | ||
| 59 | // | ||
| 60 | //var wix3TextDump = String.Join(Environment.NewLine, wix3Dump.OrderBy(val => val)); | ||
| 61 | //var wix4TextDump = String.Join(Environment.NewLine, wix4Dump.OrderBy(val => val)); | ||
| 62 | //Assert.Equal(wix3TextDump, wix4TextDump); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | private static string RowToString(Wix3.Row row) | ||
| 67 | { | ||
| 68 | var fields = String.Join(",", row.Fields.Select(field => field.Data?.ToString())); | ||
| 69 | |||
| 70 | // Massage output to match WiX v3 rows and v4 tuples. | ||
| 71 | // | ||
| 72 | switch (row.Table.Name) | ||
| 73 | { | ||
| 74 | case "File": | ||
| 75 | var fieldValues = row.Fields.Take(7).Select(field => field.Data?.ToString()).ToArray(); | ||
| 76 | if (fieldValues[3] == null) | ||
| 77 | { | ||
| 78 | // "Somebody" sometimes writes out a null field even when the column definition says | ||
| 79 | // it's non-nullable. Not naming names or anything. (SWID tags.) | ||
| 80 | fieldValues[3] = "0"; | ||
| 81 | } | ||
| 82 | fields = String.Join(",", fieldValues); | ||
| 83 | break; | ||
| 84 | case "WixFile": | ||
| 85 | fields = String.Join(",", row.Fields.Take(8).Select(field => field.Data?.ToString())); | ||
| 86 | break; | ||
| 87 | } | ||
| 88 | |||
| 89 | return $"{row.Table.Name},{fields}"; | ||
| 90 | } | ||
| 91 | |||
| 92 | private static string TupleToString(WixToolset.Data.IntermediateTuple tuple) | ||
| 93 | { | ||
| 94 | var fields = String.Join(",", tuple.Fields.Select(field => field?.AsString())); | ||
| 95 | |||
| 96 | switch (tuple.Definition.Name) | ||
| 97 | { | ||
| 98 | // Massage output to match WiX v3 rows and v4 tuples. | ||
| 99 | // | ||
| 100 | case "Component": | ||
| 101 | { | ||
| 102 | var componentTuple = (ComponentTuple)tuple; | ||
| 103 | var attributes = ComponentLocation.Either == componentTuple.Location ? WindowsInstallerConstants.MsidbComponentAttributesOptional : 0; | ||
| 104 | attributes |= ComponentLocation.SourceOnly == componentTuple.Location ? WindowsInstallerConstants.MsidbComponentAttributesSourceOnly : 0; | ||
| 105 | attributes |= ComponentKeyPathType.Registry == componentTuple.KeyPathType ? WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath : 0; | ||
| 106 | attributes |= ComponentKeyPathType.OdbcDataSource == componentTuple.KeyPathType ? WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource : 0; | ||
| 107 | attributes |= componentTuple.DisableRegistryReflection ? WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection : 0; | ||
| 108 | attributes |= componentTuple.NeverOverwrite ? WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite : 0; | ||
| 109 | attributes |= componentTuple.Permanent ? WindowsInstallerConstants.MsidbComponentAttributesPermanent : 0; | ||
| 110 | attributes |= componentTuple.SharedDllRefCount ? WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount : 0; | ||
| 111 | attributes |= componentTuple.Shared ? WindowsInstallerConstants.MsidbComponentAttributesShared : 0; | ||
| 112 | attributes |= componentTuple.Transitive ? WindowsInstallerConstants.MsidbComponentAttributesTransitive : 0; | ||
| 113 | attributes |= componentTuple.UninstallWhenSuperseded ? WindowsInstallerConstants.MsidbComponentAttributes64bit : 0; | ||
| 114 | attributes |= componentTuple.Win64 ? WindowsInstallerConstants.MsidbComponentAttributes64bit : 0; | ||
| 115 | |||
| 116 | fields = String.Join(",", | ||
| 117 | componentTuple.ComponentId, | ||
| 118 | componentTuple.Directory_, | ||
| 119 | attributes.ToString(), | ||
| 120 | componentTuple.Condition, | ||
| 121 | componentTuple.KeyPath | ||
| 122 | ); | ||
| 123 | break; | ||
| 124 | } | ||
| 125 | case "CustomAction": | ||
| 126 | { | ||
| 127 | var customActionTuple = (CustomActionTuple)tuple; | ||
| 128 | var type = customActionTuple.Win64 ? WindowsInstallerConstants.MsidbCustomActionType64BitScript : 0; | ||
| 129 | type |= customActionTuple.TSAware ? WindowsInstallerConstants.MsidbCustomActionTypeTSAware : 0; | ||
| 130 | type |= customActionTuple.Impersonate ? 0 : WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate; | ||
| 131 | type |= customActionTuple.IgnoreResult ? WindowsInstallerConstants.MsidbCustomActionTypeContinue : 0; | ||
| 132 | type |= customActionTuple.Hidden ? WindowsInstallerConstants.MsidbCustomActionTypeHideTarget : 0; | ||
| 133 | type |= customActionTuple.Async ? WindowsInstallerConstants.MsidbCustomActionTypeAsync : 0; | ||
| 134 | type |= CustomActionExecutionType.FirstSequence == customActionTuple.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence : 0; | ||
| 135 | type |= CustomActionExecutionType.OncePerProcess == customActionTuple.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess : 0; | ||
| 136 | type |= CustomActionExecutionType.ClientRepeat == customActionTuple.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat : 0; | ||
| 137 | type |= CustomActionExecutionType.Deferred == customActionTuple.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript : 0; | ||
| 138 | type |= CustomActionExecutionType.Rollback == customActionTuple.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback : 0; | ||
| 139 | type |= CustomActionExecutionType.Commit == customActionTuple.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit : 0; | ||
| 140 | type |= CustomActionSourceType.File == customActionTuple.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeSourceFile : 0; | ||
| 141 | type |= CustomActionSourceType.Directory == customActionTuple.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeDirectory : 0; | ||
| 142 | type |= CustomActionSourceType.Property == customActionTuple.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeProperty : 0; | ||
| 143 | type |= CustomActionTargetType.Dll == customActionTuple.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeDll : 0; | ||
| 144 | type |= CustomActionTargetType.Exe == customActionTuple.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeExe : 0; | ||
| 145 | type |= CustomActionTargetType.TextData == customActionTuple.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeTextData : 0; | ||
| 146 | type |= CustomActionTargetType.JScript == customActionTuple.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeJScript : 0; | ||
| 147 | type |= CustomActionTargetType.VBScript == customActionTuple.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeVBScript : 0; | ||
| 148 | |||
| 149 | fields = String.Join(",", | ||
| 150 | type.ToString(), | ||
| 151 | customActionTuple.Source, | ||
| 152 | customActionTuple.Target, | ||
| 153 | customActionTuple.PatchUninstall ? WindowsInstallerConstants.MsidbCustomActionTypePatchUninstall.ToString() : null | ||
| 154 | ); | ||
| 155 | break; | ||
| 156 | } | ||
| 157 | case "Feature": | ||
| 158 | { | ||
| 159 | var featureTuple = (FeatureTuple)tuple; | ||
| 160 | var attributes = featureTuple.DisallowAbsent ? WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent : 0; | ||
| 161 | attributes |= featureTuple.DisallowAdvertise ? WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise : 0; | ||
| 162 | attributes |= FeatureInstallDefault.FollowParent == featureTuple.InstallDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFollowParent : 0; | ||
| 163 | attributes |= FeatureInstallDefault.Source == featureTuple.InstallDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFavorSource : 0; | ||
| 164 | attributes |= FeatureTypicalDefault.Advertise == featureTuple.TypicalDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise : 0; | ||
| 165 | |||
| 166 | fields = String.Join(",", | ||
| 167 | featureTuple.Feature_Parent, | ||
| 168 | featureTuple.Title, | ||
| 169 | featureTuple.Description, | ||
| 170 | featureTuple.Display.ToString(), | ||
| 171 | featureTuple.Level.ToString(), | ||
| 172 | featureTuple.Directory_, | ||
| 173 | attributes.ToString()); | ||
| 174 | break; | ||
| 175 | } | ||
| 176 | case "File": | ||
| 177 | { | ||
| 178 | var fileTuple = (FileTuple)tuple; | ||
| 179 | fields = String.Join(",", | ||
| 180 | fileTuple.Component_, | ||
| 181 | fileTuple.LongFileName, | ||
| 182 | fileTuple.FileSize.ToString(), | ||
| 183 | fileTuple.Version, | ||
| 184 | fileTuple.Language, | ||
| 185 | ((fileTuple.ReadOnly ? WindowsInstallerConstants.MsidbFileAttributesReadOnly : 0) | ||
| 186 | | (fileTuple.Hidden ? WindowsInstallerConstants.MsidbFileAttributesHidden : 0) | ||
| 187 | | (fileTuple.System ? WindowsInstallerConstants.MsidbFileAttributesSystem : 0) | ||
| 188 | | (fileTuple.Vital ? WindowsInstallerConstants.MsidbFileAttributesVital : 0) | ||
| 189 | | (fileTuple.Checksum ? WindowsInstallerConstants.MsidbFileAttributesChecksum : 0) | ||
| 190 | | ((fileTuple.Compressed.HasValue && fileTuple.Compressed.Value) ? WindowsInstallerConstants.MsidbFileAttributesCompressed : 0) | ||
| 191 | | ((fileTuple.Compressed.HasValue && !fileTuple.Compressed.Value) ? WindowsInstallerConstants.MsidbFileAttributesNoncompressed : 0)) | ||
| 192 | .ToString()); | ||
| 193 | break; | ||
| 194 | } | ||
| 195 | |||
| 196 | case "Registry": | ||
| 197 | { | ||
| 198 | var registryTuple = (RegistryTuple)tuple; | ||
| 199 | var value = registryTuple.Value; | ||
| 200 | |||
| 201 | switch (registryTuple.ValueType) | ||
| 202 | { | ||
| 203 | case RegistryValueType.Binary: | ||
| 204 | value = String.Concat("#x", value); | ||
| 205 | break; | ||
| 206 | case RegistryValueType.Expandable: | ||
| 207 | value = String.Concat("#%", value); | ||
| 208 | break; | ||
| 209 | case RegistryValueType.Integer: | ||
| 210 | value = String.Concat("#", value); | ||
| 211 | break; | ||
| 212 | case RegistryValueType.MultiString: | ||
| 213 | switch (registryTuple.ValueAction) | ||
| 214 | { | ||
| 215 | case RegistryValueActionType.Append: | ||
| 216 | value = String.Concat("[~]", value); | ||
| 217 | break; | ||
| 218 | case RegistryValueActionType.Prepend: | ||
| 219 | value = String.Concat(value, "[~]"); | ||
| 220 | break; | ||
| 221 | case RegistryValueActionType.Write: | ||
| 222 | default: | ||
| 223 | if (null != value && -1 == value.IndexOf("[~]", StringComparison.Ordinal)) | ||
| 224 | { | ||
| 225 | value = String.Concat("[~]", value, "[~]"); | ||
| 226 | } | ||
| 227 | break; | ||
| 228 | } | ||
| 229 | break; | ||
| 230 | case RegistryValueType.String: | ||
| 231 | // escape the leading '#' character for string registry keys | ||
| 232 | if (null != value && value.StartsWith("#", StringComparison.Ordinal)) | ||
| 233 | { | ||
| 234 | value = String.Concat("#", value); | ||
| 235 | } | ||
| 236 | break; | ||
| 237 | } | ||
| 238 | |||
| 239 | fields = String.Join(",", | ||
| 240 | ((int)registryTuple.Root).ToString(), | ||
| 241 | registryTuple.Key, | ||
| 242 | registryTuple.Name, | ||
| 243 | value, | ||
| 244 | registryTuple.Component_ | ||
| 245 | ); | ||
| 246 | break; | ||
| 247 | } | ||
| 248 | |||
| 249 | case "RemoveRegistry": | ||
| 250 | { | ||
| 251 | var removeRegistryTuple = (RemoveRegistryTuple)tuple; | ||
| 252 | fields = String.Join(",", | ||
| 253 | ((int)removeRegistryTuple.Root).ToString(), | ||
| 254 | removeRegistryTuple.Key, | ||
| 255 | removeRegistryTuple.Name, | ||
| 256 | removeRegistryTuple.Component_ | ||
| 257 | ); | ||
| 258 | break; | ||
| 259 | } | ||
| 260 | |||
| 261 | case "ServiceControl": | ||
| 262 | { | ||
| 263 | var serviceControlTuple = (ServiceControlTuple)tuple; | ||
| 264 | |||
| 265 | var events = serviceControlTuple.InstallRemove ? WindowsInstallerConstants.MsidbServiceControlEventDelete : 0; | ||
| 266 | events |= serviceControlTuple.UninstallRemove ? WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete : 0; | ||
| 267 | events |= serviceControlTuple.InstallStart ? WindowsInstallerConstants.MsidbServiceControlEventStart : 0; | ||
| 268 | events |= serviceControlTuple.UninstallStart ? WindowsInstallerConstants.MsidbServiceControlEventUninstallStart : 0; | ||
| 269 | events |= serviceControlTuple.InstallStop ? WindowsInstallerConstants.MsidbServiceControlEventStop : 0; | ||
| 270 | events |= serviceControlTuple.UninstallStop ? WindowsInstallerConstants.MsidbServiceControlEventUninstallStop : 0; | ||
| 271 | |||
| 272 | fields = String.Join(",", | ||
| 273 | serviceControlTuple.Name, | ||
| 274 | events.ToString(), | ||
| 275 | serviceControlTuple.Arguments, | ||
| 276 | serviceControlTuple.Wait == true ? "1" : "0", | ||
| 277 | serviceControlTuple.Component_ | ||
| 278 | ); | ||
| 279 | break; | ||
| 280 | } | ||
| 281 | |||
| 282 | case "ServiceInstall": | ||
| 283 | { | ||
| 284 | var serviceInstallTuple = (ServiceInstallTuple)tuple; | ||
| 285 | |||
| 286 | var errorControl = (int)serviceInstallTuple.ErrorControl; | ||
| 287 | errorControl |= serviceInstallTuple.Vital ? WindowsInstallerConstants.MsidbServiceInstallErrorControlVital : 0; | ||
| 288 | |||
| 289 | var serviceType = (int)serviceInstallTuple.ServiceType; | ||
| 290 | serviceType |= serviceInstallTuple.Interactive ? WindowsInstallerConstants.MsidbServiceInstallInteractive : 0; | ||
| 291 | |||
| 292 | fields = String.Join(",", | ||
| 293 | serviceInstallTuple.Name, | ||
| 294 | serviceInstallTuple.DisplayName, | ||
| 295 | serviceType.ToString(), | ||
| 296 | ((int)serviceInstallTuple.StartType).ToString(), | ||
| 297 | errorControl.ToString(), | ||
| 298 | serviceInstallTuple.LoadOrderGroup, | ||
| 299 | serviceInstallTuple.Dependencies, | ||
| 300 | serviceInstallTuple.StartName, | ||
| 301 | serviceInstallTuple.Password, | ||
| 302 | serviceInstallTuple.Arguments, | ||
| 303 | serviceInstallTuple.Component_, | ||
| 304 | serviceInstallTuple.Description | ||
| 305 | ); | ||
| 306 | break; | ||
| 307 | } | ||
| 308 | |||
| 309 | case "Upgrade": | ||
| 310 | { | ||
| 311 | var upgradeTuple = (UpgradeTuple)tuple; | ||
| 312 | |||
| 313 | var attributes = upgradeTuple.MigrateFeatures ? WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures : 0; | ||
| 314 | attributes |= upgradeTuple.OnlyDetect ? WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect : 0; | ||
| 315 | attributes |= upgradeTuple.IgnoreRemoveFailures ? WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure : 0; | ||
| 316 | attributes |= upgradeTuple.VersionMinInclusive ? WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive : 0; | ||
| 317 | attributes |= upgradeTuple.VersionMaxInclusive ? WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive : 0; | ||
| 318 | attributes |= upgradeTuple.ExcludeLanguages ? WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive : 0; | ||
| 319 | |||
| 320 | fields = String.Join(",", | ||
| 321 | upgradeTuple.VersionMin, | ||
| 322 | upgradeTuple.VersionMax, | ||
| 323 | upgradeTuple.Language, | ||
| 324 | attributes.ToString(), | ||
| 325 | upgradeTuple.Remove, | ||
| 326 | upgradeTuple.ActionProperty | ||
| 327 | ); | ||
| 328 | break; | ||
| 329 | } | ||
| 330 | |||
| 331 | case "WixAction": | ||
| 332 | { | ||
| 333 | var wixActionTuple = (WixActionTuple)tuple; | ||
| 334 | fields = String.Join(",", | ||
| 335 | wixActionTuple.SequenceTable, | ||
| 336 | wixActionTuple.Action, | ||
| 337 | wixActionTuple.Condition, | ||
| 338 | // BUGBUGBUG: AB#2626 | ||
| 339 | wixActionTuple.Sequence == 0 ? String.Empty : wixActionTuple.Sequence.ToString(), | ||
| 340 | wixActionTuple.Before, | ||
| 341 | wixActionTuple.After, | ||
| 342 | wixActionTuple.Overridable == true ? "1" : "0" | ||
| 343 | ); | ||
| 344 | break; | ||
| 345 | } | ||
| 346 | |||
| 347 | case "WixComplexReference": | ||
| 348 | { | ||
| 349 | var wixComplexReferenceTuple = (WixComplexReferenceTuple)tuple; | ||
| 350 | fields = String.Join(",", | ||
| 351 | wixComplexReferenceTuple.Parent, | ||
| 352 | ((int)wixComplexReferenceTuple.ParentType).ToString(), | ||
| 353 | wixComplexReferenceTuple.ParentLanguage, | ||
| 354 | wixComplexReferenceTuple.Child, | ||
| 355 | ((int)wixComplexReferenceTuple.ChildType).ToString(), | ||
| 356 | wixComplexReferenceTuple.IsPrimary ? "1" : "0" | ||
| 357 | ); | ||
| 358 | break; | ||
| 359 | } | ||
| 360 | |||
| 361 | case "WixFile": | ||
| 362 | { | ||
| 363 | var wixFileTuple = (WixFileTuple)tuple; | ||
| 364 | fields = String.Concat( | ||
| 365 | wixFileTuple.AssemblyType == FileAssemblyType.DotNetAssembly ? "0" : wixFileTuple.AssemblyType == FileAssemblyType.Win32Assembly ? "1" : String.Empty, ",", | ||
| 366 | String.Join(",", tuple.Fields.Skip(2).Take(6).Select(field => (string)field).ToArray())); | ||
| 367 | break; | ||
| 368 | } | ||
| 369 | |||
| 370 | case "WixProperty": | ||
| 371 | { | ||
| 372 | var wixPropertyTuple = (WixPropertyTuple)tuple; | ||
| 373 | var attributes = 0; | ||
| 374 | attributes |= wixPropertyTuple.Admin ? 0x1 : 0; | ||
| 375 | attributes |= wixPropertyTuple.Hidden ? 0x2 : 0; | ||
| 376 | attributes |= wixPropertyTuple.Secure ? 0x4 : 0; | ||
| 377 | |||
| 378 | fields = String.Join(",", | ||
| 379 | wixPropertyTuple.Property_, | ||
| 380 | attributes.ToString() | ||
| 381 | ); | ||
| 382 | break; | ||
| 383 | } | ||
| 384 | |||
| 385 | } | ||
| 386 | |||
| 387 | var id = tuple.Id == null ? String.Empty : String.Concat(",", tuple.Id.Id); | ||
| 388 | return $"{tuple.Definition.Name}{id},{fields}"; | ||
| 389 | } | ||
| 390 | } | ||
| 391 | } | ||
diff --git a/src/test/WixToolsetTest.Converters.Tupleizer/TestData/Integration/test.wixout b/src/test/WixToolsetTest.Converters.Tupleizer/TestData/Integration/test.wixout new file mode 100644 index 00000000..da64b8af --- /dev/null +++ b/src/test/WixToolsetTest.Converters.Tupleizer/TestData/Integration/test.wixout | |||
| Binary files differ | |||
diff --git a/src/test/WixToolsetTest.Converters.Tupleizer/TestData/Integration/test.wixproj b/src/test/WixToolsetTest.Converters.Tupleizer/TestData/Integration/test.wixproj new file mode 100644 index 00000000..8af13dc8 --- /dev/null +++ b/src/test/WixToolsetTest.Converters.Tupleizer/TestData/Integration/test.wixproj | |||
| @@ -0,0 +1,47 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <Project ToolsVersion="4.0" DefaultTargets="Build" InitialTargets="EnsureWixToolsetInstalled" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> | ||
| 3 | <PropertyGroup> | ||
| 4 | <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> | ||
| 5 | <Platform Condition=" '$(Platform)' == '' ">x86</Platform> | ||
| 6 | <ProductVersion>3.10</ProductVersion> | ||
| 7 | <ProjectGuid>d59f1c1e-9238-49fa-bfa2-ec1d9c2dda1d</ProjectGuid> | ||
| 8 | <SchemaVersion>2.0</SchemaVersion> | ||
| 9 | <OutputName>TupleizerWixout</OutputName> | ||
| 10 | <OutputType>Package</OutputType> | ||
| 11 | </PropertyGroup> | ||
| 12 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' "> | ||
| 13 | <OutputPath>bin\$(Configuration)\</OutputPath> | ||
| 14 | <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath> | ||
| 15 | <DefineConstants>Debug</DefineConstants> | ||
| 16 | </PropertyGroup> | ||
| 17 | <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' "> | ||
| 18 | <OutputPath>bin\$(Configuration)\</OutputPath> | ||
| 19 | <IntermediateOutputPath>obj\$(Configuration)\</IntermediateOutputPath> | ||
| 20 | </PropertyGroup> | ||
| 21 | <ItemGroup> | ||
| 22 | <Compile Include="Product.wxs" /> | ||
| 23 | </ItemGroup> | ||
| 24 | <ItemGroup> | ||
| 25 | <WixExtension Include="WixUtilExtension"> | ||
| 26 | <HintPath>$(WixExtDir)\WixUtilExtension.dll</HintPath> | ||
| 27 | <Name>WixUtilExtension</Name> | ||
| 28 | </WixExtension> | ||
| 29 | <WixExtension Include="WixNetFxExtension"> | ||
| 30 | <HintPath>$(WixExtDir)\WixNetFxExtension.dll</HintPath> | ||
| 31 | <Name>WixNetFxExtension</Name> | ||
| 32 | </WixExtension> | ||
| 33 | </ItemGroup> | ||
| 34 | <Import Project="$(WixTargetsPath)" Condition=" '$(WixTargetsPath)' != '' " /> | ||
| 35 | <Import Project="$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets" Condition=" '$(WixTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets') " /> | ||
| 36 | <Target Name="EnsureWixToolsetInstalled" Condition=" '$(WixTargetsImported)' != 'true' "> | ||
| 37 | <Error Text="The WiX Toolset v3.11 (or newer) build tools must be installed to build this project. To download the WiX Toolset, see http://wixtoolset.org/releases/" /> | ||
| 38 | </Target> | ||
| 39 | <!-- | ||
| 40 | To modify your build process, add your task inside one of the targets below and uncomment it. | ||
| 41 | Other similar extension points exist, see Wix.targets. | ||
| 42 | <Target Name="BeforeBuild"> | ||
| 43 | </Target> | ||
| 44 | <Target Name="AfterBuild"> | ||
| 45 | </Target> | ||
| 46 | --> | ||
| 47 | </Project> \ No newline at end of file | ||
diff --git a/src/test/WixToolsetTest.Converters.Tupleizer/TestData/Integration/test.wxs b/src/test/WixToolsetTest.Converters.Tupleizer/TestData/Integration/test.wxs new file mode 100644 index 00000000..1006a254 --- /dev/null +++ b/src/test/WixToolsetTest.Converters.Tupleizer/TestData/Integration/test.wxs | |||
| @@ -0,0 +1,36 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"> | ||
| 3 | <Product Id="*" Name="TupleizerWixout" Language="1033" Version="1.0.0.0" Manufacturer="FireGiant" UpgradeCode="14a02d7f-9b32-4c92-b1f1-da518bf4e32a"> | ||
| 4 | <Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" /> | ||
| 5 | |||
| 6 | <MajorUpgrade DowngradeErrorMessage="A newer version of [ProductName] is already installed." AllowSameVersionUpgrades="yes" IgnoreRemoveFailure="yes" /> | ||
| 7 | <MediaTemplate /> | ||
| 8 | |||
| 9 | <Feature Id="ProductFeature" Title="TupleizerWixout" Level="1"> | ||
| 10 | <Feature Id="ChildFeature"> | ||
| 11 | <ComponentGroupRef Id="ProductComponents" /> | ||
| 12 | </Feature> | ||
| 13 | </Feature> | ||
| 14 | |||
| 15 | <PropertyRef Id="WIX_IS_NETFRAMEWORK_462_OR_LATER_INSTALLED" /> | ||
| 16 | <CustomActionRef Id="WixFailWhenDeferred" /> | ||
| 17 | <Property Id="WIXFAILWHENDEFERRED" Value="1" Secure="yes" /> | ||
| 18 | </Product> | ||
| 19 | |||
| 20 | <Fragment> | ||
| 21 | <Directory Id="TARGETDIR" Name="SourceDir"> | ||
| 22 | <Directory Id="ProgramFilesFolder"> | ||
| 23 | <Directory Id="INSTALLFOLDER" Name="TupleizerWixout" /> | ||
| 24 | </Directory> | ||
| 25 | </Directory> | ||
| 26 | </Fragment> | ||
| 27 | |||
| 28 | <Fragment> | ||
| 29 | <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER"> | ||
| 30 | <Component Id="ProductComponent"> | ||
| 31 | <File Checksum="yes" ReadOnly="yes" Source="$(env.WIX)\bin\candle.exe" Assembly=".net" AssemblyApplication="candle.exe" /> | ||
| 32 | <RegistryValue Root="HKLM" Key="SOFTWARE\WiX Toolset" Name="[ProductName]Installed" Value="1" Type="integer" /> | ||
| 33 | </Component> | ||
| 34 | </ComponentGroup> | ||
| 35 | </Fragment> | ||
| 36 | </Wix> | ||
diff --git a/src/test/WixToolsetTest.Converters.Tupleizer/WixToolsetTest.Converters.Tupleizer.csproj b/src/test/WixToolsetTest.Converters.Tupleizer/WixToolsetTest.Converters.Tupleizer.csproj new file mode 100644 index 00000000..fa6a6bcf --- /dev/null +++ b/src/test/WixToolsetTest.Converters.Tupleizer/WixToolsetTest.Converters.Tupleizer.csproj | |||
| @@ -0,0 +1,33 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <!-- 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. --> | ||
| 3 | |||
| 4 | <Project Sdk="Microsoft.NET.Sdk"> | ||
| 5 | |||
| 6 | <PropertyGroup> | ||
| 7 | <TargetFramework>net461</TargetFramework> | ||
| 8 | <IsPackable>false</IsPackable> | ||
| 9 | </PropertyGroup> | ||
| 10 | |||
| 11 | <ItemGroup> | ||
| 12 | <Content Include="TestData\Integration\test.wixout" CopyToOutputDirectory="PreserveNewest" /> | ||
| 13 | </ItemGroup> | ||
| 14 | |||
| 15 | <ItemGroup> | ||
| 16 | <ProjectReference Include="..\..\WixToolset.Converters.Tupleizer\WixToolset.Converters.Tupleizer.csproj" /> | ||
| 17 | </ItemGroup> | ||
| 18 | |||
| 19 | <ItemGroup> | ||
| 20 | <PackageReference Include="WixToolset.Data" Version="4.0.*" /> | ||
| 21 | <PackageReference Include="WixBuildTools.TestSupport" Version="4.0.*" /> | ||
| 22 | </ItemGroup> | ||
| 23 | |||
| 24 | <ItemGroup> | ||
| 25 | <Reference Include="wix" HintPath="..\..\deps\wix.dll" /> | ||
| 26 | </ItemGroup> | ||
| 27 | |||
| 28 | <ItemGroup> | ||
| 29 | <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" /> | ||
| 30 | <PackageReference Include="xunit" Version="2.4.1" /> | ||
| 31 | <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="All" /> | ||
| 32 | </ItemGroup> | ||
| 33 | </Project> | ||
diff --git a/src/test/WixToolsetTest.Converters/ConverterFixture.cs b/src/test/WixToolsetTest.Converters/ConverterFixture.cs new file mode 100644 index 00000000..97769cd6 --- /dev/null +++ b/src/test/WixToolsetTest.Converters/ConverterFixture.cs | |||
| @@ -0,0 +1,554 @@ | |||
| 1 | // 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. | ||
| 2 | |||
| 3 | namespace WixToolsetTest.Converters | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.IO; | ||
| 7 | using System.Text; | ||
| 8 | using System.Xml.Linq; | ||
| 9 | using WixToolset.Converters; | ||
| 10 | using WixToolset.Data; | ||
| 11 | using WixToolset.Extensibility; | ||
| 12 | using WixToolset.Extensibility.Services; | ||
| 13 | using Xunit; | ||
| 14 | |||
| 15 | public class ConverterFixture | ||
| 16 | { | ||
| 17 | private static readonly XNamespace Wix4Namespace = "http://wixtoolset.org/schemas/v4/wxs"; | ||
| 18 | |||
| 19 | [Fact] | ||
| 20 | public void EnsuresDeclaration() | ||
| 21 | { | ||
| 22 | var parse = String.Join(Environment.NewLine, | ||
| 23 | "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>", | ||
| 24 | " <Fragment />", | ||
| 25 | "</Wix>"); | ||
| 26 | |||
| 27 | var expected = String.Join(Environment.NewLine, | ||
| 28 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 29 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 30 | " <Fragment />", | ||
| 31 | "</Wix>"); | ||
| 32 | |||
| 33 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 34 | |||
| 35 | var messaging = new DummyMessaging(); | ||
| 36 | var converter = new Wix3Converter(messaging, 2, null, null); | ||
| 37 | |||
| 38 | var errors = converter.ConvertDocument(document); | ||
| 39 | |||
| 40 | var actual = UnformattedDocumentString(document); | ||
| 41 | |||
| 42 | Assert.Equal(1, errors); | ||
| 43 | Assert.Equal(expected, actual); | ||
| 44 | } | ||
| 45 | |||
| 46 | [Fact] | ||
| 47 | public void EnsuresUtf8Declaration() | ||
| 48 | { | ||
| 49 | var parse = String.Join(Environment.NewLine, | ||
| 50 | "<?xml version='1.0'?>", | ||
| 51 | "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>", | ||
| 52 | " <Fragment />", | ||
| 53 | "</Wix>"); | ||
| 54 | |||
| 55 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 56 | |||
| 57 | var messaging = new DummyMessaging(); | ||
| 58 | var converter = new Wix3Converter(messaging, 4, null, null); | ||
| 59 | |||
| 60 | var errors = converter.ConvertDocument(document); | ||
| 61 | |||
| 62 | Assert.Equal(1, errors); | ||
| 63 | Assert.Equal("1.0", document.Declaration.Version); | ||
| 64 | Assert.Equal("utf-8", document.Declaration.Encoding); | ||
| 65 | } | ||
| 66 | |||
| 67 | [Fact] | ||
| 68 | public void CanFixWhitespace() | ||
| 69 | { | ||
| 70 | var parse = String.Join(Environment.NewLine, | ||
| 71 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 72 | "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>", | ||
| 73 | " <Fragment>", | ||
| 74 | " <Property Id='Prop'", | ||
| 75 | " Value='Val'>", | ||
| 76 | " </Property>", | ||
| 77 | " </Fragment>", | ||
| 78 | "</Wix>"); | ||
| 79 | |||
| 80 | var expected = String.Join(Environment.NewLine, | ||
| 81 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 82 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 83 | " <Fragment>", | ||
| 84 | " <Property Id=\"Prop\" Value=\"Val\" />", | ||
| 85 | " </Fragment>", | ||
| 86 | "</Wix>"); | ||
| 87 | |||
| 88 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 89 | |||
| 90 | var messaging = new DummyMessaging(); | ||
| 91 | var converter = new Wix3Converter(messaging, 4, null, null); | ||
| 92 | |||
| 93 | var errors = converter.ConvertDocument(document); | ||
| 94 | |||
| 95 | var actual = UnformattedDocumentString(document); | ||
| 96 | |||
| 97 | Assert.Equal(expected, actual); | ||
| 98 | Assert.Equal(4, errors); | ||
| 99 | } | ||
| 100 | |||
| 101 | [Fact] | ||
| 102 | public void CanPreserveNewLines() | ||
| 103 | { | ||
| 104 | var parse = String.Join(Environment.NewLine, | ||
| 105 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 106 | "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>", | ||
| 107 | " <Fragment>", | ||
| 108 | "", | ||
| 109 | " <Property Id='Prop' Value='Val' />", | ||
| 110 | "", | ||
| 111 | " </Fragment>", | ||
| 112 | "</Wix>"); | ||
| 113 | |||
| 114 | var expected = String.Join(Environment.NewLine, | ||
| 115 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 116 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 117 | " <Fragment>", | ||
| 118 | "", | ||
| 119 | " <Property Id=\"Prop\" Value=\"Val\" />", | ||
| 120 | "", | ||
| 121 | " </Fragment>", | ||
| 122 | "</Wix>"); | ||
| 123 | |||
| 124 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 125 | |||
| 126 | var messaging = new DummyMessaging(); | ||
| 127 | var converter = new Wix3Converter(messaging, 4, null, null); | ||
| 128 | |||
| 129 | var conversions = converter.ConvertDocument(document); | ||
| 130 | |||
| 131 | var actual = UnformattedDocumentString(document); | ||
| 132 | |||
| 133 | Assert.Equal(expected, actual); | ||
| 134 | Assert.Equal(3, conversions); | ||
| 135 | } | ||
| 136 | |||
| 137 | [Fact] | ||
| 138 | public void CanConvertWithNewLineAtEndOfFile() | ||
| 139 | { | ||
| 140 | var parse = String.Join(Environment.NewLine, | ||
| 141 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 142 | "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>", | ||
| 143 | " <Fragment>", | ||
| 144 | "", | ||
| 145 | " <Property Id='Prop' Value='Val' />", | ||
| 146 | "", | ||
| 147 | " </Fragment>", | ||
| 148 | "</Wix>", | ||
| 149 | ""); | ||
| 150 | |||
| 151 | var expected = String.Join(Environment.NewLine, | ||
| 152 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 153 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 154 | " <Fragment>", | ||
| 155 | "", | ||
| 156 | " <Property Id=\"Prop\" Value=\"Val\" />", | ||
| 157 | "", | ||
| 158 | " </Fragment>", | ||
| 159 | "</Wix>", | ||
| 160 | ""); | ||
| 161 | |||
| 162 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 163 | |||
| 164 | var messaging = new DummyMessaging(); | ||
| 165 | var converter = new Wix3Converter(messaging, 4, null, null); | ||
| 166 | |||
| 167 | var conversions = converter.ConvertDocument(document); | ||
| 168 | |||
| 169 | var actual = UnformattedDocumentString(document); | ||
| 170 | |||
| 171 | Assert.Equal(expected, actual); | ||
| 172 | Assert.Equal(3, conversions); | ||
| 173 | } | ||
| 174 | |||
| 175 | [Fact] | ||
| 176 | public void CanFixCdataWhitespace() | ||
| 177 | { | ||
| 178 | var parse = String.Join(Environment.NewLine, | ||
| 179 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 180 | "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>", | ||
| 181 | " <Fragment>", | ||
| 182 | " <Property Id='Prop'>", | ||
| 183 | " <![CDATA[1<2]]>", | ||
| 184 | " </Property>", | ||
| 185 | " </Fragment>", | ||
| 186 | "</Wix>"); | ||
| 187 | |||
| 188 | var expected = String.Join(Environment.NewLine, | ||
| 189 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 190 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 191 | " <Fragment>", | ||
| 192 | " <Property Id=\"Prop\"><![CDATA[1<2]]></Property>", | ||
| 193 | " </Fragment>", | ||
| 194 | "</Wix>"); | ||
| 195 | |||
| 196 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 197 | |||
| 198 | var messaging = new DummyMessaging(); | ||
| 199 | var converter = new Wix3Converter(messaging, 2, null, null); | ||
| 200 | |||
| 201 | var errors = converter.ConvertDocument(document); | ||
| 202 | |||
| 203 | var actual = UnformattedDocumentString(document); | ||
| 204 | |||
| 205 | Assert.Equal(expected, actual); | ||
| 206 | Assert.Equal(2, errors); | ||
| 207 | } | ||
| 208 | |||
| 209 | [Fact] | ||
| 210 | public void CanFixCdataWithWhitespace() | ||
| 211 | { | ||
| 212 | var parse = String.Join(Environment.NewLine, | ||
| 213 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 214 | "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>", | ||
| 215 | " <Fragment>", | ||
| 216 | " <Property Id='Prop'>", | ||
| 217 | " <![CDATA[", | ||
| 218 | " 1<2", | ||
| 219 | " ]]>", | ||
| 220 | " </Property>", | ||
| 221 | " </Fragment>", | ||
| 222 | "</Wix>"); | ||
| 223 | |||
| 224 | var expected = String.Join(Environment.NewLine, | ||
| 225 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 226 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 227 | " <Fragment>", | ||
| 228 | " <Property Id=\"Prop\"><![CDATA[1<2]]></Property>", | ||
| 229 | " </Fragment>", | ||
| 230 | "</Wix>"); | ||
| 231 | |||
| 232 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 233 | |||
| 234 | var messaging = new DummyMessaging(); | ||
| 235 | var converter = new Wix3Converter(messaging, 2, null, null); | ||
| 236 | |||
| 237 | var errors = converter.ConvertDocument(document); | ||
| 238 | |||
| 239 | var actual = UnformattedDocumentString(document); | ||
| 240 | |||
| 241 | Assert.Equal(expected, actual); | ||
| 242 | Assert.Equal(2, errors); | ||
| 243 | } | ||
| 244 | |||
| 245 | [Fact] | ||
| 246 | public void CanConvertMainNamespace() | ||
| 247 | { | ||
| 248 | var parse = String.Join(Environment.NewLine, | ||
| 249 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 250 | "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi'>", | ||
| 251 | " <Fragment />", | ||
| 252 | "</Wix>"); | ||
| 253 | |||
| 254 | var expected = String.Join(Environment.NewLine, | ||
| 255 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 256 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 257 | " <Fragment />", | ||
| 258 | "</Wix>"); | ||
| 259 | |||
| 260 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 261 | |||
| 262 | var messaging = new DummyMessaging(); | ||
| 263 | var converter = new Wix3Converter(messaging, 2, null, null); | ||
| 264 | |||
| 265 | var errors = converter.ConvertDocument(document); | ||
| 266 | |||
| 267 | var actual = UnformattedDocumentString(document); | ||
| 268 | |||
| 269 | Assert.Equal(1, errors); | ||
| 270 | //Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace()); | ||
| 271 | Assert.Equal(expected, actual); | ||
| 272 | } | ||
| 273 | |||
| 274 | [Fact] | ||
| 275 | public void CanConvertNamedMainNamespace() | ||
| 276 | { | ||
| 277 | var parse = String.Join(Environment.NewLine, | ||
| 278 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 279 | "<w:Wix xmlns:w='http://schemas.microsoft.com/wix/2006/wi'>", | ||
| 280 | " <w:Fragment />", | ||
| 281 | "</w:Wix>"); | ||
| 282 | |||
| 283 | var expected = String.Join(Environment.NewLine, | ||
| 284 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 285 | "<w:Wix xmlns:w=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 286 | " <w:Fragment />", | ||
| 287 | "</w:Wix>"); | ||
| 288 | |||
| 289 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 290 | |||
| 291 | var messaging = new DummyMessaging(); | ||
| 292 | var converter = new Wix3Converter(messaging, 2, null, null); | ||
| 293 | |||
| 294 | var errors = converter.ConvertDocument(document); | ||
| 295 | |||
| 296 | var actual = UnformattedDocumentString(document); | ||
| 297 | |||
| 298 | Assert.Equal(1, errors); | ||
| 299 | Assert.Equal(expected, actual); | ||
| 300 | Assert.Equal(Wix4Namespace, document.Root.GetNamespaceOfPrefix("w")); | ||
| 301 | } | ||
| 302 | |||
| 303 | [Fact] | ||
| 304 | public void CanConvertNonWixDefaultNamespace() | ||
| 305 | { | ||
| 306 | var parse = String.Join(Environment.NewLine, | ||
| 307 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 308 | "<w:Wix xmlns:w='http://schemas.microsoft.com/wix/2006/wi' xmlns='http://schemas.microsoft.com/wix/UtilExtension'>", | ||
| 309 | " <w:Fragment>", | ||
| 310 | " <Test />", | ||
| 311 | " </w:Fragment>", | ||
| 312 | "</w:Wix>"); | ||
| 313 | |||
| 314 | var expected = String.Join(Environment.NewLine, | ||
| 315 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 316 | "<w:Wix xmlns:w=\"http://wixtoolset.org/schemas/v4/wxs\" xmlns=\"http://wixtoolset.org/schemas/v4/wxs/util\">", | ||
| 317 | " <w:Fragment>", | ||
| 318 | " <Test />", | ||
| 319 | " </w:Fragment>", | ||
| 320 | "</w:Wix>"); | ||
| 321 | |||
| 322 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 323 | |||
| 324 | var messaging = new DummyMessaging(); | ||
| 325 | var converter = new Wix3Converter(messaging, 2, null, null); | ||
| 326 | |||
| 327 | var errors = converter.ConvertDocument(document); | ||
| 328 | |||
| 329 | var actual = UnformattedDocumentString(document); | ||
| 330 | |||
| 331 | Assert.Equal(expected, actual); | ||
| 332 | Assert.Equal(2, errors); | ||
| 333 | Assert.Equal(Wix4Namespace, document.Root.GetNamespaceOfPrefix("w")); | ||
| 334 | Assert.Equal("http://wixtoolset.org/schemas/v4/wxs/util", document.Root.GetDefaultNamespace()); | ||
| 335 | } | ||
| 336 | |||
| 337 | [Fact] | ||
| 338 | public void CanConvertExtensionNamespace() | ||
| 339 | { | ||
| 340 | var parse = String.Join(Environment.NewLine, | ||
| 341 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 342 | "<Wix xmlns='http://schemas.microsoft.com/wix/2006/wi' xmlns:util='http://schemas.microsoft.com/wix/UtilExtension'>", | ||
| 343 | " <Fragment />", | ||
| 344 | "</Wix>"); | ||
| 345 | |||
| 346 | var expected = String.Join(Environment.NewLine, | ||
| 347 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 348 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\" xmlns:util=\"http://wixtoolset.org/schemas/v4/wxs/util\">", | ||
| 349 | " <Fragment />", | ||
| 350 | "</Wix>"); | ||
| 351 | |||
| 352 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 353 | |||
| 354 | var messaging = new DummyMessaging(); | ||
| 355 | var converter = new Wix3Converter(messaging, 2, null, null); | ||
| 356 | |||
| 357 | var errors = converter.ConvertDocument(document); | ||
| 358 | |||
| 359 | var actual = UnformattedDocumentString(document); | ||
| 360 | |||
| 361 | Assert.Equal(2, errors); | ||
| 362 | Assert.Equal(expected, actual); | ||
| 363 | Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace()); | ||
| 364 | } | ||
| 365 | |||
| 366 | [Fact] | ||
| 367 | public void CanConvertMissingNamespace() | ||
| 368 | { | ||
| 369 | var parse = String.Join(Environment.NewLine, | ||
| 370 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 371 | "<Wix>", | ||
| 372 | " <Fragment />", | ||
| 373 | "</Wix>"); | ||
| 374 | |||
| 375 | var expected = String.Join(Environment.NewLine, | ||
| 376 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 377 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 378 | " <Fragment />", | ||
| 379 | "</Wix>"); | ||
| 380 | |||
| 381 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 382 | |||
| 383 | var messaging = new DummyMessaging(); | ||
| 384 | var converter = new Wix3Converter(messaging, 2, null, null); | ||
| 385 | |||
| 386 | var errors = converter.ConvertDocument(document); | ||
| 387 | |||
| 388 | var actual = UnformattedDocumentString(document); | ||
| 389 | |||
| 390 | Assert.Equal(1, errors); | ||
| 391 | Assert.Equal(expected, actual); | ||
| 392 | Assert.Equal(Wix4Namespace, document.Root.GetDefaultNamespace()); | ||
| 393 | } | ||
| 394 | |||
| 395 | [Fact] | ||
| 396 | public void CanConvertAnonymousFile() | ||
| 397 | { | ||
| 398 | var parse = String.Join(Environment.NewLine, | ||
| 399 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 400 | "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>", | ||
| 401 | " <File Source='path\\to\\foo.txt' />", | ||
| 402 | "</Wix>"); | ||
| 403 | |||
| 404 | var expected = String.Join(Environment.NewLine, | ||
| 405 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 406 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 407 | " <File Id=\"foo.txt\" Source=\"path\\to\\foo.txt\" />", | ||
| 408 | "</Wix>"); | ||
| 409 | |||
| 410 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 411 | |||
| 412 | var messaging = new DummyMessaging(); | ||
| 413 | var converter = new Wix3Converter(messaging, 2, null, null); | ||
| 414 | |||
| 415 | var errors = converter.ConvertDocument(document); | ||
| 416 | |||
| 417 | var actual = UnformattedDocumentString(document); | ||
| 418 | |||
| 419 | Assert.Equal(1, errors); | ||
| 420 | Assert.Equal(expected, actual); | ||
| 421 | } | ||
| 422 | |||
| 423 | [Fact] | ||
| 424 | public void CanConvertShortNameDirectoryWithoutName() | ||
| 425 | { | ||
| 426 | var parse = String.Join(Environment.NewLine, | ||
| 427 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 428 | "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>", | ||
| 429 | " <Directory ShortName='iamshort' />", | ||
| 430 | "</Wix>"); | ||
| 431 | |||
| 432 | var expected = String.Join(Environment.NewLine, | ||
| 433 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 434 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 435 | " <Directory Name=\"iamshort\" />", | ||
| 436 | "</Wix>"); | ||
| 437 | |||
| 438 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 439 | |||
| 440 | var messaging = new DummyMessaging(); | ||
| 441 | var converter = new Wix3Converter(messaging, 2, null, null); | ||
| 442 | |||
| 443 | var errors = converter.ConvertDocument(document); | ||
| 444 | |||
| 445 | var actual = UnformattedDocumentString(document); | ||
| 446 | |||
| 447 | Assert.Equal(1, errors); | ||
| 448 | Assert.Equal(expected, actual); | ||
| 449 | } | ||
| 450 | |||
| 451 | [Fact] | ||
| 452 | public void CanConvertSuppressSignatureValidationNo() | ||
| 453 | { | ||
| 454 | var parse = String.Join(Environment.NewLine, | ||
| 455 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 456 | "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>", | ||
| 457 | " <MsiPackage SuppressSignatureValidation='no' />", | ||
| 458 | "</Wix>"); | ||
| 459 | |||
| 460 | var expected = String.Join(Environment.NewLine, | ||
| 461 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 462 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 463 | " <MsiPackage EnableSignatureValidation=\"yes\" />", | ||
| 464 | "</Wix>"); | ||
| 465 | |||
| 466 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 467 | |||
| 468 | var messaging = new DummyMessaging(); | ||
| 469 | var converter = new Wix3Converter(messaging, 2, null, null); | ||
| 470 | |||
| 471 | var errors = converter.ConvertDocument(document); | ||
| 472 | |||
| 473 | var actual = UnformattedDocumentString(document); | ||
| 474 | |||
| 475 | Assert.Equal(1, errors); | ||
| 476 | Assert.Equal(expected, actual); | ||
| 477 | } | ||
| 478 | |||
| 479 | [Fact] | ||
| 480 | public void CanConvertSuppressSignatureValidationYes() | ||
| 481 | { | ||
| 482 | var parse = String.Join(Environment.NewLine, | ||
| 483 | "<?xml version='1.0' encoding='utf-8'?>", | ||
| 484 | "<Wix xmlns='http://wixtoolset.org/schemas/v4/wxs'>", | ||
| 485 | " <Payload SuppressSignatureValidation='yes' />", | ||
| 486 | "</Wix>"); | ||
| 487 | |||
| 488 | var expected = String.Join(Environment.NewLine, | ||
| 489 | "<?xml version=\"1.0\" encoding=\"utf-16\"?>", | ||
| 490 | "<Wix xmlns=\"http://wixtoolset.org/schemas/v4/wxs\">", | ||
| 491 | " <Payload />", | ||
| 492 | "</Wix>"); | ||
| 493 | |||
| 494 | var document = XDocument.Parse(parse, LoadOptions.PreserveWhitespace | LoadOptions.SetLineInfo); | ||
| 495 | |||
| 496 | var messaging = new DummyMessaging(); | ||
| 497 | var converter = new Wix3Converter(messaging, 2, null, null); | ||
| 498 | |||
| 499 | var errors = converter.ConvertDocument(document); | ||
| 500 | |||
| 501 | var actual = UnformattedDocumentString(document); | ||
| 502 | |||
| 503 | Assert.Equal(1, errors); | ||
| 504 | Assert.Equal(expected, actual); | ||
| 505 | } | ||
| 506 | |||
| 507 | private static string UnformattedDocumentString(XDocument document) | ||
| 508 | { | ||
| 509 | var sb = new StringBuilder(); | ||
| 510 | |||
| 511 | using (var writer = new StringWriter(sb)) | ||
| 512 | { | ||
| 513 | document.Save(writer, SaveOptions.DisableFormatting); | ||
| 514 | } | ||
| 515 | |||
| 516 | return sb.ToString(); | ||
| 517 | } | ||
| 518 | |||
| 519 | private class DummyMessaging : IMessaging | ||
| 520 | { | ||
| 521 | public bool EncounteredError { get; set; } | ||
| 522 | |||
| 523 | public int LastErrorNumber { get; set; } | ||
| 524 | |||
| 525 | public bool ShowVerboseMessages { get; set; } | ||
| 526 | |||
| 527 | public bool SuppressAllWarnings { get; set; } | ||
| 528 | |||
| 529 | public bool WarningsAsError { get; set; } | ||
| 530 | |||
| 531 | public void ElevateWarningMessage(int warningNumber) | ||
| 532 | { | ||
| 533 | } | ||
| 534 | |||
| 535 | public string FormatMessage(Message message) => String.Empty; | ||
| 536 | |||
| 537 | public void SetListener(IMessageListener listener) | ||
| 538 | { | ||
| 539 | } | ||
| 540 | |||
| 541 | public void SuppressWarningMessage(int warningNumber) | ||
| 542 | { | ||
| 543 | } | ||
| 544 | |||
| 545 | public void Write(Message message) | ||
| 546 | { | ||
| 547 | } | ||
| 548 | |||
| 549 | public void Write(string message, bool verbose = false) | ||
| 550 | { | ||
| 551 | } | ||
| 552 | } | ||
| 553 | } | ||
| 554 | } | ||
diff --git a/src/test/WixToolsetTest.Converters/TestData/Preprocessor/ConvertedPreprocessor.wxs b/src/test/WixToolsetTest.Converters/TestData/Preprocessor/ConvertedPreprocessor.wxs new file mode 100644 index 00000000..dcd43e35 --- /dev/null +++ b/src/test/WixToolsetTest.Converters/TestData/Preprocessor/ConvertedPreprocessor.wxs | |||
| @@ -0,0 +1,62 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <!-- 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. --> | ||
| 3 | |||
| 4 | |||
| 5 | |||
| 6 | <?include WixVer.wxi ?> | ||
| 7 | |||
| 8 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:swid="http://wixtoolset.org/schemas/v4/wxs/tag" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 9 | <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)" Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D"> | ||
| 10 | <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" /> | ||
| 11 | <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" /> | ||
| 12 | |||
| 13 | <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." /> | ||
| 14 | |||
| 15 | <MediaTemplate CabinetTemplate="core{0}.cab" /> | ||
| 16 | |||
| 17 | <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1"> | ||
| 18 | <Component Id="Licensing" Directory="INSTALLFOLDER"> | ||
| 19 | <File Id="LICENSE.TXT" Source="LICENSE.TXT" /> | ||
| 20 | </Component> | ||
| 21 | |||
| 22 | <Component Id="ProductRegistration" Directory="INSTALLFOLDER"> | ||
| 23 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 24 | <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 25 | </RegistryKey> | ||
| 26 | </Component> | ||
| 27 | |||
| 28 | <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER"> | ||
| 29 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x"> | ||
| 30 | <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 31 | </RegistryKey> | ||
| 32 | </Component> | ||
| 33 | |||
| 34 | <Component Id="ProductInformation" Directory="BinFolder"> | ||
| 35 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 36 | <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string" /> | ||
| 37 | <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" /> | ||
| 38 | </RegistryKey> | ||
| 39 | |||
| 40 | <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" /> | ||
| 41 | </Component> | ||
| 42 | |||
| 43 | <Component Directory="BinFolder"> | ||
| 44 | <File Id="wixtoolset.org.ico" Source="common\wixtoolset.org.ico"> | ||
| 45 | <?include ComRegistration.wxi ?> | ||
| 46 | </File> | ||
| 47 | <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" /> | ||
| 48 | </Component> | ||
| 49 | |||
| 50 | <ComponentGroupRef Id="ToolsetComponents" /> | ||
| 51 | <ComponentGroupRef Id="ExtensionComponents" /> | ||
| 52 | <ComponentGroupRef Id="LuxComponents" /> | ||
| 53 | <ComponentGroupRef Id="DocComponents" /> | ||
| 54 | </Feature> | ||
| 55 | |||
| 56 | <FeatureRef Id="Feature_MSBuild" /> | ||
| 57 | <FeatureRef Id="Feature_Intellisense2010" /> | ||
| 58 | <FeatureRef Id="Feature_Intellisense2012" /> | ||
| 59 | <FeatureRef Id="Feature_Intellisense2013" /> | ||
| 60 | <FeatureRef Id="Feature_Intellisense2015" /> | ||
| 61 | </Product> | ||
| 62 | </Wix> | ||
diff --git a/src/test/WixToolsetTest.Converters/TestData/Preprocessor/Preprocessor.wxs b/src/test/WixToolsetTest.Converters/TestData/Preprocessor/Preprocessor.wxs new file mode 100644 index 00000000..2eb908c2 --- /dev/null +++ b/src/test/WixToolsetTest.Converters/TestData/Preprocessor/Preprocessor.wxs | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <!-- 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. --> | ||
| 3 | |||
| 4 | |||
| 5 | |||
| 6 | <?include WixVer.wxi ?> | ||
| 7 | |||
| 8 | <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:swid="http://schemas.microsoft.com/wix/TagExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> | ||
| 9 | <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)" | ||
| 10 | Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D"> | ||
| 11 | <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" /> | ||
| 12 | <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" /> | ||
| 13 | |||
| 14 | <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." /> | ||
| 15 | |||
| 16 | <MediaTemplate CabinetTemplate="core{0}.cab" /> | ||
| 17 | |||
| 18 | <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1"> | ||
| 19 | <Component Id="Licensing" Directory="INSTALLFOLDER"> | ||
| 20 | <File Source="LICENSE.TXT" /> | ||
| 21 | </Component> | ||
| 22 | |||
| 23 | <Component Id="ProductRegistration" Directory="INSTALLFOLDER"> | ||
| 24 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 25 | <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 26 | </RegistryKey> | ||
| 27 | </Component> | ||
| 28 | |||
| 29 | <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER"> | ||
| 30 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x"> | ||
| 31 | <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 32 | </RegistryKey> | ||
| 33 | </Component> | ||
| 34 | |||
| 35 | <Component Id="ProductInformation" Directory="BinFolder"> | ||
| 36 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 37 | <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string"/> | ||
| 38 | <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" /> | ||
| 39 | </RegistryKey> | ||
| 40 | |||
| 41 | <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" /> | ||
| 42 | </Component> | ||
| 43 | |||
| 44 | <Component Directory="BinFolder"> | ||
| 45 | <File Source="common\wixtoolset.org.ico"> | ||
| 46 | <?include ComRegistration.wxi ?> | ||
| 47 | </File> | ||
| 48 | <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" /> | ||
| 49 | </Component> | ||
| 50 | |||
| 51 | <ComponentGroupRef Id="ToolsetComponents" /> | ||
| 52 | <ComponentGroupRef Id="ExtensionComponents" /> | ||
| 53 | <ComponentGroupRef Id="LuxComponents" /> | ||
| 54 | <ComponentGroupRef Id="DocComponents" /> | ||
| 55 | </Feature> | ||
| 56 | |||
| 57 | <FeatureRef Id="Feature_MSBuild" /> | ||
| 58 | <FeatureRef Id="Feature_Intellisense2010" /> | ||
| 59 | <FeatureRef Id="Feature_Intellisense2012" /> | ||
| 60 | <FeatureRef Id="Feature_Intellisense2013" /> | ||
| 61 | <FeatureRef Id="Feature_Intellisense2015" /> | ||
| 62 | </Product> | ||
| 63 | </Wix> | ||
diff --git a/src/test/WixToolsetTest.Converters/TestData/Preprocessor/wixcop.settings.xml b/src/test/WixToolsetTest.Converters/TestData/Preprocessor/wixcop.settings.xml new file mode 100644 index 00000000..9d3ad496 --- /dev/null +++ b/src/test/WixToolsetTest.Converters/TestData/Preprocessor/wixcop.settings.xml | |||
| @@ -0,0 +1,9 @@ | |||
| 1 | <?xml version="1.0"?> | ||
| 2 | <Settings> | ||
| 3 | <IgnoreErrors> | ||
| 4 | <Test Id="WhitespacePrecedingNodeWrong"/> | ||
| 5 | <Test Id="WhitespacePrecedingEndElementWrong"/> | ||
| 6 | </IgnoreErrors> | ||
| 7 | <ErrorsAsWarnings/> | ||
| 8 | <ExemptFiles/> | ||
| 9 | </Settings> \ 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 new file mode 100644 index 00000000..b0630f65 --- /dev/null +++ b/src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v3.wxs | |||
| @@ -0,0 +1,65 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <!-- 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. --> | ||
| 3 | |||
| 4 | |||
| 5 | |||
| 6 | <?include WixVer.wxi ?> | ||
| 7 | |||
| 8 | <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:swid="http://schemas.microsoft.com/wix/TagExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> | ||
| 9 | <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)" | ||
| 10 | Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D"> | ||
| 11 | <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" /> | ||
| 12 | <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" /> | ||
| 13 | |||
| 14 | <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." /> | ||
| 15 | |||
| 16 | <MediaTemplate CabinetTemplate="core{0}.cab" /> | ||
| 17 | |||
| 18 | <Property Id="QtExecCmdTimeout" Value="600000" /> | ||
| 19 | <CustomAction Id="InstallVSTemplateCommand" Property="QtExecCmdLine" Value=""[VSENVPRODUCT80]\devenv.exe" /setup" /> | ||
| 20 | <CustomAction Id="InstallVSTemplate" BinaryKey="WixCA" DllEntry="CAQuietExec" Return="asyncWait" /> | ||
| 21 | |||
| 22 | <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1"> | ||
| 23 | <Component Id="Licensing" Directory="INSTALLFOLDER"> | ||
| 24 | <File Source="LICENSE.TXT" /> | ||
| 25 | </Component> | ||
| 26 | |||
| 27 | <Component Id="ProductRegistration" Directory="INSTALLFOLDER"> | ||
| 28 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 29 | <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 30 | </RegistryKey> | ||
| 31 | </Component> | ||
| 32 | |||
| 33 | <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER"> | ||
| 34 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x"> | ||
| 35 | <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 36 | </RegistryKey> | ||
| 37 | </Component> | ||
| 38 | |||
| 39 | <Component Id="ProductInformation" Directory="BinFolder"> | ||
| 40 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 41 | <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string"/> | ||
| 42 | <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" /> | ||
| 43 | </RegistryKey> | ||
| 44 | |||
| 45 | <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" /> | ||
| 46 | </Component> | ||
| 47 | |||
| 48 | <Component Directory="BinFolder"> | ||
| 49 | <File Source="common\wixtoolset.org.ico" /> | ||
| 50 | <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" /> | ||
| 51 | </Component> | ||
| 52 | |||
| 53 | <ComponentGroupRef Id="ToolsetComponents" /> | ||
| 54 | <ComponentGroupRef Id="ExtensionComponents" /> | ||
| 55 | <ComponentGroupRef Id="LuxComponents" /> | ||
| 56 | <ComponentGroupRef Id="DocComponents" /> | ||
| 57 | </Feature> | ||
| 58 | |||
| 59 | <FeatureRef Id="Feature_MSBuild" /> | ||
| 60 | <FeatureRef Id="Feature_Intellisense2010" /> | ||
| 61 | <FeatureRef Id="Feature_Intellisense2012" /> | ||
| 62 | <FeatureRef Id="Feature_Intellisense2013" /> | ||
| 63 | <FeatureRef Id="Feature_Intellisense2015" /> | ||
| 64 | </Product> | ||
| 65 | </Wix> | ||
diff --git a/src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v4_expected.wxs b/src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v4_expected.wxs new file mode 100644 index 00000000..be487147 --- /dev/null +++ b/src/test/WixToolsetTest.Converters/TestData/QtExec.bad/v4_expected.wxs | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <!-- 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. --> | ||
| 3 | |||
| 4 | |||
| 5 | |||
| 6 | <?include WixVer.wxi ?> | ||
| 7 | |||
| 8 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:swid="http://wixtoolset.org/schemas/v4/wxs/tag" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 9 | <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)" Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D"> | ||
| 10 | <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" /> | ||
| 11 | <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" /> | ||
| 12 | |||
| 13 | <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." /> | ||
| 14 | |||
| 15 | <MediaTemplate CabinetTemplate="core{0}.cab" /> | ||
| 16 | |||
| 17 | <Property Id="QtExecCmdTimeout" Value="600000" /> | ||
| 18 | <CustomAction Id="InstallVSTemplateCommand" Property="WixQuietExecCmdLine" Value=""[VSENVPRODUCT80]\devenv.exe" /setup" /> | ||
| 19 | <CustomAction Id="InstallVSTemplate" BinaryKey="UtilCA" DllEntry="WixQuietExec" Return="asyncWait" /> | ||
| 20 | |||
| 21 | <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1"> | ||
| 22 | <Component Id="Licensing" Directory="INSTALLFOLDER"> | ||
| 23 | <File Id="LICENSE.TXT" Source="LICENSE.TXT" /> | ||
| 24 | </Component> | ||
| 25 | |||
| 26 | <Component Id="ProductRegistration" Directory="INSTALLFOLDER"> | ||
| 27 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 28 | <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 29 | </RegistryKey> | ||
| 30 | </Component> | ||
| 31 | |||
| 32 | <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER"> | ||
| 33 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x"> | ||
| 34 | <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 35 | </RegistryKey> | ||
| 36 | </Component> | ||
| 37 | |||
| 38 | <Component Id="ProductInformation" Directory="BinFolder"> | ||
| 39 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 40 | <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string" /> | ||
| 41 | <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" /> | ||
| 42 | </RegistryKey> | ||
| 43 | |||
| 44 | <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" /> | ||
| 45 | </Component> | ||
| 46 | |||
| 47 | <Component Directory="BinFolder"> | ||
| 48 | <File Id="wixtoolset.org.ico" Source="common\wixtoolset.org.ico" /> | ||
| 49 | <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" /> | ||
| 50 | </Component> | ||
| 51 | |||
| 52 | <ComponentGroupRef Id="ToolsetComponents" /> | ||
| 53 | <ComponentGroupRef Id="ExtensionComponents" /> | ||
| 54 | <ComponentGroupRef Id="LuxComponents" /> | ||
| 55 | <ComponentGroupRef Id="DocComponents" /> | ||
| 56 | </Feature> | ||
| 57 | |||
| 58 | <FeatureRef Id="Feature_MSBuild" /> | ||
| 59 | <FeatureRef Id="Feature_Intellisense2010" /> | ||
| 60 | <FeatureRef Id="Feature_Intellisense2012" /> | ||
| 61 | <FeatureRef Id="Feature_Intellisense2013" /> | ||
| 62 | <FeatureRef Id="Feature_Intellisense2015" /> | ||
| 63 | </Product> | ||
| 64 | </Wix> | ||
diff --git a/src/test/WixToolsetTest.Converters/TestData/QtExec/v3.wxs b/src/test/WixToolsetTest.Converters/TestData/QtExec/v3.wxs new file mode 100644 index 00000000..8d81a758 --- /dev/null +++ b/src/test/WixToolsetTest.Converters/TestData/QtExec/v3.wxs | |||
| @@ -0,0 +1,64 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <!-- 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. --> | ||
| 3 | |||
| 4 | |||
| 5 | |||
| 6 | <?include WixVer.wxi ?> | ||
| 7 | |||
| 8 | <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:swid="http://schemas.microsoft.com/wix/TagExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> | ||
| 9 | <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)" | ||
| 10 | Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D"> | ||
| 11 | <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" /> | ||
| 12 | <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" /> | ||
| 13 | |||
| 14 | <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." /> | ||
| 15 | |||
| 16 | <MediaTemplate CabinetTemplate="core{0}.cab" /> | ||
| 17 | |||
| 18 | <CustomAction Id="InstallVSTemplateCommand" Property="QtExecCmdLine" Value=""[VSENVPRODUCT80]\devenv.exe" /setup" /> | ||
| 19 | <CustomAction Id="InstallVSTemplate" BinaryKey="WixCA" DllEntry="CAQuietExec" Return="asyncWait" /> | ||
| 20 | |||
| 21 | <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1"> | ||
| 22 | <Component Id="Licensing" Directory="INSTALLFOLDER"> | ||
| 23 | <File Source="LICENSE.TXT" /> | ||
| 24 | </Component> | ||
| 25 | |||
| 26 | <Component Id="ProductRegistration" Directory="INSTALLFOLDER"> | ||
| 27 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 28 | <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 29 | </RegistryKey> | ||
| 30 | </Component> | ||
| 31 | |||
| 32 | <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER"> | ||
| 33 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x"> | ||
| 34 | <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 35 | </RegistryKey> | ||
| 36 | </Component> | ||
| 37 | |||
| 38 | <Component Id="ProductInformation" Directory="BinFolder"> | ||
| 39 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 40 | <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string"/> | ||
| 41 | <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" /> | ||
| 42 | </RegistryKey> | ||
| 43 | |||
| 44 | <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" /> | ||
| 45 | </Component> | ||
| 46 | |||
| 47 | <Component Directory="BinFolder"> | ||
| 48 | <File Source="common\wixtoolset.org.ico" /> | ||
| 49 | <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" /> | ||
| 50 | </Component> | ||
| 51 | |||
| 52 | <ComponentGroupRef Id="ToolsetComponents" /> | ||
| 53 | <ComponentGroupRef Id="ExtensionComponents" /> | ||
| 54 | <ComponentGroupRef Id="LuxComponents" /> | ||
| 55 | <ComponentGroupRef Id="DocComponents" /> | ||
| 56 | </Feature> | ||
| 57 | |||
| 58 | <FeatureRef Id="Feature_MSBuild" /> | ||
| 59 | <FeatureRef Id="Feature_Intellisense2010" /> | ||
| 60 | <FeatureRef Id="Feature_Intellisense2012" /> | ||
| 61 | <FeatureRef Id="Feature_Intellisense2013" /> | ||
| 62 | <FeatureRef Id="Feature_Intellisense2015" /> | ||
| 63 | </Product> | ||
| 64 | </Wix> | ||
diff --git a/src/test/WixToolsetTest.Converters/TestData/QtExec/v4_expected.wxs b/src/test/WixToolsetTest.Converters/TestData/QtExec/v4_expected.wxs new file mode 100644 index 00000000..22a961b2 --- /dev/null +++ b/src/test/WixToolsetTest.Converters/TestData/QtExec/v4_expected.wxs | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <!-- 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. --> | ||
| 3 | |||
| 4 | |||
| 5 | |||
| 6 | <?include WixVer.wxi ?> | ||
| 7 | |||
| 8 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:swid="http://wixtoolset.org/schemas/v4/wxs/tag" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 9 | <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)" Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D"> | ||
| 10 | <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" /> | ||
| 11 | <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" /> | ||
| 12 | |||
| 13 | <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." /> | ||
| 14 | |||
| 15 | <MediaTemplate CabinetTemplate="core{0}.cab" /> | ||
| 16 | |||
| 17 | <CustomAction Id="InstallVSTemplateCommand" Property="WixQuietExecCmdLine" Value=""[VSENVPRODUCT80]\devenv.exe" /setup" /> | ||
| 18 | <CustomAction Id="InstallVSTemplate" BinaryKey="UtilCA" DllEntry="WixQuietExec" Return="asyncWait" /> | ||
| 19 | |||
| 20 | <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1"> | ||
| 21 | <Component Id="Licensing" Directory="INSTALLFOLDER"> | ||
| 22 | <File Id="LICENSE.TXT" Source="LICENSE.TXT" /> | ||
| 23 | </Component> | ||
| 24 | |||
| 25 | <Component Id="ProductRegistration" Directory="INSTALLFOLDER"> | ||
| 26 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 27 | <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 28 | </RegistryKey> | ||
| 29 | </Component> | ||
| 30 | |||
| 31 | <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER"> | ||
| 32 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x"> | ||
| 33 | <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 34 | </RegistryKey> | ||
| 35 | </Component> | ||
| 36 | |||
| 37 | <Component Id="ProductInformation" Directory="BinFolder"> | ||
| 38 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 39 | <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string" /> | ||
| 40 | <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" /> | ||
| 41 | </RegistryKey> | ||
| 42 | |||
| 43 | <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" /> | ||
| 44 | </Component> | ||
| 45 | |||
| 46 | <Component Directory="BinFolder"> | ||
| 47 | <File Id="wixtoolset.org.ico" Source="common\wixtoolset.org.ico" /> | ||
| 48 | <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" /> | ||
| 49 | </Component> | ||
| 50 | |||
| 51 | <ComponentGroupRef Id="ToolsetComponents" /> | ||
| 52 | <ComponentGroupRef Id="ExtensionComponents" /> | ||
| 53 | <ComponentGroupRef Id="LuxComponents" /> | ||
| 54 | <ComponentGroupRef Id="DocComponents" /> | ||
| 55 | </Feature> | ||
| 56 | |||
| 57 | <FeatureRef Id="Feature_MSBuild" /> | ||
| 58 | <FeatureRef Id="Feature_Intellisense2010" /> | ||
| 59 | <FeatureRef Id="Feature_Intellisense2012" /> | ||
| 60 | <FeatureRef Id="Feature_Intellisense2013" /> | ||
| 61 | <FeatureRef Id="Feature_Intellisense2015" /> | ||
| 62 | </Product> | ||
| 63 | </Wix> | ||
diff --git a/src/test/WixToolsetTest.Converters/TestData/SingleFile/ConvertedSingleFile.wxs b/src/test/WixToolsetTest.Converters/TestData/SingleFile/ConvertedSingleFile.wxs new file mode 100644 index 00000000..aacb68fa --- /dev/null +++ b/src/test/WixToolsetTest.Converters/TestData/SingleFile/ConvertedSingleFile.wxs | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <!-- 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. --> | ||
| 3 | |||
| 4 | |||
| 5 | |||
| 6 | <?include WixVer.wxi ?> | ||
| 7 | |||
| 8 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" xmlns:swid="http://wixtoolset.org/schemas/v4/wxs/tag" xmlns:util="http://wixtoolset.org/schemas/v4/wxs/util"> | ||
| 9 | <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)" Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D"> | ||
| 10 | <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" /> | ||
| 11 | <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" /> | ||
| 12 | |||
| 13 | <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." /> | ||
| 14 | |||
| 15 | <MediaTemplate CabinetTemplate="core{0}.cab" /> | ||
| 16 | |||
| 17 | <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1"> | ||
| 18 | <Component Id="Licensing" Directory="INSTALLFOLDER"> | ||
| 19 | <File Id="LICENSE.TXT" Source="LICENSE.TXT" /> | ||
| 20 | </Component> | ||
| 21 | |||
| 22 | <Component Id="ProductRegistration" Directory="INSTALLFOLDER"> | ||
| 23 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 24 | <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 25 | </RegistryKey> | ||
| 26 | </Component> | ||
| 27 | |||
| 28 | <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER"> | ||
| 29 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x"> | ||
| 30 | <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 31 | </RegistryKey> | ||
| 32 | </Component> | ||
| 33 | |||
| 34 | <Component Id="ProductInformation" Directory="BinFolder"> | ||
| 35 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 36 | <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string" /> | ||
| 37 | <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" /> | ||
| 38 | </RegistryKey> | ||
| 39 | |||
| 40 | <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" /> | ||
| 41 | </Component> | ||
| 42 | |||
| 43 | <Component Directory="BinFolder"> | ||
| 44 | <File Id="wixtoolset.org.ico" Source="common\wixtoolset.org.ico" /> | ||
| 45 | <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" /> | ||
| 46 | </Component> | ||
| 47 | |||
| 48 | <ComponentGroupRef Id="ToolsetComponents" /> | ||
| 49 | <ComponentGroupRef Id="ExtensionComponents" /> | ||
| 50 | <ComponentGroupRef Id="LuxComponents" /> | ||
| 51 | <ComponentGroupRef Id="DocComponents" /> | ||
| 52 | </Feature> | ||
| 53 | |||
| 54 | <FeatureRef Id="Feature_MSBuild" /> | ||
| 55 | <FeatureRef Id="Feature_Intellisense2010" /> | ||
| 56 | <FeatureRef Id="Feature_Intellisense2012" /> | ||
| 57 | <FeatureRef Id="Feature_Intellisense2013" /> | ||
| 58 | <FeatureRef Id="Feature_Intellisense2015" /> | ||
| 59 | </Product> | ||
| 60 | </Wix> | ||
diff --git a/src/test/WixToolsetTest.Converters/TestData/SingleFile/SingleFile.wxs b/src/test/WixToolsetTest.Converters/TestData/SingleFile/SingleFile.wxs new file mode 100644 index 00000000..310ae811 --- /dev/null +++ b/src/test/WixToolsetTest.Converters/TestData/SingleFile/SingleFile.wxs | |||
| @@ -0,0 +1,61 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <!-- 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. --> | ||
| 3 | |||
| 4 | |||
| 5 | |||
| 6 | <?include WixVer.wxi ?> | ||
| 7 | |||
| 8 | <Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:swid="http://schemas.microsoft.com/wix/TagExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"> | ||
| 9 | <Product Id="*" Name="!(loc.ShortProduct) v$(var.WixMajorMinor) Core" Language="1033" Manufacturer="!(loc.Company)" | ||
| 10 | Version="$(var.WixMsiProductVersion)" UpgradeCode="3618724B-2523-44F9-A908-866AA619504D"> | ||
| 11 | <Package Compressed="yes" InstallerVersion="200" SummaryCodepage="1252" InstallScope="perMachine" /> | ||
| 12 | <swid:Tag Regid="!(loc.Regid)" InstallDirectory="INSTALLFOLDER" /> | ||
| 13 | |||
| 14 | <MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed." /> | ||
| 15 | |||
| 16 | <MediaTemplate CabinetTemplate="core{0}.cab" /> | ||
| 17 | |||
| 18 | <Feature Id="Feature_WiX" Title="WiX Toolset" Level="1"> | ||
| 19 | <Component Id="Licensing" Directory="INSTALLFOLDER"> | ||
| 20 | <File Source="LICENSE.TXT" /> | ||
| 21 | </Component> | ||
| 22 | |||
| 23 | <Component Id="ProductRegistration" Directory="INSTALLFOLDER"> | ||
| 24 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 25 | <RegistryValue Name="InstallFolder" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 26 | </RegistryKey> | ||
| 27 | </Component> | ||
| 28 | |||
| 29 | <Component Id="ProductFamilyRegistration" Directory="INSTALLFOLDER"> | ||
| 30 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajor).x"> | ||
| 31 | <RegistryValue Name="v$(var.WixMajorMinor)" Value="[INSTALLFOLDER]" Type="string" /> | ||
| 32 | </RegistryKey> | ||
| 33 | </Component> | ||
| 34 | |||
| 35 | <Component Id="ProductInformation" Directory="BinFolder"> | ||
| 36 | <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Windows Installer XML\$(var.WixMajorMinor)"> | ||
| 37 | <RegistryValue Name="InstallRoot" Value="[BinFolder]" Type="string"/> | ||
| 38 | <RegistryValue Name="ProductVersion" Value="[ProductVersion]" Type="string" /> | ||
| 39 | </RegistryKey> | ||
| 40 | |||
| 41 | <RemoveFolder Id="CleanupShortcutFolder" Directory="ShortcutFolder" On="uninstall" /> | ||
| 42 | </Component> | ||
| 43 | |||
| 44 | <Component Directory="BinFolder"> | ||
| 45 | <File Source="common\wixtoolset.org.ico" /> | ||
| 46 | <util:InternetShortcut Id="wixtoolset.org" Directory="ShortcutFolder" Name="WiX Home Page" Target="http://wixtoolset.org/" IconFile="file://[#wixtoolset.org.ico]" /> | ||
| 47 | </Component> | ||
| 48 | |||
| 49 | <ComponentGroupRef Id="ToolsetComponents" /> | ||
| 50 | <ComponentGroupRef Id="ExtensionComponents" /> | ||
| 51 | <ComponentGroupRef Id="LuxComponents" /> | ||
| 52 | <ComponentGroupRef Id="DocComponents" /> | ||
| 53 | </Feature> | ||
| 54 | |||
| 55 | <FeatureRef Id="Feature_MSBuild" /> | ||
| 56 | <FeatureRef Id="Feature_Intellisense2010" /> | ||
| 57 | <FeatureRef Id="Feature_Intellisense2012" /> | ||
| 58 | <FeatureRef Id="Feature_Intellisense2013" /> | ||
| 59 | <FeatureRef Id="Feature_Intellisense2015" /> | ||
| 60 | </Product> | ||
| 61 | </Wix> | ||
diff --git a/src/test/WixToolsetTest.Converters/WixToolsetTest.Converters.csproj b/src/test/WixToolsetTest.Converters/WixToolsetTest.Converters.csproj new file mode 100644 index 00000000..d16c3d16 --- /dev/null +++ b/src/test/WixToolsetTest.Converters/WixToolsetTest.Converters.csproj | |||
| @@ -0,0 +1,39 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <!-- 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. --> | ||
| 3 | |||
| 4 | <Project Sdk="Microsoft.NET.Sdk"> | ||
| 5 | <PropertyGroup> | ||
| 6 | <TargetFramework>netcoreapp2.1</TargetFramework> | ||
| 7 | <IsPackable>false</IsPackable> | ||
| 8 | </PropertyGroup> | ||
| 9 | |||
| 10 | <ItemGroup> | ||
| 11 | <None Remove="TestData\SingleFile\ConvertedSingleFile.wxs" /> | ||
| 12 | <None Remove="TestData\SingleFile\SingleFile.wxs" /> | ||
| 13 | </ItemGroup> | ||
| 14 | <ItemGroup> | ||
| 15 | <Content Include="TestData\SingleFile\ConvertedSingleFile.wxs" CopyToOutputDirectory="PreserveNewest" /> | ||
| 16 | <Content Include="TestData\SingleFile\SingleFile.wxs" CopyToOutputDirectory="PreserveNewest" /> | ||
| 17 | <Content Include="TestData\Preprocessor\ConvertedPreprocessor.wxs" CopyToOutputDirectory="PreserveNewest" /> | ||
| 18 | <Content Include="TestData\Preprocessor\Preprocessor.wxs" CopyToOutputDirectory="PreserveNewest" /> | ||
| 19 | <Content Include="TestData\Preprocessor\wixcop.settings.xml" CopyToOutputDirectory="PreserveNewest" /> | ||
| 20 | <Content Include="TestData\QtExec\v3.wxs" CopyToOutputDirectory="PreserveNewest" /> | ||
| 21 | <Content Include="TestData\QtExec\v4_expected.wxs" CopyToOutputDirectory="PreserveNewest" /> | ||
| 22 | <Content Include="TestData\QtExec.bad\v3.wxs" CopyToOutputDirectory="PreserveNewest" /> | ||
| 23 | <Content Include="TestData\QtExec.bad\v4_expected.wxs" CopyToOutputDirectory="PreserveNewest" /> | ||
| 24 | </ItemGroup> | ||
| 25 | |||
| 26 | <ItemGroup> | ||
| 27 | <ProjectReference Include="..\..\WixToolset.Converters\WixToolset.Converters.csproj" /> | ||
| 28 | </ItemGroup> | ||
| 29 | |||
| 30 | <ItemGroup> | ||
| 31 | <PackageReference Include="WixBuildTools.TestSupport" Version="4.0.*" /> | ||
| 32 | </ItemGroup> | ||
| 33 | |||
| 34 | <ItemGroup> | ||
| 35 | <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" /> | ||
| 36 | <PackageReference Include="xunit" Version="2.4.1" /> | ||
| 37 | <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" PrivateAssets="All" /> | ||
| 38 | </ItemGroup> | ||
| 39 | </Project> | ||
