001 package railo.transformer.bytecode.util; 002 003 import java.io.IOException; 004 import java.util.ArrayList; 005 import java.util.Iterator; 006 import java.util.List; 007 008 import org.objectweb.asm.ClassReader; 009 import org.objectweb.asm.ClassWriter; 010 import org.objectweb.asm.FieldVisitor; 011 import org.objectweb.asm.Label; 012 import org.objectweb.asm.Opcodes; 013 import org.objectweb.asm.Type; 014 import org.objectweb.asm.commons.GeneratorAdapter; 015 import org.objectweb.asm.commons.Method; 016 017 import railo.aprint; 018 import railo.commons.digest.MD5; 019 import railo.commons.io.IOUtil; 020 import railo.commons.io.res.Resource; 021 import railo.commons.lang.StringUtil; 022 import railo.runtime.component.Property; 023 import railo.runtime.exp.PageException; 024 import railo.runtime.net.rpc.AxisCaster; 025 import railo.runtime.op.Caster; 026 import railo.runtime.type.dt.TimeSpanImpl; 027 import railo.runtime.type.util.ArrayUtil; 028 import railo.runtime.type.util.ListUtil; 029 import railo.transformer.bytecode.Body; 030 import railo.transformer.bytecode.BytecodeContext; 031 import railo.transformer.bytecode.BytecodeException; 032 import railo.transformer.bytecode.Literal; 033 import railo.transformer.bytecode.Page; 034 import railo.transformer.bytecode.Position; 035 import railo.transformer.bytecode.ScriptBody; 036 import railo.transformer.bytecode.Statement; 037 import railo.transformer.bytecode.cast.Cast; 038 import railo.transformer.bytecode.cast.CastBoolean; 039 import railo.transformer.bytecode.cast.CastDouble; 040 import railo.transformer.bytecode.cast.CastString; 041 import railo.transformer.bytecode.expression.ExprDouble; 042 import railo.transformer.bytecode.expression.ExprString; 043 import railo.transformer.bytecode.expression.Expression; 044 import railo.transformer.bytecode.expression.var.Argument; 045 import railo.transformer.bytecode.expression.var.BIF; 046 import railo.transformer.bytecode.expression.var.Member; 047 import railo.transformer.bytecode.expression.var.NullExpression; 048 import railo.transformer.bytecode.expression.var.Variable; 049 import railo.transformer.bytecode.expression.var.VariableString; 050 import railo.transformer.bytecode.literal.Identifier; 051 import railo.transformer.bytecode.literal.LitBoolean; 052 import railo.transformer.bytecode.literal.LitDouble; 053 import railo.transformer.bytecode.literal.LitString; 054 import railo.transformer.bytecode.statement.FlowControl; 055 import railo.transformer.bytecode.statement.FlowControlBreak; 056 import railo.transformer.bytecode.statement.FlowControlContinue; 057 import railo.transformer.bytecode.statement.FlowControlFinal; 058 import railo.transformer.bytecode.statement.FlowControlRetry; 059 import railo.transformer.bytecode.statement.PrintOut; 060 import railo.transformer.bytecode.statement.TryCatchFinally; 061 import railo.transformer.bytecode.statement.tag.Attribute; 062 import railo.transformer.bytecode.statement.tag.Tag; 063 import railo.transformer.bytecode.statement.tag.TagComponent; 064 import railo.transformer.bytecode.statement.tag.TagTry; 065 import railo.transformer.cfml.evaluator.EvaluatorException; 066 067 public final class ASMUtil { 068 069 //private static final int VERSION_2=1; 070 //private static final int VERSION_3=2; 071 072 public static final short TYPE_ALL=0; 073 public static final short TYPE_BOOLEAN=1; 074 public static final short TYPE_NUMERIC=2; 075 public static final short TYPE_STRING=4; 076 077 078 079 080 //private static int version=0; 081 082 private final static Method CONSTRUCTOR_OBJECT = Method.getMethod("void <init> ()"); 083 private static final Method _SRC_NAME = new Method("_srcName", 084 Types.STRING, 085 new Type[]{} 086 );; 087 //private static final String VERSION_MESSAGE = "you use an invalid version of the ASM Jar, please update your jar files"; 088 private static long id=0; 089 090 /** 091 * Gibt zurueck ob das direkt uebergeordnete Tag mit dem uebergebenen Full-Name (Namespace und Name) existiert. 092 * @param el Startelement, von wo aus gesucht werden soll. 093 * @param fullName Name des gesuchten Tags. 094 * @return Existiert ein solches Tag oder nicht. 095 */ 096 public static boolean hasAncestorTag(Tag tag, String fullName) { 097 return getAncestorTag(tag, fullName)!=null; 098 } 099 100 101 /** 102 * Gibt das uebergeordnete CFXD Tag Element zurueck, falls dies nicht existiert wird null zurueckgegeben. 103 * @param el Element von dem das parent Element zurueckgegeben werden soll. 104 * @return uebergeordnete CFXD Tag Element 105 */ 106 public static Tag getParentTag(Tag tag) { 107 Statement p=tag.getParent(); 108 if(p==null)return null; 109 p=p.getParent(); 110 if(p instanceof Tag) return (Tag) p; 111 return null; 112 } 113 114 public static boolean isParentTag(Tag tag,String fullName) { 115 Tag p = getParentTag(tag); 116 if(p==null) return false; 117 return p.getFullname().equalsIgnoreCase(fullName); 118 119 } 120 public static boolean isParentTag(Tag tag,Class clazz) { 121 Tag p = getParentTag(tag); 122 if(p==null) return false; 123 return p.getClass()==clazz; 124 125 } 126 127 public static boolean hasAncestorRetryFCStatement(Statement stat,String label) { 128 return getAncestorRetryFCStatement(stat,null,label)!=null; 129 } 130 131 public static boolean hasAncestorBreakFCStatement(Statement stat,String label) { 132 return getAncestorBreakFCStatement(stat,null,label)!=null; 133 } 134 135 public static boolean hasAncestorContinueFCStatement(Statement stat,String label) { 136 return getAncestorContinueFCStatement(stat,null,label)!=null; 137 } 138 139 140 141 public static FlowControlRetry getAncestorRetryFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, String label) { 142 return (FlowControlRetry) getAncestorFCStatement(stat, finallyLabels, FlowControl.RETRY,label); 143 } 144 public static FlowControlBreak getAncestorBreakFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, String label) { 145 return (FlowControlBreak) getAncestorFCStatement(stat, finallyLabels, FlowControl.BREAK,label); 146 } 147 148 public static FlowControlContinue getAncestorContinueFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, String label) { 149 return (FlowControlContinue) getAncestorFCStatement(stat, finallyLabels, FlowControl.CONTINUE,label); 150 } 151 152 private static FlowControl getAncestorFCStatement(Statement stat, List<FlowControlFinal> finallyLabels, int flowType, String label) { 153 Statement parent = stat; 154 FlowControlFinal fcf; 155 while(true) { 156 parent=parent.getParent(); 157 if(parent==null)return null; 158 if( 159 ((flowType==FlowControl.RETRY && parent instanceof FlowControlRetry) || 160 (flowType==FlowControl.CONTINUE && parent instanceof FlowControlContinue) || 161 (flowType==FlowControl.BREAK && parent instanceof FlowControlBreak)) 162 && 163 labelMatch((FlowControl)parent,label)) { 164 if(parent instanceof ScriptBody){ 165 List<FlowControlFinal> _finallyLabels=finallyLabels==null?null:new ArrayList<FlowControlFinal>(); 166 167 FlowControl scriptBodyParent = getAncestorFCStatement(parent,_finallyLabels,flowType,label); 168 if(scriptBodyParent!=null) { 169 if(finallyLabels!=null){ 170 Iterator<FlowControlFinal> it = _finallyLabels.iterator(); 171 while(it.hasNext()){ 172 finallyLabels.add(it.next()); 173 } 174 } 175 return scriptBodyParent; 176 } 177 return (FlowControl)parent; 178 } 179 return (FlowControl) parent; 180 } 181 182 // only if not last 183 if(finallyLabels!=null){ 184 fcf = parent.getFlowControlFinal(); 185 if(fcf!=null){ 186 finallyLabels.add(fcf); 187 } 188 } 189 190 } 191 } 192 193 private static boolean labelMatch(FlowControl fc, String label) { 194 if(StringUtil.isEmpty(label,true)) return true; 195 String fcl = fc.getLabel(); 196 if(StringUtil.isEmpty(fcl,true)) return false; 197 198 return label.trim().equalsIgnoreCase(fcl.trim()); 199 } 200 201 202 public static void leadFlow(BytecodeContext bc,Statement stat, int flowType, String label) throws BytecodeException { 203 List<FlowControlFinal> finallyLabels=new ArrayList<FlowControlFinal>(); 204 205 FlowControl fc; 206 String name; 207 if(FlowControl.BREAK==flowType) { 208 fc=ASMUtil.getAncestorBreakFCStatement(stat,finallyLabels,label); 209 name="break"; 210 } 211 else if(FlowControl.CONTINUE==flowType) { 212 fc=ASMUtil.getAncestorContinueFCStatement(stat,finallyLabels,label); 213 name="continue"; 214 } 215 else { 216 fc=ASMUtil.getAncestorRetryFCStatement(stat,finallyLabels,label); 217 name="retry"; 218 } 219 220 if(fc==null) 221 throw new BytecodeException(name+" must be inside a loop (for,while,do-while,<cfloop>,<cfwhile> ...)",stat.getStart()); 222 223 GeneratorAdapter adapter = bc.getAdapter(); 224 225 Label end; 226 if(FlowControl.BREAK==flowType) end=((FlowControlBreak)fc).getBreakLabel(); 227 else if(FlowControl.CONTINUE==flowType) end=((FlowControlContinue)fc).getContinueLabel(); 228 else end=((FlowControlRetry)fc).getRetryLabel(); 229 230 // first jump to all final labels 231 FlowControlFinal[] arr = finallyLabels.toArray(new FlowControlFinal[finallyLabels.size()]); 232 if(arr.length>0) { 233 FlowControlFinal fcf; 234 for(int i=0;i<arr.length;i++){ 235 fcf=arr[i]; 236 237 // first 238 if(i==0) { 239 adapter.visitJumpInsn(Opcodes.GOTO, fcf.getFinalEntryLabel()); 240 } 241 242 // last 243 if(arr.length==i+1) fcf.setAfterFinalGOTOLabel(end); 244 else fcf.setAfterFinalGOTOLabel(arr[i+1].getFinalEntryLabel()); 245 } 246 247 } 248 else bc.getAdapter().visitJumpInsn(Opcodes.GOTO, end); 249 } 250 251 252 253 public static boolean hasAncestorTryStatement(Statement stat) { 254 return getAncestorTryStatement(stat)!=null; 255 } 256 257 public static Statement getAncestorTryStatement(Statement stat) { 258 Statement parent = stat; 259 while(true) { 260 parent=parent.getParent(); 261 if(parent==null)return null; 262 263 if(parent instanceof TagTry) { 264 return parent; 265 } 266 else if(parent instanceof TryCatchFinally) { 267 return parent; 268 } 269 } 270 } 271 272 273 274 275 /** 276 * Gibt ein uebergeordnetes Tag mit dem uebergebenen Full-Name (Namespace und Name) zurueck, 277 * falls ein solches existiert, andernfalls wird null zurueckgegeben. 278 * @param el Startelement, von wo aus gesucht werden soll. 279 * @param fullName Name des gesuchten Tags. 280 * @return �bergeornetes Element oder null. 281 */ 282 public static Tag getAncestorTag(Tag tag, String fullName) { 283 Statement parent=tag; 284 while(true) { 285 parent=parent.getParent(); 286 if(parent==null)return null; 287 if(parent instanceof Tag) { 288 tag=(Tag) parent; 289 if(tag.getFullname().equalsIgnoreCase(fullName)) 290 return tag; 291 } 292 } 293 } 294 295 296 297 /** 298 * extract the content of a attribut 299 * @param cfxdTag 300 * @param attrName 301 * @return attribute value 302 * @throws EvaluatorException 303 */ 304 public static Boolean getAttributeBoolean(Tag tag,String attrName) throws EvaluatorException { 305 Boolean b= getAttributeLiteral(tag, attrName).getBoolean(null); 306 if(b==null)throw new EvaluatorException("attribute ["+attrName+"] must be a constant boolean value"); 307 return b; 308 } 309 310 /** 311 * extract the content of a attribut 312 * @param cfxdTag 313 * @param attrName 314 * @return attribute value 315 * @throws EvaluatorException 316 */ 317 public static Boolean getAttributeBoolean(Tag tag,String attrName, Boolean defaultValue) { 318 Literal lit=getAttributeLiteral(tag, attrName,null); 319 if(lit==null) return defaultValue; 320 return lit.getBoolean(defaultValue); 321 } 322 323 324 /** 325 * extract the content of a attribut 326 * @param cfxdTag 327 * @param attrName 328 * @return attribute value 329 * @throws EvaluatorException 330 */ 331 public static String getAttributeString(Tag tag,String attrName) throws EvaluatorException { 332 return getAttributeLiteral(tag, attrName).getString(); 333 } 334 335 /** 336 * extract the content of a attribut 337 * @param cfxdTag 338 * @param attrName 339 * @return attribute value 340 * @throws EvaluatorException 341 */ 342 public static String getAttributeString(Tag tag,String attrName, String defaultValue) { 343 Literal lit=getAttributeLiteral(tag, attrName,null); 344 if(lit==null) return defaultValue; 345 return lit.getString(); 346 } 347 348 /** 349 * extract the content of a attribut 350 * @param cfxdTag 351 * @param attrName 352 * @return attribute value 353 * @throws EvaluatorException 354 */ 355 public static Literal getAttributeLiteral(Tag tag,String attrName) throws EvaluatorException { 356 Attribute attr = tag.getAttribute(attrName); 357 if(attr!=null && attr.getValue() instanceof Literal) return ((Literal)attr.getValue()); 358 throw new EvaluatorException("attribute ["+attrName+"] must be a constant value"); 359 } 360 361 362 363 /** 364 * extract the content of a attribut 365 * @param cfxdTag 366 * @param attrName 367 * @return attribute value 368 * @throws EvaluatorException 369 */ 370 public static Literal getAttributeLiteral(Tag tag,String attrName, Literal defaultValue) { 371 Attribute attr = tag.getAttribute(attrName); 372 if(attr!=null && attr.getValue() instanceof Literal) return ((Literal)attr.getValue()); 373 return defaultValue; 374 } 375 376 377 378 379 /** 380 * Prueft ob das das angegebene Tag in der gleichen Ebene nach dem angegebenen Tag vorkommt. 381 * @param tag Ausgangspunkt, nach diesem tag darf das angegebene nicht vorkommen. 382 * @param nameToFind Tag Name der nicht vorkommen darf 383 * @return kommt das Tag vor. 384 */ 385 public static boolean hasSisterTagAfter(Tag tag, String nameToFind) { 386 Body body=(Body) tag.getParent(); 387 List<Statement> stats = body.getStatements(); 388 Iterator<Statement> it = stats.iterator(); 389 Statement other; 390 391 boolean isAfter=false; 392 while(it.hasNext()) { 393 other=it.next(); 394 395 if(other instanceof Tag) { 396 if(isAfter) { 397 if(((Tag) other).getTagLibTag().getName().equals(nameToFind)) 398 return true; 399 } 400 else if(other == tag) isAfter=true; 401 } 402 } 403 return false; 404 } 405 406 /** 407 * Prueft ob das angegebene Tag innerhalb seiner Ebene einmalig ist oder nicht. 408 * @param tag Ausgangspunkt, nach diesem tag darf das angegebene nicht vorkommen. 409 * @return kommt das Tag vor. 410 */ 411 public static boolean hasSisterTagWithSameName(Tag tag) { 412 413 Body body=(Body) tag.getParent(); 414 List<Statement> stats = body.getStatements(); 415 Iterator<Statement> it = stats.iterator(); 416 Statement other; 417 String name=tag.getTagLibTag().getName(); 418 419 while(it.hasNext()) { 420 other=it.next(); 421 if(other != tag && other instanceof Tag && ((Tag) other).getTagLibTag().getName().equals(name)) 422 return true; 423 424 } 425 return false; 426 } 427 428 /** 429 * remove this tag from his parent body 430 * @param tag 431 */ 432 public static void remove(Tag tag) { 433 Body body=(Body) tag.getParent(); 434 body.getStatements().remove(tag); 435 } 436 437 /** 438 * replace src with trg 439 * @param src 440 * @param trg 441 */ 442 public static void replace(Tag src, Tag trg, boolean moveBody) { 443 trg.setParent(src.getParent()); 444 445 Body p=(Body) src.getParent(); 446 List<Statement> stats = p.getStatements(); 447 Iterator<Statement> it = stats.iterator(); 448 Statement stat; 449 int count=0; 450 451 while(it.hasNext()) { 452 stat=it.next(); 453 if(stat==src) { 454 if(moveBody && src.getBody()!=null)src.getBody().setParent(trg); 455 stats.set(count, trg); 456 break; 457 } 458 count++; 459 } 460 } 461 462 public static Page getAncestorPage(Statement stat) throws BytecodeException { 463 Statement parent=stat; 464 while(true) { 465 parent=parent.getParent(); 466 if(parent==null) { 467 throw new BytecodeException("missing parent Statement of Statement",stat.getStart()); 468 //return null; 469 } 470 if(parent instanceof Page) return (Page) parent; 471 } 472 } 473 474 public static Page getAncestorPage(Statement stat, Page defaultValue) { 475 Statement parent=stat; 476 while(true) { 477 parent=parent.getParent(); 478 if(parent==null) { 479 return defaultValue; 480 } 481 if(parent instanceof Page) return (Page) parent; 482 } 483 } 484 485 public static void listAncestor(Statement stat) { 486 Statement parent=stat; 487 aprint.o(stat); 488 while(true) { 489 parent=parent.getParent(); 490 if(parent instanceof Page)aprint.o("page-> "+ ((Page)parent).getSource()); 491 else aprint.o("parent-> "+ parent); 492 if(parent==null) break; 493 } 494 } 495 496 497 public static Tag getAncestorComponent(Statement stat) throws BytecodeException { 498 //print.ln("getAncestorPage:"+stat); 499 Statement parent=stat; 500 while(true) { 501 parent=parent.getParent(); 502 //print.ln(" - "+parent); 503 if(parent==null) { 504 throw new BytecodeException("missing parent Statement of Statement",stat.getStart()); 505 //return null; 506 } 507 if(parent instanceof TagComponent) 508 //if(parent instanceof Tag && "component".equals(((Tag)parent).getTagLibTag().getName())) 509 return (Tag) parent; 510 } 511 } 512 513 public static Statement getRoot(Statement stat) { 514 while(true) { 515 if(isRoot(stat)) { 516 return stat; 517 } 518 stat=stat.getParent(); 519 } 520 } 521 522 523 524 public static boolean isRoot(Statement statement) { 525 //return statement instanceof Page || (statement instanceof Tag && "component".equals(((Tag)statement).getTagLibTag().getName())); 526 return statement instanceof Page || statement instanceof TagComponent; 527 } 528 529 public static void invokeMethod(GeneratorAdapter adapter, Type type, Method method) { 530 if(type.getClass().isInterface()) 531 adapter.invokeInterface(type, method); 532 else 533 adapter.invokeVirtual(type, method); 534 } 535 536 public static byte[] createPojo(String className, ASMProperty[] properties,Class parent,Class[] interfaces, String srcName) throws PageException { 537 className=className.replace('.', '/'); 538 className=className.replace('\\', '/'); 539 className=ListUtil.trim(className, "/"); 540 String[] inter=null; 541 if(interfaces!=null){ 542 inter=new String[interfaces.length]; 543 for(int i=0;i<inter.length;i++){ 544 inter[i]=interfaces[i].getName().replace('.', '/'); 545 } 546 } 547 // CREATE CLASS 548 //ClassWriter cw = new ClassWriter(true); 549 ClassWriter cw = ASMUtil.getClassWriter(); 550 cw.visit(Opcodes.V1_2, Opcodes.ACC_PUBLIC, className, null, parent.getName().replace('.', '/'), inter); 551 String md5; 552 try{ 553 md5=createMD5(properties); 554 } 555 catch(Throwable t){ 556 md5=""; 557 t.printStackTrace(); 558 } 559 560 FieldVisitor fv = cw.visitField(Opcodes.ACC_PUBLIC + Opcodes.ACC_FINAL + Opcodes.ACC_STATIC, "_md5_", "Ljava/lang/String;", null, md5); 561 fv.visitEnd(); 562 563 564 // Constructor 565 GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC,CONSTRUCTOR_OBJECT,null,null,cw); 566 adapter.loadThis(); 567 adapter.invokeConstructor(toType(parent,true), CONSTRUCTOR_OBJECT); 568 adapter.returnValue(); 569 adapter.endMethod(); 570 571 // properties 572 for(int i=0;i<properties.length;i++){ 573 createProperty(cw,className,properties[i]); 574 } 575 576 // complexType src 577 if(!StringUtil.isEmpty(srcName)) { 578 GeneratorAdapter _adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC+Opcodes.ACC_FINAL+ Opcodes.ACC_STATIC , _SRC_NAME, null, null, cw); 579 _adapter.push(srcName); 580 _adapter.returnValue(); 581 _adapter.endMethod(); 582 } 583 584 cw.visitEnd(); 585 return cw.toByteArray(); 586 } 587 588 private static void createProperty(ClassWriter cw,String classType, ASMProperty property) throws PageException { 589 String name = property.getName(); 590 Type type = property.getASMType(); 591 Class clazz = property.getClazz(); 592 593 cw.visitField(Opcodes.ACC_PRIVATE, name, type.toString(), null, null).visitEnd(); 594 595 int load=loadFor(type); 596 //int sizeOf=sizeOf(type); 597 598 // get<PropertyName>():<type> 599 Type[] types=new Type[0]; 600 Method method = new Method((clazz==boolean.class?"get":"get")+StringUtil.ucFirst(name),type,types); 601 GeneratorAdapter adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , method, null, null, cw); 602 603 Label start = new Label(); 604 adapter.visitLabel(start); 605 606 adapter.visitVarInsn(Opcodes.ALOAD, 0); 607 adapter.visitFieldInsn(Opcodes.GETFIELD, classType, name, type.toString()); 608 adapter.returnValue(); 609 610 Label end = new Label(); 611 adapter.visitLabel(end); 612 adapter.visitLocalVariable("this", "L"+classType+";", null, start, end, 0); 613 adapter.visitEnd(); 614 615 adapter.endMethod(); 616 617 618 619 620 621 // set<PropertyName>(object):void 622 types=new Type[]{type}; 623 method = new Method("set"+StringUtil.ucFirst(name),Types.VOID,types); 624 adapter = new GeneratorAdapter(Opcodes.ACC_PUBLIC , method, null, null, cw); 625 626 start = new Label(); 627 adapter.visitLabel(start); 628 adapter.visitVarInsn(Opcodes.ALOAD, 0); 629 adapter.visitVarInsn(load, 1); 630 adapter.visitFieldInsn(Opcodes.PUTFIELD, classType, name, type.toString()); 631 632 adapter.visitInsn(Opcodes.RETURN); 633 end = new Label(); 634 adapter.visitLabel(end); 635 adapter.visitLocalVariable("this", "L"+classType+";", null, start, end, 0); 636 adapter.visitLocalVariable(name, type.toString(), null, start, end, 1); 637 //adapter.visitMaxs(0, 0);//.visitMaxs(sizeOf+1, sizeOf+1);// hansx 638 adapter.visitEnd(); 639 640 adapter.endMethod(); 641 642 643 644 645 } 646 647 public static int loadFor(Type type) { 648 if(type.equals(Types.BOOLEAN_VALUE) || type.equals(Types.INT_VALUE) || type.equals(Types.CHAR) || type.equals(Types.SHORT_VALUE)) 649 return Opcodes.ILOAD; 650 if(type.equals(Types.FLOAT_VALUE)) 651 return Opcodes.FLOAD; 652 if(type.equals(Types.LONG_VALUE)) 653 return Opcodes.LLOAD; 654 if(type.equals(Types.DOUBLE_VALUE)) 655 return Opcodes.DLOAD; 656 return Opcodes.ALOAD; 657 } 658 659 public static int sizeOf(Type type) { 660 if(type.equals(Types.LONG_VALUE) || type.equals(Types.DOUBLE_VALUE)) 661 return 2; 662 return 1; 663 } 664 665 666 /** 667 * translate a string cfml type definition to a Type Object 668 * @param cfType 669 * @param axistype 670 * @return 671 * @throws PageException 672 */ 673 public static Type toType(String cfType, boolean axistype) throws PageException { 674 return toType(Caster.cfTypeToClass(cfType), axistype); 675 } 676 677 /** 678 * translate a string cfml type definition to a Type Object 679 * @param cfType 680 * @param axistype 681 * @return 682 * @throws PageException 683 */ 684 public static Type toType(Class type, boolean axistype) { 685 if(axistype)type=AxisCaster.toAxisTypeClass(type); 686 return Type.getType(type); 687 } 688 689 690 public static String createMD5(ASMProperty[] props) { 691 692 StringBuffer sb=new StringBuffer(); 693 for(int i=0;i<props.length;i++){ 694 sb.append("name:"+props[i].getName()+";"); 695 if(props[i] instanceof Property){ 696 sb.append("type:"+((Property)props[i]).getType()+";"); 697 } 698 else { 699 try { 700 sb.append("type:"+props[i].getASMType()+";"); 701 702 } 703 catch (PageException e) {} 704 } 705 } 706 try { 707 return MD5.getDigestAsString(sb.toString()); 708 } catch (IOException e) { 709 return ""; 710 } 711 } 712 713 714 715 public static void removeLiterlChildren(Tag tag, boolean recursive) { 716 Body body=tag.getBody(); 717 if(body!=null) { 718 List<Statement> list = body.getStatements(); 719 Statement[] stats = list.toArray(new Statement[list.size()]); 720 PrintOut po; 721 Tag t; 722 for(int i=0;i<stats.length;i++) { 723 if(stats[i] instanceof PrintOut) { 724 po=(PrintOut) stats[i]; 725 if(po.getExpr() instanceof Literal) { 726 body.getStatements().remove(po); 727 } 728 } 729 else if(recursive && stats[i] instanceof Tag) { 730 t=(Tag) stats[i]; 731 if(t.getTagLibTag().isAllowRemovingLiteral()) { 732 removeLiterlChildren(t, recursive); 733 } 734 } 735 } 736 } 737 } 738 739 740 public synchronized static String getId() { 741 if(id<0)id=0; 742 return StringUtil.addZeros(++id,6); 743 } 744 745 746 public static boolean isEmpty(Body body) { 747 return body==null || body.isEmpty(); 748 } 749 750 751 /** 752 * @param adapter 753 * @param expr 754 * @param mode 755 */ 756 public static void pop(GeneratorAdapter adapter, Expression expr,int mode) { 757 if(mode==Expression.MODE_VALUE && (expr instanceof ExprDouble))adapter.pop2(); 758 else adapter.pop(); 759 } 760 public static void pop(GeneratorAdapter adapter, Type type) { 761 if(type.equals(Types.DOUBLE_VALUE))adapter.pop2(); 762 else if(type.equals(Types.VOID)); 763 else adapter.pop(); 764 } 765 766 767 public static ClassWriter getClassWriter() { 768 return new ClassWriter(ClassWriter.COMPUTE_MAXS|ClassWriter.COMPUTE_FRAMES); 769 /*if(true) return new ClassWriter(ClassWriter.COMPUTE_MAXS); 770 771 772 if(version==VERSION_2) 773 return new ClassWriter(ClassWriter.COMPUTE_MAXS+ClassWriter.COMPUTE_FRAMES); 774 775 try{ 776 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); 777 version=VERSION_2; 778 return cw; 779 } 780 catch(NoSuchMethodError err){ 781 if(version==0){ 782 version=VERSION_3; 783 } 784 785 PrintWriter ew = ThreadLocalPageContext.getConfig().getErrWriter(); 786 SystemOut.printDate(ew, VERSION_MESSAGE); 787 788 try { 789 return ClassWriter.class.getConstructor(new Class[]{boolean.class}).newInstance(new Object[]{Boolean.TRUE}); 790 791 } 792 catch (Exception e) { 793 throw new RuntimeException(Caster.toPageException(e)); 794 795 } 796 }*/ 797 } 798 799 /* 800 * For 3.1 801 * 802 * public static ClassWriter getClassWriter() { 803 if(version==VERSION_3) 804 return new ClassWriter(ClassWriter.COMPUTE_MAXS); 805 806 try{ 807 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); 808 version=VERSION_3; 809 return cw; 810 } 811 catch(NoSuchMethodError err){ 812 if(version==0){ 813 version=VERSION_2; 814 throw new RuntimeException(new ApplicationException(VERSION_MESSAGE+ 815 ", after reload this version will work as well, but please update to newer version")); 816 } 817 818 PrintWriter ew = ThreadLocalPageContext.getConfig().getErrWriter(); 819 SystemOut.printDate(ew, VERSION_MESSAGE); 820 //err.printStackTrace(ew); 821 822 try { 823 return (ClassWriter) ClassWriter.class.getConstructor(new Class[]{boolean.class}).newInstance(new Object[]{Boolean.TRUE}); 824 825 } 826 catch (Exception e) { 827 throw new RuntimeException(Caster.toPageException(e)); 828 829 } 830 } 831 }*/ 832 833 834 public static String createOverfowMethod() { 835 return "_call"+ASMUtil.getId(); 836 } 837 838 public static boolean isOverfowMethod(String name) { 839 return name.startsWith("_call") && name.length()>=11; 840 } 841 842 843 public static boolean isDotKey(ExprString expr) { 844 return expr instanceof LitString && !((LitString)expr).fromBracket(); 845 } 846 847 public static String toString(Expression exp,String defaultValue) { 848 try { 849 return toString(exp); 850 } catch (BytecodeException e) { 851 return defaultValue; 852 } 853 } 854 public static String toString(Expression exp) throws BytecodeException { 855 if(exp instanceof Variable) { 856 return toString(VariableString.toExprString(exp)); 857 } 858 else if(exp instanceof VariableString) { 859 return ((VariableString)exp).castToString(); 860 } 861 else if(exp instanceof Literal) { 862 return ((Literal)exp).toString(); 863 } 864 return null; 865 } 866 867 868 public static Boolean toBoolean(Attribute attr, Position start) throws BytecodeException { 869 if(attr==null) 870 throw new BytecodeException("attribute does not exist",start); 871 872 if(attr.getValue() instanceof Literal){ 873 Boolean b=((Literal)attr.getValue()).getBoolean(null); 874 if(b!=null) return b; 875 } 876 throw new BytecodeException("attribute ["+attr.getName()+"] must be a constant boolean value",start); 877 878 879 } 880 public static Boolean toBoolean(Attribute attr, int line, Boolean defaultValue) { 881 if(attr==null) 882 return defaultValue; 883 884 if(attr.getValue() instanceof Literal){ 885 Boolean b=((Literal)attr.getValue()).getBoolean(null); 886 if(b!=null) return b; 887 } 888 return defaultValue; 889 } 890 891 892 public static boolean isCFC(Statement s) { 893 Statement p; 894 while((p=s.getParent())!=null){ 895 s=p; 896 } 897 898 return true; 899 } 900 901 public static boolean isLiteralAttribute(Tag tag, String attrName, short type,boolean required,boolean throwWhenNot) throws EvaluatorException { 902 return isLiteralAttribute(tag,tag.getAttribute(attrName), type, required, throwWhenNot); 903 } 904 905 906 public static boolean isLiteralAttribute(Tag tag,Attribute attr, short type,boolean required,boolean throwWhenNot) throws EvaluatorException { 907 String strType="/constant"; 908 if(attr!=null && !isNull(attr.getValue())) { 909 910 switch(type){ 911 case TYPE_ALL: 912 if(attr.getValue() instanceof Literal) return true; 913 break; 914 case TYPE_BOOLEAN: 915 if(CastBoolean.toExprBoolean(attr.getValue()) instanceof LitBoolean) return true; 916 strType=" boolean"; 917 break; 918 case TYPE_NUMERIC: 919 if(CastDouble.toExprDouble(attr.getValue()) instanceof LitDouble) return true; 920 strType=" numeric"; 921 break; 922 case TYPE_STRING: 923 if(CastString.toExprString(attr.getValue()) instanceof LitString) return true; 924 strType=" string"; 925 break; 926 } 927 if(!throwWhenNot) return false; 928 throw new EvaluatorException("Attribute ["+attr.getName()+"] of the Tag ["+tag.getFullname()+"] must be a literal"+strType+" value. "+ 929 "attributes java class type "+attr.getValue().getClass().getName()); 930 } 931 if(required){ 932 if(!throwWhenNot) return false; 933 throw new EvaluatorException("Attribute ["+attr.getName()+"] of the Tag ["+tag.getFullname()+"] is required"); 934 } 935 return false; 936 } 937 938 939 public static boolean isNull(Expression expr) { 940 if(expr instanceof NullExpression) return true; 941 if(expr instanceof Cast) { 942 return isNull(((Cast)expr).getExpr()); 943 } 944 return false; 945 } 946 947 948 public static boolean isRefType(Type type) { 949 return 950 !(type==Types.BYTE_VALUE || type==Types.BOOLEAN_VALUE || type==Types.CHAR || type==Types.DOUBLE_VALUE || 951 type==Types.FLOAT_VALUE || type==Types.INT_VALUE || type==Types.LONG_VALUE || type==Types.SHORT_VALUE); 952 } 953 954 955 public static Type toRefType(Type type) { 956 if(type==Types.BYTE_VALUE) return Types.BYTE; 957 if(type==Types.BOOLEAN_VALUE) return Types.BOOLEAN; 958 if(type==Types.CHAR) return Types.CHARACTER; 959 if(type==Types.DOUBLE_VALUE) return Types.DOUBLE; 960 if(type==Types.FLOAT_VALUE) return Types.FLOAT; 961 if(type==Types.INT_VALUE) return Types.INTEGER; 962 if(type==Types.LONG_VALUE) return Types.LONG; 963 if(type==Types.SHORT_VALUE) return Types.SHORT; 964 965 return type; 966 } 967 968 /** 969 * return value type only when there is one 970 * @param type 971 * @return 972 */ 973 public static Type toValueType(Type type) { 974 if(type==Types.BYTE) return Types.BYTE_VALUE; 975 if(type==Types.BOOLEAN) return Types.BOOLEAN_VALUE; 976 if(type==Types.CHARACTER) return Types.CHAR; 977 if(type==Types.DOUBLE) return Types.DOUBLE_VALUE; 978 if(type==Types.FLOAT) return Types.FLOAT_VALUE; 979 if(type==Types.INTEGER) return Types.INT_VALUE; 980 if(type==Types.LONG) return Types.LONG_VALUE; 981 if(type==Types.SHORT) return Types.SHORT_VALUE; 982 983 return type; 984 } 985 986 987 public static Class getValueTypeClass(Type type, Class defaultValue) { 988 989 if(type==Types.BYTE_VALUE) return byte.class; 990 if(type==Types.BOOLEAN_VALUE) return boolean.class; 991 if(type==Types.CHAR) return char.class; 992 if(type==Types.DOUBLE_VALUE) return double.class; 993 if(type==Types.FLOAT_VALUE) return float.class; 994 if(type==Types.INT_VALUE) return int.class; 995 if(type==Types.LONG_VALUE) return long.class; 996 if(type==Types.SHORT_VALUE) return short.class; 997 998 return defaultValue; 999 } 1000 1001 1002 public static ASMProperty[] toASMProperties(Property[] properties) { 1003 ASMProperty[] asmp=new ASMProperty[properties.length]; 1004 for(int i=0;i<asmp.length;i++){ 1005 asmp[i]=(ASMProperty) properties[i]; 1006 } 1007 return asmp; 1008 } 1009 1010 1011 public static boolean containsComponent(Body body) { 1012 if(body==null) return false; 1013 1014 Iterator<Statement> it = body.getStatements().iterator(); 1015 while(it.hasNext()){ 1016 if(it.next() instanceof TagComponent)return true; 1017 } 1018 return false; 1019 } 1020 1021 1022 public static void dummy1(BytecodeContext bc) { 1023 bc.getAdapter().visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "currentTimeMillis", "()J"); 1024 bc.getAdapter().visitInsn(Opcodes.POP2); 1025 } 1026 public static void dummy2(BytecodeContext bc) { 1027 bc.getAdapter().visitMethodInsn(Opcodes.INVOKESTATIC, "java/lang/System", "nanoTime", "()J"); 1028 bc.getAdapter().visitInsn(Opcodes.POP2); 1029 } 1030 1031 1032 /** 1033 * convert a clas array to a type array 1034 * @param classes 1035 * @return 1036 */ 1037 public static Type[] toTypes(Class<?>[] classes) { 1038 if(classes==null || classes.length==0) 1039 return new Type[0]; 1040 1041 Type[] types=new Type[classes.length]; 1042 for(int i=0;i<classes.length;i++) { 1043 types[i]=Type.getType(classes[i]); 1044 } 1045 return types; 1046 } 1047 1048 1049 public static String display(ExprString name) { 1050 if(name instanceof Literal) { 1051 if(name instanceof Identifier) 1052 return ((Identifier)name).getRaw(); 1053 return ((Literal)name).getString(); 1054 1055 } 1056 return name.toString(); 1057 } 1058 1059 1060 public static long timeSpanToLong(Expression val) throws EvaluatorException { 1061 if(val instanceof Literal) { 1062 Double d = ((Literal)val).getDouble(null); 1063 if(d==null) throw cacheWithinException(); 1064 return TimeSpanImpl.fromDays(d.doubleValue()).getMillis(); 1065 } 1066 // createTimespan 1067 else if(val instanceof Variable) { 1068 Variable var=(Variable)val; 1069 if(var.getMembers().size()==1) { 1070 Member first = var.getFirstMember(); 1071 if(first instanceof BIF) { 1072 BIF bif=(BIF) first; 1073 if("createTimeSpan".equalsIgnoreCase(bif.getFlf().getName())) { 1074 Argument[] args = bif.getArguments(); 1075 int len=ArrayUtil.size(args); 1076 if(len>=4 && len<=5) { 1077 double days=toDouble(args[0].getValue()); 1078 double hours=toDouble(args[1].getValue()); 1079 double minutes=toDouble(args[2].getValue()); 1080 double seconds=toDouble(args[3].getValue()); 1081 double millis=len==5?toDouble(args[4].getValue()):0; 1082 return new TimeSpanImpl((int)days,(int)hours,(int)minutes,(int)seconds,(int)millis).getMillis(); 1083 } 1084 } 1085 } 1086 } 1087 } 1088 throw cacheWithinException(); 1089 } 1090 1091 1092 1093 private static EvaluatorException cacheWithinException() { 1094 return new EvaluatorException("value of cachedWithin must be a literal timespan, like 0.1 or createTimespan(1,2,3,4)"); 1095 } 1096 1097 1098 private static double toDouble(Expression e) throws EvaluatorException { 1099 if(!(e instanceof Literal)) 1100 throw new EvaluatorException("Paremeters of the function createTimeSpan have to be literal numeric values in this context"); 1101 Double d = ((Literal)e).getDouble(null); 1102 if(d==null) 1103 throw new EvaluatorException("Paremeters of the function createTimeSpan have to be literal numeric values in this context"); 1104 1105 return d.doubleValue(); 1106 } 1107 1108 public static void visitLabel(GeneratorAdapter ga, Label label) { 1109 if(label!=null) ga.visitLabel(label); 1110 } 1111 1112 1113 1114 public static String getClassName(Resource res) throws IOException{ 1115 byte[] src=IOUtil.toBytes(res); 1116 ClassReader cr = new ClassReader(src); 1117 return cr.getClassName(); 1118 } 1119 1120 public static String getClassName(byte[] barr){ 1121 return new ClassReader(barr).getClassName(); 1122 } 1123 1124 1125 public static String getSourceName(Class clazz) throws IOException { 1126 return SourceNameClassVisitor.getSourceName(clazz); 1127 } 1128 1129 }