aboutsummaryrefslogtreecommitdiff
path: root/src/dtf/WixToolset.Dtf.Resources/VersionResource.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/dtf/WixToolset.Dtf.Resources/VersionResource.cs415
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
3namespace 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}