aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/CompilerCore.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core/CompilerCore.cs')
-rw-r--r--src/WixToolset.Core/CompilerCore.cs760
1 files changed, 92 insertions, 668 deletions
diff --git a/src/WixToolset.Core/CompilerCore.cs b/src/WixToolset.Core/CompilerCore.cs
index 46a2e435..26c19acc 100644
--- a/src/WixToolset.Core/CompilerCore.cs
+++ b/src/WixToolset.Core/CompilerCore.cs
@@ -1,6 +1,6 @@
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. 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 2
3namespace WixToolset 3namespace WixToolset.Core
4{ 4{
5 using System; 5 using System;
6 using System.Collections; 6 using System.Collections;
@@ -17,6 +17,7 @@ namespace WixToolset
17 using WixToolset.Data; 17 using WixToolset.Data;
18 using WixToolset.Data.Tuples; 18 using WixToolset.Data.Tuples;
19 using WixToolset.Extensibility; 19 using WixToolset.Extensibility;
20 using WixToolset.Extensibility.Services;
20 using Wix = WixToolset.Data.Serialize; 21 using Wix = WixToolset.Data.Serialize;
21 22
22 internal enum ValueListKind 23 internal enum ValueListKind
@@ -40,7 +41,7 @@ namespace WixToolset
40 /// <summary> 41 /// <summary>
41 /// Core class for the compiler. 42 /// Core class for the compiler.
42 /// </summary> 43 /// </summary>
43 internal sealed class CompilerCore //: ICompilerCore 44 internal sealed class CompilerCore
44 { 45 {
45 internal static readonly XNamespace W3SchemaPrefix = "http://www.w3.org/"; 46 internal static readonly XNamespace W3SchemaPrefix = "http://www.w3.org/";
46 internal static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs"; 47 internal static readonly XNamespace WixNamespace = "http://wixtoolset.org/schemas/v4/wxs";
@@ -50,19 +51,6 @@ namespace WixToolset
50 private const string IllegalLongFilenameCharacters = @"[\\\?|><:/\*""]"; // illegal: \ ? | > < : / * " 51 private const string IllegalLongFilenameCharacters = @"[\\\?|><:/\*""]"; // illegal: \ ? | > < : / * "
51 private static readonly Regex IllegalLongFilename = new Regex(IllegalLongFilenameCharacters, RegexOptions.Compiled); 52 private static readonly Regex IllegalLongFilename = new Regex(IllegalLongFilenameCharacters, RegexOptions.Compiled);
52 53
53 private const string LegalLongFilenameCharacters = @"[^\\\?|><:/\*""]"; // opposite of illegal above.
54 private static readonly Regex LegalLongFilename = new Regex(String.Concat("^", LegalLongFilenameCharacters, @"{1,259}$"), RegexOptions.Compiled);
55
56 private const string LegalRelativeLongFilenameCharacters = @"[^\?|><:/\*""]"; // (like legal long, but we allow '\') illegal: ? | > < : / * "
57 private static readonly Regex LegalRelativeLongFilename = new Regex(String.Concat("^", LegalRelativeLongFilenameCharacters, @"{1,259}$"), RegexOptions.Compiled);
58
59 private const string LegalWildcardLongFilenameCharacters = @"[^\\|><:/""]"; // illegal: \ | > < : / "
60 private static readonly Regex LegalWildcardLongFilename = new Regex(String.Concat("^", LegalWildcardLongFilenameCharacters, @"{1,259}$"));
61
62 private static readonly Regex PutGuidHere = new Regex(@"PUT\-GUID\-(?:\d+\-)?HERE", RegexOptions.Singleline);
63
64 private static readonly Regex LegalIdentifierWithAccess = new Regex(@"^((?<access>public|internal|protected|private)\s+)?(?<id>[_A-Za-z][0-9A-Za-z_\.]*)$", RegexOptions.Compiled | RegexOptions.ExplicitCapture);
65
66 public const int DefaultMaximumUncompressedMediaSize = 200; // Default value is 200 MB 54 public const int DefaultMaximumUncompressedMediaSize = 200; // Default value is 200 MB
67 public const int MinValueOfMaxCabSizeForLargeFileSplitting = 20; // 20 MB 55 public const int MinValueOfMaxCabSizeForLargeFileSplitting = 20; // 20 MB
68 public const int MaxValueOfMaxCabSizeForLargeFileSplitting = 2 * 1024; // 2048 MB (i.e. 2 GB) 56 public const int MaxValueOfMaxCabSizeForLargeFileSplitting = 2 * 1024; // 2048 MB (i.e. 2 GB)
@@ -141,7 +129,7 @@ namespace WixToolset
141 }); 129 });
142 130
143 private Dictionary<XNamespace, ICompilerExtension> extensions; 131 private Dictionary<XNamespace, ICompilerExtension> extensions;
144 private ITupleDefinitionCreator creator; 132 private IParseHelper parseHelper;
145 private Intermediate intermediate; 133 private Intermediate intermediate;
146 134
147 private HashSet<string> activeSectionInlinedDirectoryIds; 135 private HashSet<string> activeSectionInlinedDirectoryIds;
@@ -152,10 +140,10 @@ namespace WixToolset
152 /// </summary> 140 /// </summary>
153 /// <param name="intermediate">The Intermediate object representing compiled source document.</param> 141 /// <param name="intermediate">The Intermediate object representing compiled source document.</param>
154 /// <param name="extensions">The WiX extensions collection.</param> 142 /// <param name="extensions">The WiX extensions collection.</param>
155 internal CompilerCore(Intermediate intermediate, ITupleDefinitionCreator creator, Dictionary<XNamespace, ICompilerExtension> extensions) 143 internal CompilerCore(Intermediate intermediate, IParseHelper parseHelper, Dictionary<XNamespace, ICompilerExtension> extensions)
156 { 144 {
157 this.extensions = extensions; 145 this.extensions = extensions;
158 this.creator = creator; 146 this.parseHelper = parseHelper;
159 this.intermediate = intermediate; 147 this.intermediate = intermediate;
160 } 148 }
161 149
@@ -166,12 +154,6 @@ namespace WixToolset
166 public IntermediateSection ActiveSection { get; private set; } 154 public IntermediateSection ActiveSection { get; private set; }
167 155
168 /// <summary> 156 /// <summary>
169 /// Gets or sets the platform which the compiler will use when defaulting 64-bit attributes and elements.
170 /// </summary>
171 /// <value>The platform which the compiler will use when defaulting 64-bit attributes and elements.</value>
172 public Platform CurrentPlatform { get; set; }
173
174 /// <summary>
175 /// Gets whether the compiler core encountered an error while processing. 157 /// Gets whether the compiler core encountered an error while processing.
176 /// </summary> 158 /// </summary>
177 /// <value>Flag if core encountered an error during processing.</value> 159 /// <value>Flag if core encountered an error during processing.</value>
@@ -231,12 +213,7 @@ namespace WixToolset
231 /// <returns>true if the filename is ambiguous; false otherwise.</returns> 213 /// <returns>true if the filename is ambiguous; false otherwise.</returns>
232 public static bool IsAmbiguousFilename(string filename) 214 public static bool IsAmbiguousFilename(string filename)
233 { 215 {
234 if (null == filename || 0 == filename.Length) 216 return String.IsNullOrEmpty(filename) ? false : CompilerCore.AmbiguousFilename.IsMatch(filename);
235 {
236 return false;
237 }
238
239 return CompilerCore.AmbiguousFilename.IsMatch(filename);
240 } 217 }
241 218
242 /// <summary> 219 /// <summary>
@@ -246,7 +223,7 @@ namespace WixToolset
246 /// <returns>true if the value is an identifier; false otherwise.</returns> 223 /// <returns>true if the value is an identifier; false otherwise.</returns>
247 public bool IsValidIdentifier(string value) 224 public bool IsValidIdentifier(string value)
248 { 225 {
249 return Common.IsIdentifier(value); 226 return this.parseHelper.IsValidIdentifier(value);
250 } 227 }
251 228
252 /// <summary> 229 /// <summary>
@@ -256,14 +233,7 @@ namespace WixToolset
256 /// <returns>True if the identifier is a valid loc identifier.</returns> 233 /// <returns>True if the identifier is a valid loc identifier.</returns>
257 public bool IsValidLocIdentifier(string identifier) 234 public bool IsValidLocIdentifier(string identifier)
258 { 235 {
259 if (String.IsNullOrEmpty(identifier)) 236 return this.parseHelper.IsValidIdentifier(identifier);
260 {
261 return false;
262 }
263
264 Match match = Common.WixVariableRegex.Match(identifier);
265
266 return (match.Success && "loc" == match.Groups["namespace"].Value && 0 == match.Index && identifier.Length == match.Length);
267 } 237 }
268 238
269 /// <summary> 239 /// <summary>
@@ -275,34 +245,7 @@ namespace WixToolset
275 /// <returns>True if the filename is a valid long filename</returns> 245 /// <returns>True if the filename is a valid long filename</returns>
276 public bool IsValidLongFilename(string filename, bool allowWildcards = false, bool allowRelative = false) 246 public bool IsValidLongFilename(string filename, bool allowWildcards = false, bool allowRelative = false)
277 { 247 {
278 if (String.IsNullOrEmpty(filename)) 248 return this.parseHelper.IsValidLongFilename(filename, allowWildcards, allowRelative);
279 {
280 return false;
281 }
282
283 // check for a non-period character (all periods is not legal)
284 bool nonPeriodFound = false;
285 foreach (char character in filename)
286 {
287 if ('.' != character)
288 {
289 nonPeriodFound = true;
290 break;
291 }
292 }
293
294 if (allowWildcards)
295 {
296 return (nonPeriodFound && CompilerCore.LegalWildcardLongFilename.IsMatch(filename));
297 }
298 else if (allowRelative)
299 {
300 return (nonPeriodFound && CompilerCore.LegalRelativeLongFilename.IsMatch(filename));
301 }
302 else
303 {
304 return (nonPeriodFound && CompilerCore.LegalLongFilename.IsMatch(filename));
305 }
306 } 249 }
307 250
308 /// <summary> 251 /// <summary>
@@ -313,7 +256,7 @@ namespace WixToolset
313 /// <returns>True if the filename is a valid short filename</returns> 256 /// <returns>True if the filename is a valid short filename</returns>
314 public bool IsValidShortFilename(string filename, bool allowWildcards) 257 public bool IsValidShortFilename(string filename, bool allowWildcards)
315 { 258 {
316 return Common.IsValidShortFilename(filename, allowWildcards); 259 return this.parseHelper.IsValidShortFilename(filename, allowWildcards);
317 } 260 }
318 261
319 /// <summary> 262 /// <summary>
@@ -337,52 +280,7 @@ namespace WixToolset
337 /// <returns>The generated 8.3-compliant short file/directory name.</returns> 280 /// <returns>The generated 8.3-compliant short file/directory name.</returns>
338 public string CreateShortName(string longName, bool keepExtension, bool allowWildcards, params string[] args) 281 public string CreateShortName(string longName, bool keepExtension, bool allowWildcards, params string[] args)
339 { 282 {
340 // canonicalize the long name if its not a localization identifier (they are case-sensitive) 283 return this.parseHelper.CreateShortName(longName, keepExtension, allowWildcards, args);
341 if (!this.IsValidLocIdentifier(longName))
342 {
343 longName = longName.ToLowerInvariant();
344 }
345
346 // collect all the data
347 List<string> strings = new List<string>(1 + args.Length);
348 strings.Add(longName);
349 strings.AddRange(args);
350
351 // prepare for hashing
352 string stringData = String.Join("|", strings);
353 byte[] data = Encoding.UTF8.GetBytes(stringData);
354
355 // hash the data
356 byte[] hash;
357 using (SHA1 sha1 = new SHA1CryptoServiceProvider())
358 {
359 hash = sha1.ComputeHash(data);
360 }
361
362 // generate the short file/directory name without an extension
363 StringBuilder shortName = new StringBuilder(Convert.ToBase64String(hash));
364 shortName.Remove(8, shortName.Length - 8).Replace('+', '-').Replace('/', '_');
365
366 if (keepExtension)
367 {
368 string extension = Path.GetExtension(longName);
369
370 if (4 < extension.Length)
371 {
372 extension = extension.Substring(0, 4);
373 }
374
375 shortName.Append(extension);
376
377 // check the generated short name to ensure its still legal (the extension may not be legal)
378 if (!this.IsValidShortFilename(shortName.ToString(), allowWildcards))
379 {
380 // remove the extension (by truncating the generated file name back to the generated characters)
381 shortName.Length -= extension.Length;
382 }
383 }
384
385 return shortName.ToString().ToLowerInvariant();
386 } 284 }
387 285
388 /// <summary> 286 /// <summary>
@@ -422,8 +320,7 @@ namespace WixToolset
422 /// <returns>The node's inner text trimmed.</returns> 320 /// <returns>The node's inner text trimmed.</returns>
423 public string GetTrimmedInnerText(XElement element) 321 public string GetTrimmedInnerText(XElement element)
424 { 322 {
425 string value = Common.GetInnerText(element); 323 return this.parseHelper.GetTrimmedInnerText(element);
426 return (null == value) ? null : value.Trim();
427 } 324 }
428 325
429 /// <summary> 326 /// <summary>
@@ -431,23 +328,9 @@ namespace WixToolset
431 /// </summary> 328 /// </summary>
432 /// <param name="element">The element to ensure inner text is a condition.</param> 329 /// <param name="element">The element to ensure inner text is a condition.</param>
433 /// <returns>The value converted into a safe condition.</returns> 330 /// <returns>The value converted into a safe condition.</returns>
434 [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")]
435 public string GetConditionInnerText(XElement element) 331 public string GetConditionInnerText(XElement element)
436 { 332 {
437 string value = element.Value; 333 return this.parseHelper.GetConditionInnerText(element);
438 if (0 < value.Length)
439 {
440 value = value.Trim();
441 value = value.Replace('\t', ' ');
442 value = value.Replace('\r', ' ');
443 value = value.Replace('\n', ' ');
444 }
445 else // return null for a non-existant condition
446 {
447 value = null;
448 }
449
450 return value;
451 } 334 }
452 335
453 /// <summary> 336 /// <summary>
@@ -458,7 +341,7 @@ namespace WixToolset
458 /// <returns>The generated GUID for the given namespace and value.</returns> 341 /// <returns>The generated GUID for the given namespace and value.</returns>
459 public string CreateGuid(Guid namespaceGuid, string value) 342 public string CreateGuid(Guid namespaceGuid, string value)
460 { 343 {
461 return Uuid.NewUuid(namespaceGuid, value).ToString("B").ToUpperInvariant(); 344 return this.parseHelper.CreateGuid(namespaceGuid, value);
462 } 345 }
463 346
464 /// <summary> 347 /// <summary>
@@ -510,46 +393,7 @@ namespace WixToolset
510 /// <returns>Identifier of the leaf directory created.</returns> 393 /// <returns>Identifier of the leaf directory created.</returns>
511 public string CreateDirectoryReferenceFromInlineSyntax(SourceLineNumber sourceLineNumbers, XAttribute attribute, string parentId) 394 public string CreateDirectoryReferenceFromInlineSyntax(SourceLineNumber sourceLineNumbers, XAttribute attribute, string parentId)
512 { 395 {
513 string id = null; 396 return this.parseHelper.CreateDirectoryReferenceFromInlineSyntax(this.ActiveSection, sourceLineNumbers, attribute, parentId);
514 string[] inlineSyntax = this.GetAttributeInlineDirectorySyntax(sourceLineNumbers, attribute, true);
515
516 if (null != inlineSyntax)
517 {
518 // Special case the single entry in the inline syntax since it is the most common case
519 // and needs no extra processing. It's just a reference to an existing directory.
520 if (1 == inlineSyntax.Length)
521 {
522 id = inlineSyntax[0];
523 this.CreateSimpleReference(sourceLineNumbers, "Directory", id);
524 }
525 else // start creating rows for the entries in the inline syntax
526 {
527 id = parentId;
528
529 int pathStartsAt = 0;
530 if (inlineSyntax[0].EndsWith(":"))
531 {
532 // TODO: should overriding the parent identifier with a specific id be an error or a warning or just let it slide?
533 //if (null != parentId)
534 //{
535 // this.core.OnMessage(WixErrors.Xxx(sourceLineNumbers));
536 //}
537
538 id = inlineSyntax[0].TrimEnd(':');
539 this.CreateSimpleReference(sourceLineNumbers, "Directory", id);
540
541 pathStartsAt = 1;
542 }
543
544 for (int i = pathStartsAt; i < inlineSyntax.Length; ++i)
545 {
546 Identifier inlineId = this.CreateDirectoryRow(sourceLineNumbers, null, id, inlineSyntax[i]);
547 id = inlineId.Id;
548 }
549 }
550 }
551
552 return id;
553 } 397 }
554 398
555 /// <summary> 399 /// <summary>
@@ -575,59 +419,9 @@ namespace WixToolset
575 /// <param name="name">The registry entry name.</param> 419 /// <param name="name">The registry entry name.</param>
576 /// <param name="value">The registry entry value.</param> 420 /// <param name="value">The registry entry value.</param>
577 /// <param name="componentId">The component which will control installation/uninstallation of the registry entry.</param> 421 /// <param name="componentId">The component which will control installation/uninstallation of the registry entry.</param>
578 /// <param name="escapeLeadingHash">If true, "escape" leading '#' characters so the value is written as a REG_SZ.</param>
579 public Identifier CreateRegistryRow(SourceLineNumber sourceLineNumbers, int root, string key, string name, string value, string componentId, bool escapeLeadingHash)
580 {
581 Identifier id = null;
582
583 if (!this.EncounteredError)
584 {
585 if (-1 > root || 3 < root)
586 {
587 throw new ArgumentOutOfRangeException("root");
588 }
589
590 if (null == key)
591 {
592 throw new ArgumentNullException("key");
593 }
594
595 if (null == componentId)
596 {
597 throw new ArgumentNullException("componentId");
598 }
599
600 // escape the leading '#' character for string registry values
601 if (escapeLeadingHash && null != value && value.StartsWith("#", StringComparison.Ordinal))
602 {
603 value = String.Concat("#", value);
604 }
605
606 id = this.CreateIdentifier("reg", componentId, root.ToString(CultureInfo.InvariantCulture.NumberFormat), key.ToLowerInvariant(), (null != name ? name.ToLowerInvariant() : name));
607
608 var row = this.CreateRow(sourceLineNumbers, TupleDefinitionType.Registry, id);
609 row.Set(1, root);
610 row.Set(2, key);
611 row.Set(3, name);
612 row.Set(4, value);
613 row.Set(5, componentId);
614 }
615
616 return id;
617 }
618
619 /// <summary>
620 /// Creates a Registry row in the active section.
621 /// </summary>
622 /// <param name="sourceLineNumbers">Source and line number of the current row.</param>
623 /// <param name="root">The registry entry root.</param>
624 /// <param name="key">The registry entry key.</param>
625 /// <param name="name">The registry entry name.</param>
626 /// <param name="value">The registry entry value.</param>
627 /// <param name="componentId">The component which will control installation/uninstallation of the registry entry.</param>
628 public Identifier CreateRegistryRow(SourceLineNumber sourceLineNumbers, int root, string key, string name, string value, string componentId) 422 public Identifier CreateRegistryRow(SourceLineNumber sourceLineNumbers, int root, string key, string name, string value, string componentId)
629 { 423 {
630 return this.CreateRegistryRow(sourceLineNumbers, root, key, name, value, componentId, true); 424 return this.parseHelper.CreateRegistryRow(this.ActiveSection, sourceLineNumbers, root, key, name, value, componentId, true);
631 } 425 }
632 426
633 /// <summary> 427 /// <summary>
@@ -646,9 +440,7 @@ namespace WixToolset
646 // If this simple reference hasn't been added to the active section already, add it. 440 // If this simple reference hasn't been added to the active section already, add it.
647 if (this.activeSectionSimpleReferences.Add(id)) 441 if (this.activeSectionSimpleReferences.Add(id))
648 { 442 {
649 var wixSimpleReferenceRow = (WixSimpleReferenceTuple)this.CreateRow(sourceLineNumbers, TupleDefinitionType.WixSimpleReference); 443 this.parseHelper.CreateSimpleReference(this.ActiveSection, sourceLineNumbers, tableName, primaryKeys);
650 wixSimpleReferenceRow.Table = tableName;
651 wixSimpleReferenceRow.PrimaryKeys = joinedKeys;
652 } 444 }
653 } 445 }
654 } 446 }
@@ -665,21 +457,7 @@ namespace WixToolset
665 { 457 {
666 if (!this.EncounteredError) 458 if (!this.EncounteredError)
667 { 459 {
668 if (null == parentId || ComplexReferenceParentType.Unknown == parentType) 460 this.parseHelper.CreateWixGroupRow(this.ActiveSection, sourceLineNumbers, parentType, parentId, childType, childId);
669 {
670 return;
671 }
672
673 if (null == childId)
674 {
675 throw new ArgumentNullException("childId");
676 }
677
678 var row = (WixGroupTuple)this.CreateRow(sourceLineNumbers, TupleDefinitionType.WixGroup);
679 row.ParentId = parentId;
680 row.ParentType = parentType;
681 row.ChildId = childId;
682 row.ChildType = childType;
683 } 461 }
684 } 462 }
685 463
@@ -693,16 +471,7 @@ namespace WixToolset
693 { 471 {
694 if (!this.EncounteredError) 472 if (!this.EncounteredError)
695 { 473 {
696 var row = this.CreateRow(sourceLineNumbers, TupleDefinitionType.WixEnsureTable); 474 this.parseHelper.EnsureTable(this.ActiveSection, sourceLineNumbers, tableName);
697 row.Set(0, tableName);
698
699 // We don't add custom table definitions to the tableDefinitions collection,
700 // so if it's not in there, it better be a custom table. If the Id is just wrong,
701 // instead of a custom table, we get an unresolved reference at link time.
702 if (!this.creator.TryGetTupleDefinitionByName(tableName, out var ignored))
703 {
704 this.CreateSimpleReference(sourceLineNumbers, "WixCustomTable", tableName);
705 }
706 } 475 }
707 } 476 }
708 477
@@ -716,7 +485,7 @@ namespace WixToolset
716 [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")] 485 [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")]
717 public string GetAttributeValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, EmptyRule emptyRule = EmptyRule.CanBeWhitespaceOnly) 486 public string GetAttributeValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, EmptyRule emptyRule = EmptyRule.CanBeWhitespaceOnly)
718 { 487 {
719 return Common.GetAttributeValue(sourceLineNumbers, attribute, emptyRule); 488 return this.parseHelper.GetAttributeValue(sourceLineNumbers, attribute, emptyRule);
720 } 489 }
721 490
722 /// <summary> 491 /// <summary>
@@ -800,7 +569,7 @@ namespace WixToolset
800 [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")] 569 [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")]
801 public int GetAttributeIntegerValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, int minimum, int maximum) 570 public int GetAttributeIntegerValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, int minimum, int maximum)
802 { 571 {
803 return Common.GetAttributeIntegerValue(sourceLineNumbers, attribute, minimum, maximum); 572 return this.parseHelper.GetAttributeIntegerValue(sourceLineNumbers, attribute, minimum, maximum);
804 } 573 }
805 574
806 /// <summary> 575 /// <summary>
@@ -813,39 +582,7 @@ namespace WixToolset
813 /// <returns>The attribute's long value or a special value if an error occurred during conversion.</returns> 582 /// <returns>The attribute's long value or a special value if an error occurred during conversion.</returns>
814 public long GetAttributeLongValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, long minimum, long maximum) 583 public long GetAttributeLongValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, long minimum, long maximum)
815 { 584 {
816 Debug.Assert(minimum > CompilerConstants.LongNotSet && minimum > CompilerConstants.IllegalLong, "The legal values for this attribute collide with at least one sentinel used during parsing."); 585 return this.parseHelper.GetAttributeLongValue(sourceLineNumbers, attribute, minimum, maximum);
817
818 string value = this.GetAttributeValue(sourceLineNumbers, attribute);
819
820 if (0 < value.Length)
821 {
822 try
823 {
824 long longValue = Convert.ToInt64(value, CultureInfo.InvariantCulture.NumberFormat);
825
826 if (CompilerConstants.LongNotSet == longValue || CompilerConstants.IllegalLong == longValue)
827 {
828 this.OnMessage(WixErrors.IntegralValueSentinelCollision(sourceLineNumbers, longValue));
829 }
830 else if (minimum > longValue || maximum < longValue)
831 {
832 this.OnMessage(WixErrors.IntegralValueOutOfRange(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, longValue, minimum, maximum));
833 longValue = CompilerConstants.IllegalLong;
834 }
835
836 return longValue;
837 }
838 catch (FormatException)
839 {
840 this.OnMessage(WixErrors.IllegalLongValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
841 }
842 catch (OverflowException)
843 {
844 this.OnMessage(WixErrors.IllegalLongValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
845 }
846 }
847
848 return CompilerConstants.IllegalLong;
849 } 586 }
850 587
851 /// <summary> 588 /// <summary>
@@ -956,73 +693,9 @@ namespace WixToolset
956 /// <param name="generatable">Determines whether the guid can be automatically generated.</param> 693 /// <param name="generatable">Determines whether the guid can be automatically generated.</param>
957 /// <param name="canBeEmpty">If true, no error is raised on empty value. If false, an error is raised.</param> 694 /// <param name="canBeEmpty">If true, no error is raised on empty value. If false, an error is raised.</param>
958 /// <returns>The attribute's guid value or a special value if an error occurred.</returns> 695 /// <returns>The attribute's guid value or a special value if an error occurred.</returns>
959 [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")]
960 [SuppressMessage("Microsoft.Performance", "CA1807:AvoidUnnecessaryStringCreation")]
961 public string GetAttributeGuidValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool generatable = false, bool canBeEmpty = false) 696 public string GetAttributeGuidValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool generatable = false, bool canBeEmpty = false)
962 { 697 {
963 if (null == attribute) 698 return this.parseHelper.GetAttributeGuidValue(sourceLineNumbers, attribute, generatable, canBeEmpty);
964 {
965 throw new ArgumentNullException("attribute");
966 }
967
968 EmptyRule emptyRule = canBeEmpty ? EmptyRule.CanBeEmpty : EmptyRule.CanBeWhitespaceOnly;
969 string value = this.GetAttributeValue(sourceLineNumbers, attribute, emptyRule);
970
971 if (String.IsNullOrEmpty(value) && canBeEmpty)
972 {
973 return String.Empty;
974 }
975 else if (!String.IsNullOrEmpty(value))
976 {
977 // If the value starts and ends with braces or parenthesis, accept that and strip them off.
978 if ((value.StartsWith("{", StringComparison.Ordinal) && value.EndsWith("}", StringComparison.Ordinal))
979 || (value.StartsWith("(", StringComparison.Ordinal) && value.EndsWith(")", StringComparison.Ordinal)))
980 {
981 value = value.Substring(1, value.Length - 2);
982 }
983
984 try
985 {
986 Guid guid;
987
988 if (generatable && "*".Equals(value, StringComparison.Ordinal))
989 {
990 return value;
991 }
992
993 if (CompilerCore.PutGuidHere.IsMatch(value))
994 {
995 this.OnMessage(WixErrors.ExampleGuid(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
996 return CompilerConstants.IllegalGuid;
997 }
998 else if (value.StartsWith("!(loc", StringComparison.Ordinal) || value.StartsWith("$(loc", StringComparison.Ordinal) || value.StartsWith("!(wix", StringComparison.Ordinal))
999 {
1000 return value;
1001 }
1002 else
1003 {
1004 guid = new Guid(value);
1005 }
1006
1007 string uppercaseGuid = guid.ToString().ToUpper(CultureInfo.InvariantCulture);
1008
1009 if (this.ShowPedanticMessages)
1010 {
1011 if (uppercaseGuid != value)
1012 {
1013 this.OnMessage(WixErrors.GuidContainsLowercaseLetters(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
1014 }
1015 }
1016
1017 return String.Concat("{", uppercaseGuid, "}");
1018 }
1019 catch (FormatException)
1020 {
1021 this.OnMessage(WixErrors.IllegalGuidValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
1022 }
1023 }
1024
1025 return CompilerConstants.IllegalGuid;
1026 } 699 }
1027 700
1028 /// <summary> 701 /// <summary>
@@ -1033,27 +706,7 @@ namespace WixToolset
1033 /// <returns>The attribute's identifier value or a special value if an error occurred.</returns> 706 /// <returns>The attribute's identifier value or a special value if an error occurred.</returns>
1034 public Identifier GetAttributeIdentifier(SourceLineNumber sourceLineNumbers, XAttribute attribute) 707 public Identifier GetAttributeIdentifier(SourceLineNumber sourceLineNumbers, XAttribute attribute)
1035 { 708 {
1036 string value = Common.GetAttributeValue(sourceLineNumbers, attribute, EmptyRule.CanBeEmpty); 709 return this.parseHelper.GetAttributeIdentifier(sourceLineNumbers, attribute);
1037 AccessModifier access = AccessModifier.Public;
1038
1039 Match match = CompilerCore.LegalIdentifierWithAccess.Match(value);
1040 if (!match.Success)
1041 {
1042 return null;
1043 }
1044 else if (match.Groups["access"].Success)
1045 {
1046 access = (AccessModifier)Enum.Parse(typeof(AccessModifier), match.Groups["access"].Value, true);
1047 }
1048
1049 value = match.Groups["id"].Value;
1050
1051 if (Common.IsIdentifier(value) && 72 < value.Length)
1052 {
1053 this.OnMessage(WixWarnings.IdentifierTooLong(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
1054 }
1055
1056 return new Identifier(value, access);
1057 } 710 }
1058 711
1059 /// <summary> 712 /// <summary>
@@ -1064,7 +717,7 @@ namespace WixToolset
1064 /// <returns>The attribute's identifier value or a special value if an error occurred.</returns> 717 /// <returns>The attribute's identifier value or a special value if an error occurred.</returns>
1065 public string GetAttributeIdentifierValue(SourceLineNumber sourceLineNumbers, XAttribute attribute) 718 public string GetAttributeIdentifierValue(SourceLineNumber sourceLineNumbers, XAttribute attribute)
1066 { 719 {
1067 return Common.GetAttributeIdentifierValue(sourceLineNumbers, attribute); 720 return this.parseHelper.GetAttributeIdentifierValue(sourceLineNumbers, attribute);
1068 } 721 }
1069 722
1070 /// <summary> 723 /// <summary>
@@ -1075,23 +728,7 @@ namespace WixToolset
1075 /// <returns>The attribute's YesNoType value.</returns> 728 /// <returns>The attribute's YesNoType value.</returns>
1076 public YesNoType GetAttributeYesNoValue(SourceLineNumber sourceLineNumbers, XAttribute attribute) 729 public YesNoType GetAttributeYesNoValue(SourceLineNumber sourceLineNumbers, XAttribute attribute)
1077 { 730 {
1078 string value = this.GetAttributeValue(sourceLineNumbers, attribute); 731 return this.parseHelper.GetAttributeYesNoValue(sourceLineNumbers, attribute);
1079
1080 YesNoType result = YesNoType.IllegalValue;
1081 if (value.Equals("yes") || value.Equals("true"))
1082 {
1083 result = YesNoType.Yes;
1084 }
1085 else if (value.Equals("no") || value.Equals("false"))
1086 {
1087 result = YesNoType.No;
1088 }
1089 else
1090 {
1091 this.OnMessage(WixErrors.IllegalYesNoValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
1092 }
1093
1094 return result;
1095 } 732 }
1096 733
1097 /// <summary> 734 /// <summary>
@@ -1103,28 +740,7 @@ namespace WixToolset
1103 [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")] 740 [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")]
1104 public YesNoDefaultType GetAttributeYesNoDefaultValue(SourceLineNumber sourceLineNumbers, XAttribute attribute) 741 public YesNoDefaultType GetAttributeYesNoDefaultValue(SourceLineNumber sourceLineNumbers, XAttribute attribute)
1105 { 742 {
1106 string value = this.GetAttributeValue(sourceLineNumbers, attribute); 743 return this.parseHelper.GetAttributeYesNoDefaultValue(sourceLineNumbers, attribute);
1107
1108 if (0 < value.Length)
1109 {
1110 switch (Wix.Enums.ParseYesNoDefaultType(value))
1111 {
1112 case Wix.YesNoDefaultType.@default:
1113 return YesNoDefaultType.Default;
1114 case Wix.YesNoDefaultType.no:
1115 return YesNoDefaultType.No;
1116 case Wix.YesNoDefaultType.yes:
1117 return YesNoDefaultType.Yes;
1118 case Wix.YesNoDefaultType.NotSet:
1119 // Previous code never returned 'NotSet'!
1120 break;
1121 default:
1122 this.OnMessage(WixErrors.IllegalYesNoDefaultValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
1123 break;
1124 }
1125 }
1126
1127 return YesNoDefaultType.IllegalValue;
1128 } 744 }
1129 745
1130 /// <summary> 746 /// <summary>
@@ -1202,41 +818,7 @@ namespace WixToolset
1202 [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")] 818 [SuppressMessage("Microsoft.Design", "CA1059:MembersShouldNotExposeCertainConcreteTypes")]
1203 public string GetAttributeLongFilename(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool allowWildcards = false, bool allowRelative = false) 819 public string GetAttributeLongFilename(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool allowWildcards = false, bool allowRelative = false)
1204 { 820 {
1205 if (null == attribute) 821 return this.parseHelper.GetAttributeLongFilename(sourceLineNumbers, attribute, allowWildcards, allowRelative);
1206 {
1207 throw new ArgumentNullException("attribute");
1208 }
1209
1210 string value = this.GetAttributeValue(sourceLineNumbers, attribute);
1211
1212 if (0 < value.Length)
1213 {
1214 if (!this.IsValidLongFilename(value, allowWildcards, allowRelative) && !this.IsValidLocIdentifier(value))
1215 {
1216 if (allowRelative)
1217 {
1218 this.OnMessage(WixErrors.IllegalRelativeLongFilename(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
1219 }
1220 else
1221 {
1222 this.OnMessage(WixErrors.IllegalLongFilename(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
1223 }
1224 }
1225 else if (allowRelative)
1226 {
1227 string normalizedPath = value.Replace('\\', '/');
1228 if (normalizedPath.StartsWith("../", StringComparison.Ordinal) || normalizedPath.Contains("/../"))
1229 {
1230 this.OnMessage(WixErrors.PayloadMustBeRelativeToCache(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
1231 }
1232 }
1233 else if (CompilerCore.IsAmbiguousFilename(value))
1234 {
1235 this.OnMessage(WixWarnings.AmbiguousFileOrDirectoryName(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
1236 }
1237 }
1238
1239 return value;
1240 } 822 }
1241 823
1242 /// <summary> 824 /// <summary>
@@ -1247,31 +829,7 @@ namespace WixToolset
1247 /// <returns>The attribute's version value.</returns> 829 /// <returns>The attribute's version value.</returns>
1248 public string GetAttributeVersionValue(SourceLineNumber sourceLineNumbers, XAttribute attribute) 830 public string GetAttributeVersionValue(SourceLineNumber sourceLineNumbers, XAttribute attribute)
1249 { 831 {
1250 string value = this.GetAttributeValue(sourceLineNumbers, attribute); 832 return this.parseHelper.GetAttributeVersionValue(sourceLineNumbers, attribute);
1251
1252 if (!String.IsNullOrEmpty(value))
1253 {
1254 try
1255 {
1256 return new Version(value).ToString();
1257 }
1258 catch (FormatException) // illegal integer in version
1259 {
1260 // Allow versions to contain binder variables.
1261 if (Common.ContainsValidBinderVariable(value))
1262 {
1263 return value;
1264 }
1265
1266 this.OnMessage(WixErrors.IllegalVersionValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
1267 }
1268 catch (ArgumentException)
1269 {
1270 this.OnMessage(WixErrors.IllegalVersionValue(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
1271 }
1272 }
1273
1274 return null;
1275 } 833 }
1276 834
1277 /// <summary> 835 /// <summary>
@@ -1453,7 +1011,7 @@ namespace WixToolset
1453 /// <returns>True if a property is found in the string.</returns> 1011 /// <returns>True if a property is found in the string.</returns>
1454 public bool ContainsProperty(string possibleProperty) 1012 public bool ContainsProperty(string possibleProperty)
1455 { 1013 {
1456 return Common.ContainsProperty(possibleProperty); 1014 return this.parseHelper.ContainsProperty(possibleProperty);
1457 } 1015 }
1458 1016
1459 /// <summary> 1017 /// <summary>
@@ -1465,8 +1023,7 @@ namespace WixToolset
1465 [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.InvalidOperationException.#ctor(System.String)")] 1023 [SuppressMessage("Microsoft.Globalization", "CA1303:DoNotPassLiteralsAsLocalizedParameters", MessageId = "System.InvalidOperationException.#ctor(System.String)")]
1466 public Identifier CreateIdentifier(string prefix, params string[] args) 1024 public Identifier CreateIdentifier(string prefix, params string[] args)
1467 { 1025 {
1468 string id = Common.GenerateIdentifier(prefix, args); 1026 return this.parseHelper.CreateIdentifier(prefix, args);
1469 return new Identifier(id, AccessModifier.Private);
1470 } 1027 }
1471 1028
1472 /// <summary> 1029 /// <summary>
@@ -1476,8 +1033,7 @@ namespace WixToolset
1476 /// <returns></returns> 1033 /// <returns></returns>
1477 public Identifier CreateIdentifierFromFilename(string filename) 1034 public Identifier CreateIdentifierFromFilename(string filename)
1478 { 1035 {
1479 string id = Common.GetIdentifierFromName(filename); 1036 return this.parseHelper.CreateIdentifierFromFilename(filename);
1480 return new Identifier(id, AccessModifier.Private);
1481 } 1037 }
1482 1038
1483 /// <summary> 1039 /// <summary>
@@ -1488,22 +1044,7 @@ namespace WixToolset
1488 /// <param name="context">Extra information about the context in which this element is being parsed.</param> 1044 /// <param name="context">Extra information about the context in which this element is being parsed.</param>
1489 public void ParseExtensionAttribute(XElement element, XAttribute attribute, IDictionary<string, string> context = null) 1045 public void ParseExtensionAttribute(XElement element, XAttribute attribute, IDictionary<string, string> context = null)
1490 { 1046 {
1491 // Ignore attributes defined by the W3C because we'll assume they are always right. 1047 this.parseHelper.ParseExtensionAttribute(this.extensions.Values, this.intermediate, this.ActiveSection, element, attribute, context);
1492 if ((String.IsNullOrEmpty(attribute.Name.NamespaceName) && attribute.Name.LocalName.Equals("xmlns", StringComparison.Ordinal)) ||
1493 attribute.Name.NamespaceName.StartsWith(CompilerCore.W3SchemaPrefix.NamespaceName, StringComparison.Ordinal))
1494 {
1495 return;
1496 }
1497
1498 if (this.TryFindExtension(attribute.Name.NamespaceName, out var extension))
1499 {
1500 extension.ParseAttribute(element, attribute, context);
1501 }
1502 else
1503 {
1504 SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(element);
1505 this.OnMessage(WixErrors.UnhandledExtensionAttribute(sourceLineNumbers, element.Name.LocalName, attribute.Name.LocalName, attribute.Name.NamespaceName));
1506 }
1507 } 1048 }
1508 1049
1509 /// <summary> 1050 /// <summary>
@@ -1514,16 +1055,7 @@ namespace WixToolset
1514 /// <param name="context">Extra information about the context in which this element is being parsed.</param> 1055 /// <param name="context">Extra information about the context in which this element is being parsed.</param>
1515 public void ParseExtensionElement(XElement parentElement, XElement element, IDictionary<string, string> context = null) 1056 public void ParseExtensionElement(XElement parentElement, XElement element, IDictionary<string, string> context = null)
1516 { 1057 {
1517 if (this.TryFindExtension(element.Name.Namespace, out var extension)) 1058 this.parseHelper.ParseExtensionElement(this.extensions.Values, this.intermediate, this.ActiveSection, parentElement, element, context);
1518 {
1519 SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(parentElement);
1520 extension.ParseElement(parentElement, element, context);
1521 }
1522 else
1523 {
1524 SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(element);
1525 this.OnMessage(WixErrors.UnhandledExtensionElement(childSourceLineNumbers, parentElement.Name.LocalName, element.Name.LocalName, element.Name.NamespaceName));
1526 }
1527 } 1059 }
1528 1060
1529 /// <summary> 1061 /// <summary>
@@ -1532,17 +1064,7 @@ namespace WixToolset
1532 /// <param name="element">Element to parse children.</param> 1064 /// <param name="element">Element to parse children.</param>
1533 public void ParseForExtensionElements(XElement element) 1065 public void ParseForExtensionElements(XElement element)
1534 { 1066 {
1535 foreach (XElement child in element.Elements()) 1067 this.parseHelper.ParseForExtensionElements(this.extensions.Values, this.intermediate, this.ActiveSection, element);
1536 {
1537 if (element.Name.Namespace == child.Name.Namespace)
1538 {
1539 this.UnexpectedElement(element, child);
1540 }
1541 else
1542 {
1543 this.ParseExtensionElement(element, child);
1544 }
1545 }
1546 } 1068 }
1547 1069
1548 /// <summary> 1070 /// <summary>
@@ -1553,20 +1075,7 @@ namespace WixToolset
1553 /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param> 1075 /// <param name="contextValues">Extra information about the context in which this element is being parsed.</param>
1554 public ComponentKeyPath ParsePossibleKeyPathExtensionElement(XElement parentElement, XElement element, IDictionary<string, string> context) 1076 public ComponentKeyPath ParsePossibleKeyPathExtensionElement(XElement parentElement, XElement element, IDictionary<string, string> context)
1555 { 1077 {
1556 ComponentKeyPath keyPath = null; 1078 return this.parseHelper.ParsePossibleKeyPathExtensionElement(this.extensions.Values, this.intermediate, this.ActiveSection, parentElement, element, context);
1557
1558 ICompilerExtension extension;
1559 if (this.TryFindExtension(element.Name.Namespace, out extension))
1560 {
1561 keyPath = extension.ParsePossibleKeyPathElement(parentElement, element, context);
1562 }
1563 else
1564 {
1565 SourceLineNumber childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(element);
1566 this.OnMessage(WixErrors.UnhandledExtensionElement(childSourceLineNumbers, parentElement.Name.LocalName, element.Name.LocalName, element.Name.NamespaceName));
1567 }
1568
1569 return keyPath;
1570 } 1079 }
1571 1080
1572 /// <summary> 1081 /// <summary>
@@ -1576,8 +1085,7 @@ namespace WixToolset
1576 /// <param name="attribute">The unexpected attribute.</param> 1085 /// <param name="attribute">The unexpected attribute.</param>
1577 public void UnexpectedAttribute(XElement element, XAttribute attribute) 1086 public void UnexpectedAttribute(XElement element, XAttribute attribute)
1578 { 1087 {
1579 SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(element); 1088 this.parseHelper.UnexpectedAttribute(element, attribute);
1580 Common.UnexpectedAttribute(sourceLineNumbers, attribute);
1581 } 1089 }
1582 1090
1583 /// <summary> 1091 /// <summary>
@@ -1587,9 +1095,7 @@ namespace WixToolset
1587 /// <param name="childElement">The unexpected child element.</param> 1095 /// <param name="childElement">The unexpected child element.</param>
1588 public void UnexpectedElement(XElement parentElement, XElement childElement) 1096 public void UnexpectedElement(XElement parentElement, XElement childElement)
1589 { 1097 {
1590 SourceLineNumber sourceLineNumbers = Preprocessor.GetSourceLineNumbers(childElement); 1098 this.parseHelper.UnexpectedElement(parentElement, childElement);
1591
1592 this.OnMessage(WixErrors.UnexpectedElement(sourceLineNumbers, parentElement.Name.LocalName, childElement.Name.LocalName));
1593 } 1099 }
1594 1100
1595 /// <summary> 1101 /// <summary>
@@ -1667,30 +1173,6 @@ namespace WixToolset
1667 } 1173 }
1668 1174
1669 /// <summary> 1175 /// <summary>
1670 /// Creates a WiX complex reference in the active section.
1671 /// </summary>
1672 /// <param name="sourceLineNumbers">Source line information.</param>
1673 /// <param name="parentType">The parent type.</param>
1674 /// <param name="parentId">The parent id.</param>
1675 /// <param name="parentLanguage">The parent language.</param>
1676 /// <param name="childType">The child type.</param>
1677 /// <param name="childId">The child id.</param>
1678 /// <param name="isPrimary">Whether the child is primary.</param>
1679 internal void CreateWixComplexReferenceRow(SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, string parentLanguage, ComplexReferenceChildType childType, string childId, bool isPrimary)
1680 {
1681 if (!this.EncounteredError)
1682 {
1683 var wixComplexReferenceRow = (WixComplexReferenceTuple)this.CreateRow(sourceLineNumbers, TupleDefinitionType.WixComplexReference);
1684 wixComplexReferenceRow.Parent = parentId;
1685 wixComplexReferenceRow.ParentType = parentType;
1686 wixComplexReferenceRow.ParentLanguage = parentLanguage;
1687 wixComplexReferenceRow.Child = childId;
1688 wixComplexReferenceRow.ChildType = childType;
1689 wixComplexReferenceRow.IsPrimary = isPrimary;
1690 }
1691 }
1692
1693 /// <summary>
1694 /// Creates WixComplexReference and WixGroup rows in the active section. 1176 /// Creates WixComplexReference and WixGroup rows in the active section.
1695 /// </summary> 1177 /// </summary>
1696 /// <param name="sourceLineNumbers">Source line information.</param> 1178 /// <param name="sourceLineNumbers">Source line information.</param>
@@ -1702,8 +1184,7 @@ namespace WixToolset
1702 /// <param name="isPrimary">Whether the child is primary.</param> 1184 /// <param name="isPrimary">Whether the child is primary.</param>
1703 public void CreateComplexReference(SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, string parentLanguage, ComplexReferenceChildType childType, string childId, bool isPrimary) 1185 public void CreateComplexReference(SourceLineNumber sourceLineNumbers, ComplexReferenceParentType parentType, string parentId, string parentLanguage, ComplexReferenceChildType childType, string childId, bool isPrimary)
1704 { 1186 {
1705 this.CreateWixComplexReferenceRow(sourceLineNumbers, parentType, parentId, parentLanguage, childType, childId, isPrimary); 1187 this.parseHelper.CreateComplexReference(this.ActiveSection, sourceLineNumbers, parentType, parentId, parentLanguage, childType, childId, isPrimary);
1706 this.CreateWixGroupRow(sourceLineNumbers, parentType, parentId, childType, childId);
1707 } 1188 }
1708 1189
1709 /// <summary> 1190 /// <summary>
@@ -1719,56 +1200,57 @@ namespace WixToolset
1719 /// <returns>Identifier for the newly created row.</returns> 1200 /// <returns>Identifier for the newly created row.</returns>
1720 internal Identifier CreateDirectoryRow(SourceLineNumber sourceLineNumbers, Identifier id, string parentId, string name, string shortName = null, string sourceName = null, string shortSourceName = null) 1201 internal Identifier CreateDirectoryRow(SourceLineNumber sourceLineNumbers, Identifier id, string parentId, string name, string shortName = null, string sourceName = null, string shortSourceName = null)
1721 { 1202 {
1722 string defaultDir = null; 1203 //string defaultDir = null;
1723 1204
1724 if (name.Equals("SourceDir") || this.IsValidShortFilename(name, false)) 1205 //if (name.Equals("SourceDir") || this.IsValidShortFilename(name, false))
1725 { 1206 //{
1726 defaultDir = name; 1207 // defaultDir = name;
1727 } 1208 //}
1728 else 1209 //else
1729 { 1210 //{
1730 if (String.IsNullOrEmpty(shortName)) 1211 // if (String.IsNullOrEmpty(shortName))
1731 { 1212 // {
1732 shortName = this.CreateShortName(name, false, false, "Directory", parentId); 1213 // shortName = this.CreateShortName(name, false, false, "Directory", parentId);
1733 } 1214 // }
1734 1215
1735 defaultDir = String.Concat(shortName, "|", name); 1216 // defaultDir = String.Concat(shortName, "|", name);
1736 } 1217 //}
1737 1218
1738 if (!String.IsNullOrEmpty(sourceName)) 1219 //if (!String.IsNullOrEmpty(sourceName))
1739 { 1220 //{
1740 if (this.IsValidShortFilename(sourceName, false)) 1221 // if (this.IsValidShortFilename(sourceName, false))
1741 { 1222 // {
1742 defaultDir = String.Concat(defaultDir, ":", sourceName); 1223 // defaultDir = String.Concat(defaultDir, ":", sourceName);
1743 } 1224 // }
1744 else 1225 // else
1745 { 1226 // {
1746 if (String.IsNullOrEmpty(shortSourceName)) 1227 // if (String.IsNullOrEmpty(shortSourceName))
1747 { 1228 // {
1748 shortSourceName = this.CreateShortName(sourceName, false, false, "Directory", parentId); 1229 // shortSourceName = this.CreateShortName(sourceName, false, false, "Directory", parentId);
1749 } 1230 // }
1750 1231
1751 defaultDir = String.Concat(defaultDir, ":", shortSourceName, "|", sourceName); 1232 // defaultDir = String.Concat(defaultDir, ":", shortSourceName, "|", sourceName);
1752 } 1233 // }
1753 } 1234 //}
1754 1235
1755 // For anonymous directories, create the identifier. If this identifier already exists in the 1236 //// For anonymous directories, create the identifier. If this identifier already exists in the
1756 // active section, bail so we don't add duplicate anonymous directory rows (which are legal 1237 //// active section, bail so we don't add duplicate anonymous directory rows (which are legal
1757 // but bloat the intermediate and ultimately make the linker do "busy work"). 1238 //// but bloat the intermediate and ultimately make the linker do "busy work").
1758 if (null == id) 1239 //if (null == id)
1759 { 1240 //{
1760 id = this.CreateIdentifier("dir", parentId, name, shortName, sourceName, shortSourceName); 1241 // id = this.CreateIdentifier("dir", parentId, name, shortName, sourceName, shortSourceName);
1761 1242
1762 if (!this.activeSectionInlinedDirectoryIds.Add(id.Id)) 1243 // if (!this.activeSectionInlinedDirectoryIds.Add(id.Id))
1763 { 1244 // {
1764 return id; 1245 // return id;
1765 } 1246 // }
1766 } 1247 //}
1767 1248
1768 var row = this.CreateRow(sourceLineNumbers, TupleDefinitionType.Directory, id); 1249 //var row = this.CreateRow(sourceLineNumbers, TupleDefinitionType.Directory, id);
1769 row.Set(1, parentId); 1250 //row.Set(1, parentId);
1770 row.Set(2, defaultDir); 1251 //row.Set(2, defaultDir);
1771 return id; 1252 //return id;
1253 return this.parseHelper.CreateDirectoryRow(this.ActiveSection, sourceLineNumbers, id, parentId, name, shortName, sourceName, shortSourceName, this.activeSectionInlinedDirectoryIds);
1772 } 1254 }
1773 1255
1774 /// <summary> 1256 /// <summary>
@@ -1780,65 +1262,7 @@ namespace WixToolset
1780 /// <returns>Inline directory syntax split into array of strings or null if the syntax did not parse.</returns> 1262 /// <returns>Inline directory syntax split into array of strings or null if the syntax did not parse.</returns>
1781 internal string[] GetAttributeInlineDirectorySyntax(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool resultUsedToCreateReference = false) 1263 internal string[] GetAttributeInlineDirectorySyntax(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool resultUsedToCreateReference = false)
1782 { 1264 {
1783 string[] result = null; 1265 return this.parseHelper.GetAttributeInlineDirectorySyntax(sourceLineNumbers, attribute, resultUsedToCreateReference);
1784 string value = this.GetAttributeValue(sourceLineNumbers, attribute);
1785
1786 if (!String.IsNullOrEmpty(value))
1787 {
1788 int pathStartsAt = 0;
1789 result = value.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
1790 if (result[0].EndsWith(":", StringComparison.Ordinal))
1791 {
1792 string id = result[0].TrimEnd(':');
1793 if (1 == result.Length)
1794 {
1795 this.OnMessage(WixErrors.InlineDirectorySyntaxRequiresPath(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, id));
1796 return null;
1797 }
1798 else if (!this.IsValidIdentifier(id))
1799 {
1800 this.OnMessage(WixErrors.IllegalIdentifier(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, id));
1801 return null;
1802 }
1803
1804 pathStartsAt = 1;
1805 }
1806 else if (resultUsedToCreateReference && 1 == result.Length)
1807 {
1808 if (value.EndsWith("\\"))
1809 {
1810 if (!this.IsValidLongFilename(result[0]))
1811 {
1812 this.OnMessage(WixErrors.IllegalLongFilename(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, result[0]));
1813 return null;
1814 }
1815 }
1816 else if (!this.IsValidIdentifier(result[0]))
1817 {
1818 this.OnMessage(WixErrors.IllegalIdentifier(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, result[0]));
1819 return null;
1820 }
1821
1822 return result; // return early to avoid additional checks below.
1823 }
1824
1825 // Check each part of the relative path to ensure that it is a valid directory name.
1826 for (int i = pathStartsAt; i < result.Length; ++i)
1827 {
1828 if (!this.IsValidLongFilename(result[i]))
1829 {
1830 this.OnMessage(WixErrors.IllegalLongFilename(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, result[i]));
1831 return null;
1832 }
1833 }
1834
1835 if (1 < result.Length && !value.EndsWith("\\"))
1836 {
1837 this.OnMessage(WixWarnings.BackslashTerminateInlineDirectorySyntax(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
1838 }
1839 }
1840
1841 return result;
1842 } 1266 }
1843 1267
1844 /// <summary> 1268 /// <summary>