aboutsummaryrefslogtreecommitdiff
path: root/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs')
-rw-r--r--src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs216
1 files changed, 105 insertions, 111 deletions
diff --git a/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs b/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs
index d9087ce3..e75f5fe5 100644
--- a/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs
+++ b/src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs
@@ -19,6 +19,8 @@ namespace WixToolset.Core.ExtensibilityServices
19 19
20 internal class ParseHelper : IParseHelper 20 internal class ParseHelper : IParseHelper
21 { 21 {
22 private static readonly char[] InlineDirectorySeparators = new char[] { ':', '\\', '/' };
23
22 public ParseHelper(IWixToolsetServiceProvider serviceProvider) 24 public ParseHelper(IWixToolsetServiceProvider serviceProvider)
23 { 25 {
24 this.ServiceProvider = serviceProvider; 26 this.ServiceProvider = serviceProvider;
@@ -53,13 +55,7 @@ namespace WixToolset.Core.ExtensibilityServices
53 this.CreateWixGroupSymbol(section, sourceLineNumbers, parentType, parentId, childType, childId); 55 this.CreateWixGroupSymbol(section, sourceLineNumbers, parentType, parentId, childType, childId);
54 } 56 }
55 57
56 [Obsolete] 58 public Identifier CreateDirectorySymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string parentId, string name, string shortName = null, string sourceName = null, string shortSourceName = null)
57 public Identifier CreateDirectoryRow(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string parentId, string name, ISet<string> sectionInlinedDirectoryIds, string shortName = null, string sourceName = null, string shortSourceName = null)
58 {
59 return this.CreateDirectorySymbol(section, sourceLineNumbers, id, parentId, name, sectionInlinedDirectoryIds, shortName, sourceName, shortSourceName);
60 }
61
62 public Identifier CreateDirectorySymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, Identifier id, string parentId, string name, ISet<string> sectionInlinedDirectoryIds, string shortName = null, string sourceName = null, string shortSourceName = null)
63 { 59 {
64 // For anonymous directories, create the identifier. If this identifier already exists in the 60 // For anonymous directories, create the identifier. If this identifier already exists in the
65 // active section, bail so we don't add duplicate anonymous directory symbols (which are legal 61 // active section, bail so we don't add duplicate anonymous directory symbols (which are legal
@@ -67,11 +63,6 @@ namespace WixToolset.Core.ExtensibilityServices
67 if (null == id) 63 if (null == id)
68 { 64 {
69 id = this.CreateIdentifier("dir", parentId, name, shortName, sourceName, shortSourceName); 65 id = this.CreateIdentifier("dir", parentId, name, shortName, sourceName, shortSourceName);
70
71 if (!sectionInlinedDirectoryIds.Add(id.Id))
72 {
73 return id;
74 }
75 } 66 }
76 67
77 var symbol = section.AddSymbol(new DirectorySymbol(sourceLineNumbers, id) 68 var symbol = section.AddSymbol(new DirectorySymbol(sourceLineNumbers, id)
@@ -86,48 +77,30 @@ namespace WixToolset.Core.ExtensibilityServices
86 return symbol.Id; 77 return symbol.Id;
87 } 78 }
88 79
89 public string CreateDirectoryReferenceFromInlineSyntax(IntermediateSection section, SourceLineNumber sourceLineNumbers, string parentId, XAttribute attribute, ISet<string> sectionInlinedDirectoryIds) 80 public string CreateDirectoryReferenceFromInlineSyntax(IntermediateSection section, SourceLineNumber sourceLineNumbers, XAttribute attribute, string parentId, string inlineSyntax, IDictionary<string, string> sectionCachedInlinedDirectoryIds)
90 { 81 {
91 string id = null; 82 if (String.IsNullOrEmpty(inlineSyntax))
92 var inlineSyntax = this.GetAttributeInlineDirectorySyntax(sourceLineNumbers, attribute, true);
93
94 if (null != inlineSyntax)
95 { 83 {
96 // Special case the single entry in the inline syntax since it is the most common case 84 inlineSyntax = attribute.Value;
97 // and needs no extra processing. It's just a reference to an existing directory. 85 }
98 if (1 == inlineSyntax.Length)
99 {
100 id = inlineSyntax[0];
101 this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, id);
102 }
103 else // start creating symbols for the entries in the inline syntax
104 {
105 id = parentId;
106
107 var pathStartsAt = 0;
108 if (inlineSyntax[0].EndsWith(":", StringComparison.Ordinal))
109 {
110 // TODO: should overriding the parent identifier with a specific id be an error or a warning or just let it slide?
111 //if (null != parentId)
112 //{
113 // this.core.Write(WixErrors.Xxx(sourceLineNumbers));
114 //}
115
116 id = inlineSyntax[0].TrimEnd(':');
117 this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, id);
118 86
119 pathStartsAt = 1; 87 // If no separator is found, the string is a simple reference.
120 } 88 var separatorFound = inlineSyntax.IndexOfAny(InlineDirectorySeparators);
89 if (separatorFound == -1)
90 {
91 this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, inlineSyntax);
92 return inlineSyntax;
93 }
121 94
122 for (var i = pathStartsAt; i < inlineSyntax.Length; ++i) 95 // If a parent id was provided and the inline syntax does not start with a directory reference, prepend the parent id.
123 { 96 if (!String.IsNullOrEmpty(parentId) && inlineSyntax[separatorFound] != ':')
124 var inlineId = this.CreateDirectorySymbol(section, sourceLineNumbers, null, id, inlineSyntax[i], sectionInlinedDirectoryIds); 97 {
125 id = inlineId.Id; 98 inlineSyntax = String.Concat(parentId, ":", inlineSyntax);
126 }
127 }
128 } 99 }
129 100
130 return id; 101 inlineSyntax = inlineSyntax.TrimEnd('\\', '/');
102
103 return this.ParseInlineSyntax(section, sourceLineNumbers, attribute, inlineSyntax, sectionCachedInlinedDirectoryIds);
131 } 104 }
132 105
133 public string CreateGuid(Guid namespaceGuid, string value) 106 public string CreateGuid(Guid namespaceGuid, string value)
@@ -544,69 +517,6 @@ namespace WixToolset.Core.ExtensibilityServices
544 return Common.GetAttributeIdentifierValue(this.Messaging, sourceLineNumbers, attribute); 517 return Common.GetAttributeIdentifierValue(this.Messaging, sourceLineNumbers, attribute);
545 } 518 }
546 519
547 public string[] GetAttributeInlineDirectorySyntax(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool resultUsedToCreateReference = false)
548 {
549 string[] result = null;
550 var value = this.GetAttributeValue(sourceLineNumbers, attribute);
551
552 if (!String.IsNullOrEmpty(value))
553 {
554 var pathStartsAt = 0;
555 result = value.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
556 if (result[0].EndsWith(":", StringComparison.Ordinal))
557 {
558 var id = result[0].TrimEnd(':');
559 if (1 == result.Length)
560 {
561 this.Messaging.Write(ErrorMessages.InlineDirectorySyntaxRequiresPath(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, id));
562 return null;
563 }
564 else if (!this.IsValidIdentifier(id))
565 {
566 this.Messaging.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, id));
567 return null;
568 }
569
570 pathStartsAt = 1;
571 }
572 else if (resultUsedToCreateReference && 1 == result.Length)
573 {
574 if (value.EndsWith("\\", StringComparison.Ordinal))
575 {
576 if (!this.IsValidLongFilename(result[0], false, false))
577 {
578 this.Messaging.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, result[0]));
579 return null;
580 }
581 }
582 else if (!this.IsValidIdentifier(result[0]))
583 {
584 this.Messaging.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, result[0]));
585 return null;
586 }
587
588 return result; // return early to avoid additional checks below.
589 }
590
591 // Check each part of the relative path to ensure that it is a valid directory name.
592 for (var i = pathStartsAt; i < result.Length; ++i)
593 {
594 if (!this.IsValidLongFilename(result[i], false, false))
595 {
596 this.Messaging.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value, result[i]));
597 return null;
598 }
599 }
600
601 if (1 < result.Length && !value.EndsWith("\\", StringComparison.Ordinal))
602 {
603 this.Messaging.Write(WarningMessages.BackslashTerminateInlineDirectorySyntax(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, value));
604 }
605 }
606
607 return result;
608 }
609
610 public int GetAttributeIntegerValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, int minimum, int maximum) 520 public int GetAttributeIntegerValue(SourceLineNumber sourceLineNumbers, XAttribute attribute, int minimum, int maximum)
611 { 521 {
612 return Common.GetAttributeIntegerValue(this.Messaging, sourceLineNumbers, attribute, minimum, maximum); 522 return Common.GetAttributeIntegerValue(this.Messaging, sourceLineNumbers, attribute, minimum, maximum);
@@ -1032,6 +942,90 @@ namespace WixToolset.Core.ExtensibilityServices
1032 this.Creator = this.ServiceProvider.GetService<ISymbolDefinitionCreator>(); 942 this.Creator = this.ServiceProvider.GetService<ISymbolDefinitionCreator>();
1033 } 943 }
1034 944
945 private string ParseInlineSyntax(IntermediateSection section, SourceLineNumber sourceLineNumbers, XAttribute attribute, string inlineSyntax, IDictionary<string, string> sectionCachedInlinedDirectoryIds)
946 {
947 if (!sectionCachedInlinedDirectoryIds.TryGetValue(inlineSyntax, out var id))
948 {
949 string parentId;
950 int nameIndex;
951
952 var separatorIndex = inlineSyntax.LastIndexOfAny(InlineDirectorySeparators);
953 if (separatorIndex == -1)
954 {
955 nameIndex = 0;
956 parentId = "TARGETDIR";
957 }
958 else if (inlineSyntax[separatorIndex] == '\\' || inlineSyntax[separatorIndex] == '/')
959 {
960 nameIndex = separatorIndex + 1;
961
962 if (separatorIndex == 0)
963 {
964 parentId = "TARGETDIR";
965 }
966 else if (inlineSyntax[separatorIndex - 1] == ':')
967 {
968 parentId = this.ParseParentReference(section, sourceLineNumbers, attribute, inlineSyntax, separatorIndex - 1);
969 }
970 else
971 {
972 var parentInlineDirectory = inlineSyntax.Substring(0, separatorIndex);
973 parentId = this.ParseInlineSyntax(section, sourceLineNumbers, attribute, parentInlineDirectory.TrimEnd('\\', '/'), sectionCachedInlinedDirectoryIds);
974 }
975 }
976 else
977 {
978 nameIndex = separatorIndex + 1;
979 parentId = this.ParseParentReference(section, sourceLineNumbers, attribute, inlineSyntax, separatorIndex);
980 }
981
982 if (nameIndex == inlineSyntax.Length)
983 {
984 id = parentId;
985 }
986 else
987 {
988 var name = nameIndex != -1 ? inlineSyntax.Substring(nameIndex) : null;
989
990 if (!this.IsValidLongFilename(name, false, false))
991 {
992 this.Messaging.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, attribute.Value, name));
993 return null;
994 }
995
996 var identifier = this.CreateDirectorySymbol(section, sourceLineNumbers, null, parentId, name);
997
998 id = identifier.Id;
999 }
1000
1001 sectionCachedInlinedDirectoryIds.Add(inlineSyntax, id);
1002 }
1003
1004 return id;
1005 }
1006
1007 private string ParseParentReference(IntermediateSection section, SourceLineNumber sourceLineNumbers, XAttribute attribute, string reference, int colonIndex)
1008 {
1009 if (colonIndex == 0)
1010 {
1011 this.Messaging.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, attribute.Value, String.Empty));
1012 return null;
1013 }
1014 else
1015 {
1016 var parentId = reference.Substring(0, colonIndex);
1017
1018 if (!Common.IsIdentifier(parentId))
1019 {
1020 this.Messaging.Write(ErrorMessages.IllegalIdentifier(sourceLineNumbers, attribute.Parent.Name.LocalName, attribute.Name.LocalName, attribute.Value, parentId));
1021 return null;
1022 }
1023
1024 this.CreateSimpleReference(section, sourceLineNumbers, SymbolDefinitions.Directory, parentId);
1025 return parentId;
1026 }
1027 }
1028
1035 private static bool TryFindExtension(IEnumerable<ICompilerExtension> extensions, XNamespace ns, out ICompilerExtension extension) 1029 private static bool TryFindExtension(IEnumerable<ICompilerExtension> extensions, XNamespace ns, out ICompilerExtension extension)
1036 { 1030 {
1037 extension = null; 1031 extension = null;