aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Data.WindowsInstaller/Table.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Data.WindowsInstaller/Table.cs')
-rw-r--r--src/WixToolset.Data.WindowsInstaller/Table.cs435
1 files changed, 0 insertions, 435 deletions
diff --git a/src/WixToolset.Data.WindowsInstaller/Table.cs b/src/WixToolset.Data.WindowsInstaller/Table.cs
deleted file mode 100644
index 4c0df0ad..00000000
--- a/src/WixToolset.Data.WindowsInstaller/Table.cs
+++ /dev/null
@@ -1,435 +0,0 @@
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
4{
5 using System;
6 using System.Collections.Generic;
7 using System.Diagnostics;
8 using System.Diagnostics.CodeAnalysis;
9 using System.Globalization;
10 using System.IO;
11 using System.Text;
12 using System.Xml;
13 using WixToolset.Data.Rows;
14
15 /// <summary>
16 /// Object that represents a table in a database.
17 /// </summary>
18 public sealed class Table
19 {
20 /// <summary>
21 /// Creates a table in a section.
22 /// </summary>
23 /// <param name="section">Section to add table to.</param>
24 /// <param name="tableDefinition">Definition of the table.</param>
25 public Table(TableDefinition tableDefinition)
26 {
27 this.Definition = tableDefinition;
28 this.Rows = new List<Row>();
29 }
30
31 /// <summary>
32 /// Gets the table definition.
33 /// </summary>
34 /// <value>Definition of the table.</value>
35 public TableDefinition Definition { get; private set; }
36
37 /// <summary>
38 /// Gets the name of the table.
39 /// </summary>
40 /// <value>Name of the table.</value>
41 public string Name
42 {
43 get { return this.Definition.Name; }
44 }
45
46 /// <summary>
47 /// Gets or sets the table transform operation.
48 /// </summary>
49 /// <value>The table transform operation.</value>
50 public TableOperation Operation { get; set; }
51
52 /// <summary>
53 /// Gets the rows contained in the table.
54 /// </summary>
55 /// <value>Rows contained in the table.</value>
56 public IList<Row> Rows { get; private set; }
57
58 /// <summary>
59 /// Creates a new row in the table.
60 /// </summary>
61 /// <param name="sourceLineNumbers">Original source lines for this row.</param>
62 /// <param name="add">Specifies whether to only create the row or add it to the table automatically.</param>
63 /// <returns>Row created in table.</returns>
64 public Row CreateRow(SourceLineNumber sourceLineNumbers, bool add = true)
65 {
66 Row row;
67
68 switch (this.Name)
69 {
70 case "BBControl":
71 row = new BBControlRow(sourceLineNumbers, this);
72 break;
73 case "WixBundlePackage":
74 row = new WixBundlePackageRow(sourceLineNumbers, this);
75 break;
76 case "WixBundleExePackage":
77 row = new WixBundleExePackageRow(sourceLineNumbers, this);
78 break;
79 case "WixBundleMsiPackage":
80 row = new WixBundleMsiPackageRow(sourceLineNumbers, this);
81 break;
82 case "WixBundleMspPackage":
83 row = new WixBundleMspPackageRow(sourceLineNumbers, this);
84 break;
85 case "WixBundleMsuPackage":
86 row = new WixBundleMsuPackageRow(sourceLineNumbers, this);
87 break;
88 case "Component":
89 row = new ComponentRow(sourceLineNumbers, this);
90 break;
91 case "WixBundleContainer":
92 row = new WixBundleContainerRow(sourceLineNumbers, this);
93 break;
94 case "Control":
95 row = new ControlRow(sourceLineNumbers, this);
96 break;
97 case "File":
98 row = new FileRow(sourceLineNumbers, this);
99 break;
100 case "WixBundleMsiFeature":
101 row = new WixBundleMsiFeatureRow(sourceLineNumbers, this);
102 break;
103 case "WixBundleMsiProperty":
104 row = new WixBundleMsiPropertyRow(sourceLineNumbers, this);
105 break;
106 case "Media":
107 row = new MediaRow(sourceLineNumbers, this);
108 break;
109 case "WixBundlePayload":
110 row = new WixBundlePayloadRow(sourceLineNumbers, this);
111 break;
112 case "Property":
113 row = new PropertyRow(sourceLineNumbers, this);
114 break;
115 case "WixRelatedBundle":
116 row = new WixRelatedBundleRow(sourceLineNumbers, this);
117 break;
118 case "WixBundleRelatedPackage":
119 row = new WixBundleRelatedPackageRow(sourceLineNumbers, this);
120 break;
121 case "WixBundleRollbackBoundary":
122 row = new WixBundleRollbackBoundaryRow(sourceLineNumbers, this);
123 break;
124 case "Upgrade":
125 row = new UpgradeRow(sourceLineNumbers, this);
126 break;
127 case "WixBundleVariable":
128 row = new WixBundleVariableRow(sourceLineNumbers, this);
129 break;
130 case "WixAction":
131 row = new WixActionRow(sourceLineNumbers, this);
132 break;
133 case "WixApprovedExeForElevation":
134 row = new WixApprovedExeForElevationRow(sourceLineNumbers, this);
135 break;
136 case "WixBundle":
137 row = new WixBundleRow(sourceLineNumbers, this);
138 break;
139 case "WixBundlePackageExitCode":
140 row = new WixBundlePackageExitCodeRow(sourceLineNumbers, this);
141 break;
142 case "WixBundlePatchTargetCode":
143 row = new WixBundlePatchTargetCodeRow(sourceLineNumbers, this);
144 break;
145 case "WixBundleSlipstreamMsp":
146 row = new WixBundleSlipstreamMspRow(sourceLineNumbers, this);
147 break;
148 case "WixBundleUpdate":
149 row = new WixBundleUpdateRow(sourceLineNumbers, this);
150 break;
151 case "WixBundleCatalog":
152 row = new WixBundleCatalogRow(sourceLineNumbers, this);
153 break;
154 case "WixChain":
155 row = new WixChainRow(sourceLineNumbers, this);
156 break;
157 case "WixChainItem":
158 row = new WixChainItemRow(sourceLineNumbers, this);
159 break;
160 case "WixBundlePackageCommandLine":
161 row = new WixBundlePackageCommandLineRow(sourceLineNumbers, this);
162 break;
163 case "WixComplexReference":
164 row = new WixComplexReferenceRow(sourceLineNumbers, this);
165 break;
166 case "WixDeltaPatchFile":
167 row = new WixDeltaPatchFileRow(sourceLineNumbers, this);
168 break;
169 case "WixDeltaPatchSymbolPaths":
170 row = new WixDeltaPatchSymbolPathsRow(sourceLineNumbers, this);
171 break;
172 case "WixFile":
173 row = new WixFileRow(sourceLineNumbers, this);
174 break;
175 case "WixGroup":
176 row = new WixGroupRow(sourceLineNumbers, this);
177 break;
178 case "WixMedia":
179 row = new WixMediaRow(sourceLineNumbers, this);
180 break;
181 case "WixMediaTemplate":
182 row = new WixMediaTemplateRow(sourceLineNumbers, this);
183 break;
184 case "WixMerge":
185 row = new WixMergeRow(sourceLineNumbers, this);
186 break;
187 case "WixPayloadProperties":
188 row = new WixPayloadPropertiesRow(sourceLineNumbers, this);
189 break;
190 case "WixProperty":
191 row = new WixPropertyRow(sourceLineNumbers, this);
192 break;
193 case "WixSimpleReference":
194 row = new WixSimpleReferenceRow(sourceLineNumbers, this);
195 break;
196 case "WixUpdateRegistration":
197 row = new WixUpdateRegistrationRow(sourceLineNumbers, this);
198 break;
199
200 default:
201 row = new Row(sourceLineNumbers, this);
202 break;
203 }
204
205 if (add)
206 {
207 this.Rows.Add(row);
208 }
209
210 return row;
211 }
212
213 /// <summary>
214 /// Parse a table from the xml.
215 /// </summary>
216 /// <param name="reader">XmlReader where the intermediate is persisted.</param>
217 /// <param name="section">Section to populate with persisted data.</param>
218 /// <param name="tableDefinitions">TableDefinitions to use in the intermediate.</param>
219 /// <returns>The parsed table.</returns>
220 internal static Table Read(XmlReader reader, TableDefinitionCollection tableDefinitions)
221 {
222 Debug.Assert("table" == reader.LocalName);
223
224 bool empty = reader.IsEmptyElement;
225 TableOperation operation = TableOperation.None;
226 string name = null;
227
228 while (reader.MoveToNextAttribute())
229 {
230 switch (reader.LocalName)
231 {
232 case "name":
233 name = reader.Value;
234 break;
235 case "op":
236 switch (reader.Value)
237 {
238 case "add":
239 operation = TableOperation.Add;
240 break;
241 case "drop":
242 operation = TableOperation.Drop;
243 break;
244 default:
245 throw new XmlException();
246 }
247 break;
248 }
249 }
250
251 if (null == name)
252 {
253 throw new XmlException();
254 }
255
256 TableDefinition tableDefinition = tableDefinitions[name];
257 Table table = new Table(tableDefinition);
258 table.Operation = operation;
259
260 if (!empty)
261 {
262 bool done = false;
263
264 // loop through all the rows in a table
265 while (!done && reader.Read())
266 {
267 switch (reader.NodeType)
268 {
269 case XmlNodeType.Element:
270 switch (reader.LocalName)
271 {
272 case "row":
273 Row.Read(reader, table);
274 break;
275 default:
276 throw new XmlException();
277 }
278 break;
279 case XmlNodeType.EndElement:
280 done = true;
281 break;
282 }
283 }
284
285 if (!done)
286 {
287 throw new XmlException();
288 }
289 }
290
291 return table;
292 }
293
294 /// <summary>
295 /// Modularize the table.
296 /// </summary>
297 /// <param name="modularizationGuid">String containing the GUID of the Merge Module, if appropriate.</param>
298 /// <param name="suppressModularizationIdentifiers">Optional collection of identifiers that should not be modularized.</param>
299 public void Modularize(string modularizationGuid, ISet<string> suppressModularizationIdentifiers)
300 {
301 List<int> modularizedColumns = new List<int>();
302
303 // find the modularized columns
304 for (int i = 0; i < this.Definition.Columns.Count; i++)
305 {
306 if (ColumnModularizeType.None != this.Definition.Columns[i].ModularizeType)
307 {
308 modularizedColumns.Add(i);
309 }
310 }
311
312 if (0 < modularizedColumns.Count)
313 {
314 foreach (Row row in this.Rows)
315 {
316 foreach (int modularizedColumn in modularizedColumns)
317 {
318 Field field = row.Fields[modularizedColumn];
319
320 if (null != field.Data)
321 {
322 field.Data = row.GetModularizedValue(field, modularizationGuid, suppressModularizationIdentifiers);
323 }
324 }
325 }
326 }
327 }
328
329 /// <summary>
330 /// Persists a row in an XML format.
331 /// </summary>
332 /// <param name="writer">XmlWriter where the Row should persist itself as XML.</param>
333 [SuppressMessage("Microsoft.Globalization", "CA1308:NormalizeStringsToUppercase", Justification = "Changing the way this string normalizes would result " +
334 "in a change to the way the intermediate files are generated, potentially causing extra churn in patches on an MSI built from an older version of WiX. " +
335 "Furthermore, there is no security hole here, as the strings won't need to make a round trip")]
336 internal void Write(XmlWriter writer)
337 {
338 if (null == writer)
339 {
340 throw new ArgumentNullException("writer");
341 }
342
343 writer.WriteStartElement("table", Intermediate.XmlNamespaceUri);
344 writer.WriteAttributeString("name", this.Name);
345
346 if (TableOperation.None != this.Operation)
347 {
348 writer.WriteAttributeString("op", this.Operation.ToString().ToLowerInvariant());
349 }
350
351 foreach (Row row in this.Rows)
352 {
353 row.Write(writer);
354 }
355
356 writer.WriteEndElement();
357 }
358
359 /// <summary>
360 /// Writes the table in IDT format to the provided stream.
361 /// </summary>
362 /// <param name="writer">Stream to write the table to.</param>
363 /// <param name="keepAddedColumns">Whether to keep columns added in a transform.</param>
364 public void ToIdtDefinition(StreamWriter writer, bool keepAddedColumns)
365 {
366 if (this.Definition.Unreal)
367 {
368 return;
369 }
370
371 if (TableDefinition.MaxColumnsInRealTable < this.Definition.Columns.Count)
372 {
373 throw new WixException(WixDataErrors.TooManyColumnsInRealTable(this.Definition.Name, this.Definition.Columns.Count, TableDefinition.MaxColumnsInRealTable));
374 }
375
376 // Tack on the table header, and flush before we start writing bytes directly to the stream.
377 writer.Write(this.Definition.ToIdtDefinition(keepAddedColumns));
378 writer.Flush();
379
380 using (var binary = new BinaryWriter(writer.BaseStream, writer.Encoding, true))
381 {
382 // Create an encoding that replaces characters with question marks, and doesn't throw. We'll
383 // use this in case of errors
384 Encoding convertEncoding = Encoding.GetEncoding(writer.Encoding.CodePage);
385
386 foreach (Row row in this.Rows)
387 {
388 if (row.Redundant)
389 {
390 continue;
391 }
392
393 string rowString = row.ToIdtDefinition(keepAddedColumns);
394 byte[] rowBytes;
395
396 try
397 {
398 // GetBytes will throw an exception if any character doesn't match our current encoding
399 rowBytes = writer.Encoding.GetBytes(rowString);
400 }
401 catch (EncoderFallbackException)
402 {
403 Messaging.Instance.OnMessage(WixDataErrors.InvalidStringForCodepage(row.SourceLineNumbers, Convert.ToString(writer.Encoding.WindowsCodePage, CultureInfo.InvariantCulture)));
404
405 rowBytes = convertEncoding.GetBytes(rowString);
406 }
407
408 binary.Write(rowBytes, 0, rowBytes.Length);
409 }
410 }
411 }
412
413 /// <summary>
414 /// Validates the rows of this OutputTable and throws if it collides on
415 /// primary keys.
416 /// </summary>
417 public void ValidateRows()
418 {
419 Dictionary<string, SourceLineNumber> primaryKeys = new Dictionary<string, SourceLineNumber>();
420
421 foreach (Row row in this.Rows)
422 {
423 string primaryKey = row.GetPrimaryKey();
424
425 SourceLineNumber collisionSourceLineNumber;
426 if (primaryKeys.TryGetValue(primaryKey, out collisionSourceLineNumber))
427 {
428 throw new WixException(WixDataErrors.DuplicatePrimaryKey(collisionSourceLineNumber, primaryKey, this.Definition.Name));
429 }
430
431 primaryKeys.Add(primaryKey, row.SourceLineNumbers);
432 }
433 }
434 }
435}