aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Data/Library.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/WixToolset.Data/Library.cs297
1 files changed, 297 insertions, 0 deletions
diff --git a/src/WixToolset.Data/Library.cs b/src/WixToolset.Data/Library.cs
new file mode 100644
index 00000000..bb04d216
--- /dev/null
+++ b/src/WixToolset.Data/Library.cs
@@ -0,0 +1,297 @@
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.IO;
8 using System.Linq;
9 using System.Xml;
10
11 /// <summary>
12 /// Object that represents a library file.
13 /// </summary>
14 public sealed class Library
15 {
16 public const string XmlNamespaceUri = "http://wixtoolset.org/schemas/v4/wixlib";
17 private static readonly Version CurrentVersion = new Version("4.0.0.0");
18
19 private string id;
20 private Dictionary<string, Localization> localizations;
21 private List<Section> sections;
22
23 /// <summary>
24 /// Instantiates a new empty library which is only useful from static creating methods.
25 /// </summary>
26 private Library()
27 {
28 this.localizations = new Dictionary<string, Localization>();
29 this.sections = new List<Section>();
30 }
31
32 /// <summary>
33 /// Instantiate a new library populated with sections.
34 /// </summary>
35 /// <param name="sections">Sections to add to the library.</param>
36 public Library(IEnumerable<Section> sections)
37 {
38 this.localizations = new Dictionary<string, Localization>();
39 this.sections = new List<Section>(sections);
40
41 this.id = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).TrimEnd('=').Replace('+', '.').Replace('/', '_');
42 foreach (Section section in this.sections)
43 {
44 section.LibraryId = this.id;
45 }
46 }
47
48 /// <summary>
49 /// Get the sections contained in this library.
50 /// </summary>
51 /// <value>Sections contained in this library.</value>
52 public IEnumerable<Section> Sections { get { return this.sections; } }
53
54 /// <summary>
55 /// Add a localization file to this library.
56 /// </summary>
57 /// <param name="localization">The localization file to add.</param>
58 public void AddLocalization(Localization localization)
59 {
60 Localization existingCulture;
61 if (this.localizations.TryGetValue(localization.Culture, out existingCulture))
62 {
63 existingCulture.Merge(localization);
64 }
65 else
66 {
67 this.localizations.Add(localization.Culture, localization);
68 }
69 }
70
71 /// <summary>
72 /// Gets localization files from this library that match the cultures passed in, in the order of the array of cultures.
73 /// </summary>
74 /// <param name="cultures">The list of cultures to get localizations for.</param>
75 /// <returns>All localizations contained in this library that match the set of cultures provided, in the same order.</returns>
76 public IEnumerable<Localization> GetLocalizations(string[] cultures)
77 {
78 foreach (string culture in cultures ?? new string[0])
79 {
80 Localization localization;
81 if (this.localizations.TryGetValue(culture, out localization))
82 {
83 yield return localization;
84 }
85 }
86 }
87
88 /// <summary>
89 /// Loads a library from a path on disk.
90 /// </summary>
91 /// <param name="path">Path to library file saved on disk.</param>
92 /// <param name="tableDefinitions">Collection containing TableDefinitions to use when reconstituting the intermediates.</param>
93 /// <param name="suppressVersionCheck">Suppresses wix.dll version mismatch check.</param>
94 /// <returns>Returns the loaded library.</returns>
95 public static Library Load(string path, TableDefinitionCollection tableDefinitions, bool suppressVersionCheck)
96 {
97 using (FileStream stream = File.OpenRead(path))
98 {
99 return Load(stream, new Uri(Path.GetFullPath(path)), tableDefinitions, suppressVersionCheck);
100 }
101 }
102
103 /// <summary>
104 /// Loads a library from a stream.
105 /// </summary>
106 /// <param name="stream">Stream containing the library file.</param>
107 /// <param name="uri">Uri for finding this stream.</param>
108 /// <param name="tableDefinitions">Collection containing TableDefinitions to use when reconstituting the intermediates.</param>
109 /// <param name="suppressVersionCheck">Suppresses wix.dll version mismatch check.</param>
110 /// <returns>Returns the loaded library.</returns>
111 public static Library Load(Stream stream, Uri uri, TableDefinitionCollection tableDefinitions, bool suppressVersionCheck)
112 {
113 using (FileStructure fs = FileStructure.Read(stream))
114 {
115 if (FileFormat.Wixlib != fs.FileFormat)
116 {
117 throw new WixUnexpectedFileFormatException(uri.LocalPath, FileFormat.Wixlib, fs.FileFormat);
118 }
119
120 using (XmlReader reader = XmlReader.Create(fs.GetDataStream(), null, uri.AbsoluteUri))
121 {
122 try
123 {
124 reader.MoveToContent();
125 return Library.Read(reader, tableDefinitions, suppressVersionCheck);
126 }
127 catch (XmlException xe)
128 {
129 throw new WixCorruptFileException(uri.LocalPath, fs.FileFormat, xe);
130 }
131 }
132 }
133 }
134
135 /// <summary>
136 /// Saves a library to a path on disk.
137 /// </summary>
138 /// <param name="path">Path to save library file to on disk.</param>
139 /// <param name="resolver">The WiX path resolver.</param>
140 public void Save(string path, ILibraryBinaryFileResolver resolver)
141 {
142 List<string> embedFilePaths = new List<string>();
143
144 // Resolve paths to files that are to be embedded in the library.
145 if (null != resolver)
146 {
147 foreach (Table table in this.sections.SelectMany(s => s.Tables))
148 {
149 foreach (Row row in table.Rows)
150 {
151 foreach (ObjectField objectField in row.Fields.Where(f => f is ObjectField))
152 {
153 if (null != objectField.Data)
154 {
155 string file = resolver.Resolve(row.SourceLineNumbers, table.Name, (string)objectField.Data);
156 if (!String.IsNullOrEmpty(file))
157 {
158 // File was successfully resolved so track the embedded index as the embedded file index.
159 objectField.EmbeddedFileIndex = embedFilePaths.Count;
160 embedFilePaths.Add(file);
161 }
162 else
163 {
164 Messaging.Instance.OnMessage(WixDataErrors.FileNotFound(row.SourceLineNumbers, (string)objectField.Data, table.Name));
165 }
166 }
167 else // clear out embedded file id in case there was one there before.
168 {
169 objectField.EmbeddedFileIndex = null;
170 }
171 }
172 }
173 }
174 }
175
176 // Do not save the library if errors were found while resolving object paths.
177 if (Messaging.Instance.EncounteredError)
178 {
179 return;
180 }
181
182 // Ensure the location to output the library exists and write it out.
183 Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path)));
184
185 using (FileStream stream = File.Create(path))
186 using (FileStructure fs = FileStructure.Create(stream, FileFormat.Wixlib, embedFilePaths))
187 using (XmlWriter writer = XmlWriter.Create(fs.GetDataStream()))
188 {
189 writer.WriteStartDocument();
190
191 this.Write(writer);
192
193 writer.WriteEndDocument();
194 }
195 }
196
197 /// <summary>
198 /// Parse the root library element.
199 /// </summary>
200 /// <param name="reader">XmlReader with library persisted as Xml.</param>
201 /// <param name="tableDefinitions">Collection containing TableDefinitions to use when reconstituting the intermediates.</param>
202 /// <param name="suppressVersionCheck">Suppresses check for wix.dll version mismatch.</param>
203 /// <returns>The parsed Library.</returns>
204 private static Library Read(XmlReader reader, TableDefinitionCollection tableDefinitions, bool suppressVersionCheck)
205 {
206 if (!reader.LocalName.Equals("wixLibrary"))
207 {
208 throw new XmlException();
209 }
210
211 bool empty = reader.IsEmptyElement;
212 Library library = new Library();
213 Version version = null;
214
215 while (reader.MoveToNextAttribute())
216 {
217 switch (reader.LocalName)
218 {
219 case "version":
220 version = new Version(reader.Value);
221 break;
222 case "id":
223 library.id = reader.Value;
224 break;
225 }
226 }
227
228 if (!suppressVersionCheck && null != version && !Library.CurrentVersion.Equals(version))
229 {
230 throw new WixException(WixDataErrors.VersionMismatch(SourceLineNumber.CreateFromUri(reader.BaseURI), "library", version.ToString(), Library.CurrentVersion.ToString()));
231 }
232
233 if (!empty)
234 {
235 bool done = false;
236
237 while (!done && (XmlNodeType.Element == reader.NodeType || reader.Read()))
238 {
239 switch (reader.NodeType)
240 {
241 case XmlNodeType.Element:
242 switch (reader.LocalName)
243 {
244 case "localization":
245 Localization localization = Localization.Read(reader, tableDefinitions);
246 library.localizations.Add(localization.Culture, localization);
247 break;
248 case "section":
249 Section section = Section.Read(reader, tableDefinitions);
250 section.LibraryId = library.id;
251 library.sections.Add(section);
252 break;
253 default:
254 throw new XmlException();
255 }
256 break;
257 case XmlNodeType.EndElement:
258 done = true;
259 break;
260 }
261 }
262
263 if (!done)
264 {
265 throw new XmlException();
266 }
267 }
268
269 return library;
270 }
271
272 /// <summary>
273 /// Persists a library in an XML format.
274 /// </summary>
275 /// <param name="writer">XmlWriter where the library should persist itself as XML.</param>
276 private void Write(XmlWriter writer)
277 {
278 writer.WriteStartElement("wixLibrary", XmlNamespaceUri);
279
280 writer.WriteAttributeString("version", CurrentVersion.ToString());
281
282 writer.WriteAttributeString("id", this.id);
283
284 foreach (Localization localization in this.localizations.Values)
285 {
286 localization.Write(writer);
287 }
288
289 foreach (Section section in this.sections)
290 {
291 section.Write(writer);
292 }
293
294 writer.WriteEndElement();
295 }
296 }
297}