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 }