【原创】用C语言对 PNG 文件里面的各段数据的 CRC 进行检查
开发环境:Microsoft Visual Studio 2012 Express,Visual C++运行环境:Windows 7 Home Premium
源代码文件名:crccheck.cpp
程序代码:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <tchar.h> //ref_start[<span style="color: #008000; text-decoration: underline;">http://www.[/color]] /* Table of CRCs of all 8-bit messages. */ unsigned long crc_table[256]; /* Flag: has the table been computed? Initially false. */ int crc_table_computed = 0; /* Make the table for a fast CRC. */ void make_crc_table(void) { unsigned long c; int n, k; for (n = 0; n < 256; n++) { c = (unsigned long) n; for (k = 0; k < 8; k++) { if (c & 1) c = 0xedb88320L ^ (c >> 1); else c = c >> 1; } crc_table[n] = c; } crc_table_computed = 1; } /* Update a running CRC with the bytes buf[0..len-1]--the CRC should be initialized to all 1's, and the transmitted value is the 1's complement of the final running CRC (see the crc() routine below). */ unsigned long update_crc(unsigned long crc, unsigned char *buf, int len) { unsigned long c = crc; int n; if (!crc_table_computed) make_crc_table(); for (n = 0; n < len; n++) { c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8); } return c; } /* Return the CRC of the bytes buf[0..len-1]. */ unsigned long crc(unsigned char *buf, int len) { return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL; } //ref_end[<span style="color: #008000; text-decoration: underline;">http://www.[/color]] struct DATASTREAM { unsigned char ucSignature[8]; unsigned char ucChunkDataLength[4]; unsigned long ulChunkTypeAndChunkDataLength; unsigned char ucChunkTypeAndChunkData[4 + 32768]; unsigned char ucCrcInFile[4]; // CRC of ChunkType and ChunkData[In PNG Files] unsigned long ulCrcInFile; // CRC of ChunkType and ChunkData[In PNG Files] } datastream; int main(int argc, char* argv[]) { unsigned long ulCrcByCalc; // CRC of ChunkType and ChunkData[By Calculate] size_t freadsize = 0; // The number of full items actually read bool bCrcCheckResult = true; if(2 == argc) { // Check arg OK #ifdef _DEBUG printf("arg:%s %s[%d]\n", argv[0], argv[1], __LINE__); #endif } else { // Check arg NG printf("usage:%s path/file.png\n", argv[0], __LINE__); return false; } // Open for read (will fail if file does not exist) FILE *filestream = NULL; if( NULL != (filestream = fopen( argv[1], "rb" )) ) { #ifdef _DEBUG printf( "fopen OK[%d]\n", __LINE__); #endif } else { printf( "fopen NG[%d]\n", __LINE__); return false; } //Signature_start freadsize = fread( datastream.ucSignature, sizeof( char ), sizeof( datastream.ucSignature ), filestream); if(freadsize == sizeof( datastream.ucSignature )) { #ifdef _DEBUG printf( "fread OK:%s[%d]\n", "Signature", __LINE__); #endif if (datastream.ucSignature[0] == 0x89 && datastream.ucSignature[1] == 0x50 && datastream.ucSignature[2] == 0x4E && datastream.ucSignature[3] == 0x47 && datastream.ucSignature[4] == 0x0D && datastream.ucSignature[5] == 0x0A && datastream.ucSignature[6] == 0x1A && datastream.ucSignature[7] == 0x0A) { #ifdef _DEBUG printf( "check OK:%s[%d]\n", "Signature", __LINE__); #endif } else { printf( "check NG:%s[%d]\n", "Signature", __LINE__); return false; } } else { printf( "fread NG:%s[%d]\n", "Signature", __LINE__); return false; } //Signature_end do { //ChunkDataLength_start freadsize = fread( datastream.ucChunkDataLength, sizeof( char ), sizeof( datastream.ucChunkDataLength ), filestream); if(freadsize == sizeof( datastream.ucChunkDataLength )) { #ifdef _DEBUG printf( "fread OK:%s[%d]\n", "ChunkDataLength", __LINE__); #endif datastream.ulChunkTypeAndChunkDataLength = 4 + ( (datastream.ucChunkDataLength[0] << 24) | (datastream.ucChunkDataLength[1] << 16) | (datastream.ucChunkDataLength[2] << 8) | (datastream.ucChunkDataLength[3] ) ); //ChunkTypeAndChunkData_start freadsize = fread( datastream.ucChunkTypeAndChunkData, sizeof( char ), datastream.ulChunkTypeAndChunkDataLength, filestream); if(freadsize == datastream.ulChunkTypeAndChunkDataLength) { #ifdef _DEBUG printf( "fread OK:%s[%d]\n", "ChunkTypeAndChunkData", __LINE__); #endif for(int ii = 0; ii < 4; ii++) { printf("%c", datastream.ucChunkTypeAndChunkData[ii]); } //CrcInFile_start freadsize = fread( datastream.ucCrcInFile, sizeof( char ), sizeof( datastream.ucCrcInFile ), filestream); if(freadsize == sizeof( datastream.ucCrcInFile )) { #ifdef _DEBUG printf( "fread OK:%s[%d]\n", "CrcInFile", __LINE__); #endif datastream.ulCrcInFile = ( (datastream.ucCrcInFile[0] << 24) | (datastream.ucCrcInFile[1] << 16) | (datastream.ucCrcInFile[2] << 8) | (datastream.ucCrcInFile[3] ) ); ulCrcByCalc = crc( datastream.ucChunkTypeAndChunkData, datastream.ulChunkTypeAndChunkDataLength); if( ulCrcByCalc == datastream.ulCrcInFile ){ printf(" check OK!\n"); } else { bCrcCheckResult = false; printf(" check NG!\n"); printf("->CrcInFile:%08X\n", datastream.ulCrcInFile); printf("->CrcByCalc:%08X\n", ulCrcByCalc); } } else { printf( "fread NG:%s[%d]\n", "CrcInFile", __LINE__); return false; } //CrcInFile_end } else { printf( "fread NG:%s[%d]\n", "ChunkTypeAndChunkData", __LINE__); return false; } //ChunkTypeAndChunkData_end } else { printf( "fread NG:%s[%d]\n", "ChunkDataLength", __LINE__); return false; } //ChunkDataLength_end } while (!( datastream.ucChunkTypeAndChunkData[0] == 0x49 && // I datastream.ucChunkTypeAndChunkData[1] == 0x45 && // E datastream.ucChunkTypeAndChunkData[2] == 0x4E && // N datastream.ucChunkTypeAndChunkData[3] == 0x44)); // D // Close stream if it is not NULL if( filestream ) { if ( !fclose( filestream ) ) { #ifdef _DEBUG printf( "close OK[%d]\n", __LINE__); #endif } else { printf( "close NG(close failed)[%d]\n", __LINE__); return false; } } else { printf( "close NG(file pointer is null)[%d]\n", __LINE__); return false; } if( bCrcCheckResult ) { printf( "Everything OK!\n", __LINE__); } else { printf( "Something NG!\n", __LINE__); } return 0; }
用来编译以及运行的批处理的文件名:run.bat
程序代码:
@echo off cls if exist crccheck.exe del crccheck.exe cl crccheck.cpp echo ====== echo crccheck.exe ok.png crccheck.exe ok.png echo ====== echo crccheck.exe ng.png crccheck.exe ng.png echo ====== echo crccheck.exe not.png crccheck.exe not.png echo ====== echo crccheck.exe no.png crccheck.exe no.png echo ======
使用附件里的图片的运行结果
程序代码:
====== crccheck.exe ok.png IHDR check OK! sRGB check OK! gAMA check OK! pHYs check OK! IDAT check OK! IEND check OK! Everything OK! ====== crccheck.exe ng.png IHDR check NG! ->CrcInFile:4EB1AFF6 ->CrcByCalc:E4B1AFF6 sRGB check NG! ->CrcInFile:EACE1CE9 ->CrcByCalc:AECE1CE9 gAMA check NG! ->CrcInFile:B0FC6105 ->CrcByCalc:0BFC6105 pHYs check NG! ->CrcInFile:7C6FA864 ->CrcByCalc:C76FA864 IDAT check OK! IEND check NG! ->CrcInFile:EA426082 ->CrcByCalc:AE426082 Something NG! ====== crccheck.exe not.png check NG:Signature[114] ====== crccheck.exe no.png fopen NG[87] ======
ok.png【用Windows自带的画图工具生成的PNG文件】
ng.png【以ok.png为基础,用二进制编辑软件改动了PNG文件的CRC校验数据,为了对比,仅把头2个数字调换了一下】
not.png【用Windows自带的画图工具生成的Bitmap文件,将其扩展名改为png】
批处理中的no.png【是用来测试文件不存在的时候的输出的,测试时目录中不应该有这个文件】
有相同需求的朋友可以互相交流