<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">import java.io.*;  // for PushbackInputStream, FileInputStream, EOFException

/**
 * &lt;P&gt;
 * Disasm.java: Convert binary files to 80*86 assembler. Version 1.00
 * &lt;P&gt;
 * License:
 * &lt;P&gt;
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation.
 * &lt;P&gt;
 * This program 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 for more details.
 * &lt;P&gt;
 * Finally, if you use this code in an application, then please acknowledge
 * DJ Delorie, Kent Williams and myself, in that order, as the original
 * authors, in your documentation.  There is at least one shareware package
 * out there which uses this code without acknowledgement (you know who you
 * are, David)
 * &lt;P&gt;
 * Comments:
 * &lt;P&gt;
 * The code was originally snaffled from the GNU C++ debugger, as ported
 * to DOS by DJ Delorie and Kent Williams (williams@herky.cs.uiowa.edu).
 * Extensively modified by Robin Hilliard in Jan and May 1992 and
  * various minor bug fixes up to and including November 1995.
 * &lt;P&gt;
 * The disassembler is entirely
 * table driven so it's fairly easy to change to suit your own tastes.
 * &lt;P&gt;
 * The instruction table has been modified to correspond with that in
 * `Programmer's Technical Reference: The Processor and Coprocessor',
 * Robert L. Hummel, Ziff-Davis Press, 1992.  Missing (read "undocumented")
 * instructions were added and many mistakes and omissions corrected.
 * &lt;P&gt;
 * The emulated coprocessor instructions on interrupts 34--3E are disassembled
 * if the "-e" command line option is specified.  I don't deal with segment
 * overrides to emulated '87 instructions, read Hummel if you *really* want to
 * know all the gory details (you don't.).  The Borland defined shortcuts on
 * int 3E are not disassembled either (they're not real instructions anyway!)
 * &lt;P&gt;
 * Command line switches (case sensitive):
 * &lt;P&gt;
 * -e :  Disassemble (unoverridden) emulated 80*87 instructions (not default)
 * &lt;P&gt;
 * -3 :  Assume code is 32 bit (default==16)
 * &lt;P&gt;
 * -x :  Output all numbers in pure hex (no leading zeros or trailing "h"s.)
 * &lt;P&gt;
 * -s :  Don't specify operand size (ie omit "byte ptr", "word ptr" and
 * "dword ptr" from instruction output.
 * &lt;P&gt;
 * -d :  Don't specify distance of calls and jumps (near/far/short)
 * (not default)
 * &lt;P&gt;
 * Health warning:
 * &lt;P&gt;
 * When writing and degbugging this code, I didn't have
 * a 32-bit disassembler to compare this guy's output with.  It's therefore
 * quite likely that bugs will appear when disassembling instructions which use
 * the 386 and 486's native 32 bit mode.  It seems to work fine in 16 bit mode.
 * &lt;P&gt;
 * Any comments/updates/bug reports to:
 * &lt;P&gt;
 * Robin Hilliard, Lough Guitane, Killarney, Co. Kerry, Ireland.
 * Tel:         [+353] 64-54014
 * Internet: robin@flapjack.ieunet.ie
 * Compu$erve:  100042, 1237
 * &lt;P&gt;
 * If you feel like registering, and possibly get notices of updates and
 * other items of software, then send me a post card of your home town.
 * &lt;P&gt;
 * Thanks and enjoy!
 * &lt;P&gt;
 * Java port George Ruban, gruban@geocities.com, 3/25/97
 * http://www.geocities.com/SiliconValley/Vista/2013
 * 
 */
public class Disasm
{
  /* variables controlled by command line flags */
  int  seg_size=16;   /* default size is 16 */
  boolean do_hex = false;    // default is to use reassemblable instructions
  boolean do_distance = true; // default is to use reassemblable instructions
  boolean do_emul87 = false; /* don't try to disassemble emulated instructions*/
  boolean do_size = true;   /* default to outputting explicit operand size */
  boolean must_do_size;  /* used with do_size */

  boolean wordop;        /* dealing with word or byte operand */
  PushbackInputStream infile;         /* input stream */
  int instruction_length;
  int instruction_offset;
  boolean done_space;    /* for opcodes with &gt; one space */
  boolean patch87;       /* fudge variable used in 8087 emu patching code */

  StringBuffer ubuf = new StringBuffer(50);
  int col;               /* output column */
  char prefix;           /* segment override prefix byte */
  int modrmv;            /* flag for getting modrm byte */
  int sibv;              /* flag for getting sib byte   */
  int opsize;            /* just like it says ...       */
  int addrsize;

/* some defines for extracting instruction bit fields from bytes */

  byte MOD(byte a) { return  (byte)((a&gt;&gt;&gt;6)&amp;3); }
  byte REG(byte a)   { return (byte)((a&gt;&gt;&gt;3)&amp;7); }
  byte RM(byte a)   { return (byte)(a&amp;7); }
  byte SCALE(byte a)    { return (byte)((a&gt;&gt;&gt;6)&amp;3);  }
  byte INDEX(byte a)    { return (byte)((a&gt;&gt;&gt;3)&amp;7);  }
  byte BASE(byte a)     { return (byte)(a&amp;7);  }
 
  /** Constructor, dissassembling a file specified by a filename. 
   * The only other public method need be unassemble, 
   * which will be made to return an instruction. */
  public Disasm(String infilename) throws FileNotFoundException
  {
   infile = new PushbackInputStream( new FileInputStream(infilename) );
 }

