1 /* 2 * Copyright (c) 2001, 2003, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.java.util.jar.pack; 27 28 29 import com.sun.java.util.jar.pack.ConstantPool.Entry; 30 import com.sun.java.util.jar.pack.ConstantPool.Index; 31 import com.sun.java.util.jar.pack.ConstantPool.NumberEntry; 32 import com.sun.java.util.jar.pack.Package.Class; 33 import com.sun.java.util.jar.pack.Package.InnerClass; 34 import java.io.BufferedOutputStream; 35 import java.io.ByteArrayOutputStream; 36 import java.io.DataOutputStream; 37 import java.io.IOException; 38 import java.io.OutputStream; 39 import java.util.Iterator; 40 import java.util.List; 41 42 /** 43 * Writer for a class file that is incorporated into a package. 44 * @author John Rose 45 */ 46 class ClassWriter implements Constants { 47 int verbose; 48 49 Package pkg; 50 Class cls; 51 DataOutputStream out; 52 Index cpIndex; 53 54 ClassWriter(Class cls, OutputStream out) throws IOException { 55 this.pkg = cls.getPackage(); 56 this.cls = cls; 57 this.verbose = pkg.verbose; 58 this.out = new DataOutputStream(new BufferedOutputStream(out)); 59 this.cpIndex = ConstantPool.makeIndex(cls.toString(), cls.getCPMap()); 60 this.cpIndex.flattenSigs = true; 61 if (verbose > 1) 62 Utils.log.fine("local CP="+(verbose > 2 ? cpIndex.dumpString() : cpIndex.toString())); 63 } 64 65 private void writeShort(int x) throws IOException { 66 out.writeShort(x); 67 } 68 69 private void writeInt(int x) throws IOException { 70 out.writeInt(x); 71 } 72 73 /** Write a 2-byte int representing a CP entry, using the local cpIndex. */ 74 private void writeRef(Entry e) throws IOException { 75 int i = (e == null) ? 0 : cpIndex.indexOf(e); 76 writeShort(i); 77 } 78 79 void write() throws IOException { 80 boolean ok = false; 81 try { 82 if (verbose > 1) Utils.log.fine("...writing "+cls); 83 writeMagicNumbers(); 84 writeConstantPool(); 85 writeHeader(); 86 writeMembers(false); // fields 87 writeMembers(true); // methods 88 writeAttributes(ATTR_CONTEXT_CLASS, cls); 89 /* Closing here will cause all the underlying 90 streams to close, Causing the jar stream 91 to close prematurely, instead we just flush. 92 out.close(); 93 */ 94 out.flush(); 95 ok = true; 96 } finally { 97 if (!ok) { 98 Utils.log.warning("Error on output of "+cls); 99 } 100 } 101 } 102 103 void writeMagicNumbers() throws IOException { 104 writeInt(cls.magic); 105 writeShort(cls.minver); 106 writeShort(cls.majver); 107 } 108 109 void writeConstantPool() throws IOException { 110 Entry[] cpMap = cls.cpMap; 111 writeShort(cpMap.length); 112 for (int i = 0; i < cpMap.length; i++) { 113 Entry e = cpMap[i]; 114 assert((e == null) == (i == 0 || cpMap[i-1] != null && cpMap[i-1].isDoubleWord())); 115 if (e == null) continue; 116 byte tag = e.getTag(); 117 if (verbose > 2) 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.writeInt(((NumberEntry)e).numberValue().intValue()); 128 break; 129 case CONSTANT_Float: 130 float fval = ((NumberEntry)e).numberValue().floatValue(); 131 out.writeInt(Float.floatToRawIntBits(fval)); 132 break; 133 case CONSTANT_Long: 134 out.writeLong(((NumberEntry)e).numberValue().longValue()); 135 break; 136 case CONSTANT_Double: 137 double dval = ((NumberEntry)e).numberValue().doubleValue(); 138 out.writeLong(Double.doubleToRawLongBits(dval)); 139 break; 140 case CONSTANT_Class: 141 case CONSTANT_String: 142 writeRef(e.getRef(0)); 143 break; 144 case CONSTANT_Fieldref: 145 case CONSTANT_Methodref: 146 case CONSTANT_InterfaceMethodref: 147 case CONSTANT_NameandType: 148 writeRef(e.getRef(0)); 149 writeRef(e.getRef(1)); 150 break; 151 default: 152 throw new IOException("Bad constant pool tag "+tag); 153 } 154 } 155 } 156 157 void writeHeader() throws IOException { 158 writeShort(cls.flags); 159 writeRef(cls.thisClass); 160 writeRef(cls.superClass); 161 writeShort(cls.interfaces.length); 162 for (int i = 0; i < cls.interfaces.length; i++) { 163 writeRef(cls.interfaces[i]); 164 } 165 } 166 167 void writeMembers(boolean doMethods) throws IOException { 168 List mems; 169 if (!doMethods) 170 mems = cls.getFields(); 171 else 172 mems = cls.getMethods(); 173 writeShort(mems.size()); 174 for (Iterator i = mems.iterator(); i.hasNext(); ) { 175 Class.Member m = (Class.Member) i.next(); 176 writeMember(m, doMethods); 177 } 178 } 179 180 void writeMember(Class.Member m, boolean doMethod) throws IOException { 181 if (verbose > 2) Utils.log.fine("writeMember "+m); 182 writeShort(m.flags); 183 writeRef(m.getDescriptor().nameRef); 184 writeRef(m.getDescriptor().typeRef); 185 writeAttributes(!doMethod ? ATTR_CONTEXT_FIELD : ATTR_CONTEXT_METHOD, 186 m); 187 } 188 189 // handy buffer for collecting attrs 190 ByteArrayOutputStream buf = new ByteArrayOutputStream(); 191 DataOutputStream bufOut = new DataOutputStream(buf); 192 193 void writeAttributes(int ctype, Attribute.Holder h) throws IOException { 194 if (h.attributes == null) { 195 writeShort(0); // attribute size 196 return; 197 } 198 writeShort(h.attributes.size()); 199 for (Iterator i = h.attributes.iterator(); i.hasNext(); ) { 200 Attribute a = (Attribute) i.next(); 201 a.finishRefs(cpIndex); 202 writeRef(a.getNameRef()); 203 if (a.layout() == Package.attrCodeEmpty || 204 a.layout() == Package.attrInnerClassesEmpty) { 205 // These are hardwired. 206 DataOutputStream savedOut = out; 207 assert(out != bufOut); 208 buf.reset(); 209 out = bufOut; 210 if (a.name() == "Code") { 211 Class.Method m = (Class.Method) h; 212 writeCode(m.code); 213 } else { 214 assert(h == cls); 215 writeInnerClasses(cls); 216 } 217 out = savedOut; 218 if (verbose > 2) 219 Utils.log.fine("Attribute "+a.name()+" ["+buf.size()+"]"); 220 writeInt(buf.size()); 221 buf.writeTo(out); 222 } else { 223 if (verbose > 2) 224 Utils.log.fine("Attribute "+a.name()+" ["+a.size()+"]"); 225 writeInt(a.size()); 226 out.write(a.bytes()); 227 } 228 } 229 } 230 231 void writeCode(Code code) throws IOException { 232 code.finishRefs(cpIndex); 233 writeShort(code.max_stack); 234 writeShort(code.max_locals); 235 writeInt(code.bytes.length); 236 out.write(code.bytes); 237 int nh = code.getHandlerCount(); 238 writeShort(nh); 239 for (int i = 0; i < nh; i++) { 240 writeShort(code.handler_start[i]); 241 writeShort(code.handler_end[i]); 242 writeShort(code.handler_catch[i]); 243 writeRef(code.handler_class[i]); 244 } 245 writeAttributes(ATTR_CONTEXT_CODE, code); 246 } 247 248 void writeInnerClasses(Class cls) throws IOException { 249 List ics = cls.getInnerClasses(); 250 writeShort(ics.size()); 251 for (Iterator i = ics.iterator(); i.hasNext(); ) { 252 InnerClass ic = (InnerClass) i.next(); 253 writeRef(ic.thisClass); 254 writeRef(ic.outerClass); 255 writeRef(ic.name); 256 writeShort(ic.flags); 257 } 258 } 259 }