| /* |
| * Copyright 2000-2014 JetBrains s.r.o. |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.jetbrains.java.decompiler.struct.consts; |
| |
| import org.jetbrains.java.decompiler.code.CodeConstants; |
| import org.jetbrains.java.decompiler.main.DecompilerContext; |
| import org.jetbrains.java.decompiler.modules.renamer.PoolInterceptor; |
| import org.jetbrains.java.decompiler.struct.gen.FieldDescriptor; |
| import org.jetbrains.java.decompiler.struct.gen.MethodDescriptor; |
| import org.jetbrains.java.decompiler.struct.gen.VarType; |
| import org.jetbrains.java.decompiler.util.DataInputFullStream; |
| |
| import java.io.DataInputStream; |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.List; |
| |
| public class ConstantPool { |
| |
| public static final int FIELD = 1; |
| public static final int METHOD = 2; |
| |
| private List<PooledConstant> pool = new ArrayList<PooledConstant>(); |
| private PoolInterceptor interceptor; |
| |
| |
| public ConstantPool(DataInputStream in) throws IOException { |
| int size = in.readUnsignedShort(); |
| int[] pass = new int[size]; |
| |
| // first dummy constant |
| pool.add(null); |
| |
| // first pass: read the elements |
| for (int i = 1; i < size; i++) { |
| byte tag = (byte)in.readUnsignedByte(); |
| |
| switch (tag) { |
| case CodeConstants.CONSTANT_Utf8: |
| pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Utf8, in.readUTF())); |
| break; |
| case CodeConstants.CONSTANT_Integer: |
| pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Integer, new Integer(in.readInt()))); |
| break; |
| case CodeConstants.CONSTANT_Float: |
| pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Float, new Float(in.readFloat()))); |
| break; |
| case CodeConstants.CONSTANT_Long: |
| pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Long, new Long(in.readLong()))); |
| pool.add(null); |
| i++; |
| break; |
| case CodeConstants.CONSTANT_Double: |
| pool.add(new PrimitiveConstant(CodeConstants.CONSTANT_Double, new Double(in.readDouble()))); |
| pool.add(null); |
| i++; |
| break; |
| case CodeConstants.CONSTANT_Class: |
| case CodeConstants.CONSTANT_String: |
| case CodeConstants.CONSTANT_MethodType: |
| pool.add(new PrimitiveConstant(tag, in.readUnsignedShort())); |
| pass[i] = 1; |
| break; |
| case CodeConstants.CONSTANT_Fieldref: |
| case CodeConstants.CONSTANT_Methodref: |
| case CodeConstants.CONSTANT_InterfaceMethodref: |
| case CodeConstants.CONSTANT_NameAndType: |
| case CodeConstants.CONSTANT_InvokeDynamic: |
| pool.add(new LinkConstant(tag, in.readUnsignedShort(), in.readUnsignedShort())); |
| if (tag == CodeConstants.CONSTANT_NameAndType) { |
| pass[i] = 1; |
| } |
| else { |
| pass[i] = 2; |
| } |
| break; |
| case CodeConstants.CONSTANT_MethodHandle: |
| pool.add(new LinkConstant(tag, in.readUnsignedByte(), in.readUnsignedShort())); |
| pass[i] = 3; |
| break; |
| } |
| } |
| |
| // resolving complex pool elements |
| for (int passIndex = 1; passIndex <= 3; passIndex++) { |
| for (int i = 1; i < size; i++) { |
| if (pass[i] == passIndex) { |
| pool.get(i).resolveConstant(this); |
| } |
| } |
| } |
| |
| // get global constant pool interceptor instance, if any available |
| interceptor = DecompilerContext.getPoolInterceptor(); |
| } |
| |
| public static void skipPool(DataInputFullStream in) throws IOException { |
| int size = in.readUnsignedShort(); |
| |
| for (int i = 1; i < size; i++) { |
| switch (in.readUnsignedByte()) { |
| case CodeConstants.CONSTANT_Utf8: |
| in.readUTF(); |
| break; |
| case CodeConstants.CONSTANT_Integer: |
| case CodeConstants.CONSTANT_Float: |
| case CodeConstants.CONSTANT_Fieldref: |
| case CodeConstants.CONSTANT_Methodref: |
| case CodeConstants.CONSTANT_InterfaceMethodref: |
| case CodeConstants.CONSTANT_NameAndType: |
| case CodeConstants.CONSTANT_InvokeDynamic: |
| in.discard(4); |
| break; |
| case CodeConstants.CONSTANT_Long: |
| case CodeConstants.CONSTANT_Double: |
| in.discard(8); |
| i++; |
| break; |
| case CodeConstants.CONSTANT_Class: |
| case CodeConstants.CONSTANT_String: |
| case CodeConstants.CONSTANT_MethodType: |
| in.discard(2); |
| break; |
| case CodeConstants.CONSTANT_MethodHandle: |
| in.discard(3); |
| } |
| } |
| } |
| |
| public int size() { |
| return pool.size(); |
| } |
| |
| public String[] getClassElement(int elementType, String className, int nameIndex, int descriptorIndex) { |
| String elementName = ((PrimitiveConstant)getConstant(nameIndex)).getString(); |
| String descriptor = ((PrimitiveConstant)getConstant(descriptorIndex)).getString(); |
| |
| if (interceptor != null) { |
| String newElement = interceptor.getName(className + " " + elementName + " " + descriptor); |
| if (newElement != null) { |
| elementName = newElement.split(" ")[1]; |
| } |
| |
| int type = elementType == FIELD ? CodeConstants.CONSTANT_Fieldref : CodeConstants.CONSTANT_Methodref; |
| String newDescriptor = buildNewDescriptor(type, descriptor); |
| if (newDescriptor != null) { |
| descriptor = newDescriptor; |
| } |
| } |
| |
| return new String[]{elementName, descriptor}; |
| } |
| |
| public PooledConstant getConstant(int index) { |
| return pool.get(index); |
| } |
| |
| public PrimitiveConstant getPrimitiveConstant(int index) { |
| PrimitiveConstant cn = (PrimitiveConstant)getConstant(index); |
| |
| if (cn != null && interceptor != null) { |
| if (cn.type == CodeConstants.CONSTANT_Class) { |
| String newName = buildNewClassname(cn.getString()); |
| if (newName != null) { |
| cn = new PrimitiveConstant(CodeConstants.CONSTANT_Class, newName); |
| } |
| } |
| } |
| |
| return cn; |
| } |
| |
| public LinkConstant getLinkConstant(int index) { |
| LinkConstant ln = (LinkConstant)getConstant(index); |
| |
| if (ln != null && interceptor != null && |
| (ln.type == CodeConstants.CONSTANT_Fieldref || |
| ln.type == CodeConstants.CONSTANT_Methodref || |
| ln.type == CodeConstants.CONSTANT_InterfaceMethodref)) { |
| String newClassName = buildNewClassname(ln.classname); |
| String newElement = interceptor.getName(ln.classname + " " + ln.elementname + " " + ln.descriptor); |
| String newDescriptor = buildNewDescriptor(ln.type, ln.descriptor); |
| |
| if (newClassName != null || newElement != null || newDescriptor != null) { |
| String className = newClassName == null ? ln.classname : newClassName; |
| String elementName = newElement == null ? ln.elementname : newElement.split(" ")[1]; |
| String descriptor = newDescriptor == null ? ln.descriptor : newDescriptor; |
| ln = new LinkConstant(ln.type, className, elementName, descriptor); |
| } |
| } |
| |
| return ln; |
| } |
| |
| private String buildNewClassname(String className) { |
| VarType vt = new VarType(className, true); |
| |
| String newName = interceptor.getName(vt.value); |
| if (newName != null) { |
| StringBuilder buffer = new StringBuilder(); |
| |
| if (vt.arraydim > 0) { |
| for (int i = 0; i < vt.arraydim; i++) { |
| buffer.append("["); |
| } |
| |
| buffer.append("L").append(newName).append(";"); |
| } |
| else { |
| buffer.append(newName); |
| } |
| |
| return buffer.toString(); |
| } |
| |
| return null; |
| } |
| |
| private String buildNewDescriptor(int type, String descriptor) { |
| boolean updated = false; |
| |
| if (type == CodeConstants.CONSTANT_Fieldref) { |
| FieldDescriptor fd = FieldDescriptor.parseDescriptor(descriptor); |
| |
| VarType fType = fd.type; |
| if (fType.type == CodeConstants.TYPE_OBJECT) { |
| String newClassName = buildNewClassname(fType.value); |
| if (newClassName != null) { |
| fType.value = newClassName; |
| updated = true; |
| } |
| } |
| |
| if (updated) { |
| return fd.getDescriptor(); |
| } |
| } |
| else { |
| MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor); |
| |
| // parameters |
| for (VarType paramType : md.params) { |
| if (paramType.type == CodeConstants.TYPE_OBJECT) { |
| String newClassName = buildNewClassname(paramType.value); |
| if (newClassName != null) { |
| paramType.value = newClassName; |
| updated = true; |
| } |
| } |
| } |
| |
| // return value |
| if (md.ret.type == CodeConstants.TYPE_OBJECT) { |
| String newClassName = buildNewClassname(md.ret.value); |
| if (newClassName != null) { |
| md.ret.value = newClassName; |
| updated = true; |
| } |
| } |
| |
| if (updated) { |
| return md.getDescriptor(); |
| } |
| } |
| |
| return null; |
| } |
| } |