001 package railo.runtime.interpreter; 002 003 import railo.commons.lang.ParserString; 004 import railo.commons.lang.StringList; 005 import railo.commons.lang.StringUtil; 006 import railo.runtime.PageContext; 007 import railo.runtime.PageContextImpl; 008 import railo.runtime.exp.ExpressionException; 009 import railo.runtime.exp.PageException; 010 import railo.runtime.op.Caster; 011 import railo.runtime.type.Collection; 012 import railo.runtime.type.KeyImpl; 013 import railo.runtime.type.Scope; 014 import railo.runtime.type.ref.VariableReference; 015 import railo.runtime.type.scope.Argument; 016 import railo.runtime.type.scope.CallerImpl; 017 import railo.runtime.type.scope.ScopeSupport; 018 import railo.runtime.type.scope.UndefinedImpl; 019 import railo.runtime.type.scope.Variables; 020 021 /** 022 * Class to check and interpret Variable Strings 023 */ 024 public final class VariableInterpreter { 025 026 private static final Object NULL = new Object(); 027 028 /** 029 * reads a subelement from a struct 030 * @param pc 031 * @param collection 032 * @param var 033 * @return matching Object 034 * @throws PageException 035 */ 036 public static Object getVariable(PageContext pc, Collection collection,String var) throws PageException { 037 StringList list = parse(pc,new ParserString(var),false); 038 if(list==null) throw new ExpressionException("invalid variable declaration ["+var+"]"); 039 040 while(list.hasNextNext()) { 041 collection=Caster.toCollection(collection.get(list.next())); 042 } 043 return collection.get(list.next()); 044 } 045 046 public static String scopeInt2String(int type) { 047 switch(type) { 048 case Scope.SCOPE_APPLICATION: return "application"; 049 case Scope.SCOPE_ARGUMENTS: return "arguments"; 050 case Scope.SCOPE_CGI: return "cgi"; 051 case Scope.SCOPE_COOKIE: return "cookie"; 052 case Scope.SCOPE_CLIENT: return "client"; 053 case Scope.SCOPE_FORM: return "form"; 054 case Scope.SCOPE_REQUEST: return "request"; 055 case Scope.SCOPE_SESSION: return "session"; 056 case Scope.SCOPE_SERVER: return "server"; 057 case Scope.SCOPE_URL: return "url"; 058 case Scope.SCOPE_VARIABLES: return "variables"; 059 case Scope.SCOPE_CLUSTER: return "cluster"; 060 } 061 return null; 062 } 063 064 065 public static Object getVariableEL(PageContext pc, Collection collection,String var) { 066 StringList list = parse(pc,new ParserString(var),false); 067 if(list==null) return null; 068 069 while(list.hasNextNext()) { 070 collection=Caster.toCollection(collection.get(list.next(),null),null); 071 if(collection==null) return null; 072 } 073 return collection.get(list.next(),null); 074 } 075 076 /** 077 * get a variable from page context 078 * @param pc Page Context 079 * @param var variable string to get value to 080 * @return the value 081 * @throws PageException 082 */ 083 public static Object getVariable(PageContext pc,String var) throws PageException { 084 StringList list = parse(pc,new ParserString(var),false); 085 if(list==null) throw new ExpressionException("invalid variable declaration ["+var+"]"); 086 087 int scope=scopeString2Int(list.next()); 088 Object coll =null; 089 if(scope==Scope.SCOPE_UNDEFINED) { 090 coll=pc.undefinedScope().get(list.current()); 091 } 092 else { 093 coll=VariableInterpreter.scope(pc, scope, list.hasNext()); 094 //coll=pc.scope(scope); 095 } 096 097 while(list.hasNext()) { 098 coll=pc.getVariableUtil().get(pc,coll,list.next()); 099 } 100 return coll; 101 } 102 103 104 public static Object getVariable(PageContext pc,String str,Scope scope) throws PageException { 105 return _variable(pc, str,NULL, scope); 106 } 107 public static Object setVariable(PageContext pc,String str,Object value,Scope scope) throws PageException { 108 return _variable(pc, str,value, scope); 109 } 110 111 public static Object _variable(PageContext pc,String str,Object value,Scope scope) throws PageException { 112 // define a ohter enviroment for the function 113 if(scope!=null){ 114 115 // Variables Scope 116 Variables var=null; 117 if(scope instanceof Variables){ 118 var=(Variables) scope; 119 } 120 else if(scope instanceof CallerImpl){ 121 var=((CallerImpl) scope).getVariablesScope(); 122 } 123 if(var!=null){ 124 Variables current=pc.variablesScope(); 125 pc.setVariablesScope(var); 126 try{ 127 if(value!=NULL) return setVariable(pc, str,value); 128 return getVariable(pc, str); 129 } 130 finally{ 131 pc.setVariablesScope(current); 132 } 133 } 134 135 // Undefined Scope 136 else if(scope instanceof UndefinedImpl) { 137 PageContextImpl pci=(PageContextImpl) pc; 138 UndefinedImpl undefined=(UndefinedImpl) scope; 139 140 boolean check=undefined.getCheckArguments(); 141 Variables orgVar=pc.variablesScope(); 142 Argument orgArgs=pc.argumentsScope(); 143 Scope orgLocal=pc.localScope(); 144 145 pci.setVariablesScope(undefined.variablesScope()); 146 if(check)pci.setFunctionScopes(undefined.localScope(), undefined.argumentsScope()); 147 try{ 148 if(value!=NULL) return setVariable(pc, str,value); 149 return getVariable(pc, str); 150 } 151 finally{ 152 pc.setVariablesScope(orgVar); 153 if(check)pci.setFunctionScopes(orgLocal,orgArgs); 154 } 155 } 156 } 157 if(value!=NULL) return setVariable(pc, str,value); 158 return getVariable(pc, str); 159 } 160 161 162 163 164 /** 165 * get a variable from page context 166 * @param pc Page Context 167 * @param var variable string to get value to 168 * @return the value 169 */ 170 public static Object getVariableEL(PageContext pc,String var) { 171 StringList list = parse(pc,new ParserString(var),false); 172 if(list==null) return null; 173 174 int scope=scopeString2Int(list.next()); 175 Object coll =null; 176 if(scope==Scope.SCOPE_UNDEFINED) { 177 coll=pc.undefinedScope().get(list.current(),null); 178 if(coll==null) return null; 179 } 180 else { 181 try { 182 coll=VariableInterpreter.scope(pc, scope, list.hasNext()); 183 //coll=pc.scope(scope); 184 } 185 catch (PageException e) { 186 return null; 187 } 188 } 189 190 while(list.hasNext()) { 191 coll=pc.getVariableUtil().get(pc,coll,list.next(),null); 192 if(coll==null) return null; 193 } 194 return coll; 195 } 196 197 /** 198 * return a variable reference by string syntax ("scopename.key.key" -> "url.name") 199 * a variable reference, references to variable, to modifed it, with global effect. 200 * @param pc 201 * @param var variable name to get 202 * @return variable as Reference 203 * @throws PageException 204 */ 205 public static VariableReference getVariableReference(PageContext pc,String var) throws PageException { 206 StringList list = parse(pc,new ParserString(var),false); 207 if(list==null) throw new ExpressionException("invalid variable declaration ["+var+"]"); 208 209 if(list.size()==1) { 210 return new VariableReference(pc.undefinedScope(),list.next()); 211 } 212 int scope=scopeString2Int(list.next()); 213 214 Object coll; 215 if(scope==Scope.SCOPE_UNDEFINED){ 216 coll=pc.touch(pc.undefinedScope(),list.current()); 217 } 218 else{ 219 coll=VariableInterpreter.scope(pc, scope, list.hasNext()); 220 //coll=pc.scope(scope); 221 } 222 223 224 while(list.hasNextNext()) { 225 coll=pc.touch(coll,list.next()); 226 } 227 228 if(!(coll instanceof Collection)) 229 throw new ExpressionException("invalid variable ["+var+"]"); 230 return new VariableReference((Collection)coll,list.next()); 231 } 232 233 /** 234 * sets a variable to page Context 235 * @param pc pagecontext of the new variable 236 * @param var String of variable definition 237 * @param value value to set to variable 238 * @return value setted 239 * @throws PageException 240 */ 241 public static Object setVariable(PageContext pc,String var, Object value) throws PageException { 242 StringList list = parse(pc,new ParserString(var),false); 243 if(list==null) throw new ExpressionException("invalid variable name declaration ["+var+"]"); 244 245 if(list.size()==1) { 246 return pc.undefinedScope().set(list.next(),value); 247 } 248 249 // min 2 elements 250 int scope=scopeString2Int(list.next()); 251 Object coll; 252 if(scope==Scope.SCOPE_UNDEFINED){ 253 coll=pc.touch(pc.undefinedScope(),list.current()); 254 } 255 else { 256 coll=VariableInterpreter.scope(pc, scope, true); 257 //coll=pc.scope(scope); 258 } 259 260 261 while(list.hasNextNext()) { 262 coll=pc.touch(coll,list.next()); 263 } 264 return pc.set(coll,list.next(),value); 265 } 266 267 /** 268 * removes a variable eith matching name from page context 269 * @param pc 270 * @param var 271 * @return has removed or not 272 * @throws PageException 273 */ 274 public static Object removeVariable(PageContext pc,String var) throws PageException { 275 //print.ln("var:"+var); 276 StringList list = parse(pc,new ParserString(var),false); 277 if(list==null) throw new ExpressionException("invalid variable declaration ["+var+"]"); 278 279 if(list.size()==1) { 280 return pc.undefinedScope().remove(KeyImpl.init(list.next())); 281 } 282 283 int scope=scopeString2Int(list.next()); 284 285 Object coll; 286 if(scope==Scope.SCOPE_UNDEFINED){ 287 coll=pc.undefinedScope().get(list.current()); 288 } 289 else { 290 coll=VariableInterpreter.scope(pc, scope, true); 291 //coll=pc.scope(scope); 292 } 293 294 while(list.hasNextNext()) { 295 coll=pc.get(coll,list.next()); 296 } 297 return Caster.toCollection(coll).remove(KeyImpl.init(list.next())); 298 } 299 300 301 302 /** 303 * check if a variable is defined in Page Context 304 * @param pc PageContext to check 305 * @param var variable String 306 * @return exists or not 307 */ 308 public static boolean isDefined(PageContext pc,String var) { 309 StringList list = parse(pc,new ParserString(var),false); 310 if(list==null) return false; 311 try { 312 int scope=scopeString2Int(list.next()); 313 Object coll =NULL; 314 if(scope==Scope.SCOPE_UNDEFINED) { 315 coll=pc.undefinedScope().get(list.current(),null); 316 if(coll==null)return false; 317 } 318 else { 319 coll=VariableInterpreter.scope(pc, scope, list.hasNext()); 320 //coll=pc.scope(scope); 321 } 322 323 while(list.hasNext()) { 324 coll=pc.getVariableUtil().getCollection(pc,coll,list.next(),null); 325 if(coll==null)return false; 326 } 327 } catch (PageException e) { 328 return false; 329 } 330 return true; 331 } 332 333 334 335 336 /* 337 public static boolean isDefined(PageContext pc,String var) { 338 StringList list = parse(pc,new ParserString(var)); 339 if(list==null) return false; 340 341 int scope=scopeString2Int(list.next()); 342 Object coll =NULL; 343 if(scope==Scope.SCOPE_UNDEFINED) { 344 coll=pc.undefinedScope().get(list.current(),NULL); 345 if(coll==NULL) return false; 346 } 347 else { 348 try { 349 coll=pc.scope(scope); 350 } catch (PageException e) { 351 return false; 352 } 353 } 354 355 while(list.hasNext()) { 356 coll=pc.getVariableUtil().get(pc,coll,list.next(),NULL); 357 //print.out(coll); 358 if(coll==NULL) return false; 359 } 360 361 return true; 362 } 363 */ 364 365 366 /** 367 * parse a Literal variable String and return result as String List 368 * @param pc Page Context 369 * @param ps ParserString to read 370 * @return Variable Definition in a String List 371 */ 372 private static StringList parse(PageContext pc,ParserString ps, boolean doLowerCase) { 373 String id=readIdentifier(ps,doLowerCase); 374 if(id==null)return null; 375 StringList list=new StringList(id); 376 CFMLExpressionInterpreter interpreter=null; 377 378 while(true) { 379 if(ps.forwardIfCurrent('.')) { 380 id=readIdentifier(ps,doLowerCase); 381 if(id==null)return null; 382 list.add(id); 383 } 384 else if(ps.forwardIfCurrent('[')) { 385 if(interpreter==null)interpreter=new CFMLExpressionInterpreter(); 386 try { 387 list.add(Caster.toString(interpreter.interpretPart(pc,ps))); 388 } catch (PageException e) { 389 return null; 390 } 391 if(!ps.forwardIfCurrent(']')) return null; 392 ps.removeSpace(); 393 } 394 else break; 395 } 396 if(ps.isValidIndex()) return null; 397 list.reset(); 398 return list; 399 } 400 401 public static StringList parse(String var, boolean doLowerCase) { 402 ParserString ps = new ParserString(var); 403 String id=readIdentifier(ps,doLowerCase); 404 if(id==null)return null; 405 StringList list=new StringList(id); 406 407 while(true) { 408 if(ps.forwardIfCurrent('.')) { 409 id=readIdentifier(ps,doLowerCase); 410 if(id==null)return null; 411 list.add(id); 412 } 413 else break; 414 } 415 if(ps.isValidIndex()) return null; 416 list.reset(); 417 return list; 418 } 419 420 /** 421 * translate a string type definition to its int representation 422 * @param type type to translate 423 * @return int representation matching to given string 424 */ 425 public static int scopeString2Int(String type) { 426 type=StringUtil.toLowerCase(type); 427 char c=type.charAt(0); 428 if('a'==c) { 429 if("application".equals(type)) return Scope.SCOPE_APPLICATION; 430 else if("arguments".equals(type)) return Scope.SCOPE_ARGUMENTS; 431 } 432 else if('c'==c) { 433 if("cgi".equals(type)) return Scope.SCOPE_CGI; 434 if("cookie".equals(type)) return Scope.SCOPE_COOKIE; 435 if("client".equals(type)) return Scope.SCOPE_CLIENT; 436 if("cluster".equals(type)) return Scope.SCOPE_CLUSTER; 437 } 438 else if('f'==c) { 439 if("form".equals(type)) return Scope.SCOPE_FORM; 440 } 441 else if('l'==c) { 442 if("local".equals(type)) return Scope.SCOPE_LOCAL;// LLL 443 } 444 else if('r'==c) { 445 if("request".equals(type)) return Scope.SCOPE_REQUEST; 446 } 447 else if('s'==c) { 448 if("session".equals(type)) return Scope.SCOPE_SESSION; 449 if("server".equals(type)) return Scope.SCOPE_SERVER; 450 } 451 else if('u'==c) { 452 if("url".equals(type)) return Scope.SCOPE_URL; 453 } 454 else if('v'==c) { 455 if("variables".equals(type)) return Scope.SCOPE_VARIABLES; 456 } 457 return Scope.SCOPE_UNDEFINED; 458 } 459 460 public static int scopeKey2Int(Collection.Key type) { 461 char c=type.lowerCharAt(0); 462 if('a'==c) { 463 if(ScopeSupport.APPLICATION.equalsIgnoreCase(type)) return Scope.SCOPE_APPLICATION; 464 else if(KeyImpl.ARGUMENTS.equalsIgnoreCase(type)) return Scope.SCOPE_ARGUMENTS; 465 } 466 else if('c'==c) { 467 if(ScopeSupport.CGI.equalsIgnoreCase(type)) return Scope.SCOPE_CGI; 468 if(ScopeSupport.COOKIE.equalsIgnoreCase(type)) return Scope.SCOPE_COOKIE; 469 if(ScopeSupport.CLIENT.equalsIgnoreCase(type)) return Scope.SCOPE_CLIENT; 470 if(ScopeSupport.CLUSTER.equalsIgnoreCase(type)) return Scope.SCOPE_CLUSTER; 471 } 472 else if('f'==c) { 473 if(ScopeSupport.FORM.equalsIgnoreCase(type)) return Scope.SCOPE_FORM; 474 } 475 else if('r'==c) { 476 if(ScopeSupport.REQUEST.equalsIgnoreCase(type)) return Scope.SCOPE_REQUEST; 477 } 478 else if('s'==c) { 479 if(ScopeSupport.SESSION.equalsIgnoreCase(type)) return Scope.SCOPE_SESSION; 480 if(KeyImpl.SERVER.equalsIgnoreCase(type)) return Scope.SCOPE_SERVER; 481 } 482 else if('u'==c) { 483 if(ScopeSupport.URL.equalsIgnoreCase(type)) return Scope.SCOPE_URL; 484 } 485 else if('v'==c) { 486 if(KeyImpl.VARIABLES.equalsIgnoreCase(type)) return Scope.SCOPE_VARIABLES; 487 } 488 return Scope.SCOPE_UNDEFINED; 489 } 490 491 private static String readIdentifier(ParserString ps, boolean doLowerCase) { 492 493 ps.removeSpace(); 494 if(ps.isAfterLast())return null; 495 int start=ps.getPos(); 496 if(!isFirstVarLetter(ps.getCurrentLower())) return null; 497 ps.next(); 498 499 while(ps.isValidIndex()) { 500 if(isVarLetter(ps.getCurrentLower()))ps.next(); 501 else break; 502 } 503 ps.removeSpace(); 504 return doLowerCase?ps.substringLower(start,ps.getPos()-start):ps.substring(start,ps.getPos()-start); 505 } 506 507 508 private static boolean isFirstVarLetter(char c) { 509 return (c>='a' && c<='z') || c=='_' || c=='$'; 510 } 511 512 private static boolean isVarLetter(char c) { 513 return (c>='a' && c<='z') || (c>='0' && c<='9') || c=='_' || c=='$'; 514 } 515 516 public static Object scope(PageContext pc, int scope, boolean touch) throws PageException { 517 switch(scope) { 518 case Scope.SCOPE_UNDEFINED: return pc.undefinedScope(); 519 case Scope.SCOPE_URL: return pc.urlScope(); 520 case Scope.SCOPE_FORM: return pc.formScope(); 521 case Scope.SCOPE_VARIABLES: return pc.variablesScope(); 522 case Scope.SCOPE_REQUEST: return pc.requestScope(); 523 case Scope.SCOPE_CGI: return pc.cgiScope(); 524 case Scope.SCOPE_APPLICATION: return pc.applicationScope(); 525 case Scope.SCOPE_ARGUMENTS: return pc.argumentsScope(); 526 case Scope.SCOPE_SESSION: return pc.sessionScope(); 527 case Scope.SCOPE_SERVER: return pc.serverScope(); 528 case Scope.SCOPE_COOKIE: return pc.cookieScope(); 529 case Scope.SCOPE_CLIENT: return pc.clientScope(); 530 case ScopeSupport.SCOPE_VAR: return pc.localScope(); 531 case Scope.SCOPE_CLUSTER: return pc.clusterScope(); 532 533 case Scope.SCOPE_LOCAL: 534 if(touch) return ((PageContextImpl)pc).localTouch(); 535 return ((PageContextImpl)pc).localGet(); 536 } 537 return pc.variablesScope(); 538 } 539 540 }