/* Copyright 1999 Enhanced Software Technologies Inc.
 * All Rights Reserved
 *
 * Released under a BSD-style license. See file LICENSE for info.
 *
 * bin2hex.c: binary to hex conversions. 
 *
 * RCS CHANGE LOG
 * $Log: bin2hex.c,v $
 * Revision 1.1.1.1  2001/05/17 17:10:59  elgreen
 * Initial checkin
 *
 * Revision 1.3  2000/12/12 16:41:21  eric
 * aescrypt 0.6 (large patch by Peter Pentchev).
 *
 * Revision 1.2  2000/04/05 22:09:19  eric
 * Daily checkin...
 *
 * Revision 1.1  2000/03/28 23:54:28  eric
 * Initial checkin -- aescrypt/aesget
 *
 * Revision 1.4  1999/12/20 14:51:53  eric
 * Added dstring.h to headers list.
 *
 * Revision 1.3  1999/11/18 16:23:36  eric
 * More mods to make it work. Start of the 'rsh' functionality.
 *
 * Revision 1.2  1999/09/30 20:32:28  eric
 * Refreshed after Richard foobared the CVS archive
 *
 * Revision 1.1  1999/09/23 00:09:34  eric
 * Initial checkin
 *
 *
 * $Date: 2001/05/17 17:10:59 $
 */

/* #define DEBUG 1 */

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "dstring.h"

static char HEXSTR[]="0123456789ABCDEF";


unsigned int unhexnib(unsigned char hexchar) {
  if (hexchar>='0' && hexchar <='9') {
    return hexchar-'0';
  }
  if (hexchar>='A' && hexchar <='F') {
    return hexchar-'A'+10;
  }
  if (hexchar>='a' && hexchar <='f') {
    return hexchar-'a'+10;
  }
  return -1; /* ERROR! */
}


/***************************************************************************
 * STRAIGHT BIG_ENDIAN FUNCTIONS
 ***************************************************************************
 * These do not attempt to switch between big endian/little endian byte
 * order. We use these mostly when we are hexifying stuff that was
 * created by mpz_t or etc... 
 **************************************************************************/

unsigned char *hexify_block( unsigned char *resultbuf, int length ) {
  unsigned char *resultstr;
  int i;
  int leftnib;
  int rightnib;
  unsigned int ch;

  resultstr= (unsigned char *)malloc(length*2+1);  /* 16 bytes * 2 + terminator */

  /* if big endian, start at beginning & go up */
  for (i=0;i<length;i++) {
    ch=(unsigned int) *resultbuf++;
    leftnib= (ch >> 4) & 0x0f ;
    rightnib = ch & 0x0f;
    resultstr[i*2]=HEXSTR[leftnib];
    resultstr[i*2+1]=HEXSTR[rightnib];
  }
  resultstr[length*2]=0; /* terminate it! */
  return resultstr;

}  

/* Okay, new design: unhexify_block was not working right :-(. Thus
 * here's what I am going to do:
 *  1) take the incoming hex string and massage it to the right length
 *  2) Do a straight left-to-right hex to decimal conversion!
 */

unsigned char *unhexify_block(unsigned char *str, int length) {
  unsigned char *source;
  unsigned char *result;

  int hexlen=length*2;
  int len=strlen(str);

  int i;

  unsigned int ch;
  int leftnib;
  int rightnib;

  /* Now to do it: */
  result=(char *)malloc(length);
  
  if (len < hexlen) {
    source=d_lpad(str,'0',hexlen);
  } else {
    source=d_dup(str);
    source[hexlen]=0; /* chop off the right hand side if needed! */
  }

#ifdef DEBUG
  printf("hex2bin: length=%d, source='%s'\n",length,source);
#endif
  /* Now do straight left to right: */
  for (i=0;i<length;i++) {
    leftnib=unhexnib(source[i*2]);
    rightnib=unhexnib(source[i*2+1]);
    ch=(leftnib <<4) | rightnib;
#ifdef DEBUGDEBUG
    printf("hex2bin: ch[%d]=%x\n",i,ch);
#endif
    result[i]=(unsigned char) ch; /* voila! */
  }
  
  free(source);  /* Get rid of memory leak! */

  /* and return! */
  return result;
}

#ifdef FOOFOOFOO
     
unsigned char *unhexify_block(unsigned char *str, int length) {
  unsigned char *source;
  unsigned char *result;
  int hexlen = length*2;
  int i;
  
  unsigned int ch;
  int leftnib;
  int rightnib;


  unsigned char *resultwalk;
  unsigned char *strwalk;

  if (strlen(str) < hexlen) {
    source=d_lpad(str,'0',hexlen);
  } else {
    source=d_dup(str);  
  }

  /* now allocate our space: */ 
  result=(char *) malloc(length); /* has to be that length, divided by two. */
  memset(result,0,length);

  /* We always do big_endian, meaning that we must start at the LSB and come
   * backwards to make sure we don't leave trailing zeros. 
   */   
  resultwalk=result+length-1;
  strwalk=str+strlen(str)-2;
  for (i=0;i<length;i++) {
    leftnib=unhexnib(*strwalk++);
    rightnib=unhexnib(*strwalk--);
    strwalk-=2; /* go to previous... */
    ch=(leftnib << 4) | rightnib;
    *resultwalk-- = (unsigned char) ch; /* and set it! */
  }
  return result;
}
#endif
