summaryrefslogtreecommitdiff
path: root/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java')
-rw-r--r--plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java173
1 files changed, 173 insertions, 0 deletions
diff --git a/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java
new file mode 100644
index 000000000000..70254d82977a
--- /dev/null
+++ b/plugins/java-decompiler/engine/src/org/jetbrains/java/decompiler/struct/lazy/LazyLoader.java
@@ -0,0 +1,173 @@
+/*
+ * 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.lazy;
+
+import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider;
+import org.jetbrains.java.decompiler.struct.StructMethod;
+import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
+import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
+import org.jetbrains.java.decompiler.util.DataInputFullStream;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+public class LazyLoader {
+
+ private final Map<String, Link> mapClassLinks = new HashMap<String, Link>();
+ private final IBytecodeProvider provider;
+
+ public LazyLoader(IBytecodeProvider provider) {
+ this.provider = provider;
+ }
+
+ public void addClassLink(String classname, Link link) {
+ mapClassLinks.put(classname, link);
+ }
+
+ public void removeClassLink(String classname) {
+ mapClassLinks.remove(classname);
+ }
+
+ public Link getClassLink(String classname) {
+ return mapClassLinks.get(classname);
+ }
+
+ public ConstantPool loadPool(String classname) {
+ try {
+ DataInputFullStream in = getClassStream(classname);
+ if (in == null) return null;
+
+ try {
+ in.discard(8);
+ return new ConstantPool(in);
+ }
+ finally {
+ in.close();
+ }
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public byte[] loadBytecode(StructMethod mt, int codeFullLength) {
+ String className = mt.getClassStruct().qualifiedName;
+
+ try {
+ DataInputFullStream in = getClassStream(className);
+ if (in == null) return null;
+
+ try {
+ in.discard(8);
+
+ ConstantPool pool = mt.getClassStruct().getPool();
+ if (pool == null) {
+ pool = new ConstantPool(in);
+ }
+ else {
+ ConstantPool.skipPool(in);
+ }
+
+ in.discard(6);
+
+ // interfaces
+ in.discard(in.readUnsignedShort() * 2);
+
+ // fields
+ int size = in.readUnsignedShort();
+ for (int i = 0; i < size; i++) {
+ in.discard(6);
+ skipAttributes(in);
+ }
+
+ // methods
+ size = in.readUnsignedShort();
+ for (int i = 0; i < size; i++) {
+ in.discard(2);
+
+ int nameIndex = in.readUnsignedShort();
+ int descriptorIndex = in.readUnsignedShort();
+
+ String[] values = pool.getClassElement(ConstantPool.METHOD, className, nameIndex, descriptorIndex);
+ if (!mt.getName().equals(values[0]) || !mt.getDescriptor().equals(values[1])) {
+ skipAttributes(in);
+ continue;
+ }
+
+ int attrSize = in.readUnsignedShort();
+ for (int j = 0; j < attrSize; j++) {
+ int attrNameIndex = in.readUnsignedShort();
+ String attrName = pool.getPrimitiveConstant(attrNameIndex).getString();
+ if (!StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrName)) {
+ in.discard(in.readInt());
+ continue;
+ }
+
+ in.discard(12);
+ byte[] code = new byte[codeFullLength];
+ in.readFull(code);
+ return code;
+ }
+
+ break;
+ }
+ }
+ finally {
+ in.close();
+ }
+
+ return null;
+ }
+ catch (IOException ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ public DataInputFullStream getClassStream(String externalPath, String internalPath) throws IOException {
+ byte[] bytes = provider.getBytecode(externalPath, internalPath);
+ return new DataInputFullStream(bytes);
+ }
+
+ public DataInputFullStream getClassStream(String qualifiedClassName) throws IOException {
+ Link link = mapClassLinks.get(qualifiedClassName);
+ return link == null ? null : getClassStream(link.externalPath, link.internalPath);
+ }
+
+ public static void skipAttributes(DataInputFullStream in) throws IOException {
+ int length = in.readUnsignedShort();
+ for (int i = 0; i < length; i++) {
+ in.discard(2);
+ in.discard(in.readInt());
+ }
+ }
+
+
+ public static class Link {
+ public static final int CLASS = 1;
+ public static final int ENTRY = 2;
+
+ public int type;
+ public String externalPath;
+ public String internalPath;
+
+ public Link(int type, String externalPath, String internalPath) {
+ this.type = type;
+ this.externalPath = externalPath;
+ this.internalPath = internalPath;
+ }
+ }
+}