  /** Not static because depends on do_hex */
  String addr_to_hex(int addr, boolean splitup)
  {
    String buffer;
    int offset = addr &amp; 0xFFFF;
    int segment = (addr &gt;&gt;&gt; 16) &amp; 0xFFFF;

    if (splitup) {
      if (segment==0 || segment==0xffff) /* 'coz of wraparound */
        buffer = hexString(offset, 4, do_hex);
      else
        buffer = hexString(segment, 4, do_hex) + ":" +
                 hexString(offset, 4, do_hex);
    } else {
      if (segment==0 || segment==0xffff) /* 'coz of wraparound */
        buffer = hexString(offset, 4, do_hex);
      else
        buffer = hexString(addr, 8, do_hex);
    }
    return buffer;
  }

  /** Prints a hex number with a minimum field width.
    * @param do_hex true to stick an 'h' on the end. */
  public static String hexString(int val, int width, boolean doHex)
  {
    StringBuffer buf = new StringBuffer(width + 1);
    buf.append(Integer.toString(val, 16));
    while(buf.length() &lt; width) buf.insert(0, '0');
    if(doHex) buf.append('h');
    return buf.toString();
  }

  /** @exception EOFException on end of file */
  byte getbyte() throws IOException
  {
    int c;
    
    c = infile.read();
    if (c==-1)
      throw new EOFException(); // instead of longjmp
    System.out.print(hexString(c, 2, false));  /* print out byte */
    col += 2;
    if (patch87) {
      c -= 0x5C;     /* fixup second byte in emulated '87 instruction */
      patch87 = false;
    }
    instruction_length++;
    instruction_offset++;
    return (byte)c;
  }

  /* used for lookahead */
  byte silent_getbyte() throws IOException
  {
    return (byte)infile.read();
  }

  /* return byte to input stream */
  void silent_returnbyte(byte c) throws IOException
  {
    infile.unread(c);
  }

  /*
     only one modrm or sib byte per instruction, tho' they need to be
     returned a few times...
  */
  byte modrm() throws IOException
  {
    if (modrmv == -1)
      modrmv = (int) getbyte() &amp; 0xFF;
    return (byte) modrmv;
  }


  byte sib() throws IOException
  {
    if (sibv == -1)
      sibv = (int) getbyte()&amp; 0xFF;
    return (byte) sibv;
  }

  void uputchar(char c)
  {
    if (c == '\t') {
      if (done_space) {      /* don't tab out if already done so */
        uputchar(' ');
      } else {
        done_space = true;
        do {
          ubuf.append(' ');
        } while ((ubuf.length() % 8) != 0);
      }
    } else
      ubuf.append(c);
  }

