/*                                                                       */
/*  CRCUtil.c - Utilities per l'utilizzo di codici CRC a 16 e a 32 bit   */
/*                                                                       */
/*  di Alberto Geneletti      per Amiga Magazine - Marzo 92              */
/*                                                                       */


#define GEN16   0x1021
#define GEN32   0x04c11db6


/*  Definizione del polinomio generatore a 16 bit standard CCITT         */
/*                                                                       */
/*               16   12   5                                             */
/*              x  + x  + x + 1                                          */
/*                                                                       */
/*  e del polinomio generatore a 32 bit standard CCITT                   */
/*                                                                       */
/*    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   */
/*                                                                       */


#define CRC_OK  0x0000
#define CRC_BAD 0xffff


/*  Definizione dei codici di controllo restituiti dalle due funzioni    */
/*  CheckCRC16() e CheckCRC(32)                                          */



/*                                                                       */
/*   F U N Z I O N I   P E R   C O D I C I   C R C   A   1 6   B I T     */    
/*                                                                       */

 
/*    DoCRC16 - Restituisce la checksum CRC (calcolata secondo il poli-  */
/*              nomio generatore a 16 bit definito con l'identificatore  */
/*              GEN16) di un messaggio, del quale deve essere specifica- */
/*              ta la lunghezza, contenuto in un buffer.                 */
/*              Tale buffer dovra' prevedere in coda due byte extra, nei */
/*              quali verra' depositata automaticamente la checksum al   */
/*              termine dell'operazione.                                 */

int DoCRC16(unsigned char *buffer, int lunghezza)
{
int crc, cont, msb, maschera;
unsigned char *chk;

for (cont = 0; cont < 2; ++cont)
buffer[lunghezza++] = '\0';

crc = 0;
chk = (unsigned char *)&crc;

for (cont = 0; cont < lunghezza; ++cont)
	for (maschera = 0x80; maschera != 0; maschera >>= 1) 
         {
		msb = crc & 0x8000;
		crc <<= 1;
		crc |= (buffer[cont] & maschera ? 1 : 0);
		if (msb)
	         crc ^= GEN16;
	 }

lunghezza -= 2;
chk += 2;
for (cont = 0; cont < 2; ++cont)
buffer[lunghezza++] = *chk++;
 
return (crc & 0xffff);
}




/*   GetCRC16 - Restituisce la checksum CRC a 16 bit posizionata in     */ 
/*              coda ad un buffer contenente un messaggio di lunghezza  */
/*              nota.                                                   */

int GetCRC16(unsigned char *buffer, int lunghezza)
{
int crc,cont;
unsigned char *chk = (unsigned char *)&crc;

chk += 2;
for (cont = 0; cont < 2; ++cont)
*chk++ = buffer[lunghezza++];
 
return (crc);
}




/* CheckCRC16 - Verifica l'esatta corrispondenza tra la checksum a 16    */
/*              bit posizionata in coda al buffer contenente un messag-  */
/*              gio di lunghezza nota e la checksum ricalcolata del      */
/*              messaggio stesso.                                        */
/*              Restituisce un opportuno codice di controllo.            */
/*              Attenzione: in coda al messaggio verra' sostituita la    */
/*              nuova checksum.                                          */

int CheckCRC16(unsigned char *buffer, int lunghezza)
{
int crc,chk;

crc = GetCRC16(buffer, lunghezza);
chk = DoCRC16(buffer, lunghezza);

if (crc == chk)
     return(CRC_OK);

return(CRC_BAD);
}




/*                                                                       */
/*   F U N Z I O N I   P E R   C O D I C I   C R C   A   3 2   B I T     */    
/*                                                                       */
 
/*    DoCRC32 - Restituisce la checksum CRC (calcolata secondo il poli-  */
/*              nomio generatore a 32 bit definito con l'identificatore  */
/*              GEN32) di un messaggio, del quale deve essere specifica- */
/*              ta la lunghezza, contenuto in un buffer.                 */
/*              Tale buffer dovra' prevedere in coda quattro byte extra, */
/*              nei quali verra' depositata automaticamente la checksum  */
/*              al termine dell'operazione.                              */

int DoCRC32(unsigned char *buffer, int lunghezza)
{

int crc, cont, msb, maschera;
unsigned char *chk;

for (cont = 0; cont < 4; ++cont)
buffer[lunghezza++] = '\0';

crc = 0L;
chk = (unsigned char *)&crc;

for (cont = 0; cont < lunghezza; ++cont)
	for (maschera = 0x80; maschera != 0; maschera >>= 1) 
         {
		msb = crc & 0x8000;
		crc <<= 1;
		crc |= (buffer[cont] & maschera ? 1 : 0);
		if (msb)
	         crc ^= GEN32;
	 }

lunghezza -= 4;
for (cont = 0; cont < 4; ++cont)
buffer[lunghezza++] = *chk++;

return (crc);
}




/*   GetCRC32 - Restituisce la checksum CRC a 32 bit posizionata in     */ 
/*              coda ad un buffer contenente un messaggio di lunghezza  */
/*              nota.                                                   */

int GetCRC32(unsigned char *buffer, int lunghezza)
{
int crc,cont;
unsigned char *chk = (unsigned char *)&crc;

for (cont = 0; cont < 4; ++cont)
*chk++ = buffer[lunghezza++];
 
return (crc);
}




/* CheckCRC32 - Verifica l'esatta corrispondenza tra la checksum a 32    */
/*              bit posizionata in coda al buffer contenente un messag-  */
/*              gio di lunghezza nota e la checksum ricalcolata del      */
/*              messaggio stesso.                                        */
/*              Restituisce un opportuno codice di controllo.            */
/*              Attenzione: in coda al messaggio verra' sostituita la    */
/*              nuova checksum.                                          */

int CheckCRC32(unsigned char *buffer, int lunghezza)
{
int crc,chk;

crc = GetCRC32(buffer, lunghezza);
chk = DoCRC32(buffer, lunghezza);

if (crc == chk)
     return(CRC_OK);

return(CRC_BAD);
}



