001: /*
002: * Copyright 2001-2003 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package com.sun.java.util.jar.pack;
027:
028: import java.io.*;
029: import java.util.*;
030: import com.sun.java.util.jar.pack.Package.Class;
031: import com.sun.java.util.jar.pack.Package.InnerClass;
032: import com.sun.java.util.jar.pack.ConstantPool.*;
033:
034: /**
035: * Writer for a class file that is incorporated into a package.
036: * @author John Rose
037: * @version 1.21, 05/05/07
038: */
039: class ClassWriter implements Constants {
040: int verbose;
041:
042: Package pkg;
043: Class cls;
044: DataOutputStream out;
045: Index cpIndex;
046:
047: ClassWriter(Class cls, OutputStream out) throws IOException {
048: this .pkg = cls.getPackage();
049: this .cls = cls;
050: this .verbose = pkg.verbose;
051: this .out = new DataOutputStream(new BufferedOutputStream(out));
052: this .cpIndex = ConstantPool.makeIndex(cls.toString(), cls
053: .getCPMap());
054: this .cpIndex.flattenSigs = true;
055: if (verbose > 1)
056: Utils.log.fine("local CP="
057: + (verbose > 2 ? cpIndex.dumpString() : cpIndex
058: .toString()));
059: }
060:
061: private void writeShort(int x) throws IOException {
062: out.writeShort(x);
063: }
064:
065: private void writeInt(int x) throws IOException {
066: out.writeInt(x);
067: }
068:
069: /** Write a 2-byte int representing a CP entry, using the local cpIndex. */
070: private void writeRef(Entry e) throws IOException {
071: int i = (e == null) ? 0 : cpIndex.indexOf(e);
072: writeShort(i);
073: }
074:
075: void write() throws IOException {
076: boolean ok = false;
077: try {
078: if (verbose > 1)
079: Utils.log.fine("...writing " + cls);
080: writeMagicNumbers();
081: writeConstantPool();
082: writeHeader();
083: writeMembers(false); // fields
084: writeMembers(true); // methods
085: writeAttributes(ATTR_CONTEXT_CLASS, cls);
086: /* Closing here will cause all the underlying
087: streams to close, Causing the jar stream
088: to close prematurely, instead we just flush.
089: out.close();
090: */
091: out.flush();
092: ok = true;
093: } finally {
094: if (!ok) {
095: Utils.log.warning("Error on output of " + cls);
096: }
097: }
098: }
099:
100: void writeMagicNumbers() throws IOException {
101: writeInt(cls.magic);
102: writeShort(cls.minver);
103: writeShort(cls.majver);
104: }
105:
106: void writeConstantPool() throws IOException {
107: Entry[] cpMap = cls.cpMap;
108: writeShort(cpMap.length);
109: for (int i = 0; i < cpMap.length; i++) {
110: Entry e = cpMap[i];
111: assert ((e == null) == (i == 0 || cpMap[i - 1] != null
112: && cpMap[i - 1].isDoubleWord()));
113: if (e == null)
114: continue;
115: byte tag = e.getTag();
116: if (verbose > 2)
117: Utils.log.fine(" CP[" + i + "] = " + e);
118: out.write(tag);
119: switch (tag) {
120: case CONSTANT_Signature:
121: assert (false); // should not reach here
122: break;
123: case CONSTANT_Utf8:
124: out.writeUTF(e.stringValue());
125: break;
126: case CONSTANT_Integer:
127: out
128: .writeInt(((NumberEntry) e).numberValue()
129: .intValue());
130: break;
131: case CONSTANT_Float:
132: float fval = ((NumberEntry) e).numberValue()
133: .floatValue();
134: out.writeInt(Float.floatToRawIntBits(fval));
135: break;
136: case CONSTANT_Long:
137: out.writeLong(((NumberEntry) e).numberValue()
138: .longValue());
139: break;
140: case CONSTANT_Double:
141: double dval = ((NumberEntry) e).numberValue()
142: .doubleValue();
143: out.writeLong(Double.doubleToRawLongBits(dval));
144: break;
145: case CONSTANT_Class:
146: case CONSTANT_String:
147: writeRef(e.getRef(0));
148: break;
149: case CONSTANT_Fieldref:
150: case CONSTANT_Methodref:
151: case CONSTANT_InterfaceMethodref:
152: case CONSTANT_NameandType:
153: writeRef(e.getRef(0));
154: writeRef(e.getRef(1));
155: break;
156: default:
157: throw new IOException("Bad constant pool tag " + tag);
158: }
159: }
160: }
161:
162: void writeHeader() throws IOException {
163: writeShort(cls.flags);
164: writeRef(cls.this Class);
165: writeRef(cls.super Class);
166: writeShort(cls.interfaces.length);
167: for (int i = 0; i < cls.interfaces.length; i++) {
168: writeRef(cls.interfaces[i]);
169: }
170: }
171:
172: void writeMembers(boolean doMethods) throws IOException {
173: List mems;
174: if (!doMethods)
175: mems = cls.getFields();
176: else
177: mems = cls.getMethods();
178: writeShort(mems.size());
179: for (Iterator i = mems.iterator(); i.hasNext();) {
180: Class.Member m = (Class.Member) i.next();
181: writeMember(m, doMethods);
182: }
183: }
184:
185: void writeMember(Class.Member m, boolean doMethod)
186: throws IOException {
187: if (verbose > 2)
188: Utils.log.fine("writeMember " + m);
189: writeShort(m.flags);
190: writeRef(m.getDescriptor().nameRef);
191: writeRef(m.getDescriptor().typeRef);
192: writeAttributes(!doMethod ? ATTR_CONTEXT_FIELD
193: : ATTR_CONTEXT_METHOD, m);
194: }
195:
196: // handy buffer for collecting attrs
197: ByteArrayOutputStream buf = new ByteArrayOutputStream();
198: DataOutputStream bufOut = new DataOutputStream(buf);
199:
200: void writeAttributes(int ctype, Attribute.Holder h)
201: throws IOException {
202: if (h.attributes == null) {
203: writeShort(0); // attribute size
204: return;
205: }
206: writeShort(h.attributes.size());
207: for (Iterator i = h.attributes.iterator(); i.hasNext();) {
208: Attribute a = (Attribute) i.next();
209: a.finishRefs(cpIndex);
210: writeRef(a.getNameRef());
211: if (a.layout() == Package.attrCodeEmpty
212: || a.layout() == Package.attrInnerClassesEmpty) {
213: // These are hardwired.
214: DataOutputStream savedOut = out;
215: assert (out != bufOut);
216: buf.reset();
217: out = bufOut;
218: if (a.name() == "Code") {
219: Class.Method m = (Class.Method) h;
220: writeCode(m.code);
221: } else {
222: assert (h == cls);
223: writeInnerClasses(cls);
224: }
225: out = savedOut;
226: if (verbose > 2)
227: Utils.log.fine("Attribute " + a.name() + " ["
228: + buf.size() + "]");
229: writeInt(buf.size());
230: buf.writeTo(out);
231: } else {
232: if (verbose > 2)
233: Utils.log.fine("Attribute " + a.name() + " ["
234: + a.size() + "]");
235: writeInt(a.size());
236: out.write(a.bytes());
237: }
238: }
239: }
240:
241: void writeCode(Code code) throws IOException {
242: code.finishRefs(cpIndex);
243: writeShort(code.max_stack);
244: writeShort(code.max_locals);
245: writeInt(code.bytes.length);
246: out.write(code.bytes);
247: int nh = code.getHandlerCount();
248: writeShort(nh);
249: for (int i = 0; i < nh; i++) {
250: writeShort(code.handler_start[i]);
251: writeShort(code.handler_end[i]);
252: writeShort(code.handler_catch[i]);
253: writeRef(code.handler_class[i]);
254: }
255: writeAttributes(ATTR_CONTEXT_CODE, code);
256: }
257:
258: void writeInnerClasses(Class cls) throws IOException {
259: List ics = cls.getInnerClasses();
260: writeShort(ics.size());
261: for (Iterator i = ics.iterator(); i.hasNext();) {
262: InnerClass ic = (InnerClass) i.next();
263: writeRef(ic.thisClass);
264: writeRef(ic.outerClass);
265: writeRef(ic.name);
266: writeShort(ic.flags);
267: }
268: }
269: }
|