AppleII: Savestate MegaFun. All existing savestates are obsoleted.
This commit is contained in:
parent
0ca6faea01
commit
15b29de1c2
|
@ -33,6 +33,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
|
||||||
String,
|
String,
|
||||||
F32,
|
F32,
|
||||||
F64,
|
F64,
|
||||||
|
ByteArray,
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LBR : JsonReader
|
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.String: t = JsonToken.String; v = r.ReadString(); break;
|
||||||
case LBTOK.F32: t = JsonToken.Float; v = r.ReadSingle(); break;
|
case LBTOK.F32: t = JsonToken.Float; v = r.ReadSingle(); break;
|
||||||
case LBTOK.F64: t = JsonToken.Float; v = r.ReadDouble(); break;
|
case LBTOK.F64: t = JsonToken.Float; v = r.ReadDouble(); break;
|
||||||
|
case LBTOK.ByteArray: t = JsonToken.Bytes; v = r.ReadBytes(r.ReadInt32()); break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
|
@ -88,7 +90,9 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
|
||||||
|
|
||||||
public override byte[] ReadAsBytes()
|
public override byte[] ReadAsBytes()
|
||||||
{
|
{
|
||||||
throw new NotImplementedException();
|
if (!Read() || t != JsonToken.Bytes)
|
||||||
|
return null;
|
||||||
|
return (byte[])v;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override DateTime? ReadAsDateTime()
|
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(float value) { WT(LBTOK.F32); w.Write(value); }
|
||||||
public override void WriteValue(double value) { WT(LBTOK.F64); 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 WriteComment(string text) { throw new NotImplementedException(); }
|
||||||
public override void WriteWhitespace(string ws) { throw new NotImplementedException(); }
|
public override void WriteWhitespace(string ws) { throw new NotImplementedException(); }
|
||||||
protected override void WriteIndent() { 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 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 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(char value) { throw new NotImplementedException(); }
|
||||||
public override void WriteValue(DateTime value) { throw new NotImplementedException(); }
|
public override void WriteValue(DateTime value) { throw new NotImplementedException(); }
|
||||||
public override void WriteValue(DateTimeOffset value) { throw new NotImplementedException(); }
|
public override void WriteValue(DateTimeOffset value) { throw new NotImplementedException(); }
|
||||||
|
|
|
@ -14,12 +14,69 @@ namespace Jellyfish.Virtu
|
||||||
// JSON.NET cannot, when reading, use PreserveReferencesHandling on arrays, although it fully supports it on writing.
|
// 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.
|
// 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?
|
// 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...
|
// 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)
|
public override bool CanConvert(Type objectType)
|
||||||
{
|
{
|
||||||
if (!typeof(Array).IsAssignableFrom(objectType))
|
if (!typeof(Array).IsAssignableFrom(objectType))
|
||||||
|
@ -34,9 +91,7 @@ namespace Jellyfish.Virtu
|
||||||
public override bool CanRead { get { return true; } }
|
public override bool CanRead { get { return true; } }
|
||||||
public override bool CanWrite { get { return true; } }
|
public override bool CanWrite { get { return true; } }
|
||||||
|
|
||||||
int nextRef = 1;
|
private JsonSerializer bareserializer = new JsonSerializer(); // full default settings, separate context
|
||||||
Dictionary<object, int> refs = new Dictionary<object, int>();
|
|
||||||
Dictionary<int, Array> readrefs = new Dictionary<int, Array>();
|
|
||||||
|
|
||||||
private static void ReadExpectType(JsonReader reader, JsonToken expected)
|
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)
|
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
|
object ret;
|
||||||
if (reader.TokenType == JsonToken.Null)
|
if (reader.TokenType == JsonToken.Null)
|
||||||
return null;
|
return null;
|
||||||
if (reader.TokenType != JsonToken.StartObject)
|
else if (reader.TokenType != JsonToken.StartObject)
|
||||||
throw new InvalidOperationException();
|
throw new InvalidOperationException();
|
||||||
|
|
||||||
ReadExpectType(reader, JsonToken.PropertyName);
|
ReadExpectType(reader, JsonToken.PropertyName);
|
||||||
if (reader.Value.ToString() != "$myRef")
|
string prop = reader.Value.ToString();
|
||||||
throw new InvalidOperationException();
|
ReadExpectType(reader, JsonToken.String);
|
||||||
ReadExpectType(reader, JsonToken.Integer);
|
string val = reader.Value.ToString();
|
||||||
int myRef = Convert.ToInt32(reader.Value);
|
if (prop == "$ref")
|
||||||
|
|
||||||
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++)
|
|
||||||
{
|
{
|
||||||
if (!reader.Read())
|
ret = serializer.ReferenceResolver.ResolveReference(serializer, val);
|
||||||
throw new InvalidOperationException();
|
ReadExpectType(reader, JsonToken.EndObject);
|
||||||
ret.SetValue(serializer.Deserialize(reader, elementType), i);
|
}
|
||||||
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
|
||||||
{
|
{
|
||||||
int myRef;
|
if (serializer.ReferenceResolver.IsReferenced(serializer, value))
|
||||||
if (refs.TryGetValue(value, out myRef))
|
|
||||||
{
|
{
|
||||||
writer.WriteStartObject();
|
writer.WriteStartObject();
|
||||||
writer.WritePropertyName("$myRef");
|
writer.WritePropertyName("$ref");
|
||||||
writer.WriteValue(myRef);
|
writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value));
|
||||||
writer.WriteEndObject();
|
writer.WriteEndObject();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
myRef = nextRef++;
|
|
||||||
refs.Add(value, myRef);
|
|
||||||
writer.WriteStartObject();
|
writer.WriteStartObject();
|
||||||
writer.WritePropertyName("$myRef");
|
writer.WritePropertyName("$id");
|
||||||
writer.WriteValue(myRef);
|
writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value));
|
||||||
writer.WritePropertyName("$myCount"); // not needed, but avoids us having to make some sort of temp structure on deserialization
|
writer.WritePropertyName("$values");
|
||||||
writer.WriteValue(((Array)value).Length);
|
WriteInternal(writer, value, serializer);
|
||||||
writer.WritePropertyName("$myVals");
|
|
||||||
writer.WriteStartArray();
|
|
||||||
var elementType = value.GetType().GetElementType();
|
|
||||||
foreach (object o in (Array)value)
|
|
||||||
{
|
|
||||||
serializer.Serialize(writer, o, elementType);
|
|
||||||
}
|
|
||||||
writer.WriteEndArray();
|
|
||||||
writer.WriteEndObject();
|
writer.WriteEndObject();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Binary file not shown.
Loading…
Reference in New Issue