1 package br
.org
.javadecompiler
.decoder
;
3 import br
.org
.javadecompiler
.classfile
.AccessFlags
;
4 import br
.org
.javadecompiler
.classfile
.ConstantPool
;
5 import br
.org
.javadecompiler
.classfile
.FieldOrMethod
;
6 import br
.org
.javadecompiler
.classfile
.JavaClass
;
7 import br
.org
.javadecompiler
.classfile
.Field
;
8 import br
.org
.javadecompiler
.classfile
.Method
;
9 import br
.org
.javadecompiler
.classfile
.attribute
.Attribute
;
10 import br
.org
.javadecompiler
.classfile
.attribute
.AttributeOwner
;
11 import br
.org
.javadecompiler
.classfile
.attribute
.CodeAttribute
;
12 import br
.org
.javadecompiler
.classfile
.attribute
.ConstantValueAttribute
;
13 import br
.org
.javadecompiler
.classfile
.attribute
.DeprecatedAttribute
;
14 import br
.org
.javadecompiler
.classfile
.attribute
.ExceptionsAttribute
;
15 import br
.org
.javadecompiler
.classfile
.attribute
.InnerClassesAttribute
;
16 import br
.org
.javadecompiler
.classfile
.attribute
.LineNumberTableAttribute
;
17 import br
.org
.javadecompiler
.classfile
.attribute
.LocalVariableTableAttribute
;
18 import br
.org
.javadecompiler
.classfile
.attribute
.SignatureAttribute
;
19 import br
.org
.javadecompiler
.classfile
.attribute
.SourceFileAttribute
;
20 import br
.org
.javadecompiler
.classfile
.attribute
.SyntheticAttribute
;
21 import br
.org
.javadecompiler
.classfile
.attribute
.UnknownAttribute
;
22 import br
.org
.javadecompiler
.classfile
.constant
.ClassConstant
;
23 import br
.org
.javadecompiler
.classfile
.constant
.Constant
;
24 import br
.org
.javadecompiler
.classfile
.constant
.ConstantTag
;
25 import br
.org
.javadecompiler
.classfile
.constant
.DoubleConstant
;
26 import br
.org
.javadecompiler
.classfile
.constant
.FieldReferenceConstant
;
27 import br
.org
.javadecompiler
.classfile
.constant
.FloatConstant
;
28 import br
.org
.javadecompiler
.classfile
.constant
.IntegerConstant
;
29 import br
.org
.javadecompiler
.classfile
.constant
.InterfaceMethodReferenceConstant
;
30 import br
.org
.javadecompiler
.classfile
.constant
.LongConstant
;
31 import br
.org
.javadecompiler
.classfile
.constant
.MethodReferenceConstant
;
32 import br
.org
.javadecompiler
.classfile
.constant
.NameAndTypeConstant
;
33 import br
.org
.javadecompiler
.classfile
.constant
.PrimitiveTypeOrStringConstant
;
34 import br
.org
.javadecompiler
.classfile
.constant
.ReferenceConstant
;
35 import br
.org
.javadecompiler
.classfile
.constant
.StringConstant
;
36 import br
.org
.javadecompiler
.classfile
.constant
.UTF8Constant
;
37 import br
.org
.javadecompiler
.exception
.ClassReaderException
;
38 import br
.org
.javadecompiler
.exception
.DecoderException
;
39 import br
.org
.javadecompiler
.reader
.ClassReader
;
41 import org
.apache
.log4j
.Logger
;
43 public final class Decoder
{
44 private final Logger logger
= Logger
.getLogger(this.getClass());
46 private final ClassReader reader
;
47 private final JavaClass ownerClass
;
49 private Decoder(JavaClass ownerClass
, ClassReader reader
) {
50 this.ownerClass
= ownerClass
;
54 public static JavaClass
decodeClass(ClassReader reader
) throws DecoderException
, ClassReaderException
{
55 Decoder decoder
= new Decoder(new JavaClass(), reader
);
56 decoder
.decodeClass();
57 return decoder
.ownerClass
;
60 private void decodeClass() throws DecoderException
, ClassReaderException
{
63 long magic
= reader
.readUnsignedInt();
64 if (magic
!= 0xcafebabeL
)
65 throw new DecoderException("Invalid magic number: 0x" + Utils
.formatHex(magic
, 8));
67 ownerClass
.setMinorVersion(reader
.readUnsignedShort());
68 ownerClass
.setMajorVersion(reader
.readUnsignedShort());
69 if (logger
.isDebugEnabled())
70 logger
.debug("Class version: " + ownerClass
.getMajorVersion() + "." + ownerClass
.getMinorVersion());
74 ownerClass
.setAccessFlags(reader
.readUnsignedShort());
75 if (!AccessFlags
.isValidClassFlags(ownerClass
.getAccessFlags()))
76 throw new DecoderException("Invalid class flags: 0x" + Utils
.formatHex(ownerClass
.getAccessFlags(), 4));
78 int thisClassIndex
= reader
.readUnsignedShort();
79 ownerClass
.setThisClass((ClassConstant
) ownerClass
.getConstantPool().getConstant(thisClassIndex
));
80 int superClassIndex
= reader
.readUnsignedShort();
81 if (superClassIndex
!= 0)
82 ownerClass
.setSuperClass((ClassConstant
) ownerClass
.getConstantPool().getConstant(superClassIndex
));
84 if (!"java/lang/Object".equals(ownerClass
.getThisClass().getName().getValue()))
85 throw new DecoderException("Class without a super class");
90 ownerClass
.setFields(decodeFields());
91 ownerClass
.setMethods(decodeMethods());
92 ownerClass
.setAttributes(decodeAttributes(ownerClass
));
94 if (reader
.available() != 0)
95 throw new DecoderException("End of stream expected");
99 private void decodeConstantPool() throws DecoderException
, ClassReaderException
{
101 ConstantPool pool
= new ConstantPool();
102 Constant constants
[] = new Constant
[reader
.readUnsignedShort()];
103 pool
.setConstants(constants
);
104 ownerClass
.setConstantPool(pool
);
105 pool
.setOwnerClass(ownerClass
);
106 if (logger
.isDebugEnabled())
107 logger
.debug("Constant pool size: " + constants
.length
);
110 if (logger
.isDebugEnabled())
111 logger
.debug("Decoding constants: step 1");
114 for(index
= 1; index
< constants
.length
; index
++) {
115 Constant constant
= decodeConstantFirstPass(index
);
116 constants
[index
] = constant
;
118 if ((constant
instanceof LongConstant
) || (constant
instanceof DoubleConstant
))
121 if (index
> constants
.length
)
122 throw new DecoderException("Last constant cannot be of type Long or Double");
126 if (logger
.isDebugEnabled()) {
127 logger
.debug("Decoding constants: step 2");
129 for(index
= 1; index
< constants
.length
; index
++) {
130 Constant constant
= constants
[index
];
131 decodeConstantSecondPass(constant
, pool
);
133 if ((constant
instanceof LongConstant
) || (constant
instanceof DoubleConstant
))
138 private Constant
decodeConstantFirstPass(int index
) throws DecoderException
, ClassReaderException
{
139 int tagValue
= reader
.readUnsignedByte();
142 Constant constant
= createNewConstantByTag(tagValue
);
144 constant
.setOwnerClass(ownerClass
);
145 constant
.setIndex(index
);
148 case ConstantTag
.STRING_TAG
:
149 case ConstantTag
.CLASS_TAG
:
152 case ConstantTag
.NAMEANDTYPE_TAG
:
153 case ConstantTag
.FIELDREF_TAG
:
154 case ConstantTag
.INTERFACEMETHODREF_TAG
:
155 case ConstantTag
.METHODREF_TAG
:
156 case ConstantTag
.INTEGER_TAG
:
157 case ConstantTag
.FLOAT_TAG
:
160 case ConstantTag
.DOUBLE_TAG
:
161 case ConstantTag
.LONG_TAG
:
164 case ConstantTag
.UTF8_TAG
:
165 size
= reader
.readUnsignedShort();
172 private void decodeConstantSecondPass(Constant constant
, ConstantPool pool
) throws DecoderException
, ClassReaderException
{
173 reader
.readUnsignedByte();
174 if (constant
instanceof ClassConstant
) {
175 ClassConstant result
= (ClassConstant
) constant
;
176 int nameIndex
= reader
.readUnsignedShort();
177 result
.setName((UTF8Constant
) pool
.getConstant(nameIndex
));
178 } else if (constant
instanceof ReferenceConstant
) {
179 ReferenceConstant result
= (ReferenceConstant
) constant
;
180 int classIndex
= reader
.readUnsignedShort();
181 int nameAndTypeIndex
= reader
.readUnsignedShort();
182 result
.setReferenceClass((ClassConstant
) pool
.getConstant(classIndex
));
183 result
.setNameAndTypeInfo((NameAndTypeConstant
) pool
.getConstant(nameAndTypeIndex
));
184 } else if (constant
instanceof StringConstant
) {
185 StringConstant result
= (StringConstant
) constant
;
186 int stringIndex
= reader
.readUnsignedShort();
187 result
.setValue((UTF8Constant
) pool
.getConstant(stringIndex
));
188 } else if (constant
instanceof IntegerConstant
) {
189 IntegerConstant result
= (IntegerConstant
) constant
;
190 result
.setValue(reader
.readSignedInt());
191 } else if (constant
instanceof FloatConstant
) {
192 FloatConstant result
= (FloatConstant
) constant
;
193 result
.setValue(reader
.readFloat());
194 } else if (constant
instanceof DoubleConstant
) {
195 DoubleConstant result
= (DoubleConstant
) constant
;
196 result
.setValue(reader
.readDouble());
197 } else if (constant
instanceof LongConstant
) {
198 LongConstant result
= (LongConstant
) constant
;
199 result
.setValue(reader
.readSignedLong());
200 } else if (constant
instanceof NameAndTypeConstant
) {
201 NameAndTypeConstant result
= (NameAndTypeConstant
) constant
;
202 int nameIndex
= reader
.readUnsignedShort();
203 int descriptorIndex
= reader
.readUnsignedShort();
204 result
.setName((UTF8Constant
) pool
.getConstant(nameIndex
));
205 result
.setDescriptor((UTF8Constant
) pool
.getConstant(descriptorIndex
));
206 } else if (constant
instanceof UTF8Constant
) {
207 UTF8Constant result
= (UTF8Constant
) constant
;
208 result
.setValue(reader
.readUtf8());
212 private Constant
createNewConstantByTag(int tagValue
) {
214 case ConstantTag
.UTF8_TAG
:
215 return new UTF8Constant();
216 case ConstantTag
.INTEGER_TAG
:
217 return new IntegerConstant();
218 case ConstantTag
.FLOAT_TAG
:
219 return new FloatConstant();
220 case ConstantTag
.LONG_TAG
:
221 return new LongConstant();
222 case ConstantTag
.DOUBLE_TAG
:
223 return new DoubleConstant();
224 case ConstantTag
.CLASS_TAG
:
225 return new ClassConstant();
226 case ConstantTag
.STRING_TAG
:
227 return new StringConstant();
228 case ConstantTag
.FIELDREF_TAG
:
229 return new FieldReferenceConstant();
230 case ConstantTag
.METHODREF_TAG
:
231 return new MethodReferenceConstant();
232 case ConstantTag
.INTERFACEMETHODREF_TAG
:
233 return new InterfaceMethodReferenceConstant();
234 case ConstantTag
.NAMEANDTYPE_TAG
:
235 return new NameAndTypeConstant();
240 private void decodeInterfaces() throws DecoderException
, ClassReaderException
{
241 ClassConstant
[]interfaces
= new ClassConstant
[reader
.readUnsignedShort()];
242 for(int i
= 0; i
< interfaces
.length
; i
++) {
243 int interfaceIndex
= reader
.readUnsignedShort();
244 interfaces
[i
] = (ClassConstant
) ownerClass
.getConstantPool().getConstant(interfaceIndex
);
246 ownerClass
.setInterfaces(interfaces
);
249 private Field
[] decodeFields() throws DecoderException
, ClassReaderException
{
250 Field
[] result
= new Field
[reader
.readUnsignedShort()];
251 for(int i
= 0; i
< result
.length
; i
++) {
252 result
[i
] = new Field();
253 decodeFieldOrMethod(result
[i
]);
258 private Method
[] decodeMethods() throws DecoderException
, ClassReaderException
{
259 Method
[] result
= new Method
[reader
.readUnsignedShort()];
260 for(int i
= 0; i
< result
.length
; i
++) {
261 result
[i
] = new Method();
262 decodeFieldOrMethod(result
[i
]);
267 private void decodeFieldOrMethod(FieldOrMethod fieldOrMethod
) throws DecoderException
, ClassReaderException
{
268 fieldOrMethod
.setAccessFlags(reader
.readUnsignedShort());
269 int nameIndex
= reader
.readUnsignedShort();
270 fieldOrMethod
.setName((UTF8Constant
) ownerClass
.getConstantPool().getConstant(nameIndex
));
271 int descriptorIndex
= reader
.readUnsignedShort();
272 fieldOrMethod
.setDescriptor((UTF8Constant
) ownerClass
.getConstantPool().getConstant(descriptorIndex
));
273 fieldOrMethod
.setAttributes(decodeAttributes(fieldOrMethod
));
274 fieldOrMethod
.setOwnerClass(ownerClass
);
277 private Attribute
[] decodeAttributes(AttributeOwner owner
) throws DecoderException
, ClassReaderException
{
278 Attribute
[] result
= new Attribute
[reader
.readUnsignedShort()];
279 for(int i
= 0; i
< result
.length
; i
++) {
280 result
[i
] = decodeAttribute(owner
);
286 private Attribute
decodeAttribute(AttributeOwner owner
) throws DecoderException
, ClassReaderException
{
287 int attributeNameIndex
= reader
.readUnsignedShort();
288 UTF8Constant attributeName
= (UTF8Constant
) ownerClass
.getConstantPool().getConstant(attributeNameIndex
);
289 String name
= attributeName
.getValue();
291 if (Attribute
.CONSTANT_VALUE_ATTRIBUTE
.equals(name
)) {
292 result
= decodeConstantValueAttribute();
293 } else if (Attribute
.CODE_ATTRIBUTE
.equals(name
)) {
294 result
= decodeCodeAttribute();
295 } else if (Attribute
.DEPRECATED_ATTRIBUTE
.equals(name
)) {
296 result
= decodeDeprecatedAttribute();
297 } else if (Attribute
.EXCEPTIONS_ATTRIBUTE
.equals(name
)) {
298 result
= decodeExceptionsAttribute();
299 } else if (Attribute
.INNER_CLASSES_ATTRIBUTE
.equals(name
)) {
300 result
= decodeInnerClassesAttribute();
301 } else if (Attribute
.LINE_NUMBER_TABLE_ATTRIBUTE
.equals(name
)) {
302 result
= decodeLineNumberTableAttribute();
303 } else if (Attribute
.LOCAL_VARIABLE_TABLE_ATTRIBUTE
.equals(name
)) {
304 result
= decodeLocalVariableTableAttribute();
305 } else if (Attribute
.SOURCE_FILE_ATTRIBUTE
.equals(name
)) {
306 result
= decodeSourceFileAttribute();
307 } else if (Attribute
.SYNTHETIC_ATTRIBUTE
.equals(name
)) {
308 result
= decodeSyntheticAttribute();
309 } else if (Attribute
.SIGNATURE_ATTRIBUTE
.equals(name
)) {
310 result
= decodeSignatureAttribute();
312 result
= decodeUnknownAttribute();
313 if (logger
.isDebugEnabled()) {
314 logger
.debug("Unknown Attribute: " + attributeName
.getValue());
318 result
.setAttributeName(attributeName
);
319 result
.setOnwerClass(ownerClass
);
320 result
.setOwner(owner
);
325 private ConstantValueAttribute
decodeConstantValueAttribute() throws DecoderException
, ClassReaderException
{
326 long attributeLength
= reader
.readUnsignedInt();
327 if (attributeLength
!= 2)
328 throw new DecoderException("Invalid ConstantValue attribute length");
329 int constantValueIndex
= reader
.readUnsignedShort();
330 ConstantValueAttribute result
= new ConstantValueAttribute();
331 result
.setConstantValue((PrimitiveTypeOrStringConstant
) ownerClass
.getConstantPool().getConstant(constantValueIndex
));
335 private CodeAttribute
decodeCodeAttribute() throws DecoderException
, ClassReaderException
{
336 CodeAttribute result
= new CodeAttribute();
337 long attributeLength
= reader
.readUnsignedInt();
338 int before
= reader
.position();
339 result
.setMaxStack(reader
.readUnsignedShort());
340 result
.setMaxLocals(reader
.readUnsignedShort());
341 byte[] byteCode
= new byte[(int) reader
.readUnsignedInt()];
342 reader
.read(byteCode
, 0, byteCode
.length
);
343 result
.setByteCode(byteCode
);
344 int numberOfExceptions
= reader
.readUnsignedShort();
345 result
.setExceptionTable(new CodeAttribute
.CodeException
[numberOfExceptions
]);
346 for(int i
= 0; i
< numberOfExceptions
; i
++) {
347 CodeAttribute
.CodeException codeException
= result
.new CodeException();
348 codeException
.setStartPc(reader
.readUnsignedShort());
349 codeException
.setEndPc(reader
.readUnsignedShort());
350 codeException
.setHandlerPc(reader
.readUnsignedShort());
351 int catchTypeIndex
= reader
.readUnsignedShort();
352 if (catchTypeIndex
!= 0)
353 codeException
.setCatchType((ClassConstant
) ownerClass
.getConstantPool().getConstant(catchTypeIndex
));
354 result
.getExceptionTable()[i
] = codeException
;
356 decodeAttributes(result
);
357 if (attributeLength
!= (reader
.position() - before
))
358 throw new DecoderException("Invalid Code attribute length");
362 private DeprecatedAttribute
decodeDeprecatedAttribute() throws DecoderException
, ClassReaderException
{
363 DeprecatedAttribute result
= new DeprecatedAttribute();
364 long attributeLength
= reader
.readUnsignedInt();
365 if (attributeLength
!= 0)
366 throw new DecoderException("Invalid Deprecated attribute length");
370 private ExceptionsAttribute
decodeExceptionsAttribute() throws DecoderException
, ClassReaderException
{
371 ExceptionsAttribute result
= new ExceptionsAttribute();
372 long attributeLength
= reader
.readUnsignedInt();
373 int numberOfExceptions
= reader
.readUnsignedShort();
374 if (attributeLength
!= 2 * (numberOfExceptions
+ 1))
375 throw new DecoderException("Invalid Exceptions attribute length");
376 ClassConstant
[] exceptions
= new ClassConstant
[numberOfExceptions
];
377 for(int i
= 0; i
< exceptions
.length
; i
++) {
378 int exceptionIndex
= reader
.readUnsignedShort();
379 exceptions
[i
] = (ClassConstant
) ownerClass
.getConstantPool().getConstant(exceptionIndex
);
381 result
.setExceptions(exceptions
);
385 private InnerClassesAttribute
decodeInnerClassesAttribute() throws DecoderException
, ClassReaderException
{
386 InnerClassesAttribute result
= new InnerClassesAttribute();
387 long attributeLength
= reader
.readUnsignedInt();
388 int numberOfInnerClasses
= reader
.readUnsignedShort();
389 if (attributeLength
!= 8 * numberOfInnerClasses
+ 2)
390 throw new DecoderException("Invalid InnerClasses attribute length");
391 result
.setInnerClasses(new InnerClassesAttribute
.InnerClass
[numberOfInnerClasses
]);
392 for(int i
= 0; i
< numberOfInnerClasses
; i
++) {
393 InnerClassesAttribute
.InnerClass innerClass
= result
.new InnerClass();
394 int innerClassInfoIndex
= reader
.readUnsignedShort();
395 if (innerClassInfoIndex
!= 0)
396 innerClass
.setInnerClassInfo((ClassConstant
) ownerClass
.getConstantPool().getConstant(innerClassInfoIndex
));
397 int outerClassInfoIndex
= reader
.readUnsignedShort();
398 if (outerClassInfoIndex
!= 0)
399 innerClass
.setOuterClassInfo((ClassConstant
) ownerClass
.getConstantPool().getConstant(outerClassInfoIndex
));
400 int nameIndex
= reader
.readUnsignedShort();
402 innerClass
.setName((UTF8Constant
) ownerClass
.getConstantPool().getConstant(nameIndex
));
403 innerClass
.setAccessFlags(reader
.readUnsignedShort());
404 result
.getInnerClasses()[i
] = innerClass
;
409 private LineNumberTableAttribute
decodeLineNumberTableAttribute() throws DecoderException
, ClassReaderException
{
410 LineNumberTableAttribute result
= new LineNumberTableAttribute();
411 long attributeLength
= reader
.readUnsignedInt();
412 int numberOfLines
= reader
.readUnsignedShort();
413 if (attributeLength
!= 4 * numberOfLines
+ 2)
414 throw new DecoderException("Invalid LineNumberTable attribute length");
415 result
.setLineNumberTable(new LineNumberTableAttribute
.LineNumber
[numberOfLines
]);
416 for(int i
= 0; i
< numberOfLines
; i
++) {
417 LineNumberTableAttribute
.LineNumber lineNumber
= result
.new LineNumber();
418 lineNumber
.setStartPc(reader
.readUnsignedShort());
419 lineNumber
.setLineNumber(reader
.readUnsignedShort());
420 result
.getLineNumberTable()[i
] = lineNumber
;
425 private LocalVariableTableAttribute
decodeLocalVariableTableAttribute() throws DecoderException
, ClassReaderException
{
426 LocalVariableTableAttribute result
= new LocalVariableTableAttribute();
427 long attributeLength
= reader
.readUnsignedInt();
428 int numberOfLocalVariables
= reader
.readUnsignedShort();
429 if (attributeLength
!= 10 * numberOfLocalVariables
+ 2)
430 throw new DecoderException("Invalid LocalVariableTable attribute length");
431 result
.setLocalVariableTable(new LocalVariableTableAttribute
.LocalVariable
[numberOfLocalVariables
]);
432 for(int i
= 0; i
< numberOfLocalVariables
; i
++) {
433 LocalVariableTableAttribute
.LocalVariable localVariable
= result
.new LocalVariable();
434 localVariable
.setStartPc(reader
.readUnsignedShort());
435 localVariable
.setLength(reader
.readUnsignedShort());
436 int nameIndex
= reader
.readUnsignedShort();
437 localVariable
.setName((UTF8Constant
) ownerClass
.getConstantPool().getConstant(nameIndex
));
438 int descriptorIndex
= reader
.readUnsignedShort();
439 localVariable
.setDescriptor((UTF8Constant
) ownerClass
.getConstantPool().getConstant(descriptorIndex
));
440 localVariable
.setIndex(reader
.readUnsignedShort());
441 result
.getLocalVariableTable()[i
] = localVariable
;
447 private SourceFileAttribute
decodeSourceFileAttribute() throws DecoderException
, ClassReaderException
{
448 SourceFileAttribute result
= new SourceFileAttribute();
449 long attributeLength
= reader
.readUnsignedInt();
450 if (attributeLength
!= 2)
451 throw new DecoderException("Invalid SourceFile attribute length");
452 int sourceFileIndex
= reader
.readUnsignedShort();
453 result
.setSourceFile((UTF8Constant
) ownerClass
.getConstantPool().getConstant(sourceFileIndex
));
457 private SyntheticAttribute
decodeSyntheticAttribute() throws DecoderException
, ClassReaderException
{
458 SyntheticAttribute result
= new SyntheticAttribute();
459 long attributeLength
= reader
.readUnsignedInt();
460 if (attributeLength
!= 0)
461 throw new DecoderException("Invalid Synthetic attribute length");
465 private SignatureAttribute
decodeSignatureAttribute() throws DecoderException
, ClassReaderException
{
466 SignatureAttribute result
= new SignatureAttribute();
467 long attributeLength
= reader
.readUnsignedInt();
468 if (attributeLength
!= 2)
469 throw new DecoderException("Invalid Signature attribute length");
470 int signatureIndex
= reader
.readUnsignedShort();
471 result
.setSignature((UTF8Constant
) ownerClass
.getConstantPool().getConstant(signatureIndex
));
475 private UnknownAttribute
decodeUnknownAttribute() throws DecoderException
, ClassReaderException
{
476 UnknownAttribute result
= new UnknownAttribute();
477 long attributeLength
= reader
.readUnsignedInt();
478 byte[] bytes
= new byte[(int) attributeLength
];
479 reader
.read(bytes
, 0, bytes
.length
);
480 result
.setBytes(bytes
);