diff options
Diffstat (limited to 'src/WixToolset.Core/Compiler.cs')
-rw-r--r-- | src/WixToolset.Core/Compiler.cs | 168 |
1 files changed, 86 insertions, 82 deletions
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()) |