AppleII: Savestate MegaFun. All existing savestates are obsoleted.

This commit is contained in:
goyuken 2015-05-19 01:20:35 +00:00
parent 0ca6faea01
commit 15b29de1c2
3 changed files with 96 additions and 55 deletions

View File

@ -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(); }

View File

@ -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<object, int> refs = new Dictionary<object, int>();
Dictionary<int, Array> readrefs = new Dictionary<int, Array>();
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();
}
}

Binary file not shown.