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}