这个是对文件进行hash
我们这里主要看加密算法,这里有十个加密算法。md2 md4 md5 sha1 sha224 sha256 sha384 sha512 crc32 adler32
前面八个都是用的系统的init update final 函数进行运算的。而后面两个是自己定义的api 为了配合定义的宏定义init_hash(Type,Init,Update,Final,Length)
这里有几个c数组。
int hash_type_total = 10;
void *ctx[hash_type_total];
int(*ctx_init[hash_type_total])(void *);
int(*ctx_update[hash_type_total])(void *, const void *, CC_LONG);
int(*ctx_final[hash_type_total])(unsigned char *, void *);
long digist_length[hash_type_total];
unsigned char *digest[hash_type_total];
ctx 数组装的是 void * 类型的指针
ctx_init 数组装的是 int ()(void *) 类型的指针
ctx_update 数组装的是 int ()(void *, const void *, CC_LONG) 类型指针
ctx_final 装的是int()(unsigned char *, void *) 类型的指针
看懂这里再往下看。
到#undef init_hash 行以前就是给这些数组赋值。这些数组保存的是函数指针
这里我们先学习下 md5 用CC_MD5_Init CC_MD5_Update CC_MD5_Final 使用
NSFileHandle *handle= [NSFileHandle fileHandleForReadingAtPath:path];
if(handle== nil ) {
return nil;
}
CC_MD5_CTX md5;
CC_MD5_Init(&md5);
BOOLdone=NO;
while(!done)
{
NSData*fileData= [handle readDataOfLength: 256 ];
CC_MD5_Update(&md5, [fileData bytes], [fileData length]);
if( [fileData length] == 0 )done=YES;
}
unsigned char digest[CC_MD5_DIGEST_LENGTH];
CC_MD5_Final(digest, &md5);
NSString*s= [NSString stringWithFormat: @"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
digest[0], digest[1],
digest[2], digest[3],
digest[4], digest[5],
digest[6], digest[7],
digest[8], digest[9],
digest[10], digest[11],
digest[12], digest[13],
digest[14], digest[15]];
这就是用法。我们看看yykit 大神怎么在这个里面干嘛。想要看懂这个函数。要了解c语言文件操作的几个函数。
函数原型:FILE * fopen(const char * path, const char * mode); 就是打开文件
int fseeko(FILE *stream, off_t offset, int fromwhere);
参数:
stream:文件指针
fromwhere:偏移起始位置
offset:偏移量
功能:函数设置文件指针stream的位置。如果执行成功,stream将指向以fromwhere(偏移起始位置:文件头0(SEEK_SET),当前位置1(SEEK_CUR),文件尾2(SEEK_END))为基准,偏移offset(指针偏移量)个字节的位置。如果执行失败(比如offset超过文件自身大小),则不改变stream指向的位置。
ftell
函数 ftell 用于得到文件位置指针当前位置相对于文件首的偏移字节数。
size_t****fread (****void********buffer,****size_tsize,****size_tcount,****FILE********stream) ;
buffer
用于接收数据的内存地址
size
要读的每个数据项的字节数,单位是字节
count
要读count个数据项,每个数据项size个字节.
stream
输入流
int feof(FILE *stream);
参数
流 :FILE结构的指针
feof是C语言标准库函数,其原型在stdio.h中,其功能是检测流上的文件结束符,如果文件结束,则返回非0值,否则返回0,文件结束符只能被clearerr()清除。
fd = fopen(path, "rb");
if (!fd) goto cleanup;
if (fseeko(fd, 0, SEEK_END) != 0) goto cleanup;
file_size = ftell(fd);
if (fseeko(fd, 0, SEEK_SET) != 0) goto cleanup;
if (file_size < 0) goto cleanup;
yykit 大神写的这段代码的意思 就是读取文件大小。
if (block) {
while (!done && !stop) {
size_t size = fread(buf, 1, BUF_SIZE, fd);
if (size < BUF_SIZE) {
if (feof(fd)) done = YES; // finish
else { stop = YES; break; } // error
}
for (int i = 0; i < hash_type_total; i++) {
if (ctx[i]) ctx_update[i](ctx[i], buf, (CC_LONG)size);
}
readed += size;
if (!done) {
loop++;
if ((loop % BLOCK_LOOP_FACTOR) == 0) {
block(file_size, readed, &stop);
}
}
}
}
要是配置block 的话。读取文件每次都去 BUF_SIZE =512k大小 将数据更新到update函数中
这里检查loop 次数。要是读取数据大于8M的话就回调一下block。
以md5加密为例最终结构都更新到CC_MD5_Update 函数中。
没有block 就是不用回调而已。用法一样不做介绍
最后就是收集数据了。
ctx_final[i](digest[i], ctx[i]); 已md5 为例。这个地方就是调用CC_MD5_Final()函数
NSUInteger type = 1 << I;
NSData *data = [NSData dataWithBytes:digest[i] length:digist_length[I]];
NSMutableString *str = [NSMutableString string];
unsigned char *bytes = (unsigned char *)data.bytes;
for (NSUInteger d = 0; d < data.length; d++) {
[str appendFormat:@"%02x", bytes[d]];
}
转换成最后的结果。
将结果保存到相关属性里面。
这里我们主要是要看看crc32 和Adler32 类型的算法
crc32 用法
Usage example:
uLong crc = crc32(0L, Z_NULL, 0);
while (read_buffer(buffer, length) != EOF) {
crc = crc32(crc, buffer, length);
}
if (crc != original_crc) error();
yykit大神将其拆解成 init update final 形式
adler32用法和 crc32 用法相同。
我们这里不对每个算法做原理分析和使用场景分析。
网友评论