mev-4.0.01/source/org/tigr/microarray/mev/r/REXP.java

Code
Comments
Other
Rev Date Author Line
2 26 Feb 07 jari 1 package org.tigr.microarray.mev.r;
2 26 Feb 07 jari 2
2 26 Feb 07 jari 3 import java.util.*;
2 26 Feb 07 jari 4
2 26 Feb 07 jari 5 /** representation of R-eXpressions in Java
2 26 Feb 07 jari 6
2 26 Feb 07 jari 7     @version $Id$
2 26 Feb 07 jari 8 */
2 26 Feb 07 jari 9 public class REXP extends Object {
2 26 Feb 07 jari 10     /** xpression type: NULL */
2 26 Feb 07 jari 11     public static final int XT_NULL=0;
2 26 Feb 07 jari 12     /** xpression type: integer */
2 26 Feb 07 jari 13     public static final int XT_INT=1;
2 26 Feb 07 jari 14     /** xpression type: double */
2 26 Feb 07 jari 15     public static final int XT_DOUBLE=2;
2 26 Feb 07 jari 16     /** xpression type: String */
2 26 Feb 07 jari 17     public static final int XT_STR=3;
2 26 Feb 07 jari 18     /** xpression type: language construct (currently content is same as list) */
2 26 Feb 07 jari 19     public static final int XT_LANG=4;
2 26 Feb 07 jari 20     /** xpression type: symbol (content is symbol name: String) */
2 26 Feb 07 jari 21     public static final int XT_SYM=5;
2 26 Feb 07 jari 22     /** xpression type: RBool */    
2 26 Feb 07 jari 23     public static final int XT_BOOL=6;
2 26 Feb 07 jari 24     /** xpression type: Vector */
2 26 Feb 07 jari 25     public static final int XT_VECTOR=16;
2 26 Feb 07 jari 26     /** xpression type: RList */
2 26 Feb 07 jari 27     public static final int XT_LIST=17;
2 26 Feb 07 jari 28     /** xpression type: closure (there is no java class for that type (yet?). currently the body of the closure is stored in the content part of the REXP. Please note that this may change in the future!) */
2 26 Feb 07 jari 29     public static final int XT_CLOS=18;
2 26 Feb 07 jari 30     /** xpression type: int[] */
2 26 Feb 07 jari 31     public static final int XT_ARRAY_INT=32;
2 26 Feb 07 jari 32     /** xpression type: double[] */
2 26 Feb 07 jari 33     public static final int XT_ARRAY_DOUBLE=33;
2 26 Feb 07 jari 34     /** xpression type: String[] (currently not used, Vector is used instead) */
2 26 Feb 07 jari 35     public static final int XT_ARRAY_STR=34;
2 26 Feb 07 jari 36     /** internal use only! this constant should never appear in a REXP */
2 26 Feb 07 jari 37     public static final int XT_ARRAY_BOOL_UA=35;
2 26 Feb 07 jari 38     /** xpression type: RBool[] */
2 26 Feb 07 jari 39     public static final int XT_ARRAY_BOOL=36;
2 26 Feb 07 jari 40     /** xpression type: unknown; no assumptions can be made about the content */
2 26 Feb 07 jari 41     public static final int XT_UNKNOWN=48;
2 26 Feb 07 jari 42
2 26 Feb 07 jari 43     /** xpression type: RFactor; this XT is internally generated (ergo is does not come from Rsrv.h) to support RFactor class which is built from XT_ARRAY_INT */
2 26 Feb 07 jari 44     public static final int XT_FACTOR=127; 
2 26 Feb 07 jari 45
2 26 Feb 07 jari 46     /** xpression type */
2 26 Feb 07 jari 47     int Xt;
2 26 Feb 07 jari 48     /** attribute xpression or <code>null</code> if none */
2 26 Feb 07 jari 49     REXP attr;
2 26 Feb 07 jari 50     /** content of the xpression - its object type is dependent of {@link #Xt} */
2 26 Feb 07 jari 51     Object cont;
2 26 Feb 07 jari 52
2 26 Feb 07 jari 53     /** cached binary length; valid only if positive */
2 26 Feb 07 jari 54     long cachedBinaryLength=-1;
2 26 Feb 07 jari 55     
2 26 Feb 07 jari 56     /** construct a new, empty (NULL) expression w/o attribute */
2 26 Feb 07 jari 57     public REXP() { Xt=0; attr=null; cont=null; }
2 26 Feb 07 jari 58
2 26 Feb 07 jari 59     /** construct a new xpression of type t and content o, but no attribute
2 26 Feb 07 jari 60   @param t xpression type (XT_...)
2 26 Feb 07 jari 61   @param o content */
2 26 Feb 07 jari 62     public REXP(int t, Object o) {
2 26 Feb 07 jari 63   Xt=t; cont=o; attr=null;
2 26 Feb 07 jari 64     }
2 26 Feb 07 jari 65
2 26 Feb 07 jari 66     /** construct a new xpression of type t, content o and attribute at
2 26 Feb 07 jari 67   @param t xpression type
2 26 Feb 07 jari 68   @param o content
2 26 Feb 07 jari 69   @param at attribute */
2 26 Feb 07 jari 70     public REXP(int t, Object o, REXP at) {
2 26 Feb 07 jari 71   Xt=t; cont=o; attr=at;
2 26 Feb 07 jari 72     }
2 26 Feb 07 jari 73
2 26 Feb 07 jari 74     /** construct a new xpression of type XT_ARRAY_DOUBLE and content val
2 26 Feb 07 jari 75         @param val array of doubles to store in the REXP */
2 26 Feb 07 jari 76     public REXP(double[] val) {
2 26 Feb 07 jari 77         this(XT_ARRAY_DOUBLE,val);
2 26 Feb 07 jari 78     }
2 26 Feb 07 jari 79
2 26 Feb 07 jari 80     /** construct a new xpression of type XT_ARRAY_INT and content val
2 26 Feb 07 jari 81         @param val array of integers to store in the REXP */
2 26 Feb 07 jari 82     public REXP(int[] val) {
2 26 Feb 07 jari 83         this(XT_ARRAY_INT,val);
2 26 Feb 07 jari 84     }
2 26 Feb 07 jari 85     
2 26 Feb 07 jari 86     /** construct a new xpression of type XT_ARRAY_INT and content val
2 26 Feb 07 jari 87       @param val array of integers to store in the REXP */
2 26 Feb 07 jari 88     public REXP(String[] val) {
2 26 Feb 07 jari 89       this(XT_ARRAY_STR,val);
2 26 Feb 07 jari 90     }
2 26 Feb 07 jari 91     
2 26 Feb 07 jari 92     /** get attribute of the REXP. In R every object can have attached attribute xpression. Some more complex structures such as classes are built that way.
2 26 Feb 07 jari 93         @return attribute xpression or <code>null</code> if there is none associated */
2 26 Feb 07 jari 94     public REXP getAttribute() {
2 26 Feb 07 jari 95         return attr;
2 26 Feb 07 jari 96     }
2 26 Feb 07 jari 97
2 26 Feb 07 jari 98     /** get raw content. Use as... methods to retrieve contents of known type.
2 26 Feb 07 jari 99         @return content of the REXP */
2 26 Feb 07 jari 100     public Object getContent() {
2 26 Feb 07 jari 101         return cont;
2 26 Feb 07 jari 102     }
2 26 Feb 07 jari 103
2 26 Feb 07 jari 104     /** get xpression type (see XT_.. constants) of the content. It defines the type of the content object.
2 26 Feb 07 jari 105         @return xpression type */
2 26 Feb 07 jari 106     public int getType() {
2 26 Feb 07 jari 107         return Xt;
2 26 Feb 07 jari 108     }
2 26 Feb 07 jari 109     
2 26 Feb 07 jari 110     /** parses byte buffer for binary representation of xpressions - read one xpression slot (descends recursively for aggregated xpressions such as lists, vectors etc.)
2 26 Feb 07 jari 111   @param x xpression object to store the parsed xpression in
2 26 Feb 07 jari 112   @param buf buffer containing the binary representation
2 26 Feb 07 jari 113   @param o offset in the buffer to start at
2 26 Feb 07 jari 114         @return position just behind the parsed xpression. Can be use for successive calls to {@link #parseREXP} if more than one expression is stored in the binary array. */
2 26 Feb 07 jari 115     public static int parseREXP(REXP x, byte[] buf, int o) {
2 26 Feb 07 jari 116   int xl=Rtalk.getLen(buf,o);
2 26 Feb 07 jari 117   boolean hasAtt=((buf[o]&128)!=0);
2 26 Feb 07 jari 118         boolean isLong=((buf[o]&64)!=0);
2 26 Feb 07 jari 119   int xt=(int)(buf[o]&63);
2 26 Feb 07 jari 120         //System.out.println("parseREXP: type="+xt+", len="+xl+", hasAtt="+hasAtt+", isLong="+isLong);
2 26 Feb 07 jari 121         if (isLong) o+=4;
2 26 Feb 07 jari 122         o+=4;
2 26 Feb 07 jari 123   int eox=o+xl;
2 26 Feb 07 jari 124   
2 26 Feb 07 jari 125   x.Xt=xt; x.attr=null;
2 26 Feb 07 jari 126   if (hasAtt) o=parseREXP(x.attr=new REXP(),buf,o);
2 26 Feb 07 jari 127   if (xt==XT_NULL) {
2 26 Feb 07 jari 128       x.cont=null; return o;
2 26 Feb 07 jari 129   };
2 26 Feb 07 jari 130   if (xt==XT_DOUBLE) {
2 26 Feb 07 jari 131       long lr=Rtalk.getLong(buf,o);
2 26 Feb 07 jari 132       x.cont=new Double(Double.longBitsToDouble(lr));
2 26 Feb 07 jari 133       o+=8;
2 26 Feb 07 jari 134       if (o!=eox) {
2 26 Feb 07 jari 135     System.out.println("Warning: double SEXP size mismatch\n");
2 26 Feb 07 jari 136     o=eox;
2 26 Feb 07 jari 137       };
2 26 Feb 07 jari 138       return o;
2 26 Feb 07 jari 139   }
2 26 Feb 07 jari 140   if (xt==XT_ARRAY_DOUBLE) {
2 26 Feb 07 jari 141       int as=(eox-o)/8,i=0;
2 26 Feb 07 jari 142       double[] d=new double[as];
2 26 Feb 07 jari 143       while (o<eox) {
2 26 Feb 07 jari 144     d[i]=Double.longBitsToDouble(Rtalk.getLong(buf,o));
2 26 Feb 07 jari 145     o+=8;
2 26 Feb 07 jari 146     i++;
2 26 Feb 07 jari 147       };
2 26 Feb 07 jari 148       if (o!=eox) {
2 26 Feb 07 jari 149     System.out.println("Warning: double array SEXP size mismatch\n");
2 26 Feb 07 jari 150     o=eox;
2 26 Feb 07 jari 151       };
2 26 Feb 07 jari 152       x.cont=d;
2 26 Feb 07 jari 153       return o;
2 26 Feb 07 jari 154   };
2 26 Feb 07 jari 155   if (xt==XT_BOOL) {
2 26 Feb 07 jari 156       x.cont=new RBool(buf[o]); o++;
2 26 Feb 07 jari 157       if (o!=eox) {
2 26 Feb 07 jari 158                 if (eox!=o+3) // o+3 could happen if the result was aligned (1 byte data + 3 bytes padding)
2 26 Feb 07 jari 159                     System.out.println("Warning: bool SEXP size mismatch\n");
2 26 Feb 07 jari 160     o=eox;
2 26 Feb 07 jari 161       };
2 26 Feb 07 jari 162       return o;
2 26 Feb 07 jari 163   };
2 26 Feb 07 jari 164   if (xt==XT_ARRAY_BOOL_UA) {
2 26 Feb 07 jari 165       int as=(eox-o), i=0;
2 26 Feb 07 jari 166             x.Xt=XT_ARRAY_BOOL; // XT_ARRAY_BOOL_UA is only old transport type for XT_ARRAY_BOOL
2 26 Feb 07 jari 167       RBool[] d=new RBool[as];
2 26 Feb 07 jari 168       while(o<eox) {
2 26 Feb 07 jari 169     d[i]=new RBool(buf[o]);
2 26 Feb 07 jari 170     i++; o++;
2 26 Feb 07 jari 171       };
2 26 Feb 07 jari 172       x.cont=d;
2 26 Feb 07 jari 173       return o;
2 26 Feb 07 jari 174   };
2 26 Feb 07 jari 175         if (xt==XT_ARRAY_BOOL) {
2 26 Feb 07 jari 176             int as=Rtalk.getInt(buf,o);
2 26 Feb 07 jari 177             o+=4;
2 26 Feb 07 jari 178             int i=0;
2 26 Feb 07 jari 179             RBool[] d=new RBool[as];
2 26 Feb 07 jari 180             while(o<eox && i<as) {
2 26 Feb 07 jari 181                 d[i]=new RBool(buf[o]);
2 26 Feb 07 jari 182                 i++; o++;
2 26 Feb 07 jari 183             }
2 26 Feb 07 jari 184       // skip the padding
2 26 Feb 07 jari 185       while ((i&3)!=0) { i++; o++; };
2 26 Feb 07 jari 186             x.cont=d;
2 26 Feb 07 jari 187             return o;
2 26 Feb 07 jari 188         };
2 26 Feb 07 jari 189         if (xt==XT_INT) {
2 26 Feb 07 jari 190       x.cont=new Integer(Rtalk.getInt(buf,o));
2 26 Feb 07 jari 191       o+=4;
2 26 Feb 07 jari 192       if (o!=eox) {
2 26 Feb 07 jari 193     System.out.println("Warning: int SEXP size mismatch\n");
2 26 Feb 07 jari 194     o=eox;
2 26 Feb 07 jari 195       };
2 26 Feb 07 jari 196       return o;
2 26 Feb 07 jari 197   }
2 26 Feb 07 jari 198   if (xt==XT_ARRAY_INT) {
2 26 Feb 07 jari 199       int as=(eox-o)/4,i=0;
2 26 Feb 07 jari 200       int[] d=new int[as];
2 26 Feb 07 jari 201       while (o<eox) {
2 26 Feb 07 jari 202     d[i]=Rtalk.getInt(buf,o);
2 26 Feb 07 jari 203     o+=4;
2 26 Feb 07 jari 204     i++;
2 26 Feb 07 jari 205       };
2 26 Feb 07 jari 206       if (o!=eox) {
2 26 Feb 07 jari 207     System.out.println("Warning: int array SEXP size mismatch\n");
2 26 Feb 07 jari 208     o=eox;
2 26 Feb 07 jari 209       };
2 26 Feb 07 jari 210       x.cont=d;
2 26 Feb 07 jari 211       // hack for lists - special lists attached to int are factors
2 26 Feb 07 jari 212       if (x.attr!=null && x.attr.Xt==XT_LIST && x.attr.cont!=null &&
2 26 Feb 07 jari 213     ((RList)x.attr.cont).head!=null &&
2 26 Feb 07 jari 214     ((RList)x.attr.cont).body!=null &&
2 26 Feb 07 jari 215     ((RList)x.attr.cont).head.cont!=null &&
2 26 Feb 07 jari 216     ((RList)x.attr.cont).body.cont!=null &&
2 26 Feb 07 jari 217     ((RList)x.attr.cont).head.Xt==XT_VECTOR &&
2 26 Feb 07 jari 218     ((RList)x.attr.cont).body.Xt==XT_LIST &&
2 26 Feb 07 jari 219     ((RList)((RList)x.attr.cont).body.cont).head!=null &&
2 26 Feb 07 jari 220     ((RList)((RList)x.attr.cont).body.cont).head.Xt==XT_STR &&
2 26 Feb 07 jari 221     ((String)((RList)((RList)x.attr.cont).body.cont).head.cont).compareTo("factor")==0) {
2 26 Feb 07 jari 222     RFactor f=new RFactor(d,(Vector)((RList)x.attr.cont).head.cont);
2 26 Feb 07 jari 223     x.cont=f;
2 26 Feb 07 jari 224     x.Xt=XT_FACTOR;
2 26 Feb 07 jari 225     x.attr=null;
2 26 Feb 07 jari 226       };
2 26 Feb 07 jari 227       return o;
2 26 Feb 07 jari 228   };
2 26 Feb 07 jari 229   if (xt==XT_VECTOR) {
2 26 Feb 07 jari 230       Vector v=new Vector();
2 26 Feb 07 jari 231       while(o<eox) {
2 26 Feb 07 jari 232     REXP xx=new REXP();
2 26 Feb 07 jari 233     o=parseREXP(xx,buf,o);
2 26 Feb 07 jari 234     v.addElement(xx);
2 26 Feb 07 jari 235       };
2 26 Feb 07 jari 236       if (o!=eox) {
2 26 Feb 07 jari 237     System.out.println("Warning: int vector SEXP size mismatch\n");
2 26 Feb 07 jari 238     o=eox;
2 26 Feb 07 jari 239       };
2 26 Feb 07 jari 240       x.cont=v;
2 26 Feb 07 jari 241       // fixup for lists since they're stored as attributes of vectors
2 26 Feb 07 jari 242       if (x.attr!=null && x.attr.Xt==XT_LIST && x.attr.cont!=null) {
2 26 Feb 07 jari 243     RList l=new RList();
2 26 Feb 07 jari 244     l.head=((RList)x.attr.cont).head;
2 26 Feb 07 jari 245     l.body=new REXP(XT_VECTOR,v);
2 26 Feb 07 jari 246     x.cont=l;
2 26 Feb 07 jari 247     x.Xt=XT_LIST; x.attr=x.attr.attr;
2 26 Feb 07 jari 248     // one more hack: we're de-vectorizing strings if alone
2 26 Feb 07 jari 249     // so we should invert that in case of list heads
2 26 Feb 07 jari 250     if (l.head.Xt==XT_STR) {
2 26 Feb 07 jari 251         Vector sv=new Vector();
2 26 Feb 07 jari 252         sv.addElement(l.head);
2 26 Feb 07 jari 253         l.head=new REXP(XT_VECTOR,sv,l.head.attr);
2 26 Feb 07 jari 254         l.head.attr=null;
2 26 Feb 07 jari 255     };
2 26 Feb 07 jari 256       };
2 26 Feb 07 jari 257       return o;
2 26 Feb 07 jari 258   };
2 26 Feb 07 jari 259   if (xt==XT_STR) {
2 26 Feb 07 jari 260       int i=o;
2 26 Feb 07 jari 261       while (buf[i]!=0 && i<eox) i++;
2 26 Feb 07 jari 262       try {
2 26 Feb 07 jari 263     x.cont=new String(buf,o,i-o,Rconnection.transferCharset);
2 26 Feb 07 jari 264       } catch(Exception e) {
2 26 Feb 07 jari 265     System.out.println("unable to convert string\n");
2 26 Feb 07 jari 266     x.cont=null;
2 26 Feb 07 jari 267       };
2 26 Feb 07 jari 268       o=eox;
2 26 Feb 07 jari 269       return o;
2 26 Feb 07 jari 270   };
2 26 Feb 07 jari 271   if (xt==XT_LIST || xt==XT_LANG) {
2 26 Feb 07 jari 272       RList rl=new RList();
2 26 Feb 07 jari 273       rl.head=new REXP();
2 26 Feb 07 jari 274       rl.body=new REXP();
2 26 Feb 07 jari 275       rl.tag=null;
2 26 Feb 07 jari 276       o=parseREXP(rl.head,buf,o); // CAR
2 26 Feb 07 jari 277       o=parseREXP(rl.body,buf,o); // CDR
2 26 Feb 07 jari 278       if (o!=eox) {
2 26 Feb 07 jari 279     // if there is more data then it's presumably the TAG entry
2 26 Feb 07 jari 280     rl.tag=new REXP();
2 26 Feb 07 jari 281     o=parseREXP(rl.tag,buf,o);
2 26 Feb 07 jari 282     if (o!=eox) {
2 26 Feb 07 jari 283         System.out.println("Warning: list SEXP size mismatch\n");
2 26 Feb 07 jari 284         o=eox;
2 26 Feb 07 jari 285     }
2 26 Feb 07 jari 286       };
2 26 Feb 07 jari 287       x.cont=rl;
2 26 Feb 07 jari 288       return o;
2 26 Feb 07 jari 289   };
2 26 Feb 07 jari 290
2 26 Feb 07 jari 291   if (xt==XT_SYM) {
2 26 Feb 07 jari 292       REXP sym=new REXP();
2 26 Feb 07 jari 293       o=parseREXP(sym,buf,o); // PRINTNAME that's all we will use
2 26 Feb 07 jari 294       String s=null;
2 26 Feb 07 jari 295       if (sym.Xt==XT_STR) s=(String)sym.cont; else s=sym.toString();
2 26 Feb 07 jari 296       x.cont=s; // content of a symbol is its printname string (so far)
2 26 Feb 07 jari 297       o=eox;
2 26 Feb 07 jari 298       return o;
2 26 Feb 07 jari 299   }
2 26 Feb 07 jari 300
2 26 Feb 07 jari 301   if (xt==XT_CLOS) {
2 26 Feb 07 jari 302       REXP form=new REXP();
2 26 Feb 07 jari 303       REXP body=new REXP();
2 26 Feb 07 jari 304       o=parseREXP(form,buf,o);
2 26 Feb 07 jari 305       o=parseREXP(body,buf,o);
2 26 Feb 07 jari 306       if (o!=eox) {
2 26 Feb 07 jari 307     System.out.println("Warning: closure SEXP size mismatch\n");
2 26 Feb 07 jari 308     o=eox;
2 26 Feb 07 jari 309       }
2 26 Feb 07 jari 310             /* curently closures are not coded into their own objects, basically due to lack of demand. */
2 26 Feb 07 jari 311       x.cont=body;
2 26 Feb 07 jari 312       return o;
2 26 Feb 07 jari 313   }
2 26 Feb 07 jari 314
2 26 Feb 07 jari 315   if (xt==XT_UNKNOWN) {
2 26 Feb 07 jari 316       x.cont=new Integer(Rtalk.getInt(buf,o));
2 26 Feb 07 jari 317       o=eox;
2 26 Feb 07 jari 318       return o;
2 26 Feb 07 jari 319   }
2 26 Feb 07 jari 320
2 26 Feb 07 jari 321   x.cont=null;
2 26 Feb 07 jari 322   o=eox;
2 26 Feb 07 jari 323   System.out.println("unhandled type: "+xt);
2 26 Feb 07 jari 324   return o;
2 26 Feb 07 jari 325     }
2 26 Feb 07 jari 326
2 26 Feb 07 jari 327     /** Calculates the length of the binary representation of the REXP including all headers. This is the amount of memory necessary to store the REXP via {@link #getBinaryRepresentation}.
2 26 Feb 07 jari 328         <p>Please note that currently only XT_[ARRAY_]INT, XT_[ARRAY_]DOUBLE and XT_[ARRAY_]STR are supported! All other types will return 4 which is the size of the header.
2 26 Feb 07 jari 329         @return length of the REXP including headers (4 or 8 bytes)*/
2 26 Feb 07 jari 330     public int getBinaryLength() {
2 26 Feb 07 jari 331   int l=0;
2 26 Feb 07 jari 332   switch (Xt) {
2 26 Feb 07 jari 333   case XT_INT: l=4; break;
2 26 Feb 07 jari 334   case XT_DOUBLE: l=8; break;
2 26 Feb 07 jari 335   case XT_STR: l=(cont==null)?1:((String)cont).length()+1; break;
2 26 Feb 07 jari 336   case XT_ARRAY_INT: l=(cont==null)?0:((int[])cont).length*4; break;
2 26 Feb 07 jari 337   case XT_ARRAY_DOUBLE: l=(cont==null)?0:((double[])cont).length*8; break;
2 26 Feb 07 jari 338   case XT_ARRAY_STR:
2 26 Feb 07 jari 339     if (cachedBinaryLength<0) { // if there's no cache, we have to count..
2 26 Feb 07 jari 340       if (cont==null) cachedBinaryLength=4; else {
2 26 Feb 07 jari 341         String sa[]=(String[])cont;
2 26 Feb 07 jari 342         int i=0, io=0;
2 26 Feb 07 jari 343         while (i<sa.length) {
2 26 Feb 07 jari 344     if (sa[i]!=null) {
2 26 Feb 07 jari 345       try {
2 26 Feb 07 jari 346         byte b[]=sa[i].getBytes(Rconnection.transferCharset);
2 26 Feb 07 jari 347         io+=b.length;
2 26 Feb 07 jari 348         b=null;
2 26 Feb 07 jari 349       } catch (java.io.UnsupportedEncodingException uex) {
2 26 Feb 07 jari 350         // FIXME: we should so something ... so far we hope noone's gonna mess with the encoding
2 26 Feb 07 jari 351       }
2 26 Feb 07 jari 352     }
2 26 Feb 07 jari 353     io++;
2 26 Feb 07 jari 354     i++;
2 26 Feb 07 jari 355         }
2 26 Feb 07 jari 356         while ((io&3)!=0) io++;
2 26 Feb 07 jari 357         cachedBinaryLength=io+4;
2 26 Feb 07 jari 358         if (cachedBinaryLength>0xfffff0)
2 26 Feb 07 jari 359     cachedBinaryLength+=4;
2 26 Feb 07 jari 360       }
2 26 Feb 07 jari 361     }
2 26 Feb 07 jari 362     return (int)cachedBinaryLength;
2 26 Feb 07 jari 363   } // switch
2 26 Feb 07 jari 364         if (l>0xfffff0) l+=4; // large data need 4 more bytes
2 26 Feb 07 jari 365   return l+4;
2 26 Feb 07 jari 366     }
2 26 Feb 07 jari 367
2 26 Feb 07 jari 368     /** Stores the REXP in its binary (ready-to-send) representation including header into a buffer and returns the index of the byte behind the REXP.
2 26 Feb 07 jari 369         <p>Please note that currently only XT_[ARRAY_]INT, XT_[ARRAY_]DOUBLE and XT_[ARRAY_]STR are supported! All other types will be stored as SEXP of the length 0 without any contents.
2 26 Feb 07 jari 370         @param buf buffer to store the REXP binary into
2 26 Feb 07 jari 371         @param off offset of the first byte where to store the REXP
2 26 Feb 07 jari 372         @return the offset of the first byte behind the stored REXP */
2 26 Feb 07 jari 373     public int getBinaryRepresentation(byte[] buf, int off) {
2 26 Feb 07 jari 374   int myl=getBinaryLength();
2 26 Feb 07 jari 375         boolean isLarge=(myl>0xfffff0);
2 26 Feb 07 jari 376         Rtalk.setHdr(Xt,myl-(isLarge?8:4),buf,off);
2 26 Feb 07 jari 377         off+=(isLarge?8:4);
2 26 Feb 07 jari 378   switch (Xt) {
2 26 Feb 07 jari 379   case XT_INT: Rtalk.setInt(asInt(),buf,off); break;
2 26 Feb 07 jari 380   case XT_DOUBLE: Rtalk.setLong(Double.doubleToLongBits(asDouble()),buf,off); break;
2 26 Feb 07 jari 381   case XT_ARRAY_INT:
2 26 Feb 07 jari 382       if (cont!=null) {
2 26 Feb 07 jari 383     int ia[]=(int[])cont;
2 26 Feb 07 jari 384     int i=0, io=off;
2 26 Feb 07 jari 385     while(i<ia.length) {
2 26 Feb 07 jari 386         Rtalk.setInt(ia[i++],buf,io); io+=4;
2 26 Feb 07 jari 387     }
2 26 Feb 07 jari 388       }
2 26 Feb 07 jari 389       break;
2 26 Feb 07 jari 390   case XT_ARRAY_DOUBLE:
2 26 Feb 07 jari 391       if (cont!=null) {
2 26 Feb 07 jari 392     double da[]=(double[])cont;
2 26 Feb 07 jari 393     int i=0, io=off;
2 26 Feb 07 jari 394     while(i<da.length) {
2 26 Feb 07 jari 395         Rtalk.setLong(Double.doubleToLongBits(da[i++]),buf,io); io+=8;
2 26 Feb 07 jari 396     }
2 26 Feb 07 jari 397       }
2 26 Feb 07 jari 398       break;
2 26 Feb 07 jari 399   case XT_ARRAY_STR:
2 26 Feb 07 jari 400     if (cont!=null) {
2 26 Feb 07 jari 401       String sa[]=(String[])cont;
2 26 Feb 07 jari 402       int i=0, io=off;
2 26 Feb 07 jari 403       while (i<sa.length) {
2 26 Feb 07 jari 404         if (sa[i]!=null) {
2 26 Feb 07 jari 405     try {
2 26 Feb 07 jari 406       byte b[]=sa[i].getBytes(Rconnection.transferCharset);
2 26 Feb 07 jari 407       System.arraycopy(b,0,buf,io,b.length);
2 26 Feb 07 jari 408       io+=b.length;
2 26 Feb 07 jari 409       b=null;
2 26 Feb 07 jari 410     } catch (java.io.UnsupportedEncodingException uex) {
2 26 Feb 07 jari 411       // FIXME: we should so something ... so far we hope noone's gonna mess with the encoding
2 26 Feb 07 jari 412     }
2 26 Feb 07 jari 413         }
2 26 Feb 07 jari 414         buf[io++]=0;
2 26 Feb 07 jari 415         i++;
2 26 Feb 07 jari 416       }
2 26 Feb 07 jari 417       i=io-off;
2 26 Feb 07 jari 418       while ((i&3)!=0) { buf[io++]=1; i++; } // padding if necessary..
2 26 Feb 07 jari 419     }
2 26 Feb 07 jari 420   }
2 26 Feb 07 jari 421   return off+myl;
2 26 Feb 07 jari 422     }
2 26 Feb 07 jari 423
2 26 Feb 07 jari 424     /** returns human-readable name of the xpression type as string. Arrays are denoted by a trailing asterisk (*).
2 26 Feb 07 jari 425   @param xt xpression type
2 26 Feb 07 jari 426   @return name of the xpression type */
2 26 Feb 07 jari 427     public static String xtName(int xt) {
2 26 Feb 07 jari 428   if (xt==XT_NULL) return "NULL";
2 26 Feb 07 jari 429   if (xt==XT_INT) return "INT";
2 26 Feb 07 jari 430   if (xt==XT_STR) return "STRING";
2 26 Feb 07 jari 431   if (xt==XT_DOUBLE) return "REAL";
2 26 Feb 07 jari 432   if (xt==XT_BOOL) return "BOOL";
2 26 Feb 07 jari 433   if (xt==XT_ARRAY_INT) return "INT*";
2 26 Feb 07 jari 434   if (xt==XT_ARRAY_STR) return "STRING*";
2 26 Feb 07 jari 435   if (xt==XT_ARRAY_DOUBLE) return "REAL*";
2 26 Feb 07 jari 436   if (xt==XT_ARRAY_BOOL) return "BOOL*";
2 26 Feb 07 jari 437   if (xt==XT_SYM) return "SYMBOL";
2 26 Feb 07 jari 438   if (xt==XT_LANG) return "LANG";
2 26 Feb 07 jari 439   if (xt==XT_LIST) return "LIST";
2 26 Feb 07 jari 440   if (xt==XT_CLOS) return "CLOS";
2 26 Feb 07 jari 441   if (xt==XT_VECTOR) return "VECTOR";
2 26 Feb 07 jari 442   if (xt==XT_FACTOR) return "FACTOR";
2 26 Feb 07 jari 443   if (xt==XT_UNKNOWN) return "UNKNOWN";
2 26 Feb 07 jari 444   return "<unknown "+xt+">";
2 26 Feb 07 jari 445     }  
2 26 Feb 07 jari 446
2 26 Feb 07 jari 447     /** get content of the REXP as string (if it is one)
2 26 Feb 07 jari 448         @return string content or <code>null</code> if the REXP is no string */
2 26 Feb 07 jari 449     public String asString() {
2 26 Feb 07 jari 450         return (Xt==XT_STR)?(String)cont:null;
2 26 Feb 07 jari 451     }
2 26 Feb 07 jari 452
2 26 Feb 07 jari 453     /** get content of the REXP as int (if it is one)
2 26 Feb 07 jari 454         @return int content or 0 if the REXP is no integer */
2 26 Feb 07 jari 455     public int asInt() {
2 26 Feb 07 jari 456         if (Xt==XT_ARRAY_INT) {
2 26 Feb 07 jari 457             int i[]=(int[])cont;
2 26 Feb 07 jari 458             if (i!=null && i.length>0) return i[0];
2 26 Feb 07 jari 459         }
2 26 Feb 07 jari 460         return (Xt==XT_INT)?((Integer)cont).intValue():0;
2 26 Feb 07 jari 461     }
2 26 Feb 07 jari 462
2 26 Feb 07 jari 463     /** get content of the REXP as double (if it is one)
2 26 Feb 07 jari 464         @return double content or 0.0 if the REXP is no double */
2 26 Feb 07 jari 465     public double asDouble() {
2 26 Feb 07 jari 466         if (Xt==XT_ARRAY_DOUBLE) {
2 26 Feb 07 jari 467             double d[]=(double[])cont;
2 26 Feb 07 jari 468             if (d!=null && d.length>0) return d[0];
2 26 Feb 07 jari 469         }
2 26 Feb 07 jari 470         return (Xt==XT_DOUBLE)?((Double)cont).doubleValue():0.0;
2 26 Feb 07 jari 471     }
2 26 Feb 07 jari 472
2 26 Feb 07 jari 473     /** get content of the REXP as {@link Vector} (if it is one)
2 26 Feb 07 jari 474         @return Vector content or <code>null</code> if the REXP is no Vector */
2 26 Feb 07 jari 475     public Vector asVector() {
2 26 Feb 07 jari 476         return (Xt==XT_VECTOR)?(Vector)cont:null;
2 26 Feb 07 jari 477     }
2 26 Feb 07 jari 478
2 26 Feb 07 jari 479     /** get content of the REXP as {@link RFactor} (if it is one)
2 26 Feb 07 jari 480         @return {@link RFactor} content or <code>null</code> if the REXP is no factor */
2 26 Feb 07 jari 481     public RFactor asFactor() {
2 26 Feb 07 jari 482         return (Xt==XT_FACTOR)?(RFactor)cont:null;
2 26 Feb 07 jari 483     }
2 26 Feb 07 jari 484
2 26 Feb 07 jari 485     /** get content of the REXP as {@link RList} (if it is one)
2 26 Feb 07 jari 486         @return {@link RList} content or <code>null</code> if the REXP is no list */
2 26 Feb 07 jari 487     public RList asList() {
2 26 Feb 07 jari 488         return (Xt==XT_LIST)?(RList)cont:null;
2 26 Feb 07 jari 489     }
2 26 Feb 07 jari 490
2 26 Feb 07 jari 491     /** get content of the REXP as {@link RBool} (if it is one)
2 26 Feb 07 jari 492         @return {@link RBool} content or <code>null</code> if the REXP is no logical value */
2 26 Feb 07 jari 493     public RBool asBool() {
2 26 Feb 07 jari 494         return (Xt==XT_BOOL)?(RBool)cont:null;
2 26 Feb 07 jari 495     }
2 26 Feb 07 jari 496
2 26 Feb 07 jari 497     /** get content of the REXP as an array of doubles. Array of integers, single double and single integer are automatically converted into such an array if necessary.
2 26 Feb 07 jari 498         @return double[] content or <code>null</code> if the REXP is not a array of doubles or integers */
2 26 Feb 07 jari 499     public double[] asDoubleArray() {
2 26 Feb 07 jari 500         if (Xt==XT_ARRAY_DOUBLE) return (double[])cont;
2 26 Feb 07 jari 501         if (Xt==XT_DOUBLE) {
2 26 Feb 07 jari 502             double[] d=new double[1]; d[0]=asDouble(); return d;
2 26 Feb 07 jari 503         }
2 26 Feb 07 jari 504         if (Xt==XT_INT) {
2 26 Feb 07 jari 505             double[] d=new double[1]; d[0]=((Integer)cont).doubleValue(); return d;
2 26 Feb 07 jari 506         }
2 26 Feb 07 jari 507         if (Xt==XT_ARRAY_INT) {
2 26 Feb 07 jari 508             int[] i=asIntArray();
2 26 Feb 07 jari 509             if (i==null) return null;
2 26 Feb 07 jari 510             double[] d=new double[i.length];
2 26 Feb 07 jari 511             int j=0;
2 26 Feb 07 jari 512             while (j<i.length) {
2 26 Feb 07 jari 513                 d[j]=(double)i[j]; j++;
2 26 Feb 07 jari 514             }
2 26 Feb 07 jari 515             return d;
2 26 Feb 07 jari 516         }
2 26 Feb 07 jari 517         return null;
2 26 Feb 07 jari 518     }
2 26 Feb 07 jari 519
2 26 Feb 07 jari 520     /** get content of the REXP as an array of integers. Unlike {@link #asDoubleArray} <u>NO</u> automatic conversion is done if the content is not an array of the correct type, because there is no canonical representation of doubles as integers. A single integer is returned as an array of the length 1.
2 26 Feb 07 jari 521         @return double[] content or <code>null</code> if the REXP is not a array of  integers */
2 26 Feb 07 jari 522     public int[] asIntArray() {
2 26 Feb 07 jari 523         if (Xt==XT_ARRAY_INT) return (int[])cont;
2 26 Feb 07 jari 524         if (Xt==XT_INT) {
2 26 Feb 07 jari 525             int[] i=new int[1]; i[0]=asInt(); return i;
2 26 Feb 07 jari 526         }
2 26 Feb 07 jari 527         return null;
2 26 Feb 07 jari 528     }
2 26 Feb 07 jari 529
2 26 Feb 07 jari 530     /** returns the content of the REXP as a matrix of doubles (2D-array: m[rows][cols]). This is the same form as used by popular math packages for Java, such as JAMA. This means that following leads to desired results:<br>
2 26 Feb 07 jari 531         <code>Matrix m=new Matrix(c.eval("matrix(c(1,2,3,4,5,6),2,3)").asDoubleMatrix());</code>
2 26 Feb 07 jari 532         @return 2D array of doubles in the form double[rows][cols] or <code>null</code> if the contents is no 2-dimensional matrix of doubles */
2 26 Feb 07 jari 533     public double[][] asDoubleMatrix() {
2 26 Feb 07 jari 534         if (Xt!=XT_ARRAY_DOUBLE || attr==null || attr.Xt!=XT_LIST) return null;
2 26 Feb 07 jari 535         REXP dim=attr.asList().getHead();
2 26 Feb 07 jari 536         if (dim==null || dim.Xt!=XT_ARRAY_INT) return null; // we need dimension attr
2 26 Feb 07 jari 537         int[] ds=dim.asIntArray();
2 26 Feb 07 jari 538         if (ds==null || ds.length!=2) return null; // matrix must be 2-dimensional
2 26 Feb 07 jari 539         int m=ds[0], n=ds[1];
2 26 Feb 07 jari 540         double[][] r=new double[m][n];
2 26 Feb 07 jari 541         double[] ct=asDoubleArray();
2 26 Feb 07 jari 542         if (ct==null) return null;
2 26 Feb 07 jari 543         // R stores matrices as matrix(c(1,2,3,4),2,2) = col1:(1,2), col2:(3,4)
2 26 Feb 07 jari 544         // we need to copy everything, since we create 2d array from 1d array
2 26 Feb 07 jari 545         int i=0,k=0;
2 26 Feb 07 jari 546         while (i<n) {
2 26 Feb 07 jari 547             int j=0;
2 26 Feb 07 jari 548             while (j<m) {
2 26 Feb 07 jari 549                 r[j++][i]=ct[k++];
2 26 Feb 07 jari 550             }
2 26 Feb 07 jari 551             i++;
2 26 Feb 07 jari 552         }
2 26 Feb 07 jari 553         return r;
2 26 Feb 07 jari 554     }
2 26 Feb 07 jari 555
2 26 Feb 07 jari 556     /** this is just an alias for {@link #asDoubleMatrix()}. */
2 26 Feb 07 jari 557     public double[][] asMatrix() {
2 26 Feb 07 jari 558         return asDoubleMatrix();
2 26 Feb 07 jari 559     }
2 26 Feb 07 jari 560     
2 26 Feb 07 jari 561     /** displayable contents of the expression. The expression is traversed recursively if aggregation types are used (Vector, List, etc.)
2 26 Feb 07 jari 562         @return String descriptive representation of the xpression */
2 26 Feb 07 jari 563     public String toString() {
2 26 Feb 07 jari 564   StringBuffer sb=
2 26 Feb 07 jari 565       new StringBuffer("["+xtName(Xt)+" ");
2 26 Feb 07 jari 566   if (attr!=null) sb.append("\nattr="+attr+"\n ");
2 26 Feb 07 jari 567   if (Xt==XT_DOUBLE) sb.append((Double)cont);
2 26 Feb 07 jari 568   if (Xt==XT_INT) sb.append((Integer)cont);
2 26 Feb 07 jari 569   if (Xt==XT_BOOL) sb.append((RBool)cont);
2 26 Feb 07 jari 570   if (Xt==XT_FACTOR) sb.append((RFactor)cont);
2 26 Feb 07 jari 571   if (Xt==XT_ARRAY_DOUBLE) {
2 26 Feb 07 jari 572       double[] d=(double[])cont;
2 26 Feb 07 jari 573       sb.append("(");
2 26 Feb 07 jari 574       for(int i=0; i<d.length; i++) {
2 26 Feb 07 jari 575     sb.append(d[i]);
2 26 Feb 07 jari 576     if (i<d.length-1) sb.append(", ");
2 26 Feb 07 jari 577                 if (i==99) {
2 26 Feb 07 jari 578                     sb.append("... ("+(d.length-100)+" more values follow)");
2 26 Feb 07 jari 579                     break;
2 26 Feb 07 jari 580                 }
2 26 Feb 07 jari 581       };
2 26 Feb 07 jari 582       sb.append(")");
2 26 Feb 07 jari 583   };
2 26 Feb 07 jari 584   if (Xt==XT_ARRAY_INT) {
2 26 Feb 07 jari 585       int[] d=(int[])cont;
2 26 Feb 07 jari 586       sb.append("(");
2 26 Feb 07 jari 587       for(int i=0; i<d.length; i++) {
2 26 Feb 07 jari 588     sb.append(d[i]);
2 26 Feb 07 jari 589     if (i<d.length-1) sb.append(", ");
2 26 Feb 07 jari 590                 if (i==99) {
2 26 Feb 07 jari 591                     sb.append("... ("+(d.length-100)+" more values follow)");
2 26 Feb 07 jari 592                     break;
2 26 Feb 07 jari 593                 }
2 26 Feb 07 jari 594             };
2 26 Feb 07 jari 595       sb.append(")");
2 26 Feb 07 jari 596   };
2 26 Feb 07 jari 597   if (Xt==XT_ARRAY_BOOL) {
2 26 Feb 07 jari 598       RBool[] d=(RBool[])cont;
2 26 Feb 07 jari 599       sb.append("(");
2 26 Feb 07 jari 600       for(int i=0; i<d.length; i++) {
2 26 Feb 07 jari 601     sb.append(d[i]);
2 26 Feb 07 jari 602     if (i<d.length-1) sb.append(", ");
2 26 Feb 07 jari 603       };
2 26 Feb 07 jari 604       sb.append(")");
2 26 Feb 07 jari 605   };
2 26 Feb 07 jari 606   if (Xt==XT_VECTOR) {
2 26 Feb 07 jari 607       Vector v=(Vector)cont;
2 26 Feb 07 jari 608       sb.append("(");
2 26 Feb 07 jari 609       for(int i=0; i<v.size(); i++) {
2 26 Feb 07 jari 610     sb.append(((REXP)v.elementAt(i)).toString());
2 26 Feb 07 jari 611     if (i<v.size()-1) sb.append(", ");
2 26 Feb 07 jari 612       };
2 26 Feb 07 jari 613       sb.append(")");
2 26 Feb 07 jari 614   };
2 26 Feb 07 jari 615   if (Xt==XT_STR) {
2 26 Feb 07 jari 616       sb.append("\"");
2 26 Feb 07 jari 617       sb.append((String)cont);
2 26 Feb 07 jari 618       sb.append("\"");
2 26 Feb 07 jari 619   };
2 26 Feb 07 jari 620   if (Xt==XT_SYM) {
2 26 Feb 07 jari 621       sb.append((String)cont);
2 26 Feb 07 jari 622   };
2 26 Feb 07 jari 623   if (Xt==XT_LIST || Xt==XT_LANG) {
2 26 Feb 07 jari 624       RList l=(RList)cont;
2 26 Feb 07 jari 625       sb.append(l.head); sb.append(" <-> ");
2 26 Feb 07 jari 626       sb.append(l.body);
2 26 Feb 07 jari 627   };
2 26 Feb 07 jari 628   if (Xt==XT_UNKNOWN) sb.append((Integer)cont);
2 26 Feb 07 jari 629   sb.append("]");
2 26 Feb 07 jari 630   return sb.toString();
2 26 Feb 07 jari 631     };
2 26 Feb 07 jari 632 }