SearchPath.pathSeparatorChar -> altPathSeparatorChar

SearchPath: allow both pathSeparators.
BinaryInfo: ALL_ATTRIBUTES splitted in KNOWNATTRIB, UNKNOWNATTRIBS
ClassInfo: innerClasses overworked, some more comments


git-svn-id: https://svn.code.sf.net/p/jode/code/trunk@1179 379699f6-c40d-0410-875b-85095c16579e
branch_1_1
jochen 25 years ago
parent 80d71addd4
commit 0270969c56
  1. 7
      jode/jode/bytecode/BinaryInfo.java.in
  2. 4
      jode/jode/bytecode/BytecodeInfo.java.in
  3. 95
      jode/jode/bytecode/ClassInfo.java.in
  4. 4
      jode/jode/bytecode/FieldInfo.java
  5. 5
      jode/jode/bytecode/InnerClassInfo.java
  6. 8
      jode/jode/bytecode/MethodInfo.java
  7. 89
      jode/jode/bytecode/SearchPath.java

@ -40,10 +40,13 @@ public class BinaryInfo {
public static final int FIELDS = 0x02; public static final int FIELDS = 0x02;
public static final int METHODS = 0x04; public static final int METHODS = 0x04;
public static final int CONSTANTS = 0x08; public static final int CONSTANTS = 0x08;
public static final int ALL_ATTRIBUTES = 0x10; public static final int KNOWNATTRIBS = 0x10;
public static final int INNERCLASSES = 0x20; public static final int INNERCLASSES = 0x20;
public static final int OUTERCLASSES = 0x40; public static final int OUTERCLASSES = 0x40;
public static final int UNKNOWNATTRIBS = 0x80;
public static final int FULLINFO = 0xff; public static final int FULLINFO = 0xff;
public static final int MOSTINFO = 0x7f;
public static final int REFLECTINFO = 0x6f;
private Map unknownAttributes = null; private Map unknownAttributes = null;
@ -71,7 +74,7 @@ public class BinaryInfo {
int howMuch) throws IOException { int howMuch) throws IOException {
byte[] data = new byte[length]; byte[] data = new byte[length];
input.readFully(data); input.readFully(data);
if ((howMuch & ALL_ATTRIBUTES) != 0) { if ((howMuch & UNKNOWNATTRIBS) != 0) {
if (unknownAttributes == null) if (unknownAttributes == null)
unknownAttributes = new SimpleMap(); unknownAttributes = new SimpleMap();
unknownAttributes.put(name, data); unknownAttributes.put(name, data);

@ -209,7 +209,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
protected void readAttribute(String name, int length, ConstantPool cp, protected void readAttribute(String name, int length, ConstantPool cp,
DataInputStream input, DataInputStream input,
int howMuch) throws IOException { int howMuch) throws IOException {
if ((howMuch & ALL_ATTRIBUTES) != 0 if ((howMuch & KNOWNATTRIBS) != 0
&& name.equals("LocalVariableTable")) { && name.equals("LocalVariableTable")) {
if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0) if ((GlobalOptions.debuggingFlags & GlobalOptions.DEBUG_LVT) != 0)
GlobalOptions.err.println("LocalVariableTable of "+methodInfo); GlobalOptions.err.println("LocalVariableTable of "+methodInfo);
@ -271,7 +271,7 @@ public class BytecodeInfo extends BinaryInfo implements Opcodes {
+" range "+start+" - "+end +" range "+start+" - "+end
+" slot "+slot); +" slot "+slot);
} }
} else if ((howMuch & ALL_ATTRIBUTES) != 0 } else if ((howMuch & KNOWNATTRIBS) != 0
&& name.equals("LineNumberTable")) { && name.equals("LineNumberTable")) {
int count = input.readUnsignedShort(); int count = input.readUnsignedShort();
if (length != 2 + count * 4) { if (length != 2 + count * 4) {

@ -35,13 +35,41 @@ import java.lang.reflect.Modifier;
/** /**
* This class does represent a class similar to java.lang.Class. You * This class does represent a class similar to java.lang.Class. You
* can get the super class and the interfaces. * can get the super class and the interfaces. <br>
* *
* The main difference to java.lang.Class is, that the objects are builded * The main difference to java.lang.Class is, that the objects are builded
* from a stream containing the .class file, and that it uses the * from a stream containing the .class file, and that it uses the
* <code>Type</code> to represent types instead of Class itself. * <code>Type</code> to represent types instead of Class itself. <br>
* *
* @author Jochen Hoenicke * <h2>The InnerClasses attribute</h2>
*
* The InnerClasses attribute is transformed in a special way by this
* class so we want to taker a closer look. According to the <a
* href="http://java.sun.com/products/jdk/1.1/docs/guide/innerclasses/spec/innerclasses.doc10.html#18814">inner
* class specification</a> there must be an InnerClass attribute for
* every non top-level class that is referenced somewhere in the
* bytecode. This implies that if this is an inner class, it must
* contain a inner class attribute for itself. Before a class is
* referenced as outer class in an InnerClass attribute, it must be
* described by another InnerClass attribute. <br>
*
* Since every class references itself, there must be informations
* about the outer class for each class scoped class. If that outer
* class is an outer class again, there must be information about it,
* too. This particular chain of InnerClassInfos is returned by the
* getOuterClasses() method; for convenience in reverse order, i.e.
* current class first, then the outer classes from innermost to
* outermost. <br>
*
* A valid bytecode must also contain InnerClass infos for each inner
* classes it declares. These information are returned by the
* getInnerClasses() method. The order of these classes is the same
* as in the bytecode attribute.
*
* All remaining attributes are returned by getExtraClasses() in the
* same order as in the bytecode attribute.
*
* @author Jochen Hoenicke
*/ */
public class ClassInfo extends BinaryInfo { public class ClassInfo extends BinaryInfo {
@ -133,7 +161,7 @@ public class ClassInfo extends BinaryInfo {
ConstantPool cp, ConstantPool cp,
DataInputStream input, DataInputStream input,
int howMuch) throws IOException { int howMuch) throws IOException {
if ((howMuch & ALL_ATTRIBUTES) != 0 && name.equals("SourceFile")) { if ((howMuch & KNOWNATTRIBS) != 0 && name.equals("SourceFile")) {
if (length != 2) if (length != 2)
throw new ClassFormatException("SourceFile attribute" throw new ClassFormatException("SourceFile attribute"
+ " has wrong length"); + " has wrong length");
@ -141,6 +169,9 @@ public class ClassInfo extends BinaryInfo {
} else if ((howMuch & (OUTERCLASSES | INNERCLASSES)) != 0 } else if ((howMuch & (OUTERCLASSES | INNERCLASSES)) != 0
&& name.equals("InnerClasses")) { && name.equals("InnerClasses")) {
int count = input.readUnsignedShort(); int count = input.readUnsignedShort();
if (length != 2 + 8 * count)
throw new ClassFormatException
("InnerClasses attribute has wrong length");
int innerCount = 0, outerCount = 0, extraCount = 0; int innerCount = 0, outerCount = 0, extraCount = 0;
InnerClassInfo[] innerClassInfo = new InnerClassInfo[count]; InnerClassInfo[] innerClassInfo = new InnerClassInfo[count];
for (int i=0; i< count; i++) { for (int i=0; i< count; i++) {
@ -164,16 +195,22 @@ public class ClassInfo extends BinaryInfo {
else else
innerClassInfo[count - (++extraCount)] = ici; innerClassInfo[count - (++extraCount)] = ici;
} }
/* Now innerClasses are at the front of innerClassInfo array
* in correct order. The other InnerClassInfos are in reverse
* order in the rest of the innerClassInfo array.
*/
/* We now count the outerClasses. The reverse order is the
* right thing for us.
*/
{ {
String lastOuterName = getName(); String lastOuterName = getName();
for (int i = count - extraCount; i < count; i++) { for (int i = count - extraCount;
i < count && lastOuterName != null; i++) {
InnerClassInfo ici = innerClassInfo[i]; InnerClassInfo ici = innerClassInfo[i];
if (ici.inner.equals(lastOuterName)) { if (ici.inner.equals(lastOuterName)) {
for (int j = i; j > count - extraCount; j--)
innerClassInfo[j] = innerClassInfo[j-1];
innerClassInfo[count-extraCount] = ici;
extraCount--;
outerCount++; outerCount++;
extraCount--;
lastOuterName = ici.outer; lastOuterName = ici.outer;
} }
} }
@ -187,21 +224,35 @@ public class ClassInfo extends BinaryInfo {
if (outerCount > 0) { if (outerCount > 0) {
outerClasses = new InnerClassInfo[outerCount]; outerClasses = new InnerClassInfo[outerCount];
System.arraycopy(innerClassInfo, innerCount,
outerClasses, 0, outerCount);
} else } else
outerClasses = null; outerClasses = null;
if (extraCount > 0) { if (extraCount > 0) {
extraClasses = new InnerClassInfo[extraCount]; extraClasses = new InnerClassInfo[extraCount];
System.arraycopy(innerClassInfo, innerCount + outerCount,
extraClasses, 0, extraCount);
} else } else
extraClasses = null; extraClasses = null;
/* The last part: We split between outer and extra classes.
* In this step we will also revert the order of the extra
* classes.
*/
{
int outerPtr = 0;
String lastOuterName = getName();
for (int i = count - extraCount - outerCount;
i < count && lastOuterName != null; i++) {
InnerClassInfo ici = innerClassInfo[i];
if (length != 2 + 8 * count) /* If we counted correctly there is no NullPointer
throw new ClassFormatException * or ArrayIndexOutOfBoundsException here
("InnerClasses attribute has wrong length"); */
if (ici.inner.equals(lastOuterName)) {
outerClasses[outerPtr++] = ici;
lastOuterName = ici.outer;
} else
extraClasses[--extraCount] = ici;
}
}
} else } else
super.readAttribute(name, length, cp, input, howMuch); super.readAttribute(name, length, cp, input, howMuch);
} }
@ -242,12 +293,12 @@ public class ClassInfo extends BinaryInfo {
} }
/* fields */ /* fields */
if ((howMuch & (FIELDS | ALL_ATTRIBUTES)) != 0) { if ((howMuch & (FIELDS | KNOWNATTRIBS | UNKNOWNATTRIBS)) != 0) {
int count = input.readUnsignedShort(); int count = input.readUnsignedShort();
if ((howMuch & FIELDS) != 0) if ((status & FIELDS) == 0)
fields = new FieldInfo[count]; fields = new FieldInfo[count];
for (int i=0; i< count; i++) { for (int i=0; i< count; i++) {
if ((howMuch & FIELDS) != 0) if ((status & FIELDS) == 0)
fields[i] = new FieldInfo(this); fields[i] = new FieldInfo(this);
fields[i].read(cpool, input, howMuch); fields[i].read(cpool, input, howMuch);
} }
@ -261,12 +312,12 @@ public class ClassInfo extends BinaryInfo {
} }
/* methods */ /* methods */
if ((howMuch & (METHODS | ALL_ATTRIBUTES)) != 0) { if ((howMuch & (METHODS | KNOWNATTRIBS | UNKNOWNATTRIBS)) != 0) {
int count = input.readUnsignedShort(); int count = input.readUnsignedShort();
if ((howMuch & METHODS) != 0) if ((status & METHODS) == 0)
methods = new MethodInfo[count]; methods = new MethodInfo[count];
for (int i=0; i< count; i++) { for (int i=0; i< count; i++) {
if ((howMuch & METHODS) != 0) if ((status & METHODS) == 0)
methods[i] = new MethodInfo(this); methods[i] = new MethodInfo(this);
methods[i].read(cpool, input, howMuch); methods[i].read(cpool, input, howMuch);
} }

@ -49,7 +49,7 @@ public class FieldInfo extends BinaryInfo {
ConstantPool cp, ConstantPool cp,
DataInputStream input, DataInputStream input,
int howMuch) throws IOException { int howMuch) throws IOException {
if ((howMuch & ALL_ATTRIBUTES) != 0 && name.equals("ConstantValue")) { if ((howMuch & KNOWNATTRIBS) != 0 && name.equals("ConstantValue")) {
if (length != 2) if (length != 2)
throw new ClassFormatException("ConstantValue attribute" throw new ClassFormatException("ConstantValue attribute"
+ " has wrong length"); + " has wrong length");
@ -161,7 +161,7 @@ public class FieldInfo extends BinaryInfo {
} }
public Object getConstant() { public Object getConstant() {
clazzInfo.loadInfo(ALL_ATTRIBUTES); clazzInfo.loadInfo(KNOWNATTRIBS);
return constant; return constant;
} }

@ -33,5 +33,10 @@ public class InnerClassInfo {
this.name = name; this.name = name;
this.modifiers = modif; this.modifiers = modif;
} }
public String toString() {
return "InnerClassInfo["+inner+","+outer+","+name+","
+java.lang.reflect.Modifier.toString(modifiers)+"]";
}
} }

@ -51,10 +51,10 @@ public class MethodInfo extends BinaryInfo {
protected void readAttribute(String name, int length, ConstantPool cp, protected void readAttribute(String name, int length, ConstantPool cp,
DataInputStream input, DataInputStream input,
int howMuch) throws IOException { int howMuch) throws IOException {
if ((howMuch & ALL_ATTRIBUTES) != 0 && name.equals("Code")) { if ((howMuch & KNOWNATTRIBS) != 0 && name.equals("Code")) {
bytecode = new BytecodeInfo(this); bytecode = new BytecodeInfo(this);
bytecode.read(cp, input); bytecode.read(cp, input);
} else if ((howMuch & ALL_ATTRIBUTES) != 0 } else if ((howMuch & KNOWNATTRIBS) != 0
&& name.equals("Exceptions")) { && name.equals("Exceptions")) {
int count = input.readUnsignedShort(); int count = input.readUnsignedShort();
exceptions = new String[count]; exceptions = new String[count];
@ -213,12 +213,12 @@ public class MethodInfo extends BinaryInfo {
} }
public void setBytecode(BytecodeInfo newBytecode) { public void setBytecode(BytecodeInfo newBytecode) {
clazzInfo.loadInfo(ALL_ATTRIBUTES); clazzInfo.loadInfo(KNOWNATTRIBS);
bytecode = newBytecode; bytecode = newBytecode;
} }
public void setExceptions(String[] newExceptions) { public void setExceptions(String[] newExceptions) {
clazzInfo.loadInfo(ALL_ATTRIBUTES); clazzInfo.loadInfo(KNOWNATTRIBS);
exceptions = newExceptions; exceptions = newExceptions;
} }

@ -48,8 +48,12 @@ public class SearchPath {
/** /**
* We need a different pathSeparatorChar, since ':' (used for most * We need a different pathSeparatorChar, since ':' (used for most
* UNIX System, is used a protocol separator in URLs. * UNIX System, is used a protocol separator in URLs.
*
* We currently allow both pathSeparatorChar and
* altPathSeparatorChar and decide if it is a protocol separator
* by context.
*/ */
public static final char pathSeparatorChar = ','; public static final char altPathSeparatorChar = ',';
URL[] bases; URL[] bases;
byte[][] urlzips; byte[][] urlzips;
File[] dirs; File[] dirs;
@ -176,34 +180,86 @@ public class SearchPath {
* entries may also be zip or jar files. * entries may also be zip or jar files.
*/ */
public SearchPath(String path) { public SearchPath(String path) {
StringTokenizer tokenizer = // Calculate a good approximation (rounded upwards) of the tokens
new StringTokenizer(path, // in this path.
String.valueOf(pathSeparatorChar)); int length = 1;
int length = tokenizer.countTokens(); for (int index=path.indexOf(File.pathSeparatorChar);
index != -1; length++)
index = path.indexOf(File.pathSeparatorChar, index+1);
if (File.pathSeparatorChar != altPathSeparatorChar) {
for (int index=path.indexOf(altPathSeparatorChar);
index != -1; length++)
index = path.indexOf(altPathSeparatorChar, index+1);
}
bases = new URL[length]; bases = new URL[length];
urlzips = new byte[length][]; urlzips = new byte[length][];
dirs = new File[length]; dirs = new File[length];
zips = new ZipFile[length]; zips = new ZipFile[length];
zipEntries = new Hashtable[length]; zipEntries = new Hashtable[length];
zipDirs = new String[length]; zipDirs = new String[length];
for (int i=0; i< length; i++) { int i = 0;
String token = tokenizer.nextToken(); for (int ptr=0; ptr < path.length(); ptr++, i++) {
int next = ptr;
while (next < path.length()
&& path.charAt(next) != File.pathSeparatorChar
&& path.charAt(next) != altPathSeparatorChar)
next++;
int index = ptr;
colon_separator:
while (next > ptr
&& next < path.length()
&& path.charAt(next) == ':') {
// Check if this is a URL instead of a pathSeparator
// Since this is a while loop it allows nested urls like
// jar:ftp://ftp.foo.org/pub/foo.jar!/
while (index < next) {
char c = path.charAt(index);
// According to RFC 1738 letters, digits, '+', '-'
// and '.' are allowed SCHEMA characters. We
// disallow '.' because it is a good marker that
// the user has specified a filename instead of a
// URL.
if ((c < 'A' || c > 'Z')
&& (c < 'a' || c > 'z')
&& (c < '0' || c > '9')
&& "+-".indexOf(c) == -1) {
break colon_separator;
}
index++;
}
next++;
index++;
while (next < path.length()
&& path.charAt(next) != File.pathSeparatorChar
&& path.charAt(next) != altPathSeparatorChar)
next++;
}
String token = path.substring(ptr, next);
ptr = next;
boolean mustBeJar = false; boolean mustBeJar = false;
// We handle jar URL's ourself. // We handle jar URL's ourself.
if (token.startsWith("jar:")) { if (token.startsWith("jar:")) {
int index = 0; index = 0;
do { do {
index = token.indexOf('!', index); index = token.indexOf('!', index);
} while (token.charAt(index+1) != '/'); } while (index != -1 && index != token.length()-1
&& token.charAt(index+1) != '/');
if (index == -1 || index == token.length()-1) {
GlobalOptions.err.println("Warning: Illegal jar url "
+ token + ".");
continue;
}
zipDirs[i] = token.substring(index+2); zipDirs[i] = token.substring(index+2);
if (!zipDirs[i].endsWith("/")) if (!zipDirs[i].endsWith("/"))
zipDirs[i] = zipDirs[i] + "/"; zipDirs[i] = zipDirs[i] + "/";
token = token.substring(4, index); token = token.substring(4, index);
mustBeJar = true; mustBeJar = true;
} }
int index = token.indexOf(':'); index = token.indexOf(':');
if (index != -1 && index < token.length()-2 if (index != -1 && index < token.length()-2
&& token.charAt(index+1) == '/' && token.charAt(index+1) == '/'
&& token.charAt(index+2) == '/') { && token.charAt(index+2) == '/') {
@ -221,9 +277,9 @@ public class SearchPath {
} catch (IOException ex) { } catch (IOException ex) {
// ignore // ignore
} catch (SecurityException ex) { } catch (SecurityException ex) {
GlobalOptions.err.println("Warning: Security exception " GlobalOptions.err.println
+"while accessing " ("Warning: Security exception while accessing "
+bases[i]+"."); +bases[i]+".");
} }
} catch (MalformedURLException ex) { } catch (MalformedURLException ex) {
/* disable entry */ /* disable entry */
@ -243,8 +299,9 @@ public class SearchPath {
} }
} catch (SecurityException ex) { } catch (SecurityException ex) {
/* disable this entry */ /* disable this entry */
GlobalOptions.err.println("Warning: SecurityException while" GlobalOptions.err.println
+ " accessing " + token); ("Warning: SecurityException while accessing "
+ token + ".");
dirs[i] = null; dirs[i] = null;
} }
} }

Loading…
Cancel
Save