Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653
  1. package org.aspectj.apache.bcel.classfile;
  2. /* ====================================================================
  3. * The Apache Software License, Version 1.1
  4. *
  5. * Copyright (c) 2001 The Apache Software Foundation. All rights
  6. * reserved.
  7. *
  8. * Redistribution and use in source and binary forms, with or without
  9. * modification, are permitted provided that the following conditions
  10. * are met:
  11. *
  12. * 1. Redistributions of source code must retain the above copyright
  13. * notice, this list of conditions and the following disclaimer.
  14. *
  15. * 2. Redistributions in binary form must reproduce the above copyright
  16. * notice, this list of conditions and the following disclaimer in
  17. * the documentation and/or other materials provided with the
  18. * distribution.
  19. *
  20. * 3. The end-user documentation included with the redistribution,
  21. * if any, must include the following acknowledgment:
  22. * "This product includes software developed by the
  23. * Apache Software Foundation (http://www.apache.org/)."
  24. * Alternately, this acknowledgment may appear in the software itself,
  25. * if and wherever such third-party acknowledgments normally appear.
  26. *
  27. * 4. The names "Apache" and "Apache Software Foundation" and
  28. * "Apache BCEL" must not be used to endorse or promote products
  29. * derived from this software without prior written permission. For
  30. * written permission, please contact apache@apache.org.
  31. *
  32. * 5. Products derived from this software may not be called "Apache",
  33. * "Apache BCEL", nor may "Apache" appear in their name, without
  34. * prior written permission of the Apache Software Foundation.
  35. *
  36. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  37. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  38. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  39. * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  40. * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  41. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  42. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  43. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  44. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  45. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  46. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  47. * SUCH DAMAGE.
  48. * ====================================================================
  49. *
  50. * This software consists of voluntary contributions made by many
  51. * individuals on behalf of the Apache Software Foundation. For more
  52. * information on the Apache Software Foundation, please see
  53. * <http://www.apache.org/>.
  54. */
  55. import java.io.ByteArrayInputStream;
  56. import java.io.ByteArrayOutputStream;
  57. import java.io.CharArrayReader;
  58. import java.io.CharArrayWriter;
  59. import java.io.DataOutputStream;
  60. import java.io.FilterReader;
  61. import java.io.FilterWriter;
  62. import java.io.IOException;
  63. import java.io.PrintStream;
  64. import java.io.PrintWriter;
  65. import java.io.Reader;
  66. import java.io.Writer;
  67. import java.util.ArrayList;
  68. import java.util.Iterator;
  69. import java.util.List;
  70. import java.util.zip.GZIPInputStream;
  71. import java.util.zip.GZIPOutputStream;
  72. import org.aspectj.apache.bcel.Constants;
  73. import org.aspectj.apache.bcel.classfile.annotation.Annotation;
  74. import org.aspectj.apache.bcel.classfile.annotation.ElementNameValuePair;
  75. import org.aspectj.apache.bcel.classfile.annotation.RuntimeInvisibleAnnotations;
  76. import org.aspectj.apache.bcel.classfile.annotation.RuntimeInvisibleParameterAnnotations;
  77. import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleAnnotations;
  78. import org.aspectj.apache.bcel.classfile.annotation.RuntimeVisibleParameterAnnotations;
  79. import org.aspectj.apache.bcel.generic.ConstantPoolGen;
  80. import org.aspectj.apache.bcel.generic.annotation.AnnotationGen;
  81. import org.aspectj.apache.bcel.util.ByteSequence;
  82. /**
  83. * Utility functions that do not really belong to any class in particular.
  84. *
  85. * @version $Id: Utility.java,v 1.5.2.1 2007/02/09 10:45:09 aclement Exp $
  86. * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  87. *
  88. * modified: Andy Clement 2-mar-05 Removed unnecessary static and optimized
  89. */
  90. public abstract class Utility {
  91. /* The `WIDE' instruction is used in the byte code to allow 16-bit wide indices for local
  92. * variables. This opcode precedes an 'ILOAD', e.g.. The opcode immediately following takes
  93. * an extra byte which is combined with the following byte to form a 16-bit value.
  94. */
  95. private static boolean wide = false;
  96. /**
  97. * Convert bit field of flags into string such as 'static final'.
  98. *
  99. * @param access_flags Access flags
  100. * @return String representation of flags
  101. */
  102. public static final String accessToString(int access_flags) {
  103. return accessToString(access_flags, false);
  104. }
  105. /**
  106. * Convert bit field of flags into string such as 'static final'.
  107. *
  108. * Special case: Classes compiled with new compilers and with the
  109. * 'ACC_SUPER' flag would be said to be "synchronized". This is
  110. * because SUN used the same value for the flags 'ACC_SUPER' and
  111. * 'ACC_SYNCHRONIZED'.
  112. *
  113. * @param access_flags Access flags
  114. * @param for_class access flags are for class qualifiers ?
  115. * @return String representation of flags
  116. */
  117. public static final String accessToString(int access_flags, boolean for_class) {
  118. StringBuffer buf = new StringBuffer();
  119. int p = 0;
  120. for (int i=0; p < Constants.MAX_ACC_FLAG; i++) { // Loop through known flags
  121. p = pow2(i);
  122. if ((access_flags & p) != 0) {
  123. // Special case: see comment at top of class...
  124. if (for_class && ((p == Constants.ACC_SUPER) || (p == Constants.ACC_INTERFACE)))
  125. continue;
  126. buf.append(Constants.ACCESS_NAMES[i]).append(" ");
  127. }
  128. }
  129. return buf.toString().trim();
  130. }
  131. /**
  132. * @return "class" or "interface", depending on the ACC_INTERFACE flag
  133. */
  134. public static final String classOrInterface(int access_flags) {
  135. return ((access_flags & Constants.ACC_INTERFACE) != 0)? "interface" : "class";
  136. }
  137. /**
  138. * Disassemble a byte array of JVM byte codes starting from code line
  139. * 'index' and return the disassembled string representation. Decode only
  140. * 'num' opcodes (including their operands), use -1 if you want to
  141. * decompile everything.
  142. *
  143. * @param code byte code array
  144. * @param constant_pool Array of constants
  145. * @param index offset in `code' array
  146. * <EM>(number of opcodes, not bytes!)</EM>
  147. * @param length number of opcodes to decompile, -1 for all
  148. * @param verbose be verbose, e.g. print constant pool index
  149. * @return String representation of byte codes
  150. */
  151. public static final String codeToString(byte[] code,
  152. ConstantPool constant_pool,
  153. int index, int length, boolean verbose)
  154. {
  155. StringBuffer buf = new StringBuffer(code.length * 20); // Should be sufficient
  156. ByteSequence stream = new ByteSequence(code);
  157. try {
  158. for (int i=0; i < index; i++) // Skip `index' lines of code
  159. codeToString(stream, constant_pool, verbose);
  160. for (int i=0; stream.available() > 0; i++) {
  161. if ((length < 0) || (i < length)) {
  162. String indices = fillup(stream.getIndex() + ":", 6, true, ' ');
  163. buf.append(indices + codeToString(stream, constant_pool, verbose) + '\n');
  164. }
  165. }
  166. } catch(IOException e) {
  167. System.out.println(buf.toString());
  168. e.printStackTrace();
  169. throw new ClassFormatException("Byte code error: " + e);
  170. }
  171. return buf.toString();
  172. }
  173. /**
  174. * Disassemble a stream of byte codes and return the
  175. * string representation.
  176. */
  177. public static final String codeToString(byte[] code, ConstantPool constant_pool, int index, int length) {
  178. return codeToString(code, constant_pool, index, length, true);
  179. }
  180. public static final String codeToString(ByteSequence bytes, ConstantPool constant_pool)
  181. throws IOException {
  182. return codeToString(bytes, constant_pool, true);
  183. }
  184. /**
  185. * Shorten long class names, <em>java/lang/String</em> becomes <em>String</em>.
  186. *
  187. * @param str The long class name
  188. * @return Compacted class name
  189. */
  190. public static final String compactClassName(String str) {
  191. return compactClassName(str, true);
  192. }
  193. /**
  194. * Shorten long class name <em>str</em>, i.e., chop off the <em>prefix</em>,
  195. * if the
  196. * class name starts with this string and the flag <em>chopit</em> is true.
  197. * Slashes <em>/</em> are converted to dots <em>.</em>.
  198. *
  199. * @param str The long class name
  200. * @param prefix The prefix the get rid off
  201. * @param chopit Flag that determines whether chopping is executed or not
  202. * @return Compacted class name
  203. */
  204. public static final String compactClassName(String str,
  205. String prefix,
  206. boolean chopit)
  207. {
  208. int len = prefix.length();
  209. str = str.replace('/', '.'); // Is '/' on all systems, even DOS
  210. if (chopit) {
  211. // If string starts with 'prefix' and contains no further dots
  212. if (str.startsWith(prefix) && (str.substring(len).indexOf('.') == -1))
  213. str = str.substring(len);
  214. }
  215. return str;
  216. }
  217. /**
  218. * Shorten long class names, <em>java/lang/String</em> becomes
  219. * <em>java.lang.String</em>,
  220. * e.g.. If <em>chopit</em> is <em>true</em> the prefix <em>java.lang</em>
  221. * is also removed.
  222. *
  223. * @param str The long class name
  224. * @param chopit Flag that determines whether chopping is executed or not
  225. * @return Compacted class name
  226. */
  227. public static final String compactClassName(String str, boolean chopit) {
  228. return compactClassName(str, "java.lang.", chopit);
  229. }
  230. // bit modification
  231. /**
  232. * @return 'flag' with bit 'i' set to 1
  233. */
  234. public static final int setBit(int flag, int i) {
  235. return flag | pow2(i);
  236. }
  237. /**
  238. * @return 'flag' with bit 'i' set to 0
  239. */
  240. public static final int clearBit(int flag, int i) {
  241. int bit = pow2(i);
  242. return (flag & bit) == 0? flag : flag ^ bit;
  243. }
  244. /**
  245. * @return true, if bit 'i' in 'flag' is set
  246. */
  247. public static final boolean isSet(int flag, int i) {
  248. return (flag & pow2(i)) != 0;
  249. }
  250. /**
  251. * Converts string containing the method return and argument types
  252. * to a byte code method signature.
  253. *
  254. * @param returnType Return type of method (e.g. "char" or "java.lang.String[]")
  255. * @param methodArgs Types of method arguments
  256. * @return Byte code representation of method signature
  257. */
  258. public final static String methodTypeToSignature(String returnType, String[] methodArgs) throws ClassFormatException {
  259. StringBuffer buf = new StringBuffer("(");
  260. if (methodArgs != null) {
  261. for (int i=0; i < methodArgs.length; i++) {
  262. String str = getSignature(methodArgs[i]);
  263. if (str.equals("V")) // void can't be a method argument
  264. throw new ClassFormatException("Invalid type: " + methodArgs[i]);
  265. buf.append(str);
  266. }
  267. }
  268. buf.append(")" + getSignature(returnType));
  269. return buf.toString();
  270. }
  271. /**
  272. * @param signature Method signature
  273. * @return Array of argument types
  274. * @throws ClassFormatException
  275. */
  276. public static final String[] methodSignatureArgumentTypes(String signature) throws ClassFormatException {
  277. return methodSignatureArgumentTypes(signature, true);
  278. }
  279. /**
  280. * For some method signature (class file format) like '([Ljava/lang/String;Z)V' this returns an array
  281. * of strings representing the arguments in their 'normal' form, e.g. '{java.lang.String[],boolean}'
  282. *
  283. * @param signature Method signature
  284. * @param chopit Shorten class names
  285. * @return Array of argument types
  286. */
  287. public static final String[] methodSignatureArgumentTypes(String signature,boolean chopit) throws ClassFormatException {
  288. ArrayList vec = new ArrayList();
  289. int index;
  290. String[] types;
  291. try { // Read all declarations between for `(' and `)'
  292. if (signature.charAt(0) != '(')
  293. throw new ClassFormatException("Invalid method signature: " + signature);
  294. index = 1; // current string position
  295. while(signature.charAt(index) != ')') {
  296. ResultHolder rh = signatureToStringInternal(signature.substring(index),chopit);
  297. vec.add(rh.getResult());
  298. index += rh.getConsumedChars();
  299. }
  300. } catch(StringIndexOutOfBoundsException e) {
  301. throw new ClassFormatException("Invalid method signature: " + signature);
  302. }
  303. types = new String[vec.size()];
  304. vec.toArray(types);
  305. return types;
  306. }
  307. /**
  308. * For some method signature (class file format) like '([Ljava/lang/String;)Z' this returns
  309. * the string representing the return type its 'normal' form, e.g. 'boolean'
  310. *
  311. * @param signature Method signature
  312. * @return return type of method
  313. * @throws ClassFormatException
  314. */
  315. public static final String methodSignatureReturnType(String signature) throws ClassFormatException {
  316. return methodSignatureReturnType(signature, true);
  317. }
  318. /**
  319. * For some method signature (class file format) like '([Ljava/lang/String;)Z' this returns
  320. * the string representing the return type its 'normal' form, e.g. 'boolean'
  321. *
  322. * @param signature Method signature
  323. * @param chopit Shorten class names
  324. * @return return type of method
  325. */
  326. public static final String methodSignatureReturnType(String signature,boolean chopit) throws ClassFormatException {
  327. int index;
  328. String type;
  329. try {
  330. // Read return type after `)'
  331. index = signature.lastIndexOf(')') + 1;
  332. type = signatureToString(signature.substring(index), chopit);
  333. } catch (StringIndexOutOfBoundsException e) {
  334. throw new ClassFormatException("Invalid method signature: " + signature);
  335. }
  336. return type;
  337. }
  338. public static final String methodSignatureToString(String signature,String name,String access) {
  339. return methodSignatureToString(signature, name, access, true);
  340. }
  341. public static final String methodSignatureToString(String signature,String name,
  342. String access,boolean chopit) {
  343. return methodSignatureToString(signature, name, access, chopit, null);
  344. }
  345. /**
  346. * This method converts such a string into a Java type declaration like
  347. * 'void main(String[])' and throws a 'ClassFormatException' when the parsed
  348. * type is invalid.
  349. *
  350. * @param signature Method signature
  351. * @param name Method name
  352. * @param access Method access rights
  353. * @return Java type declaration
  354. * @throws ClassFormatException
  355. */
  356. public static final String methodSignatureToString(String signature, String name,
  357. String access, boolean chopit, LocalVariableTable vars) throws ClassFormatException {
  358. //
  359. //
  360. // if (signature.charAt(0)!='(')
  361. // throw new ClassFormatException("Invalid method signature: " + signature);
  362. //
  363. // // Break the signature into two pieces: ([PARAMS])[RETURNTYPE]
  364. // int lastBracketPos = signature.lastIndexOf(")");
  365. // String parameters = signature.substring(1,lastBracketPos);
  366. // String returnType = signature.substring(lastBracketPos+1);
  367. //
  368. // // e.g. parameters="Ljava/util/List<Ljava/lang/String;>;"
  369. // // returnType="V"
  370. //
  371. // // Break signature into its parts
  372. // // dont want lots of substringing so lets use an index
  373. // int posn=0;
  374. // StringBuffer piece;
  375. // while (posn<parameters.length()) {
  376. // piece = new StringBuffer();
  377. // posn+=getSignatureFrom(parameters,piece);
  378. // }
  379. //
  380. StringBuffer buf = new StringBuffer("(");
  381. String type;
  382. int index;
  383. int var_index = (access.indexOf("static") >= 0)? 0 : 1;
  384. try { // Read all declarations between for `(' and `)'
  385. if (signature.charAt(0) != '(')
  386. throw new ClassFormatException("Invalid method signature: " + signature);
  387. index = 1; // current string position
  388. while(signature.charAt(index) != ')') {
  389. ResultHolder rh = signatureToStringInternal(signature.substring(index), chopit);
  390. String param_type = rh.getResult();
  391. buf.append(param_type);
  392. if(vars != null) {
  393. LocalVariable l = vars.getLocalVariable(var_index);
  394. if(l != null) buf.append(" " + l.getName());
  395. } else {
  396. buf.append(" arg" + var_index);
  397. }
  398. if("double".equals(param_type) || "long".equals(param_type))
  399. var_index += 2;
  400. else
  401. var_index++;
  402. buf.append(", ");
  403. index += rh.getConsumedChars();
  404. }
  405. index++;
  406. // Read return type after `)'
  407. type = signatureToString(signature.substring(index), chopit);
  408. } catch(StringIndexOutOfBoundsException e) { // Should never occur
  409. throw new ClassFormatException("Invalid method signature: " + signature);
  410. }
  411. if(buf.length() > 1) // Tack off the extra ", "
  412. buf.setLength(buf.length() - 2);
  413. buf.append(")");
  414. return access + ((access.length() > 0)? " " : "") + // May be an empty string
  415. type + " " + name + buf.toString();
  416. }
  417. /**
  418. * Replace all occurences of <em>old</em> in <em>str</em> with <em>new</em>.
  419. *
  420. * @param str String to permute
  421. * @param old String to be replaced
  422. * @param new Replacement string
  423. * @return new String object
  424. */
  425. public static final String replace(String str, String old, String new_) {
  426. int index, old_index;
  427. StringBuffer buf = new StringBuffer();
  428. try {
  429. index = str.indexOf(old);
  430. if ( index != -1) {
  431. old_index = 0;
  432. // While we have something to replace
  433. while((index = str.indexOf(old, old_index)) != -1) {
  434. buf.append(str.substring(old_index, index)); // append prefix
  435. buf.append(new_); // append replacement
  436. old_index = index + old.length(); // Skip 'old'.length chars
  437. }
  438. buf.append(str.substring(old_index)); // append rest of string
  439. str = buf.toString();
  440. }
  441. } catch(StringIndexOutOfBoundsException e) {
  442. System.err.println(e);
  443. }
  444. return str;
  445. }
  446. /**
  447. * Converts signature to string with all class names compacted.
  448. *
  449. * @param signature to convert
  450. * @return Human readable signature
  451. */
  452. public static final String signatureToString(String signature) {
  453. return signatureToString(signature, true);
  454. }
  455. public static final String signatureToString(String signature,boolean chopit) {
  456. ResultHolder rh = signatureToStringInternal(signature,chopit);
  457. return rh.getResult();
  458. }
  459. /**
  460. * This method converts this string into a Java type declaration such as
  461. * 'String[]' and throws a `ClassFormatException' when the parsed type is
  462. * invalid.
  463. *
  464. * @param signature Class signature
  465. * @param chopit Flag that determines whether chopping is executed or not
  466. * @return Java type declaration
  467. */
  468. public static final ResultHolder signatureToStringInternal(String signature,boolean chopit) {
  469. int processedChars = 1; // This is the default, read just one char
  470. try {
  471. switch(signature.charAt(0)) {
  472. case 'B' : return ResultHolder.BYTE;
  473. case 'C' : return ResultHolder.CHAR;
  474. case 'D' : return ResultHolder.DOUBLE;
  475. case 'F' : return ResultHolder.FLOAT;
  476. case 'I' : return ResultHolder.INT;
  477. case 'J' : return ResultHolder.LONG;
  478. case 'L' : { // Full class name
  479. int index = signature.indexOf(';'); // Look for closing `;'
  480. // Jump to the correct ';'
  481. if (index!=-1 &&
  482. signature.length()>index+1 &&
  483. signature.charAt(index+1)=='>') index = index+2;
  484. if (index < 0)
  485. throw new ClassFormatException("Invalid signature: " + signature);
  486. int genericStart = signature.indexOf('<');
  487. int genericEnd = signature.indexOf('>');
  488. if (genericStart !=-1) {
  489. // FIXME asc going to need a lot more work in here for generics
  490. ResultHolder rh = signatureToStringInternal(signature.substring(genericStart+1,genericEnd),chopit);
  491. ResultHolder retval = new ResultHolder(compactClassName(signature.substring(1,genericStart)+"<"+
  492. rh.getResult()+">",chopit),genericEnd+1);
  493. return retval;
  494. } else {
  495. processedChars = index + 1; // "Lblabla;" `L' and `;' are removed
  496. ResultHolder retval = new ResultHolder(compactClassName(signature.substring(1, index), chopit),processedChars);
  497. return retval;
  498. }
  499. }
  500. case 'S' : return ResultHolder.SHORT;
  501. case 'Z' : return ResultHolder.BOOLEAN;
  502. case '[' : { // Array declaration
  503. StringBuffer brackets;
  504. int consumedChars,n;
  505. brackets = new StringBuffer(); // Accumulate []'s
  506. // Count opening brackets and look for optional size argument
  507. for(n=0; signature.charAt(n) == '['; n++)
  508. brackets.append("[]");
  509. consumedChars = n;
  510. // The rest of the string denotes a `<field_type>'
  511. ResultHolder restOfIt = signatureToStringInternal(signature.substring(n),chopit);
  512. // type = signatureToString(signature.substring(n), chopit);
  513. consumedChars+= restOfIt.getConsumedChars();
  514. return new ResultHolder(restOfIt.getResult() + brackets.toString(),consumedChars);
  515. }
  516. case 'V' : return ResultHolder.VOID;
  517. default : throw new ClassFormatException("Invalid signature: `" +
  518. signature + "'");
  519. }
  520. } catch(StringIndexOutOfBoundsException e) { // Should never occur
  521. throw new ClassFormatException("Invalid signature: " + e + ":" + signature);
  522. }
  523. }
  524. /**
  525. * Parse Java type such as "char", or "java.lang.String[]" and return the
  526. * signature in byte code format, e.g. "C" or "[Ljava/lang/String;" respectively.
  527. *
  528. * @param type Java type
  529. * @return byte code signature
  530. */
  531. public static String getSignature(String type) {
  532. StringBuffer buf = new StringBuffer();
  533. char[] chars = type.toCharArray();
  534. boolean char_found = false, delim = false;
  535. int index = -1;
  536. loop:
  537. for (int i=0; i < chars.length; i++) {
  538. switch (chars[i]) {
  539. case ' ': case '\t': case '\n': case '\r': case '\f':
  540. if (char_found) delim = true;
  541. break;
  542. case '[':
  543. if (!char_found) throw new RuntimeException("Illegal type: " + type);
  544. index = i;
  545. break loop;
  546. default:
  547. char_found = true;
  548. if (!delim) buf.append(chars[i]);
  549. }
  550. }
  551. int brackets = 0;
  552. if(index > 0) brackets = countBrackets(type.substring(index));
  553. type = buf.toString();
  554. buf.setLength(0);
  555. for (int i=0; i < brackets; i++) buf.append('[');
  556. boolean found = false;
  557. for(int i=Constants.T_BOOLEAN; (i <= Constants.T_VOID) && !found; i++) {
  558. if (Constants.TYPE_NAMES[i].equals(type)) {
  559. found = true;
  560. buf.append(Constants.SHORT_TYPE_NAMES[i]);
  561. }
  562. }
  563. // Class name
  564. if (!found) buf.append('L' + type.replace('.', '/') + ';');
  565. return buf.toString();
  566. }
  567. /**
  568. * Return type of method signature as a byte value as defined in <em>Constants</em>
  569. *
  570. * @param signature in format described above
  571. * @return type of method signature
  572. * @see Constants
  573. */
  574. public static final byte typeOfMethodSignature(String signature) throws ClassFormatException {
  575. int index;
  576. try {
  577. if (signature.charAt(0) != '(')
  578. throw new ClassFormatException("Invalid method signature: " + signature);
  579. index = signature.lastIndexOf(')') + 1;
  580. return typeOfSignature(signature.substring(index));
  581. } catch(StringIndexOutOfBoundsException e) {
  582. throw new ClassFormatException("Invalid method signature: " + signature);
  583. }
  584. }
  585. /** Map opcode names to opcode numbers. E.g., return Constants.ALOAD for "aload"
  586. */
  587. public static short searchOpcode(String name) {
  588. name = name.toLowerCase();
  589. for (short i=0; i < Constants.OPCODE_NAMES.length; i++) {
  590. if (Constants.OPCODE_NAMES[i].equals(name))
  591. return i;
  592. }
  593. return -1;
  594. }
  595. /**
  596. * Convert (signed) byte to (unsigned) short value, i.e., all negative
  597. * values become positive.
  598. */
  599. private static final short byteToShort(byte b) {
  600. return (b < 0)? (short)(256 + b) : (short)b;
  601. }
  602. /**
  603. * Convert bytes into hexidecimal string
  604. *
  605. * @return bytes as hexidecimal string, e.g. 00 FA 12 ...
  606. */
  607. public static final String toHexString(byte[] bytes) {
  608. StringBuffer buf = new StringBuffer();
  609. for(int i=0; i < bytes.length; i++) {
  610. short b = byteToShort(bytes[i]);
  611. String hex = Integer.toString(b, 0x10);
  612. // Just one digit, so prepend 0
  613. if (b < 0x10) buf.append('0');
  614. buf.append(hex);
  615. if (i < bytes.length - 1) buf.append(' ');
  616. }
  617. return buf.toString();
  618. }
  619. /**
  620. * Return a string for an integer justified left or right and filled up with
  621. * 'fill' characters if necessary.
  622. *
  623. * @param i integer to format
  624. * @param length length of desired string
  625. * @param left_justify format left or right
  626. * @param fill fill character
  627. * @return formatted int
  628. */
  629. public static final String format(int i, int length, boolean left_justify, char fill) {
  630. return fillup(Integer.toString(i), length, left_justify, fill);
  631. }
  632. /**
  633. * Fillup char with up to length characters with char `fill' and justify it left or right.
  634. *
  635. * @param str string to format
  636. * @param length length of desired string
  637. * @param left_justify format left or right
  638. * @param fill fill character
  639. * @return formatted string
  640. */
  641. public static final String fillup(String str, int length, boolean left_justify, char fill) {
  642. int len = length - str.length();
  643. char[] buf = new char[(len < 0)? 0 : len];
  644. for(int j=0; j < buf.length; j++)
  645. buf[j] = fill;
  646. if(left_justify)
  647. return str + new String(buf);
  648. return new String(buf) + str;
  649. }
  650. static final boolean equals(byte[] a, byte[] b) {
  651. int size;
  652. if((size=a.length) != b.length)
  653. return false;
  654. for(int i=0; i < size; i++)
  655. if(a[i] != b[i])
  656. return false;
  657. return true;
  658. }
  659. public static final void printArray(PrintStream out, Object[] obj) {
  660. out.println(printArray(obj, true));
  661. }
  662. public static final void printArray(PrintWriter out, Object[] obj) {
  663. out.println(printArray(obj, true));
  664. }
  665. public static final String printArray(Object[] obj) {
  666. return printArray(obj, true);
  667. }
  668. public static final String printArray(Object[] obj, boolean braces) {
  669. return printArray(obj, braces, false);
  670. }
  671. public static final String printArray(Object[] obj, boolean braces,
  672. boolean quote) {
  673. if(obj == null)
  674. return null;
  675. StringBuffer buf = new StringBuffer();
  676. if(braces)
  677. buf.append('{');
  678. for(int i=0; i < obj.length; i++) {
  679. if(obj[i] != null) {
  680. buf.append((quote? "\"" : "") + obj[i].toString() + (quote? "\"" : ""));
  681. } else {
  682. buf.append("null");
  683. }
  684. if(i < obj.length - 1) {
  685. buf.append(", ");
  686. }
  687. }
  688. if(braces)
  689. buf.append('}');
  690. return buf.toString();
  691. }
  692. /** @return true, if character is one of (a, ... z, A, ... Z, 0, ... 9, _)
  693. */
  694. public static boolean isJavaIdentifierPart(char ch) {
  695. return ((ch >= 'a') && (ch <= 'z')) ||
  696. ((ch >= 'A') && (ch <= 'Z')) ||
  697. ((ch >= '0') && (ch <= '9')) ||
  698. (ch == '_');
  699. }
  700. /**
  701. * Encode byte array it into Java identifier string, i.e., a string
  702. * that only contains the following characters: (a, ... z, A, ... Z,
  703. * 0, ... 9, _, $). The encoding algorithm itself is not too
  704. * clever: if the current byte's ASCII value already is a valid Java
  705. * identifier part, leave it as it is. Otherwise it writes the
  706. * escape character($) followed by <p><ul><li> the ASCII value as a
  707. * hexadecimal string, if the value is not in the range
  708. * 200..247</li> <li>a Java identifier char not used in a lowercase
  709. * hexadecimal string, if the value is in the range
  710. * 200..247</li><ul></p>
  711. *
  712. * <p>This operation inflates the original byte array by roughly 40-50%</p>
  713. *
  714. * @param bytes the byte array to convert
  715. * @param compress use gzip to minimize string
  716. */
  717. public static String encode(byte[] bytes, boolean compress) throws IOException {
  718. if(compress) {
  719. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  720. GZIPOutputStream gos = new GZIPOutputStream(baos);
  721. gos.write(bytes, 0, bytes.length);
  722. gos.close();
  723. baos.close();
  724. bytes = baos.toByteArray();
  725. }
  726. CharArrayWriter caw = new CharArrayWriter();
  727. JavaWriter jw = new JavaWriter(caw);
  728. for(int i=0; i < bytes.length; i++) {
  729. int in = bytes[i] & 0x000000ff; // Normalize to unsigned
  730. jw.write(in);
  731. }
  732. return caw.toString();
  733. }
  734. /** Decode a string back to a byte array.
  735. *
  736. * @param bytes the byte array to convert
  737. * @param uncompress use gzip to uncompress the stream of bytes
  738. */
  739. public static byte[] decode(String s, boolean uncompress) throws IOException {
  740. char[] chars = s.toCharArray();
  741. CharArrayReader car = new CharArrayReader(chars);
  742. JavaReader jr = new JavaReader(car);
  743. ByteArrayOutputStream bos = new ByteArrayOutputStream();
  744. int ch;
  745. while((ch = jr.read()) >= 0) {
  746. bos.write(ch);
  747. }
  748. bos.close();
  749. car.close();
  750. jr.close();
  751. byte[] bytes = bos.toByteArray();
  752. if(uncompress) {
  753. GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(bytes));
  754. byte[] tmp = new byte[bytes.length * 3]; // Rough estimate
  755. int count = 0;
  756. int b;
  757. while((b = gis.read()) >= 0)
  758. tmp[count++] = (byte)b;
  759. bytes = new byte[count];
  760. System.arraycopy(tmp, 0, bytes, 0, count);
  761. }
  762. return bytes;
  763. }
  764. // A-Z, g-z, _, $
  765. private static final int FREE_CHARS = 48;
  766. private static int[] CHAR_MAP = new int[FREE_CHARS];
  767. private static int[] MAP_CHAR = new int[256]; // Reverse map
  768. private static final char ESCAPE_CHAR = '$';
  769. static {
  770. int j = 0, k = 0;
  771. for(int i='A'; i <= 'Z'; i++) {
  772. CHAR_MAP[j] = i;
  773. MAP_CHAR[i] = j;
  774. j++;
  775. }
  776. for(int i='g'; i <= 'z'; i++) {
  777. CHAR_MAP[j] = i;
  778. MAP_CHAR[i] = j;
  779. j++;
  780. }
  781. CHAR_MAP[j] = '$';
  782. MAP_CHAR['$'] = j;
  783. j++;
  784. CHAR_MAP[j] = '_';
  785. MAP_CHAR['_'] = j;
  786. }
  787. /** Decode characters into bytes.
  788. * Used by <a href="Utility.html#decode(java.lang.String, boolean)">decode()</a>
  789. */
  790. private static class JavaReader extends FilterReader {
  791. public JavaReader(Reader in) {
  792. super(in);
  793. }
  794. public int read() throws IOException {
  795. int b = in.read();
  796. if(b != ESCAPE_CHAR) {
  797. return b;
  798. } else {
  799. int i = in.read();
  800. if(i < 0)
  801. return -1;
  802. if(((i >= '0') && (i <= '9')) || ((i >= 'a') && (i <= 'f'))) { // Normal escape
  803. int j = in.read();
  804. if(j < 0)
  805. return -1;
  806. char[] tmp = { (char)i, (char)j };
  807. int s = Integer.parseInt(new String(tmp), 16);
  808. return s;
  809. } else { // Special escape
  810. return MAP_CHAR[i];
  811. }
  812. }
  813. }
  814. public int read(char[] cbuf, int off, int len) throws IOException {
  815. for(int i=0; i < len; i++)
  816. cbuf[off + i] = (char)read();
  817. return len;
  818. }
  819. }
  820. /** Encode bytes into valid java identifier characters.
  821. * Used by <a href="Utility.html#encode(byte[], boolean)">encode()</a>
  822. */
  823. private static class JavaWriter extends FilterWriter {
  824. public JavaWriter(Writer out) {
  825. super(out);
  826. }
  827. public void write(int b) throws IOException {
  828. if(isJavaIdentifierPart((char)b) && (b != ESCAPE_CHAR)) {
  829. out.write(b);
  830. } else {
  831. out.write(ESCAPE_CHAR); // Escape character
  832. // Special escape
  833. if(b >= 0 && b < FREE_CHARS) {
  834. out.write(CHAR_MAP[b]);
  835. } else { // Normal escape
  836. char[] tmp = Integer.toHexString(b).toCharArray();
  837. if(tmp.length == 1) {
  838. out.write('0');
  839. out.write(tmp[0]);
  840. } else {
  841. out.write(tmp[0]);
  842. out.write(tmp[1]);
  843. }
  844. }
  845. }
  846. }
  847. public void write(char[] cbuf, int off, int len) throws IOException {
  848. for(int i=0; i < len; i++)
  849. write(cbuf[off + i]);
  850. }
  851. public void write(String str, int off, int len) throws IOException {
  852. write(str.toCharArray(), off, len);
  853. }
  854. }
  855. /**
  856. * Escape all occurences of newline chars '\n', quotes \", etc.
  857. */
  858. public static final String convertString(String label) {
  859. char[] ch = label.toCharArray();
  860. StringBuffer buf = new StringBuffer();
  861. for(int i=0; i < ch.length; i++) {
  862. switch(ch[i]) {
  863. case '\n':
  864. buf.append("\\n"); break;
  865. case '\r':
  866. buf.append("\\r"); break;
  867. case '\"':
  868. buf.append("\\\""); break;
  869. case '\'':
  870. buf.append("\\'"); break;
  871. case '\\':
  872. buf.append("\\\\"); break;
  873. default:
  874. buf.append(ch[i]); break;
  875. }
  876. }
  877. return buf.toString();
  878. }
  879. public static List getListOfAnnotationNames(Annotation a) {
  880. List l = a.getValues();
  881. List names = new ArrayList();
  882. for (Iterator i = l.iterator(); i.hasNext();) {
  883. ElementNameValuePair element = (ElementNameValuePair) i.next();
  884. names.add(element.getNameString());
  885. }
  886. return names;
  887. }
  888. /**
  889. * Converts a list of AnnotationGen objects into a set of attributes
  890. * that can be attached to the class file.
  891. *
  892. * @param cp The constant pool gen where we can create the necessary name refs
  893. * @param vec A list of AnnotationGen objects
  894. */
  895. public static Attribute[] getAnnotationAttributes(ConstantPoolGen cp,List vec) {
  896. if (vec.size()==0) return null;
  897. try {
  898. int countVisible = 0;
  899. int countInvisible = 0;
  900. // put the annotations in the right output stream
  901. for (int i=0; i<vec.size(); i++) {
  902. AnnotationGen a = (AnnotationGen)vec.get(i);
  903. if (a.isRuntimeVisible()) countVisible++;
  904. else countInvisible++;
  905. }
  906. ByteArrayOutputStream rvaBytes = new ByteArrayOutputStream();
  907. ByteArrayOutputStream riaBytes = new ByteArrayOutputStream();
  908. DataOutputStream rvaDos = new DataOutputStream(rvaBytes);
  909. DataOutputStream riaDos = new DataOutputStream(riaBytes);
  910. rvaDos.writeShort(countVisible);
  911. riaDos.writeShort(countInvisible);
  912. // put the annotations in the right output stream
  913. for (int i=0; i<vec.size(); i++) {
  914. AnnotationGen a = (AnnotationGen)vec.get(i);
  915. if (a.isRuntimeVisible()) a.dump(rvaDos);
  916. else a.dump(riaDos);
  917. }
  918. rvaDos.close();
  919. riaDos.close();
  920. byte[] rvaData = rvaBytes.toByteArray();
  921. byte[] riaData = riaBytes.toByteArray();
  922. int rvaIndex = -1;
  923. int riaIndex = -1;
  924. if (rvaData.length>2) rvaIndex = cp.addUtf8("RuntimeVisibleAnnotations");
  925. if (riaData.length>2) riaIndex = cp.addUtf8("RuntimeInvisibleAnnotations");
  926. List newAttributes = new ArrayList();
  927. if (rvaData.length>2) {
  928. newAttributes.add(
  929. new RuntimeVisibleAnnotations(rvaIndex,rvaData.length,rvaData,cp.getConstantPool()));
  930. }
  931. if (riaData.length>2) {
  932. newAttributes.add(
  933. new RuntimeInvisibleAnnotations(riaIndex,riaData.length,riaData,cp.getConstantPool()));
  934. }
  935. return (Attribute[])newAttributes.toArray(new Attribute[]{});
  936. } catch (IOException e) {
  937. System.err.println("IOException whilst processing annotations");
  938. e.printStackTrace();
  939. }
  940. return null;
  941. }
  942. /**
  943. * Annotations against a class are stored in one of four attribute kinds:
  944. * - RuntimeVisibleParameterAnnotations
  945. * - RuntimeInvisibleParameterAnnotations
  946. */
  947. public static Attribute[] getParameterAnnotationAttributes(ConstantPoolGen cp,List[] /*Array of lists, array size depends on #params */ vec) {
  948. int visCount[] = new int[vec.length];
  949. int totalVisCount = 0;
  950. int invisCount[] = new int[vec.length];
  951. int totalInvisCount = 0;
  952. try {
  953. for (int i=0; i<vec.length; i++) {
  954. List l = vec[i];
  955. if (l!=null) {
  956. for (Iterator iter = l.iterator(); iter.hasNext();) {
  957. AnnotationGen element = (AnnotationGen) iter.next();
  958. if (element.isRuntimeVisible()) {visCount[i]++;totalVisCount++;}
  959. else {invisCount[i]++;totalInvisCount++;}
  960. }
  961. }
  962. }
  963. // Lets do the visible ones
  964. ByteArrayOutputStream rvaBytes = new ByteArrayOutputStream();
  965. DataOutputStream rvaDos = new DataOutputStream(rvaBytes);
  966. rvaDos.writeByte(vec.length); // First goes number of parameters
  967. for (int i=0; i<vec.length; i++) {
  968. rvaDos.writeShort(visCount[i]);
  969. if (visCount[i]>0) {
  970. List l = vec[i];
  971. for (Iterator iter = l.iterator(); iter.hasNext();) {
  972. AnnotationGen element = (AnnotationGen) iter.next();
  973. if (element.isRuntimeVisible()) element.dump(rvaDos);
  974. }
  975. }
  976. }
  977. rvaDos.close();
  978. // Lets do the invisible ones
  979. ByteArrayOutputStream riaBytes = new ByteArrayOutputStream();
  980. DataOutputStream riaDos = new DataOutputStream(riaBytes);
  981. riaDos.writeByte(vec.length); // First goes number of parameters
  982. for (int i=0; i<vec.length; i++) {
  983. riaDos.writeShort(invisCount[i]);
  984. if (invisCount[i]>0) {
  985. List l = vec[i];
  986. for (Iterator iter = l.iterator(); iter.hasNext();) {
  987. AnnotationGen element = (AnnotationGen) iter.next();
  988. if (!element.isRuntimeVisible()) element.dump(riaDos);
  989. }
  990. }
  991. }
  992. riaDos.close();
  993. byte[] rvaData = rvaBytes.toByteArray();
  994. byte[] riaData = riaBytes.toByteArray();
  995. int rvaIndex = -1;
  996. int riaIndex = -1;
  997. if (totalVisCount>0) rvaIndex = cp.addUtf8("RuntimeVisibleParameterAnnotations");
  998. if (totalInvisCount>0) riaIndex = cp.addUtf8("RuntimeInvisibleParameterAnnotations");
  999. List newAttributes = new ArrayList();
  1000. if (totalVisCount>0) {
  1001. newAttributes.add(
  1002. new RuntimeVisibleParameterAnnotations(rvaIndex,rvaData.length,rvaData,cp.getConstantPool()));
  1003. }
  1004. if (totalInvisCount>0) {
  1005. newAttributes.add(
  1006. new RuntimeInvisibleParameterAnnotations(riaIndex,riaData.length,riaData,cp.getConstantPool()));
  1007. }
  1008. return (Attribute[])newAttributes.toArray(new Attribute[]{});
  1009. } catch (IOException e) {
  1010. System.err.println("IOException whilst processing parameter annotations");
  1011. e.printStackTrace();
  1012. }
  1013. return null;
  1014. }
  1015. private static final boolean is_digit(char ch) {
  1016. return (ch >= '0') && (ch <= '9');
  1017. }
  1018. private static final boolean is_space(char ch) {
  1019. return (ch == ' ') || (ch == '\t') || (ch == '\r') || (ch == '\n');
  1020. }
  1021. private static class ResultHolder {
  1022. private String result;
  1023. private int consumed;
  1024. public static final ResultHolder BYTE = new ResultHolder("byte",1);
  1025. public static final ResultHolder CHAR = new ResultHolder("char",1);
  1026. public static final ResultHolder DOUBLE = new ResultHolder("double",1);
  1027. public static final ResultHolder FLOAT = new ResultHolder("float",1);
  1028. public static final ResultHolder INT = new ResultHolder("int",1);
  1029. public static final ResultHolder LONG = new ResultHolder("long",1);
  1030. public static final ResultHolder SHORT = new ResultHolder("short",1);
  1031. public static final ResultHolder BOOLEAN = new ResultHolder("boolean",1);
  1032. public static final ResultHolder VOID = new ResultHolder("void",1);
  1033. public ResultHolder(String s,int c) {
  1034. result = s;
  1035. consumed = c;
  1036. }
  1037. public String getResult() { return result;}
  1038. public int getConsumedChars() { return consumed; }
  1039. }
  1040. // code below here I am happy with ....
  1041. /**
  1042. * Return type of signature as a byte value as defined in <em>Constants</em>
  1043. *
  1044. * @param signature in format described above
  1045. * @return type of signature
  1046. * @see Constants
  1047. */
  1048. public static final byte typeOfSignature(String signature) throws ClassFormatException {
  1049. try {
  1050. switch(signature.charAt(0)) {
  1051. case 'B' : return Constants.T_BYTE;
  1052. case 'C' : return Constants.T_CHAR;
  1053. case 'D' : return Constants.T_DOUBLE;
  1054. case 'F' : return Constants.T_FLOAT;
  1055. case 'I' : return Constants.T_INT;
  1056. case 'J' : return Constants.T_LONG;
  1057. case 'L' : return Constants.T_REFERENCE;
  1058. case '[' : return Constants.T_ARRAY;
  1059. case 'V' : return Constants.T_VOID;
  1060. case 'Z' : return Constants.T_BOOLEAN;
  1061. case 'S' : return Constants.T_SHORT;
  1062. default:
  1063. throw new ClassFormatException("Invalid method signature: " + signature);
  1064. }
  1065. } catch(StringIndexOutOfBoundsException e) {
  1066. throw new ClassFormatException("Invalid method signature: " + signature);
  1067. }
  1068. }
  1069. public static final byte typeOfSignature(char c) throws ClassFormatException {
  1070. switch(c) {
  1071. case 'B' : return Constants.T_BYTE;
  1072. case 'C' : return Constants.T_CHAR;
  1073. case 'D' : return Constants.T_DOUBLE;
  1074. case 'F' : return Constants.T_FLOAT;
  1075. case 'I' : return Constants.T_INT;
  1076. case 'J' : return Constants.T_LONG;
  1077. case 'L' : return Constants.T_REFERENCE;
  1078. case '[' : return Constants.T_ARRAY;
  1079. case 'V' : return Constants.T_VOID;
  1080. case 'Z' : return Constants.T_BOOLEAN;
  1081. case 'S' : return Constants.T_SHORT;
  1082. default:
  1083. throw new ClassFormatException("Invalid type of signature: " + c);
  1084. }
  1085. }
  1086. public static final String readClassTypeSignatureFrom(String signature) {
  1087. StringBuffer sb = new StringBuffer();
  1088. readClassTypeSignatureFrom(signature,0,sb,false);
  1089. return sb.toString();
  1090. }
  1091. /**
  1092. * Takes a string and consumes a single complete signature from it, returning
  1093. * how many chars it consumed. The chopit flag indicates whether to shorten
  1094. * type references ( java/lang/String => String )
  1095. *
  1096. * FIXME asc this should also create some kind of object you can query for information about whether its parameterized, what the bounds are, etc...
  1097. */
  1098. public static final int readClassTypeSignatureFrom(String signature, int posn, StringBuffer result, boolean chopit) {
  1099. int idx = posn;
  1100. try {
  1101. switch (signature.charAt(idx)) {
  1102. case 'B' : result.append("byte"); return 1;
  1103. case 'C' : result.append("char"); return 1;
  1104. case 'D' : result.append("double"); return 1;
  1105. case 'F' : result.append("float"); return 1;
  1106. case 'I' : result.append("int"); return 1;
  1107. case 'J' : result.append("long"); return 1;
  1108. case 'S' : result.append("short"); return 1;
  1109. case 'Z' : result.append("boolean");return 1;
  1110. case 'V' : result.append("void"); return 1;
  1111. //FIXME ASC Need a state machine to check we are parsing the right stuff here !
  1112. case 'T' :
  1113. idx++;
  1114. int nextSemiIdx = signature.indexOf(';',idx);
  1115. result.append(signature.substring(idx,nextSemiIdx));
  1116. return nextSemiIdx+1-posn;
  1117. case '+' :
  1118. result.append("? extends ");
  1119. return readClassTypeSignatureFrom(signature,idx+1,result,chopit)+1;
  1120. case '-' :
  1121. result.append("? super ");
  1122. return readClassTypeSignatureFrom(signature,idx+1,result,chopit)+1;
  1123. case '*' :
  1124. result.append("?");
  1125. return 1;
  1126. case 'L' : // Full class name
  1127. boolean parameterized = false;
  1128. int idxSemicolon = signature.indexOf(';',idx); // Look for closing ';' or '<'
  1129. int idxAngly = signature.indexOf('<',idx);
  1130. int endOfSig = idxSemicolon;
  1131. if ((idxAngly!=-1) && idxAngly<endOfSig) { endOfSig = idxAngly; parameterized = true; }
  1132. String p = signature.substring(idx+1,endOfSig);
  1133. String t = compactClassName(p,chopit);
  1134. result.append(t);
  1135. idx=endOfSig;
  1136. // we might have finished now, depending on whether this is a parameterized type...
  1137. if (parameterized) {
  1138. idx++;
  1139. result.append("<");
  1140. while (signature.charAt(idx)!='>') {
  1141. idx+=readClassTypeSignatureFrom(signature,idx,result,chopit);
  1142. if (signature.charAt(idx)!='>') result.append(",");
  1143. }
  1144. result.append(">");idx++;
  1145. }
  1146. if (signature.charAt(idx)!=';') throw new RuntimeException("Did not find ';' at end of signature, found "+signature.charAt(idx));
  1147. idx++;
  1148. return idx-posn;
  1149. case '[' : // Array declaration
  1150. int dim = 0;
  1151. while (signature.charAt(idx)=='[') {dim++;idx++;}
  1152. idx+=readClassTypeSignatureFrom(signature,idx,result,chopit);
  1153. while (dim>0) {result.append("[]");dim--;}
  1154. return idx-posn;
  1155. default : throw new ClassFormatException("Invalid signature: `" +
  1156. signature + "'");
  1157. }
  1158. } catch(StringIndexOutOfBoundsException e) { // Should never occur
  1159. throw new ClassFormatException("Invalid signature: " + e + ":" + signature);
  1160. }
  1161. }
  1162. private static int countBrackets(String brackets) {
  1163. char[] chars = brackets.toCharArray();
  1164. int count = 0;
  1165. boolean open = false;
  1166. for(int i=0; i<chars.length; i++) {
  1167. switch(chars[i]) {
  1168. case '[':
  1169. if (open) throw new RuntimeException("Illegally nested brackets:" + brackets);
  1170. open = true;
  1171. break;
  1172. case ']':
  1173. if (!open) throw new RuntimeException("Illegally nested brackets:" + brackets);
  1174. open = false;
  1175. count++;
  1176. break;
  1177. default:
  1178. }
  1179. }
  1180. if (open) throw new RuntimeException("Illegally nested brackets:" + brackets);
  1181. return count;
  1182. }
  1183. /**
  1184. * Disassemble a stream of byte codes and return the string representation.
  1185. *
  1186. * @param bytes stream of bytes
  1187. * @param constant_pool Array of constants
  1188. * @param verbose be verbose, e.g. print constant pool index
  1189. * @return String representation of byte code
  1190. */
  1191. public static final String codeToString(ByteSequence bytes,
  1192. ConstantPool constant_pool, boolean verbose) throws IOException {
  1193. short opcode = (short)bytes.readUnsignedByte();
  1194. int default_offset=0, low, high, npairs;
  1195. int index, vindex, constant;
  1196. int[] match, jump_table;
  1197. int no_pad_bytes=0, offset;
  1198. StringBuffer buf = new StringBuffer(Constants.OPCODE_NAMES[opcode]);
  1199. /* Special case: Skip (0-3) padding bytes, i.e., the
  1200. * following bytes are 4-byte-aligned
  1201. */
  1202. if ((opcode == Constants.TABLESWITCH) || (opcode == Constants.LOOKUPSWITCH)) {
  1203. int remainder = bytes.getIndex() % 4;
  1204. no_pad_bytes = (remainder == 0)? 0 : 4 - remainder;
  1205. for (int i=0; i < no_pad_bytes; i++) {
  1206. byte b = bytes.readByte();
  1207. if (b != 0)
  1208. System.err.println("Warning: Padding byte != 0 in " + Constants.OPCODE_NAMES[opcode] + ":" + b);
  1209. }
  1210. // Both cases have a field default_offset in common
  1211. default_offset = bytes.readInt();
  1212. }
  1213. switch(opcode) {
  1214. /* Table switch has variable length arguments.
  1215. */
  1216. case Constants.TABLESWITCH:
  1217. low = bytes.readInt();
  1218. high = bytes.readInt();
  1219. offset = bytes.getIndex() - 12 - no_pad_bytes - 1;
  1220. default_offset += offset;
  1221. buf.append("\tdefault = " + default_offset + ", low = " + low +
  1222. ", high = " + high + "(");
  1223. jump_table = new int[high - low + 1];
  1224. for (int i=0; i < jump_table.length; i++) {
  1225. jump_table[i] = offset + bytes.readInt();
  1226. buf.append(jump_table[i]);
  1227. if (i < jump_table.length - 1) buf.append(", ");
  1228. }
  1229. buf.append(")");
  1230. break;
  1231. /* Lookup switch has variable length arguments.
  1232. */
  1233. case Constants.LOOKUPSWITCH: {
  1234. npairs = bytes.readInt();
  1235. offset = bytes.getIndex() - 8 - no_pad_bytes - 1;
  1236. match = new int[npairs];
  1237. jump_table = new int[npairs];
  1238. default_offset += offset;
  1239. buf.append("\tdefault = " + default_offset + ", npairs = " + npairs + " (");
  1240. for (int i=0; i < npairs; i++) {
  1241. match[i] = bytes.readInt();
  1242. jump_table[i] = offset + bytes.readInt();
  1243. buf.append("(" + match[i] + ", " + jump_table[i] + ")");
  1244. if(i < npairs - 1) buf.append(", ");
  1245. }
  1246. buf.append(")");
  1247. }
  1248. break;
  1249. // Two address bytes + offset from start of byte stream form the jump target
  1250. case Constants.GOTO: case Constants.IFEQ: case Constants.IFGE: case Constants.IFGT:
  1251. case Constants.IFLE: case Constants.IFLT: case Constants.JSR: case Constants.IFNE:
  1252. case Constants.IFNONNULL: case Constants.IFNULL: case Constants.IF_ACMPEQ:
  1253. case Constants.IF_ACMPNE: case Constants.IF_ICMPEQ: case Constants.IF_ICMPGE: case Constants.IF_ICMPGT:
  1254. case Constants.IF_ICMPLE: case Constants.IF_ICMPLT: case Constants.IF_ICMPNE:
  1255. buf.append("\t\t#" + ((bytes.getIndex() - 1) + bytes.readShort()));
  1256. break;
  1257. // 32-bit wide jumps
  1258. case Constants.GOTO_W: case Constants.JSR_W:
  1259. buf.append("\t\t#" + ((bytes.getIndex() - 1) + bytes.readInt()));
  1260. break;
  1261. // Index byte references local variable (register)
  1262. case Constants.ALOAD: case Constants.ASTORE: case Constants.DLOAD: case Constants.DSTORE: case Constants.FLOAD:
  1263. case Constants.FSTORE: case Constants.ILOAD: case Constants.ISTORE: case Constants.LLOAD: case Constants.LSTORE:
  1264. case Constants.RET:
  1265. if (wide) {
  1266. vindex = bytes.readUnsignedShort();
  1267. wide=false; // Clear flag
  1268. } else
  1269. vindex = bytes.readUnsignedByte();
  1270. buf.append("\t\t%" + vindex);
  1271. break;
  1272. /*
  1273. * Remember wide byte which is used to form a 16-bit address in the
  1274. * following instruction. Relies on that the method is called again with
  1275. * the following opcode.
  1276. */
  1277. case Constants.WIDE: wide=true; buf.append("\t(wide)"); break;
  1278. // Array of basic type
  1279. case Constants.NEWARRAY: buf.append("\t\t<" + Constants.TYPE_NAMES[bytes.readByte()] + ">"); break;
  1280. // Access object/class fields
  1281. case Constants.GETFIELD: case Constants.GETSTATIC: case Constants.PUTFIELD: case Constants.PUTSTATIC:
  1282. index = bytes.readUnsignedShort();
  1283. buf.append("\t\t" +
  1284. constant_pool.constantToString(index, Constants.CONSTANT_Fieldref) +
  1285. (verbose? " (" + index + ")" : ""));
  1286. break;
  1287. // Operands are references to classes in constant pool
  1288. case Constants.NEW:
  1289. case Constants.CHECKCAST:
  1290. buf.append("\t");
  1291. case Constants.INSTANCEOF:
  1292. index = bytes.readUnsignedShort();
  1293. buf.append("\t<" + constant_pool.constantToString(index,Constants.CONSTANT_Class) +
  1294. ">" + (verbose? " (" + index + ")" : ""));
  1295. break;
  1296. // Operands are references to methods in constant pool
  1297. case Constants.INVOKESPECIAL: case Constants.INVOKESTATIC: case Constants.INVOKEVIRTUAL:
  1298. index = bytes.readUnsignedShort();
  1299. buf.append("\t" + constant_pool.constantToString(index,Constants.CONSTANT_Methodref) +
  1300. (verbose? " (" + index + ")" : ""));
  1301. break;
  1302. case Constants.INVOKEINTERFACE:
  1303. index = bytes.readUnsignedShort();
  1304. int nargs = bytes.readUnsignedByte(); // historical, redundant
  1305. buf.append("\t" +
  1306. constant_pool.constantToString(index,Constants.CONSTANT_InterfaceMethodref) +
  1307. (verbose? " (" + index + ")\t" : "") + nargs + "\t" +
  1308. bytes.readUnsignedByte()); // Last byte is a reserved space
  1309. break;
  1310. // Operands are references to items in constant pool
  1311. case Constants.LDC_W: case Constants.LDC2_W:
  1312. index = bytes.readUnsignedShort();
  1313. buf.append("\t\t" + constant_pool.constantToString
  1314. (index, constant_pool.getConstant(index).getTag()) +
  1315. (verbose? " (" + index + ")" : ""));
  1316. break;
  1317. case Constants.LDC:
  1318. index = bytes.readUnsignedByte();
  1319. buf.append("\t\t" +
  1320. constant_pool.constantToString
  1321. (index, constant_pool.getConstant(index).getTag()) +
  1322. (verbose? " (" + index + ")" : ""));
  1323. break;
  1324. // Array of references
  1325. case Constants.ANEWARRAY:
  1326. index = bytes.readUnsignedShort();
  1327. buf.append("\t\t<" + compactClassName(constant_pool.getConstantString
  1328. (index, Constants.CONSTANT_Class), false) +
  1329. ">" + (verbose? " (" + index + ")": ""));
  1330. break;
  1331. // Multidimensional array of references
  1332. case Constants.MULTIANEWARRAY: {
  1333. index = bytes.readUnsignedShort();
  1334. int dimensions = bytes.readUnsignedByte();
  1335. buf.append("\t<" + compactClassName(constant_pool.getConstantString
  1336. (index, Constants.CONSTANT_Class), false) +
  1337. ">\t" + dimensions + (verbose? " (" + index + ")" : ""));
  1338. }
  1339. break;
  1340. // Increment local variable
  1341. case Constants.IINC:
  1342. if (wide) {
  1343. vindex = bytes.readUnsignedShort();
  1344. constant = bytes.readShort();
  1345. wide = false;
  1346. } else {
  1347. vindex = bytes.readUnsignedByte();
  1348. constant = bytes.readByte();
  1349. }
  1350. buf.append("\t\t%" + vindex + "\t" + constant);
  1351. break;
  1352. default:
  1353. if (Constants.NO_OF_OPERANDS[opcode] > 0) {
  1354. for (int i=0; i < Constants.TYPE_OF_OPERANDS[opcode].length; i++) {
  1355. buf.append("\t\t");
  1356. switch(Constants.TYPE_OF_OPERANDS[opcode][i]) {
  1357. case Constants.T_BYTE: buf.append(bytes.readByte()); break;
  1358. case Constants.T_SHORT: buf.append(bytes.readShort()); break;
  1359. case Constants.T_INT: buf.append(bytes.readInt()); break;
  1360. default: // Never reached
  1361. System.err.println("Unreachable default case reached!");
  1362. System.exit(-1);
  1363. }
  1364. }
  1365. }
  1366. }
  1367. return buf.toString();
  1368. }
  1369. // private helpers
  1370. private static final int pow2(int n) {
  1371. return 1 << n;
  1372. }
  1373. }