3030import java .io .ByteArrayInputStream ;
3131import java .io .DataInputStream ;
3232import java .io .IOException ;
33+ import java .util .ArrayList ;
34+ import java .util .Collections ;
35+ import java .util .List ;
3336
3437/**
3538 * Utilities for quickly processing class files without fully parsing them.
@@ -49,8 +52,11 @@ public final class ClassHeaderMetadata implements FastClassAccessor {
4952 public final int thisClassIndex ;
5053 public final int superClassIndex ;
5154 public final int interfacesCount ;
55+ public final int @ NotNull [] interfaceIndices ;
5256 public final @ NotNull String binaryThisName ;
5357 public final @ Nullable String binarySuperName ;
58+ /** List is unmodifiable */
59+ public final @ NotNull List <@ NotNull String > binaryInterfaceNames ;
5460
5561 /**
5662 * Attempts to parse a class header.
@@ -88,6 +94,9 @@ public ClassHeaderMetadata(byte @NotNull [] bytes) {
8894 this .thisClassIndex = u16 (bytes , cpOff + Offsets .pastCpThisClassU16 );
8995 this .superClassIndex = u16 (bytes , cpOff + Offsets .pastCpSuperClassU16 );
9096 this .interfacesCount = u16 (bytes , cpOff + Offsets .pastCpInterfacesCountU16 );
97+ this .interfaceIndices = new int [this .interfacesCount ];
98+ List <String > interfaceNames = new ArrayList <>(this .interfacesCount );
99+
91100 // Parse this&super names
92101 if (constantPoolEntryTypes [thisClassIndex - 1 ] != ConstantPoolEntryTypes .Class ) {
93102 throw new IllegalArgumentException ("This class index is not a class ref" );
@@ -110,6 +119,25 @@ public ClassHeaderMetadata(byte @NotNull [] bytes) {
110119 }
111120 this .binarySuperName = modifiedUtf8 (bytes , constantPoolEntryOffsets [superNameIndex - 1 ] + 1 );
112121 }
122+
123+ // Parse interface names
124+ for (int i = 0 ; i < this .interfacesCount ; i ++) {
125+ final int interfaceOffset = cpOff + Offsets .pastCpInterfacesList + i * 2 ;
126+ final int interfaceIndex = u16 (bytes , interfaceOffset );
127+ if (constantPoolEntryTypes [interfaceIndex - 1 ] != ConstantPoolEntryTypes .Class ) {
128+ throw new IllegalArgumentException ("Interface " + i + " index is not a class ref" );
129+ }
130+ final int interfaceNameIndex = u16 (bytes , constantPoolEntryOffsets [interfaceIndex - 1 ] + 1 );
131+ if (constantPoolEntryTypes [interfaceNameIndex - 1 ] != ConstantPoolEntryTypes .Utf8 ) {
132+ throw new IllegalArgumentException ("Interface " + i + " index does not point to a UTF8 entry" );
133+ }
134+ final String binaryInterfaceName =
135+ modifiedUtf8 (bytes , constantPoolEntryOffsets [interfaceNameIndex - 1 ] + 1 );
136+
137+ this .interfaceIndices [i ] = interfaceIndex ;
138+ interfaceNames .add (binaryInterfaceName );
139+ }
140+ this .binaryInterfaceNames = Collections .unmodifiableList (interfaceNames );
113141 }
114142
115143 /** Helpers to read big-endian values from class files. */
@@ -189,6 +217,8 @@ private Offsets() {}
189217 public static final int pastCpSuperClassU16 = pastCpThisClassU16 + 2 ;
190218 /** The value of the interfaces_count item gives the number of direct superinterfaces of this class or interface type */
191219 public static final int pastCpInterfacesCountU16 = pastCpSuperClassU16 + 2 ;
220+
221+ public static final int pastCpInterfacesList = pastCpInterfacesCountU16 + 2 ;
192222 }
193223
194224 public enum ConstantPoolEntryTypes {
@@ -354,4 +384,9 @@ public boolean isEnum() {
354384 public @ Nullable String binarySuperName () {
355385 return binarySuperName ;
356386 }
357- }
387+
388+ @ Override
389+ public @ NotNull List <@ NotNull String > binaryInterfaceNames () {
390+ return binaryInterfaceNames ;
391+ }
392+ }
0 commit comments