/* 判斷長度爲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;
}