1 package sli.kim.classfile; 2 3 import java.util.*; 4 import java.io.*; 5 6 12 public class ClassFileWriter { 13 19 public void write(ClassInfo classInfo, OutputStream out) 20 throws IOException, ClassFileWriteException 21 { 22 ConstPool cp = classInfo.getConstPool(); 23 if (cp == null) 24 cp = new ConstPool(); 25 boolean debugEnabled = Debug.isEnabled(); 27 Debug.setEnabled(false); 28 writeClass(cp, classInfo, new NullOutputStream()); 29 Debug.setEnabled(debugEnabled); 30 BufferedOutputStream bos = new BufferedOutputStream(out); 32 DataOutputStream dos = new DataOutputStream(bos); 33 writeClass(cp, classInfo, dos); 34 dos.flush(); dos.close(); 35 bos.flush(); bos.close(); 36 } 37 38 private void writeClass(ConstPool cp, ClassInfo classInfo, DataOutput out) 39 throws IOException, ClassFileWriteException 40 { 41 out.writeInt(0xCAFEBABE); 42 out.writeInt(0x0003002D); 43 44 cp.write(out); 45 46 { 48 short flags = classInfo.getAccessFlags(); 49 short classIndex = cp.getIndexOfClassAdd(classInfo.getName()); 50 short superClassIndex = cp.getIndexOfClassAdd(classInfo.getSuperClassName()); 51 52 if (Debug.writeClass != null) Debug.println(Debug.writeClass, 53 "flags=" + flags + 54 "; class index=" + classIndex + 55 "; super class index=" + superClassIndex); 56 57 out.writeShort(flags); 58 out.writeShort(classIndex); 59 out.writeShort(superClassIndex); 60 } 61 62 String [] interfaces = classInfo.getInterfaces(); 64 if (Debug.writeClass != null) Debug.println(Debug.writeClass, 65 "#interfaces=" + interfaces.length); 66 Debug.indent(); 67 out.writeShort(interfaces.length); 68 for (int i = 0; i < interfaces.length; i++) 69 writeInterface(interfaces[i], cp, out); 70 Debug.outdent(); 71 72 FieldInfo[] fields = classInfo.getFields(); 74 if (Debug.writeClass != null) Debug.println(Debug.writeClass, 75 "#fields=" + fields.length); 76 Debug.indent(); 77 out.writeShort(fields.length); 78 for (int i = 0; i < fields.length; i++) 79 writeField(fields[i], cp, out); 80 Debug.outdent(); 81 82 MethodInfo[] methods = classInfo.getMethods(); 84 if (Debug.writeClass != null) Debug.println(Debug.writeClass, 85 "#methods=" + methods.length); 86 Debug.indent(); 87 out.writeShort(methods.length); 88 for (int i = 0; i < methods.length; i++) 89 writeMethod(methods[i], cp, out); 90 Debug.outdent(); 91 92 AttributeInfo[] attributes = classInfo.getAttributes(); 94 String sourceFile = classInfo.getSourceFile(); 95 InnerClassInfo[] innerClasses = classInfo.getInnerClasses(); 96 int numAttributes = attributes.length + (sourceFile != null ? 1 : 0) + 97 (innerClasses != null ? 1 : 0); 98 99 if (Debug.writeClass != null) Debug.println(Debug.writeClass, 100 "#attributes=" + numAttributes); 101 Debug.indent(); 102 103 out.writeShort(numAttributes); 104 105 if (sourceFile != null) 107 writeSourceFile(sourceFile, cp, out); 108 109 if (innerClasses != null) 111 writeInnerClasses(innerClasses, cp, out); 112 113 writeUnknownAttributes(attributes, cp, out); 115 116 Debug.outdent(); 117 } 118 119 private void writeInterface(String className, ConstPool cp, DataOutput out) 120 throws IOException 121 { 122 short classIndex = cp.getIndexOfClassAdd(className); 123 if (Debug.writeInterface != null) Debug.println(Debug.writeInterface, 124 "class index=" + classIndex); 125 out.writeShort(classIndex); 126 } 127 128 private void writeField(FieldInfo fieldInfo, ConstPool cp, DataOutput out) 129 throws IOException, ClassFileWriteException 130 { 131 { 133 short flags = fieldInfo.getAccessFlags(); 134 short nameIndex = cp.getIndexOfUTFAdd(fieldInfo.getName()); 135 short signatureIndex = cp.getIndexOfUTFAdd(fieldInfo.getSignature()); 136 137 if (Debug.writeField != null) Debug.println(Debug.writeField, 138 "flags=" + flags + 139 "; name index=" + nameIndex + 140 "; signature index=" + signatureIndex); 141 142 out.writeShort(flags); 143 out.writeShort(nameIndex); 144 out.writeShort(signatureIndex); 145 } 146 147 AttributeInfo[] attributes = fieldInfo.getAttributes(); 149 Object constValue = fieldInfo.getConstantValue(); 150 int numAttributes = (constValue != null ? 1 : 0) + attributes.length; 151 152 if (Debug.writeField != null) Debug.println(Debug.writeField, 153 "#attributes=" + numAttributes); 154 Debug.indent(); 155 156 out.writeShort((short)numAttributes); 157 158 if (constValue != null) 160 writeConstantValue(constValue, cp, out); 161 162 if (fieldInfo.isSynthetic()) { 164 writeAttributeNameIndex("Synthetic", Debug.writeField, cp, out); 165 out.writeInt(0); } 167 168 writeUnknownAttributes(fieldInfo.getAttributes(), cp, out); 170 171 Debug.outdent(); 172 } 173 174 private void writeMethod(MethodInfo methodInfo, ConstPool cp, 175 DataOutput out) throws IOException 176 { 177 { 179 short flags = methodInfo.getAccessFlags(); 180 short nameIndex = cp.getIndexOfUTFAdd(methodInfo.getName()); 181 short signatureIndex = cp.getIndexOfUTFAdd(methodInfo.getSignature()); 182 183 if (Debug.writeMethod != null) Debug.println(Debug.writeMethod, 184 "flags=" + flags + 185 "; name index=" + nameIndex + 186 "; signature index=" + signatureIndex); 187 188 out.writeShort(flags); 189 out.writeShort(nameIndex); 190 out.writeShort(signatureIndex); 191 } 192 193 AttributeInfo[] methodAttributes = methodInfo.getAttributes(); 195 String [] exceptions = methodInfo.getExceptions(); 196 boolean deprecated = methodInfo.isDeprecated(); 197 if (exceptions.length == 0) 198 exceptions = null; 199 CodeInfo codeInfo = methodInfo.getCodeInfo(); 200 int numAttributes = (exceptions != null ? 1 : 0) + (codeInfo != null ? 1 : 0) + 201 (deprecated ? 1 : 0) + methodAttributes.length; 202 203 if (Debug.writeMethod != null) Debug.println(Debug.writeMethod, 204 "#attributes=" + numAttributes); 205 Debug.indent(); 206 207 out.writeShort((short)numAttributes); 208 209 if (exceptions != null) 211 writeExceptions(exceptions, cp, out); 212 213 if (codeInfo != null) 215 writeCode(codeInfo, cp, out); 216 217 if (deprecated) { 219 writeAttributeNameIndex("Deprecated", Debug.writeMethod, cp, out); 220 out.writeInt(0); } 222 223 writeUnknownAttributes(methodAttributes, cp, out); 225 226 Debug.outdent(); 227 } 228 229 private void writeCode(CodeInfo codeInfo, ConstPool cp, DataOutput out) 230 throws IOException 231 { 232 writeAttributeNameIndex("Code", Debug.writeMethod, cp, out); 233 out = new LengthFirstOS(out); 234 235 { 237 short maxStack = codeInfo.getMaxStack(); 238 short maxLocals = codeInfo.getMaxLocals(); 239 byte[] bytecode = codeInfo.getBytecode(); 240 241 if (Debug.writeCode != null) Debug.println(Debug.writeCode, 242 "maxStack=" + maxStack + 243 "; maxLocals=" + maxLocals + 244 "; bytecode length=" + bytecode.length); 245 246 out.writeShort(maxStack); 247 out.writeShort(maxLocals); 248 out.writeInt(bytecode.length); 249 out.write(bytecode); 250 } 251 252 ExceptionInfo[] exceptionTable = codeInfo.getExceptionTable(); 254 255 if (Debug.writeCode != null) Debug.println(Debug.writeCode, 256 "exception table length=" + exceptionTable.length); 257 Debug.indent(); 258 259 out.writeShort(exceptionTable.length); 260 for (int i = 0; i < exceptionTable.length; i++) { 261 short startPC = exceptionTable[i].startPC; 262 short endPC = exceptionTable[i].endPC; 263 short handlerPC = exceptionTable[i].handlerPC; 264 String catchType = exceptionTable[i].catchType; 265 short catchTypeIndex = 0; 266 if (catchType != null) cp.getIndexOfClassAdd(exceptionTable[i].catchType); 268 269 if (Debug.writeCode != null) Debug.println(Debug.writeCode, 270 "startPC = " + startPC + 271 "; endPC = " + endPC + 272 "; handlerPC = " + handlerPC + 273 "; catch type index=" + catchTypeIndex); 274 275 out.writeShort(startPC); 276 out.writeShort(endPC); 277 out.writeShort(handlerPC); 278 out.writeShort(catchTypeIndex); 279 } 280 281 Debug.outdent(); 282 283 AttributeInfo[] codeAttributes = codeInfo.getAttributes(); 285 LineNumberInfo[] lineNumberTable = codeInfo.getLineNumberTable(); 286 LocalVariableInfo[] localVariableTable = codeInfo.getLocalVariableTable(); 287 int numCodeAttributes = (lineNumberTable != null ? 1 : 0) + 288 (localVariableTable != null ? 1 : 0) + codeAttributes.length; 289 290 if (Debug.writeCode != null) Debug.println(Debug.writeCode, 291 "#attributes=" + numCodeAttributes); 292 Debug.indent(); 293 294 out.writeShort(numCodeAttributes); 295 296 if (lineNumberTable != null) 298 writeLineNumberTable(lineNumberTable, cp, out); 299 300 if (localVariableTable != null) 302 writeLocalVariableTable(localVariableTable, cp, out); 303 304 writeUnknownAttributes(codeAttributes, cp, out); 306 ((LengthFirstOS)out).close(); 307 308 Debug.outdent(); 309 } 310 311 private void writeSourceFile(String filename, ConstPool cp, DataOutput out) 312 throws IOException 313 { 314 writeAttributeNameIndex("SourceFile", Debug.writeClass, cp, out); 315 316 out.writeInt(2); short filenameIndex = cp.getIndexOfUTFAdd(filename); 318 319 Debug.indent(); 320 if (Debug.writeClass != null) Debug.println(Debug.writeClass, 321 "source file index=" + filenameIndex); 322 Debug.outdent(); 323 324 out.writeShort(filenameIndex); 325 } 326 327 private void writeConstantValue(Object constValue, ConstPool cp, DataOutput out) 328 throws IOException, ClassFileWriteException 329 { 330 writeAttributeNameIndex("ConstantValue", Debug.writeField, cp, out); 331 out = new LengthFirstOS(out); 332 ConstPoolEntry searchEntry = new ConstPoolEntry(); 333 if (constValue instanceof String ) 334 searchEntry.setString(cp.getIndexOfUTFAdd((String )constValue)); 335 else if (constValue instanceof Integer ) 336 searchEntry.setInt(((Integer )constValue).intValue()); 337 else if (constValue instanceof Long ) 338 searchEntry.setLong(((Long )constValue).longValue()); 339 else if (constValue instanceof Float ) 340 searchEntry.setFloat(((Float )constValue).floatValue()); 341 else if (constValue instanceof Double ) 342 searchEntry.setDouble(((Double )constValue).doubleValue()); 343 else 344 throw new ClassFileWriteException("Unrecognized constant value " + constValue); 345 short cvIndex = cp.getIndexOfEntryAdd(searchEntry); 346 347 Debug.indent(); 348 if (Debug.writeField != null) Debug.println(Debug.writeField, 349 "constant value index=" + cvIndex); 350 Debug.outdent(); 351 352 out.writeShort(cvIndex); 353 ((LengthFirstOS)out).close(); 354 } 355 356 private void writeExceptions(String [] exceptions, ConstPool cp, 357 DataOutput out) throws IOException 358 { 359 writeAttributeNameIndex("Exceptions", Debug.writeMethod, cp, out); 360 out = new LengthFirstOS(out); 361 362 if (Debug.writeMethod != null) Debug.println(Debug.writeMethod, 363 "#exceptions=" + exceptions.length); 364 Debug.indent(); 365 366 out.writeShort(exceptions.length); 367 for (int i = 0; i < exceptions.length; i++) { 368 short classIndex = cp.getIndexOfClassAdd(exceptions[i]); 369 370 if (Debug.writeMethod != null) Debug.println(Debug.writeMethod, 371 "exception class index = " + classIndex); 372 373 out.writeShort(classIndex); 374 } 375 376 Debug.outdent(); 377 378 ((LengthFirstOS)out).close(); 379 } 380 381 private void writeLocalVariableTable(LocalVariableInfo[] localVariableTable, 382 ConstPool cp, DataOutput out) throws IOException 383 { 384 writeAttributeNameIndex("LocalVariableTable", Debug.writeCode, cp, out); 385 out = new LengthFirstOS(out); 386 387 Debug.indent(); 388 if (Debug.writeLocalVariables != null) Debug.println(Debug.writeLocalVariables, 389 "#local variables=" + localVariableTable.length); 390 391 out.writeShort(localVariableTable.length); 392 for (int i = 0; i < localVariableTable.length; i++) { 393 short startPC = localVariableTable[i].startPC; 394 short length = localVariableTable[i].length; 395 short nameIndex = cp.getIndexOfUTFAdd(localVariableTable[i].name); 396 short signatureIndex = cp.getIndexOfUTFAdd(localVariableTable[i].signature); 397 short slot = localVariableTable[i].slot; 398 399 if (Debug.writeLocalVariables != null) Debug.println(Debug.writeLocalVariables, 400 "startPC=" + startPC + 401 "; length=" + length + 402 "; nameIndex=" + nameIndex + 403 "; signatureIndex=" + signatureIndex + 404 "; slot=" + slot); 405 406 out.writeShort(startPC); 407 out.writeShort(length); 408 out.writeShort(nameIndex); 409 out.writeShort(signatureIndex); 410 out.writeShort(slot); 411 } 412 ((LengthFirstOS)out).close(); 413 414 Debug.outdent(); 415 } 416 417 private void writeLineNumberTable(LineNumberInfo[] lineNumberTable, 418 ConstPool cp, DataOutput out) throws IOException 419 { 420 writeAttributeNameIndex("LineNumberTable", Debug.writeCode, cp, out); 421 out = new LengthFirstOS(out); 422 423 Debug.indent(); 424 if (Debug.writeLineNumbers != null) Debug.println(Debug.writeLineNumbers, 425 "#line numbers=" + lineNumberTable.length); 426 427 out.writeShort(lineNumberTable.length); 428 for (int i = 0; i < lineNumberTable.length; i++) { 429 short startPC = lineNumberTable[i].startPC; 430 short lineNumber = lineNumberTable[i].lineNumber; 431 432 if (Debug.writeLineNumbers != null) Debug.println(Debug.writeLineNumbers, 433 "startPC=" + startPC + 434 "; lineNumber=" + lineNumber); 435 436 out.writeShort(startPC); 437 out.writeShort(lineNumber); 438 } 439 ((LengthFirstOS)out).close(); 440 441 Debug.outdent(); 442 } 443 444 private void writeInnerClasses(InnerClassInfo[] innerClasses, ConstPool cp, 445 DataOutput out) throws IOException 446 { 447 writeAttributeNameIndex("InnerClasses", Debug.writeClass, cp, out); 448 out = new LengthFirstOS(out); 449 450 Debug.indent(); 451 if (Debug.writeInnerClasses != null) Debug.println(Debug.writeInnerClasses, 452 "#inner classes=" + innerClasses.length); 453 454 out.writeShort(innerClasses.length); 455 for (int i = 0; i < innerClasses.length; i++) { 456 short innerClassIndex = cp.getIndexOfClassAdd(innerClasses[i].innerClass); 457 short outerClassIndex = 0; 458 if (innerClasses[i].outerClass != null) outerClassIndex = cp.getIndexOfClassAdd(innerClasses[i].outerClass); 460 short simpleNameIndex = 0; 461 if (innerClasses[i].simpleName != null) simpleNameIndex = cp.getIndexOfUTFAdd(innerClasses[i].simpleName); 463 short flags = innerClasses[i].flags; 464 465 if (Debug.writeInnerClasses != null) Debug.println(Debug.writeInnerClasses, 466 "inner class index=" + innerClassIndex + 467 "; outer class index=" + outerClassIndex + 468 "; simple name index=" + simpleNameIndex + 469 "; flags=" + flags); 470 471 out.writeShort(innerClassIndex); 472 out.writeShort(outerClassIndex); 473 out.writeShort(simpleNameIndex); 474 out.writeShort(flags); 475 } 476 ((LengthFirstOS)out).close(); 477 478 Debug.outdent(); 479 } 480 481 private void writeAttributeNameIndex(String attrName, String debugMsg, 482 ConstPool cp, DataOutput out) throws IOException 483 { 484 short index = cp.getIndexOfUTFAdd(attrName); 485 486 if (debugMsg != null) Debug.println(debugMsg, 487 "attribute name index=" + index); 488 489 out.writeShort(index); 490 } 491 492 private void writeUnknownAttributes(AttributeInfo[] attributes, 493 ConstPool cp, DataOutput out) throws IOException 494 { 495 for (int i = 0; i < attributes.length; i++) { 496 short attrNameIndex = cp.getIndexOfUTFAdd(attributes[i].getName()); 497 byte[] data = attributes[i].getData(); 498 499 if (Debug.writeUnknownAttribute != null) Debug.println(Debug.writeUnknownAttribute, 500 "attribute name index=" + attrNameIndex + 501 "; attribute length=" + data.length); 502 503 out.writeShort(attrNameIndex); 504 out.writeInt(data.length); 505 out.write(data); 506 } 507 } 508 } 509 510 class LengthFirstOS implements DataOutput { 517 DataOutput realOut; 518 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 519 DataOutputStream dos = new DataOutputStream(baos); 520 521 public LengthFirstOS(DataOutput realOut) { 522 this.realOut = realOut; 523 } 524 public void write(byte b[]) throws IOException { 525 dos.write(b); 526 } 527 public void write(byte b[], int off, int len) throws IOException { 528 dos.write(b, off, len); 529 } 530 public void write(int b) throws IOException { 531 dos.write(b); 532 } 533 public void writeBoolean(boolean v) throws IOException { 534 dos.writeBoolean(v); 535 } 536 public void writeByte(int v) throws IOException { 537 dos.writeByte(v); 538 } 539 public void writeBytes(String s) throws IOException { 540 dos.writeBytes(s); 541 } 542 public void writeChar(int v) throws IOException { 543 dos.writeChar(v); 544 } 545 public void writeChars(String s) throws IOException { 546 dos.writeChars(s); 547 } 548 public void writeDouble(double v) throws IOException { 549 dos.writeDouble(v); 550 } 551 public void writeFloat(float v) throws IOException { 552 dos.writeFloat(v); 553 } 554 public void writeInt(int v) throws IOException { 555 dos.writeInt(v); 556 } 557 public void writeLong(long v) throws IOException { 558 dos.writeLong(v); 559 } 560 public void writeShort(int v) throws IOException { 561 dos.writeShort(v); 562 } 563 public void writeUTF(String str) throws IOException { 564 dos.writeUTF(str); 565 } 566 public void close() throws IOException { 567 dos.flush(); dos.close(); 568 baos.flush(); baos.close(); 569 byte[] data = baos.toByteArray(); 570 realOut.writeInt((short)data.length); 571 realOut.write(data); 572 } 573 } 574 | Popular Tags |