main
cs 165 lines 6.34 KB
Raw
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
3 namespace WixToolset.Core.ExtensibilityServices
4 {
5 using System;
6 using System.Collections.Generic;
7 using System.IO;
8 using WixToolset.Data;
9 using WixToolset.Extensibility;
10 using WixToolset.Extensibility.Data;
11 using WixToolset.Extensibility.Services;
12
13 internal class FileResolver : IFileResolver
14 {
15 private const string BindPathOpenString = "!(bindpath.";
16
17 public string ResolveFile(string source, IEnumerable<ILibrarianExtension> librarianExtensions, IEnumerable<IBindPath> bindPaths, SourceLineNumber sourceLineNumbers, IntermediateSymbolDefinition symbolDefinition)
18 {
19 var checkedPaths = new List<string>();
20
21 foreach (var extension in librarianExtensions)
22 {
23 var resolved = extension.ResolveFile(sourceLineNumbers, symbolDefinition, source);
24
25 if (resolved?.CheckedPaths != null)
26 {
27 checkedPaths.AddRange(resolved.CheckedPaths);
28 }
29
30 if (!String.IsNullOrEmpty(resolved?.Path))
31 {
32 return resolved?.Path;
33 }
34 }
35
36 return this.MustResolveUsingBindPaths(source, symbolDefinition, sourceLineNumbers, bindPaths, checkedPaths);
37 }
38
39 public string ResolveFile(string source, IEnumerable<IResolverExtension> resolverExtensions, IEnumerable<IBindPath> bindPaths, BindStage bindStage, SourceLineNumber sourceLineNumbers, IntermediateSymbolDefinition symbolDefinition, IEnumerable<string> alreadyCheckedPaths = null)
40 {
41 var checkedPaths = new List<string>();
42
43 if (alreadyCheckedPaths != null)
44 {
45 checkedPaths.AddRange(alreadyCheckedPaths);
46 }
47
48 foreach (var extension in resolverExtensions)
49 {
50 var resolved = extension.ResolveFile(source, symbolDefinition, sourceLineNumbers, bindStage);
51
52 if (resolved?.CheckedPaths != null)
53 {
54 checkedPaths.AddRange(resolved.CheckedPaths);
55 }
56
57 if (!String.IsNullOrEmpty(resolved?.Path))
58 {
59 return resolved?.Path;
60 }
61 }
62
63 return this.MustResolveUsingBindPaths(source, symbolDefinition, sourceLineNumbers, bindPaths, checkedPaths);
64 }
65
66 private string MustResolveUsingBindPaths(string source, IntermediateSymbolDefinition symbolDefinition, SourceLineNumber sourceLineNumbers, IEnumerable<IBindPath> bindPaths, List<string> checkedPaths)
67 {
68 string resolved = null;
69
70 // If the file exists, we're good to go.
71 checkedPaths.Add(source);
72 if (CheckFileExists(source))
73 {
74 resolved = source;
75 }
76 else if (Path.IsPathRooted(source)) // path is rooted so bindpaths won't help, bail since the file apparently doesn't exist.
77 {
78 resolved = null;
79 }
80 else // not a rooted path so let's try applying all the different source resolution options.
81 {
82 var bindName = String.Empty;
83 var path = source;
84 var pathWithoutSourceDir = String.Empty;
85
86 if (source.StartsWith(BindPathOpenString, StringComparison.Ordinal))
87 {
88 var closeParen = source.IndexOf(')', BindPathOpenString.Length);
89
90 if (-1 != closeParen)
91 {
92 bindName = source.Substring(BindPathOpenString.Length, closeParen - BindPathOpenString.Length);
93 path = source.Substring(BindPathOpenString.Length + bindName.Length + 1); // +1 for the closing paren.
94 path = path.TrimStart('\\'); // remove starting '\\' char so the path doesn't look rooted.
95 }
96 }
97 else if (source.StartsWith("SourceDir\\", StringComparison.Ordinal) || source.StartsWith("SourceDir/", StringComparison.Ordinal))
98 {
99 pathWithoutSourceDir = path.Substring(10);
100 }
101
102 foreach (var bindPath in bindPaths)
103 {
104 if (String.IsNullOrEmpty(bindName))
105 {
106 if (String.IsNullOrEmpty(bindPath.Name))
107 {
108 if (!String.IsNullOrEmpty(pathWithoutSourceDir))
109 {
110 resolved = ResolveWithBindPath(bindPath.Path, pathWithoutSourceDir, checkedPaths);
111 }
112
113 if (String.IsNullOrEmpty(resolved))
114 {
115 resolved = ResolveWithBindPath(bindPath.Path, path, checkedPaths);
116 }
117 }
118 }
119 else if (bindName.Equals(bindPath.Name, StringComparison.OrdinalIgnoreCase))
120 {
121 resolved = ResolveWithBindPath(bindPath.Path, path, checkedPaths);
122 }
123
124 if (!String.IsNullOrEmpty(resolved))
125 {
126 break;
127 }
128 }
129 }
130
131 if (null == resolved)
132 {
133 throw new WixException(ErrorMessages.FileNotFound(sourceLineNumbers, source, symbolDefinition?.Name, checkedPaths));
134 }
135
136 return resolved;
137 }
138
139 private static string ResolveWithBindPath(string bindPath, string relativePath, List<string> checkedPaths)
140 {
141 var filePath = Path.Combine(bindPath, relativePath);
142
143 checkedPaths.Add(filePath);
144
145 if (CheckFileExists(filePath))
146 {
147 return filePath;
148 }
149
150 return null;
151 }
152
153 private static bool CheckFileExists(string path)
154 {
155 try
156 {
157 return File.Exists(path);
158 }
159 catch (ArgumentException)
160 {
161 throw new WixException(ErrorMessages.IllegalCharactersInPath(path));
162 }
163 }
164 }
165 }