// 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.
namespace WixToolset.Core
{
using System;
using System.Collections.Generic;
using System.Linq;
using WixToolset.Core.Bind;
using WixToolset.Data;
using WixToolset.Data.Tuples;
using WixToolset.Extensibility;
using WixToolset.Extensibility.Data;
using WixToolset.Extensibility.Services;
///
/// Resolver for the WiX toolset.
///
internal class Resolver : IResolver
{
internal Resolver(IServiceProvider serviceProvider)
{
this.ServiceProvider = serviceProvider;
this.Messaging = serviceProvider.GetService();
}
private IServiceProvider ServiceProvider { get; }
private IMessaging Messaging { get; }
public IEnumerable BindPaths { get; set; }
public string IntermediateFolder { get; set; }
public Intermediate IntermediateRepresentation { get; set; }
public IEnumerable Localizations { get; set; }
public IEnumerable FilterCultures { get; set; }
public ResolveResult Resolve(IResolveContext context)
{
foreach (var extension in context.Extensions)
{
extension.PreResolve(context);
}
ResolveResult resolveResult = null;
try
{
PopulateVariableResolver(context);
this.LocalizeUI(context);
resolveResult = this.DoResolve(context);
}
finally
{
foreach (var extension in context.Extensions)
{
extension.PostResolve(resolveResult);
}
}
return resolveResult;
}
private ResolveResult DoResolve(IResolveContext context)
{
var buildingPatch = context.IntermediateRepresentation.Sections.Any(s => s.Type == SectionType.Patch);
var filesWithEmbeddedFiles = new ExtractEmbeddedFiles();
IEnumerable delayedFields;
{
var command = new ResolveFieldsCommand();
command.Messaging = this.Messaging;
command.BuildingPatch = buildingPatch;
command.VariableResolver = context.VariableResolver;
command.BindPaths = context.BindPaths;
command.Extensions = context.Extensions;
command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles;
command.IntermediateFolder = context.IntermediateFolder;
command.Intermediate = context.IntermediateRepresentation;
command.SupportDelayedResolution = true;
command.Execute();
delayedFields = command.DelayedFields;
}
#if REVISIT_FOR_PATCHING
if (context.IntermediateRepresentation.SubStorages != null)
{
foreach (SubStorage transform in context.IntermediateRepresentation.SubStorages)
{
var command = new ResolveFieldsCommand();
command.BuildingPatch = buildingPatch;
command.BindVariableResolver = context.WixVariableResolver;
command.BindPaths = context.BindPaths;
command.Extensions = context.Extensions;
command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles;
command.IntermediateFolder = context.IntermediateFolder;
command.Intermediate = context.IntermediateRepresentation;
command.SupportDelayedResolution = false;
command.Execute();
}
}
#endif
var expectedEmbeddedFiles = filesWithEmbeddedFiles.GetExpectedEmbeddedFiles();
return new ResolveResult
{
Codepage = context.VariableResolver.Codepage,
ExpectedEmbeddedFiles = expectedEmbeddedFiles,
DelayedFields = delayedFields,
IntermediateRepresentation = context.IntermediateRepresentation
};
}
///
/// Localize dialogs and controls.
///
private void LocalizeUI(IResolveContext context)
{
foreach (var section in context.IntermediateRepresentation.Sections)
{
foreach (var row in section.Tuples.OfType())
{
string dialog = row.Dialog;
if (context.VariableResolver.TryGetLocalizedControl(dialog, null, out LocalizedControl localizedControl))
{
if (CompilerConstants.IntegerNotSet != localizedControl.X)
{
row.HCentering = localizedControl.X;
}
if (CompilerConstants.IntegerNotSet != localizedControl.Y)
{
row.VCentering = localizedControl.Y;
}
if (CompilerConstants.IntegerNotSet != localizedControl.Width)
{
row.Width = localizedControl.Width;
}
if (CompilerConstants.IntegerNotSet != localizedControl.Height)
{
row.Height = localizedControl.Height;
}
row.Attributes = row.Attributes | localizedControl.Attributes;
if (!String.IsNullOrEmpty(localizedControl.Text))
{
row.Title = localizedControl.Text;
}
}
}
foreach (var row in section.Tuples.OfType())
{
string dialog = row.Dialog_;
string control = row.Control;
if (context.VariableResolver.TryGetLocalizedControl(dialog, control, out LocalizedControl localizedControl))
{
if (CompilerConstants.IntegerNotSet != localizedControl.X)
{
row.X = localizedControl.X;
}
if (CompilerConstants.IntegerNotSet != localizedControl.Y)
{
row.Y = localizedControl.Y;
}
if (CompilerConstants.IntegerNotSet != localizedControl.Width)
{
row.Width = localizedControl.Width;
}
if (CompilerConstants.IntegerNotSet != localizedControl.Height)
{
row.Height = localizedControl.Height;
}
row.Attributes = row.Attributes | localizedControl.Attributes;
if (!String.IsNullOrEmpty(localizedControl.Text))
{
row.Text = localizedControl.Text;
}
}
}
}
}
private static void PopulateVariableResolver(IResolveContext context)
{
var creator = context.ServiceProvider.GetService();
var localizations = FilterLocalizations(context);
foreach (var localization in localizations)
{
context.VariableResolver.AddLocalization(localization);
}
// Gather all the wix variables.
var wixVariableTuples = context.IntermediateRepresentation.Sections.SelectMany(s => s.Tuples).OfType();
foreach (var tuple in wixVariableTuples)
{
context.VariableResolver.AddVariable(tuple.SourceLineNumbers, tuple.WixVariable, tuple.Value, tuple.Overridable);
}
}
private static IEnumerable FilterLocalizations(IResolveContext context)
{
var result = new List();
var filter = CalculateCultureFilter(context);
var localizations = context.Localizations.Concat(context.IntermediateRepresentation.Localizations).ToList();
AddFilteredLocalizations(result, filter, localizations);
// Filter localizations provided by extensions with data.
var creator = context.ServiceProvider.GetService();
foreach (var data in context.ExtensionData)
{
var library = data.GetLibrary(creator);
if (library?.Localizations != null && library.Localizations.Any())
{
var extensionFilter = (!filter.Any() && data.DefaultCulture != null) ? new[] { data.DefaultCulture } : filter;
AddFilteredLocalizations(result, extensionFilter, library.Localizations);
}
}
return result;
}
private static IEnumerable CalculateCultureFilter(IResolveContext context)
{
var filter = context.FilterCultures ?? Array.Empty();
// If no filter was specified, look for a language neutral localization file specified
// from the command-line (not embedded in the intermediate). If found, filter on language
// neutral.
if (!filter.Any() && context.Localizations.Any(l => String.IsNullOrEmpty(l.Culture)))
{
filter = new[] { String.Empty };
}
return filter;
}
private static void AddFilteredLocalizations(List result, IEnumerable filter, IEnumerable localizations)
{
// If there is no filter, return all localizations.
if (!filter.Any())
{
result.AddRange(localizations);
}
else // filter localizations in order specified by the filter
{
foreach (var culture in filter)
{
result.AddRange(localizations.Where(l => culture.Equals(l.Culture, StringComparison.OrdinalIgnoreCase) || String.IsNullOrEmpty(l.Culture)));
}
}
}
}
}