using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices; using Newtonsoft.Json; namespace BizHawk.Emulation.Common { // managed counterpart to unmanaged serialization code in GB and WSWAN cores // T is a class that has any other data you want to serialize in it public class TextState where T : new() { public TextState() { ExtraData = new T(); } public class Node { public Dictionary Data = new Dictionary(); public Dictionary Objects = new Dictionary(); } public Node Root = new Node(); [JsonIgnore] Stack Nodes; [JsonIgnore] Node Current { get { return Nodes.Peek(); } } public void Prepare() { Nodes = new Stack(); Nodes.Push(Root); } public void Save(IntPtr data, int length, string name) { byte[] d = new byte[length]; Marshal.Copy(data, d, 0, length); Current.Data.Add(name, d); // will except for us if the key is already present } public void Load(IntPtr data, int length, string name) { byte[] d = Current.Data[name]; if (length != d.Length) throw new InvalidOperationException(); Marshal.Copy(d, 0, data, length); } public void EnterSectionSave(string name) { Node next = new Node(); Current.Objects.Add(name, next); Nodes.Push(next); } public void EnterSectionLoad(string name) { Node next = Current.Objects[name]; Nodes.Push(next); } public void EnterSection(string name) { // works for either save or load, but as a consequence cannot report intelligent // errors about section name mismatches Node next = null; Current.Objects.TryGetValue(name, out next); if (next == null) { next = new Node(); Current.Objects.Add(name, next); } Nodes.Push(next); } public void ExitSection(string name) { Node last = Nodes.Pop(); if (Current.Objects[name] != last) throw new InvalidOperationException(); } // other data besides the core public T ExtraData; public TextStateFPtrs GetFunctionPointersSave() { return new TextStateFPtrs { Save = new TextStateFPtrs.DataFunction(Save), Load = null, EnterSection = new TextStateFPtrs.SectionFunction(EnterSectionSave), ExitSection = new TextStateFPtrs.SectionFunction(ExitSection) }; } public TextStateFPtrs GetFunctionPointersLoad() { return new TextStateFPtrs { Save = null, Load = new TextStateFPtrs.DataFunction(Load), EnterSection = new TextStateFPtrs.SectionFunction(EnterSectionLoad), ExitSection = new TextStateFPtrs.SectionFunction(ExitSection) }; } } [StructLayout(LayoutKind.Sequential)] public struct TextStateFPtrs { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void DataFunction(IntPtr data, int length, string name); [UnmanagedFunctionPointer(CallingConvention.Cdecl)] public delegate void SectionFunction(string name); public DataFunction Save; public DataFunction Load; public SectionFunction EnterSection; public SectionFunction ExitSection; } }