aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Data/WindowsInstaller/ColumnDefinition.cs
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2017-12-07 14:17:39 -0800
committerRob Mensching <rob@firegiant.com>2017-12-07 14:17:39 -0800
commit221da62c05ef2b515eb507c77655514cd0ec32a4 (patch)
treefabec5b8ac871f17de6fe0aad3e6188b9af42bfb /src/WixToolset.Data/WindowsInstaller/ColumnDefinition.cs
parentca376995792d2e2a1a7f39760989496702a8f603 (diff)
downloadwix-221da62c05ef2b515eb507c77655514cd0ec32a4.tar.gz
wix-221da62c05ef2b515eb507c77655514cd0ec32a4.tar.bz2
wix-221da62c05ef2b515eb507c77655514cd0ec32a4.zip
Reintegrate MSI constructs into WxToolset.Data.WindowsInstaller namespace
Diffstat (limited to 'src/WixToolset.Data/WindowsInstaller/ColumnDefinition.cs')
-rw-r--r--src/WixToolset.Data/WindowsInstaller/ColumnDefinition.cs685
1 files changed, 685 insertions, 0 deletions
diff --git a/src/WixToolset.Data/WindowsInstaller/ColumnDefinition.cs b/src/WixToolset.Data/WindowsInstaller/ColumnDefinition.cs
new file mode 100644
index 00000000..b6d4f29f
--- /dev/null
+++ b/src/WixToolset.Data/WindowsInstaller/ColumnDefinition.cs
@@ -0,0 +1,685 @@
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 WixToolset.Data.WindowsInstaller
4{
5 using System;
6 using System.Globalization;
7 using System.Xml;
8
9 /// <summary>
10 /// Definition of a table's column.
11 /// </summary>
12 public sealed class ColumnDefinition : IComparable<ColumnDefinition>
13 {
14 /// <summary>
15 /// Creates a new column definition.
16 /// </summary>
17 /// <param name="name">Name of column.</param>
18 /// <param name="type">Type of column</param>
19 /// <param name="length">Length of column.</param>
20 /// <param name="primaryKey">If column is primary key.</param>
21 /// <param name="nullable">If column is nullable.</param>
22 /// <param name="category">Validation category for column.</param>
23 /// <param name="minValue">Optional minimum value for the column.</param>
24 /// <param name="maxValue">Optional maximum value for the colum.</param>
25 /// <param name="keyTable">Optional name of table for foreign key.</param>
26 /// <param name="keyColumn">Optional name of column for foreign key.</param>
27 /// <param name="possibilities">Set of possible values for column.</param>
28 /// <param name="description">Description of column in vaidation table.</param>
29 /// <param name="modularizeType">Type of modularization for column</param>
30 /// <param name="forceLocalizable">If the column is localizable.</param>
31 /// <param name="useCData">If whitespace should be preserved in a CDATA node.</param>
32 public ColumnDefinition(string name, ColumnType type, int length, bool primaryKey, bool nullable, ColumnCategory category, long? minValue = null, long? maxValue = null, string keyTable = null, int? keyColumn = null, string possibilities = null, string description = null, ColumnModularizeType? modularizeType = null, bool forceLocalizable = false, bool useCData = false)
33 {
34 this.Name = name;
35 this.Type = type;
36 this.Length = length;
37 this.PrimaryKey = primaryKey;
38 this.Nullable = nullable;
39 this.ModularizeType = CalculateModularizationType(modularizeType, category);
40 this.IsLocalizable = forceLocalizable || ColumnType.Localized == type;
41 this.MinValue = minValue;
42 this.MaxValue = maxValue;
43 this.KeyTable = keyTable;
44 this.KeyColumn = keyColumn;
45 this.Category = category;
46 this.Possibilities = possibilities;
47 this.Description = description;
48 this.UseCData = useCData;
49 }
50
51 /// <summary>
52 /// Gets whether this column was added via a transform.
53 /// </summary>
54 /// <value>Whether this column was added via a transform.</value>
55 public bool Added { get; set; }
56
57 /// <summary>
58 /// Gets the name of the column.
59 /// </summary>
60 /// <value>Name of column.</value>
61 public string Name { get; }
62
63 /// <summary>
64 /// Gets the type of the column.
65 /// </summary>
66 /// <value>Type of column.</value>
67 public ColumnType Type { get; }
68
69 /// <summary>
70 /// Gets the length of the column.
71 /// </summary>
72 /// <value>Length of column.</value>
73 public int Length { get; }
74
75 /// <summary>
76 /// Gets if the column is a primary key.
77 /// </summary>
78 /// <value>true if column is primary key.</value>
79 public bool PrimaryKey { get; }
80
81 /// <summary>
82 /// Gets if the column is nullable.
83 /// </summary>
84 /// <value>true if column is nullable.</value>
85 public bool Nullable { get; }
86
87 /// <summary>
88 /// Gets the type of modularization for this column.
89 /// </summary>
90 /// <value>Column's modularization type.</value>
91 public ColumnModularizeType ModularizeType { get; }
92
93 /// <summary>
94 /// Gets if the column is localizable. Can be because the type is localizable, or because the column
95 /// was explicitly set to be so.
96 /// </summary>
97 /// <value>true if column is localizable.</value>
98 public bool IsLocalizable { get; }
99
100 /// <summary>
101 /// Gets the minimum value for the column.
102 /// </summary>
103 /// <value>Minimum value for the column.</value>
104 public long? MinValue { get; }
105
106 /// <summary>
107 /// Gets the maximum value for the column.
108 /// </summary>
109 /// <value>Maximum value for the column.</value>
110 public long? MaxValue { get; }
111
112 /// <summary>
113 /// Gets the table that has the foreign key for this column
114 /// </summary>
115 /// <value>Foreign key table name.</value>
116 public string KeyTable { get; }
117
118 /// <summary>
119 /// Gets the foreign key column that this column refers to.
120 /// </summary>
121 /// <value>Foreign key column.</value>
122 public int? KeyColumn { get; }
123
124 /// <summary>
125 /// Gets the validation category for this column.
126 /// </summary>
127 /// <value>Validation category.</value>
128 public ColumnCategory Category { get; }
129
130 /// <summary>
131 /// Gets the set of possibilities for this column.
132 /// </summary>
133 /// <value>Set of possibilities for this column.</value>
134 public string Possibilities { get; }
135
136 /// <summary>
137 /// Gets the description for this column.
138 /// </summary>
139 /// <value>Description of column.</value>
140 public string Description { get; }
141
142 /// <summary>
143 /// Gets if whitespace should be preserved in a CDATA node.
144 /// </summary>
145 /// <value>true if whitespace should be preserved in a CDATA node.</value>
146 public bool UseCData { get; }
147
148 /// <summary>
149 /// Parses a column definition in a table definition.
150 /// </summary>
151 /// <param name="reader">Reader to get data from.</param>
152 /// <returns>The ColumnDefintion represented by the Xml.</returns>
153 internal static ColumnDefinition Read(XmlReader reader)
154 {
155 if (!reader.LocalName.Equals("columnDefinition"))
156 {
157 throw new XmlException();
158 }
159
160 bool added = false;
161 ColumnCategory category = ColumnCategory.Unknown;
162 string description = null;
163 bool empty = reader.IsEmptyElement;
164 int? keyColumn = null;
165 string keyTable = null;
166 int length = -1;
167 bool localizable = false;
168 long? maxValue = null;
169 long? minValue = null;
170 var modularize = ColumnModularizeType.None;
171 string name = null;
172 bool nullable = false;
173 string possibilities = null;
174 bool primaryKey = false;
175 var type = ColumnType.Unknown;
176 bool useCData = false;
177
178 // parse the attributes
179 while (reader.MoveToNextAttribute())
180 {
181 switch (reader.LocalName)
182 {
183 case "added":
184 added = reader.Value.Equals("yes");
185 break;
186 case "category":
187 switch (reader.Value)
188 {
189 case "anyPath":
190 category = ColumnCategory.AnyPath;
191 break;
192 case "binary":
193 category = ColumnCategory.Binary;
194 break;
195 case "cabinet":
196 category = ColumnCategory.Cabinet;
197 break;
198 case "condition":
199 category = ColumnCategory.Condition;
200 break;
201 case "customSource":
202 category = ColumnCategory.CustomSource;
203 break;
204 case "defaultDir":
205 category = ColumnCategory.DefaultDir;
206 break;
207 case "doubleInteger":
208 category = ColumnCategory.DoubleInteger;
209 break;
210 case "filename":
211 category = ColumnCategory.Filename;
212 break;
213 case "formatted":
214 category = ColumnCategory.Formatted;
215 break;
216 case "formattedSddl":
217 category = ColumnCategory.FormattedSDDLText;
218 break;
219 case "guid":
220 category = ColumnCategory.Guid;
221 break;
222 case "identifier":
223 category = ColumnCategory.Identifier;
224 break;
225 case "integer":
226 category = ColumnCategory.Integer;
227 break;
228 case "language":
229 category = ColumnCategory.Language;
230 break;
231 case "lowerCase":
232 category = ColumnCategory.LowerCase;
233 break;
234 case "path":
235 category = ColumnCategory.Path;
236 break;
237 case "paths":
238 category = ColumnCategory.Paths;
239 break;
240 case "property":
241 category = ColumnCategory.Property;
242 break;
243 case "regPath":
244 category = ColumnCategory.RegPath;
245 break;
246 case "shortcut":
247 category = ColumnCategory.Shortcut;
248 break;
249 case "template":
250 category = ColumnCategory.Template;
251 break;
252 case "text":
253 category = ColumnCategory.Text;
254 break;
255 case "timeDate":
256 category = ColumnCategory.TimeDate;
257 break;
258 case "upperCase":
259 category = ColumnCategory.UpperCase;
260 break;
261 case "version":
262 category = ColumnCategory.Version;
263 break;
264 case "wildCardFilename":
265 category = ColumnCategory.WildCardFilename;
266 break;
267 default:
268 throw new InvalidOperationException();
269 }
270 break;
271 case "description":
272 description = reader.Value;
273 break;
274 case "keyColumn":
275 keyColumn = Convert.ToInt32(reader.Value, 10);
276 break;
277 case "keyTable":
278 keyTable = reader.Value;
279 break;
280 case "length":
281 length = Convert.ToInt32(reader.Value, 10);
282 break;
283 case "localizable":
284 localizable = reader.Value.Equals("yes");
285 break;
286 case "maxValue":
287 maxValue = Convert.ToInt32(reader.Value, 10);
288 break;
289 case "minValue":
290 minValue = Convert.ToInt32(reader.Value, 10);
291 break;
292 case "modularize":
293 switch (reader.Value)
294 {
295 case "column":
296 modularize = ColumnModularizeType.Column;
297 break;
298 case "companionFile":
299 modularize = ColumnModularizeType.CompanionFile;
300 break;
301 case "condition":
302 modularize = ColumnModularizeType.Condition;
303 break;
304 case "controlEventArgument":
305 modularize = ColumnModularizeType.ControlEventArgument;
306 break;
307 case "controlText":
308 modularize = ColumnModularizeType.ControlText;
309 break;
310 case "icon":
311 modularize = ColumnModularizeType.Icon;
312 break;
313 case "none":
314 modularize = ColumnModularizeType.None;
315 break;
316 case "property":
317 modularize = ColumnModularizeType.Property;
318 break;
319 case "semicolonDelimited":
320 modularize = ColumnModularizeType.SemicolonDelimited;
321 break;
322 default:
323 throw new XmlException();
324 }
325 break;
326 case "name":
327 switch (reader.Value)
328 {
329 case "CREATE":
330 case "DELETE":
331 case "DROP":
332 case "INSERT":
333 throw new XmlException();
334 default:
335 name = reader.Value;
336 break;
337 }
338 break;
339 case "nullable":
340 nullable = reader.Value.Equals("yes");
341 break;
342 case "primaryKey":
343 primaryKey = reader.Value.Equals("yes");
344 break;
345 case "set":
346 possibilities = reader.Value;
347 break;
348 case "type":
349 switch (reader.Value)
350 {
351 case "localized":
352 type = ColumnType.Localized;
353 break;
354 case "number":
355 type = ColumnType.Number;
356 break;
357 case "object":
358 type = ColumnType.Object;
359 break;
360 case "string":
361 type = ColumnType.String;
362 break;
363 case "preserved":
364 type = ColumnType.Preserved;
365 break;
366 default:
367 throw new XmlException();
368 }
369 break;
370 case "useCData":
371 useCData = reader.Value.Equals("yes");
372 break;
373 }
374 }
375
376 // parse the child elements (there should be none)
377 if (!empty)
378 {
379 bool done = false;
380
381 while (!done && reader.Read())
382 {
383 switch (reader.NodeType)
384 {
385 case XmlNodeType.Element:
386 throw new XmlException();
387 case XmlNodeType.EndElement:
388 done = true;
389 break;
390 }
391 }
392
393 if (!done)
394 {
395 throw new XmlException();
396 }
397 }
398
399 ColumnDefinition columnDefinition = new ColumnDefinition(name, type, length, primaryKey, nullable, category, minValue, maxValue, keyTable, keyColumn, possibilities, description, modularize, localizable, useCData);
400 columnDefinition.Added = added;
401
402 return columnDefinition;
403 }
404
405 /// <summary>
406 /// Persists a ColumnDefinition in an XML format.
407 /// </summary>
408 /// <param name="writer">XmlWriter where the Output should persist itself as XML.</param>
409 internal void Write(XmlWriter writer)
410 {
411 writer.WriteStartElement("columnDefinition", TableDefinitionCollection.XmlNamespaceUri);
412
413 writer.WriteAttributeString("name", this.Name);
414
415 switch (this.Type)
416 {
417 case ColumnType.Localized:
418 writer.WriteAttributeString("type", "localized");
419 break;
420 case ColumnType.Number:
421 writer.WriteAttributeString("type", "number");
422 break;
423 case ColumnType.Object:
424 writer.WriteAttributeString("type", "object");
425 break;
426 case ColumnType.String:
427 writer.WriteAttributeString("type", "string");
428 break;
429 case ColumnType.Preserved:
430 writer.WriteAttributeString("type", "preserved");
431 break;
432 }
433
434 writer.WriteAttributeString("length", this.Length.ToString(CultureInfo.InvariantCulture.NumberFormat));
435
436 if (this.PrimaryKey)
437 {
438 writer.WriteAttributeString("primaryKey", "yes");
439 }
440
441 if (this.Nullable)
442 {
443 writer.WriteAttributeString("nullable", "yes");
444 }
445
446 if (this.IsLocalizable)
447 {
448 writer.WriteAttributeString("localizable", "yes");
449 }
450
451 if (this.Added)
452 {
453 writer.WriteAttributeString("added", "yes");
454 }
455
456 switch (this.ModularizeType)
457 {
458 case ColumnModularizeType.Column:
459 writer.WriteAttributeString("modularize", "column");
460 break;
461 case ColumnModularizeType.CompanionFile:
462 writer.WriteAttributeString("modularize", "companionFile");
463 break;
464 case ColumnModularizeType.Condition:
465 writer.WriteAttributeString("modularize", "condition");
466 break;
467 case ColumnModularizeType.ControlEventArgument:
468 writer.WriteAttributeString("modularize", "controlEventArgument");
469 break;
470 case ColumnModularizeType.ControlText:
471 writer.WriteAttributeString("modularize", "controlText");
472 break;
473 case ColumnModularizeType.Icon:
474 writer.WriteAttributeString("modularize", "icon");
475 break;
476 case ColumnModularizeType.None:
477 // this is the default value
478 break;
479 case ColumnModularizeType.Property:
480 writer.WriteAttributeString("modularize", "property");
481 break;
482 case ColumnModularizeType.SemicolonDelimited:
483 writer.WriteAttributeString("modularize", "semicolonDelimited");
484 break;
485 }
486
487 if (this.MinValue.HasValue)
488 {
489 writer.WriteAttributeString("minValue", this.MinValue.Value.ToString(CultureInfo.InvariantCulture.NumberFormat));
490 }
491
492 if (this.MaxValue.HasValue)
493 {
494 writer.WriteAttributeString("maxValue", this.MaxValue.Value.ToString(CultureInfo.InvariantCulture.NumberFormat));
495 }
496
497 if (!String.IsNullOrEmpty(this.KeyTable))
498 {
499 writer.WriteAttributeString("keyTable", this.KeyTable);
500 }
501
502 if (this.KeyColumn.HasValue)
503 {
504 writer.WriteAttributeString("keyColumn", this.KeyColumn.HasValue.ToString(CultureInfo.InvariantCulture.NumberFormat));
505 }
506
507 switch (this.Category)
508 {
509 case ColumnCategory.AnyPath:
510 writer.WriteAttributeString("category", "anyPath");
511 break;
512 case ColumnCategory.Binary:
513 writer.WriteAttributeString("category", "binary");
514 break;
515 case ColumnCategory.Cabinet:
516 writer.WriteAttributeString("category", "cabinet");
517 break;
518 case ColumnCategory.Condition:
519 writer.WriteAttributeString("category", "condition");
520 break;
521 case ColumnCategory.CustomSource:
522 writer.WriteAttributeString("category", "customSource");
523 break;
524 case ColumnCategory.DefaultDir:
525 writer.WriteAttributeString("category", "defaultDir");
526 break;
527 case ColumnCategory.DoubleInteger:
528 writer.WriteAttributeString("category", "doubleInteger");
529 break;
530 case ColumnCategory.Filename:
531 writer.WriteAttributeString("category", "filename");
532 break;
533 case ColumnCategory.Formatted:
534 writer.WriteAttributeString("category", "formatted");
535 break;
536 case ColumnCategory.FormattedSDDLText:
537 writer.WriteAttributeString("category", "formattedSddl");
538 break;
539 case ColumnCategory.Guid:
540 writer.WriteAttributeString("category", "guid");
541 break;
542 case ColumnCategory.Identifier:
543 writer.WriteAttributeString("category", "identifier");
544 break;
545 case ColumnCategory.Integer:
546 writer.WriteAttributeString("category", "integer");
547 break;
548 case ColumnCategory.Language:
549 writer.WriteAttributeString("category", "language");
550 break;
551 case ColumnCategory.LowerCase:
552 writer.WriteAttributeString("category", "lowerCase");
553 break;
554 case ColumnCategory.Path:
555 writer.WriteAttributeString("category", "path");
556 break;
557 case ColumnCategory.Paths:
558 writer.WriteAttributeString("category", "paths");
559 break;
560 case ColumnCategory.Property:
561 writer.WriteAttributeString("category", "property");
562 break;
563 case ColumnCategory.RegPath:
564 writer.WriteAttributeString("category", "regPath");
565 break;
566 case ColumnCategory.Shortcut:
567 writer.WriteAttributeString("category", "shortcut");
568 break;
569 case ColumnCategory.Template:
570 writer.WriteAttributeString("category", "template");
571 break;
572 case ColumnCategory.Text:
573 writer.WriteAttributeString("category", "text");
574 break;
575 case ColumnCategory.TimeDate:
576 writer.WriteAttributeString("category", "timeDate");
577 break;
578 case ColumnCategory.UpperCase:
579 writer.WriteAttributeString("category", "upperCase");
580 break;
581 case ColumnCategory.Version:
582 writer.WriteAttributeString("category", "version");
583 break;
584 case ColumnCategory.WildCardFilename:
585 writer.WriteAttributeString("category", "wildCardFilename");
586 break;
587 }
588
589 if (!String.IsNullOrEmpty(this.Possibilities))
590 {
591 writer.WriteAttributeString("set", this.Possibilities);
592 }
593
594 if (!String.IsNullOrEmpty(this.Description))
595 {
596 writer.WriteAttributeString("description", this.Description);
597 }
598
599 if (this.UseCData)
600 {
601 writer.WriteAttributeString("useCData", "yes");
602 }
603
604 writer.WriteEndElement();
605 }
606
607 /// <summary>
608 /// Compare this column definition to another column definition.
609 /// </summary>
610 /// <remarks>
611 /// Only Windows Installer traits are compared, allowing for updates to WiX-specific table definitions.
612 /// </remarks>
613 /// <param name="other">The <see cref="ColumnDefinition"/> to compare with this one.</param>
614 /// <returns>0 if the columns' core propeties are the same; otherwise, non-0.</returns>
615 public int CompareTo(ColumnDefinition other)
616 {
617 // by definition, this object is greater than null
618 if (null == other)
619 {
620 return 1;
621 }
622
623 // compare column names
624 int ret = String.Compare(this.Name, other.Name, StringComparison.Ordinal);
625
626 // compare column types
627 if (0 == ret)
628 {
629 ret = this.Type == other.Type ? 0 : -1;
630
631 // compare column lengths
632 if (0 == ret)
633 {
634 ret = this.Length == other.Length ? 0 : -1;
635
636 // compare whether both are primary keys
637 if (0 == ret)
638 {
639 ret = this.PrimaryKey == other.PrimaryKey ? 0 : -1;
640
641 // compare nullability
642 if (0 == ret)
643 {
644 ret = this.Nullable == other.Nullable ? 0 : -1;
645 }
646 }
647 }
648 }
649
650 return ret;
651 }
652
653 private static ColumnModularizeType CalculateModularizationType(ColumnModularizeType? modularizeType, ColumnCategory category)
654 {
655 if (modularizeType.HasValue)
656 {
657 return modularizeType.Value;
658 }
659
660 switch (category)
661 {
662 case ColumnCategory.Identifier:
663 case ColumnCategory.CustomSource:
664 return ColumnModularizeType.Column;
665
666 case ColumnCategory.Condition:
667 return ColumnModularizeType.Condition;
668
669 case ColumnCategory.AnyPath:
670 case ColumnCategory.Formatted:
671 case ColumnCategory.FormattedSDDLText:
672 case ColumnCategory.Path:
673 case ColumnCategory.Paths:
674 case ColumnCategory.RegPath:
675 case ColumnCategory.Template:
676 return ColumnModularizeType.Property;
677
678 case ColumnCategory.Shortcut:
679 return ColumnModularizeType.Property;
680 }
681
682 return ColumnModularizeType.None;
683 }
684 }
685}