main
cs 520 lines 24.4 KB
Raw
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.Core
4 {
5 using System;
6 using System.Collections.Generic;
7 using System.Linq;
8 using System.Xml.Linq;
9 using WixToolset.Data;
10 using WixToolset.Data.Symbols;
11
12 /// <summary>
13 /// Compiler of the WiX toolset.
14 /// </summary>
15 internal partial class Compiler : ICompiler
16 {
17 /// <summary>
18 /// Parses a custom table element.
19 /// </summary>
20 /// <param name="node">Element to parse.</param>
21 /// <remarks>not cleaned</remarks>
22 private void ParseCustomTableElement(XElement node)
23 {
24 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
25 string tableId = null;
26 var unreal = false;
27 var columns = new List<WixCustomTableColumnSymbol>();
28 var foundColumns = false;
29
30 foreach (var attrib in node.Attributes())
31 {
32 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
33 {
34 switch (attrib.Name.LocalName)
35 {
36 case "Id":
37 tableId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
38 break;
39 case "Unreal":
40 unreal = YesNoType.Yes == this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
41 break;
42 default:
43 this.Core.UnexpectedAttribute(node, attrib);
44 break;
45 }
46 }
47 else
48 {
49 this.Core.ParseExtensionAttribute(node, attrib);
50 }
51 }
52
53 if (null == tableId)
54 {
55 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
56 }
57 else if (31 < tableId.Length)
58 {
59 this.Core.Write(ErrorMessages.CustomTableNameTooLong(sourceLineNumbers, node.Name.LocalName, "Id", tableId));
60 }
61
62 foreach (var child in node.Elements())
63 {
64 if (CompilerCore.WixNamespace == child.Name.Namespace)
65 {
66 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
67 switch (child.Name.LocalName)
68 {
69 case "Column":
70 foundColumns = true;
71
72 var column = this.ParseColumnElement(child, childSourceLineNumbers, tableId);
73 if (column != null)
74 {
75 columns.Add(column);
76 }
77 break;
78 case "Row":
79 this.ParseRowElement(child, childSourceLineNumbers, tableId);
80 break;
81 default:
82 this.Core.UnexpectedElement(node, child);
83 break;
84 }
85 }
86 else
87 {
88 this.Core.ParseExtensionElement(node, child);
89 }
90 }
91
92 if (columns.Count > 0)
93 {
94 if (!columns.Where(c => c.PrimaryKey).Any())
95 {
96 this.Core.Write(ErrorMessages.CustomTableMissingPrimaryKey(sourceLineNumbers));
97 }
98
99 if (!this.Core.EncounteredError)
100 {
101 var columnNames = String.Join(new string(WixCustomTableSymbol.ColumnNamesSeparator, 1), columns.Select(c => c.Name));
102
103 this.Core.AddSymbol(new WixCustomTableSymbol(sourceLineNumbers, new Identifier(AccessModifier.Global, tableId))
104 {
105 ColumnNames = columnNames,
106 Unreal = unreal,
107 });
108 }
109 else if (!foundColumns)
110 {
111 this.Core.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, node.Name.LocalName, "Column"));
112 }
113 }
114 }
115
116 /// <summary>
117 /// Parses a CustomTableRef element.
118 /// </summary>
119 /// <param name="node">Element to parse.</param>
120 private void ParseCustomTableRefElement(XElement node)
121 {
122 var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node);
123 string tableId = null;
124
125 foreach (var attrib in node.Attributes())
126 {
127 if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace)
128 {
129 switch (attrib.Name.LocalName)
130 {
131 case "Id":
132 tableId = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib);
133 this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.WixCustomTable, tableId);
134 this.Core.EnsureTable(sourceLineNumbers, tableId);
135 break;
136 default:
137 this.Core.UnexpectedAttribute(node, attrib);
138 break;
139 }
140 }
141 else
142 {
143 this.Core.ParseExtensionAttribute(node, attrib);
144 }
145 }
146
147 if (null == tableId)
148 {
149 this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id"));
150 }
151
152 foreach (var child in node.Elements())
153 {
154 if (CompilerCore.WixNamespace == child.Name.Namespace)
155 {
156 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
157 switch (child.Name.LocalName)
158 {
159 case "Row":
160 this.ParseRowElement(child, childSourceLineNumbers, tableId);
161 break;
162 default:
163 this.Core.UnexpectedElement(node, child);
164 break;
165 }
166 }
167 else
168 {
169 this.Core.ParseExtensionElement(node, child);
170 }
171 }
172 }
173
174 /// <summary>
175 /// Parses a Column element.
176 /// </summary>
177 /// <param name="child">Element to parse.</param>
178 /// <param name="childSourceLineNumbers">Element's SourceLineNumbers.</param>
179 /// <param name="tableId">Table Id.</param>
180 private WixCustomTableColumnSymbol ParseColumnElement(XElement child, SourceLineNumber childSourceLineNumbers, string tableId)
181 {
182 string columnName = null;
183 IntermediateFieldType? columnType = null;
184 var description = String.Empty;
185 int? keyColumn = null;
186 var keyTable = String.Empty;
187 var localizable = false;
188 long? maxValue = null;
189 long? minValue = null;
190 WixCustomTableColumnCategoryType? category = null;
191 var modularization = WixCustomTableColumnModularizeType.None;
192 var nullable = false;
193 var primaryKey = false;
194 var setValues = String.Empty;
195 var columnUnreal = false;
196 var width = 0;
197
198 foreach (var childAttrib in child.Attributes())
199 {
200 switch (childAttrib.Name.LocalName)
201 {
202 case "Id":
203 columnName = this.Core.GetAttributeIdentifierValue(childSourceLineNumbers, childAttrib);
204 break;
205 case "Category":
206 var categoryValue = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib);
207 switch (categoryValue)
208 {
209 case "text":
210 category = WixCustomTableColumnCategoryType.Text;
211 break;
212 case "upperCase":
213 category = WixCustomTableColumnCategoryType.UpperCase;
214 break;
215 case "lowerCase":
216 category = WixCustomTableColumnCategoryType.LowerCase;
217 break;
218 case "integer":
219 category = WixCustomTableColumnCategoryType.Integer;
220 break;
221 case "doubleInteger":
222 category = WixCustomTableColumnCategoryType.DoubleInteger;
223 break;
224 case "timeDate":
225 category = WixCustomTableColumnCategoryType.TimeDate;
226 break;
227 case "identifier":
228 category = WixCustomTableColumnCategoryType.Identifier;
229 break;
230 case "property":
231 category = WixCustomTableColumnCategoryType.Property;
232 break;
233 case "filename":
234 category = WixCustomTableColumnCategoryType.Filename;
235 break;
236 case "wildCardFilename":
237 category = WixCustomTableColumnCategoryType.WildCardFilename;
238 break;
239 case "path":
240 category = WixCustomTableColumnCategoryType.Path;
241 break;
242 case "paths":
243 category = WixCustomTableColumnCategoryType.Paths;
244 break;
245 case "anyPath":
246 category = WixCustomTableColumnCategoryType.AnyPath;
247 break;
248 case "defaultDir":
249 category = WixCustomTableColumnCategoryType.DefaultDir;
250 break;
251 case "regPath":
252 category = WixCustomTableColumnCategoryType.RegPath;
253 break;
254 case "formatted":
255 category = WixCustomTableColumnCategoryType.Formatted;
256 break;
257 case "formattedSddl":
258 category = WixCustomTableColumnCategoryType.FormattedSddl;
259 break;
260 case "template":
261 category = WixCustomTableColumnCategoryType.Template;
262 break;
263 case "condition":
264 category = WixCustomTableColumnCategoryType.Condition;
265 break;
266 case "guid":
267 category = WixCustomTableColumnCategoryType.Guid;
268 break;
269 case "version":
270 category = WixCustomTableColumnCategoryType.Version;
271 break;
272 case "language":
273 category = WixCustomTableColumnCategoryType.Language;
274 break;
275 case "binary":
276 category = WixCustomTableColumnCategoryType.Binary;
277 break;
278 case "customSource":
279 category = WixCustomTableColumnCategoryType.CustomSource;
280 break;
281 case "cabinet":
282 category = WixCustomTableColumnCategoryType.Cabinet;
283 break;
284 case "shortcut":
285 category = WixCustomTableColumnCategoryType.Shortcut;
286 break;
287 case "":
288 break;
289 default:
290 this.Core.Write(ErrorMessages.IllegalAttributeValue(childSourceLineNumbers, child.Name.LocalName, "Category", categoryValue,
291 "text", "upperCase", "lowerCase", "integer", "doubleInteger", "timeDate", "identifier", "property", "filename",
292 "wildCardFilename", "path", "paths", "anyPath", "defaultDir", "regPath", "formatted", "formattedSddl", "template",
293 "condition", "guid", "version", "language", "binary", "customSource", "cabinet", "shortcut"));
294 columnType = IntermediateFieldType.String; // set a value to prevent expected attribute error below.
295 break;
296 }
297 break;
298 case "Description":
299 description = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib);
300 break;
301 case "KeyColumn":
302 keyColumn = this.Core.GetAttributeIntegerValue(childSourceLineNumbers, childAttrib, 1, 32);
303 break;
304 case "KeyTable":
305 keyTable = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib);
306 break;
307 case "Localizable":
308 localizable = YesNoType.Yes == this.Core.GetAttributeYesNoValue(childSourceLineNumbers, childAttrib);
309 break;
310 case "MaxValue":
311 maxValue = this.Core.GetAttributeLongValue(childSourceLineNumbers, childAttrib, Int32.MinValue + 1, Int32.MaxValue);
312 break;
313 case "MinValue":
314 minValue = this.Core.GetAttributeLongValue(childSourceLineNumbers, childAttrib, Int32.MinValue + 1, Int32.MaxValue);
315 break;
316 case "Modularize":
317 var modularizeValue = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib);
318 switch (modularizeValue)
319 {
320 case "column":
321 modularization = WixCustomTableColumnModularizeType.Column;
322 break;
323 case "companionFile":
324 modularization = WixCustomTableColumnModularizeType.CompanionFile;
325 break;
326 case "condition":
327 modularization = WixCustomTableColumnModularizeType.Condition;
328 break;
329 case "controlEventArgument":
330 modularization = WixCustomTableColumnModularizeType.ControlEventArgument;
331 break;
332 case "controlText":
333 modularization = WixCustomTableColumnModularizeType.ControlText;
334 break;
335 case "icon":
336 modularization = WixCustomTableColumnModularizeType.Icon;
337 break;
338 case "none":
339 modularization = WixCustomTableColumnModularizeType.None;
340 break;
341 case "property":
342 modularization = WixCustomTableColumnModularizeType.Property;
343 break;
344 case "semicolonDelimited":
345 modularization = WixCustomTableColumnModularizeType.SemicolonDelimited;
346 break;
347 case "":
348 break;
349 default:
350 this.Core.Write(ErrorMessages.IllegalAttributeValue(childSourceLineNumbers, child.Name.LocalName, "Modularize", modularizeValue, "column", "companionFile", "condition", "controlEventArgument", "controlText", "icon", "property", "semicolonDelimited"));
351 columnType = IntermediateFieldType.String; // set a value to prevent expected attribute error below.
352 break;
353 }
354 break;
355 case "Nullable":
356 nullable = YesNoType.Yes == this.Core.GetAttributeYesNoValue(childSourceLineNumbers, childAttrib);
357 break;
358 case "PrimaryKey":
359 primaryKey = YesNoType.Yes == this.Core.GetAttributeYesNoValue(childSourceLineNumbers, childAttrib);
360 break;
361 case "Set":
362 setValues = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib);
363 break;
364 case "Type":
365 var typeValue = this.Core.GetAttributeValue(childSourceLineNumbers, childAttrib);
366 switch (typeValue)
367 {
368 case "binary":
369 columnType = IntermediateFieldType.Path;
370 break;
371 case "int":
372 columnType = IntermediateFieldType.Number;
373 break;
374 case "string":
375 columnType = IntermediateFieldType.String;
376 break;
377 case "":
378 break;
379 default:
380 this.Core.Write(ErrorMessages.IllegalAttributeValue(childSourceLineNumbers, child.Name.LocalName, "Type", typeValue, "binary", "int", "string"));
381 columnType = IntermediateFieldType.String; // set a value to prevent expected attribute error below.
382 break;
383 }
384 break;
385 case "Width":
386 width = this.Core.GetAttributeIntegerValue(childSourceLineNumbers, childAttrib, 0, Int32.MaxValue);
387 break;
388 case "Unreal":
389 columnUnreal = YesNoType.Yes == this.Core.GetAttributeYesNoValue(childSourceLineNumbers, childAttrib);
390 break;
391 default:
392 this.Core.UnexpectedAttribute(child, childAttrib);
393 break;
394 }
395 }
396
397 if (null == columnName)
398 {
399 this.Core.Write(ErrorMessages.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Id"));
400 }
401
402 if (!columnType.HasValue)
403 {
404 this.Core.Write(ErrorMessages.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Type"));
405 }
406 else if (columnType == IntermediateFieldType.Number)
407 {
408 if (2 != width && 4 != width)
409 {
410 this.Core.Write(ErrorMessages.CustomTableIllegalColumnWidth(childSourceLineNumbers, child.Name.LocalName, "Width", width));
411 }
412 }
413 else if (columnType == IntermediateFieldType.Path)
414 {
415 if (!category.HasValue)
416 {
417 category = WixCustomTableColumnCategoryType.Binary;
418 }
419 else if (category != WixCustomTableColumnCategoryType.Binary)
420 {
421 this.Core.Write(ErrorMessages.ExpectedBinaryCategory(childSourceLineNumbers));
422 }
423 }
424
425 this.Core.ParseForExtensionElements(child);
426
427 if (this.Core.EncounteredError)
428 {
429 return null;
430 }
431
432 var attributes = primaryKey ? WixCustomTableColumnSymbolAttributes.PrimaryKey : WixCustomTableColumnSymbolAttributes.None;
433 attributes |= localizable ? WixCustomTableColumnSymbolAttributes.Localizable : WixCustomTableColumnSymbolAttributes.None;
434 attributes |= nullable ? WixCustomTableColumnSymbolAttributes.Nullable : WixCustomTableColumnSymbolAttributes.None;
435 attributes |= columnUnreal ? WixCustomTableColumnSymbolAttributes.Unreal : WixCustomTableColumnSymbolAttributes.None;
436
437 var column = this.Core.AddSymbol(new WixCustomTableColumnSymbol(childSourceLineNumbers, new Identifier(AccessModifier.Section, tableId, columnName))
438 {
439 TableRef = tableId,
440 Name = columnName,
441 Type = columnType.Value,
442 Attributes = attributes,
443 Width = width,
444 Category = category,
445 Description = description,
446 KeyColumn = keyColumn,
447 KeyTable = keyTable,
448 MaxValue = maxValue,
449 MinValue = minValue,
450 Modularize = modularization,
451 Set = setValues,
452 });
453 return column;
454 }
455
456 /// <summary>
457 /// Parses a Row element.
458 /// </summary>
459 /// <param name="node">Element to parse.</param>
460 /// <param name="sourceLineNumbers">Element's SourceLineNumbers.</param>
461 /// <param name="tableId">Table Id.</param>
462 private void ParseRowElement(XElement node, SourceLineNumber sourceLineNumbers, string tableId)
463 {
464 var rowId = Guid.NewGuid().ToString("N").ToUpperInvariant();
465
466 foreach (var attrib in node.Attributes())
467 {
468 this.Core.ParseExtensionAttribute(node, attrib);
469 }
470
471 foreach (var child in node.Elements())
472 {
473 var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
474 switch (child.Name.LocalName)
475 {
476 case "Data":
477 string columnName = null;
478 string data = null;
479 foreach (var attrib in child.Attributes())
480 {
481 switch (attrib.Name.LocalName)
482 {
483 case "Column":
484 columnName = this.Core.GetAttributeValue(childSourceLineNumbers, attrib);
485 break;
486 case "Value":
487 data = this.Core.GetAttributeValue(childSourceLineNumbers, attrib);
488 break;
489 default:
490 this.Core.ParseExtensionAttribute(child, attrib);
491 break;
492 }
493 }
494
495 this.Core.InnerTextDisallowed(node, "Value");
496
497 if (null == columnName)
498 {
499 this.Core.Write(ErrorMessages.ExpectedAttribute(childSourceLineNumbers, child.Name.LocalName, "Column"));
500 }
501
502 if (!this.Core.EncounteredError)
503 {
504 this.Core.AddSymbol(new WixCustomTableCellSymbol(childSourceLineNumbers, new Identifier(AccessModifier.Section, tableId, rowId, columnName))
505 {
506 RowId = rowId,
507 ColumnRef = columnName,
508 TableRef = tableId,
509 Data = data
510 });
511 }
512 break;
513 default:
514 this.Core.UnexpectedElement(node, child);
515 break;
516 }
517 }
518 }
519 }
520 }