// DSigUtil.java
// $Id: DSigUtil.java,v 1.1 1997/04/15 20:39:13 yhchu Exp $
// (c) COPYRIGHT MIT and INRIA, 1997.
// Please first read the full copyright statement in file COPYRIGHT.html

// The source code is jointly developed by W3C and some of its members
// participating in the Digital Signature Initiative.  The authors are:
//    Mark Champine, HP, <champine@apollo.hp.com>
//    Yang-hua Chu, MIT/W3C, <yhchu@w3.org>
//    Vasanthan Dasan, Sun, <vasanthan.dasan@central.sun.com>
//    Peter Lipp, University of Technology, Graz <plipp@iaik.tu-graz.ac.at>
//    Andreas Sterbenz, U. of Technology, Graz <sterbenz@iaik.tu-graz.ac.at>

// Update History
// YC: 971030, ported from 1st DSig library
//   : numerous small changes

package w3c.www.dsig;

import java.io.* ;
import java.util.* ;
import java.security.*;
import java.net.URL;
import w3c.tools.codec.*;
import java.math.BigInteger;


/**
 * Some random utilities used for DSig
 *
 * @author Yang-hua Chu
 * @author Andreas Sterbenz
 * @version 1.0beta (last modified 17-october-1997)
 */


public class DSigUtil {

  public static boolean DEBUG = false;

  /**
   * Wait for user to press a key
   */
  public static void waitKey()
  {
    System.out.println("Hit the <RETURN> key.");
    try {
      System.in.read();
    } catch( java.io.IOException e ) {
      ;
    }
  }


  /**
   * Encode a BigInteger in Base 64 encoding. Included here as
   * signature suite implementations will frequently need it.
   */
  public static String bigIntegerToBase64(BigInteger bi)
  {
    String bindigest = new String(bi.toByteArray());
    Base64Encoder base64enc = new Base64Encoder(bindigest);
    return base64enc.processString();
  }


  /**
   * Decode a Base 64 encoded BigInteger. Return the BigInteger
   * object or null if the input was not properly encoded.
   * Included here as signature suite implementations will
   * frequently need it.
   */
  public static BigInteger base64ToBigInteger(String b64)
  {
    try {
      Base64Decoder base64dec = new Base64Decoder(b64);
      String binnumber = base64dec.processString();
      return new BigInteger(binnumber.getBytes());
    } catch( Base64FormatException e ) {
      return null;
    }
  }


  public static String byteArrayToBase64(byte[] bytes)
  {
    Base64Encoder base64enc = new Base64Encoder(bytes);
    return base64enc.processString();
  }


  /**
   * Returns a byte array representatino of a base64 string.
   * @exception DSigException if the String is a valid base64 String.
   */
  public static byte[] base64ToByteArray(String s)
       throws DSigException
  {
    try {
      Base64Decoder base64dec = new Base64Decoder(s);
      return (base64dec.processString()).getBytes();
    } catch (Exception e) {
      throw new DSigException(e.getMessage());
    }
  }


  /**
   * Returns a vector form of a dictionary
   */
  public static Vector dictionaryToVector(Dictionary dict)
  {
    Vector v = new Vector();
    Enumeration keys = dict.keys();
    while (keys.hasMoreElements()) {
      String key = (String) keys.nextElement();
      Object val = dict.get(key);
      if (val instanceof Dictionary)
      val = dictionaryToVector((Dictionary) val);  // recursion
      Vector pair = new Vector();
      pair.addElement(key);   // return to work on!!!
      pair.addElement(val);
      v.addElement(pair);
    }
    return v;
  }


  private static Hashtable vectorToHashtable(Vector v)
  {
    Hashtable tbl = new Hashtable();
    for (int i=0; i<v.size(); i++) {
      Vector pair = (Vector) v.elementAt(i);
      Object key = pair.elementAt(0);
      Object val = pair.elementAt(1);
      if (val instanceof Vector)
	val = vectorToHashtable((Vector) val);
      tbl.put(key, val);
    }
    return tbl;
  }


  /**
   * Reads a string from the user.  <code>msg</code> is the question
   * displayed to the user, and <code>def</code> if the default answer
   * if the user simply press return key.
   */
  public static String readln(String msg, String def)
  {
    String s = "";
    System.out.print(msg + " [" + def + "] : ");
    System.out.flush();
    try { s = new DataInputStream(System.in).readLine(); }
    catch (Exception e) { }
    if (s.equals("")) s = def;
    return s;
  }

  /**
   * Produces a string representation of an s-expression.
   */
  public static String toString(Object exp)
  {
    if (exp == null)
      return "";
    if (exp instanceof Number)
	return exp.toString();
	
    if (exp instanceof URL ||
	exp instanceof Date ||
	exp instanceof ISODate)
    return "\"" + exp.toString() + "\"";

    if (exp instanceof String)
    return "\"" + (String)exp + "\"";

    if (exp instanceof Vector) {
      String s = "(";
      for (int i=0; i < ((Vector)exp).size(); i++)
        s += " " + toString(((Vector)exp).elementAt(i));
      return s += " )";
    }

    // Andreas Sterbenz: addition
    if( exp instanceof Boolean ) {
      return exp.toString();
    }

    // error
    return "<#unknown " + exp.getClass().getName() + ":" + exp.toString() + ">)";
  }


  /**
   * Print a hexdump of the given byte array. Remainder from
   * debugging.
   */
  public static void printHexDump(byte[] data)
  {
    final char[] hexchars = ("0123456789ABCDEF".toCharArray());

    int n = data.length;
    for(int i=0; i<=n; i+=16)
    {
      // make sure we got some leading zeros...
      String ofs = Integer.toHexString(i | 0x10000000);
      System.out.print(ofs.substring(4) + ": ");
      int k = n - i;
      if( k > 16 ) k = 16;
      for(int j=0; j<k; j++ ) {
        System.out.print(hexchars[(data[i+j]&0xff)>>4]);
        System.out.print(hexchars[data[i+j]&0x0f] + (j==7 ? "  " : " "));
      }
      System.out.println();
    }
  }
}
