1. package com.sun.org.apache.bcel.internal.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 com.sun.org.apache.bcel.internal.Constants;
  56. import java.io.*;
  57. /**
  58. * This class represents the constant pool, i.e., a table of constants.
  59. * It may contain null references, due to the JVM specification that skips
  60. * an entry after an 8-byte constant (double, long) entry.
  61. *
  62. * @version $Id: ConstantPool.java,v 1.1.1.1 2001/10/29 19:59:59 jvanzyl Exp $
  63. * @see Constant
  64. * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A>
  65. */
  66. public class ConstantPool implements Cloneable, Node {
  67. private int constant_pool_count;
  68. private Constant[] constant_pool;
  69. /**
  70. * @param constant_pool Array of constants
  71. */
  72. public ConstantPool(Constant[] constant_pool)
  73. {
  74. setConstantPool(constant_pool);
  75. }
  76. /**
  77. * Read constants from given file stream.
  78. *
  79. * @param file Input stream
  80. * @throw IOException
  81. * @throw ClassFormatError
  82. */
  83. ConstantPool(DataInputStream file) throws IOException, ClassFormatError
  84. {
  85. byte tag;
  86. constant_pool_count = file.readUnsignedShort();
  87. constant_pool = new Constant[constant_pool_count];
  88. /* constant_pool[0] is unused by the compiler and may be used freely
  89. * by the implementation.
  90. */
  91. for(int i=1; i < constant_pool_count; i++) {
  92. constant_pool[i] = Constant.readConstant(file);
  93. /* Quote from the JVM specification:
  94. * "All eight byte constants take up two spots in the constant pool.
  95. * If this is the n'th byte in the constant pool, then the next item
  96. * will be numbered n+2"
  97. *
  98. * Thus we have to increment the index counter.
  99. */
  100. tag = constant_pool[i].getTag();
  101. if((tag == Constants.CONSTANT_Double) || (tag == Constants.CONSTANT_Long))
  102. i++;
  103. }
  104. }
  105. /**
  106. * Called by objects that are traversing the nodes of the tree implicitely
  107. * defined by the contents of a Java class. I.e., the hierarchy of methods,
  108. * fields, attributes, etc. spawns a tree of objects.
  109. *
  110. * @param v Visitor object
  111. */
  112. public void accept(Visitor v) {
  113. v.visitConstantPool(this);
  114. }
  115. /**
  116. * Resolve constant to a string representation.
  117. *
  118. * @param constant Constant to be printed
  119. * @return String representation
  120. */
  121. public String constantToString(Constant c)
  122. throws ClassFormatError
  123. {
  124. String str;
  125. int i;
  126. byte tag = c.getTag();
  127. switch(tag) {
  128. case Constants.CONSTANT_Class:
  129. i = ((ConstantClass)c).getNameIndex();
  130. c = getConstant(i, Constants.CONSTANT_Utf8);
  131. str = Utility.compactClassName(((ConstantUtf8)c).getBytes(), false);
  132. break;
  133. case Constants.CONSTANT_String:
  134. i = ((ConstantString)c).getStringIndex();
  135. c = getConstant(i, Constants.CONSTANT_Utf8);
  136. str = "\"" + escape(((ConstantUtf8)c).getBytes()) + "\"";
  137. break;
  138. case Constants.CONSTANT_Utf8: str = ((ConstantUtf8)c).getBytes(); break;
  139. case Constants.CONSTANT_Double: str = "" + ((ConstantDouble)c).getBytes(); break;
  140. case Constants.CONSTANT_Float: str = "" + ((ConstantFloat)c).getBytes(); break;
  141. case Constants.CONSTANT_Long: str = "" + ((ConstantLong)c).getBytes(); break;
  142. case Constants.CONSTANT_Integer: str = "" + ((ConstantInteger)c).getBytes(); break;
  143. case Constants.CONSTANT_NameAndType:
  144. str = (constantToString(((ConstantNameAndType)c).getNameIndex(),
  145. Constants.CONSTANT_Utf8) + " " +
  146. constantToString(((ConstantNameAndType)c).getSignatureIndex(),
  147. Constants.CONSTANT_Utf8));
  148. break;
  149. case Constants.CONSTANT_InterfaceMethodref: case Constants.CONSTANT_Methodref:
  150. case Constants.CONSTANT_Fieldref:
  151. str = (constantToString(((ConstantCP)c).getClassIndex(),
  152. Constants.CONSTANT_Class) + "." +
  153. constantToString(((ConstantCP)c).getNameAndTypeIndex(),
  154. Constants.CONSTANT_NameAndType));
  155. break;
  156. default: // Never reached
  157. throw new RuntimeException("Unknown constant type " + tag);
  158. }
  159. return str;
  160. }
  161. private static final String escape(String str) {
  162. int len = str.length();
  163. StringBuffer buf = new StringBuffer(len + 5);
  164. char[] ch = str.toCharArray();
  165. for(int i=0; i < len; i++) {
  166. switch(ch[i]) {
  167. case '\n' : buf.append("\\n"); break;
  168. case '\r' : buf.append("\\r"); break;
  169. case '\t' : buf.append("\\t"); break;
  170. case '\b' : buf.append("\\b"); break;
  171. case '"' : buf.append("\\\""); break;
  172. default: buf.append(ch[i]);
  173. }
  174. }
  175. return buf.toString();
  176. }
  177. /**
  178. * Retrieve constant at `index' from constant pool and resolve it to
  179. * a string representation.
  180. *
  181. * @param index of constant in constant pool
  182. * @param tag expected type
  183. * @return String representation
  184. */
  185. public String constantToString(int index, byte tag)
  186. throws ClassFormatError
  187. {
  188. Constant c = getConstant(index, tag);
  189. return constantToString(c);
  190. }
  191. /**
  192. * Dump constant pool to file stream in binary format.
  193. *
  194. * @param file Output file stream
  195. * @throw IOException
  196. */
  197. public void dump(DataOutputStream file) throws IOException
  198. {
  199. file.writeShort(constant_pool_count);
  200. for(int i=1; i < constant_pool_count; i++)
  201. if(constant_pool[i] != null)
  202. constant_pool[i].dump(file);
  203. }
  204. /**
  205. * Get constant from constant pool.
  206. *
  207. * @param index Index in constant pool
  208. * @return Constant value
  209. * @see Constant
  210. */
  211. public Constant getConstant(int index) {
  212. if (index >= constant_pool.length || index < 0)
  213. throw new ClassFormatError("Invalid constant pool reference: " +
  214. index + ". Constant pool size is: " +
  215. constant_pool.length);
  216. return constant_pool[index];
  217. }
  218. /**
  219. * Get constant from constant pool and check whether it has the
  220. * expected type.
  221. *
  222. * @param index Index in constant pool
  223. * @param tag Tag of expected constant, i.e., its type
  224. * @return Constant value
  225. * @see Constant
  226. * @throw ClassFormatError
  227. */
  228. public Constant getConstant(int index, byte tag)
  229. throws ClassFormatError
  230. {
  231. Constant c;
  232. c = getConstant(index);
  233. if(c == null)
  234. throw new ClassFormatError("Constant pool at index " + index + " is null.");
  235. if(c.getTag() == tag)
  236. return c;
  237. else
  238. throw new ClassFormatError("Expected class `" + Constants.CONSTANT_NAMES[tag] +
  239. "' at index " + index + " and got " + c);
  240. }
  241. /**
  242. * @return Array of constants.
  243. * @see Constant
  244. */
  245. public Constant[] getConstantPool() { return constant_pool; }
  246. /**
  247. * Get string from constant pool and bypass the indirection of
  248. * `ConstantClass' and `ConstantString' objects. I.e. these classes have
  249. * an index field that points to another entry of the constant pool of
  250. * type `ConstantUtf8' which contains the real data.
  251. *
  252. * @param index Index in constant pool
  253. * @param tag Tag of expected constant, either ConstantClass or ConstantString
  254. * @return Contents of string reference
  255. * @see ConstantClass
  256. * @see ConstantString
  257. * @throw ClassFormatError
  258. */
  259. public String getConstantString(int index, byte tag)
  260. throws ClassFormatError
  261. {
  262. Constant c;
  263. int i;
  264. String s;
  265. c = getConstant(index, tag);
  266. /* This switch() is not that elegant, since the two classes have the
  267. * same contents, they just differ in the name of the index
  268. * field variable.
  269. * But we want to stick to the JVM naming conventions closely though
  270. * we could have solved these more elegantly by using the same
  271. * variable name or by subclassing.
  272. */
  273. switch(tag) {
  274. case Constants.CONSTANT_Class: i = ((ConstantClass)c).getNameIndex(); break;
  275. case Constants.CONSTANT_String: i = ((ConstantString)c).getStringIndex(); break;
  276. default:
  277. throw new RuntimeException("getConstantString called with illegal tag " + tag);
  278. }
  279. // Finally get the string from the constant pool
  280. c = getConstant(i, Constants.CONSTANT_Utf8);
  281. return ((ConstantUtf8)c).getBytes();
  282. }
  283. /**
  284. * @return Length of constant pool.
  285. */
  286. public int getLength()
  287. {
  288. return constant_pool_count;
  289. }
  290. /**
  291. * @param constant Constant to set
  292. */
  293. public void setConstant(int index, Constant constant) {
  294. constant_pool[index] = constant;
  295. }
  296. /**
  297. * @param constant_pool
  298. */
  299. public void setConstantPool(Constant[] constant_pool) {
  300. this.constant_pool = constant_pool;
  301. constant_pool_count = (constant_pool == null)? 0 : constant_pool.length;
  302. }
  303. /**
  304. * @return String representation.
  305. */
  306. public String toString() {
  307. StringBuffer buf = new StringBuffer();
  308. for(int i=1; i < constant_pool_count; i++)
  309. buf.append(i + ")" + constant_pool[i] + "\n");
  310. return buf.toString();
  311. }
  312. /**
  313. * @return deep copy of this constant pool
  314. */
  315. public ConstantPool copy() {
  316. ConstantPool c = null;
  317. try {
  318. c = (ConstantPool)clone();
  319. } catch(CloneNotSupportedException e) {}
  320. c.constant_pool = new Constant[constant_pool_count];
  321. for(int i=1; i < constant_pool_count; i++) {
  322. if(constant_pool[i] != null)
  323. c.constant_pool[i] = constant_pool[i].copy();
  324. }
  325. return c;
  326. }
  327. }