  /*------------------------------------------------------------------------*/
  /** Returns number of bytes represented by a letter code. 
    * Not static because depends on opsize. */
  int bytes(char c)
  {
    switch (c) {
    case 'b':
      return 1;
    case 'w':
      return 2;
    case 'd':
      return 4;
    case 'v':
      return opsize / 8; // number of bytes in an int    
    default:
      throw new InternalError("Unexpected char " + c);
    }
}
  
  
  /*----------------------------------------------------------------------*/
  void outhex(char subtype, int extend, boolean optional, 
              int defsize,  boolean sign) throws IOException
  {
    int n=0;    
    boolean s = false;
    int delta = 0;
    char signchar = '+';
    
    switch (subtype) {
    case 'q':
      if (wordop) {
        n = opsize/8;
      } else {
        n = 1;
      }
      break;
    case 'a':
      break;
    case 'x':
      extend = 2;
      n = 1;
      break;
    case 'b':
      n = 1;
      break;
    case 'w':
      n = 2;
      break;
    case 'd':
      n = 4;
      break;
    case 'c':
    case 'v':
      n = defsize / 8;
      break;
    case 'p':
      n = (defsize / 8) + 2;      
      s = true;
      break;
    case 'z':
      n = 1;
      break;
    default:
      throw new InternalError("Unexpected subtype " + subtype);
    }
    for (int i=0; i&lt;n; i++)
    {
      delta |= ((int)getbyte() &amp; 0xFF) &lt;&lt; (8 * i);
    }
    if (s) {
      ubuf.append(hexString(delta &amp; 0xFF, 2, false));
      delta &gt;&gt;&gt;= 8;
      ubuf.append(hexString(delta &amp; 0xFF, 2, false));
      delta &gt;&gt;&gt;= 8;
      ubuf.append(':');
      n -= 2;
    }

    if (extend &gt; n) {
      if (subtype != 'x') {
        if (delta&lt;0) {
          delta = -delta;
          signchar = '-';
        } else
          signchar = '+';
        if (delta != 0 || !optional){
          ubuf.append(signchar + hexString(delta, extend, do_hex));
        }  
      } else { // (subtype == 'x')
        if (extend==2)
           delta &amp;= 0xFFFF;
        ubuf.append(signchar + hexString(delta, extend, do_hex));
      }
      return;
    } // end if (extend&gt;n)
    if ((n == 4) &amp;&amp; !sign) {
      ubuf.append(addr_to_hex(delta, false));
      return;
    }
    switch (n) {
    case 1:
      if (sign &amp;&amp; (byte)delta&lt;0) {
        delta = -delta;
        signchar = '-';
      } else
        signchar = '+';
      if (sign)
        ubuf.append(signchar);      
      ubuf.append(hexString(delta, n*2, do_hex));      
      break;
      
    case 2:
      if (sign &amp;&amp; (short)delta&lt;0) {
        signchar = '-';
        delta = -delta;
      } else
        signchar = '+';
      if (sign)        
        ubuf.append(signchar);
      ubuf.append(hexString(delta, n*2, do_hex));      
      break;
      
    case 4:
      if (sign &amp;&amp; delta&lt;0) {
        delta = -delta;
        signchar = '-';
      } else
        signchar = '+';
      if (sign)
        ubuf.append(signchar);
      ubuf.append(hexString(delta, n*2, do_hex));      
      break;
    }
  }

/*------------------------------------------------------------------------*/

void reg_name(int regnum, char size)
{
  if (size == 'F') { /* floating point register? */
    ubuf.append("st(" + regnum + ")");
    return;
  }
  if (((size == 'v') &amp;&amp; (opsize == 32)) || (size == 'd'))
    ubuf.append('e');
  if ((size=='q' || size == 'b' || size=='c') &amp;&amp; !wordop) {
    uputchar("acdbacdb".charAt(regnum));
    uputchar("llllhhhh".charAt(regnum));
  } else {
    uputchar("acdbsbsd".charAt(regnum));
    uputchar("xxxxppii".charAt(regnum));
  }
}


/*------------------------------------------------------------------------*/
void do_sib(int m) throws IOException
{
  byte s, i, b;

  s = SCALE(sib());
  i = INDEX(sib());
  b = BASE(sib());
  switch (b) {     /* pick base */
  case 0: ua_str("%p:[eax"); break;
  case 1: ua_str("%p:[ecx"); break;
  case 2: ua_str("%p:[edx"); break;
  case 3: ua_str("%p:[ebx"); break;
  case 4: ua_str("%p:[esp"); break;
  case 5:
       if (m == 0) {
         ua_str("%p:[");
         outhex('d', 4, false, addrsize, false);
       } else {
         ua_str("%p:[ebp");
       }
       break;
  case 6: ua_str("%p:[esi"); break;
  case 7: ua_str("%p:[edi"); break;
  }
  switch (i) {     /* and index */
  case 0: ubuf.append("+eax"); break;
  case 1: ubuf.append("+ecx"); break;
  case 2: ubuf.append("+edx"); break;
  case 3: ubuf.append("+ebx"); break;
  case 4: break;
  case 5: ubuf.append("+ebp"); break;
  case 6: ubuf.append("+esi"); break;
  case 7: ubuf.append("+edi"); break;
  }
  if (i != 4) {
    switch (s) {    /* and scale */
      case 0: ubuf.append(""); break;
      case 1: ubuf.append("*2"); break;
      case 2: ubuf.append("*4"); break;
      case 3: ubuf.append("*8"); break;
    }
  }
}



/*------------------------------------------------------------------------*/
void do_modrm(char subtype) throws IOException
{
  byte mod = MOD(modrm());
  byte rm = RM(modrm());
  int extend = addrsize / 8;

  if (mod == 3) { /* specifies two registers */
    reg_name(rm, subtype);
    return;
  }
  if (must_do_size) {
    if (wordop) {
      if (addrsize==32 || opsize==32) {       /* then must specify size */
        ua_str("dword ptr ");
      } else {
        ua_str("word ptr ");
      }
    } else {
      ua_str("byte ptr ");
    }
  }
  if ((mod == 0) &amp;&amp; (rm == 5) &amp;&amp; (addrsize == 32)) {/* mem operand with 32 bit ofs */
    ua_str("%p:[");
    outhex('d', extend, false, addrsize, false);
    uputchar(']');
    return;
  }
  if ((mod == 0) &amp;&amp; (rm == 6) &amp;&amp; (addrsize == 16)) { /* 16 bit dsplcmnt */
    ua_str("%p:[");
    outhex('w', extend, false, addrsize, false);
    uputchar(']');
    return;
  }
  if ((addrsize != 32) || (rm != 4))
    ua_str("%p:[");
  if (addrsize == 16) {
    switch (rm) {
    case 0: ubuf.append("bx+si"); break;
    case 1: ubuf.append("bx+di"); break;
    case 2: ubuf.append("bp+si"); break;
    case 3: ubuf.append("bp+di"); break;
    case 4: ubuf.append("si"); break;
    case 5: ubuf.append("di"); break;
    case 6: ubuf.append("bp"); break;
    case 7: ubuf.append("bx"); break;
    }
  } else {
    switch (rm) {
    case 0: ubuf.append("eax"); break;
    case 1: ubuf.append("ecx"); break;
    case 2: ubuf.append("edx"); break;
    case 3: ubuf.append("ebx"); break;
    case 4: do_sib(mod); break;
    case 5: ubuf.append("ebp"); break;
    case 6: ubuf.append("esi"); break;
    case 7: ubuf.append("edi"); break;
    }
  }
  switch (mod) {
  case 1:
       outhex('b', extend, true, addrsize, false);
       break;
  case 2:
       outhex('v', extend, true, addrsize, true);
       break;
  }
  uputchar(']');
}



/*------------------------------------------------------------------------*/
void floating_point(int e1) throws IOException
{
  int esc = e1*8 + REG(modrm());

  if (MOD(modrm()) == 3) {
    if (fspecial[esc] != null) {
      if (fspecial[esc][0].charAt(0) == '*') {
        ua_str(fspecial[esc][0].substring(1));
      } else {
        ua_str(fspecial[esc][RM(modrm())]);
      }
    } else {
      ua_str(floatops[esc]);
      ua_str(" %EF");
    }
  } else {
    ua_str(floatops[esc]);
    ua_str(" %EF");
  }
}




/*------------------------------------------------------------------------*/
/* Main table driver                                                      */
void percent(char type, char subtype) throws IOException
{
  int vofs;
  int extend = addrsize / 16;
  byte i; // one read byte

start:
  switch (type) {
  case 'A':                          /* direct address */
       outhex(subtype, extend, false, addrsize, false);
       break;

  case 'C':                          /* reg(r/m) picks control reg */
       ubuf.append("C" + REG(modrm()));
       must_do_size = false;
       break;

  case 'D':                          /* reg(r/m) picks debug reg */
       ubuf.append("D" + REG(modrm()));
       must_do_size = false;
       break;

  case 'E':                          /* r/m picks operand */
       do_modrm(subtype);
       break;

  case 'G':                          /* reg(r/m) picks register */
       if (subtype == 'F')                 /* 80*87 operand?   */
         reg_name(RM(modrm()), subtype);
       else
         reg_name(REG(modrm()), subtype);
       must_do_size = false;
       break;

  case 'I':                            /* immed data */
       outhex(subtype, 0, false, opsize, false);
       break;

  case 'J':                            /* relative IP offset */
       switch(bytes(subtype)) {              /* sizeof offset value */
       case 1:
            vofs = getbyte();   // signed!
            break;
       case 2:
            vofs = (int)getbyte() &amp; 0xFF;
            vofs |= ((int)getbyte() &amp; 0xFF) &lt;&lt; 8;
            vofs = (short)vofs; // signed!
            break;
       case 4:
            vofs = ((int)getbyte() &amp; 0xFF); /* yuk! */
            vofs |= ((int)getbyte() &amp; 0xFF) &lt;&lt; 8;
            vofs |= ((int)getbyte() &amp; 0xFF) &lt;&lt; 16;
            vofs |= ((int)getbyte() &amp; 0xFF) &lt;&lt; 24;
            break;
	default:
		throw new InternalError("type "+ type + 
                                    " unexpected bytes(subtype)");
       }
       ubuf.append(addr_to_hex(vofs+instruction_offset, true));
       break;

  case 'K':
       if (!do_distance)
         break;
       switch (subtype) {
       case 'f':
            ua_str("far ");
            break;
       case 'n':
            ua_str("near ");
            break;
       case 's':
            ua_str("short ");
            break;
       default:
            throw new InternalError("type "+ type + 
                                    " unexpected subtype " + subtype);
       }
       break;

  case 'M':                            /* r/m picks memory */
       do_modrm(subtype);
       break;

  case 'O':                            /* offset only */
       ua_str("%p:[");
       outhex(subtype, extend, false, addrsize, false);
       uputchar(']');
       break;

  case 'P':                            /* prefix byte (rh) */
       ua_str("%p:");
       break;

  case 'R':                            /* mod(r/m) picks register */
       reg_name(REG(modrm()), subtype);      /* rh */
       must_do_size = false;
       break;

  case 'S':                            /* reg(r/m) picks segment reg */
       uputchar("ecsdfg".charAt( REG(modrm()) ) );
       uputchar('s');
       must_do_size = false;
       break;

  case 'T':                            /* reg(r/m) picks T reg */
       ubuf.append("tr" + REG(modrm()));
       must_do_size = false;
       break;

  case 'X':                            /* ds:si type operator */
       ubuf.append("ds:[");
       if (addrsize == 32)
         uputchar('e');
       ubuf.append("si]");
       break;

  case 'Y':                            /* es:di type operator */
       ubuf.append("es:[");
       if (addrsize == 32)
         uputchar('e');
       ubuf.append("di]");
       break;

  case '2':                            /* old [pop cs]! now indexes */
       ua_str(second[getbyte()]);      /* instructions in 386/486   */
       break;

  case 'g':                            /* modrm group `subtype' (0--7) */
       ua_str(groups[subtype-'0'][REG(modrm())]);
       break;

  case 'd':                             /* sizeof operand==dword? */
       if (opsize == 32)
         uputchar('d');
       uputchar(subtype);
       break;

  case 'w':                             /* insert explicit size specifier */
       if (opsize == 32)
         uputchar('d');
       else
         uputchar('w');
       uputchar(subtype);
       break;

  case 'e':                         /* extended reg name */
       if (opsize == 32) {
         if (subtype == 'w')
           uputchar('d');
         else {
           uputchar('e');
           uputchar(subtype);
         }
       } else
         uputchar(subtype);
       break;

  case 'f':                    /* '87 opcode */
       floating_point(subtype-'0');
       break;

  case 'j':
       if (addrsize==32 || opsize==32) /* both of them?! */
         uputchar('e');
       break;

  case 'p':                    /* prefix byte */
       switch (subtype)  {
       case 'c':
       case 'd':
       case 'e':
       case 'f':
       case 'g':
       case 's':
            prefix = subtype;
            i = getbyte();
            wordop = (i &amp; 1) == 1;
            ua_str(opmap1[(int)i &amp; 0xFF]);
            break;
       case ':':
            if (prefix != 0)
              ubuf.append(prefix + "s:");
            break;
       case ' ':
            i = getbyte();
            wordop = (i &amp; 1) == 1;
            ua_str(opmap1[(int)i &amp; 0xFF]);
            break;
       default:
           throw new InternalError("type "+ type + 
                                    " unexpected subtype " + subtype);
       }
       break;

  case 's':                           /* size override */
       switch (subtype) {
       case 'a':
            addrsize = 48 - addrsize;
            i = getbyte();
            wordop = (i &amp; 1) == 1;
            ua_str(opmap1[(int)i &amp; 0xFF]);
            break;
       case 'o':
            opsize = 48 - opsize;
            i = getbyte();
            wordop = (i &amp; 1) == 1;
            ua_str(opmap1[(int)i &amp; 0xFF]);
            break;
       default:
           throw new InternalError("type " + type + 
                                    " unexpected subtype " + subtype);
       }
       break;
    default:
       throw new InternalError("unexpected type " + type);
   }
}


/** printf-style string printing */
void ua_str(String str) throws IOException
{
  char c;
  int i;

  if (str == null) {
    ubuf.append("&lt;invalid&gt;");
    return;
  }
  if (strpbrk(str, "CDFGRST") &gt;= 0) /* specifiers for registers=&gt;no size 2b specified */
    must_do_size = false;
  for(i = 0; i &lt; str.length() ; ++i){
    c = str.charAt(i);
    if (c == '%') {
      c = str.charAt(++i);
      percent(c, str.charAt(++i));
    } else if (c == ' ') {
      uputchar('\t');
    } else {
      uputchar(c);
    }
  }
}

/** Like the strpbrk from C - returns the index of first character from
 * ct in cs, -1 if not found. */
static int strpbrk(String cs, String ct)
{
  for(int i=0; i&lt;cs.length(); ++i){
    if(ct.indexOf(cs.charAt(i)) &gt;= 0) return i;
  }
  return -1;
}

/** Unassembles a single instruction starting
 * at ofs in file. 
 * @returns the length of the instruction */
public int unassemble(int ofs) throws IOException
{
  String str;
  byte    c, c2;

  instruction_offset = ofs;
  System.out.print(hexString(ofs, 4, false) + ' ');
  prefix = (char) 0;
  modrmv = sibv = -1;     /* set modrm and sib flags */
  opsize = addrsize = seg_size;
  col = 0;
  ubuf.setLength(0); // flush the ubuf
  done_space = false;
  instruction_length = 0;
  c = getbyte();
  wordop = (c &amp; 1) == 1;
  patch87 = false;
  must_do_size = do_size;
  if (do_emul87) {
    if (c==0xCD) { /* wanna do emu '87 and -&gt;ing to int? */
      c2 = silent_getbyte();
      if (((int)c2 &amp; 0xFF) &gt;= 0x34 &amp;&amp; ((int)c2 &amp; 0xFF) &lt;= 0x3E)
        patch87 = true;   /* emulated instruction!  =&gt; must repatch two bytes */
      silent_returnbyte(c2);
      c -= 0x32;
    }
  }
  if ((str = opmap1[(int)c &amp; 0xFF]) == null) {    /* invalid instruction? */
    uputchar('d');                    /* then output byte defines */
    uputchar('b');
    uputchar('\t');
    ubuf.append(hexString((int)c &amp; 0xFF, 2, do_hex));
  } else {
    ua_str(str);                      /* valid instruction */
  }
  for(int i=col; i&lt;15; ++i) 
    System.out.print(' '); 
  col = 15 + ubuf.length();
  do {
    uputchar(' ');
    col++;
  } while (col &lt; 43);
  System.out.println(ubuf);
  return instruction_length;
}

static boolean isoption(char c)
{
  return (c=='/' || c=='-');
}

/** prints usage information, exits. */
static void help()
{
  System.err.println(
      "2ASM  Version 1.01  (C) Copyright 1992, Robin Hilliard\n" +
      "Converts binary files to 80*86 assembly\n" +
      "Usage:\n" +
      "\t2asm &lt;file&gt; [-e] [-3] [-x] [-s] [-d]\n" +
      "Switches:\n" +
      "\t-e :\tDisassemble (unoverridden) emulated 80*87 instructions\n" +
      "\t-3 :\tAssume code is 32 bit (default==16)\n" +
      "\t-x :\tOutput numbers in pure hex (default is reassemblable)\n" +
      "\t-s :\tDon't specify operand size, even where necessary\n" +
      "\t-d :\tDon't specify distance short/near/far jmps and calls"
      );
  System.exit(1);
}

/** Test driver - disassembles a file. */
public static void main(String args[]) 
  throws FileNotFoundException, IOException
{
  int instr_len;
  int offset;
  String infilename = null;
  char c;

  int  seg_size=16;   /* default size is 16 */
  boolean do_hex = false;    // default is to use reassemblable instructions
  boolean do_distance = true; // default is to use reassemblable instructions
  boolean do_emul87 = false; /* don't try to disassemble emulated instrcutions */
  boolean do_size = true;   /* default to outputting explicit operand size */

  for(int i=0; i&lt;args.length; ++i)
  {
    int j = 0; // args[i].charAt(j) = **argv
    if (args[i].charAt(j)=='?') help(); // never returns;
    if (isoption(args[i].charAt(j))) {
      while (isoption( args[i].charAt(j) )) {
nextflag:
        switch (c = args[i].charAt(++j) ){
        case 'e':
             do_emul87 = true;
             break;
        case '3':
             seg_size = 32;
             break;
        case 'x':
             do_hex = true;
             break;
        case 's':
             do_size = false;
             break;
        case 'd':
             do_distance = false;
             break;
        case '?':
        case 'H':
             help(); // never returns
        default:
             System.err.println("Unknown option: `" + c + "'");
             help(); // never returns
        }
        ++j;
      }
    } else { /* assume that its a file name */
      if (infilename != null) {
        System.err.println("Second filename argument: \"" + args[i] +'\"');
        System.exit(1);
      }
      infilename = args[i];
    }
  }
  Disasm d = new Disasm(infilename); 
  d.seg_size=seg_size;
  d.do_hex = do_hex;
  d.do_distance = do_distance; 
  d.do_emul87 = do_emul87;
  d.do_size = do_size;  

  offset = 0;
  if(infilename.toLowerCase().endsWith(".com")) /* not perfect, fix later */
    offset = 0x100;
  try {
    do {
      instr_len = d.unassemble(offset);
      offset += instr_len;
    } while (instr_len != 0); /* whoops, no files &gt; 64k */
  } catch (IOException e)
  { 
    if(!(e instanceof EOFException))
    {
       throw e;
    }
  }
}

/** Percent tokens in strings:
   First char after '%':
  A - direct address
  C - reg of r/m picks control register
  D - reg of r/m picks debug register
  E - r/m picks operand
  F - flags register
  G - reg of r/m picks general register
  I - immediate data
  J - relative IP offset
+       K - call/jmp distance
  M - r/m picks memory
  O - no r/m, offset only
  R - mod of r/m picks register only
  S - reg of r/m picks segment register
  T - reg of r/m picks test register
  X - DS:ESI
  Y - ES:EDI
  2 - prefix of two-byte opcode
+       e - put in 'e' if use32 (second char is part of reg name)
+           put in 'w' for use16 or 'd' for use32 (second char is 'w')
+       j - put in 'e' in jcxz if prefix==0x66
  f - floating point (second char is esc value)
  g - do r/m group 'n', n==0..7
  p - prefix
  s - size override (second char is a,o)
+       d - put d if double arg, nothing otherwise (pushfd, popfd &amp;c)
+       w - put w if word, d if double arg, nothing otherwise (lodsw/lodsd)
+       P - simple prefix

   Second char after '%':
  a - two words in memory (BOUND)
  b - byte
  c - byte or word
  d - dword
+       f - far call/jmp
+       n - near call/jmp
        p - 32 or 48 bit pointer
+       q - byte/word thingy
  s - six byte pseudo-descriptor
  v - word or dword
        w - word
+       x - sign extended byte
  F - use floating regs in mod/rm
  1-8 - group number, esc value, etc
*/

/* watch out for aad &amp;&amp; aam with odd operands */

String opmap1[] = {
/* 0 */
  "add %Eb,%Gb",      "add %Ev,%Gv",     "add %Gb,%Eb",    "add %Gv,%Ev",
  "add al,%Ib",       "add %eax,%Iv",    "push es",        "pop es",
  "or %Eb,%Gb",       "or %Ev,%Gv",      "or %Gb,%Eb",     "or %Gv,%Ev",
  "or al,%Ib",        "or %eax,%Iv",     "push cs",        "%2 ",
/* 1 */
  "adc %Eb,%Gb",      "adc %Ev,%Gv",     "adc %Gb,%Eb",    "adc %Gv,%Ev",
  "adc al,%Ib",       "adc %eax,%Iv",    "push ss",        "pop ss",
  "sbb %Eb,%Gb",      "sbb %Ev,%Gv",     "sbb %Gb,%Eb",    "sbb %Gv,%Ev",
  "sbb al,%Ib",       "sbb %eax,%Iv",    "push ds",        "pop ds",
/* 2 */
  "and %Eb,%Gb",      "and %Ev,%Gv",     "and %Gb,%Eb",    "and %Gv,%Ev",
  "and al,%Ib",       "and %eax,%Iv",    "%pe",            "daa",
  "sub %Eb,%Gb",      "sub %Ev,%Gv",     "sub %Gb,%Eb",    "sub %Gv,%Ev",
  "sub al,%Ib",       "sub %eax,%Iv",    "%pc",            "das",
/* 3 */
  "xor %Eb,%Gb",      "xor %Ev,%Gv",     "xor %Gb,%Eb",    "xor %Gv,%Ev",
  "xor al,%Ib",       "xor %eax,%Iv",    "%ps",            "aaa",
  "cmp %Eb,%Gb",      "cmp %Ev,%Gv",     "cmp %Gb,%Eb",    "cmp %Gv,%Ev",
  "cmp al,%Ib",       "cmp %eax,%Iv",    "%pd",            "aas",
/* 4 */
  "inc %eax",         "inc %ecx",        "inc %edx",       "inc %ebx",
  "inc %esp",         "inc %ebp",        "inc %esi",       "inc %edi",
  "dec %eax",         "dec %ecx",        "dec %edx",       "dec %ebx",
  "dec %esp",         "dec %ebp",        "dec %esi",       "dec %edi",
/* 5 */
  "push %eax",        "push %ecx",       "push %edx",      "push %ebx",
  "push %esp",        "push %ebp",       "push %esi",      "push %edi",
  "pop %eax",         "pop %ecx",        "pop %edx",       "pop %ebx",
  "pop %esp",         "pop %ebp",        "pop %esi",       "pop %edi",
/* 6 */
  "pusha%d ",         "popa%d ",         "bound %Gv,%Ma",  "arpl %Ew,%Rw",
  "%pf",              "%pg",             "%so",            "%sa",
  "push %Iv",         "imul %Gv,%Ev,%Iv","push %Ix",       "imul %Gv,%Ev,%Ib",
  "insb",             "ins%ew",          "outsb",          "outs%ew",
/* 7 */
  "jo %Jb",           "jno %Jb",         "jc %Jb",         "jnc %Jb",
  "je %Jb",           "jne %Jb",         "jbe %Jb",        "ja %Jb",
  "js %Jb",           "jns %Jb",         "jpe %Jb",        "jpo %Jb",
  "jl %Jb",           "jge %Jb",         "jle %Jb",        "jg %Jb",
/* 8 */
  "%g0 %Eb,%Ib",      "%g0 %Ev,%Iv",     "%g0 %Ev,%Ix",    "%g0 %Ev,%Ix",
  "test %Eb,%Gb",     "test %Ev,%Gv",    "xchg %Eb,%Gb",   "xchg %Ev,%Gv",
  "mov %Eb,%Gb",      "mov %Ev,%Gv",     "mov %Gb,%Eb",    "mov %Gv,%Ev",
  "mov %Ew,%Sw",      "lea %Gv,%M ",     "mov %Sw,%Ew",    "pop %Ev",
/* 9 */
  "nop",              "xchg %ecx,%eax",  "xchg %edx,%eax", "xchg %ebx,%eax",
  "xchg %esp,%eax",   "xchg %ebp,%eax",  "xchg %esi,%eax", "xchg %edi,%eax",
  "cbw",              "cwd",             "call %Ap",       "fwait",
  "pushf%d ",         "popf%d ",         "sahf",           "lahf",
/* a */
  "mov al,%Oc",       "mov %eax,%Ov",    "mov %Oc,al",     "mov %Ov,%eax",
  "%P movsb",         "%P movs%w ",       "%P cmpsb",       "%P cmps%w ",
  "test al,%Ib",      "test %eax,%Iv",   "%P stosb",       "%P stos%w ",
  "%P lodsb",         "%P lods%w ",      "%P scasb",       "%P scas%w ",
/* b */
  "mov al,%Ib",       "mov cl,%Ib",      "mov dl,%Ib",     "mov bl,%Ib",
  "mov ah,%Ib",       "mov ch,%Ib",      "mov dh,%Ib",     "mov bh,%Ib",
  "mov %eax,%Iv",     "mov %ecx,%Iv",    "mov %edx,%Iv",   "mov %ebx,%Iv",
  "mov %esp,%Iv",     "mov %ebp,%Iv",    "mov %esi,%Iv",   "mov %edi,%Iv",
/* c */
  "%g1 %Eb,%Ib",      "%g1 %Ev,%Ib",     "ret %Iw",        "ret",
  "les %Gv,%Mp",      "lds %Gv,%Mp",     "mov %Eb,%Ib",    "mov %Ev,%Iv",
  "enter %Iw,%Ib",    "leave",           "retf %Iw",       "retf",
  "int 03",           "int %Ib",         "into",           "iret%d ",
/* d */
  "%g1 %Eb,1",        "%g1 %Ev,1",       "%g1 %Eb,cl",     "%g1 %Ev,cl",
  "aam ; %Ib",        "aad ; %Ib",       "setalc",         "xlat",
  "%f0",              "%f1",             "%f2",            "%f3",
  "%f4",              "%f5",             "%f6",            "%f7",
/* e */
  "loopne %Jb",       "loope %Jb",       "loop %Jb",       "j%j cxz %Jb",
  "in al,%Ib",        "in %eax,%Ib",     "out %Ib,al",     "out %Ib,%eax",
  "call %Jv",         "jmp %Jv",         "jmp %Ap",        "jmp %Ks%Jb",
  "in al,dx",         "in %eax,dx",      "out dx,al",      "out dx,%eax",
/* f */
  "lock %p ",         null,              "repne %p ",      "repe %p ",
  "hlt",              "cmc",             "%g2",            "%g2",
  "clc",              "stc",             "cli",            "sti",
  "cld",              "std",             "%g3",            "%g4"
};


String second[] = {
/* 0 */
  "%g5",              "%g6",             "lar %Gv,%Ew",    "lsl %Gv,%Ew",
  null,               "loadall",         "clts",           "loadall",
  "invd",             "wbinvd",          null,              null,
  null,               null,              null,              null,
/* 1 */
  "mov %Eb,%Gb",      "mov %Ev,%Gv",     "mov %Gb,%Eb",    "mov %Gv,%Ev",
  null,               null,              null,             null,
  null,               null,              null,             null,
  null,               null,              null,             null,
/* 2 */
  "mov eax,%Cd",      "mov eax,%Dd",     "mov %Cd,eax",    "mov %Dd,eax",
  "mov %Rd,%Td",      null,              "mov %Td,%Rd",    null,
  null,               null,              null,             null,
  null,               null,              null,             null,
/* 3 */
  "wrmsr",            "rdtsc",           "rdmsr",          null, 
  null, null, null, null,
  null, null, null, null, 
  null, null, null, null,
/* 4 */
  null, null, null, null, null, null, null, null,
  null, null, null, null, null, null, null, null,
/* 5 */
  null, null, null, null, null, null, null, null,
  null, null, null, null, null, null, null, null,
/* 6 */
  null, null, null, null, null, null, null, null,
  null, null, null, null, null, null, null, null,
/* 7 */
  null, null, null, null, null, null, null, null,
  null, null, null, null, null, null, null, null,
/* 8 */
  "jo %Jv",           "jno %Jv",         "jb %Jv",         "jnb %Jv",
  "jz %Jv",           "jnz %Jv",         "jbe %Jv",        "ja %Jv",
  "js %Jv",           "jns %Jv",         "jp %Jv",         "jnp %Jv",
  "jl %Jv",           "jge %Jv",         "jle %Jv",        "jg %Jv",
/* 9 */
  "seto %Eb",         "setno %Eb",       "setc %Eb",       "setnc %Eb",
  "setz %Eb",         "setnz %Eb",       "setbe %Eb",      "setnbe %Eb",
  "sets %Eb",         "setns %Eb",       "setp %Eb",       "setnp %Eb",
  "setl %Eb",         "setge %Eb",       "setle %Eb",      "setg %Eb",
/* a */
  "push fs",          "pop fs",          "cpuid",          "bt %Ev,%Gv",
  "shld %Ev,%Gv,%Ib", "shld %Ev,%Gv,cl", null,             null,
  "push gs",          "pop gs",          "rsm",            "bts %Ev,%Gv",
  "shrd %Ev,%Gv,%Ib", "shrd %Ev,%Gv,cl", null,             "imul %Gv,%Ev",
/* b */
  "cmpxchg %Eb,%Gb",  "cmpxchg %Ev,%Gv", "lss %Mp",        "btr %Ev,%Gv",
  "lfs %Mp",          "lgs %Mp",         "movzx %Gv,%Eb",  "movzx %Gv,%Ew",
  null,               null,              "%g7 %Ev,%Ib",    "btc %Ev,%Gv",
  "bsf %Gv,%Ev",      "bsr %Gv,%Ev",     "movsx %Gv,%Eb",  "movsx %Gv,%Ew",
/* c */
  "xadd %Eb,%Gb",     "xadd %Ev,%Gv",    null,             null,
  null,               null,              null,             "cmpxchg8b %Ev",
  "bswap eax",        "bswap ecx",       "bswap edx",      "bswap ebx",
  "bswap esp",        "bswap ebp",       "bswap esi",      "bswap edi",
/* d */
  null, null, null, null, null, null, null, null,
  null, null, null, null, null, null, null, null,
/* e */
  null, null, null, null, null, null, null, null,
  null, null, null, null, null, null, null, null,
/* f */
  null, null, null, null, null, null, null, null,
  null, null, null, null, null, null, null, null,
};


String groups[][] = {   /* group 0 is group 3 for %Ev set */
/* 0 */
  { "add",            "or",              "adc",            "sbb",
    "and",            "sub",             "xor",            "cmp"           },
/* 1 */
  { "rol",            "ror",             "rcl",            "rcr",
    "shl",            "shr",             "shl",            "sar"           },
/* 2 */  /* v   v*/
  { "test %Eq,%Iq",   "test %Eq,%Iq",    "not %Ev",        "neg %Ev",
    "mul %Ec",        "imul %Ec",        "div %Ec",        "idiv %Ec" },
/* 3 */
  { "inc %Eb",        "dec %Eb",         null,             null,
    null,             null,              null,             null            },
/* 4 */
  { "inc %Ev",        "dec %Ev",         "call %Kn%Ev",    "call %Kf%Ep",
    "jmp %Kn%Ev",     "jmp %Kf%Ep",      "push %Ev",       null               },
/* 5 */
  { "sldt %Ew",       "str %Ew",         "lldt %Ew",       "ltr %Ew",
    "verr %Ew",       "verw %Ew",        null,             null               },
/* 6 */
  { "sgdt %Ms",       "sidt %Ms",        "lgdt %Ms",       "lidt %Ms",
    "smsw %Ew",       null,              "lmsw %Ew",       "invlpg %Ev"       },
/* 7 */
  { null,             null,              null,             null,
    "bt",             "bts",             "btr",            "btc"           }
};

/* null here means invalid.  If first entry starts with '*', use st(i) */
/* no assumed %EFs here.  Indexed by RM(modrm())                       */
String f0[]     = { null, null, null, null, null, null, null, null};
String fop_9[]  = { "*fxch st,%GF" };
String fop_10[] = { "fnop", null, null, null, null, null, null, null };
String fop_12[] = { "fchs", "fabs", null, null, "ftst", "fxam", null, null };
String fop_13[] = { "fld1", "fldl2t", "fldl2e", "fldpi",
                   "fldlg2", "fldln2", "fldz", null };
String fop_14[] = { "f2xm1", "fyl2x", "fptan", "fpatan",
                   "fxtract", "fprem1", "fdecstp", "fincstp" };
String fop_15[] = { "fprem", "fyl2xp1", "fsqrt", "fsincos",
                   "frndint", "fscale", "fsin", "fcos" };
String fop_21[] = { null, "fucompp", null, null, null, null, null, null };
String fop_28[] = { null, null, "fclex", "finit", null, null, null, null };
String fop_32[] = { "*fadd %GF,st" };
String fop_33[] = { "*fmul %GF,st" };
String fop_36[] = { "*fsubr %GF,st" };
String fop_37[] = { "*fsub %GF,st" };
String fop_38[] = { "*fdivr %GF,st" };
String fop_39[] = { "*fdiv %GF,st" };
String fop_40[] = { "*ffree %GF" };
String fop_42[] = { "*fst %GF" };
String fop_43[] = { "*fstp %GF" };
String fop_44[] = { "*fucom %GF" };
String fop_45[] = { "*fucomp %GF" };
String fop_48[] = { "*faddp %GF,st" };
String fop_49[] = { "*fmulp %GF,st" };
String fop_51[] = { null, "fcompp", null, null, null, null, null, null };
String fop_52[] = { "*fsubrp %GF,st" };
String fop_53[] = { "*fsubp %GF,st" };
String fop_54[] = { "*fdivrp %GF,st" };
String fop_55[] = { "*fdivp %GF,st" };
String fop_60[] = { "fstsw ax", null, null, null, null, null, null, null };

String fspecial[][] = { 
  /* 0=use st(i), 1=undefined 0 in fop_* means undefined */
  null, null, null, null, null, null, null, null,
  null, fop_9, fop_10, null, fop_12, fop_13, fop_14, fop_15,
  f0, f0, f0, f0, f0, fop_21, f0, f0,
  f0, f0, f0, f0, fop_28, f0, f0, f0,
  fop_32, fop_33, f0, f0, fop_36, fop_37, fop_38, fop_39,
  fop_40, f0, fop_42, fop_43, fop_44, fop_45, f0, f0,
  fop_48, fop_49, f0, fop_51, fop_52, fop_53, fop_54, fop_55,
  f0, f0, f0, f0, fop_60, f0, f0, f0,
};

String floatops[] = { /* assumed " %EF" at end of each.  mod != 3 only */
/*00*/ "fadd", "fmul", "fcom", "fcomp",
       "fsub", "fsubr", "fdiv", "fdivr",
/*08*/ "fld", null, "fst", "fstp",
       "fldenv", "fldcw", "fstenv", "fstcw",
/*16*/ "fiadd", "fimul", "ficomw", "ficompw",
       "fisub", "fisubr", "fidiv", "fidivr",
/*24*/ "fild", null, "fist", "fistp",
       "frstor", "fldt", null, "fstpt",
/*32*/ "faddq", "fmulq", "fcomq", "fcompq",
       "fsubq", "fsubrq", "fdivq", "fdivrq",
/*40*/ "fldq", null, "fstq", "fstpq",
       null, null, "fsave", "fstsw",
/*48*/ "fiaddw", "fimulw", "ficomw", "ficompw",
       "fisubw", "fisubrw", "fidivw", "fidivr",
/*56*/ "fildw", null, "fistw", "fistpw",
       "fbldt", "fildq", "fbstpt", "fistpq"
};
}
</pre></body></html>