java-decompiler: fixes and cleanups
- unified attribute loading code - common methods for checking member flags - verifying skip() - correct resource closing - typos
This commit is contained in:
@@ -18,6 +18,7 @@ package org.jetbrains.java.decompiler.struct;
|
||||
import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver;
|
||||
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
|
||||
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader.Link;
|
||||
import org.jetbrains.java.decompiler.util.DataInputFullStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
@@ -98,7 +99,15 @@ public class ContextUnit {
|
||||
List<StructClass> lstClasses = new ArrayList<StructClass>();
|
||||
for (StructClass cl : classes) {
|
||||
String oldname = cl.qualifiedName;
|
||||
StructClass newcl = new StructClass(loader.getClassStream(oldname), cl.isOwn(), loader);
|
||||
|
||||
StructClass newcl;
|
||||
DataInputFullStream in = loader.getClassStream(oldname);
|
||||
try {
|
||||
newcl = new StructClass(in, cl.isOwn(), loader);
|
||||
}
|
||||
finally {
|
||||
in.close();
|
||||
}
|
||||
|
||||
lstClasses.add(newcl);
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
package org.jetbrains.java.decompiler.struct;
|
||||
|
||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
|
||||
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
||||
import org.jetbrains.java.decompiler.struct.consts.PrimitiveConstant;
|
||||
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
|
||||
@@ -24,94 +23,96 @@ import org.jetbrains.java.decompiler.util.DataInputFullStream;
|
||||
import org.jetbrains.java.decompiler.util.InterpreterUtil;
|
||||
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
/*
|
||||
ClassFile {
|
||||
u4 magic;
|
||||
u2 minor_version;
|
||||
u2 major_version;
|
||||
u2 constant_pool_count;
|
||||
cp_info constant_pool[constant_pool_count-1];
|
||||
u2 access_flags;
|
||||
u2 this_class;
|
||||
u2 super_class;
|
||||
u2 interfaces_count;
|
||||
u2 interfaces[interfaces_count];
|
||||
u2 fields_count;
|
||||
field_info fields[fields_count];
|
||||
u2 methods_count;
|
||||
method_info methods[methods_count];
|
||||
u2 attributes_count;
|
||||
attribute_info attributes[attributes_count];
|
||||
}
|
||||
class_file {
|
||||
u4 magic;
|
||||
u2 minor_version;
|
||||
u2 major_version;
|
||||
u2 constant_pool_count;
|
||||
cp_info constant_pool[constant_pool_count-1];
|
||||
u2 access_flags;
|
||||
u2 this_class;
|
||||
u2 super_class;
|
||||
u2 interfaces_count;
|
||||
u2 interfaces[interfaces_count];
|
||||
u2 fields_count;
|
||||
field_info fields[fields_count];
|
||||
u2 methods_count;
|
||||
method_info methods[methods_count];
|
||||
u2 attributes_count;
|
||||
attribute_info attributes[attributes_count];
|
||||
}
|
||||
*/
|
||||
public class StructClass extends StructMember {
|
||||
|
||||
public class StructClass {
|
||||
public final String qualifiedName;
|
||||
public final PrimitiveConstant superClass;
|
||||
|
||||
// *****************************************************************************
|
||||
// public fields
|
||||
// *****************************************************************************
|
||||
|
||||
public int minor_version;
|
||||
|
||||
public int major_version;
|
||||
|
||||
public int access_flags;
|
||||
|
||||
public int this_class;
|
||||
|
||||
public int super_class;
|
||||
|
||||
public PrimitiveConstant thisClass;
|
||||
|
||||
public PrimitiveConstant superClass;
|
||||
|
||||
public String qualifiedName;
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// private fields
|
||||
// *****************************************************************************
|
||||
private final boolean own;
|
||||
private final LazyLoader loader;
|
||||
private final int minorVersion;
|
||||
private final int majorVersion;
|
||||
private final int[] interfaces;
|
||||
private final String[] interfaceNames;
|
||||
private final VBStyleCollection<StructField, String> fields;
|
||||
private final VBStyleCollection<StructMethod, String> methods;
|
||||
|
||||
private ConstantPool pool;
|
||||
|
||||
private int[] interfaces;
|
||||
|
||||
private String[] interfaceNames;
|
||||
|
||||
private VBStyleCollection<StructField, String> fields = new VBStyleCollection<StructField, String>();
|
||||
|
||||
private VBStyleCollection<StructMethod, String> methods = new VBStyleCollection<StructMethod, String>();
|
||||
|
||||
private VBStyleCollection<StructGeneralAttribute, String> attributes = new VBStyleCollection<StructGeneralAttribute, String>();
|
||||
|
||||
private boolean own = true;
|
||||
|
||||
private LazyLoader loader;
|
||||
|
||||
// *****************************************************************************
|
||||
// constructors
|
||||
// *****************************************************************************
|
||||
|
||||
public StructClass(String filename, boolean own, LazyLoader loader) throws IOException {
|
||||
this(new FileInputStream(filename), own, loader);
|
||||
}
|
||||
|
||||
public StructClass(InputStream inStream, boolean own, LazyLoader loader) throws IOException {
|
||||
this(new DataInputFullStream(inStream), own, loader);
|
||||
}
|
||||
|
||||
public StructClass(DataInputFullStream inStream, boolean own, LazyLoader loader) throws IOException {
|
||||
public StructClass(DataInputFullStream in, boolean own, LazyLoader loader) throws IOException {
|
||||
this.own = own;
|
||||
this.loader = loader;
|
||||
|
||||
initStruct(inStream);
|
||||
}
|
||||
in.discard(4);
|
||||
|
||||
// *****************************************************************************
|
||||
// public methods
|
||||
// *****************************************************************************
|
||||
minorVersion = in.readUnsignedShort();
|
||||
majorVersion = in.readUnsignedShort();
|
||||
|
||||
pool = new ConstantPool(in);
|
||||
|
||||
accessFlags = in.readUnsignedShort();
|
||||
int thisClassIdx = in.readUnsignedShort();
|
||||
int superClassIdx = in.readUnsignedShort();
|
||||
qualifiedName = pool.getPrimitiveConstant(thisClassIdx).getString();
|
||||
superClass = pool.getPrimitiveConstant(superClassIdx);
|
||||
|
||||
// interfaces
|
||||
int length = in.readUnsignedShort();
|
||||
interfaces = new int[length];
|
||||
interfaceNames = new String[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
interfaces[i] = in.readUnsignedShort();
|
||||
interfaceNames[i] = pool.getPrimitiveConstant(interfaces[i]).getString();
|
||||
}
|
||||
|
||||
// fields
|
||||
length = in.readUnsignedShort();
|
||||
fields = new VBStyleCollection<StructField, String>();
|
||||
for (int i = 0; i < length; i++) {
|
||||
StructField field = new StructField(in, this);
|
||||
fields.addWithKey(field, InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor()));
|
||||
}
|
||||
|
||||
// methods
|
||||
length = in.readUnsignedShort();
|
||||
methods = new VBStyleCollection<StructMethod, String>();
|
||||
for (int i = 0; i < length; i++) {
|
||||
StructMethod method = new StructMethod(in, this);
|
||||
methods.addWithKey(method, InterpreterUtil.makeUniqueKey(method.getName(), method.getDescriptor()));
|
||||
}
|
||||
|
||||
// attributes
|
||||
attributes = readAttributes(in, pool);
|
||||
|
||||
releaseResources();
|
||||
}
|
||||
|
||||
public boolean hasField(String name, String descriptor) {
|
||||
return getField(name, descriptor) != null;
|
||||
@@ -129,45 +130,6 @@ public class StructClass {
|
||||
return methods.getWithKey(InterpreterUtil.makeUniqueKey(name, descriptor));
|
||||
}
|
||||
|
||||
public void writeToFile(File file) throws IOException {
|
||||
DataOutputStream out = new DataOutputStream(new FileOutputStream(file));
|
||||
writeToOutputStream(out);
|
||||
out.close();
|
||||
}
|
||||
|
||||
public void writeToOutputStream(DataOutputStream out) throws IOException {
|
||||
|
||||
out.writeInt(0xCAFEBABE);
|
||||
out.writeShort(minor_version);
|
||||
out.writeShort(major_version);
|
||||
|
||||
getPool().writeToOutputStream(out);
|
||||
|
||||
out.writeShort(access_flags);
|
||||
out.writeShort(this_class);
|
||||
out.writeShort(super_class);
|
||||
|
||||
out.writeShort(interfaces.length);
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
out.writeShort(interfaces[i]);
|
||||
}
|
||||
|
||||
out.writeShort(fields.size());
|
||||
for (int i = 0; i < fields.size(); i++) {
|
||||
fields.get(i).writeToStream(out);
|
||||
}
|
||||
|
||||
out.writeShort(methods.size());
|
||||
for (int i = 0; i < methods.size(); i++) {
|
||||
methods.get(i).writeToStream(out);
|
||||
}
|
||||
|
||||
out.writeShort(attributes.size());
|
||||
for (StructGeneralAttribute attr : attributes) {
|
||||
attr.writeToStream(out);
|
||||
}
|
||||
}
|
||||
|
||||
public String getInterface(int i) {
|
||||
return interfaceNames[i];
|
||||
}
|
||||
@@ -178,118 +140,10 @@ public class StructClass {
|
||||
}
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// private methods
|
||||
// *****************************************************************************
|
||||
|
||||
private void initStruct(DataInputFullStream in) throws IOException {
|
||||
|
||||
in.skip(4);
|
||||
|
||||
this.minor_version = in.readUnsignedShort();
|
||||
this.major_version = in.readUnsignedShort();
|
||||
|
||||
pool = new ConstantPool(in);
|
||||
|
||||
this.access_flags = in.readUnsignedShort();
|
||||
|
||||
this_class = in.readUnsignedShort();
|
||||
thisClass = pool.getPrimitiveConstant(this_class);
|
||||
qualifiedName = thisClass.getString();
|
||||
|
||||
super_class = in.readUnsignedShort();
|
||||
superClass = pool.getPrimitiveConstant(super_class);
|
||||
|
||||
// interfaces
|
||||
int length = in.readUnsignedShort();
|
||||
int[] arrInterfaces = new int[length];
|
||||
String[] arrInterfaceNames = new String[length];
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
arrInterfaces[i] = in.readUnsignedShort();
|
||||
arrInterfaceNames[i] = pool.getPrimitiveConstant(arrInterfaces[i]).getString();
|
||||
}
|
||||
this.interfaces = arrInterfaces;
|
||||
this.interfaceNames = arrInterfaceNames;
|
||||
|
||||
// fields
|
||||
VBStyleCollection<StructField, String> lstFields = new VBStyleCollection<StructField, String>();
|
||||
length = in.readUnsignedShort();
|
||||
for (int i = 0; i < length; i++) {
|
||||
StructField field = new StructField();
|
||||
field.access_flags = in.readUnsignedShort();
|
||||
field.name_index = in.readUnsignedShort();
|
||||
field.descriptor_index = in.readUnsignedShort();
|
||||
|
||||
field.initStrings(pool, this_class);
|
||||
|
||||
field.setAttributes(readAttributes(in));
|
||||
|
||||
lstFields.addWithKey(field, InterpreterUtil.makeUniqueKey(field.getName(), field.getDescriptor()));
|
||||
}
|
||||
this.fields = lstFields;
|
||||
|
||||
// methods
|
||||
length = in.readUnsignedShort();
|
||||
for (int i = 0; i < length; i++) {
|
||||
StructMethod meth = new StructMethod(in, own, this);
|
||||
|
||||
//if(qualifiedName.endsWith("JUnitStatusLine") && !meth.getName().equals("onProcessStarted") && !meth.getName().startsWith("access")) {
|
||||
//if(!meth.getName().equals("run")) {
|
||||
// continue;
|
||||
//}
|
||||
|
||||
methods.addWithKey(meth, InterpreterUtil.makeUniqueKey(meth.getName(), meth.getDescriptor()));
|
||||
}
|
||||
|
||||
// attributes
|
||||
this.attributes = readAttributes(in);
|
||||
|
||||
|
||||
// release memory
|
||||
if (loader != null) {
|
||||
pool = null;
|
||||
}
|
||||
}
|
||||
|
||||
private VBStyleCollection<StructGeneralAttribute, String> readAttributes(DataInputFullStream in) throws IOException {
|
||||
|
||||
VBStyleCollection<StructGeneralAttribute, String> lstAttribute = new VBStyleCollection<StructGeneralAttribute, String>();
|
||||
|
||||
int length = in.readUnsignedShort();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int attr_nameindex = in.readUnsignedShort();
|
||||
String attrname = pool.getPrimitiveConstant(attr_nameindex).getString();
|
||||
|
||||
StructGeneralAttribute attr = StructGeneralAttribute.getMatchingAttributeInstance(attr_nameindex, attrname);
|
||||
|
||||
if (attr != null) {
|
||||
byte[] arr = new byte[in.readInt()];
|
||||
in.readFull(arr);
|
||||
attr.setInfo(arr);
|
||||
|
||||
attr.initContent(pool);
|
||||
lstAttribute.addWithKey(attr, attr.getName());
|
||||
}
|
||||
else {
|
||||
in.skip(in.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
return lstAttribute;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// getter and setter methods
|
||||
// *****************************************************************************
|
||||
|
||||
public ConstantPool getPool() {
|
||||
|
||||
if (pool == null && loader != null) {
|
||||
pool = loader.loadPool(qualifiedName);
|
||||
}
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
@@ -309,10 +163,6 @@ public class StructClass {
|
||||
return fields;
|
||||
}
|
||||
|
||||
public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public boolean isOwn() {
|
||||
return own;
|
||||
}
|
||||
@@ -322,15 +172,15 @@ public class StructClass {
|
||||
}
|
||||
|
||||
public boolean isVersionGE_1_5() {
|
||||
return (major_version > 48 || (major_version == 48 && minor_version > 0)); // FIXME: check second condition
|
||||
return (majorVersion > 48 || (majorVersion == 48 && minorVersion > 0)); // FIXME: check second condition
|
||||
}
|
||||
|
||||
public boolean isVersionGE_1_7() {
|
||||
return (major_version >= 51);
|
||||
return (majorVersion >= 51);
|
||||
}
|
||||
|
||||
public int getBytecodeVersion() {
|
||||
switch (major_version) {
|
||||
switch (majorVersion) {
|
||||
case 52:
|
||||
return CodeConstants.BYTECODE_JAVA_8;
|
||||
case 51:
|
||||
|
||||
@@ -19,6 +19,7 @@ import org.jetbrains.java.decompiler.main.DecompilerContext;
|
||||
import org.jetbrains.java.decompiler.main.extern.IDecompilatSaver;
|
||||
import org.jetbrains.java.decompiler.main.extern.IFernflowerLogger;
|
||||
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
|
||||
import org.jetbrains.java.decompiler.util.DataInputFullStream;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -136,7 +137,15 @@ public class StructContext {
|
||||
|
||||
if (filename.endsWith(".class")) {
|
||||
try {
|
||||
StructClass cl = new StructClass(loader.getClassStream(file.getAbsolutePath(), null), isOwn, loader);
|
||||
StructClass cl;
|
||||
|
||||
DataInputFullStream in = loader.getClassStream(file.getAbsolutePath(), null);
|
||||
try {
|
||||
cl = new StructClass(in, isOwn, loader);
|
||||
}
|
||||
finally {
|
||||
in.close();
|
||||
}
|
||||
|
||||
classes.put(cl.qualifiedName, cl);
|
||||
unit.addClass(cl, filename);
|
||||
@@ -145,8 +154,8 @@ public class StructContext {
|
||||
isClass = true;
|
||||
}
|
||||
catch (IOException ex) {
|
||||
DecompilerContext.getLogger()
|
||||
.writeMessage("Invalid class file: " + (path.length() > 0 ? path + "/" : "") + filename, IFernflowerLogger.ERROR);
|
||||
DecompilerContext.getLogger().writeMessage("Invalid class file: " + (path.length() > 0 ? path + "/" : "") + filename,
|
||||
IFernflowerLogger.ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,96 +15,44 @@
|
||||
*/
|
||||
package org.jetbrains.java.decompiler.struct;
|
||||
|
||||
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
|
||||
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
||||
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||
import org.jetbrains.java.decompiler.util.DataInputFullStream;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
field_info {
|
||||
u2 access_flags;
|
||||
u2 name_index;
|
||||
u2 descriptor_index;
|
||||
u2 attributes_count;
|
||||
attribute_info attributes[attributes_count];
|
||||
}
|
||||
field_info {
|
||||
u2 access_flags;
|
||||
u2 name_index;
|
||||
u2 descriptor_index;
|
||||
u2 attributes_count;
|
||||
attribute_info attributes[attributes_count];
|
||||
}
|
||||
*/
|
||||
public class StructField extends StructMember {
|
||||
|
||||
public class StructField {
|
||||
private final String name;
|
||||
private final String descriptor;
|
||||
|
||||
// *****************************************************************************
|
||||
// public fields
|
||||
// *****************************************************************************
|
||||
|
||||
public int access_flags;
|
||||
public int name_index;
|
||||
public int descriptor_index;
|
||||
public StructField(DataInputFullStream in, StructClass clStruct) throws IOException {
|
||||
accessFlags = in.readUnsignedShort();
|
||||
int nameIndex = in.readUnsignedShort();
|
||||
int descriptorIndex = in.readUnsignedShort();
|
||||
|
||||
private String name;
|
||||
private String descriptor;
|
||||
|
||||
// *****************************************************************************
|
||||
// private fields
|
||||
// *****************************************************************************
|
||||
|
||||
private VBStyleCollection<StructGeneralAttribute, String> attributes;
|
||||
|
||||
// *****************************************************************************
|
||||
// constructors
|
||||
// *****************************************************************************
|
||||
|
||||
public StructField() {
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// public methods
|
||||
// *****************************************************************************
|
||||
|
||||
public void writeToStream(DataOutputStream out) throws IOException {
|
||||
|
||||
out.writeShort(access_flags);
|
||||
out.writeShort(name_index);
|
||||
out.writeShort(descriptor_index);
|
||||
|
||||
out.writeShort(attributes.size());
|
||||
for (StructGeneralAttribute attr : attributes) {
|
||||
attr.writeToStream(out);
|
||||
}
|
||||
}
|
||||
|
||||
public void initStrings(ConstantPool pool, int class_index) {
|
||||
String[] values = pool.getClassElement(ConstantPool.FIELD, class_index, name_index, descriptor_index);
|
||||
ConstantPool pool = clStruct.getPool();
|
||||
String[] values = pool.getClassElement(ConstantPool.FIELD, clStruct.qualifiedName, nameIndex, descriptorIndex);
|
||||
name = values[0];
|
||||
descriptor = values[1];
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// getter and setter methods
|
||||
// *****************************************************************************
|
||||
|
||||
public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public void setAttributes(VBStyleCollection<StructGeneralAttribute, String> attributes) {
|
||||
this.attributes = attributes;
|
||||
}
|
||||
|
||||
public String getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
public void setDescriptor(String descriptor) {
|
||||
this.descriptor = descriptor;
|
||||
attributes = readAttributes(in, pool);
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
public String getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
}
|
||||
|
||||
87
src/org/jetbrains/java/decompiler/struct/StructMember.java
Normal file
87
src/org/jetbrains/java/decompiler/struct/StructMember.java
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import org.jetbrains.java.decompiler.code.CodeConstants;
|
||||
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
|
||||
import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
|
||||
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
||||
import org.jetbrains.java.decompiler.util.DataInputFullStream;
|
||||
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class StructMember {
|
||||
|
||||
protected int accessFlags;
|
||||
protected VBStyleCollection<StructGeneralAttribute, String> attributes;
|
||||
|
||||
|
||||
public int getAccessFlags() {
|
||||
return accessFlags;
|
||||
}
|
||||
|
||||
public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public boolean hasModifier(int modifier) {
|
||||
return (accessFlags & modifier) == modifier;
|
||||
}
|
||||
|
||||
public boolean isSynthetic() {
|
||||
return hasModifier(CodeConstants.ACC_SYNTHETIC) || attributes.containsKey(StructGeneralAttribute.ATTRIBUTE_SYNTHETIC);
|
||||
}
|
||||
|
||||
protected VBStyleCollection<StructGeneralAttribute, String> readAttributes(DataInputFullStream in, ConstantPool pool) throws IOException {
|
||||
VBStyleCollection<StructGeneralAttribute, String> attributes = new VBStyleCollection<StructGeneralAttribute, String>();
|
||||
|
||||
int length = in.readUnsignedShort();
|
||||
for (int i = 0; i < length; i++) {
|
||||
int nameIndex = in.readUnsignedShort();
|
||||
String name = pool.getPrimitiveConstant(nameIndex).getString();
|
||||
|
||||
StructGeneralAttribute attribute = readAttribute(in, pool, name);
|
||||
|
||||
if (attribute != null) {
|
||||
if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name) && attributes.containsKey(name)) {
|
||||
// merge all variable tables
|
||||
StructLocalVariableTableAttribute table = (StructLocalVariableTableAttribute)attributes.getWithKey(name);
|
||||
table.addLocalVariableTable((StructLocalVariableTableAttribute)attribute);
|
||||
}
|
||||
else {
|
||||
attributes.addWithKey(attribute, attribute.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return attributes;
|
||||
}
|
||||
|
||||
protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantPool pool, String name) throws IOException {
|
||||
StructGeneralAttribute attribute = StructGeneralAttribute.createAttribute(name);
|
||||
if (attribute == null) {
|
||||
in.discard(in.readInt());
|
||||
}
|
||||
else {
|
||||
byte[] data = new byte[in.readInt()];
|
||||
in.readFull(data);
|
||||
attribute.setInfo(data);
|
||||
attribute.initContent(pool);
|
||||
}
|
||||
return attribute;
|
||||
}
|
||||
}
|
||||
@@ -17,267 +17,106 @@ package org.jetbrains.java.decompiler.struct;
|
||||
|
||||
import org.jetbrains.java.decompiler.code.*;
|
||||
import org.jetbrains.java.decompiler.struct.attr.StructGeneralAttribute;
|
||||
import org.jetbrains.java.decompiler.struct.attr.StructLocalVariableTableAttribute;
|
||||
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
||||
import org.jetbrains.java.decompiler.struct.lazy.LazyLoader;
|
||||
import org.jetbrains.java.decompiler.util.DataInputFullStream;
|
||||
import org.jetbrains.java.decompiler.util.VBStyleCollection;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.java.decompiler.code.CodeConstants.*;
|
||||
|
||||
/*
|
||||
method_info {
|
||||
u2 access_flags;
|
||||
u2 name_index;
|
||||
u2 descriptor_index;
|
||||
u2 attributes_count;
|
||||
attribute_info attributes[attributes_count];
|
||||
}
|
||||
method_info {
|
||||
u2 access_flags;
|
||||
u2 name_index;
|
||||
u2 descriptor_index;
|
||||
u2 attributes_count;
|
||||
attribute_info attributes[attributes_count];
|
||||
}
|
||||
*/
|
||||
public class StructMethod extends StructMember {
|
||||
|
||||
public class StructMethod implements CodeConstants {
|
||||
private static final int[] opr_iconst = {-1, 0, 1, 2, 3, 4, 5};
|
||||
private static final int[] opr_loadstore = {0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3};
|
||||
private static final int[] opcs_load = {opc_iload, opc_lload, opc_fload, opc_dload, opc_aload};
|
||||
private static final int[] opcs_store = {opc_istore, opc_lstore, opc_fstore, opc_dstore, opc_astore};
|
||||
|
||||
// *****************************************************************************
|
||||
// public fields
|
||||
// *****************************************************************************
|
||||
|
||||
public int name_index;
|
||||
|
||||
public int descriptor_index;
|
||||
|
||||
// *****************************************************************************
|
||||
// private fields
|
||||
// *****************************************************************************
|
||||
|
||||
private static final int[] opr_iconst = new int[]{-1, 0, 1, 2, 3, 4, 5};
|
||||
|
||||
private static final int[] opr_loadstore = new int[]{0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3};
|
||||
|
||||
private static final int[] opcs_load = new int[]{opc_iload, opc_lload, opc_fload, opc_dload, opc_aload};
|
||||
|
||||
private static final int[] opcs_store = new int[]{opc_istore, opc_lstore, opc_fstore, opc_dstore, opc_astore};
|
||||
|
||||
|
||||
private int accessFlags;
|
||||
|
||||
private VBStyleCollection<StructGeneralAttribute, String> attributes;
|
||||
|
||||
private int localVariables;
|
||||
|
||||
private int maxStack;
|
||||
|
||||
private String name;
|
||||
|
||||
private String descriptor;
|
||||
|
||||
private InstructionSequence seq;
|
||||
private final StructClass classStruct;
|
||||
private final String name;
|
||||
private final String descriptor;
|
||||
|
||||
private boolean containsCode = false;
|
||||
|
||||
private StructClass classStruct;
|
||||
private int localVariables = 0;
|
||||
private int codeLength = 0;
|
||||
private int codeFullLength = 0;
|
||||
private InstructionSequence seq;
|
||||
private boolean expanded = false;
|
||||
|
||||
|
||||
// lazy properties
|
||||
private boolean lazy;
|
||||
|
||||
private boolean expanded;
|
||||
|
||||
private byte[] code_content;
|
||||
|
||||
private int code_length = 0;
|
||||
|
||||
private int code_fulllength = 0;
|
||||
|
||||
// *****************************************************************************
|
||||
// constructors
|
||||
// *****************************************************************************
|
||||
|
||||
public StructMethod(DataInputFullStream in, boolean own, StructClass clstruct) throws IOException {
|
||||
this(in, true, own, clstruct);
|
||||
}
|
||||
|
||||
public StructMethod(DataInputFullStream in, boolean lazy, boolean own, StructClass clstruct) throws IOException {
|
||||
|
||||
this.lazy = lazy;
|
||||
this.expanded = !lazy;
|
||||
this.classStruct = clstruct;
|
||||
public StructMethod(DataInputFullStream in, StructClass clStruct) throws IOException {
|
||||
classStruct = clStruct;
|
||||
|
||||
accessFlags = in.readUnsignedShort();
|
||||
name_index = in.readUnsignedShort();
|
||||
descriptor_index = in.readUnsignedShort();
|
||||
int nameIndex = in.readUnsignedShort();
|
||||
int descriptorIndex = in.readUnsignedShort();
|
||||
|
||||
ConstantPool pool = clstruct.getPool();
|
||||
|
||||
initStrings(pool, clstruct.this_class);
|
||||
|
||||
VBStyleCollection<StructGeneralAttribute, String> lstAttribute = new VBStyleCollection<StructGeneralAttribute, String>();
|
||||
int len = in.readUnsignedShort();
|
||||
for (int i = 0; i < len; i++) {
|
||||
|
||||
int attr_nameindex = in.readUnsignedShort();
|
||||
String attrname = pool.getPrimitiveConstant(attr_nameindex).getString();
|
||||
|
||||
if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrname)) {
|
||||
if (!own) {
|
||||
// skip code in foreign classes
|
||||
in.skip(8);
|
||||
in.skip(in.readInt());
|
||||
in.skip(8 * in.readUnsignedShort());
|
||||
}
|
||||
else {
|
||||
containsCode = true;
|
||||
|
||||
in.skip(4);
|
||||
|
||||
maxStack = in.readUnsignedShort();
|
||||
localVariables = in.readUnsignedShort();
|
||||
|
||||
if (lazy) {
|
||||
code_length = in.readInt();
|
||||
|
||||
in.skip(code_length);
|
||||
|
||||
int exc_length = in.readUnsignedShort();
|
||||
code_fulllength = code_length + exc_length * 8 + 2;
|
||||
|
||||
in.skip(exc_length * 8);
|
||||
}
|
||||
else {
|
||||
seq = parseBytecode(in, in.readInt(), pool);
|
||||
}
|
||||
}
|
||||
|
||||
// code attributes
|
||||
int length = in.readUnsignedShort();
|
||||
for (int j = 0; j < length; j++) {
|
||||
int codeattr_nameindex = in.readUnsignedShort();
|
||||
String codeattrname = pool.getPrimitiveConstant(codeattr_nameindex).getString();
|
||||
|
||||
readAttribute(in, pool, lstAttribute, codeattr_nameindex, codeattrname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
readAttribute(in, pool, lstAttribute, attr_nameindex, attrname);
|
||||
}
|
||||
}
|
||||
|
||||
attributes = lstAttribute;
|
||||
}
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// public methods
|
||||
// *****************************************************************************
|
||||
|
||||
public void writeToStream(DataOutputStream out) throws IOException {
|
||||
|
||||
out.writeShort(accessFlags);
|
||||
out.writeShort(name_index);
|
||||
out.writeShort(descriptor_index);
|
||||
|
||||
out.writeShort(attributes.size());
|
||||
|
||||
for (StructGeneralAttribute attr : attributes) {
|
||||
if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(attr.getName())) {
|
||||
out.writeShort(attr.getAttribute_name_index());
|
||||
|
||||
if (lazy && !expanded) {
|
||||
out.writeInt(10 + code_content.length);
|
||||
out.writeShort(maxStack);
|
||||
out.writeShort(localVariables);
|
||||
out.writeInt(code_length);
|
||||
out.write(code_content);
|
||||
}
|
||||
else {
|
||||
ByteArrayOutputStream codeout = new ByteArrayOutputStream();
|
||||
seq.writeCodeToStream(new DataOutputStream(codeout));
|
||||
|
||||
ByteArrayOutputStream excout = new ByteArrayOutputStream();
|
||||
seq.writeExceptionsToStream(new DataOutputStream(excout));
|
||||
|
||||
out.writeInt(10 + codeout.size() + excout.size());
|
||||
|
||||
out.writeShort(maxStack);
|
||||
out.writeShort(localVariables);
|
||||
out.writeInt(codeout.size());
|
||||
codeout.writeTo(out);
|
||||
excout.writeTo(out);
|
||||
}
|
||||
// no attributes
|
||||
out.writeShort(0);
|
||||
}
|
||||
else {
|
||||
attr.writeToStream(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void readAttribute(DataInputFullStream in,
|
||||
ConstantPool pool,
|
||||
VBStyleCollection<StructGeneralAttribute, String> lstAttribute,
|
||||
int attr_nameindex,
|
||||
String attrname) throws IOException {
|
||||
|
||||
StructGeneralAttribute attribute = StructGeneralAttribute.getMatchingAttributeInstance(attr_nameindex, attrname);
|
||||
|
||||
if (attribute != null) {
|
||||
attrname = attribute.getName();
|
||||
|
||||
byte[] arr = new byte[in.readInt()];
|
||||
in.readFull(arr);
|
||||
attribute.setInfo(arr);
|
||||
|
||||
attribute.initContent(pool);
|
||||
|
||||
if (StructGeneralAttribute.ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(attrname) &&
|
||||
lstAttribute.containsKey(attrname)) {
|
||||
// merge all variable tables
|
||||
StructLocalVariableTableAttribute oldattr = (StructLocalVariableTableAttribute)lstAttribute.getWithKey(attrname);
|
||||
oldattr.addLocalVariableTable((StructLocalVariableTableAttribute)attribute);
|
||||
}
|
||||
else {
|
||||
lstAttribute.addWithKey(attribute, attribute.getName());
|
||||
}
|
||||
}
|
||||
else {
|
||||
in.skip(in.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
private void initStrings(ConstantPool pool, int class_index) {
|
||||
String[] values = pool.getClassElement(ConstantPool.METHOD, class_index, name_index, descriptor_index);
|
||||
ConstantPool pool = clStruct.getPool();
|
||||
String[] values = pool.getClassElement(ConstantPool.METHOD, clStruct.qualifiedName, nameIndex, descriptorIndex);
|
||||
name = values[0];
|
||||
descriptor = values[1];
|
||||
|
||||
attributes = readAttributes(in, pool);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StructGeneralAttribute readAttribute(DataInputFullStream in, ConstantPool pool, String name) throws IOException {
|
||||
if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(name)) {
|
||||
if (!classStruct.isOwn()) {
|
||||
// skip code in foreign classes
|
||||
in.discard(8);
|
||||
in.discard(in.readInt());
|
||||
in.discard(8 * in.readUnsignedShort());
|
||||
}
|
||||
else {
|
||||
containsCode = true;
|
||||
in.discard(6);
|
||||
localVariables = in.readUnsignedShort();
|
||||
codeLength = in.readInt();
|
||||
in.discard(codeLength);
|
||||
int exc_length = in.readUnsignedShort();
|
||||
in.discard(exc_length * 8);
|
||||
codeFullLength = codeLength + exc_length * 8 + 2;
|
||||
}
|
||||
|
||||
LazyLoader.skipAttributes(in);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
return super.readAttribute(in, pool, name);
|
||||
}
|
||||
|
||||
public void expandData() throws IOException {
|
||||
if (containsCode && lazy && !expanded) {
|
||||
|
||||
byte[] codearr = classStruct.getLoader().loadBytecode(this, code_fulllength);
|
||||
|
||||
seq = parseBytecode(new DataInputFullStream(new ByteArrayInputStream(codearr)), code_length, classStruct.getPool());
|
||||
if (containsCode && !expanded) {
|
||||
byte[] code = classStruct.getLoader().loadBytecode(this, codeFullLength);
|
||||
seq = parseBytecode(new DataInputFullStream(new ByteArrayInputStream(code)), codeLength, classStruct.getPool());
|
||||
expanded = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void releaseResources() throws IOException {
|
||||
if (containsCode && lazy && expanded) {
|
||||
if (containsCode && expanded) {
|
||||
seq = null;
|
||||
expanded = false;
|
||||
}
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// private methods
|
||||
// *****************************************************************************
|
||||
|
||||
private InstructionSequence parseBytecode(DataInputFullStream in, int length, ConstantPool pool) throws IOException {
|
||||
|
||||
VBStyleCollection<Instruction, Integer> collinstr = new VBStyleCollection<Instruction, Integer>();
|
||||
VBStyleCollection<Instruction, Integer> instructions = new VBStyleCollection<Instruction, Integer>();
|
||||
|
||||
int bytecode_version = classStruct.getBytecodeVersion();
|
||||
|
||||
@@ -370,7 +209,7 @@ public class StructMethod implements CodeConstants {
|
||||
case opc_invokedynamic:
|
||||
if (classStruct.isVersionGE_1_7()) { // instruction unused in Java 6 and before
|
||||
operands.add(new Integer(in.readUnsignedShort()));
|
||||
in.skip(2);
|
||||
in.discard(2);
|
||||
group = GROUP_INVOCATION;
|
||||
i += 4;
|
||||
}
|
||||
@@ -420,7 +259,7 @@ public class StructMethod implements CodeConstants {
|
||||
case opc_invokeinterface:
|
||||
operands.add(new Integer(in.readUnsignedShort()));
|
||||
operands.add(new Integer(in.readUnsignedByte()));
|
||||
in.skip(1);
|
||||
in.discard(1);
|
||||
group = GROUP_INVOCATION;
|
||||
i += 4;
|
||||
break;
|
||||
@@ -430,7 +269,7 @@ public class StructMethod implements CodeConstants {
|
||||
i += 3;
|
||||
break;
|
||||
case opc_tableswitch:
|
||||
in.skip((4 - (i + 1) % 4) % 4);
|
||||
in.discard((4 - (i + 1) % 4) % 4);
|
||||
i += ((4 - (i + 1) % 4) % 4); // padding
|
||||
operands.add(new Integer(in.readInt()));
|
||||
i += 4;
|
||||
@@ -449,7 +288,7 @@ public class StructMethod implements CodeConstants {
|
||||
|
||||
break;
|
||||
case opc_lookupswitch:
|
||||
in.skip((4 - (i + 1) % 4) % 4);
|
||||
in.discard((4 - (i + 1) % 4) % 4);
|
||||
i += ((4 - (i + 1) % 4) % 4); // padding
|
||||
operands.add(new Integer(in.readInt()));
|
||||
i += 4;
|
||||
@@ -483,7 +322,7 @@ public class StructMethod implements CodeConstants {
|
||||
|
||||
Instruction instr = ConstantsUtil.getInstructionInstance(opcode, wide, group, bytecode_version, ops);
|
||||
|
||||
collinstr.addWithKey(instr, new Integer(offset));
|
||||
instructions.addWithKey(instr, new Integer(offset));
|
||||
|
||||
i++;
|
||||
}
|
||||
@@ -507,7 +346,7 @@ public class StructMethod implements CodeConstants {
|
||||
lstHandlers.add(handler);
|
||||
}
|
||||
|
||||
InstructionSequence seq = new FullInstructionSequence(collinstr, new ExceptionTable(lstHandlers));
|
||||
InstructionSequence seq = new FullInstructionSequence(instructions, new ExceptionTable(lstHandlers));
|
||||
|
||||
// initialize instructions
|
||||
int i = seq.length() - 1;
|
||||
@@ -524,41 +363,27 @@ public class StructMethod implements CodeConstants {
|
||||
return seq;
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// getter and setter methods
|
||||
// *****************************************************************************
|
||||
|
||||
public InstructionSequence getInstructionSequence() {
|
||||
return seq;
|
||||
}
|
||||
|
||||
public String getDescriptor() {
|
||||
return descriptor;
|
||||
public StructClass getClassStruct() {
|
||||
return classStruct;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getAccessFlags() {
|
||||
return accessFlags;
|
||||
public String getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
public boolean containsCode() {
|
||||
return containsCode;
|
||||
}
|
||||
|
||||
public int getLocalVariables() {
|
||||
return localVariables;
|
||||
}
|
||||
|
||||
public VBStyleCollection<StructGeneralAttribute, String> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
|
||||
public StructClass getClassStruct() {
|
||||
return classStruct;
|
||||
}
|
||||
|
||||
public boolean containsCode() {
|
||||
return containsCode;
|
||||
public InstructionSequence getInstructionSequence() {
|
||||
return seq;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -17,9 +17,6 @@ package org.jetbrains.java.decompiler.struct.attr;
|
||||
|
||||
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@@ -38,30 +35,6 @@ public class StructExceptionsAttribute extends StructGeneralAttribute {
|
||||
}
|
||||
}
|
||||
|
||||
public void writeToStream(DataOutputStream out) throws IOException {
|
||||
|
||||
out.writeShort(attribute_name_index);
|
||||
|
||||
ByteArrayOutputStream codeout = new ByteArrayOutputStream();
|
||||
DataOutputStream dataout = new DataOutputStream(codeout);
|
||||
|
||||
int len = throwsExceptions.size();
|
||||
dataout.writeShort(len);
|
||||
|
||||
if (len > 0) {
|
||||
info = new byte[len * 2];
|
||||
for (int i = 0, j = 0; i < len; i++, j += 2) {
|
||||
int index = throwsExceptions.get(i).intValue();
|
||||
info[j] = (byte)(index >> 8);
|
||||
info[j + 1] = (byte)(index & 0xFF);
|
||||
}
|
||||
dataout.write(info);
|
||||
}
|
||||
|
||||
out.writeInt(codeout.size());
|
||||
out.write(codeout.toByteArray());
|
||||
}
|
||||
|
||||
public String getExcClassname(int index, ConstantPool pool) {
|
||||
return pool.getPrimitiveConstant(throwsExceptions.get(index).intValue()).getString();
|
||||
}
|
||||
|
||||
@@ -17,17 +17,13 @@ package org.jetbrains.java.decompiler.struct.attr;
|
||||
|
||||
import org.jetbrains.java.decompiler.struct.consts.ConstantPool;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/*
|
||||
attribute_info {
|
||||
u2 attribute_name_index;
|
||||
u4 attribute_length;
|
||||
u1 info[attribute_length];
|
||||
}
|
||||
attribute_info {
|
||||
u2 attribute_name_index;
|
||||
u4 attribute_length;
|
||||
u1 info[attribute_length];
|
||||
}
|
||||
*/
|
||||
|
||||
public class StructGeneralAttribute {
|
||||
|
||||
public static final String ATTRIBUTE_CODE = "Code";
|
||||
@@ -48,74 +44,51 @@ public class StructGeneralAttribute {
|
||||
public static final String ATTRIBUTE_SYNTHETIC = "Synthetic";
|
||||
public static final String ATTRIBUTE_DEPRECATED = "Deprecated";
|
||||
|
||||
|
||||
// *****************************************************************************
|
||||
// private fields
|
||||
// *****************************************************************************
|
||||
|
||||
protected int attribute_name_index;
|
||||
|
||||
protected String name;
|
||||
protected byte[] info;
|
||||
|
||||
protected String name;
|
||||
|
||||
// *****************************************************************************
|
||||
// public methods
|
||||
// *****************************************************************************
|
||||
|
||||
public void writeToStream(DataOutputStream out) throws IOException {
|
||||
out.writeShort(attribute_name_index);
|
||||
out.writeInt(info.length);
|
||||
if (info.length > 0) {
|
||||
out.write(info);
|
||||
}
|
||||
}
|
||||
|
||||
public void initContent(ConstantPool pool) {
|
||||
name = pool.getPrimitiveConstant(attribute_name_index).getString();
|
||||
}
|
||||
|
||||
public static StructGeneralAttribute getMatchingAttributeInstance(int nameindex, String attrname) {
|
||||
|
||||
public static StructGeneralAttribute createAttribute(String name) {
|
||||
StructGeneralAttribute attr;
|
||||
|
||||
if (ATTRIBUTE_INNER_CLASSES.equals(attrname)) {
|
||||
if (ATTRIBUTE_INNER_CLASSES.equals(name)) {
|
||||
attr = new StructInnerClassesAttribute();
|
||||
}
|
||||
else if (ATTRIBUTE_CONSTANT_VALUE.equals(attrname)) {
|
||||
else if (ATTRIBUTE_CONSTANT_VALUE.equals(name)) {
|
||||
attr = new StructConstantValueAttribute();
|
||||
}
|
||||
else if (ATTRIBUTE_SIGNATURE.equals(attrname)) {
|
||||
else if (ATTRIBUTE_SIGNATURE.equals(name)) {
|
||||
attr = new StructGenericSignatureAttribute();
|
||||
}
|
||||
else if (ATTRIBUTE_ANNOTATION_DEFAULT.equals(attrname)) {
|
||||
else if (ATTRIBUTE_ANNOTATION_DEFAULT.equals(name)) {
|
||||
attr = new StructAnnDefaultAttribute();
|
||||
}
|
||||
else if (ATTRIBUTE_EXCEPTIONS.equals(attrname)) {
|
||||
else if (ATTRIBUTE_EXCEPTIONS.equals(name)) {
|
||||
attr = new StructExceptionsAttribute();
|
||||
}
|
||||
else if (ATTRIBUTE_ENCLOSING_METHOD.equals(attrname)) {
|
||||
else if (ATTRIBUTE_ENCLOSING_METHOD.equals(name)) {
|
||||
attr = new StructEnclosingMethodAttribute();
|
||||
}
|
||||
else if (ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS.equals(attrname) ||
|
||||
ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS.equals(attrname)) {
|
||||
else if (ATTRIBUTE_RUNTIME_VISIBLE_ANNOTATIONS.equals(name) ||
|
||||
ATTRIBUTE_RUNTIME_INVISIBLE_ANNOTATIONS.equals(name)) {
|
||||
attr = new StructAnnotationAttribute();
|
||||
}
|
||||
else if (ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(attrname) ||
|
||||
ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(attrname)) {
|
||||
else if (ATTRIBUTE_RUNTIME_VISIBLE_PARAMETER_ANNOTATIONS.equals(name) ||
|
||||
ATTRIBUTE_RUNTIME_INVISIBLE_PARAMETER_ANNOTATIONS.equals(name)) {
|
||||
attr = new StructAnnotationParameterAttribute();
|
||||
}
|
||||
else if (ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attrname) ||
|
||||
ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attrname)) {
|
||||
else if (ATTRIBUTE_RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(name) ||
|
||||
ATTRIBUTE_RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(name)) {
|
||||
attr = new StructAnnotationTypeAttribute();
|
||||
}
|
||||
else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(attrname)) {
|
||||
else if (ATTRIBUTE_LOCAL_VARIABLE_TABLE.equals(name)) {
|
||||
attr = new StructLocalVariableTableAttribute();
|
||||
}
|
||||
else if (ATTRIBUTE_BOOTSTRAP_METHODS.equals(attrname)) {
|
||||
else if (ATTRIBUTE_BOOTSTRAP_METHODS.equals(name)) {
|
||||
attr = new StructBootstrapMethodsAttribute();
|
||||
}
|
||||
else if (ATTRIBUTE_SYNTHETIC.equals(attrname) || ATTRIBUTE_DEPRECATED.equals(attrname)) {
|
||||
else if (ATTRIBUTE_SYNTHETIC.equals(name) ||
|
||||
ATTRIBUTE_DEPRECATED.equals(name)) {
|
||||
attr = new StructGeneralAttribute();
|
||||
}
|
||||
else {
|
||||
@@ -123,17 +96,11 @@ public class StructGeneralAttribute {
|
||||
return null;
|
||||
}
|
||||
|
||||
attr.setAttribute_name_index(nameindex);
|
||||
attr.name = name;
|
||||
return attr;
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// getter and setter methods
|
||||
// *****************************************************************************
|
||||
|
||||
public byte[] getInfo() {
|
||||
return info;
|
||||
}
|
||||
public void initContent(ConstantPool pool) { }
|
||||
|
||||
public void setInfo(byte[] info) {
|
||||
this.info = info;
|
||||
@@ -142,16 +109,4 @@ public class StructGeneralAttribute {
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public int getAttribute_name_index() {
|
||||
return attribute_name_index;
|
||||
}
|
||||
|
||||
public void setAttribute_name_index(int attribute_name_index) {
|
||||
this.attribute_name_index = attribute_name_index;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ 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.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -31,25 +31,14 @@ import java.util.List;
|
||||
public class ConstantPool {
|
||||
|
||||
public static final int FIELD = 1;
|
||||
|
||||
public static final int METHOD = 2;
|
||||
|
||||
// *****************************************************************************
|
||||
// private fields
|
||||
// *****************************************************************************
|
||||
|
||||
private List<PooledConstant> pool = new ArrayList<PooledConstant>();
|
||||
|
||||
private PoolInterceptor interceptor;
|
||||
|
||||
// *****************************************************************************
|
||||
// constructors
|
||||
// *****************************************************************************
|
||||
|
||||
public ConstantPool(DataInputStream in) throws IOException {
|
||||
|
||||
int size = in.readUnsignedShort();
|
||||
|
||||
int[] pass = new int[size];
|
||||
|
||||
// first dummy constant
|
||||
@@ -57,7 +46,6 @@ public class ConstantPool {
|
||||
|
||||
// first pass: read the elements
|
||||
for (int i = 1; i < size; i++) {
|
||||
|
||||
byte tag = (byte)in.readUnsignedByte();
|
||||
|
||||
switch (tag) {
|
||||
@@ -106,11 +94,10 @@ public class ConstantPool {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// resolving complex pool elements
|
||||
for (int pass_index = 1; pass_index <= 3; pass_index++) {
|
||||
for (int passIndex = 1; passIndex <= 3; passIndex++) {
|
||||
for (int i = 1; i < size; i++) {
|
||||
if (pass[i] == pass_index) {
|
||||
if (pass[i] == passIndex) {
|
||||
pool.get(i).resolveConstant(this);
|
||||
}
|
||||
}
|
||||
@@ -120,23 +107,7 @@ public class ConstantPool {
|
||||
interceptor = DecompilerContext.getPoolInterceptor();
|
||||
}
|
||||
|
||||
// *****************************************************************************
|
||||
// public methods
|
||||
// *****************************************************************************
|
||||
|
||||
public void writeToOutputStream(DataOutputStream out) throws IOException {
|
||||
|
||||
out.writeShort(pool.size());
|
||||
for (int i = 1; i < pool.size(); i++) {
|
||||
PooledConstant cnst = pool.get(i);
|
||||
if (cnst != null) {
|
||||
cnst.writeToStream(out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void skipPool(DataInputStream in) throws IOException {
|
||||
|
||||
public static void skipPool(DataInputFullStream in) throws IOException {
|
||||
int size = in.readUnsignedShort();
|
||||
|
||||
for (int i = 1; i < size; i++) {
|
||||
@@ -151,20 +122,20 @@ public class ConstantPool {
|
||||
case CodeConstants.CONSTANT_InterfaceMethodref:
|
||||
case CodeConstants.CONSTANT_NameAndType:
|
||||
case CodeConstants.CONSTANT_InvokeDynamic:
|
||||
in.skip(4);
|
||||
in.discard(4);
|
||||
break;
|
||||
case CodeConstants.CONSTANT_Long:
|
||||
case CodeConstants.CONSTANT_Double:
|
||||
in.skip(8);
|
||||
in.discard(8);
|
||||
i++;
|
||||
break;
|
||||
case CodeConstants.CONSTANT_Class:
|
||||
case CodeConstants.CONSTANT_String:
|
||||
case CodeConstants.CONSTANT_MethodType:
|
||||
in.skip(2);
|
||||
in.discard(2);
|
||||
break;
|
||||
case CodeConstants.CONSTANT_MethodHandle:
|
||||
in.skip(3);
|
||||
in.discard(3);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -173,27 +144,24 @@ public class ConstantPool {
|
||||
return pool.size();
|
||||
}
|
||||
|
||||
public String[] getClassElement(int element_type, int class_index, int name_index, int descriptor_index) {
|
||||
|
||||
String classname = ((PrimitiveConstant)getConstant(class_index)).getString();
|
||||
String elementname = ((PrimitiveConstant)getConstant(name_index)).getString();
|
||||
String descriptor = ((PrimitiveConstant)getConstant(descriptor_index)).getString();
|
||||
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 new_element = interceptor.getName(classname + " " + elementname + " " + descriptor);
|
||||
|
||||
if (new_element != null) {
|
||||
elementname = new_element.split(" ")[1];
|
||||
String newElement = interceptor.getName(className + " " + elementName + " " + descriptor);
|
||||
if (newElement != null) {
|
||||
elementName = newElement.split(" ")[1];
|
||||
}
|
||||
|
||||
String new_descriptor = buildNewDescriptor(element_type == FIELD ? CodeConstants.CONSTANT_Fieldref : CodeConstants.CONSTANT_Methodref,
|
||||
descriptor);
|
||||
if (new_descriptor != null) {
|
||||
descriptor = new_descriptor;
|
||||
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};
|
||||
return new String[]{elementName, descriptor};
|
||||
}
|
||||
|
||||
public PooledConstant getConstant(int index) {
|
||||
@@ -205,9 +173,9 @@ public class ConstantPool {
|
||||
|
||||
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);
|
||||
String newName = buildNewClassname(cn.getString());
|
||||
if (newName != null) {
|
||||
cn = new PrimitiveConstant(CodeConstants.CONSTANT_Class, newName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,33 +186,30 @@ public class ConstantPool {
|
||||
public LinkConstant getLinkConstant(int index) {
|
||||
LinkConstant ln = (LinkConstant)getConstant(index);
|
||||
|
||||
if (ln != null && interceptor != null) {
|
||||
if (ln.type == CodeConstants.CONSTANT_Fieldref ||
|
||||
ln.type == CodeConstants.CONSTANT_Methodref ||
|
||||
ln.type == CodeConstants.CONSTANT_InterfaceMethodref) {
|
||||
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);
|
||||
|
||||
String new_classname = buildNewClassname(ln.classname);
|
||||
String new_element = interceptor.getName(ln.classname + " " + ln.elementname + " " + ln.descriptor);
|
||||
String new_descriptor = buildNewDescriptor(ln.type, ln.descriptor);
|
||||
|
||||
if (new_classname != null || new_element != null || new_descriptor != null) {
|
||||
|
||||
ln = new LinkConstant(ln.type, new_classname == null ? ln.classname : new_classname,
|
||||
new_element == null ? ln.elementname : new_element.split(" ")[1],
|
||||
new_descriptor == null ? ln.descriptor : new_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) {
|
||||
private String buildNewClassname(String className) {
|
||||
VarType vt = new VarType(className, true);
|
||||
|
||||
VarType vt = new VarType(classname, true);
|
||||
|
||||
String newname = interceptor.getName(vt.value);
|
||||
if (newname != null) {
|
||||
String newName = interceptor.getName(vt.value);
|
||||
if (newName != null) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
|
||||
if (vt.arraydim > 0) {
|
||||
@@ -252,10 +217,10 @@ public class ConstantPool {
|
||||
buffer.append("[");
|
||||
}
|
||||
|
||||
buffer.append("L").append(newname).append(";");
|
||||
buffer.append("L").append(newName).append(";");
|
||||
}
|
||||
else {
|
||||
buffer.append(newname);
|
||||
buffer.append(newName);
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
@@ -265,17 +230,16 @@ public class ConstantPool {
|
||||
}
|
||||
|
||||
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 newclname = buildNewClassname(ftype.value);
|
||||
if (newclname != null) {
|
||||
ftype.value = newclname;
|
||||
VarType fType = fd.type;
|
||||
if (fType.type == CodeConstants.TYPE_OBJECT) {
|
||||
String newClassName = buildNewClassname(fType.value);
|
||||
if (newClassName != null) {
|
||||
fType.value = newClassName;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
@@ -285,14 +249,14 @@ public class ConstantPool {
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
MethodDescriptor md = MethodDescriptor.parseDescriptor(descriptor);
|
||||
// params
|
||||
for (VarType partype : md.params) {
|
||||
if (partype.type == CodeConstants.TYPE_OBJECT) {
|
||||
String newclname = buildNewClassname(partype.value);
|
||||
if (newclname != null) {
|
||||
partype.value = newclname;
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
@@ -300,9 +264,9 @@ public class ConstantPool {
|
||||
|
||||
// return value
|
||||
if (md.ret.type == CodeConstants.TYPE_OBJECT) {
|
||||
String newclname = buildNewClassname(md.ret.value);
|
||||
if (newclname != null) {
|
||||
md.ret.value = newclname;
|
||||
String newClassName = buildNewClassname(md.ret.value);
|
||||
if (newClassName != null) {
|
||||
md.ret.value = newClassName;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ public class DataPoint {
|
||||
MethodDescriptor md = MethodDescriptor.parseDescriptor(mt.getDescriptor());
|
||||
|
||||
int k = 0;
|
||||
if ((mt.getAccessFlags() & CodeConstants.ACC_STATIC) == 0) {
|
||||
if (!mt.hasModifier(CodeConstants.ACC_STATIC)) {
|
||||
point.setVariable(k++, new VarType(CodeConstants.TYPE_OBJECT, 0, null));
|
||||
}
|
||||
|
||||
|
||||
@@ -24,11 +24,11 @@ import org.jetbrains.java.decompiler.util.DataInputFullStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class LazyLoader {
|
||||
|
||||
private HashMap<String, Link> mapClassLinks = new HashMap<String, Link>();
|
||||
|
||||
private Map<String, Link> mapClassLinks = new HashMap<String, Link>();
|
||||
private IBytecodeProvider provider;
|
||||
|
||||
public LazyLoader(IBytecodeProvider provider) {
|
||||
@@ -47,98 +47,88 @@ public class LazyLoader {
|
||||
return mapClassLinks.get(classname);
|
||||
}
|
||||
|
||||
|
||||
public ConstantPool loadPool(String classname) {
|
||||
|
||||
try {
|
||||
|
||||
DataInputFullStream in = getClassStream(classname);
|
||||
if (in == null) {
|
||||
return null;
|
||||
if (in == null) return null;
|
||||
|
||||
try {
|
||||
in.discard(8);
|
||||
return new ConstantPool(in);
|
||||
}
|
||||
finally {
|
||||
in.close();
|
||||
}
|
||||
|
||||
in.skip(8);
|
||||
|
||||
return new ConstantPool(in);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public byte[] loadBytecode(StructMethod mt, int code_fulllength) {
|
||||
public byte[] loadBytecode(StructMethod mt, int codeFullLength) {
|
||||
String className = mt.getClassStruct().qualifiedName;
|
||||
|
||||
try {
|
||||
DataInputFullStream in = getClassStream(className);
|
||||
if (in == null) return null;
|
||||
|
||||
DataInputFullStream in = getClassStream(mt.getClassStruct().qualifiedName);
|
||||
if (in == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
in.discard(8);
|
||||
|
||||
byte[] res = null;
|
||||
|
||||
in.skip(8);
|
||||
|
||||
ConstantPool pool = mt.getClassStruct().getPool();
|
||||
if (pool == null) {
|
||||
pool = new ConstantPool(in);
|
||||
}
|
||||
else {
|
||||
ConstantPool.skipPool(in);
|
||||
}
|
||||
|
||||
in.skip(2);
|
||||
int this_class = in.readUnsignedShort();
|
||||
in.skip(2);
|
||||
|
||||
// interfaces
|
||||
in.skip(in.readUnsignedShort() * 2);
|
||||
|
||||
// fields
|
||||
int size = in.readUnsignedShort();
|
||||
for (int i = 0; i < size; i++) {
|
||||
in.skip(6);
|
||||
skipAttributes(in);
|
||||
}
|
||||
|
||||
// methods
|
||||
size = in.readUnsignedShort();
|
||||
for (int i = 0; i < size; i++) {
|
||||
in.skip(2);
|
||||
|
||||
int name_index = in.readUnsignedShort();
|
||||
int descriptor_index = in.readUnsignedShort();
|
||||
|
||||
String[] elem_arr = pool.getClassElement(ConstantPool.METHOD, this_class, name_index, descriptor_index);
|
||||
String name = elem_arr[0];
|
||||
|
||||
if (mt.getName().equals(name)) {
|
||||
String descriptor = elem_arr[1];
|
||||
if (mt.getDescriptor().equals(descriptor)) {
|
||||
|
||||
int len = in.readUnsignedShort();
|
||||
for (int j = 0; j < len; j++) {
|
||||
|
||||
int attr_nameindex = in.readUnsignedShort();
|
||||
String attrname = pool.getPrimitiveConstant(attr_nameindex).getString();
|
||||
|
||||
if (StructGeneralAttribute.ATTRIBUTE_CODE.equals(attrname)) {
|
||||
in.skip(12);
|
||||
|
||||
res = new byte[code_fulllength];
|
||||
in.readFull(res);
|
||||
return res;
|
||||
}
|
||||
else {
|
||||
in.skip(in.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
ConstantPool pool = mt.getClassStruct().getPool();
|
||||
if (pool == null) {
|
||||
pool = new ConstantPool(in);
|
||||
}
|
||||
else {
|
||||
ConstantPool.skipPool(in);
|
||||
}
|
||||
|
||||
skipAttributes(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;
|
||||
@@ -148,39 +138,38 @@ public class LazyLoader {
|
||||
}
|
||||
}
|
||||
|
||||
public DataInputFullStream getClassStream(String externPath, String internPath) throws IOException {
|
||||
InputStream instream = provider.getBytecodeStream(externPath, internPath);
|
||||
return instream == null ? null : new DataInputFullStream(instream);
|
||||
@SuppressWarnings("IOResourceOpenedButNotSafelyClosed")
|
||||
public DataInputFullStream getClassStream(String externalPath, String internalPath) throws IOException {
|
||||
InputStream stream = provider.getBytecodeStream(externalPath, internalPath);
|
||||
return stream == null ? null : new DataInputFullStream(stream);
|
||||
}
|
||||
|
||||
public DataInputFullStream getClassStream(String qualifiedClassName) throws IOException {
|
||||
Link link = mapClassLinks.get(qualifiedClassName);
|
||||
return link == null ? null : getClassStream(link.externPath, link.internPath);
|
||||
return link == null ? null : getClassStream(link.externalPath, link.internalPath);
|
||||
}
|
||||
|
||||
private static void skipAttributes(DataInputFullStream in) throws IOException {
|
||||
|
||||
public static void skipAttributes(DataInputFullStream in) throws IOException {
|
||||
int length = in.readUnsignedShort();
|
||||
for (int i = 0; i < length; i++) {
|
||||
in.skip(2);
|
||||
in.skip(in.readInt());
|
||||
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 externPath;
|
||||
public String internPath;
|
||||
public String externalPath;
|
||||
public String internalPath;
|
||||
|
||||
public Link(int type, String externPath, String internPath) {
|
||||
public Link(int type, String externalPath, String internalPath) {
|
||||
this.type = type;
|
||||
this.externPath = externPath;
|
||||
this.internPath = internPath;
|
||||
this.externalPath = externalPath;
|
||||
this.internalPath = internalPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user