Skip to content

Instantly share code, notes, and snippets.

@xiangwan
Created September 19, 2011 04:50
Show Gist options
  • Save xiangwan/1225981 to your computer and use it in GitHub Desktop.
Save xiangwan/1225981 to your computer and use it in GitHub Desktop.

Revisions

  1. 向晚 renamed this gist May 29, 2012. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  2. 向晚 revised this gist Sep 19, 2011. 1 changed file with 205 additions and 0 deletions.
    205 changes: 205 additions & 0 deletions C php Serializer.cs
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,205 @@
    /// <summary>
    /// Serializer Class.
    /// </summary>
    public class Serializer
    {
    //types:
    // N = null
    // s = string
    // i = int
    // d = double
    // a = array (hashtable)

    private Dictionary<Hashtable, bool> seenHashtables; //for serialize (to infinte prevent loops)
    private Dictionary<ArrayList, bool> seenArrayLists; //for serialize (to infinte prevent loops) lol

    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 Encoding StringEncoding = new System.Text.UTF8Encoding();

    private System.Globalization.NumberFormatInfo nfi;

    public Serializer()
    {
    this.nfi = new System.Globalization.NumberFormatInfo();
    this.nfi.NumberGroupSeparator = "";
    this.nfi.NumberDecimalSeparator = ".";
    }

    public string Serialize(object obj)
    {
    this.seenArrayLists = new Dictionary<ArrayList, bool>();
    this.seenHashtables = new Dictionary<Hashtable, bool>();

    return this.serialize(obj, new StringBuilder()).ToString();
    }//Serialize(object obj)

    private StringBuilder serialize(object obj, StringBuilder sb)
    {
    if (obj == null)
    {
    return sb.Append("N;");
    }
    else if (obj is string)
    {
    string str = (string)obj;
    if (this.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:" + this.StringEncoding.GetByteCount(str) + ":\"" + 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.ToString(this.nfi) + ";");
    }
    else if (obj is double)
    {
    double d = (double)obj;

    return sb.Append("d:" + d.ToString(this.nfi) + ";");
    }
    else if (obj is ArrayList)
    {
    if (this.seenArrayLists.ContainsKey((ArrayList)obj))
    return sb.Append("N;");//cycle detected
    else
    this.seenArrayLists.Add((ArrayList)obj, true);

    ArrayList a = (ArrayList)obj;
    sb.Append("a:" + a.Count + ":{");
    for (int i = 0; i < a.Count; i++)
    {
    this.serialize(i, sb);
    this.serialize(a[i], sb);
    }
    sb.Append("}");
    return sb;
    }
    else if (obj is Hashtable)
    {
    if (this.seenHashtables.ContainsKey((Hashtable)obj))
    return sb.Append("N;");//cycle detected
    else
    this.seenHashtables.Add((Hashtable)obj, true);

    Hashtable a = (Hashtable)obj;
    sb.Append("a:" + a.Count + ":{");
    foreach (DictionaryEntry entry in a)
    {
    this.serialize(entry.Key, sb);
    this.serialize(entry.Value, sb);
    }
    sb.Append("}");
    return sb;
    }
    else
    {
    return sb;
    }
    }//Serialize(object obj)

    public object Deserialize(string str)
    {
    this.pos = 0;
    return deserialize(str);
    }//Deserialize(string str)

    private object deserialize(string str)
    {
    if (str == null || str.Length <= this.pos)
    return new Object();

    int start, end, length;
    string stLen;
    switch (str[this.pos])
    {
    case 'N':
    this.pos += 2;
    return null;
    case 'b':
    char chBool;
    chBool = str[pos + 2];
    this.pos += 4;
    return chBool == '1';
    case 'i':
    string stInt;
    start = str.IndexOf(":", this.pos) + 1;
    end = str.IndexOf(";", start);
    stInt = str.Substring(start, end - start);
    this.pos += 3 + stInt.Length;
    return Int32.Parse(stInt, this.nfi);
    case 'd':
    string stDouble;
    start = str.IndexOf(":", this.pos) + 1;
    end = str.IndexOf(";", start);
    stDouble = str.Substring(start, end - start);
    this.pos += 3 + stDouble.Length;
    return Double.Parse(stDouble, this.nfi);
    case 's':
    start = str.IndexOf(":", this.pos) + 1;
    end = str.IndexOf(":", start);
    stLen = str.Substring(start, end - start);
    int bytelen = Int32.Parse(stLen);
    length = bytelen;
    //This is the byte length, not the character length - so we migth
    //need to shorten it before usage. This also implies bounds checking
    if ((end + 2 + length) >= str.Length) length = str.Length - 2 - end;
    string stRet = str.Substring(end + 2, length);
    while (this.StringEncoding.GetByteCount(stRet) > bytelen)
    {
    length--;
    stRet = str.Substring(end + 2, length);
    }
    this.pos += 6 + stLen.Length + length;
    if (this.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(":", this.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);
    this.pos += 4 + stLen.Length; //a:Len:{
    for (int i = 0; i < length; i++)
    {
    //read key
    object key = deserialize(str);
    //read value
    object val = deserialize(str);

    if (alRet != null)
    {
    if (key is int && (int)key == alRet.Count)
    alRet.Add(val);
    else
    alRet = null;
    }
    htRet[key] = val;
    }
    this.pos++; //skip the }
    if (this.pos < str.Length && str[this.pos] == ';')//skipping our old extra array semi-colon bug (er... php's weirdness)
    this.pos++;
    if (alRet != null)
    return alRet;
    else
    return htRet;
    default:
    return "";
    }//switch
    }//unserialzie(object)
    }//class Serializer
  3. 向晚 created this gist Sep 19, 2011.
    206 changes: 206 additions & 0 deletions C# php Serializer
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,206 @@

    /// <summary>
    /// Serializer Class.
    /// </summary>
    public class Serializer
    {
    //types:
    // N = null
    // s = string
    // i = int
    // d = double
    // a = array (hashtable)

    private Dictionary<Hashtable, bool> seenHashtables; //for serialize (to infinte prevent loops)
    private Dictionary<ArrayList, bool> seenArrayLists; //for serialize (to infinte prevent loops) lol

    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 Encoding StringEncoding = new System.Text.UTF8Encoding();

    private System.Globalization.NumberFormatInfo nfi;

    public Serializer()
    {
    this.nfi = new System.Globalization.NumberFormatInfo();
    this.nfi.NumberGroupSeparator = "";
    this.nfi.NumberDecimalSeparator = ".";
    }

    public string Serialize(object obj)
    {
    this.seenArrayLists = new Dictionary<ArrayList, bool>();
    this.seenHashtables = new Dictionary<Hashtable, bool>();

    return this.serialize(obj, new StringBuilder()).ToString();
    }//Serialize(object obj)

    private StringBuilder serialize(object obj, StringBuilder sb)
    {
    if (obj == null)
    {
    return sb.Append("N;");
    }
    else if (obj is string)
    {
    string str = (string)obj;
    if (this.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:" + this.StringEncoding.GetByteCount(str) + ":\"" + 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.ToString(this.nfi) + ";");
    }
    else if (obj is double)
    {
    double d = (double)obj;

    return sb.Append("d:" + d.ToString(this.nfi) + ";");
    }
    else if (obj is ArrayList)
    {
    if (this.seenArrayLists.ContainsKey((ArrayList)obj))
    return sb.Append("N;");//cycle detected
    else
    this.seenArrayLists.Add((ArrayList)obj, true);

    ArrayList a = (ArrayList)obj;
    sb.Append("a:" + a.Count + ":{");
    for (int i = 0; i < a.Count; i++)
    {
    this.serialize(i, sb);
    this.serialize(a[i], sb);
    }
    sb.Append("}");
    return sb;
    }
    else if (obj is Hashtable)
    {
    if (this.seenHashtables.ContainsKey((Hashtable)obj))
    return sb.Append("N;");//cycle detected
    else
    this.seenHashtables.Add((Hashtable)obj, true);

    Hashtable a = (Hashtable)obj;
    sb.Append("a:" + a.Count + ":{");
    foreach (DictionaryEntry entry in a)
    {
    this.serialize(entry.Key, sb);
    this.serialize(entry.Value, sb);
    }
    sb.Append("}");
    return sb;
    }
    else
    {
    return sb;
    }
    }//Serialize(object obj)

    public object Deserialize(string str)
    {
    this.pos = 0;
    return deserialize(str);
    }//Deserialize(string str)

    private object deserialize(string str)
    {
    if (str == null || str.Length <= this.pos)
    return new Object();

    int start, end, length;
    string stLen;
    switch (str[this.pos])
    {
    case 'N':
    this.pos += 2;
    return null;
    case 'b':
    char chBool;
    chBool = str[pos + 2];
    this.pos += 4;
    return chBool == '1';
    case 'i':
    string stInt;
    start = str.IndexOf(":", this.pos) + 1;
    end = str.IndexOf(";", start);
    stInt = str.Substring(start, end - start);
    this.pos += 3 + stInt.Length;
    return Int32.Parse(stInt, this.nfi);
    case 'd':
    string stDouble;
    start = str.IndexOf(":", this.pos) + 1;
    end = str.IndexOf(";", start);
    stDouble = str.Substring(start, end - start);
    this.pos += 3 + stDouble.Length;
    return Double.Parse(stDouble, this.nfi);
    case 's':
    start = str.IndexOf(":", this.pos) + 1;
    end = str.IndexOf(":", start);
    stLen = str.Substring(start, end - start);
    int bytelen = Int32.Parse(stLen);
    length = bytelen;
    //This is the byte length, not the character length - so we migth
    //need to shorten it before usage. This also implies bounds checking
    if ((end + 2 + length) >= str.Length) length = str.Length - 2 - end;
    string stRet = str.Substring(end + 2, length);
    while (this.StringEncoding.GetByteCount(stRet) > bytelen)
    {
    length--;
    stRet = str.Substring(end + 2, length);
    }
    this.pos += 6 + stLen.Length + length;
    if (this.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(":", this.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);
    this.pos += 4 + stLen.Length; //a:Len:{
    for (int i = 0; i < length; i++)
    {
    //read key
    object key = deserialize(str);
    //read value
    object val = deserialize(str);

    if (alRet != null)
    {
    if (key is int && (int)key == alRet.Count)
    alRet.Add(val);
    else
    alRet = null;
    }
    htRet[key] = val;
    }
    this.pos++; //skip the }
    if (this.pos < str.Length && str[this.pos] == ';')//skipping our old extra array semi-colon bug (er... php's weirdness)
    this.pos++;
    if (alRet != null)
    return alRet;
    else
    return htRet;
    default:
    return "";
    }//switch
    }//unserialzie(object)
    }//class Serializer