aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/Common.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core/Common.cs')
-rw-r--r--src/WixToolset.Core/Common.cs324
1 files changed, 129 insertions, 195 deletions
diff --git a/src/WixToolset.Core/Common.cs b/src/WixToolset.Core/Common.cs
index 79f06135..848f009a 100644
--- a/src/WixToolset.Core/Common.cs
+++ b/src/WixToolset.Core/Common.cs
@@ -18,124 +18,35 @@ namespace WixToolset.Core
18 /// <summary> 18 /// <summary>
19 /// Common Wix utility methods and types. 19 /// Common Wix utility methods and types.
20 /// </summary> 20 /// </summary>
21 public static class Common 21 internal static class Common
22 { 22 {
23 // TODO: Find a place to put all of these so they doesn't have to be public and exposed by WixToolset.Core.dll 23 private static readonly char[] IllegalShortFilenameCharacters = new[] { '\\', '?', '|', '>', '<', ':', '/', '*', '\"', '+', ',', ';', '=', '[', ']', '.', ' ' };
24 /// <summary> 24 private static readonly char[] IllegalWildcardShortFilenameCharacters = new[] { '\\', '|', '>', '<', ':', '/', '\"', '+', ',', ';', '=', '[', ']', '.', ' ' };
25 ///
26 /// </summary>
27 public const string UpgradeDetectedProperty = "WIX_UPGRADE_DETECTED";
28 /// <summary>
29 ///
30 /// </summary>
31 public const string UpgradePreventedCondition = "NOT WIX_UPGRADE_DETECTED";
32 /// <summary>
33 ///
34 /// </summary>
35 public const string DowngradeDetectedProperty = "WIX_DOWNGRADE_DETECTED";
36 /// <summary>
37 ///
38 /// </summary>
39 public const string DowngradePreventedCondition = "NOT WIX_DOWNGRADE_DETECTED";
40
41 //-------------------------------------------------------------------------------------------------
42 // Layout of an Access Mask (from http://technet.microsoft.com/en-us/library/cc783530(WS.10).aspx)
43 //
44 // -------------------------------------------------------------------------------------------------
45 // |31|30|29|28|27|26|25|24|23|22|21|20|19|18|17|16|15|14|13|12|11|10|09|08|07|06|05|04|03|02|01|00|
46 // -------------------------------------------------------------------------------------------------
47 // |GR|GW|GE|GA| Reserved |AS|StandardAccessRights| Object-Specific Access Rights |
48 //
49 // Key
50 // GR = Generic Read
51 // GW = Generic Write
52 // GE = Generic Execute
53 // GA = Generic All
54 // AS = Right to access SACL
55 //
56 // TODO: what is the expected decompile behavior if a bit is found that is not explicitly enumerated
57 //
58 //-------------------------------------------------------------------------------------------------
59 // Generic Access Rights (per WinNT.h)
60 // ---------------------
61 // GENERIC_ALL (0x10000000L)
62 // GENERIC_EXECUTE (0x20000000L)
63 // GENERIC_WRITE (0x40000000L)
64 // GENERIC_READ (0x80000000L)
65 // TODO: Find a place to put this that it doesn't have to be public and exposed by WixToolset.Core.dll
66 /// <summary>
67 ///
68 /// </summary>
69 public static readonly string[] GenericPermissions = { "GenericAll", "GenericExecute", "GenericWrite", "GenericRead" };
70
71 // Standard Access Rights (per WinNT.h)
72 // ----------------------
73 // DELETE (0x00010000L)
74 // READ_CONTROL (0x00020000L)
75 // WRITE_DAC (0x00040000L)
76 // WRITE_OWNER (0x00080000L)
77 // SYNCHRONIZE (0x00100000L)
78 // TODO: Find a place to put this that it doesn't have to be public and exposed by WixToolset.Core.dll
79 /// <summary>
80 ///
81 /// </summary>
82 public static readonly string[] StandardPermissions = { "Delete", "ReadPermission", "ChangePermission", "TakeOwnership", "Synchronize" };
83
84 // Object-Specific Access Rights
85 // =============================
86 // Directory Access Rights (per WinNT.h)
87 // -----------------------
88 // FILE_LIST_DIRECTORY ( 0x0001 )
89 // FILE_ADD_FILE ( 0x0002 )
90 // FILE_ADD_SUBDIRECTORY ( 0x0004 )
91 // FILE_READ_EA ( 0x0008 )
92 // FILE_WRITE_EA ( 0x0010 )
93 // FILE_TRAVERSE ( 0x0020 )
94 // FILE_DELETE_CHILD ( 0x0040 )
95 // FILE_READ_ATTRIBUTES ( 0x0080 )
96 // FILE_WRITE_ATTRIBUTES ( 0x0100 )
97 // TODO: Find a place to put this that it doesn't have to be public and exposed by WixToolset.Core.dll
98 /// <summary>
99 ///
100 /// </summary>
101 public static readonly string[] FolderPermissions = { "Read", "CreateFile", "CreateChild", "ReadExtendedAttributes", "WriteExtendedAttributes", "Traverse", "DeleteChild", "ReadAttributes", "WriteAttributes" };
102
103 // Registry Access Rights (per TODO)
104 // ----------------------
105 // TODO: Find a place to put this that it doesn't have to be public and exposed by WixToolset.Core.dll
106 /// <summary>
107 ///
108 /// </summary>
109 public static readonly string[] RegistryPermissions = { "Read", "Write", "CreateSubkeys", "EnumerateSubkeys", "Notify", "CreateLink" };
110
111 // File Access Rights (per WinNT.h)
112 // ------------------
113 // FILE_READ_DATA ( 0x0001 )
114 // FILE_WRITE_DATA ( 0x0002 )
115 // FILE_APPEND_DATA ( 0x0004 )
116 // FILE_READ_EA ( 0x0008 )
117 // FILE_WRITE_EA ( 0x0010 )
118 // FILE_EXECUTE ( 0x0020 )
119 // via mask FILE_ALL_ACCESS ( 0x0040 )
120 // FILE_READ_ATTRIBUTES ( 0x0080 )
121 // FILE_WRITE_ATTRIBUTES ( 0x0100 )
122 //
123 // STANDARD_RIGHTS_REQUIRED (0x000F0000L)
124 // FILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0x1FF)
125 // TODO: Find a place to put this that it doesn't have to be public and exposed by WixToolset.Core.dll
126 /// <summary>
127 ///
128 /// </summary>
129 public static readonly string[] FilePermissions = { "Read", "Write", "Append", "ReadExtendedAttributes", "WriteExtendedAttributes", "Execute", "FileAllRights", "ReadAttributes", "WriteAttributes" };
130 25
131 internal static readonly char[] IllegalLongFilenameCharacters = new[] { '\\', '/', '?', '*', '|', '>', '<', ':', '\"' }; // illegal: \ / ? | > < : / * " 26 internal static readonly char[] IllegalLongFilenameCharacters = new[] { '\\', '/', '?', '*', '|', '>', '<', ':', '\"' }; // illegal: \ / ? | > < : / * "
132 internal static readonly char[] IllegalRelativeLongFilenameCharacters = new[] { '?', '*', '|', '>', '<', ':', '\"' }; // like illegal, but we allow '\' and '/' 27 internal static readonly char[] IllegalRelativeLongFilenameCharacters = new[] { '?', '*', '|', '>', '<', ':', '\"' }; // like illegal, but we allow '\' and '/'
133 internal static readonly char[] IllegalWildcardLongFilenameCharacters = new[] { '\\', '/', '|', '>', '<', ':', '\"' }; // like illegal: but we allow '*' and '?' 28 internal static readonly char[] IllegalWildcardLongFilenameCharacters = new[] { '\\', '/', '|', '>', '<', ':', '\"' }; // like illegal: but we allow '*' and '?'
134 29
135 private static readonly char[] IllegalShortFilenameCharacters = new[] { '\\', '?', '|', '>', '<', ':', '/', '*', '\"', '+', ',', ';', '=', '[', ']', '.', ' ' }; 30 public static string GetCanonicalRelativePath(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string relativePath, IMessaging messageHandler)
136 private static readonly char[] IllegalWildcardShortFilenameCharacters = new[] { '\\', '|', '>', '<', ':', '/', '\"', '+', ',', ';', '=', '[', ']', '.', ' ' }; 31 {
137 32 const string root = @"C:\";
33 if (!Path.IsPathRooted(relativePath))
34 {
35 var normalizedPath = Path.GetFullPath(root + relativePath);
36 if (normalizedPath.StartsWith(root))
37 {
38 var canonicalizedPath = normalizedPath.Substring(root.Length);
39 if (canonicalizedPath != relativePath)
40 {
41 messageHandler.Write(WarningMessages.PathCanonicalized(sourceLineNumbers, elementName, attributeName, relativePath, canonicalizedPath));
42 }
43 return canonicalizedPath;
44 }
45 }
138 46
47 messageHandler.Write(ErrorMessages.PayloadMustBeRelativeToCache(sourceLineNumbers, elementName, attributeName, relativePath));
48 return relativePath;
49 }
139 50
140 /// <summary> 51 /// <summary>
141 /// Gets a valid code page from the given web name or integer value. 52 /// Gets a valid code page from the given web name or integer value.
@@ -157,8 +68,8 @@ namespace WixToolset.Core
157 { 68 {
158 Encoding encoding; 69 Encoding encoding;
159 70
160 // check if a integer as a string was passed 71 // Check if a integer as a string was passed.
161 if (Int32.TryParse(value, out int codePage)) 72 if (Int32.TryParse(value, out var codePage))
162 { 73 {
163 if (0 == codePage) 74 if (0 == codePage)
164 { 75 {
@@ -198,18 +109,91 @@ namespace WixToolset.Core
198 } 109 }
199 catch (ArgumentException ex) 110 catch (ArgumentException ex)
200 { 111 {
201 // rethrow as NotSupportedException since either can be thrown 112 // Rethrow as NotSupportedException since either can be thrown
202 // if the system does not support the specified code page 113 // if the system does not support the specified code page.
203 throw new NotSupportedException(ex.Message, ex); 114 throw new NotSupportedException(ex.Message, ex);
204 } 115 }
205 } 116 }
206 117
207 /// <summary> 118 /// <summary>
208 /// Verifies if a filename is a valid short filename. 119 /// Verifies if an identifier is a valid binder variable name.
120 /// </summary>
121 /// <param name="variable">Binder variable name to verify.</param>
122 /// <returns>True if the identifier is a valid binder variable name.</returns>
123 public static bool IsValidBinderVariable(string variable)
124 {
125 return TryParseWixVariable(variable, 0, out var parsed) && parsed.Index == 0 && parsed.Length == variable.Length && (parsed.Namespace == "bind" || parsed.Namespace == "wix");
126 }
127
128 /// <summary>
129 /// Verifies if a string contains a valid binder variable name.
130 /// </summary>
131 /// <param name="verify">String to verify.</param>
132 /// <returns>True if the string contains a valid binder variable name.</returns>
133 public static bool ContainsValidBinderVariable(string verify)
134 {
135 return TryParseWixVariable(verify, 0, out var parsed) && (parsed.Namespace == "bind" || parsed.Namespace == "wix");
136 }
137
138 /// <summary>
139 /// Verifies the given string is a valid 4-part version module or bundle version.
209 /// </summary> 140 /// </summary>
210 /// <param name="filename">Filename to verify.</param> 141 /// <param name="version">The version to verify.</param>
211 /// <param name="allowWildcards">true if wildcards are allowed in the filename.</param> 142 /// <returns>True if version is a valid module or bundle version.</returns>
212 /// <returns>True if the filename is a valid short filename</returns> 143 public static bool IsValidFourPartVersion(string version)
144 {
145 if (!Common.IsValidBinderVariable(version))
146 {
147 if (!Version.TryParse(version, out var ver) || 65535 < ver.Major || 65535 < ver.Minor || 65535 < ver.Build || 65535 < ver.Revision)
148 {
149 return false;
150 }
151 }
152
153 return true;
154 }
155
156 public static bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative)
157 {
158 if (String.IsNullOrEmpty(filename))
159 {
160 return false;
161 }
162 else if (filename.Length > 259)
163 {
164 return false;
165 }
166
167 // Check for a non-period character (all periods is not legal)
168 var allPeriods = true;
169 foreach (var character in filename)
170 {
171 if ('.' != character)
172 {
173 allPeriods = false;
174 break;
175 }
176 }
177
178 if (allPeriods)
179 {
180 return false;
181 }
182
183 if (allowWildcards)
184 {
185 return filename.IndexOfAny(Common.IllegalWildcardLongFilenameCharacters) == -1;
186 }
187 else if (allowRelative)
188 {
189 return filename.IndexOfAny(Common.IllegalRelativeLongFilenameCharacters) == -1;
190 }
191 else
192 {
193 return filename.IndexOfAny(Common.IllegalLongFilenameCharacters) == -1;
194 }
195 }
196
213 public static bool IsValidShortFilename(string filename, bool allowWildcards) 197 public static bool IsValidShortFilename(string filename, bool allowWildcards)
214 { 198 {
215 if (String.IsNullOrEmpty(filename)) 199 if (String.IsNullOrEmpty(filename))
@@ -291,55 +275,6 @@ namespace WixToolset.Core
291 } 275 }
292 276
293 /// <summary> 277 /// <summary>
294 /// Verifies if an identifier is a valid binder variable name.
295 /// </summary>
296 /// <param name="variable">Binder variable name to verify.</param>
297 /// <returns>True if the identifier is a valid binder variable name.</returns>
298 public static bool IsValidBinderVariable(string variable)
299 {
300 return TryParseWixVariable(variable, 0, out var parsed) && parsed.Index == 0 && parsed.Length == variable.Length && (parsed.Namespace == "bind" || parsed.Namespace == "wix");
301 }
302
303 /// <summary>
304 /// Verifies if a string contains a valid binder variable name.
305 /// </summary>
306 /// <param name="verify">String to verify.</param>
307 /// <returns>True if the string contains a valid binder variable name.</returns>
308 public static bool ContainsValidBinderVariable(string verify)
309 {
310 return TryParseWixVariable(verify, 0, out var parsed) && (parsed.Namespace == "bind" || parsed.Namespace == "wix");
311 }
312
313 /// <summary>
314 /// Verifies the given string is a valid module or bundle version.
315 /// </summary>
316 /// <param name="version">The version to verify.</param>
317 /// <returns>True if version is a valid module or bundle version.</returns>
318 public static bool IsValidModuleOrBundleVersion(string version)
319 {
320 if (!Common.IsValidBinderVariable(version))
321 {
322 Version ver;
323
324 try
325 {
326 ver = new Version(version);
327 }
328 catch (ArgumentException)
329 {
330 return false;
331 }
332
333 if (65535 < ver.Major || 65535 < ver.Minor || 65535 < ver.Build || 65535 < ver.Revision)
334 {
335 return false;
336 }
337 }
338
339 return true;
340 }
341
342 /// <summary>
343 /// Generate a new Windows Installer-friendly guid. 278 /// Generate a new Windows Installer-friendly guid.
344 /// </summary> 279 /// </summary>
345 /// <returns>A new guid.</returns> 280 /// <returns>A new guid.</returns>
@@ -451,14 +386,14 @@ namespace WixToolset.Core
451 /// <param name="markAttribute">If true, add the attribute to each file. If false, remove it.</param> 386 /// <param name="markAttribute">If true, add the attribute to each file. If false, remove it.</param>
452 private static void RecursiveFileAttributes(string path, FileAttributes fileAttribute, bool markAttribute, IMessaging messageHandler) 387 private static void RecursiveFileAttributes(string path, FileAttributes fileAttribute, bool markAttribute, IMessaging messageHandler)
453 { 388 {
454 foreach (string subDirectory in Directory.GetDirectories(path)) 389 foreach (var subDirectory in Directory.GetDirectories(path))
455 { 390 {
456 RecursiveFileAttributes(subDirectory, fileAttribute, markAttribute, messageHandler); 391 RecursiveFileAttributes(subDirectory, fileAttribute, markAttribute, messageHandler);
457 } 392 }
458 393
459 foreach (string filePath in Directory.GetFiles(path)) 394 foreach (var filePath in Directory.GetFiles(path))
460 { 395 {
461 FileAttributes attributes = File.GetAttributes(filePath); 396 var attributes = File.GetAttributes(filePath);
462 if (markAttribute) 397 if (markAttribute)
463 { 398 {
464 attributes = attributes | fileAttribute; // add to list of attributes 399 attributes = attributes | fileAttribute; // add to list of attributes
@@ -506,16 +441,15 @@ namespace WixToolset.Core
506 /// <returns>An array of strings of length 4. The contents are: short target, long target, short source, and long source.</returns> 441 /// <returns>An array of strings of length 4. The contents are: short target, long target, short source, and long source.</returns>
507 /// <remarks> 442 /// <remarks>
508 /// If any particular file name part is not parsed, its set to null in the appropriate location of the returned array of strings. 443 /// If any particular file name part is not parsed, its set to null in the appropriate location of the returned array of strings.
509 /// However, the returned array will always be of length 4. 444 /// Thus the returned array will always be of length 4.
510 /// </remarks> 445 /// </remarks>
511 public static string[] GetNames(string value) 446 public static string[] GetNames(string value)
512 { 447 {
513 string[] names = new string[4]; 448 var targetSeparator = value.IndexOf(':');
514 int targetSeparator = value.IndexOf(':');
515 449
516 // split source and target 450 // split source and target
517 string sourceName = null; 451 string sourceName = null;
518 string targetName = value; 452 var targetName = value;
519 if (0 <= targetSeparator) 453 if (0 <= targetSeparator)
520 { 454 {
521 sourceName = value.Substring(targetSeparator + 1); 455 sourceName = value.Substring(targetSeparator + 1);
@@ -526,7 +460,7 @@ namespace WixToolset.Core
526 string sourceLongName = null; 460 string sourceLongName = null;
527 if (null != sourceName) 461 if (null != sourceName)
528 { 462 {
529 int sourceLongNameSeparator = sourceName.IndexOf('|'); 463 var sourceLongNameSeparator = sourceName.IndexOf('|');
530 if (0 <= sourceLongNameSeparator) 464 if (0 <= sourceLongNameSeparator)
531 { 465 {
532 sourceLongName = sourceName.Substring(sourceLongNameSeparator + 1); 466 sourceLongName = sourceName.Substring(sourceLongNameSeparator + 1);
@@ -535,7 +469,7 @@ namespace WixToolset.Core
535 } 469 }
536 470
537 // split the target short and long names 471 // split the target short and long names
538 int targetLongNameSeparator = targetName.IndexOf('|'); 472 var targetLongNameSeparator = targetName.IndexOf('|');
539 string targetLongName = null; 473 string targetLongName = null;
540 if (0 <= targetLongNameSeparator) 474 if (0 <= targetLongNameSeparator)
541 { 475 {
@@ -543,19 +477,19 @@ namespace WixToolset.Core
543 targetName = targetName.Substring(0, targetLongNameSeparator); 477 targetName = targetName.Substring(0, targetLongNameSeparator);
544 } 478 }
545 479
546 // remove the long source name when its identical to the long source name 480 // Remove the long source name when its identical to the short source name.
547 if (null != sourceName && sourceName == sourceLongName) 481 if (null != sourceName && sourceName == sourceLongName)
548 { 482 {
549 sourceLongName = null; 483 sourceLongName = null;
550 } 484 }
551 485
552 // remove the long target name when its identical to the long target name 486 // Remove the long target name when its identical to the long target name.
553 if (null != targetName && targetName == targetLongName) 487 if (null != targetName && targetName == targetLongName)
554 { 488 {
555 targetLongName = null; 489 targetLongName = null;
556 } 490 }
557 491
558 // remove the source names when they are identical to the target names 492 // Remove the source names when they are identical to the target names.
559 if (sourceName == targetName && sourceLongName == targetLongName) 493 if (sourceName == targetName && sourceLongName == targetLongName)
560 { 494 {
561 sourceName = null; 495 sourceName = null;
@@ -563,28 +497,28 @@ namespace WixToolset.Core
563 } 497 }
564 498
565 // target name(s) 499 // target name(s)
566 if ("." != targetName) 500 if ("." == targetName)
567 { 501 {
568 names[0] = targetName; 502 targetName = null;
569 } 503 }
570 504
571 if (null != targetLongName && "." != targetLongName) 505 if ("." == targetLongName)
572 { 506 {
573 names[1] = targetLongName; 507 targetLongName = null;
574 } 508 }
575 509
576 // source name(s) 510 // source name(s)
577 if (null != sourceName) 511 if ("." == sourceName)
578 { 512 {
579 names[2] = sourceName; 513 sourceName = null;
580 } 514 }
581 515
582 if (null != sourceLongName && "." != sourceLongName) 516 if ("." == sourceLongName)
583 { 517 {
584 names[3] = sourceLongName; 518 sourceLongName = null;
585 } 519 }
586 520
587 return names; 521 return new[] { targetName, targetLongName, sourceName, sourceLongName };
588 } 522 }
589 523
590 /// <summary> 524 /// <summary>
@@ -596,7 +530,7 @@ namespace WixToolset.Core
596 /// <returns>The name.</returns> 530 /// <returns>The name.</returns>
597 public static string GetName(string value, bool source, bool longName) 531 public static string GetName(string value, bool source, bool longName)
598 { 532 {
599 string[] names = GetNames(value); 533 var names = GetNames(value);
600 534
601 if (source) 535 if (source)
602 { 536 {
@@ -674,7 +608,7 @@ namespace WixToolset.Core
674 /// <returns>The attribute's identifier value or a special value if an error occurred.</returns> 608 /// <returns>The attribute's identifier value or a special value if an error occurred.</returns>
675 internal static string GetAttributeIdentifierValue(IMessaging messaging, SourceLineNumber sourceLineNumbers, XAttribute attribute) 609 internal static string GetAttributeIdentifierValue(IMessaging messaging, SourceLineNumber sourceLineNumbers, XAttribute attribute)
676 { 610 {
677 string value = Common.GetAttributeValue(messaging, sourceLineNumbers, attribute, EmptyRule.CanBeWhitespaceOnly); 611 var value = Common.GetAttributeValue(messaging, sourceLineNumbers, attribute, EmptyRule.CanBeWhitespaceOnly);
678 612
679 if (Common.IsIdentifier(value)) 613 if (Common.IsIdentifier(value))
680 { 614 {
@@ -713,8 +647,8 @@ namespace WixToolset.Core
713 { 647 {
714 Debug.Assert(minimum > CompilerConstants.IntegerNotSet && minimum > CompilerConstants.IllegalInteger, "The legal values for this attribute collide with at least one sentinel used during parsing."); 648 Debug.Assert(minimum > CompilerConstants.IntegerNotSet && minimum > CompilerConstants.IllegalInteger, "The legal values for this attribute collide with at least one sentinel used during parsing.");
715 649
716 string value = Common.GetAttributeValue(messaging, sourceLineNumbers, attribute, EmptyRule.CanBeWhitespaceOnly); 650 var value = Common.GetAttributeValue(messaging, sourceLineNumbers, attribute, EmptyRule.CanBeWhitespaceOnly);
717 int integer = CompilerConstants.IllegalInteger; 651 var integer = CompilerConstants.IllegalInteger;
718 652
719 if (0 < value.Length) 653 if (0 < value.Length)
720 { 654 {
@@ -748,8 +682,8 @@ namespace WixToolset.Core
748 /// <returns>The attribute's YesNoType value.</returns> 682 /// <returns>The attribute's YesNoType value.</returns>
749 internal static YesNoType GetAttributeYesNoValue(IMessaging messaging, SourceLineNumber sourceLineNumbers, XAttribute attribute) 683 internal static YesNoType GetAttributeYesNoValue(IMessaging messaging, SourceLineNumber sourceLineNumbers, XAttribute attribute)
750 { 684 {
751 string value = Common.GetAttributeValue(messaging, sourceLineNumbers, attribute, EmptyRule.CanBeWhitespaceOnly); 685 var value = Common.GetAttributeValue(messaging, sourceLineNumbers, attribute, EmptyRule.CanBeWhitespaceOnly);
752 YesNoType yesNo = YesNoType.IllegalValue; 686 var yesNo = YesNoType.IllegalValue;
753 687
754 if ("yes".Equals(value) || "true".Equals(value)) 688 if ("yes".Equals(value) || "true".Equals(value))
755 { 689 {