diff a/test/lib/org/openjdk/asmtools/jcdec/Main.java b/test/lib/org/openjdk/asmtools/jcdec/Main.java
--- /dev/null
+++ b/test/lib/org/openjdk/asmtools/jcdec/Main.java
@@ -0,0 +1,957 @@
+/*
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package org.openjdk.asmtools.jcdec;
+
+import static org.openjdk.asmtools.jcoder.JcodTokens.*;
+import org.openjdk.asmtools.jdis.uEscWriter;
+import org.openjdk.asmtools.util.I18NResourceBundle;
+import org.openjdk.asmtools.util.ProductInfo;
+import java.io.DataInputStream;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
+/**
+ * Main program of the JavaCard DeCoder
+ *
+ */
+public class Main {
+
+    /*-------------------------------------------------------- */
+    /* Main Fields */
+    /**
+     * Name of the program.
+     */
+    String program;
+
+    public static final I18NResourceBundle i18n
+            = I18NResourceBundle.getBundleForClass(Main.class);
+    /**
+     * The stream where error message are printed.
+     */
+    PrintWriter out;
+    boolean DebugFlag = false;
+    boolean printDetails = false;
+    int shift = 0;
+    private static final char hexTable[] = {
+        '0', '1', '2', '3', '4', '5', '6', '7',
+        '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+    };
+    /*-------------------------------------------------------- */
+
+    static String toHex(long val, int width) {
+        StringBuffer s = new StringBuffer();
+        for (int i = width * 2 - 1; i >= 0; i--) {
+            s.append(hexTable[((int) (val >> (4 * i))) & 0xF]);
+        }
+        return "0x" + s.toString();
+    }
+
+    static String toHex(long val) {
+        int width;
+        for (width = 8; width > 0; width--) {
+            if ((val >> (width - 1) * 8) != 0) {
+                break;
+            }
+        }
+        return toHex(val, width);
+    }
+
+    void printByteHex(PrintWriter out, int b) {
+        out.print(hexTable[(b >> 4) & 0xF]);
+        out.print(hexTable[b & 0xF]);
+    }
+
+    /*========================================================*/
+    void out_begin(String s) {
+        for (int i = 0; i < shift; i++) {
+            out.print("  ");
+        }
+        out.println(s);
+        shift++;
+    }
+
+    void out_print(String s) {
+        for (int i = 0; i < shift; i++) {
+            out.print("  ");
+        }
+        out.print(s);
+    }
+
+    void out_println(String s) {
+        for (int i = 0; i < shift; i++) {
+            out.print("  ");
+        }
+        out.println(s);
+    }
+
+    void out_end(String s) {
+        shift--;
+        for (int i = 0; i < shift; i++) {
+            out.print("  ");
+        }
+        out.println(s);
+    }
+
+    String startArray(int length) {
+        return "[" + (printDetails ? Integer.toString(length) : "") + "]";
+    }
+
+    void printBytes(DataInputStream in, int len) throws IOException {
+        try {
+            for (int i = 0; i < len; i++) {
+                if (i % 8 == 0) {
+                    out_print("0x");
+                }
+                printByteHex(out, in.readByte());
+                if (i % 8 == 7) {
+                    out.println(";");
+                }
+            }
+        } finally {
+            if (len % 8 != 0) {
+                out.println(";");
+            }
+        }
+    }
+
+    /*========================================================*/
+    static final int EXPORT_MAGIC = 0x00FACADE;
+    static final int HEADER_MAGIC = 0xDECAFFED;
+    static String[] compNames = {
+        "Header",
+        "Directory",
+        "Applet",
+        "Import",
+        "ConstantPool",
+        "Class",
+        "Method",
+        "StaticField",
+        "RefLocation",
+        "Export",
+        "Descriptor"
+    };
+
+    static String compName(int compNum) {
+        try {
+            return compNames[compNum - 1];
+        } catch (ArrayIndexOutOfBoundsException e) {
+            return "tag " + compNum + "???";
+        }
+    }
+    String[] cPoolStrings;
+
+    void decodeAttr(DataInputStream in) throws IOException {
+        int name_cpx = in.readUnsignedShort(), len = in.readInt();
+        String AttrName = null;
+        String endingComment = "Attr(#" + name_cpx + ")";
+        try {
+            endingComment = AttrName = cPoolStrings[name_cpx];
+        } catch (ArrayIndexOutOfBoundsException e) {
+        }
+        if (printDetails) {
+            out_begin("Attr(#" + name_cpx + ", " + len + ") { // " + AttrName);
+        } else {
+            out_begin("Attr(#" + name_cpx + ") { // " + AttrName);
+        }
+        if (AttrName == null) {
+            printBytes(in, len);
+        } else if (AttrName.equals("ConstantValue")) {
+            if (len != 2) {
+                out_println("// invalid length of ConstantValue attr: " + len + " (should be 2)");
+                printBytes(in, len);
+            } else {
+                out_println("#" + in.readUnsignedShort() + ";");
+            }
+        } else {
+            printBytes(in, len);
+        }
+        out_end("} // end " + endingComment);
+    }
+
+    void decodeExp(String inpName) throws IOException {
+        DataInputStream in = new DataInputStream(new FileInputStream(inpName));
+        out_println("file " + inpName);
+        out_begin("{  // export file");
+
+        int magic = in.readInt();
+        out_print(toHex(magic, 4) + ";  // ");
+        if (magic != EXPORT_MAGIC) {
+            out.print("wrong magic: 0x" + Integer.toString(EXPORT_MAGIC, 16) + " expected");
+        } else {
+            out_print("magic");
+        }
+        out.println();
+        out_println(in.readUnsignedByte() + "b;  // minor version");
+        out_println(in.readUnsignedByte() + "b;  // major version");
+
+        int cp_count = in.readUnsignedShort();
+        cPoolStrings = new String[cp_count];
+        out_begin(startArray(cp_count) + " { //  Constant Pool");
+        for (int i = 0; i < cp_count; i++) {
+            int tag = in.readUnsignedByte();
+            ConstType tg = constType(tag);
+            switch (tg) {
+                case CONSTANT_UTF8:
+                    out_print("Utf8 \"");
+
+                    StringBuffer sb = new StringBuffer();
+                    String s = in.readUTF();
+                    cPoolStrings[i] = s;
+                    for (int k = 0; k < s.length(); k++) {
+                        char c = s.charAt(k);
+                        switch (c) {
+                            case '\t':
+                                sb.append('\\').append('t');
+                                break;
+                            case '\n':
+                                sb.append('\\').append('n');
+                                break;
+                            case '\r':
+                                sb.append('\\').append('r');
+                                break;
+                            case '\"':
+                                sb.append('\\').append('\"');
+                                break;
+                            default:
+                                sb.append(c);
+                        }
+                    }
+                    out.println(sb.append("\"; // #").append(i).toString());
+                    break;
+
+                case CONSTANT_INTEGER:
+                    out_println("int " + toHex(in.readInt(), 4) + "; // #" + i);
+                    break;
+
+                case CONSTANT_CLASS:
+                    out_println("class #" + in.readUnsignedShort() + "; // #" + i);
+                    break;
+
+                case CONSTANT_JAVACARD_PACKAGE:
+                    out_begin("package { // #" + i);
+                    out_println(toHex(in.readUnsignedByte(), 1) + ";  // flags");
+                    out_println("#" + in.readUnsignedShort() + "; // name");
+                    out_println(in.readUnsignedByte() + "b;  // minor version");
+                    out_println(in.readUnsignedByte() + "b;  // major version");
+                    int aid_len = in.readUnsignedByte();
+                    out_begin("Bytes" + startArray(aid_len) + "b {");
+                    printBytes(in, aid_len);
+                    out_end("};"); // Bytes[]
+                    out_end("};"); // package info
+                    break;
+
+                default:
+                    throw new Error("invalid constant type: " + (int) tag);
+            }
+        }
+        ;
+        out_end("} // Constant pool");
+        out_println("#" + in.readUnsignedShort() + ";  // this package");
+        int class_count = in.readUnsignedByte();
+        out_begin(startArray(class_count) + "b { //  classes");
+        for (int i = 0; i < class_count; i++) {
+            out_begin("{ // class " + i);
+
+            out_println(in.readUnsignedByte() + "b; // token");
+
+            int flags = in.readUnsignedShort();
+            out_print("0x");
+            printByteHex(out, flags >> 8);
+            printByteHex(out, flags);
+            out.println("; // flags");
+
+            out_println("#" + in.readUnsignedShort() + ";  // this class");
+
+            int sup_count = in.readUnsignedShort();
+            out_begin(startArray(sup_count) + " { // supers");
+            for (int k = 0; k < sup_count; k++) {
+                out_println("#" + in.readUnsignedShort() + ";");
+            }
+            out_end("} // supers");
+
+            int int_count = in.readUnsignedByte();
+            out_begin(startArray(int_count) + "b { // interfaces");
+            for (int k = 0; k < int_count; k++) {
+                out_println("#" + in.readUnsignedShort() + ";");
+            }
+            out_end("} // interfaces");
+
+            int field_count = in.readUnsignedShort();
+            out_begin(startArray(field_count) + " { // fields");
+            for (int k = 0; k < field_count; k++) {
+                out_begin("{ // field " + k);
+                out_println(in.readUnsignedByte() + "b; // token");
+
+                int f_flags = in.readUnsignedShort();
+                out_print("0x");
+                printByteHex(out, f_flags >> 8);
+                printByteHex(out, f_flags);
+                out.println("; // flags");
+
+                out_println("#" + in.readUnsignedShort() + ";  // this field name");
+                out_println("#" + in.readUnsignedShort() + ";  // this field descriptor");
+
+                int attr_count = in.readUnsignedShort();
+                out_begin(startArray(attr_count) + " { // Attributes");
+                for (int ai = 0; ai < attr_count; ai++) {
+                    decodeAttr(in);
+                }
+                out_end("} // Attributes");
+                out_end("};");
+            }
+            out_end("} // fields");
+
+            int mth_count = in.readUnsignedShort();
+            out_begin(startArray(mth_count) + " { // methods");
+            for (int k = 0; k < mth_count; k++) {
+                out_begin("{ // method " + k);
+                out_println(in.readUnsignedByte() + "b; // token");
+
+                int mth_flags = in.readUnsignedShort();
+                out_print("0x");
+                printByteHex(out, mth_flags >> 8);
+                printByteHex(out, mth_flags);
+                out.println("; // flags");
+
+                out_println("#" + in.readUnsignedShort() + ";  // this method name");
+                out_println("#" + in.readUnsignedShort() + ";  // this method descriptor");
+                out_end("};");
+            }
+            out_end("} // methods");
+            out_end("};");
+        }
+        out_end("} // classes");
+        endComponent(in);
+    }
+
+    DataInputStream beginComponent(String inpName) throws IOException {
+        DataInputStream in = new DataInputStream(new FileInputStream(inpName));
+        out_println("file " + inpName);
+
+        int tag = in.readUnsignedByte();
+        out_print("Component(" + tag);
+        int size = in.readUnsignedShort();
+        if (printDetails) {
+            out.print(", " + size);
+        }
+        out_begin(") { // " + compName(tag));
+        return in;
+    }
+
+    void endComponent(DataInputStream in) throws IOException {
+        out_end("};"); // Component
+        int avail = in.available();
+        if (avail > 0) {
+            out.println("=========== extra bytes:");
+            for (int k = 0; k < 8; k++) {
+                printBytes(in, avail >= 8 ? 8 : avail);
+                avail = in.available();
+                if (avail == 0) {
+                    break;
+                }
+            }
+            if (avail > 0) {
+                out.println("  there is also " + avail + " bytes available");
+            }
+        }
+        in.close();
+    }
+
+    ArrayList<Integer> methodsLengths = null;
+    ArrayList<Integer> methodsOffsets = null;
+
+    void decodeHeader(String inpName) throws IOException {
+        DataInputStream in = beginComponent(inpName);
+
+        int magic = in.readInt();
+        out_print(toHex(magic, 4) + ";  // ");
+        if (magic != HEADER_MAGIC) {
+            out.print("wrong magic: 0x" + Integer.toString(HEADER_MAGIC, 16) + " expected");
+        } else {
+            out_print("magic");
+        }
+        out.println();
+        out_println(in.readUnsignedByte() + "b;  // minor version");
+        out_println(in.readUnsignedByte() + "b;  // major version");
+        out_println(toHex(in.readUnsignedByte(), 1) + ";  // flags");
+
+        out_begin("{  // package info");
+        out_println(in.readUnsignedByte() + "b;  // minor version");
+        out_println(in.readUnsignedByte() + "b;  // major version");
+        int aid_len = in.readUnsignedByte();
+        out_begin("Bytes" + startArray(aid_len) + "b {");
+        printBytes(in, aid_len);
+        out_end("};"); // Bytes[]
+        out_end("};"); // package info
+        endComponent(in);
+    }
+
+    void decodeDirectory(String inpName) throws IOException {
+        DataInputStream in = beginComponent(inpName);
+
+        int i;
+        out_begin("{  // component sizes");
+        for (i = 0; i < 11; i++) {
+            out_println(in.readUnsignedShort() + ";  // " + (i + 1));
+        }
+        out_end("};");
+
+        out_begin("{  // static field size");
+        out_println(in.readUnsignedShort() + ";  // image size");
+        out_println(in.readUnsignedShort() + ";  // array init count");
+        out_println(in.readUnsignedShort() + ";  // array init size");
+        out_end("};");
+
+        out_println(in.readUnsignedByte() + "b;  // import count");
+        out_println(in.readUnsignedByte() + "b;  // applet count");
+
+        int custom_count = in.readUnsignedByte();
+        out_begin(startArray(custom_count) + "b { // custom components");
+        for (i = 0; i < custom_count; i++) {
+            out_print("Comp(" + in.readUnsignedByte());  // tag;
+            int size2 = in.readUnsignedShort();
+            if (printDetails) {
+                out_print(", " + size2);
+            }
+            out_begin(") {");
+            int aid_len = in.readUnsignedByte();
+            out_begin("Bytes" + startArray(aid_len) + "b {");
+            printBytes(in, aid_len);
+            out_end("};");
+            out_end("};");
+        }
+        out_end("};");
+
+        endComponent(in);
+    }
+
+    void decodeApplet(String inpName) throws IOException {
+        DataInputStream in = beginComponent(inpName);
+
+        int applet_count = in.readUnsignedByte();
+        out_begin(startArray(applet_count) + "b { // applets");
+        for (int i = 0; i < applet_count; i++) {
+            out_begin("{ // applet " + i);
+            int aid_len = in.readUnsignedByte();
+            out_begin("Bytes" + startArray(aid_len) + "b {");
+            printBytes(in, aid_len);
+            out_end("};"); // Bytes[]
+            out_println(in.readUnsignedShort() + ";  // install method offset");
+            out_end("};"); // applet
+        }
+        out_end("};"); // applets
+        endComponent(in);
+    }
+
+    void decodeImport(String inpName) throws IOException {
+        DataInputStream in = beginComponent(inpName);
+
+        int package_count = in.readUnsignedByte();
+        out_begin(startArray(package_count) + "b { //  packages");
+        for (int i = 0; i < package_count; i++) {
+            out_begin("{ // package " + i);
+            out_println(in.readUnsignedByte() + "b;  // minor version");
+            out_println(in.readUnsignedByte() + "b;  // major version");
+            int aid_len = in.readUnsignedByte();
+            out_begin("Bytes" + startArray(aid_len) + "b {");
+            printBytes(in, aid_len);
+            out_end("};"); // Bytes[]
+            out_end("};"); // package info
+        }
+        out_end("};"); //  package info
+        endComponent(in);
+    }
+
+    static String[] refNames = {
+        "Classref",
+        "InstanceFieldref",
+        "VirtualMethodref",
+        "SuperMethodref",
+        "StaticFieldref",
+        "StaticMethodref"
+    };
+
+    void decodeConstantPool(String inpName) throws IOException {
+        DataInputStream in = beginComponent(inpName);
+
+        int items_count = in.readUnsignedShort();
+        out_begin(startArray(items_count) + " { //  items");
+        for (int i = 0; i < items_count; i++) {
+            int tag = in.readUnsignedByte();
+            int info1 = in.readUnsignedByte(),
+                    info2 = in.readUnsignedByte(),
+                    info3 = in.readUnsignedByte();
+            out_print(tag + "b ");
+            if ((tag > 0) && (tag <= 6)) {
+                if ((info1 & 0x80) == 0) {
+                    if (tag <= 4) {
+                        out_print(((info1 << 8) | info2) + " " + info3 + "b;");
+                    } else {
+                        out_print(info1 + "b " + ((info2 << 8) | info3) + ";");
+                    }
+                    out.print(" // internal ");
+                } else {
+                    out.print(info1 + "b " + info2 + "b " + info3 + "b;");
+                    out.print(" // external ");
+                }
+                out.println(refNames[tag - 1]);
+            } else {
+                out.print(info1 + "b " + info2 + "b " + info3 + "b;");
+                out.println(" // unknown tag ");
+            }
+        }
+        out_end("};"); //  CP array
+        endComponent(in);
+    }
+
+    void printClassref(DataInputStream in) throws IOException {
+        int info1 = in.readUnsignedByte(),
+                info2 = in.readUnsignedByte();
+        if ((info1 & 0x80) == 0) {
+            out_print(((info1 << 8) | info2) + ";");
+            out_print(" // internal ");
+        } else {
+            out_print(info1 + "b " + info2 + "b;");
+            out_print(" // external ");
+        }
+        out_println(" Classref ");
+    }
+
+    void decodeClass(String inpName) throws IOException {
+        DataInputStream in = beginComponent(inpName);
+
+        for (int i = 0; in.available() > 0; i++) {
+            out_begin("{ // class " + i);
+            int bitfield = in.readUnsignedByte();
+            int interface_count = bitfield & 0x0F;
+            out_print("0x");
+            printByteHex(out, bitfield);
+            out.println("; // bitfield");
+            if ((bitfield & 0x80) != 0) {
+                // interface
+                for (int k = 0; k < interface_count; k++) {
+                    printClassref(in);
+                }
+            } else {
+                // class
+                printClassref(in);
+                out_println(in.readUnsignedByte() + "b;  // declared instance size");
+                out_println(in.readUnsignedByte() + "b;  // first reference token");
+                out_println(in.readUnsignedByte() + "b;  // reference count");
+                out_println(in.readUnsignedByte() + "b;  // public method table base");
+                int pumrc = in.readUnsignedByte();
+                out_println(pumrc + "b;  // public method table count");
+                out_println(in.readUnsignedByte() + "b;  // package method table base");
+                int pamrc = in.readUnsignedByte();
+                out_println(pamrc + "b;  // package method table count");
+                out_begin("{ // public method table");
+                for (int k = 0; k < pumrc; k++) {
+                    out_println(in.readUnsignedShort() + ";");
+                }
+                out_end("};");
+                out_begin("{ // package method table");
+                for (int k = 0; k < pamrc; k++) {
+                    out_println(in.readUnsignedShort() + ";");
+                }
+                out_end("};");
+                out_begin("{ // implemented interfaces");
+                for (int k = 0; k < interface_count; k++) {
+                    out_begin("{ // interface " + k);
+                    printClassref(in);
+                    int count = in.readUnsignedByte();
+                    out_begin("Bytes" + startArray(count) + "b {");
+                    printBytes(in, count);
+                    out_end("};"); // Bytes[]
+                    out_end("};");
+                }
+                out_end("};");
+            }
+            out_end("};");
+        }
+        endComponent(in);
+    }
+
+    void decodeDescriptor(String inpName) throws IOException {
+        DataInputStream in = beginComponent(inpName);
+
+        methodsLengths = new ArrayList<>();
+        methodsOffsets = new ArrayList<>();
+        int class_count = in.readUnsignedByte();
+        out_begin(startArray(class_count) + "b { // classes");
+        for (int c = 0; c < class_count; c++) {
+            out_begin("{ // class " + c);
+            out_println(in.readUnsignedByte() + "b; // token");
+            out_print("0x");
+            printByteHex(out, in.readUnsignedByte());
+            out.println("; // flags");
+            printClassref(in);
+            int icount = in.readUnsignedByte();
+            out_println(icount + "b; // interface count");
+            int fcount = in.readUnsignedShort();
+            out_println(fcount + "; // field count");
+            int mcount = in.readUnsignedShort();
+            out_println(mcount + "; // method count");
+            if (icount != 0) {
+                out_begin("{ // interfaces");
+                for (int i = 0; i < icount; i++) {
+                    printClassref(in);
+                }
+                out_end("};");
+            }
+            for (int i = 0; i < fcount; i++) {
+                out_begin("{ // field " + i);
+                out_println(in.readUnsignedByte() + "b; // token");
+                int flags = in.readUnsignedByte();
+                out_print("0x");
+                printByteHex(out, flags);
+                out.println("; // flags");
+                if ((flags & 0x08) == 0) {
+                    printClassref(in);
+                    out_println(in.readUnsignedByte() + "b; // token");
+                } else { // static field
+                    int info1 = in.readUnsignedByte(),
+                            info2 = in.readUnsignedByte(),
+                            info3 = in.readUnsignedByte();
+                    if ((info1 & 0x80) == 0) {
+                        out_print(info1 + "b " + ((info2 << 8) | info3) + ";");
+                        out.println(" // internal field");
+                    } else {
+                        out.print(info1 + "b " + info2 + "b " + info3 + "b;");
+                        out.println(" // external field");
+                    }
+                }
+                int type = in.readUnsignedShort();
+                if ((type & 0x8000) == 0) {
+                    out_println(type + "; // reference type");
+                } else {
+                    out_print("0x");
+                    printByteHex(out, type >> 8);
+                    printByteHex(out, type);
+                    out.println("; // primitive type");
+                }
+                out_end("};");
+            }
+            for (int i = 0; i < mcount; i++) {
+                int token = in.readUnsignedByte();
+                int flags = in.readUnsignedByte();
+                int m_offset = in.readUnsignedShort();
+                int t_offset = in.readUnsignedShort();
+                int bytecode_count = in.readUnsignedShort();
+                if (m_offset != 0) {
+                    out_begin("{ // method " + i + " (" + methodsLengths.size() + ")");
+                    methodsLengths.add(bytecode_count);
+                    methodsOffsets.add(m_offset);
+                } else {
+                    out_begin("{ // method " + i);
+                }
+                out_println(token + "b; // token");
+                out_print("0x");
+                printByteHex(out, flags);
+                out.println("; // flags");
+                out_println(m_offset + "; // method offset");
+                out_println(t_offset + "; // type offset");
+                out_println(bytecode_count + "; // bytecode count");
+                out_println(in.readUnsignedShort() + "; // exception handler count");
+                out_println(in.readUnsignedShort() + "; // exception handler index");
+                out_end("};");
+            }
+            out_end("};"); // class i
+        }
+        out_end("}; // classes");
+
+        int cp_count = in.readUnsignedShort();
+        out_begin(startArray(cp_count) + " { // constant pool types");
+        for (int i = 0; i < cp_count; i++) {
+            int type = in.readUnsignedShort();
+            if (type == 0xFFFF) {
+                out_println("0xFFFF;");
+            } else {
+                out_println(type + "; ");
+            }
+        }
+        out_end("}; // constant pool types");
+
+        out_begin("{ // type descriptors");
+        for (int i = 0; in.available() > 0; i++) {
+            int nibble_count = in.readUnsignedByte();
+            out_print(nibble_count + "b; ");
+            printBytes(in, (nibble_count + 1) / 2);
+        }
+        out_end("}; // type descriptors");
+        endComponent(in);
+    }
+
+    void decodeMethod(String inpName) throws IOException {
+        DataInputStream in = beginComponent(inpName);
+
+        int handler_count = in.readUnsignedByte();
+        out_begin(startArray(handler_count) + "b { // exception handlers");
+        for (int i = 0; i < handler_count; i++) {
+            out_print(in.readUnsignedShort() + ", ");
+            int bitfield = in.readUnsignedShort();
+            out.print("0x");
+            printByteHex(out, bitfield >> 8);
+            printByteHex(out, bitfield);
+            out.print(", " + in.readUnsignedShort() + ", ");
+            out.println(in.readUnsignedShort() + "; // handler " + i);
+        }
+        out_end("};"); // handlers
+
+        if (methodsLengths == null) {
+            out.println("// Descriptor.cap absent - methods not printed");
+        } else {
+            int f_offset = 1 + handler_count * 8;
+            for (int i = 0; i < methodsLengths.size(); i++) {
+                out_begin("{ // method " + i);
+                int m_offset = methodsOffsets.get(i);
+                if (m_offset != f_offset) {
+                    out.println("file offset=" + f_offset + " but m_offset=" + m_offset);
+                    break;
+                }
+                int bitfield = in.readUnsignedByte();
+                if ((bitfield & 0x80) == 0) {
+                    out_print("0x");
+                    printByteHex(out, bitfield);
+                    out.println("; // flags, max_stack");
+                    out_print("0x");
+                    printByteHex(out, in.readUnsignedByte());
+                    out.println("; // nargs, max_locals");
+                    f_offset += 2;
+                } else {
+                    out_print("0x");
+                    printByteHex(out, bitfield);
+                    out.println("; // flags, padding");
+                    out_println(in.readUnsignedByte() + "b; // max_stack");
+                    out_println(in.readUnsignedByte() + "b; // nargs");
+                    out_println(in.readUnsignedByte() + "b; // max_locals");
+                    f_offset += 4;
+                }
+                int bytecode_count = methodsLengths.get(i);
+                out_begin("{ // bytecodes");
+                printBytes(in, bytecode_count);
+                f_offset += bytecode_count;
+                out_end("};");
+                out_end("};");
+            }
+        }
+
+        endComponent(in);
+    }
+
+    void decodeStaticField(String inpName) throws IOException {
+        DataInputStream in = beginComponent(inpName);
+
+        int image_size = in.readUnsignedShort();
+        out_println(image_size + "; // image size");
+        int reference_count = in.readUnsignedShort();
+        out_println(reference_count + "; // reference count");
+        int array_init_count = in.readUnsignedShort();
+        out_begin(startArray(array_init_count) + " { // array_init_info");
+        for (int i = 0; i < array_init_count; i++) {
+            out_println(in.readUnsignedByte() + "b // type ");
+            int count = in.readUnsignedShort();
+            out_begin("Bytes" + startArray(count) + "s { // values");
+            printBytes(in, count);
+            out_end("};"); // Bytes[]
+        }
+        out_end("};"); // array_init_info
+        int default_value_count = in.readUnsignedShort();
+        out_println(default_value_count + "; // default value count");
+        int non_default_value_count = in.readUnsignedShort();
+        out_begin("Bytes" + startArray(non_default_value_count) + "s { // non default values");
+        printBytes(in, non_default_value_count);
+        out_end("};"); // Bytes[]
+
+        endComponent(in);
+    }
+
+    void decodeRefLocation(String inpName) throws IOException {
+        DataInputStream in = beginComponent(inpName);
+
+        int byte_index_count = in.readUnsignedShort();
+        out_begin("Bytes" + startArray(byte_index_count) + "s { // offsets to byte indices");
+        printBytes(in, byte_index_count);
+        out_end("};"); // Bytes[]
+
+        byte_index_count = in.readUnsignedShort();
+        out_begin("Bytes" + startArray(byte_index_count) + "s { // offsets to byte2 indices");
+        printBytes(in, byte_index_count);
+        out_end("};"); // Bytes[]
+
+        endComponent(in);
+    }
+
+    void decodeExport(String inpName) throws IOException {
+        DataInputStream in = beginComponent(inpName);
+        int class_count = in.readUnsignedByte();
+        out_begin(startArray(class_count) + "b { // classes");
+        for (int i = 0; i < class_count; i++) {
+            out_begin("{ // class " + i);
+            out_println(in.readUnsignedShort() + "; // class offset");
+            int fcount = in.readUnsignedByte();
+            out_println(fcount + "b; // static field count");
+            int mcount = in.readUnsignedByte();
+            out_println(mcount + "b; // static method count");
+            out_begin("{ // static field offsets");
+            for (int j = 0; j < fcount; j++) {
+                out_println(in.readUnsignedShort() + "; // field " + j + " offset");
+            }
+            out_end("};");
+            out_begin("{ // static method offsets");
+            for (int j = 0; j < mcount; j++) {
+                out_println(in.readUnsignedShort() + "; // method " + j + " offset");
+            }
+            out_end("};");
+            out_end("};"); // class i
+        }
+        out_end("};"); // classes
+        endComponent(in);
+    }
+    /*========================================================*/
+
+    /**
+     * Constructor.
+     */
+    public Main(PrintWriter out, String program) {
+        this.out = out;
+        this.program = program;
+    }
+
+    public void error(String msg) {
+        out.println(program + ": " + msg);
+    }
+
+    /**
+     * Usage
+     */
+    public void usage() {
+        out.println(i18n.getString("jcdec.usage"));
+        out.println(i18n.getString("jcdec.opt.g"));
+        out.println(i18n.getString("jcdec.opt.version"));
+    }
+
+    /**
+     * Run the decoder
+     */
+    public synchronized boolean decode(String argv[]) {
+//      int flags = F_WARNINGS;
+        long tm = System.currentTimeMillis();
+        ArrayList<String> vargs = new ArrayList<>();
+        ArrayList<String> vj = new ArrayList<>();
+        boolean nowrite = false;
+        int addOptions = 0;
+
+        // Parse arguments
+        for (int i = 0; i < argv.length; i++) {
+            String arg = argv[i];
+            if (arg.equals("-g")) {
+                printDetails = true;
+                vargs.add(arg);
+            } else if (arg.equals("-v")) {
+                DebugFlag = true;
+                vargs.add(arg);
+                out.println("arg[" + i + "]=" + argv[i] + "/verbose");
+            } else if (arg.equals("-version")) {
+                out.println(ProductInfo.FULL_VERSION);
+            } else if (arg.startsWith("-")) {
+//out.println("arg["+i+"]="+argv[i]+"/invalid flag");
+                error(i18n.getString("jcdec.error.invalid_flag", arg));
+                usage();
+                return false;
+            } else {
+                vargs.add(arg);
+                vj.add(arg);
+            }
+        }
+
+        if (vj.isEmpty()) {
+            usage();
+            return false;
+        }
+
+//        String[] names = new String[vj.size()];
+//        vj.copyInto(names);
+        String[] names = null;
+        names = vj.toArray(names);
+decode:
+        for (int k = 0; k < names.length; k++) {
+            String inpname = names[k];
+            try {
+                if (inpname.endsWith(".cap")) {
+                    String shortName = inpname.substring(0, inpname.length() - 4);
+                    if (shortName.endsWith("Header")) {
+                        decodeHeader(inpname);
+                    } else if (shortName.endsWith("Directory")) {
+                        decodeDirectory(inpname);
+                    } else if (shortName.endsWith("Applet")) {
+                        decodeApplet(inpname);
+                    } else if (shortName.endsWith("Import")) {
+                        decodeImport(inpname);
+                    } else if (shortName.endsWith("ConstantPool")) {
+                        decodeConstantPool(inpname);
+                    } else if (shortName.endsWith("Class")) {
+                        decodeClass(inpname);
+                    } else if (shortName.endsWith("Descriptor")) {
+                        decodeDescriptor(inpname);
+                    } else if (shortName.endsWith("Method")) {
+                        decodeMethod(inpname);
+                    } else if (shortName.endsWith("StaticField")) {
+                        decodeStaticField(inpname);
+                    } else if (shortName.endsWith("RefLocation")) {
+                        decodeRefLocation(inpname);
+                    } else if (shortName.endsWith("Export")) {
+                        decodeExport(inpname);
+                    } else {
+                        continue decode;
+                    }
+                    out.println("");
+                } else if (inpname.endsWith(".exp")) {
+                    decodeExp(inpname);
+                    out.println("");
+                }
+                continue decode;
+            } catch (FileNotFoundException ee) {
+                error(i18n.getString("jcdec.error.cannot_read", inpname));
+            } catch (Error ee) {
+                ee.printStackTrace();
+                error(i18n.getString("jcdec.error.fatal_error"));
+            } catch (Exception ee) {
+                ee.printStackTrace();
+                error(i18n.getString("jcdec.error.fatal_exception"));
+            }
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Main program
+     */
+    public static void main(String argv[]) {
+        Main decoder = new Main(new PrintWriter(new uEscWriter(System.out)), "jcdec");
+        System.exit(decoder.decode(argv) ? 0 : 1);
+    }
+}
