package jas; import java.io.*; import java.util.Hashtable; import java.util.Enumeration; import java.util.Vector; /** * This is the place where all information about the class to * be created resides. * * @author $Author: jonmeyerny $ * @version $Revision: 1.1 $ */ public class ClassEnv implements RuntimeConstants { int magic; short version_lo, version_hi; CP this_class, super_class; short class_access; Hashtable cpe, cpe_index; Vector interfaces; Vector vars; Vector methods; SourceAttr source; SignatureAttr signature; SourceDebugExtensionAttr debug; EnclosingMethodAttr enclosing; DeprecatedAttr depr; InnerClassesAttr innerclasses; AnnotationAttr annVis, annInvis; Vector generic; public ClassEnv() { // Fill in reasonable defaults magic = JAVA_MAGIC; version_lo = (short) JAVA_MINOR_VERSION; version_hi = (short) JAVA_VERSION; // Initialize bags cpe = new Hashtable(); cpe_index = null; interfaces = new Vector(); vars = new Vector(); methods = new Vector(); annVis = annInvis = null; generic = new Vector(); } /** * Define this class to have this name. * @param name CPE representing name for class. (This is usually * a ClassCP) */ public void setClass(CP name) { this_class = name; addCPItem(name); } /** * Define this class to have this superclass * @param name CPE representing name for class. (This is usually * a ClassCP) */ public void setSuperClass(CP name) { super_class = name; addCPItem(name); } /** * Set the class access for this class. Constants understood * by this are present along with the java Beta distribution. * @param access number representing access permissions for * the entire class. * @see RuntimeConstants */ public void setClassAccess(short access) { class_access = access; } /** * Add this CP to the list of interfaces supposedly implemented by * this class. Note that the CP ought to be a ClassCP to make * sense to the VM. */ public void addInterface(CP ifc) { addCPItem(ifc); interfaces.addElement(ifc); } /** * Add this to the list of interfaces supposedly implemented * by this class. Note that each CP is usually a ClassCP. * @param ilist An array of CP items representing the * interfaces implemented by this class. */ public void addInterface(CP ilist[]) { for (int i=0; i<ilist.length; i++) { interfaces.addElement(ilist[i]); addCPItem(ilist[i]); } } public void addField(Var v) { vars.addElement(v); v.resolve(this); } /** * Write the contents of the class. * * @param out DataOutputStream on which the contents are written. */ public void write(DataOutputStream out) throws IOException, jasError { // Headers out.writeInt(magic); out.writeShort(version_lo); out.writeShort(version_hi); // cpe items int curidx = 1; // make up indices for entries cpe_index = new Hashtable(); for (Enumeration e = cpe.elements(); e.hasMoreElements();) { CP tmp = (CP)(e.nextElement()); cpe_index.put(tmp.getUniq(), new Integer(curidx)); curidx++; if ((tmp instanceof LongCP) || (tmp instanceof DoubleCP)) curidx++; } out.writeShort((short)curidx); // Now write out all the entries for (Enumeration e = cpe.elements(); e.hasMoreElements();) { CP now = (CP) (e.nextElement()); now.write(this, out); } // Class hierarchy/access out.writeShort(class_access); out.writeShort(getCPIndex(this_class)); out.writeShort(getCPIndex(super_class)); // interfaces out.writeShort(interfaces.size()); for (Enumeration e = interfaces.elements(); e.hasMoreElements();) { CP c = (CP)(e.nextElement()); out.writeShort(getCPIndex(c)); } // variables out.writeShort(vars.size()); for (Enumeration e = vars.elements(); e.hasMoreElements();) { Var v = (Var)(e.nextElement()); v.write(this, out); } // methods out.writeShort(methods.size()); for (Enumeration e = methods.elements(); e.hasMoreElements();) { Method m = (Method)(e.nextElement()); m.write(this, out); } // additional attributes short numExtra = 0; if (source != null) { numExtra++; } if (debug != null) { numExtra++; } if (enclosing != null) { numExtra++; } if (signature != null) { numExtra++; } if (innerclasses != null) { numExtra++; } if (depr != null) { numExtra++; } if (annVis != null) { numExtra++; } if (annInvis != null) { numExtra++; } numExtra += generic.size(); out.writeShort(numExtra); if (source != null) { source.write(this, out); } if (debug != null) { debug.write(this, out); } if (enclosing != null) { enclosing.write(this, out); } if (signature != null) { signature.write(this, out); } if (innerclasses != null) { innerclasses.write(this, out); } if (depr != null) { depr.write(this, out); } if (annVis != null) { annVis.write(this, out); } if (annInvis != null) { annInvis.write(this, out); } for (Enumeration gen=generic.elements(); gen.hasMoreElements(); ) { GenericAttr gattr = (GenericAttr)gen.nextElement(); gattr.write(this, out); } out.flush(); } /** * This is the method to add CPE items to a class. CPE items for * a class are "uniquefied". Ie, if you add a CPE items whose * contents already exist in the class, only one entry is finally * written out when the class is written. * * @param cp Item to be added to the class */ public void addCPItem(CP cp) { String uniq = cp.getUniq(); CP intern; if ((intern = (CP)(cpe.get(uniq))) == null) { // add it cpe.put(uniq, cp); // resolve it so it adds anything // which it depends on cp.resolve(this); } } /** * Add an attribute specifying the name of the source file * for the class * @param source SourceAttribute specifying the source for the file */ public void setSource(SourceAttr source) { this.source = source; source.resolve(this); } /** * Add an attribute specifying the name of the source file * for the clas. * @param source String with the name of the class */ public void setSource(String source) { this.source = new SourceAttr(source); this.source.resolve(this); } /** * Add an attribute specifying extended debug information * @param debug String the extended debug information */ public void setSourceDebugExtension(String debug) { if ( this.debug != null ) this.debug.append(debug); else { this.debug = new SourceDebugExtensionAttr(debug); this.debug.resolve(this); } } /** * Add an attribute specifying the enclosing method of this class * @param cls String the enclosing class * @param mtd String the enclosing method * @param dsc String the enclosing method descriptor */ public void setEnclosingMethod(String cls, String mtd, String dsc) { this.enclosing = new EnclosingMethodAttr(cls, mtd, dsc); this.enclosing.resolve(this); } /** * Add an attribute specifying the signature of this class * @param sig String the signature */ public void setSignature(String sig) { this.signature = new SignatureAttr(sig); this.signature.resolve(this); } public void setDeprecated(DeprecatedAttr depr) { this.depr = depr; depr.resolve(this); } /** * Add a generic attribute to the class file. A generic attribute * contains a stream of uninterpreted bytes which is ignored by * the VM (as long as its name doesn't conflict with other names * for attributes that are understood by the VM) */ public void addGenericAttr(GenericAttr g) { generic.addElement(g); g.resolve(this); } public void addInnerClass(short iacc, String name, String inner, String outer) { if(innerclasses == null) { innerclasses = new InnerClassesAttr(); innerclasses.resolve(this); } InnerClass ic = new InnerClass(iacc, name, inner, outer); ic.resolve(this); innerclasses.addInnerClass(ic); } /* * procedure group for annotation description */ public Annotation addAnnotation(boolean visible, String clsname) { Annotation ann = new Annotation(clsname); AnnotationAttr aa = visible ? annVis : annInvis; if(aa == null) { aa = new AnnotationAttr(visible); if(visible) annVis = aa; else annInvis = aa; } aa.add(ann); return(ann); } public void endHeader() { if(annVis != null) annVis.resolve(this); if(annInvis != null) annInvis.resolve(this); } /** * This allows more control over generating CP's for methods * if you feel so inclined. */ public void addMethod(Method m) { m.resolve(this); methods.addElement(m); } short getCPIndex(CP cp) throws jasError { if (cpe_index == null) throw new jasError("Internal error: CPE index has not been generated"); Integer idx = (Integer)(cpe_index.get(cp.getUniq())); if (idx == null) throw new jasError("Item " + cp + " not in the class"); return ((short)(idx.intValue())); } /** * Change the bytecode version of this class * The version will be version_high.version_low * @param version_high short * @param version_low short */ public void setVersion(short version_high, short version_low) { version_hi = version_high; version_lo = version_low; } }