import java.io.*;
import java.util.*;
import java.text.*;

/***************************************************************************

    Dump -- Write a Hex Dump of a File to Stdout

    Invoking this application from the command line without parameters
    gives the syntax.

 ***************************************************************************/

    class Dump
      {
      byte[] abOne;
      long lOffset;
      long iLength;
      String sAscii;
      String sMargin;
      InputStream isData;
      int iByteInLine;
      int iByteInCluster;
      int iLinesInCluster;
      boolean bRunningOnAsciiSystem;


      Dump ()
        {
        Properties prSystem;
        Object oPlatformNotAscii;

        abOne = new byte[1];
        sAscii = "";
        iByteInLine = 0;
        iByteInCluster = 0;
        iLinesInCluster = 0;

        bRunningOnAsciiSystem = true;
        prSystem = System.getProperties ();
        oPlatformNotAscii = prSystem.getProperty ("platform.notASCII");
        if ((oPlatformNotAscii != null) && oPlatformNotAscii.equals ("true"))
          {
          bRunningOnAsciiSystem = false;
          }
        }


      Dump (byte[] abIn)
        {
        this (new ByteArrayInputStream (abIn), "    ");
        }


      Dump (InputStream is, String sMarginIn)
        {
        this (is, Integer.MAX_VALUE, sMarginIn);
        }


      Dump (InputStream is, int iLengthIn, String sMarginIn)
        {
        this ();
        isData = is;
        iLength = iLengthIn;
        sMargin = sMarginIn;
        }


      public void dump (OutputStream osIn)
        {
        int i;
        int iByte;
        StringBuffer sb;

        if (iLength <= 0) return;
        try
          {
          i = 0;
          lOffset = -1;
          sb = new StringBuffer ();
          newLine (sb, true);

          while ((iByte = isData.read ()) != -1)
            {
            lOffset++;
            if (lOffset % 4096 == 0)
              {
              osIn.write (sb.toString().getBytes ());
              sb = new StringBuffer ();
              }
            byteOut (sb, iByte);
            if (++i >= iLength) break;
            }

          lastLine (sb);
          sb.append ("\n");
          osIn.write (sb.toString().getBytes ());
          }
        catch (Exception e)
          {
          System.out.println ("dump(): " + e);
          }
        }


      public String toString ()
        {
        int i;
        int iByte;
        StringBuffer sb;

        if (iLength <= 0) return ("\n");
        try
          {
          i = 0;
          lOffset = -1;
          sb = new StringBuffer ();
          newLine (sb, true);

          while ((iByte = isData.read ()) != -1)
            {
            lOffset++;
            byteOut (sb, iByte);
            if (++i >= iLength) break;
            }

          lastLine (sb);
          sb.append ("\n");
          return (sb.toString ());
          }
        catch (Exception e)
          {
          System.out.println ("toString(): " + e);
          }

        return ("** dump error **");
        }


      void byteOut (StringBuffer sbIn, int iIn)
        {
        char c;
        String s;

        sbIn.append (toHexWidth (iIn, 2));
        if (bRunningOnAsciiSystem && (iIn > 31) && (iIn < 128))
          {
          sAscii = sAscii + (char) iIn;
          }
        else if (!bRunningOnAsciiSystem 
        && ((iIn == 0x40) || (iIn == 0xad) || (iIn == 0xbd)
        || ((iIn >= 0x4a) && (iIn <= 0x50))
        || ((iIn >= 0x5a) && (iIn <= 0x61))
        || ((iIn >= 0x6b) && (iIn <= 0x6f))
        || ((iIn >= 0x7a) && (iIn <= 0x7f))
        || ((iIn >= 0x81) && (iIn <= 0x89))
        || ((iIn >= 0x8b) && (iIn <= 0x8f))
        || ((iIn >= 0x91) && (iIn <= 0x99))
        || ((iIn >= 0x9b) && (iIn <= 0xa9))
        || ((iIn >= 0xc1) && (iIn <= 0xc9))
        || ((iIn >= 0xd1) && (iIn <= 0xd9))
        || ((iIn >= 0xe2) && (iIn <= 0xe9))
        || ((iIn >= 0xf0) && (iIn <= 0xf9))))
          {
          abOne[0] = (byte) iIn;
          try
            {
            s = new String (abOne, "IBM-1047");  
            sAscii = sAscii + s;   
            }
          catch (UnsupportedEncodingException e)
            {
            System.out.println ("ERROR: This non-Ascii system does not "
              + "support code page IBM-1047.");
            System.exit (12);
            }
          }
        else
          {
          sAscii = sAscii + ".";
          }
//System.out.println ();
//System.out.println ("AsciiSys=" + bRunningOnAsciiSystem + " iIn=" + iIn + " cIn->" + (char) iIn
//  + "<-  sAscii->" + sAscii + "<-");
//System.out.println ();

        if (++iByteInCluster >= 2)
          {
          sbIn.append (" ");
          iByteInCluster = 0;
          }

        if (((iByteInLine + 1) % 8) == 0)
          {
          sbIn.append (" ");
          }

        if (++iByteInLine >= 16)
          {
          newLine (sbIn, false);
          }
        }


      void newLine (StringBuffer sbIn, boolean bFirstLine)
        {
        if (!bFirstLine)
          {
          while (sAscii.length () < 16)
            {
            sAscii = sAscii + " ";
            }

          sbIn.append ("   *" + sAscii + "*\n");
          iLinesInCluster++;
          }

        if (iLinesInCluster >= 8)
          {
          sbIn.append ("\n");
          iLinesInCluster = 0;
          }

        sbIn.append (sMargin + toHexWidth (lOffset + 1, 4) + ":  ");

        iByteInLine = 0;
        sAscii = "";
        }


      void lastLine (StringBuffer sbIn)
        {
        if (iByteInLine < 8)  sbIn.append (" ");
        if (iByteInLine < 16) sbIn.append (" ");

        while (++iByteInLine <= 16)
          {
          sbIn.append ("  ");
          if ((iByteInLine % 2) == 0) sbIn.append (" ");
          }

        while (sAscii.length () < 16)
          {
          sAscii = sAscii + " ";
          }

        sbIn.append ("   *" + sAscii + "*\n");
        iByteInLine = 0;
        sAscii = "";
        }


      String toHexWidth (long lIn, int iWidth)
        {
        return (toHexWidth ((int) lIn, iWidth));
        }


      String toHexWidth (int iIn, int iWidth)
        {
        StringBuffer sbAnswer;
        int i;
        char c;
        int iWk;
        int iNibbleMask = 0x0000000f;

        sbAnswer = new StringBuffer ("");
        for (i = 0; i < iWidth; i++)
          {
          iWk = iIn >> (i * 4);
          iWk = iWk & iNibbleMask;
          c = (char) iWk;
          if (c < 10)
            {
            c += '0';
            }
          else
            {
            c = (char) (c - 10 + 'A');
            }
          sbAnswer.insert (0, c);
          }
        return (sbAnswer.toString ());
        }


      public static void main (String[] args)
        {
        Dump dmp;
        File f;
        FileInputStream fis;
        String s;
        SimpleDateFormat sdf;

        if (args.length < 1)
          {
          System.out.println ("Format: java Dump filename");
          System.exit (1);
          }

        f = new File (".", args[0]);
        try
          {
          fis = new FileInputStream (f);
          dmp = new Dump (fis, "    ");

          System.out.println ("\n\n");
          s = "    FILE = " + f.getName ();
          while (s.length () < 37) s = s + " ";
          sdf = new SimpleDateFormat ("MM/dd/yyyy hh:mm:ss a"); // format date str
          s = s + "DATE: " + sdf.format (new Date (f.lastModified ()));
          System.out.println (s);

          System.out.println ("    DDIR = " + f.getParent ());
          System.out.println ("    --------------------------------"
            + "--------------------------------------\n");

          dmp.dump (System.out);
          fis.close ();
          }
        catch (Exception e)
          {
          System.out.println ("Exception: " + e);
          }
        }
      }

