/* Copyright (c) <2003-2011> <Julio Jerez, Newton Game Dynamics>
 * 
 * This software is provided 'as-is', without any express or implied
 * warranty. In no event will the authors be held liable for any damages
 * arising from the use of this software.
 * 
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 * 
 * 1. The origin of this software must not be misrepresented; you must not
 * claim that you wrote the original software. If you use this software
 * in a product, an acknowledgment in the product documentation would be
 * appreciated but is not required.
 * 
 * 2. Altered source versions must be plainly marked as such, and must not be
 * misrepresented as being the original software.
 * 
 * 3. This notice may not be removed or altered from any source distribution.
 */

#include "dgStdafx.h"
#include "dgCRC.h"
#include "dgList.h"
#include "dgTree.h"
#include "dgDebug.h"
#include "dgRandom.h"

namespace InternalCRC
{
const dgInt32 STRING_POOL_SIZE = 1024 * 8 - 256;

static dgUnsigned32 randBits[] =
{ 0x00000001, 0x2C11F801, 0xDFD8F60E, 0x6C8FA2B7, 0xB573754C, 0x1522DCDD,
    0x21615D3A, 0xE1B307F3, 0x12AFA158, 0x53D18179, 0x70950126, 0x941702EF,
    0x756FE824, 0x694801D5, 0x36DF4DD2, 0x63D80FAB, 0xB8AE95B0, 0x902439F1,
    0x090C6F3E, 0x2B7C6A27, 0x8344B5FC, 0x67D3C5CD, 0x22F5516A, 0x2FB00E63,
    0xFC761508, 0x87B00169, 0x27EBA056, 0x8CC0B85F, 0xE33D3ED4, 0x95DA08C5,
    0x13E5C802, 0x9DD9E41B, 0xD4577F60, 0x3DD6B7E1, 0x096AF46E, 0x1A00CD97,
    0x4B10E2AC, 0x22EAAABD, 0x683F119A, 0x62D070D3, 0xA8D034B8, 0xAA363D59,
    0x58CECB86, 0x40F589CF, 0x4F630184, 0x38918BB5, 0xB85B8E32, 0x0A6A948B,
    0x9A099510, 0x402871D1, 0x11E7859E, 0xEE73CD07, 0x4142FB5C, 0x39D68BAD,
    0x0FE19DCA, 0xE35B2F43, 0x75590068, 0x66433549, 0x929182B6, 0x71EC773F,
    0xBBAC3034, 0xF2BD8AA5, 0x5743A062, 0x5AB120FB, 0x5ABFD6C0, 0xDDD867C1,
    0xDC3522CE, 0xD0EC6877, 0xE106000C, 0xB7C6689D, 0xED3FF5FA, 0xC75749B3,
    0x126B7818, 0x1A75E939, 0x0546C5E6, 0x8A9C80AF, 0x48A3CAE4, 0x756D0595,
    0x7060FE92, 0xA594896B, 0x12354470, 0x896599B1, 0xDAC6CBFE, 0xCB419FE7,
    0x9C44F0BC, 0xAFA9418D, 0xB87D1A2A, 0x428BC023, 0x33229BC8, 0xC92D5929,
    0xB1C19516, 0x0FBCA61F, 0xE594D194, 0x716EFC85, 0x0036A8C2, 0xD7BBCDDB,
    0x16E4DE20, 0xD10F07A1, 0x68CF812E, 0x390A7357, 0x8BAACD6C, 0x2C2E167D,
    0x3E7C0A5A, 0x167F9293, 0x3D596B78, 0x08888519, 0x9994F046, 0x0FC3E78F,
    0x008A4444, 0x87526F75, 0xB0079EF2, 0x238DEE4B, 0xCA09A3D0, 0x4ED3B191,
    0xFA42425E, 0x379DE2C7, 0x1EA2961C, 0x1FC3E76D, 0x90DFC68A, 0x0279C103,
    0xF9AAE728, 0xF2666D09, 0xEF13D776, 0x92E944FF, 0x364F22F4, 0x37665E65,
    0x05D6E122, 0x7131EABB, 0x479E9580, 0x98729781, 0x4BD20F8E, 0x1612EE37,
    0xCB574ACC, 0x5499B45D, 0x360B4EBA, 0x33814B73, 0x43720ED8, 0x146610F9,
    0x45514AA6, 0x0B23BE6F, 0x026E6DA4, 0xD1B9C955, 0x94676F52, 0xCE8EC32B,
    0x165EB330, 0x2F6AB971, 0x92F1E8BE, 0xC54095A7, 0xBEB3EB7C, 0x5C9E7D4D,
    0x5921A2EA, 0xB45D31E3, 0xB8C9E288, 0x5FE670E9, 0xC02049D6, 0xC42A53DF,
    0x6F332454, 0x661BB045, 0x2B3C4982, 0xDF4B779B, 0xD7C4FCE0, 0x70FB1761,
    0xADD4CDEE, 0x47BDD917, 0x8C63782C, 0x8181423D, 0xFA05C31A, 0xDD947453,
    0x6A8D6238, 0x1A068CD9, 0x4413D506, 0x5374054F, 0xC5A84704, 0xB41B1335,
    0x06986FB2, 0x4CCF080B, 0xF80C7290, 0x8622B151, 0x536DBF1E, 0x21E1B887,
    0xDED0F0DC, 0xB4B1032D, 0x1D5AAF4A, 0xC56E12C3, 0x8C578DE8, 0xCBA564C9,
    0xA67EEC36, 0x0837D2BF, 0x3D98D5B4, 0x1B06F225, 0xFF7EE1E2, 0x3640747B,
    0x5E301440, 0x53A08741, 0x436FBC4E, 0xC9C333F7, 0x2727558C, 0x7F5CC01D,
    0xFC83677A, 0xAFF10D33, 0x24836598, 0x3161F8B9, 0xDD748F66, 0x5B6CBC2F,
    0xAD8FD064, 0x89EE4D15, 0xBBB2A012, 0xA086BCEB, 0x1BEAE1F0, 0x69F39931,
    0x764DC57E, 0x17394B67, 0x4D51A63C, 0xF273790D, 0x35A2EBAA, 0x7EE463A3,
    0xBC2BE948, 0x2B9B48A9, 0x2FC7BE96, 0x5FC9C19F, 0x3AD83714, 0x6FA02405,
    0xDDB6AA42, 0xE648E15B, 0x1DB7DBA0, 0xF55AE721, 0x4D3ADAAE, 0xB3DAFED7,
    0x5FFAE2EC, 0x96A42DFD, 0xFB9C3BDA, 0x21CF1613, 0x0F2C18F8, 0xAE705499,
    0x650B79C6, 0x31C5E30F, 0x097D09C4, 0xAAAB76F5, 0x34CE0072, 0x27EDE1CB,
    0xDAD20150, 0xADD57111, 0xC229FBDE, 0x8AFF4E47, 0x448E0B9C, 0x5C5DDEED,
    0x4612580A, 0x05F82483, 0xBC1EF4A8, 0xB1C01C89, 0xF592C0F6, 0x6798207F,
    0xEC494874, 0x795F45E5, 0xECFBA2A2, 0xBB9CBE3B, 0xF567104f, 0x47289407,
    0x25683fa6, 0x2fde5836, };

struct StringPool
{
  char buff[STRING_POOL_SIZE];

