diff options
Diffstat (limited to 'src/test/WixToolsetTest.Converters.Symbolizer/ConvertTuplesFixture.cs')
| -rw-r--r-- | src/test/WixToolsetTest.Converters.Symbolizer/ConvertTuplesFixture.cs | 606 |
1 files changed, 606 insertions, 0 deletions
diff --git a/src/test/WixToolsetTest.Converters.Symbolizer/ConvertTuplesFixture.cs b/src/test/WixToolsetTest.Converters.Symbolizer/ConvertTuplesFixture.cs new file mode 100644 index 00000000..ae054079 --- /dev/null +++ b/src/test/WixToolsetTest.Converters.Symbolizer/ConvertTuplesFixture.cs | |||
| @@ -0,0 +1,606 @@ | |||
| 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.Symbolizer | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using System.IO; | ||
| 8 | using System.Linq; | ||
| 9 | using WixBuildTools.TestSupport; | ||
| 10 | using Wix3 = Microsoft.Tools.WindowsInstallerXml; | ||
| 11 | using WixToolset.Converters.Symbolizer; | ||
| 12 | using WixToolset.Data; | ||
| 13 | using WixToolset.Data.WindowsInstaller; | ||
| 14 | using WixToolset.Data.Symbols; | ||
| 15 | using Xunit; | ||
| 16 | |||
| 17 | public class ConvertSymbolsFixture | ||
| 18 | { | ||
| 19 | [Fact] | ||
| 20 | public void CanLoadWixoutAndConvertToIntermediate() | ||
| 21 | { | ||
| 22 | var rootFolder = TestData.Get(); | ||
| 23 | var dataFolder = TestData.Get(@"TestData\Integration"); | ||
| 24 | |||
| 25 | using (var fs = new DisposableFileSystem()) | ||
| 26 | { | ||
| 27 | var intermediateFolder = fs.GetFolder(); | ||
| 28 | |||
| 29 | var path = Path.Combine(dataFolder, "test.wixout"); | ||
| 30 | |||
| 31 | var intermediate = ConvertSymbols.ConvertFile(path); | ||
| 32 | |||
| 33 | Assert.NotNull(intermediate); | ||
| 34 | Assert.Single(intermediate.Sections); | ||
| 35 | Assert.Equal(String.Empty, intermediate.Id); | ||
| 36 | |||
| 37 | // Save and load to guarantee round-tripping support. | ||
| 38 | // | ||
| 39 | var wixiplFile = Path.Combine(intermediateFolder, "test.wixipl"); | ||
| 40 | intermediate.Save(wixiplFile); | ||
| 41 | |||
| 42 | intermediate = Intermediate.Load(wixiplFile); | ||
| 43 | |||
| 44 | var output = Wix3.Output.Load(path, suppressVersionCheck: true, suppressSchema: true); | ||
| 45 | var wixMediaByDiskId = IndexWixMediaTableByDiskId(output); | ||
| 46 | |||
| 47 | // Dump to text for easy diffing, with some massaging to keep v3 and v4 diffable. | ||
| 48 | // | ||
| 49 | var tables = output.Tables.Cast<Wix3.Table>(); | ||
| 50 | var wix3Dump = tables | ||
| 51 | .SelectMany(table => table.Rows.Cast<Wix3.Row>() | ||
| 52 | .SelectMany(row => RowToStrings(row, wixMediaByDiskId))) | ||
| 53 | .Where(s => !String.IsNullOrEmpty(s)) | ||
| 54 | .OrderBy(s => s) | ||
| 55 | .ToArray(); | ||
| 56 | |||
| 57 | var symbols = intermediate.Sections.SelectMany(s => s.Symbols); | ||
| 58 | |||
| 59 | var assemblySymbolsByFileId = symbols.OfType<AssemblySymbol>().ToDictionary(a => a.Id.Id); | ||
| 60 | |||
| 61 | var wix4Dump = symbols | ||
| 62 | .SelectMany(symbol => SymbolToStrings(symbol, assemblySymbolsByFileId)) | ||
| 63 | .OrderBy(s => s) | ||
| 64 | .ToArray(); | ||
| 65 | |||
| 66 | #if false | ||
| 67 | Assert.Equal(wix3Dump, wix4Dump); | ||
| 68 | #else // useful when you want to diff the outputs with another diff tool. | ||
| 69 | var wix3TextDump = String.Join(Environment.NewLine, wix3Dump); | ||
| 70 | var wix4TextDump = String.Join(Environment.NewLine, wix4Dump); | ||
| 71 | |||
| 72 | var path3 = Path.Combine(Path.GetTempPath(), "~3.txt"); | ||
| 73 | var path4 = Path.Combine(Path.GetTempPath(), "~4.txt"); | ||
| 74 | |||
| 75 | File.WriteAllText(path3, wix3TextDump); | ||
| 76 | File.WriteAllText(path4, wix4TextDump); | ||
| 77 | |||
| 78 | Assert.Equal(wix3TextDump, wix4TextDump); | ||
| 79 | #endif | ||
| 80 | } | ||
| 81 | } | ||
| 82 | |||
| 83 | private static Dictionary<int, Wix3.WixMediaRow> IndexWixMediaTableByDiskId(Wix3.Output output) | ||
| 84 | { | ||
| 85 | var wixMediaByDiskId = new Dictionary<int, Wix3.WixMediaRow>(); | ||
| 86 | var wixMediaTable = output.Tables["WixMedia"]; | ||
| 87 | |||
| 88 | if (wixMediaTable != null) | ||
| 89 | { | ||
| 90 | foreach (Wix3.WixMediaRow row in wixMediaTable.Rows) | ||
| 91 | { | ||
| 92 | wixMediaByDiskId.Add((int)row[0], row); | ||
| 93 | } | ||
| 94 | } | ||
| 95 | |||
| 96 | return wixMediaByDiskId; | ||
| 97 | } | ||
| 98 | |||
| 99 | private static IEnumerable<string> RowToStrings(Wix3.Row row, Dictionary<int, Wix3.WixMediaRow> wixMediaByDiskId) | ||
| 100 | { | ||
| 101 | string fields = null; | ||
| 102 | |||
| 103 | // Massage output to match WiX v3 rows and v4 symbols. | ||
| 104 | // | ||
| 105 | switch (row.Table.Name) | ||
| 106 | { | ||
| 107 | case "Directory": | ||
| 108 | var dirs = SplitDefaultDir((string)row[2]); | ||
| 109 | fields = String.Join(",", row[0], row[1], dirs[0], dirs[1], dirs[2], dirs[3]); | ||
| 110 | break; | ||
| 111 | case "File": | ||
| 112 | { | ||
| 113 | var fieldValues = row.Fields.Take(7).Select(SafeConvertField).ToArray(); | ||
| 114 | if (fieldValues[3] == null) | ||
| 115 | { | ||
| 116 | // "Somebody" sometimes writes out a null field even when the column definition says | ||
| 117 | // it's non-nullable. Not naming names or anything. (SWID tags.) | ||
| 118 | fieldValues[3] = "0"; | ||
| 119 | } | ||
| 120 | fields = String.Join(",", fieldValues); | ||
| 121 | break; | ||
| 122 | } | ||
| 123 | case "Media": | ||
| 124 | var compression = wixMediaByDiskId.TryGetValue((int)row[0], out var wixMedia) ? (CompressionLevel?)Enum.Parse(typeof(CompressionLevel), SafeConvertField(wixMedia.Fields[1]), true) : null; | ||
| 125 | |||
| 126 | fields = String.Join(",", row.Fields.Select(SafeConvertField)); | ||
| 127 | fields = String.Join(",", fields, (int?)compression, SafeConvertField(wixMedia?.Fields[2])); | ||
| 128 | break; | ||
| 129 | case "RegLocator": | ||
| 130 | var type = (int)row[4]; | ||
| 131 | fields = String.Join(",", row[0], row[1], row[2], row[3], type & 0xF, (type & 0x10) == 0x10); | ||
| 132 | break; | ||
| 133 | case "RemoveFile": | ||
| 134 | var attributes = (int)row[4]; | ||
| 135 | var onInstall = (attributes & 1) == 1 ? (bool?)true : null; | ||
| 136 | var onUninstall = (attributes & 2) == 2 ? (bool?)true : null; | ||
| 137 | fields = String.Join(",", row.Fields.Take(4).Select(SafeConvertField)); | ||
| 138 | fields = String.Join(",", fields, onInstall, onUninstall); | ||
| 139 | break; | ||
| 140 | case "Shortcut": | ||
| 141 | var split = ((string)row[2]).Split('|'); | ||
| 142 | var afterName = String.Join(",", row.Fields.Skip(3).Select(SafeConvertField)); | ||
| 143 | fields = String.Join(",", row[0], row[1], split.Length > 1 ? split[1] : split[0], split.Length > 1 ? split[0] : String.Empty, afterName); | ||
| 144 | break; | ||
| 145 | case "WixAction": | ||
| 146 | var table = (int)SequenceStringToSequenceTable(row[0]); | ||
| 147 | fields = String.Join(",", table, row[1], row[2], row[3], row[4], row[5], row[6]); | ||
| 148 | break; | ||
| 149 | case "WixFile": | ||
| 150 | { | ||
| 151 | var fieldValues = row.Fields.Select(SafeConvertField).ToArray(); | ||
| 152 | if (fieldValues[8] == null) | ||
| 153 | { | ||
| 154 | // "Somebody" sometimes writes out a null field even when the column definition says | ||
| 155 | // it's non-nullable. Not naming names or anything. (SWID tags.) | ||
| 156 | fieldValues[8] = "0"; | ||
| 157 | } | ||
| 158 | if (fieldValues[10] == null) | ||
| 159 | { | ||
| 160 | // WixFile rows that come from merge modules will not have the attributes column set | ||
| 161 | // so initilaize with 0. | ||
| 162 | fieldValues[10] = "0"; | ||
| 163 | } | ||
| 164 | fields = String.Join(",", fieldValues); | ||
| 165 | break; | ||
| 166 | } | ||
| 167 | case "WixMedia": | ||
| 168 | break; | ||
| 169 | default: | ||
| 170 | fields = String.Join(",", row.Fields.Select(SafeConvertField)); | ||
| 171 | break; | ||
| 172 | } | ||
| 173 | |||
| 174 | if (fields != null) | ||
| 175 | { | ||
| 176 | yield return $"{row.Table.Name}:{fields}"; | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | private static IEnumerable<string> SymbolToStrings(IntermediateSymbol symbol, Dictionary<string, AssemblySymbol> assemblySymbolsByFileId) | ||
| 181 | { | ||
| 182 | var name = symbol.Definition.Type == SymbolDefinitionType.SummaryInformation ? "_SummaryInformation" : symbol.Definition.Name; | ||
| 183 | var id = symbol.Id?.Id ?? String.Empty; | ||
| 184 | |||
| 185 | string fields; | ||
| 186 | switch (symbol.Definition.Name) | ||
| 187 | { | ||
| 188 | // Massage output to match WiX v3 rows and v4 symbols. | ||
| 189 | // | ||
| 190 | case "Component": | ||
| 191 | { | ||
| 192 | var componentSymbol = (ComponentSymbol)symbol; | ||
| 193 | var attributes = ComponentLocation.Either == componentSymbol.Location ? WindowsInstallerConstants.MsidbComponentAttributesOptional : 0; | ||
| 194 | attributes |= ComponentLocation.SourceOnly == componentSymbol.Location ? WindowsInstallerConstants.MsidbComponentAttributesSourceOnly : 0; | ||
| 195 | attributes |= ComponentKeyPathType.Registry == componentSymbol.KeyPathType ? WindowsInstallerConstants.MsidbComponentAttributesRegistryKeyPath : 0; | ||
| 196 | attributes |= ComponentKeyPathType.OdbcDataSource == componentSymbol.KeyPathType ? WindowsInstallerConstants.MsidbComponentAttributesODBCDataSource : 0; | ||
| 197 | attributes |= componentSymbol.DisableRegistryReflection ? WindowsInstallerConstants.MsidbComponentAttributesDisableRegistryReflection : 0; | ||
| 198 | attributes |= componentSymbol.NeverOverwrite ? WindowsInstallerConstants.MsidbComponentAttributesNeverOverwrite : 0; | ||
| 199 | attributes |= componentSymbol.Permanent ? WindowsInstallerConstants.MsidbComponentAttributesPermanent : 0; | ||
| 200 | attributes |= componentSymbol.SharedDllRefCount ? WindowsInstallerConstants.MsidbComponentAttributesSharedDllRefCount : 0; | ||
| 201 | attributes |= componentSymbol.Shared ? WindowsInstallerConstants.MsidbComponentAttributesShared : 0; | ||
| 202 | attributes |= componentSymbol.Transitive ? WindowsInstallerConstants.MsidbComponentAttributesTransitive : 0; | ||
| 203 | attributes |= componentSymbol.UninstallWhenSuperseded ? WindowsInstallerConstants.MsidbComponentAttributes64bit : 0; | ||
| 204 | attributes |= componentSymbol.Win64 ? WindowsInstallerConstants.MsidbComponentAttributes64bit : 0; | ||
| 205 | |||
| 206 | fields = String.Join(",", | ||
| 207 | componentSymbol.ComponentId, | ||
| 208 | componentSymbol.DirectoryRef, | ||
| 209 | attributes.ToString(), | ||
| 210 | componentSymbol.Condition, | ||
| 211 | componentSymbol.KeyPath | ||
| 212 | ); | ||
| 213 | break; | ||
| 214 | } | ||
| 215 | case "CustomAction": | ||
| 216 | { | ||
| 217 | var customActionSymbol = (CustomActionSymbol)symbol; | ||
| 218 | var type = customActionSymbol.Win64 ? WindowsInstallerConstants.MsidbCustomActionType64BitScript : 0; | ||
| 219 | type |= customActionSymbol.TSAware ? WindowsInstallerConstants.MsidbCustomActionTypeTSAware : 0; | ||
| 220 | type |= customActionSymbol.Impersonate ? 0 : WindowsInstallerConstants.MsidbCustomActionTypeNoImpersonate; | ||
| 221 | type |= customActionSymbol.IgnoreResult ? WindowsInstallerConstants.MsidbCustomActionTypeContinue : 0; | ||
| 222 | type |= customActionSymbol.Hidden ? WindowsInstallerConstants.MsidbCustomActionTypeHideTarget : 0; | ||
| 223 | type |= customActionSymbol.Async ? WindowsInstallerConstants.MsidbCustomActionTypeAsync : 0; | ||
| 224 | type |= CustomActionExecutionType.FirstSequence == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeFirstSequence : 0; | ||
| 225 | type |= CustomActionExecutionType.OncePerProcess == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeOncePerProcess : 0; | ||
| 226 | type |= CustomActionExecutionType.ClientRepeat == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeClientRepeat : 0; | ||
| 227 | type |= CustomActionExecutionType.Deferred == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript : 0; | ||
| 228 | type |= CustomActionExecutionType.Rollback == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeRollback : 0; | ||
| 229 | type |= CustomActionExecutionType.Commit == customActionSymbol.ExecutionType ? WindowsInstallerConstants.MsidbCustomActionTypeInScript | WindowsInstallerConstants.MsidbCustomActionTypeCommit : 0; | ||
| 230 | type |= CustomActionSourceType.File == customActionSymbol.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeSourceFile : 0; | ||
| 231 | type |= CustomActionSourceType.Directory == customActionSymbol.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeDirectory : 0; | ||
| 232 | type |= CustomActionSourceType.Property == customActionSymbol.SourceType ? WindowsInstallerConstants.MsidbCustomActionTypeProperty : 0; | ||
| 233 | type |= CustomActionTargetType.Dll == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeDll : 0; | ||
| 234 | type |= CustomActionTargetType.Exe == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeExe : 0; | ||
| 235 | type |= CustomActionTargetType.TextData == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeTextData : 0; | ||
| 236 | type |= CustomActionTargetType.JScript == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeJScript : 0; | ||
| 237 | type |= CustomActionTargetType.VBScript == customActionSymbol.TargetType ? WindowsInstallerConstants.MsidbCustomActionTypeVBScript : 0; | ||
| 238 | |||
| 239 | fields = String.Join(",", | ||
| 240 | type.ToString(), | ||
| 241 | customActionSymbol.Source, | ||
| 242 | customActionSymbol.Target, | ||
| 243 | customActionSymbol.PatchUninstall ? WindowsInstallerConstants.MsidbCustomActionTypePatchUninstall.ToString() : null | ||
| 244 | ); | ||
| 245 | break; | ||
| 246 | } | ||
| 247 | case "Directory": | ||
| 248 | { | ||
| 249 | var directorySymbol = (DirectorySymbol)symbol; | ||
| 250 | |||
| 251 | if (!String.IsNullOrEmpty(directorySymbol.ComponentGuidGenerationSeed)) | ||
| 252 | { | ||
| 253 | yield return $"WixDirectory:{directorySymbol.Id.Id},{directorySymbol.ComponentGuidGenerationSeed}"; | ||
| 254 | } | ||
| 255 | |||
| 256 | fields = String.Join(",", directorySymbol.ParentDirectoryRef, directorySymbol.Name, directorySymbol.ShortName, directorySymbol.SourceName, directorySymbol.SourceShortName); | ||
| 257 | break; | ||
| 258 | } | ||
| 259 | case "Feature": | ||
| 260 | { | ||
| 261 | var featureSymbol = (FeatureSymbol)symbol; | ||
| 262 | var attributes = featureSymbol.DisallowAbsent ? WindowsInstallerConstants.MsidbFeatureAttributesUIDisallowAbsent : 0; | ||
| 263 | attributes |= featureSymbol.DisallowAdvertise ? WindowsInstallerConstants.MsidbFeatureAttributesDisallowAdvertise : 0; | ||
| 264 | attributes |= FeatureInstallDefault.FollowParent == featureSymbol.InstallDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFollowParent : 0; | ||
| 265 | attributes |= FeatureInstallDefault.Source == featureSymbol.InstallDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFavorSource : 0; | ||
| 266 | attributes |= FeatureTypicalDefault.Advertise == featureSymbol.TypicalDefault ? WindowsInstallerConstants.MsidbFeatureAttributesFavorAdvertise : 0; | ||
| 267 | |||
| 268 | fields = String.Join(",", | ||
| 269 | featureSymbol.ParentFeatureRef, | ||
| 270 | featureSymbol.Title, | ||
| 271 | featureSymbol.Description, | ||
| 272 | featureSymbol.Display.ToString(), | ||
| 273 | featureSymbol.Level.ToString(), | ||
| 274 | featureSymbol.DirectoryRef, | ||
| 275 | attributes.ToString()); | ||
| 276 | break; | ||
| 277 | } | ||
| 278 | case "File": | ||
| 279 | { | ||
| 280 | var fileSymbol = (FileSymbol)symbol; | ||
| 281 | |||
| 282 | if (fileSymbol.BindPath != null) | ||
| 283 | { | ||
| 284 | yield return $"BindImage:{fileSymbol.Id.Id},{fileSymbol.BindPath}"; | ||
| 285 | } | ||
| 286 | |||
| 287 | if (fileSymbol.FontTitle != null) | ||
| 288 | { | ||
| 289 | yield return $"Font:{fileSymbol.Id.Id},{fileSymbol.FontTitle}"; | ||
| 290 | } | ||
| 291 | |||
| 292 | if (fileSymbol.SelfRegCost.HasValue) | ||
| 293 | { | ||
| 294 | yield return $"SelfReg:{fileSymbol.Id.Id},{fileSymbol.SelfRegCost}"; | ||
| 295 | } | ||
| 296 | |||
| 297 | int? assemblyAttributes = null; | ||
| 298 | if (assemblySymbolsByFileId.TryGetValue(fileSymbol.Id.Id, out var assemblySymbol)) | ||
| 299 | { | ||
| 300 | if (assemblySymbol.Type == AssemblyType.DotNetAssembly) | ||
| 301 | { | ||
| 302 | assemblyAttributes = 0; | ||
| 303 | } | ||
| 304 | else if (assemblySymbol.Type == AssemblyType.Win32Assembly) | ||
| 305 | { | ||
| 306 | assemblyAttributes = 1; | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | yield return "WixFile:" + String.Join(",", | ||
| 311 | fileSymbol.Id.Id, | ||
| 312 | assemblyAttributes, | ||
| 313 | assemblySymbol?.ManifestFileRef, | ||
| 314 | assemblySymbol?.ApplicationFileRef, | ||
| 315 | fileSymbol.DirectoryRef, | ||
| 316 | fileSymbol.DiskId, | ||
| 317 | fileSymbol.Source.Path, | ||
| 318 | null, // assembly processor arch | ||
| 319 | fileSymbol.PatchGroup, | ||
| 320 | (fileSymbol.Attributes & FileSymbolAttributes.GeneratedShortFileName) != 0 ? 1 : 0, | ||
| 321 | (int)fileSymbol.PatchAttributes, | ||
| 322 | fileSymbol.RetainLengths, | ||
| 323 | fileSymbol.IgnoreOffsets, | ||
| 324 | fileSymbol.IgnoreLengths, | ||
| 325 | fileSymbol.RetainOffsets | ||
| 326 | ); | ||
| 327 | |||
| 328 | var fileAttributes = 0; | ||
| 329 | fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.ReadOnly) != 0 ? WindowsInstallerConstants.MsidbFileAttributesReadOnly : 0; | ||
| 330 | fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Hidden) != 0 ? WindowsInstallerConstants.MsidbFileAttributesHidden : 0; | ||
| 331 | fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.System) != 0 ? WindowsInstallerConstants.MsidbFileAttributesSystem : 0; | ||
| 332 | fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Vital) != 0 ? WindowsInstallerConstants.MsidbFileAttributesVital : 0; | ||
| 333 | fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Checksum) != 0 ? WindowsInstallerConstants.MsidbFileAttributesChecksum : 0; | ||
| 334 | fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Compressed) != 0 ? WindowsInstallerConstants.MsidbFileAttributesCompressed : 0; | ||
| 335 | fileAttributes |= (fileSymbol.Attributes & FileSymbolAttributes.Uncompressed) != 0 ? WindowsInstallerConstants.MsidbFileAttributesNoncompressed : 0; | ||
| 336 | |||
| 337 | fields = String.Join(",", | ||
| 338 | fileSymbol.ComponentRef, | ||
| 339 | fileSymbol.Name, | ||
| 340 | fileSymbol.FileSize.ToString(), | ||
| 341 | fileSymbol.Version, | ||
| 342 | fileSymbol.Language, | ||
| 343 | fileAttributes); | ||
| 344 | break; | ||
| 345 | } | ||
| 346 | |||
| 347 | case "Media": | ||
| 348 | fields = String.Join(",", symbol.Fields.Skip(1).Select(SafeConvertField)); | ||
| 349 | break; | ||
| 350 | |||
| 351 | case "Assembly": | ||
| 352 | { | ||
| 353 | var assemblySymbol = (AssemblySymbol)symbol; | ||
| 354 | |||
| 355 | id = null; | ||
| 356 | name = "MsiAssembly"; | ||
| 357 | fields = String.Join(",", assemblySymbol.ComponentRef, assemblySymbol.FeatureRef, assemblySymbol.ManifestFileRef, assemblySymbol.ApplicationFileRef, assemblySymbol.Type == AssemblyType.Win32Assembly ? 1 : 0); | ||
| 358 | break; | ||
| 359 | } | ||
| 360 | case "RegLocator": | ||
| 361 | { | ||
| 362 | var locatorSymbol = (RegLocatorSymbol)symbol; | ||
| 363 | |||
| 364 | fields = String.Join(",", (int)locatorSymbol.Root, locatorSymbol.Key, locatorSymbol.Name, (int)locatorSymbol.Type, locatorSymbol.Win64); | ||
| 365 | break; | ||
| 366 | } | ||
| 367 | case "Registry": | ||
| 368 | { | ||
| 369 | var registrySymbol = (RegistrySymbol)symbol; | ||
| 370 | var value = registrySymbol.Value; | ||
| 371 | |||
| 372 | switch (registrySymbol.ValueType) | ||
| 373 | { | ||
| 374 | case RegistryValueType.Binary: | ||
| 375 | value = String.Concat("#x", value); | ||
| 376 | break; | ||
| 377 | case RegistryValueType.Expandable: | ||
| 378 | value = String.Concat("#%", value); | ||
| 379 | break; | ||
| 380 | case RegistryValueType.Integer: | ||
| 381 | value = String.Concat("#", value); | ||
| 382 | break; | ||
| 383 | case RegistryValueType.MultiString: | ||
| 384 | switch (registrySymbol.ValueAction) | ||
| 385 | { | ||
| 386 | case RegistryValueActionType.Append: | ||
| 387 | value = String.Concat("[~]", value); | ||
| 388 | break; | ||
| 389 | case RegistryValueActionType.Prepend: | ||
| 390 | value = String.Concat(value, "[~]"); | ||
| 391 | break; | ||
| 392 | case RegistryValueActionType.Write: | ||
| 393 | default: | ||
| 394 | if (null != value && -1 == value.IndexOf("[~]", StringComparison.Ordinal)) | ||
| 395 | { | ||
| 396 | value = String.Concat("[~]", value, "[~]"); | ||
| 397 | } | ||
| 398 | break; | ||
| 399 | } | ||
| 400 | break; | ||
| 401 | case RegistryValueType.String: | ||
| 402 | // escape the leading '#' character for string registry keys | ||
| 403 | if (null != value && value.StartsWith("#", StringComparison.Ordinal)) | ||
| 404 | { | ||
| 405 | value = String.Concat("#", value); | ||
| 406 | } | ||
| 407 | break; | ||
| 408 | } | ||
| 409 | |||
| 410 | fields = String.Join(",", | ||
| 411 | ((int)registrySymbol.Root).ToString(), | ||
| 412 | registrySymbol.Key, | ||
| 413 | registrySymbol.Name, | ||
| 414 | value, | ||
| 415 | registrySymbol.ComponentRef | ||
| 416 | ); | ||
| 417 | break; | ||
| 418 | } | ||
| 419 | |||
| 420 | case "RemoveRegistry": | ||
| 421 | { | ||
| 422 | var removeRegistrySymbol = (RemoveRegistrySymbol)symbol; | ||
| 423 | fields = String.Join(",", | ||
| 424 | ((int)removeRegistrySymbol.Root).ToString(), | ||
| 425 | removeRegistrySymbol.Key, | ||
| 426 | removeRegistrySymbol.Name, | ||
| 427 | removeRegistrySymbol.ComponentRef | ||
| 428 | ); | ||
| 429 | break; | ||
| 430 | } | ||
| 431 | |||
| 432 | case "ServiceControl": | ||
| 433 | { | ||
| 434 | var serviceControlSymbol = (ServiceControlSymbol)symbol; | ||
| 435 | |||
| 436 | var events = serviceControlSymbol.InstallRemove ? WindowsInstallerConstants.MsidbServiceControlEventDelete : 0; | ||
| 437 | events |= serviceControlSymbol.UninstallRemove ? WindowsInstallerConstants.MsidbServiceControlEventUninstallDelete : 0; | ||
| 438 | events |= serviceControlSymbol.InstallStart ? WindowsInstallerConstants.MsidbServiceControlEventStart : 0; | ||
| 439 | events |= serviceControlSymbol.UninstallStart ? WindowsInstallerConstants.MsidbServiceControlEventUninstallStart : 0; | ||
| 440 | events |= serviceControlSymbol.InstallStop ? WindowsInstallerConstants.MsidbServiceControlEventStop : 0; | ||
| 441 | events |= serviceControlSymbol.UninstallStop ? WindowsInstallerConstants.MsidbServiceControlEventUninstallStop : 0; | ||
| 442 | |||
| 443 | fields = String.Join(",", | ||
| 444 | serviceControlSymbol.Name, | ||
| 445 | events.ToString(), | ||
| 446 | serviceControlSymbol.Arguments, | ||
| 447 | serviceControlSymbol.Wait == true ? "1" : "0", | ||
| 448 | serviceControlSymbol.ComponentRef | ||
| 449 | ); | ||
| 450 | break; | ||
| 451 | } | ||
| 452 | |||
| 453 | case "ServiceInstall": | ||
| 454 | { | ||
| 455 | var serviceInstallSymbol = (ServiceInstallSymbol)symbol; | ||
| 456 | |||
| 457 | var errorControl = (int)serviceInstallSymbol.ErrorControl; | ||
| 458 | errorControl |= serviceInstallSymbol.Vital ? WindowsInstallerConstants.MsidbServiceInstallErrorControlVital : 0; | ||
| 459 | |||
| 460 | var serviceType = (int)serviceInstallSymbol.ServiceType; | ||
| 461 | serviceType |= serviceInstallSymbol.Interactive ? WindowsInstallerConstants.MsidbServiceInstallInteractive : 0; | ||
| 462 | |||
| 463 | fields = String.Join(",", | ||
| 464 | serviceInstallSymbol.Name, | ||
| 465 | serviceInstallSymbol.DisplayName, | ||
| 466 | serviceType.ToString(), | ||
| 467 | ((int)serviceInstallSymbol.StartType).ToString(), | ||
| 468 | errorControl.ToString(), | ||
| 469 | serviceInstallSymbol.LoadOrderGroup, | ||
| 470 | serviceInstallSymbol.Dependencies, | ||
| 471 | serviceInstallSymbol.StartName, | ||
| 472 | serviceInstallSymbol.Password, | ||
| 473 | serviceInstallSymbol.Arguments, | ||
| 474 | serviceInstallSymbol.ComponentRef, | ||
| 475 | serviceInstallSymbol.Description | ||
| 476 | ); | ||
| 477 | break; | ||
| 478 | } | ||
| 479 | |||
| 480 | case "Upgrade": | ||
| 481 | { | ||
| 482 | var upgradeSymbol = (UpgradeSymbol)symbol; | ||
| 483 | |||
| 484 | var attributes = upgradeSymbol.MigrateFeatures ? WindowsInstallerConstants.MsidbUpgradeAttributesMigrateFeatures : 0; | ||
| 485 | attributes |= upgradeSymbol.OnlyDetect ? WindowsInstallerConstants.MsidbUpgradeAttributesOnlyDetect : 0; | ||
| 486 | attributes |= upgradeSymbol.IgnoreRemoveFailures ? WindowsInstallerConstants.MsidbUpgradeAttributesIgnoreRemoveFailure : 0; | ||
| 487 | attributes |= upgradeSymbol.VersionMinInclusive ? WindowsInstallerConstants.MsidbUpgradeAttributesVersionMinInclusive : 0; | ||
| 488 | attributes |= upgradeSymbol.VersionMaxInclusive ? WindowsInstallerConstants.MsidbUpgradeAttributesVersionMaxInclusive : 0; | ||
| 489 | attributes |= upgradeSymbol.ExcludeLanguages ? WindowsInstallerConstants.MsidbUpgradeAttributesLanguagesExclusive : 0; | ||
| 490 | |||
| 491 | fields = String.Join(",", | ||
| 492 | upgradeSymbol.VersionMin, | ||
| 493 | upgradeSymbol.VersionMax, | ||
| 494 | upgradeSymbol.Language, | ||
| 495 | attributes.ToString(), | ||
| 496 | upgradeSymbol.Remove, | ||
| 497 | upgradeSymbol.ActionProperty | ||
| 498 | ); | ||
| 499 | break; | ||
| 500 | } | ||
| 501 | |||
| 502 | case "WixAction": | ||
| 503 | { | ||
| 504 | var wixActionSymbol = (WixActionSymbol)symbol; | ||
| 505 | var data = wixActionSymbol.Fields[(int)WixActionSymbolFields.SequenceTable].AsObject(); | ||
| 506 | var sequenceTableAsInt = data is string ? (int)SequenceStringToSequenceTable(data) : (int)wixActionSymbol.SequenceTable; | ||
| 507 | |||
| 508 | fields = String.Join(",", | ||
| 509 | sequenceTableAsInt, | ||
| 510 | wixActionSymbol.Action, | ||
| 511 | wixActionSymbol.Condition, | ||
| 512 | wixActionSymbol.Sequence?.ToString() ?? String.Empty, | ||
| 513 | wixActionSymbol.Before, | ||
| 514 | wixActionSymbol.After, | ||
| 515 | wixActionSymbol.Overridable == true ? "1" : "0" | ||
| 516 | ); | ||
| 517 | break; | ||
| 518 | } | ||
| 519 | |||
| 520 | case "WixComplexReference": | ||
| 521 | { | ||
| 522 | var wixComplexReferenceSymbol = (WixComplexReferenceSymbol)symbol; | ||
| 523 | fields = String.Join(",", | ||
| 524 | wixComplexReferenceSymbol.Parent, | ||
| 525 | (int)wixComplexReferenceSymbol.ParentType, | ||
| 526 | wixComplexReferenceSymbol.ParentLanguage, | ||
| 527 | wixComplexReferenceSymbol.Child, | ||
| 528 | (int)wixComplexReferenceSymbol.ChildType, | ||
| 529 | wixComplexReferenceSymbol.IsPrimary ? "1" : "0" | ||
| 530 | ); | ||
| 531 | break; | ||
| 532 | } | ||
| 533 | |||
| 534 | case "WixProperty": | ||
| 535 | { | ||
| 536 | var wixPropertySymbol = (WixPropertySymbol)symbol; | ||
| 537 | var attributes = wixPropertySymbol.Admin ? 0x1 : 0; | ||
| 538 | attributes |= wixPropertySymbol.Hidden ? 0x2 : 0; | ||
| 539 | attributes |= wixPropertySymbol.Secure ? 0x4 : 0; | ||
| 540 | |||
| 541 | fields = String.Join(",", | ||
| 542 | wixPropertySymbol.PropertyRef, | ||
| 543 | attributes.ToString() | ||
| 544 | ); | ||
| 545 | break; | ||
| 546 | } | ||
| 547 | |||
| 548 | default: | ||
| 549 | fields = String.Join(",", symbol.Fields.Select(SafeConvertField)); | ||
| 550 | break; | ||
| 551 | } | ||
| 552 | |||
| 553 | fields = String.IsNullOrEmpty(id) ? fields : String.IsNullOrEmpty(fields) ? id : $"{id},{fields}"; | ||
| 554 | yield return $"{name}:{fields}"; | ||
| 555 | } | ||
| 556 | |||
| 557 | private static SequenceTable SequenceStringToSequenceTable(object sequenceString) | ||
| 558 | { | ||
| 559 | switch (sequenceString) | ||
| 560 | { | ||
| 561 | case "AdminExecuteSequence": | ||
| 562 | return SequenceTable.AdminExecuteSequence; | ||
| 563 | case "AdminUISequence": | ||
| 564 | return SequenceTable.AdminUISequence; | ||
| 565 | case "AdvtExecuteSequence": | ||
| 566 | return SequenceTable.AdvertiseExecuteSequence; | ||
| 567 | case "InstallExecuteSequence": | ||
| 568 | return SequenceTable.InstallExecuteSequence; | ||
| 569 | case "InstallUISequence": | ||
| 570 | return SequenceTable.InstallUISequence; | ||
| 571 | default: | ||
| 572 | throw new ArgumentException($"Unknown sequence: {sequenceString}"); | ||
| 573 | } | ||
| 574 | } | ||
| 575 | |||
| 576 | private static string SafeConvertField(Wix3.Field field) | ||
| 577 | { | ||
| 578 | return field?.Data?.ToString(); | ||
| 579 | } | ||
| 580 | |||
| 581 | private static string SafeConvertField(IntermediateField field) | ||
| 582 | { | ||
| 583 | var data = field.AsObject(); | ||
| 584 | if (data is IntermediateFieldPathValue path) | ||
| 585 | { | ||
| 586 | return path.Path; | ||
| 587 | } | ||
| 588 | |||
| 589 | return data?.ToString(); | ||
| 590 | } | ||
| 591 | |||
| 592 | private static string[] SplitDefaultDir(string defaultDir) | ||
| 593 | { | ||
| 594 | var split1 = defaultDir.Split(':'); | ||
| 595 | var targetSplit = split1.Length > 1 ? split1[1].Split('|') : split1[0].Split('|'); | ||
| 596 | var sourceSplit = split1.Length > 1 ? split1[0].Split('|') : new[] { String.Empty }; | ||
| 597 | return new[] | ||
| 598 | { | ||
| 599 | targetSplit.Length > 1 ? targetSplit[1] : targetSplit[0], | ||
| 600 | targetSplit.Length > 1 ? targetSplit[0] : String.Empty, | ||
| 601 | sourceSplit.Length > 1 ? sourceSplit[1] : sourceSplit[0], | ||
| 602 | sourceSplit.Length > 1 ? sourceSplit[0] : String.Empty | ||
| 603 | }; | ||
| 604 | } | ||
| 605 | } | ||
| 606 | } | ||
