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