  StringPool()
  {
  }

  StringPool(const StringPool &arg)
  {
  }
};

/*	
 class CRCStringLookup: public dgTree<char *, dgUnsigned32>, public dgList<StringPool>
 {
 
 dgInt32 size;
 char *ptr;
 
 void AddContainer ()
 {
 StringPool tmp;
 dgListNode *node;
 
 //			Addtop (tmp);
 //			node = GetFirst();
 node = Addtop (tmp);

 ptr = node->GetInfo().buff;
 size = STRING_POOL_SIZE;
 }
 
 public:

 CRCStringLookup () 
 :dgTree<char *, dgUnsigned32>(NULL), dgList<StringPool>()
 {
 AddContainer();
 }
 
 ~CRCStringLookup () 
 {
 }


 void AddString (dgUnsigned32 crc, const char *string)
 {
 dgInt32 length;
 
 if (dgTree<char *, dgUnsigned32>::Find(crc)) {
 return;
 }
 
 length = dgInt32 (strlen (string)) + 1;
 if (size < length) {
 AddContainer();
 }
 
 strcpy (ptr, string);
 Insert (ptr, crc);
 
 ptr += length;
 size -= length;
 }

 const char* FindString (dgUnsigned32 crc) const
 {
 dgTreeNode *node;

 node = dgTree<char *, dgUnsigned32>::Find(crc);
 //			return node ? node->GetInfo() : NULL;
 return node ? node->GetInfo() : NULL;
 }
 };

 static CRCStringLookup& GetDatabase ()
 {
 static CRCStringLookup database;
 return database;
 }
 */

/*
 dgUnsigned32 RSHash(char* str, dgUnsigned32 len)
 {
 dgUnsigned32 b    = 378551;
 dgUnsigned32 a    = 63689;
 dgUnsigned32 hash = 0;
 dgUnsigned32 i    = 0;

 for(i = 0; i < len; str++, i++)	{
 hash = hash * a + (*str);
 a    = a * b;
 }

 return (hash & 0x7FFFFFFF);
 }
 // End Of RS Hash Function 


 dgUnsigned32 JSHash(char* str, dgUnsigned32 len)
 {
 dgUnsigned32 hash = 1315423911;
 dgUnsigned32 i    = 0;

 for(i = 0; i < len; str++, i++)
 {
 hash ^= ((hash << 5) + (*str) + (hash >> 2));
 }

 return (hash & 0x7FFFFFFF);
 }
 // End Of JS Hash Function 


 dgUnsigned32 PJWHash(char* str, dgUnsigned32 len)
 {
 dgUnsigned32 BitsInUnsignedInt = (dgUnsigned32)(sizeof(dgUnsigned32) * 8);
 dgUnsigned32 ThreeQuarters     = (dgUnsigned32)((BitsInUnsignedInt  * 3) / 4);
 dgUnsigned32 OneEighth         = (dgUnsigned32)(BitsInUnsignedInt / 8);
 dgUnsigned32 HighBits          = (dgUnsigned32)(0xFFFFFFFF) << (BitsInUnsignedInt - OneEighth);
 dgUnsigned32 hash              = 0;
 dgUnsigned32 test              = 0;
 dgUnsigned32 i                 = 0;

 for(i = 0; i < len; str++, i++)
 {
 hash = (hash << OneEighth) + (*str);

 if((test = hash & HighBits)  != 0)
 {
 hash = (( hash ^ (test >> ThreeQuarters)) & (~HighBits));
 }
 }

 return (hash & 0x7FFFFFFF);
 }
 // End Of  P. J. Weinberger Hash Function 


 dgUnsigned32 ELFHash(char* str, dgUnsigned32 len)
 {
 dgUnsigned32 hash = 0;
 dgUnsigned32 x    = 0;
 dgUnsigned32 i    = 0;

 for(i = 0; i < len; str++, i++)
 {
 hash = (hash << 4) + (*str);
 if((x = hash & 0xF0000000L) != 0)
 {
 hash ^= (x >> 24);
 hash &= ~x;
 }
 }

 return (hash & 0x7FFFFFFF);
 }
 // End Of ELF Hash Function 


 dgUnsigned32 BKDRHash(char* str, dgUnsigned32 len)
 {
 dgUnsigned32 seed = 131; // 31 131 1313 13131 131313 etc.. 
 dgUnsigned32 hash = 0;
 dgUnsigned32 i    = 0;

 for(i = 0; i < len; str++, i++)
 {
 hash = (hash * seed) + (*str);
 }

 return (hash & 0x7FFFFFFF);
 }
 // End Of BKDR Hash Function 


 dgUnsigned32 SDBMHash(char* str, dgUnsigned32 len)
 {
 dgUnsigned32 hash = 0;
 dgUnsigned32 i    = 0;

 for(i = 0; i < len; str++, i++)
 {
 hash = (*str) + (hash << 6) + (hash << 16) - hash;
 }

 return (hash & 0x7FFFFFFF);
 }
 // End Of SDBM Hash Function 


 dgUnsigned32 DEKHash(char* str, dgUnsigned32 len)
 {
 dgUnsigned32 hash = len;
 dgUnsigned32 i    = 0;

 for(i = 0; i < len; str++, i++)
 {
 hash = ((hash << 5) ^ (hash >> 27)) ^ (*str);
 }
 return (hash & 0x7FFFFFFF);
 }
 // End Of DEK Hash Function 


 dgUnsigned32 APHash(char* str, dgUnsigned32 len)
 {
 dgUnsigned32 hash = 0;
 dgUnsigned32 i    = 0;

 for(i = 0; i < len; str++, i++)
 {
 hash ^= ((i & 1) == 0) ? (  (hash <<  7) ^ (*str) ^ (hash >> 3)) :
 (~((hash << 11) ^ (*str) ^ (hash >> 5)));
 }

 return (hash & 0x7FFFFFFF);
 }
 */

// End Of DJB Hash Function 
dgUnsigned32 DJBHash(const char* const str, dgInt32 len)
{
  dgUnsigned32 hash = 5381;
  for (dgInt32 i = 0; i < len; i++)
  {
    //hash = ((hash << 5) + hash) + (*str);
    hash = ((hash << 5) + hash) + str[i];
  }

  return (hash & 0x7FFFFFFF);
}
}

