Удобно например для обмена массивами данных с сервером, без всяких XML/JSon (юзаем PHPSerializer.Serialize(array) - и вуаля).
- Код: Выделить всё
using UnityEngine;
using System;
using System.Text;
using System.Collections;
public class PHPSerializer : MonoBehaviour {
//types:
// s = string
// i = int
// d = double
// a = array (hashtable)
private ArrayList hashes; //for serialize (to infinte prevent loops)
private int pos; //for unserialize
public bool XMLSafe = true;
//This member tells the serializer wether or not to strip carriage returns from strings when serializing and adding them back in when deserializing
//http://www.w3.org/TR/REC-xml/#sec-line-ends
public string Serialize(object obj)
{
hashes = new ArrayList();
return serialize(obj).ToString();
}//Serialize(object obj)
private StringBuilder serialize(object obj)
{
StringBuilder sb = new StringBuilder();
if(obj == null)
{
return sb.Append("N;");
}
else if(obj is string)
{
string str = (string)obj;
if(XMLSafe)
{
str = str.Replace("\r\n","\n");//replace \r\n with \n
str = str.Replace("\r", "\n");//replace \r not followed by \n with a single \n Should we do this?
}
return sb.Append("s:" + str.Length + ":\"" + str + "\";");
}
else if(obj is bool)
{
return sb.Append("b:" + (((bool)obj) ? "1" : "0") + ";");
}
else if(obj is int)
{
int i = (int)obj;
return sb.Append("i:" + i + ";");
}
else if(obj is double)
{
double d = (double)obj;
return sb.Append("d:" + d + ";");
}
else if(obj is ArrayList)
{
if(hashes.Contains(obj.GetHashCode()))
return sb.Append("N;");
else
hashes.Add(obj.GetHashCode());
ArrayList a = (ArrayList)obj;
sb.Append("a:" + a.Count + ":{");
for(int i = 0; i < a.Count; i++)
{
sb.Append(serialize(i));
sb.Append(serialize(a[i]));
}
sb.Append("}");
return sb;
}
else if(obj is Hashtable)
{
if(hashes.Contains(obj.GetHashCode()))
return sb.Append("N;");
else
hashes.Add(obj.GetHashCode());
Hashtable a = (Hashtable)obj;
sb.Append("a:" + a.Count + ":{");
foreach(DictionaryEntry entry in a)
{
sb.Append(serialize(entry.Key));
sb.Append(serialize(entry.Value));
}
sb.Append("}");
return sb;
}
else
{
return sb;
}
}//Serialize(object obj)
public object Unserialize(string str)
{
pos = 0;
return unserialize(str);
}//Unserialize(string str)
private object unserialize(string str)
{
if(str == null || str.Length <= pos)
return new object();
int start, end, length;
string stLen;
switch(str[pos])
{
case 'N':
pos += 2;
return null;
case 'b':
char chBool;
chBool = str[pos + 2];
pos += 4;
return chBool == '1';
case 'i':
string stInt;
start = str.IndexOf(":", pos) + 1;
end = str.IndexOf(";", start);
stInt = str.Substring(start, end - start);
pos += 3 + stInt.Length;
return Int32.Parse(stInt);
case 'd':
string stDouble;
start = str.IndexOf(":", pos) + 1;
end = str.IndexOf(";", start);
stDouble = str.Substring(start, end - start);
pos += 3 + stDouble.Length;
return Double.Parse(stDouble);
case 's':
//TODO: add bounds checking code
start = str.IndexOf(":", pos) + 1;
end = str.IndexOf(":", start);
stLen = str.Substring(start, end - start);
length = Int32.Parse(stLen);
pos += 6 + stLen.Length + length;
string stRet = str.Substring(end + 2, length);
if(XMLSafe)
{
stRet = stRet.Replace("\n", "\r\n");
}
return stRet;
case 'a':
//if keys are ints 0 through N, returns an ArrayList, else returns Hashtable
start = str.IndexOf(":", pos) + 1;
end = str.IndexOf(":", start);
stLen = str.Substring(start, end - start);
length = Int32.Parse(stLen);
Hashtable htRet = new Hashtable(length);
ArrayList alRet = new ArrayList(length);
pos += 4 + stLen.Length; //a:Len:{
for(int i = 0; i < length; i++)
{
//read key
object key = unserialize(str);
//read value
object val = unserialize(str);
if(alRet != null)
{
if(key is int && (int)key == alRet.Count)
alRet.Add(val);
else
alRet = null;
}
htRet[key] = val;
}
pos++; //skip the }
if(pos < str.Length && str[pos] == ';')//skipping our old extra array semi-colon bug (er... php's weirdness)
pos++;
if(alRet != null)
return alRet;
else
return htRet;
default:
return "";
}//switch
}//unserialzie(object)
public void TestSerialize()
{
string errors = "";
if(Serialize(false) != "b:0;")
errors += "serialize bool failed, ";
if(Serialize(1) != "i:1;")
errors += "serialize int failed, ";
if(Serialize(3.14159) != "d:3.14159;")
errors += "serialize double failed, ";
if(Serialize("hello world") != "s:11:\"hello world\";")
errors += "serialize string failed, ";
Hashtable ht = new Hashtable();
ht.Add(0, "zero");
string target = "a:1:{i:0;s:4:\"zero\";};";
string result = Serialize(ht);
if(result != target)
errors += "serialize array failed, ";
if(Serialize("hello world") != "s:11:\"hello world\";")
errors += "serialize string failed, ";
if(errors.Length != 0)
throw new Exception(errors);
}
public void TestUnserialize()
{
if(((string)Unserialize("s:11:\"hello world\";")) != "hello world")
throw new Exception("unserialize failed");
}
public void TestComplex()
{
string errors = "";
Hashtable ht = new Hashtable();
ht.Add(0, false);
ht.Add(1, 1.5);
ht.Add(2, "two");
ht.Add("self", ht);
string result = Serialize(ht);
Hashtable unht = (Hashtable)Unserialize(result);
if((bool)unht[0] != false
|| (double)unht[1] != 1.5
|| (string)unht[2] != "two"
|| unht["self"] != null)
errors += "serialize complex failed, ";
if(errors.Length != 0)
throw new Exception(errors);
}
}