2023-05-25 02:20:01 -05:00
|
|
|
using Newtonsoft.Json;
|
|
|
|
|
using Newtonsoft.Json.Bson;
|
2023-05-25 03:54:56 -05:00
|
|
|
using Newtonsoft.Json.Linq;
|
2023-05-25 02:20:01 -05:00
|
|
|
using System;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Runtime.Serialization;
|
|
|
|
|
|
|
|
|
|
namespace Microsoft.Iris.Debug;
|
|
|
|
|
|
|
|
|
|
internal class BsonFormatter : IFormatter
|
|
|
|
|
{
|
|
|
|
|
private readonly JsonSerializer _serializer;
|
|
|
|
|
|
|
|
|
|
public ISurrogateSelector SurrogateSelector { get; set; }
|
|
|
|
|
|
|
|
|
|
public SerializationBinder Binder { get; set; }
|
|
|
|
|
|
|
|
|
|
public StreamingContext Context { get; set; }
|
|
|
|
|
|
|
|
|
|
public BsonFormatter(JsonSerializerSettings settings = null) : this(new StreamingContext(StreamingContextStates.All), settings)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public BsonFormatter(StreamingContext context, JsonSerializerSettings settings = null)
|
|
|
|
|
{
|
|
|
|
|
Context = context;
|
|
|
|
|
|
|
|
|
|
settings ??= new()
|
|
|
|
|
{
|
|
|
|
|
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
|
|
|
|
Converters = new JsonConverter[]
|
|
|
|
|
{
|
|
|
|
|
new BsonFallbackConverter()
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
_serializer = JsonSerializer.Create(settings);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public object Deserialize(Stream serializationStream)
|
|
|
|
|
{
|
2023-05-25 21:01:48 -05:00
|
|
|
using BsonDataReader reader = new(serializationStream)
|
2023-05-25 02:20:01 -05:00
|
|
|
{
|
|
|
|
|
CloseInput = false
|
|
|
|
|
};
|
2023-05-25 02:27:06 -05:00
|
|
|
|
2023-05-25 21:01:48 -05:00
|
|
|
BsonPackage package = new(_serializer, reader);
|
|
|
|
|
return package.Object ?? package.SerializedObject;
|
2023-05-25 02:20:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Serialize(Stream serializationStream, object graph)
|
|
|
|
|
{
|
2023-05-25 21:01:48 -05:00
|
|
|
using BsonDataWriter writer = new(serializationStream);
|
2023-05-25 03:54:56 -05:00
|
|
|
_serializer.Serialize(writer, new[] { graph?.GetType().FullName, graph });
|
2023-05-25 02:20:01 -05:00
|
|
|
writer.Flush();
|
|
|
|
|
}
|
2023-05-25 21:01:48 -05:00
|
|
|
|
|
|
|
|
private class BsonPackage
|
|
|
|
|
{
|
|
|
|
|
public BsonPackage(JsonSerializer serializer, JsonReader reader)
|
|
|
|
|
{
|
|
|
|
|
var package = (JObject)serializer.Deserialize(reader);
|
|
|
|
|
|
|
|
|
|
TypeName = package["0"].Value<string>();
|
|
|
|
|
SerializedObject = (JObject)package["1"];
|
|
|
|
|
|
|
|
|
|
// If the type is accessible from the current domain,
|
|
|
|
|
// create an instance of it.
|
|
|
|
|
var type = Type.GetType(TypeName);
|
|
|
|
|
if (type != null)
|
|
|
|
|
Object = SerializedObject.ToObject(type, serializer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public string TypeName { get; set; }
|
|
|
|
|
|
|
|
|
|
public JObject SerializedObject { get; set; }
|
|
|
|
|
|
|
|
|
|
public object Object { get; set; }
|
|
|
|
|
}
|
2023-05-25 02:20:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
internal class BsonFallbackConverter : JsonConverter
|
|
|
|
|
{
|
|
|
|
|
public override bool CanConvert(Type objectType)
|
|
|
|
|
{
|
|
|
|
|
return !objectType.Attributes.HasFlag(System.Reflection.TypeAttributes.Serializable)
|
2023-05-25 21:01:48 -05:00
|
|
|
|| objectType.IsEnum || objectType == typeof(uint) || objectType == typeof(ulong)
|
|
|
|
|
|| objectType == typeof(Type);
|
2023-05-25 02:20:01 -05:00
|
|
|
}
|
|
|
|
|
|
2023-05-25 21:01:48 -05:00
|
|
|
public override object ReadJson(JsonReader reader, Type objectType, object jsonValue, JsonSerializer serializer)
|
2023-05-25 02:20:01 -05:00
|
|
|
{
|
2023-05-25 21:01:48 -05:00
|
|
|
jsonValue = reader.Value;
|
|
|
|
|
if (objectType == reader.ValueType)
|
|
|
|
|
return jsonValue;
|
|
|
|
|
|
|
|
|
|
if (objectType == typeof(uint))
|
|
|
|
|
return BitConverter.ToUInt32((byte[])jsonValue, 0);
|
|
|
|
|
else if (objectType == typeof(ulong))
|
|
|
|
|
return BitConverter.ToUInt64((byte[])jsonValue, 0);
|
|
|
|
|
else if (objectType.IsEnum)
|
2023-05-25 03:54:56 -05:00
|
|
|
{
|
2023-05-25 21:01:48 -05:00
|
|
|
if (reader.ValueType == typeof(string))
|
|
|
|
|
return Enum.Parse(objectType, (string)reader.Value);
|
|
|
|
|
|
|
|
|
|
return Enum.ToObject(objectType, reader.Value);
|
|
|
|
|
}
|
|
|
|
|
else if (objectType == typeof(Type))
|
|
|
|
|
{
|
|
|
|
|
if (jsonValue is not string typeName)
|
|
|
|
|
return null;
|
|
|
|
|
|
|
|
|
|
return Type.GetType(typeName);
|
2023-05-25 03:54:56 -05:00
|
|
|
}
|
|
|
|
|
|
2023-05-25 21:01:48 -05:00
|
|
|
return jsonValue?.ToString();
|
2023-05-25 02:20:01 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
|
|
|
|
{
|
|
|
|
|
var objectType = value?.GetType();
|
|
|
|
|
object serializedValue;
|
|
|
|
|
|
|
|
|
|
if (objectType == typeof(uint))
|
|
|
|
|
serializedValue = BitConverter.GetBytes((uint)value);
|
|
|
|
|
else if (objectType == typeof(ulong))
|
|
|
|
|
serializedValue = BitConverter.GetBytes((ulong)value);
|
|
|
|
|
else
|
|
|
|
|
serializedValue = value?.ToString();
|
|
|
|
|
|
|
|
|
|
serializer.Serialize(writer, serializedValue);
|
|
|
|
|
}
|
|
|
|
|
}
|