1292 lines
51 KiB
Java
1292 lines
51 KiB
Java
/*
|
|
* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
package org.openjdk.asmtools.jdec;
|
|
|
|
import org.openjdk.asmtools.common.Module;
|
|
import org.openjdk.asmtools.asmutils.StringUtils;
|
|
import org.openjdk.asmtools.jasm.Modifiers;
|
|
import org.openjdk.asmtools.jcoder.JcodTokens;
|
|
import org.openjdk.asmtools.util.I18NResourceBundle;
|
|
|
|
import java.awt.event.KeyEvent;
|
|
import java.io.DataInputStream;
|
|
import java.io.EOFException;
|
|
import java.io.IOException;
|
|
import java.io.PrintWriter;
|
|
|
|
import static java.lang.String.format;
|
|
import static org.openjdk.asmtools.jasm.Tables.*;
|
|
import static org.openjdk.asmtools.jasm.Tables.AnnotElemType.AE_UNKNOWN;
|
|
import static org.openjdk.asmtools.jasm.TypeAnnotationTypes.*;
|
|
|
|
/**
|
|
* Class data of the Java Decoder
|
|
*/
|
|
class ClassData {
|
|
|
|
private byte[] types;
|
|
private Object[] cpool;
|
|
private int CPlen;
|
|
private NestedByteArrayInputStream countedin;
|
|
private DataInputStream in;
|
|
private PrintWriter out;
|
|
private int[] cpe_pos;
|
|
private boolean printDetails;
|
|
private String entityType = "";
|
|
private String entityName = "";
|
|
|
|
public static I18NResourceBundle i18n
|
|
= I18NResourceBundle.getBundleForClass(Main.class);
|
|
|
|
ClassData(DataInputStream dis, int printFlags, PrintWriter out) throws IOException {
|
|
byte[] buf = new byte[dis.available()];
|
|
try {
|
|
if (dis.read(buf) <= 0)
|
|
throw new IOException("The file is empty");
|
|
} finally {
|
|
dis.close();
|
|
}
|
|
countedin = new NestedByteArrayInputStream(buf);
|
|
in = new DataInputStream(countedin);
|
|
this.out = out;
|
|
printDetails = ((printFlags & 1) == 1);
|
|
}
|
|
|
|
/*========================================================*/
|
|
private static final char[] hexTable = {
|
|
'0', '1', '2', '3', '4', '5', '6', '7',
|
|
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
|
};
|
|
|
|
private String toHex(long val, int width) {
|
|
StringBuilder s = new StringBuilder();
|
|
for (int i = width * 2 - 1; i >= 0; i--) {
|
|
s.append(hexTable[((int) (val >> (4 * i))) & 0xF]);
|
|
}
|
|
return "0x" + s.toString();
|
|
}
|
|
|
|
private String toHex(long val) {
|
|
int width;
|
|
for (width = 8; width > 0; width--) {
|
|
if ((val >> (width - 1) * 8) != 0) {
|
|
break;
|
|
}
|
|
}
|
|
return toHex(val, width);
|
|
}
|
|
|
|
private void printByteHex(PrintWriter out, int b) {
|
|
out.print(hexTable[(b >> 4) & 0xF]);
|
|
out.print(hexTable[b & 0xF]);
|
|
}
|
|
|
|
private void printBytes(PrintWriter out, DataInputStream in, int len)
|
|
throws IOException {
|
|
try {
|
|
for (int i = 0; i < len; i++) {
|
|
if (i % 8 == 0) {
|
|
out_print("0x");
|
|
}
|
|
printByteHex(out, in.readByte());
|
|
if (i % 8 == 7) {
|
|
out.println(";");
|
|
}
|
|
}
|
|
} finally {
|
|
if (len % 8 != 0) {
|
|
out.println(";");
|
|
}
|
|
}
|
|
}
|
|
|
|
private void printRestOfBytes() {
|
|
for (int i = 0; ; i++) {
|
|
try {
|
|
byte b = in.readByte();
|
|
if (i % 8 == 0) {
|
|
out_print("0x");
|
|
}
|
|
printByteHex(out, b);
|
|
if (i % 8 == 7) {
|
|
out.print(";\n");
|
|
}
|
|
} catch (IOException e) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void printUtf8InfoIndex(int index, String indexName) {
|
|
String name = (String) cpool[index];
|
|
out_print("#" + index + "; // ");
|
|
if (printDetails) {
|
|
out.println(String.format("%-16s",indexName) + " : " + name);
|
|
} else {
|
|
out.println(indexName);
|
|
}
|
|
}
|
|
|
|
/*========================================================*/
|
|
private int shift = 0;
|
|
|
|
private void out_begin(String s) {
|
|
for (int i = 0; i < shift; i++) {
|
|
out.print(" ");
|
|
}
|
|
out.println(s);
|
|
shift++;
|
|
}
|
|
|
|
private void out_print(String s) {
|
|
for (int i = 0; i < shift; i++) {
|
|
out.print(" ");
|
|
}
|
|
out.print(s);
|
|
}
|
|
|
|
private void out_println(String s) {
|
|
for (int i = 0; i < shift; i++) {
|
|
out.print(" ");
|
|
}
|
|
out.println(s);
|
|
}
|
|
|
|
private void out_end(String s) {
|
|
shift--;
|
|
for (int i = 0; i < shift; i++) {
|
|
out.print(" ");
|
|
}
|
|
out.println(s);
|
|
}
|
|
|
|
private String startArray(int length) {
|
|
return "[" + (printDetails ? Integer.toString(length) : "") + "]";
|
|
}
|
|
|
|
private void startArrayCmt(int length, String comment) {
|
|
out_begin(startArray(length) + format(" {%s", comment == null ? "" : " // " + comment));
|
|
}
|
|
|
|
private void startArrayCmtB(int length, String comment) {
|
|
out_begin(startArray(length) + format("b {%s", comment == null ? "" : " // " + comment));
|
|
}
|
|
|
|
/*========================================================*/
|
|
private void readCP(DataInputStream in) throws IOException {
|
|
int length = in.readUnsignedShort();
|
|
CPlen = length;
|
|
traceln(i18n.getString("jdec.trace.CP_len", length));
|
|
types = new byte[length];
|
|
cpool = new Object[length];
|
|
cpe_pos = new int[length];
|
|
for (int i = 1; i < length; i++) {
|
|
byte btag;
|
|
int v1;
|
|
long lv;
|
|
cpe_pos[i] = countedin.getPos();
|
|
btag = in.readByte();
|
|
traceln(i18n.getString("jdec.trace.CP_entry", i, btag));
|
|
types[i] = btag;
|
|
ConstType tg = tag(btag);
|
|
switch (tg) {
|
|
case CONSTANT_UTF8:
|
|
cpool[i] = in.readUTF();
|
|
break;
|
|
case CONSTANT_INTEGER:
|
|
v1 = in.readInt();
|
|
cpool[i] = v1;
|
|
break;
|
|
case CONSTANT_FLOAT:
|
|
v1 = Float.floatToIntBits(in.readFloat());
|
|
cpool[i] = v1;
|
|
break;
|
|
case CONSTANT_LONG:
|
|
lv = in.readLong();
|
|
cpool[i] = lv;
|
|
i++;
|
|
break;
|
|
case CONSTANT_DOUBLE:
|
|
lv = Double.doubleToLongBits(in.readDouble());
|
|
cpool[i] = lv;
|
|
i++;
|
|
break;
|
|
case CONSTANT_CLASS:
|
|
case CONSTANT_STRING:
|
|
case CONSTANT_MODULE:
|
|
case CONSTANT_PACKAGE:
|
|
v1 = in.readUnsignedShort();
|
|
cpool[i] = v1;
|
|
break;
|
|
case CONSTANT_INTERFACEMETHOD:
|
|
case CONSTANT_FIELD:
|
|
case CONSTANT_METHOD:
|
|
case CONSTANT_NAMEANDTYPE:
|
|
cpool[i] = "#" + in.readUnsignedShort() + " #" + in.readUnsignedShort();
|
|
break;
|
|
case CONSTANT_DYNAMIC:
|
|
case CONSTANT_INVOKEDYNAMIC:
|
|
cpool[i] = in.readUnsignedShort() + "s #" + in.readUnsignedShort();
|
|
break;
|
|
case CONSTANT_METHODHANDLE:
|
|
cpool[i] = in.readUnsignedByte() + "b #" + in.readUnsignedShort();
|
|
break;
|
|
case CONSTANT_METHODTYPE:
|
|
cpool[i] = "#" + in.readUnsignedShort();
|
|
break;
|
|
default:
|
|
CPlen = i;
|
|
printCP(out);
|
|
out_println(toHex(btag, 1) + "; // invalid constant type: " + (int) btag + " for element " + i);
|
|
throw new ClassFormatError();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void printCP(PrintWriter out) {
|
|
int length = CPlen;
|
|
startArrayCmt(length, "Constant Pool");
|
|
out_println("; // first element is empty");
|
|
try {
|
|
int size;
|
|
for (int i = 1; i < length; i = i + size) {
|
|
size = 1;
|
|
byte btag = types[i];
|
|
ConstType tg = tag(btag);
|
|
int pos = cpe_pos[i];
|
|
String tagstr;
|
|
String valstr;
|
|
int v1;
|
|
long lv;
|
|
if (tg != null) {
|
|
tagstr = tg.parseKey();
|
|
} else {
|
|
throw new Error("Can't get a tg representing the type of Constant in the Constant Pool at: " + i);
|
|
}
|
|
switch (tg) {
|
|
case CONSTANT_UTF8: {
|
|
tagstr = "Utf8";
|
|
valstr = StringUtils.Utf8ToString((String) cpool[i]);
|
|
}
|
|
break;
|
|
case CONSTANT_FLOAT:
|
|
case CONSTANT_INTEGER:
|
|
v1 = (Integer) cpool[i];
|
|
valstr = toHex(v1, 4);
|
|
break;
|
|
case CONSTANT_DOUBLE:
|
|
case CONSTANT_LONG:
|
|
lv = (Long) cpool[i];
|
|
valstr = toHex(lv, 8) + ";";
|
|
size = 2;
|
|
break;
|
|
case CONSTANT_CLASS:
|
|
case CONSTANT_MODULE:
|
|
case CONSTANT_PACKAGE:
|
|
case CONSTANT_STRING:
|
|
v1 = (Integer) cpool[i];
|
|
valstr = "#" + v1;
|
|
break;
|
|
case CONSTANT_INTERFACEMETHOD:
|
|
case CONSTANT_FIELD:
|
|
case CONSTANT_METHOD:
|
|
case CONSTANT_NAMEANDTYPE:
|
|
case CONSTANT_METHODHANDLE:
|
|
case CONSTANT_METHODTYPE:
|
|
case CONSTANT_DYNAMIC:
|
|
case CONSTANT_INVOKEDYNAMIC:
|
|
valstr = (String) cpool[i];
|
|
break;
|
|
default:
|
|
throw new Error("invalid constant type: " + (int) btag);
|
|
}
|
|
out_print(tagstr + " " + valstr + "; // #" + i);
|
|
if (printDetails) {
|
|
out_println(" at " + toHex(pos));
|
|
} else {
|
|
out.println();
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("} // Constant Pool");
|
|
out.println();
|
|
}
|
|
}
|
|
|
|
private String getStringPos() {
|
|
return " at " + toHex(countedin.getPos());
|
|
}
|
|
|
|
private String getCommentPosCond() {
|
|
if (printDetails) {
|
|
return " // " + getStringPos();
|
|
} else {
|
|
return "";
|
|
}
|
|
}
|
|
|
|
private void decodeCPXAttr(DataInputStream in, int len, String attrname, PrintWriter out) throws IOException {
|
|
decodeCPXAttrM(in, len, attrname, out, 1);
|
|
}
|
|
|
|
private void decodeCPXAttrM(DataInputStream in, int len, String attrname, PrintWriter out, int expectedIndices) throws IOException {
|
|
if (len != expectedIndices * 2) {
|
|
out_println("// invalid length of " + attrname + " attr: " + len + " (should be " + (expectedIndices * 2) + ") > ");
|
|
printBytes(out, in, len);
|
|
} else {
|
|
StringBuilder outputString = new StringBuilder();
|
|
for (int k = 1; k <= expectedIndices; k++) {
|
|
outputString.append("#").append(in.readUnsignedShort()).append("; ");
|
|
if (k % 16 == 0) {
|
|
out_println(outputString.toString().replaceAll("\\s+$",""));
|
|
outputString = new StringBuilder();
|
|
}
|
|
}
|
|
if (outputString.length() > 0) {
|
|
out_println(outputString.toString().replaceAll("\\s+$",""));
|
|
}
|
|
}
|
|
}
|
|
|
|
private void printStackMap(DataInputStream in, int elementsNum) throws IOException {
|
|
int num;
|
|
if (elementsNum > 0) {
|
|
num = elementsNum;
|
|
} else {
|
|
num = in.readUnsignedShort();
|
|
}
|
|
out.print(startArray(num) + (elementsNum > 0 ? "z" : "") + "{");
|
|
try {
|
|
for (int k = 0; k < num; k++) {
|
|
int maptype = in.readUnsignedByte();
|
|
StackMapType mptyp = stackMapType(maptype, out);
|
|
String maptypeImg;
|
|
if (printDetails) {
|
|
maptypeImg = maptype + "b";
|
|
} else {
|
|
try {
|
|
maptypeImg = mptyp.parsekey();
|
|
} catch (ArrayIndexOutOfBoundsException e) {
|
|
maptypeImg = "/* BAD TYPE: */ " + maptype + "b";
|
|
}
|
|
}
|
|
switch (mptyp) {
|
|
case ITEM_Object:
|
|
case ITEM_NewObject:
|
|
maptypeImg = maptypeImg + "," + in.readUnsignedShort();
|
|
break;
|
|
case ITEM_UNKNOWN:
|
|
maptypeImg = maptype + "b";
|
|
break;
|
|
default:
|
|
}
|
|
out.print(maptypeImg);
|
|
if (k < num - 1) {
|
|
out.print("; ");
|
|
}
|
|
}
|
|
} finally {
|
|
out.print("}");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Processes 4.7.20 The RuntimeVisibleTypeAnnotations Attribute, 4.7.21 The RuntimeInvisibleTypeAnnotations Attribute
|
|
* <code>type_annotation</code> structure.
|
|
*/
|
|
private void decodeTargetTypeAndRefInfo(DataInputStream in) throws IOException {
|
|
int tt = in.readUnsignedByte(); // [4.7.20] annotations[], type_annotation { u1 target_type; ...}
|
|
ETargetType targetType = ETargetType.getTargetType(tt);
|
|
if( targetType == null ) {
|
|
throw new Error("Type annotation: invalid target_type(u1) " + tt);
|
|
}
|
|
ETargetInfo targetInfo = targetType.targetInfo();
|
|
out_println(toHex(tt, 1) + "; // target_type: " + targetType.parseKey());
|
|
switch (targetInfo) {
|
|
case TYPEPARAM: //[3.3.1] meth_type_param, class_type_param:
|
|
out_println(toHex(in.readUnsignedByte(), 1) + "; // param_index");
|
|
break;
|
|
case SUPERTYPE: //[3.3.2] class_exts_impls
|
|
out_println(toHex(in.readUnsignedShort(), 2) + "; // type_index");
|
|
break;
|
|
case TYPEPARAM_BOUND: //[3.3.3] class_type_param_bnds, meth_type_param_bnds
|
|
out_println(toHex(in.readUnsignedByte(), 1) + "; // param_index");
|
|
out_println(toHex(in.readUnsignedByte(), 1) + "; // bound_index");
|
|
break;
|
|
case EMPTY: //[3.3.4] meth_receiver, meth_ret_type, field
|
|
// NOTE: reference_info is empty for this annotation's target
|
|
break;
|
|
case METHODPARAM: //[3.3.5] meth_formal_param:
|
|
out_println(toHex(in.readUnsignedByte(), 1) + "; // parameter_index");
|
|
break;
|
|
case EXCEPTION: //[3.3.61] throws_type
|
|
//KTL: Updated index to UShort for JSR308 change
|
|
out_println(in.readUnsignedShort() + "; // type_index");
|
|
break;
|
|
case LOCALVAR: //[3.3.7] local_var, resource_var
|
|
{
|
|
int lv_num = in.readUnsignedShort();
|
|
startArrayCmt(lv_num, "local_variables");
|
|
try {
|
|
for (int i = 0; i < lv_num; i++) {
|
|
out_println(in.readUnsignedShort() + " " + in.readUnsignedShort()
|
|
+ " " + in.readUnsignedShort() + ";" + getCommentPosCond());
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
}
|
|
break;
|
|
case CATCH: //[3.3.8] exception_param
|
|
out_println(in.readUnsignedShort() + "; // exception_table_index");
|
|
break;
|
|
case OFFSET: //[3.3.9] type_test (instanceof), obj_creat (new)
|
|
// constr_ref_receiver, meth_ref_receiver
|
|
out_println(in.readUnsignedShort() + "; // offset");
|
|
break;
|
|
case TYPEARG: //[3.3.10] cast, constr_ref_typearg, meth_invoc_typearg
|
|
// constr_invoc_typearg, meth_ref_typearg
|
|
out_println(in.readUnsignedShort() + "; // offset");
|
|
out_println(toHex(in.readUnsignedByte(), 1) + "; // type_index");
|
|
break;
|
|
default: // should never happen
|
|
out_println(toHex(tt, 1) + "; // invalid target_info: " + tt);
|
|
throw new ClassFormatError();
|
|
}
|
|
// [4.7.20.2]
|
|
int path_length = in.readUnsignedByte(); // type_path { u1 path_length; ...}
|
|
startArrayCmtB(path_length, "type_paths");
|
|
try {
|
|
for (int i = 0; i < path_length; i++) {
|
|
// print the type_path elements
|
|
out_println("{ " + toHex(in.readUnsignedByte(), 1) // { u1 type_path_kind;
|
|
+ "; " + toHex(in.readUnsignedByte(), 1) // u1 type_argument_index; }
|
|
+ "; } // type_path[" + i + "]"); // path[i]
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
}
|
|
|
|
private void decodeElementValue(DataInputStream in, PrintWriter out) throws IOException {
|
|
out_begin("{ // element_value");
|
|
try {
|
|
char tg = (char) in.readByte();
|
|
AnnotElemType tag = annotElemType(tg);
|
|
if (tag != AE_UNKNOWN) {
|
|
out_println("'" + tg + "';");
|
|
}
|
|
switch (tag) {
|
|
case AE_BYTE:
|
|
case AE_CHAR:
|
|
case AE_DOUBLE:
|
|
case AE_FLOAT:
|
|
case AE_INT:
|
|
case AE_LONG:
|
|
case AE_SHORT:
|
|
case AE_BOOLEAN:
|
|
case AE_STRING:
|
|
decodeCPXAttr(in, 2, "const_value_index", out);
|
|
break;
|
|
case AE_ENUM:
|
|
out_begin("{ // enum_const_value");
|
|
decodeCPXAttr(in, 2, "type_name_index", out);
|
|
decodeCPXAttr(in, 2, "const_name_index", out);
|
|
out_end("} // enum_const_value");
|
|
break;
|
|
case AE_CLASS:
|
|
decodeCPXAttr(in, 2, "class_info_index", out);
|
|
break;
|
|
case AE_ANNOTATION:
|
|
decodeAnnotation(in, out);
|
|
break;
|
|
case AE_ARRAY:
|
|
int ev_num = in.readUnsignedShort();
|
|
startArrayCmt(ev_num, "array_value");
|
|
try {
|
|
for (int i = 0; i < ev_num; i++) {
|
|
decodeElementValue(in, out);
|
|
if (i < ev_num - 1) {
|
|
out_println(";");
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("} // array_value");
|
|
}
|
|
break;
|
|
case AE_UNKNOWN:
|
|
default:
|
|
String msg = "invalid element_value" + (isPrintableChar(tg) ? " tag type : " + tg : "");
|
|
out_println(toHex(tg, 1) + "; // " + msg);
|
|
throw new ClassFormatError(msg);
|
|
}
|
|
} finally {
|
|
out_end("} // element_value");
|
|
}
|
|
}
|
|
|
|
public boolean isPrintableChar(char c) {
|
|
Character.UnicodeBlock block = Character.UnicodeBlock.of(c);
|
|
return (!Character.isISOControl(c)) &&
|
|
c != KeyEvent.CHAR_UNDEFINED &&
|
|
block != null &&
|
|
block != Character.UnicodeBlock.SPECIALS;
|
|
}
|
|
|
|
private void decodeAnnotation(DataInputStream in, PrintWriter out) throws IOException {
|
|
out_begin("{ // annotation");
|
|
try {
|
|
decodeCPXAttr(in, 2, "field descriptor", out);
|
|
int evp_num = in.readUnsignedShort();
|
|
decodeElementValuePairs(evp_num, in, out);
|
|
} finally {
|
|
out_end("} // annotation");
|
|
}
|
|
}
|
|
|
|
private void decodeElementValuePairs(int count, DataInputStream in, PrintWriter out) throws IOException {
|
|
startArrayCmt(count, "element_value_pairs");
|
|
try {
|
|
for (int i = 0; i < count; i++) {
|
|
out_begin("{ // element value pair");
|
|
try {
|
|
decodeCPXAttr(in, 2, "name of the annotation type element", out);
|
|
decodeElementValue(in, out);
|
|
} finally {
|
|
out_end("} // element value pair");
|
|
if (i < count - 1) {
|
|
out_println(";");
|
|
}
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("} // element_value_pairs");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* component_info { JEP 359 Record(Preview): class file 58.65535
|
|
* u2 name_index;
|
|
* u2 descriptor_index;
|
|
* u2 attributes_count;
|
|
* attribute_info attributes[attributes_count];
|
|
* }
|
|
*
|
|
* or
|
|
* field_info {
|
|
* u2 access_flags;
|
|
* u2 name_index;
|
|
* u2 descriptor_index;
|
|
* u2 attributes_count;
|
|
* attribute_info attributes[attributes_count];
|
|
* }
|
|
* or
|
|
* method_info {
|
|
* u2 access_flags;
|
|
* u2 name_index;
|
|
* u2 descriptor_index;
|
|
* u2 attributes_count;
|
|
* attribute_info attributes[attributes_count];
|
|
* }
|
|
*
|
|
*/
|
|
private void decodeInfo(DataInputStream in, PrintWriter out, String elementName, boolean hasAccessFlag) throws IOException {
|
|
out_begin("{ // " + elementName + (printDetails ? getStringPos() : ""));
|
|
try {
|
|
if(hasAccessFlag) {
|
|
// u2 access_flags;
|
|
out_println(toHex(in.readShort(), 2) + "; // access");
|
|
}
|
|
// u2 name_index
|
|
printUtf8InfoIndex(in.readUnsignedShort(), "name_index");
|
|
// u2 descriptor_index
|
|
printUtf8InfoIndex(in.readUnsignedShort(), "descriptor_index");
|
|
// u2 attributes_count;
|
|
// attribute_info attributes[attributes_count]
|
|
decodeAttrs(in, out);
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
}
|
|
|
|
private void decodeTypeAnnotation(DataInputStream in, PrintWriter out) throws IOException {
|
|
out_begin("{ // type_annotation");
|
|
try {
|
|
decodeTargetTypeAndRefInfo(in);
|
|
decodeCPXAttr(in, 2, "field descriptor", out);
|
|
int evp_num = in.readUnsignedShort();
|
|
decodeElementValuePairs(evp_num, in, out);
|
|
} finally {
|
|
out_end("} // type_annotation");
|
|
}
|
|
}
|
|
|
|
private void decodeBootstrapMethod(DataInputStream in) throws IOException {
|
|
out_begin("{ // bootstrap_method");
|
|
try {
|
|
out_println("#" + in.readUnsignedShort() + "; // bootstrap_method_ref");
|
|
int bm_args_cnt = in.readUnsignedShort();
|
|
startArrayCmt(bm_args_cnt, "bootstrap_arguments");
|
|
try {
|
|
for (int i = 0; i < bm_args_cnt; i++) {
|
|
out_println("#" + in.readUnsignedShort() + ";" + getCommentPosCond());
|
|
}
|
|
} finally {
|
|
out_end("} // bootstrap_arguments");
|
|
}
|
|
} finally {
|
|
out_end("} // bootstrap_method");
|
|
}
|
|
}
|
|
|
|
private void decodeAttr(DataInputStream in, PrintWriter out) throws IOException {
|
|
// Read one attribute
|
|
String posComment = getStringPos();
|
|
int name_cpx = in.readUnsignedShort(), btag, len;
|
|
|
|
String AttrName = "";
|
|
try {
|
|
btag = types[name_cpx];
|
|
ConstType tag = tag(btag);
|
|
|
|
if (tag == ConstType.CONSTANT_UTF8) {
|
|
AttrName = (String) cpool[name_cpx];
|
|
}
|
|
} catch (ArrayIndexOutOfBoundsException ignored) {
|
|
}
|
|
AttrTag tg = attrtag(AttrName);
|
|
String endingComment = AttrName;
|
|
len = in.readInt();
|
|
countedin.enter(len);
|
|
try {
|
|
if (printDetails) {
|
|
out_begin("Attr(#" + name_cpx + ", " + len + ") { // " + AttrName + posComment);
|
|
} else {
|
|
out_begin("Attr(#" + name_cpx + ") { // " + AttrName);
|
|
}
|
|
|
|
switch (tg) {
|
|
case ATT_Code:
|
|
out_println(in.readUnsignedShort() + "; // max_stack");
|
|
out_println(in.readUnsignedShort() + "; // max_locals");
|
|
int code_len = in.readInt();
|
|
out_begin("Bytes" + startArray(code_len) + "{");
|
|
try {
|
|
printBytes(out, in, code_len);
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
int trap_num = in.readUnsignedShort();
|
|
startArrayCmt(trap_num, "Traps");
|
|
try {
|
|
for (int i = 0; i < trap_num; i++) {
|
|
out_println(in.readUnsignedShort() + " " +
|
|
in.readUnsignedShort() + " " +
|
|
in.readUnsignedShort() + " " +
|
|
in.readUnsignedShort() + ";" +
|
|
getCommentPosCond());
|
|
}
|
|
} finally {
|
|
out_end("} // end Traps");
|
|
}
|
|
// Read the attributes
|
|
decodeAttrs(in, out);
|
|
break;
|
|
|
|
case ATT_Exceptions:
|
|
int count = in.readUnsignedShort();
|
|
startArrayCmt(count, AttrName);
|
|
try {
|
|
for (int i = 0; i < count; i++) {
|
|
out_println("#" + in.readUnsignedShort() + ";" +
|
|
getCommentPosCond());
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
case ATT_LineNumberTable:
|
|
int ll_num = in.readUnsignedShort();
|
|
startArrayCmt(ll_num, "line_number_table");
|
|
try {
|
|
for (int i = 0; i < ll_num; i++) {
|
|
out_println(in.readUnsignedShort() + " " +
|
|
in.readUnsignedShort() + ";" +
|
|
getCommentPosCond());
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
case ATT_LocalVariableTable:
|
|
case ATT_LocalVariableTypeTable:
|
|
int lvt_num = in.readUnsignedShort();
|
|
startArrayCmt(lvt_num, AttrName);
|
|
try {
|
|
for (int i = 0; i < lvt_num; i++) {
|
|
out_println(in.readUnsignedShort() + " " +
|
|
in.readUnsignedShort() + " " +
|
|
in.readUnsignedShort() + " " +
|
|
in.readUnsignedShort() + " " +
|
|
in.readUnsignedShort() + ";" +
|
|
getCommentPosCond());
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
case ATT_InnerClasses:
|
|
int ic_num = in.readUnsignedShort();
|
|
startArrayCmt(ic_num, "classes");
|
|
try {
|
|
for (int i = 0; i < ic_num; i++) {
|
|
out_println("#" + in.readUnsignedShort() + " #" +
|
|
in.readUnsignedShort() + " #" +
|
|
in.readUnsignedShort() + " " +
|
|
in.readUnsignedShort() + ";" + getCommentPosCond());
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
case ATT_StackMap:
|
|
int e_num = in.readUnsignedShort();
|
|
startArrayCmt(e_num, "");
|
|
try {
|
|
for (int k = 0; k < e_num; k++) {
|
|
int start_pc = in.readUnsignedShort();
|
|
out_print("" + start_pc + ", ");
|
|
printStackMap(in, 0);
|
|
out.print(", ");
|
|
printStackMap(in, 0);
|
|
out.println(";");
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
case ATT_StackMapTable:
|
|
int et_num = in.readUnsignedShort();
|
|
startArrayCmt(et_num, "");
|
|
try {
|
|
for (int k = 0; k < et_num; k++) {
|
|
int frame_type = in.readUnsignedByte();
|
|
StackMapFrameType ftype = stackMapFrameType(frame_type);
|
|
switch (ftype) {
|
|
case SAME_FRAME:
|
|
// type is same_frame;
|
|
out_print("" + frame_type + "b");
|
|
out.println("; // same_frame");
|
|
break;
|
|
case SAME_LOCALS_1_STACK_ITEM_FRAME:
|
|
// type is same_locals_1_stack_item_frame
|
|
out_print("" + frame_type + "b, ");
|
|
// read additional single stack element
|
|
printStackMap(in, 1);
|
|
out.println("; // same_locals_1_stack_item_frame");
|
|
break;
|
|
case SAME_LOCALS_1_STACK_ITEM_EXTENDED_FRAME:
|
|
// type is same_locals_1_stack_item_frame_extended
|
|
int noffset = in.readUnsignedShort();
|
|
out_print("" + frame_type + "b, " + noffset + ", ");
|
|
// read additional single stack element
|
|
printStackMap(in, 1);
|
|
out.println("; // same_locals_1_stack_item_frame_extended");
|
|
break;
|
|
case CHOP_1_FRAME:
|
|
case CHOP_2_FRAME:
|
|
case CHOP_3_FRAME:
|
|
// type is chop_frame
|
|
int coffset = in.readUnsignedShort();
|
|
out_print("" + frame_type + "b, " + coffset);
|
|
out.println("; // chop_frame " + (251 - frame_type));
|
|
break;
|
|
case SAME_FRAME_EX:
|
|
// type is same_frame_extended;
|
|
int xoffset = in.readUnsignedShort();
|
|
out_print("" + frame_type + "b, " + xoffset);
|
|
out.println("; // same_frame_extended");
|
|
break;
|
|
case APPEND_FRAME:
|
|
// type is append_frame
|
|
int aoffset = in.readUnsignedShort();
|
|
out_print("" + frame_type + "b, " + aoffset + ", ");
|
|
// read additional locals
|
|
printStackMap(in, frame_type - 251);
|
|
out.println("; // append_frame " + (frame_type - 251));
|
|
break;
|
|
case FULL_FRAME:
|
|
// type is full_frame
|
|
int foffset = in.readUnsignedShort();
|
|
out_print("" + frame_type + "b, " + foffset + ", ");
|
|
printStackMap(in, 0);
|
|
out.print(", ");
|
|
printStackMap(in, 0);
|
|
out.println("; // full_frame");
|
|
break;
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
case ATT_EnclosingMethod:
|
|
decodeCPXAttrM(in, len, AttrName, out, 2);
|
|
break;
|
|
case ATT_AnnotationDefault:
|
|
decodeElementValue(in, out);
|
|
break;
|
|
case ATT_RuntimeInvisibleAnnotations:
|
|
case ATT_RuntimeVisibleAnnotations:
|
|
int an_num = in.readUnsignedShort();
|
|
startArrayCmt(an_num, "annotations");
|
|
try {
|
|
for (int i = 0; i < an_num; i++) {
|
|
decodeAnnotation(in, out);
|
|
if (i < an_num - 1) {
|
|
out_println(";");
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
// 4.7.20 The RuntimeVisibleTypeAnnotations Attribute
|
|
// 4.7.21 The RuntimeInvisibleTypeAnnotations Attribute
|
|
case ATT_RuntimeInvisibleTypeAnnotations:
|
|
case ATT_RuntimeVisibleTypeAnnotations:
|
|
int ant_num = in.readUnsignedShort();
|
|
startArrayCmt(ant_num, "annotations");
|
|
try {
|
|
for (int i = 0; i < ant_num; i++) {
|
|
decodeTypeAnnotation(in, out);
|
|
if (i < ant_num - 1) {
|
|
out_println(";");
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
case ATT_RuntimeInvisibleParameterAnnotations:
|
|
case ATT_RuntimeVisibleParameterAnnotations:
|
|
int pm_num = in.readUnsignedByte();
|
|
startArrayCmtB(pm_num, "parameters");
|
|
try {
|
|
for (int k = 0; k < pm_num; k++) {
|
|
int anp_num = in.readUnsignedShort();
|
|
startArrayCmt(anp_num, "annotations");
|
|
try {
|
|
for (int i = 0; i < anp_num; i++) {
|
|
decodeAnnotation(in, out);
|
|
if (k < anp_num - 1) {
|
|
out_println(";");
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
if (k < pm_num - 1) {
|
|
out_println(";");
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
case ATT_BootstrapMethods:
|
|
int bm_num = in.readUnsignedShort();
|
|
startArrayCmt(bm_num, "bootstrap_methods");
|
|
try {
|
|
for (int i = 0; i < bm_num; i++) {
|
|
decodeBootstrapMethod(in);
|
|
if (i < bm_num - 1) {
|
|
out_println(";");
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
case ATT_Module:
|
|
decodeModule(in);
|
|
break;
|
|
case ATT_TargetPlatform:
|
|
decodeCPXAttrM(in, len, AttrName, out, 3);
|
|
break;
|
|
case ATT_ModulePackages:
|
|
int p_num = in.readUnsignedShort();
|
|
startArrayCmt(p_num, null);
|
|
try {
|
|
decodeCPXAttrM(in, len - 2, AttrName, out, p_num);
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
// MethodParameters_attribute {
|
|
// u2 attribute_name_index;
|
|
// u4 attribute_length;
|
|
// u1 parameters_count;
|
|
// { u2 name_index;
|
|
// u2 access_flags;
|
|
// } parameters[parameters_count];
|
|
// }
|
|
case ATT_MethodParameters:
|
|
int pcount = in.readUnsignedByte();
|
|
startArrayCmtB(pcount, AttrName);
|
|
try {
|
|
for (int i = 0; i < pcount; i++) {
|
|
out_println("#" + in.readUnsignedShort() + " " +
|
|
toHex(in.readUnsignedShort(), 2) + ";" +
|
|
getCommentPosCond());
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
// JEP 359 Record(Preview): class file 58.65535
|
|
// Record_attribute {
|
|
// u2 attribute_name_index;
|
|
// u4 attribute_length;
|
|
// u2 components_count;
|
|
// component_info components[components_count];
|
|
// }
|
|
case ATT_Record:
|
|
int ncomps = in.readUnsignedShort();
|
|
startArrayCmt(ncomps, "components");
|
|
try {
|
|
for (int i = 0; i < ncomps; i++) {
|
|
decodeInfo(in,out,"component",false);
|
|
if (i < ncomps - 1) {
|
|
out_println(";");
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
case ATT_ConstantValue:
|
|
case ATT_Signature:
|
|
case ATT_SourceFile:
|
|
decodeCPXAttr(in, len, AttrName, out);
|
|
break;
|
|
// JEP 181 (Nest-based Access Control): class file 55.0
|
|
// NestHost_attribute {
|
|
// u2 attribute_name_index;
|
|
// u4 attribute_length;
|
|
// u2 host_class_index;
|
|
// }
|
|
case ATT_NestHost:
|
|
decodeTypes(in, out, 1);
|
|
break;
|
|
// JEP 181 (Nest-based Access Control): class file 55.0
|
|
// NestMembers_attribute {
|
|
// u2 attribute_name_index;
|
|
// u4 attribute_length;
|
|
// u2 number_of_classes;
|
|
// u2 classes[number_of_classes];
|
|
// }
|
|
case ATT_NestMembers:
|
|
// JEP 360 (Sealed types): class file 59.65535
|
|
// PermittedSubtypes_attribute {
|
|
// u2 attribute_name_index;
|
|
// u4 attribute_length;
|
|
// u2 permitted_subtypes_count;
|
|
// u2 classes[permitted_subtypes_count];
|
|
// }
|
|
case ATT_PermittedSubtypes:
|
|
int nsubtypes = in.readUnsignedShort();
|
|
startArrayCmt(nsubtypes, "classes");
|
|
try {
|
|
decodeTypes(in, out, nsubtypes);
|
|
} finally {
|
|
out_end("}");
|
|
}
|
|
break;
|
|
default:
|
|
printBytes(out, in, len);
|
|
if (AttrName == null) {
|
|
endingComment = "Attr(#" + name_cpx + ")";
|
|
}
|
|
}
|
|
|
|
} catch (EOFException e) {
|
|
out.println("// ======== unexpected end of attribute array");
|
|
} finally {
|
|
int rest = countedin.available();
|
|
if (rest > 0) {
|
|
out.println("// ======== attribute array started " + posComment + " has " + rest + " bytes more:");
|
|
printBytes(out, in, rest);
|
|
}
|
|
out_end("} // end " + endingComment);
|
|
countedin.leave();
|
|
}
|
|
}
|
|
|
|
private void decodeModuleStatement(String statementName, DataInputStream in) throws IOException {
|
|
// u2 {exports|opens}_count
|
|
int count = in.readUnsignedShort();
|
|
startArrayCmt(count, statementName);
|
|
try {
|
|
for (int i = 0; i < count; i++) {
|
|
// u2 {exports|opens}_index; u2 {exports|opens}_flags
|
|
int index = in.readUnsignedShort();
|
|
int nFlags = in.readUnsignedShort();
|
|
String sFlags = printDetails ? Module.Modifier.getStatementFlags(nFlags) : "";
|
|
out_println("#" + index + " " + toHex(nFlags, 2) + (sFlags.isEmpty() ? "" : " // [ " + sFlags + " ]"));
|
|
int exports_to_count = in.readUnsignedShort();
|
|
startArrayCmt(exports_to_count, null);
|
|
try {
|
|
for (int j = 0; j < exports_to_count; j++) {
|
|
out_println("#" + in.readUnsignedShort() + ";");
|
|
}
|
|
} finally {
|
|
out_end("};");
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("} // " + statementName + "\n");
|
|
}
|
|
}
|
|
|
|
private void decodeModule(DataInputStream in) throws IOException {
|
|
//u2 module_name_index
|
|
int index = in.readUnsignedShort();
|
|
entityName = (String) cpool[(Integer) cpool[index]];
|
|
out_print("#" + index + "; // ");
|
|
if (printDetails) {
|
|
out.println(String.format("%-16s","name_index") + " : " + entityName);
|
|
} else {
|
|
out.println("name_index");
|
|
}
|
|
|
|
// u2 module_flags
|
|
int moduleFlags = in.readUnsignedShort();
|
|
out_print(toHex(moduleFlags, 2) + "; // flags");
|
|
if (printDetails) {
|
|
out_print(" " + Module.Modifier.getModuleFlags(moduleFlags));
|
|
}
|
|
out.println();
|
|
|
|
//u2 module_version
|
|
int versionIndex = in.readUnsignedShort();
|
|
out_println("#" + versionIndex + "; // version");
|
|
|
|
// u2 requires_count
|
|
int count = in.readUnsignedShort();
|
|
startArrayCmt(count, "requires");
|
|
try {
|
|
for (int i = 0; i < count; i++) {
|
|
// u2 requires_index; u2 requires_flags; u2 requires_version_index
|
|
index = in.readUnsignedShort();
|
|
int nFlags = in.readUnsignedShort();
|
|
versionIndex = in.readUnsignedShort();
|
|
String sFlags = printDetails ? Module.Modifier.getStatementFlags(nFlags) : "";
|
|
out_println("#" + index + " " + toHex(nFlags, 2) + " #" + versionIndex + ";" + (sFlags.isEmpty() ? "" : " // " + sFlags));
|
|
}
|
|
} finally {
|
|
out_end("} // requires\n");
|
|
}
|
|
|
|
decodeModuleStatement("exports", in);
|
|
|
|
decodeModuleStatement("opens", in);
|
|
// u2 uses_count
|
|
count = in.readUnsignedShort();
|
|
startArrayCmt(count, "uses");
|
|
try {
|
|
for (int i = 0; i < count; i++) {
|
|
// u2 uses_index
|
|
out_println("#" + in.readUnsignedShort() + ";");
|
|
}
|
|
} finally {
|
|
out_end("} // uses\n");
|
|
}
|
|
count = in.readUnsignedShort(); // u2 provides_count
|
|
startArrayCmt(count, "provides");
|
|
try {
|
|
for (int i = 0; i < count; i++) {
|
|
// u2 provides_index
|
|
out_println("#" + in.readUnsignedShort());
|
|
int provides_with_count = in.readUnsignedShort();
|
|
// u2 provides_with_count
|
|
startArrayCmt(provides_with_count, null);
|
|
try {
|
|
for (int j = 0; j < provides_with_count; j++) {
|
|
// u2 provides_with_index;
|
|
out_println("#" + in.readUnsignedShort() + ";");
|
|
}
|
|
} finally {
|
|
out_end("};");
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("} // provides\n");
|
|
}
|
|
}
|
|
|
|
private void decodeAttrs(DataInputStream in, PrintWriter out) throws IOException {
|
|
// Read the attributes
|
|
int attr_num = in.readUnsignedShort();
|
|
startArrayCmt(attr_num, "Attributes");
|
|
try {
|
|
for (int i = 0; i < attr_num; i++) {
|
|
decodeAttr(in, out);
|
|
if (i + 1 < attr_num) {
|
|
out_println(";");
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("} // Attributes");
|
|
}
|
|
}
|
|
|
|
private void decodeMembers(DataInputStream in, PrintWriter out, String groupName, String elementName) throws IOException {
|
|
int count = in.readUnsignedShort();
|
|
traceln(groupName + "=" + count);
|
|
startArrayCmt(count, groupName);
|
|
try {
|
|
for (int i = 0; i < count; i++) {
|
|
decodeInfo(in,out,elementName,true);
|
|
if (i + 1 < count) {
|
|
out_println(";");
|
|
}
|
|
}
|
|
} finally {
|
|
out_end("} // " + groupName);
|
|
out.println();
|
|
}
|
|
}
|
|
|
|
void decodeClass(String fileName) throws IOException {
|
|
// Read the header
|
|
try {
|
|
int magic = in.readInt();
|
|
int min_version = in.readUnsignedShort();
|
|
int version = in.readUnsignedShort();
|
|
|
|
// Read the constant pool
|
|
readCP(in);
|
|
short access = in.readShort(); // don't care about sign
|
|
int this_cpx = in.readUnsignedShort();
|
|
|
|
try {
|
|
entityName = (String) cpool[(Integer) cpool[this_cpx]];
|
|
if (entityName.equals("module-info")) {
|
|
entityType = "module";
|
|
entityName = "";
|
|
} else {
|
|
entityType = "class";
|
|
}
|
|
if (!entityName.isEmpty() && (JcodTokens.keyword_token_ident(entityName) != JcodTokens.Token.IDENT || JcodTokens.constValue(entityName) != -1)) {
|
|
// JCod can't parse a entityName matching a keyword or a constant value,
|
|
// then use the filename instead:
|
|
out_begin(String.format("file \"%s.class\" {", entityName));
|
|
} else {
|
|
out_begin(format("%s %s {", entityType, entityName));
|
|
}
|
|
} catch (Exception e) {
|
|
entityName = fileName;
|
|
out.println("// " + e.getMessage() + " while accessing entityName");
|
|
out_begin(format("%s %s { // source file name", entityType, entityName));
|
|
}
|
|
|
|
out_print(toHex(magic, 4) + ";");
|
|
if (magic != JAVA_MAGIC) {
|
|
out.print(" // wrong magic: 0x" + Integer.toString(JAVA_MAGIC, 16) + " expected");
|
|
}
|
|
out.println();
|
|
out_println(min_version + "; // minor version");
|
|
out_println(version + "; // version");
|
|
|
|
// Print the constant pool
|
|
printCP(out);
|
|
out_println(toHex(access, 2) + "; // access" +
|
|
(printDetails ? " [" + (" " + Modifiers.accessString(access, CF_Context.CTX_CLASS).toUpperCase()).replaceAll(" (\\S)", " ACC_$1") + "]" : ""));
|
|
out_println("#" + this_cpx + ";// this_cpx");
|
|
int super_cpx = in.readUnsignedShort();
|
|
out_println("#" + super_cpx + ";// super_cpx");
|
|
traceln(i18n.getString("jdec.trace.access_thisCpx_superCpx", access, this_cpx, super_cpx));
|
|
out.println();
|
|
|
|
// Read the interfaces
|
|
int numinterfaces = in.readUnsignedShort();
|
|
traceln(i18n.getString("jdec.trace.numinterfaces", numinterfaces));
|
|
startArrayCmt(numinterfaces, "Interfaces");
|
|
try {
|
|
decodeTypes(in, out, numinterfaces);
|
|
} finally {
|
|
out_end("} // Interfaces\n");
|
|
}
|
|
// Read the fields
|
|
decodeMembers(in, out, "Fields", "field");
|
|
|
|
// Read the methods
|
|
decodeMembers(in, out, "Methods", "method");
|
|
|
|
// Read the attributes
|
|
decodeAttrs(in, out);
|
|
} catch (EOFException ignored) {
|
|
} catch (ClassFormatError err) {
|
|
String msg = err.getMessage();
|
|
out.println("//------- ClassFormatError" +
|
|
(msg == null || msg.isEmpty() ? "" : ": " + msg));
|
|
printRestOfBytes();
|
|
} finally {
|
|
out_end(format("} // end %s %s", entityType, entityName));
|
|
}
|
|
} // end decodeClass()
|
|
|
|
private void decodeTypes(DataInputStream in, PrintWriter out, int count) throws IOException {
|
|
for (int i = 0; i < count; i++) {
|
|
int type_cpx = in.readUnsignedShort();
|
|
traceln(i18n.getString("jdec.trace.type", i, type_cpx));
|
|
out_print("#" + type_cpx + ";");
|
|
if (printDetails) {
|
|
String name = (String) cpool[(int)cpool[type_cpx]];
|
|
out.println(" // " + name + getStringPos());
|
|
} else {
|
|
out.println();
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ====================================================== */
|
|
boolean DebugFlag = false;
|
|
|
|
public void trace(String s) {
|
|
if (!DebugFlag) {
|
|
return;
|
|
}
|
|
System.out.print(s);
|
|
}
|
|
|
|
public void traceln(String s) {
|
|
if (!DebugFlag) {
|
|
return;
|
|
}
|
|
System.out.println(s);
|
|
}
|
|
}// end class ClassData
|
|
|