diff --git a/BizHawk.Emulation.Cores/Computers/AppleII/LBSON.cs b/BizHawk.Emulation.Cores/Computers/AppleII/LBSON.cs index 76df21fa69..2265df2788 100644 --- a/BizHawk.Emulation.Cores/Computers/AppleII/LBSON.cs +++ b/BizHawk.Emulation.Cores/Computers/AppleII/LBSON.cs @@ -33,6 +33,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII String, F32, F64, + ByteArray, } public class LBR : JsonReader @@ -79,6 +80,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII case LBTOK.String: t = JsonToken.String; v = r.ReadString(); break; case LBTOK.F32: t = JsonToken.Float; v = r.ReadSingle(); break; case LBTOK.F64: t = JsonToken.Float; v = r.ReadDouble(); break; + case LBTOK.ByteArray: t = JsonToken.Bytes; v = r.ReadBytes(r.ReadInt32()); break; default: throw new InvalidOperationException(); @@ -88,7 +90,9 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII public override byte[] ReadAsBytes() { - throw new NotImplementedException(); + if (!Read() || t != JsonToken.Bytes) + return null; + return (byte[])v; } public override DateTime? ReadAsDateTime() @@ -193,6 +197,8 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII public override void WriteValue(float value) { WT(LBTOK.F32); w.Write(value); } public override void WriteValue(double value) { WT(LBTOK.F64); w.Write(value); } + public override void WriteValue(byte[] value) { WT(LBTOK.ByteArray); w.Write(value.Length); w.Write(value); } + public override void WriteComment(string text) { throw new NotImplementedException(); } public override void WriteWhitespace(string ws) { throw new NotImplementedException(); } protected override void WriteIndent() { throw new NotImplementedException(); } @@ -209,7 +215,6 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII public override void WriteValue(string value) { WT(LBTOK.String); w.Write(value); } public override void WritePropertyName(string name, bool escape) { WT(LBTOK.Property); w.Write(name); } // no escaping required - public override void WriteValue(byte[] value) { throw new NotImplementedException(); } public override void WriteValue(char value) { throw new NotImplementedException(); } public override void WriteValue(DateTime value) { throw new NotImplementedException(); } public override void WriteValue(DateTimeOffset value) { throw new NotImplementedException(); } diff --git a/ExternalCoreProjects/Virtu/ExtraConverters.cs b/ExternalCoreProjects/Virtu/ExtraConverters.cs index 2e66bfc438..bac21795b3 100644 --- a/ExternalCoreProjects/Virtu/ExtraConverters.cs +++ b/ExternalCoreProjects/Virtu/ExtraConverters.cs @@ -14,12 +14,69 @@ namespace Jellyfish.Virtu // JSON.NET cannot, when reading, use PreserveReferencesHandling on arrays, although it fully supports it on writing. // stupid decision, but there you have it. we need that to work here. - // as an added "bonus", this disables base64ing of byte[] arrays. - // TODO: optimize the byte/short/int cases. - // TODO: on serialization, the type of the object is available, but is the expected type (ie, the one that we'll be fed during deserialization) available? // need this to at least detect covariance cases... + private object ReadInternal(JsonReader reader, Type objectType, JsonSerializer serializer) + { + Type elementType = objectType.GetElementType(); + if (elementType.IsPrimitive) + { + if (!reader.Read()) + throw new InvalidOperationException(); + return bareserializer.Deserialize(reader, objectType); + } + else + { + int cap = 16; + Array ret = Array.CreateInstance(elementType, cap); + int used = 0; + + ReadExpectType(reader, JsonToken.StartArray); + + while (true) + { + if (!reader.Read()) + throw new InvalidOperationException(); + if (reader.TokenType == JsonToken.EndArray) + break; + ret.SetValue(serializer.Deserialize(reader, elementType), used++); + if (used == cap) + { + cap *= 2; + Array tmp = Array.CreateInstance(elementType, cap); + Array.Copy(ret, tmp, used); + ret = tmp; + } + } + if (used != cap) + { + Array tmp = Array.CreateInstance(elementType, used); + Array.Copy(ret, tmp, used); + ret = tmp; + } + return ret; + } + } + + private void WriteInternal(JsonWriter writer, object value, JsonSerializer serializer) + { + var elementType = value.GetType().GetElementType(); + if (elementType.IsPrimitive) + { + bareserializer.Serialize(writer, value); + } + else + { + writer.WriteStartArray(); + foreach (object o in (Array)value) + { + serializer.Serialize(writer, o, elementType); + } + writer.WriteEndArray(); + } + } + public override bool CanConvert(Type objectType) { if (!typeof(Array).IsAssignableFrom(objectType)) @@ -34,9 +91,7 @@ namespace Jellyfish.Virtu public override bool CanRead { get { return true; } } public override bool CanWrite { get { return true; } } - int nextRef = 1; - Dictionary refs = new Dictionary(); - Dictionary readrefs = new Dictionary(); + private JsonSerializer bareserializer = new JsonSerializer(); // full default settings, separate context private static void ReadExpectType(JsonReader reader, JsonToken expected) { @@ -48,72 +103,53 @@ namespace Jellyfish.Virtu public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { + object ret; if (reader.TokenType == JsonToken.Null) return null; - if (reader.TokenType != JsonToken.StartObject) + else if (reader.TokenType != JsonToken.StartObject) throw new InvalidOperationException(); ReadExpectType(reader, JsonToken.PropertyName); - if (reader.Value.ToString() != "$myRef") - throw new InvalidOperationException(); - ReadExpectType(reader, JsonToken.Integer); - int myRef = Convert.ToInt32(reader.Value); - - if (!reader.Read()) - throw new InvalidOperationException(); - if (reader.TokenType == JsonToken.EndObject) - return readrefs[myRef]; - else if (reader.TokenType != JsonToken.PropertyName || reader.Value.ToString() != "$myCount") - throw new InvalidOperationException(); - ReadExpectType(reader, JsonToken.Integer); - int myCount = Convert.ToInt32(reader.Value); - - ReadExpectType(reader, JsonToken.PropertyName); - if (reader.Value.ToString() != "$myVals") - throw new InvalidOperationException(); - ReadExpectType(reader, JsonToken.StartArray); - var elementType = objectType.GetElementType(); - Array ret = Array.CreateInstance(elementType, myCount); - for (int i = 0; i < myCount; i++) + string prop = reader.Value.ToString(); + ReadExpectType(reader, JsonToken.String); + string val = reader.Value.ToString(); + if (prop == "$ref") { - if (!reader.Read()) - throw new InvalidOperationException(); - ret.SetValue(serializer.Deserialize(reader, elementType), i); + ret = serializer.ReferenceResolver.ResolveReference(serializer, val); + ReadExpectType(reader, JsonToken.EndObject); + } + else if (prop == "$id") + { + ReadExpectType(reader, JsonToken.PropertyName); + if (reader.Value.ToString() != "$values") + throw new InvalidOperationException(); + ret = ReadInternal(reader, objectType, serializer); + ReadExpectType(reader, JsonToken.EndObject); + serializer.ReferenceResolver.AddReference(serializer, val, ret); + } + else + { + throw new InvalidOperationException(); } - ReadExpectType(reader, JsonToken.EndArray); - - ReadExpectType(reader, JsonToken.EndObject); - readrefs[myRef] = ret; return ret; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { - int myRef; - if (refs.TryGetValue(value, out myRef)) + if (serializer.ReferenceResolver.IsReferenced(serializer, value)) { writer.WriteStartObject(); - writer.WritePropertyName("$myRef"); - writer.WriteValue(myRef); + writer.WritePropertyName("$ref"); + writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value)); writer.WriteEndObject(); } else { - myRef = nextRef++; - refs.Add(value, myRef); writer.WriteStartObject(); - writer.WritePropertyName("$myRef"); - writer.WriteValue(myRef); - writer.WritePropertyName("$myCount"); // not needed, but avoids us having to make some sort of temp structure on deserialization - writer.WriteValue(((Array)value).Length); - writer.WritePropertyName("$myVals"); - writer.WriteStartArray(); - var elementType = value.GetType().GetElementType(); - foreach (object o in (Array)value) - { - serializer.Serialize(writer, o, elementType); - } - writer.WriteEndArray(); + writer.WritePropertyName("$id"); + writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value)); + writer.WritePropertyName("$values"); + WriteInternal(writer, value, serializer); writer.WriteEndObject(); } } diff --git a/References/Virtu.dll b/References/Virtu.dll index e718b8e167..1c24e33c1c 100644 Binary files a/References/Virtu.dll and b/References/Virtu.dll differ