1/*
2 * ProGuard -- shrinking, optimization, obfuscation, and preverification
3 *             of Java bytecode.
4 *
5 * Copyright (c) 2002-2009 Eric Lafortune (eric@graphics.cornell.edu)
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21package proguard.classfile.io;
22
23import proguard.classfile.*;
24import proguard.classfile.attribute.*;
25import proguard.classfile.attribute.annotation.*;
26import proguard.classfile.attribute.annotation.visitor.*;
27import proguard.classfile.attribute.preverification.*;
28import proguard.classfile.attribute.preverification.visitor.*;
29import proguard.classfile.attribute.visitor.*;
30import proguard.classfile.constant.*;
31import proguard.classfile.constant.visitor.ConstantVisitor;
32import proguard.classfile.util.*;
33import proguard.classfile.visitor.*;
34
35import java.io.DataInput;
36
37/**
38 * This ClassVisitor fills out the ProgramClass objects that it visits with data
39 * from the given DataInput object.
40 *
41 * @author Eric Lafortune
42 */
43public class ProgramClassReader
44extends      SimplifiedVisitor
45implements   ClassVisitor,
46             MemberVisitor,
47             ConstantVisitor,
48             AttributeVisitor,
49             InnerClassesInfoVisitor,
50             ExceptionInfoVisitor,
51             StackMapFrameVisitor,
52             VerificationTypeVisitor,
53             LineNumberInfoVisitor,
54             LocalVariableInfoVisitor,
55             LocalVariableTypeInfoVisitor,
56             AnnotationVisitor,
57             ElementValueVisitor
58{
59    private final RuntimeDataInput dataInput;
60
61
62    /**
63     * Creates a new ProgramClassReader for reading from the given DataInput.
64     */
65    public ProgramClassReader(DataInput dataInput)
66    {
67        this.dataInput = new RuntimeDataInput(dataInput);
68    }
69
70
71    // Implementations for ClassVisitor.
72
73    public void visitProgramClass(ProgramClass programClass)
74    {
75        // Read and check the magic number.
76        programClass.u4magic = dataInput.readInt();
77
78        ClassUtil.checkMagicNumber(programClass.u4magic);
79
80        // Read and check the version numbers.
81        int u2minorVersion = dataInput.readUnsignedShort();
82        int u2majorVersion = dataInput.readUnsignedShort();
83
84        programClass.u4version = ClassUtil.internalClassVersion(u2majorVersion,
85                                                                u2minorVersion);
86
87        ClassUtil.checkVersionNumbers(programClass.u4version);
88
89        // Read the constant pool. Note that the first entry is not used.
90        programClass.u2constantPoolCount = dataInput.readUnsignedShort();
91
92        programClass.constantPool = new Constant[programClass.u2constantPoolCount];
93        for (int index = 1; index < programClass.u2constantPoolCount; index++)
94        {
95            Constant constant = createConstant();
96            constant.accept(programClass, this);
97            programClass.constantPool[index] = constant;
98
99            // Long constants and double constants take up two entries in the
100            // constant pool.
101            int tag = constant.getTag();
102            if (tag == ClassConstants.CONSTANT_Long ||
103                tag == ClassConstants.CONSTANT_Double)
104            {
105                programClass.constantPool[++index] = null;
106            }
107        }
108
109        // Read the general class information.
110        programClass.u2accessFlags = dataInput.readUnsignedShort();
111        programClass.u2thisClass   = dataInput.readUnsignedShort();
112        programClass.u2superClass  = dataInput.readUnsignedShort();
113
114        // Read the interfaces.
115        programClass.u2interfacesCount = dataInput.readUnsignedShort();
116
117        programClass.u2interfaces = new int[programClass.u2interfacesCount];
118        for (int index = 0; index < programClass.u2interfacesCount; index++)
119        {
120            programClass.u2interfaces[index] = dataInput.readUnsignedShort();
121        }
122
123        // Read the fields.
124        programClass.u2fieldsCount = dataInput.readUnsignedShort();
125
126        programClass.fields = new ProgramField[programClass.u2fieldsCount];
127        for (int index = 0; index < programClass.u2fieldsCount; index++)
128        {
129            ProgramField programField = new ProgramField();
130            this.visitProgramField(programClass, programField);
131            programClass.fields[index] = programField;
132        }
133
134        // Read the methods.
135        programClass.u2methodsCount = dataInput.readUnsignedShort();
136
137        programClass.methods = new ProgramMethod[programClass.u2methodsCount];
138        for (int index = 0; index < programClass.u2methodsCount; index++)
139        {
140            ProgramMethod programMethod = new ProgramMethod();
141            this.visitProgramMethod(programClass, programMethod);
142            programClass.methods[index] = programMethod;
143        }
144
145        // Read the class attributes.
146        programClass.u2attributesCount = dataInput.readUnsignedShort();
147
148        programClass.attributes = new Attribute[programClass.u2attributesCount];
149        for (int index = 0; index < programClass.u2attributesCount; index++)
150        {
151            Attribute attribute = createAttribute(programClass);
152            attribute.accept(programClass, this);
153            programClass.attributes[index] = attribute;
154        }
155    }
156
157
158    public void visitLibraryClass(LibraryClass libraryClass)
159    {
160    }
161
162
163    // Implementations for MemberVisitor.
164
165    public void visitProgramField(ProgramClass programClass, ProgramField programField)
166    {
167        // Read the general field information.
168        programField.u2accessFlags     = dataInput.readUnsignedShort();
169        programField.u2nameIndex       = dataInput.readUnsignedShort();
170        programField.u2descriptorIndex = dataInput.readUnsignedShort();
171
172        // Read the field attributes.
173        programField.u2attributesCount = dataInput.readUnsignedShort();
174
175        programField.attributes = new Attribute[programField.u2attributesCount];
176        for (int index = 0; index < programField.u2attributesCount; index++)
177        {
178            Attribute attribute = createAttribute(programClass);
179            attribute.accept(programClass, programField, this);
180            programField.attributes[index] = attribute;
181        }
182    }
183
184
185    public void visitProgramMethod(ProgramClass programClass, ProgramMethod programMethod)
186    {
187        // Read the general method information.
188        programMethod.u2accessFlags     = dataInput.readUnsignedShort();
189        programMethod.u2nameIndex       = dataInput.readUnsignedShort();
190        programMethod.u2descriptorIndex = dataInput.readUnsignedShort();
191
192        // Read the method attributes.
193        programMethod.u2attributesCount = dataInput.readUnsignedShort();
194
195        programMethod.attributes = new Attribute[programMethod.u2attributesCount];
196        for (int index = 0; index < programMethod.u2attributesCount; index++)
197        {
198            Attribute attribute = createAttribute(programClass);
199            attribute.accept(programClass, programMethod, this);
200            programMethod.attributes[index] = attribute;
201        }
202    }
203
204
205    public void visitLibraryMember(LibraryClass libraryClass, LibraryMember libraryMember)
206    {
207    }
208
209
210    // Implementations for ConstantVisitor.
211
212    public void visitIntegerConstant(Clazz clazz, IntegerConstant integerConstant)
213    {
214        integerConstant.u4value = dataInput.readInt();
215    }
216
217
218    public void visitLongConstant(Clazz clazz, LongConstant longConstant)
219    {
220        longConstant.u8value = dataInput.readLong();
221    }
222
223
224    public void visitFloatConstant(Clazz clazz, FloatConstant floatConstant)
225    {
226        floatConstant.f4value = dataInput.readFloat();
227    }
228
229
230    public void visitDoubleConstant(Clazz clazz, DoubleConstant doubleConstant)
231    {
232        doubleConstant.f8value = dataInput.readDouble();
233    }
234
235
236    public void visitStringConstant(Clazz clazz, StringConstant stringConstant)
237    {
238        stringConstant.u2stringIndex = dataInput.readUnsignedShort();
239    }
240
241
242    public void visitUtf8Constant(Clazz clazz, Utf8Constant utf8Constant)
243    {
244        int u2length = dataInput.readUnsignedShort();
245
246        // Read the UTF-8 bytes.
247        byte[] bytes = new byte[u2length];
248        dataInput.readFully(bytes);
249        utf8Constant.setBytes(bytes);
250    }
251
252
253    public void visitAnyRefConstant(Clazz clazz, RefConstant refConstant)
254    {
255        refConstant.u2classIndex       = dataInput.readUnsignedShort();
256        refConstant.u2nameAndTypeIndex = dataInput.readUnsignedShort();
257    }
258
259
260    public void visitClassConstant(Clazz clazz, ClassConstant classConstant)
261    {
262        classConstant.u2nameIndex = dataInput.readUnsignedShort();
263    }
264
265
266    public void visitNameAndTypeConstant(Clazz clazz, NameAndTypeConstant nameAndTypeConstant)
267    {
268        nameAndTypeConstant.u2nameIndex       = dataInput.readUnsignedShort();
269        nameAndTypeConstant.u2descriptorIndex = dataInput.readUnsignedShort();
270    }
271
272
273    // Implementations for AttributeVisitor.
274
275    public void visitUnknownAttribute(Clazz clazz, UnknownAttribute unknownAttribute)
276    {
277        // Read the unknown information.
278        byte[] info = new byte[unknownAttribute.u4attributeLength];
279        dataInput.readFully(info);
280        unknownAttribute.info = info;
281    }
282
283
284    public void visitSourceFileAttribute(Clazz clazz, SourceFileAttribute sourceFileAttribute)
285    {
286        sourceFileAttribute.u2sourceFileIndex = dataInput.readUnsignedShort();
287    }
288
289
290    public void visitSourceDirAttribute(Clazz clazz, SourceDirAttribute sourceDirAttribute)
291    {
292        sourceDirAttribute.u2sourceDirIndex = dataInput.readUnsignedShort();
293    }
294
295
296    public void visitInnerClassesAttribute(Clazz clazz, InnerClassesAttribute innerClassesAttribute)
297    {
298        // Read the inner classes.
299        innerClassesAttribute.u2classesCount = dataInput.readUnsignedShort();
300
301        innerClassesAttribute.classes = new InnerClassesInfo[innerClassesAttribute.u2classesCount];
302        for (int index = 0; index < innerClassesAttribute.u2classesCount; index++)
303        {
304            InnerClassesInfo innerClassesInfo = new InnerClassesInfo();
305            this.visitInnerClassesInfo(clazz, innerClassesInfo);
306            innerClassesAttribute.classes[index] = innerClassesInfo;
307        }
308    }
309
310
311    public void visitEnclosingMethodAttribute(Clazz clazz, EnclosingMethodAttribute enclosingMethodAttribute)
312    {
313        enclosingMethodAttribute.u2classIndex       = dataInput.readUnsignedShort();
314        enclosingMethodAttribute.u2nameAndTypeIndex = dataInput.readUnsignedShort();
315    }
316
317
318    public void visitDeprecatedAttribute(Clazz clazz, DeprecatedAttribute deprecatedAttribute)
319    {
320        // This attribute does not contain any additional information.
321    }
322
323
324    public void visitSyntheticAttribute(Clazz clazz, SyntheticAttribute syntheticAttribute)
325    {
326        // This attribute does not contain any additional information.
327    }
328
329
330    public void visitSignatureAttribute(Clazz clazz, SignatureAttribute signatureAttribute)
331    {
332        signatureAttribute.u2signatureIndex = dataInput.readUnsignedShort();
333    }
334
335
336    public void visitConstantValueAttribute(Clazz clazz, Field field, ConstantValueAttribute constantValueAttribute)
337    {
338        constantValueAttribute.u2constantValueIndex = dataInput.readUnsignedShort();
339    }
340
341
342    public void visitExceptionsAttribute(Clazz clazz, Method method, ExceptionsAttribute exceptionsAttribute)
343    {
344        // Read the exceptions.
345        exceptionsAttribute.u2exceptionIndexTableLength = dataInput.readUnsignedShort();
346
347        exceptionsAttribute.u2exceptionIndexTable = new int[exceptionsAttribute.u2exceptionIndexTableLength];
348        for (int index = 0; index < exceptionsAttribute.u2exceptionIndexTableLength; index++)
349        {
350            exceptionsAttribute.u2exceptionIndexTable[index] = dataInput.readUnsignedShort();
351        }
352    }
353
354
355    public void visitCodeAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute)
356    {
357        // Read the stack size and local variable frame size.
358        codeAttribute.u2maxStack   = dataInput.readUnsignedShort();
359        codeAttribute.u2maxLocals  = dataInput.readUnsignedShort();
360
361        // Read the byte code.
362        codeAttribute.u4codeLength = dataInput.readInt();
363
364        byte[] code = new byte[codeAttribute.u4codeLength];
365        dataInput.readFully(code);
366        codeAttribute.code = code;
367
368        // Read the exceptions.
369        codeAttribute.u2exceptionTableLength = dataInput.readUnsignedShort();
370
371        codeAttribute.exceptionTable = new ExceptionInfo[codeAttribute.u2exceptionTableLength];
372        for (int index = 0; index < codeAttribute.u2exceptionTableLength; index++)
373        {
374            ExceptionInfo exceptionInfo = new ExceptionInfo();
375            this.visitExceptionInfo(clazz, method, codeAttribute, exceptionInfo);
376            codeAttribute.exceptionTable[index] = exceptionInfo;
377        }
378
379        // Read the code attributes.
380        codeAttribute.u2attributesCount = dataInput.readUnsignedShort();
381
382        codeAttribute.attributes = new Attribute[codeAttribute.u2attributesCount];
383        for (int index = 0; index < codeAttribute.u2attributesCount; index++)
384        {
385            Attribute attribute = createAttribute(clazz);
386            attribute.accept(clazz, method, codeAttribute, this);
387            codeAttribute.attributes[index] = attribute;
388        }
389    }
390
391
392    public void visitStackMapAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapAttribute stackMapAttribute)
393    {
394        // Read the stack map frames (only full frames, without tag).
395        stackMapAttribute.u2stackMapFramesCount = dataInput.readUnsignedShort();
396
397        stackMapAttribute.stackMapFrames = new FullFrame[stackMapAttribute.u2stackMapFramesCount];
398        for (int index = 0; index < stackMapAttribute.u2stackMapFramesCount; index++)
399        {
400            FullFrame stackMapFrame = new FullFrame();
401            this.visitFullFrame(clazz, method, codeAttribute, index, stackMapFrame);
402            stackMapAttribute.stackMapFrames[index] = stackMapFrame;
403        }
404    }
405
406
407    public void visitStackMapTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, StackMapTableAttribute stackMapTableAttribute)
408    {
409        // Read the stack map frames.
410        stackMapTableAttribute.u2stackMapFramesCount = dataInput.readUnsignedShort();
411
412        stackMapTableAttribute.stackMapFrames = new StackMapFrame[stackMapTableAttribute.u2stackMapFramesCount];
413        for (int index = 0; index < stackMapTableAttribute.u2stackMapFramesCount; index++)
414        {
415            StackMapFrame stackMapFrame = createStackMapFrame();
416            stackMapFrame.accept(clazz, method, codeAttribute, 0, this);
417            stackMapTableAttribute.stackMapFrames[index] = stackMapFrame;
418        }
419    }
420
421
422    public void visitLineNumberTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberTableAttribute lineNumberTableAttribute)
423    {
424        // Read the line numbers.
425        lineNumberTableAttribute.u2lineNumberTableLength = dataInput.readUnsignedShort();
426
427        lineNumberTableAttribute.lineNumberTable = new LineNumberInfo[lineNumberTableAttribute.u2lineNumberTableLength];
428        for (int index = 0; index < lineNumberTableAttribute.u2lineNumberTableLength; index++)
429        {
430            LineNumberInfo lineNumberInfo = new LineNumberInfo();
431            this.visitLineNumberInfo(clazz, method, codeAttribute, lineNumberInfo);
432            lineNumberTableAttribute.lineNumberTable[index] = lineNumberInfo;
433        }
434    }
435
436
437    public void visitLocalVariableTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTableAttribute localVariableTableAttribute)
438    {
439        // Read the local variables.
440        localVariableTableAttribute.u2localVariableTableLength = dataInput.readUnsignedShort();
441
442        localVariableTableAttribute.localVariableTable = new LocalVariableInfo[localVariableTableAttribute.u2localVariableTableLength];
443        for (int index = 0; index < localVariableTableAttribute.u2localVariableTableLength; index++)
444        {
445            LocalVariableInfo localVariableInfo = new LocalVariableInfo();
446            this.visitLocalVariableInfo(clazz, method, codeAttribute, localVariableInfo);
447            localVariableTableAttribute.localVariableTable[index] = localVariableInfo;
448        }
449    }
450
451
452    public void visitLocalVariableTypeTableAttribute(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeTableAttribute localVariableTypeTableAttribute)
453    {
454        // Read the local variable types.
455        localVariableTypeTableAttribute.u2localVariableTypeTableLength = dataInput.readUnsignedShort();
456
457        localVariableTypeTableAttribute.localVariableTypeTable = new LocalVariableTypeInfo[localVariableTypeTableAttribute.u2localVariableTypeTableLength];
458        for (int index = 0; index < localVariableTypeTableAttribute.u2localVariableTypeTableLength; index++)
459        {
460            LocalVariableTypeInfo localVariableTypeInfo = new LocalVariableTypeInfo();
461            this.visitLocalVariableTypeInfo(clazz, method, codeAttribute, localVariableTypeInfo);
462            localVariableTypeTableAttribute.localVariableTypeTable[index] = localVariableTypeInfo;
463        }
464    }
465
466
467    public void visitAnyAnnotationsAttribute(Clazz clazz, AnnotationsAttribute annotationsAttribute)
468    {
469        // Read the annotations.
470        annotationsAttribute.u2annotationsCount = dataInput.readUnsignedShort();
471
472        annotationsAttribute.annotations = new Annotation[annotationsAttribute.u2annotationsCount];
473        for (int index = 0; index < annotationsAttribute.u2annotationsCount; index++)
474        {
475            Annotation annotation = new Annotation();
476            this.visitAnnotation(clazz, annotation);
477            annotationsAttribute.annotations[index] = annotation;
478        }
479    }
480
481
482    public void visitAnyParameterAnnotationsAttribute(Clazz clazz, Method method, ParameterAnnotationsAttribute parameterAnnotationsAttribute)
483    {
484        // Read the parameter annotations.
485        parameterAnnotationsAttribute.u2parametersCount           = dataInput.readUnsignedByte();
486
487        // The java compilers of JDK 1.5, JDK 1.6, and Eclipse all count the
488        // number of parameters of constructors of non-static inner classes
489        // incorrectly. Fix it right here.
490        int parameterStart = 0;
491        if (method.getName(clazz).equals(ClassConstants.INTERNAL_METHOD_NAME_INIT))
492        {
493            int realParametersCount = ClassUtil.internalMethodParameterCount(method.getDescriptor(clazz));
494            parameterStart = realParametersCount - parameterAnnotationsAttribute.u2parametersCount;
495            parameterAnnotationsAttribute.u2parametersCount = realParametersCount;
496        }
497
498        parameterAnnotationsAttribute.u2parameterAnnotationsCount = new int[parameterAnnotationsAttribute.u2parametersCount];
499        parameterAnnotationsAttribute.parameterAnnotations        = new Annotation[parameterAnnotationsAttribute.u2parametersCount][];
500
501        for (int parameterIndex = parameterStart; parameterIndex < parameterAnnotationsAttribute.u2parametersCount; parameterIndex++)
502        {
503            // Read the parameter annotations of the given parameter.
504            int u2annotationsCount = dataInput.readUnsignedShort();
505
506            Annotation[] annotations = new Annotation[u2annotationsCount];
507
508            for (int index = 0; index < u2annotationsCount; index++)
509            {
510                Annotation annotation = new Annotation();
511                this.visitAnnotation(clazz, annotation);
512                annotations[index] = annotation;
513            }
514
515            parameterAnnotationsAttribute.u2parameterAnnotationsCount[parameterIndex] = u2annotationsCount;
516            parameterAnnotationsAttribute.parameterAnnotations[parameterIndex]        = annotations;
517        }
518    }
519
520
521    public void visitAnnotationDefaultAttribute(Clazz clazz, Method method, AnnotationDefaultAttribute annotationDefaultAttribute)
522    {
523        // Read the default element value.
524        ElementValue elementValue = createElementValue();
525        elementValue.accept(clazz, null, this);
526        annotationDefaultAttribute.defaultValue = elementValue;
527    }
528
529
530    // Implementations for InnerClassesInfoVisitor.
531
532    public void visitInnerClassesInfo(Clazz clazz, InnerClassesInfo innerClassesInfo)
533    {
534        innerClassesInfo.u2innerClassIndex       = dataInput.readUnsignedShort();
535        innerClassesInfo.u2outerClassIndex       = dataInput.readUnsignedShort();
536        innerClassesInfo.u2innerNameIndex        = dataInput.readUnsignedShort();
537        innerClassesInfo.u2innerClassAccessFlags = dataInput.readUnsignedShort();
538    }
539
540
541    // Implementations for ExceptionInfoVisitor.
542
543    public void visitExceptionInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, ExceptionInfo exceptionInfo)
544    {
545        exceptionInfo.u2startPC   = dataInput.readUnsignedShort();
546        exceptionInfo.u2endPC     = dataInput.readUnsignedShort();
547        exceptionInfo.u2handlerPC = dataInput.readUnsignedShort();
548        exceptionInfo.u2catchType = dataInput.readUnsignedShort();
549    }
550
551
552    // Implementations for StackMapFrameVisitor.
553
554    public void visitSameZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameZeroFrame sameZeroFrame)
555    {
556        if (sameZeroFrame.getTag() == StackMapFrame.SAME_ZERO_FRAME_EXTENDED)
557        {
558            sameZeroFrame.u2offsetDelta = dataInput.readUnsignedShort();
559        }
560    }
561
562
563    public void visitSameOneFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, SameOneFrame sameOneFrame)
564    {
565        if (sameOneFrame.getTag() == StackMapFrame.SAME_ONE_FRAME_EXTENDED)
566        {
567            sameOneFrame.u2offsetDelta = dataInput.readUnsignedShort();
568        }
569
570        // Read the verification type of the stack entry.
571        VerificationType verificationType = createVerificationType();
572        verificationType.accept(clazz, method, codeAttribute, offset, this);
573        sameOneFrame.stackItem = verificationType;
574    }
575
576
577    public void visitLessZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, LessZeroFrame lessZeroFrame)
578    {
579        lessZeroFrame.u2offsetDelta = dataInput.readUnsignedShort();
580    }
581
582
583    public void visitMoreZeroFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, MoreZeroFrame moreZeroFrame)
584    {
585        moreZeroFrame.u2offsetDelta = dataInput.readUnsignedShort();
586
587        // Read the verification types of the additional local variables.
588        moreZeroFrame.additionalVariables = new VerificationType[moreZeroFrame.additionalVariablesCount];
589        for (int index = 0; index < moreZeroFrame.additionalVariablesCount; index++)
590        {
591            VerificationType verificationType = createVerificationType();
592            verificationType.accept(clazz, method, codeAttribute, offset, this);
593            moreZeroFrame.additionalVariables[index] = verificationType;
594        }
595    }
596
597
598    public void visitFullFrame(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, FullFrame fullFrame)
599    {
600        fullFrame.u2offsetDelta = dataInput.readUnsignedShort();
601
602        // Read the verification types of the local variables.
603        fullFrame.variablesCount = dataInput.readUnsignedShort();
604        fullFrame.variables = new VerificationType[fullFrame.variablesCount];
605        for (int index = 0; index < fullFrame.variablesCount; index++)
606        {
607            VerificationType verificationType = createVerificationType();
608            verificationType.variablesAccept(clazz, method, codeAttribute, offset, index, this);
609            fullFrame.variables[index] = verificationType;
610        }
611
612        // Read the verification types of the stack entries.
613        fullFrame.stackCount = dataInput.readUnsignedShort();
614        fullFrame.stack = new VerificationType[fullFrame.stackCount];
615        for (int index = 0; index < fullFrame.stackCount; index++)
616        {
617            VerificationType verificationType = createVerificationType();
618            verificationType.stackAccept(clazz, method, codeAttribute, offset, index, this);
619            fullFrame.stack[index] = verificationType;
620        }
621    }
622
623
624    // Implementations for VerificationTypeVisitor.
625
626    public void visitAnyVerificationType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, VerificationType verificationType)
627    {
628        // Most verification types don't contain any additional information.
629    }
630
631
632    public void visitObjectType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, ObjectType objectType)
633    {
634        objectType.u2classIndex = dataInput.readUnsignedShort();
635    }
636
637
638    public void visitUninitializedType(Clazz clazz, Method method, CodeAttribute codeAttribute, int offset, UninitializedType uninitializedType)
639    {
640        uninitializedType.u2newInstructionOffset = dataInput.readUnsignedShort();
641    }
642
643
644    // Implementations for LineNumberInfoVisitor.
645
646    public void visitLineNumberInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LineNumberInfo lineNumberInfo)
647    {
648        lineNumberInfo.u2startPC    = dataInput.readUnsignedShort();
649        lineNumberInfo.u2lineNumber = dataInput.readUnsignedShort();
650    }
651
652
653    // Implementations for LocalVariableInfoVisitor.
654
655    public void visitLocalVariableInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableInfo localVariableInfo)
656    {
657        localVariableInfo.u2startPC         = dataInput.readUnsignedShort();
658        localVariableInfo.u2length          = dataInput.readUnsignedShort();
659        localVariableInfo.u2nameIndex       = dataInput.readUnsignedShort();
660        localVariableInfo.u2descriptorIndex = dataInput.readUnsignedShort();
661        localVariableInfo.u2index           = dataInput.readUnsignedShort();
662    }
663
664
665    // Implementations for LocalVariableTypeInfoVisitor.
666
667    public void visitLocalVariableTypeInfo(Clazz clazz, Method method, CodeAttribute codeAttribute, LocalVariableTypeInfo localVariableTypeInfo)
668    {
669        localVariableTypeInfo.u2startPC        = dataInput.readUnsignedShort();
670        localVariableTypeInfo.u2length         = dataInput.readUnsignedShort();
671        localVariableTypeInfo.u2nameIndex      = dataInput.readUnsignedShort();
672        localVariableTypeInfo.u2signatureIndex = dataInput.readUnsignedShort();
673        localVariableTypeInfo.u2index          = dataInput.readUnsignedShort();
674    }
675
676
677    // Implementations for AnnotationVisitor.
678
679    public void visitAnnotation(Clazz clazz, Annotation annotation)
680    {
681        // Read the annotation type.
682        annotation.u2typeIndex = dataInput.readUnsignedShort();
683
684        // Read the element value pairs.
685        annotation.u2elementValuesCount = dataInput.readUnsignedShort();
686
687        annotation.elementValues = new ElementValue[annotation.u2elementValuesCount];
688        for (int index = 0; index < annotation.u2elementValuesCount; index++)
689        {
690            int u2elementNameIndex = dataInput.readUnsignedShort();
691            ElementValue elementValue = createElementValue();
692            elementValue.u2elementNameIndex = u2elementNameIndex;
693            elementValue.accept(clazz, annotation, this);
694            annotation.elementValues[index] = elementValue;
695        }
696    }
697
698
699    // Implementations for ElementValueVisitor.
700
701    public void visitConstantElementValue(Clazz clazz, Annotation annotation, ConstantElementValue constantElementValue)
702    {
703        constantElementValue.u2constantValueIndex = dataInput.readUnsignedShort();
704    }
705
706
707    public void visitEnumConstantElementValue(Clazz clazz, Annotation annotation, EnumConstantElementValue enumConstantElementValue)
708    {
709        enumConstantElementValue.u2typeNameIndex     = dataInput.readUnsignedShort();
710        enumConstantElementValue.u2constantNameIndex = dataInput.readUnsignedShort();
711    }
712
713
714    public void visitClassElementValue(Clazz clazz, Annotation annotation, ClassElementValue classElementValue)
715    {
716        classElementValue.u2classInfoIndex = dataInput.readUnsignedShort();
717    }
718
719
720    public void visitAnnotationElementValue(Clazz clazz, Annotation annotation, AnnotationElementValue annotationElementValue)
721    {
722        // Read the annotation.
723        Annotation annotationValue = new Annotation();
724        this.visitAnnotation(clazz, annotationValue);
725        annotationElementValue.annotationValue = annotationValue;
726    }
727
728
729    public void visitArrayElementValue(Clazz clazz, Annotation annotation, ArrayElementValue arrayElementValue)
730    {
731        // Read the element values.
732        arrayElementValue.u2elementValuesCount = dataInput.readUnsignedShort();
733
734        arrayElementValue.elementValues = new ElementValue[arrayElementValue.u2elementValuesCount];
735        for (int index = 0; index < arrayElementValue.u2elementValuesCount; index++)
736        {
737            ElementValue elementValue = createElementValue();
738            elementValue.accept(clazz, annotation, this);
739            arrayElementValue.elementValues[index] = elementValue;
740        }
741    }
742
743
744    // Small utility methods.
745
746    private Constant createConstant()
747    {
748        int u1tag = dataInput.readUnsignedByte();
749
750        switch (u1tag)
751        {
752            case ClassConstants.CONSTANT_Utf8:               return new Utf8Constant();
753            case ClassConstants.CONSTANT_Integer:            return new IntegerConstant();
754            case ClassConstants.CONSTANT_Float:              return new FloatConstant();
755            case ClassConstants.CONSTANT_Long:               return new LongConstant();
756            case ClassConstants.CONSTANT_Double:             return new DoubleConstant();
757            case ClassConstants.CONSTANT_String:             return new StringConstant();
758            case ClassConstants.CONSTANT_Fieldref:           return new FieldrefConstant();
759            case ClassConstants.CONSTANT_Methodref:          return new MethodrefConstant();
760            case ClassConstants.CONSTANT_InterfaceMethodref: return new InterfaceMethodrefConstant();
761            case ClassConstants.CONSTANT_Class:              return new ClassConstant();
762            case ClassConstants.CONSTANT_NameAndType:        return new NameAndTypeConstant();
763
764            default: throw new RuntimeException("Unknown constant type ["+u1tag+"] in constant pool");
765        }
766    }
767
768
769    private Attribute createAttribute(Clazz clazz)
770    {
771        int u2attributeNameIndex = dataInput.readUnsignedShort();
772        int u4attributeLength    = dataInput.readInt();
773        String attributeName     = clazz.getString(u2attributeNameIndex);
774        Attribute attribute =
775            attributeName.equals(ClassConstants.ATTR_SourceFile)                           ? (Attribute)new SourceFileAttribute():
776            attributeName.equals(ClassConstants.ATTR_SourceDir)                            ? (Attribute)new SourceDirAttribute():
777            attributeName.equals(ClassConstants.ATTR_InnerClasses)                         ? (Attribute)new InnerClassesAttribute():
778            attributeName.equals(ClassConstants.ATTR_EnclosingMethod)                      ? (Attribute)new EnclosingMethodAttribute():
779            attributeName.equals(ClassConstants.ATTR_Deprecated)                           ? (Attribute)new DeprecatedAttribute():
780            attributeName.equals(ClassConstants.ATTR_Synthetic)                            ? (Attribute)new SyntheticAttribute():
781            attributeName.equals(ClassConstants.ATTR_Signature)                            ? (Attribute)new SignatureAttribute():
782            attributeName.equals(ClassConstants.ATTR_ConstantValue)                        ? (Attribute)new ConstantValueAttribute():
783            attributeName.equals(ClassConstants.ATTR_Exceptions)                           ? (Attribute)new ExceptionsAttribute():
784            attributeName.equals(ClassConstants.ATTR_Code)                                 ? (Attribute)new CodeAttribute():
785            attributeName.equals(ClassConstants.ATTR_StackMap)                             ? (Attribute)new StackMapAttribute():
786            attributeName.equals(ClassConstants.ATTR_StackMapTable)                        ? (Attribute)new StackMapTableAttribute():
787            attributeName.equals(ClassConstants.ATTR_LineNumberTable)                      ? (Attribute)new LineNumberTableAttribute():
788            attributeName.equals(ClassConstants.ATTR_LocalVariableTable)                   ? (Attribute)new LocalVariableTableAttribute():
789            attributeName.equals(ClassConstants.ATTR_LocalVariableTypeTable)               ? (Attribute)new LocalVariableTypeTableAttribute():
790            attributeName.equals(ClassConstants.ATTR_RuntimeVisibleAnnotations)            ? (Attribute)new RuntimeVisibleAnnotationsAttribute():
791            attributeName.equals(ClassConstants.ATTR_RuntimeInvisibleAnnotations)          ? (Attribute)new RuntimeInvisibleAnnotationsAttribute():
792            attributeName.equals(ClassConstants.ATTR_RuntimeVisibleParameterAnnotations)   ? (Attribute)new RuntimeVisibleParameterAnnotationsAttribute():
793            attributeName.equals(ClassConstants.ATTR_RuntimeInvisibleParameterAnnotations) ? (Attribute)new RuntimeInvisibleParameterAnnotationsAttribute():
794            attributeName.equals(ClassConstants.ATTR_AnnotationDefault)                    ? (Attribute)new AnnotationDefaultAttribute():
795                                                                                             (Attribute)new UnknownAttribute(u4attributeLength);
796        attribute.u2attributeNameIndex = u2attributeNameIndex;
797
798        return attribute;
799    }
800
801
802    private StackMapFrame createStackMapFrame()
803    {
804        int u1tag = dataInput.readUnsignedByte();
805
806        return
807            u1tag < StackMapFrame.SAME_ONE_FRAME           ? (StackMapFrame)new SameZeroFrame(u1tag) :
808            u1tag < StackMapFrame.SAME_ONE_FRAME_EXTENDED  ? (StackMapFrame)new SameOneFrame(u1tag)  :
809            u1tag < StackMapFrame.LESS_ZERO_FRAME          ? (StackMapFrame)new SameOneFrame(u1tag)  :
810            u1tag < StackMapFrame.SAME_ZERO_FRAME_EXTENDED ? (StackMapFrame)new LessZeroFrame(u1tag) :
811            u1tag < StackMapFrame.MORE_ZERO_FRAME          ? (StackMapFrame)new SameZeroFrame(u1tag) :
812            u1tag < StackMapFrame.FULL_FRAME               ? (StackMapFrame)new MoreZeroFrame(u1tag) :
813                                                             (StackMapFrame)new FullFrame();
814    }
815
816
817    private VerificationType createVerificationType()
818    {
819        int u1tag = dataInput.readUnsignedByte();
820
821        switch (u1tag)
822        {
823            case VerificationType.INTEGER_TYPE:            return new IntegerType();
824            case VerificationType.FLOAT_TYPE:              return new FloatType();
825            case VerificationType.LONG_TYPE:               return new LongType();
826            case VerificationType.DOUBLE_TYPE:             return new DoubleType();
827            case VerificationType.TOP_TYPE:                return new TopType();
828            case VerificationType.OBJECT_TYPE:             return new ObjectType();
829            case VerificationType.NULL_TYPE:               return new NullType();
830            case VerificationType.UNINITIALIZED_TYPE:      return new UninitializedType();
831            case VerificationType.UNINITIALIZED_THIS_TYPE: return new UninitializedThisType();
832
833            default: throw new RuntimeException("Unknown verification type ["+u1tag+"] in stack map frame");
834        }
835    }
836
837
838    private ElementValue createElementValue()
839    {
840        int u1tag = dataInput.readUnsignedByte();
841
842        switch (u1tag)
843        {
844            case ClassConstants.INTERNAL_TYPE_BOOLEAN:
845            case ClassConstants.INTERNAL_TYPE_BYTE:
846            case ClassConstants.INTERNAL_TYPE_CHAR:
847            case ClassConstants.INTERNAL_TYPE_SHORT:
848            case ClassConstants.INTERNAL_TYPE_INT:
849            case ClassConstants.INTERNAL_TYPE_FLOAT:
850            case ClassConstants.INTERNAL_TYPE_LONG:
851            case ClassConstants.INTERNAL_TYPE_DOUBLE:
852            case ClassConstants.ELEMENT_VALUE_STRING_CONSTANT: return new ConstantElementValue(u1tag);
853
854            case ClassConstants.ELEMENT_VALUE_ENUM_CONSTANT:   return new EnumConstantElementValue();
855            case ClassConstants.ELEMENT_VALUE_CLASS:           return new ClassElementValue();
856            case ClassConstants.ELEMENT_VALUE_ANNOTATION:      return new AnnotationElementValue();
857            case ClassConstants.ELEMENT_VALUE_ARRAY:           return new ArrayElementValue();
858
859            default: throw new IllegalArgumentException("Unknown element value tag ["+u1tag+"]");
860        }
861    }
862}
863