aboutsummaryrefslogtreecommitdiff
path: root/src/tools/heat/RegFileHarvester.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/heat/RegFileHarvester.cs')
-rw-r--r--src/tools/heat/RegFileHarvester.cs436
1 files changed, 0 insertions, 436 deletions
diff --git a/src/tools/heat/RegFileHarvester.cs b/src/tools/heat/RegFileHarvester.cs
deleted file mode 100644
index 49cf4c01..00000000
--- a/src/tools/heat/RegFileHarvester.cs
+++ /dev/null
@@ -1,436 +0,0 @@
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.Harvesters
4{
5 using System;
6 using System.Collections;
7 using System.Globalization;
8 using System.IO;
9 using WixToolset.Data;
10 using WixToolset.Harvesters.Data;
11 using WixToolset.Harvesters.Extensibility;
12 using Wix = WixToolset.Harvesters.Serialize;
13
14 /// <summary>
15 /// Harvest WiX authoring for a reg file.
16 /// </summary>
17 public sealed class RegFileHarvester : BaseHarvesterExtension
18 {
19 private static readonly string ComponentPrefix = "cmp";
20
21 /// <summary>
22 /// Current line in the reg file being processed.
23 /// </summary>
24 private int currentLineNumber = 0;
25
26 /// <summary>
27 /// Flag indicating whether this is a unicode registry file.
28 /// </summary>
29 private bool unicodeRegistry;
30
31 /// <summary>
32 /// Harvest a file.
33 /// </summary>
34 /// <param name="argument">The path of the file.</param>
35 /// <returns>A harvested file.</returns>
36 public override Wix.Fragment[] Harvest(string argument)
37 {
38 if (null == argument)
39 {
40 throw new ArgumentNullException("argument");
41 }
42
43 // Harvest the keys from the registry file
44 Wix.Fragment fragment = this.HarvestRegFile(argument);
45
46 return new Wix.Fragment[] { fragment };
47 }
48
49 /// <summary>
50 /// Harvest a reg file.
51 /// </summary>
52 /// <param name="path">The path of the file.</param>
53 /// <returns>A harvested registy file.</returns>
54 public Wix.Fragment HarvestRegFile(string path)
55 {
56 if (null == path)
57 {
58 throw new ArgumentNullException("path");
59 }
60
61 if (!File.Exists(path))
62 {
63 throw new WixException(HarvesterErrors.FileNotFound(path));
64 }
65
66 var directory = DirectoryHelper.CreateDirectory("TARGETDIR");
67
68 // Use absolute paths
69 path = Path.GetFullPath(path);
70 FileInfo file = new FileInfo(path);
71
72 using (StreamReader sr = file.OpenText())
73 {
74 string line;
75 this.currentLineNumber = 0;
76
77 while (null != (line = this.GetNextLine(sr)))
78 {
79 if (line.StartsWith(@"Windows Registry Editor Version 5.00"))
80 {
81 this.unicodeRegistry = true;
82 }
83 else if (line.StartsWith(@"REGEDIT4"))
84 {
85 this.unicodeRegistry = false;
86 }
87 else if (line.StartsWith(@"[HKEY_CLASSES_ROOT\"))
88 {
89 this.ConvertKey(sr, ref directory, Wix.RegistryRootType.HKCR, line.Substring(19, line.Length - 20));
90 }
91 else if (line.StartsWith(@"[HKEY_CURRENT_USER\"))
92 {
93 this.ConvertKey(sr, ref directory, Wix.RegistryRootType.HKCU, line.Substring(19, line.Length - 20));
94 }
95 else if (line.StartsWith(@"[HKEY_LOCAL_MACHINE\"))
96 {
97 this.ConvertKey(sr, ref directory, Wix.RegistryRootType.HKLM, line.Substring(20, line.Length - 21));
98 }
99 else if (line.StartsWith(@"[HKEY_USERS\"))
100 {
101 this.ConvertKey(sr, ref directory, Wix.RegistryRootType.HKU, line.Substring(12, line.Length - 13));
102 }
103 }
104 }
105
106 Console.WriteLine("Processing complete");
107
108 Wix.Fragment fragment = new Wix.Fragment();
109 fragment.AddChild(directory);
110
111 return fragment;
112 }
113
114 /// <summary>
115 /// Converts the registry key to a WiX component element.
116 /// </summary>
117 /// <param name="sr">The registry file stream.</param>
118 /// <param name="directory">A WiX directory reference.</param>
119 /// <param name="root">The root key.</param>
120 /// <param name="line">The current line.</param>
121 private void ConvertKey(StreamReader sr, ref Wix.DirectoryBase directory, Wix.RegistryRootType root, string line)
122 {
123 Wix.Component component = new Wix.Component();
124
125 component.Id = this.Core.GenerateIdentifier(ComponentPrefix, line);
126 component.KeyPath = Wix.YesNoType.yes;
127
128 this.ConvertValues(sr, ref component, root, line);
129 directory.AddChild(component);
130 }
131
132 /// <summary>
133 /// Converts the registry values to WiX regisry key element.
134 /// </summary>
135 /// <param name="sr">The registry file stream.</param>
136 /// <param name="component">A WiX component reference.</param>
137 /// <param name="root">The root key.</param>
138 /// <param name="line">The current line.</param>
139 private void ConvertValues(StreamReader sr, ref Wix.Component component, Wix.RegistryRootType root, string line)
140 {
141 string name = null;
142 string value = null;
143 var registryKey = new Wix.RegistryKey
144 {
145 Root = root,
146 Key = line
147 };
148
149 while (this.GetValue(sr, ref name, ref value, out var type))
150 {
151 Wix.RegistryValue registryValue = new Wix.RegistryValue();
152 ArrayList charArray;
153
154 // Don't specifiy name for default attribute
155 if (!String.IsNullOrEmpty(name))
156 {
157 registryValue.Name = name;
158 }
159
160 registryValue.Type = type;
161
162 switch (type)
163 {
164 case Wix.RegistryValue.TypeType.binary:
165 registryValue.Value = value.Replace(",", String.Empty).ToUpper();
166 break;
167
168 case Wix.RegistryValue.TypeType.integer:
169 registryValue.Value = Int32.Parse(value, NumberStyles.HexNumber).ToString();
170 break;
171
172 case Wix.RegistryValue.TypeType.expandable:
173 charArray = this.ConvertCharList(value);
174 value = String.Empty;
175
176 // create the string, remove the terminating null
177 for (int i = 0; i < charArray.Count; i++)
178 {
179 if ('\0' != (char)charArray[i])
180 {
181 value += charArray[i];
182 }
183 }
184
185 registryValue.Value = value;
186 break;
187
188 case Wix.RegistryValue.TypeType.multiString:
189 charArray = this.ConvertCharList(value);
190 value = String.Empty;
191
192 // Convert the character array to a string so we can simply split it at the nulls, ignore the final null null.
193 for (int i = 0; i < (charArray.Count - 2); i++)
194 {
195 value += charArray[i];
196 }
197
198 // Although the value can use [~] the preffered way is to use MultiStringValue
199 string[] parts = value.Split("\0".ToCharArray());
200 foreach (string part in parts)
201 {
202 Wix.MultiStringValue multiStringValue = new Wix.MultiStringValue();
203 multiStringValue.Value = part;
204 registryValue.AddChild(multiStringValue);
205 }
206
207 break;
208
209 case Wix.RegistryValue.TypeType.@string:
210 // Remove \\ and \"
211 value = value.ToString().Replace("\\\"", "\"");
212 value = value.ToString().Replace(@"\\", @"\");
213 // Escape [ and ]
214 value = value.ToString().Replace(@"[", @"[\[]");
215 value = value.ToString().Replace(@"]", @"[\]]");
216 // This undoes the duplicate escaping caused by the second replace
217 value = value.ToString().Replace(@"[\[[\]]", @"[\[]");
218 // Escape $
219 value = value.ToString().Replace(@"$", @"$$");
220
221 registryValue.Value = value;
222 break;
223
224 default:
225 throw new ApplicationException(String.Format("Did not recognize the type of reg value on line {0}", this.currentLineNumber));
226 }
227
228 registryKey.AddChild(registryValue);
229 }
230
231 // Make sure empty keys are created
232 if (null == value)
233 {
234 registryKey.ForceCreateOnInstall = Wix.YesNoType.yes;
235 }
236
237 component.AddChild(registryKey);
238 }
239
240 /// <summary>
241 /// Parse a value from a line.
242 /// </summary>
243 /// <param name="sr">Reader for the reg file.</param>
244 /// <param name="name">Name of the value.</param>
245 /// <param name="value">Value of the value.</param>
246 /// <param name="type">Type of the value.</param>
247 /// <returns>true if the value can be parsed, false otherwise.</returns>
248 private bool GetValue(StreamReader sr, ref string name, ref string value, out Wix.RegistryValue.TypeType type)
249 {
250 string line = this.GetNextLine(sr);
251
252 if (null == line || 0 == line.Length)
253 {
254 type = 0;
255 return false;
256 }
257
258 string[] parts;
259
260 if (line.StartsWith("@"))
261 {
262 // Special case for default value
263 parts = line.Trim().Split("=".ToCharArray(), 2);
264
265 name = null;
266 }
267 else
268 {
269 parts = line.Trim().Split("=".ToCharArray());
270
271 // It is valid to have an '=' in the name or the data. This is probably a string so the separator will be '"="'.
272 if (2 != parts.Length)
273 {
274 string[] stringSeparator = new string[] { "\"=\"" };
275 parts = line.Trim().Split(stringSeparator, StringSplitOptions.None);
276
277 if (2 != parts.Length)
278 {
279 // Line still no parsed correctly
280 throw new ApplicationException(String.Format("Cannot parse value: {0} at line {1}.", line, this.currentLineNumber));
281 }
282
283 // Put back quotes stripped by Split()
284 parts[0] += "\"";
285 parts[1] = "\"" + parts[1];
286 }
287
288 name = parts[0].Substring(1, parts[0].Length - 2);
289 }
290
291 if (parts[1].StartsWith("hex:"))
292 {
293 // binary
294 value = parts[1].Substring(4);
295 type = Wix.RegistryValue.TypeType.binary;
296 }
297 else if (parts[1].StartsWith("dword:"))
298 {
299 // dword
300 value = parts[1].Substring(6);
301 type = Wix.RegistryValue.TypeType.integer;
302 }
303 else if (parts[1].StartsWith("hex(2):"))
304 {
305 // expandable string
306 value = parts[1].Substring(7);
307 type = Wix.RegistryValue.TypeType.expandable;
308 }
309 else if (parts[1].StartsWith("hex(7):"))
310 {
311 // multi-string
312 value = parts[1].Substring(7);
313 type = Wix.RegistryValue.TypeType.multiString;
314 }
315 else if (parts[1].StartsWith("hex("))
316 {
317 // Give a better error when we find something that isn't supported
318 // by specifying the type that isn't supported.
319 string unsupportedType = "";
320
321 if (parts[1].StartsWith("hex(0")) { unsupportedType = "REG_NONE"; }
322 else if (parts[1].StartsWith("hex(6")) { unsupportedType = "REG_LINK"; }
323 else if (parts[1].StartsWith("hex(8")) { unsupportedType = "REG_RESOURCE_LIST"; }
324 else if (parts[1].StartsWith("hex(9")) { unsupportedType = "REG_FULL_RESOURCE_DESCRIPTOR"; }
325 else if (parts[1].StartsWith("hex(a")) { unsupportedType = "REG_RESOURCE_REQUIREMENTS_LIST"; }
326 else if (parts[1].StartsWith("hex(b")) { unsupportedType = "REG_QWORD"; }
327
328 // REG_NONE(0), REG_LINK(6), REG_RESOURCE_LIST(8), REG_FULL_RESOURCE_DESCRIPTOR(9), REG_RESOURCE_REQUIREMENTS_LIST(a), REG_QWORD(b)
329 this.Core.Messaging.Write(HarvesterWarnings.UnsupportedRegistryType(parts[0], this.currentLineNumber, unsupportedType));
330
331 type = 0;
332 return false;
333 }
334 else if (parts[1].StartsWith("\""))
335 {
336 // string
337 value = parts[1].Substring(1, parts[1].Length - 2);
338 type = Wix.RegistryValue.TypeType.@string;
339 }
340 else
341 {
342 // unsupported value
343 throw new ApplicationException(String.Format("Unsupported registry value {0} at line {1}.", line, this.currentLineNumber));
344 }
345
346 return true;
347 }
348
349 /// <summary>
350 /// Get the next line from the reg file input stream.
351 /// </summary>
352 /// <param name="sr">Reader for the reg file.</param>
353 /// <returns>The next line.</returns>
354 private string GetNextLine(StreamReader sr)
355 {
356 string line;
357 string totalLine = null;
358
359 while (null != (line = sr.ReadLine()))
360 {
361 bool stop = true;
362
363 this.currentLineNumber++;
364 line = line.Trim();
365
366 if (line.EndsWith("\\"))
367 {
368 stop = false;
369 line = line.Substring(0, line.Length - 1);
370 }
371
372 if (null == totalLine)
373 {
374 // first line
375 totalLine = line;
376 }
377 else
378 {
379 // other lines
380 totalLine += line;
381 }
382
383 // break if there is no more info for this line
384 if (stop)
385 {
386 break;
387 }
388 }
389
390 return totalLine;
391 }
392
393 /// <summary>
394 /// Convert a character list into the proper WiX format for either unicode or ansi lists.
395 /// </summary>
396 /// <param name="charList">List of characters.</param>
397 /// <returns>Array of characters.</returns>
398 private ArrayList ConvertCharList(string charList)
399 {
400 if (String.IsNullOrEmpty(charList))
401 {
402 return new ArrayList();
403 }
404
405 string[] strChars = charList.Split(",".ToCharArray());
406
407 ArrayList charArray = new ArrayList();
408
409 if (this.unicodeRegistry)
410 {
411 if (0 != strChars.Length % 2)
412 {
413 throw new ApplicationException(String.Format("Problem parsing Expandable string data at line {0}, its probably not Unicode.", this.currentLineNumber));
414 }
415
416 for (int i = 0; i < strChars.Length; i += 2)
417 {
418 string chars = strChars[i + 1] + strChars[i];
419 int unicodeInt = Int32.Parse(chars, NumberStyles.HexNumber);
420 char unicodeChar = (char)unicodeInt;
421 charArray.Add(unicodeChar);
422 }
423 }
424 else
425 {
426 for (int i = 0; i < strChars.Length; i++)
427 {
428 char charValue = (char)Int32.Parse(strChars[i], NumberStyles.HexNumber);
429 charArray.Add(charValue);
430 }
431 }
432
433 return charArray;
434 }
435 }
436}