domingo, 14 de marzo de 2010

El día que un CRC cambió mi vida parte III

Continuamos con la saga del CRC.

En esta 3ª entrega os muestro como calcular el CRC a un fichero, utilizando CRCs estandarizados como el CRC-16 y el CRC-CCITT.

El código está hecho en C y es portable a Linux para todo aquel que lo desee.


Como podréis observar el código está contenido en un sólo módulo y es muy secuencial, con el fin de que se pueda seguir fácilmente y sin demasiadas complicaciones.

No obstante todo el que quiera aportar algo más o mejorar la aplicación, pues que lo haga sin más. Todos estamos aquí para seguir aprendiendo unos de otros.

Sin más rodeos anexo el código fuente:



/*****************************************************************************/
/*                                                                           */
/*  NOMBRE      : CRCx.c                                                     */
/*  AUTOR       : Longinos Recuero Bustos                                    */
/*  EMAIL       : lrecuero1@alumno.uned.es                                   */
/*  WEB         : http://longinox.blogspot.com/                              */
/*  FECHA       : 14/03/2010                                                 */
/*  LICENCIA    : GPL                                                        */
/*  DESCRIPCIÓN : Aplicación que calcula a un fichero un CRC estandarizado.  */
/*                                                                           */
/*****************************************************************************/

/* INCLUSIÓN DE HEADERS ******************************************************/

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

/* DEFINICIÓN DE CONSTANTES SIMBÓLICAS ***************************************/

#define CRC_CCITT 0x1021
#define CRC_16    0x8005

/* DEFINICIÓN DE TIPOS *******************************************************/

typedef enum
{
 FALSE = 0,
 TRUE
}TBoolean;

/* DEFINICIÓN DE PROTOTIPOS DE FUNCIONES *************************************/

void calculoCRCx( unsigned char value, unsigned int *crc );

/* MAIN PROGRAM **************************************************************/

int main( int argc, char* argv[] )
{
 /* Se comprueba que si se ha introducido la ruta del fichero */
 if( argc > 1 )
 {
  /* Argumentos OK */
  FILE *fichero;

  /* Se obtiene el manejador del fichero */
  fichero = fopen( argv[ 1 ], "r" );

  if( fichero != NULL )
  {
   /* OK: El fichero existe */

   /* Contador de bytes leidos */
   unsigned int contador = 0;

   /* Valor inicial del CRC */
   unsigned int crc = 0;

   /* Se almcena el primer byte a tratar */
   unsigned char byte = fgetc( fichero );

   /* Mientras queden bytes por leer... */
   while( !feof( fichero ) )
   {
    contador++;

    /* Se formatea la salida */
    if( byte > 0x0F )
    {
     printf( "0x%X\t", byte );
    }
    else
    {
     printf( "0x0%X\t", byte );
    }

    calculoCRCx( byte, &crc );

    /* Se almacena el próximo byte a tratar */
    byte = fgetc( fichero );
   }

   /* Se cierra el fichero */
   fclose( fichero );

   /* Se enmascaran los 32 bits de menos peso */
   crc &= 0xFFFF;

   /* Se muestra el CRC calculado formateando la salida */
   puts("\n\n------------------- FIN -------------------\n");
   printf( "\n\tBytes leidos:\t%d\n", contador );
   printf( "\n\tCRC calculado:\t0x%X\n", crc );
   puts("\n-------------------------------------------\n");
  }
  else
  {
   /* FALLO: No exite el fichero */
   puts("\n\t¡¡¡ ERROR !!!. No existe el fichero\n");
   return EXIT_FAILURE;
  }
 }
 else
 {
  /* FALLO: No se ha introducido nugún argumento */
  puts("\n\t¡¡¡ ERROR !!!. Se necesita la ruta del fichero\n");
  return EXIT_FAILURE;
 }

 return EXIT_SUCCESS;
}

/* FUNCIONES PRVADAS *********************************************************/

void calculoCRCx( unsigned char byte, unsigned int *crc )
{
 unsigned char i;
 unsigned int  polinomioGenerador  = CRC_16;

 /* Para cada byte del fichero... */
 for( i = 0; i < 8; i++ )
 {
  /* Se comprueba si el bit actual está a 1 */
  TBoolean es_Bit_A_Uno = ( ( ( byte >> ( 7 - i ) ) & 1 ) == 1 );

  /* Se comprueba si el MSB actual del crc está a 1 */
  TBoolean es_MSB_CRC_A_Uno = ( ( ( *crc >> 15 ) & 1 )  == 1 );

  *crc <<= 1;

  /* Si los booleanos son distintos uno de otro */
  if( es_MSB_CRC_A_Uno ^ es_Bit_A_Uno )
  {
   /* XOR entre el crc actual y el polinómio generador */
   *crc ^= polinomioGenerador;
  }
 }
}
Para probar esta aplicación desde línea de comandos, se llama al ejecutable pasándole como único argumento la ruta del fichero.

Ej.: CRCx C:\TEMP\vacaciones.jpg

El resultado será la visualización por consola de todos los bytes que componen el fichero, el número de bytes tratados y el CRC calculado.

Como veis la cosa no es tan trivial como se planteo en la entrega anterior, pero si nos vale para entender como se hace en el mundo real.

Podéis contrastar el resultado obtenido aquí y que además contiene abundante información del tema que nos ocupa a un nivel mucho más profundo.

Os dejo el código fuente y el ejecutable para el que no tenga ganas de teclear ni compilar:


En la próxima y última entrega de esta saga veremos como proteger nuestro código de depuradores usando para ello nuestra estrella, el CRC.

No hay comentarios:

Publicar un comentario