/*
问题:一张PNG图片HIDR Chunk中的数据为:
00 00 00 0D 49 48 44 52 00 00 00 DC 00 00 00 DC 10 06 00 00 00 4B CA 13 C2
Chunk Type Code域和Chunk Data部分是:49 48 44 52 00 00 00 DC 00 00 00 DC 10 06 00 00 00
如何验证用该数据计算得到的CRC校验码是:4B CA 13 C2 ?
下面是代码验证过程代码和总结。
方法:用比较法来验证,为了得到结果综合法分析结合转换思想,逐步推进。
*/
# include <stdio.h>
# include <string.h>
/*1.char*,unsigned char*,char,unsigned char的理解
char*,unsigned char*记录的就是二进制转换到的十六进制的字节码[整(整数补码(正整数还是原码负整数补码),浮点数IEEE74原码,字符编码原码),
存放顺序是先入先存放的,超过一个字节就会区分大小端存放。char*,unsigned char*指针转换到char,unsigned char会转换到字符类型。
但是char,unsigned char整数运算还是十六进制的字节码(包括位运算之类),所以可以提供十六进制整数序列,用整数指针访问序列每个元素(对于十六进制的字节码直接进行CRC计算。
如果希望char,unsigned char整数运算,能得到从整数来的值那么需要截取一个字节来处理;或者采用结构体赋予整型值放置在内存或者二进制文件中读取出来,然后一个个char,unsigned char整数运算
处理。
2.大小端转换,png图片数据是用Big-Endian存储数值数据的需要转换为大端模式。
数值数据存在大小端区别,CC++结构体存储数值数据到二进制文件中,是以小端模式存放的,其实内存中也是小端模式的字节存放的(主流的CPU都这样);而PNG数值类型数据是以
大端模式存放的,所以从二进制文件中读取出来的时候需要经过大端到小端的转换,写入到png文件中的时候需要经过小端到大端的转换,而png的一些基于二进制CRC校验
都是在大端模式下的缓存块中进行的(压缩不确定是否如此,应该是在小端模式下进行压缩编码的)。
3.结构体内存对齐,结构体在内存中本身存在内存对齐,所以写入到二进制文件中也有内存对齐问题, 读取出来时候需要减掉得到真实有用数据。
结构体内存对齐参数由#pragma pack(8)决定默认是8
1)第一个是系统找一个以对齐参数N倍数的地址为初地址(首地址偏移为0),后面的地址依次用min(N,本成员)作为实际对齐参数,该参数首个倍数地址(从首地址偏移)作为成员内存地址;
2) 内存对齐最终大小,是max(n1,n2,n3,...)最大元素的整数倍,不够后面就补0字节。
特殊:
1)嵌套结构体是作为一个递归成员,内部成员大小为n自身对齐min(n,N)。但是内部第一个偏移:将内部最大作为n最终取min(n,N)作为对齐参数,首个倍数地址为内存地址。
内部右边界到外部第一个偏移:用的就是外部的成员作为n最终取min(n,N),首个倍数地址作为内存地址。
2) 数组成员(拆分):包含数组时候,整个数组不是作为一个成员,而是里面的每个元素作为一个结构体成员。
3) 有位段时的对齐规则(组合):同类型的、相邻的可连续在一个类型的存储空间中存放的位段成员作为一个该类型的成员变量来对待, 不是同类型的、相邻的位段成员,分别当作一个单独得该类型的成员来对待,分配一个完整的类型空间,其长度为该类型的长度,其他成员的分配规则不变,仍然按照前述的对齐规则进行。
*/
typedef unsigned int uint ;
typedef unsigned char BYTE ;
static uint POLYNOMIAL = 0xEDB88320 ;
uint g_CRCTable[256] ;
// 定义4MB 4194304为最大读取,如果大于也是读取4MB内容作为CRC计算
#define MAXLEN 1024
#define SToB_32(digitalValue) (uint((BYTE)digitalValue) << 24 \
| uint((BYTE)digitalValue >> 8) << 16\
| uint((BYTE)digitalValue >> 16) << 8\
| uint((BYTE)digitalValue >> 24))
void init_table()
{
int i, j, crc ;
for (i = 0 ; i < 256 ; i++)
for (j = 0, g_CRCTable[i] = i ; j < 8 ; j++)
g_CRCTable[i] = (g_CRCTable[i]>>1)^((g_CRCTable[i]&1)?POLYNOMIAL:0) ;
}
uint crc32(uint crc, char *buff, int len)
{
crc = ~crc;
for (int i = 0; i < len; i++)
{
int data = buff[i];
crc = (crc >> 8) ^ g_CRCTable[(crc ^ buff[i]) & 0xff];
}
return ~crc;
}
uint crc32_foruint(uint crc, unsigned int data[], int len)
{
crc = ~crc;
for (int i = 0; i < len; i++)
{
int nData = data[i];
crc = (crc >> 8) ^ g_CRCTable[(crc ^ data[i]) & 0xff];
}
return ~crc;
}
uint crc32_fromFile(const char *pDestPath, int nAlignWidth)
{
uint crcValue = 0;
FILE *pFile = NULL;
pFile = fopen(pDestPath, "rb");
if(pFile == NULL)
{
printf("fopen:%s fail!", pDestPath);
return 0;
}
fseek(pFile,0L, SEEK_END);
int nFileLenght = ftell(pFile) - nAlignWidth; //减去结构体对齐大小
fseek(pFile,0L, SEEK_SET);
if(nFileLenght > MAXLEN)
{
printf("File: %s 's size is bigger than %u byte.", pDestPath, unsigned int(MAXLEN));
}
char buffer[MAXLEN];
fread(buffer, sizeof(char), nFileLenght, pFile);
fclose(pFile);
crcValue = crc32(crcValue, buffer, nFileLenght);
return crcValue;
}
bool writetofile(const char *pDestPath, unsigned char buffer[], int count)
{
FILE *pFile = NULL;
pFile = fopen(pDestPath, "wb");
if(pFile == NULL)
{
printf("fopen or create:%s fail!", pDestPath);
return false;
}
fwrite(buffer, sizeof(unsigned char), count, pFile);
fclose(pFile);
return true;
}
int main ()
{
// 初始化表
init_table();
char s[] = "aaaaaa";
printf("%08X\n", crc32(0, s, strlen(s)));
unsigned int crcFileValue = crc32_fromFile("f:\\data\\testcrc.txt", 0);// testcrc.txt里面是aaaaaaa
printf("%08X\n",crcFileValue);
// arrayData是PNG图片的IHDR数据块的Chunk Type Code域和Chunk Data域中的数据
// 含义:0x49,0x48,0x44,0x52是"IHDR"Chunk块标志位,0x00,0x00,0x00,0xDC是PNG的Big-Endian表示的宽220pixel
// 高也是220pixel,深度是0x10真彩色,颜色类型是0x06带a类型的真彩色,0x00表示用Deflate压缩编码压缩图像数据
// 0x00表示将来使用更好的压缩方法预留,0x00表示非隔行扫描.
unsigned int arrayData[17] = {/*0x00,0x00,0x00,0x0D,*/0x49,0x48,0x44,0x52,0x00,0x00,0x00,\
0xDC,0x00,0x00,0x00,0xDC,0x10,0x06,0x00,0x00,0x00};// 图像中的CRC为 0x4BCA13C2
unsigned int crcValue = crc32_foruint(0, arrayData, 17);
printf("%08X\n", crcValue);// 验证输出确实为0x4BCA13C2,也是crcValue的Big-Endian模式的一个输出。
struct tagFileHead
{
unsigned char mark[4];
unsigned int widthPixel;
unsigned int heightPixel;
unsigned char methon[5];
};
tagFileHead fileHead;
fileHead.mark[0] = 'I';
fileHead.mark[1] = 'H';
fileHead.mark[2] = 'D';
fileHead.mark[3] = 'R';
fileHead.widthPixel = SToB_32(220);
fileHead.heightPixel = SToB_32(220);
fileHead.methon[0] = 16;
fileHead.methon[1] = 6;
fileHead.methon[2] = 0;
fileHead.methon[3] = 0;
fileHead.methon[4] = 0;
/*fileHead.methon[4] = NULL;
fileHead.methon[4] = 0;
fileHead.methon[4] = 0;*/
const char *pDestPath = "f:\\data\\crc";
FILE *pFile = fopen(pDestPath, "wb");
if(pFile == NULL)
{
printf("fopen or create:%s fail!", pDestPath);
return false;
}
fwrite((void*)&fileHead, sizeof(tagFileHead), 1, pFile);
fclose(pFile);
unsigned int crcFileValue2 = crc32_fromFile("f:\\data\\crc", 3);
printf("%08X\n",crcFileValue2);
return 0 ;
}
;