using System.Collections;
using System.IO;
using System.Text;
using System.Globalization;
using System;
namespace Tools
{
/// <exclude/>
public class Serialiser
{
const string Version="4.5";
/// <exclude/>
public void VersionCheck()
{
if (Encode)
Serialise(Version);
else
{
string version=Deserialise() as string;
if (version==null)
throw new Exception("Serialisation error - found data from version 4.4 or earlier");
else if (version!=Version)
throw new Exception("Serialisation error - expected version "+Version+", found data from version "+version);
}
}
enum SerType
{
Null, Int, Bool, Char, String, Hashtable, Encoding,
UnicodeCategory, Symtype,
Charset, TokClassDef, Action, Dfa,
ResWds, // 4.7
ParserOldAction, ParserSimpleAction, ParserShift, ParserReduce, ParseState,
ParsingInfo, CSymbol, Literal, Production, EOF };
delegate object ObjectSerialiser(object o,Serialiser s);
static Serialiser()
{
srs[SerType.Null] = new ObjectSerialiser(NullSerialise);
tps[typeof(int)] = SerType.Int; srs[SerType.Int] = new ObjectSerialiser(IntSerialise);
tps[typeof(string)] = SerType.String; srs[SerType.String] = new ObjectSerialiser(StringSerialise);
tps[typeof(Hashtable)] = SerType.Hashtable; srs[SerType.Hashtable] = new ObjectSerialiser(HashtableSerialise);
tps[typeof(char)] = SerType.Char; srs[SerType.Char] = new ObjectSerialiser(CharSerialise);
tps[typeof(bool)] = SerType.Bool; srs[SerType.Bool] = new ObjectSerialiser(BoolSerialise);
tps[typeof(Encoding)] = SerType.Encoding; srs[SerType.Encoding] = new ObjectSerialiser(EncodingSerialise);
tps[typeof(UnicodeCategory)] = SerType.UnicodeCategory; srs[SerType.UnicodeCategory] = new ObjectSerialiser(UnicodeCategorySerialise);
tps[typeof(CSymbol.SymType)] = SerType.Symtype; srs[SerType.Symtype] = new ObjectSerialiser(SymtypeSerialise);
tps[typeof(Charset)] = SerType.Charset; srs[SerType.Charset] = new ObjectSerialiser(Charset.Serialise);
tps[typeof(TokClassDef)] = SerType.TokClassDef; srs[SerType.TokClassDef] = new ObjectSerialiser(TokClassDef.Serialise);
tps[typeof(Dfa)] = SerType.Dfa; srs[SerType.Dfa] = new ObjectSerialiser(Dfa.Serialise);
tps[typeof(ResWds)] = SerType.ResWds; srs[SerType.ResWds] = new ObjectSerialiser(ResWds.Serialise); // 4.7
tps[typeof(Dfa.Action)] = SerType.Action; srs[SerType.Action] = new ObjectSerialiser(Dfa.Action.Serialise);
tps[typeof(ParserOldAction)] = SerType.ParserOldAction; srs[SerType.ParserOldAction] = new ObjectSerialiser(ParserOldAction.Serialise);
tps[typeof(ParserSimpleAction)] = SerType.ParserSimpleAction; srs[SerType.ParserSimpleAction] = new ObjectSerialiser(ParserSimpleAction.Serialise);
tps[typeof(ParserShift)] = SerType.ParserShift; srs[SerType.ParserShift] = new ObjectSerialiser(ParserShift.Serialise);
tps[typeof(ParserReduce)] = SerType.ParserReduce; srs[SerType.ParserReduce] = new ObjectSerialiser(ParserReduce.Serialise);
tps[typeof(ParseState)] = SerType.ParseState; srs[SerType.ParseState] = new ObjectSerialiser(ParseState.Serialise);
tps[typeof(ParsingInfo)] = SerType.ParsingInfo; srs[SerType.ParsingInfo] = new ObjectSerialiser(ParsingInfo.Serialise);
tps[typeof(CSymbol)] = SerType.CSymbol; srs[SerType.CSymbol] = new ObjectSerialiser(CSymbol.Serialise);
tps[typeof(Literal)] = SerType.Literal; srs[SerType.Literal] = new ObjectSerialiser(Literal.Serialise);
tps[typeof(Production)] = SerType.Production; srs[SerType.Production] = new ObjectSerialiser(Production.Serialise);
tps[typeof(EOF)] = SerType.EOF; srs[SerType.EOF] = new ObjectSerialiser(EOF.Serialise);
}
// on Encode, we ignore the return value which is always null
// Otherwise, o if non-null is an instance of the subclass
TextWriter f = null;
int[] b = null;
int pos = 0;
Hashtable obs = new Hashtable(); // object->int (code) or int->object (decode)
static Hashtable tps = new Hashtable(); // type->SerType
static Hashtable srs = new Hashtable(); // SerType->ObjectSerialiser
int id = 100;
int cl = 0;
/// <exclude/>
public Serialiser(TextWriter ff)
{
f = ff;
}
/// <exclude/>
public Serialiser(int[] bb)
{
b = bb;
}
/// <exclude/>
public bool Encode { get { return f!=null; }}
void _Write(SerType t)
{
_Write((int)t);
}
/// <exclude/>
public void _Write(int i)
{
if (cl==5)
{
f.WriteLine();
cl = 0;
}
cl++;
f.Write(i);
f.Write(",");
}
/// <exclude/>
public int _Read()
{
return b[pos++];
}
static object NullSerialise(object o,Serialiser s)
{
return null;
}
static object IntSerialise(object o,Serialiser s)
{
if (s.Encode)
{
s._Write((int)o);
return null;
}
return s._Read();
}
static object StringSerialise(object o,Serialiser s)
{
if (s==null)
return "";
Encoding e = new UnicodeEncoding();
if (s.Encode)
{
byte[] b = e.GetBytes((string)o);
s._Write(b.Length);
for (int j=0;j<b.Length;j++)
s._Write((int)b[j]);
return null;
}
int ln = s._Read();
byte[] bb = new byte[ln];
for (int k=0;k<ln;k++)
bb[k] = (byte)s._Read();
string r = e.GetString(bb,0,ln);
return r;
}
static object HashtableSerialise(object o,Serialiser s)
{
if (s==null)
return new Hashtable();
Hashtable h = (Hashtable)o;
if (s.Encode)
{
s._Write(h.Count);
foreach (DictionaryEntry d in h)
{
s.Serialise(d.Key);
s.Serialise(d.Value);
}
return null;
}
int ct = s._Read();
for (int j=0;j<ct;j++)
{
object k = s.Deserialise();
object v = s.Deserialise();
h[k] = v;
}
return h;
}
static object CharSerialise(object o,Serialiser s)
{
Encoding e = new UnicodeEncoding();
if (s.Encode)
{
byte[] b = e.GetBytes(new string((char)o,1));
s._Write((int)b[0]);
s._Write((int)b[1]);
return null;
}
byte[] bb = new byte[2];
bb[0] = (byte)s._Read();
bb[1] = (byte)s._Read();
string r = e.GetString(bb,0,2);
return r[0];
}
static object BoolSerialise(object o,Serialiser s)
{
if (s.Encode)
{
s._Write(((bool)o)?1:0);
return null;
}
int v = s._Read();
return v!=0;
}
static object EncodingSerialise(object o,Serialiser s)
{
if (s.Encode)
{
Encoding e = (Encoding)o;
s.Serialise(e.WebName);
return null;
}
switch((string)s.Deserialise())
{
case "us-ascii": return Encoding.ASCII;
case "utf-16": return Encoding.Unicode;
case "utf-7": return Encoding.UTF7;
case "utf-8": return Encoding.UTF8;
}
throw new Exception("Unknown encoding");
}
static object UnicodeCategorySerialise(object o,Serialiser s)
{
if (s.Encode)
{
s._Write((int)o);
return null;
}
return (UnicodeCategory)s._Read();
}
static object SymtypeSerialise(object o,Serialiser s)
{
if (s.Encode)
{
s._Write((int)o);
return null;
}
return (CSymbol.SymType)s._Read();
}
/// <exclude/>
public void Serialise(object o)
{
if (o==null)
{
_Write(SerType.Null);
return;
}
if (o is Encoding)
{
_Write(SerType.Encoding);
EncodingSerialise(o,this);
return;
}
Type t = o.GetType();
if (t.IsClass)
{
object p = obs[o];
if (p!=null)
{
_Write((int)p);
return;
}
else
{
int e = ++id;
_Write(e);
obs[o] = e;
}
}
object so = tps[t];
if (so!=null)
{
SerType s = (SerType)so;
_Write(s);
ObjectSerialiser os = (ObjectSerialiser)srs[s];
os(o,this);
}
else
throw new Exception("unknown type "+t.FullName);
}
/// <exclude/>
public object Deserialise()
{
int t = _Read();
int u = 0;
if (t>100)
{
u = t;
if (u<=obs.Count+100)
return obs[u];
t = _Read();
}
ObjectSerialiser os = (ObjectSerialiser)srs[(SerType)t];
if (os!=null)
{
if (u>0)
{ // ?? strange bug in mono: workaround in CSTools 4.5a leads to not chaining assignments here
object r = os(null,null); // allow for recursive structures: create and store first
obs[u] = r;
r = os(r,this); // really deserialise it
obs[u] = r; // we need to store it again for strings
return r;
}
return os(null,this);
}
else
throw new Exception("unknown type "+t);
}
}
/* public class Test
{
static string curline = "";
static int pos = 0;
static bool EOF = false;
static void GetLine(TextReader f)
{
curline = f.ReadLine();
pos = 0;
if (curline == null)
EOF = true;
}
static int GetInt(TextReader f)
{
int v = 0;
bool s = false;
while (pos<curline.Length)
{
char c = curline[pos++];
if (c==' ')
continue;
if (c=='-')
{
s = true;
continue;
}
if (c==',')
{
if (s)
v = -v;
if (pos==curline.Length)
GetLine(f);
return v;
}
if (c>='0' && c<='9')
{
v = v*10 + (c-'0');
continue;
}
throw new Exception("illegal character");
}
throw new Exception("bad line");
}
public static void Main(string[] args)
{
TextWriter x = new StreamWriter("out.txt");
Hashtable t = new Hashtable();
t["John"] = 12;
t["Mary"] = 34;
Serialiser sr = new Serialiser(x);
Console.WriteLine("Encoding");
sr.Serialise(t);
x.Close();
ArrayList a = new ArrayList();
TextReader y = new StreamReader("out.txt");
GetLine(y);
while (!EOF)
a.Add(GetInt(y));
y.Close();
for (int k=0;k<a.Count;k++)
Console.WriteLine((int)a[k]);
int[] b = new int[a.Count];
for (int k=0;k<a.Count;k++)
b[k] = (int)a[k];
Serialiser dr = new Serialiser(b);
Hashtable h = (Hashtable)dr.Deserialise();
foreach (DictionaryEntry d in h)
Console.WriteLine((string)d.Key + "->" + (int)d.Value);
}
} */
}