Improve detection of the last slice

This commit is contained in:
Yutaka Sawada
2024-06-09 12:45:37 +09:00
committed by GitHub
parent 77e20ad55c
commit de3a853228

View File

@@ -1,5 +1,5 @@
// verify.c
// Copyright : 2022-10-14 Yutaka Sawada
// Copyright : 2024-06-09 Yutaka Sawada
// License : GPL
#ifndef _UNICODE
@@ -1253,21 +1253,22 @@ static int search_block_slide(
slice_ctx *sc)
{
unsigned char *buf, hash[16], hash2[16], err_mag, *short_use;
int i, j, find_num, find_flag, find_next, find_last, short_next;
int i, j, find_num, find_flag, find_next, find_last, short_next, short2_next, tmp_next;
int block_count, short_count, tiny_count, tiny_skip, num, i1, i2, i3, i4;
int *order, *index, index_shift;
unsigned int len, off, end_off, err_off;
unsigned int prev_crc, fail_count, rear_off, overlap_count;
unsigned int crc, *crcs, *short_crcs;
unsigned int time_last, time_slide;
__int64 file_off, file_next, short_off, fail_off;
__int64 file_off, file_next, short_off, short2_off, tmp_off, fail_off;
if (file_size + 1 < last_off + (__int64)(sc->min_size))
return 0; // 小さすぎるファイルは調べない
find_num = 0; // このファイル内で何ブロック見つけたか
find_next = -1; // 次に見つかると予想したブロックの番号
find_last = -1; // 最後に見つけたブロックの番号 (-1=不明)
short_next = -1;
short_next = -1; // 予想される末尾ブロックの番号
short2_next = -1;
fail_count = 0; // CRC は一致したけど MD5 が違った回数
fail_off = 0;
rear_off = 0;
@@ -1278,24 +1279,32 @@ static int search_block_slide(
find_last = find_next - 1; // 最後に見つけたブロックの番号
if ((last_off >= files[num1].size) || (last_off + block_size > file_size + 1))
find_next = -1; // 予想位置がファイル・サイズを超えると駄目
if ((last_size < block_size) && (files[num1].b_num >= 2) && // 末尾の半端なブロックの番号と想定位置
(last_off < files[num1].size) && (files[num1].size <= file_size + 1)){
short_next = files[num1].b_off + files[num1].b_num - 1; // 末尾ブロックの番号
if (find_next == short_next)
if ((last_size < block_size) && (last_off < files[num1].size)){ // 末尾の半端なブロックの番号と想定位置
tmp_next = files[num1].b_off + files[num1].b_num - 1; // 末尾ブロックの番号
if (find_next == tmp_next)
find_next = -1; // 予想が重複したら末尾ブロックとして探す
short_off = files[num1].size - last_size;
// ファイルサイズが1ブロック未満でも、同じサイズならエラー訂正を試みる
} else if ((last_off == 0) && (file_size == files[num1].size) && (file_size < (__int64)block_size)){
short_off = 0;
short_next = files[num1].b_off;
if ((files[num1].b_num >= 2) && (files[num1].size <= file_size + 1)){ // 本来の位置を調べる
short_next = tmp_next;
short_off = files[num1].size - last_size;
} else if ((last_off == 0) && (file_size == last_size)){ // ファイルが1ブロック未満でも、同じサイズならエラー訂正を試みる
short_next = tmp_next;
short_off = 0;
}
if (last_size < file_size){ // 末尾を調べる
short2_next = tmp_next;
short2_off = file_size - last_size;
}
}
if (file_size > files[num1].size){
rear_off = (unsigned int)((file_size - files[num1].size) % (__int64)block_size);
} else if (file_size < files[num1].size){
rear_off = block_size - (unsigned int)((files[num1].size - file_size) % (__int64)block_size);
}
//printf("file = %d, find_next = %d, find_last = %d\n", num1, find_next, find_last);
//printf("short_off = %I64d, short_next = %d, rear_off = %d\n", short_off, short_next, rear_off);
/* printf("file = %d, find_next = %d, find_last = %d, rear_off = %d\n", num1, find_next, find_last, rear_off);
if (short_next >= 0)
printf("short_off = %I64d, short_next = %d\n", short_off, short_next);
if (short2_next >= 0)
printf("short2_off = %I64d, short2_next = %d\n", short2_off, short2_next);*/
}
file_off = last_off; // 検査開始位置から調べる
buf = sc->buf;
@@ -1374,8 +1383,11 @@ static int search_block_slide(
if (last_off < file_off + last_size)
last_off = file_off + last_size; // 一番大きな半端なブロックの終端
find_next = -2; // 小さなファイルが見つかった = ブロック検出の予想が外れた
if (i == short_next)
short_next = -1; // 末尾ブロックは検出済み
if (i == short_next){ // この末尾ブロックは検出済み
short_next = -1;
} else if (i == short2_next){
short2_next = -1;
}
// 経過表示
if (GetTickCount() - time_last >= UPDATE_TIME){
@@ -1416,7 +1428,7 @@ static int search_block_slide(
// ブロック・サイズごとに探す
if (((block_count > 0) && ((file_off + (__int64)block_size <= file_size)
|| (find_next >= 0))) || (short_next >= 0)){ // ブロックの位置を予想して探す
|| (find_next >= 0))) || (short_next >= 0) || (short2_next >= 0)){ // ブロックの位置を予想して探す
// 前からスライドさせながらチェックサムを比較する
//printf("slide search from %I64d, file %d, next = %d\n", file_off, num1, find_next);
off = 0; // buf 内でのオフセット
@@ -1445,8 +1457,13 @@ static int search_block_slide(
while (off < end_off){
find_flag = -2;
// 次の番号のブロックがその位置にあるかを先に調べる (発見済みでも)
if ((short_next >= 0) && (file_off + off == short_off)){ // 半端なブロックなら
i = short_next;
if (((short_next >= 0) && (file_off + off == short_off)) ||
((short2_next >= 0) && (file_off + off == short2_off))){ // 半端なブロックなら
if ((short_next >= 0) && (file_off + off == short_off)){
i = short_next;
} else {
i = short2_next;
}
num = s_blk[i].file;
if ((short_use[num] & 4) == 0){ // パディング部分を取り除いた CRC-32 を逆算する
short_crcs[num] = crc_reverse_zero(s_blk[i].crc, block_size - s_blk[i].size);
@@ -1456,7 +1473,8 @@ static int search_block_slide(
find_flag = correct_error(buf + off, s_blk[i].size, s_blk[i].hash, short_crcs[num], &err_off, &err_mag);
if (find_flag == 0)
find_flag = 2;
} else if ((find_next >= 0) && (file_off + off == last_off)){ // フルサイズのブロックなら
}
if ((find_flag < 0) && (find_next >= 0) && (file_off + off == last_off)){ // フルサイズのブロックなら
i = find_next;
if (crc == s_blk[i].crc){
data_md5(buf + off, block_size, hash);
@@ -1661,20 +1679,81 @@ static int search_block_slide(
find_next = i + 1;
if ((find_next >= source_num) || (s_blk[find_next].file != num)){
// 最後までいった、またはファイルが異なる
short_next = -1;
find_next = -1;
if ((short_next >= 0) && ((s_blk[short_next].exist & 0x1000) != 0))
short_next = -1;
if ((short2_next >= 0) && ((s_blk[short2_next].exist & 0x1000) != 0))
short2_next = -1;
} else if (s_blk[find_next].size < block_size){ // 半端なブロックは別に調べる
short_next = find_next;
short_off = file_off + off + block_size;
//printf("short_off = %I64d, short_next = %d, file = %d\n", short_off, short_next, num);
if (file_off + off + block_size + s_blk[find_next].size <= file_size){ // ファイル内に収まってる時だけ
tmp_next = find_next;
tmp_off = file_off + off + block_size;
if (find_flag <= 3){ // 順当な位置で見つけた場合
if ((tmp_next == short_next) && (tmp_off == short_off)){
// 予測済みのと一致するなら何もしない
} else if ((short_next >= 0) && (short2_next < 0)){ // 予測と異なるけど、別のが空いてるなら、そっちに記録する
//printf("short2_off = %I64d, short2_next = %d, file = %d\n", tmp_off, tmp_next, num);
short2_next = tmp_next;
short2_off = tmp_off;
} else {
if ((short_next >= 0) && (tmp_next == short2_next) && (tmp_off == short2_off)){ // 既に予測済みのと一致するなら入れ替える
short2_next = short_next;
short2_off = short_off;
//printf("exchange short2_off = %I64d, short2_next = %d\n", short2_off, short2_next);
}
//printf("short_off = %I64d, short_next = %d, file = %d\n", tmp_off, tmp_next, num);
short_next = tmp_next;
short_off = tmp_off;
}
} else if ((short_next < 0) &&
(((__int64)block_size * (__int64)(tmp_next - files[num].b_off) == tmp_off) ||
(tmp_off + s_blk[tmp_next].size == file_size))){
// 検出ブロックが順当でなくても、末尾ブロックの開始位置や末端がファイル・サイズに一致すれば
//printf("short_off = %I64d, short_next = %d, file = %d\n", tmp_off, tmp_next, num);
short_next = tmp_next;
short_off = tmp_off;
} else {
//printf("short2_off = %I64d, short2_next = %d, file = %d\n", tmp_off, tmp_next, num);
short2_next = tmp_next;
short2_off = tmp_off;
}
}
find_next = -1;
} else {
short_next = files[num].b_off + files[num].b_num - 1; // 末尾ブロックの番号
if (s_blk[short_next].size < block_size){ // 半端なブロックは別に調べる
short_off = file_off + off + (__int64)(short_next - i) * (__int64)block_size;
//printf("short_off = %I64d, short_next = %d, file = %d\n", short_off, short_next, num);
} else {
short_next = -1;
tmp_next = files[num].b_off + files[num].b_num - 1; // 末尾ブロックの番号
if (s_blk[tmp_next].size < block_size){ // 半端なブロックは別に調べる
tmp_off = file_off + off + (__int64)(tmp_next - i) * (__int64)block_size;
if (tmp_off + s_blk[tmp_next].size <= file_size){ // ファイル内に収まってる時だけ
if (find_flag <= 3){ // 順当な位置で見つけた場合
if ((tmp_next == short_next) && (tmp_off == short_off)){
// 予測済みのと一致するなら何もしない
} else if ((short_next >= 0) && (short2_next < 0)){ // 予測と異なるけど、別のが空いてるなら、そっちに記録する
//printf("far short2_off = %I64d, short2_next = %d, file = %d\n", tmp_off, tmp_next, num);
short2_next = tmp_next;
short2_off = tmp_off;
} else {
if ((short_next >= 0) && (tmp_next == short2_next) && (tmp_off == short2_off)){ // 既に予測済みのと一致するなら入れ替える
short2_next = short_next;
short2_off = short_off;
//printf("exchange short2_off = %I64d, short2_next = %d\n", short2_off, short2_next);
}
//printf("far short_off = %I64d, short_next = %d, file = %d\n", tmp_off, tmp_next, num);
short_next = tmp_next;
short_off = tmp_off;
}
} else if ((short_next < 0) &&
(((__int64)block_size * (__int64)(tmp_next - files[num].b_off) == tmp_off) ||
(tmp_off + s_blk[tmp_next].size == file_size))){
// 検出ブロックが順当でなくても、末尾ブロックの開始位置や末端がファイル・サイズに一致すれば
//printf("far short_off = %I64d, short_next = %d, file = %d\n", tmp_off, tmp_next, num);
short_next = tmp_next;
short_off = tmp_off;
} else if ((short2_next != tmp_next) || (short2_off != tmp_off)){
//printf("far short2_off = %I64d, short2_next = %d, file = %d\n", tmp_off, tmp_next, num);
short2_next = tmp_next;
short2_off = tmp_off;
}
}
}
}
tiny_skip = 0; // 小さなファイルをブロック直後に一回だけ探す