/****************************************************************************/
/*                                                                          */
/*  PROGRAM:            FILECRC                                             */
/*                                                                          */
/*  LAST UPDATE:        June 21, 1992 [14:57:03]                            */
/*                                                                          */
/*  AUTHOR:             N. Scott Pearson                                    */
/*                                                                          */
/*  ACKNOWLEDGMENTS:    This program was derived  from  a  program  called  */
/*                      CRCMAN  written  by Mark R. Nelson. It accompanied  */
/*      an article on file verification using CRCs which was presented  in  */
/*      the May 1992 edition of Dr. Dobbs Journal.                          */
/*                                                                          */
/*  DESCRIPTION:        This program calculates  and  outputs  the  CRC-32  */
/*                      value  for the file whose pathname is specified on  */
/*      the command line. CRC-32 is an acronym for  the  "32-bit  Cyclical  */
/*      Redundancy Check" algorithm. CRC-32 generally refers to a specific  */
/*      32-bit  CRC  formula  sanctioned  by  the  CCITT, an international  */
/*      standards body primarily concerned with telecommunications. CRC-32  */
/*      is used in communications protocols such as  HDLC  and  ZMODEM  to  */
/*      verify  the  integrity of blocks of data being transferred through  */
/*      various media.                                                      */
/*                                                                          */
/*          CRC  calculations  are  done  using  a  technique   with   the  */
/*      formidable  name  of  "polynomial  division".  A  block  of  data,  */
/*      regardless of how long, is treated as if each bit in the block  is  */
/*      the  coefficient  in  a  long  polynomial.  For  example, a single  */
/*      hexadecimal byte, 0F0H, would be considered to be the polynomial:   */
/*                                                                          */
/*                   7     6     5     4     3     2     1     0            */
/*                 1X  + 1X  + 1X  + 1X  + 0X  + 0X  + 0X  + 0X             */
/*                                                                          */
/*      The terms with coefficients of 0 drop out, so the  polynomial  can  */
/*      be expressed as:                                                    */
/*                                                                          */
/*                                7    6    5    4                          */
/*                               X  + X  + X  + X                           */
/*                                                                          */
/*      If we are calculating the CRC of an  entire  file,  the  exponents  */
/*      will  be  very large, but this is not a problem. The actual values  */
/*      of the exponents do not come into play during the  calculation  of  */
/*      the  CRC,  so the CRC values can grow infinitely without affecting  */
/*      the algorithm.                                                      */
/*                                                                          */
/*          The calculation of the  CRC  is  done  by  dividing  a  second  */
/*      polynomial,  the "generator polynomial", into the file polynomial,  */
/*      producing a quotient and a  remainder.  The  generator  polynomial  */
/*      used by the CRC-32 is:                                              */
/*                                                                          */
/*       32   26   23   22   16   12   11   10   8   7   5   4   2   1      */
/*      X  + X  + X  + X  + X  + X  + X  + X  + X + X + X + X + X + X + 1   */
/*                                                                          */
/*      After dividing this generator polynomial into our file polynomial,  */
/*      we  simply  discard  the  quotient,  and  use the remainder as our  */
/*      32-bit CRC.                                                         */
/*                                                                          */
/*          Polynomial division to create a CRC was originally done  using  */
/*      hardware  shift  registers  and  boolean glue logic.. Fortunately,  */
/*      "cookbook" algorithms now exist to implement the CRC on PCs  in  a  */
/*      relatively  fast  and  efficient manner. In this program, we use a  */
/*      table-lookup version of  the  algorithm  that  exchanges  a  small  */
/*      increase in storage for a fast calculation.                         */
/*                                                                          */
/*          If  you  are  interested  in  more  details  on  how  the  CRC  */
/*      calculations work, two excellent references are:                    */
/*                                                                          */
/*      "C Programmer's Guide to Serial Communications",  by Joe Campbell.  */
/*      (Howard W. Samms, 1988)                                             */
/*                                                                          */
/*      "A tutorial on CRC Computations",  by Tenkasi Ramabadran and Sunil  */
/*      S. Gaitonde. (IEEE Micro, August 1988)                              */
/*                                                                          */
/****************************************************************************/

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

unsigned char buffer[512], *p;
unsigned long temp1, temp2, crc;
FILE *        file;
int           count, i;

