Files
MultiPar/source/sfv_md5/verify.c
2024-11-30 13:08:09 +09:00

970 lines
31 KiB
C

// verify.c
// Copyright : 2024-11-30 Yutaka Sawada
// License : The MIT license
#ifndef _UNICODE
#define _UNICODE
#endif
#ifndef UNICODE
#define UNICODE
#endif
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0601 // Windows 7 or later
#endif
#include <stdio.h>
#include <windows.h>
#include "common.h"
#include "crc.h"
#include "verify.h"
#include "ini.h"
#include "phmd5.h"
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// CRC-32 を比較する
// 0 = ファイルが存在して完全である
// 1 = ファイルが存在しない
// 2 = ファイルが破損してる
static int file_crc32_check(
int num,
char *ascii_name,
wchar_t *uni_name,
wchar_t *file_path,
unsigned int crc2)
{
unsigned char buf[IO_SIZE];
int len, off, bad_flag;
unsigned int crc, time_last, meta_data[7];
__int64 file_size = 0, file_left;
HANDLE hFile;
prog_last = -1;
time_last = GetTickCount() / UPDATE_TIME; // 時刻の変化時に経過を表示する
wcscpy(file_path, base_dir);
// 先頭の「..\」を許可してるので、基準ディレクトリから上に遡る。
len = base_len - 1;
off = 0;
while ((uni_name[off] == '.') && (uni_name[off + 1] == '.') && (uni_name[off + 2] == '\\')){
off += 3;
file_path[len] = 0;
while (file_path[len] != '\\'){
file_path[len] = 0;
len--;
}
}
wcscat(file_path, uni_name + off);
// 読み込むファイルを開く
hFile = CreateFile(file_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE){
bad_flag = 1; // 消失は記録しない
} else {
bad_flag = check_ini_state(num, meta_data, hFile);
memcpy(&file_size, meta_data, 8);
if (bad_flag == -2){ // 記録が無い場合 (属性取得エラーは不明にする)
file_left = file_size;
crc = 0xFFFFFFFF; // 初期化
while (file_left > 0){
len = IO_SIZE;
if (file_left < IO_SIZE)
len = (int)file_left;
if (!ReadFile(hFile, buf, len, &bad_flag, NULL) || (len != bad_flag))
break; // 読み取りエラーは必ず破損になる
file_left -= len;
// CRC-32 を更新する
crc = crc_update(crc, buf, len);
// 経過表示
if (GetTickCount() / UPDATE_TIME != time_last){
if (print_progress_file((int)(((file_size - file_left) * 1000) / file_size), uni_name)){
CloseHandle(hFile);
return 2;
}
time_last = GetTickCount() / UPDATE_TIME;
}
}
crc ^= 0xFFFFFFFF; // 最終処理
if ((crc != crc2) || (file_left > 0)){
bad_flag = 2; // ハッシュ値が異なる、または途中まで
} else {
bad_flag = 0; // 完全
}
write_ini_state(num, meta_data, bad_flag); // 検査結果を記録する、完全か破損
}
CloseHandle(hFile);
}
switch (bad_flag){
case 0:
printf("%13I64d Complete : \"%s\"\n", file_size, ascii_name);
break;
case 1:
printf(" 0 Missing : \"%s\"\n", ascii_name);
bad_flag = 4 | 8;
break;
case 2:
printf("%13I64d Damaged : \"%s\"\n", file_size, ascii_name);
bad_flag = 4;
break;
default: // IOエラー等
printf(" ? Unknown : \"%s\"\n", ascii_name);
bad_flag = 4;
break;
}
fflush(stdout);
return bad_flag;
}
// SFV ファイル
int verify_sfv(
char *ascii_buf,
wchar_t *file_path)
{
wchar_t *line_off, uni_buf[MAX_LEN];
unsigned int err = 0, rv, line_len, name_len, crc, line_num, num, comment;
// ファイル数を調べる
comment = 0;
num = 0;
line_num = 1;
line_off = text_buf;
while (*line_off != 0){ // 一行ずつ処理する
line_len = 0;
while (line_off[line_len] != 0){ // 改行までを一行とする
if (line_off[line_len] == '\n')
break;
if (line_off[line_len] == '\r')
break;
line_len++;
}
// 行の内容が適正か調べる
if (line_off[0] == ';'){ // コメント
if (((comment & 1) == 0) && (line_len > 8) && (line_len < MAX_LEN)){
// クリエイターの表示がまだなら
if (wcsncmp(line_off, L"; Generated by ", 15) == 0){ // WIN-SFV32, SFV32nix
wcsncpy(uni_buf, line_off + 15, line_len - 15);
uni_buf[line_len - 15] = 0;
comment |= 1;
} else if (wcsncmp(line_off, L"; Using ", 8) == 0){
wcsncpy(uni_buf, line_off + 8, line_len - 8);
uni_buf[line_len - 8] = 0;
comment |= 1; // 同一行を二度表示しない
}
if (comment & 1){
uni_buf[COMMENT_LEN - 1] = 0; // 表示する文字数を制限する
utf16_to_cp(uni_buf, ascii_buf, COMMENT_LEN * 3, cp_output);
printf("Creator : %s\n", ascii_buf);
comment |= 4;
}
}
if (((comment & 6) == 0) && (line_len < MAX_LEN)){
// 最初のコメントの表示がまだなら
crc = 1;
while (crc < line_len){
if (line_off[crc] != ' ')
break;
crc++;
}
if (crc < line_len){
wcsncpy(uni_buf, line_off + crc, line_len - crc);
uni_buf[line_len - crc] = 0;
uni_buf[COMMENT_LEN - 1] = 0; // 表示する文字数を制限する
utf16_to_cp(uni_buf, ascii_buf, COMMENT_LEN * 3, cp_output);
printf("Comment : %s\n", ascii_buf);
}
comment |= 2; // 「;」だけの行も認識する
}
comment &= ~4; // bit 4 を消す
} else if ((line_len > 9) && (line_off[line_len - 9] == ' ') // CRC の前がスペース
&& (base16_len(line_off + (line_len - 8)) == 8)){ // 16進数で8文字
// ファイル名
name_len = line_len - 9;
if (base_len + name_len < MAX_LEN){
while (line_off[name_len - 1] == ' ')
name_len--;
// ファイル名の前後が「"」で囲まれてる場合は取り除く
if ((line_off[0] == '"') && (line_off[name_len - 1] == '"')){
name_len -= 2;
wcsncpy(uni_buf, line_off + 1, name_len);
} else {
wcsncpy(uni_buf, line_off, name_len);
}
uni_buf[name_len] = 0;
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
if (rv > 1){
if ((comment & 8) == 0){
comment |= 8;
printf("\nWarning about filenames :\n");
}
if (rv == 16){
printf("line%d: filename is invalid\n", line_num);
num++; // 浄化できないファイル名
} else if ((rv & 6) == 0){
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
printf("line%d: \"%s\" is invalid\n", line_num, ascii_buf);
} else {
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
printf("line%d: \"%s\" was sanitized\n", line_num, ascii_buf);
}
}
if (rv != 16)
file_num++;
} else {
if ((comment & 8) == 0){
comment |= 8;
printf("\nWarning about filenames :\n");
}
printf("line%d: filename is invalid\n", line_num);
num++; // 長すぎるファイル名
}
} else if (line_len > 0){
//printf("line %d is invalid\n", line_num);
num++; // 内容が認識できない行
}
// 次の行へ
line_off += line_len;
if (*line_off == '\n')
line_off++;
if (*line_off == '\r'){
line_off++;
if (*line_off == '\n') // 「\r\n」を一つの改行として扱う
line_off++;
}
line_num++;
}
if (comment & 8)
printf("\n");
// チェックサム・ファイルの状態
if (num == 0){
printf("Status : Good\n");
} else {
printf("Status : Damaged\n");
err |= 16; // 後で 256に変更する
}
if (file_num == 0){
printf("valid file is not found\n");
return 1;
}
printf("\nInput File list : %d\n", file_num);
printf(" CRC-32 : Filename\n");
fflush(stdout);
line_off = text_buf;
while (*line_off != 0){ // 一行ずつ処理する
line_len = 0;
while (line_off[line_len] != 0){ // 改行までを一行とする
if (line_off[line_len] == '\n')
break;
if (line_off[line_len] == '\r')
break;
line_len++;
}
// 行の内容が適正か調べる
if ((line_off[0] != ';') && // コメントではない
(line_len > 9) && (line_off[line_len - 9] == ' ') // CRC の前がスペース
&& (base16_len(line_off + (line_len - 8)) == 8)){ // 16進数で8文字
// ファイル名
name_len = line_len - 9;
if (base_len + name_len < MAX_LEN){
while (line_off[name_len - 1] == ' ')
name_len--;
// ファイル名の前後が「"」で囲まれてる場合は取り除く
if ((line_off[0] == '"') && (line_off[name_len - 1] == '"')){
name_len -= 2;
wcsncpy(uni_buf, line_off + 1, name_len);
} else {
wcsncpy(uni_buf, line_off, name_len);
}
uni_buf[name_len] = 0;
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
if (rv != 16){
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
// CRC
crc = get_val32h(line_off + (line_len - 8));
printf("%08X : \"%s\"\n", crc, ascii_buf);
}
}
}
// 次の行へ
line_off += line_len;
if (*line_off == '\n')
line_off++;
if (*line_off == '\r'){
line_off++;
if (*line_off == '\n') // 「\r\n」を一つの改行として扱う
line_off++;
}
}
printf("\nVerifying Input File :\n");
printf(" Size Status : Filename\n");
fflush(stdout);
if (recent_data != 0){ // 前回の検査結果を使うなら
PHMD5 ctx;
// チェックサム・ファイル識別用にハッシュ値を計算する
Phmd5Begin(&ctx);
Phmd5Process(&ctx, (unsigned char *)text_buf, text_len * 2);
Phmd5End(&ctx);
// 前回の検査結果が存在するか
check_ini_file(ctx.hash, text_len);
}
num = 0;
line_off = text_buf;
while (*line_off != 0){ // 一行ずつ処理する
line_len = 0;
while (line_off[line_len] != 0){ // 改行までを一行とする
if (line_off[line_len] == '\n')
break;
if (line_off[line_len] == '\r')
break;
line_len++;
}
// 行の内容が適正か調べる
if ((line_off[0] != ';') && // コメントではない
(line_len > 9) && (line_off[line_len - 9] == ' ') // CRC の前がスペース
&& (base16_len(line_off + (line_len - 8)) == 8)){ // 16進数で8文字
// ファイル名
name_len = line_len - 9;
if (base_len + name_len < MAX_LEN){
while (line_off[name_len - 1] == ' ')
name_len--;
// ファイル名の前後が「"」で囲まれてる場合は取り除く
if ((line_off[0] == '"') && (line_off[name_len - 1] == '"')){
name_len -= 2;
wcsncpy(uni_buf, line_off + 1, name_len);
} else {
wcsncpy(uni_buf, line_off, name_len);
}
uni_buf[name_len] = 0;
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
if (rv != 16){
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
// CRC
crc = get_val32h(line_off + (line_len - 8));
rv = file_crc32_check(num, ascii_buf, uni_buf, file_path, crc);
if (rv & 3){
err = rv;
break;
}
if (rv & 0xC){ // Missing or Damaged
err |= rv;
err += 0x100;
}
num++;
}
}
}
// 次の行へ
line_off += line_len;
if (*line_off == '\n')
line_off++;
if (*line_off == '\r'){
line_off++;
if (*line_off == '\n') // 「\r\n」を一つの改行として扱う
line_off++;
}
}
return err;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// MD5 を比較する
// 0 = ファイルが存在して完全である
// 1 = ファイルが存在しない
// 2 = ファイルが破損してる
static int file_md5_check(
int num,
char *ascii_name,
wchar_t *uni_name,
wchar_t *file_path,
unsigned char *hash)
{
unsigned char buf[IO_SIZE];
int len, off, bad_flag;
unsigned int time_last, meta_data[8];
__int64 file_size = 0, file_left;
HANDLE hFile;
PHMD5 ctx;
prog_last = -1;
time_last = GetTickCount() / UPDATE_TIME; // 時刻の変化時に経過を表示する
wcscpy(file_path, base_dir);
// 先頭の「..\」を許可してるので、基準ディレクトリから上に遡る。
len = base_len - 1;
off = 0;
while ((uni_name[off] == '.') && (uni_name[off + 1] == '.') && (uni_name[off + 2] == '\\')){
off += 3;
file_path[len] = 0;
while (file_path[len] != '\\'){
file_path[len] = 0;
len--;
}
}
wcscat(file_path, uni_name + off);
//printf("path = \"%S\"\n", file_path);
// 読み込むファイルを開く
hFile = CreateFile(file_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE){
bad_flag = 1; // 消失は記録しない
} else {
bad_flag = check_ini_state(num, meta_data, hFile);
memcpy(&file_size, meta_data, 8);
if (bad_flag == -2){ // 記録が無い場合 (属性取得エラーは不明にする)
file_left = file_size;
Phmd5Begin(&ctx); // 初期化
while (file_left > 0){
len = IO_SIZE;
if (file_left < IO_SIZE)
len = (int)file_left;
if (!ReadFile(hFile, buf, len, &bad_flag, NULL) || (len != bad_flag))
break; // 読み取りエラーは必ず破損になる
file_left -= len;
// MD5 を更新する
Phmd5Process(&ctx, buf, len);
// 経過表示
if (GetTickCount() / UPDATE_TIME != time_last){
if (print_progress_file((int)(((file_size - file_left) * 1000) / file_size), uni_name)){
CloseHandle(hFile);
return 2;
}
time_last = GetTickCount() / UPDATE_TIME;
}
}
Phmd5End(&ctx); // 最終処理
// printf("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X %d\n",
// ctx.hash[0], ctx.hash[1], ctx.hash[2], ctx.hash[3], ctx.hash[4], ctx.hash[5], ctx.hash[6], ctx.hash[7],
// ctx.hash[8], ctx.hash[9], ctx.hash[10], ctx.hash[11], ctx.hash[12], ctx.hash[13], ctx.hash[14], ctx.hash[15]);
if ((memcmp(hash, ctx.hash, 16) != 0) || (file_left > 0)){
bad_flag = 2; // ハッシュ値が異なる、または途中まで
} else {
bad_flag = 0; // 完全
}
write_ini_state(num, meta_data, bad_flag); // 検査結果を記録する、完全か破損
}
CloseHandle(hFile);
}
switch (bad_flag){
case 0:
printf("%13I64d Complete : \"%s\"\n", file_size, ascii_name);
break;
case 1:
printf(" 0 Missing : \"%s\"\n", ascii_name);
bad_flag = 4 | 8;
break;
case 2:
printf("%13I64d Damaged : \"%s\"\n", file_size, ascii_name);
bad_flag = 4;
break;
default: // IOエラー等
printf(" ? Unknown : \"%s\"\n", ascii_name);
bad_flag = 4;
break;
}
fflush(stdout);
return bad_flag;
}
// MD5 ファイル
int verify_md5(
char *ascii_buf,
wchar_t *file_path)
{
unsigned char hash[16];
wchar_t *line_off, uni_buf[MAX_LEN], num_buf[3];
unsigned int err = 0, i, rv, line_len, name_len, line_num, num, comment;
// ファイル数を調べる
comment = 0;
num = 0;
line_num = 1;
line_off = text_buf;
while (*line_off != 0){ // 一行ずつ処理する
line_len = 0;
while (line_off[line_len] != 0){ // 改行までを一行とする
if (line_off[line_len] == '\n')
break;
if (line_off[line_len] == '\r')
break;
line_len++;
}
// 行の内容が適正か調べる
if (line_off[0] == ';'){ // コメント
if (((comment & 1) == 0) && (line_len > 8) && (line_len < MAX_LEN)){
// クリエイターの表示がまだなら
if (wcsncmp(line_off, L"; Generated by ", 15) == 0){ // md5sum, Easy MD5 Creator
wcsncpy(uni_buf, line_off + 15, line_len - 15);
uni_buf[line_len - 15] = 0;
comment = 1;
} else if (wcsncmp(line_off, L"; Using ", 8) == 0){
wcsncpy(uni_buf, line_off + 8, line_len - 8);
uni_buf[line_len - 8] = 0;
comment = 1;
}
if (comment & 1){
uni_buf[COMMENT_LEN - 1] = 0; // 表示する文字数を制限する
utf16_to_cp(uni_buf, ascii_buf, COMMENT_LEN * 3, cp_output);
printf("Creator : %s\n", ascii_buf);
comment |= 4; // 同一行を二度表示しない
}
}
if (((comment & 6) == 0) && (line_len < MAX_LEN)){
// 最初のコメントの表示がまだなら
i = 1;
while (i < line_len){
if (line_off[i] != ' ')
break;
i++;
}
if (i < line_len){
wcsncpy(uni_buf, line_off + i, line_len - i);
uni_buf[line_len - i] = 0;
uni_buf[COMMENT_LEN - 1] = 0; // 表示する文字数を制限する
utf16_to_cp(uni_buf, ascii_buf, COMMENT_LEN * 3, cp_output);
printf("Comment : %s\n", ascii_buf);
}
comment |= 2; // 「;」だけの行も認識する
}
comment &= ~4; // bit 4 を消す
} else if (line_off[0] == '#'){ // コメント
if (((comment & 1) == 0) && (line_len > 8) && (line_len < MAX_LEN)){
// クリエイターの表示がまだなら
if (wcsncmp(line_off, L"# Generated by ", 15) == 0){ // OpenHashTab
wcsncpy(uni_buf, line_off + 15, line_len - 15);
uni_buf[line_len - 15] = 0;
comment = 1;
} else if (wcsncmp(line_off, L"# MD5 checksum generated by ", 28) == 0){ // IsoBuster
wcsncpy(uni_buf, line_off + 28, line_len - 28);
uni_buf[line_len - 28] = 0;
comment = 1;
} else if (wcsncmp(line_off, L"#MD5 checksums generated by ", 28) == 0){ // xACT
wcsncpy(uni_buf, line_off + 28, line_len - 28);
uni_buf[line_len - 28] = 0;
comment = 1;
} else if (wcsncmp(line_off, L"# MD5 checksums generated by ", 29) == 0){ // MD5summer
wcsncpy(uni_buf, line_off + 29, line_len - 29);
uni_buf[line_len - 29] = 0;
comment = 1;
}
if (comment & 1){
uni_buf[COMMENT_LEN - 1] = 0; // 表示する文字数を制限する
utf16_to_cp(uni_buf, ascii_buf, COMMENT_LEN * 3, cp_output);
printf("Creator : %s\n", ascii_buf);
}
}
} else if (line_len > 33){ // コメントではない
// MD5 の後がスペース (md5sum 形式)
if ((line_off[32] == ' ') && (base16_len(line_off) == 32)){
// ファイル名
name_len = line_len - 33;
if (base_len + name_len < MAX_LEN){
// タイプ記号「*」までのスペースは複数個でもいい
while (line_off[line_len - name_len] == ' ')
name_len--;
if (line_off[line_len - name_len] == '*')
name_len--;
wcsncpy(uni_buf, line_off + (line_len - name_len), name_len);
uni_buf[name_len] = 0;
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
if (rv > 1){
if ((comment & 8) == 0){
comment |= 8;
printf("\nWarning about filenames :\n");
}
if (rv == 16){
printf("line%d: filename is invalid\n", line_num);
num++; // 浄化できないファイル名
} else if ((rv & 6) == 0){
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
printf("line%d: \"%s\" is invalid\n", line_num, ascii_buf);
} else {
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
printf("line%d: \"%s\" was sanitized\n", line_num, ascii_buf);
}
}
if (rv != 16)
file_num++;
} else {
if ((comment & 8) == 0){
comment |= 8;
printf("\nWarning about filenames :\n");
}
printf("line%d: filename is invalid\n", line_num);
num++; // 長すぎるファイル名
}
// ファイル名の後にMD5
} else if ((line_off[line_len - 33] == ' ') && (base16_len(line_off + (line_len - 32)) == 32)){
// MD5 の前が括弧 (BSD/OpenSSL 形式)
if (((wcsncmp(line_off, L"MD5(", 4) == 0) || (wcsncmp(line_off, L"MD5 (", 5) == 0))
&& ((wcsncmp(line_off + (line_len - 35), L")= ", 3) == 0) ||
(wcsncmp(line_off + (line_len - 36), L") = ", 4) == 0))){
// ファイル名
name_len = line_len - 35 - 4;
if (base_len + name_len < MAX_LEN){
if (line_off[line_len - 35] != ')')
name_len--;
if (line_off[3] == ' '){
name_len--;
wcsncpy(uni_buf, line_off + 5, name_len);
} else {
wcsncpy(uni_buf, line_off + 4, name_len);
}
uni_buf[name_len] = 0;
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
if (rv > 1){
if ((comment & 8) == 0){
comment |= 8;
printf("\nWarning about filenames :\n");
}
if (rv == 16){
printf("line%d: filename is invalid\n", line_num);
num++; // 浄化できないファイル名
} else if ((rv & 6) == 0){
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
printf("line%d: \"%s\" is invalid\n", line_num, ascii_buf);
} else {
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
printf("line%d: \"%s\" was sanitized\n", line_num, ascii_buf);
}
}
if (rv != 16)
file_num++;
} else {
if ((comment & 8) == 0){
comment |= 8;
printf("\nWarning about filenames :\n");
}
printf("line%d: filename is invalid\n", line_num);
num++; // 長すぎるファイル名
}
} else { // MD5 の前がスペース (Easy MD5 Creator 形式)
// ファイル名
name_len = line_len - 33;
if (base_len + name_len < MAX_LEN){
while (line_off[name_len - 1] == ' ')
name_len--;
wcsncpy(uni_buf, line_off, name_len);
uni_buf[name_len] = 0;
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
if (rv > 1){
if ((comment & 8) == 0){
comment |= 8;
printf("\nWarning about filenames :\n");
}
if (rv == 16){
printf("line%d: filename is invalid\n", line_num);
num++; // 浄化できないファイル名
} else if ((rv & 6) == 0){
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
printf("line%d: \"%s\" is invalid\n", line_num, ascii_buf);
} else {
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
printf("line%d: \"%s\" was sanitized\n", line_num, ascii_buf);
}
}
if (rv != 16)
file_num++;
} else {
if ((comment & 8) == 0){
comment |= 8;
printf("\nWarning about filenames :\n");
}
printf("line%d: filename is invalid\n", line_num);
num++; // 長すぎるファイル名
}
}
} else {
num++; // 内容が認識できない行
}
} else if (line_len > 0){
num++; // 内容が認識できない行
}
// 次の行へ
line_off += line_len;
if (*line_off == '\n')
line_off++;
if (*line_off == '\r'){
line_off++;
if (*line_off == '\n') // 「\r\n」を一つの改行として扱う
line_off++;
}
line_num++;
}
if (comment & 8)
printf("\n");
// チェックサム・ファイルの状態
if (num == 0){
printf("Status : Good\n");
} else {
printf("Status : Damaged\n");
err |= 16; // 後で 256に変更する
}
if (file_num == 0){
printf("valid file is not found\n");
return 1;
}
printf("\nInput File list : %d\n", file_num);
printf("\t MD5 Hash\t\t : Filename\n");
fflush(stdout);
line_off = text_buf;
while (*line_off != 0){ // 一行ずつ処理する
line_len = 0;
while (line_off[line_len] != 0){ // 改行までを一行とする
if (line_off[line_len] == '\n')
break;
if (line_off[line_len] == '\r')
break;
line_len++;
}
// 行の内容が適正か調べる
if ((line_off[0] != ';') && (line_len > 33)){ // コメントではない
// MD5 の後がスペース (md5sum 形式)
if ((line_off[32] == ' ') && (base16_len(line_off) == 32)){
// ファイル名
name_len = line_len - 33;
if (base_len + name_len < MAX_LEN){
// タイプ記号「*」までのスペースは複数個でもいい
while (line_off[line_len - name_len] == ' ')
name_len--;
if (line_off[line_len - name_len] == '*')
name_len--;
wcsncpy(uni_buf, line_off + (line_len - name_len), name_len);
uni_buf[name_len] = 0;
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
if (rv != 16){
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
// MD5
num_buf[2] = 0;
for (i = 0; i < 16; i++){
wcsncpy(num_buf, line_off + (i * 2), 2);
hash[i] = (unsigned char)get_val32h(num_buf);
}
printf("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X : \"%s\"\n",
hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7],
hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], ascii_buf);
}
}
// ファイル名の後にMD5
} else if ((line_off[line_len - 33] == ' ') && (base16_len(line_off + (line_len - 32)) == 32)){
// MD5 の前が括弧 (BSD/OpenSSL 形式)
if (((wcsncmp(line_off, L"MD5(", 4) == 0) || (wcsncmp(line_off, L"MD5 (", 5) == 0))
&& ((wcsncmp(line_off + (line_len - 35), L")= ", 3) == 0) ||
(wcsncmp(line_off + (line_len - 36), L") = ", 4) == 0))){
// ファイル名
name_len = line_len - 35 - 4;
if (base_len + name_len < MAX_LEN){
if (line_off[line_len - 35] != ')')
name_len--;
if (line_off[3] == ' '){
name_len--;
wcsncpy(uni_buf, line_off + 5, name_len);
} else {
wcsncpy(uni_buf, line_off + 4, name_len);
}
uni_buf[name_len] = 0;
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
if (rv != 16){
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
// MD5
num_buf[2] = 0;
for (i = 0; i < 16; i++){
wcsncpy(num_buf, line_off + (line_len - 32 + (i * 2)), 2);
hash[i] = (unsigned char)get_val32h(num_buf);
}
printf("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X : \"%s\"\n",
hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7],
hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], ascii_buf);
}
}
} else { // MD5 の前がスペース (Easy MD5 Creator 形式)
// ファイル名
name_len = line_len - 33;
if (base_len + name_len < MAX_LEN){
while (line_off[name_len - 1] == ' ')
name_len--;
wcsncpy(uni_buf, line_off, name_len);
uni_buf[name_len] = 0;
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
if (rv != 16){
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
// MD5
num_buf[2] = 0;
for (i = 0; i < 16; i++){
wcsncpy(num_buf, line_off + (line_len - 32 + (i * 2)), 2);
hash[i] = (unsigned char)get_val32h(num_buf);
}
printf("%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X : \"%s\"\n",
hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7],
hash[8], hash[9], hash[10], hash[11], hash[12], hash[13], hash[14], hash[15], ascii_buf);
}
}
}
}
}
// 次の行へ
line_off += line_len;
if (*line_off == '\n')
line_off++;
if (*line_off == '\r'){
line_off++;
if (*line_off == '\n') // 「\r\n」を一つの改行として扱う
line_off++;
}
}
printf("\nVerifying Input File :\n");
printf(" Size Status : Filename\n");
fflush(stdout);
if (recent_data != 0){ // 前回の検査結果を使うなら
PHMD5 ctx;
// チェックサム・ファイル識別用にハッシュ値を計算する
Phmd5Begin(&ctx);
Phmd5Process(&ctx, (unsigned char *)text_buf, text_len * 2);
Phmd5End(&ctx);
// 前回の検査結果が存在するか
check_ini_file(ctx.hash, text_len);
}
num = 0;
line_off = text_buf;
while (*line_off != 0){ // 一行ずつ処理する
line_len = 0;
while (line_off[line_len] != 0){ // 改行までを一行とする
if (line_off[line_len] == '\n')
break;
if (line_off[line_len] == '\r')
break;
line_len++;
}
// 行の内容が適正か調べる
if ((line_off[0] != ';') && (line_len > 33)){ // コメントではない
// MD5 の後がスペース (md5sum 形式)
if ((line_off[32] == ' ') && (base16_len(line_off) == 32)){
// ファイル名
name_len = line_len - 33;
if (base_len + name_len < MAX_LEN){
// タイプ記号「*」までのスペースは複数個でもいい
while (line_off[line_len - name_len] == ' ')
name_len--;
if (line_off[line_len - name_len] == '*')
name_len--;
wcsncpy(uni_buf, line_off + (line_len - name_len), name_len);
uni_buf[name_len] = 0;
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
if (rv != 16){
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
// MD5
num_buf[2] = 0;
for (i = 0; i < 16; i++){
wcsncpy(num_buf, line_off + (i * 2), 2);
hash[i] = (unsigned char)get_val32h(num_buf);
}
rv = file_md5_check(num, ascii_buf, uni_buf, file_path, hash);
if (rv & 3){
err = rv;
break;
}
if (rv & 0xC){ // Missing or Damaged
err |= rv;
err += 0x100;
}
num++;
}
}
// ファイル名の後にMD5
} else if ((line_off[line_len - 33] == ' ') && (base16_len(line_off + (line_len - 32)) == 32)){
// MD5 の前が括弧 (BSD/OpenSSL 形式)
if (((wcsncmp(line_off, L"MD5(", 4) == 0) || (wcsncmp(line_off, L"MD5 (", 5) == 0))
&& ((wcsncmp(line_off + (line_len - 35), L")= ", 3) == 0) ||
(wcsncmp(line_off + (line_len - 36), L") = ", 4) == 0))){
// ファイル名
name_len = line_len - 35 - 4;
if (base_len + name_len < MAX_LEN){
if (line_off[line_len - 35] != ')')
name_len--;
if (line_off[3] == ' '){
name_len--;
wcsncpy(uni_buf, line_off + 5, name_len);
} else {
wcsncpy(uni_buf, line_off + 4, name_len);
}
uni_buf[name_len] = 0;
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
if (rv != 16){
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
// MD5
num_buf[2] = 0;
for (i = 0; i < 16; i++){
wcsncpy(num_buf, line_off + (line_len - 32 + (i * 2)), 2);
hash[i] = (unsigned char)get_val32h(num_buf);
}
rv = file_md5_check(num, ascii_buf, uni_buf, file_path, hash);
if (rv & 3){
err = rv;
break;
}
if (rv & 0xC){ // Missing or Damaged
err |= rv;
err += 0x100;
}
num++;
}
}
} else { // MD5 の前がスペース (Easy MD5 Creator 形式)
// ファイル名
name_len = line_len - 33;
if (base_len + name_len < MAX_LEN){
while (line_off[name_len - 1] == ' ')
name_len--;
wcsncpy(uni_buf, line_off, name_len);
uni_buf[name_len] = 0;
rv = sanitize_filename(uni_buf); // ファイル名を浄化する
if (rv != 16){
utf16_to_cp(uni_buf, ascii_buf, MAX_LEN * 3, cp_output);
// MD5
num_buf[2] = 0;
for (i = 0; i < 16; i++){
wcsncpy(num_buf, line_off + (line_len - 32 + (i * 2)), 2);
hash[i] = (unsigned char)get_val32h(num_buf);
}
rv = file_md5_check(num, ascii_buf, uni_buf, file_path, hash);
if (rv & 3){
err = rv;
break;
}
if (rv & 0xC){ // Missing or Damaged
err |= rv;
err += 0x100;
}
num++;
}
}
}
}
}
// 次の行へ
line_off += line_len;
if (*line_off == '\n')
line_off++;
if (*line_off == '\r'){
line_off++;
if (*line_off == '\n') // 「\r\n」を一つの改行として扱う
line_off++;
}
}
return err;
}