1  //!-- UTF8
     2  /*
     3  Oregano Multiuser Server - Version 1.2.0 - January 4th, 2005
     4   
     5  	Web:  www.oregano-server.org
     6  	Mail: info@oregano-server.org
     7   
     8  	Copyright 2003 - 2004 - 2004 Jens Halm / Cologne, Germany
     9   
    10   This library is free software; you can redistribute it and/or
    11   modify it under the terms of the GNU Lesser General Public
    12   License as published by the Free Software Foundation; either
    13   version 2.1 of the License, or (at your option) any later version.
    14   
    15   This library is distributed in the hope that it will be useful,
    16   but WITHOUT ANY WARRANTY; without even the implied warranty of
    17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
    18   Lesser General Public License for more details.
    19   
    20   You should have received a copy of the GNU Lesser General Public
    21   License along with this library; if not, write to the Free Software
    22   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    23   */
    24  
    25  /*
    26  -------------------------------------------
    27  	Classe DataTransformer
    28  
    29  	@description :
    30  	Gestion de l'encodage des pièces jointes.
    31  	Associé avec Message.
    32  	Singleton
    33  
    34  	@author Jens Halm copyright http://www.spicefactory.org/
    35  	@author erixtekila copyleft http://www.v-i-a.net  
    36  -------------------------------------------
    37  	version history :
    38  	1.2.0 : 05/02/05
    39  			- Portage en actionscript 2 pour le
    40  			compile time type checking
    41  			- Casting des variables
    42  			- Correction de quelques fautes de syntaxe.
    43  			- Singleton.
    44  -------------------------------------------
    45  */
    46  
    47  import org.omus.data.MarshalledProperties;
    48  import org.omus.data.Table;
    49  import org.omus.data.TableDefinition;
    50  
    51  import org.omus.util._Class;
    52  
    53  /**
    54   *	Gestion de l'encodage des pièces jointes.
    55   *
    56   *	Cette classe est implémentée en suivant le modèle Singleton.
    57   *	Un accès global à son instance est obtenu graçe à la méthode getInstance.
    58   *
    59   *	@see org.omus.msg.Message
    60   *
    61   *	@author Jens Halm copyright http://www.spicefactory.org/
    62   *	@author erixtekila copyleft http://www.v-i-a.net 
    63   *	@version 1.2.0
    64   */
    65  class org.omus.data.DataTransformer
    66  {
    67  	//--------------------
    68  	// PROPRIETES
    69  	//--------------------
    70  	/**
    71  	 *	Référence globale.
    72  	 */
    73  	private static var _instance:DataTransformer;
    74  	
    75  	//--------------------
    76  	// CONSTRUCTEUR
    77  	//--------------------
    78  	/**
    79  	 *	Gère l'encodage des pièces jointes en sortie.
    80  	 */
    81  	private function DataTransformer()
    82  	{
    83  		// trace(this+ " installé.");
    84  	}
    85  	
    86  	//--------------------
    87  	// METHODES PUBLIQUES
    88  	//--------------------
    89  	/**
    90  	 *	Utilisé dans un contexte littéral
    91  	 *	@return	Une chaine définissant l'objet
    92  	 */
    93  	public function toString():String
    94  	{
    95  		return "[Object DataTransformer]";
    96  	}
    97  	
    98  	/**
    99  	 *	Encodage d'une liste
   100  	 *
   101  	 *	@param value	Objet à encoder.
   102  	 *	@return			Une chaine encodée au format "Marshall"
   103  	 */
   104  	public function marshal_array (value:Object):String
   105  	{
   106  		var long = value.length;// TODO : à tester.
   107  		var s = "#a";
   108  		s += long;
   109  		s += "#x";
   110  		for (var i = 0; i < long ; i++) {
   111  			var tp = typeof(value[i]);
   112  			if (tp == "function" || tp == "undefined" || tp == "null") continue;
   113  			s += marshal(value[i]);
   114  		}
   115  		s += "#z";
   116  		return s;
   117  	}
   118  	
   119  	/**
   120  	 *	Encodage d'une liste
   121  	 *	(Alias de marshall_array)
   122  	 *
   123  	 *	@param value	Objet à encoder.
   124  	 *	@return			Une chaine encodée au format "Marshall"
   125  	 */
   126  	public function marshal_largeArray (value:Array):String
   127  	{
   128  		return marshal_array(value);
   129  	}
   130  	
   131  	/**
   132  	 *	Encodage d'un objet
   133  	 *
   134  	 *	@param value	Objet à encoder.
   135  	 *	@return			Une chaine encodée au format "Marshall"
   136  	 */
   137  	public function marshal_object (value:Object):String
   138  	{
   139  		var pref = "#o";
   140  		// TODO : Accès Singleton
   141  		var clazz = _Class.getInstance();
   142  		var cl = clazz.getClassName(value);
   143  		if (cl != null) pref += cl;
   144  		pref += "#y";
   145  		var s = "#x";
   146  		var cnt = 0;
   147  		for (var each:String in value) {
   148  			var tp = typeof(value[each]);
   149  			if (tp == "function" || tp == "undefined" || tp == "null") continue;
   150  			s += this.escape(each);
   151  			s += "#y";
   152  			s += marshal(value[each]);// Recursif
   153  			cnt++;
   154  		}
   155  		s += "#z";
   156  		return pref + cnt + s;
   157  	}
   158  	
   159  	/**
   160  	 *	Encodage d'un objet
   161  	 *	(Alias de marshall_objet)
   162  	 *
   163  	 *	@param value	Objet à encoder.
   164  	 *	@return			Une chaine encodée au format "Marshall"
   165  	 */
   166  	public function marshal_largeObject(value:Object):String
   167  	{
   168  		return marshal_object(value);
   169  	}
   170  	
   171  	
   172  	//--------------------
   173  	// METHODES PRIVEES
   174  	//--------------------
   175  	/**
   176  	 *	Encode tout objet au format "Marshall".
   177  	 *	Centralise le processus.
   178  	 *
   179  	 *	@param value	Objet à encoder.
   180  	 *	@return			Une chaine encodée.
   181  	 */
   182  	private function marshal (value:Object):String
   183  	{
   184  		var tp = typeof (value);
   185  		// Dispatch l'encodage en fonction des type de variable.
   186  		if (tp != "object") 
   187  		{
   188  			return this["marshal_" + tp](value);
   189  		} else 
   190  		{
   191  			// Une fonction globale Array() existe, impossible de caster value avec…
   192  			if (value instanceof Array) return marshal_array(value);
   193  			// Une fonction globale Date() existe, impossible de caster value avec…
   194  			if (value instanceof Date) return marshal_date(value);
   195  			if (value instanceof MarshalledProperties) return marshal_premarshalled(value);
   196  			if (value instanceof Table) return marshal_table(Table(value));
   197  			return marshal_object(value);
   198  		}
   199  	}
   200  	
   201  	/**
   202  	 *	Encode le type d'une variable
   203  	 *
   204  	 *	@param value		Les valeurs à encoder.
   205  	 *	@param clazz		Le type de variable.
   206  	 *	@return				Une chaine encodée.
   207  	 */
   208  	private function marshalType (value:Object, clazz:Object):String
   209  	{
   210  		if (typeof(clazz) == "string") 
   211  		{
   212  			return this["marshal_" + clazz](value);
   213  		} else 
   214  		{
   215  			// TODO : Vérifier le type de clazz
   216  			// because of Flash 5 reporting true for (Array == Date) we have to compare their prototypes:
   217  			// Une fonction globale Array() existe, impossible de caster value avec…
   218  			if (clazz["prototype"] == Array.prototype) return marshal_array(value);
   219  			// Une fonction globale Date() existe, impossible de caster value avec…
   220  			if (clazz["prototype"] == Date.prototype) return marshal_date(value);
   221  			if (clazz["prototype"] == Table.prototype) return marshal_table(Table(value));
   222  			return marshal_object(value);
   223  		}
   224  	}
   225  	
   226  	/**
   227  	 *	Encode un booléen.
   228  	 *
   229  	 *	@param value		Les valeurs à encoder.
   230  	 *	@return				Une chaine encodée.
   231  	 */
   232  	private function marshal_boolean (value:Boolean):String
   233  	{
   234  		return "#b" + ((value) ? "1" : "0") + "#x";
   235  	}
   236  	
   237  	/**
   238  	 *	Encode ?
   239  	 *
   240  	 *	@param value		Les valeurs à encoder.
   241  	 *	@return				Une chaine encodée.
   242  	 */
   243  	private function marshal_counter (value:Object):String
   244  	{
   245  		return "#c" + value + "#x";
   246  	}
   247  	
   248  	/**
   249  	 *	Encode un nombre entier.
   250  	 *
   251  	 *	@param value		Les valeurs à encoder.
   252  	 *	@return				Une chaine encodée.
   253  	 */
   254  	private function marshal_int (value:Number):String
   255  	{
   256  		return "#i" + value + "#x";
   257  	}
   258  	
   259  	/**
   260  	 *	Encode un nombre long.
   261  	 *
   262  	 *	@param value		Les valeur à encoder.
   263  	 *	@return				Une chaine encodée.
   264  	 */
   265  	private function marshal_long (value:Number):String
   266  	{
   267  		return "#l" + value + "#x";
   268  	}
   269  	
   270  	/**
   271  	 *	Encode un nombre à virgule flottante.
   272  	 *
   273  	 *	@param value		Les valeur à encoder.
   274  	 *	@return				Une chaine encodée.
   275  	 */
   276  	private function marshal_float (value:Number):String
   277  	{
   278  		return "#f" + value + "#x";
   279  	}
   280  	
   281  	/**
   282  	 *	Encode un nombre à virgule flottante.
   283  	 *	(alias de marshal_float)
   284  	 *
   285  	 *	@param value		Les valeur à encoder.
   286  	 *	@return				Une chaine encodée.
   287  	 */
   288  	private function marshal_number(value:Number):String
   289  	{
   290  		return marshal_float(value);
   291  	}
   292  	
   293  	/**
   294  	 *	Encode une chaine.
   295  	 *
   296  	 *	@param value		Les valeur à encoder.
   297  	 *	@return				Une chaine encodée.
   298  	 */
   299  	private function marshal_string (value:String):String
   300  	{
   301  		return "#s" + this.escape(value) + "#y";
   302  	}
   303  	
   304  	/**
   305  	 *	Encode une chaine large.
   306  	 *
   307  	 *	@param value		Les valeur à encoder.
   308  	 *	@return				Une chaine encodée.
   309  	 */
   310  	private function marshal_largeString(value:String):String
   311  	{
   312  		return marshal_string(value);
   313  	}	
   314  	
   315  	/**
   316  	 *	Encode une date.
   317  	 *
   318  	 *	@param value		Les valeur à encoder.
   319  	 *	@return				Une chaine encodée.
   320  	 */
   321  	private function marshal_date (value:Object):String
   322  	{
   323  		return "#d" + value.getTime() + "#x";
   324  	}
   325  	
   326  	/**
   327  	 *	Encode un type Table ou propriétaire d'Oregano.
   328  	 *
   329  	 *	@param value		Les valeur à encoder.
   330  	 *	@return				Une chaine encodée.
   331  	 */
   332  	private function marshal_premarshalled (value:Object):String
   333  	{
   334  		 var pref = "#o#y";
   335  		 var s = "#x";
   336  		 var cnt = 0;
   337  		 var ps = value.props;
   338  		 for (var each:String in ps) 
   339  		 {
   340  			 s += this.escape(each);
   341  			 s += "#y";
   342  			 var val = ps[each];
   343  			 if (typeof(val) != "string") 
   344  			 {
   345  				 s+= val.getMarshalledSequence();
   346  			 } else
   347  			 {
   348  				 s+= val;
   349  			 }
   350  			 cnt++;
   351  		 }
   352  		 s += "#z";
   353  		 return pref + cnt + s;
   354  	 }
   355  	 
   356  	/**
   357  	 *	Encode un enregistrement de Table.
   358  	 *
   359  	 *	@param row			Un enregistrement de la table.
   360  	 *	@param def			La definition de la table.
   361  	 *	@return				Une chaine encodée.
   362  	 */
   363  	public function marshal_row (row:Object, def:TableDefinition):String
   364  	{
   365  		 var pref = "#a";
   366  		 var s = "#x";
   367  		 var cnt = 0;
   368  		 var cols = def.getColumnCount();
   369  		 for (var i = 0; i < cols; i++) {
   370  			 var name = def.getColumnName(i);
   371  			 var type = def.getColumnType(i);
   372  			 s += marshalType(row[name], type);
   373  			 cnt++;
   374  		 }
   375  		 s += "#z";
   376  		 return pref + cnt + s;
   377  	 }
   378  	 
   379  	 /**
   380  	  *	Encode un type Table.
   381  	  *
   382  	  *	@param value		Les valeur à encoder.
   383  	  *	@return				Une chaine encodée.
   384  	  */
   385  	private function marshal_table (value:Table):String
   386  	{
   387  		 var s = "#t";
   388  		 var rowCnt = value.rowList.length;
   389  		 s += rowCnt;
   390  		 s += "#x";
   391  		 s += value.nextRowID;
   392  		 s += "#x";
   393  		 
   394  		 // table definition
   395  		 var def = value.getDefinition();
   396  		 var colCnt = def.getColumnCount();
   397  		 var cols = def.getColumnNames();
   398  		 s += colCnt;
   399  		 s += "#x";
   400  		 for (var i = 0; i < colCnt; i++)
   401  		 {
   402  			 s += "#";
   403  			 // TODO : Accès Singleton
   404  			 var clazz = _Class.getInstance();
   405  			 s += clazz.cellTypeToChar(def.getColumnType(i));
   406  			 s += cols[i];
   407  			 s += "#y";
   408  		 }
   409  		 
   410  		 // table data
   411  		 var rl = value.rowList;
   412  		 for (var j = 0; j < rowCnt; j++)
   413  		 {
   414  			 var row = rl[j];
   415  			 s += "#r";
   416  			 s += row.__rowID;
   417  			 s += "#x";
   418  			 for (var idx = 0; idx < colCnt; idx++) 
   419  			 {
   420  				 var cell = row[cols[idx]];
   421  				 var type = def.getColumnType(idx);
   422  				 // Dispatch de l'encodage.
   423  				 s += this["marshal_" + type](cell);
   424  			 }
   425  		 }
   426  		 s += "#z";
   427  		 return s;
   428  	 }
   429  	
   430  	/**
   431  	 *	Encodage d'une table (large)
   432  	 *	(Alias de marshall_table)
   433  	 *
   434  	 *	@param value	Objet à encoder.
   435  	 *	@return			Une chaine encodée au format "Marshall"
   436  	 */
   437  	private function marshal_largeTable (value:Table):String
   438  	{
   439  		return marshal_table(value);
   440  	}	 
   441  	 
   442  	 /**
   443  	  *	Echappe une chaine de caractères.
   444  	  *
   445  	  *	@param orig		Chaine originale.
   446  	  *	@return			Une chaine échappée.
   447  	  */
   448  	private function escape (orig:String):String
   449  	{
   450  		 var len = orig.length;
   451  		 var clean = true;
   452  		 var s:String;
   453  		 for (var i = 1; i <= len; i++) 
   454  		 {
   455  			 // 
   456  			 var c = orig.substr(i-1, 1);
   457  			 if (c == "#") {
   458  				 if (clean) {
   459  					 // first occurence
   460  					 s = "#e" + orig.substr(0, i-1);
   461  					 clean = false;
   462  				 }
   463  				 s += "##";
   464  			 } else {
   465  				 s += c;
   466  			 }
   467  		 }
   468  		 if (clean) return orig;
   469  		 else return s;
   470  	 }
   471  	
   472  	//--------------------
   473  	// METHODES STATIQUES
   474  	//--------------------
   475  	/**
   476  	 *	Utilisé dans un contexte littéral
   477  	 *	@return	Une chaine définissant l'objet
   478  	 */
   479  	public static function toLog():String
   480  	{
   481  		return "[Object DataTransformer]";
   482  	}
   483  	
   484  	/**
   485  	 *	Accès global au Singleton.
   486  	 */
   487  	public static function getInstance():DataTransformer
   488  	{
   489  		if(_instance == undefined) _instance = new DataTransformer();
   490  		return _instance;
   491  	}
   492  }
   493