1 19 20 package edu.umd.cs.findbugs.classfile.engine; 21 22 import java.io.DataInputStream ; 23 import java.io.IOException ; 24 import java.util.TreeSet ; 25 26 import edu.umd.cs.findbugs.classfile.ClassDescriptor; 27 import edu.umd.cs.findbugs.classfile.FieldDescriptor; 28 import edu.umd.cs.findbugs.classfile.IClassConstants; 29 import edu.umd.cs.findbugs.classfile.ICodeBaseEntry; 30 import edu.umd.cs.findbugs.classfile.InvalidClassFileFormatException; 31 import edu.umd.cs.findbugs.classfile.MethodDescriptor; 32 import edu.umd.cs.findbugs.classfile.analysis.ClassInfo; 33 import edu.umd.cs.findbugs.classfile.analysis.ClassNameAndSuperclassInfo; 34 import edu.umd.cs.findbugs.util.ClassName; 35 36 43 public class ClassParser { 44 45 static class Constant { 46 int tag; 47 Object [] data; 48 49 Constant(int tag, Object [] data) { 50 this.tag = tag; 51 this.data = data; 52 } 53 } 54 55 private DataInputStream in; 56 private ClassDescriptor expectedClassDescriptor; 57 private ICodeBaseEntry codeBaseEntry; 58 private Constant[] constantPool; 59 60 67 public ClassParser( 68 DataInputStream in, 69 ClassDescriptor expectedClassDescriptor, 70 ICodeBaseEntry codeBaseEntry) { 71 this.in = in; 72 this.expectedClassDescriptor = expectedClassDescriptor; 73 this.codeBaseEntry = codeBaseEntry; 74 } 75 76 84 public void parse(ClassNameAndSuperclassInfo classInfo) throws InvalidClassFileFormatException { 85 try { 86 int magic = in.readInt(); 87 int major_version = in.readUnsignedShort(); 88 int minor_version = in.readUnsignedShort(); 89 int constant_pool_count = in.readUnsignedShort(); 90 91 constantPool = new Constant[constant_pool_count]; 92 for (int i = 1; i < constantPool.length; i++) { 93 constantPool[i] = readConstant(); 94 if (constantPool[i].tag == IClassConstants.CONSTANT_Double || 95 constantPool[i].tag == IClassConstants.CONSTANT_Long) { 96 ++i; 98 } 99 } 100 101 int access_flags = in.readUnsignedShort(); 102 103 int this_class = in.readUnsignedShort(); 104 ClassDescriptor thisClassDescriptor = 105 getClassDescriptor(this_class); 106 107 int super_class = in.readUnsignedShort(); 108 ClassDescriptor superClassDescriptor = 109 getClassDescriptor(super_class); 110 111 int interfaces_count = in.readUnsignedShort(); 112 if (interfaces_count < 0) { 113 throw new InvalidClassFileFormatException(expectedClassDescriptor, codeBaseEntry); 114 } 115 ClassDescriptor[] interfaceDescriptorList = new ClassDescriptor[interfaces_count]; 116 for (int i = 0; i < interfaceDescriptorList.length; i++) { 117 interfaceDescriptorList[i] = getClassDescriptor(in.readUnsignedShort()); 118 } 119 120 classInfo.setClassDescriptor(thisClassDescriptor); 121 classInfo.setSuperclassDescriptor(superClassDescriptor); 122 classInfo.setInterfaceDescriptorList(interfaceDescriptorList); 123 classInfo.setCodeBaseEntry(codeBaseEntry); 124 classInfo.setAccessFlags(access_flags); 125 } catch (IOException e) { 126 throw new InvalidClassFileFormatException(expectedClassDescriptor, codeBaseEntry, e); 127 } 128 } 129 130 138 public void parse(ClassInfo classInfo) throws InvalidClassFileFormatException { 139 parse((ClassNameAndSuperclassInfo) classInfo); 140 141 try { 142 int fields_count = in.readUnsignedShort(); 143 if (fields_count < 0 ) { 144 throw new InvalidClassFileFormatException(expectedClassDescriptor, codeBaseEntry); 145 } 146 FieldDescriptor[] fieldDescriptorList = new FieldDescriptor[fields_count]; 147 for (int i = 0; i < fields_count; i++) { 148 fieldDescriptorList[i] = readField(classInfo.getClassDescriptor()); 149 } 150 151 int methods_count = in.readUnsignedShort(); 152 if (methods_count < 0) { 153 throw new InvalidClassFileFormatException(expectedClassDescriptor, codeBaseEntry); 154 } 155 MethodDescriptor[] methodDescriptorList = new MethodDescriptor[methods_count]; 156 for (int i = 0; i < methods_count; i++) { 157 methodDescriptorList[i] = readMethod(classInfo.getClassDescriptor()); 158 } 159 160 ClassDescriptor[] referencedClassDescriptorList = extractReferencedClasses(); 164 165 classInfo.setFieldDescriptorList(fieldDescriptorList); 166 classInfo.setMethodDescriptorList(methodDescriptorList); 167 classInfo.setReferencedClassDescriptorList(referencedClassDescriptorList); 168 } catch (IOException e) { 169 throw new InvalidClassFileFormatException(expectedClassDescriptor, codeBaseEntry, e); 170 } 171 172 } 173 174 180 private ClassDescriptor[] extractReferencedClasses() throws InvalidClassFileFormatException { 181 TreeSet <ClassDescriptor> referencedClassSet = new TreeSet <ClassDescriptor>(); 182 for (Constant constant : constantPool) { 183 if (constant == null) { 184 continue; 185 } 186 if (constant.tag == IClassConstants.CONSTANT_Class) { 187 String className = getUtf8String((Integer )constant.data[0]); 188 if (className.indexOf('[') >= 0) { 189 extractReferencedClassesFromSignature(referencedClassSet, className); 190 } else if (ClassName.isValidClassName(className)) { 191 referencedClassSet.add(new ClassDescriptor(className)); 192 } 193 } else if (constant.tag == IClassConstants.CONSTANT_Methodref 194 || constant.tag == IClassConstants.CONSTANT_Fieldref 195 || constant.tag == IClassConstants.CONSTANT_InterfaceMethodref) { 196 String className = getClassName((Integer ) constant.data[0]); 198 extractReferencedClassesFromSignature(referencedClassSet, className); 199 200 String signature = getSignatureFromNameAndType((Integer )constant.data[1]); 202 extractReferencedClassesFromSignature(referencedClassSet, signature); 203 } 204 } 205 ClassDescriptor[] referencedClassDescriptorList = 206 referencedClassSet.toArray(new ClassDescriptor[referencedClassSet.size()]); 207 return referencedClassDescriptorList; 208 } 209 210 214 private void extractReferencedClassesFromSignature(TreeSet <ClassDescriptor> referencedClassSet, String signature) { 215 while (signature.length() > 0) { 216 int start = signature.indexOf('L'); 217 if (start < 0) { 218 break; 219 } 220 signature = signature.substring(start); 221 int end = signature.indexOf(';'); 222 if (end < 0) { 223 break; 224 } 225 String className = signature.substring(1, end); 226 if (ClassName.isValidClassName(className)) { 227 referencedClassSet.add(new ClassDescriptor(className)); 228 } 229 signature = signature.substring(end + 1); 230 } 231 } 232 233 private static final String [] CONSTANT_FORMAT_MAP = { 240 null, 241 "8", null, 243 "I", "F", "L", "D", "i", "i", "ii", "ii", "ii", "ii", }; 254 255 262 private Constant readConstant() 263 throws InvalidClassFileFormatException, IOException { 264 int tag = in.readUnsignedByte(); 265 if (tag < 0 || tag >= CONSTANT_FORMAT_MAP.length || CONSTANT_FORMAT_MAP[tag] == null) { 266 throw new InvalidClassFileFormatException(expectedClassDescriptor, codeBaseEntry); 267 } 268 String format = CONSTANT_FORMAT_MAP[tag]; 269 Object [] data = new Object [format.length()]; 270 for (int i = 0; i < format.length(); i++) { 271 char spec = format.charAt(i); 272 switch (spec) { 273 case '8': 274 data[i] = in.readUTF(); 275 break; 276 case 'I': 277 data[i] = (Integer )in.readInt(); 278 break; 279 case 'F': 280 data[i] = new Float (in.readFloat()); 281 break; 282 case 'L': 283 data[i] = (Long )in.readLong(); 284 break; 285 case 'D': 286 data[i] = new Double (in.readDouble()); 287 break; 288 case 'i': 289 data[i] = (Integer )in.readUnsignedShort(); 290 break; 291 default: throw new IllegalStateException (); 292 } 293 } 294 295 return new Constant(tag, data); 296 } 297 298 306 private String getClassName(int index) throws InvalidClassFileFormatException { 307 if (index == 0) { 308 return null; 309 } 310 311 checkConstantPoolIndex(index); 312 Constant constant = constantPool[index]; 313 checkConstantTag(constant, IClassConstants.CONSTANT_Class); 314 315 int refIndex = ((Integer )constant.data[0]).intValue(); 316 String stringValue = getUtf8String(refIndex); 317 318 return stringValue; 319 } 320 321 328 private ClassDescriptor getClassDescriptor(int index) throws InvalidClassFileFormatException { 329 String className = getClassName(index); 330 return className != null ? new ClassDescriptor(className) : null; 331 } 332 333 340 private String getUtf8String(int refIndex) throws InvalidClassFileFormatException { 341 checkConstantPoolIndex(refIndex); 342 Constant refConstant = constantPool[refIndex]; 343 checkConstantTag(refConstant, IClassConstants.CONSTANT_Utf8); 344 return (String ) refConstant.data[0]; 345 } 346 347 355 private void checkConstantPoolIndex(int index) throws InvalidClassFileFormatException { 356 if (index < 0 || index >= constantPool.length || constantPool[index] == null) { 357 throw new InvalidClassFileFormatException(expectedClassDescriptor, codeBaseEntry); 358 } 359 } 360 361 368 private void checkConstantTag(Constant constant, int expectedTag) 369 throws InvalidClassFileFormatException { 370 if (constant.tag != expectedTag) { 371 throw new InvalidClassFileFormatException(expectedClassDescriptor, codeBaseEntry); 372 } 373 } 374 375 interface FieldOrMethodDescriptorCreator<E> { 376 public E create(String className, String name, String signature, int accessFlags); 377 } 378 379 387 private FieldDescriptor readField(ClassDescriptor thisClassDescriptor) 388 throws IOException , InvalidClassFileFormatException { 389 return readFieldOrMethod(thisClassDescriptor, new FieldOrMethodDescriptorCreator<FieldDescriptor>() { 390 393 public FieldDescriptor create(String className, String name, String signature, int accessFlags) { 394 return new FieldDescriptor(className, name, signature, (accessFlags & IClassConstants.ACC_STATIC) != 0); 395 } 396 }); 397 } 398 399 407 private MethodDescriptor readMethod(ClassDescriptor thisClassDescriptor) 408 throws InvalidClassFileFormatException, IOException { 409 return readFieldOrMethod(thisClassDescriptor, new FieldOrMethodDescriptorCreator<MethodDescriptor>(){ 410 413 public MethodDescriptor create(String className, String name, String signature, int accessFlags) { 414 return new MethodDescriptor(className, name, signature, (accessFlags & IClassConstants.ACC_STATIC) != 0); 415 } 416 }); 417 } 418 419 430 private<E> E readFieldOrMethod( 431 ClassDescriptor thisClassDescriptor, FieldOrMethodDescriptorCreator<E> creator) 432 throws IOException , InvalidClassFileFormatException { 433 int access_flags = in.readUnsignedShort(); 434 int name_index = in.readUnsignedShort(); 435 int descriptor_index = in.readUnsignedShort(); 436 int attributes_count = in.readUnsignedShort(); 437 438 String name = getUtf8String(name_index); 439 String signature = getUtf8String(descriptor_index); 440 if (attributes_count < 0) { 441 throw new InvalidClassFileFormatException(expectedClassDescriptor, codeBaseEntry); 442 } 443 for (int i = 0; i < attributes_count; i++) { 444 readAttribute(); 445 } 446 447 return creator.create( 448 thisClassDescriptor.getClassName(), name, signature, access_flags); 449 } 450 451 457 private void readAttribute() throws IOException , InvalidClassFileFormatException { 458 int attribute_name_index = in.readUnsignedShort(); 459 int attribute_length = in.readInt(); 460 if (attribute_length < 0) { 461 throw new InvalidClassFileFormatException(expectedClassDescriptor, codeBaseEntry); 462 } 463 byte[] buf = new byte[attribute_length]; 464 in.readFully(buf); 465 } 466 467 474 private String getSignatureFromNameAndType(int index) throws InvalidClassFileFormatException { 475 checkConstantPoolIndex(index); 476 Constant constant = constantPool[index]; 477 checkConstantTag(constant, IClassConstants.CONSTANT_NameAndType); 478 return getUtf8String((Integer ) constant.data[1]); 479 } 480 } 481 | Popular Tags |