1 /* 2 * Copyright (c) 2009, 2017, 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 package org.openjdk.asmtools.jcdec; 24 25 import static org.openjdk.asmtools.jcoder.JcodTokens.*; 26 import org.openjdk.asmtools.jdis.uEscWriter; 27 import org.openjdk.asmtools.util.I18NResourceBundle; 28 import org.openjdk.asmtools.util.ProductInfo; 29 import java.io.DataInputStream; 30 import java.io.FileInputStream; 31 import java.io.FileNotFoundException; 32 import java.io.IOException; 33 import java.io.PrintWriter; 34 import java.util.ArrayList; 35 36 /** 37 * Main program of the JavaCard DeCoder 38 * 39 */ 40 public class Main { 41 42 /*-------------------------------------------------------- */ 43 /* Main Fields */ 44 /** 45 * Name of the program. 46 */ 47 String program; 48 49 public static final I18NResourceBundle i18n 50 = I18NResourceBundle.getBundleForClass(Main.class); 51 /** 52 * The stream where error message are printed. 53 */ 54 PrintWriter out; 55 boolean DebugFlag = false; 56 boolean printDetails = false; 57 int shift = 0; 58 private static final char hexTable[] = { 59 '0', '1', '2', '3', '4', '5', '6', '7', 60 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' 61 }; 62 /*-------------------------------------------------------- */ 63 64 static String toHex(long val, int width) { 65 StringBuffer s = new StringBuffer(); 66 for (int i = width * 2 - 1; i >= 0; i--) { 67 s.append(hexTable[((int) (val >> (4 * i))) & 0xF]); 68 } 69 return "0x" + s.toString(); 70 } 71 72 static String toHex(long val) { 73 int width; 74 for (width = 8; width > 0; width--) { 75 if ((val >> (width - 1) * 8) != 0) { 76 break; 77 } 78 } 79 return toHex(val, width); 80 } 81 82 void printByteHex(PrintWriter out, int b) { 83 out.print(hexTable[(b >> 4) & 0xF]); 84 out.print(hexTable[b & 0xF]); 85 } 86 87 /*========================================================*/ 88 void out_begin(String s) { 89 for (int i = 0; i < shift; i++) { 90 out.print(" "); 91 } 92 out.println(s); 93 shift++; 94 } 95 96 void out_print(String s) { 97 for (int i = 0; i < shift; i++) { 98 out.print(" "); 99 } 100 out.print(s); 101 } 102 103 void out_println(String s) { 104 for (int i = 0; i < shift; i++) { 105 out.print(" "); 106 } 107 out.println(s); 108 } 109 110 void out_end(String s) { 111 shift--; 112 for (int i = 0; i < shift; i++) { 113 out.print(" "); 114 } 115 out.println(s); 116 } 117 118 String startArray(int length) { 119 return "[" + (printDetails ? Integer.toString(length) : "") + "]"; 120 } 121 122 void printBytes(DataInputStream in, int len) throws IOException { 123 try { 124 for (int i = 0; i < len; i++) { 125 if (i % 8 == 0) { 126 out_print("0x"); 127 } 128 printByteHex(out, in.readByte()); 129 if (i % 8 == 7) { 130 out.println(";"); 131 } 132 } 133 } finally { 134 if (len % 8 != 0) { 135 out.println(";"); 136 } 137 } 138 } 139 140 /*========================================================*/ 141 static final int EXPORT_MAGIC = 0x00FACADE; 142 static final int HEADER_MAGIC = 0xDECAFFED; 143 static String[] compNames = { 144 "Header", 145 "Directory", 146 "Applet", 147 "Import", 148 "ConstantPool", 149 "Class", 150 "Method", 151 "StaticField", 152 "RefLocation", 153 "Export", 154 "Descriptor" 155 }; 156 157 static String compName(int compNum) { 158 try { 159 return compNames[compNum - 1]; 160 } catch (ArrayIndexOutOfBoundsException e) { 161 return "tag " + compNum + "???"; 162 } 163 } 164 String[] cPoolStrings; 165 166 void decodeAttr(DataInputStream in) throws IOException { 167 int name_cpx = in.readUnsignedShort(), len = in.readInt(); 168 String AttrName = null; 169 String endingComment = "Attr(#" + name_cpx + ")"; 170 try { 171 endingComment = AttrName = cPoolStrings[name_cpx]; 172 } catch (ArrayIndexOutOfBoundsException e) { 173 } 174 if (printDetails) { 175 out_begin("Attr(#" + name_cpx + ", " + len + ") { // " + AttrName); 176 } else { 177 out_begin("Attr(#" + name_cpx + ") { // " + AttrName); 178 } 179 if (AttrName == null) { 180 printBytes(in, len); 181 } else if (AttrName.equals("ConstantValue")) { 182 if (len != 2) { 183 out_println("// invalid length of ConstantValue attr: " + len + " (should be 2)"); 184 printBytes(in, len); 185 } else { 186 out_println("#" + in.readUnsignedShort() + ";"); 187 } 188 } else { 189 printBytes(in, len); 190 } 191 out_end("} // end " + endingComment); 192 } 193 194 void decodeExp(String inpName) throws IOException { 195 DataInputStream in = new DataInputStream(new FileInputStream(inpName)); 196 out_println("file " + inpName); 197 out_begin("{ // export file"); 198 199 int magic = in.readInt(); 200 out_print(toHex(magic, 4) + "; // "); 201 if (magic != EXPORT_MAGIC) { 202 out.print("wrong magic: 0x" + Integer.toString(EXPORT_MAGIC, 16) + " expected"); 203 } else { 204 out_print("magic"); 205 } 206 out.println(); 207 out_println(in.readUnsignedByte() + "b; // minor version"); 208 out_println(in.readUnsignedByte() + "b; // major version"); 209 210 int cp_count = in.readUnsignedShort(); 211 cPoolStrings = new String[cp_count]; 212 out_begin(startArray(cp_count) + " { // Constant Pool"); 213 for (int i = 0; i < cp_count; i++) { 214 int tag = in.readUnsignedByte(); 215 ConstType tg = constType(tag); 216 switch (tg) { 217 case CONSTANT_UTF8: 218 out_print("Utf8 \""); 219 220 StringBuffer sb = new StringBuffer(); 221 String s = in.readUTF(); 222 cPoolStrings[i] = s; 223 for (int k = 0; k < s.length(); k++) { 224 char c = s.charAt(k); 225 switch (c) { 226 case '\t': 227 sb.append('\\').append('t'); 228 break; 229 case '\n': 230 sb.append('\\').append('n'); 231 break; 232 case '\r': 233 sb.append('\\').append('r'); 234 break; 235 case '\"': 236 sb.append('\\').append('\"'); 237 break; 238 default: 239 sb.append(c); 240 } 241 } 242 out.println(sb.append("\"; // #").append(i).toString()); 243 break; 244 245 case CONSTANT_INTEGER: 246 out_println("int " + toHex(in.readInt(), 4) + "; // #" + i); 247 break; 248 249 case CONSTANT_CLASS: 250 out_println("class #" + in.readUnsignedShort() + "; // #" + i); 251 break; 252 253 case CONSTANT_JAVACARD_PACKAGE: 254 out_begin("package { // #" + i); 255 out_println(toHex(in.readUnsignedByte(), 1) + "; // flags"); 256 out_println("#" + in.readUnsignedShort() + "; // name"); 257 out_println(in.readUnsignedByte() + "b; // minor version"); 258 out_println(in.readUnsignedByte() + "b; // major version"); 259 int aid_len = in.readUnsignedByte(); 260 out_begin("Bytes" + startArray(aid_len) + "b {"); 261 printBytes(in, aid_len); 262 out_end("};"); // Bytes[] 263 out_end("};"); // package info 264 break; 265 266 default: 267 throw new Error("invalid constant type: " + (int) tag); 268 } 269 } 270 ; 271 out_end("} // Constant pool"); 272 out_println("#" + in.readUnsignedShort() + "; // this package"); 273 int class_count = in.readUnsignedByte(); 274 out_begin(startArray(class_count) + "b { // classes"); 275 for (int i = 0; i < class_count; i++) { 276 out_begin("{ // class " + i); 277 278 out_println(in.readUnsignedByte() + "b; // token"); 279 280 int flags = in.readUnsignedShort(); 281 out_print("0x"); 282 printByteHex(out, flags >> 8); 283 printByteHex(out, flags); 284 out.println("; // flags"); 285 286 out_println("#" + in.readUnsignedShort() + "; // this class"); 287 288 int sup_count = in.readUnsignedShort(); 289 out_begin(startArray(sup_count) + " { // supers"); 290 for (int k = 0; k < sup_count; k++) { 291 out_println("#" + in.readUnsignedShort() + ";"); 292 } 293 out_end("} // supers"); 294 295 int int_count = in.readUnsignedByte(); 296 out_begin(startArray(int_count) + "b { // interfaces"); 297 for (int k = 0; k < int_count; k++) { 298 out_println("#" + in.readUnsignedShort() + ";"); 299 } 300 out_end("} // interfaces"); 301 302 int field_count = in.readUnsignedShort(); 303 out_begin(startArray(field_count) + " { // fields"); 304 for (int k = 0; k < field_count; k++) { 305 out_begin("{ // field " + k); 306 out_println(in.readUnsignedByte() + "b; // token"); 307 308 int f_flags = in.readUnsignedShort(); 309 out_print("0x"); 310 printByteHex(out, f_flags >> 8); 311 printByteHex(out, f_flags); 312 out.println("; // flags"); 313 314 out_println("#" + in.readUnsignedShort() + "; // this field name"); 315 out_println("#" + in.readUnsignedShort() + "; // this field descriptor"); 316 317 int attr_count = in.readUnsignedShort(); 318 out_begin(startArray(attr_count) + " { // Attributes"); 319 for (int ai = 0; ai < attr_count; ai++) { 320 decodeAttr(in); 321 } 322 out_end("} // Attributes"); 323 out_end("};"); 324 } 325 out_end("} // fields"); 326 327 int mth_count = in.readUnsignedShort(); 328 out_begin(startArray(mth_count) + " { // methods"); 329 for (int k = 0; k < mth_count; k++) { 330 out_begin("{ // method " + k); 331 out_println(in.readUnsignedByte() + "b; // token"); 332 333 int mth_flags = in.readUnsignedShort(); 334 out_print("0x"); 335 printByteHex(out, mth_flags >> 8); 336 printByteHex(out, mth_flags); 337 out.println("; // flags"); 338 339 out_println("#" + in.readUnsignedShort() + "; // this method name"); 340 out_println("#" + in.readUnsignedShort() + "; // this method descriptor"); 341 out_end("};"); 342 } 343 out_end("} // methods"); 344 out_end("};"); 345 } 346 out_end("} // classes"); 347 endComponent(in); 348 } 349 350 DataInputStream beginComponent(String inpName) throws IOException { 351 DataInputStream in = new DataInputStream(new FileInputStream(inpName)); 352 out_println("file " + inpName); 353 354 int tag = in.readUnsignedByte(); 355 out_print("Component(" + tag); 356 int size = in.readUnsignedShort(); 357 if (printDetails) { 358 out.print(", " + size); 359 } 360 out_begin(") { // " + compName(tag)); 361 return in; 362 } 363 364 void endComponent(DataInputStream in) throws IOException { 365 out_end("};"); // Component 366 int avail = in.available(); 367 if (avail > 0) { 368 out.println("=========== extra bytes:"); 369 for (int k = 0; k < 8; k++) { 370 printBytes(in, avail >= 8 ? 8 : avail); 371 avail = in.available(); 372 if (avail == 0) { 373 break; 374 } 375 } 376 if (avail > 0) { 377 out.println(" there is also " + avail + " bytes available"); 378 } 379 } 380 in.close(); 381 } 382 383 ArrayList<Integer> methodsLengths = null; 384 ArrayList<Integer> methodsOffsets = null; 385 386 void decodeHeader(String inpName) throws IOException { 387 DataInputStream in = beginComponent(inpName); 388 389 int magic = in.readInt(); 390 out_print(toHex(magic, 4) + "; // "); 391 if (magic != HEADER_MAGIC) { 392 out.print("wrong magic: 0x" + Integer.toString(HEADER_MAGIC, 16) + " expected"); 393 } else { 394 out_print("magic"); 395 } 396 out.println(); 397 out_println(in.readUnsignedByte() + "b; // minor version"); 398 out_println(in.readUnsignedByte() + "b; // major version"); 399 out_println(toHex(in.readUnsignedByte(), 1) + "; // flags"); 400 401 out_begin("{ // package info"); 402 out_println(in.readUnsignedByte() + "b; // minor version"); 403 out_println(in.readUnsignedByte() + "b; // major version"); 404 int aid_len = in.readUnsignedByte(); 405 out_begin("Bytes" + startArray(aid_len) + "b {"); 406 printBytes(in, aid_len); 407 out_end("};"); // Bytes[] 408 out_end("};"); // package info 409 endComponent(in); 410 } 411 412 void decodeDirectory(String inpName) throws IOException { 413 DataInputStream in = beginComponent(inpName); 414 415 int i; 416 out_begin("{ // component sizes"); 417 for (i = 0; i < 11; i++) { 418 out_println(in.readUnsignedShort() + "; // " + (i + 1)); 419 } 420 out_end("};"); 421 422 out_begin("{ // static field size"); 423 out_println(in.readUnsignedShort() + "; // image size"); 424 out_println(in.readUnsignedShort() + "; // array init count"); 425 out_println(in.readUnsignedShort() + "; // array init size"); 426 out_end("};"); 427 428 out_println(in.readUnsignedByte() + "b; // import count"); 429 out_println(in.readUnsignedByte() + "b; // applet count"); 430 431 int custom_count = in.readUnsignedByte(); 432 out_begin(startArray(custom_count) + "b { // custom components"); 433 for (i = 0; i < custom_count; i++) { 434 out_print("Comp(" + in.readUnsignedByte()); // tag; 435 int size2 = in.readUnsignedShort(); 436 if (printDetails) { 437 out_print(", " + size2); 438 } 439 out_begin(") {"); 440 int aid_len = in.readUnsignedByte(); 441 out_begin("Bytes" + startArray(aid_len) + "b {"); 442 printBytes(in, aid_len); 443 out_end("};"); 444 out_end("};"); 445 } 446 out_end("};"); 447 448 endComponent(in); 449 } 450 451 void decodeApplet(String inpName) throws IOException { 452 DataInputStream in = beginComponent(inpName); 453 454 int applet_count = in.readUnsignedByte(); 455 out_begin(startArray(applet_count) + "b { // applets"); 456 for (int i = 0; i < applet_count; i++) { 457 out_begin("{ // applet " + i); 458 int aid_len = in.readUnsignedByte(); 459 out_begin("Bytes" + startArray(aid_len) + "b {"); 460 printBytes(in, aid_len); 461 out_end("};"); // Bytes[] 462 out_println(in.readUnsignedShort() + "; // install method offset"); 463 out_end("};"); // applet 464 } 465 out_end("};"); // applets 466 endComponent(in); 467 } 468 469 void decodeImport(String inpName) throws IOException { 470 DataInputStream in = beginComponent(inpName); 471 472 int package_count = in.readUnsignedByte(); 473 out_begin(startArray(package_count) + "b { // packages"); 474 for (int i = 0; i < package_count; i++) { 475 out_begin("{ // package " + i); 476 out_println(in.readUnsignedByte() + "b; // minor version"); 477 out_println(in.readUnsignedByte() + "b; // major version"); 478 int aid_len = in.readUnsignedByte(); 479 out_begin("Bytes" + startArray(aid_len) + "b {"); 480 printBytes(in, aid_len); 481 out_end("};"); // Bytes[] 482 out_end("};"); // package info 483 } 484 out_end("};"); // package info 485 endComponent(in); 486 } 487 488 static String[] refNames = { 489 "Classref", 490 "InstanceFieldref", 491 "VirtualMethodref", 492 "SuperMethodref", 493 "StaticFieldref", 494 "StaticMethodref" 495 }; 496 497 void decodeConstantPool(String inpName) throws IOException { 498 DataInputStream in = beginComponent(inpName); 499 500 int items_count = in.readUnsignedShort(); 501 out_begin(startArray(items_count) + " { // items"); 502 for (int i = 0; i < items_count; i++) { 503 int tag = in.readUnsignedByte(); 504 int info1 = in.readUnsignedByte(), 505 info2 = in.readUnsignedByte(), 506 info3 = in.readUnsignedByte(); 507 out_print(tag + "b "); 508 if ((tag > 0) && (tag <= 6)) { 509 if ((info1 & 0x80) == 0) { 510 if (tag <= 4) { 511 out_print(((info1 << 8) | info2) + " " + info3 + "b;"); 512 } else { 513 out_print(info1 + "b " + ((info2 << 8) | info3) + ";"); 514 } 515 out.print(" // internal "); 516 } else { 517 out.print(info1 + "b " + info2 + "b " + info3 + "b;"); 518 out.print(" // external "); 519 } 520 out.println(refNames[tag - 1]); 521 } else { 522 out.print(info1 + "b " + info2 + "b " + info3 + "b;"); 523 out.println(" // unknown tag "); 524 } 525 } 526 out_end("};"); // CP array 527 endComponent(in); 528 } 529 530 void printClassref(DataInputStream in) throws IOException { 531 int info1 = in.readUnsignedByte(), 532 info2 = in.readUnsignedByte(); 533 if ((info1 & 0x80) == 0) { 534 out_print(((info1 << 8) | info2) + ";"); 535 out_print(" // internal "); 536 } else { 537 out_print(info1 + "b " + info2 + "b;"); 538 out_print(" // external "); 539 } 540 out_println(" Classref "); 541 } 542 543 void decodeClass(String inpName) throws IOException { 544 DataInputStream in = beginComponent(inpName); 545 546 for (int i = 0; in.available() > 0; i++) { 547 out_begin("{ // class " + i); 548 int bitfield = in.readUnsignedByte(); 549 int interface_count = bitfield & 0x0F; 550 out_print("0x"); 551 printByteHex(out, bitfield); 552 out.println("; // bitfield"); 553 if ((bitfield & 0x80) != 0) { 554 // interface 555 for (int k = 0; k < interface_count; k++) { 556 printClassref(in); 557 } 558 } else { 559 // class 560 printClassref(in); 561 out_println(in.readUnsignedByte() + "b; // declared instance size"); 562 out_println(in.readUnsignedByte() + "b; // first reference token"); 563 out_println(in.readUnsignedByte() + "b; // reference count"); 564 out_println(in.readUnsignedByte() + "b; // public method table base"); 565 int pumrc = in.readUnsignedByte(); 566 out_println(pumrc + "b; // public method table count"); 567 out_println(in.readUnsignedByte() + "b; // package method table base"); 568 int pamrc = in.readUnsignedByte(); 569 out_println(pamrc + "b; // package method table count"); 570 out_begin("{ // public method table"); 571 for (int k = 0; k < pumrc; k++) { 572 out_println(in.readUnsignedShort() + ";"); 573 } 574 out_end("};"); 575 out_begin("{ // package method table"); 576 for (int k = 0; k < pamrc; k++) { 577 out_println(in.readUnsignedShort() + ";"); 578 } 579 out_end("};"); 580 out_begin("{ // implemented interfaces"); 581 for (int k = 0; k < interface_count; k++) { 582 out_begin("{ // interface " + k); 583 printClassref(in); 584 int count = in.readUnsignedByte(); 585 out_begin("Bytes" + startArray(count) + "b {"); 586 printBytes(in, count); 587 out_end("};"); // Bytes[] 588 out_end("};"); 589 } 590 out_end("};"); 591 } 592 out_end("};"); 593 } 594 endComponent(in); 595 } 596 597 void decodeDescriptor(String inpName) throws IOException { 598 DataInputStream in = beginComponent(inpName); 599 600 methodsLengths = new ArrayList<>(); 601 methodsOffsets = new ArrayList<>(); 602 int class_count = in.readUnsignedByte(); 603 out_begin(startArray(class_count) + "b { // classes"); 604 for (int c = 0; c < class_count; c++) { 605 out_begin("{ // class " + c); 606 out_println(in.readUnsignedByte() + "b; // token"); 607 out_print("0x"); 608 printByteHex(out, in.readUnsignedByte()); 609 out.println("; // flags"); 610 printClassref(in); 611 int icount = in.readUnsignedByte(); 612 out_println(icount + "b; // interface count"); 613 int fcount = in.readUnsignedShort(); 614 out_println(fcount + "; // field count"); 615 int mcount = in.readUnsignedShort(); 616 out_println(mcount + "; // method count"); 617 if (icount != 0) { 618 out_begin("{ // interfaces"); 619 for (int i = 0; i < icount; i++) { 620 printClassref(in); 621 } 622 out_end("};"); 623 } 624 for (int i = 0; i < fcount; i++) { 625 out_begin("{ // field " + i); 626 out_println(in.readUnsignedByte() + "b; // token"); 627 int flags = in.readUnsignedByte(); 628 out_print("0x"); 629 printByteHex(out, flags); 630 out.println("; // flags"); 631 if ((flags & 0x08) == 0) { 632 printClassref(in); 633 out_println(in.readUnsignedByte() + "b; // token"); 634 } else { // static field 635 int info1 = in.readUnsignedByte(), 636 info2 = in.readUnsignedByte(), 637 info3 = in.readUnsignedByte(); 638 if ((info1 & 0x80) == 0) { 639 out_print(info1 + "b " + ((info2 << 8) | info3) + ";"); 640 out.println(" // internal field"); 641 } else { 642 out.print(info1 + "b " + info2 + "b " + info3 + "b;"); 643 out.println(" // external field"); 644 } 645 } 646 int type = in.readUnsignedShort(); 647 if ((type & 0x8000) == 0) { 648 out_println(type + "; // reference type"); 649 } else { 650 out_print("0x"); 651 printByteHex(out, type >> 8); 652 printByteHex(out, type); 653 out.println("; // primitive type"); 654 } 655 out_end("};"); 656 } 657 for (int i = 0; i < mcount; i++) { 658 int token = in.readUnsignedByte(); 659 int flags = in.readUnsignedByte(); 660 int m_offset = in.readUnsignedShort(); 661 int t_offset = in.readUnsignedShort(); 662 int bytecode_count = in.readUnsignedShort(); 663 if (m_offset != 0) { 664 out_begin("{ // method " + i + " (" + methodsLengths.size() + ")"); 665 methodsLengths.add(bytecode_count); 666 methodsOffsets.add(m_offset); 667 } else { 668 out_begin("{ // method " + i); 669 } 670 out_println(token + "b; // token"); 671 out_print("0x"); 672 printByteHex(out, flags); 673 out.println("; // flags"); 674 out_println(m_offset + "; // method offset"); 675 out_println(t_offset + "; // type offset"); 676 out_println(bytecode_count + "; // bytecode count"); 677 out_println(in.readUnsignedShort() + "; // exception handler count"); 678 out_println(in.readUnsignedShort() + "; // exception handler index"); 679 out_end("};"); 680 } 681 out_end("};"); // class i 682 } 683 out_end("}; // classes"); 684 685 int cp_count = in.readUnsignedShort(); 686 out_begin(startArray(cp_count) + " { // constant pool types"); 687 for (int i = 0; i < cp_count; i++) { 688 int type = in.readUnsignedShort(); 689 if (type == 0xFFFF) { 690 out_println("0xFFFF;"); 691 } else { 692 out_println(type + "; "); 693 } 694 } 695 out_end("}; // constant pool types"); 696 697 out_begin("{ // type descriptors"); 698 for (int i = 0; in.available() > 0; i++) { 699 int nibble_count = in.readUnsignedByte(); 700 out_print(nibble_count + "b; "); 701 printBytes(in, (nibble_count + 1) / 2); 702 } 703 out_end("}; // type descriptors"); 704 endComponent(in); 705 } 706 707 void decodeMethod(String inpName) throws IOException { 708 DataInputStream in = beginComponent(inpName); 709 710 int handler_count = in.readUnsignedByte(); 711 out_begin(startArray(handler_count) + "b { // exception handlers"); 712 for (int i = 0; i < handler_count; i++) { 713 out_print(in.readUnsignedShort() + ", "); 714 int bitfield = in.readUnsignedShort(); 715 out.print("0x"); 716 printByteHex(out, bitfield >> 8); 717 printByteHex(out, bitfield); 718 out.print(", " + in.readUnsignedShort() + ", "); 719 out.println(in.readUnsignedShort() + "; // handler " + i); 720 } 721 out_end("};"); // handlers 722 723 if (methodsLengths == null) { 724 out.println("// Descriptor.cap absent - methods not printed"); 725 } else { 726 int f_offset = 1 + handler_count * 8; 727 for (int i = 0; i < methodsLengths.size(); i++) { 728 out_begin("{ // method " + i); 729 int m_offset = methodsOffsets.get(i); 730 if (m_offset != f_offset) { 731 out.println("file offset=" + f_offset + " but m_offset=" + m_offset); 732 break; 733 } 734 int bitfield = in.readUnsignedByte(); 735 if ((bitfield & 0x80) == 0) { 736 out_print("0x"); 737 printByteHex(out, bitfield); 738 out.println("; // flags, max_stack"); 739 out_print("0x"); 740 printByteHex(out, in.readUnsignedByte()); 741 out.println("; // nargs, max_locals"); 742 f_offset += 2; 743 } else { 744 out_print("0x"); 745 printByteHex(out, bitfield); 746 out.println("; // flags, padding"); 747 out_println(in.readUnsignedByte() + "b; // max_stack"); 748 out_println(in.readUnsignedByte() + "b; // nargs"); 749 out_println(in.readUnsignedByte() + "b; // max_locals"); 750 f_offset += 4; 751 } 752 int bytecode_count = methodsLengths.get(i); 753 out_begin("{ // bytecodes"); 754 printBytes(in, bytecode_count); 755 f_offset += bytecode_count; 756 out_end("};"); 757 out_end("};"); 758 } 759 } 760 761 endComponent(in); 762 } 763 764 void decodeStaticField(String inpName) throws IOException { 765 DataInputStream in = beginComponent(inpName); 766 767 int image_size = in.readUnsignedShort(); 768 out_println(image_size + "; // image size"); 769 int reference_count = in.readUnsignedShort(); 770 out_println(reference_count + "; // reference count"); 771 int array_init_count = in.readUnsignedShort(); 772 out_begin(startArray(array_init_count) + " { // array_init_info"); 773 for (int i = 0; i < array_init_count; i++) { 774 out_println(in.readUnsignedByte() + "b // type "); 775 int count = in.readUnsignedShort(); 776 out_begin("Bytes" + startArray(count) + "s { // values"); 777 printBytes(in, count); 778 out_end("};"); // Bytes[] 779 } 780 out_end("};"); // array_init_info 781 int default_value_count = in.readUnsignedShort(); 782 out_println(default_value_count + "; // default value count"); 783 int non_default_value_count = in.readUnsignedShort(); 784 out_begin("Bytes" + startArray(non_default_value_count) + "s { // non default values"); 785 printBytes(in, non_default_value_count); 786 out_end("};"); // Bytes[] 787 788 endComponent(in); 789 } 790 791 void decodeRefLocation(String inpName) throws IOException { 792 DataInputStream in = beginComponent(inpName); 793 794 int byte_index_count = in.readUnsignedShort(); 795 out_begin("Bytes" + startArray(byte_index_count) + "s { // offsets to byte indices"); 796 printBytes(in, byte_index_count); 797 out_end("};"); // Bytes[] 798 799 byte_index_count = in.readUnsignedShort(); 800 out_begin("Bytes" + startArray(byte_index_count) + "s { // offsets to byte2 indices"); 801 printBytes(in, byte_index_count); 802 out_end("};"); // Bytes[] 803 804 endComponent(in); 805 } 806 807 void decodeExport(String inpName) throws IOException { 808 DataInputStream in = beginComponent(inpName); 809 int class_count = in.readUnsignedByte(); 810 out_begin(startArray(class_count) + "b { // classes"); 811 for (int i = 0; i < class_count; i++) { 812 out_begin("{ // class " + i); 813 out_println(in.readUnsignedShort() + "; // class offset"); 814 int fcount = in.readUnsignedByte(); 815 out_println(fcount + "b; // static field count"); 816 int mcount = in.readUnsignedByte(); 817 out_println(mcount + "b; // static method count"); 818 out_begin("{ // static field offsets"); 819 for (int j = 0; j < fcount; j++) { 820 out_println(in.readUnsignedShort() + "; // field " + j + " offset"); 821 } 822 out_end("};"); 823 out_begin("{ // static method offsets"); 824 for (int j = 0; j < mcount; j++) { 825 out_println(in.readUnsignedShort() + "; // method " + j + " offset"); 826 } 827 out_end("};"); 828 out_end("};"); // class i 829 } 830 out_end("};"); // classes 831 endComponent(in); 832 } 833 /*========================================================*/ 834 835 /** 836 * Constructor. 837 */ 838 public Main(PrintWriter out, String program) { 839 this.out = out; 840 this.program = program; 841 } 842 843 public void error(String msg) { 844 out.println(program + ": " + msg); 845 } 846 847 /** 848 * Usage 849 */ 850 public void usage() { 851 out.println(i18n.getString("jcdec.usage")); 852 out.println(i18n.getString("jcdec.opt.g")); 853 out.println(i18n.getString("jcdec.opt.version")); 854 } 855 856 /** 857 * Run the decoder 858 */ 859 public synchronized boolean decode(String argv[]) { 860 // int flags = F_WARNINGS; 861 long tm = System.currentTimeMillis(); 862 ArrayList<String> vargs = new ArrayList<>(); 863 ArrayList<String> vj = new ArrayList<>(); 864 boolean nowrite = false; 865 int addOptions = 0; 866 867 // Parse arguments 868 for (int i = 0; i < argv.length; i++) { 869 String arg = argv[i]; 870 if (arg.equals("-g")) { 871 printDetails = true; 872 vargs.add(arg); 873 } else if (arg.equals("-v")) { 874 DebugFlag = true; 875 vargs.add(arg); 876 out.println("arg[" + i + "]=" + argv[i] + "/verbose"); 877 } else if (arg.equals("-version")) { 878 out.println(ProductInfo.FULL_VERSION); 879 } else if (arg.startsWith("-")) { 880 //out.println("arg["+i+"]="+argv[i]+"/invalid flag"); 881 error(i18n.getString("jcdec.error.invalid_flag", arg)); 882 usage(); 883 return false; 884 } else { 885 vargs.add(arg); 886 vj.add(arg); 887 } 888 } 889 890 if (vj.isEmpty()) { 891 usage(); 892 return false; 893 } 894 895 // String[] names = new String[vj.size()]; 896 // vj.copyInto(names); 897 String[] names = null; 898 names = vj.toArray(names); 899 decode: 900 for (int k = 0; k < names.length; k++) { 901 String inpname = names[k]; 902 try { 903 if (inpname.endsWith(".cap")) { 904 String shortName = inpname.substring(0, inpname.length() - 4); 905 if (shortName.endsWith("Header")) { 906 decodeHeader(inpname); 907 } else if (shortName.endsWith("Directory")) { 908 decodeDirectory(inpname); 909 } else if (shortName.endsWith("Applet")) { 910 decodeApplet(inpname); 911 } else if (shortName.endsWith("Import")) { 912 decodeImport(inpname); 913 } else if (shortName.endsWith("ConstantPool")) { 914 decodeConstantPool(inpname); 915 } else if (shortName.endsWith("Class")) { 916 decodeClass(inpname); 917 } else if (shortName.endsWith("Descriptor")) { 918 decodeDescriptor(inpname); 919 } else if (shortName.endsWith("Method")) { 920 decodeMethod(inpname); 921 } else if (shortName.endsWith("StaticField")) { 922 decodeStaticField(inpname); 923 } else if (shortName.endsWith("RefLocation")) { 924 decodeRefLocation(inpname); 925 } else if (shortName.endsWith("Export")) { 926 decodeExport(inpname); 927 } else { 928 continue decode; 929 } 930 out.println(""); 931 } else if (inpname.endsWith(".exp")) { 932 decodeExp(inpname); 933 out.println(""); 934 } 935 continue decode; 936 } catch (FileNotFoundException ee) { 937 error(i18n.getString("jcdec.error.cannot_read", inpname)); 938 } catch (Error ee) { 939 ee.printStackTrace(); 940 error(i18n.getString("jcdec.error.fatal_error")); 941 } catch (Exception ee) { 942 ee.printStackTrace(); 943 error(i18n.getString("jcdec.error.fatal_exception")); 944 } 945 return false; 946 } 947 return true; 948 } 949 950 /** 951 * Main program 952 */ 953 public static void main(String argv[]) { 954 Main decoder = new Main(new PrintWriter(new uEscWriter(System.out)), "jcdec"); 955 System.exit(decoder.decode(argv) ? 0 : 1); 956 } 957 }