aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core.WindowsInstaller
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core.WindowsInstaller')
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs447
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs7
-rw-r--r--src/WixToolset.Core.WindowsInstaller/Bind/LoadTableDefinitionsCommand.cs257
3 files changed, 349 insertions, 362 deletions
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs
index ffc4e84d..0c1aa312 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs
@@ -18,8 +18,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind
18 private const int DefaultMaximumUncompressedMediaSize = 200; // Default value is 200 MB 18 private const int DefaultMaximumUncompressedMediaSize = 200; // Default value is 200 MB
19 private const int MaxValueOfMaxCabSizeForLargeFileSplitting = 2 * 1024; // 2048 MB (i.e. 2 GB) 19 private const int MaxValueOfMaxCabSizeForLargeFileSplitting = 2 * 1024; // 2048 MB (i.e. 2 GB)
20 20
21 private static readonly char[] ColonCharacter = new[] { ':' };
22
23 public CreateOutputFromIRCommand(IMessaging messaging, IntermediateSection section, TableDefinitionCollection tableDefinitions, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtensions, IWindowsInstallerBackendHelper backendHelper) 21 public CreateOutputFromIRCommand(IMessaging messaging, IntermediateSection section, TableDefinitionCollection tableDefinitions, IEnumerable<IWindowsInstallerBackendBinderExtension> backendExtensions, IWindowsInstallerBackendHelper backendHelper)
24 { 22 {
25 this.Messaging = messaging; 23 this.Messaging = messaging;
@@ -54,171 +52,174 @@ namespace WixToolset.Core.WindowsInstaller.Bind
54 52
55 private void AddSectionToOutput() 53 private void AddSectionToOutput()
56 { 54 {
55 var cellsByTableAndRowId = new Dictionary<string, List<WixCustomTableCellTuple>>();
56
57 foreach (var tuple in this.Section.Tuples) 57 foreach (var tuple in this.Section.Tuples)
58 { 58 {
59 var unknownTuple = false; 59 var unknownTuple = false;
60 switch (tuple.Definition.Type) 60 switch (tuple.Definition.Type)
61 { 61 {
62 case TupleDefinitionType.AppSearch: 62 case TupleDefinitionType.AppSearch:
63 this.AddTupleDefaultly(tuple); 63 this.AddTupleDefaultly(tuple);
64 this.Output.EnsureTable(this.TableDefinitions["Signature"]); 64 this.Output.EnsureTable(this.TableDefinitions["Signature"]);
65 break; 65 break;
66 66
67 case TupleDefinitionType.Assembly: 67 case TupleDefinitionType.Assembly:
68 this.AddAssemblyTuple((AssemblyTuple)tuple); 68 this.AddAssemblyTuple((AssemblyTuple)tuple);
69 break; 69 break;
70 70
71 case TupleDefinitionType.BBControl: 71 case TupleDefinitionType.BBControl:
72 this.AddBBControlTuple((BBControlTuple)tuple); 72 this.AddBBControlTuple((BBControlTuple)tuple);
73 break; 73 break;
74 74
75 case TupleDefinitionType.Class: 75 case TupleDefinitionType.Class:
76 this.AddClassTuple((ClassTuple)tuple); 76 this.AddClassTuple((ClassTuple)tuple);
77 break; 77 break;
78 78
79 case TupleDefinitionType.Control: 79 case TupleDefinitionType.Control:
80 this.AddControlTuple((ControlTuple)tuple); 80 this.AddControlTuple((ControlTuple)tuple);
81 break; 81 break;
82 82
83 case TupleDefinitionType.Component: 83 case TupleDefinitionType.Component:
84 this.AddComponentTuple((ComponentTuple)tuple); 84 this.AddComponentTuple((ComponentTuple)tuple);
85 break; 85 break;
86 86
87 case TupleDefinitionType.CustomAction: 87 case TupleDefinitionType.CustomAction:
88 this.AddCustomActionTuple((CustomActionTuple)tuple); 88 this.AddCustomActionTuple((CustomActionTuple)tuple);
89 break; 89 break;
90 90
91 case TupleDefinitionType.Dialog: 91 case TupleDefinitionType.Dialog:
92 this.AddDialogTuple((DialogTuple)tuple); 92 this.AddDialogTuple((DialogTuple)tuple);
93 break; 93 break;
94 94
95 case TupleDefinitionType.Directory: 95 case TupleDefinitionType.Directory:
96 this.AddDirectoryTuple((DirectoryTuple)tuple); 96 this.AddDirectoryTuple((DirectoryTuple)tuple);
97 break; 97 break;
98 98
99 case TupleDefinitionType.Environment: 99 case TupleDefinitionType.Environment:
100 this.AddEnvironmentTuple((EnvironmentTuple)tuple); 100 this.AddEnvironmentTuple((EnvironmentTuple)tuple);
101 break; 101 break;
102 102
103 case TupleDefinitionType.Error: 103 case TupleDefinitionType.Error:
104 this.AddErrorTuple((ErrorTuple)tuple); 104 this.AddErrorTuple((ErrorTuple)tuple);
105 break; 105 break;
106 106
107 case TupleDefinitionType.Feature: 107 case TupleDefinitionType.Feature:
108 this.AddFeatureTuple((FeatureTuple)tuple); 108 this.AddFeatureTuple((FeatureTuple)tuple);
109 break; 109 break;
110 110
111 case TupleDefinitionType.File: 111 case TupleDefinitionType.File:
112 this.AddFileTuple((FileTuple)tuple); 112 this.AddFileTuple((FileTuple)tuple);
113 break; 113 break;
114 114
115 case TupleDefinitionType.IniFile: 115 case TupleDefinitionType.IniFile:
116 this.AddIniFileTuple((IniFileTuple)tuple); 116 this.AddIniFileTuple((IniFileTuple)tuple);
117 break; 117 break;
118 118
119 case TupleDefinitionType.Media: 119 case TupleDefinitionType.Media:
120 this.AddMediaTuple((MediaTuple)tuple); 120 this.AddMediaTuple((MediaTuple)tuple);
121 break; 121 break;
122 122
123 case TupleDefinitionType.ModuleConfiguration: 123 case TupleDefinitionType.ModuleConfiguration:
124 this.AddModuleConfigurationTuple((ModuleConfigurationTuple)tuple); 124 this.AddModuleConfigurationTuple((ModuleConfigurationTuple)tuple);
125 break; 125 break;
126 126
127 case TupleDefinitionType.MsiEmbeddedUI: 127 case TupleDefinitionType.MsiEmbeddedUI:
128 this.AddMsiEmbeddedUITuple((MsiEmbeddedUITuple)tuple); 128 this.AddMsiEmbeddedUITuple((MsiEmbeddedUITuple)tuple);
129 break; 129 break;
130 130
131 case TupleDefinitionType.MsiServiceConfig: 131 case TupleDefinitionType.MsiServiceConfig:
132 this.AddMsiServiceConfigTuple((MsiServiceConfigTuple)tuple); 132 this.AddMsiServiceConfigTuple((MsiServiceConfigTuple)tuple);
133 break; 133 break;
134 134
135 case TupleDefinitionType.MsiServiceConfigFailureActions: 135 case TupleDefinitionType.MsiServiceConfigFailureActions:
136 this.AddMsiServiceConfigFailureActionsTuple((MsiServiceConfigFailureActionsTuple)tuple); 136 this.AddMsiServiceConfigFailureActionsTuple((MsiServiceConfigFailureActionsTuple)tuple);
137 break; 137 break;
138 138
139 case TupleDefinitionType.MoveFile: 139 case TupleDefinitionType.MoveFile:
140 this.AddMoveFileTuple((MoveFileTuple)tuple); 140 this.AddMoveFileTuple((MoveFileTuple)tuple);
141 break; 141 break;
142 142
143 case TupleDefinitionType.ProgId: 143 case TupleDefinitionType.ProgId:
144 this.AddTupleDefaultly(tuple); 144 this.AddTupleDefaultly(tuple);
145 this.Output.EnsureTable(this.TableDefinitions["Extension"]); 145 this.Output.EnsureTable(this.TableDefinitions["Extension"]);
146 break; 146 break;
147 147
148 case TupleDefinitionType.Property: 148 case TupleDefinitionType.Property:
149 this.AddPropertyTuple((PropertyTuple)tuple); 149 this.AddPropertyTuple((PropertyTuple)tuple);
150 break; 150 break;
151 151
152 case TupleDefinitionType.RemoveFile: 152 case TupleDefinitionType.RemoveFile:
153 this.AddRemoveFileTuple((RemoveFileTuple)tuple); 153 this.AddRemoveFileTuple((RemoveFileTuple)tuple);
154 break; 154 break;
155 155
156 case TupleDefinitionType.Registry: 156 case TupleDefinitionType.Registry:
157 this.AddRegistryTuple((RegistryTuple)tuple); 157 this.AddRegistryTuple((RegistryTuple)tuple);
158 break; 158 break;
159 159
160 case TupleDefinitionType.RegLocator: 160 case TupleDefinitionType.RegLocator:
161 this.AddRegLocatorTuple((RegLocatorTuple)tuple); 161 this.AddRegLocatorTuple((RegLocatorTuple)tuple);
162 break; 162 break;
163 163
164 case TupleDefinitionType.RemoveRegistry: 164 case TupleDefinitionType.RemoveRegistry:
165 this.AddRemoveRegistryTuple((RemoveRegistryTuple)tuple); 165 this.AddRemoveRegistryTuple((RemoveRegistryTuple)tuple);
166 break; 166 break;
167 167
168 case TupleDefinitionType.ServiceControl: 168 case TupleDefinitionType.ServiceControl:
169 this.AddServiceControlTuple((ServiceControlTuple)tuple); 169 this.AddServiceControlTuple((ServiceControlTuple)tuple);
170 break; 170 break;
171 171
172 case TupleDefinitionType.ServiceInstall: 172 case TupleDefinitionType.ServiceInstall:
173 this.AddServiceInstallTuple((ServiceInstallTuple)tuple); 173 this.AddServiceInstallTuple((ServiceInstallTuple)tuple);
174 break; 174 break;
175 175
176 case TupleDefinitionType.Shortcut: 176 case TupleDefinitionType.Shortcut:
177 this.AddShortcutTuple((ShortcutTuple)tuple); 177 this.AddShortcutTuple((ShortcutTuple)tuple);
178 break; 178 break;
179 179
180 case TupleDefinitionType.TextStyle: 180 case TupleDefinitionType.TextStyle:
181 this.AddTextStyleTuple((TextStyleTuple)tuple); 181 this.AddTextStyleTuple((TextStyleTuple)tuple);
182 break; 182 break;
183 183
184 case TupleDefinitionType.Upgrade: 184 case TupleDefinitionType.Upgrade:
185 this.AddUpgradeTuple((UpgradeTuple)tuple); 185 this.AddUpgradeTuple((UpgradeTuple)tuple);
186 break; 186 break;
187 187
188 case TupleDefinitionType.WixAction: 188 case TupleDefinitionType.WixAction:
189 this.AddWixActionTuple((WixActionTuple)tuple); 189 this.AddWixActionTuple((WixActionTuple)tuple);
190 break; 190 break;
191 191
192 case TupleDefinitionType.WixMediaTemplate: 192 case TupleDefinitionType.WixMediaTemplate:
193 this.AddWixMediaTemplateTuple((WixMediaTemplateTuple)tuple); 193 this.AddWixMediaTemplateTuple((WixMediaTemplateTuple)tuple);
194 break; 194 break;
195 195
196 case TupleDefinitionType.WixCustomRow: 196 case TupleDefinitionType.WixCustomTableCell:
197 this.AddWixCustomRowTuple((WixCustomRowTuple)tuple); 197 this.IndexCustomTableCellTuple((WixCustomTableCellTuple)tuple, cellsByTableAndRowId);
198 break; 198 break;
199 199
200 case TupleDefinitionType.WixEnsureTable: 200 case TupleDefinitionType.WixEnsureTable:
201 this.AddWixEnsureTableTuple((WixEnsureTableTuple)tuple); 201 this.AddWixEnsureTableTuple((WixEnsureTableTuple)tuple);
202 break; 202 break;
203 203
204 // ignored. 204 // ignored.
205 case TupleDefinitionType.WixComponentGroup: 205 case TupleDefinitionType.WixComponentGroup:
206 case TupleDefinitionType.WixDeltaPatchFile: 206 case TupleDefinitionType.WixDeltaPatchFile:
207 case TupleDefinitionType.WixFeatureGroup: 207 case TupleDefinitionType.WixFeatureGroup:
208 case TupleDefinitionType.WixPatchBaseline: 208 case TupleDefinitionType.WixPatchBaseline:
209 break; 209 break;
210 210
211 // Already processed. 211 // Already processed by LoadTableDefinitions.
212 case TupleDefinitionType.WixCustomTable: 212 case TupleDefinitionType.WixCustomTable:
213 break; 213 case TupleDefinitionType.WixCustomTableColumn:
214 break;
214 215
215 case TupleDefinitionType.MustBeFromAnExtension: 216 case TupleDefinitionType.MustBeFromAnExtension:
216 unknownTuple = !this.AddTupleFromExtension(tuple); 217 unknownTuple = !this.AddTupleFromExtension(tuple);
217 break; 218 break;
218 219
219 default: 220 default:
220 unknownTuple = !this.AddTupleDefaultly(tuple); 221 unknownTuple = !this.AddTupleDefaultly(tuple);
221 break; 222 break;
222 } 223 }
223 224
224 if (unknownTuple) 225 if (unknownTuple)
@@ -226,6 +227,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind
226 this.Messaging.Write(WarningMessages.TupleNotTranslatedToOutput(tuple)); 227 this.Messaging.Write(WarningMessages.TupleNotTranslatedToOutput(tuple));
227 } 228 }
228 } 229 }
230
231 this.AddIndexedCellTuples(cellsByTableAndRowId);
229 } 232 }
230 233
231 private void AddAssemblyTuple(AssemblyTuple tuple) 234 private void AddAssemblyTuple(AssemblyTuple tuple)
@@ -383,16 +386,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind
383 private void AddDialogTuple(DialogTuple tuple) 386 private void AddDialogTuple(DialogTuple tuple)
384 { 387 {
385 var attributes = tuple.Visible ? WindowsInstallerConstants.MsidbDialogAttributesVisible : 0; 388 var attributes = tuple.Visible ? WindowsInstallerConstants.MsidbDialogAttributesVisible : 0;
386 attributes|= tuple.Modal ? WindowsInstallerConstants.MsidbDialogAttributesModal : 0; 389 attributes |= tuple.Modal ? WindowsInstallerConstants.MsidbDialogAttributesModal : 0;
387 attributes|= tuple.Minimize ? WindowsInstallerConstants.MsidbDialogAttributesMinimize : 0; 390 attributes |= tuple.Minimize ? WindowsInstallerConstants.MsidbDialogAttributesMinimize : 0;
388 attributes|= tuple.CustomPalette ? WindowsInstallerConstants.MsidbDialogAttributesUseCustomPalette: 0; 391 attributes |= tuple.CustomPalette ? WindowsInstallerConstants.MsidbDialogAttributesUseCustomPalette : 0;
389 attributes|= tuple.ErrorDialog ? WindowsInstallerConstants.MsidbDialogAttributesError : 0; 392 attributes |= tuple.ErrorDialog ? WindowsInstallerConstants.MsidbDialogAttributesError : 0;
390 attributes|= tuple.LeftScroll ? WindowsInstallerConstants.MsidbDialogAttributesLeftScroll : 0; 393 attributes |= tuple.LeftScroll ? WindowsInstallerConstants.MsidbDialogAttributesLeftScroll : 0;
391 attributes|= tuple.KeepModeless ? WindowsInstallerConstants.MsidbDialogAttributesKeepModeless : 0; 394 attributes |= tuple.KeepModeless ? WindowsInstallerConstants.MsidbDialogAttributesKeepModeless : 0;
392 attributes|= tuple.RightAligned ? WindowsInstallerConstants.MsidbDialogAttributesRightAligned : 0; 395 attributes |= tuple.RightAligned ? WindowsInstallerConstants.MsidbDialogAttributesRightAligned : 0;
393 attributes|= tuple.RightToLeft ? WindowsInstallerConstants.MsidbDialogAttributesRTLRO : 0; 396 attributes |= tuple.RightToLeft ? WindowsInstallerConstants.MsidbDialogAttributesRTLRO : 0;
394 attributes|= tuple.SystemModal ? WindowsInstallerConstants.MsidbDialogAttributesSysModal : 0; 397 attributes |= tuple.SystemModal ? WindowsInstallerConstants.MsidbDialogAttributesSysModal : 0;
395 attributes|= tuple.TrackDiskSpace ? WindowsInstallerConstants.MsidbDialogAttributesTrackDiskSpace : 0; 398 attributes |= tuple.TrackDiskSpace ? WindowsInstallerConstants.MsidbDialogAttributesTrackDiskSpace : 0;
396 399
397 var row = this.CreateRow(tuple, "Dialog"); 400 var row = this.CreateRow(tuple, "Dialog");
398 row[0] = tuple.Id.Id; 401 row[0] = tuple.Id.Id;
@@ -419,7 +422,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
419 targetName = "."; 422 targetName = ".";
420 } 423 }
421 424
422 var defaultDir = String.IsNullOrEmpty(sourceName) ? targetName : targetName + ":" + sourceName ; 425 var defaultDir = String.IsNullOrEmpty(sourceName) ? targetName : targetName + ":" + sourceName;
423 426
424 var row = this.CreateRow(tuple, "Directory"); 427 var row = this.CreateRow(tuple, "Directory");
425 row[0] = tuple.Id.Id; 428 row[0] = tuple.Id.Id;
@@ -436,25 +439,25 @@ namespace WixToolset.Core.WindowsInstaller.Bind
436 439
437 switch (tuple.Action) 440 switch (tuple.Action)
438 { 441 {
439 case EnvironmentActionType.Create: 442 case EnvironmentActionType.Create:
440 action = "+"; 443 action = "+";
441 break; 444 break;
442 case EnvironmentActionType.Set: 445 case EnvironmentActionType.Set:
443 action = "="; 446 action = "=";
444 break; 447 break;
445 case EnvironmentActionType.Remove: 448 case EnvironmentActionType.Remove:
446 action = "!"; 449 action = "!";
447 break; 450 break;
448 } 451 }
449 452
450 switch (tuple.Part) 453 switch (tuple.Part)
451 { 454 {
452 case EnvironmentPartType.First: 455 case EnvironmentPartType.First:
453 value = String.Concat(value, tuple.Separator, "[~]"); 456 value = String.Concat(value, tuple.Separator, "[~]");
454 break; 457 break;
455 case EnvironmentPartType.Last: 458 case EnvironmentPartType.Last:
456 value = String.Concat("[~]", tuple.Separator, value); 459 value = String.Concat("[~]", tuple.Separator, value);
457 break; 460 break;
458 } 461 }
459 462
460 var row = this.CreateRow(tuple, "Environment"); 463 var row = this.CreateRow(tuple, "Environment");
@@ -661,40 +664,40 @@ namespace WixToolset.Core.WindowsInstaller.Bind
661 664
662 switch (tuple.ValueType) 665 switch (tuple.ValueType)
663 { 666 {
664 case RegistryValueType.Binary: 667 case RegistryValueType.Binary:
665 value = String.Concat("#x", value); 668 value = String.Concat("#x", value);
666 break;
667 case RegistryValueType.Expandable:
668 value = String.Concat("#%", value);
669 break;
670 case RegistryValueType.Integer:
671 value = String.Concat("#", value);
672 break;
673 case RegistryValueType.MultiString:
674 switch (tuple.ValueAction)
675 {
676 case RegistryValueActionType.Append:
677 value = String.Concat("[~]", value);
678 break; 669 break;
679 case RegistryValueActionType.Prepend: 670 case RegistryValueType.Expandable:
680 value = String.Concat(value, "[~]"); 671 value = String.Concat("#%", value);
681 break; 672 break;
682 case RegistryValueActionType.Write: 673 case RegistryValueType.Integer:
683 default: 674 value = String.Concat("#", value);
684 if (null != value && -1 == value.IndexOf("[~]", StringComparison.Ordinal)) 675 break;
676 case RegistryValueType.MultiString:
677 switch (tuple.ValueAction)
685 { 678 {
686 value = String.Format(CultureInfo.InvariantCulture, "[~]{0}[~]", value); 679 case RegistryValueActionType.Append:
680 value = String.Concat("[~]", value);
681 break;
682 case RegistryValueActionType.Prepend:
683 value = String.Concat(value, "[~]");
684 break;
685 case RegistryValueActionType.Write:
686 default:
687 if (null != value && -1 == value.IndexOf("[~]", StringComparison.Ordinal))
688 {
689 value = String.Format(CultureInfo.InvariantCulture, "[~]{0}[~]", value);
690 }
691 break;
692 }
693 break;
694 case RegistryValueType.String:
695 // escape the leading '#' character for string registry keys
696 if (null != value && value.StartsWith("#", StringComparison.Ordinal))
697 {
698 value = String.Concat("#", value);
687 } 699 }
688 break; 700 break;
689 }
690 break;
691 case RegistryValueType.String:
692 // escape the leading '#' character for string registry keys
693 if (null != value && value.StartsWith("#", StringComparison.Ordinal))
694 {
695 value = String.Concat("#", value);
696 }
697 break;
698 } 701 }
699 702
700 var row = this.CreateRow(tuple, "Registry"); 703 var row = this.CreateRow(tuple, "Registry");
@@ -757,7 +760,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind
757 row[3] = tuple.Arguments; 760 row[3] = tuple.Arguments;
758 if (tuple.Wait.HasValue) 761 if (tuple.Wait.HasValue)
759 { 762 {
760 row[4] = tuple.Wait.Value ? 1 : 0; 763 row[4] = tuple.Wait.Value ? 1 : 0;
761 } 764 }
762 row[5] = tuple.ComponentRef; 765 row[5] = tuple.ComponentRef;
763 } 766 }
@@ -938,83 +941,89 @@ namespace WixToolset.Core.WindowsInstaller.Bind
938 row[2] = tuple.Sequence; 941 row[2] = tuple.Sequence;
939 } 942 }
940 } 943 }
941
942 private void AddWixCustomRowTuple(WixCustomRowTuple tuple)
943 {
944 var customTableDefinition = this.TableDefinitions[tuple.Table];
945 944
946 if (customTableDefinition.Unreal) 945 private void IndexCustomTableCellTuple(WixCustomTableCellTuple wixCustomTableCellTuple, Dictionary<string, List<WixCustomTableCellTuple>> cellsByTableAndRowId)
946 {
947 var tableAndRowId = wixCustomTableCellTuple.TableRef + "/" + wixCustomTableCellTuple.RowId;
948 if (!cellsByTableAndRowId.TryGetValue(tableAndRowId, out var cells))
947 { 949 {
948 950 cells = new List<WixCustomTableCellTuple>();
949 return; 951 cellsByTableAndRowId.Add(tableAndRowId, cells);
950 } 952 }
951 953
952 var customRow = this.CreateRow(tuple, customTableDefinition); 954 cells.Add(wixCustomTableCellTuple);
955 }
953 956
954#if TODO // SectionId seems like a good thing to preserve. 957 private void AddIndexedCellTuples(Dictionary<string, List<WixCustomTableCellTuple>> cellsByTableAndRowId)
955 customRow.SectionId = tuple.SectionId; 958 {
956#endif 959 foreach (var rowOfCells in cellsByTableAndRowId.Values)
960 {
961 var firstCellTuple = rowOfCells[0];
962 var customTableDefinition = this.TableDefinitions[firstCellTuple.TableRef];
957 963
958 var data = tuple.FieldDataSeparated; 964 if (customTableDefinition.Unreal)
965 {
966 return;
967 }
959 968
960 for (var i = 0; i < data.Length; ++i) 969 var customRow = this.CreateRow(firstCellTuple, customTableDefinition);
961 { 970 var customRowFieldsByColumnName = customRow.Fields.ToDictionary(f => f.Column.Name);
962 var foundColumn = false;
963 var item = data[i].Split(ColonCharacter, 2);
964 971
965 for (var j = 0; j < customRow.Fields.Length; ++j) 972#if TODO // SectionId seems like a good thing to preserve.
973 customRow.SectionId = tuple.SectionId;
974#endif
975 foreach (var cell in rowOfCells)
966 { 976 {
967 if (customRow.Fields[j].Column.Name == item[0]) 977 var data = cell.Data;
978
979 if (customRowFieldsByColumnName.TryGetValue(cell.ColumnRef, out var rowField))
968 { 980 {
969 if (0 < item[1].Length) 981 if (!String.IsNullOrEmpty(data))
970 { 982 {
971 if (ColumnType.Number == customRow.Fields[j].Column.Type) 983 if (rowField.Column.Type == ColumnType.Number)
972 { 984 {
973 try 985 try
974 { 986 {
975 customRow.Fields[j].Data = Convert.ToInt32(item[1], CultureInfo.InvariantCulture); 987 rowField.Data = Convert.ToInt32(data, CultureInfo.InvariantCulture);
976 } 988 }
977 catch (FormatException) 989 catch (FormatException)
978 { 990 {
979 this.Messaging.Write(ErrorMessages.IllegalIntegerValue(tuple.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name, item[1])); 991 this.Messaging.Write(ErrorMessages.IllegalIntegerValue(cell.SourceLineNumbers, rowField.Column.Name, customTableDefinition.Name, data));
980 } 992 }
981 catch (OverflowException) 993 catch (OverflowException)
982 { 994 {
983 this.Messaging.Write(ErrorMessages.IllegalIntegerValue(tuple.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name, item[1])); 995 this.Messaging.Write(ErrorMessages.IllegalIntegerValue(cell.SourceLineNumbers, rowField.Column.Name, customTableDefinition.Name, data));
984 } 996 }
985 } 997 }
986 else if (ColumnCategory.Identifier == customRow.Fields[j].Column.Category) 998 else if (rowField.Column.Category == ColumnCategory.Identifier)
987 { 999 {
988 if (Common.IsIdentifier(item[1]) || Common.IsValidBinderVariable(item[1]) || ColumnCategory.Formatted == customRow.Fields[j].Column.Category) 1000 if (Common.IsIdentifier(data) || Common.IsValidBinderVariable(data) || ColumnCategory.Formatted == rowField.Column.Category)
989 { 1001 {
990 customRow.Fields[j].Data = item[1]; 1002 rowField.Data = data;
991 } 1003 }
992 else 1004 else
993 { 1005 {
994 this.Messaging.Write(ErrorMessages.IllegalIdentifier(tuple.SourceLineNumbers, "Data", item[1])); 1006 this.Messaging.Write(ErrorMessages.IllegalIdentifier(cell.SourceLineNumbers, "Data", data));
995 } 1007 }
996 } 1008 }
997 else 1009 else
998 { 1010 {
999 customRow.Fields[j].Data = item[1]; 1011 rowField.Data = data;
1000 } 1012 }
1001 } 1013 }
1002 foundColumn = true; 1014 }
1003 break; 1015 else
1016 {
1017 this.Messaging.Write(ErrorMessages.UnexpectedCustomTableColumn(cell.SourceLineNumbers, cell.ColumnRef));
1004 } 1018 }
1005 } 1019 }
1006 1020
1007 if (!foundColumn) 1021 for (var i = 0; i < customTableDefinition.Columns.Length; ++i)
1008 {
1009 this.Messaging.Write(ErrorMessages.UnexpectedCustomTableColumn(tuple.SourceLineNumbers, item[0]));
1010 }
1011 }
1012
1013 for (var i = 0; i < customTableDefinition.Columns.Length; ++i)
1014 {
1015 if (!customTableDefinition.Columns[i].Nullable && (null == customRow.Fields[i].Data || 0 == customRow.Fields[i].Data.ToString().Length))
1016 { 1022 {
1017 this.Messaging.Write(ErrorMessages.NoDataForColumn(tuple.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name)); 1023 if (!customTableDefinition.Columns[i].Nullable && (null == customRow.Fields[i].Data || 0 == customRow.Fields[i].Data.ToString().Length))
1024 {
1025 this.Messaging.Write(ErrorMessages.NoDataForColumn(firstCellTuple.SourceLineNumbers, customTableDefinition.Columns[i].Name, customTableDefinition.Name));
1026 }
1018 } 1027 }
1019 } 1028 }
1020 } 1029 }
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs
index eff94e80..6edbdd1c 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/GenerateDatabaseCommand.cs
@@ -314,18 +314,19 @@ namespace WixToolset.Core.WindowsInstaller.Bind
314 break; 314 break;
315 315
316 case ColumnType.Object: 316 case ColumnType.Object:
317 if (null != row[i]) 317 var path = row.FieldAsString(i);
318 if (null != path)
318 { 319 {
319 needStream = true; 320 needStream = true;
320 try 321 try
321 { 322 {
322 record.SetStream(i + 1, row.FieldAsString(i)); 323 record.SetStream(i + 1, path);
323 } 324 }
324 catch (Win32Exception e) 325 catch (Win32Exception e)
325 { 326 {
326 if (0xA1 == e.NativeErrorCode) // ERROR_BAD_PATHNAME 327 if (0xA1 == e.NativeErrorCode) // ERROR_BAD_PATHNAME
327 { 328 {
328 throw new WixException(ErrorMessages.FileNotFound(row.SourceLineNumbers, row.FieldAsString(i))); 329 throw new WixException(ErrorMessages.FileNotFound(row.SourceLineNumbers, path));
329 } 330 }
330 else 331 else
331 { 332 {
diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/LoadTableDefinitionsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/LoadTableDefinitionsCommand.cs
index eba7bdbe..d7809034 100644
--- a/src/WixToolset.Core.WindowsInstaller/Bind/LoadTableDefinitionsCommand.cs
+++ b/src/WixToolset.Core.WindowsInstaller/Bind/LoadTableDefinitionsCommand.cs
@@ -32,11 +32,15 @@ namespace WixToolset.Core.WindowsInstaller.Bind
32 public TableDefinitionCollection Execute() 32 public TableDefinitionCollection Execute()
33 { 33 {
34 var tableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All); 34 var tableDefinitions = new TableDefinitionCollection(WindowsInstallerTableDefinitions.All);
35 var customColumnsById = this.Section.Tuples.OfType<WixCustomTableColumnTuple>().ToDictionary(t => t.Id.Id);
35 36
36 foreach (var tuple in this.Section.Tuples.OfType<WixCustomTableTuple>()) 37 if (customColumnsById.Any())
37 { 38 {
38 var customTableDefinition = this.CreateCustomTable(tuple); 39 foreach (var tuple in this.Section.Tuples.OfType<WixCustomTableTuple>())
39 tableDefinitions.Add(customTableDefinition); 40 {
41 var customTableDefinition = this.CreateCustomTable(tuple, customColumnsById);
42 tableDefinitions.Add(customTableDefinition);
43 }
40 } 44 }
41 45
42 foreach (var backendExtension in this.BackendExtensions) 46 foreach (var backendExtension in this.BackendExtensions)
@@ -56,177 +60,150 @@ namespace WixToolset.Core.WindowsInstaller.Bind
56 return this.TableDefinitions; 60 return this.TableDefinitions;
57 } 61 }
58 62
59 private TableDefinition CreateCustomTable(WixCustomTableTuple tuple) 63 private TableDefinition CreateCustomTable(WixCustomTableTuple tuple, Dictionary<string, WixCustomTableColumnTuple> customColumnsById)
60 { 64 {
61 var columnNames = tuple.ColumnNames.Split('\t'); 65 var columnNames = tuple.ColumnNamesSeparated;
62 var columnTypes = tuple.ColumnTypes.Split('\t');
63 var primaryKeys = tuple.PrimaryKeys.Split('\t');
64 var minValues = tuple.MinValues?.Split('\t');
65 var maxValues = tuple.MaxValues?.Split('\t');
66 var keyTables = tuple.KeyTables?.Split('\t');
67 var keyColumns = tuple.KeyColumns?.Split('\t');
68 var categories = tuple.Categories?.Split('\t');
69 var sets = tuple.Sets?.Split('\t');
70 var descriptions = tuple.Descriptions?.Split('\t');
71 var modularizations = tuple.Modularizations?.Split('\t');
72
73 var currentPrimaryKey = 0;
74
75 var columns = new List<ColumnDefinition>(columnNames.Length); 66 var columns = new List<ColumnDefinition>(columnNames.Length);
76 for (var i = 0; i < columnNames.Length; ++i) 67
68 foreach (var name in columnNames)
77 { 69 {
78 var name = columnNames[i]; 70 var column = customColumnsById[tuple.Id.Id + "/" + name];
71
79 var type = ColumnType.Unknown; 72 var type = ColumnType.Unknown;
80 73
81 if (columnTypes[i].StartsWith("s", StringComparison.OrdinalIgnoreCase)) 74 if (column.Type == IntermediateFieldType.String)
82 {
83 type = ColumnType.String;
84 }
85 else if (columnTypes[i].StartsWith("l", StringComparison.OrdinalIgnoreCase))
86 { 75 {
87 type = ColumnType.Localized; 76 type = column.Localizable ? ColumnType.Localized : ColumnType.String;
88 } 77 }
89 else if (columnTypes[i].StartsWith("i", StringComparison.OrdinalIgnoreCase)) 78 else if (column.Type == IntermediateFieldType.Number)
90 { 79 {
91 type = ColumnType.Number; 80 type = ColumnType.Number;
92 } 81 }
93 else if (columnTypes[i].StartsWith("v", StringComparison.OrdinalIgnoreCase)) 82 else if (column.Type == IntermediateFieldType.Path)
94 { 83 {
95 type = ColumnType.Object; 84 type = ColumnType.Object;
96 } 85 }
97 86
98 var nullable = columnTypes[i].Substring(0, 1) == columnTypes[i].Substring(0, 1).ToUpperInvariant();
99 var length = Convert.ToInt32(columnTypes[i].Substring(1), CultureInfo.InvariantCulture);
100
101 var primaryKey = false;
102 if (currentPrimaryKey < primaryKeys.Length && primaryKeys[currentPrimaryKey] == columnNames[i])
103 {
104 primaryKey = true;
105 currentPrimaryKey++;
106 }
107
108 var minValue = String.IsNullOrEmpty(minValues?[i]) ? (int?)null : Convert.ToInt32(minValues[i], CultureInfo.InvariantCulture);
109 var maxValue = String.IsNullOrEmpty(maxValues?[i]) ? (int?)null : Convert.ToInt32(maxValues[i], CultureInfo.InvariantCulture);
110 var keyColumn = String.IsNullOrEmpty(keyColumns?[i]) ? (int?)null : Convert.ToInt32(keyColumns[i], CultureInfo.InvariantCulture);
111
112 var category = ColumnCategory.Unknown; 87 var category = ColumnCategory.Unknown;
113 if (null != categories && null != categories[i] && 0 < categories[i].Length) 88 switch (column.Category)
114 { 89 {
115 switch (categories[i]) 90 case "Text":
116 { 91 category = ColumnCategory.Text;
117 case "Text": 92 break;
118 category = ColumnCategory.Text; 93 case "UpperCase":
119 break; 94 category = ColumnCategory.UpperCase;
120 case "UpperCase": 95 break;
121 category = ColumnCategory.UpperCase; 96 case "LowerCase":
122 break; 97 category = ColumnCategory.LowerCase;
123 case "LowerCase": 98 break;
124 category = ColumnCategory.LowerCase; 99 case "Integer":
125 break; 100 category = ColumnCategory.Integer;
126 case "Integer": 101 break;
127 category = ColumnCategory.Integer; 102 case "DoubleInteger":
128 break; 103 category = ColumnCategory.DoubleInteger;
129 case "DoubleInteger": 104 break;
130 category = ColumnCategory.DoubleInteger; 105 case "TimeDate":
131 break; 106 category = ColumnCategory.TimeDate;
132 case "TimeDate": 107 break;
133 category = ColumnCategory.TimeDate; 108 case "Identifier":
134 break; 109 category = ColumnCategory.Identifier;
135 case "Identifier": 110 break;
136 category = ColumnCategory.Identifier; 111 case "Property":
137 break; 112 category = ColumnCategory.Property;
138 case "Property": 113 break;
139 category = ColumnCategory.Property; 114 case "Filename":
140 break; 115 category = ColumnCategory.Filename;
141 case "Filename": 116 break;
142 category = ColumnCategory.Filename; 117 case "WildCardFilename":
143 break; 118 category = ColumnCategory.WildCardFilename;
144 case "WildCardFilename": 119 break;
145 category = ColumnCategory.WildCardFilename; 120 case "Path":
146 break; 121 category = ColumnCategory.Path;
147 case "Path": 122 break;
148 category = ColumnCategory.Path; 123 case "Paths":
149 break; 124 category = ColumnCategory.Paths;
150 case "Paths": 125 break;
151 category = ColumnCategory.Paths; 126 case "AnyPath":
152 break; 127 category = ColumnCategory.AnyPath;
153 case "AnyPath": 128 break;
154 category = ColumnCategory.AnyPath; 129 case "DefaultDir":
155 break; 130 category = ColumnCategory.DefaultDir;
156 case "DefaultDir": 131 break;
157 category = ColumnCategory.DefaultDir; 132 case "RegPath":
158 break; 133 category = ColumnCategory.RegPath;
159 case "RegPath": 134 break;
160 category = ColumnCategory.RegPath; 135 case "Formatted":
161 break; 136 category = ColumnCategory.Formatted;
162 case "Formatted": 137 break;
163 category = ColumnCategory.Formatted; 138 case "FormattedSddl":
164 break; 139 category = ColumnCategory.FormattedSDDLText;
165 case "FormattedSddl": 140 break;
166 category = ColumnCategory.FormattedSDDLText; 141 case "Template":
167 break; 142 category = ColumnCategory.Template;
168 case "Template": 143 break;
169 category = ColumnCategory.Template; 144 case "Condition":
170 break; 145 category = ColumnCategory.Condition;
171 case "Condition": 146 break;
172 category = ColumnCategory.Condition; 147 case "Guid":
173 break; 148 category = ColumnCategory.Guid;
174 case "Guid": 149 break;
175 category = ColumnCategory.Guid; 150 case "Version":
176 break; 151 category = ColumnCategory.Version;
177 case "Version": 152 break;
178 category = ColumnCategory.Version; 153 case "Language":
179 break; 154 category = ColumnCategory.Language;
180 case "Language": 155 break;
181 category = ColumnCategory.Language; 156 case "Binary":
182 break; 157 category = ColumnCategory.Binary;
183 case "Binary": 158 break;
184 category = ColumnCategory.Binary; 159 case "CustomSource":
185 break; 160 category = ColumnCategory.CustomSource;
186 case "CustomSource": 161 break;
187 category = ColumnCategory.CustomSource; 162 case "Cabinet":
188 break; 163 category = ColumnCategory.Cabinet;
189 case "Cabinet": 164 break;
190 category = ColumnCategory.Cabinet; 165 case "Shortcut":
191 break; 166 category = ColumnCategory.Shortcut;
192 case "Shortcut": 167 break;
193 category = ColumnCategory.Shortcut; 168 default:
194 break; 169 break;
195 default:
196 break;
197 }
198 } 170 }
199 171
200 var keyTable = keyTables?[i];
201 var setValue = sets?[i];
202 var description = descriptions?[i];
203 var modString = modularizations?[i];
204 var modularization = ColumnModularizeType.None; 172 var modularization = ColumnModularizeType.None;
205 173
206 switch (modString) 174 switch (column.Modularize)
207 { 175 {
208 case null: 176 case null:
209 case "None": 177 case WixCustomTableColumnModularizeType.None:
210 modularization = ColumnModularizeType.None; 178 modularization = ColumnModularizeType.None;
211 break; 179 break;
212 case "Column": 180 case WixCustomTableColumnModularizeType.Column:
213 modularization = ColumnModularizeType.Column; 181 modularization = ColumnModularizeType.Column;
214 break; 182 break;
215 case "Property": 183 case WixCustomTableColumnModularizeType.CompanionFile:
216 modularization = ColumnModularizeType.Property; 184 modularization = ColumnModularizeType.CompanionFile;
217 break; 185 break;
218 case "Condition": 186 case WixCustomTableColumnModularizeType.Condition:
219 modularization = ColumnModularizeType.Condition; 187 modularization = ColumnModularizeType.Condition;
220 break; 188 break;
221 case "CompanionFile": 189 case WixCustomTableColumnModularizeType.ControlEventArgument:
222 modularization = ColumnModularizeType.CompanionFile; 190 modularization = ColumnModularizeType.ControlEventArgument;
191 break;
192 case WixCustomTableColumnModularizeType.ControlText:
193 modularization = ColumnModularizeType.ControlText;
194 break;
195 case WixCustomTableColumnModularizeType.Icon:
196 modularization = ColumnModularizeType.Icon;
197 break;
198 case WixCustomTableColumnModularizeType.Property:
199 modularization = ColumnModularizeType.Property;
223 break; 200 break;
224 case "SemicolonDelimited": 201 case WixCustomTableColumnModularizeType.SemicolonDelimited:
225 modularization = ColumnModularizeType.SemicolonDelimited; 202 modularization = ColumnModularizeType.SemicolonDelimited;
226 break; 203 break;
227 } 204 }
228 205
229 var columnDefinition = new ColumnDefinition(name, type, length, primaryKey, nullable, category, minValue, maxValue, keyTable, keyColumn, setValue, description, modularization, ColumnType.Localized == type, true); 206 var columnDefinition = new ColumnDefinition(name, type, column.Width, column.PrimaryKey, column.Nullable, category, column.MinValue, column.MaxValue, column.KeyTable, column.KeyColumn, column.Set, column.Description, modularization, ColumnType.Localized == type, useCData: true, column.Unreal);
230 columns.Add(columnDefinition); 207 columns.Add(columnDefinition);
231 } 208 }
232 209