aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Data/WindowsInstaller/Output.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Data/WindowsInstaller/Output.cs')
-rw-r--r--src/WixToolset.Data/WindowsInstaller/Output.cs274
1 files changed, 274 insertions, 0 deletions
diff --git a/src/WixToolset.Data/WindowsInstaller/Output.cs b/src/WixToolset.Data/WindowsInstaller/Output.cs
new file mode 100644
index 00000000..6164622d
--- /dev/null
+++ b/src/WixToolset.Data/WindowsInstaller/Output.cs
@@ -0,0 +1,274 @@
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.Collections.Generic;
7 using System.Globalization;
8 using System.IO;
9 using System.Linq;
10 using System.Xml;
11
12 /// <summary>
13 /// Output is generated by the linker.
14 /// </summary>
15 public sealed class Output
16 {
17 public const string XmlNamespaceUri = "http://wixtoolset.org/schemas/v4/wixout";
18 private static readonly Version CurrentVersion = new Version("4.0.0.0");
19
20 /// <summary>
21 /// Creates a new empty output object.
22 /// </summary>
23 /// <param name="sourceLineNumbers">The source line information for the output.</param>
24 public Output(SourceLineNumber sourceLineNumbers)
25 {
26 this.SourceLineNumbers = sourceLineNumbers;
27 this.SubStorages = new List<SubStorage>();
28 this.Tables = new TableIndexedCollection();
29 }
30
31 /// <summary>
32 /// Gets the type of the output.
33 /// </summary>
34 /// <value>Type of the output.</value>
35 public OutputType Type { get; set; }
36
37 /// <summary>
38 /// Gets or sets the codepage for this output.
39 /// </summary>
40 /// <value>Codepage of the output.</value>
41 public int Codepage { get; set; }
42
43 /// <summary>
44 /// Gets the source line information for this output.
45 /// </summary>
46 /// <value>The source line information for this output.</value>
47 public SourceLineNumber SourceLineNumbers { get; private set; }
48
49 /// <summary>
50 /// Gets the substorages in this output.
51 /// </summary>
52 /// <value>The substorages in this output.</value>
53 public ICollection<SubStorage> SubStorages { get; private set; }
54
55 /// <summary>
56 /// Gets the tables contained in this output.
57 /// </summary>
58 /// <value>Collection of tables.</value>
59 public TableIndexedCollection Tables { get; private set; }
60
61 /// <summary>
62 /// Loads an output from a path on disk.
63 /// </summary>
64 /// <param name="path">Path to output file saved on disk.</param>
65 /// <param name="suppressVersionCheck">Suppresses wix.dll version mismatch check.</param>
66 /// <returns>Output object.</returns>
67 public static Output Load(string path, bool suppressVersionCheck)
68 {
69 using (FileStream stream = File.OpenRead(path))
70 using (FileStructure fs = FileStructure.Read(stream))
71 {
72 if (FileFormat.Wixout != fs.FileFormat)
73 {
74 throw new WixUnexpectedFileFormatException(path, FileFormat.Wixout, fs.FileFormat);
75 }
76
77 Uri uri = new Uri(Path.GetFullPath(path));
78 using (XmlReader reader = XmlReader.Create(fs.GetDataStream(), null, uri.AbsoluteUri))
79 {
80 try
81 {
82 reader.MoveToContent();
83 return Output.Read(reader, suppressVersionCheck);
84 }
85 catch (XmlException xe)
86 {
87 throw new WixCorruptFileException(path, fs.FileFormat, xe);
88 }
89 }
90 }
91 }
92
93 /// <summary>
94 /// Saves an output to a path on disk.
95 /// </summary>
96 /// <param name="path">Path to save output file to on disk.</param>
97 public void Save(string path)
98 {
99 Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path)));
100
101 using (FileStream stream = File.Create(path))
102 using (FileStructure fs = FileStructure.Create(stream, FileFormat.Wixout, null))
103 using (XmlWriter writer = XmlWriter.Create(fs.GetDataStream()))
104 {
105 writer.WriteStartDocument();
106 this.Write(writer);
107 writer.WriteEndDocument();
108 }
109 }
110
111 /// <summary>
112 /// Processes an XmlReader and builds up the output object.
113 /// </summary>
114 /// <param name="reader">Reader to get data from.</param>
115 /// <param name="suppressVersionCheck">Suppresses wix.dll version mismatch check.</param>
116 /// <returns>The Output represented by the Xml.</returns>
117 internal static Output Read(XmlReader reader, bool suppressVersionCheck)
118 {
119 if (!reader.LocalName.Equals("wixOutput"))
120 {
121 throw new XmlException();
122 }
123
124 bool empty = reader.IsEmptyElement;
125 Output output = new Output(SourceLineNumber.CreateFromUri(reader.BaseURI));
126 Version version = null;
127
128 while (reader.MoveToNextAttribute())
129 {
130 switch (reader.LocalName)
131 {
132 case "codepage":
133 output.Codepage = Convert.ToInt32(reader.Value, CultureInfo.InvariantCulture.NumberFormat);
134 break;
135 case "type":
136 switch (reader.Value)
137 {
138 case "Bundle":
139 output.Type = OutputType.Bundle;
140 break;
141 case "Module":
142 output.Type = OutputType.Module;
143 break;
144 case "Patch":
145 output.Type = OutputType.Patch;
146 break;
147 case "PatchCreation":
148 output.Type = OutputType.PatchCreation;
149 break;
150 case "Product":
151 output.Type = OutputType.Product;
152 break;
153 case "Transform":
154 output.Type = OutputType.Transform;
155 break;
156 default:
157 throw new XmlException();
158 }
159 break;
160 case "version":
161 version = new Version(reader.Value);
162 break;
163 }
164 }
165
166 if (!suppressVersionCheck && null != version && !Output.CurrentVersion.Equals(version))
167 {
168 throw new WixException(WixDataErrors.VersionMismatch(SourceLineNumber.CreateFromUri(reader.BaseURI), "wixOutput", version.ToString(), Output.CurrentVersion.ToString()));
169 }
170
171 // loop through the rest of the xml building up the Output object
172 TableDefinitionCollection tableDefinitions = null;
173 List<Table> tables = new List<Table>();
174 if (!empty)
175 {
176 bool done = false;
177
178 // loop through all the fields in a row
179 while (!done && reader.Read())
180 {
181 switch (reader.NodeType)
182 {
183 case XmlNodeType.Element:
184 switch (reader.LocalName)
185 {
186 case "subStorage":
187 output.SubStorages.Add(SubStorage.Read(reader));
188 break;
189 case "table":
190 if (null == tableDefinitions)
191 {
192 throw new XmlException();
193 }
194 tables.Add(Table.Read(reader, tableDefinitions));
195 break;
196 case "tableDefinitions":
197 tableDefinitions = TableDefinitionCollection.Read(reader);
198 break;
199 default:
200 throw new XmlException();
201 }
202 break;
203 case XmlNodeType.EndElement:
204 done = true;
205 break;
206 }
207 }
208
209 if (!done)
210 {
211 throw new XmlException();
212 }
213 }
214
215 output.Tables = new TableIndexedCollection(tables);
216 return output;
217 }
218
219 /// <summary>
220 /// Ensure this output contains a particular table.
221 /// </summary>
222 /// <param name="tableDefinition">Definition of the table that should exist.</param>
223 /// <param name="section">Optional section to use for the table. If one is not provided, the entry section will be used.</param>
224 /// <returns>The table in this output.</returns>
225 public Table EnsureTable(TableDefinition tableDefinition)
226 {
227 if (!this.Tables.TryGetTable(tableDefinition.Name, out Table table))
228 {
229 table = new Table(tableDefinition);
230 this.Tables.Add(table);
231 }
232
233 return table;
234 }
235
236 /// <summary>
237 /// Persists an output in an XML format.
238 /// </summary>
239 /// <param name="writer">XmlWriter where the Output should persist itself as XML.</param>
240 internal void Write(XmlWriter writer)
241 {
242 writer.WriteStartElement("wixOutput", XmlNamespaceUri);
243
244 writer.WriteAttributeString("type", this.Type.ToString());
245
246 if (0 != this.Codepage)
247 {
248 writer.WriteAttributeString("codepage", this.Codepage.ToString(CultureInfo.InvariantCulture));
249 }
250
251 writer.WriteAttributeString("version", Output.CurrentVersion.ToString());
252
253 // Collect all the table definitions and write them.
254 TableDefinitionCollection tableDefinitions = new TableDefinitionCollection();
255 foreach (Table table in this.Tables)
256 {
257 tableDefinitions.Add(table.Definition);
258 }
259 tableDefinitions.Write(writer);
260
261 foreach (Table table in this.Tables.OrderBy(t => t.Name))
262 {
263 table.Write(writer);
264 }
265
266 foreach (SubStorage subStorage in this.SubStorages)
267 {
268 subStorage.Write(writer);
269 }
270
271 writer.WriteEndElement();
272 }
273 }
274}