jtulach@144: /* jtulach@144: * Copyright (c) 2002, 2004, Oracle and/or its affiliates. All rights reserved. jtulach@144: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. jtulach@144: * jtulach@144: * This code is free software; you can redistribute it and/or modify it jtulach@144: * under the terms of the GNU General Public License version 2 only, as jtulach@144: * published by the Free Software Foundation. Oracle designates this jtulach@144: * particular file as subject to the "Classpath" exception as provided jtulach@144: * by Oracle in the LICENSE file that accompanied this code. jtulach@144: * jtulach@144: * This code is distributed in the hope that it will be useful, but WITHOUT jtulach@144: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or jtulach@144: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License jtulach@144: * version 2 for more details (a copy is included in the LICENSE file that jtulach@144: * accompanied this code). jtulach@144: * jtulach@144: * You should have received a copy of the GNU General Public License version jtulach@144: * 2 along with this work; if not, write to the Free Software Foundation, jtulach@144: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. jtulach@144: * jtulach@144: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA jtulach@144: * or visit www.oracle.com if you need additional information or have any jtulach@144: * questions. jtulach@144: */ jtulach@144: jtulach@144: jtulach@167: package org.apidesign.javap; jtulach@144: jtulach@144: import java.io.*; jtulach@144: jtulach@144: /** jtulach@144: * Central data repository of the Java Disassembler. jtulach@144: * Stores all the information in java class file. jtulach@144: * jtulach@144: * @author Sucheta Dambalkar (Adopted code from jdis) jtulach@144: */ jaroslav@151: public final class ClassData implements RuntimeConstants { jtulach@144: jtulach@144: private int magic; jtulach@144: private int minor_version; jtulach@144: private int major_version; jtulach@144: private int cpool_count; jtulach@144: private Object cpool[]; jtulach@144: private int access; jtulach@144: private int this_class = 0;; jtulach@144: private int super_class; jtulach@144: private int interfaces_count; jtulach@144: private int[] interfaces = new int[0];; jtulach@144: private int fields_count; jtulach@144: private FieldData[] fields; jtulach@144: private int methods_count; jtulach@144: private MethodData[] methods; jtulach@144: private InnerClassData[] innerClasses; jtulach@144: private int attributes_count; jtulach@144: private AttrData[] attrs; jtulach@144: private String classname; jtulach@144: private String superclassname; jtulach@144: private int source_cpx=0; jtulach@144: private byte tags[]; jtulach@144: private Hashtable indexHashAscii = new Hashtable(); jtulach@144: private String pkgPrefix=""; jtulach@144: private int pkgPrefixLen=0; jtulach@144: jtulach@144: /** jtulach@144: * Read classfile to disassemble. jtulach@144: */ jaroslav@149: public ClassData(InputStream infile) throws IOException { jaroslav@149: this.read(new DataInputStream(infile)); jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Reads and stores class file information. jtulach@144: */ jtulach@144: public void read(DataInputStream in) throws IOException { jtulach@144: // Read the header jtulach@144: magic = in.readInt(); jtulach@144: if (magic != JAVA_MAGIC) { jtulach@144: throw new ClassFormatError("wrong magic: " + jtulach@144: toHex(magic) + ", expected " + jtulach@144: toHex(JAVA_MAGIC)); jtulach@144: } jtulach@144: minor_version = in.readShort(); jtulach@144: major_version = in.readShort(); jtulach@144: if (major_version != JAVA_VERSION) { jtulach@144: } jtulach@144: jtulach@144: // Read the constant pool jtulach@144: readCP(in); jtulach@144: access = in.readUnsignedShort(); jtulach@144: this_class = in.readUnsignedShort(); jtulach@144: super_class = in.readUnsignedShort(); jtulach@144: jtulach@144: //Read interfaces. jtulach@144: interfaces_count = in.readUnsignedShort(); jtulach@144: if(interfaces_count > 0){ jtulach@144: interfaces = new int[interfaces_count]; jtulach@144: } jtulach@144: for (int i = 0; i < interfaces_count; i++) { jtulach@144: interfaces[i]=in.readShort(); jtulach@144: } jtulach@144: jtulach@144: // Read the fields jtulach@144: readFields(in); jtulach@144: jtulach@144: // Read the methods jtulach@144: readMethods(in); jtulach@144: jtulach@144: // Read the attributes jtulach@144: attributes_count = in.readUnsignedShort(); jtulach@144: attrs=new AttrData[attributes_count]; jtulach@144: for (int k = 0; k < attributes_count; k++) { jtulach@144: int name_cpx=in.readUnsignedShort(); jtulach@144: if (getTag(name_cpx)==CONSTANT_UTF8 jtulach@144: && getString(name_cpx).equals("SourceFile") jtulach@144: ){ if (in.readInt()!=2) jtulach@144: throw new ClassFormatError("invalid attr length"); jtulach@144: source_cpx=in.readUnsignedShort(); jtulach@144: AttrData attr=new AttrData(this); jtulach@144: attr.read(name_cpx); jtulach@144: attrs[k]=attr; jtulach@144: jtulach@144: } else if (getTag(name_cpx)==CONSTANT_UTF8 jtulach@144: && getString(name_cpx).equals("InnerClasses") jtulach@144: ){ int length=in.readInt(); jtulach@144: int num=in.readUnsignedShort(); jtulach@144: if (2+num*8 != length) jtulach@144: throw new ClassFormatError("invalid attr length"); jtulach@144: innerClasses=new InnerClassData[num]; jtulach@144: for (int j = 0; j < num; j++) { jtulach@144: InnerClassData innerClass=new InnerClassData(this); jtulach@144: innerClass.read(in); jtulach@144: innerClasses[j]=innerClass; jtulach@144: } jtulach@144: AttrData attr=new AttrData(this); jtulach@144: attr.read(name_cpx); jtulach@144: attrs[k]=attr; jtulach@144: } else { jtulach@144: AttrData attr=new AttrData(this); jtulach@144: attr.read(name_cpx, in); jtulach@144: attrs[k]=attr; jtulach@144: } jtulach@144: } jtulach@144: in.close(); jtulach@144: } // end ClassData.read() jtulach@144: jtulach@144: /** jtulach@144: * Reads and stores constant pool info. jtulach@144: */ jtulach@144: void readCP(DataInputStream in) throws IOException { jtulach@144: cpool_count = in.readUnsignedShort(); jtulach@144: tags = new byte[cpool_count]; jtulach@144: cpool = new Object[cpool_count]; jtulach@144: for (int i = 1; i < cpool_count; i++) { jtulach@144: byte tag = in.readByte(); jtulach@144: jtulach@144: switch(tags[i] = tag) { jtulach@144: case CONSTANT_UTF8: jtulach@144: String str=in.readUTF(); jtulach@144: indexHashAscii.put(cpool[i] = str, new Integer(i)); jtulach@144: break; jtulach@144: case CONSTANT_INTEGER: jtulach@144: cpool[i] = new Integer(in.readInt()); jtulach@144: break; jtulach@144: case CONSTANT_FLOAT: jtulach@144: cpool[i] = new Float(in.readFloat()); jtulach@144: break; jtulach@144: case CONSTANT_LONG: jtulach@144: cpool[i++] = new Long(in.readLong()); jtulach@144: break; jtulach@144: case CONSTANT_DOUBLE: jtulach@144: cpool[i++] = new Double(in.readDouble()); jtulach@144: break; jtulach@144: case CONSTANT_CLASS: jtulach@144: case CONSTANT_STRING: jtulach@144: cpool[i] = new CPX(in.readUnsignedShort()); jtulach@144: break; jtulach@144: jtulach@144: case CONSTANT_FIELD: jtulach@144: case CONSTANT_METHOD: jtulach@144: case CONSTANT_INTERFACEMETHOD: jtulach@144: case CONSTANT_NAMEANDTYPE: jtulach@144: cpool[i] = new CPX2(in.readUnsignedShort(), in.readUnsignedShort()); jtulach@144: break; jtulach@144: jtulach@144: case 0: jtulach@144: default: jtulach@144: throw new ClassFormatError("invalid constant type: " + (int)tags[i]); jtulach@144: } jtulach@144: } jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Reads and strores field info. jtulach@144: */ jtulach@144: protected void readFields(DataInputStream in) throws IOException { jtulach@144: int fields_count = in.readUnsignedShort(); jtulach@144: fields=new FieldData[fields_count]; jtulach@144: for (int k = 0; k < fields_count; k++) { jtulach@144: FieldData field=new FieldData(this); jtulach@144: field.read(in); jtulach@144: fields[k]=field; jtulach@144: } jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Reads and strores Method info. jtulach@144: */ jtulach@144: protected void readMethods(DataInputStream in) throws IOException { jtulach@144: int methods_count = in.readUnsignedShort(); jtulach@144: methods=new MethodData[methods_count]; jtulach@144: for (int k = 0; k < methods_count ; k++) { jtulach@144: MethodData method=new MethodData(this); jtulach@144: method.read(in); jtulach@144: methods[k]=method; jtulach@144: } jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * get a string jtulach@144: */ jtulach@144: public String getString(int n) { jaroslav@151: if (n == 0) { jaroslav@151: return null; jaroslav@151: } else { jaroslav@151: return (String)cpool[n]; jaroslav@151: } jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * get the type of constant given an index jtulach@144: */ jtulach@144: public byte getTag(int n) { jtulach@144: try{ jtulach@144: return tags[n]; jtulach@144: } catch (ArrayIndexOutOfBoundsException e) { jtulach@144: return (byte)100; jtulach@144: } jtulach@144: } jtulach@144: jtulach@144: static final String hexString="0123456789ABCDEF"; jtulach@144: jtulach@144: public static char hexTable[]=hexString.toCharArray(); jtulach@144: jtulach@144: static String toHex(long val, int width) { jtulach@144: StringBuffer s = new StringBuffer(); jtulach@144: for (int i=width-1; i>=0; i--) jtulach@144: s.append(hexTable[((int)(val>>(4*i)))&0xF]); jtulach@144: return "0x"+s.toString(); jtulach@144: } jtulach@144: jtulach@144: static String toHex(long val) { jtulach@144: int width; jtulach@144: for (width=16; width>0; width--) { jtulach@144: if ((val>>(width-1)*4)!=0) break; jtulach@144: } jtulach@144: return toHex(val, width); jtulach@144: } jtulach@144: jtulach@144: static String toHex(int val) { jtulach@144: int width; jtulach@144: for (width=8; width>0; width--) { jtulach@144: if ((val>>(width-1)*4)!=0) break; jtulach@144: } jtulach@144: return toHex(val, width); jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns the name of this class. jtulach@144: */ jtulach@144: public String getClassName() { jtulach@144: String res=null; jtulach@144: if (this_class==0) { jtulach@144: return res; jtulach@144: } jtulach@144: int tcpx; jtulach@144: try { jtulach@144: if (tags[this_class]!=CONSTANT_CLASS) { jtulach@144: return res; //" "; jtulach@144: } jtulach@144: tcpx=((CPX)cpool[this_class]).cpx; jtulach@144: } catch (ArrayIndexOutOfBoundsException e) { jtulach@144: return res; // "#"+cpx+"// invalid constant pool index"; jtulach@144: } catch (Throwable e) { jtulach@144: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; jtulach@144: } jtulach@144: jtulach@144: try { jtulach@144: return (String)(cpool[tcpx]); jtulach@144: } catch (ArrayIndexOutOfBoundsException e) { jtulach@144: return res; // "class #"+scpx+"// invalid constant pool index"; jtulach@144: } catch (ClassCastException e) { jtulach@144: return res; // "class #"+scpx+"// invalid constant pool reference"; jtulach@144: } catch (Throwable e) { jtulach@144: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; jtulach@144: } jtulach@144: jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns the name of class at perticular index. jtulach@144: */ jtulach@144: public String getClassName(int cpx) { jtulach@144: String res="#"+cpx; jtulach@144: if (cpx==0) { jtulach@144: return res; jtulach@144: } jtulach@144: int scpx; jtulach@144: try { jtulach@144: if (tags[cpx]!=CONSTANT_CLASS) { jtulach@144: return res; //" "; jtulach@144: } jtulach@144: scpx=((CPX)cpool[cpx]).cpx; jtulach@144: } catch (ArrayIndexOutOfBoundsException e) { jtulach@144: return res; // "#"+cpx+"// invalid constant pool index"; jtulach@144: } catch (Throwable e) { jtulach@144: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; jtulach@144: } jtulach@144: res="#"+scpx; jtulach@144: try { jtulach@144: return (String)(cpool[scpx]); jtulach@144: } catch (ArrayIndexOutOfBoundsException e) { jtulach@144: return res; // "class #"+scpx+"// invalid constant pool index"; jtulach@144: } catch (ClassCastException e) { jtulach@144: return res; // "class #"+scpx+"// invalid constant pool reference"; jtulach@144: } catch (Throwable e) { jtulach@144: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; jtulach@144: } jtulach@144: } jaroslav@355: jaroslav@355: public int getAccessFlags() { jaroslav@355: return access; jaroslav@355: } jtulach@144: jtulach@144: /** jtulach@144: * Returns true if it is a class jtulach@144: */ jtulach@144: public boolean isClass() { jtulach@144: if((access & ACC_INTERFACE) == 0) return true; jtulach@144: return false; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns true if it is a interface. jtulach@144: */ jtulach@144: public boolean isInterface(){ jtulach@144: if((access & ACC_INTERFACE) != 0) return true; jtulach@144: return false; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns true if this member is public, false otherwise. jtulach@144: */ jtulach@144: public boolean isPublic(){ jtulach@144: return (access & ACC_PUBLIC) != 0; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns the access of this class or interface. jtulach@144: */ jtulach@144: public String[] getAccess(){ jtulach@144: Vector v = new Vector(); jtulach@144: if ((access & ACC_PUBLIC) !=0) v.addElement("public"); jtulach@144: if ((access & ACC_FINAL) !=0) v.addElement("final"); jtulach@144: if ((access & ACC_ABSTRACT) !=0) v.addElement("abstract"); jtulach@144: String[] accflags = new String[v.size()]; jtulach@144: v.copyInto(accflags); jtulach@144: return accflags; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns list of innerclasses. jtulach@144: */ jtulach@144: public InnerClassData[] getInnerClasses(){ jtulach@144: return innerClasses; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns list of attributes. jtulach@144: */ jaroslav@152: final AttrData[] getAttributes(){ jtulach@144: return attrs; jtulach@144: } jaroslav@152: jaroslav@152: public byte[] findAnnotationData(boolean classRetention) { jaroslav@152: String n = classRetention ? jaroslav@152: "RuntimeInvisibleAnnotations" : // NOI18N jaroslav@152: "RuntimeVisibleAnnotations"; // NOI18N jaroslav@152: return findAttr(n, attrs); jaroslav@152: } jtulach@144: jtulach@144: /** jtulach@144: * Returns true if superbit is set. jtulach@144: */ jtulach@144: public boolean isSuperSet(){ jtulach@144: if ((access & ACC_SUPER) !=0) return true; jtulach@144: return false; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns super class name. jtulach@144: */ jtulach@144: public String getSuperClassName(){ jtulach@144: String res=null; jtulach@144: if (super_class==0) { jtulach@144: return res; jtulach@144: } jtulach@144: int scpx; jtulach@144: try { jtulach@144: if (tags[super_class]!=CONSTANT_CLASS) { jtulach@144: return res; //" "; jtulach@144: } jtulach@144: scpx=((CPX)cpool[super_class]).cpx; jtulach@144: } catch (ArrayIndexOutOfBoundsException e) { jtulach@144: return res; // "#"+cpx+"// invalid constant pool index"; jtulach@144: } catch (Throwable e) { jtulach@144: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; jtulach@144: } jtulach@144: jtulach@144: try { jtulach@144: return (String)(cpool[scpx]); jtulach@144: } catch (ArrayIndexOutOfBoundsException e) { jtulach@144: return res; // "class #"+scpx+"// invalid constant pool index"; jtulach@144: } catch (ClassCastException e) { jtulach@144: return res; // "class #"+scpx+"// invalid constant pool reference"; jtulach@144: } catch (Throwable e) { jtulach@144: return res; // "#"+cpx+"// ERROR IN DISASSEMBLER"; jtulach@144: } jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns list of super interfaces. jtulach@144: */ jtulach@144: public String[] getSuperInterfaces(){ jtulach@144: String interfacenames[] = new String[interfaces.length]; jtulach@144: int interfacecpx = -1; jtulach@144: for(int i = 0; i < interfaces.length; i++){ jtulach@144: interfacecpx=((CPX)cpool[interfaces[i]]).cpx; jtulach@144: interfacenames[i] = (String)(cpool[interfacecpx]); jtulach@144: } jtulach@144: return interfacenames; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns string at prticular constant pool index. jtulach@144: */ jtulach@144: public String getStringValue(int cpoolx) { jtulach@144: try { jtulach@144: return ((String)cpool[cpoolx]); jtulach@144: } catch (ArrayIndexOutOfBoundsException e) { jtulach@144: return "//invalid constant pool index:"+cpoolx; jtulach@144: } catch (ClassCastException e) { jtulach@144: return "//invalid constant pool ref:"+cpoolx; jtulach@144: } jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns list of field info. jtulach@144: */ jtulach@144: public FieldData[] getFields(){ jtulach@144: return fields; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns list of method info. jtulach@144: */ jtulach@144: public MethodData[] getMethods(){ jtulach@144: return methods; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns constant pool entry at that index. jtulach@144: */ jtulach@144: public CPX2 getCpoolEntry(int cpx){ jtulach@144: return ((CPX2)(cpool[cpx])); jtulach@144: } jtulach@144: jtulach@144: public Object getCpoolEntryobj(int cpx){ jtulach@144: return (cpool[cpx]); jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns index of this class. jtulach@144: */ jtulach@144: public int getthis_cpx(){ jtulach@144: return this_class; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns string at that index. jtulach@144: */ jtulach@144: public String StringValue(int cpx) { jaroslav@151: return stringValue(cpx, false); jaroslav@151: } jaroslav@151: public String stringValue(int cpx, boolean textual) { jaroslav@230: return stringValue(cpx, textual, null); jaroslav@230: } jaroslav@230: public String stringValue(int cpx, String[] classRefs) { jaroslav@230: return stringValue(cpx, true, classRefs); jaroslav@230: } jaroslav@230: private String stringValue(int cpx, boolean textual, String[] refs) { jtulach@144: if (cpx==0) return "#0"; jtulach@144: int tag; jtulach@144: Object x; jtulach@144: String suffix=""; jtulach@144: try { jtulach@144: tag=tags[cpx]; jtulach@144: x=cpool[cpx]; jtulach@144: } catch (IndexOutOfBoundsException e) { jtulach@144: return ""; jtulach@144: } jtulach@144: jtulach@144: if (x==null) return ""; jtulach@144: switch (tag) { jtulach@144: case CONSTANT_UTF8: { jtulach@161: if (!textual) { jtulach@161: return (String)x; jtulach@161: } jtulach@157: StringBuilder sb=new StringBuilder(); jtulach@144: String s=(String)x; jtulach@144: for (int k=0; k"; jtulach@144: } catch (ClassCastException e) { jtulach@144: return ""; jtulach@144: } jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns unqualified class name. jtulach@144: */ jtulach@144: public String getShortClassName(int cpx) { jtulach@144: String classname=javaName(getClassName(cpx)); jtulach@144: pkgPrefixLen=classname.lastIndexOf("/")+1; jtulach@144: if (pkgPrefixLen!=0) { jtulach@144: pkgPrefix=classname.substring(0,pkgPrefixLen); jtulach@144: if (classname.startsWith(pkgPrefix)) { jtulach@144: return classname.substring(pkgPrefixLen); jtulach@144: } jtulach@144: } jtulach@144: return classname; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns source file name. jtulach@144: */ jtulach@144: public String getSourceName(){ jtulach@144: return getName(source_cpx); jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns package name. jtulach@144: */ jtulach@144: public String getPkgName(){ jtulach@144: String classname=getClassName(this_class); jtulach@144: pkgPrefixLen=classname.lastIndexOf("/")+1; jtulach@144: if (pkgPrefixLen!=0) { jtulach@144: pkgPrefix=classname.substring(0,pkgPrefixLen); jtulach@144: return("package "+pkgPrefix.substring(0,pkgPrefixLen-1)+";\n"); jtulach@144: }else return null; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns total constant pool entry count. jtulach@144: */ jtulach@144: public int getCpoolCount(){ jtulach@144: return cpool_count; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns minor version of class file. jtulach@144: */ jtulach@144: public int getMinor_version(){ jtulach@144: return minor_version; jtulach@144: } jtulach@144: jtulach@144: /** jtulach@144: * Returns major version of class file. jtulach@144: */ jtulach@144: public int getMajor_version(){ jtulach@144: return major_version; jtulach@144: } jaroslav@149: jaroslav@149: private boolean isJavaIdentifierStart(int cp) { jaroslav@149: return ('a' <= cp && cp <= 'z') || ('A' <= cp && cp <= 'Z'); jaroslav@149: } jaroslav@149: jaroslav@149: private boolean isJavaIdentifierPart(int cp) { jaroslav@149: return isJavaIdentifierStart(cp) || ('0' <= cp && cp <= '9'); jaroslav@149: } jaroslav@151: jaroslav@151: public String[] getNameAndType(int indx) { jaroslav@151: return getNameAndType(indx, 0, new String[2]); jaroslav@151: } jaroslav@151: jaroslav@151: private String[] getNameAndType(int indx, int at, String[] arr) { jaroslav@151: CPX2 c2 = getCpoolEntry(indx); jaroslav@151: arr[at] = StringValue(c2.cpx1); jaroslav@151: arr[at + 1] = StringValue(c2.cpx2); jaroslav@151: return arr; jaroslav@151: } jaroslav@151: jaroslav@151: public String[] getFieldInfoName(int indx) { jaroslav@151: CPX2 c2 = getCpoolEntry(indx); jaroslav@151: String[] arr = new String[3]; jaroslav@151: arr[0] = getClassName(c2.cpx1); jaroslav@151: return getNameAndType(c2.cpx2, 1, arr); jaroslav@151: } jaroslav@152: jaroslav@152: static byte[] findAttr(String n, AttrData[] attrs) { jaroslav@152: for (AttrData ad : attrs) { jaroslav@152: if (n.equals(ad.getAttrName())) { jaroslav@152: return ad.getData(); jaroslav@152: } jaroslav@152: } jaroslav@152: return null; jaroslav@152: } jtulach@144: }