From 8cbaf6304ab046e35b5b38a104f41f9e30de990e Mon Sep 17 00:00:00 2001 From: goyuken Date: Tue, 19 May 2015 21:39:29 +0000 Subject: [PATCH] clean up array handling in apple 2 savestates --- ExternalCoreProjects/Virtu/ExtraConverters.cs | 143 +++++++++--------- References/Virtu.dll | Bin 146432 -> 146432 bytes 2 files changed, 72 insertions(+), 71 deletions(-) diff --git a/ExternalCoreProjects/Virtu/ExtraConverters.cs b/ExternalCoreProjects/Virtu/ExtraConverters.cs index 19c66eb7ba..743fe4bef9 100644 --- a/ExternalCoreProjects/Virtu/ExtraConverters.cs +++ b/ExternalCoreProjects/Virtu/ExtraConverters.cs @@ -12,71 +12,13 @@ namespace Jellyfish.Virtu public class ArrayConverter : JsonConverter { // 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. + // Doing so while being able to fully preserve circular references would require storing the length of the array, + // or reading ahead in the JSON to compute the length. For arrays that could contain reference types, we choose the latter. + // For arrays of primitive types, there is no issue. // 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)) @@ -103,7 +45,6 @@ namespace Jellyfish.Virtu public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { - object ret; if (reader.TokenType == JsonToken.Null) return null; else if (reader.TokenType != JsonToken.StartObject) @@ -112,26 +53,63 @@ namespace Jellyfish.Virtu ReadExpectType(reader, JsonToken.PropertyName); string prop = reader.Value.ToString(); ReadExpectType(reader, JsonToken.String); - string val = reader.Value.ToString(); + string id = reader.Value.ToString(); if (prop == "$ref") { - ret = serializer.ReferenceResolver.ResolveReference(serializer, val); + object ret = serializer.ReferenceResolver.ResolveReference(serializer, id); ReadExpectType(reader, JsonToken.EndObject); + return ret; } else if (prop == "$id") { ReadExpectType(reader, JsonToken.PropertyName); - if (reader.Value.ToString() != "$values") + prop = reader.Value.ToString(); + if (prop == "$length") // complex array + { + ReadExpectType(reader, JsonToken.Integer); + int length = Convert.ToInt32(reader.Value); + ReadExpectType(reader, JsonToken.PropertyName); + if (reader.Value.ToString() != "$values") + throw new InvalidOperationException(); + + Type elementType = objectType.GetElementType(); + + Array ret = Array.CreateInstance(elementType, length); + // must register reference before deserializing elements to handle possible circular references + serializer.ReferenceResolver.AddReference(serializer, id, ret); + int index = 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), index++); + } + ReadExpectType(reader, JsonToken.EndObject); + return ret; + } + else if (prop == "$values") // simple array + { + if (!reader.Read()) + throw new InvalidOperationException(); + object ret = bareserializer.Deserialize(reader, objectType); + // OK to add this after deserializing, as arrays of primitive types can't contain backrefs + serializer.ReferenceResolver.AddReference(serializer, id, ret); + ReadExpectType(reader, JsonToken.EndObject); + return ret; + } + else + { throw new InvalidOperationException(); - ret = ReadInternal(reader, objectType, serializer); - ReadExpectType(reader, JsonToken.EndObject); - serializer.ReferenceResolver.AddReference(serializer, val, ret); + } } else { throw new InvalidOperationException(); } - return ret; } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) @@ -139,17 +117,40 @@ namespace Jellyfish.Virtu if (serializer.ReferenceResolver.IsReferenced(serializer, value)) { writer.WriteStartObject(); + writer.WritePropertyName("$ref"); writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value)); + writer.WriteEndObject(); } else { writer.WriteStartObject(); + writer.WritePropertyName("$id"); writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value)); - writer.WritePropertyName("$values"); - WriteInternal(writer, value, serializer); + + var elementType = value.GetType().GetElementType(); + if (elementType.IsPrimitive) + { + writer.WritePropertyName("$values"); + bareserializer.Serialize(writer, value); + } + else + { + var array = (Array)value; + writer.WritePropertyName("$length"); + writer.WriteValue(array.Length); + + writer.WritePropertyName("$values"); + writer.WriteStartArray(); + foreach (object o in array) + { + serializer.Serialize(writer, o, elementType); + } + writer.WriteEndArray(); + } + writer.WriteEndObject(); } } diff --git a/References/Virtu.dll b/References/Virtu.dll index 1c24e33c1c3cbc2f10f83ec479c5ce6da3fd1514..8ead617deea02ecb4a0f4c44d466c7acb1b1057f 100644 GIT binary patch delta 8289 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