From ca376995792d2e2a1a7f39760989496702a8f603 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Wed, 6 Dec 2017 11:21:42 -0800 Subject: Fix handling of long values and baseUri in path fields --- src/WixToolset.Data/Intermediate.cs | 49 ++++++++++++-------- src/WixToolset.Data/IntermediateField.cs | 5 +- src/WixToolset.Data/IntermediateFieldDefinition.cs | 1 + src/WixToolset.Data/IntermediateFieldExtensions.cs | 53 ++++++++++++++-------- src/WixToolset.Data/IntermediateFieldValue.cs | 27 +++++------ src/WixToolset.Data/IntermediateSection.cs | 4 +- src/WixToolset.Data/IntermediateTuple.cs | 5 +- src/WixToolset.Data/SourceLineNumber.cs | 2 +- src/test/WixToolsetTest.Data/SerializeFixture.cs | 43 ++++++++++++++++++ 9 files changed, 132 insertions(+), 57 deletions(-) create mode 100644 src/test/WixToolsetTest.Data/SerializeFixture.cs (limited to 'src') diff --git a/src/WixToolset.Data/Intermediate.cs b/src/WixToolset.Data/Intermediate.cs index 4d4e17cc..81a97151 100644 --- a/src/WixToolset.Data/Intermediate.cs +++ b/src/WixToolset.Data/Intermediate.cs @@ -4,8 +4,9 @@ namespace WixToolset.Data { using System; using System.Collections.Generic; - using System.Linq; using System.IO; + using System.Linq; + using System.Reflection; using SimpleJson; /// @@ -99,48 +100,60 @@ namespace WixToolset.Data { using (var stream = File.OpenRead(path)) { + var uri = new Uri(Path.GetFullPath(path)); var creator = new SimpleTupleDefinitionCreator(); - return Intermediate.Load(stream, path, creator, suppressVersionCheck); + return Intermediate.Load(stream, uri, creator, suppressVersionCheck); } } /// /// Loads an intermediate from a stream. /// - /// Stream to intermediate file. + /// Assembly with intermediate embedded in resource stream. + /// Name of resource stream. /// Suppress checking for wix.dll version mismatches. /// Returns the loaded intermediate. - public static Intermediate Load(Stream stream, bool suppressVersionCheck = false) + public static Intermediate Load(Assembly assembly, string resourceName, bool suppressVersionCheck = false) { var creator = new SimpleTupleDefinitionCreator(); - return Intermediate.Load(stream, creator, suppressVersionCheck); + return Intermediate.Load(assembly, resourceName, creator, suppressVersionCheck); } /// - /// Loads an intermediate from a path on disk. + /// Loads an intermediate from a stream. /// - /// Path to intermediate file saved on disk. + /// Assembly with intermediate embedded in resource stream. + /// Name of resource stream. /// ITupleDefinitionCreator to use when reconstituting the intermediate. /// Suppress checking for wix.dll version mismatches. /// Returns the loaded intermediate. - public static Intermediate Load(string path, ITupleDefinitionCreator creator, bool suppressVersionCheck = false) + public static Intermediate Load(Assembly assembly, string resourceName, ITupleDefinitionCreator creator, bool suppressVersionCheck = false) { - using (var stream = File.OpenRead(path)) + using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName)) { - return Intermediate.Load(stream, path, creator, suppressVersionCheck); + var uriBuilder = new UriBuilder(assembly.CodeBase); + uriBuilder.Scheme = "embeddedresource"; + uriBuilder.Fragment = resourceName; + + return Intermediate.Load(resourceStream, uriBuilder.Uri, creator, suppressVersionCheck); } } /// /// Loads an intermediate from a path on disk. /// - /// Stream to intermediate file. + /// Path to intermediate file saved on disk. /// ITupleDefinitionCreator to use when reconstituting the intermediate. /// Suppress checking for wix.dll version mismatches. /// Returns the loaded intermediate. - public static Intermediate Load(Stream stream, ITupleDefinitionCreator creator, bool suppressVersionCheck = false) + public static Intermediate Load(string path, ITupleDefinitionCreator creator, bool suppressVersionCheck = false) { - return Load(stream, "", creator, suppressVersionCheck); + using (var stream = File.OpenRead(path)) + { + var uri = new Uri(Path.GetFullPath(path)); + + return Intermediate.Load(stream, uri, creator, suppressVersionCheck); + } } /// @@ -206,11 +219,11 @@ namespace WixToolset.Data /// Loads an intermediate from a path on disk. /// /// Stream to intermediate file. - /// Path name of intermediate file. + /// Path name of intermediate file. /// ITupleDefinitionCreator to use when reconstituting the intermediate. /// Suppress checking for wix.dll version mismatches. /// Returns the loaded intermediate. - internal static Intermediate Load(Stream stream, string path, ITupleDefinitionCreator creator, bool suppressVersionCheck = false) + internal static Intermediate Load(Stream stream, Uri baseUri, ITupleDefinitionCreator creator, bool suppressVersionCheck = false) { JsonObject jsonObject; @@ -218,7 +231,7 @@ namespace WixToolset.Data { if (FileFormat.WixIR != fs.FileFormat) { - throw new WixUnexpectedFileFormatException(path, FileFormat.WixIR, fs.FileFormat); + throw new WixUnexpectedFileFormatException(baseUri.LocalPath, FileFormat.WixIR, fs.FileFormat); } var json = fs.GetData(); @@ -231,7 +244,7 @@ namespace WixToolset.Data if (!Version.TryParse(versionJson, out var version) || !Intermediate.CurrentVersion.Equals(version)) { - throw new WixException(WixDataErrors.VersionMismatch(SourceLineNumber.CreateFromUri(path), "intermediate", versionJson, Intermediate.CurrentVersion.ToString())); + throw new WixException(WixDataErrors.VersionMismatch(SourceLineNumber.CreateFromUri(baseUri.AbsoluteUri), "intermediate", versionJson, Intermediate.CurrentVersion.ToString())); } } @@ -253,7 +266,7 @@ namespace WixToolset.Data var sectionsJson = jsonObject.GetValueOrDefault("sections"); foreach (JsonObject sectionJson in sectionsJson) { - var section = IntermediateSection.Deserialize(creator, sectionJson); + var section = IntermediateSection.Deserialize(creator, baseUri, sectionJson); sections.Add(section); } diff --git a/src/WixToolset.Data/IntermediateField.cs b/src/WixToolset.Data/IntermediateField.cs index eba0e1ab..48cdceea 100644 --- a/src/WixToolset.Data/IntermediateField.cs +++ b/src/WixToolset.Data/IntermediateField.cs @@ -2,6 +2,7 @@ namespace WixToolset.Data { + using System; using System.Diagnostics; using SimpleJson; @@ -50,13 +51,13 @@ namespace WixToolset.Data return field.AsString(); } - internal static IntermediateField Deserialize(IntermediateFieldDefinition definition, JsonObject jsonObject) + internal static IntermediateField Deserialize(IntermediateFieldDefinition definition, Uri baseUri, JsonObject jsonObject) { var field = new IntermediateField(definition); if (jsonObject != null) { - field.Value = IntermediateFieldValue.Deserialize(jsonObject); + field.Value = IntermediateFieldValue.Deserialize(jsonObject, baseUri, definition.Type); } return field; diff --git a/src/WixToolset.Data/IntermediateFieldDefinition.cs b/src/WixToolset.Data/IntermediateFieldDefinition.cs index c77a2ae8..5e1d8f29 100644 --- a/src/WixToolset.Data/IntermediateFieldDefinition.cs +++ b/src/WixToolset.Data/IntermediateFieldDefinition.cs @@ -7,6 +7,7 @@ namespace WixToolset.Data String, Bool, Number, + LargeNumber, Path, } diff --git a/src/WixToolset.Data/IntermediateFieldExtensions.cs b/src/WixToolset.Data/IntermediateFieldExtensions.cs index be225452..89a6b903 100644 --- a/src/WixToolset.Data/IntermediateFieldExtensions.cs +++ b/src/WixToolset.Data/IntermediateFieldExtensions.cs @@ -21,26 +21,15 @@ namespace WixToolset.Data { // Null is always allowed. } - else if (field.Type == IntermediateFieldType.Bool && !(value is bool)) + else if (field.Type == IntermediateFieldType.String && !(value is string)) { if (value is int) { - data = ((int)value) != 0; + data = value.ToString(); } - else if (value is string str) + else if (value is bool b) { - if (str.Equals("yes", StringComparison.OrdinalIgnoreCase) || str.Equals("true", StringComparison.OrdinalIgnoreCase)) - { - data = true; - } - else if (str.Equals("no", StringComparison.OrdinalIgnoreCase) || str.Equals("false", StringComparison.OrdinalIgnoreCase)) - { - data = false; - } - else - { - throw new ArgumentException(nameof(value)); - } + data = b ? "true" : "false"; } else { @@ -58,15 +47,26 @@ namespace WixToolset.Data throw new ArgumentException(nameof(value)); } } - else if (field.Type == IntermediateFieldType.String && !(value is string)) + else if (field.Type == IntermediateFieldType.Bool && !(value is bool)) { if (value is int) { - data = value.ToString(); + data = ((int)value) != 0; } - else if (value is bool b) + else if (value is string str) { - data = b ? "true" : "false"; + if (str.Equals("yes", StringComparison.OrdinalIgnoreCase) || str.Equals("true", StringComparison.OrdinalIgnoreCase)) + { + data = true; + } + else if (str.Equals("no", StringComparison.OrdinalIgnoreCase) || str.Equals("false", StringComparison.OrdinalIgnoreCase)) + { + data = false; + } + else + { + throw new ArgumentException(nameof(value)); + } } else { @@ -84,6 +84,21 @@ namespace WixToolset.Data throw new ArgumentException(nameof(value)); } } + else if (field.Type == IntermediateFieldType.LargeNumber && !(value is long)) + { + if (value is string str && Int64.TryParse(str, out var number)) + { + data = number; + } + else if (value is int i) + { + data = (long)i; + } + else + { + throw new ArgumentException(nameof(value)); + } + } field.Value = new IntermediateFieldValue { diff --git a/src/WixToolset.Data/IntermediateFieldValue.cs b/src/WixToolset.Data/IntermediateFieldValue.cs index 2064afec..88bfb910 100644 --- a/src/WixToolset.Data/IntermediateFieldValue.cs +++ b/src/WixToolset.Data/IntermediateFieldValue.cs @@ -45,7 +45,7 @@ namespace WixToolset.Data return value.AsString(); } - internal static IntermediateFieldValue Deserialize(JsonObject jsonObject) + internal static IntermediateFieldValue Deserialize(JsonObject jsonObject, Uri baseUri, IntermediateFieldType type) { var context = jsonObject.GetValueOrDefault("context"); if (!jsonObject.TryGetValue("data", out var data)) @@ -55,26 +55,30 @@ namespace WixToolset.Data var value = data; - if (data is JsonObject jsonData) + if (data is string) { - Uri baseUri = null; - - if (jsonData.TryGetValue("baseUri", out var baseUriValue) && baseUriValue is string) + } + else if (data is long) + { + if (type == IntermediateFieldType.Number) { - baseUri = new Uri((string)baseUriValue); + value = Convert.ToInt32(data); } + } + else if (data is JsonObject jsonData) + { jsonData.TryGetValue("embeddedIndex", out var embeddedIndex); value = new IntermediateFieldPathValue { - BaseUri = baseUri, - EmbeddedFileIndex = (int?)embeddedIndex, + BaseUri = (embeddedIndex == null) ? null : baseUri, + EmbeddedFileIndex = (embeddedIndex == null) ? null : (int?)Convert.ToInt32(embeddedIndex), Path = jsonData.GetValueOrDefault("path"), }; } var previousValueJson = jsonObject.GetValueOrDefault("prev"); - var previousValue = (previousValueJson == null) ? null : IntermediateFieldValue.Deserialize(previousValueJson); + var previousValue = (previousValueJson == null) ? null : IntermediateFieldValue.Deserialize(previousValueJson, baseUri, type); return new IntermediateFieldValue { @@ -97,10 +101,7 @@ namespace WixToolset.Data { var jsonData = new JsonObject(); - if (pathField.BaseUri != null) - { - jsonData.Add("baseUri", pathField.BaseUri.AbsoluteUri); - } + // pathField.BaseUri is set during load, not saved. if (pathField.EmbeddedFileIndex.HasValue) { diff --git a/src/WixToolset.Data/IntermediateSection.cs b/src/WixToolset.Data/IntermediateSection.cs index 5d17eb31..54758136 100644 --- a/src/WixToolset.Data/IntermediateSection.cs +++ b/src/WixToolset.Data/IntermediateSection.cs @@ -61,7 +61,7 @@ namespace WixToolset.Data /// /// Parse a section from the JSON data. /// - internal static IntermediateSection Deserialize(ITupleDefinitionCreator creator, JsonObject jsonObject) + internal static IntermediateSection Deserialize(ITupleDefinitionCreator creator, Uri baseUri, JsonObject jsonObject) { var codepage = jsonObject.GetValueOrDefault("codepage", 0); var id = jsonObject.GetValueOrDefault("id"); @@ -83,7 +83,7 @@ namespace WixToolset.Data foreach (JsonObject tupleJson in tuplesJson) { - var tuple = IntermediateTuple.Deserialize(creator, tupleJson); + var tuple = IntermediateTuple.Deserialize(creator, baseUri, tupleJson); section.Tuples.Add(tuple); } diff --git a/src/WixToolset.Data/IntermediateTuple.cs b/src/WixToolset.Data/IntermediateTuple.cs index cda133b5..e5df9ecb 100644 --- a/src/WixToolset.Data/IntermediateTuple.cs +++ b/src/WixToolset.Data/IntermediateTuple.cs @@ -2,6 +2,7 @@ namespace WixToolset.Data { + using System; using SimpleJson; public class IntermediateTuple @@ -28,7 +29,7 @@ namespace WixToolset.Data public IntermediateField this[int index] => this.Fields[index]; - internal static IntermediateTuple Deserialize(ITupleDefinitionCreator creator, JsonObject jsonObject) + internal static IntermediateTuple Deserialize(ITupleDefinitionCreator creator, Uri baseUri, JsonObject jsonObject) { var definitionName = jsonObject.GetValueOrDefault("type"); var idJson = jsonObject.GetValueOrDefault("id"); @@ -45,7 +46,7 @@ namespace WixToolset.Data { if (tuple.Fields.Length > i && fieldsJson[i] is JsonObject fieldJson) { - tuple.Fields[i] = IntermediateField.Deserialize(tuple.Definition.FieldDefinitions[i], fieldJson); + tuple.Fields[i] = IntermediateField.Deserialize(tuple.Definition.FieldDefinitions[i], baseUri, fieldJson); } } diff --git a/src/WixToolset.Data/SourceLineNumber.cs b/src/WixToolset.Data/SourceLineNumber.cs index 742f6e9d..8ec65201 100644 --- a/src/WixToolset.Data/SourceLineNumber.cs +++ b/src/WixToolset.Data/SourceLineNumber.cs @@ -146,7 +146,7 @@ namespace WixToolset.Data } // make the local path look like a normal local path - string localPath = new Uri(uri).LocalPath; + var localPath = new Uri(uri).LocalPath; localPath = localPath.TrimStart(Path.AltDirectorySeparatorChar).Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); return new SourceLineNumber(localPath); diff --git a/src/test/WixToolsetTest.Data/SerializeFixture.cs b/src/test/WixToolsetTest.Data/SerializeFixture.cs new file mode 100644 index 00000000..9883053f --- /dev/null +++ b/src/test/WixToolsetTest.Data/SerializeFixture.cs @@ -0,0 +1,43 @@ +// 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 WixToolsetTest.Data +{ + using System; + using System.IO; + using System.Linq; + using WixToolset.Data; + using WixToolset.Data.Tuples; + using Xunit; + + public class SerializeFixture + { + [Fact] + public void CanSaveAndLoadIntermediate() + { + var sln = new SourceLineNumber("test.wxs", 1); + + 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 }, null, null); + + var path = Path.GetTempFileName(); + intermediate.Save(path); + + var loaded = Intermediate.Load(path); + + var tuple = (ComponentTuple)loaded.Sections.Single().Tuples.Single(); + + Assert.Equal("TestComponent", tuple.Id.Id); + Assert.Equal(AccessModifier.Public, tuple.Id.Access); + Assert.Equal("TestFolder", tuple.Directory_); + Assert.Equal(2, tuple.Attributes); + } + } +} -- cgit v1.2.3-55-g6feb