diff options
Diffstat (limited to '')
-rw-r--r-- | src/WixToolset.Data/WixOutput.cs | 233 |
1 files changed, 233 insertions, 0 deletions
diff --git a/src/WixToolset.Data/WixOutput.cs b/src/WixToolset.Data/WixOutput.cs new file mode 100644 index 00000000..f27f7c77 --- /dev/null +++ b/src/WixToolset.Data/WixOutput.cs | |||
@@ -0,0 +1,233 @@ | |||
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.Data | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using System.IO.Compression; | ||
8 | using System.Reflection; | ||
9 | using System.Text; | ||
10 | |||
11 | /// <summary> | ||
12 | /// Class that understands the standard file structure of the WiX toolset. | ||
13 | /// </summary> | ||
14 | public class WixOutput : IDisposable | ||
15 | { | ||
16 | private readonly ZipArchive archive; | ||
17 | private bool disposed; | ||
18 | |||
19 | private WixOutput(Uri uri, ZipArchive archive) | ||
20 | { | ||
21 | this.Uri = uri; | ||
22 | this.archive = archive; | ||
23 | } | ||
24 | |||
25 | public Uri Uri { get; } | ||
26 | |||
27 | /// <summary> | ||
28 | /// Creates a new file structure in memory. | ||
29 | /// </summary> | ||
30 | /// <returns>Newly created <c>WixOutput</c>.</returns> | ||
31 | public static WixOutput Create() | ||
32 | { | ||
33 | var uri = new Uri("memorystream:"); | ||
34 | |||
35 | var stream = new MemoryStream(); | ||
36 | |||
37 | return WixOutput.Create(uri, stream); | ||
38 | } | ||
39 | |||
40 | /// <summary> | ||
41 | /// Creates a new file structure on disk. | ||
42 | /// </summary> | ||
43 | /// <param name="path">Path to write file structure to.</param> | ||
44 | /// <returns>Newly created <c>WixOutput</c>.</returns> | ||
45 | public static WixOutput Create(string path) | ||
46 | { | ||
47 | var uri = new Uri(Path.GetFullPath(path)); | ||
48 | |||
49 | var stream = File.Create(path); | ||
50 | |||
51 | return WixOutput.Create(uri, stream); | ||
52 | } | ||
53 | |||
54 | /// <summary> | ||
55 | /// Creates a new file structure. | ||
56 | /// </summary> | ||
57 | /// <param name="stream">Stream to write the file structure to.</param> | ||
58 | /// <param name="embedFilePaths">Paths to files to embedd in the file structure.</param> | ||
59 | /// <returns>Newly created <c>WixOutput</c>.</returns> | ||
60 | public static WixOutput Create(Uri uri, Stream stream) | ||
61 | { | ||
62 | var archive = new ZipArchive(stream, ZipArchiveMode.Update); | ||
63 | |||
64 | return new WixOutput(uri, archive); | ||
65 | } | ||
66 | |||
67 | /// <summary> | ||
68 | /// Loads a wixout from a path on disk. | ||
69 | /// </summary> | ||
70 | /// <param name="path">Path to wixout file saved on disk.</param> | ||
71 | /// <returns>Loaded created <c>WixOutput</c>.</returns> | ||
72 | public static WixOutput Read(string path) | ||
73 | { | ||
74 | var uri = new Uri(Path.GetFullPath(path)); | ||
75 | |||
76 | var stream = File.OpenRead(path); | ||
77 | |||
78 | return Read(uri, stream); | ||
79 | } | ||
80 | |||
81 | /// <summary> | ||
82 | /// Loads a wixout from a path on disk or embedded resource in assembly. | ||
83 | /// </summary> | ||
84 | /// <param name="baseUri">Uri with local path to wixout file saved on disk or embedded resource in assembly.</param> | ||
85 | /// <returns>Loaded created <c>WixOutput</c>.</returns> | ||
86 | public static WixOutput Read(Uri baseUri) | ||
87 | { | ||
88 | // If the embedded files are stored in an assembly resource stream (usually | ||
89 | // a .wixlib embedded in a WixExtension). | ||
90 | if ("embeddedresource" == baseUri.Scheme) | ||
91 | { | ||
92 | var assemblyPath = Path.GetFullPath(baseUri.LocalPath); | ||
93 | var resourceName = baseUri.Fragment.TrimStart('#'); | ||
94 | |||
95 | var assembly = Assembly.LoadFile(assemblyPath); | ||
96 | return WixOutput.Read(assembly, resourceName); | ||
97 | } | ||
98 | else // normal file (usually a binary .wixlib on disk). | ||
99 | { | ||
100 | var stream = File.OpenRead(baseUri.LocalPath); | ||
101 | return WixOutput.Read(baseUri, stream); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | /// <summary> | ||
106 | /// Loads a wixout from a assembly resource stream. | ||
107 | /// </summary> | ||
108 | /// <param name="path">Path to wixout file saved on disk.</param> | ||
109 | public static WixOutput Read(Assembly assembly, string resourceName) | ||
110 | { | ||
111 | var resourceStream = assembly.GetManifestResourceStream(resourceName); | ||
112 | |||
113 | var uriBuilder = new UriBuilder(assembly.CodeBase) | ||
114 | { | ||
115 | Scheme = "embeddedresource", | ||
116 | Fragment = resourceName | ||
117 | }; | ||
118 | |||
119 | return Read(uriBuilder.Uri, resourceStream); | ||
120 | } | ||
121 | |||
122 | /// <summary> | ||
123 | /// Reads a file structure from an open stream. | ||
124 | /// </summary> | ||
125 | /// <param name="stream">Stream to read from.</param> | ||
126 | /// <returns>Loaded created <c>WixOutput</c>.</returns> | ||
127 | public static WixOutput Read(Uri uri, Stream stream, bool leaveOpen = false) | ||
128 | { | ||
129 | try | ||
130 | { | ||
131 | var archive = new ZipArchive(stream, ZipArchiveMode.Read, leaveOpen); | ||
132 | |||
133 | return new WixOutput(uri, archive); | ||
134 | } | ||
135 | catch (InvalidDataException) | ||
136 | { | ||
137 | throw new WixException(ErrorMessages.CorruptFileFormat(uri.AbsoluteUri, "wixout")); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | /// <summary> | ||
142 | /// Extracts an embedded file. | ||
143 | /// </summary> | ||
144 | /// <param name="embeddedId">Id to the file to extract.</param> | ||
145 | /// <param name="outputPath">Path to write the extracted file to.</param> | ||
146 | public void ExtractEmbeddedFile(string embeddedId, string outputPath) | ||
147 | { | ||
148 | var entry = this.archive.GetEntry(embeddedId); | ||
149 | |||
150 | if (entry == null) | ||
151 | { | ||
152 | throw new ArgumentOutOfRangeException(nameof(embeddedId)); | ||
153 | } | ||
154 | |||
155 | var folder = Path.GetDirectoryName(outputPath); | ||
156 | |||
157 | Directory.CreateDirectory(folder); | ||
158 | |||
159 | entry.ExtractToFile(outputPath); | ||
160 | } | ||
161 | |||
162 | /// <summary> | ||
163 | /// Creates a data stream in the wixout. | ||
164 | /// </summary> | ||
165 | /// <returns>Stream to the data of the file.</returns> | ||
166 | public Stream CreateDataStream(string name) | ||
167 | { | ||
168 | var entry = this.archive.CreateEntry(name); | ||
169 | |||
170 | return entry.Open(); | ||
171 | } | ||
172 | |||
173 | public void ImportDataStream(string name, string path) | ||
174 | { | ||
175 | this.archive.CreateEntryFromFile(path, name, System.IO.Compression.CompressionLevel.Optimal); | ||
176 | } | ||
177 | |||
178 | /// <summary> | ||
179 | /// Gets a non-closing stream to the data of the file. | ||
180 | /// </summary> | ||
181 | /// <returns>Stream to the data of the file.</returns> | ||
182 | public Stream GetDataStream(string name) | ||
183 | { | ||
184 | var entry = this.archive.GetEntry(name); | ||
185 | |||
186 | return entry.Open(); | ||
187 | } | ||
188 | |||
189 | /// <summary> | ||
190 | /// Gets the data of the file as a string. | ||
191 | /// </summary> | ||
192 | /// <returns>String contents data of the file.</returns> | ||
193 | public string GetData(string name) | ||
194 | { | ||
195 | var entry = this.archive.GetEntry(name); | ||
196 | |||
197 | var bytes = new byte[entry.Length]; | ||
198 | |||
199 | using (var stream = entry.Open()) | ||
200 | { | ||
201 | stream.Read(bytes, 0, bytes.Length); | ||
202 | } | ||
203 | |||
204 | return Encoding.UTF8.GetString(bytes); | ||
205 | } | ||
206 | |||
207 | /// <summary> | ||
208 | /// Disposes of the internal state of the file structure. | ||
209 | /// </summary> | ||
210 | public void Dispose() | ||
211 | { | ||
212 | this.Dispose(true); | ||
213 | GC.SuppressFinalize(this); | ||
214 | } | ||
215 | |||
216 | /// <summary> | ||
217 | /// Disposes of the internsl state of the file structure. | ||
218 | /// </summary> | ||
219 | /// <param name="disposing">True if disposing.</param> | ||
220 | protected virtual void Dispose(bool disposing) | ||
221 | { | ||
222 | if (!this.disposed) | ||
223 | { | ||
224 | if (disposing) | ||
225 | { | ||
226 | this.archive?.Dispose(); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | this.disposed = true; | ||
231 | } | ||
232 | } | ||
233 | } | ||