/* crc.c : PUBLIC DOMAIN - Jon Mayo - August 11, 2006 * - You may remove any comments you wish, modify this code any way you wish, * and distribute any way you wish.*/ /* Calculates a CRC32 (ANSI X3.66) or CRC16 on a block of data */ /* History: * 2006-09-28: added CRC-16 support * 2006-09-18: modified to be useful as a crc32 utility and to detect C99-mode */ #include "crc.h" /* ANSI X3.66 crc-32 polynomial: * x^0 + x^1 + x^2 + x^4 + x^5 + x^7 + x^8 + x^10 + * x^11 + x^12 + x^16 + x^22 + x^23 + x^26 + x^32 */ static const crc32_t crc32_tab[] = { 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; /* crc-16 polynomial: * x^16 + x^12 + x^5 + 1 * * entries are padded to a word size to make for faster lookups */ static const unsigned crc16_tab[] = { 0x0000, 0x1081, 0x2102, 0x3183, 0x4204, 0x5285, 0x6306, 0x7387, 0x8408, 0x9489, 0xa50a, 0xb58b, 0xc60c, 0xd68d, 0xe70e, 0xf78f }; /* calculates crc32 on buffer 'ptr' of 'cnt' bytes. * crc is the initial crc to use. use ~0U initially, or pass the result of * the previous crc32_calc invocation. * returns the crc32 of the buffer plus the crc passed */ crc32_t crc32_calc(const void *ptr, size_t cnt, crc32_t crc) { const unsigned char *p=ptr; while(cnt--) { crc = (crc >> 4) ^ crc32_tab[(crc & 0xf) ^ (*p & 0xf)]; crc = (crc >> 4) ^ crc32_tab[(crc & 0xf) ^ (*p++ >> 4)]; } return crc; } /* calculates crc16 on buffer 'ptr' of 'cnt' bytes. * crc is the initial crc to use. * for CCITT use ~0U initially, for XMODEM use 0 * or pass the result of the previous crc16_calc invocation. * returns the crc16 of the buffer */ crc16_t crc16_calc(const void *ptr, size_t cnt, crc16_t crc) { const unsigned char *p=ptr; while(cnt--) { crc = (crc >> 4) ^ crc16_tab[(crc & 0xf) ^ (*p & 0xf)]; crc = (crc >> 4) ^ crc16_tab[(crc & 0xf) ^ (*p++ >> 4)]; } return crc; } /* define to try the examples */ #ifdef STAND_ALONE #include #include #include static int flag_crc16=0, flag_crc32=0; /* simple example: */ void example_simple(void) { const char test[] = "Hello World!"; crc32_t crc32; crc16_t crc16; /* we pass ~0 (0xffffffff) as the starting crc, and then invert the result * crc. the inverted crc is used for a trick that will be shown later. * it will not work to pass 0, then skip the invert(~). crc doesn't work * that way */ crc32= ~crc32_calc(test, strlen(test), ~0U); printf("CRC32 : %08X\n", crc32); crc16= ~crc16_calc(test, strlen(test), ~0); printf("CRC16 : %04hX\n", crc16); } void example_fancy(void) { char test[] = "Hello World!...."; /* reserve 4 bytes */ crc32_t crc32, residue32; crc16_t crc16, residue16; unsigned len, i; len=strlen(test)-4; /* don't use the reserved bytes */ /* this gets the CRC, like before */ crc32=~crc32_calc(test, len, ~0U); crc16=~crc16_calc(test, len, ~0); /* put the crc we calculated as the last 4 bytes of data */ for(i=0;i<4;i++) { /* place the data as little endian. crc type must be unsigned!! */ test[len+i]=(crc32>>(i*8))&255; } /* crc over the data AND the crc we calculated. you don't invert when you * want the residue. */ residue32=crc32_calc(test, len+4, ~0U); /* put the crc we calculated as the last 2 bytes of data */ for(i=0;i<2;i++) { /* place the data as little endian. crc type must be unsigned!! */ test[len+i]=(crc16>>(i*8))&255; } /* crc over the data AND the crc we calculated. you don't invert when you * want the residue. */ residue16=crc16_calc(test, len+2, ~0); printf("CRC32 : %08X\n", crc32); printf("RESIDUE32 : %08X (should be %08lX)\n", residue32, CRC32_RESIDUE); printf("CRC16 : %04hX\n", crc16); printf("RESIDUE16 : %04hX (should be %04hX)\n", residue16, CRC16_RESIDUE); } void example_file(FILE *f, const char *filename, crc32_t *crc32, crc16_t *crc16) { crc32_t tmpcrc32=~0U; /* initial */ crc16_t tmpcrc16=~0; /* initial */ char buf[1024]; ssize_t len; /* default to crc32 if unspecified */ if(!flag_crc16 && !flag_crc32) flag_crc32=1; while((len=fread(buf, 1, sizeof buf, f))>0) { /* just keep feeding the previous CRC in */ if(flag_crc32) { tmpcrc32=crc32_calc(buf, len, tmpcrc32); } if(flag_crc16) { tmpcrc16=crc16_calc(buf, len, tmpcrc16); } } if(len<0) perror(filename); if(flag_crc32) { *crc32=~tmpcrc32; /* we invert it at the end */ } if(flag_crc16) { *crc16=~tmpcrc16; /* we invert it at the end */ } } void process_arg(const char *filename) { crc32_t crc32; crc16_t crc16; FILE *f; if(filename[0]=='-') { if(filename[1]==0) { example_file(stdin, filename, &crc32, &crc16); } else if(filename[1]=='t') { /* test code */ example_simple(); example_fancy(); exit(EXIT_SUCCESS); } else if(filename[1]=='1' && filename[2]=='6') { flag_crc16=1; return; } else if(filename[1]=='3' && filename[2]=='2') { flag_crc32=1; return; } else { fprintf(stderr, "usage: crc [-16] [-32] [-ht] [files ...]\n"); exit(EXIT_FAILURE); } } else { f=fopen(filename, "rb"); if(!f) { perror(filename); return; } example_file(f, filename, &crc32, &crc16); fclose(f); } if(flag_crc32) { printf("CRC32 (%s) = %08x\n", filename, crc32); } if(flag_crc16) { printf("CRC16 (%s) = %04hx\n", filename, crc16); } } int main(int argc, const char **argv) { int i; /* use this as a real utility */ if(argc==1) { crc32_t crc32; crc16_t crc16; example_file(stdin, "stdin", &crc32, &crc16); } else { for(i=1;i