/****************************************************************************/
/*  CRCTable[] - Instead of performing a  straightforward  calculation  of  */
/*  the 32-bit CRC using a series of logical operations, this program uses  */
/*  faster  table  lookup  method.  The  values in the table were produced  */
/*  using the following program:                                            */
/*                                                                          */
/*      #include <stdio.h>                                                  */
/*                                                                          */
/*      #define CRC32_POLYNOMIAL 0xedb88320L                                */
/*                                                                          */
/*      int main( int argc, char *argv[] )                                  */
/*          {                                                               */
/*          unsigned long   crc;                                            */
/*          int             i, j;                                           */
/*                                                                          */
/*          printf( "    " );                                               */
/*                                                                          */
/*          for ( i = 0; i <= 255; i++ )                                    */
/*              {                                                           */
/*              crc = i;                                                    */
/*                                                                          */
/*              for ( j = 8; j > 0; j-- )                                   */
/*                  {                                                       */
/*                  if ( crc & 1 )                                          */
/*                      crc = (crc >> 1) ^ CRC32_POLYNOMIAL;                */
/*                  else                                                    */
/*                      crc >>= 1;                                          */
/*                  }                                                       */
/*                                                                          */
/*              printf( "0x%08lxL", crc );                                  */
/*                                                                          */
/*              if ( i != 255 )                                             */
/*                  {                                                       */
/*                  putchar( ',' );                                         */
/*                                                                          */
/*                  if ( (i + 1) % 5 )                                      */
/*                      putchar( ' ' );                                     */
/*                  else                                                    */
/*                      printf( "\n    " );                                 */
/*                  }                                                       */
/*              }                                                           */
/*                                                                          */
/*          putchar( '\n' );                                                */
/*          return( 0 );                                                    */
/*          }                                                               */
/*                                                                          */
/****************************************************************************/

const unsigned long CRCtable[256] = 
    {
    0x00000000L, 0x77073096L, 0xff1f723cL, 0xaa1a62caL, 0x076dc419L,
    0x706af48fL, 0xfa74b645L, 0xaf75a6b3L, 0x0edb8832L, 0x79dcb8a4L,
    0xf1e6fa2eL, 0xa8e3ea98L, 0x09b64c2bL, 0x7eb17cbdL, 0xf8c93e17L,
    0xa1c02ea1L, 0x1db71064L, 0x6ab020f2L, 0x04ca8258L, 0x95cf52eeL,
    0x1adad47dL, 0x6ddde4ebL, 0x05e5c661L, 0x94e496d7L, 0x136c9856L,
    0x646ba8c0L, 0x0e730a8aL, 0x9b76dafcL, 0x14015c4fL, 0x63066cd9L,
    0x0b104e73L, 0x9e191e05L, 0x3b6e20c8L, 0x4c69105eL, 0xe67152f4L,
    0xb3788282L, 0x3c03e4d1L, 0x4b04d447L, 0xe31e960dL, 0xb61bc67bL,
    0x35b5a8faL, 0x42b2986cL, 0xecccdae6L, 0xbdcd0a40L, 0x32d86ce3L,
    0x45df5c75L, 0xede71edfL, 0xbce24e69L, 0x26d930acL, 0x51de003aL,
    0xd9e86280L, 0xc0e17226L, 0x21b4f4b5L, 0x56b3c423L, 0xd0cba6a9L,
    0xc9ceb61fL, 0x2802b89eL, 0x5f058808L, 0xd71deac2L, 0xc21cfa34L,
    0x2f6f7c87L, 0x58684c11L, 0xd2722ebbL, 0xc7773e4dL, 0x76dc4190L,
    0x01db7106L, 0xa9e331ccL, 0xf0e6213aL, 0x71b18589L, 0x06b6b51fL,
    0xa0c0f5b5L, 0xf9c9e543L, 0x7807c9a2L, 0x0f00f934L, 0xa71ab99eL,
    0xf21fa928L, 0x7f6a0dbbL, 0x086d3d2dL, 0xa2757da7L, 0xf7746d11L,
    0x6b6b51f4L, 0x1c6c6162L, 0x967641e8L, 0x0373115eL, 0x6c0695edL,
    0x1b01a57bL, 0x931905d1L, 0x0610d567L, 0x65b0d9c6L, 0x12b7e950L,
    0x9ccfc9faL, 0x0dca998cL, 0x62dd1ddfL, 0x15da2d49L, 0x9de48d03L,
    0x0ce55d75L, 0x4db26158L, 0x3ab551ceL, 0xb4cd1184L, 0xe5cc41f2L,
    0x4adfa541L, 0x3dd895d7L, 0xb5e2d57dL, 0xe4e7050bL, 0x4369e96aL,
    0x346ed9fcL, 0xbe789956L, 0xeb71c9d0L, 0x44042d73L, 0x33031de5L,
    0xbb1b5d6fL, 0xee1e8dd9L, 0x5005713cL, 0x270241aaL, 0xcf1c2110L,
    0xda1d3196L, 0x5768b525L, 0x206f85b3L, 0xca77e519L, 0xdf72f5afL,
    0x5edef90eL, 0x29d9c998L, 0xc1e1a932L, 0xd8e8b9c4L, 0x59b33d17L,
    0x2eb40d81L, 0xc8ce6d4bL, 0xd1cb7dbdL, 0xfec99420L, 0xabc0c4c6L,
    0x03b6e20cL, 0x74b1d29aL, 0xfbe65849L, 0xaee388bfL, 0x04db2615L,
    0x73dc1683L, 0xf4741c22L, 0xa5754c94L, 0x0d6d6a3eL, 0x7a6a5aa8L,
    0xf51fd01bL, 0xa41a00adL, 0x0a00ae27L, 0x7d079eb1L, 0x0110a454L,
    0x9819b4e2L, 0x1e01f268L, 0x6906c2feL, 0x0873686dL, 0x917678dbL,
    0x196c3671L, 0x6e6b06e7L, 0x0fe52c86L, 0x9ae43ce0L, 0x10da7a5aL,
    0x67dd4accL, 0x0acae07fL, 0x9fcff009L, 0x17b7be43L, 0x60b08ed5L,
    0xe7e7b4f8L, 0xb2e2a48eL, 0x38d8c2c4L, 0x4fdff252L, 0xe2cc7801L,
    0xb7cd6877L, 0x3fb506ddL, 0x48b2364bL, 0xe91e3ceaL, 0xb01b2c5cL,
    0x36034af6L, 0x41047a60L, 0xe071f0d3L, 0xb978e065L, 0x316e8eefL,
    0x4669be79L, 0xdc72c49cL, 0xcd77942aL, 0x256fd2a0L, 0x5268e236L,
    0xdd1d88a5L, 0xcc1c5813L, 0x220216b9L, 0x5505262fL, 0xd6cb4cceL,
    0xc3ce1c38L, 0x2bb45a92L, 0x5cb36a04L, 0xd3e800b7L, 0xc6e1d041L,
    0x2cd99e8bL, 0x5bdeae1dL, 0xac75d3b0L, 0xfd740336L, 0x756aa39cL,
    0x026d930aL, 0xad1a17b9L, 0xfc1f474fL, 0x72076785L, 0x05005713L,
    0xa6c05b92L, 0xf3c98b24L, 0x7bb12baeL, 0x0cb61b38L, 0xa3e39fabL,
    0xf6e6cf1dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x97e4e3e4L, 0x02e5f352L,
    0x68ddb3f8L, 0x1fda836eL, 0x92cf27ddL, 0x07ca376bL, 0x6fb077e1L,
    0x18b74777L, 0x99196bf6L, 0x00107b70L, 0x66063bcaL, 0x11010b5cL,
    0x9076af0fL, 0x0973bf79L, 0x616bffd3L, 0x166ccf45L, 0xb11bf388L,
    0xe81ee3feL, 0x4e048354L, 0x3903b3c2L, 0xb8783771L, 0xe1712707L,
    0x4969474dL, 0x3e6e77dbL, 0xbfe27b5aL, 0xeae76becL, 0x40df0b66L,
    0x37d83bf0L, 0xbacdbf63L, 0xefccafd5L, 0x47b2cf7fL, 0x30b5ffe9L,
    0xcece032cL, 0xdbcbd39aL, 0x53b39330L, 0x24b4a3a6L, 0xcbe14715L,
    0xdee817a3L, 0x54de5729L, 0x23d967bfL, 0xc4778b3eL, 0xd5725bc8L,
    0x5d681b02L, 0x2a6f2b94L, 0xc51ccf47L, 0xd41d9fb1L, 0x5a05df1bL,
    0x2d02ef8dL
    };
    
