aboutsummaryrefslogtreecommitdiff
path: root/src/test/WixToolsetTest.Converters.Symbolizer/ConvertTuplesFixture.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/WixToolsetTest.Converters.Symbolizer/ConvertTuplesFixture.cs')
-rw-r--r--src/test/WixToolsetTest.Converters.Symbolizer/ConvertTuplesFixture.cs606
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
3namespace 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}