diff options
Diffstat (limited to '')
-rw-r--r-- | src/dtf/WixToolset.Dtf.Resources/VersionResource.cs | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/src/dtf/WixToolset.Dtf.Resources/VersionResource.cs b/src/dtf/WixToolset.Dtf.Resources/VersionResource.cs new file mode 100644 index 00000000..9955fa03 --- /dev/null +++ b/src/dtf/WixToolset.Dtf.Resources/VersionResource.cs | |||
@@ -0,0 +1,415 @@ | |||
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.Dtf.Resources | ||
4 | { | ||
5 | using System; | ||
6 | using System.IO; | ||
7 | using System.Text; | ||
8 | using System.Reflection; | ||
9 | using System.Collections; | ||
10 | using System.Collections.Generic; | ||
11 | using System.Globalization; | ||
12 | using System.Diagnostics.CodeAnalysis; | ||
13 | |||
14 | /// <summary> | ||
15 | /// A subclass of Resource which provides specific methods for manipulating the resource data. | ||
16 | /// </summary> | ||
17 | /// <remarks> | ||
18 | /// The resource is of type <see cref="ResourceType.Version"/> (RT_VERSION). | ||
19 | /// </remarks> | ||
20 | [SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")] | ||
21 | public sealed class VersionResource : Resource, ICollection<VersionStringTable> | ||
22 | { | ||
23 | internal bool dirty; | ||
24 | private VersionInfo rawVersionInfo; | ||
25 | private FixedFileVersionInfo rawFileVersionInfo; | ||
26 | |||
27 | /// <summary> | ||
28 | /// Creates a new VersionResource object without any data. The data can be later loaded from a file. | ||
29 | /// </summary> | ||
30 | /// <param name="name">Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#".</param> | ||
31 | /// <param name="locale">Locale of the resource</param> | ||
32 | public VersionResource(string name, int locale) | ||
33 | : this(name, locale, null) | ||
34 | { | ||
35 | } | ||
36 | |||
37 | /// <summary> | ||
38 | /// Creates a new VersionResource object with data. The data can be later saved to a file. | ||
39 | /// </summary> | ||
40 | /// <param name="name">Name of the resource. For a numeric resource identifier, prefix the decimal number with a "#".</param> | ||
41 | /// <param name="locale">Locale of the resource</param> | ||
42 | /// <param name="data">Raw resource data</param> | ||
43 | public VersionResource(string name, int locale, byte[] data) | ||
44 | : base(ResourceType.Version, name, locale, data) | ||
45 | { | ||
46 | this.RefreshVersionInfo(data); | ||
47 | } | ||
48 | |||
49 | /// <summary> | ||
50 | /// Gets or sets the raw data of the resource. The data is in the format of the VS_VERSIONINFO structure. | ||
51 | /// </summary> | ||
52 | public override byte[] Data | ||
53 | { | ||
54 | get | ||
55 | { | ||
56 | if (this.dirty) | ||
57 | { | ||
58 | this.rawVersionInfo.Data = (byte[]) this.rawFileVersionInfo; | ||
59 | base.Data = (byte[]) this.rawVersionInfo; | ||
60 | this.dirty = false; | ||
61 | } | ||
62 | |||
63 | return base.Data; | ||
64 | } | ||
65 | set | ||
66 | { | ||
67 | base.Data = value; | ||
68 | this.RefreshVersionInfo(value); | ||
69 | this.dirty = false; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | private void RefreshVersionInfo(byte[] refreshData) | ||
74 | { | ||
75 | if (refreshData == null) | ||
76 | { | ||
77 | this.rawVersionInfo = new VersionInfo("VS_VERSION_INFO"); | ||
78 | this.rawFileVersionInfo = new FixedFileVersionInfo(); | ||
79 | } | ||
80 | else | ||
81 | { | ||
82 | this.rawVersionInfo = (VersionInfo) refreshData; | ||
83 | this.rawFileVersionInfo = (FixedFileVersionInfo) this.rawVersionInfo.Data; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | /// <summary> | ||
88 | /// Gets or sets the binary locale-independent file version of the version resource. | ||
89 | /// </summary> | ||
90 | public Version FileVersion | ||
91 | { | ||
92 | get | ||
93 | { | ||
94 | return this.rawFileVersionInfo.FileVersion; | ||
95 | } | ||
96 | set | ||
97 | { | ||
98 | this.rawFileVersionInfo.FileVersion = value; | ||
99 | this.dirty = true; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | /// <summary> | ||
104 | /// Gets or sets the binary locale-independent product version of the version resource. | ||
105 | /// </summary> | ||
106 | public Version ProductVersion | ||
107 | { | ||
108 | get | ||
109 | { | ||
110 | return this.rawFileVersionInfo.ProductVersion; | ||
111 | } | ||
112 | set | ||
113 | { | ||
114 | this.rawFileVersionInfo.ProductVersion = value; | ||
115 | this.dirty = true; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | /// <summary> | ||
120 | /// Gets or sets a bitmask that specifies the build types of the file. | ||
121 | /// </summary> | ||
122 | public VersionBuildTypes BuildTypes | ||
123 | { | ||
124 | get | ||
125 | { | ||
126 | return this.rawFileVersionInfo.FileFlags & | ||
127 | this.rawFileVersionInfo.FileFlagsMask; | ||
128 | } | ||
129 | set | ||
130 | { | ||
131 | this.rawFileVersionInfo.FileFlags = value; | ||
132 | this.rawFileVersionInfo.FileFlagsMask = value; | ||
133 | this.dirty = true; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | /// <summary> | ||
138 | /// Gets or sets the general type of the file. | ||
139 | /// </summary> | ||
140 | public VersionFileType FileType | ||
141 | { | ||
142 | get | ||
143 | { | ||
144 | return this.rawFileVersionInfo.FileType; | ||
145 | } | ||
146 | set | ||
147 | { | ||
148 | this.rawFileVersionInfo.FileType = value; | ||
149 | this.dirty = true; | ||
150 | } | ||
151 | } | ||
152 | |||
153 | /// <summary> | ||
154 | /// Gets or sets the specific type of the file. | ||
155 | /// </summary> | ||
156 | public VersionFileSubtype FileSubtype | ||
157 | { | ||
158 | get | ||
159 | { | ||
160 | return this.rawFileVersionInfo.FileSubtype; | ||
161 | } | ||
162 | set | ||
163 | { | ||
164 | this.rawFileVersionInfo.FileSubtype = value; | ||
165 | this.dirty = true; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | /// <summary> | ||
170 | /// Gets or sets the binary creation date and time. | ||
171 | /// </summary> | ||
172 | public DateTime Timestamp | ||
173 | { | ||
174 | get | ||
175 | { | ||
176 | return this.rawFileVersionInfo.Timestamp; | ||
177 | } | ||
178 | set | ||
179 | { | ||
180 | this.rawFileVersionInfo.Timestamp = value; | ||
181 | this.dirty = true; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | /// <summary> | ||
186 | /// Gets the string table for a specific locale, or null if there is no table for that locale. | ||
187 | /// </summary> | ||
188 | /// <seealso cref="Add(int)"/> | ||
189 | /// <seealso cref="Remove(int)"/> | ||
190 | public VersionStringTable this[int locale] | ||
191 | { | ||
192 | get | ||
193 | { | ||
194 | VersionInfo svi = this.rawVersionInfo["StringFileInfo"]; | ||
195 | if (svi != null) | ||
196 | { | ||
197 | foreach (VersionInfo strings in svi) | ||
198 | { | ||
199 | int stringsLocale = UInt16.Parse(strings.Key.Substring(0, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture); | ||
200 | if (stringsLocale == locale) | ||
201 | { | ||
202 | return new VersionStringTable(this, strings); | ||
203 | } | ||
204 | } | ||
205 | } | ||
206 | return null; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | /// <summary> | ||
211 | /// Adds a new version string table for a locale. | ||
212 | /// </summary> | ||
213 | /// <param name="locale">Locale of the table</param> | ||
214 | /// <returns>The new string table, or the existing table if the locale already existed.</returns> | ||
215 | public VersionStringTable Add(int locale) | ||
216 | { | ||
217 | VersionInfo svi = this.rawVersionInfo["StringFileInfo"]; | ||
218 | if (svi == null) | ||
219 | { | ||
220 | svi = new VersionInfo("StringFileInfo"); | ||
221 | this.rawVersionInfo.Add(svi); | ||
222 | } | ||
223 | foreach (VersionInfo strings in svi) | ||
224 | { | ||
225 | int stringsLocale = UInt16.Parse(strings.Key.Substring(0, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture); | ||
226 | if (stringsLocale == locale) | ||
227 | { | ||
228 | return new VersionStringTable(this, strings); | ||
229 | } | ||
230 | } | ||
231 | |||
232 | VersionInfo newStrings = new VersionInfo( | ||
233 | ((ushort) locale).ToString("x4", CultureInfo.InvariantCulture) + ((ushort) 1200).ToString("x4", CultureInfo.InvariantCulture)); | ||
234 | svi.Add(newStrings); | ||
235 | this.dirty = true; | ||
236 | |||
237 | VersionInfo vvi = this.rawVersionInfo["VarFileInfo"]; | ||
238 | if (vvi == null) | ||
239 | { | ||
240 | vvi = new VersionInfo("VarFileInfo"); | ||
241 | vvi.Add(new VersionInfo("Translation")); | ||
242 | this.rawVersionInfo.Add(vvi); | ||
243 | } | ||
244 | VersionInfo tVerInfo = vvi["Translation"]; | ||
245 | if (tVerInfo != null) | ||
246 | { | ||
247 | byte[] oldValue = tVerInfo.Data; | ||
248 | if (oldValue == null) oldValue = new byte[0]; | ||
249 | tVerInfo.Data = new byte[oldValue.Length + 4]; | ||
250 | Array.Copy(oldValue, tVerInfo.Data, oldValue.Length); | ||
251 | using (BinaryWriter bw = new BinaryWriter(new MemoryStream(tVerInfo.Data, oldValue.Length, 4, true))) | ||
252 | { | ||
253 | bw.Write((ushort) locale); | ||
254 | bw.Write((ushort) 1200); | ||
255 | } | ||
256 | } | ||
257 | |||
258 | return new VersionStringTable(this, newStrings); | ||
259 | } | ||
260 | |||
261 | /// <summary> | ||
262 | /// Removes a version string table for a locale. | ||
263 | /// </summary> | ||
264 | /// <param name="locale">Locale of the table</param> | ||
265 | public void Remove(int locale) | ||
266 | { | ||
267 | VersionInfo svi = this.rawVersionInfo["StringFileInfo"]; | ||
268 | if (svi != null) | ||
269 | { | ||
270 | foreach (VersionInfo strings in svi) | ||
271 | { | ||
272 | int stringsLocale = UInt16.Parse(strings.Key.Substring(0, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture); | ||
273 | if (stringsLocale == locale) | ||
274 | { | ||
275 | svi.Remove(strings); | ||
276 | this.dirty = true; | ||
277 | break; | ||
278 | } | ||
279 | } | ||
280 | |||
281 | } | ||
282 | |||
283 | VersionInfo vvi = this.rawVersionInfo["VarFileInfo"]; | ||
284 | if (vvi != null) | ||
285 | { | ||
286 | VersionInfo tVerInfo = vvi["Translation"]; | ||
287 | if (tVerInfo != null) | ||
288 | { | ||
289 | byte[] newValue = new byte[tVerInfo.Data.Length]; | ||
290 | int j = 0; | ||
291 | using (BinaryWriter bw = new BinaryWriter(new MemoryStream(newValue, 0, newValue.Length, true))) | ||
292 | { | ||
293 | using (BinaryReader br = new BinaryReader(new MemoryStream(tVerInfo.Data))) | ||
294 | { | ||
295 | for (int i = tVerInfo.Data.Length / 4; i > 0; i--) | ||
296 | { | ||
297 | ushort tLocale = br.ReadUInt16(); | ||
298 | ushort cp = br.ReadUInt16(); | ||
299 | if (tLocale != locale) | ||
300 | { | ||
301 | bw.Write((ushort) tLocale); | ||
302 | bw.Write((ushort) cp); | ||
303 | j++; | ||
304 | } | ||
305 | } | ||
306 | } | ||
307 | } | ||
308 | tVerInfo.Data = new byte[j * 4]; | ||
309 | Array.Copy(newValue, tVerInfo.Data, tVerInfo.Data.Length); | ||
310 | } | ||
311 | } | ||
312 | } | ||
313 | |||
314 | /// <summary> | ||
315 | /// Checks if a version string table exists for a given locale. | ||
316 | /// </summary> | ||
317 | /// <param name="locale">Locale to search for</param> | ||
318 | /// <returns>True if a string table was found for the locale; false otherwise.</returns> | ||
319 | public bool Contains(int locale) | ||
320 | { | ||
321 | return this[locale] != null; | ||
322 | } | ||
323 | |||
324 | /// <summary> | ||
325 | /// Gets the number string tables in the version resource. | ||
326 | /// </summary> | ||
327 | public int Count | ||
328 | { | ||
329 | get | ||
330 | { | ||
331 | VersionInfo svi = this.rawVersionInfo["StringFileInfo"]; | ||
332 | return svi != null ? svi.Count : 0; | ||
333 | } | ||
334 | } | ||
335 | |||
336 | /// <summary> | ||
337 | /// Removes all string tables from the version resource. | ||
338 | /// </summary> | ||
339 | public void Clear() | ||
340 | { | ||
341 | VersionInfo svi = this.rawVersionInfo["StringFileInfo"]; | ||
342 | if (svi != null) | ||
343 | { | ||
344 | svi.Clear(); | ||
345 | this.dirty = true; | ||
346 | } | ||
347 | } | ||
348 | |||
349 | bool ICollection<VersionStringTable>.IsReadOnly | ||
350 | { | ||
351 | get | ||
352 | { | ||
353 | return false; | ||
354 | } | ||
355 | } | ||
356 | |||
357 | void ICollection<VersionStringTable>.Add(VersionStringTable item) | ||
358 | { | ||
359 | throw new NotSupportedException(); | ||
360 | } | ||
361 | |||
362 | bool ICollection<VersionStringTable>.Remove(VersionStringTable item) | ||
363 | { | ||
364 | throw new NotSupportedException(); | ||
365 | } | ||
366 | |||
367 | bool ICollection<VersionStringTable>.Contains(VersionStringTable item) | ||
368 | { | ||
369 | throw new NotSupportedException(); | ||
370 | } | ||
371 | |||
372 | /// <summary> | ||
373 | /// Copies the version string tables to an array, starting at a particular array index. | ||
374 | /// </summary> | ||
375 | /// <param name="array">The one-dimensional Array that is the destination of the elements copied | ||
376 | /// from the collection. The Array must have zero-based indexing.</param> | ||
377 | /// <param name="arrayIndex">The zero-based index in array at which copying begins.</param> | ||
378 | public void CopyTo(VersionStringTable[] array, int arrayIndex) | ||
379 | { | ||
380 | VersionInfo svi = this.rawVersionInfo["StringFileInfo"]; | ||
381 | if (svi != null) | ||
382 | { | ||
383 | foreach (VersionInfo strings in svi) | ||
384 | { | ||
385 | array[arrayIndex++] = new VersionStringTable(this, strings); | ||
386 | } | ||
387 | } | ||
388 | } | ||
389 | |||
390 | /// <summary> | ||
391 | /// Gets an enumerator that can iterate over the version string tables in the collection. | ||
392 | /// </summary> | ||
393 | /// <returns>An enumerator that returns <see cref="VersionStringTable"/> objects.</returns> | ||
394 | public IEnumerator<VersionStringTable> GetEnumerator() | ||
395 | { | ||
396 | VersionInfo svi = this.rawVersionInfo["StringFileInfo"]; | ||
397 | if (svi != null) | ||
398 | { | ||
399 | foreach (VersionInfo strings in svi) | ||
400 | { | ||
401 | yield return new VersionStringTable(this, strings); | ||
402 | } | ||
403 | } | ||
404 | } | ||
405 | |||
406 | /// <summary> | ||
407 | /// Gets an enumerator that can iterate over the version string tables in the collection. | ||
408 | /// </summary> | ||
409 | /// <returns>An enumerator that returns <see cref="VersionStringTable"/> objects.</returns> | ||
410 | IEnumerator IEnumerable.GetEnumerator() | ||
411 | { | ||
412 | return this.GetEnumerator(); | ||
413 | } | ||
414 | } | ||
415 | } | ||