/****************************************************************************/
/*  blockCRC() - Calculates the CRC for a block of data  using  the  table  */
/*  lookup  method.  It accepts an original value for the CRC, and returns  */
/*  the updated value.                                                      */
/****************************************************************************/

unsigned long blockCRC( unsigned int count, unsigned long _crc, void *buffer )
    {
    p = (unsigned char *)buffer;
    
    while ( count-- )
        {
        temp1 = (_crc >> 8) & 0x00ffffffL;
        temp2 = CRCtable[((int)_crc ^ *p++) & 0xff];
        _crc = temp1 ^ temp2;
        }
        
    return( _crc );
    }

/****************************************************************************/
/*  main() - Performs the calculation of the 32-bit  CRC  for  the  entire  */
/*  file.  We  precondition  the CRC value with all 1's, then invert every  */
/*  bit after the entire falue has been done. This gives us  a  CRC  value  */
/*  that corresponds with the values calculated by PKZIP and ARJ.           */
/****************************************************************************/

int main( int argc, char *argv[] )
    {
    if ( ( argc == 1 ) || ( argc > 2 ) )
        {
        printf( "\nUSE: filecrc <file>\n\n", argv[0] );
        return( 1 );
        }
        
    file = fopen( argv[1], "rb" );
    
    if ( file == NULL )
        {
        printf( "\nCould not open file \"%s\"\n\n", argv[1] );
        return( 1 );
        }
        
    crc = 0xffffffffL;
    i = 0;
    
    for ( ; ; )
        {
        count = fread( buffer, 1, 512, file );
        
        if ( count == 0 )
            break;
        
        if ( (i++ % 32) == 0 )
            putchar( '.' );
            
        crc = blockCRC( count, crc, buffer );
        }
        
    printf( "\n\nCRC-32 for file \"%s\" is 0x%08lx\n\n", argv[1], crc );
    exit( 0 );
    }
