From 7b013ac66a36e0f73d480ef28771a65f64b57e19 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Sat, 30 Dec 2017 01:31:32 -0800 Subject: Support serializing localization information in Intermediates --- src/WixToolset.Data/Bind/BindVariable.cs | 33 ++++++++++- src/WixToolset.Data/Intermediate.cs | 34 +++++------ src/WixToolset.Data/Json/JsonObjectExtensions.cs | 45 +++++++++++++++ src/WixToolset.Data/Localization.cs | 72 +++++++++++++++++++++++- src/WixToolset.Data/LocalizedControl.cs | 33 +++++++++++ src/test/WixToolsetTest.Data/SerializeFixture.cs | 56 ++++++++++++++++++ 6 files changed, 253 insertions(+), 20 deletions(-) diff --git a/src/WixToolset.Data/Bind/BindVariable.cs b/src/WixToolset.Data/Bind/BindVariable.cs index 06c004e1..276dae38 100644 --- a/src/WixToolset.Data/Bind/BindVariable.cs +++ b/src/WixToolset.Data/Bind/BindVariable.cs @@ -1,9 +1,11 @@ // 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.Data.Rows +namespace WixToolset.Data.Bind { + using SimpleJson; + /// - /// Specialization of a row for the WixVariable table. + /// Bind variable. /// public sealed class BindVariable { @@ -29,5 +31,32 @@ namespace WixToolset.Data.Rows /// /// Whether this variable is overridable. public bool Overridable { get; set; } + + internal JsonObject Serialize() + { + var jsonObject = new JsonObject + { + { "name", this.Id }, + }; + + jsonObject.AddIsNotNullOrEmpty("value", this.Value); + jsonObject.AddNonDefaultValue("overridable", this.Overridable, false); + jsonObject.AddNonDefaultValue("ln", this.SourceLineNumbers?.Serialize()); + + return jsonObject; + } + + internal static BindVariable Deserialize(JsonObject jsonObject) + { + var variable = new BindVariable() + { + Id = jsonObject.GetValueOrDefault("name"), + Value = jsonObject.GetValueOrDefault("value"), + Overridable = jsonObject.GetValueOrDefault("overridable", false), + SourceLineNumbers = jsonObject.GetValueOrDefault("ln") + }; + + return variable; + } } } diff --git a/src/WixToolset.Data/Intermediate.cs b/src/WixToolset.Data/Intermediate.cs index a23cc091..ae507058 100644 --- a/src/WixToolset.Data/Intermediate.cs +++ b/src/WixToolset.Data/Intermediate.cs @@ -198,17 +198,17 @@ namespace WixToolset.Data jsonObject.Add("definitions", customDefinitionsJson); } - //if (this.Localizations.Any()) - //{ - // var localizationsJson = new JsonArray(); - // foreach (var localization in this.Localizations) - // { - // var localizationJson = localization.Serialize(); - // localizationsJson.Add(localizationJson); - // } - - // jsonObject.Add("localizations", localizationsJson); - //} + if (this.Localizations.Any()) + { + var localizationsJson = new JsonArray(); + foreach (var localization in this.Localizations) + { + var localizationJson = localization.Serialize(); + localizationsJson.Add(localizationJson); + } + + jsonObject.Add("localizations", localizationsJson); + } var json = SimpleJson.SerializeObject(jsonObject); writer.Write(json); @@ -272,12 +272,12 @@ namespace WixToolset.Data var localizations = new Dictionary(StringComparer.OrdinalIgnoreCase); - //var localizationsJson = jsonObject.GetValueOrDefault("localizations") ?? new JsonArray(); - //foreach (JsonObject localizationJson in localizationsJson) - //{ - // var localization = Localization.Deserialize(localizationJson); - // localizations.Add(localization.Culture, localization); - //} + var localizationsJson = jsonObject.GetValueOrDefault("localizations") ?? new JsonArray(); + foreach (JsonObject localizationJson in localizationsJson) + { + var localization = Localization.Deserialize(localizationJson); + localizations.Add(localization.Culture, localization); + } return new Intermediate(id, sections, localizations, null); } diff --git a/src/WixToolset.Data/Json/JsonObjectExtensions.cs b/src/WixToolset.Data/Json/JsonObjectExtensions.cs index 296a7ab6..e9e170ee 100644 --- a/src/WixToolset.Data/Json/JsonObjectExtensions.cs +++ b/src/WixToolset.Data/Json/JsonObjectExtensions.cs @@ -7,6 +7,51 @@ namespace WixToolset.Data internal static class JsonObjectExtensions { + public static JsonObject AddNonDefaultValue(this JsonObject jsonObject, string key, bool value, bool defaultValue = default(bool)) + { + if (value != defaultValue) + { + jsonObject.Add(key, value); + } + + return jsonObject; + } + + public static JsonObject AddNonDefaultValue(this JsonObject jsonObject, string key, int value, int defaultValue = default(int)) + { + if (value != defaultValue) + { + jsonObject.Add(key, value); + } + + return jsonObject; + } + + public static JsonObject AddNonDefaultValue(this JsonObject jsonObject, string key, object value, object defaultValue = null) + { + if (value != defaultValue) + { + jsonObject.Add(key, value); + } + + return jsonObject; + } + + public static JsonObject AddIsNotNullOrEmpty(this JsonObject jsonObject, string key, string value) + { + if (!String.IsNullOrEmpty(value)) + { + jsonObject.Add(key, value); + } + + return jsonObject; + } + + public static bool GetValueOrDefault(this JsonObject jsonObject, string key, bool defaultValue) + { + return jsonObject.TryGetValue(key, out var value) ? Convert.ToBoolean(value) : defaultValue; + } + public static int GetValueOrDefault(this JsonObject jsonObject, string key, int defaultValue) { return jsonObject.TryGetValue(key, out var value) ? Convert.ToInt32(value) : defaultValue; diff --git a/src/WixToolset.Data/Localization.cs b/src/WixToolset.Data/Localization.cs index 10eff2e1..4ddef77b 100644 --- a/src/WixToolset.Data/Localization.cs +++ b/src/WixToolset.Data/Localization.cs @@ -7,8 +7,9 @@ namespace WixToolset.Data using System.Diagnostics; using System.Globalization; using System.Xml; + using SimpleJson; using WixToolset.Data.Msi; - using WixToolset.Data.Rows; + using WixToolset.Data.Bind; /// /// Object that represents a localization file. @@ -74,6 +75,75 @@ namespace WixToolset.Data } } + internal JsonObject Serialize() + { + var jsonObject = new JsonObject + { + { "codepage", this.Codepage }, + }; + + jsonObject.AddIsNotNullOrEmpty("culture", this.Culture); + + // Serialize bind variables. + if (this.Variables.Count > 0) + { + var variablesJson = new JsonArray(this.Variables.Count); + + foreach (var variable in this.Variables) + { + var variableJson = variable.Serialize(); + + variablesJson.Add(variableJson); + } + + jsonObject.Add("variables", variablesJson); + } + + // Serialize localized control. + if (this.LocalizedControls.Count > 0) + { + var controlsJson = new JsonObject(); + + foreach (var controlWithKey in this.LocalizedControls) + { + var controlJson = controlWithKey.Value.Serialize(); + + controlsJson.Add(controlWithKey.Key, controlJson); + } + + jsonObject.Add("controls", controlsJson); + } + + return jsonObject; + } + + internal static Localization Deserialize(JsonObject jsonObject) + { + var codepage = jsonObject.GetValueOrDefault("codepage", 0); + var culture = jsonObject.GetValueOrDefault("culture"); + + var variables = new Dictionary(); + var variablesJson = jsonObject.GetValueOrDefault("variables", new JsonArray()); + foreach (JsonObject variableJson in variablesJson) + { + var bindPath = BindVariable.Deserialize(variableJson); + variables.Add(bindPath.Id, bindPath); + } + + var controls = new Dictionary(); + var controlsJson = jsonObject.GetValueOrDefault("controls"); + if (controlsJson != null) + { + foreach (var controlJsonWithKey in controlsJson) + { + var control = LocalizedControl.Deserialize((JsonObject)controlJsonWithKey.Value); + controls.Add(controlJsonWithKey.Key, control); + } + } + + return new Localization(codepage, culture, variables, controls); + } + /// /// Loads a localization file from a stream. /// diff --git a/src/WixToolset.Data/LocalizedControl.cs b/src/WixToolset.Data/LocalizedControl.cs index 979f9fde..cb60b7ba 100644 --- a/src/WixToolset.Data/LocalizedControl.cs +++ b/src/WixToolset.Data/LocalizedControl.cs @@ -3,6 +3,7 @@ namespace WixToolset.Data { using System; + using SimpleJson; public class LocalizedControl { @@ -47,5 +48,37 @@ namespace WixToolset.Data /// The id of the control. /// The localized control id. public static string GetKey(string dialog, string control) => String.Concat(dialog, "/", control); + + internal JsonObject Serialize() + { + var jsonObject = new JsonObject + { + { "dialog", this.Dialog }, + }; + + jsonObject.AddIsNotNullOrEmpty("control", this.Control); + jsonObject.AddNonDefaultValue("x", this.X, 0); + jsonObject.AddNonDefaultValue("y", this.Y, 0); + jsonObject.AddNonDefaultValue("width", this.Width, 0); + jsonObject.AddNonDefaultValue("height", this.Height, 0); + jsonObject.AddNonDefaultValue("attribs", this.Attributes, 0); + jsonObject.AddIsNotNullOrEmpty("text", this.Text); + + return jsonObject; + } + + internal static LocalizedControl Deserialize(JsonObject jsonObject) + { + var dialog = jsonObject.GetValueOrDefault("dialog"); + var control = jsonObject.GetValueOrDefault("control"); + var x = jsonObject.GetValueOrDefault("x", 0); + var y = jsonObject.GetValueOrDefault("y", 0); + var width = jsonObject.GetValueOrDefault("width", 0); + var height = jsonObject.GetValueOrDefault("height", 0); + var attribs = jsonObject.GetValueOrDefault("attribs", 0); + var text = jsonObject.GetValueOrDefault("text"); + + return new LocalizedControl(dialog, control, x, y, width, height, attribs, text); + } } } diff --git a/src/test/WixToolsetTest.Data/SerializeFixture.cs b/src/test/WixToolsetTest.Data/SerializeFixture.cs index 9883053f..1e03481d 100644 --- a/src/test/WixToolsetTest.Data/SerializeFixture.cs +++ b/src/test/WixToolsetTest.Data/SerializeFixture.cs @@ -6,6 +6,7 @@ namespace WixToolsetTest.Data using System.IO; using System.Linq; using WixToolset.Data; + using WixToolset.Data.Bind; using WixToolset.Data.Tuples; using Xunit; @@ -39,5 +40,60 @@ namespace WixToolsetTest.Data Assert.Equal("TestFolder", tuple.Directory_); Assert.Equal(2, tuple.Attributes); } + + [Fact] + public void CanSaveAndLoadIntermediateWithLocalization() + { + var sln = new SourceLineNumber("test.wxs", 10); + + var bindVariables = new[] + { + new BindVariable { Id = "TestVar1", Value = "TestValue1", SourceLineNumbers = sln }, + new BindVariable { Id = "TestVar2", Value = "TestValue2", Overridable = true, SourceLineNumbers = sln }, + }; + + var controls = new[] + { + new LocalizedControl("TestDlg1", "TestControl1", 10, 10, 100, 100, 0, null), + new LocalizedControl("TestDlg1", "TestControl2", 100, 90, 50, 70, 0, "localized"), + }; + + var localizations = new[] + { + new Localization(65001, null, bindVariables.ToDictionary(b => b.Id), controls.ToDictionary(c => c.GetKey())) + }; + + var section = new IntermediateSection("test", SectionType.Product, 65001); + + section.Tuples.Add(new ComponentTuple(sln, new Identifier("TestComponent", AccessModifier.Public)) + { + ComponentId = new Guid(1, 0, 0, new byte[8]).ToString("B"), + Directory_ = "TestFolder", + Attributes = 2, + }); + + var intermediate = new Intermediate("TestIntermediate", new[] { section }, localizations.ToDictionary(l => l.Culture), null); + + var path = Path.GetTempFileName(); + try + { + intermediate.Save(path); + + var loaded = Intermediate.Load(path); + + var loc = loaded.Localizations.Single(); + Assert.Equal(65001, loc.Codepage); + Assert.Empty(loc.Culture); + Assert.Equal(new[] + { + "TestVar1/TestValue1/False", + "TestVar2/TestValue2/True", + }, loc.Variables.Select(v => String.Join("/", v.Id, v.Value, v.Overridable)).ToArray()); + } + finally + { + File.Delete(path); + } + } } } -- cgit v1.2.3-55-g6feb