main
cs 272 lines 10.6 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
4 {
5 using System;
6 using System.Collections.Generic;
7 using System.Globalization;
8 using System.Linq;
9 using WixToolset.Core.Bind;
10 using WixToolset.Data;
11 using WixToolset.Data.Symbols;
12 using WixToolset.Extensibility;
13 using WixToolset.Extensibility.Data;
14 using WixToolset.Extensibility.Services;
15
16 /// <summary>
17 /// Resolver for the WiX toolset.
18 /// </summary>
19 internal class Resolver : IResolver
20 {
21 internal Resolver(IServiceProvider serviceProvider)
22 {
23 this.ServiceProvider = serviceProvider;
24
25 this.Messaging = serviceProvider.GetService<IMessaging>();
26
27 this.FileResolver = serviceProvider.GetService<IFileResolver>();
28 }
29
30 private IServiceProvider ServiceProvider { get; }
31
32 private IMessaging Messaging { get; }
33
34 private IFileResolver FileResolver { get; }
35
36 public IResolveResult Resolve(IResolveContext context)
37 {
38 foreach (var extension in context.Extensions)
39 {
40 extension.PreResolve(context);
41 }
42
43 ResolveResult resolveResult = null;
44 try
45 {
46 var filteredLocalizations = FilterLocalizations(context);
47
48 var variableResolver = this.CreateVariableResolver(context, filteredLocalizations);
49
50 this.LocalizeUI(variableResolver, context.IntermediateRepresentation);
51
52 resolveResult = this.ResolveFields(context, variableResolver);
53
54 var primaryLocalization = filteredLocalizations.FirstOrDefault();
55
56 if (primaryLocalization != null)
57 {
58 this.TryGetCultureInfo(primaryLocalization.Culture, out var cultureInfo);
59
60 resolveResult.Codepage = primaryLocalization.Codepage ?? cultureInfo?.TextInfo.ANSICodePage;
61
62 resolveResult.SummaryInformationCodepage = primaryLocalization.SummaryInformationCodepage ?? primaryLocalization.Codepage ?? cultureInfo?.TextInfo.ANSICodePage;
63
64 resolveResult.PackageLcid = cultureInfo?.LCID;
65 }
66 }
67 finally
68 {
69 foreach (var extension in context.Extensions)
70 {
71 extension.PostResolve(resolveResult);
72 }
73 }
74
75 return resolveResult;
76 }
77
78 private ResolveResult ResolveFields(IResolveContext context, IVariableResolver variableResolver)
79 {
80 var filesWithEmbeddedFiles = new ExtractEmbeddedFiles();
81
82 IReadOnlyCollection<DelayedField> delayedFields;
83 {
84 var command = new ResolveFieldsCommand(this.Messaging, this.FileResolver, variableResolver, context.BindPaths, context.Extensions, filesWithEmbeddedFiles, context.IntermediateFolder, context.IntermediateRepresentation, context.AllowUnresolvedVariables);
85 command.Execute();
86
87 delayedFields = command.DelayedFields;
88 }
89
90 var expectedEmbeddedFiles = filesWithEmbeddedFiles.GetExpectedEmbeddedFiles();
91
92 context.IntermediateRepresentation.UpdateLevel(IntermediateLevels.Resolved);
93
94 return new ResolveResult
95 {
96 ExpectedEmbeddedFiles = expectedEmbeddedFiles,
97 DelayedFields = delayedFields,
98 IntermediateRepresentation = context.IntermediateRepresentation
99 };
100 }
101
102 /// <summary>
103 /// Localize dialogs and controls.
104 /// </summary>
105 private void LocalizeUI(IVariableResolver variableResolver, Intermediate intermediate)
106 {
107 foreach (var section in intermediate.Sections)
108 {
109 foreach (var symbol in section.Symbols.OfType<DialogSymbol>())
110 {
111 if (variableResolver.TryGetLocalizedControl(symbol.Id.Id, null, out var localizedControl))
112 {
113 if (CompilerConstants.IntegerNotSet != localizedControl.X)
114 {
115 symbol.HCentering = localizedControl.X;
116 }
117
118 if (CompilerConstants.IntegerNotSet != localizedControl.Y)
119 {
120 symbol.VCentering = localizedControl.Y;
121 }
122
123 if (CompilerConstants.IntegerNotSet != localizedControl.Width)
124 {
125 symbol.Width = localizedControl.Width;
126 }
127
128 if (CompilerConstants.IntegerNotSet != localizedControl.Height)
129 {
130 symbol.Height = localizedControl.Height;
131 }
132
133 symbol.RightAligned |= localizedControl.RightAligned;
134 symbol.RightToLeft |= localizedControl.RightToLeft;
135 symbol.LeftScroll |= localizedControl.LeftScroll;
136
137 if (!String.IsNullOrEmpty(localizedControl.Text))
138 {
139 symbol.Title = localizedControl.Text;
140 }
141 }
142 }
143
144 foreach (var symbol in section.Symbols.OfType<ControlSymbol>())
145 {
146 if (variableResolver.TryGetLocalizedControl(symbol.DialogRef, symbol.Control, out var localizedControl))
147 {
148 if (CompilerConstants.IntegerNotSet != localizedControl.X)
149 {
150 symbol.X = localizedControl.X;
151 }
152
153 if (CompilerConstants.IntegerNotSet != localizedControl.Y)
154 {
155 symbol.Y = localizedControl.Y;
156 }
157
158 if (CompilerConstants.IntegerNotSet != localizedControl.Width)
159 {
160 symbol.Width = localizedControl.Width;
161 }
162
163 if (CompilerConstants.IntegerNotSet != localizedControl.Height)
164 {
165 symbol.Height = localizedControl.Height;
166 }
167
168 symbol.RightAligned |= localizedControl.RightAligned;
169 symbol.RightToLeft |= localizedControl.RightToLeft;
170 symbol.LeftScroll |= localizedControl.LeftScroll;
171
172 if (!String.IsNullOrEmpty(localizedControl.Text))
173 {
174 symbol.Text = localizedControl.Text;
175 }
176 }
177 }
178 }
179 }
180
181 private IVariableResolver CreateVariableResolver(IResolveContext context, IEnumerable<Localization> filteredLocalizations)
182 {
183 var variableResolver = this.ServiceProvider.GetService<IVariableResolver>();
184
185 foreach (var localization in filteredLocalizations)
186 {
187 variableResolver.AddLocalization(localization);
188 }
189
190 foreach (var bindVariable in context.BindVariables)
191 {
192 variableResolver.AddVariable(null, bindVariable.Key, bindVariable.Value, false);
193 }
194
195 // Gather all the wix variables.
196 var wixVariableSymbols = context.IntermediateRepresentation.Sections.SelectMany(s => s.Symbols).OfType<WixVariableSymbol>();
197 foreach (var symbol in wixVariableSymbols)
198 {
199 variableResolver.AddVariable(symbol.SourceLineNumbers, symbol.Id.Id, symbol.Value, symbol.Overridable);
200 }
201
202 return variableResolver;
203 }
204
205 private bool TryGetCultureInfo(string culture, out CultureInfo cultureInfo)
206 {
207 cultureInfo = null;
208
209 if (!String.IsNullOrEmpty(culture))
210 {
211 try
212 {
213 cultureInfo = new CultureInfo(culture, useUserOverride: false);
214 }
215 catch
216 {
217 this.Messaging.Write("");
218 }
219 }
220
221 return cultureInfo != null;
222 }
223
224 private static IEnumerable<Localization> FilterLocalizations(IResolveContext context)
225 {
226 var result = new List<Localization>();
227 var filter = CalculateCultureFilter(context);
228
229 var localizations = context.Localizations.Concat(context.IntermediateRepresentation.Localizations).ToList();
230
231 AddFilteredLocalizations(result, filter, localizations);
232
233 return result;
234 }
235
236 private static IEnumerable<string> CalculateCultureFilter(IResolveContext context)
237 {
238 var filter = context.FilterCultures ?? Array.Empty<string>();
239
240 // If no filter was specified, look for a language neutral localization file specified
241 // from the command-line (not embedded in the intermediate). If found, filter on language
242 // neutral.
243 if (!filter.Any() && context.Localizations.Any(l => String.IsNullOrEmpty(l.Culture)))
244 {
245 filter = new[] { String.Empty };
246 }
247
248 return filter;
249 }
250
251 private static void AddFilteredLocalizations(List<Localization> result, IEnumerable<string> filter, IEnumerable<Localization> localizations)
252 {
253 // If there is no filter, return all localizations provided by the user (either as a .wxl or from a .wixlib on the command-line)
254 // **and only** the extension's default culture localizations.
255 if (!filter.Any())
256 {
257 // The filter turns out to be really simple, skip localizations that came from an extension (LocalizationLocation.Extension)
258 // but keep those that are marked as the extension's default culture (LocalizationLocation.ExtensionDefaultCulture).
259 var filtered = localizations.Where(l => l.Location != LocalizationLocation.Extension);
260
261 result.AddRange(filtered);
262 }
263 else // filter localizations in order specified by the filter
264 {
265 foreach (var culture in filter)
266 {
267 result.AddRange(localizations.Where(l => culture.Equals(l.Culture, StringComparison.OrdinalIgnoreCase) || String.IsNullOrEmpty(l.Culture)));
268 }
269 }
270 }
271 }
272 }