1 /* 2 addIdentifier * Copyright (c) 2002, 2005, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 /* 26 * Portions Copyright (c) 2011 Jonas Maebe 27 */ 28 29 30 package fpc.tools.javapp; 31 32 import java.util.*; 33 import java.io.*; 34 35 import org.jgrapht.graph.DefaultEdge; 36 import org.jgrapht.graph.SimpleDirectedGraph; 37 import org.jgrapht.traverse.TopologicalOrderIterator; 38 39 import static fpc.tools.javapp.RuntimeConstants.*; 40 41 /** 42 * Program to print information about class files 43 * 44 * @author Sucheta Dambalkar 45 */ 46 public class JavapPrinter { 47 JavapEnvironment env; 48 PascalClassData cls; 49 // byte[] code; 50 String lP= ""; 51 PrintWriter out; 52 String prefix; 53 boolean doCollectDependencies; 54 boolean printOnlySkel; 55 56 private ArrayList<JavapPrinter> innerClassPrinters; 57 JavapPrinter(InputStream cname, PrintWriter out, JavapEnvironment env, String prefix, PascalClassData outerClass, boolean doCollectDependencies, boolean printOnlySkel)58 public JavapPrinter(InputStream cname, PrintWriter out, JavapEnvironment env, String prefix, PascalClassData outerClass, boolean doCollectDependencies, boolean printOnlySkel){ 59 this.out = out; 60 this.cls = new PascalClassData(cname,outerClass,env,doCollectDependencies); 61 this.env = env; 62 this.prefix = prefix; 63 this.doCollectDependencies = doCollectDependencies; 64 this.printOnlySkel = printOnlySkel; 65 innerClassPrinters = new ArrayList<JavapPrinter>(); 66 collectInnerClasses(); 67 } 68 69 /** 70 * Entry point to print class file information. 71 */ print()72 public void print(){ 73 printclassHeader(); 74 if (!printOnlySkel) { 75 printfields(); 76 printMethods(); 77 } 78 printend(); 79 } 80 81 /** 82 * Print a description of the class (not members). 83 */ printclassHeader()84 public void printclassHeader(){ 85 String vis = cls.getVisibilitySectionName(); 86 String shortname; 87 if (!cls.isInnerClass()) 88 shortname = cls.getShortPascalClassName(); 89 else { 90 shortname = cls.getShortClassName(); 91 } 92 if (!cls.isInnerClass()) { 93 if (vis != null) { 94 // inner class in separate visibility section 95 // (except in case of interface, those cannot have visibility 96 // sections) 97 if (!PascalClassData.currentUnit.parentIsKnownInterface(cls.getClassName())) { 98 out.println(prefix.substring(4)+vis); 99 } 100 out.println(prefix.substring(2)+"type"); 101 } 102 } 103 // the actual class/interface 104 out.print(prefix); 105 if(cls.isInterface()) { 106 // The only useful access modifier of an interface is 107 // public; interfaces are always marked as abstract and 108 // cannot be final. 109 out.print(shortname + " = interface "); 110 } 111 else if(cls.isClass()) { 112 out.print(shortname+" = class "); 113 String []accflags = cls.getModifiers(); 114 printAccess(accflags); 115 } 116 117 out.print("external "); 118 String pkgname = cls.getClassPackageName(); 119 if (pkgname != null) 120 out.print("'"+pkgname+"' "); 121 out.print("name '"+cls.getExternalShortClassName()+"' "); 122 123 if (!printOnlySkel) { 124 // FPC doesn't like it when you say that an interface's superclass is 125 // java.lang.Object, since that's a class (although at the JVM level 126 // it's true) 127 boolean printedOpeningBracket = false; 128 String superClass = cls.getSuperClassName(); 129 if((superClass != null) && 130 (cls.isClass() || 131 !PascalClassData.getShortPascalClassName(superClass).equals("JLObject"))){ 132 printedOpeningBracket = true; 133 String fullPascalSuperClass = PascalClassData.getFullPascalClassName(superClass); 134 String reducedPascalSuperClass = fullPascalSuperClass; 135 if (!PascalClassData.currentUnit.isExternalInnerClass(superClass) && 136 ((PascalClassData)cls).outerClass != null) { 137 reducedPascalSuperClass = fullPascalSuperClass.replace(((PascalClassData)cls).outerClass.getShortPascalClassName()+".",""); 138 } 139 if (reducedPascalSuperClass.equals(fullPascalSuperClass)) { 140 out.print("(" + PascalClassData.getShortPascalClassName(superClass)); 141 } else { 142 out.print("(" + reducedPascalSuperClass); 143 } 144 145 } 146 147 String []interfacelist = cls.getPascalSuperInterfaces(); 148 if(interfacelist.length > 0){ 149 // assume all classes that implement interfaces inherit from 150 // a class (correct, since java.lang.Object does not implement 151 // any interfaces 152 if (!printedOpeningBracket) { 153 out.print("("); 154 printedOpeningBracket=true; 155 out.print(interfacelist[0]); 156 } 157 else 158 out.print(", "+interfacelist[0]); 159 for(int j = 1; j < interfacelist.length; j++){ 160 out.print(", "+interfacelist[j]); 161 } 162 } 163 if (printedOpeningBracket) 164 out.print(")"); 165 } 166 /* inner classes */ 167 printClassAttributes(); 168 } 169 170 /** 171 * Print verbose output. 172 */ printverbosecls()173 public void printverbosecls(){ 174 out.println(prefix+" minor version: "+cls.getMinor_version()); 175 out.println(prefix+" major version: "+cls.getMajor_version()); 176 out.println(prefix+" Constant pool:"); 177 printcp(); 178 env.showallAttr = true; 179 } 180 181 /** 182 * Print class attribute information. 183 */ printClassAttributes()184 public void printClassAttributes(){ 185 out.println(); 186 AttrData[] clsattrs = cls.getAttributes(); 187 for(int i = 0; i < clsattrs.length; i++){ 188 String clsattrname = clsattrs[i].getAttrName(); 189 if(clsattrname.equals("InnerClasses")){ 190 printInnerClasses(); 191 } 192 } 193 } 194 195 /** 196 * Print the fields 197 */ printfields()198 public void printfields(){ 199 FieldData[] fields = cls.getFields(); 200 String prevVis = ""; 201 String prevMod = ""; 202 prefix=prefix+" "; 203 for(int f = 0; f < fields.length; f++){ 204 PascalFieldData field = (PascalFieldData)fields[f]; 205 if (field.isSynthetic()) 206 continue; 207 String[] accflags = field.getAccess(); 208 if(checkAccess(accflags)){ 209 String newVis = field.getVisibilitySectionName(); 210 String newMod = field.getModifiers(); 211 /* new visibility section? (Java interfaces can have 212 * public const sections) 213 * Also rewrite in case of a changed modifier (var, 214 * const, ...), because in Delphi mode that resets 215 * the visibility too 216 **/ 217 if (cls.isClass() && 218 (!newVis.equals(prevVis) || 219 !newMod.equals(prevMod))) { 220 out.println(prefix.substring(4)+newVis); 221 prevVis=newVis; 222 /* actually "var", but that will introduce gaps */ 223 prevMod=""; 224 } 225 /* new modifiers section? (sealed, var, class var, const) */ 226 if (!newMod.equals(prevMod)) { 227 out.println(prefix.substring(2)+newMod); 228 prevMod=newMod; 229 } 230 // the field name 231 String fieldName = field.getName(); 232 out.print(prefix); 233 // allowed, but discouraged and mainly for auto-generated fields 234 // not yet possible in Pascal, hide for now 235 if (fieldName.contains("$")) 236 out.print("// "); 237 if (!field.isFormalConst()) { 238 out.print(fieldName+": "+field.getType()); 239 } else { 240 out.print(fieldName); 241 printConstantValue(field); 242 } 243 244 // print field attribute information. 245 printFieldAttributes(field); 246 if (!field.isFormalConst()) { 247 out.print("; external name '"+fieldName.substring(env.prefix_field.length())+"'"); 248 } 249 out.println(";"); 250 } 251 } 252 prefix=prefix.substring(4); 253 } 254 255 256 /* print field attribute information. */ printFieldAttributes(FieldData field)257 public void printFieldAttributes(FieldData field){ 258 if (field.isDeprecated()) 259 out.print(" deprecated"); 260 } 261 262 /** 263 * Print the methods 264 */ printMethods()265 public void printMethods(){ 266 MethodData[] methods = cls.getMethods(); 267 String prevVis = ""; 268 prefix=prefix+" "; 269 for(int m = 0; m < methods.length; m++){ 270 PascalMethodData method = (PascalMethodData)methods[m]; 271 if (method.isSynthetic()) 272 continue; 273 String[] accflags = method.getAccess(); 274 if(checkAccess(accflags)){ 275 String newVis = method.getVisibilitySectionName(); 276 /* new visibility section? (interfaces don't have visibility 277 * sections, and Java interface methods are also all public) 278 **/ 279 if (cls.isClass() && 280 !newVis.equals(prevVis)) { 281 out.println(prefix.substring(2)+newVis); 282 prevVis=newVis; 283 } 284 printMethodSignature(method); 285 } 286 } 287 prefix=prefix.substring(2); 288 } 289 PrintSignatureVariants(PascalMethodData method, StringBuilder sigStart, StringBuilder sigEnd, boolean useConstOpenArray, boolean forceSingleVarVersion)290 protected void PrintSignatureVariants(PascalMethodData method, StringBuilder sigStart, StringBuilder sigEnd, boolean useConstOpenArray, boolean forceSingleVarVersion){ 291 java.util.Set<PascalTypeSignature.ParaFlags> paraFlags; 292 293 paraFlags = java.util.EnumSet.noneOf(PascalTypeSignature.ParaFlags.class); 294 String dynArrParas = method.getParameters(paraFlags); 295 296 paraFlags.add(PascalTypeSignature.ParaFlags.OpenArrays); 297 if (useConstOpenArray) 298 paraFlags.add(PascalTypeSignature.ParaFlags.OpenConstArrays); 299 String openArrParas = method.getParameters(paraFlags); 300 301 String regularVarParas = ""; 302 if (env.addVarOverloads && 303 (!useConstOpenArray || 304 forceSingleVarVersion)) { 305 paraFlags = java.util.EnumSet.noneOf(PascalTypeSignature.ParaFlags.class); 306 paraFlags.add(PascalTypeSignature.ParaFlags.SingleVar); 307 regularVarParas = method.getParameters(paraFlags); 308 } 309 310 out.print(sigStart+dynArrParas+sigEnd); 311 printExceptions(method); 312 out.println(); 313 if (!dynArrParas.equals(openArrParas)) { 314 out.print(sigStart+openArrParas+sigEnd); 315 printExceptions(method); 316 out.println(); 317 } 318 if ((regularVarParas != "") && 319 !dynArrParas.equals(regularVarParas)) { 320 out.print(sigStart+regularVarParas+sigEnd); 321 printExceptions(method); 322 out.println(); 323 } 324 } 325 326 /** 327 * Print method signature. 328 */ printMethodSignature(PascalMethodData method)329 public void printMethodSignature(PascalMethodData method){ 330 StringBuilder sigStart = new StringBuilder(); 331 StringBuilder sigEnd; 332 sigStart.append(prefix); 333 String pascalName = method.getName(); 334 boolean varargs = (method.access & ACC_VARARGS) != 0; 335 if(pascalName.equals("<init>")){ 336 sigStart.append("constructor create"); 337 sigEnd = new StringBuilder(); 338 // to fix compilation in Delphi mode 339 sigEnd.append("; overload;"); 340 PrintSignatureVariants(method,sigStart,sigEnd,true,true); 341 }else if(pascalName.equals("<clinit>")){ 342 sigStart.append("class constructor classcreate"); 343 }else{ 344 String rettype = method.getReturnType(); 345 java.util.Set<PascalTypeSignature.ParaFlags> paraFlags; 346 if (method.isStatic()) 347 sigStart.append("class "); 348 if (rettype.equals("")) 349 sigStart.append("procedure "); 350 else 351 sigStart.append("function "); 352 sigStart.append(pascalName); 353 sigEnd = new StringBuilder(); 354 if (!rettype.equals("")) 355 sigEnd.append(": "+rettype); 356 if (method.isStatic()) 357 sigEnd.append("; static"); 358 String externalName = method.getExternalName(); 359 if (externalName != null) 360 sigEnd.append("; external name '"+externalName+"'"); 361 // to fix compilation in Delphi mode 362 sigEnd.append("; overload;"); 363 // all interface methods are marked as "abstract", and cannot be final 364 if (!cls.isInterface()) 365 sigEnd.append(method.getModifiers()); 366 367 PrintSignatureVariants(method,sigStart,sigEnd,varargs,false); 368 } 369 } 370 371 /** 372 * print method attribute information. 373 */ printMethodAttributes(MethodData method)374 public void printMethodAttributes(MethodData method){ 375 Vector methodattrs = method.getAttributes(); 376 // Vector codeattrs = method.getCodeAttributes(); 377 for(int k = 0; k < methodattrs.size(); k++){ 378 String methodattrname = ((AttrData)methodattrs.elementAt(k)).getAttrName(); 379 if(methodattrname.equals("Code")){ 380 /* 381 printcodeSequence(method); 382 printExceptionTable(method); 383 for(int c = 0; c < codeattrs.size(); c++){ 384 String codeattrname = ((AttrData)codeattrs.elementAt(c)).getAttrName(); 385 if(codeattrname.equals("LineNumberTable")){ 386 printLineNumTable(method); 387 }else if(codeattrname.equals("LocalVariableTable")){ 388 printLocVarTable(method); 389 }else if(codeattrname.equals("StackMapTable")) { 390 // Java SE JSR 202 stack map tables 391 printStackMapTable(method); 392 }else if(codeattrname.equals("StackMap")) { 393 // Java ME CLDC stack maps 394 printStackMap(method); 395 } else { 396 printAttrData((AttrData)codeattrs.elementAt(c)); 397 } 398 } 399 */ 400 }else if(methodattrname.equals("Exceptions")){ 401 out.println(prefix+" Exceptions: "); 402 printExceptions(method); 403 }else if (methodattrname.equals("Deprecated")){ 404 out.println(prefix+" Deprecated: "+ method.isDeprecated()); 405 }else if (methodattrname.equals("Synthetic")){ 406 out.println(prefix+" Synthetic: "+ method.isSynthetic()); 407 }else { 408 printAttrData((AttrData)methodattrs.elementAt(k)); 409 } 410 } 411 out.println(); 412 } 413 414 /** 415 * Print exceptions. 416 */ printExceptions(MethodData method)417 public void printExceptions(MethodData method){ 418 int []exc_index_table = method.get_exc_index_table(); 419 if (exc_index_table != null) { 420 out.print(" // throws "); 421 int k; 422 int l = exc_index_table.length; 423 424 for (k=0; k<l; k++) { 425 out.print(javaclassname(cls.getClassName(exc_index_table[k]))); 426 if (k<l-1) out.print(", "); 427 } 428 } 429 } 430 431 /** 432 * Print code sequence. 433 */ printcodeSequence(MethodData method)434 public void printcodeSequence(MethodData method){ 435 /* 436 code = method.getCode(); 437 if(code != null){ 438 out.println(prefix+" Code:"); 439 if(env.showVerbose){ 440 printVerboseHeader(method); 441 } 442 443 for (int pc=0; pc < code.length; ) { 444 out.print(prefix+" "+pc+":\t"); 445 pc=pc+printInstr(pc); 446 out.println(); 447 } 448 } 449 */ 450 } 451 452 /** 453 * Print instructions. 454 */ 455 // public int printInstr(int pc){ 456 // int opcode = getUbyte(pc); 457 // int opcode2; 458 // String mnem; 459 // switch (opcode) { 460 // case opc_nonpriv: 461 // case opc_priv: 462 // opcode2 = getUbyte(pc+1); 463 // mnem=Tables.opcName((opcode<<8)+opcode2); 464 // if (mnem==null) 465 // // assume all (even nonexistent) priv and nonpriv instructions 466 // // are 2 bytes long 467 // mnem=Tables.opcName(opcode)+" "+opcode2; 468 // out.print(mnem); 469 // return 2; 470 // case opc_wide: { 471 // opcode2 = getUbyte(pc+1); 472 // mnem=Tables.opcName((opcode<<8)+opcode2); 473 // if (mnem==null) { 474 // // nonexistent opcode - but we have to print something 475 // out.print("bytecode "+opcode); 476 // return 1; 477 // } 478 // out.print(mnem+" "+getUShort(pc+2)); 479 // if (opcode2==opc_iinc) { 480 // out.print(", "+getShort(pc+4)); 481 // return 6; 482 // } 483 // return 4; 484 // } 485 // } 486 // mnem=Tables.opcName(opcode); 487 // if (mnem==null) { 488 // // nonexistent opcode - but we have to print something 489 // out.print("bytecode "+opcode); 490 // return 1; 491 // } 492 // if (opcode>opc_jsr_w) { 493 // // pseudo opcodes should be printed as bytecodes 494 // out.print("bytecode "+opcode); 495 // return 1; 496 // } 497 // out.print(Tables.opcName(opcode)); 498 // switch (opcode) { 499 // case opc_aload: case opc_astore: 500 // case opc_fload: case opc_fstore: 501 // case opc_iload: case opc_istore: 502 // case opc_lload: case opc_lstore: 503 // case opc_dload: case opc_dstore: 504 // case opc_ret: 505 // out.print("\t"+getUbyte(pc+1)); 506 // return 2; 507 // case opc_iinc: 508 // out.print("\t"+getUbyte(pc+1)+", "+getbyte(pc+2)); 509 // return 3; 510 // case opc_tableswitch:{ 511 // int tb=align(pc+1); 512 // int default_skip = getInt(tb); /* default skip pamount */ 513 // int low = getInt(tb+4); 514 // int high = getInt(tb+8); 515 // int count = high - low; 516 // out.print("{ //"+low+" to "+high); 517 // for (int i = 0; i <= count; i++) 518 // out.print( "\n\t\t" + (i+low) + ": "+lP+(pc+getInt(tb+12+4*i))+";"); 519 // out.print("\n\t\tdefault: "+lP+(default_skip + pc) + " }"); 520 // return tb-pc+16+count*4; 521 // } 522 // 523 // case opc_lookupswitch:{ 524 // int tb=align(pc+1); 525 // int default_skip = getInt(tb); 526 // int npairs = getInt(tb+4); 527 // out.print("{ //"+npairs); 528 // for (int i = 1; i <= npairs; i++) 529 // out.print("\n\t\t"+getInt(tb+i*8) 530 // +": "+lP+(pc+getInt(tb+4+i*8))+";" 531 // ); 532 // out.print("\n\t\tdefault: "+lP+(default_skip + pc) + " }"); 533 // return tb-pc+(npairs+1)*8; 534 // } 535 // case opc_newarray: 536 // int type=getUbyte(pc+1); 537 // switch (type) { 538 // case T_BOOLEAN:out.print(" boolean");break; 539 // case T_BYTE: out.print(" byte"); break; 540 // case T_CHAR: out.print(" char"); break; 541 // case T_SHORT: out.print(" short"); break; 542 // case T_INT: out.print(" int"); break; 543 // case T_LONG: out.print(" long"); break; 544 // case T_FLOAT: out.print(" float"); break; 545 // case T_DOUBLE: out.print(" double"); break; 546 // case T_CLASS: out.print(" class"); break; 547 // default: out.print(" BOGUS TYPE:"+type); 548 // } 549 // return 2; 550 // 551 // case opc_anewarray: { 552 // int index = getUShort(pc+1); 553 // out.print("\t#"+index+"; //"); 554 // PrintConstant(index); 555 // return 3; 556 // } 557 // 558 // case opc_sipush: 559 // out.print("\t"+getShort(pc+1)); 560 // return 3; 561 // 562 // case opc_bipush: 563 // out.print("\t"+getbyte(pc+1)); 564 // return 2; 565 // 566 // case opc_ldc: { 567 // int index = getUbyte(pc+1); 568 // out.print("\t#"+index+"; //"); 569 // PrintConstant(index); 570 // return 2; 571 // } 572 // 573 // case opc_ldc_w: case opc_ldc2_w: 574 // case opc_instanceof: case opc_checkcast: 575 // case opc_new: 576 // case opc_putstatic: case opc_getstatic: 577 // case opc_putfield: case opc_getfield: 578 // case opc_invokevirtual: 579 // case opc_invokespecial: 580 // case opc_invokestatic: { 581 // int index = getUShort(pc+1); 582 // out.print("\t#"+index+"; //"); 583 // PrintConstant(index); 584 // return 3; 585 // } 586 // 587 // case opc_invokeinterface: { 588 // int index = getUShort(pc+1), nargs=getUbyte(pc+3); 589 // out.print("\t#"+index+", "+nargs+"; //"); 590 // PrintConstant(index); 591 // return 5; 592 // } 593 // 594 // case opc_multianewarray: { 595 // int index = getUShort(pc+1), dimensions=getUbyte(pc+3); 596 // out.print("\t#"+index+", "+dimensions+"; //"); 597 // PrintConstant(index); 598 // return 4; 599 // } 600 // case opc_jsr: case opc_goto: 601 // case opc_ifeq: case opc_ifge: case opc_ifgt: 602 // case opc_ifle: case opc_iflt: case opc_ifne: 603 // case opc_if_icmpeq: case opc_if_icmpne: case opc_if_icmpge: 604 // case opc_if_icmpgt: case opc_if_icmple: case opc_if_icmplt: 605 // case opc_if_acmpeq: case opc_if_acmpne: 606 // case opc_ifnull: case opc_ifnonnull: 607 // out.print("\t"+lP+(pc + getShort(pc+1)) ); 608 // return 3; 609 // 610 // case opc_jsr_w: 611 // case opc_goto_w: 612 // out.print("\t"+lP+(pc + getInt(pc+1))); 613 // return 5; 614 // 615 // default: 616 // return 1; 617 // } 618 // } 619 /** 620 * Print code attribute details. 621 */ printVerboseHeader(MethodData method)622 public void printVerboseHeader(MethodData method) { 623 /* 624 int argCount = method.getArgumentlength(); 625 if (!method.isStatic()) 626 ++argCount; // for 'this' 627 628 out.println(" Stack=" + method.getMaxStack() 629 + ", Locals=" + method.getMaxLocals() 630 + ", Args_size=" + argCount); 631 */ 632 } 633 634 635 /** 636 * Print the exception table for this method code 637 */ printExceptionTable(MethodData method)638 void printExceptionTable(MethodData method){//throws IOException 639 /* 640 Vector exception_table = method.getexception_table(); 641 if (exception_table.size() > 0) { 642 out.println(prefix+" Exception table:"); 643 out.println(prefix+" from to target type"); 644 for (int idx = 0; idx < exception_table.size(); ++idx) { 645 TrapData handler = (TrapData)exception_table.elementAt(idx); 646 out.print(prefix); 647 printFixedWidthInt(handler.start_pc, 6); 648 printFixedWidthInt(handler.end_pc, 6); 649 printFixedWidthInt(handler.handler_pc, 6); 650 out.print(" "); 651 int catch_cpx = handler.catch_cpx; 652 if (catch_cpx == 0) { 653 out.println("any"); 654 }else { 655 out.print("Class "); 656 out.println(cls.getClassName(catch_cpx)); 657 out.println(""); 658 } 659 } 660 } 661 */ 662 } 663 664 /** 665 * Print LineNumberTable attribute information. 666 */ printLineNumTable(MethodData method)667 public void printLineNumTable(MethodData method) { 668 /* 669 int numlines = method.getnumlines(); 670 Vector lin_num_tb = method.getlin_num_tb(); 671 if( lin_num_tb.size() > 0){ 672 out.println(prefix+" LineNumberTable: "); 673 for (int i=0; i<numlines; i++) { 674 LineNumData linnumtb_entry=(LineNumData)lin_num_tb.elementAt(i); 675 out.println(prefix+" line " + linnumtb_entry.line_number + ": " 676 + linnumtb_entry.start_pc); 677 } 678 } 679 out.println(); 680 */ 681 } 682 683 /** 684 * Print LocalVariableTable attribute information. 685 */ printLocVarTable(MethodData method)686 public void printLocVarTable(MethodData method){ 687 /* 688 int siz = method.getloc_var_tbsize(); 689 if(siz > 0){ 690 out.println(prefix+" LocalVariableTable: "); 691 out.print(prefix+" "); 692 out.println("Start Length Slot Name Signature"); 693 } 694 Vector loc_var_tb = method.getloc_var_tb(); 695 696 for (int i=0; i<siz; i++) { 697 LocVarData entry=(LocVarData)loc_var_tb.elementAt(i); 698 699 out.println(prefix+" "+entry.start_pc+" "+entry.length+" "+ 700 entry.slot+" "+cls.StringValue(entry.name_cpx) + 701 " "+cls.StringValue(entry.sig_cpx)); 702 } 703 out.println(); 704 */ 705 } 706 707 /** 708 * Print StackMap attribute information. 709 */ printStackMap(MethodData method)710 public void printStackMap(MethodData method) { 711 /* 712 StackMapData[] stack_map_tb = method.getStackMap(); 713 int number_of_entries = stack_map_tb.length; 714 if (number_of_entries > 0) { 715 out.println(prefix+" StackMap: number_of_entries = " + number_of_entries); 716 717 for (StackMapData frame : stack_map_tb) { 718 frame.print(this); 719 } 720 } 721 out.println(); 722 */ 723 } 724 725 /** 726 * Print StackMapTable attribute information. 727 */ printStackMapTable(MethodData method)728 public void printStackMapTable(MethodData method) { 729 /* 730 StackMapTableData[] stack_map_tb = method.getStackMapTable(); 731 int number_of_entries = stack_map_tb.length; 732 if (number_of_entries > 0) { 733 out.println(prefix+" StackMapTable: number_of_entries = " + number_of_entries); 734 735 for (StackMapTableData frame : stack_map_tb) { 736 frame.print(this); 737 } 738 } 739 out.println(); 740 */ 741 } 742 printMap(String name, int[] map)743 void printMap(String name, int[] map) { 744 out.print(name); 745 for (int i=0; i<map.length; i++) { 746 int fulltype = map[i]; 747 int type = fulltype & 0xFF; 748 int argument = fulltype >> 8; 749 switch (type) { 750 case ITEM_Object: 751 out.print(" "); 752 PrintConstant(argument); 753 break; 754 case ITEM_NewObject: 755 out.print(" " + Tables.mapTypeName(type)); 756 out.print(" " + argument); 757 break; 758 default: 759 out.print(" " + Tables.mapTypeName(type)); 760 } 761 out.print( (i==(map.length-1)? ' ' : ',')); 762 } 763 out.println("]"); 764 } 765 766 /** 767 * Print ConstantValue attribute information. 768 */ printConstantValue(FieldData field)769 public void printConstantValue(FieldData field){ 770 int cpx = (field.getConstantValueIndex()); 771 if (cpx==0) 772 return; 773 byte tag=0; 774 try { 775 tag=cls.getTag(cpx); 776 777 } catch (IndexOutOfBoundsException e) { 778 return; 779 } 780 switch (tag) { 781 case CONSTANT_METHOD: 782 case CONSTANT_INTERFACEMETHOD: 783 case CONSTANT_FIELD: 784 case CONSTANT_NAMEANDTYPE: 785 // don't print their value in the header, since they're not 786 // constant expressions anyway. We treat them as external data. 787 return; 788 } 789 out.print(" = "+ cls.StringValue(cpx)); 790 } 791 792 793 /** 794 * Collect InnerClasses 795 */ collectInnerClasses()796 public void collectInnerClasses(){//throws ioexception 797 InnerClassData[] innerClasses = cls.getInnerClasses(); 798 if(innerClasses != null){ 799 if(innerClasses.length > 0){ 800 JavapPrinter innerPrinter; 801 String curClassName = cls.getClassName(); 802 for(int i = 0 ; i < innerClasses.length; i++){ 803 String[] accflags = innerClasses[i].getAccess(); 804 PascalInnerClassData inner = (PascalInnerClassData)innerClasses[i]; 805 String innerClassName = cls.StringValue(inner.inner_class_info_index); 806 // * inner class names that do not begin with this class' name are 807 // unrelated to this class (they're nested somewhere else) 808 // * inner class names that start with 0-9 are anonymous 809 if (innerClassName.startsWith(curClassName+"$") && 810 !((innerClassName.charAt(curClassName.length()+1) >= '0') && 811 (innerClassName.charAt(curClassName.length()+1) <= '9'))) { 812 boolean accessOk = checkAccess(accflags); 813 boolean isStaticInner = inner.isStatic(); 814 innerPrinter = new JavapPrinter(env.getFileInputStream(javaclassname(innerClassName)), out, env, prefix+" ", cls, 815 doCollectDependencies && accessOk && isStaticInner, printOnlySkel || !accessOk || !isStaticInner); 816 innerClassPrinters.add(innerPrinter); 817 } 818 } 819 } 820 } 821 } 822 823 /** 824 * Print InnerClass attribute information. 825 */ 826 private final int VIS_PRIVATE = 0; 827 private final int VIS_PACKAGE = 1; 828 private final int VIS_PROTECTED = 2; 829 private final int VIS_PUBLIC = 3; 830 checkInnerVisibility(int access, int visOk)831 private boolean checkInnerVisibility(int access, int visOk) { 832 switch (visOk) { 833 case VIS_PRIVATE: 834 return ((access & ACC_PRIVATE) != 0); 835 case VIS_PACKAGE: 836 return ((access & (ACC_PUBLIC|ACC_PROTECTED|ACC_PRIVATE)) == 0); 837 case VIS_PROTECTED: 838 return ((access & ACC_PROTECTED) != 0); 839 case VIS_PUBLIC: 840 return ((access & ACC_PUBLIC) != 0); 841 default: 842 return false; 843 } 844 } 845 visibilitySectionName(int vis)846 private String visibilitySectionName(int vis) { 847 switch (vis) { 848 case VIS_PRIVATE: 849 return "strict private"; 850 case VIS_PACKAGE: 851 // should be "private", but then won't work for classes of the 852 // same package declared in different units, which happens 853 // at least for the classes in the system unit... 854 return "public"; 855 case VIS_PROTECTED: 856 return "protected"; 857 case VIS_PUBLIC: 858 return "public"; 859 default: 860 return ""; 861 } 862 } 863 printInnerClasses()864 public void printInnerClasses(){//throws ioexception 865 866 if (innerClassPrinters.size() > 1) 867 orderInnerClasses(); 868 869 if (innerClassPrinters.size() > 0) { 870 for (int protpub = VIS_PACKAGE; protpub <= VIS_PUBLIC; protpub++) { 871 // no vibility sections in interfaces 872 boolean first = true; 873 for (int i = 0; i < innerClassPrinters.size(); i++) { 874 JavapPrinter innerPrinter = innerClassPrinters.get(i); 875 if (checkInnerVisibility(innerPrinter.cls.access,protpub)) { 876 String shortInnerName = PascalClassData.getShortClassName(env,innerPrinter.cls.getClassName()); 877 String shortInnerSafeName = ClassIdentifierInfo.AddIdentifierNameForClass(cls.getClassName(),shortInnerName); 878 if (first) { 879 if (!cls.isInterface()) { 880 out.print(prefix); 881 out.println(visibilitySectionName(protpub)); 882 } 883 out.println(innerPrinter.prefix.substring(2)+"type"); 884 first = false; 885 } 886 out.print(innerPrinter.prefix+shortInnerSafeName+" = "); 887 if (innerPrinter.cls.isClass()) 888 out.println("class;"); 889 else 890 out.println("interface;"); 891 PascalUnit.printArrayTypes(out, innerPrinter.prefix, shortInnerName, shortInnerSafeName); 892 } 893 } 894 for (int i = 0; i < innerClassPrinters.size(); i++) { 895 JavapPrinter innerPrinter = innerClassPrinters.get(i); 896 if (checkInnerVisibility(innerPrinter.cls.access,protpub)) { 897 innerPrinter.print(); 898 } 899 } 900 } 901 } 902 } 903 904 /** 905 * Orders the inner classes according to their interdependencies 906 */ orderInnerClasses()907 private void orderInnerClasses() { 908 boolean haveDependencies = false; 909 for (int i = 0; i < innerClassPrinters.size(); i++) { 910 if (!innerClassPrinters.get(i).cls.getDependencies().isEmpty()) { 911 haveDependencies = true; 912 break; 913 } 914 } 915 if (haveDependencies) { 916 SimpleDirectedGraph<String,DefaultEdge> classDependencies = new SimpleDirectedGraph<String, DefaultEdge>(DefaultEdge.class); 917 for (int i = 0; i < innerClassPrinters.size(); i++) { 918 JavapPrinter innerPrinter = innerClassPrinters.get(i); 919 String currentClass = innerPrinter.cls.getClassName(); 920 if (!classDependencies.containsVertex(currentClass)) 921 classDependencies.addVertex(currentClass); 922 923 HashSet<String> dependencies = innerPrinter.cls.getDependencies(); 924 Iterator<String> depStepper = dependencies.iterator(); 925 while (depStepper.hasNext()) { 926 String dep = depStepper.next(); 927 if (!classDependencies.containsVertex(dep)) 928 classDependencies.addVertex(dep); 929 classDependencies.addEdge(dep, currentClass); 930 } 931 } 932 TopologicalOrderIterator<String,DefaultEdge> printerStepper = new TopologicalOrderIterator<String,DefaultEdge>(classDependencies); 933 934 ArrayList<JavapPrinter> orderedInnerClassPrinters = new ArrayList<JavapPrinter>(innerClassPrinters.size()); 935 while (printerStepper.hasNext()) { 936 String currentName = printerStepper.next(); 937 for (int i = 0; i < innerClassPrinters.size(); i++) { 938 if (innerClassPrinters.get(i).cls.getClassName().equals(currentName)) { 939 orderedInnerClassPrinters.add(innerClassPrinters.get(i)); 940 break; 941 } 942 } 943 } 944 innerClassPrinters = orderedInnerClassPrinters; 945 } 946 } 947 948 /** 949 * Print constant pool information. 950 */ printcp()951 public void printcp(){ 952 int cpx = 1 ; 953 954 while (cpx < cls.getCpoolCount()) { 955 out.print("const #"+cpx+" = "); 956 cpx+=PrintlnConstantEntry(cpx); 957 } 958 out.println(); 959 } 960 961 /** 962 * Print constant pool entry information. 963 */ PrintlnConstantEntry(int cpx)964 public int PrintlnConstantEntry(int cpx) { 965 int size=1; 966 byte tag=0; 967 try { 968 tag=cls.getTag(cpx); 969 } catch (IndexOutOfBoundsException e) { 970 out.println(" <Incorrect CP index>"); 971 return 1; 972 } 973 out.print(cls.StringTag(cpx)+"\t"); 974 Object x=cls.getCpoolEntryobj(cpx); 975 if (x==null) { 976 switch (tag) { 977 case CONSTANT_LONG: 978 case CONSTANT_DOUBLE: 979 size=2; 980 } 981 out.println("null;"); 982 return size; 983 } 984 String str=cls.StringValue(cpx); 985 986 switch (tag) { 987 case CONSTANT_CLASS: 988 case CONSTANT_STRING: 989 out.println("#"+(((CPX)x).cpx)+";\t// "+str); 990 break; 991 case CONSTANT_FIELD: 992 case CONSTANT_METHOD: 993 case CONSTANT_INTERFACEMETHOD: 994 out.println("#"+((CPX2)x).cpx1+".#"+((CPX2)x).cpx2+";\t// "+str); 995 break; 996 case CONSTANT_NAMEANDTYPE: 997 out.println("#"+((CPX2)x).cpx1+":#"+((CPX2)x).cpx2+";// "+str); 998 break; 999 case CONSTANT_LONG: 1000 case CONSTANT_DOUBLE: 1001 size=2; 1002 default: 1003 out.println(str+";"); 1004 } 1005 return size; 1006 } 1007 checkAccess(String accflags[])1008 public boolean checkAccess(String accflags[]){ 1009 return TypeSignature.checkAccess(accflags, this.env); 1010 } 1011 1012 /** 1013 * Prints access of class, field or method. 1014 */ printAccess(String []accflags)1015 public void printAccess(String []accflags){ 1016 1017 for(int j = 0; j < accflags.length; j++){ 1018 out.print(accflags[j]+" "); 1019 } 1020 } 1021 1022 /** 1023 * Print an integer so that it takes 'length' characters in 1024 * the output. Temporary until formatting code is stable. 1025 */ printFixedWidthInt(long x, int length)1026 public void printFixedWidthInt(long x, int length) { 1027 CharArrayWriter baStream = new CharArrayWriter(); 1028 PrintWriter pStream = new PrintWriter(baStream); 1029 pStream.print(x); 1030 String str = baStream.toString(); 1031 for (int cnt = length - str.length(); cnt > 0; --cnt) 1032 out.print(' '); 1033 out.print(str); 1034 } 1035 /* 1036 protected int getbyte (int pc) { 1037 return code[pc]; 1038 } 1039 1040 protected int getUbyte (int pc) { 1041 return code[pc]&0xFF; 1042 } 1043 1044 int getShort (int pc) { 1045 return (code[pc]<<8) | (code[pc+1]&0xFF); 1046 } 1047 1048 int getUShort (int pc) { 1049 return ((code[pc]<<8) | (code[pc+1]&0xFF))&0xFFFF; 1050 } 1051 1052 protected int getInt (int pc) { 1053 return (getShort(pc)<<16) | (getShort(pc+2)&0xFFFF); 1054 } 1055 */ 1056 /** 1057 * Print constant value at that index. 1058 */ PrintConstant(int cpx)1059 void PrintConstant(int cpx) { 1060 if (cpx==0) { 1061 out.print("#0"); 1062 return; 1063 } 1064 byte tag=0; 1065 try { 1066 tag=cls.getTag(cpx); 1067 1068 } catch (IndexOutOfBoundsException e) { 1069 out.print("#"+cpx); 1070 return; 1071 } 1072 switch (tag) { 1073 case CONSTANT_METHOD: 1074 case CONSTANT_INTERFACEMETHOD: 1075 case CONSTANT_FIELD: { 1076 // CPX2 x=(CPX2)(cpool[cpx]); 1077 CPX2 x = (CPX2)(cls.getCpoolEntry(cpx)); 1078 if (x.cpx1 == cls.getthis_cpx()) { 1079 // don't print class part for local references 1080 cpx=x.cpx2; 1081 } 1082 } 1083 } 1084 out.print(cls.TagString(tag)+" "+ cls.StringValue(cpx)); 1085 } 1086 align(int n)1087 protected static int align (int n) { 1088 return (n+3) & ~3 ; 1089 } 1090 printend()1091 public void printend(){ 1092 out.println(prefix+"end;"); 1093 out.println(); 1094 /* 1095 if (cls.isInnerClass()) { 1096 String shortName = PascalClassData.getShortClassName(cls.getClassName()); 1097 if (PascalKeywords.isPascalKeyword(shortName)) 1098 shortName = "&" + shortName; 1099 String pascalShortName = PascalClassData.getShortPascalClassName(cls.getClassName()); 1100 out.println(prefix+pascalShortName+" = "+shortName+";"); 1101 } 1102 out.println(); 1103 */ 1104 } 1105 javaclassname(String name)1106 public String javaclassname(String name){ 1107 return name.replace('/','.'); 1108 } 1109 javaparentclassname(String name)1110 public String javaparentclassname(String name) { 1111 int index = name.lastIndexOf('$'); 1112 if (index == -1) 1113 return ""; 1114 else 1115 return name.substring(0,index); 1116 } 1117 javaclassnestinglevel(String name)1118 public int javaclassnestinglevel(String name) { 1119 int count, i; 1120 count = 0; 1121 for (i=1; i < name.length(); i++) 1122 if (name.charAt(i) == '$') 1123 count++; 1124 return count; 1125 } 1126 1127 /** 1128 * Print attribute data in hex. 1129 */ printAttrData(AttrData attr)1130 public void printAttrData(AttrData attr){ 1131 byte []data = attr.getData(); 1132 int i = 0; 1133 int j = 0; 1134 out.print(" "+attr.getAttrName()+": "); 1135 out.println("length = " + cls.toHex(attr.datalen)); 1136 1137 out.print(" "); 1138 1139 1140 while (i < data.length){ 1141 String databytestring = cls.toHex(data[i]); 1142 if(databytestring.equals("0x")) out.print("00"); 1143 else if(databytestring.substring(2).length() == 1){ 1144 out.print("0"+databytestring.substring(2)); 1145 } else{ 1146 out.print(databytestring.substring(2)); 1147 } 1148 1149 j++; 1150 if(j == 16) { 1151 out.println(); 1152 out.print(" "); 1153 j = 0; 1154 } 1155 else out.print(" "); 1156 i++; 1157 } 1158 out.println(); 1159 } 1160 } 1161