| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 1540 人关注过本帖
标题:【原创】用C语言对 PNG 文件里面的各段数据的 CRC 进行检查
只看楼主 加入收藏
日知己所无
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:贵宾
威 望:38
帖 子:427
专家分:2071
注 册:2014-3-22
结帖率:92.86%
收藏
已结贴  问题点数:20 回复次数:2 
【原创】用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【是用来测试文件不存在的时候的输出的,测试时目录中不应该有这个文件】

有相同需求的朋友可以互相交流
搜索更多相关主题的帖子: Microsoft Windows 运行环境 源代码 C语言 
2014-06-14 22:39
日知己所无
Rank: 11Rank: 11Rank: 11Rank: 11
等 级:贵宾
威 望:38
帖 子:427
专家分:2071
注 册:2014-3-22
收藏
得分:0 
这里的CRC-32算法,参考了http://www.这个网页
2014-06-14 22:43
砖家的谎言
Rank: 12Rank: 12Rank: 12
等 级:禁止访问
威 望:30
帖 子:693
专家分:3898
注 册:2013-12-6
收藏
得分:20 
没看太懂,希望有能力的来帮楼主解释下

我不是砖家,要努力成为砖家。
2014-06-15 09:17
快速回复:【原创】用C语言对 PNG 文件里面的各段数据的 CRC 进行检查
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.027896 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved