Browse Source

DotNetCore: include LightJson; remove Newtonsoft.Json

pull/998/merge
Siegfried Pammer 8 years ago
parent
commit
79835afca4
  1. 28
      ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs
  2. 181
      ICSharpCode.Decompiler/DotNetCore/LightJson/JsonArray.cs
  3. 241
      ICSharpCode.Decompiler/DotNetCore/LightJson/JsonObject.cs
  4. 769
      ICSharpCode.Decompiler/DotNetCore/LightJson/JsonValue.cs
  5. 41
      ICSharpCode.Decompiler/DotNetCore/LightJson/JsonValueType.cs
  6. 102
      ICSharpCode.Decompiler/DotNetCore/LightJson/Serialization/JsonParseException.cs
  7. 413
      ICSharpCode.Decompiler/DotNetCore/LightJson/Serialization/JsonReader.cs
  8. 97
      ICSharpCode.Decompiler/DotNetCore/LightJson/Serialization/JsonSerializationException.cs
  9. 349
      ICSharpCode.Decompiler/DotNetCore/LightJson/Serialization/JsonWriter.cs
  10. 21
      ICSharpCode.Decompiler/DotNetCore/LightJson/Serialization/TextPosition.cs
  11. 212
      ICSharpCode.Decompiler/DotNetCore/LightJson/Serialization/TextScanner.cs
  12. 11
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

28
ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs

@ -4,8 +4,8 @@ using System.IO; @@ -4,8 +4,8 @@ using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using LightJson.Serialization;
using Mono.Cecil;
using Newtonsoft.Json.Linq;
namespace ICSharpCode.Decompiler
{
@ -84,16 +84,24 @@ namespace ICSharpCode.Decompiler @@ -84,16 +84,24 @@ namespace ICSharpCode.Decompiler
static IEnumerable<DotNetCorePackageInfo> LoadPackageInfos(string depsJsonFileName, string targetFramework)
{
var dependencies = JObject.Parse(File.ReadAllText(depsJsonFileName));
var runtimeInfos = dependencies["targets"][targetFramework].Children().OfType<JProperty>().ToArray();
var libraries = dependencies["libraries"].Children().OfType<JProperty>().ToArray();
var dependencies = JsonReader.Parse(File.ReadAllText(depsJsonFileName));
var runtimeInfos = dependencies["targets"][targetFramework].AsJsonObject;
var libraries = dependencies["libraries"].AsJsonObject;
if (runtimeInfos == null || libraries == null)
yield break;
foreach (var library in libraries) {
var type = library.First()["type"].ToString();
var path = library.First()["path"]?.ToString();
var runtimeInfo = runtimeInfos.FirstOrDefault(r => r.Name == library.Name)?.First()["runtime"]?.Children().OfType<JProperty>().Select(i => i.Name).ToArray();
yield return new DotNetCorePackageInfo(library.Name, type, path, runtimeInfo);
var type = library.Value["type"].AsString;
var path = library.Value["path"].AsString;
var runtimeInfo = runtimeInfos[library.Key]["runtime"].AsJsonObject;
string[] components = new string[runtimeInfo?.Count ?? 0];
if (runtimeInfo != null) {
int i = 0;
foreach (var component in runtimeInfo) {
components[i] = component.Key;
i++;
}
}
yield return new DotNetCorePackageInfo(library.Key, type, path, components);
}
}

181
ICSharpCode.Decompiler/DotNetCore/LightJson/JsonArray.cs

@ -0,0 +1,181 @@ @@ -0,0 +1,181 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace LightJson
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Represents an ordered collection of JsonValues.
/// </summary>
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(JsonArrayDebugView))]
internal sealed class JsonArray : IEnumerable<JsonValue>
{
private IList<JsonValue> items;
/// <summary>
/// Initializes a new instance of the <see cref="JsonArray"/> class.
/// </summary>
public JsonArray()
{
this.items = new List<JsonValue>();
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonArray"/> class, adding the given values to the collection.
/// </summary>
/// <param name="values">The values to be added to this collection.</param>
public JsonArray(params JsonValue[] values)
: this()
{
if (values == null) {
throw new ArgumentNullException(nameof(values));
}
foreach (var value in values) {
this.items.Add(value);
}
}
/// <summary>
/// Gets the number of values in this collection.
/// </summary>
/// <value>The number of values in this collection.</value>
public int Count {
get {
return this.items.Count;
}
}
/// <summary>
/// Gets or sets the value at the given index.
/// </summary>
/// <param name="index">The zero-based index of the value to get or set.</param>
/// <remarks>
/// The getter will return JsonValue.Null if the given index is out of range.
/// </remarks>
public JsonValue this[int index] {
get {
if (index >= 0 && index < this.items.Count) {
return this.items[index];
} else {
return JsonValue.Null;
}
}
set {
this.items[index] = value;
}
}
/// <summary>
/// Adds the given value to this collection.
/// </summary>
/// <param name="value">The value to be added.</param>
/// <returns>Returns this collection.</returns>
public JsonArray Add(JsonValue value)
{
this.items.Add(value);
return this;
}
/// <summary>
/// Inserts the given value at the given index in this collection.
/// </summary>
/// <param name="index">The index where the given value will be inserted.</param>
/// <param name="value">The value to be inserted into this collection.</param>
/// <returns>Returns this collection.</returns>
public JsonArray Insert(int index, JsonValue value)
{
this.items.Insert(index, value);
return this;
}
/// <summary>
/// Removes the value at the given index.
/// </summary>
/// <param name="index">The index of the value to be removed.</param>
/// <returns>Return this collection.</returns>
public JsonArray Remove(int index)
{
this.items.RemoveAt(index);
return this;
}
/// <summary>
/// Clears the contents of this collection.
/// </summary>
/// <returns>Returns this collection.</returns>
public JsonArray Clear()
{
this.items.Clear();
return this;
}
/// <summary>
/// Determines whether the given item is in the JsonArray.
/// </summary>
/// <param name="item">The item to locate in the JsonArray.</param>
/// <returns>Returns true if the item is found; otherwise, false.</returns>
public bool Contains(JsonValue item)
{
return this.items.Contains(item);
}
/// <summary>
/// Determines the index of the given item in this JsonArray.
/// </summary>
/// <param name="item">The item to locate in this JsonArray.</param>
/// <returns>The index of the item, if found. Otherwise, returns -1.</returns>
public int IndexOf(JsonValue item)
{
return this.items.IndexOf(item);
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>The enumerator that iterates through the collection.</returns>
public IEnumerator<JsonValue> GetEnumerator()
{
return this.items.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>The enumerator that iterates through the collection.</returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
[ExcludeFromCodeCoverage]
private class JsonArrayDebugView
{
private JsonArray jsonArray;
public JsonArrayDebugView(JsonArray jsonArray)
{
this.jsonArray = jsonArray;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public JsonValue[] Items {
get {
var items = new JsonValue[this.jsonArray.Count];
for (int i = 0; i < this.jsonArray.Count; i += 1) {
items[i] = this.jsonArray[i];
}
return items;
}
}
}
}
}

241
ICSharpCode.Decompiler/DotNetCore/LightJson/JsonObject.cs

@ -0,0 +1,241 @@ @@ -0,0 +1,241 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace LightJson
{
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
/// <summary>
/// Represents a key-value pair collection of JsonValue objects.
/// </summary>
[DebuggerDisplay("Count = {Count}")]
[DebuggerTypeProxy(typeof(JsonObjectDebugView))]
internal sealed class JsonObject : IEnumerable<KeyValuePair<string, JsonValue>>, IEnumerable<JsonValue>
{
private IDictionary<string, JsonValue> properties;
/// <summary>
/// Initializes a new instance of the <see cref="JsonObject"/> class.
/// </summary>
public JsonObject()
{
this.properties = new Dictionary<string, JsonValue>();
}
/// <summary>
/// Gets the number of properties in this JsonObject.
/// </summary>
/// <value>The number of properties in this JsonObject.</value>
public int Count {
get {
return this.properties.Count;
}
}
/// <summary>
/// Gets or sets the property with the given key.
/// </summary>
/// <param name="key">The key of the property to get or set.</param>
/// <remarks>
/// The getter will return JsonValue.Null if the given key is not assosiated with any value.
/// </remarks>
public JsonValue this[string key] {
get {
JsonValue value;
if (this.properties.TryGetValue(key, out value)) {
return value;
} else {
return JsonValue.Null;
}
}
set {
this.properties[key] = value;
}
}
/// <summary>
/// Adds a key with a null value to this collection.
/// </summary>
/// <param name="key">The key of the property to be added.</param>
/// <remarks>Returns this JsonObject.</remarks>
/// <returns>The <see cref="JsonObject"/> that was added.</returns>
public JsonObject Add(string key)
{
return this.Add(key, JsonValue.Null);
}
/// <summary>
/// Adds a value associated with a key to this collection.
/// </summary>
/// <param name="key">The key of the property to be added.</param>
/// <param name="value">The value of the property to be added.</param>
/// <returns>Returns this JsonObject.</returns>
public JsonObject Add(string key, JsonValue value)
{
this.properties.Add(key, value);
return this;
}
/// <summary>
/// Removes a property with the given key.
/// </summary>
/// <param name="key">The key of the property to be removed.</param>
/// <returns>
/// Returns true if the given key is found and removed; otherwise, false.
/// </returns>
public bool Remove(string key)
{
return this.properties.Remove(key);
}
/// <summary>
/// Clears the contents of this collection.
/// </summary>
/// <returns>Returns this JsonObject.</returns>
public JsonObject Clear()
{
this.properties.Clear();
return this;
}
/// <summary>
/// Changes the key of one of the items in the collection.
/// </summary>
/// <remarks>
/// This method has no effects if the <i>oldKey</i> does not exists.
/// If the <i>newKey</i> already exists, the value will be overwritten.
/// </remarks>
/// <param name="oldKey">The name of the key to be changed.</param>
/// <param name="newKey">The new name of the key.</param>
/// <returns>Returns this JsonObject.</returns>
public JsonObject Rename(string oldKey, string newKey)
{
if (oldKey == newKey) {
// Renaming to the same name just does nothing
return this;
}
JsonValue value;
if (this.properties.TryGetValue(oldKey, out value)) {
this[newKey] = value;
this.Remove(oldKey);
}
return this;
}
/// <summary>
/// Determines whether this collection contains an item assosiated with the given key.
/// </summary>
/// <param name="key">The key to locate in this collection.</param>
/// <returns>Returns true if the key is found; otherwise, false.</returns>
public bool ContainsKey(string key)
{
return this.properties.ContainsKey(key);
}
/// <summary>
/// Determines whether this collection contains the given JsonValue.
/// </summary>
/// <param name="value">The value to locate in this collection.</param>
/// <returns>Returns true if the value is found; otherwise, false.</returns>
public bool Contains(JsonValue value)
{
return this.properties.Values.Contains(value);
}
/// <summary>
/// Returns an enumerator that iterates through this collection.
/// </summary>
/// <returns>The enumerator that iterates through this collection.</returns>
public IEnumerator<KeyValuePair<string, JsonValue>> GetEnumerator()
{
return this.properties.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through this collection.
/// </summary>
/// <returns>The enumerator that iterates through this collection.</returns>
IEnumerator<JsonValue> IEnumerable<JsonValue>.GetEnumerator()
{
return this.properties.Values.GetEnumerator();
}
/// <summary>
/// Returns an enumerator that iterates through this collection.
/// </summary>
/// <returns>The enumerator that iterates through this collection.</returns>
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
[ExcludeFromCodeCoverage]
private class JsonObjectDebugView
{
private JsonObject jsonObject;
public JsonObjectDebugView(JsonObject jsonObject)
{
this.jsonObject = jsonObject;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public KeyValuePair[] Keys {
get {
var keys = new KeyValuePair[this.jsonObject.Count];
var i = 0;
foreach (var property in this.jsonObject) {
keys[i] = new KeyValuePair(property.Key, property.Value);
i += 1;
}
return keys;
}
}
[DebuggerDisplay("{value.ToString(),nq}", Name = "{key}", Type = "JsonValue({Type})")]
public class KeyValuePair
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private string key;
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private JsonValue value;
public KeyValuePair(string key, JsonValue value)
{
this.key = key;
this.value = value;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public object View {
get {
if (this.value.IsJsonObject) {
return (JsonObject)this.value;
} else if (this.value.IsJsonArray) {
return (JsonArray)this.value;
} else {
return this.value;
}
}
}
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private JsonValueType Type {
get {
return this.value.Type;
}
}
}
}
}
}

769
ICSharpCode.Decompiler/DotNetCore/LightJson/JsonValue.cs

@ -0,0 +1,769 @@ @@ -0,0 +1,769 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace LightJson
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using LightJson.Serialization;
/// <summary>
/// A wrapper object that contains a valid JSON value.
/// </summary>
[DebuggerDisplay("{ToString(),nq}", Type = "JsonValue({Type})")]
[DebuggerTypeProxy(typeof(JsonValueDebugView))]
internal struct JsonValue
{
/// <summary>
/// Represents a null JsonValue.
/// </summary>
public static readonly JsonValue Null = new JsonValue(JsonValueType.Null, default(double), null);
private readonly JsonValueType type;
private readonly object reference;
private readonly double value;
/// <summary>
/// Initializes a new instance of the <see cref="JsonValue"/> struct, representing a Boolean value.
/// </summary>
/// <param name="value">The value to be wrapped.</param>
public JsonValue(bool? value)
{
if (value.HasValue) {
this.reference = null;
this.type = JsonValueType.Boolean;
this.value = value.Value ? 1 : 0;
} else {
this = JsonValue.Null;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonValue"/> struct, representing a Number value.
/// </summary>
/// <param name="value">The value to be wrapped.</param>
public JsonValue(double? value)
{
if (value.HasValue) {
this.reference = null;
this.type = JsonValueType.Number;
this.value = value.Value;
} else {
this = JsonValue.Null;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonValue"/> struct, representing a String value.
/// </summary>
/// <param name="value">The value to be wrapped.</param>
public JsonValue(string value)
{
if (value != null) {
this.value = default(double);
this.type = JsonValueType.String;
this.reference = value;
} else {
this = JsonValue.Null;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonValue"/> struct, representing a JsonObject.
/// </summary>
/// <param name="value">The value to be wrapped.</param>
public JsonValue(JsonObject value)
{
if (value != null) {
this.value = default(double);
this.type = JsonValueType.Object;
this.reference = value;
} else {
this = JsonValue.Null;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonValue"/> struct, representing a Array reference value.
/// </summary>
/// <param name="value">The value to be wrapped.</param>
public JsonValue(JsonArray value)
{
if (value != null) {
this.value = default(double);
this.type = JsonValueType.Array;
this.reference = value;
} else {
this = JsonValue.Null;
}
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonValue"/> struct.
/// </summary>
/// <param name="type">The Json type of the JsonValue.</param>
/// <param name="value">
/// The internal value of the JsonValue.
/// This is used when the Json type is Number or Boolean.
/// </param>
/// <param name="reference">
/// The internal value reference of the JsonValue.
/// This value is used when the Json type is String, JsonObject, or JsonArray.
/// </param>
private JsonValue(JsonValueType type, double value, object reference)
{
this.type = type;
this.value = value;
this.reference = reference;
}
/// <summary>
/// Gets the type of this JsonValue.
/// </summary>
/// <value>The type of this JsonValue.</value>
public JsonValueType Type {
get {
return this.type;
}
}
/// <summary>
/// Gets a value indicating whether this JsonValue is Null.
/// </summary>
/// <value>A value indicating whether this JsonValue is Null.</value>
public bool IsNull {
get {
return this.Type == JsonValueType.Null;
}
}
/// <summary>
/// Gets a value indicating whether this JsonValue is a Boolean.
/// </summary>
/// <value>A value indicating whether this JsonValue is a Boolean.</value>
public bool IsBoolean {
get {
return this.Type == JsonValueType.Boolean;
}
}
/// <summary>
/// Gets a value indicating whether this JsonValue is an Integer.
/// </summary>
/// <value>A value indicating whether this JsonValue is an Integer.</value>
public bool IsInteger {
get {
if (!this.IsNumber) {
return false;
}
var value = this.value;
return unchecked((int)value) == value;
}
}
/// <summary>
/// Gets a value indicating whether this JsonValue is a Number.
/// </summary>
/// <value>A value indicating whether this JsonValue is a Number.</value>
public bool IsNumber {
get {
return this.Type == JsonValueType.Number;
}
}
/// <summary>
/// Gets a value indicating whether this JsonValue is a String.
/// </summary>
/// <value>A value indicating whether this JsonValue is a String.</value>
public bool IsString {
get {
return this.Type == JsonValueType.String;
}
}
/// <summary>
/// Gets a value indicating whether this JsonValue is a JsonObject.
/// </summary>
/// <value>A value indicating whether this JsonValue is a JsonObject.</value>
public bool IsJsonObject {
get {
return this.Type == JsonValueType.Object;
}
}
/// <summary>
/// Gets a value indicating whether this JsonValue is a JsonArray.
/// </summary>
/// <value>A value indicating whether this JsonValue is a JsonArray.</value>
public bool IsJsonArray {
get {
return this.Type == JsonValueType.Array;
}
}
/// <summary>
/// Gets a value indicating whether this JsonValue represents a DateTime.
/// </summary>
/// <value>A value indicating whether this JsonValue represents a DateTime.</value>
public bool IsDateTime {
get {
return this.AsDateTime != null;
}
}
/// <summary>
/// Gets a value indicating whether this value is true or false.
/// </summary>
/// <value>This value as a Boolean type.</value>
public bool AsBoolean {
get {
switch (this.Type) {
case JsonValueType.Boolean:
return this.value == 1;
case JsonValueType.Number:
return this.value != 0;
case JsonValueType.String:
return (string)this.reference != string.Empty;
case JsonValueType.Object:
case JsonValueType.Array:
return true;
default:
return false;
}
}
}
/// <summary>
/// Gets this value as an Integer type.
/// </summary>
/// <value>This value as an Integer type.</value>
public int AsInteger {
get {
var value = this.AsNumber;
// Prevent overflow if the value doesn't fit.
if (value >= int.MaxValue) {
return int.MaxValue;
}
if (value <= int.MinValue) {
return int.MinValue;
}
return (int)value;
}
}
/// <summary>
/// Gets this value as a Number type.
/// </summary>
/// <value>This value as a Number type.</value>
public double AsNumber {
get {
switch (this.Type) {
case JsonValueType.Boolean:
return (this.value == 1)
? 1
: 0;
case JsonValueType.Number:
return this.value;
case JsonValueType.String:
double number;
if (double.TryParse((string)this.reference, NumberStyles.Float, CultureInfo.InvariantCulture, out number)) {
return number;
} else {
goto default;
}
default:
return 0;
}
}
}
/// <summary>
/// Gets this value as a String type.
/// </summary>
/// <value>This value as a String type.</value>
public string AsString {
get {
switch (this.Type) {
case JsonValueType.Boolean:
return (this.value == 1)
? "true"
: "false";
case JsonValueType.Number:
return this.value.ToString(CultureInfo.InvariantCulture);
case JsonValueType.String:
return (string)this.reference;
default:
return null;
}
}
}
/// <summary>
/// Gets this value as an JsonObject.
/// </summary>
/// <value>This value as an JsonObject.</value>
public JsonObject AsJsonObject {
get {
return this.IsJsonObject
? (JsonObject)this.reference
: null;
}
}
/// <summary>
/// Gets this value as an JsonArray.
/// </summary>
/// <value>This value as an JsonArray.</value>
public JsonArray AsJsonArray {
get {
return this.IsJsonArray
? (JsonArray)this.reference
: null;
}
}
/// <summary>
/// Gets this value as a system.DateTime.
/// </summary>
/// <value>This value as a system.DateTime.</value>
public DateTime? AsDateTime {
get {
DateTime value;
if (this.IsString && DateTime.TryParse((string)this.reference, out value)) {
return value;
} else {
return null;
}
}
}
/// <summary>
/// Gets this (inner) value as a System.object.
/// </summary>
/// <value>This (inner) value as a System.object.</value>
public object AsObject {
get {
switch (this.Type) {
case JsonValueType.Boolean:
case JsonValueType.Number:
return this.value;
case JsonValueType.String:
case JsonValueType.Object:
case JsonValueType.Array:
return this.reference;
default:
return null;
}
}
}
/// <summary>
/// Gets or sets the value associated with the specified key.
/// </summary>
/// <param name="key">The key of the value to get or set.</param>
/// <exception cref="System.InvalidOperationException">
/// Thrown when this JsonValue is not a JsonObject.
/// </exception>
public JsonValue this[string key] {
get {
if (this.IsJsonObject) {
return ((JsonObject)this.reference)[key];
} else {
throw new InvalidOperationException("This value does not represent a JsonObject.");
}
}
set {
if (this.IsJsonObject) {
((JsonObject)this.reference)[key] = value;
} else {
throw new InvalidOperationException("This value does not represent a JsonObject.");
}
}
}
/// <summary>
/// Gets or sets the value at the specified index.
/// </summary>
/// <param name="index">The zero-based index of the value to get or set.</param>
/// <exception cref="System.InvalidOperationException">
/// Thrown when this JsonValue is not a JsonArray
/// </exception>
public JsonValue this[int index] {
get {
if (this.IsJsonArray) {
return ((JsonArray)this.reference)[index];
} else {
throw new InvalidOperationException("This value does not represent a JsonArray.");
}
}
set {
if (this.IsJsonArray) {
((JsonArray)this.reference)[index] = value;
} else {
throw new InvalidOperationException("This value does not represent a JsonArray.");
}
}
}
/// <summary>
/// Converts the given nullable boolean into a JsonValue.
/// </summary>
/// <param name="value">The value to be converted.</param>
public static implicit operator JsonValue(bool? value)
{
return new JsonValue(value);
}
/// <summary>
/// Converts the given nullable double into a JsonValue.
/// </summary>
/// <param name="value">The value to be converted.</param>
public static implicit operator JsonValue(double? value)
{
return new JsonValue(value);
}
/// <summary>
/// Converts the given string into a JsonValue.
/// </summary>
/// <param name="value">The value to be converted.</param>
public static implicit operator JsonValue(string value)
{
return new JsonValue(value);
}
/// <summary>
/// Converts the given JsonObject into a JsonValue.
/// </summary>
/// <param name="value">The value to be converted.</param>
public static implicit operator JsonValue(JsonObject value)
{
return new JsonValue(value);
}
/// <summary>
/// Converts the given JsonArray into a JsonValue.
/// </summary>
/// <param name="value">The value to be converted.</param>
public static implicit operator JsonValue(JsonArray value)
{
return new JsonValue(value);
}
/// <summary>
/// Converts the given DateTime? into a JsonValue.
/// </summary>
/// <remarks>
/// The DateTime value will be stored as a string using ISO 8601 format,
/// since JSON does not define a DateTime type.
/// </remarks>
/// <param name="value">The value to be converted.</param>
public static implicit operator JsonValue(DateTime? value)
{
if (value == null) {
return JsonValue.Null;
}
return new JsonValue(value.Value.ToString("o"));
}
/// <summary>
/// Converts the given JsonValue into an Int.
/// </summary>
/// <param name="jsonValue">The JsonValue to be converted.</param>
public static explicit operator int(JsonValue jsonValue)
{
if (jsonValue.IsInteger) {
return jsonValue.AsInteger;
} else {
return 0;
}
}
/// <summary>
/// Converts the given JsonValue into a nullable Int.
/// </summary>
/// <param name="jsonValue">The JsonValue to be converted.</param>
/// <exception cref="System.InvalidCastException">
/// Throws System.InvalidCastException when the inner value type of the
/// JsonValue is not the desired type of the conversion.
/// </exception>
public static explicit operator int? (JsonValue jsonValue)
{
if (jsonValue.IsNull) {
return null;
} else {
return (int)jsonValue;
}
}
/// <summary>
/// Converts the given JsonValue into a Bool.
/// </summary>
/// <param name="jsonValue">The JsonValue to be converted.</param>
public static explicit operator bool(JsonValue jsonValue)
{
if (jsonValue.IsBoolean) {
return jsonValue.value == 1;
} else {
return false;
}
}
/// <summary>
/// Converts the given JsonValue into a nullable Bool.
/// </summary>
/// <param name="jsonValue">The JsonValue to be converted.</param>
/// <exception cref="System.InvalidCastException">
/// Throws System.InvalidCastException when the inner value type of the
/// JsonValue is not the desired type of the conversion.
/// </exception>
public static explicit operator bool? (JsonValue jsonValue)
{
if (jsonValue.IsNull) {
return null;
} else {
return (bool)jsonValue;
}
}
/// <summary>
/// Converts the given JsonValue into a Double.
/// </summary>
/// <param name="jsonValue">The JsonValue to be converted.</param>
public static explicit operator double(JsonValue jsonValue)
{
if (jsonValue.IsNumber) {
return jsonValue.value;
} else {
return double.NaN;
}
}
/// <summary>
/// Converts the given JsonValue into a nullable Double.
/// </summary>
/// <param name="jsonValue">The JsonValue to be converted.</param>
/// <exception cref="System.InvalidCastException">
/// Throws System.InvalidCastException when the inner value type of the
/// JsonValue is not the desired type of the conversion.
/// </exception>
public static explicit operator double? (JsonValue jsonValue)
{
if (jsonValue.IsNull) {
return null;
} else {
return (double)jsonValue;
}
}
/// <summary>
/// Converts the given JsonValue into a String.
/// </summary>
/// <param name="jsonValue">The JsonValue to be converted.</param>
public static explicit operator string(JsonValue jsonValue)
{
if (jsonValue.IsString || jsonValue.IsNull) {
return jsonValue.reference as string;
} else {
return null;
}
}
/// <summary>
/// Converts the given JsonValue into a JsonObject.
/// </summary>
/// <param name="jsonValue">The JsonValue to be converted.</param>
public static explicit operator JsonObject(JsonValue jsonValue)
{
if (jsonValue.IsJsonObject || jsonValue.IsNull) {
return jsonValue.reference as JsonObject;
} else {
return null;
}
}
/// <summary>
/// Converts the given JsonValue into a JsonArray.
/// </summary>
/// <param name="jsonValue">The JsonValue to be converted.</param>
public static explicit operator JsonArray(JsonValue jsonValue)
{
if (jsonValue.IsJsonArray || jsonValue.IsNull) {
return jsonValue.reference as JsonArray;
} else {
return null;
}
}
/// <summary>
/// Converts the given JsonValue into a DateTime.
/// </summary>
/// <param name="jsonValue">The JsonValue to be converted.</param>
public static explicit operator DateTime(JsonValue jsonValue)
{
var dateTime = jsonValue.AsDateTime;
if (dateTime.HasValue) {
return dateTime.Value;
} else {
return DateTime.MinValue;
}
}
/// <summary>
/// Converts the given JsonValue into a nullable DateTime.
/// </summary>
/// <param name="jsonValue">The JsonValue to be converted.</param>
public static explicit operator DateTime? (JsonValue jsonValue)
{
if (jsonValue.IsDateTime || jsonValue.IsNull) {
return jsonValue.AsDateTime;
} else {
return null;
}
}
/// <summary>
/// Returns a value indicating whether the two given JsonValues are equal.
/// </summary>
/// <param name="a">First JsonValue to compare.</param>
/// <param name="b">Second JsonValue to compare.</param>
public static bool operator ==(JsonValue a, JsonValue b)
{
return (a.Type == b.Type)
&& (a.value == b.value)
&& Equals(a.reference, b.reference);
}
/// <summary>
/// Returns a value indicating whether the two given JsonValues are unequal.
/// </summary>
/// <param name="a">First JsonValue to compare.</param>
/// <param name="b">Second JsonValue to compare.</param>
public static bool operator !=(JsonValue a, JsonValue b)
{
return !(a == b);
}
/// <summary>
/// Returns a JsonValue by parsing the given string.
/// </summary>
/// <param name="text">The JSON-formatted string to be parsed.</param>
/// <returns>The <see cref="JsonValue"/> representing the parsed text.</returns>
public static JsonValue Parse(string text)
{
return JsonReader.Parse(text);
}
/// <inheritdoc/>
public override bool Equals(object obj)
{
if (obj == null) {
return this.IsNull;
}
var jsonValue = obj as JsonValue?;
if (jsonValue == null) {
return false;
} else {
return this == jsonValue.Value;
}
}
/// <inheritdoc/>
public override int GetHashCode()
{
if (this.IsNull) {
return this.Type.GetHashCode();
} else {
return this.Type.GetHashCode()
^ this.value.GetHashCode()
^ EqualityComparer<object>.Default.GetHashCode(this.reference);
}
}
[ExcludeFromCodeCoverage]
private class JsonValueDebugView
{
private JsonValue jsonValue;
public JsonValueDebugView(JsonValue jsonValue)
{
this.jsonValue = jsonValue;
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public JsonObject ObjectView {
get {
if (this.jsonValue.IsJsonObject) {
return (JsonObject)this.jsonValue.reference;
} else {
return null;
}
}
}
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
public JsonArray ArrayView {
get {
if (this.jsonValue.IsJsonArray) {
return (JsonArray)this.jsonValue.reference;
} else {
return null;
}
}
}
public JsonValueType Type {
get {
return this.jsonValue.Type;
}
}
public object Value {
get {
if (this.jsonValue.IsJsonObject) {
return (JsonObject)this.jsonValue.reference;
} else if (this.jsonValue.IsJsonArray) {
return (JsonArray)this.jsonValue.reference;
} else {
return this.jsonValue;
}
}
}
}
}
}

41
ICSharpCode.Decompiler/DotNetCore/LightJson/JsonValueType.cs

@ -0,0 +1,41 @@ @@ -0,0 +1,41 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace LightJson
{
/// <summary>
/// Enumerates the types of Json values.
/// </summary>
internal enum JsonValueType : byte
{
/// <summary>
/// A null value.
/// </summary>
Null = 0,
/// <summary>
/// A boolean value.
/// </summary>
Boolean,
/// <summary>
/// A number value.
/// </summary>
Number,
/// <summary>
/// A string value.
/// </summary>
String,
/// <summary>
/// An object value.
/// </summary>
Object,
/// <summary>
/// An array value.
/// </summary>
Array,
}
}

102
ICSharpCode.Decompiler/DotNetCore/LightJson/Serialization/JsonParseException.cs

@ -0,0 +1,102 @@ @@ -0,0 +1,102 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace LightJson.Serialization
{
using System;
/// <summary>
/// The exception that is thrown when a JSON message cannot be parsed.
/// </summary>
/// <remarks>
/// This exception is only intended to be thrown by LightJson.
/// </remarks>
internal sealed class JsonParseException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="JsonParseException"/> class.
/// </summary>
public JsonParseException()
: base(GetDefaultMessage(ErrorType.Unknown))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonParseException"/> class with the given error type and position.
/// </summary>
/// <param name="type">The error type that describes the cause of the error.</param>
/// <param name="position">The position in the text where the error occurred.</param>
public JsonParseException(ErrorType type, TextPosition position)
: this(GetDefaultMessage(type), type, position)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonParseException"/> class with the given message, error type, and position.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="type">The error type that describes the cause of the error.</param>
/// <param name="position">The position in the text where the error occurred.</param>
public JsonParseException(string message, ErrorType type, TextPosition position)
: base(message)
{
this.Type = type;
this.Position = position;
}
/// <summary>
/// Enumerates the types of errors that can occur when parsing a JSON message.
/// </summary>
public enum ErrorType : int
{
/// <summary>
/// Indicates that the cause of the error is unknown.
/// </summary>
Unknown = 0,
/// <summary>
/// Indicates that the text ended before the message could be parsed.
/// </summary>
IncompleteMessage,
/// <summary>
/// Indicates that a JsonObject contains more than one key with the same name.
/// </summary>
DuplicateObjectKeys,
/// <summary>
/// Indicates that the parser encountered and invalid or unexpected character.
/// </summary>
InvalidOrUnexpectedCharacter,
}
/// <summary>
/// Gets the text position where the error occurred.
/// </summary>
/// <value>The text position where the error occurred.</value>
public TextPosition Position { get; private set; }
/// <summary>
/// Gets the type of error that caused the exception to be thrown.
/// </summary>
/// <value>The type of error that caused the exception to be thrown.</value>
public ErrorType Type { get; private set; }
private static string GetDefaultMessage(ErrorType type)
{
switch (type) {
case ErrorType.IncompleteMessage:
return "The string ended before a value could be parsed.";
case ErrorType.InvalidOrUnexpectedCharacter:
return "The parser encountered an invalid or unexpected character.";
case ErrorType.DuplicateObjectKeys:
return "The parser encountered a JsonObject with duplicate keys.";
default:
return "An error occurred while parsing the JSON message.";
}
}
}
}

413
ICSharpCode.Decompiler/DotNetCore/LightJson/Serialization/JsonReader.cs

@ -0,0 +1,413 @@ @@ -0,0 +1,413 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace LightJson.Serialization
{
using System;
using System.Globalization;
using System.IO;
using System.Text;
using ErrorType = JsonParseException.ErrorType;
/// <summary>
/// Represents a reader that can read JsonValues.
/// </summary>
internal sealed class JsonReader
{
private TextScanner scanner;
private JsonReader(TextReader reader)
{
this.scanner = new TextScanner(reader);
}
/// <summary>
/// Creates a JsonValue by using the given TextReader.
/// </summary>
/// <param name="reader">The TextReader used to read a JSON message.</param>
/// <returns>The parsed <see cref="JsonValue"/>.</returns>
public static JsonValue Parse(TextReader reader)
{
if (reader == null) {
throw new ArgumentNullException(nameof(reader));
}
return new JsonReader(reader).Parse();
}
/// <summary>
/// Creates a JsonValue by reader the JSON message in the given string.
/// </summary>
/// <param name="source">The string containing the JSON message.</param>
/// <returns>The parsed <see cref="JsonValue"/>.</returns>
public static JsonValue Parse(string source)
{
if (source == null) {
throw new ArgumentNullException(nameof(source));
}
using (var reader = new StringReader(source)) {
return Parse(reader);
}
}
private string ReadJsonKey()
{
return this.ReadString();
}
private JsonValue ReadJsonValue()
{
this.scanner.SkipWhitespace();
var next = this.scanner.Peek();
if (char.IsNumber(next)) {
return this.ReadNumber();
}
switch (next) {
case '{':
return this.ReadObject();
case '[':
return this.ReadArray();
case '"':
return this.ReadString();
case '-':
return this.ReadNumber();
case 't':
case 'f':
return this.ReadBoolean();
case 'n':
return this.ReadNull();
default:
throw new JsonParseException(
ErrorType.InvalidOrUnexpectedCharacter,
this.scanner.Position);
}
}
private JsonValue ReadNull()
{
this.scanner.Assert("null");
return JsonValue.Null;
}
private JsonValue ReadBoolean()
{
switch (this.scanner.Peek()) {
case 't':
this.scanner.Assert("true");
return true;
default:
this.scanner.Assert("false");
return false;
}
}
private void ReadDigits(StringBuilder builder)
{
while (true) {
int next = this.scanner.Peek(throwAtEndOfFile: false);
if (next == -1 || !char.IsNumber((char)next)) {
return;
}
builder.Append(this.scanner.Read());
}
}
private JsonValue ReadNumber()
{
var builder = new StringBuilder();
if (this.scanner.Peek() == '-') {
builder.Append(this.scanner.Read());
}
if (this.scanner.Peek() == '0') {
builder.Append(this.scanner.Read());
} else {
this.ReadDigits(builder);
}
if (this.scanner.Peek(throwAtEndOfFile: false) == '.') {
builder.Append(this.scanner.Read());
this.ReadDigits(builder);
}
if (this.scanner.Peek(throwAtEndOfFile: false) == 'e' || this.scanner.Peek(throwAtEndOfFile: false) == 'E') {
builder.Append(this.scanner.Read());
var next = this.scanner.Peek();
switch (next) {
case '+':
case '-':
builder.Append(this.scanner.Read());
break;
}
this.ReadDigits(builder);
}
return double.Parse(
builder.ToString(),
CultureInfo.InvariantCulture);
}
private string ReadString()
{
var builder = new StringBuilder();
this.scanner.Assert('"');
while (true) {
var errorPosition = this.scanner.Position;
var c = this.scanner.Read();
if (c == '\\') {
errorPosition = this.scanner.Position;
c = this.scanner.Read();
switch (char.ToLower(c)) {
case '"':
case '\\':
case '/':
builder.Append(c);
break;
case 'b':
builder.Append('\b');
break;
case 'f':
builder.Append('\f');
break;
case 'n':
builder.Append('\n');
break;
case 'r':
builder.Append('\r');
break;
case 't':
builder.Append('\t');
break;
case 'u':
builder.Append(this.ReadUnicodeLiteral());
break;
default:
throw new JsonParseException(
ErrorType.InvalidOrUnexpectedCharacter,
errorPosition);
}
} else if (c == '"') {
break;
} else {
if (char.IsControl(c)) {
throw new JsonParseException(
ErrorType.InvalidOrUnexpectedCharacter,
errorPosition);
} else {
builder.Append(c);
}
}
}
return builder.ToString();
}
private int ReadHexDigit()
{
var errorPosition = this.scanner.Position;
switch (char.ToUpper(this.scanner.Read())) {
case '0':
return 0;
case '1':
return 1;
case '2':
return 2;
case '3':
return 3;
case '4':
return 4;
case '5':
return 5;
case '6':
return 6;
case '7':
return 7;
case '8':
return 8;
case '9':
return 9;
case 'A':
return 10;
case 'B':
return 11;
case 'C':
return 12;
case 'D':
return 13;
case 'E':
return 14;
case 'F':
return 15;
default:
throw new JsonParseException(
ErrorType.InvalidOrUnexpectedCharacter,
errorPosition);
}
}
private char ReadUnicodeLiteral()
{
int value = 0;
value += this.ReadHexDigit() * 4096; // 16^3
value += this.ReadHexDigit() * 256; // 16^2
value += this.ReadHexDigit() * 16; // 16^1
value += this.ReadHexDigit(); // 16^0
return (char)value;
}
private JsonObject ReadObject()
{
return this.ReadObject(new JsonObject());
}
private JsonObject ReadObject(JsonObject jsonObject)
{
this.scanner.Assert('{');
this.scanner.SkipWhitespace();
if (this.scanner.Peek() == '}') {
this.scanner.Read();
} else {
while (true) {
this.scanner.SkipWhitespace();
var errorPosition = this.scanner.Position;
var key = this.ReadJsonKey();
if (jsonObject.ContainsKey(key)) {
throw new JsonParseException(
ErrorType.DuplicateObjectKeys,
errorPosition);
}
this.scanner.SkipWhitespace();
this.scanner.Assert(':');
this.scanner.SkipWhitespace();
var value = this.ReadJsonValue();
jsonObject.Add(key, value);
this.scanner.SkipWhitespace();
errorPosition = this.scanner.Position;
var next = this.scanner.Read();
if (next == ',') {
// Allow trailing commas in objects
this.scanner.SkipWhitespace();
if (this.scanner.Peek() == '}') {
next = this.scanner.Read();
}
}
if (next == '}') {
break;
} else if (next == ',') {
continue;
} else {
throw new JsonParseException(
ErrorType.InvalidOrUnexpectedCharacter,
errorPosition);
}
}
}
return jsonObject;
}
private JsonArray ReadArray()
{
return this.ReadArray(new JsonArray());
}
private JsonArray ReadArray(JsonArray jsonArray)
{
this.scanner.Assert('[');
this.scanner.SkipWhitespace();
if (this.scanner.Peek() == ']') {
this.scanner.Read();
} else {
while (true) {
this.scanner.SkipWhitespace();
var value = this.ReadJsonValue();
jsonArray.Add(value);
this.scanner.SkipWhitespace();
var errorPosition = this.scanner.Position;
var next = this.scanner.Read();
if (next == ',') {
// Allow trailing commas in arrays
this.scanner.SkipWhitespace();
if (this.scanner.Peek() == ']') {
next = this.scanner.Read();
}
}
if (next == ']') {
break;
} else if (next == ',') {
continue;
} else {
throw new JsonParseException(
ErrorType.InvalidOrUnexpectedCharacter,
errorPosition);
}
}
}
return jsonArray;
}
private JsonValue Parse()
{
this.scanner.SkipWhitespace();
return this.ReadJsonValue();
}
}
}

97
ICSharpCode.Decompiler/DotNetCore/LightJson/Serialization/JsonSerializationException.cs

@ -0,0 +1,97 @@ @@ -0,0 +1,97 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace LightJson.Serialization
{
using System;
/// <summary>
/// The exception that is thrown when a JSON value cannot be serialized.
/// </summary>
/// <remarks>
/// This exception is only intended to be thrown by LightJson.
/// </remarks>
internal sealed class JsonSerializationException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="JsonSerializationException"/> class.
/// </summary>
public JsonSerializationException()
: base(GetDefaultMessage(ErrorType.Unknown))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonSerializationException"/> class with the given error type.
/// </summary>
/// <param name="type">The error type that describes the cause of the error.</param>
public JsonSerializationException(ErrorType type)
: this(GetDefaultMessage(type), type)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonSerializationException"/> class with the given message and
/// error type.
/// </summary>
/// <param name="message">The message that describes the error.</param>
/// <param name="type">The error type that describes the cause of the error.</param>
public JsonSerializationException(string message, ErrorType type)
: base(message)
{
this.Type = type;
}
/// <summary>
/// Enumerates the types of errors that can occur during serialization.
/// </summary>
public enum ErrorType
{
/// <summary>
/// Indicates that the cause of the error is unknown.
/// </summary>
Unknown = 0,
/// <summary>
/// Indicates that the writer encountered an invalid number value (NAN, infinity) during serialization.
/// </summary>
InvalidNumber,
/// <summary>
/// Indicates that the object been serialized contains an invalid JSON value type.
/// That is, a value type that is not null, boolean, number, string, object, or array.
/// </summary>
InvalidValueType,
/// <summary>
/// Indicates that the object been serialized contains a circular reference.
/// </summary>
CircularReference,
}
/// <summary>
/// Gets the type of error that caused the exception to be thrown.
/// </summary>
/// <value>
/// The type of error that caused the exception to be thrown.
/// </value>
public ErrorType Type { get; }
private static string GetDefaultMessage(ErrorType type)
{
switch (type) {
case ErrorType.InvalidNumber:
return "The value been serialized contains an invalid number value (NAN, infinity).";
case ErrorType.InvalidValueType:
return "The value been serialized contains (or is) an invalid JSON type.";
case ErrorType.CircularReference:
return "The value been serialized contains circular references.";
default:
return "An error occurred during serialization.";
}
}
}
}

349
ICSharpCode.Decompiler/DotNetCore/LightJson/Serialization/JsonWriter.cs

@ -0,0 +1,349 @@ @@ -0,0 +1,349 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace LightJson.Serialization
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using ErrorType = JsonSerializationException.ErrorType;
/// <summary>
/// Represents a writer that can write string representations of JsonValues.
/// </summary>
internal sealed class JsonWriter : IDisposable
{
private int indent;
private bool isNewLine;
private TextWriter writer;
/// <summary>
/// A set of containing all the collection objects (JsonObject/JsonArray) being rendered.
/// It is used to prevent circular references; since collections that contain themselves
/// will never finish rendering.
/// </summary>
private HashSet<IEnumerable<JsonValue>> renderingCollections;
/// <summary>
/// Initializes a new instance of the <see cref="JsonWriter"/> class.
/// </summary>
public JsonWriter()
: this(false)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="JsonWriter"/> class.
/// </summary>
/// <param name="pretty">
/// A value indicating whether the output of the writer should be human-readable.
/// </param>
public JsonWriter(bool pretty)
{
if (pretty) {
this.IndentString = "\t";
this.SpacingString = " ";
this.NewLineString = "\n";
}
}
/// <summary>
/// Gets or sets the string representing a indent in the output.
/// </summary>
/// <value>
/// The string representing a indent in the output.
/// </value>
public string IndentString { get; set; }
/// <summary>
/// Gets or sets the string representing a space in the output.
/// </summary>
/// <value>
/// The string representing a space in the output.
/// </value>
public string SpacingString { get; set; }
/// <summary>
/// Gets or sets the string representing a new line on the output.
/// </summary>
/// <value>
/// The string representing a new line on the output.
/// </value>
public string NewLineString { get; set; }
/// <summary>
/// Gets or sets a value indicating whether JsonObject properties should be written in a deterministic order.
/// </summary>
/// <value>
/// A value indicating whether JsonObject properties should be written in a deterministic order.
/// </value>
public bool SortObjects { get; set; }
/// <summary>
/// Returns a string representation of the given JsonValue.
/// </summary>
/// <param name="jsonValue">The JsonValue to serialize.</param>
/// <returns>The serialized value.</returns>
public string Serialize(JsonValue jsonValue)
{
this.Initialize();
this.Render(jsonValue);
return this.writer.ToString();
}
/// <summary>
/// Releases all the resources used by this object.
/// </summary>
public void Dispose()
{
if (this.writer != null) {
this.writer.Dispose();
}
}
private static bool IsValidNumber(double number)
{
return !(double.IsNaN(number) || double.IsInfinity(number));
}
private void Initialize()
{
this.indent = 0;
this.isNewLine = true;
this.writer = new StringWriter();
this.renderingCollections = new HashSet<IEnumerable<JsonValue>>();
}
private void Write(string text)
{
if (this.isNewLine) {
this.isNewLine = false;
this.WriteIndentation();
}
this.writer.Write(text);
}
private void WriteEncodedJsonValue(JsonValue value)
{
switch (value.Type) {
case JsonValueType.Null:
this.Write("null");
break;
case JsonValueType.Boolean:
this.Write(value.AsString);
break;
case JsonValueType.Number:
this.Write(((double)value).ToString(CultureInfo.InvariantCulture));
break;
default:
Debug.Assert(value.Type == JsonValueType.String, "value.Type == JsonValueType.String");
this.WriteEncodedString((string)value);
break;
}
}
private void WriteEncodedString(string text)
{
this.Write("\"");
for (int i = 0; i < text.Length; i += 1) {
var currentChar = text[i];
// Encoding special characters.
switch (currentChar) {
case '\\':
this.writer.Write("\\\\");
break;
case '\"':
this.writer.Write("\\\"");
break;
case '/':
this.writer.Write("\\/");
break;
case '\b':
this.writer.Write("\\b");
break;
case '\f':
this.writer.Write("\\f");
break;
case '\n':
this.writer.Write("\\n");
break;
case '\r':
this.writer.Write("\\r");
break;
case '\t':
this.writer.Write("\\t");
break;
default:
this.writer.Write(currentChar);
break;
}
}
this.writer.Write("\"");
}
private void WriteIndentation()
{
for (var i = 0; i < this.indent; i += 1) {
this.Write(this.IndentString);
}
}
private void WriteSpacing()
{
this.Write(this.SpacingString);
}
private void WriteLine()
{
this.Write(this.NewLineString);
this.isNewLine = true;
}
private void WriteLine(string line)
{
this.Write(line);
this.WriteLine();
}
private void AddRenderingCollection(IEnumerable<JsonValue> value)
{
if (!this.renderingCollections.Add(value)) {
throw new JsonSerializationException(ErrorType.CircularReference);
}
}
private void RemoveRenderingCollection(IEnumerable<JsonValue> value)
{
this.renderingCollections.Remove(value);
}
private void Render(JsonValue value)
{
switch (value.Type) {
case JsonValueType.Null:
case JsonValueType.Boolean:
case JsonValueType.Number:
case JsonValueType.String:
this.WriteEncodedJsonValue(value);
break;
case JsonValueType.Object:
this.Render((JsonObject)value);
break;
case JsonValueType.Array:
this.Render((JsonArray)value);
break;
default:
throw new JsonSerializationException(ErrorType.InvalidValueType);
}
}
private void Render(JsonArray value)
{
this.AddRenderingCollection(value);
this.WriteLine("[");
this.indent += 1;
using (var enumerator = value.GetEnumerator()) {
var hasNext = enumerator.MoveNext();
while (hasNext) {
this.Render(enumerator.Current);
hasNext = enumerator.MoveNext();
if (hasNext) {
this.WriteLine(",");
} else {
this.WriteLine();
}
}
}
this.indent -= 1;
this.Write("]");
this.RemoveRenderingCollection(value);
}
private void Render(JsonObject value)
{
this.AddRenderingCollection(value);
this.WriteLine("{");
this.indent += 1;
using (var enumerator = this.GetJsonObjectEnumerator(value)) {
var hasNext = enumerator.MoveNext();
while (hasNext) {
this.WriteEncodedString(enumerator.Current.Key);
this.Write(":");
this.WriteSpacing();
this.Render(enumerator.Current.Value);
hasNext = enumerator.MoveNext();
if (hasNext) {
this.WriteLine(",");
} else {
this.WriteLine();
}
}
}
this.indent -= 1;
this.Write("}");
this.RemoveRenderingCollection(value);
}
/// <summary>
/// Gets an JsonObject enumerator based on the configuration of this JsonWriter.
/// If JsonWriter.SortObjects is set to true, then a ordered enumerator is returned.
/// Otherwise, a faster non-deterministic enumerator is returned.
/// </summary>
/// <param name="jsonObject">The JsonObject for which to get an enumerator.</param>
/// <returns>An enumerator for the properties in a <see cref="JsonObject"/>.</returns>
private IEnumerator<KeyValuePair<string, JsonValue>> GetJsonObjectEnumerator(JsonObject jsonObject)
{
if (this.SortObjects) {
var sortedDictionary = new SortedDictionary<string, JsonValue>(StringComparer.Ordinal);
foreach (var item in jsonObject) {
sortedDictionary.Add(item.Key, item.Value);
}
return sortedDictionary.GetEnumerator();
} else {
return jsonObject.GetEnumerator();
}
}
}
}

21
ICSharpCode.Decompiler/DotNetCore/LightJson/Serialization/TextPosition.cs

@ -0,0 +1,21 @@ @@ -0,0 +1,21 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace LightJson.Serialization
{
/// <summary>
/// Represents a position within a plain text resource.
/// </summary>
internal struct TextPosition
{
/// <summary>
/// The column position, 0-based.
/// </summary>
public long Column;
/// <summary>
/// The line position, 0-based.
/// </summary>
public long Line;
}
}

212
ICSharpCode.Decompiler/DotNetCore/LightJson/Serialization/TextScanner.cs

@ -0,0 +1,212 @@ @@ -0,0 +1,212 @@
// Copyright (c) Tunnel Vision Laboratories, LLC. All Rights Reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.
namespace LightJson.Serialization
{
using System.IO;
using ErrorType = JsonParseException.ErrorType;
/// <summary>
/// Represents a text scanner that reads one character at a time.
/// </summary>
internal sealed class TextScanner
{
private TextReader reader;
private TextPosition position;
/// <summary>
/// Initializes a new instance of the <see cref="TextScanner"/> class.
/// </summary>
/// <param name="reader">The TextReader to read the text.</param>
public TextScanner(TextReader reader)
{
this.reader = reader;
}
/// <summary>
/// Gets the position of the scanner within the text.
/// </summary>
/// <value>The position of the scanner within the text.</value>
public TextPosition Position {
get {
return this.position;
}
}
/// <summary>
/// Reads the next character in the stream without changing the current position.
/// </summary>
/// <returns>The next character in the stream.</returns>
public char Peek()
=> (char)this.Peek(throwAtEndOfFile: true);
/// <summary>
/// Reads the next character in the stream without changing the current position.
/// </summary>
/// <param name="throwAtEndOfFile"><see langword="true"/> to throw an exception if the end of the file is
/// reached; otherwise, <see langword="false"/>.</param>
/// <returns>The next character in the stream, or -1 if the end of the file is reached with
/// <paramref name="throwAtEndOfFile"/> set to <see langword="false"/>.</returns>
public int Peek(bool throwAtEndOfFile)
{
var next = this.reader.Peek();
if (next == -1 && throwAtEndOfFile) {
throw new JsonParseException(
ErrorType.IncompleteMessage,
this.position);
} else {
return next;
}
}
/// <summary>
/// Reads the next character in the stream, advancing the text position.
/// </summary>
/// <returns>The next character in the stream.</returns>
public char Read()
{
var next = this.reader.Read();
if (next == -1) {
throw new JsonParseException(
ErrorType.IncompleteMessage,
this.position);
} else {
if (next == '\n') {
this.position.Line += 1;
this.position.Column = 0;
} else {
this.position.Column += 1;
}
return (char)next;
}
}
/// <summary>
/// Advances the scanner to next non-whitespace character.
/// </summary>
public void SkipWhitespace()
{
while (true) {
char next = this.Peek();
if (char.IsWhiteSpace(next)) {
this.Read();
continue;
} else if (next == '/') {
this.SkipComment();
continue;
} else {
break;
}
}
}
/// <summary>
/// Verifies that the given character matches the next character in the stream.
/// If the characters do not match, an exception will be thrown.
/// </summary>
/// <param name="next">The expected character.</param>
public void Assert(char next)
{
var errorPosition = this.position;
if (this.Read() != next) {
throw new JsonParseException(
string.Format("Parser expected '{0}'", next),
ErrorType.InvalidOrUnexpectedCharacter,
errorPosition);
}
}
/// <summary>
/// Verifies that the given string matches the next characters in the stream.
/// If the strings do not match, an exception will be thrown.
/// </summary>
/// <param name="next">The expected string.</param>
public void Assert(string next)
{
for (var i = 0; i < next.Length; i += 1) {
this.Assert(next[i]);
}
}
private void SkipComment()
{
// First character is the first slash
this.Read();
switch (this.Peek()) {
case '/':
this.SkipLineComment();
return;
case '*':
this.SkipBlockComment();
return;
default:
throw new JsonParseException(
string.Format("Parser expected '{0}'", this.Peek()),
ErrorType.InvalidOrUnexpectedCharacter,
this.position);
}
}
private void SkipLineComment()
{
// First character is the second '/' of the opening '//'
this.Read();
while (true) {
switch (this.reader.Peek()) {
case '\n':
// Reached the end of the line
this.Read();
return;
case -1:
// Reached the end of the file
return;
default:
this.Read();
continue;
}
}
}
private void SkipBlockComment()
{
// First character is the '*' of the opening '/*'
this.Read();
bool foundStar = false;
while (true) {
switch (this.reader.Peek()) {
case '*':
this.Read();
foundStar = true;
continue;
case '/':
this.Read();
if (foundStar) {
return;
} else {
foundStar = false;
continue;
}
case -1:
// Reached the end of the file
return;
default:
this.Read();
foundStar = false;
continue;
}
}
}
}
}

11
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -50,7 +50,6 @@ @@ -50,7 +50,6 @@
<ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.2.0" />
<PackageReference Include="Newtonsoft.Json" Version="9.0.1" />
<PackageReference Include="System.Collections.Immutable" Version="1.3.1" />
<PackageReference Include="System.ValueTuple" Version="4.3.0" />
</ItemGroup>
@ -276,6 +275,16 @@ @@ -276,6 +275,16 @@
<Compile Include="Documentation\XmlDocumentationProvider.cs" />
<Compile Include="DotNetCore\DotNetCorePathFinder.cs" />
<Compile Include="DotNetCore\DotNetCorePathFinderExtensions.cs" />
<Compile Include="DotNetCore\LightJson\JsonArray.cs" />
<Compile Include="DotNetCore\LightJson\JsonObject.cs" />
<Compile Include="DotNetCore\LightJson\JsonValue.cs" />
<Compile Include="DotNetCore\LightJson\JsonValueType.cs" />
<Compile Include="DotNetCore\LightJson\Serialization\JsonParseException.cs" />
<Compile Include="DotNetCore\LightJson\Serialization\JsonReader.cs" />
<Compile Include="DotNetCore\LightJson\Serialization\JsonSerializationException.cs" />
<Compile Include="DotNetCore\LightJson\Serialization\JsonWriter.cs" />
<Compile Include="DotNetCore\LightJson\Serialization\TextPosition.cs" />
<Compile Include="DotNetCore\LightJson\Serialization\TextScanner.cs" />
<Compile Include="DotNetCore\UniversalAssemblyResolver.cs" />
<Compile Include="DotNetCore\UnresolvedAssemblyNameReference.cs" />
<Compile Include="IL\ILAstWritingOptions.cs" />

Loading…
Cancel
Save