dgUnsigned32 dgApi dgCRC(const char* const name)
{
//	dgUnsigned32 c;
//	dgUnsigned32 crc;
//	unsigned char *ptr;
//	dgUnsigned32 val;
  if (!name)
  {
    return 0;
  }

  dgUnsigned32 crc = 0;
  //for (ptr = (unsigned char*)name; *ptr; ptr ++) {
  for (dgInt32 i = 0; name[i]; i++)
  {
    char c = name[i];
    dgUnsigned32 val = InternalCRC::randBits[((crc >> 24) ^ c) & 0xff];
    crc = (crc << 8) ^ val;
  }

  _ASSERTE(0);
//	InternalCRC::GetDatabase().AddString (crc, name);
  return crc;
}

dgUnsigned32 dgApi dgCRC(const void* const buffer, dgInt32 size,
    dgUnsigned32 crcAcc)
{
  _ASSERTE(buffer);
  unsigned char* const ptr = (unsigned char*) buffer;
  for (dgInt32 i = 0; i < size; i++)
  {
    dgUnsigned32 c = ptr[i];
    dgUnsigned32 val = InternalCRC::randBits[((crcAcc >> 24) ^ c) & 0xff];
    crcAcc = (crcAcc << 8) ^ val;
  }
  return crcAcc;
}

const char* dgApi dgInverseCRC(dgUnsigned32 crc)
{
  _ASSERTE(0);
  return NULL;
//	return InternalCRC::GetDatabase().FindString (crc);
}

dgUnsigned32 dgApi dgHash(const void* const string, int size)
{
  return InternalCRC::DJBHash((char*) string, size);
}
