diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/WixToolset.Core/Common.cs | 21 | ||||
| -rw-r--r-- | src/WixToolset.Core/Compiler.cs | 168 | ||||
| -rw-r--r-- | src/WixToolset.Core/CompilerCore.cs | 37 | ||||
| -rw-r--r-- | src/WixToolset.Core/ExtensibilityServices/ParseHelper.cs | 216 |
4 files changed, 220 insertions, 222 deletions
diff --git a/src/WixToolset.Core/Common.cs b/src/WixToolset.Core/Common.cs index 19c77368..7a321d29 100644 --- a/src/WixToolset.Core/Common.cs +++ b/src/WixToolset.Core/Common.cs | |||
| @@ -329,21 +329,22 @@ namespace WixToolset.Core | |||
| 329 | /// <returns>The generated identifier.</returns> | 329 | /// <returns>The generated identifier.</returns> |
| 330 | public static string GenerateIdentifier(string prefix, params string[] args) | 330 | public static string GenerateIdentifier(string prefix, params string[] args) |
| 331 | { | 331 | { |
| 332 | string stringData = String.Join("|", args); | 332 | string base64; |
| 333 | byte[] data = Encoding.UTF8.GetBytes(stringData); | ||
| 334 | 333 | ||
| 335 | // hash the data | 334 | using (var sha1 = new SHA1CryptoServiceProvider()) |
| 336 | byte[] hash; | ||
| 337 | using (SHA1 sha1 = new SHA1CryptoServiceProvider()) | ||
| 338 | { | 335 | { |
| 339 | hash = sha1.ComputeHash(data); | 336 | var combined = String.Join("|", args); |
| 337 | var data = Encoding.UTF8.GetBytes(combined); | ||
| 338 | var hash = sha1.ComputeHash(data); | ||
| 339 | base64 = Convert.ToBase64String(hash); | ||
| 340 | } | 340 | } |
| 341 | 341 | ||
| 342 | // Build up the identifier. | 342 | var identifier = new StringBuilder(32); |
| 343 | StringBuilder identifier = new StringBuilder(35, 35); | ||
| 344 | identifier.Append(prefix); | 343 | identifier.Append(prefix); |
| 345 | identifier.Append(Convert.ToBase64String(hash).TrimEnd('=')); | 344 | identifier.Append(base64); |
| 346 | identifier.Replace('+', '.').Replace('/', '_'); | 345 | identifier.Length -= 1; // removes the trailing '=' from base64 |
| 346 | identifier.Replace('+', '.'); | ||
| 347 | identifier.Replace('/', '_'); | ||
| 347 | 348 | ||
| 348 | return identifier.ToString(); | 349 | return identifier.ToString(); |
| 349 | } | 350 | } |
diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs index 3fa06f9c..c504e96f 100644 --- a/src/WixToolset.Core/Compiler.cs +++ b/src/WixToolset.Core/Compiler.cs | |||
| @@ -9,6 +9,7 @@ namespace WixToolset.Core | |||
| 9 | using System.Globalization; | 9 | using System.Globalization; |
| 10 | using System.IO; | 10 | using System.IO; |
| 11 | using System.Linq; | 11 | using System.Linq; |
| 12 | using System.Text; | ||
| 12 | using System.Xml.Linq; | 13 | using System.Xml.Linq; |
| 13 | using WixToolset.Data; | 14 | using WixToolset.Data; |
| 14 | using WixToolset.Data.Symbols; | 15 | using WixToolset.Data.Symbols; |
| @@ -25,8 +26,10 @@ namespace WixToolset.Core | |||
| 25 | private const int MinValueOfMaxCabSizeForLargeFileSplitting = 20; // 20 MB | 26 | private const int MinValueOfMaxCabSizeForLargeFileSplitting = 20; // 20 MB |
| 26 | private const int MaxValueOfMaxCabSizeForLargeFileSplitting = 2 * 1024; // 2048 MB (i.e. 2 GB) | 27 | private const int MaxValueOfMaxCabSizeForLargeFileSplitting = 2 * 1024; // 2048 MB (i.e. 2 GB) |
| 27 | 28 | ||
| 28 | private const string DefaultComponentIdPlaceholderPrefix = "WixComponentIdPlaceholder"; | 29 | private const char ComponentIdPlaceholderStart = (char)167; |
| 29 | private const string DefaultComponentIdPlaceholderWixVariablePrefix = "!(wix."; | 30 | private const char ComponentIdPlaceholderEnd = (char)167; |
| 31 | private Dictionary<string, string> componentIdPlaceholders; | ||
| 32 | |||
| 30 | // If these are true you know you are building a module or product | 33 | // If these are true you know you are building a module or product |
| 31 | // but if they are false you cannot not be sure they will not end | 34 | // but if they are false you cannot not be sure they will not end |
| 32 | // up a product or module. Use these flags carefully. | 35 | // up a product or module. Use these flags carefully. |
| @@ -36,9 +39,6 @@ namespace WixToolset.Core | |||
| 36 | private string activeName; | 39 | private string activeName; |
| 37 | private string activeLanguage; | 40 | private string activeLanguage; |
| 38 | 41 | ||
| 39 | // TODO: Implement this differently to not require the VariableResolver. | ||
| 40 | private VariableResolver componentIdPlaceholdersResolver; | ||
| 41 | |||
| 42 | /// <summary> | 42 | /// <summary> |
| 43 | /// Type of RadioButton element in a group. | 43 | /// Type of RadioButton element in a group. |
| 44 | /// </summary> | 44 | /// </summary> |
| @@ -129,7 +129,7 @@ namespace WixToolset.Core | |||
| 129 | 129 | ||
| 130 | this.Core = new CompilerCore(target, this.Messaging, parseHelper, extensionsByNamespace); | 130 | this.Core = new CompilerCore(target, this.Messaging, parseHelper, extensionsByNamespace); |
| 131 | this.Core.ShowPedanticMessages = this.ShowPedanticMessages; | 131 | this.Core.ShowPedanticMessages = this.ShowPedanticMessages; |
| 132 | this.componentIdPlaceholdersResolver = new VariableResolver(this.ServiceProvider); | 132 | this.componentIdPlaceholders = new Dictionary<string, string>(); |
| 133 | 133 | ||
| 134 | // parse the document | 134 | // parse the document |
| 135 | var source = this.Context.Source; | 135 | var source = this.Context.Source; |
| @@ -247,7 +247,7 @@ namespace WixToolset.Core | |||
| 247 | 247 | ||
| 248 | private void ResolveComponentIdPlaceholders(Intermediate target) | 248 | private void ResolveComponentIdPlaceholders(Intermediate target) |
| 249 | { | 249 | { |
| 250 | if (0 < this.componentIdPlaceholdersResolver.VariableCount) | 250 | if (0 < this.componentIdPlaceholders.Count) |
| 251 | { | 251 | { |
| 252 | foreach (var section in target.Sections) | 252 | foreach (var section in target.Sections) |
| 253 | { | 253 | { |
| @@ -255,15 +255,40 @@ namespace WixToolset.Core | |||
| 255 | { | 255 | { |
| 256 | foreach (var field in symbol.Fields) | 256 | foreach (var field in symbol.Fields) |
| 257 | { | 257 | { |
| 258 | if (field?.Type == IntermediateFieldType.String) | 258 | if (field != null && field.Type == IntermediateFieldType.String) |
| 259 | { | 259 | { |
| 260 | var data = field.AsString(); | 260 | var data = field.AsString(); |
| 261 | if (!String.IsNullOrEmpty(data)) | 261 | if (!String.IsNullOrEmpty(data)) |
| 262 | { | 262 | { |
| 263 | var resolved = this.componentIdPlaceholdersResolver.ResolveVariables(symbol.SourceLineNumbers, data, errorOnUnknown: false); | 263 | var changed = false; |
| 264 | if (resolved.UpdatedValue) | 264 | var start = data.IndexOf(ComponentIdPlaceholderStart); |
| 265 | while (start != -1) | ||
| 266 | { | ||
| 267 | var end = data.IndexOf(ComponentIdPlaceholderEnd, start + 1); | ||
| 268 | if (end == -1) | ||
| 269 | { | ||
| 270 | break; | ||
| 271 | } | ||
| 272 | |||
| 273 | var placeholderId = data.Substring(start, end - start + 1); | ||
| 274 | if (this.componentIdPlaceholders.TryGetValue(placeholderId, out var value)) | ||
| 275 | { | ||
| 276 | var sb = new StringBuilder(data); | ||
| 277 | sb.Remove(start, end - start + 1); | ||
| 278 | sb.Insert(start, value); | ||
| 279 | |||
| 280 | data = sb.ToString(); | ||
| 281 | changed = true; | ||
| 282 | |||
| 283 | end = start + value.Length; | ||
| 284 | } | ||
| 285 | |||
| 286 | start = data.IndexOf(ComponentIdPlaceholderStart, end); | ||
| 287 | } | ||
| 288 | |||
| 289 | if (changed) | ||
| 265 | { | 290 | { |
| 266 | field.Set(resolved.Value); | 291 | field.Overwrite(data); |
| 267 | } | 292 | } |
| 268 | } | 293 | } |
| 269 | } | 294 | } |
| @@ -2096,9 +2121,8 @@ namespace WixToolset.Core | |||
| 2096 | var encounteredODBCDataSource = false; | 2121 | var encounteredODBCDataSource = false; |
| 2097 | var files = 0; | 2122 | var files = 0; |
| 2098 | var guid = "*"; | 2123 | var guid = "*"; |
| 2099 | var componentIdPlaceholder = Compiler.DefaultComponentIdPlaceholderPrefix + this.componentIdPlaceholdersResolver.VariableCount; // placeholder id for defaulting Component/@Id to keypath id. | 2124 | Identifier id = null; |
| 2100 | var componentIdPlaceholderWixVariable = Compiler.DefaultComponentIdPlaceholderWixVariablePrefix + componentIdPlaceholder + ")"; | 2125 | string componentIdPlaceholder = null; |
| 2101 | var id = new Identifier(AccessModifier.Private, componentIdPlaceholderWixVariable); | ||
| 2102 | var keyFound = false; | 2126 | var keyFound = false; |
| 2103 | string keyPath = null; | 2127 | string keyPath = null; |
| 2104 | 2128 | ||
| @@ -2253,6 +2277,13 @@ namespace WixToolset.Core | |||
| 2253 | win64 = true; | 2277 | win64 = true; |
| 2254 | } | 2278 | } |
| 2255 | 2279 | ||
| 2280 | if (id == null) | ||
| 2281 | { | ||
| 2282 | // Placeholder id for defaulting Component/@Id to keypath id. | ||
| 2283 | componentIdPlaceholder = String.Concat(Compiler.ComponentIdPlaceholderStart, this.componentIdPlaceholders.Count, Compiler.ComponentIdPlaceholderEnd); | ||
| 2284 | id = new Identifier(AccessModifier.Private, componentIdPlaceholder); | ||
| 2285 | } | ||
| 2286 | |||
| 2256 | if (null == directoryId) | 2287 | if (null == directoryId) |
| 2257 | { | 2288 | { |
| 2258 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Directory")); | 2289 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Directory")); |
| @@ -2466,14 +2497,14 @@ namespace WixToolset.Core | |||
| 2466 | this.Core.Write(ErrorMessages.ImplicitComponentKeyPath(sourceLineNumbers, id.Id)); | 2497 | this.Core.Write(ErrorMessages.ImplicitComponentKeyPath(sourceLineNumbers, id.Id)); |
| 2467 | } | 2498 | } |
| 2468 | 2499 | ||
| 2469 | // if there isn't an @Id attribute value, replace the placeholder with the id of the keypath. | 2500 | // If there isn't an @Id attribute value, replace the placeholder with the id of the keypath. |
| 2470 | // either an explicit KeyPath="yes" attribute must be specified or requirements for | 2501 | // either an explicit KeyPath="yes" attribute must be specified or requirements for |
| 2471 | // generatable guid must be met. | 2502 | // generatable guid must be met. |
| 2472 | if (componentIdPlaceholderWixVariable == id.Id) | 2503 | if (componentIdPlaceholder == id.Id) |
| 2473 | { | 2504 | { |
| 2474 | if (isGeneratableGuidOk || keyFound && !String.IsNullOrEmpty(keyPath)) | 2505 | if (isGeneratableGuidOk || keyFound && !String.IsNullOrEmpty(keyPath)) |
| 2475 | { | 2506 | { |
| 2476 | this.componentIdPlaceholdersResolver.AddVariable(sourceLineNumbers, componentIdPlaceholder, keyPath, false); | 2507 | this.componentIdPlaceholders.Add(componentIdPlaceholder, keyPath); |
| 2477 | 2508 | ||
| 2478 | id = new Identifier(AccessModifier.Private, keyPath); | 2509 | id = new Identifier(AccessModifier.Private, keyPath); |
| 2479 | } | 2510 | } |
| @@ -2483,12 +2514,6 @@ namespace WixToolset.Core | |||
| 2483 | } | 2514 | } |
| 2484 | } | 2515 | } |
| 2485 | 2516 | ||
| 2486 | // If an id was not determined by now, we have to error. | ||
| 2487 | if (null == id) | ||
| 2488 | { | ||
| 2489 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Id")); | ||
| 2490 | } | ||
| 2491 | |||
| 2492 | // finally add the Component table row | 2517 | // finally add the Component table row |
| 2493 | if (!this.Core.EncounteredError) | 2518 | if (!this.Core.EncounteredError) |
| 2494 | { | 2519 | { |
| @@ -4120,9 +4145,9 @@ namespace WixToolset.Core | |||
| 4120 | Identifier id = null; | 4145 | Identifier id = null; |
| 4121 | string componentGuidGenerationSeed = null; | 4146 | string componentGuidGenerationSeed = null; |
| 4122 | var fileSourceAttribSet = false; | 4147 | var fileSourceAttribSet = false; |
| 4123 | var nameHasValue = false; | 4148 | XAttribute nameAttribute = null; |
| 4124 | var name = "."; // default to parent directory. | 4149 | var name = "."; // default to parent directory. |
| 4125 | string[] inlineSyntax = null; | 4150 | string inlineSyntax = null; |
| 4126 | string shortName = null; | 4151 | string shortName = null; |
| 4127 | string sourceName = null; | 4152 | string sourceName = null; |
| 4128 | string shortSourceName = null; | 4153 | string shortSourceName = null; |
| @@ -4148,15 +4173,8 @@ namespace WixToolset.Core | |||
| 4148 | fileSourceAttribSet = true; | 4173 | fileSourceAttribSet = true; |
| 4149 | break; | 4174 | break; |
| 4150 | case "Name": | 4175 | case "Name": |
| 4151 | nameHasValue = true; | 4176 | name = this.Core.GetAttributeValue(sourceLineNumbers, attrib); |
| 4152 | if (attrib.Value == ".") | 4177 | nameAttribute = attrib; |
| 4153 | { | ||
| 4154 | name = attrib.Value; | ||
| 4155 | } | ||
| 4156 | else | ||
| 4157 | { | ||
| 4158 | inlineSyntax = this.Core.GetAttributeInlineDirectorySyntax(sourceLineNumbers, attrib); | ||
| 4159 | } | ||
| 4160 | break; | 4178 | break; |
| 4161 | case "ShortName": | 4179 | case "ShortName": |
| 4162 | shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); | 4180 | shortName = this.Core.GetAttributeShortFilename(sourceLineNumbers, attrib, false); |
| @@ -4185,37 +4203,7 @@ namespace WixToolset.Core | |||
| 4185 | } | 4203 | } |
| 4186 | } | 4204 | } |
| 4187 | 4205 | ||
| 4188 | // Create the directory rows for the inline. | 4206 | if (nameAttribute == null) |
| 4189 | if (null != inlineSyntax) | ||
| 4190 | { | ||
| 4191 | // Special case the single entry in the inline syntax since it is the most common case | ||
| 4192 | // and needs no extra processing. It's just the name of the directory. | ||
| 4193 | if (1 == inlineSyntax.Length) | ||
| 4194 | { | ||
| 4195 | name = inlineSyntax[0]; | ||
| 4196 | } | ||
| 4197 | else | ||
| 4198 | { | ||
| 4199 | var pathStartsAt = 0; | ||
| 4200 | if (inlineSyntax[0].EndsWith(":")) | ||
| 4201 | { | ||
| 4202 | parentId = inlineSyntax[0].TrimEnd(':'); | ||
| 4203 | this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, parentId); | ||
| 4204 | |||
| 4205 | pathStartsAt = 1; | ||
| 4206 | } | ||
| 4207 | |||
| 4208 | for (var i = pathStartsAt; i < inlineSyntax.Length - 1; ++i) | ||
| 4209 | { | ||
| 4210 | var inlineId = this.Core.CreateDirectoryRow(sourceLineNumbers, null, parentId, inlineSyntax[i]); | ||
| 4211 | parentId = inlineId.Id; | ||
| 4212 | } | ||
| 4213 | |||
| 4214 | name = inlineSyntax[inlineSyntax.Length - 1]; | ||
| 4215 | } | ||
| 4216 | } | ||
| 4217 | |||
| 4218 | if (!nameHasValue) | ||
| 4219 | { | 4207 | { |
| 4220 | if (!String.IsNullOrEmpty(shortName)) | 4208 | if (!String.IsNullOrEmpty(shortName)) |
| 4221 | { | 4209 | { |
| @@ -4264,39 +4252,55 @@ namespace WixToolset.Core | |||
| 4264 | } | 4252 | } |
| 4265 | } | 4253 | } |
| 4266 | 4254 | ||
| 4267 | // Update the file source path appropriately. | 4255 | // Create the directory rows for the inline. |
| 4268 | if (fileSourceAttribSet) | 4256 | if (nameAttribute != null) |
| 4269 | { | 4257 | { |
| 4270 | if (!fileSource.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) | 4258 | var lastSlash = name.LastIndexOf('\\'); |
| 4259 | if (lastSlash > 0) | ||
| 4271 | { | 4260 | { |
| 4272 | fileSource = String.Concat(fileSource, Path.DirectorySeparatorChar); | 4261 | inlineSyntax = name; |
| 4262 | name = inlineSyntax.Substring(lastSlash + 1); | ||
| 4263 | |||
| 4264 | parentId = this.Core.CreateDirectoryReferenceFromInlineSyntax(sourceLineNumbers, nameAttribute, parentId, inlineSyntax.Substring(0, lastSlash)); | ||
| 4265 | |||
| 4266 | if (!this.Core.IsValidLongFilename(name, false, false)) | ||
| 4267 | { | ||
| 4268 | this.Messaging.Write(ErrorMessages.IllegalLongFilename(sourceLineNumbers, node.Name.LocalName, nameAttribute.Name.LocalName, nameAttribute.Value, name)); | ||
| 4269 | } | ||
| 4273 | } | 4270 | } |
| 4274 | } | 4271 | } |
| 4275 | else // add the appropriate part of this directory element to the file source. | 4272 | |
| 4273 | if (null == id) | ||
| 4276 | { | 4274 | { |
| 4277 | string append = String.IsNullOrEmpty(sourceName) ? name : sourceName; | 4275 | id = this.Core.CreateIdentifier("dir", parentId, name, shortName, sourceName, shortSourceName); |
| 4278 | 4276 | ||
| 4279 | if (!String.IsNullOrEmpty(append)) | 4277 | if (!String.IsNullOrEmpty(inlineSyntax)) |
| 4280 | { | 4278 | { |
| 4281 | fileSource = String.Concat(fileSource, append, Path.DirectorySeparatorChar); | 4279 | this.Core.AddInlineDirectoryId(inlineSyntax, id.Id); |
| 4282 | } | 4280 | } |
| 4283 | } | 4281 | } |
| 4284 | 4282 | ||
| 4285 | if (null == id) | 4283 | if ("TARGETDIR".Equals(id.Id, StringComparison.Ordinal) && !("SourceDir".Equals(name, StringComparison.Ordinal) && shortName == null && shortSourceName == null && sourceName == null)) |
| 4286 | { | 4284 | { |
| 4287 | id = this.Core.CreateIdentifier("dir", parentId, name, shortName, sourceName, shortSourceName); | 4285 | this.Core.Write(ErrorMessages.IllegalTargetDirDefaultDir(sourceLineNumbers, name)); |
| 4288 | } | 4286 | } |
| 4289 | 4287 | ||
| 4290 | // Calculate the DefaultDir for the directory row. | 4288 | // Update the file source path appropriately. |
| 4291 | var defaultDir = String.IsNullOrEmpty(shortName) ? name : String.Concat(shortName, "|", name); | 4289 | if (fileSourceAttribSet) |
| 4292 | if (!String.IsNullOrEmpty(sourceName)) | ||
| 4293 | { | 4290 | { |
| 4294 | defaultDir = String.Concat(defaultDir, ":", String.IsNullOrEmpty(shortSourceName) ? sourceName : String.Concat(shortSourceName, "|", sourceName)); | 4291 | if (!fileSource.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) |
| 4292 | { | ||
| 4293 | fileSource = String.Concat(fileSource, Path.DirectorySeparatorChar); | ||
| 4294 | } | ||
| 4295 | } | 4295 | } |
| 4296 | 4296 | else // add the appropriate part of this directory element to the file source. | |
| 4297 | if ("TARGETDIR".Equals(id.Id, StringComparison.Ordinal) && !"SourceDir".Equals(defaultDir, StringComparison.Ordinal)) | ||
| 4298 | { | 4297 | { |
| 4299 | this.Core.Write(ErrorMessages.IllegalTargetDirDefaultDir(sourceLineNumbers, defaultDir)); | 4298 | string append = String.IsNullOrEmpty(sourceName) ? name : sourceName; |
| 4299 | |||
| 4300 | if (!String.IsNullOrEmpty(append)) | ||
| 4301 | { | ||
| 4302 | fileSource = String.Concat(fileSource, append, Path.DirectorySeparatorChar); | ||
| 4303 | } | ||
| 4300 | } | 4304 | } |
| 4301 | 4305 | ||
| 4302 | foreach (var child in node.Elements()) | 4306 | foreach (var child in node.Elements()) |
diff --git a/src/WixToolset.Core/CompilerCore.cs b/src/WixToolset.Core/CompilerCore.cs index d88858ae..e2c1a3d6 100644 --- a/src/WixToolset.Core/CompilerCore.cs +++ b/src/WixToolset.Core/CompilerCore.cs | |||
| @@ -120,7 +120,7 @@ namespace WixToolset.Core | |||
| 120 | private readonly IParseHelper parseHelper; | 120 | private readonly IParseHelper parseHelper; |
| 121 | private readonly Intermediate intermediate; | 121 | private readonly Intermediate intermediate; |
| 122 | private readonly IMessaging messaging; | 122 | private readonly IMessaging messaging; |
| 123 | private HashSet<string> activeSectionInlinedDirectoryIds; | 123 | private Dictionary<string, string> activeSectionCachedInlinedDirectoryIds; |
| 124 | private HashSet<string> activeSectionSimpleReferences; | 124 | private HashSet<string> activeSectionSimpleReferences; |
| 125 | 125 | ||
| 126 | /// <summary> | 126 | /// <summary> |
| @@ -354,12 +354,13 @@ namespace WixToolset.Core | |||
| 354 | /// Creates directories using the inline directory syntax. | 354 | /// Creates directories using the inline directory syntax. |
| 355 | /// </summary> | 355 | /// </summary> |
| 356 | /// <param name="sourceLineNumbers">Source line information.</param> | 356 | /// <param name="sourceLineNumbers">Source line information.</param> |
| 357 | /// <param name="attribute">The attribute to parse.</param> | 357 | /// <param name="attribute">Attribute containing the inline syntax.</param> |
| 358 | /// <param name="parentId">Optional identifier of parent directory.</param> | 358 | /// <param name="parentId">Optional identifier of parent directory.</param> |
| 359 | /// <param name="inlineSyntax">Optional inline syntax to override attribute's value.</param> | ||
| 359 | /// <returns>Identifier of the leaf directory created.</returns> | 360 | /// <returns>Identifier of the leaf directory created.</returns> |
| 360 | public string CreateDirectoryReferenceFromInlineSyntax(SourceLineNumber sourceLineNumbers, XAttribute attribute, string parentId) | 361 | public string CreateDirectoryReferenceFromInlineSyntax(SourceLineNumber sourceLineNumbers, XAttribute attribute, string parentId, string inlineSyntax = null) |
| 361 | { | 362 | { |
| 362 | return this.parseHelper.CreateDirectoryReferenceFromInlineSyntax(this.ActiveSection, sourceLineNumbers, parentId, attribute, this.activeSectionInlinedDirectoryIds); | 363 | return this.parseHelper.CreateDirectoryReferenceFromInlineSyntax(this.ActiveSection, sourceLineNumbers, attribute, parentId, inlineSyntax, this.activeSectionCachedInlinedDirectoryIds); |
| 363 | } | 364 | } |
| 364 | 365 | ||
| 365 | /// <summary> | 366 | /// <summary> |
| @@ -1001,6 +1002,16 @@ namespace WixToolset.Core | |||
| 1001 | } | 1002 | } |
| 1002 | 1003 | ||
| 1003 | /// <summary> | 1004 | /// <summary> |
| 1005 | /// Adds inline directory syntax generated identifier. | ||
| 1006 | /// </summary> | ||
| 1007 | /// <param name="inlineSyntax">Inline directory syntax the identifier was generated.</param> | ||
| 1008 | /// <param name="id">Generated identifier for inline syntax.</param> | ||
| 1009 | internal void AddInlineDirectoryId(string inlineSyntax, string id) | ||
| 1010 | { | ||
| 1011 | this.activeSectionCachedInlinedDirectoryIds.Add(inlineSyntax, id); | ||
| 1012 | } | ||
| 1013 | |||
| 1014 | /// <summary> | ||
| 1004 | /// Creates a new section and makes it the active section in the core. | 1015 | /// Creates a new section and makes it the active section in the core. |
| 1005 | /// </summary> | 1016 | /// </summary> |
| 1006 | /// <param name="id">Unique identifier for the section.</param> | 1017 | /// <param name="id">Unique identifier for the section.</param> |
| @@ -1011,7 +1022,7 @@ namespace WixToolset.Core | |||
| 1011 | { | 1022 | { |
| 1012 | this.ActiveSection = this.CreateSection(id, type, codepage, compilationId); | 1023 | this.ActiveSection = this.CreateSection(id, type, codepage, compilationId); |
| 1013 | 1024 | ||
| 1014 | this.activeSectionInlinedDirectoryIds = new HashSet<string>(); | 1025 | this.activeSectionCachedInlinedDirectoryIds = new Dictionary<string, string>(); |
| 1015 | this.activeSectionSimpleReferences = new HashSet<string>(); | 1026 | this.activeSectionSimpleReferences = new HashSet<string>(); |
| 1016 | 1027 | ||
| 1017 | return this.ActiveSection; | 1028 | return this.ActiveSection; |
| @@ -1060,9 +1071,9 @@ namespace WixToolset.Core | |||
| 1060 | /// <param name="sourceName">Optional source name for the directory.</param> | 1071 | /// <param name="sourceName">Optional source name for the directory.</param> |
| 1061 | /// <param name="shortSourceName">Optional short source name for the directory.</param> | 1072 | /// <param name="shortSourceName">Optional short source name for the directory.</param> |
| 1062 | /// <returns>Identifier for the newly created row.</returns> | 1073 | /// <returns>Identifier for the newly created row.</returns> |
| 1063 | internal Identifier CreateDirectoryRow(SourceLineNumber sourceLineNumbers, Identifier id, string parentId, string name, string shortName = null, string sourceName = null, string shortSourceName = null) | 1074 | internal Identifier CreateDirectorySymbol(SourceLineNumber sourceLineNumbers, Identifier id, string parentId, string name, string shortName = null, string sourceName = null, string shortSourceName = null) |
| 1064 | { | 1075 | { |
| 1065 | return this.parseHelper.CreateDirectorySymbol(this.ActiveSection, sourceLineNumbers, id, parentId, name, this.activeSectionInlinedDirectoryIds, shortName, sourceName, shortSourceName); | 1076 | return this.parseHelper.CreateDirectorySymbol(this.ActiveSection, sourceLineNumbers, id, parentId, name, shortName, sourceName, shortSourceName); |
| 1066 | } | 1077 | } |
| 1067 | 1078 | ||
| 1068 | public void CreateWixSearchSymbol(SourceLineNumber sourceLineNumbers, string elementName, Identifier id, string variable, string condition, string after) | 1079 | public void CreateWixSearchSymbol(SourceLineNumber sourceLineNumbers, string elementName, Identifier id, string variable, string condition, string after) |
| @@ -1070,18 +1081,6 @@ namespace WixToolset.Core | |||
| 1070 | this.parseHelper.CreateWixSearchSymbol(this.ActiveSection, sourceLineNumbers, elementName, id, variable, condition, after, null); | 1081 | this.parseHelper.CreateWixSearchSymbol(this.ActiveSection, sourceLineNumbers, elementName, id, variable, condition, after, null); |
| 1071 | } | 1082 | } |
| 1072 | 1083 | ||
| 1073 | /// <summary> | ||
| 1074 | /// Gets the attribute value as inline directory syntax. | ||
| 1075 | /// </summary> | ||
| 1076 | /// <param name="sourceLineNumbers">Source line information.</param> | ||
| 1077 | /// <param name="attribute">Attribute containing the value to get.</param> | ||
| 1078 | /// <param name="resultUsedToCreateReference">Flag indicates whether the inline directory syntax should be processed to create a directory row or to create a directory reference.</param> | ||
| 1079 | /// <returns>Inline directory syntax split into array of strings or null if the syntax did not parse.</returns> | ||
| 1080 | internal string[] GetAttributeInlineDirectorySyntax(SourceLineNumber sourceLineNumbers, XAttribute attribute, bool resultUsedToCreateReference = false) | ||
| 1081 | { | ||
| 1082 | return this.parseHelper.GetAttributeInlineDirectorySyntax(sourceLineNumbers, attribute, resultUsedToCreateReference); | ||
| 1083 | } | ||
| 1084 | |||
| 1085 | internal WixActionSymbol ScheduleActionSymbol(SourceLineNumber sourceLineNumbers, AccessModifier access, SequenceTable sequence, string actionName, string condition = null, string beforeAction = null, string afterAction = null, bool overridable = false) | 1084 | internal WixActionSymbol ScheduleActionSymbol(SourceLineNumber sourceLineNumbers, AccessModifier access, SequenceTable sequence, string actionName, string condition = null, string beforeAction = null, string afterAction = null, bool overridable = false) |
| 1086 | { | 1085 | { |
| 1087 | return this.parseHelper.ScheduleActionSymbol(this.ActiveSection, sourceLineNumbers, access, sequence, actionName, condition, beforeAction, afterAction, overridable); | 1086 | return this.parseHelper.ScheduleActionSymbol(this.ActiveSection, sourceLineNumbers, access, sequence, actionName, condition, beforeAction, afterAction, overridable); |
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; |
