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