Criado um novo pacote
[JavaDecompiler.git] / src / main / java / br / org / javadecompiler / decoder / Decoder.java
blob1570fc6738e91d9b9749420b84e7e50b487389e0
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;
51 this.reader = reader;
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 {
61 reader.reset();
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());
72 decodeConstantPool();
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));
83 else {
84 if (!"java/lang/Object".equals(ownerClass.getThisClass().getName().getValue()))
85 throw new DecoderException("Class without a super class");
88 decodeInterfaces();
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);
109 reader.mark();
110 if (logger.isDebugEnabled())
111 logger.debug("Decoding constants: step 1");
113 int index;
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))
119 index++;
121 if (index > constants.length)
122 throw new DecoderException("Last constant cannot be of type Long or Double");
125 reader.rollback();
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))
134 index++;
138 private Constant decodeConstantFirstPass(int index) throws DecoderException, ClassReaderException {
139 int tagValue = reader.readUnsignedByte();
140 int size = 0;
142 Constant constant = createNewConstantByTag(tagValue);
144 constant.setOwnerClass(ownerClass);
145 constant.setIndex(index);
147 switch(tagValue) {
148 case ConstantTag.STRING_TAG:
149 case ConstantTag.CLASS_TAG:
150 size = 2;
151 break;
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:
158 size = 4;
159 break;
160 case ConstantTag.DOUBLE_TAG:
161 case ConstantTag.LONG_TAG:
162 size = 8;
163 break;
164 case ConstantTag.UTF8_TAG:
165 size = reader.readUnsignedShort();
166 break;
168 reader.skip(size);
169 return constant;
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) {
213 switch(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();
237 return null;
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]);
255 return result;
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]);
264 return result;
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);
283 return result;
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();
290 Attribute result;
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();
311 } else {
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);
322 return result;
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));
332 return result;
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");
359 return result;
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");
367 return result;
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);
382 return result;
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();
401 if (nameIndex != 0)
402 innerClass.setName((UTF8Constant) ownerClass.getConstantPool().getConstant(nameIndex));
403 innerClass.setAccessFlags(reader.readUnsignedShort());
404 result.getInnerClasses()[i] = innerClass;
406 return result;
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;
422 return result;
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;
444 return result;
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));
454 return result;
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");
462 return result;
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));
472 return result;
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);
481 return result;