1. /*
  2. * Copyright 2000-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. *
  16. */
  17. package org.apache.tools.ant.taskdefs.optional.depend.constantpool;
  18. import java.io.DataInputStream;
  19. import java.io.IOException;
  20. import java.util.Enumeration;
  21. import java.util.Hashtable;
  22. import java.util.Vector;
  23. /**
  24. * The constant pool of a Java class. The constant pool is a collection of
  25. * constants used in a Java class file. It stores strings, constant values,
  26. * class names, method names, field names etc.
  27. *
  28. * @see <a href="http://java.sun.com/docs/books/vmspec/">The Java Virtual
  29. * Machine Specification</a>
  30. */
  31. public class ConstantPool {
  32. /** The entries in the constant pool. */
  33. private Vector entries;
  34. /**
  35. * A Hashtable of UTF8 entries - used to get constant pool indexes of
  36. * the UTF8 values quickly
  37. */
  38. private Hashtable utf8Indexes;
  39. /** Initialise the constant pool. */
  40. public ConstantPool() {
  41. entries = new Vector();
  42. // The zero index is never present in the constant pool itself so
  43. // we add a null entry for it
  44. entries.addElement(null);
  45. utf8Indexes = new Hashtable();
  46. }
  47. /**
  48. * Read the constant pool from a class input stream.
  49. *
  50. * @param classStream the DataInputStream of a class file.
  51. * @exception IOException if there is a problem reading the constant pool
  52. * from the stream
  53. */
  54. public void read(DataInputStream classStream) throws IOException {
  55. int numEntries = classStream.readUnsignedShort();
  56. for (int i = 1; i < numEntries;) {
  57. ConstantPoolEntry nextEntry
  58. = ConstantPoolEntry.readEntry(classStream);
  59. i += nextEntry.getNumEntries();
  60. addEntry(nextEntry);
  61. }
  62. }
  63. /**
  64. * Get the size of the constant pool.
  65. *
  66. * @return the size of the constant pool
  67. */
  68. public int size() {
  69. return entries.size();
  70. }
  71. /**
  72. * Add an entry to the constant pool.
  73. *
  74. * @param entry the new entry to be added to the constant pool.
  75. * @return the index into the constant pool at which the entry is
  76. * stored.
  77. */
  78. public int addEntry(ConstantPoolEntry entry) {
  79. int index = entries.size();
  80. entries.addElement(entry);
  81. int numSlots = entry.getNumEntries();
  82. // add null entries for any additional slots required.
  83. for (int j = 0; j < numSlots - 1; ++j) {
  84. entries.addElement(null);
  85. }
  86. if (entry instanceof Utf8CPInfo) {
  87. Utf8CPInfo utf8Info = (Utf8CPInfo) entry;
  88. utf8Indexes.put(utf8Info.getValue(), new Integer(index));
  89. }
  90. return index;
  91. }
  92. /**
  93. * Resolve the entries in the constant pool. Resolution of the constant
  94. * pool involves transforming indexes to other constant pool entries
  95. * into the actual data for that entry.
  96. */
  97. public void resolve() {
  98. for (Enumeration i = entries.elements(); i.hasMoreElements();) {
  99. ConstantPoolEntry poolInfo = (ConstantPoolEntry) i.nextElement();
  100. if (poolInfo != null && !poolInfo.isResolved()) {
  101. poolInfo.resolve(this);
  102. }
  103. }
  104. }
  105. /**
  106. * Get an constant pool entry at a particular index.
  107. *
  108. * @param index the index into the constant pool.
  109. * @return the constant pool entry at that index.
  110. */
  111. public ConstantPoolEntry getEntry(int index) {
  112. return (ConstantPoolEntry) entries.elementAt(index);
  113. }
  114. /**
  115. * Get the index of a given UTF8 constant pool entry.
  116. *
  117. * @param value the string value of the UTF8 entry.
  118. * @return the index at which the given string occurs in the constant
  119. * pool or -1 if the value does not occur.
  120. */
  121. public int getUTF8Entry(String value) {
  122. int index = -1;
  123. Integer indexInteger = (Integer) utf8Indexes.get(value);
  124. if (indexInteger != null) {
  125. index = indexInteger.intValue();
  126. }
  127. return index;
  128. }
  129. /**
  130. * Get the index of a given CONSTANT_CLASS entry in the constant pool.
  131. *
  132. * @param className the name of the class for which the class entry
  133. * index is required.
  134. * @return the index at which the given class entry occurs in the
  135. * constant pool or -1 if the value does not occur.
  136. */
  137. public int getClassEntry(String className) {
  138. int index = -1;
  139. for (int i = 0; i < entries.size() && index == -1; ++i) {
  140. Object element = entries.elementAt(i);
  141. if (element instanceof ClassCPInfo) {
  142. ClassCPInfo classinfo = (ClassCPInfo) element;
  143. if (classinfo.getClassName().equals(className)) {
  144. index = i;
  145. }
  146. }
  147. }
  148. return index;
  149. }
  150. /**
  151. * Get the index of a given constant value entry in the constant pool.
  152. *
  153. * @param constantValue the constant value for which the index is
  154. * required.
  155. * @return the index at which the given value entry occurs in the
  156. * constant pool or -1 if the value does not occur.
  157. */
  158. public int getConstantEntry(Object constantValue) {
  159. int index = -1;
  160. for (int i = 0; i < entries.size() && index == -1; ++i) {
  161. Object element = entries.elementAt(i);
  162. if (element instanceof ConstantCPInfo) {
  163. ConstantCPInfo constantEntry = (ConstantCPInfo) element;
  164. if (constantEntry.getValue().equals(constantValue)) {
  165. index = i;
  166. }
  167. }
  168. }
  169. return index;
  170. }
  171. /**
  172. * Get the index of a given CONSTANT_METHODREF entry in the constant
  173. * pool.
  174. *
  175. * @param methodClassName the name of the class which contains the
  176. * method being referenced.
  177. * @param methodName the name of the method being referenced.
  178. * @param methodType the type descriptor of the method being referenced.
  179. * @return the index at which the given method ref entry occurs in the
  180. * constant pool or -1 if the value does not occur.
  181. */
  182. public int getMethodRefEntry(String methodClassName, String methodName,
  183. String methodType) {
  184. int index = -1;
  185. for (int i = 0; i < entries.size() && index == -1; ++i) {
  186. Object element = entries.elementAt(i);
  187. if (element instanceof MethodRefCPInfo) {
  188. MethodRefCPInfo methodRefEntry = (MethodRefCPInfo) element;
  189. if (methodRefEntry.getMethodClassName().equals(methodClassName)
  190. && methodRefEntry.getMethodName().equals(methodName)
  191. && methodRefEntry.getMethodType().equals(methodType)) {
  192. index = i;
  193. }
  194. }
  195. }
  196. return index;
  197. }
  198. /**
  199. * Get the index of a given CONSTANT_INTERFACEMETHODREF entry in the
  200. * constant pool.
  201. *
  202. * @param interfaceMethodClassName the name of the interface which
  203. * contains the method being referenced.
  204. * @param interfaceMethodName the name of the method being referenced.
  205. * @param interfaceMethodType the type descriptor of the method being
  206. * referenced.
  207. * @return the index at which the given method ref entry occurs in the
  208. * constant pool or -1 if the value does not occur.
  209. */
  210. public int getInterfaceMethodRefEntry(String interfaceMethodClassName,
  211. String interfaceMethodName,
  212. String interfaceMethodType) {
  213. int index = -1;
  214. for (int i = 0; i < entries.size() && index == -1; ++i) {
  215. Object element = entries.elementAt(i);
  216. if (element instanceof InterfaceMethodRefCPInfo) {
  217. InterfaceMethodRefCPInfo interfaceMethodRefEntry
  218. = (InterfaceMethodRefCPInfo) element;
  219. if (interfaceMethodRefEntry.getInterfaceMethodClassName().equals(interfaceMethodClassName)
  220. && interfaceMethodRefEntry.getInterfaceMethodName().equals(interfaceMethodName)
  221. && interfaceMethodRefEntry.getInterfaceMethodType().equals(interfaceMethodType)) {
  222. index = i;
  223. }
  224. }
  225. }
  226. return index;
  227. }
  228. /**
  229. * Get the index of a given CONSTANT_FIELDREF entry in the constant
  230. * pool.
  231. *
  232. * @param fieldClassName the name of the class which contains the field
  233. * being referenced.
  234. * @param fieldName the name of the field being referenced.
  235. * @param fieldType the type descriptor of the field being referenced.
  236. * @return the index at which the given field ref entry occurs in the
  237. * constant pool or -1 if the value does not occur.
  238. */
  239. public int getFieldRefEntry(String fieldClassName, String fieldName,
  240. String fieldType) {
  241. int index = -1;
  242. for (int i = 0; i < entries.size() && index == -1; ++i) {
  243. Object element = entries.elementAt(i);
  244. if (element instanceof FieldRefCPInfo) {
  245. FieldRefCPInfo fieldRefEntry = (FieldRefCPInfo) element;
  246. if (fieldRefEntry.getFieldClassName().equals(fieldClassName)
  247. && fieldRefEntry.getFieldName().equals(fieldName)
  248. && fieldRefEntry.getFieldType().equals(fieldType)) {
  249. index = i;
  250. }
  251. }
  252. }
  253. return index;
  254. }
  255. /**
  256. * Get the index of a given CONSTANT_NAMEANDTYPE entry in the constant
  257. * pool.
  258. *
  259. * @param name the name
  260. * @param type the type
  261. * @return the index at which the given NameAndType entry occurs in the
  262. * constant pool or -1 if the value does not occur.
  263. */
  264. public int getNameAndTypeEntry(String name, String type) {
  265. int index = -1;
  266. for (int i = 0; i < entries.size() && index == -1; ++i) {
  267. Object element = entries.elementAt(i);
  268. if (element instanceof NameAndTypeCPInfo) {
  269. NameAndTypeCPInfo nameAndTypeEntry
  270. = (NameAndTypeCPInfo) element;
  271. if (nameAndTypeEntry.getName().equals(name)
  272. && nameAndTypeEntry.getType().equals(type)) {
  273. index = i;
  274. }
  275. }
  276. }
  277. return index;
  278. }
  279. /**
  280. * Dump the constant pool to a string.
  281. *
  282. * @return the constant pool entries as strings
  283. */
  284. public String toString() {
  285. StringBuffer sb = new StringBuffer("\n");
  286. int size = entries.size();
  287. for (int i = 0; i < size; ++i) {
  288. sb.append("[" + i + "] = " + getEntry(i) + "\n");
  289. }
  290. return sb.toString();
  291. }
  292. }