Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public class PhpArrayConverter
- {
- //types:
- // N = null
- // s = string
- // i = int
- // d = double
- // a = array (hashtable)
- private readonly NumberFormatInfo numberFormatInfo;
- public Encoding StringEncoding = new UTF8Encoding();
- 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
- private int pos; //for unserialize
- private Dictionary<ArrayList, bool> seenArrayLists; //for serialize (to infinte prevent loops) lol
- private Dictionary<Hashtable, bool> seenHashtables; //for serialize (to infinte prevent loops)
- public PhpArrayConverter()
- {
- numberFormatInfo = new NumberFormatInfo();
- numberFormatInfo.NumberGroupSeparator = "";
- numberFormatInfo.NumberDecimalSeparator = ".";
- }
- public string Serialize(object obj)
- {
- seenArrayLists = new Dictionary<ArrayList, bool>();
- seenHashtables = new Dictionary<Hashtable, bool>();
- return SerializeInternal(obj, new StringBuilder()).ToString();
- }
- public object Deserialize(string str)
- {
- pos = 0;
- return DeserializeInternal(str);
- }
- private StringBuilder SerializeInternal(object obj, StringBuilder sb)
- {
- if (obj == null)
- {
- return sb.Append("N;");
- }
- if (obj is string)
- {
- var 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:" + StringEncoding.GetByteCount(str) + ":\"" + str + "\";");
- }
- if (obj is bool)
- {
- return sb.Append("b:" + (((bool) obj) ? "1" : "0") + ";");
- }
- if (obj is int)
- {
- var i = (int) obj;
- return sb.Append("i:" + i.ToString(numberFormatInfo) + ";");
- }
- if (obj is double)
- {
- var d = (double) obj;
- return sb.Append("d:" + d.ToString(numberFormatInfo) + ";");
- }
- if (obj is ArrayList)
- {
- if (seenArrayLists.ContainsKey((ArrayList) obj))
- return sb.Append("N;"); //cycle detected
- seenArrayLists.Add((ArrayList) obj, true);
- var a = (ArrayList) obj;
- sb.Append("a:" + a.Count + ":{");
- for (int i = 0; i < a.Count; i++)
- {
- SerializeInternal(i, sb);
- SerializeInternal(a[i], sb);
- }
- sb.Append("}");
- return sb;
- }
- if (obj is Hashtable)
- {
- if (seenHashtables.ContainsKey((Hashtable) obj))
- return sb.Append("N;"); //cycle detected
- seenHashtables.Add((Hashtable) obj, true);
- var a = (Hashtable) obj;
- sb.Append("a:" + a.Count + ":{");
- foreach (DictionaryEntry entry in a)
- {
- SerializeInternal(entry.Key, sb);
- SerializeInternal(entry.Value, sb);
- }
- sb.Append("}");
- return sb;
- }
- return sb;
- }
- private object DeserializeInternal(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 = str[pos + 2];
- pos += 4;
- return chBool == '1';
- case 'i':
- start = str.IndexOf(":", pos, StringComparison.Ordinal) + 1;
- end = str.IndexOf(";", start, StringComparison.Ordinal);
- string stInt = str.Substring(start, end - start);
- pos += 3 + stInt.Length;
- return Int32.Parse(stInt, numberFormatInfo);
- case 'd':
- start = str.IndexOf(":", pos, StringComparison.Ordinal) + 1;
- end = str.IndexOf(";", start, StringComparison.Ordinal);
- string stDouble = str.Substring(start, end - start);
- pos += 3 + stDouble.Length;
- return Double.Parse(stDouble, numberFormatInfo);
- case 's':
- start = str.IndexOf(":", pos, StringComparison.Ordinal) + 1;
- end = str.IndexOf(":", start, StringComparison.Ordinal);
- 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 (StringEncoding.GetByteCount(stRet) > bytelen)
- {
- length--;
- stRet = str.Substring(end + 2, length);
- }
- pos += 6 + stLen.Length + 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, StringComparison.Ordinal) + 1;
- end = str.IndexOf(":", start, StringComparison.Ordinal);
- stLen = str.Substring(start, end - start);
- length = Int32.Parse(stLen);
- var htRet = new Hashtable(length);
- var alRet = new ArrayList(length);
- pos += 4 + stLen.Length; //a:Len:{
- for (int i = 0; i < length; i++)
- {
- //read key
- object key = DeserializeInternal(str);
- //read value
- object val = DeserializeInternal(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;
- return htRet;
- default:
- return "";
- } //switch
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement