/* crc32.cc

   written by Marc Singer
   6 November 2004

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   version 2 as published by the Free Software Foundation.
   Please refer to the file debian/copyright for further details.

   -----------
   DESCRIPTION
   -----------

   An original reference for information about implementating CRC32 is
   a document written by Ross Williams in 1993, "A Painless Guide to
   CRC Error Detection Algorithms."  Using his nomenclature, the CRC
   algorithm implemented by Ethernet and Zip compression has the
   following features:

     Width  : 32
     Poly   : 04C11DB7
     iPoly  : EDB88320		// reverse bit order
     Init   : FFFFFFFF
     RefIn  : True
     RefOut : True
     XorOut : FFFFFFFF
     Check  : CBF43926

   Width parameter is the length, in bits, of the polynomial.  The
   Poly is a bit mask indicating which terms have non-zero
   coefficients.  In this case,

     g(x) = x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 +
	    x^7 + x^5 + x^4 + x^2 + x + 1

   Init is value used to initialize the CRC function.  RefIn and
   RefOut, being true, indicate that the algorithm interprets the MSB
   of each byte as an MSB.  XorOut is the XOR mask applied to the CRC
   on completion.  Check is the CRC for the sequence "123456789".

   The implementation used herein comes from BLOB and was the work of
   several people, Erik Muow, Jan-Derk Bakker, and Russell King.  It
   was found to be faster than the table algorithm though a little
   larger, ~124 bytes.

   Correcting The Algorithm
   ------------------------

   While the above description is interesting and mostly correct, it
   is more interesting to be able to compute a CRC that is compatible
   with other programs such as the GNU cksum.  To that end, a new
   implementation is chosen.  Instead of the reversed polynomial and
   bit shifting of the existing algorithms, we now use a forward
   shifting implementation.  There is no difference in the code size
   or speed, so there really isn't any reason to use the reversed
   implementation.

*/

#define POLY		(0x04c11db7)
#define IPOLY		(0xedb88320)

#if 0

/* Allegedly faster version, we want the smallest code possible */

unsigned long compute_crc32_x (unsigned long crc, const void* pv, int cb)
{
  unsigned char* pb = (unsigned char*) pv;
  unsigned long poly = IPOLY;	// Hack to get a register allocated

  crc = crc ^ 0xffffffff;	// Invert because we're continuing

#define DO_CRC\
  if (crc & 1) { crc >>= 1; crc ^= poly; }\
  else	       { crc >>= 1; }

  while (cb--) {
    crc ^= *pb++;

    DO_CRC;
    DO_CRC;
    DO_CRC;
    DO_CRC;
    DO_CRC;
    DO_CRC;
    DO_CRC;
    DO_CRC;
  }

  return crc ^ 0xffffffff;
}

#endif


/* compute_crc32

   calculates a standard 32 bit CRC checksum over a sequence of bytes.
   This implementation is optimized for the ARM architecture.  Other
   architectures, e.g. i386 will probably not be well served by this
   version as it depends on excellent optimization by the compiler as
   well as an adequate number of registers.

*/

#if 0
unsigned long compute_crc32 (unsigned long crc, const void *pv, int cb)
{
  const unsigned char* pb = (const unsigned char *) pv;

  crc ^= 0xffffffff;

  while (cb--) {
    int i;
    crc ^= *pb++;

    for (i = 8; i--; ) {
      if (crc & 1) {
	crc >>= 1;
	crc ^= IPOLY;
      }
      else
	crc >>= 1;
    }
  }

  return crc ^ 0xffffffff;
}

#endif

#if defined (CONFIG_SMALL)

/* compute_crc32

   is a working, bit oriented, MSB order crc computation routine that
   does not require zero shifting and is compatible with GNU cksum.

*/

unsigned long compute_crc32 (unsigned long crc, const void *pv, int cb)
{
  const unsigned char* pb = (const unsigned char *) pv;

  while (cb--) {
    int i;
    crc ^= *pb++ << 24;

    for (i = 8; i--; )
      if (crc & (1<<31))
	crc = (crc << 1) ^ POLY;
      else
	crc <<= 1;
  }

  return crc;
}
#endif


#if !defined (CONFIG_SMALL)

/* compute_crc32_2

   implements the CRC32 polynomial using table lookup.  Like the
   brother above, this version is compatible with GNU cksum.

*/

unsigned long compute_crc32 (unsigned long crc, const void *pv, int cb)
{
  static const unsigned long rgLookup[256] = {
    0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
    0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
    0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
    0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
    0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
    0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
    0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
    0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
    0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
    0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
    0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
    0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
    0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
    0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
    0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
    0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
    0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
    0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
    0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
    0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
    0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
    0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
    0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
    0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
    0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
    0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
    0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
    0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
    0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
    0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
    0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
    0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
    0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
    0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
    0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
    0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
    0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
    0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
    0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
    0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
    0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
    0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
    0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 };

  const char* pb = (const char*) pv;

  while (cb--)
    crc = rgLookup[((crc >> 24) ^ *pb++) & 0xff] ^ (crc << 8);
  return crc;
}

#endif

#if 0
/** Append a CRC32 of the length of a region such that the length may
    be any size.  We add bytes to the CRC starting with the LSB until
    the length is empty.  This is the method compatible with the POSIX
    cksum command. */

uint32_t compute_crc32_length (uint32_t crc, size_t cb)
{
  for (; cb; cb >>= 8) {
    uint8_t b = cb & 0xff;
    crc = compute_crc32 (crc, &b, 1);
  }
  return crc;
}
#endif
