001package com.hfg.util; 002 003 004import java.io.DataInputStream; 005import java.io.File; 006import java.io.IOException; 007import java.util.ArrayList; 008import java.util.List; 009 010//------------------------------------------------------------------------------ 011/** 012 Currently this is just a simple helper class used by ClassExplorer to extract 013 information from Java class files about the superclass and interfaces implemented. 014 <div> 015 @author J. Alex Taylor, hairyfatguy.com 016 </div> 017 */ 018//------------------------------------------------------------------------------ 019// com.hfg XML/HTML Coding Library 020// 021// This library is free software; you can redistribute it and/or 022// modify it under the terms of the GNU Lesser General Public 023// License as published by the Free Software Foundation; either 024// version 2.1 of the License, or (at your option) any later version. 025// 026// This library is distributed in the hope that it will be useful, 027// but WITHOUT ANY WARRANTY; without even the implied warranty of 028// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 029// Lesser General Public License for more details. 030// 031// You should have received a copy of the GNU Lesser General Public 032// License along with this library; if not, write to the Free Software 033// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 034// 035// J. Alex Taylor, President, Founder, CEO, COO, CFO, OOPS hairyfatguy.com 036// jataylor@hairyfatguy.com 037//------------------------------------------------------------------------------ 038// See: https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html 039 040public class BasicClassFileInfo 041{ 042 private int mMajorVersion; 043 private int mMinorVersion; 044 private int mConstantPoolCount; 045 private int mInterfacesCount; 046 047 private String mClassname; 048 private String mSuperclassname; 049 private String[] mInterfaces; 050 051 // Constant Pool tag values 052 private enum ConstantPoolTag 053 { 054 CONSTANT_Utf8(1), 055 CONSTANT_Integer(3), 056 CONSTANT_Float(4), 057 CONSTANT_Long(5), 058 CONSTANT_Double(6), 059 CONSTANT_Class(7), 060 CONSTANT_String(8), 061 CONSTANT_Fieldref(9), 062 CONSTANT_Methodref(10), 063 CONSTANT_InterfaceMethodref(11), 064 CONSTANT_NameAndType(12), 065 CONSTANT_MethodHandle(15), 066 CONSTANT_MethodType(16), 067 CONSTANT_InvokeDynamic(18); 068 069 private int mValue; 070 071 private ConstantPoolTag(int inValue) 072 { 073 mValue = inValue; 074 } 075 076 public int getValue() 077 { 078 return mValue; 079 } 080 081 public static ConstantPoolTag valueOf(int inValue) 082 { 083 ConstantPoolTag tag = null; 084 for (ConstantPoolTag poolTag : values()) 085 { 086 if (poolTag.getValue() == inValue) 087 { 088 tag = poolTag; 089 break; 090 } 091 } 092 093 return tag; 094 } 095 } 096 097 098 //-------------------------------------------------------------------------- 099 public BasicClassFileInfo(DataInputStream inStream) 100 throws IOException 101 { 102 int magic = inStream.readInt(); 103 if (magic != 0xCAFEBABE) 104 { 105 throw new IOException("Bad magic number: " + Integer.toHexString(magic)); 106 } 107 108 mMinorVersion = inStream.readUnsignedShort(); 109 mMajorVersion = inStream.readUnsignedShort(); 110 mConstantPoolCount = inStream.readUnsignedShort(); 111 112 List<ConstantPoolEntry> entries = new ArrayList<>(mConstantPoolCount); 113 114 for (int idx = 1; idx < mConstantPoolCount; idx++) 115 { 116 ConstantPoolTag tag = ConstantPoolTag.valueOf(inStream.readUnsignedByte()); 117 118 switch (tag) 119 { 120 case CONSTANT_Utf8: 121 entries.add(new Utf8Entry(inStream)); 122 break; 123 case CONSTANT_Integer: 124 entries.add(new IntegerEntry(inStream)); 125 break; 126 case CONSTANT_Float: 127 entries.add(new FloatEntry(inStream)); 128 break; 129 case CONSTANT_Long: 130 entries.add(new LongEntry(inStream)); 131 break; 132 case CONSTANT_Double: 133 entries.add(new DoubleEntry(inStream)); 134 break; 135 case CONSTANT_Class: 136 entries.add(new ClassEntry(inStream)); 137 break; 138 case CONSTANT_String: 139 entries.add(new StringEntry(inStream)); 140 break; 141 case CONSTANT_Fieldref: 142 entries.add(new FieldrefEntry(inStream)); 143 break; 144 case CONSTANT_Methodref: 145 entries.add(new MethodrefEntry(inStream)); 146 break; 147 case CONSTANT_InterfaceMethodref: 148 entries.add(new InterfaceMethodrefEntry(inStream)); 149 break; 150 case CONSTANT_NameAndType: 151 entries.add(new NameAndTypeEntry(inStream)); 152 break; 153 case CONSTANT_MethodHandle: 154 entries.add(new MethodHandleEntry(inStream)); 155 break; 156 case CONSTANT_MethodType: 157 entries.add(new MethodTypeEntry(inStream)); 158 break; 159 case CONSTANT_InvokeDynamic: 160 entries.add(new InvokeDynamicEntry(inStream)); 161 break; 162 163 } 164 } 165 166 // Access flags 167 inStream.readUnsignedShort(); 168 169 // Class name 170 int classIdx = inStream.readUnsignedShort(); 171 ClassEntry classEntry = (ClassEntry) entries.get(classIdx - 1); 172 mClassname = ((Utf8Entry) entries.get(classEntry.getNameIndex() - 1)).getString().replace(File.separator, "."); 173 174 // Super class 175 int superclassIdx = inStream.readUnsignedShort(); 176 ClassEntry superclassEntry = (ClassEntry) entries.get(superclassIdx - 1); 177 mSuperclassname = ((Utf8Entry) entries.get(superclassEntry.getNameIndex() - 1)).getString().replace(File.separator, "."); 178 179 mInterfacesCount = inStream.readUnsignedShort(); 180 if (mInterfacesCount > 0) 181 { 182 mInterfaces = new String[mInterfacesCount]; 183 for (int i = 0; i < mInterfacesCount; i++) 184 { 185 int index = inStream.readUnsignedShort(); 186 ClassEntry interfaceEntry = (ClassEntry) entries.get(index - 1); 187 mInterfaces[i] = ((Utf8Entry) entries.get(interfaceEntry.getNameIndex() - 1)).getString().replace(File.separator, "."); 188 } 189 } 190 } 191 192 //-------------------------------------------------------------------------- 193 public String getClassname() 194 { 195 return mClassname; 196 } 197 198 //-------------------------------------------------------------------------- 199 public String getSuperClassname() 200 { 201 return mSuperclassname; 202 } 203 204 //-------------------------------------------------------------------------- 205 public String[] getInterfaceClassnames() 206 { 207 return mInterfaces; 208 } 209 210 211 212 abstract class ConstantPoolEntry 213 { 214 215 } 216 217 private class Utf8Entry extends ConstantPoolEntry 218 { 219 private String mString; 220 221 //----------------------------------------------------------------------- 222 public Utf8Entry(DataInputStream inStream) 223 throws IOException 224 { 225 mString = inStream.readUTF(); 226 } 227 228 //----------------------------------------------------------------------- 229 public String getString() 230 { 231 return mString; 232 } 233 } 234 235 private class IntegerEntry extends ConstantPoolEntry 236 { 237 private int mValue; 238 239 //----------------------------------------------------------------------- 240 public IntegerEntry(DataInputStream inStream) 241 throws IOException 242 { 243 mValue = inStream.readInt(); 244 } 245 246 //----------------------------------------------------------------------- 247 public int getValue() 248 { 249 return mValue; 250 } 251 } 252 253 private class FloatEntry extends ConstantPoolEntry 254 { 255 private float mValue; 256 257 //----------------------------------------------------------------------- 258 public FloatEntry(DataInputStream inStream) 259 throws IOException 260 { 261 mValue = inStream.readFloat(); 262 } 263 264 //----------------------------------------------------------------------- 265 public float getValue() 266 { 267 return mValue; 268 } 269 } 270 271 private class LongEntry extends ConstantPoolEntry 272 { 273 private long mValue; 274 275 //----------------------------------------------------------------------- 276 public LongEntry(DataInputStream inStream) 277 throws IOException 278 { 279 mValue = inStream.readLong(); 280 } 281 282 //----------------------------------------------------------------------- 283 public long getValue() 284 { 285 return mValue; 286 } 287 } 288 289 private class DoubleEntry extends ConstantPoolEntry 290 { 291 private double mValue; 292 293 //----------------------------------------------------------------------- 294 public DoubleEntry(DataInputStream inStream) 295 throws IOException 296 { 297 mValue = inStream.readDouble(); 298 } 299 300 //----------------------------------------------------------------------- 301 public double getValue() 302 { 303 return mValue; 304 } 305 } 306 307 private class StringEntry extends ConstantPoolEntry 308 { 309 private int mIndex; 310 311 //----------------------------------------------------------------------- 312 public StringEntry(DataInputStream inStream) 313 throws IOException 314 { 315 mIndex = inStream.readUnsignedShort(); 316 } 317 318 //----------------------------------------------------------------------- 319 public int getIndex() 320 { 321 return mIndex; 322 } 323 } 324 325 private class ClassEntry extends ConstantPoolEntry 326 { 327 private int mNameIndex; 328 329 //----------------------------------------------------------------------- 330 public ClassEntry(DataInputStream inStream) 331 throws IOException 332 { 333 mNameIndex = inStream.readUnsignedShort(); 334 } 335 336 //----------------------------------------------------------------------- 337 public int getNameIndex() 338 { 339 return mNameIndex; 340 } 341 } 342 343 private class NameAndTypeEntry extends ConstantPoolEntry 344 { 345 private int mMemberNameIndex; 346 private int mTypeDescriptorIndex; 347 348 //----------------------------------------------------------------------- 349 public NameAndTypeEntry(DataInputStream inStream) 350 throws IOException 351 { 352 mMemberNameIndex = inStream.readUnsignedShort(); 353 mTypeDescriptorIndex = inStream.readUnsignedShort(); 354 } 355 356 //----------------------------------------------------------------------- 357 public int getMemberNameIndex() 358 { 359 return mMemberNameIndex; 360 } 361 362 //----------------------------------------------------------------------- 363 public int getTypeDescriptorIndex() 364 { 365 return mTypeDescriptorIndex; 366 } 367 } 368 369 private class InterfaceMethodrefEntry extends ConstantPoolEntry 370 { 371 private int mClassIndex; 372 private int mNameAndTypeIndex; 373 374 //----------------------------------------------------------------------- 375 public InterfaceMethodrefEntry(DataInputStream inStream) 376 throws IOException 377 { 378 mClassIndex = inStream.readUnsignedShort(); 379 mNameAndTypeIndex = inStream.readUnsignedShort(); 380 } 381 382 //----------------------------------------------------------------------- 383 public int getClassIndex() 384 { 385 return mClassIndex; 386 } 387 388 //----------------------------------------------------------------------- 389 public int getNameAndTypeIndex() 390 { 391 return mNameAndTypeIndex; 392 } 393 } 394 395 private class MethodrefEntry extends ConstantPoolEntry 396 { 397 private int mClassIndex; 398 private int mNameAndTypeIndex; 399 400 //----------------------------------------------------------------------- 401 public MethodrefEntry(DataInputStream inStream) 402 throws IOException 403 { 404 mClassIndex = inStream.readUnsignedShort(); 405 mNameAndTypeIndex = inStream.readUnsignedShort(); 406 } 407 408 //----------------------------------------------------------------------- 409 public int getClassIndex() 410 { 411 return mClassIndex; 412 } 413 414 //----------------------------------------------------------------------- 415 public int getNameAndTypeIndex() 416 { 417 return mNameAndTypeIndex; 418 } 419 } 420 421 private class FieldrefEntry extends ConstantPoolEntry 422 { 423 private int mClassIndex; 424 private int mNameAndTypeIndex; 425 426 //----------------------------------------------------------------------- 427 public FieldrefEntry(DataInputStream inStream) 428 throws IOException 429 { 430 mClassIndex = inStream.readUnsignedShort(); 431 mNameAndTypeIndex = inStream.readUnsignedShort(); 432 } 433 434 //----------------------------------------------------------------------- 435 public int getClassIndex() 436 { 437 return mClassIndex; 438 } 439 440 //----------------------------------------------------------------------- 441 public int getNameAndTypeIndex() 442 { 443 return mNameAndTypeIndex; 444 } 445 } 446 447 private class MethodHandleEntry extends ConstantPoolEntry 448 { 449 private int mKind; 450 private int mIndex; 451 452 //----------------------------------------------------------------------- 453 public MethodHandleEntry(DataInputStream inStream) 454 throws IOException 455 { 456 mKind = inStream.readUnsignedByte(); 457 mIndex = inStream.readUnsignedShort(); 458 } 459 460 //----------------------------------------------------------------------- 461 public int getKind() 462 { 463 return mKind; 464 } 465 466 //----------------------------------------------------------------------- 467 public int getIndex() 468 { 469 return mIndex; 470 } 471 } 472 473 private class MethodTypeEntry extends ConstantPoolEntry 474 { 475 private int mDescriptorIndex; 476 477 //----------------------------------------------------------------------- 478 public MethodTypeEntry(DataInputStream inStream) 479 throws IOException 480 { 481 mDescriptorIndex = inStream.readUnsignedShort(); 482 } 483 484 //----------------------------------------------------------------------- 485 public int getDescriptorIndex() 486 { 487 return mDescriptorIndex; 488 } 489 } 490 491 private class InvokeDynamicEntry extends ConstantPoolEntry 492 { 493 private int mBootstrapMethodAttrIndex; 494 private int mNameAndTypeIndex; 495 496 //----------------------------------------------------------------------- 497 public InvokeDynamicEntry(DataInputStream inStream) 498 throws IOException 499 { 500 mBootstrapMethodAttrIndex = inStream.readUnsignedShort(); 501 mNameAndTypeIndex = inStream.readUnsignedShort(); 502 } 503 504 //----------------------------------------------------------------------- 505 public int getBootstrapMethodAttrIndex() 506 { 507 return mBootstrapMethodAttrIndex; 508 } 509 510 //----------------------------------------------------------------------- 511 public int getNameAndTypeIndex() 512 { 513 return mNameAndTypeIndex; 514 } 515 } 516}