1/* 2 * Copyright (c) 2012, 2013, 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. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24package separate; 25 26import java.io.*; 27import java.util.*; 28 29class CfInputStream extends ByteArrayInputStream { 30 private int ct; 31 public CfInputStream(byte[] input) { 32 super(input); 33 } 34 35 byte u1() { return (byte)read(); } 36 short u2() { 37 int b0 = read() << 8; 38 int b1 = read(); 39 return (short)(b0 | b1); 40 } 41 int u4() { 42 int b0 = read() << 24; 43 int b1 = read() << 16; 44 int b2 = read() << 8; 45 int b3 = read(); 46 return b0 | b1 | b2 | b3; 47 } 48 byte[] array(int count) { 49 byte[] ret = new byte[count]; 50 read(ret, 0, count); 51 return ret; 52 } 53}; 54 55class CfOutputStream extends ByteArrayOutputStream { 56 void u1(byte b) { write((int)b); } 57 void u2(short s) { 58 write((s >> 8) & 0xff); 59 write(s & 0xff); 60 } 61 void u4(int i) { 62 write((i >> 24) & 0xff); 63 write((i >> 16) & 0xff); 64 write((i >> 8) & 0xff); 65 write(i & 0xff); 66 } 67 void array(byte[] a) { 68 write(a, 0, a.length); 69 } 70 71 public byte[] toByteArray() { return super.toByteArray(); } 72}; 73 74// A quick and dirty class file parser and representation 75public class ClassFile { 76 77 int magic; 78 short minor_version; 79 short major_version; 80 ArrayList<CpEntry> constant_pool; 81 short access_flags; 82 short this_class; 83 short super_class; 84 ArrayList<Interface> interfaces; 85 ArrayList<Field> fields; 86 ArrayList<Method> methods; 87 ArrayList<Attribute> attributes; 88 89 ClassFile(byte[] cf) { 90 CfInputStream in = new CfInputStream(cf); 91 92 magic = in.u4(); 93 minor_version = in.u2(); 94 major_version = in.u2(); 95 96 short cpCount = in.u2(); 97 constant_pool = new ArrayList<>(); 98 constant_pool.add(new CpNull()); 99 for (int i = 1; i < cpCount; ++i) { 100 constant_pool.add(CpEntry.newCpEntry(in)); 101 } 102 103 access_flags = in.u2(); 104 this_class = in.u2(); 105 super_class = in.u2(); 106 107 short ifaceCount = in.u2(); 108 interfaces = new ArrayList<>(); 109 for (int i = 0; i < ifaceCount; ++i) { 110 interfaces.add(new Interface(in)); 111 } 112 113 short fieldCount = in.u2(); 114 fields = new ArrayList<>(); 115 for (int i = 0; i < fieldCount; ++i) { 116 fields.add(new Field(in)); 117 } 118 119 short methodCount = in.u2(); 120 methods = new ArrayList<>(); 121 for (int i = 0; i < methodCount; ++i) { 122 methods.add(new Method(in)); 123 } 124 125 short attributeCount = in.u2(); 126 attributes = new ArrayList<>(); 127 for (int i = 0; i < attributeCount; ++i) { 128 attributes.add(new Attribute(in)); 129 } 130 } 131 132 byte[] toByteArray() { 133 CfOutputStream out = new CfOutputStream(); 134 135 out.u4(magic); 136 out.u2(minor_version); 137 out.u2(major_version); 138 139 out.u2((short)(constant_pool.size())); 140 for (CpEntry cp : constant_pool) { 141 cp.write(out); 142 } 143 144 out.u2(access_flags); 145 out.u2(this_class); 146 out.u2(super_class); 147 148 out.u2((short)interfaces.size()); 149 for (Interface iface : interfaces) { 150 iface.write(out); 151 } 152 153 out.u2((short)fields.size()); 154 for (Field field : fields) { 155 field.write(out); 156 } 157 158 out.u2((short)methods.size()); 159 for (Method method : methods) { 160 method.write(out); 161 } 162 163 out.u2((short)attributes.size()); 164 for (Attribute attribute : attributes) { 165 attribute.write(out); 166 } 167 168 return out.toByteArray(); 169 } 170 171 static abstract class CpEntry { 172 byte tag; 173 174 CpEntry(byte t) { tag = t; } 175 void write(CfOutputStream out) { 176 out.u1(tag); 177 } 178 179 static CpEntry newCpEntry(CfInputStream in) { 180 byte tag = in.u1(); 181 switch (tag) { 182 case CpUtf8.TAG: return new CpUtf8(in); 183 case CpInteger.TAG: return new CpInteger(in); 184 case CpFloat.TAG: return new CpFloat(in); 185 case CpLong.TAG: return new CpLong(in); 186 case CpDouble.TAG: return new CpDouble(in); 187 case CpClass.TAG: return new CpClass(in); 188 case CpString.TAG: return new CpString(in); 189 case CpFieldRef.TAG: return new CpFieldRef(in); 190 case CpMethodRef.TAG: return new CpMethodRef(in); 191 case CpInterfaceMethodRef.TAG: 192 return new CpInterfaceMethodRef(in); 193 case CpNameAndType.TAG: return new CpNameAndType(in); 194 case CpMethodHandle.TAG: return new CpMethodHandle(in); 195 case CpMethodType.TAG: return new CpMethodType(in); 196 case CpInvokeDynamic.TAG: return new CpInvokeDynamic(in); 197 default: throw new RuntimeException("Bad cp entry tag: " + tag); 198 } 199 } 200 } 201 202 static class CpNull extends CpEntry { 203 CpNull() { super((byte)0); } 204 CpNull(CfInputStream in) { super((byte)0); } 205 void write(CfOutputStream out) {} 206 } 207 208 static class CpUtf8 extends CpEntry { 209 static final byte TAG = 1; 210 byte[] bytes; 211 212 CpUtf8() { super(TAG); } 213 CpUtf8(CfInputStream in) { 214 this(); 215 short length = in.u2(); 216 bytes = in.array(length); 217 } 218 void write(CfOutputStream out) { 219 super.write(out); 220 out.u2((short)bytes.length); 221 out.array(bytes); 222 } 223 } 224 225 static class CpU4Constant extends CpEntry { 226 byte[] bytes; 227 228 CpU4Constant(byte tag) { super(tag); } 229 CpU4Constant(byte tag, CfInputStream in) { 230 this(tag); 231 bytes = in.array(4); 232 } 233 void write(CfOutputStream out) { super.write(out); out.array(bytes); } 234 } 235 static class CpInteger extends CpU4Constant { 236 static final byte TAG = 3; 237 CpInteger() { super(TAG); } 238 CpInteger(CfInputStream in) { super(TAG, in); } 239 } 240 static class CpFloat extends CpU4Constant { 241 static final byte TAG = 4; 242 CpFloat() { super(TAG); } 243 CpFloat(CfInputStream in) { super(TAG, in); } 244 } 245 246 static class CpU8Constant extends CpEntry { 247 byte[] bytes; 248 249 CpU8Constant(byte tag) { super(tag); } 250 CpU8Constant(byte tag, CfInputStream in) { 251 this(tag); 252 bytes = in.array(8); 253 } 254 void write(CfOutputStream out) { super.write(out); out.array(bytes); } 255 } 256 static class CpLong extends CpU8Constant { 257 static final byte TAG = 5; 258 CpLong() { super(TAG); } 259 CpLong(CfInputStream in) { super(TAG, in); } 260 } 261 static class CpDouble extends CpU8Constant { 262 static final byte TAG = 6; 263 CpDouble() { super(TAG); } 264 CpDouble(CfInputStream in) { super(TAG, in); } 265 } 266 267 static class CpClass extends CpEntry { 268 static final byte TAG = 7; 269 short name_index; 270 271 CpClass() { super(TAG); } 272 CpClass(CfInputStream in) { super(TAG); name_index = in.u2(); } 273 void write(CfOutputStream out) { 274 super.write(out); 275 out.u2(name_index); 276 } 277 } 278 279 static class CpString extends CpEntry { 280 static final byte TAG = 8; 281 short string_index; 282 283 CpString() { super(TAG); } 284 CpString(CfInputStream in) { super(TAG); string_index = in.u2(); } 285 void write(CfOutputStream out) { 286 super.write(out); 287 out.u2(string_index); 288 } 289 } 290 291 static class CpRef extends CpEntry { 292 short class_index; 293 short name_and_type_index; 294 295 CpRef(byte tag) { super(tag); } 296 CpRef(byte tag, CfInputStream in) { 297 this(tag); 298 class_index = in.u2(); 299 name_and_type_index = in.u2(); 300 } 301 void write(CfOutputStream out) { 302 super.write(out); 303 out.u2(class_index); 304 out.u2(name_and_type_index); 305 } 306 } 307 static class CpFieldRef extends CpRef { 308 static final byte TAG = 9; 309 CpFieldRef() { super(TAG); } 310 CpFieldRef(CfInputStream in) { super(TAG, in); } 311 } 312 static class CpMethodRef extends CpRef { 313 static final byte TAG = 10; 314 CpMethodRef() { super(TAG); } 315 CpMethodRef(CfInputStream in) { super(TAG, in); } 316 } 317 static class CpInterfaceMethodRef extends CpRef { 318 static final byte TAG = 11; 319 CpInterfaceMethodRef() { super(TAG); } 320 CpInterfaceMethodRef(CfInputStream in) { super(TAG, in); } 321 } 322 323 static class CpNameAndType extends CpEntry { 324 static final byte TAG = 12; 325 short name_index; 326 short descriptor_index; 327 328 CpNameAndType() { super(TAG); } 329 CpNameAndType(CfInputStream in) { 330 this(); 331 name_index = in.u2(); 332 descriptor_index = in.u2(); 333 } 334 void write(CfOutputStream out) { 335 super.write(out); 336 out.u2(name_index); 337 out.u2(descriptor_index); 338 } 339 } 340 341 static class CpMethodHandle extends CpEntry { 342 static final byte TAG = 15; 343 byte reference_kind; 344 short reference_index; 345 346 CpMethodHandle() { super(TAG); } 347 CpMethodHandle(CfInputStream in) { 348 this(); 349 reference_kind = in.u1(); 350 reference_index = in.u2(); 351 } 352 void write(CfOutputStream out) { 353 super.write(out); 354 out.u1(reference_kind); 355 out.u2(reference_index); 356 } 357 } 358 359 static class CpMethodType extends CpEntry { 360 static final byte TAG = 16; 361 short descriptor_index; 362 363 CpMethodType() { super(TAG); } 364 CpMethodType(CfInputStream in) { 365 this(); 366 descriptor_index = in.u2(); 367 } 368 void write(CfOutputStream out) { 369 super.write(out); 370 out.u2(descriptor_index); 371 } 372 } 373 374 static class CpInvokeDynamic extends CpEntry { 375 static final byte TAG = 18; 376 short bootstrap_index; 377 short name_and_type_index; 378 379 CpInvokeDynamic() { super(TAG); } 380 CpInvokeDynamic(CfInputStream in) { 381 this(); 382 bootstrap_index = in.u2(); 383 name_and_type_index = in.u2(); 384 } 385 void write(CfOutputStream out) { 386 super.write(out); 387 out.u2(bootstrap_index); 388 out.u2(name_and_type_index); 389 } 390 } 391 392 static class Interface { 393 short index; 394 395 Interface() {} 396 Interface(CfInputStream in) { index = in.u2(); } 397 void write(CfOutputStream out) { out.u2(index); } 398 } 399 400 static class FieldOrMethod { 401 short access_flags; 402 short name_index; 403 short descriptor_index; 404 ArrayList<Attribute> attributes; 405 406 FieldOrMethod() { attributes = new ArrayList<>(); } 407 FieldOrMethod(CfInputStream in) { 408 access_flags = in.u2(); 409 name_index = in.u2(); 410 descriptor_index = in.u2(); 411 412 short attrCount = in.u2(); 413 attributes = new ArrayList<>(); 414 for (int i = 0; i < attrCount; ++i) { 415 attributes.add(new Attribute(in)); 416 } 417 } 418 void write(CfOutputStream out) { 419 out.u2(access_flags); 420 out.u2(name_index); 421 out.u2(descriptor_index); 422 out.u2((short)attributes.size()); 423 for (Attribute attribute : attributes) { attribute.write(out); } 424 } 425 } 426 427 static class Field extends FieldOrMethod { 428 Field() {} 429 Field(CfInputStream in) { super(in); } 430 } 431 static class Method extends FieldOrMethod { 432 Method() {} 433 Method(CfInputStream in) { super(in); } 434 } 435 436 static class Attribute { 437 short attribute_name_index; 438 byte[] info; 439 440 Attribute() { info = new byte[0]; } 441 Attribute(CfInputStream in) { 442 attribute_name_index = in.u2(); 443 int length = in.u4(); 444 info = in.array(length); 445 } 446 void write(CfOutputStream out) { 447 out.u2(attribute_name_index); 448 out.u4(info.length); 449 out.array(info); 450 } 451 } 452} 453