/*--- HashPJW ---------------------------------------------------
 *  An adaptation of Peter Weinberger's (PJW) generic hashing
 *  algorithm based on Allen Holub's version. Accepts a pointer
 *  to a datum to be hashed and returns an unsigned integer.
 *-------------------------------------------------------------*/
 // PJWHash Preprocessor
#ifndef CHAR_BIT
#	define CHAR_BIT 8
#endif
#define BITS_IN_int		( sizeof( int ) * CHAR_BIT )
#define THREE_QUARTERS	((int) ((BITS_IN_int * 3) / 4))
#define ONE_EIGHTH		((int) (BITS_IN_int / 8 ))
#define HIGH_BITS		( ~((unsigned int)(~0) >> ONE_EIGHTH ))

// PJWHash
//
unsigned long PJWHash( const char *data, unsigned int cbLen ) {
	unsigned int h = 0, i, x;
    for ( x = cbLen; x;  x-- ) {
    	h = ( h << ONE_EIGHTH ) + *data++;
        if ( ( i = h & HIGH_BITS ) != 0 )
        	h = ( h ^ ( i >> THREE_QUARTERS ) ) & ~HIGH_BITS;
    }
    return h;
}

/*--- ElfHash ---------------------------------------------------
 *  The published hash algorithm used in the UNIX ELF format
 *  for object files. Accepts a pointer to a string to be hashed
 *  and returns an unsigned long.
 *-------------------------------------------------------------*/
// ELFHash
//
unsigned long ELFHash( const char *data, unsigned int cbLen ) {
	unsigned int x;
	unsigned long h = 0, g;
	for( x = cbLen; x; x-- ) {
    	h = ( h << 4 ) + *data++;
        if (  ( g = ( h & 0xF0000000L ) ) != 0 )
        	h ^= g >> 24;
        h &= ~g;
    }
    return h;
}


unsigned long __export PJWStrHash( const char *data ) {
	unsigned int cbLen;
   const char *p = data;
   for ( cbLen = 0; *p; cbLen++ ) p++;
	return PJWHash( data, cbLen );
}

unsigned long __export ELFStrHash( const char *data ) {
	unsigned int cbLen;
   const char *p = data;
   for ( cbLen = 0; *p; cbLen++ ) p++;
   return ELFHash( data, cbLen );
}

