Serializable.as
/**********************************************************\ | | | The implementation of PHPRPC Protocol 3.0 | | | | Serializable.as | | | | Release 3.0.0 | | Copyright (c) 2005-2007 by Team-PHPRPC | | | | WebSite: http://www.phprpc.org/ | | http://www.phprpc.net/ | | http://www.phprpc.com/ | | http://sourceforge.net/projects/php-rpc/ | | | | Authors: Ma Bingyao <[email protected]> | | | | This file may be distributed and/or modified under the | | terms of the GNU Lesser General Public License (LGPL) | | version 3.0 as published by the Free Software Foundation | | and appearing in the included file LICENSE. | | | \**********************************************************/ /* Serializable interface for custom PHP serialize. * * Copyright (C) 2006-2007 Ma Bingyao <[email protected]> * Version: 3.0 * LastModified: Oct 23, 2007 * This library is free. You can redistribute it and/or modify it. */ package org.phprpc.util{ import flash.utils.ByteArray; public interface Serializable { function serialize():ByteArray; function unserialize(ss:ByteArray):void; } }
PHPSerializer.as
/**********************************************************\ | | | The implementation of PHPRPC Protocol 3.0 | | | | PHPSerializer.as | | | | Release 3.0.0 | | Copyright (c) 2005-2007 by Team-PHPRPC | | | | WebSite: http://www.phprpc.org/ | | http://www.phprpc.net/ | | http://www.phprpc.com/ | | http://sourceforge.net/projects/php-rpc/ | | | | Authors: Ma Bingyao <[email protected]> | | | | This file may be distributed and/or modified under the | | terms of the GNU Lesser General Public License (LGPL) | | version 3.0 as published by the Free Software Foundation | | and appearing in the included file LICENSE. | | | \**********************************************************/ /* PHP serialize/unserialize library for ActionScript 3.0. * * Copyright (C) 2006-2007 Ma Bingyao <[email protected]> * Version: 3.0 * LastModified: Nov 6, 2007 * This library is free. You can redistribute it and/or modify it. */ package org.phprpc.util { import org.phprpc.util.Serializable; import flash.utils.ByteArray; import flash.utils.Dictionary; import flash.utils.getQualifiedClassName; import flash.utils.getDefinitionByName; public class PHPSerializer { private static function isInteger(s:String):Boolean { var i:int; var l:int = s.length; if (l > 11) { return false; } for (i = (s.charAt(0) == '-') ? 1 : 0; i < l; i++) { switch (s.charAt(i)) { case '0' : case '1' : case '2' : case '3' : case '4' : case '5' : case '6' : case '7' : case '8' : case '9' : break; default : return false; } } var n:Number = Number(s); return !(n < -2147483648 || n > 2147483647); } public static function getClassName(o:*):String { var className:String = getQualifiedClassName(o); return className.replace(/\./g, '_').replace(/\:\:/g, '_'); } private static function getObjectOfClass(cn:Array, poslist:Array, i:uint, c:String):Object { if (i < poslist.length) { var pos:uint = poslist[i]; cn[pos] = c; var obj:Object = getObjectOfClass(cn, poslist, i + 1, '.'); if (i + 1 < poslist.length) { if (obj == null) { obj = getObjectOfClass(cn, poslist, i + 1, '_'); } } return obj; } var classname:String = cn.join(''); try { return new (flash.utils.getDefinitionByName(classname) as Class); } catch (e:Error) { }; return null; } public static function createObjectOfClass(classname:String):Object { try { return new (flash.utils.getDefinitionByName(classname) as Class); } catch (e:Error) {} var poslist:Array = []; var pos:int = classname.indexOf("_"); while (pos > -1) { poslist[poslist.length] = pos; pos = classname.indexOf("_", pos + 1); } if (poslist.length > 0) { var cn:Array = classname.split(''); var obj:Object = getObjectOfClass(cn, poslist, 0, '.'); if (obj == null) { obj = getObjectOfClass(cn, poslist, 0, '_'); } if (obj != null) { return obj; } } return {name:classname}; } public static function serialize(o:Object):ByteArray { var sb:ByteArray = new ByteArray(); var ht:Dictionary = new Dictionary(); var hv:uint = 1; function _serializeNull():void { sb.writeUTFBytes('N;'); } function _serializeBoolean(b:Boolean):void { sb.writeUTFBytes(b ? 'b:1;' : 'b:0;'); } function _serializeInteger(i:int):void { sb.writeUTFBytes('i:' + i + ';'); } function _serializeDouble(d:Number):void { var s:String; if (isNaN(d)) { s = 'NAN'; } else if (d == Number.POSITIVE_INFINITY) { s = 'INF'; } else if (d == Number.NEGATIVE_INFINITY) { s = '-INF'; } else { s = d.toString(10); } sb.writeUTFBytes('d:' + s + ';'); } function _serializeByteArray(ba:ByteArray):void { ba.position = 0; sb.writeUTFBytes('s:' + ba.length + ':"'); sb.writeBytes(ba); sb.writeUTFBytes('";'); } function _serializeString(s:String):void { var utf8:ByteArray = new ByteArray(); utf8.writeUTFBytes(s); sb.writeUTFBytes('s:' + utf8.length + ':"'); sb.writeBytes(utf8); sb.writeUTFBytes('";'); } function _serializeDate(dt:Date):void { sb.writeUTFBytes('O:11:"PHPRPC_Date":7:{'); sb.writeUTFBytes('s:4:"year";'); _serializeInteger(dt.getFullYear()); sb.writeUTFBytes('s:5:"month";'); _serializeInteger(dt.getMonth() + 1); sb.writeUTFBytes('s:3:"day";'); _serializeInteger(dt.getDate()); sb.writeUTFBytes('s:4:"hour";'); _serializeInteger(dt.getHours()); sb.writeUTFBytes('s:6:"minute";'); _serializeInteger(dt.getMinutes()); sb.writeUTFBytes('s:6:"second";'); _serializeInteger(dt.getSeconds()); sb.writeUTFBytes('s:11:"millisecond";'); _serializeInteger(dt.getMilliseconds()); sb.writeUTFBytes('}'); } function _serializeArray(a:Object):void { var k:String; var l:uint = 0; for (k in a) l++; sb.writeUTFBytes('a:' + l + ':{'); for (k in a) { if (typeof (a[k]) != 'function') { isInteger(k) ? _serializeInteger(k) : _serializeString(k); _serialize(a[k]); } } sb.writeUTFBytes('}'); } function _serializeObject(o:Object, cn:String):void { var c:Serializable = o as Serializable; var cnb:ByteArray = new ByteArray(); cnb.writeUTFBytes(cn); if (c == null) { sb.writeUTFBytes('O:' + cnb.length + ':"'); sb.writeBytes(cnb); var k:String; var l:uint = 0; for (k in o) l++; sb.writeUTFBytes('":' + l + ':{'); for (k in o) { if (typeof(o[k]) != 'function') { _serializeString(k); _serialize(o[k]); } } sb.writeUTFBytes('}'); } else { var data:ByteArray = c.serialize(); sb.writeUTFBytes('C:' + cnb.length + ':"'); sb.writeBytes(cnb); sb.writeUTFBytes('":' + data.length + ':{'); sb.writeBytes(data); sb.writeUTFBytes('}'); } } function _serializePointRef(R:uint):void { sb.writeUTFBytes('R:' + R + ';'); } function _serializeRef(r:uint):void { sb.writeUTFBytes('r:' + r + ';'); } function _serialize(o:*):void { if (typeof (o) == "undefined" || o == null || o.constructor == Function) { hv++; _serializeNull(); return; } var className:String = getClassName(o); switch (o.constructor) { case Boolean : hv++; _serializeBoolean(o); break; case Number : hv++; isInteger(o) ? _serializeInteger(o) : _serializeDouble(o); break; case String : hv++; _serializeString(o); break; case ByteArray : hv++; _serializeByteArray(o); break; case Date : hv++; _serializeDate(o); break; default : var r:int = ht[o]; if (className == "Object" || o.constructor == Array) { if (r) { _serializePointRef(r); } else { ht[o] = hv++; _serializeArray(o); } } else { if (r) { hv++; _serializeRef(r); } else { ht[o] = hv++; _serializeObject(o, className); } } break; } } _serialize(o); return sb; } public static function unserialize(sb:ByteArray):* { var ht:Dictionary = new Dictionary(); var hv:int = 1; function _readNumber():String { var s:String = ''; var c:String = sb.readUTFBytes(1); while ((c != ';') && (c != ':')) { s += c; c = sb.readUTFBytes(1); } return s; } function _unserializeNull():Object { sb.position++; return null; } function _unserializeBoolean():Boolean { sb.position++; var b:Boolean = (sb.readUTFBytes(1) == '1'); sb.position++; return b; } function _unserializeInteger():int { sb.readByte(); var i:int = parseInt(_readNumber()); return i; } function _unserializeDouble():Number { sb.position++; var d:Number; var s:String = _readNumber(); switch (s) { case 'NAN' : d = Number.NaN; break; case 'INF' : d = Number.POSITIVE_INFINITY; break; case '-INF' : d = Number.NEGATIVE_INFINITY; break; default : d = parseFloat(s); } return d; } function _unserializeByteArray():ByteArray { sb.position++; var l:uint = parseInt(_readNumber()); sb.position++; var ba:ByteArray = new ByteArray(); if (l > 0) { sb.readBytes(ba, 0, l); } sb.position += 2; return ba; } function _unserializeString():String { sb.position++; var l:uint = parseInt(_readNumber()); sb.position++; var s:String = sb.readUTFBytes(l); sb.position += 2; return s; } function _unserializeEscapedString(len:int):String { sb.position++; var l:uint = parseInt(_readNumber()); sb.position++; var i:int; var s:Array = new Array(l); for (i = 0; i < l; i++) { if ((s[i] = sb.readUTFBytes(1)) == '\\') { s[i] = String.fromCharCode(parseInt(sb.readUTFBytes(len), 16)); } } sb.position += 2; return s.join(''); } function _unserializeArray():Array { sb.position++; var n:int = parseInt(_readNumber()); sb.position++; var i:int; var k:*; var a:Array = []; ht[hv++] = a; for (i = 0; i < n; i++) { switch (sb.readUTFBytes(1)) { case 'i' : k = _unserializeInteger(); break; case 's' : k = _unserializeString(); break; case 'S' : k = _unserializeEscapedString(2); break; case 'U' : k = _unserializeEscapedString(4); break; default : return null; } a[k] = _unserialize(); } sb.position++; return a; } function _unserializeDate(n:int):Date { var i:int; var k:String; var a:Object = {}; for (i = 0; i < n; i++) { switch (sb.readUTFBytes(1)) { case 's' : k = _unserializeString(); break; case 'S' : k = _unserializeEscapedString(2); break; case 'U' : k = _unserializeEscapedString(4); break; default : return null; } if (sb.readUTFBytes(1) == 'i') { a[k] = _unserializeInteger(); } else { return null; } } sb.position++; var dt:Date = new Date(a.year, a.month - 1, a.day, a.hour, a.minute, a.second, a.millisecond); ht[hv++] = dt; return dt; } function _unserializeObject():* { sb.position++; var l:uint = parseInt(_readNumber()); sb.position++; var cn:String = sb.readUTFBytes(l); sb.position += 2; var n:uint = parseInt(_readNumber()); sb.position++; if (cn == "PHPRPC_Date") { return _unserializeDate(n); } var i:int; var k:String; var o:Object = createObjectOfClass(cn); ht[hv++] = o; for (i = 0; i < n; i++) { switch (sb.readUTFBytes(1)) { case 's' : k = _unserializeString(); break; case 'S' : k = _unserializeEscapedString(2); break; case 'U' : k = _unserializeEscapedString(4); break; default : return false; } if (k.charAt(0) == '\0') { k = k.substring(k.indexOf('\0', 1) + 1, k.length); } o[k] = _unserialize(); } sb.position++; return o; } function _unserializeCustomObject():* { sb.position++; sb.position++; var l:uint = parseInt(_readNumber()); sb.position++; var cn:String = sb.readUTFBytes(l); sb.position += 2; var n:uint = parseInt(_readNumber()); sb.position++; var data:ByteArray = new ByteArray(); sb.readBytes(data, 0, n); sb.position++; var o:Object = createObjectOfClass(cn); var c:Serializable = o as Serializable; if (c == null) { o.data = data; return o; } c.unserialize(data); return c; } function _unserializeRef():* { sb.position++; var r:uint = parseInt(_readNumber()); return ht[r]; } function _unserialize():* { var result:*; switch (sb.readUTFBytes(1)) { case 'N' : result = _unserializeNull(); ht[hv] = result; hv++; return result; case 'b' : result = _unserializeBoolean(); ht[hv] = result; hv++; return result; case 'i' : result = _unserializeInteger(); ht[hv] = result; hv++; return result; case 'd' : result = _unserializeDouble(); ht[hv] = result; hv++; return result; case 's' : result = _unserializeByteArray(); ht[hv] = result; hv++; return result; case 'S' : result = _unserializeEscapedString(2); ht[hv] = result; hv++; return result; case 'U' : result = _unserializeEscapedString(4); ht[hv] = result; hv++; return result; case 'r' : result = _unserializeRef(); ht[hv] = result; hv++; return result; case 'a' : return _unserializeArray(); case 'O' : return _unserializeObject(); case 'C' : return _unserializeCustomObject(); case 'R' : return _unserializeRef(); } return false; } sb.position = 0; return _unserialize(); } } }