1 2 package jas; 3 4 import java.io.*; 5 import java.util.Hashtable; 6 import java.util.Enumeration; 7 import java.util.Vector; 8 9 10 11 /** 12 * This is the place where all information about the class to 13 * be created resides. 14 * 15 * @author $Author: jonmeyerny $ 16 * @version $Revision: 1.1 $ 17 */ 18 19 public class ClassEnv implements RuntimeConstants 20 { 21 int magic; 22 short version_lo, version_hi; 23 CP this_class, super_class; 24 short class_access; 25 Hashtable cpe, cpe_index; 26 Vector interfaces; 27 Vector vars; 28 Vector methods; 29 SourceAttr source; 30 SignatureAttr signature; 31 SourceDebugExtensionAttr debug; 32 EnclosingMethodAttr enclosing; 33 DeprecatedAttr depr; 34 InnerClassesAttr innerclasses; 35 AnnotationAttr annVis, annInvis; 36 Vector generic; 37 ClassEnv()38 public ClassEnv() 39 { 40 // Fill in reasonable defaults 41 magic = JAVA_MAGIC; 42 version_lo = (short) JAVA_MINOR_VERSION; 43 version_hi = (short) JAVA_VERSION; 44 // Initialize bags 45 cpe = new Hashtable(); 46 cpe_index = null; 47 interfaces = new Vector(); 48 vars = new Vector(); 49 methods = new Vector(); 50 annVis = annInvis = null; 51 generic = new Vector(); 52 } 53 54 /** 55 * Define this class to have this name. 56 * @param name CPE representing name for class. (This is usually 57 * a ClassCP) 58 */ setClass(CP name)59 public void setClass(CP name) 60 { this_class = name; addCPItem(name); } 61 /** 62 * Define this class to have this superclass 63 * @param name CPE representing name for class. (This is usually 64 * a ClassCP) 65 */ setSuperClass(CP name)66 public void setSuperClass(CP name) 67 { super_class = name; addCPItem(name); } 68 69 /** 70 * Set the class access for this class. Constants understood 71 * by this are present along with the java Beta distribution. 72 * @param access number representing access permissions for 73 * the entire class. 74 * @see RuntimeConstants 75 */ setClassAccess(short access)76 public void setClassAccess(short access) 77 { class_access = access; } 78 79 /** 80 * Add this CP to the list of interfaces supposedly implemented by 81 * this class. Note that the CP ought to be a ClassCP to make 82 * sense to the VM. 83 */ 84 addInterface(CP ifc)85 public void addInterface(CP ifc) 86 { 87 addCPItem(ifc); 88 interfaces.addElement(ifc); 89 } 90 91 /** 92 * Add this to the list of interfaces supposedly implemented 93 * by this class. Note that each CP is usually a ClassCP. 94 * @param ilist An array of CP items representing the 95 * interfaces implemented by this class. 96 */ addInterface(CP ilist[])97 public void addInterface(CP ilist[]) 98 { 99 for (int i=0; i<ilist.length; i++) 100 { 101 interfaces.addElement(ilist[i]); 102 addCPItem(ilist[i]); 103 } 104 } 105 addField(Var v)106 public void addField(Var v) 107 { 108 vars.addElement(v); 109 v.resolve(this); 110 } 111 /** 112 * Write the contents of the class. 113 * 114 * @param out DataOutputStream on which the contents are written. 115 */ write(DataOutputStream out)116 public void write(DataOutputStream out) 117 throws IOException, jasError 118 { 119 // Headers 120 out.writeInt(magic); 121 out.writeShort(version_lo); 122 out.writeShort(version_hi); 123 124 // cpe items 125 int curidx = 1; 126 // make up indices for entries 127 cpe_index = new Hashtable(); 128 for (Enumeration e = cpe.elements(); e.hasMoreElements();) 129 { 130 CP tmp = (CP)(e.nextElement()); 131 cpe_index.put(tmp.getUniq(), new Integer(curidx)); 132 curidx++; 133 if ((tmp instanceof LongCP) || 134 (tmp instanceof DoubleCP)) 135 curidx++; 136 } 137 out.writeShort((short)curidx); 138 139 // Now write out all the entries 140 for (Enumeration e = cpe.elements(); e.hasMoreElements();) 141 { 142 CP now = (CP) (e.nextElement()); 143 now.write(this, out); 144 } 145 146 // Class hierarchy/access 147 out.writeShort(class_access); 148 out.writeShort(getCPIndex(this_class)); 149 out.writeShort(getCPIndex(super_class)); 150 // interfaces 151 out.writeShort(interfaces.size()); 152 for (Enumeration e = interfaces.elements(); e.hasMoreElements();) 153 { 154 CP c = (CP)(e.nextElement()); 155 out.writeShort(getCPIndex(c)); 156 } 157 // variables 158 out.writeShort(vars.size()); 159 for (Enumeration e = vars.elements(); e.hasMoreElements();) 160 { 161 Var v = (Var)(e.nextElement()); 162 v.write(this, out); 163 } 164 165 // methods 166 out.writeShort(methods.size()); 167 for (Enumeration e = methods.elements(); e.hasMoreElements();) 168 { 169 Method m = (Method)(e.nextElement()); 170 m.write(this, out); 171 } 172 // additional attributes 173 short numExtra = 0; 174 if (source != null) 175 { numExtra++; } 176 if (debug != null) 177 { numExtra++; } 178 if (enclosing != null) 179 { numExtra++; } 180 if (signature != null) 181 { numExtra++; } 182 if (innerclasses != null) 183 { numExtra++; } 184 if (depr != null) 185 { numExtra++; } 186 if (annVis != null) 187 { numExtra++; } 188 if (annInvis != null) 189 { numExtra++; } 190 numExtra += generic.size(); 191 192 out.writeShort(numExtra); 193 if (source != null) 194 { source.write(this, out); } 195 if (debug != null) 196 { debug.write(this, out); } 197 if (enclosing != null) 198 { enclosing.write(this, out); } 199 if (signature != null) 200 { signature.write(this, out); } 201 if (innerclasses != null) 202 { innerclasses.write(this, out); } 203 if (depr != null) 204 { depr.write(this, out); } 205 if (annVis != null) 206 { annVis.write(this, out); } 207 if (annInvis != null) 208 { annInvis.write(this, out); } 209 for (Enumeration gen=generic.elements(); gen.hasMoreElements(); ) 210 { 211 GenericAttr gattr = (GenericAttr)gen.nextElement(); 212 gattr.write(this, out); 213 } 214 out.flush(); 215 } 216 217 /** 218 * This is the method to add CPE items to a class. CPE items for 219 * a class are "uniquefied". Ie, if you add a CPE items whose 220 * contents already exist in the class, only one entry is finally 221 * written out when the class is written. 222 * 223 * @param cp Item to be added to the class 224 */ 225 addCPItem(CP cp)226 public void addCPItem(CP cp) 227 { 228 String uniq = cp.getUniq(); 229 CP intern; 230 231 if ((intern = (CP)(cpe.get(uniq))) == null) 232 { 233 // add it 234 cpe.put(uniq, cp); 235 // resolve it so it adds anything 236 // which it depends on 237 cp.resolve(this); 238 } 239 } 240 241 /** 242 * Add an attribute specifying the name of the source file 243 * for the class 244 * @param source SourceAttribute specifying the source for the file 245 */ 246 setSource(SourceAttr source)247 public void setSource(SourceAttr source) 248 { this.source = source; source.resolve(this); } 249 250 /** 251 * Add an attribute specifying the name of the source file 252 * for the clas. 253 * @param source String with the name of the class 254 */ setSource(String source)255 public void setSource(String source) 256 { this.source = new SourceAttr(source); this.source.resolve(this); } 257 258 /** 259 * Add an attribute specifying extended debug information 260 * @param debug String the extended debug information 261 */ setSourceDebugExtension(String debug)262 public void setSourceDebugExtension(String debug) 263 { 264 if ( this.debug != null ) 265 this.debug.append(debug); 266 else { 267 this.debug = new SourceDebugExtensionAttr(debug); 268 this.debug.resolve(this); 269 } 270 } 271 272 273 /** 274 * Add an attribute specifying the enclosing method of this class 275 * @param cls String the enclosing class 276 * @param mtd String the enclosing method 277 * @param dsc String the enclosing method descriptor 278 */ setEnclosingMethod(String cls, String mtd, String dsc)279 public void setEnclosingMethod(String cls, String mtd, String dsc) 280 { this.enclosing = new EnclosingMethodAttr(cls, mtd, dsc); 281 this.enclosing.resolve(this); } 282 283 284 /** 285 * Add an attribute specifying the signature of this class 286 * @param sig String the signature 287 */ setSignature(String sig)288 public void setSignature(String sig) 289 { this.signature = new SignatureAttr(sig); 290 this.signature.resolve(this); } 291 292 setDeprecated(DeprecatedAttr depr)293 public void setDeprecated(DeprecatedAttr depr) 294 { this.depr = depr; depr.resolve(this); } 295 296 /** 297 * Add a generic attribute to the class file. A generic attribute 298 * contains a stream of uninterpreted bytes which is ignored by 299 * the VM (as long as its name doesn't conflict with other names 300 * for attributes that are understood by the VM) 301 */ addGenericAttr(GenericAttr g)302 public void addGenericAttr(GenericAttr g) 303 { generic.addElement(g); g.resolve(this); } 304 addInnerClass(short iacc, String name, String inner, String outer)305 public void addInnerClass(short iacc, String name, String inner, String outer) 306 { 307 if(innerclasses == null) { 308 innerclasses = new InnerClassesAttr(); 309 innerclasses.resolve(this); 310 } 311 InnerClass ic = new InnerClass(iacc, name, inner, outer); 312 ic.resolve(this); 313 innerclasses.addInnerClass(ic); 314 } 315 316 /* 317 * procedure group for annotation description 318 */ addAnnotation(boolean visible, String clsname)319 public Annotation addAnnotation(boolean visible, String clsname) 320 { 321 Annotation ann = new Annotation(clsname); 322 AnnotationAttr aa = visible ? annVis : annInvis; 323 if(aa == null) { 324 aa = new AnnotationAttr(visible); 325 if(visible) annVis = aa; 326 else annInvis = aa; 327 } 328 aa.add(ann); 329 return(ann); 330 } 331 endHeader()332 public void endHeader() 333 { 334 if(annVis != null) annVis.resolve(this); 335 if(annInvis != null) annInvis.resolve(this); 336 } 337 338 /** 339 * This allows more control over generating CP's for methods 340 * if you feel so inclined. 341 */ addMethod(Method m)342 public void addMethod(Method m) 343 { 344 m.resolve(this); 345 methods.addElement(m); 346 } 347 getCPIndex(CP cp)348 short getCPIndex(CP cp) 349 throws jasError 350 { 351 if (cpe_index == null) 352 throw new jasError("Internal error: CPE index has not been generated"); 353 354 Integer idx = (Integer)(cpe_index.get(cp.getUniq())); 355 if (idx == null) 356 throw new jasError("Item " + cp + " not in the class"); 357 return ((short)(idx.intValue())); 358 } 359 360 /** 361 * Change the bytecode version of this class 362 * The version will be version_high.version_low 363 * @param version_high short 364 * @param version_low short 365 */ setVersion(short version_high, short version_low)366 public void setVersion(short version_high, short version_low) 367 { 368 version_hi = version_high; 369 version_lo = version_low; 370 } 371 } 372