/* 判断长度为entrylen的entry字符串能否转换为数值,转换结果保存在v中 编码方式保存在encoding中 */
static int zipTryEncoding(unsigned char *entry, unsigned int entrylen, long long *v, unsigned char *encoding) {
long long value;
if (entrylen >= 32 || entrylen == 0)
return 0;
if (string2ll((char *)entry, entrylen, &value)) {
if (value >= 0 && value <= 12) {
*encoding = ZIP_INT_IMM_MIN + value;
} else if (value >= INT8_MIN && value <= INT8_MAX) {
*encoding = ZIP_INT_8B;
} else if (value >= INT16_MIN && value <= INT16_MAX) {
*encoding = ZIP_INT_16B;
} else if (value >= INT24_MIN && value <= INT24_MAX) {
*encoding = ZIP_INT_24B;
} else if (value >= INT32_MIN && value <= INT32_MAX) {
*encoding = ZIP_INT_32B;
} else {
*encoding = ZIP_INT_64B;
}
*v = value;
return 1;
}
return 0;
}
/* 将长度为slen的字符串s转换为long long类型的整数,
成功:返回1,
失败:返回0 */
int string2ll(const char *s, size_t slen, long long *value) {
const char *p = s;
size_t plen = 0;
int negative = 0;
unsigned long long v; /* 注意v的数据类型是无符号的,返回值value是有符号的,两者表示的数的范围是不一样的 */
/* 字符串长度为0,无需进行转换 */
if (plen == slen)
return 0;
/* 字符串长度为1,且第一个字符为0,直接转换为0
认为此处的判断可以省略,因为下文中有该条件的判断,且放在下面是合理的 */
if (slen == 1 && p[0] == '0') {
if (value != NULL)
*value = 0;
return 1;
}
/* 如果为负数,记录负数标识,
如果只有一个符号,即字符串长度为1,函数返回 */
if (p[0] == '-') {
negative = 1;
p++;
plen++;
if (plen == slen)
return 1;
}
/* 判断字符串中字符是否是数字字符 */
if (p[0] >= '1' && p[0] <= '9') { /* 第一个字符是数字字符'1'到'9',转换继续 */
v = p[0] - '0';
p++;
plen++;
} else if (p[0] == '0' && slen == 1) { /* 第一个字符是数字字符'0'且长度为1时,转换结果是0 */
*value = 0;
return 1;
} else { /* 第一个字符不是数字字符,直接返回0 */
return 0;
}
/* 循环进行字符串转换为数字 */
while (plen < slen && p[0] >= '0' && p[0] <= '9') {
/* 因为下一步操作是v *= 10,所以在执行下一步的操作之前,判断如果执行下一步操作是否会出现溢出*/
if (v > (ULLONG_MAX / 10)) /* 如果可能溢出,则返回0 */
return 0;
v *= 10; /* 字符串中先出现的字符是高位,所以先把已经转换好的数值*10 */
if (v > (ULLONG_MAX - (p[0] - '0'))) /* 进行下一步操作之前首先判断是否会溢出 */
return 0;
v += p[0] - '0';
p++; /* 字符往下走一个,已经处理的字符长度也+1 */
plen++;
}
if (plen < slen) /* 说明字符串还没有完全转换为整数的时候,出现了非数字字符,程序返回0 */
return 0;
/* 对函数的正负数进行处理 */
if (negative) {
/* 如果是负数,先判断v变成负数之前是否会溢出
这里需要理解的是,为什么判断条件不是v > (unsigned long long)(-LLONG_MIN)?
理解:以一个有符号的1字节数为例,其取值范围是-128~127,如果是最小值直接取反,
即-(-128)=128,因为最大值是127,此时就出现了溢出。
这里最后+1的操作,使用了运算的方式,将数值转换为无符号数,就不会导致数值的溢出 */
/* 一下是测试的程序:
#include <stdio.h>
#include <limits.h>
int main()
{
printf("%lld\n", LLONG_MIN);
printf("%lld", (unsigned long long)(-LLONG_MIN));
printf("%lld\n", ((unsigned long long)(-(LLONG_MIN + 1)) + 1));
return 0;
}
执行结果:
limit.c: In function ‘main’:
limit.c:7:41: warning: integer overflow in expression [-Woverflow]
printf("%lld", (unsigned long long)(-LLONG_MIN));*/
if (v > ((unsigned long long)(-(LLONG_MIN + 1)) + 1))
return 0;
if (value != NULL)
*value = -v;
} else {
if (v > LLONG_MAX) /* 如果是整数,判断是否大于有符号数的最大值,大于的话,直接返回0 */
return 0;
if (value != NULL)
*value = v;
}
return 1;
}