00001 package de.fub.bytecode.classfile;
00002
00003 import de.fub.bytecode.Constants;
00004 import de.fub.bytecode.util.ByteSequence;
00005 import java.io.*;
00006 import java.util.Vector;
00007
00008
00009
00010
00011
00012
00013
00014 public abstract class Utility implements Constants {
00015 private static int consumed_chars;
00016
00017
00018
00019
00020 private static boolean wide=false;
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 public static final String accessToString(int access_flags)
00036 {
00037 return accessToString(access_flags, false);
00038 }
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 public static final String accessToString(int access_flags,
00052 boolean for_class)
00053 {
00054 StringBuffer buf = new StringBuffer();
00055
00056 int p = 0;
00057 for(int i=0; p < MAX_ACC_FLAG; i++) {
00058 p = pow2(i);
00059
00060 if((access_flags & p) != 0) {
00061
00062
00063
00064
00065
00066 if(for_class && ((p == ACC_SUPER) || (p == ACC_INTERFACE)))
00067 continue;
00068
00069 buf.append(ACCESS_NAMES[i] + " ");
00070 }
00071 }
00072
00073 return buf.toString().trim();
00074 }
00075
00076
00077
00078
00079 private static final short byteToShort(byte b) {
00080 return (b < 0)? (short)(256 + b) : (short)b;
00081 }
00082
00083
00084
00085 public static final String classOrInterface(int access_flags) {
00086 return ((access_flags & ACC_INTERFACE) != 0)? "interface" : "class";
00087 }
00088
00089
00090
00091 public static final int clearBit(int flag, int i) {
00092 int bit = pow2(i);
00093 return (flag & bit) == 0? flag : flag ^ bit;
00094 }
00095 public static final String codeToString(byte[] code,
00096 ConstantPool constant_pool,
00097 int index, int length) {
00098 return codeToString(code, constant_pool, index, length, true);
00099 }
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114 public static final String codeToString(byte[] code,
00115 ConstantPool constant_pool,
00116 int index, int length, boolean verbose)
00117 {
00118 StringBuffer buf = new StringBuffer(code.length * 20);
00119 ByteSequence stream = new ByteSequence(code);
00120
00121 try {
00122 for(int i=0; i < index; i++)
00123 codeToString(stream, constant_pool, verbose);
00124
00125 for(int i=0; stream.available() > 0; i++) {
00126 if((length < 0) || (i < length)) {
00127 String indices = fillup(stream.getIndex() + ":", 6, true, ' ');
00128 buf.append(indices + codeToString(stream, constant_pool, verbose) + '\n');
00129 }
00130 }
00131 } catch(IOException e) {
00132 System.out.println(buf.toString());
00133 e.printStackTrace();
00134 throw new ClassFormatError("Byte code error: " + e);
00135 }
00136
00137 return buf.toString();
00138 }
00139 public static final String codeToString(ByteSequence bytes, ConstantPool constant_pool)
00140 throws IOException
00141 {
00142 return codeToString(bytes, constant_pool, true);
00143 }
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153 public static final String codeToString(ByteSequence bytes,
00154 ConstantPool constant_pool, boolean verbose)
00155 throws IOException
00156 {
00157 short opcode = (short)bytes.readUnsignedByte();
00158 int default_offset=0, low, high, npairs;
00159 int index, vindex, constant;
00160 int[] match, jump_table;
00161 int no_pad_bytes=0, offset;
00162 StringBuffer buf = new StringBuffer(OPCODE_NAMES[opcode]);
00163
00164
00165
00166
00167 if((opcode == TABLESWITCH) || (opcode == LOOKUPSWITCH)) {
00168 int remainder = bytes.getIndex() % 4;
00169 no_pad_bytes = (remainder == 0)? 0 : 4 - remainder;
00170
00171 for(int i=0; i < no_pad_bytes; i++) {
00172 byte b;
00173
00174 if((b=bytes.readByte()) != 0)
00175 System.err.println("Ooops. Padding byte != 0 " + b);
00176 }
00177
00178
00179 default_offset = bytes.readInt();
00180 }
00181
00182 switch(opcode) {
00183
00184
00185 case TABLESWITCH:
00186 low = bytes.readInt();
00187 high = bytes.readInt();
00188
00189 offset = bytes.getIndex() - 12 - no_pad_bytes - 1;
00190 default_offset += offset;
00191
00192 buf.append("\tdefault = " + default_offset + ", low = " + low +
00193 ", high = " + high + "(");
00194
00195 jump_table = new int[high - low + 1];
00196 for(int i=0; i < jump_table.length; i++) {
00197 jump_table[i] = offset + bytes.readInt();
00198 buf.append(jump_table[i]);
00199
00200 if(i < jump_table.length - 1)
00201 buf.append(", ");
00202 }
00203 buf.append(")");
00204
00205 break;
00206
00207
00208
00209 case LOOKUPSWITCH: {
00210
00211 npairs = bytes.readInt();
00212 offset = bytes.getIndex() - 8 - no_pad_bytes - 1;
00213
00214 match = new int[npairs];
00215 jump_table = new int[npairs];
00216 default_offset += offset;
00217
00218 buf.append("\tdefault = " + default_offset + ", npairs = " + npairs +
00219 " (");
00220
00221 for(int i=0; i < npairs; i++) {
00222 match[i] = bytes.readInt();
00223
00224 jump_table[i] = offset + bytes.readInt();
00225
00226 buf.append("(" + match[i] + ", " + jump_table[i] + ")");
00227
00228 if(i < npairs - 1)
00229 buf.append(", ");
00230 }
00231 buf.append(")");
00232 }
00233 break;
00234
00235
00236
00237
00238 case GOTO: case IFEQ: case IFGE: case IFGT:
00239 case IFLE: case IFLT: case JSR: case IFNE:
00240 case IFNONNULL: case IFNULL: case IF_ACMPEQ:
00241 case IF_ACMPNE: case IF_ICMPEQ: case IF_ICMPGE: case IF_ICMPGT:
00242 case IF_ICMPLE: case IF_ICMPLT: case IF_ICMPNE:
00243 buf.append("\t\t#" + ((bytes.getIndex() - 1) + bytes.readShort()));
00244 break;
00245
00246
00247
00248 case GOTO_W: case JSR_W:
00249 buf.append("\t\t#" + ((bytes.getIndex() - 1) + bytes.readInt()));
00250 break;
00251
00252
00253
00254 case ALOAD: case ASTORE: case DLOAD: case DSTORE: case FLOAD:
00255 case FSTORE: case ILOAD: case ISTORE: case LLOAD: case LSTORE:
00256 case RET:
00257 if(wide) {
00258 vindex = bytes.readUnsignedShort();
00259 wide=false;
00260 }
00261 else
00262 vindex = bytes.readUnsignedByte();
00263
00264 buf.append("\t\t%" + vindex);
00265 break;
00266
00267
00268
00269
00270
00271
00272 case WIDE:
00273 wide = true;
00274 buf.append("\t(wide)");
00275 break;
00276
00277
00278
00279 case NEWARRAY:
00280 buf.append("\t\t<" + TYPE_NAMES[bytes.readByte()] + ">");
00281 break;
00282
00283
00284
00285 case GETFIELD: case GETSTATIC: case PUTFIELD: case PUTSTATIC:
00286 index = bytes.readUnsignedShort();
00287 buf.append("\t\t" +
00288 constant_pool.constantToString(index, CONSTANT_Fieldref) +
00289 (verbose? " (" + index + ")" : ""));
00290 break;
00291
00292
00293
00294 case NEW:
00295 case CHECKCAST: case INSTANCEOF:
00296 index = bytes.readUnsignedShort();
00297 buf.append("\t\t<" + constant_pool.constantToString(index,
00298 CONSTANT_Class) +
00299 ">" + (verbose? " (" + index + ")" : ""));
00300 break;
00301
00302
00303
00304 case INVOKESPECIAL: case INVOKESTATIC: case INVOKEVIRTUAL:
00305 index = bytes.readUnsignedShort();
00306 buf.append("\t" + constant_pool.constantToString(index,
00307 CONSTANT_Methodref) +
00308 (verbose? " (" + index + ")" : ""));
00309 break;
00310
00311 case INVOKEINTERFACE:
00312 index = bytes.readUnsignedShort();
00313 int nargs = bytes.readUnsignedByte();
00314 buf.append("\t" +
00315 constant_pool.constantToString(index,
00316 CONSTANT_InterfaceMethodref) +
00317 (verbose? " (" + index + ")\t" : "") + nargs + "\t" +
00318 bytes.readUnsignedByte());
00319 break;
00320
00321
00322
00323 case LDC_W: case LDC2_W:
00324 index = bytes.readUnsignedShort();
00325
00326 buf.append("\t\t" + constant_pool.constantToString
00327 (index, constant_pool.getConstant(index).getTag()) +
00328 (verbose? " (" + index + ")" : ""));
00329 break;
00330
00331 case LDC:
00332 index = bytes.readUnsignedByte();
00333
00334 buf.append("\t\t" +
00335 constant_pool.constantToString
00336 (index, constant_pool.getConstant(index).getTag()) +
00337 (verbose? " (" + index + ")" : ""));
00338 break;
00339
00340
00341
00342 case ANEWARRAY:
00343 index = bytes.readUnsignedShort();
00344
00345 buf.append("\t\t<" + compactClassName(constant_pool.getConstantString
00346 (index, CONSTANT_Class), false) +
00347 ">" + (verbose? " (" + index + ")": ""));
00348 break;
00349
00350
00351
00352 case MULTIANEWARRAY: {
00353 index = bytes.readUnsignedShort();
00354 int dimensions = bytes.readUnsignedByte();
00355
00356 buf.append("\t<" + compactClassName(constant_pool.getConstantString
00357 (index, CONSTANT_Class), false) +
00358 ">\t" + dimensions + (verbose? " (" + index + ")" : ""));
00359 }
00360 break;
00361
00362
00363
00364 case IINC:
00365 if(wide) {
00366 vindex = bytes.readUnsignedShort();
00367 constant = bytes.readShort();
00368 wide = false;
00369 }
00370 else {
00371 vindex = bytes.readUnsignedByte();
00372 constant = bytes.readByte();
00373 }
00374 buf.append("\t\t%" + vindex + "\t" + constant);
00375 break;
00376
00377 default:
00378 if(NO_OF_OPERANDS[opcode] > 0) {
00379 for(int i=0; i < TYPE_OF_OPERANDS[opcode].length; i++) {
00380 buf.append("\t\t");
00381 switch(TYPE_OF_OPERANDS[opcode][i]) {
00382 case T_BYTE: buf.append(bytes.readByte()); break;
00383 case T_SHORT: buf.append(bytes.readShort()); break;
00384 case T_INT: buf.append(bytes.readInt()); break;
00385
00386 default:
00387 System.err.println("Unreachable default case reached!");
00388 System.exit(-1);
00389 }
00390 }
00391 }
00392 }
00393
00394 return buf.toString();
00395 }
00396
00397
00398
00399
00400
00401
00402
00403 public static final String compactClassName(String str) {
00404 return compactClassName(str, true);
00405 }
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417 public static final String compactClassName(String str,
00418 String prefix,
00419 boolean chopit)
00420 {
00421 int len = prefix.length();
00422
00423 str = str.replace('/', '.');
00424
00425 if(chopit) {
00426
00427 if(str.startsWith(prefix) &&
00428 (str.substring(len).indexOf('.') == -1))
00429 str = str.substring(len);
00430 }
00431
00432 return str;
00433 }
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444 public static final String compactClassName(String str, boolean chopit) {
00445 return compactClassName(str, "java.lang.", chopit);
00446 }
00447 static final boolean equals(byte[] a, byte[] b) {
00448 int size;
00449
00450 if((size=a.length) != b.length)
00451 return false;
00452
00453 for(int i=0; i < size; i++)
00454 if(a[i] != b[i])
00455 return false;
00456
00457 return true;
00458 }
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468 public static final String fillup(String str, int length, boolean left_justify, char fill) {
00469 int len = length - str.length();
00470 char[] buf = new char[(len < 0)? 0 : len];
00471
00472 for(int j=0; j < buf.length; j++)
00473 buf[j] = fill;
00474
00475 if(left_justify)
00476 return str + new String(buf);
00477 else
00478 return new String(buf) + str;
00479 }
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 public static final String format(int i, int length, boolean left_justify, char fill) {
00491 return fillup(Integer.toString(i), length, left_justify, fill);
00492 }
00493 private static final boolean is_digit(char ch) {
00494 return (ch >= '0') && (ch <= '9');
00495 }
00496 private static final boolean is_space(char ch) {
00497 return (ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n');
00498 }
00499
00500
00501
00502 public static final boolean isSet(int flag, int i) {
00503 return (flag & pow2(i)) != 0;
00504 }
00505
00506
00507
00508
00509
00510 public static final String[] methodSignatureArgumentTypes(String signature)
00511 throws ClassFormatError
00512 {
00513 return methodSignatureArgumentTypes(signature, true);
00514 }
00515
00516
00517
00518
00519
00520
00521 public static final String[] methodSignatureArgumentTypes(String signature,
00522 boolean chopit)
00523 throws ClassFormatError
00524 {
00525 Vector vec = new Vector();
00526 int index;
00527 String[] types;
00528
00529 try {
00530 if(signature.charAt(0) != '(')
00531 throw new ClassFormatError("Invalid method signature: " + signature);
00532
00533 index = 1;
00534
00535 while(signature.charAt(index) != ')') {
00536 vec.addElement(signatureToString(signature.substring(index), chopit));
00537 index += consumed_chars;
00538 }
00539 } catch(StringIndexOutOfBoundsException e) {
00540 throw new ClassFormatError("Invalid method signature: " + signature);
00541 }
00542
00543 types = new String[vec.size()];
00544 vec.copyInto(types);
00545 return types;
00546 }
00547
00548
00549
00550
00551
00552 public static final String methodSignatureReturnType(String signature)
00553 throws ClassFormatError
00554 {
00555 return methodSignatureReturnType(signature, true);
00556 }
00557
00558
00559
00560
00561
00562
00563 public static final String methodSignatureReturnType(String signature,
00564 boolean chopit)
00565 throws ClassFormatError
00566 {
00567 int index;
00568 String type;
00569
00570 try {
00571
00572 index = signature.lastIndexOf(')') + 1;
00573 type = signatureToString(signature.substring(index), chopit);
00574 } catch(StringIndexOutOfBoundsException e) {
00575 throw new ClassFormatError("Invalid method signature: " + signature);
00576 }
00577
00578 return type;
00579 }
00580
00581
00582
00583
00584
00585
00586
00587
00588 public static final String methodSignatureToString(String signature,
00589 String name,
00590 String access) {
00591 return methodSignatureToString(signature, name, access, true);
00592 }
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620 public static final String methodSignatureToString(String signature,
00621 String name,
00622 String access,
00623 boolean chopit)
00624 throws ClassFormatError
00625 {
00626 StringBuffer buf = new StringBuffer("(");
00627 String type;
00628 int index;
00629
00630 try {
00631 if(signature.charAt(0) != '(')
00632 throw new ClassFormatError("Invalid method signature: " + signature);
00633
00634 index = 1;
00635
00636 while(signature.charAt(index) != ')') {
00637 buf.append(signatureToString(signature.substring(index), chopit) +
00638 ", ");
00639 index += consumed_chars;
00640 }
00641
00642 index++;
00643
00644
00645 type = signatureToString(signature.substring(index), chopit);
00646
00647 } catch(StringIndexOutOfBoundsException e) {
00648 throw new ClassFormatError("Invalid method signature: " + signature);
00649 }
00650
00651 if(buf.length() > 1)
00652 buf.setLength(buf.length() - 2);
00653
00654 buf.append(")");
00655
00656 return access + ((access.length() > 0)?" " : "") +
00657 type + " " + name + buf.toString();
00658 }
00659
00660
00661
00662
00663
00664
00665
00666
00667 public final static String methodTypeToSignature(String ret, String[] argv)
00668 throws ClassFormatError
00669 {
00670 StringBuffer buf = new StringBuffer("(");
00671 String str;
00672
00673 if(argv != null)
00674 for(int i=0; i < argv.length; i++) {
00675 str = typeToSignature(argv[i]);
00676
00677 if(str.endsWith("V"))
00678 throw new ClassFormatError("Invalid type: " + argv[i]);
00679
00680 buf.append(str);
00681 }
00682
00683 str = typeToSignature(ret);
00684
00685 buf.append(")" + str);
00686
00687 return buf.toString();
00688 }
00689
00690 private static final int pow2(int n) {
00691 return 1 << n;
00692 }
00693 public static final String printArray(Object[] obj) {
00694 return printArray(obj, true);
00695 }
00696 public static final String printArray(Object[] obj, boolean braces) {
00697 if(obj == null)
00698 return null;
00699
00700 StringBuffer buf = new StringBuffer();
00701 if(braces)
00702 buf.append('{');
00703
00704 for(int i=0; i < obj.length; i++) {
00705 if(obj[i] != null)
00706 buf.append(obj[i].toString());
00707 else
00708 buf.append("null");
00709
00710 if(i < obj.length - 1)
00711 buf.append(", ");
00712 }
00713
00714 if(braces)
00715 buf.append('}');
00716
00717 return buf.toString();
00718 }
00719 public static final void printArray(PrintStream out, Object[] obj) {
00720 out.println(printArray(obj, true));
00721 }
00722 public static final void printArray(PrintWriter out, Object[] obj) {
00723 out.println(printArray(obj, true));
00724 }
00725
00726
00727
00728
00729
00730
00731
00732
00733 public static final String replace(String str, String old, String new_) {
00734 int index, old_index;
00735 StringBuffer buf = new StringBuffer();
00736
00737 try {
00738 if((index = str.indexOf(old)) != -1) {
00739 old_index = 0;
00740
00741
00742 while((index = str.indexOf(old, old_index)) != -1) {
00743 buf.append(str.substring(old_index, index));
00744 buf.append(new_);
00745
00746 old_index = index + old.length();
00747 }
00748
00749 buf.append(str.substring(old_index));
00750 str = buf.toString();
00751 }
00752 } catch(StringIndexOutOfBoundsException e) {
00753 System.err.println(e);
00754 }
00755
00756 return str;
00757 }
00758
00759
00760
00761 public static final int setBit(int flag, int i) {
00762 return flag | pow2(i);
00763 }
00764
00765
00766
00767
00768
00769
00770 public static final String signatureToString(String signature) {
00771 return signatureToString(signature, true);
00772 }
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805
00806 public static final String signatureToString(String signature,
00807 boolean chopit)
00808 throws ClassFormatError
00809 {
00810 consumed_chars = 1;
00811
00812 try {
00813 switch(signature.charAt(0)) {
00814 case 'B' : return "byte";
00815 case 'C' : return "char";
00816 case 'D' : return "double";
00817 case 'F' : return "float";
00818 case 'I' : return "int";
00819 case 'J' : return "long";
00820
00821 case 'L' : {
00822 int index = signature.indexOf(';');
00823
00824 if(index < 0)
00825 throw new ClassFormatError("Invalid signature: " + signature);
00826
00827 consumed_chars = index + 1;
00828
00829 return compactClassName(signature.substring(1, index), chopit);
00830 }
00831
00832 case 'S' : return "short";
00833 case 'Z' : return "boolean";
00834
00835 case '[' : {
00836 int n;
00837 StringBuffer buf, brackets;
00838 String type;
00839 char ch;
00840 int consumed_chars;
00841
00842 brackets = new StringBuffer();
00843
00844
00845 for(n=0; signature.charAt(n) == '['; n++)
00846 brackets.append("[]");
00847
00848 consumed_chars = n;
00849
00850
00851 type = signatureToString(signature.substring(n), chopit);
00852
00853 Utility.consumed_chars += consumed_chars;
00854 return type + brackets.toString();
00855 }
00856
00857 case 'V' : return "void";
00858
00859 default : throw new ClassFormatError("Invalid signature: `" +
00860 signature + "'");
00861 }
00862 } catch(StringIndexOutOfBoundsException e) {
00863 throw new ClassFormatError("Invalid signature: " + e + ":" + signature);
00864 }
00865 }
00866
00867
00868
00869 public static final String toHexString(byte[] bytes) {
00870 StringBuffer buf = new StringBuffer();
00871
00872 for(int i=0; i < bytes.length; i++) {
00873 short b = byteToShort(bytes[i]);
00874 String hex = Integer.toString(b, 0x10);
00875
00876 if(b < 0x10)
00877 buf.append('0');
00878
00879 buf.append(hex);
00880
00881 if(i < bytes.length - 1)
00882 buf.append(' ');
00883 }
00884
00885 return buf.toString();
00886 }
00887
00888
00889
00890
00891
00892
00893
00894 public static final byte typeOfMethodSignature(String signature)
00895 throws ClassFormatError
00896 {
00897 int index;
00898
00899 try {
00900 if(signature.charAt(0) != '(')
00901 throw new ClassFormatError("Invalid method signature: " + signature);
00902
00903 index = signature.lastIndexOf(')') + 1;
00904 return typeOfSignature(signature.substring(index));
00905 } catch(StringIndexOutOfBoundsException e) {
00906 throw new ClassFormatError("Invalid method signature: " + signature);
00907 }
00908 }
00909
00910
00911
00912
00913
00914
00915
00916 public static final byte typeOfSignature(String signature)
00917 throws ClassFormatError
00918 {
00919 try {
00920 switch(signature.charAt(0)) {
00921 case 'B' : return T_BYTE;
00922 case 'C' : return T_CHAR;
00923 case 'D' : return T_DOUBLE;
00924 case 'F' : return T_FLOAT;
00925 case 'I' : return T_INT;
00926 case 'J' : return T_LONG;
00927 case 'L' : return T_REFERENCE;
00928 case '[' : return T_ARRAY;
00929 case 'V' : return T_VOID;
00930 case 'Z' : return T_BOOLEAN;
00931 case 'S' : return T_SHORT;
00932 default:
00933 throw new ClassFormatError("Invalid method signature: " + signature);
00934 }
00935 } catch(StringIndexOutOfBoundsException e) {
00936 throw new ClassFormatError("Invalid method signature: " + signature);
00937 }
00938 }
00939
00940
00941
00942
00943
00944
00945
00946 public final static String typeToSignature(String str)
00947 throws ClassFormatError
00948 {
00949 int index = str.indexOf('[');
00950 String type, array=null, code=null;
00951
00952 try {
00953 if(index > -1) {
00954 type = str.substring(0, index);
00955 array = str.substring(index);
00956 }
00957 else
00958 type = str;
00959
00960 if(array == null)
00961 array = "";
00962 else {
00963 StringBuffer buf = new StringBuffer();
00964 char ch, lastchar='X';
00965
00966 for(int i=0; i < array.length(); i++) {
00967 ch = array.charAt(i);
00968
00969 if(ch == '[')
00970 buf.append('[');
00971 else if((ch == ']') || is_space(ch))
00972 ;
00973 else if(is_digit(ch)) {
00974 if((lastchar == '[') || is_digit(lastchar))
00975 buf.append(ch);
00976 else
00977 throw new ClassFormatError("Invalid type: " + str);
00978 }
00979 else
00980 throw new ClassFormatError("Invalid type: " + str);
00981
00982 lastchar = ch;
00983 }
00984
00985 array = buf.toString();
00986 }
00987 } catch(StringIndexOutOfBoundsException e) {
00988 throw new ClassFormatError("Invalid type: " + str);
00989 }
00990
00991 int i;
00992 for(i=T_BOOLEAN; i <= T_VOID; i++) {
00993 if(type.equals(TYPE_NAMES[i])) {
00994 code = SHORT_TYPE_NAMES[i];
00995 break;
00996 }
00997 }
00998
00999 if(i == T_VOID) {
01000 if(array.startsWith("["))
01001 throw new ClassFormatError("Invalid type: " + str);
01002 }
01003 else if(i > T_VOID)
01004 code = "L" + type.replace('.', '/') + ";";
01005
01006 return array + code;
01007 }
01008 }