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