Add files via upload
This commit is contained in:
1015
source/sfv_md5/common.c
Normal file
1015
source/sfv_md5/common.c
Normal file
File diff suppressed because it is too large
Load Diff
139
source/sfv_md5/common.h
Normal file
139
source/sfv_md5/common.h
Normal file
@@ -0,0 +1,139 @@
|
||||
|
||||
#define MAX_LEN 1024 // ファイル名の最大文字数 (末尾のNULL文字も含む)
|
||||
#define ADD_LEN 32 // 作業中にファイル名に追加する文字数
|
||||
#define EXT_LEN 16 // 拡張子として認識する最大文字数
|
||||
#define COMMENT_LEN 128 // コメントの最大文字数
|
||||
#define ALLOC_LEN 4096 // 可変長領域を何バイトごとに確保するか
|
||||
#define IO_SIZE 65536 // 16384 以上にすること
|
||||
#define UPDATE_TIME 1024 // 更新間隔 ms
|
||||
|
||||
// グローバル変数
|
||||
extern wchar_t checksum_file[MAX_LEN]; // チェックサム・ファイルのパス
|
||||
extern wchar_t base_dir[MAX_LEN]; // ソース・ファイルの基準ディレクトリ
|
||||
extern wchar_t ini_path[MAX_LEN]; // 検査結果ファイルのパス
|
||||
|
||||
extern int base_len; // ソース・ファイルの基準ディレクトリの長さ
|
||||
extern int file_num; // ソース・ファイルの数
|
||||
|
||||
// 可変長サイズの領域にテキストを保存する
|
||||
extern wchar_t *text_buf; // チェックサム・ファイルのテキスト内容
|
||||
extern int text_len; // テキストの文字数
|
||||
extern int text_max; // テキストの最大文字数
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
extern unsigned int cp_output; // Console Output Code Page
|
||||
|
||||
// 指定された Code Page から UTF-16 に変換する
|
||||
int cp_to_utf16(char *in, wchar_t *out, int max_size, unsigned int cp);
|
||||
|
||||
// Windown OS の UTF-16 から指定された Code Page に変換する
|
||||
int utf16_to_cp(wchar_t *in, char *out, int max_size, unsigned int cp);
|
||||
|
||||
// 文字列が UTF-8 かどうかを判定する (0 = maybe UTF-8)
|
||||
int check_utf8(unsigned char *text);
|
||||
|
||||
// 文字列が UTF-16 かどうかを判定して変換する
|
||||
int utf16_to_utf16(unsigned char *in, int len, wchar_t *out);
|
||||
|
||||
// UTF-16 のファイル・パスを画面出力用の Code Page を使って表示する
|
||||
void printf_cp(unsigned char *format, wchar_t *path);
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// ファイルの offset バイト目から size バイトのデータを buf に読み込む
|
||||
int file_read_data(
|
||||
HANDLE hFileRead,
|
||||
__int64 offset,
|
||||
unsigned char *buf,
|
||||
unsigned int size);
|
||||
|
||||
// ファイルの offset バイト目に size バイトのデータを buf から書き込む
|
||||
int file_write_data(
|
||||
HANDLE hFileWrite,
|
||||
__int64 offset,
|
||||
unsigned char *buf,
|
||||
unsigned int size);
|
||||
|
||||
// ファイルの offset バイト目に size バイトの指定値を書き込む
|
||||
int file_fill_data(
|
||||
HANDLE hFileWrite,
|
||||
__int64 offset,
|
||||
unsigned char value,
|
||||
unsigned int size);
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// ファイル・パスがファイル・リスト上に既に存在するか調べる
|
||||
int search_file_path(
|
||||
wchar_t *list, // ファイル・リスト
|
||||
int total_len, // ファイル・リストの文字数
|
||||
wchar_t *search_file); // 検索するファイルのパス
|
||||
|
||||
// ファイル・リストの内容を並び替える
|
||||
void sort_list(
|
||||
wchar_t *list, // ファイル・リスト
|
||||
int total_len); // ファイル・リストの文字数
|
||||
|
||||
// テキストに新しい文字列を追加する
|
||||
int add_text(wchar_t *new_text); // 追加するテキスト
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// ファイル・パスからファイル名の位置を戻す
|
||||
wchar_t * offset_file_name(wchar_t *file_path);
|
||||
|
||||
// ファイル・パスからファイル名だけ取り出す
|
||||
void get_file_name(
|
||||
wchar_t *file_path, // ファイル・パス
|
||||
wchar_t *file_name); // ファイル名
|
||||
|
||||
// ファイル・パスからディレクトリだけ取り出す、末尾は「\」か「/」
|
||||
void get_base_dir(
|
||||
wchar_t *file_path, // ファイル・パス
|
||||
wchar_t *base_path); // ディレクトリ
|
||||
|
||||
// ディレクトリ記号の「\」を「/」に置換する
|
||||
void unix_directory(wchar_t *path);
|
||||
|
||||
// 絶対パスかどうかを判定する
|
||||
int is_full_path(wchar_t *path);
|
||||
|
||||
// ファイル名が有効か確かめて、問題があれば浄化する
|
||||
int sanitize_filename(wchar_t *name);
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// 相対パスを絶対パスに変換し、パスの先頭に "\\?\" を追加する
|
||||
// 戻り値 : 0=エラー, 5~=新しいパスの長さ
|
||||
int copy_path_prefix(
|
||||
wchar_t *new_path, // 新しいパス
|
||||
int max_len, // 新しいパスの最大長さ (末尾の null文字も含む)
|
||||
wchar_t *src_path, // 元のパス (相対パスでもよい)
|
||||
wchar_t *dir_path); // 相対パスの場合に基準となるディレクトリ (NULL ならカレント・ディレクトリ)
|
||||
|
||||
// ファイル・パスから、先頭にある "\\?\" を省いた長さを戻す
|
||||
int len_without_prefix(wchar_t *file_path);
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// ユニコードの16進数文字列から数値を読み取る
|
||||
unsigned int get_val32h(wchar_t *s);
|
||||
|
||||
// 16進数の文字が何個続いてるか
|
||||
unsigned int base16_len(wchar_t *s);
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
extern int prog_last; // 前回と同じ進捗状況は出力しないので記録しておく
|
||||
|
||||
// 経過のパーセント表示、キャンセルと一時停止ができる
|
||||
// 普段は 0 を返す、キャンセル時は 0以外
|
||||
int print_progress(int prog_now);
|
||||
void print_progress_text(int prog_now, char *text);
|
||||
int print_progress_file(int prog_now, wchar_t *file_name);
|
||||
void print_progress_done(void);
|
||||
|
||||
// Win32 API のエラー・メッセージを表示する
|
||||
void print_win32_err(void);
|
||||
|
||||
51
source/sfv_md5/crc.c
Normal file
51
source/sfv_md5/crc.c
Normal file
@@ -0,0 +1,51 @@
|
||||
// crc.c
|
||||
// Copyright : 2021-05-14 Yutaka Sawada
|
||||
// License : The MIT license
|
||||
|
||||
#include "crc.h"
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
// CRC-32 計算用
|
||||
|
||||
// CRC-32
|
||||
#define CRC_POLY 0xEDB88320 // (little endian)
|
||||
unsigned int crc_table[256];
|
||||
|
||||
// CRC 計算用のテーブルを作る
|
||||
void init_crc_table(void)
|
||||
{
|
||||
unsigned int i, j, r;
|
||||
|
||||
for (i = 0; i < 256; i++){ // CRC-32
|
||||
r = i;
|
||||
for (j = 0; j < 8; j++)
|
||||
r = (r >> 1) ^ (CRC_POLY & ~((r & 1) - 1));
|
||||
crc_table[i] = r;
|
||||
}
|
||||
}
|
||||
|
||||
// CRC-32 を更新する
|
||||
unsigned int crc_update(unsigned int crc, unsigned char *buf, unsigned int len)
|
||||
{
|
||||
/*
|
||||
while (len--)
|
||||
crc = crc_table[(crc & 0xFF) ^ (*buf++)] ^ (crc >> 8);
|
||||
*/
|
||||
// 4バイトごとに計算する
|
||||
while (len >= 4){
|
||||
crc ^= *((unsigned int *)buf);
|
||||
crc = crc_table[crc & 0xFF] ^ (crc >> 8);
|
||||
crc = crc_table[crc & 0xFF] ^ (crc >> 8);
|
||||
crc = crc_table[crc & 0xFF] ^ (crc >> 8);
|
||||
crc = crc_table[crc & 0xFF] ^ (crc >> 8);
|
||||
len -= 4;
|
||||
buf += 4;
|
||||
}
|
||||
|
||||
// 余りは 1バイトずつ計算する
|
||||
while (len--)
|
||||
crc = crc_table[(crc & 0xFF) ^ (*buf++)] ^ (crc >> 8);
|
||||
|
||||
return crc;
|
||||
}
|
||||
|
||||
7
source/sfv_md5/crc.h
Normal file
7
source/sfv_md5/crc.h
Normal file
@@ -0,0 +1,7 @@
|
||||
|
||||
// CRC 計算用のテーブルを作る
|
||||
void init_crc_table(void);
|
||||
|
||||
// CRC-32 を更新する
|
||||
unsigned int crc_update(unsigned int crc, unsigned char *buf, unsigned int len);
|
||||
|
||||
181
source/sfv_md5/create.c
Normal file
181
source/sfv_md5/create.c
Normal file
@@ -0,0 +1,181 @@
|
||||
// create.c
|
||||
// Copyright : 2022-02-16 Yutaka Sawada
|
||||
// License : The MIT license
|
||||
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600 // Windows Vista or later
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "crc.h"
|
||||
#include "create.h"
|
||||
#include "phmd5.h"
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// SFV ファイル
|
||||
int create_sfv(
|
||||
wchar_t *uni_buf,
|
||||
wchar_t *file_name, // 検査対象のファイル名
|
||||
__int64 *prog_now, // 経過表示での現在位置
|
||||
__int64 total_size) // 合計ファイル・サイズ
|
||||
{
|
||||
unsigned char buf[IO_SIZE];
|
||||
unsigned int rv, len, crc, time_last;
|
||||
__int64 file_size = 0, file_left;
|
||||
HANDLE hFile;
|
||||
|
||||
time_last = GetTickCount() / UPDATE_TIME; // 時刻の変化時に経過を表示する
|
||||
|
||||
// 読み込むファイルを開く
|
||||
wcscpy(uni_buf, base_dir);
|
||||
wcscpy(uni_buf + base_len, file_name);
|
||||
hFile = CreateFile(uni_buf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE){
|
||||
printf("\n");
|
||||
print_win32_err();
|
||||
return 1;
|
||||
}
|
||||
if (!GetFileSizeEx(hFile, (PLARGE_INTEGER)&file_size)){
|
||||
printf("\n");
|
||||
print_win32_err();
|
||||
CloseHandle(hFile);
|
||||
return 1;
|
||||
}
|
||||
file_left = file_size;
|
||||
|
||||
// CRC を計算する
|
||||
crc = 0xFFFFFFFF; // 初期化
|
||||
while (file_left > 0){
|
||||
len = IO_SIZE;
|
||||
if (file_left < IO_SIZE)
|
||||
len = (unsigned int)file_left;
|
||||
if (!ReadFile(hFile, buf, len, &rv, NULL) || (len != rv)){
|
||||
printf("\n");
|
||||
print_win32_err();
|
||||
CloseHandle(hFile);
|
||||
return 1;
|
||||
}
|
||||
file_left-= len;
|
||||
(*prog_now) += len;
|
||||
// CRC-32 を更新する
|
||||
crc = crc_update(crc, buf, len);
|
||||
|
||||
// 経過表示
|
||||
if (GetTickCount() / UPDATE_TIME != time_last){
|
||||
if (print_progress((int)(((*prog_now) * 1000) / total_size))){
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
time_last = GetTickCount() / UPDATE_TIME;
|
||||
}
|
||||
}
|
||||
crc ^= 0xFFFFFFFF; // 最終処理
|
||||
CloseHandle(hFile);
|
||||
|
||||
// チェックサムを記録する
|
||||
len = wcslen(file_name);
|
||||
for (rv = 0; rv < len; rv++){
|
||||
if (file_name[rv] == ' ')
|
||||
break;
|
||||
}
|
||||
if (rv < len){
|
||||
uni_buf[0] = '"';
|
||||
wcscpy(uni_buf + 1, file_name); // 「"」で囲む
|
||||
uni_buf[len + 1] = '"';
|
||||
uni_buf[len + 2] = 0;
|
||||
} else {
|
||||
wcscpy(uni_buf, file_name); // 変換前にコピーする
|
||||
}
|
||||
unix_directory(uni_buf);
|
||||
add_text(uni_buf);
|
||||
wsprintf(uni_buf, L" %08X\r\n", crc);
|
||||
add_text(uni_buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// MD5 ファイル
|
||||
int create_md5(
|
||||
wchar_t *uni_buf,
|
||||
wchar_t *file_name, // 検査対象のファイル名
|
||||
__int64 *prog_now, // 経過表示での現在位置
|
||||
__int64 total_size) // 合計ファイル・サイズ
|
||||
{
|
||||
unsigned char buf[IO_SIZE];
|
||||
unsigned int rv, len, time_last;
|
||||
__int64 file_size = 0, file_left;
|
||||
HANDLE hFile;
|
||||
PHMD5 ctx;
|
||||
|
||||
time_last = GetTickCount() / UPDATE_TIME; // 時刻の変化時に経過を表示する
|
||||
|
||||
// 読み込むファイルを開く
|
||||
wcscpy(uni_buf, base_dir);
|
||||
wcscpy(uni_buf + base_len, file_name);
|
||||
hFile = CreateFile(uni_buf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE){
|
||||
printf("\n");
|
||||
print_win32_err();
|
||||
return 1;
|
||||
}
|
||||
if (!GetFileSizeEx(hFile, (PLARGE_INTEGER)&file_size)){
|
||||
printf("\n");
|
||||
print_win32_err();
|
||||
CloseHandle(hFile);
|
||||
return 1;
|
||||
}
|
||||
file_left = file_size;
|
||||
|
||||
// MD5 を計算する
|
||||
Phmd5Begin(&ctx); // 初期化
|
||||
while (file_left > 0){
|
||||
len = IO_SIZE;
|
||||
if (file_left < IO_SIZE)
|
||||
len = (unsigned int)file_left;
|
||||
if (!ReadFile(hFile, buf, len, &rv, NULL) || (len != rv)){
|
||||
printf("\n");
|
||||
print_win32_err();
|
||||
CloseHandle(hFile);
|
||||
return 1;
|
||||
}
|
||||
file_left-= len;
|
||||
(*prog_now) += len;
|
||||
// MD5 を更新する
|
||||
Phmd5Process(&ctx, buf, len);
|
||||
|
||||
// 経過表示
|
||||
if (GetTickCount() / UPDATE_TIME != time_last){
|
||||
if (print_progress((int)(((*prog_now) * 1000) / total_size))){
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
time_last = GetTickCount() / UPDATE_TIME;
|
||||
}
|
||||
}
|
||||
Phmd5End(&ctx); // 最終処理
|
||||
CloseHandle(hFile);
|
||||
|
||||
// チェックサムを記録する
|
||||
wsprintf(uni_buf, L"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X *",
|
||||
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]);
|
||||
add_text(uni_buf);
|
||||
wcscpy(uni_buf, file_name); // 変換前にコピーする
|
||||
unix_directory(uni_buf);
|
||||
add_text(uni_buf);
|
||||
add_text(L"\r\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
15
source/sfv_md5/create.h
Normal file
15
source/sfv_md5/create.h
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
// SFV ファイル
|
||||
int create_sfv(
|
||||
wchar_t *uni_buf,
|
||||
wchar_t *file_name, // 検査対象のファイル名
|
||||
__int64 *prog_end, // 経過表示での終了位置
|
||||
__int64 total_size); // 合計ファイル・サイズ
|
||||
|
||||
// MD5 ファイル
|
||||
int create_md5(
|
||||
wchar_t *uni_buf,
|
||||
wchar_t *file_name, // 検査対象のファイル名
|
||||
__int64 *prog_end, // 経過表示での終了位置
|
||||
__int64 total_size); // 合計ファイル・サイズ
|
||||
|
||||
414
source/sfv_md5/ini.c
Normal file
414
source/sfv_md5/ini.c
Normal file
@@ -0,0 +1,414 @@
|
||||
// ini.c
|
||||
// Copyright : 2022-02-16 Yutaka Sawada
|
||||
// License : The MIT license
|
||||
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600 // Windows Vista or later
|
||||
#endif
|
||||
|
||||
#include <malloc.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "crc.h"
|
||||
#include "ini.h"
|
||||
|
||||
/*
|
||||
ファイル名は 0_#.bin (2+32+4 = 38文字)
|
||||
「#」部分はチェックサム・ファイルを UTF-16 にエンコードした内容の
|
||||
MD5ハッシュ値を 16進数表記にする。
|
||||
|
||||
ファイル・フォーマット
|
||||
<!-- 検査結果ファイル識別用 -->
|
||||
2: 検査結果の書式バージョン
|
||||
4: 6バイト目以降からの CRC-32 チェックサム
|
||||
<!-- チェックサム・セットの識別用 -->
|
||||
4: チェックサム・ファイルの UTF-16 エンコード後の文字数
|
||||
4: チェックサム・ファイルに記録されてるソース・ファイルの数
|
||||
|
||||
<!-- 検査状態をファイルごとに記録する -->
|
||||
前半 12バイトでファイル項目を識別して、後半 18バイトに状態を保存する。
|
||||
4: ボリュームのシリアル番号
|
||||
8: ファイルのオブジェクトID
|
||||
8: ソース・ファイルのサイズ
|
||||
4: ソース・ファイルの作成日時
|
||||
4: ソース・ファイルの更新日時
|
||||
2: 下位 1-bit はファイルの状態 0=完全, 1=破損あるいはエラー
|
||||
上位 15-bit はソース・ファイル番号 0~32767
|
||||
|
||||
*/
|
||||
|
||||
#define INI_VERSION 0x1270 // 検査結果の書式が決まった時のバージョン
|
||||
#define REUSE_MIN 16384 // ファイル・サイズがこれより大きければ検査結果を利用する (16KB 以上 2GB 未満)
|
||||
#define HEADER_SIZE 14
|
||||
#define STATE_SIZE 30
|
||||
#define STATE_READ 136
|
||||
//#define VERBOSE 1 // 状態を冗長に出力する
|
||||
|
||||
static HANDLE hIniBin = NULL; // バイナリ・データ用の検査結果ファイル
|
||||
static int ini_off;
|
||||
|
||||
// 検査結果をどのくらいの期間保存するか
|
||||
int recent_data = 0;
|
||||
/*
|
||||
0 = 検査結果の再利用機能を無効にする(読み込まないし、記録もしない)
|
||||
1~7= 前回の検査結果を読み込んで、今回のを記録する。
|
||||
指定された期間よりも経過した古い記録は削除される。
|
||||
1= 1日, 2= 3日, 3= 1週間, 4= 半月, 5= 1ヶ月, 6= 1年, 7= 無制限
|
||||
+8 = 同じセットの記録を削除する、今回の結果は記録する。
|
||||
他のセットは指定された期間よりも古いものだけ削除する。
|
||||
*/
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
// File Time (UTC) を UNIX Time (UTC) に変換する
|
||||
unsigned int time_f_u(FILETIME *file_time)
|
||||
{
|
||||
unsigned __int64 int8;
|
||||
|
||||
// 1970/01/01 の File Time との差を求める
|
||||
memcpy(&int8, file_time, 8);
|
||||
int8 = (int8 - 116444736000000000) / 10000000;
|
||||
|
||||
return (unsigned int)int8;
|
||||
}
|
||||
|
||||
#ifdef VERBOSE
|
||||
// File Time (UTC) を日付の文字列に変換する
|
||||
static void time_f_date(FILETIME *ft, char *buf)
|
||||
{
|
||||
int len;
|
||||
SYSTEMTIME st_utc, st;
|
||||
|
||||
FileTimeToSystemTime(ft, &st_utc);
|
||||
if (SystemTimeToTzSpecificLocalTime(NULL, &st_utc, &st) == 0)
|
||||
memcpy(&st, &st_utc, sizeof(SYSTEMTIME));
|
||||
len = GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE | LOCALE_USE_CP_ACP, &st, NULL, buf, 32);
|
||||
if (len > 0){
|
||||
buf[len - 1] = ' ';
|
||||
len = GetTimeFormatA(LOCALE_USER_DEFAULT, LOCALE_USE_CP_ACP, &st, NULL, buf + len, 32 - len);
|
||||
}
|
||||
if (len == 0){
|
||||
wsprintfA(buf, "%4d/%02d/%02d %2d:%02d:%02d",
|
||||
st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// 2GB 未満のファイルの開始位置以降のハッシュ値を計算する
|
||||
static unsigned int file_crc_part(HANDLE hFile)
|
||||
{
|
||||
unsigned char buf[4096];
|
||||
unsigned int len, crc = 0xFFFFFFFF;
|
||||
|
||||
// 末尾まで読み込む
|
||||
do {
|
||||
if (!ReadFile(hFile, buf, 4096, &len, NULL) || (len == 0))
|
||||
break;
|
||||
// CRC-32 計算
|
||||
crc = crc_update(crc, buf, len);
|
||||
} while (len > 0);
|
||||
|
||||
return crc ^ 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
// .BIN ファイルの offset バイト目から size バイトのデータを buf に読み込む
|
||||
static int file_read_bin(
|
||||
int offset,
|
||||
unsigned char *buf,
|
||||
unsigned int size)
|
||||
{
|
||||
unsigned int rv;
|
||||
|
||||
// ファイルの位置を offsetバイト目にする
|
||||
rv = SetFilePointer(hIniBin, offset, NULL, FILE_BEGIN);
|
||||
if (rv == INVALID_SET_FILE_POINTER)
|
||||
return 1;
|
||||
|
||||
// size バイトを読み込む
|
||||
if ((!ReadFile(hIniBin, buf, size, &rv, NULL)) || (size != rv))
|
||||
return 1; // 指定サイズを読み込めなかったらエラーになる
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
// 検査結果ファイルを利用する為の関数
|
||||
|
||||
// ini_path で指定されてる検査結果ファイルを削除する
|
||||
static void delete_ini_file(void)
|
||||
{
|
||||
// 開いてるなら閉じる
|
||||
if (hIniBin != NULL){
|
||||
CloseHandle(hIniBin);
|
||||
hIniBin = NULL;
|
||||
}
|
||||
|
||||
DeleteFile(ini_path); // .bin ファイルを削除する
|
||||
|
||||
recent_data = 0; // これ以降は検査結果は利用できない
|
||||
}
|
||||
|
||||
// 検査するチェックサム・ファイルが同じであれば、再検査する必要は無い
|
||||
int check_ini_file(unsigned char *set_hash, unsigned int set_len)
|
||||
{
|
||||
unsigned char set_data[HEADER_SIZE * 2];
|
||||
wchar_t path[MAX_LEN], ini_name[INI_NAME_LEN + 1];
|
||||
int i, match;
|
||||
unsigned int file_time, time_now, time_limit;
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATA FindData;
|
||||
FILETIME ft;
|
||||
|
||||
if (recent_data == 0)
|
||||
return 0;
|
||||
|
||||
// 設定ファイルのパス
|
||||
wsprintf(ini_name, L"0_%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X.bin",
|
||||
set_hash[0], set_hash[1], set_hash[2], set_hash[3], set_hash[4], set_hash[5], set_hash[6], set_hash[7],
|
||||
set_hash[8], set_hash[9], set_hash[10], set_hash[11],set_hash[12], set_hash[13], set_hash[14], set_hash[15]);
|
||||
|
||||
// 期限を設定する
|
||||
switch (recent_data & 7){
|
||||
case 1:
|
||||
time_limit = 3600 * 24; // 1 day
|
||||
break;
|
||||
case 2:
|
||||
time_limit = 3600 * 24 * 3; // 3 days
|
||||
break;
|
||||
case 3:
|
||||
time_limit = 3600 * 24 * 7; // 1 week
|
||||
break;
|
||||
case 4:
|
||||
time_limit = 3600 * 24 * 15; // half month
|
||||
break;
|
||||
case 5:
|
||||
time_limit = 3600 * 24 * 30; // 1 month
|
||||
break;
|
||||
case 6:
|
||||
time_limit = 3600 * 24 * 365; // 1 year
|
||||
break;
|
||||
case 7:
|
||||
time_limit = 0xFFFFFFFF; // unlimited
|
||||
break;
|
||||
default: // 期間が指定されてない
|
||||
recent_data = 0;
|
||||
return 0;
|
||||
}
|
||||
GetSystemTimeAsFileTime(&ft); // 現在のシステム時刻 (UTC) を取得する
|
||||
time_now = time_f_u(&ft); // UNIX Time に変換する
|
||||
|
||||
// 記録の日時を調べて、古いのは削除する
|
||||
match = 0;
|
||||
wcscpy(path, ini_path);
|
||||
wcscat(path, L"0_*.bin"); // 文字数は後でチェックする
|
||||
hFind = FindFirstFile(path, &FindData);
|
||||
if (hFind != INVALID_HANDLE_VALUE){
|
||||
do {
|
||||
if (((FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) &&
|
||||
(wcslen(FindData.cFileName) == INI_NAME_LEN)){
|
||||
// 指定時間より古い記録は削除する
|
||||
file_time = time_f_u(&(FindData.ftLastWriteTime)); // 更新日時
|
||||
if (time_now - file_time > time_limit){
|
||||
wcscpy(path, ini_path);
|
||||
wcscat(path, FindData.cFileName);
|
||||
DeleteFile(path);
|
||||
#if VERBOSE > 1
|
||||
time_f_date(&(FindData.ftLastWriteTime), (char *)path);
|
||||
printf("Delete result: %S, %s\n", FindData.cFileName, (char *)path);
|
||||
#endif
|
||||
} else if (wcscmp(FindData.cFileName, ini_name) == 0){
|
||||
if (recent_data & 8){ // 検査結果を読み込まないが、今回のは書き込む場合
|
||||
// 以前の検査結果が存在すれば削除する
|
||||
wcscpy(path, ini_path);
|
||||
wcscat(path, ini_name);
|
||||
DeleteFile(path);
|
||||
#if VERBOSE > 1
|
||||
printf("Delete result: %S\n", ini_name);
|
||||
#endif
|
||||
} else {
|
||||
match = 1; // 設定ファイルが存在する
|
||||
}
|
||||
#ifdef VERBOSE
|
||||
ft = FindData.ftLastWriteTime; // 検査結果の更新日時
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &FindData)); // 次のファイルを検索する
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
// バイナリ・データ用の設定ファイルを開く
|
||||
wcscat(ini_path, ini_name);
|
||||
hIniBin = CreateFile(ini_path, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_FLAG_RANDOM_ACCESS, NULL);
|
||||
if (hIniBin == INVALID_HANDLE_VALUE){
|
||||
hIniBin = NULL;
|
||||
recent_data = 0; // 開けない場合は再利用しない
|
||||
return 0;
|
||||
}
|
||||
//printf("ini file path = %S\n", ini_path);
|
||||
|
||||
// 既に同名の (Set ID が同じ) ファイルが存在する場合
|
||||
set_data[0] = INI_VERSION >> 8; // 検査結果の書式バージョン
|
||||
set_data[1] = INI_VERSION & 0xFF;
|
||||
memset(set_data + 2, 0, 4); // CRC-32 は後で書き込む
|
||||
memcpy(set_data + 6, &set_len, 4);
|
||||
memcpy(set_data + 10, &file_num, 4);
|
||||
if (match != 0){ // ID が同じでも Set 内容が異なる場合は初期化する
|
||||
i = file_read_data(hIniBin, 0, set_data + HEADER_SIZE, HEADER_SIZE);
|
||||
if ((set_data[HEADER_SIZE ] != (INI_VERSION >> 8)) ||
|
||||
(set_data[HEADER_SIZE + 1] != (INI_VERSION & 0xFF))){
|
||||
i = 1; // 古いバージョンの検査結果は参照しない
|
||||
}
|
||||
if (i == 0){ // 検査結果が破損してないか確かめる
|
||||
if (SetFilePointer(hIniBin, 6, 0, FILE_BEGIN) != INVALID_SET_FILE_POINTER)
|
||||
time_now = file_crc_part(hIniBin);
|
||||
i = memcmp(&time_now, set_data + (HEADER_SIZE + 2), 4);
|
||||
}
|
||||
if (i == 0) // チェックサム・ファイルのデータを比較する
|
||||
i = memcmp(set_data + 6, set_data + (HEADER_SIZE + 6), HEADER_SIZE - 6);
|
||||
if (i != 0) // ID が同じでも Set 内容が異なる場合は初期化する
|
||||
match = 0;
|
||||
}
|
||||
|
||||
// 一致しなかった場合は今回のデータを記録する
|
||||
if (match == 0){
|
||||
// 今回のデータを書き込む
|
||||
if (file_write_data(hIniBin, 0, set_data, HEADER_SIZE) != 0){
|
||||
delete_ini_file();
|
||||
return 0;
|
||||
}
|
||||
if (SetEndOfFile(hIniBin) == 0){
|
||||
delete_ini_file();
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
#ifdef VERBOSE
|
||||
} else {
|
||||
time_f_date(&ft, (char *)path);
|
||||
printf("Date of result: %s\n", (char *)path);
|
||||
#endif
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 検査結果ファイルを閉じる
|
||||
void close_ini_file(void)
|
||||
{
|
||||
if ((recent_data != 0) && (hIniBin != NULL)){
|
||||
unsigned int new_crc, old_crc;
|
||||
|
||||
// 閉じる前に検査結果の CRC-32 を計算して記録しておく
|
||||
FlushFileBuffers(hIniBin);
|
||||
file_read_data(hIniBin, 2, (unsigned char *)&old_crc, 4);
|
||||
new_crc = file_crc_part(hIniBin);
|
||||
if (new_crc != old_crc) // 検査結果が同じなら更新しない
|
||||
file_write_data(hIniBin, 2, (unsigned char *)&new_crc, 4);
|
||||
CloseHandle(hIniBin);
|
||||
hIniBin = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// 検査結果が記録されてるかどうか
|
||||
// -1=エラー, -2=記録なし, 0=完全, 2=破損
|
||||
int check_ini_state(
|
||||
int num, // ファイル番号
|
||||
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
|
||||
HANDLE hFile) // そのファイルのハンドル
|
||||
{
|
||||
unsigned char buf[STATE_SIZE * STATE_READ];
|
||||
unsigned int rv, off, state;
|
||||
BY_HANDLE_FILE_INFORMATION fi;
|
||||
|
||||
// 現在のファイル属性を取得する
|
||||
memset(&fi, 0, sizeof(BY_HANDLE_FILE_INFORMATION));
|
||||
if (GetFileInformationByHandle(hFile, &fi) != 0){
|
||||
meta[0] = fi.nFileSizeLow;
|
||||
meta[1] = fi.nFileSizeHigh;
|
||||
if ((recent_data == 0) || ((fi.nFileSizeLow <= REUSE_MIN) && (fi.nFileSizeHigh == 0)))
|
||||
return -2; // 小さなファイルは記録を参照しない
|
||||
meta[2] = time_f_u(&(fi.ftCreationTime));
|
||||
meta[3] = time_f_u(&(fi.ftLastWriteTime));
|
||||
meta[4] = fi.dwVolumeSerialNumber;
|
||||
meta[5] = fi.nFileIndexLow;
|
||||
meta[6] = fi.nFileIndexHigh;
|
||||
} else {
|
||||
meta[0] = 0;
|
||||
meta[1] = 0;
|
||||
return -1; // 属性の読み取りエラー
|
||||
}
|
||||
|
||||
// ヘッダーの直後から開始する
|
||||
if (SetFilePointer(hIniBin, HEADER_SIZE, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER){
|
||||
delete_ini_file();
|
||||
return -2;
|
||||
}
|
||||
ini_off = HEADER_SIZE; // ファイル項目の位置
|
||||
// 一度に STATE_READ 個ずつ読み込む
|
||||
while (ReadFile(hIniBin, buf, STATE_SIZE * STATE_READ, &rv, NULL) != 0){
|
||||
if (rv < STATE_SIZE)
|
||||
break;
|
||||
// ファイル識別番号から同じファイルの記録を探す
|
||||
for (off = 0; off < rv; off += STATE_SIZE){
|
||||
if (memcmp(buf + off, meta + 4, 12) == 0){
|
||||
ini_off += off; // 同じファイルの記録があった
|
||||
state = 0;
|
||||
memcpy(&state, buf + (off + 28), 2);
|
||||
#ifdef VERBOSE
|
||||
printf("check state, num = %d, offset = %d, state = %d\n", num, HEADER_SIZE + off, (state & 1) << 1);
|
||||
#endif
|
||||
// 番号が一致したら、ファイルのサイズと日時を比較する
|
||||
if (((state >> 1) == (num & 0x7FFF)) && (memcmp(buf + (off + 12), meta, 16) == 0))
|
||||
return (state & 1) << 1;
|
||||
return -2; // 状態が変化してる
|
||||
}
|
||||
}
|
||||
ini_off += rv;
|
||||
}
|
||||
|
||||
ini_off = 0;
|
||||
return -2; // これ以上の検査記録は無い
|
||||
}
|
||||
|
||||
// ソース・ファイル状態は完全か破損だけ (消失だと検査しない)
|
||||
void write_ini_state(
|
||||
int num, // ファイル番号
|
||||
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
|
||||
int state) // 状態、0=完全, 2=破損
|
||||
{
|
||||
unsigned char buf[STATE_SIZE];
|
||||
|
||||
if ((recent_data == 0) || ((meta[0] <= REUSE_MIN) && (meta[1] == 0)))
|
||||
return; // 小さなファイルは検査結果を記録しない
|
||||
|
||||
if (ini_off == 0){ // 記録が無ければ末尾に追加する
|
||||
ini_off = GetFileSize(hIniBin, NULL);
|
||||
if (ini_off == INVALID_FILE_SIZE){
|
||||
delete_ini_file();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 今回の状態を書き込む
|
||||
memcpy(buf, meta + 4, 12);
|
||||
memcpy(buf + 12, meta, 16);
|
||||
buf[28] = (unsigned char)((state >> 1) | (num << 1));
|
||||
buf[29] = (unsigned char)(num >> 7);
|
||||
#ifdef VERBOSE
|
||||
printf("write state, num = %d, offset = %d, state = %d\n", num, ini_off, state);
|
||||
#endif
|
||||
if (file_write_data(hIniBin, ini_off, buf, STATE_SIZE) != 0){
|
||||
delete_ini_file();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
34
source/sfv_md5/ini.h
Normal file
34
source/sfv_md5/ini.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#ifndef _INI_H_
|
||||
#define _INI_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define INI_NAME_LEN 38 // 検査結果ファイルのファイル名の文字数
|
||||
|
||||
extern int recent_data;
|
||||
|
||||
unsigned int time_f_u(FILETIME *file_time);
|
||||
|
||||
int check_ini_file(unsigned char *set_hash, unsigned int set_len);
|
||||
void close_ini_file(void);
|
||||
void write_ini_file(void);
|
||||
|
||||
int check_ini_state(
|
||||
int num, // ファイル番号
|
||||
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
|
||||
HANDLE hFile); // そのファイルのハンドル
|
||||
|
||||
void write_ini_state(
|
||||
int num, // ファイル番号
|
||||
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
|
||||
int state); // 状態
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
861
source/sfv_md5/main.c
Normal file
861
source/sfv_md5/main.c
Normal file
@@ -0,0 +1,861 @@
|
||||
// main.c
|
||||
// Copyright : 2022-02-25 Yutaka Sawada
|
||||
// License : The MIT license
|
||||
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600 // Windows Vista or later
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <imagehlp.h>
|
||||
|
||||
#include "crc.h"
|
||||
#include "common.h"
|
||||
#include "create.h"
|
||||
#include "verify.h"
|
||||
#include "ini.h"
|
||||
#include "version.h"
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
void print_help(void)
|
||||
{
|
||||
printf(
|
||||
"Usage\n"
|
||||
"c(reate) [fo,t, d,u] <checksum file> [input files]\n"
|
||||
"v(erify) [vs,vd,d,u] <checksum file>\n"
|
||||
"\nOption\n"
|
||||
" /fo : Search file only for wildcard\n"
|
||||
" /t<n> : Save time stamp\n"
|
||||
" /vs<n>: Skip verification by recent result\n"
|
||||
" /vd\"*\": Set directory of recent result\n"
|
||||
" /d\"*\" : Set directory of input files\n"
|
||||
" /u : Console output is encoded with UTF-8\n"
|
||||
);
|
||||
}
|
||||
|
||||
// CRC-32 チェックサムを使って自分自身の破損を検出する
|
||||
long test_checksum(wchar_t *file_path) // 作業用
|
||||
{
|
||||
unsigned long rv, crc, chk, chk2;
|
||||
unsigned char *pAddr;
|
||||
HANDLE hFile, hMap;
|
||||
|
||||
init_crc_table(); // CRC 計算用のテーブルを作成する
|
||||
|
||||
// 実行ファイルのパスを取得する
|
||||
rv = GetModuleFileName(NULL, file_path, MAX_LEN);
|
||||
if ((rv == 0) || (rv >= MAX_LEN))
|
||||
return 1;
|
||||
|
||||
// 実行ファイルの PE checksum と CRC-32 を検証する
|
||||
hFile = CreateFile(file_path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE){
|
||||
print_win32_err();
|
||||
return 1;
|
||||
}
|
||||
rv = GetFileSize(hFile, &chk2);
|
||||
if (rv == INVALID_FILE_SIZE)
|
||||
return 1;
|
||||
hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, chk2, rv, NULL);
|
||||
if (hMap == NULL){
|
||||
CloseHandle(hFile);
|
||||
return 1;
|
||||
}
|
||||
pAddr = MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, rv);
|
||||
if (pAddr == NULL){
|
||||
CloseHandle(hMap);
|
||||
CloseHandle(hFile);
|
||||
return 1;
|
||||
}
|
||||
if (CheckSumMappedFile(pAddr, rv, &chk2, &chk) == NULL){ // PE checksum
|
||||
UnmapViewOfFile(pAddr);
|
||||
CloseHandle(hMap);
|
||||
CloseHandle(hFile);
|
||||
return 1;
|
||||
}
|
||||
crc = crc_update(0xFFFFFFFF, pAddr, rv) ^ 0xFFFFFFFF;
|
||||
UnmapViewOfFile(pAddr);
|
||||
CloseHandle(hMap);
|
||||
CloseHandle(hFile);
|
||||
|
||||
if (chk != chk2)
|
||||
return 2;
|
||||
if (crc != 0x00000000)
|
||||
return 3;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ファイルを検索してファイル・リストに追加する
|
||||
static wchar_t * search_files(
|
||||
wchar_t *list_buf, // ファイル・リスト
|
||||
wchar_t *search_path, // 検索するファイルのフル・パス
|
||||
long dir_len, // ディレクトリ部分の長さ
|
||||
long file_only, // ファイルのみにするかどうか
|
||||
long single_file, // -1 = *や?で検索指定、0~ = 単独指定
|
||||
long *list_max, // ファイル・リストの確保サイズ
|
||||
long *list_len, // ファイル・リストの文字数
|
||||
__int64 *total_size) // 合計ファイル・サイズ
|
||||
{
|
||||
wchar_t *tmp_p;
|
||||
long len, l_max, l_off, dir_len2;
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATA FindData;
|
||||
|
||||
if (list_buf == NULL){
|
||||
l_off = 0;
|
||||
l_max = ALLOC_LEN;
|
||||
list_buf = (wchar_t *)malloc(l_max);
|
||||
if (list_buf == NULL){
|
||||
printf("malloc, %d\n", l_max);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
l_max = *list_max;
|
||||
l_off = *list_len;
|
||||
}
|
||||
|
||||
// 検索する
|
||||
hFind = FindFirstFile(search_path, &FindData);
|
||||
if (hFind == INVALID_HANDLE_VALUE)
|
||||
return list_buf; // 見つからなかったらそのまま
|
||||
do {
|
||||
if ((single_file < 0) && (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
|
||||
continue; // 検索中は隠し属性が付いてるファイルを無視する
|
||||
|
||||
len = wcslen(FindData.cFileName);
|
||||
if (dir_len + len >= MAX_LEN - ADD_LEN - 2){ // 末尾に「\*」を付けて再検索するので
|
||||
FindClose(hFind);
|
||||
free(list_buf);
|
||||
printf("filename is too long\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 現在のディレクトリ部分に見つかったファイル名を連結する
|
||||
wcscpy(search_path + dir_len, FindData.cFileName);
|
||||
|
||||
// フォルダなら
|
||||
if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
|
||||
if ((file_only == 0) && wcscmp(FindData.cFileName, L".") && wcscmp(FindData.cFileName, L"..")){
|
||||
// フォルダの末尾は「\」にする
|
||||
wcscat(search_path, L"\\");
|
||||
// そのフォルダの中身を更に検索する
|
||||
dir_len2 = wcslen(search_path);
|
||||
search_path[dir_len2 ] = '*'; // 末尾に「*」を追加する
|
||||
search_path[dir_len2 + 1] = 0;
|
||||
list_buf = search_files(list_buf, search_path, dir_len2, file_only, single_file, &l_max, &l_off, total_size);
|
||||
if (list_buf == NULL){
|
||||
FindClose(hFind);
|
||||
printf("cannot search inner folder\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
} else { // ファイルなら
|
||||
if (!search_file_path(list_buf, l_off, search_path + base_len)){ // ファイル名が重複しないようにする
|
||||
if ((l_off + dir_len- base_len + len) * 2 >= l_max){ // 領域が足りなくなるなら拡張する
|
||||
l_max += ALLOC_LEN;
|
||||
tmp_p = (wchar_t *)realloc(list_buf, l_max);
|
||||
if (tmp_p == NULL){
|
||||
FindClose(hFind);
|
||||
free(list_buf);
|
||||
printf("realloc, %d\n", l_max);
|
||||
return NULL;
|
||||
} else {
|
||||
list_buf = tmp_p;
|
||||
}
|
||||
}
|
||||
|
||||
// リストにコピーする
|
||||
wcscpy(list_buf + l_off, search_path + base_len);
|
||||
l_off += dir_len - base_len + len + 1;
|
||||
file_num++;
|
||||
(*total_size) += ((__int64)FindData.nFileSizeHigh << 32) | (__int64)FindData.nFileSizeLow;
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &FindData)); // 次のファイルを検索する
|
||||
FindClose(hFind);
|
||||
|
||||
*list_max = l_max;
|
||||
*list_len = l_off;
|
||||
return list_buf;
|
||||
}
|
||||
|
||||
// ファイルの詳細情報を記録する
|
||||
long save_detail(
|
||||
wchar_t *uni_buf,
|
||||
wchar_t *file_name) // 検査対象のファイル名
|
||||
{
|
||||
__int64 file_size;
|
||||
HANDLE hFile;
|
||||
FILETIME ftWrite;
|
||||
SYSTEMTIME stUTC, stLocal;
|
||||
|
||||
// 調べるファイルを開く
|
||||
wcscpy(uni_buf, base_dir);
|
||||
wcscpy(uni_buf + base_len, file_name);
|
||||
hFile = CreateFile(uni_buf, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE){
|
||||
print_win32_err();
|
||||
return 1;
|
||||
}
|
||||
// ファイル・サイズ
|
||||
if (!GetFileSizeEx(hFile, (PLARGE_INTEGER)&file_size)){
|
||||
print_win32_err();
|
||||
CloseHandle(hFile);
|
||||
return 1;
|
||||
}
|
||||
// 更新日時
|
||||
if (!GetFileTime(hFile, NULL, NULL, &ftWrite)){
|
||||
print_win32_err();
|
||||
CloseHandle(hFile);
|
||||
return 1;
|
||||
}
|
||||
FileTimeToSystemTime(&ftWrite, &stUTC);
|
||||
SystemTimeToTzSpecificLocalTime(NULL, &stUTC, &stLocal);
|
||||
CloseHandle(hFile);
|
||||
|
||||
// サイズと日時を書き込む
|
||||
wsprintf(uni_buf, L";%13I64d %02d:%02d.%02d %4d-%02d-%02d ", file_size,
|
||||
stLocal.wHour, stLocal.wMinute, stLocal.wSecond,
|
||||
stLocal.wYear, stLocal.wMonth, stLocal.wDay);
|
||||
add_text(uni_buf);
|
||||
|
||||
// ファイル名を書き込む
|
||||
wcscpy(uni_buf, file_name); // 変換前にコピーする
|
||||
unix_directory(uni_buf);
|
||||
add_text(uni_buf);
|
||||
add_text(L"\r\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// チェックサム・ファイルを書き込む
|
||||
static long write_checksum(wchar_t *uni_buf,
|
||||
wchar_t *list_buf, long list_len, __int64 total_size, long switch_t)
|
||||
{
|
||||
char *ascii_buf;
|
||||
wchar_t *ads_p;
|
||||
long err = 0, rv, len, format;
|
||||
__int64 prog_now = 0;
|
||||
HANDLE hFile;
|
||||
FILETIME ftWrite;
|
||||
|
||||
len = wcslen(checksum_file);
|
||||
if (_wcsicmp(checksum_file + (len - 4), L".sfv") == 0){ // SFVファイル
|
||||
format = 1;
|
||||
} else if (_wcsicmp(checksum_file + (len - 4), L".md5") == 0){ // MD5ファイル
|
||||
format = 2;
|
||||
// } else {
|
||||
// printf("unknown format\n");
|
||||
// return 1;
|
||||
}
|
||||
|
||||
// チェックサム・ファイルのテキストを UTF-16 の文字列で作成する
|
||||
text_len = 0;
|
||||
text_max = ALLOC_LEN;
|
||||
text_buf = (wchar_t *)malloc(text_max * 2);
|
||||
if (text_buf == NULL){
|
||||
printf("malloc, %d\n", text_max * 2);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// コメントを書き込む
|
||||
wsprintf(uni_buf, L"; Generated by SFV/MD5 checker v%hs", PRODUCT_VERSION);
|
||||
add_text(uni_buf);
|
||||
if (switch_t >= 1){ // 作成した日時を書き込む
|
||||
SYSTEMTIME stLocal;
|
||||
GetLocalTime(&stLocal);
|
||||
wsprintf(uni_buf, L" on %4d-%02d-%02d at %02d:%02d.%02d",
|
||||
stLocal.wYear, stLocal.wMonth, stLocal.wDay,
|
||||
stLocal.wHour, stLocal.wMinute, stLocal.wSecond);
|
||||
add_text(uni_buf);
|
||||
if (switch_t >= 2){ // ファイルの詳細を書き込むなら
|
||||
add_text(L"\r\n;");
|
||||
if (file_num > 1){
|
||||
add_text(L"\r\n");
|
||||
add_text(L"; Size (Bytes) Time Date Filename\n");
|
||||
add_text(L"; ------------ -------- ---------- ------------");
|
||||
}
|
||||
}
|
||||
}
|
||||
add_text(L"\r\n");
|
||||
|
||||
if (switch_t >= 2){ // ファイルのサイズと更新日時を書き込む
|
||||
len = 0;
|
||||
while (len < list_len){
|
||||
if (save_detail(uni_buf, list_buf + len) != 0){
|
||||
printf("cannot save detail\n");
|
||||
free(text_buf);
|
||||
return 1;
|
||||
}
|
||||
len += wcslen(list_buf + len) + 1;
|
||||
}
|
||||
add_text(L";\r\n");
|
||||
}
|
||||
|
||||
// 各ファイルのチェックサムを計算する
|
||||
printf("\n");
|
||||
print_progress_text(0, "Computing file hash");
|
||||
len = 0;
|
||||
while (len < list_len){
|
||||
if (format == 1){
|
||||
rv = create_sfv(uni_buf, list_buf + len, &prog_now, total_size);
|
||||
} else if (format == 2){
|
||||
rv = create_md5(uni_buf, list_buf + len, &prog_now, total_size);
|
||||
} else {
|
||||
rv = 1;
|
||||
}
|
||||
if (rv != 0){
|
||||
free(text_buf);
|
||||
return rv; // エラー、キャンセルなど
|
||||
}
|
||||
len += wcslen(list_buf + len) + 1;
|
||||
}
|
||||
print_progress_done(); // 改行して行の先頭に戻しておく
|
||||
|
||||
// 既存ファイルの alternate data stream に書き込む場合は更新日時をそのままにする
|
||||
ads_p = wcschr(offset_file_name(checksum_file), ':');
|
||||
if (ads_p != NULL){
|
||||
*ads_p = 0;
|
||||
hFile = CreateFile(checksum_file, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL);
|
||||
*ads_p = ':';
|
||||
if (hFile == INVALID_HANDLE_VALUE){
|
||||
ads_p = NULL;
|
||||
} else {
|
||||
if (!GetFileTime(hFile, NULL, NULL, &ftWrite)){
|
||||
//print_win32_err();
|
||||
//printf("cannot read time stamp\n");
|
||||
ads_p = NULL;
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
}
|
||||
}
|
||||
|
||||
// UTF-16 から UTF-8 に変換する
|
||||
len = text_len * 3;
|
||||
ascii_buf = (char *)malloc(len);
|
||||
if (ascii_buf == NULL){
|
||||
printf("malloc, %d\n", len);
|
||||
free(text_buf);
|
||||
return 1;
|
||||
}
|
||||
if (utf16_to_cp(text_buf, ascii_buf, len, CP_UTF8) != 0){
|
||||
printf("cannot encode text\n");
|
||||
free(ascii_buf);
|
||||
free(text_buf);
|
||||
return 1;
|
||||
}
|
||||
len = strlen(ascii_buf);
|
||||
|
||||
// チェックサム・ファイルを開いて、エンコードしたテキストを書き込む
|
||||
hFile = CreateFile(checksum_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE){
|
||||
print_win32_err();
|
||||
printf("cannot create checksum file\n");
|
||||
free(ascii_buf);
|
||||
free(text_buf);
|
||||
return 1;
|
||||
}
|
||||
if (!WriteFile(hFile, ascii_buf, len, &rv, NULL)){
|
||||
print_win32_err();
|
||||
printf("cannot write checksum file\n");
|
||||
CloseHandle(hFile);
|
||||
free(ascii_buf);
|
||||
free(text_buf);
|
||||
return 1;
|
||||
}
|
||||
// main stream の更新日時を元に戻す
|
||||
if (ads_p != NULL)
|
||||
SetFileTime(hFile, NULL, NULL, &ftWrite);
|
||||
|
||||
CloseHandle(hFile); // チェックサム・ファイルを閉じる
|
||||
free(ascii_buf);
|
||||
free(text_buf);
|
||||
|
||||
printf("\nCreated successfully\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// チェックサム・ファイルを読み込む
|
||||
static long read_checksum(char *ascii_buf, wchar_t *file_path)
|
||||
{
|
||||
unsigned char *data_buf;
|
||||
unsigned long err = 0, rv, file_size;
|
||||
HANDLE hFile;
|
||||
|
||||
// 読み込むファイルを開く
|
||||
hFile = CreateFile(checksum_file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE){
|
||||
print_win32_err();
|
||||
printf("cannot open checksum file\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 2MB を越えるチェックサム・ファイルには対応しない
|
||||
file_size = GetFileSize(hFile, NULL);
|
||||
if ((file_size == INVALID_FILE_SIZE) || (file_size > (2 << 21))){
|
||||
CloseHandle(hFile);
|
||||
printf("checksum file is too large\n");
|
||||
return 1;
|
||||
}
|
||||
printf("Checksum Size\t: %d\n\n", file_size);
|
||||
fflush(stdout);
|
||||
|
||||
// ハッシュ値を記録するには最低でも 1(ファイル名)+1(スペース)+8(CRC-32) = 10バイト必要
|
||||
if (file_size < 10){
|
||||
CloseHandle(hFile);
|
||||
printf("Status : Damaged\n");
|
||||
printf("valid file is not found\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ファイル全体を読み込む
|
||||
data_buf = (unsigned char *)malloc(file_size + 2);
|
||||
if (data_buf == NULL){
|
||||
CloseHandle(hFile);
|
||||
printf("malloc, %d\n", file_size);
|
||||
return 1;
|
||||
}
|
||||
text_max = file_size + 1; // 全て ASCII 文字と仮定して、末尾に null 文字を付けた時の文字数
|
||||
text_buf = (wchar_t *)malloc(text_max * 2);
|
||||
if (text_buf == NULL){
|
||||
free(data_buf);
|
||||
CloseHandle(hFile);
|
||||
printf("malloc, %d\n", text_max * 2);
|
||||
return 1;
|
||||
}
|
||||
if (!ReadFile(hFile, data_buf, file_size, &rv, NULL) || (file_size != rv)){
|
||||
free(data_buf);
|
||||
free(text_buf);
|
||||
CloseHandle(hFile);
|
||||
printf("ReadFile, %d\n", file_size);
|
||||
return 1;
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
data_buf[file_size ] = 0; // 末尾に null 文字を付けておく
|
||||
data_buf[file_size + 1] = 0;
|
||||
|
||||
// UTF-16 の文字列に変換する
|
||||
rv = utf16_to_utf16(data_buf, file_size + 2, text_buf);
|
||||
if (rv != 0){ // UTF-16 ではなかった
|
||||
if (check_utf8(data_buf) == 0){ // UTF-8 として変換する
|
||||
rv = 0; // BOMが付いてるかどうか
|
||||
if ((data_buf[0] == 0xEF) && (data_buf[1] == 0xBB) && (data_buf[2] == 0xBF))
|
||||
rv = 3;
|
||||
rv = cp_to_utf16(data_buf + rv, text_buf, file_size + 1, CP_UTF8);
|
||||
} else {
|
||||
rv = cp_to_utf16(data_buf, text_buf, file_size + 1, CP_ACP);
|
||||
if (rv != 0)
|
||||
rv = cp_to_utf16(data_buf, text_buf, file_size + 1, 1252); // Latin-1 CP1252 で変換を試みる
|
||||
}
|
||||
}
|
||||
free(data_buf);
|
||||
if (rv != 0){
|
||||
free(text_buf);
|
||||
printf("cannot decode text\n");
|
||||
return 1;
|
||||
}
|
||||
text_len = wcslen(text_buf); // 文字数には末尾の null 文字を含まないことに注意
|
||||
|
||||
// チェックサムを検証する
|
||||
rv = wcslen(checksum_file);
|
||||
if (_wcsicmp(checksum_file + (rv - 4), L".sfv") == 0){ // SFVファイル
|
||||
err = verify_sfv(ascii_buf, file_path);
|
||||
} else if (_wcsicmp(checksum_file + (rv - 4), L".md5") == 0){ // MD5ファイル
|
||||
err = verify_md5(ascii_buf, file_path);
|
||||
// } else {
|
||||
// err = 1;
|
||||
// printf("unknown format\n");
|
||||
}
|
||||
free(text_buf);
|
||||
close_ini_file();
|
||||
|
||||
// 検査結果を表示する
|
||||
printf("\n");
|
||||
if (err == 0){
|
||||
printf("All Files Complete\n");
|
||||
} else {
|
||||
if (err & 16)
|
||||
printf("Checksum File Incomplete\n");
|
||||
if (err & 0xFFFFFF00){
|
||||
printf("%d Files Missing or Damaged\n", err >> 8);
|
||||
//err &= 0xFF;
|
||||
}
|
||||
err = ((err & 0x10) << 4) | (err & 0xEF); // 16を 256 に変更する
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
// チェックサム・ファイルとソース・ファイルの名前に問題が無いか確かめる
|
||||
static long check_filename(
|
||||
wchar_t *list_buf,
|
||||
long list_len)
|
||||
{
|
||||
wchar_t *tmp_p;
|
||||
long num, list_off = 0;
|
||||
|
||||
// SFV ファイル作成時に、ソース・ファイルの先頭が「;」だとコメントと区別できない
|
||||
if (_wcsicmp(checksum_file + (wcslen(checksum_file) - 4), L".sfv") == 0){ // SFVファイル
|
||||
for (num = 0; num < file_num; num++){
|
||||
tmp_p = list_buf + list_off;
|
||||
while (list_buf[list_off] != 0)
|
||||
list_off++;
|
||||
list_off++;
|
||||
|
||||
// ファイル名の先頭を調べる
|
||||
if (tmp_p[0] == ';'){
|
||||
printf_cp("filename is invalid, %s\n", tmp_p);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 基準ディレクトリ外にチェックサム・ファイルが存在するなら問題なし
|
||||
if (_wcsnicmp(checksum_file, base_dir, base_len) != 0)
|
||||
return 0;
|
||||
|
||||
// チェックサム・ファイルとソース・ファイルが同じ名前にならないようにする
|
||||
for (num = 0; num < file_num; num++){
|
||||
tmp_p = list_buf + list_off;
|
||||
while (list_buf[list_off] != 0)
|
||||
list_off++;
|
||||
list_off++;
|
||||
|
||||
// ファイル名との一致を調べる
|
||||
if (_wcsicmp(checksum_file + base_len, tmp_p) == 0){
|
||||
printf_cp("filename is invalid, %s\n", tmp_p);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
wmain(long argc, wchar_t *argv[])
|
||||
{
|
||||
char ascii_buf[MAX_LEN * 3];
|
||||
wchar_t file_path[MAX_LEN], *tmp_p;
|
||||
long i, j, switch_set = 0;
|
||||
/*
|
||||
t = switch_set & 0x00000003
|
||||
fo= switch_set & 0x00000020
|
||||
*/
|
||||
printf("SFV/MD5 checker version " FILE_VERSION " by Yutaka Sawada\n\n");
|
||||
if (argc < 3){
|
||||
printf("Self-Test: ");
|
||||
i = test_checksum(file_path);
|
||||
if (i == 0){
|
||||
printf("Success");
|
||||
} else if (i == 2){
|
||||
printf("PE checksum is different");
|
||||
} else if (i == 3){
|
||||
printf("CRC-32 is different");
|
||||
} else {
|
||||
printf("Error\0thedummytext");
|
||||
}
|
||||
printf("\n\n");
|
||||
print_help();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 初期化
|
||||
checksum_file[0] = 0;
|
||||
base_dir[0] = 0;
|
||||
ini_path[0] = 0;
|
||||
file_num = 0;
|
||||
cp_output = GetConsoleOutputCP();
|
||||
|
||||
// コマンド
|
||||
switch (argv[1][0]){
|
||||
case 'c': // create
|
||||
case 'v': // verify
|
||||
break;
|
||||
default:
|
||||
print_help();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// オプションとチェックサム・ファイルの指定
|
||||
for (i = 2; i < argc; i++){
|
||||
tmp_p = argv[i];
|
||||
// オプション
|
||||
if (((tmp_p[0] == '/') || (tmp_p[0] == '-')) && (tmp_p[0] == argv[2][0])){
|
||||
tmp_p++; // 先頭の識別文字をとばす
|
||||
// オプション
|
||||
if (wcscmp(tmp_p, L"u") == 0){
|
||||
cp_output = CP_UTF8;
|
||||
} else if (wcscmp(tmp_p, L"fo") == 0){
|
||||
switch_set |= 0x20;
|
||||
|
||||
// オプション (数値)
|
||||
} else if (wcsncmp(tmp_p, L"vs", 2) == 0){
|
||||
recent_data = 0;
|
||||
j = 2;
|
||||
while ((j < 2 + 2) && (tmp_p[j] >= '0') && (tmp_p[j] <= '9')){
|
||||
recent_data = (recent_data * 10) + (tmp_p[j] - '0');
|
||||
j++;
|
||||
}
|
||||
if ((recent_data == 8) || (recent_data > 15))
|
||||
recent_data = 0;
|
||||
} else if (wcsncmp(tmp_p, L"t", 1) == 0){
|
||||
j = -1;
|
||||
if ((tmp_p[1] >= '0') && (tmp_p[1] <= '2')) // 0~2 の範囲
|
||||
j = tmp_p[1] - '0';
|
||||
if (j != -1)
|
||||
switch_set |= j;
|
||||
|
||||
// オプション (文字列)
|
||||
} else if (wcsncmp(tmp_p, L"vd", 2) == 0){
|
||||
tmp_p += 2;
|
||||
j = copy_path_prefix(ini_path, MAX_LEN - INI_NAME_LEN - 1, tmp_p, NULL);
|
||||
if (j == 0){
|
||||
printf("save-directory is invalid\n");
|
||||
return 1;
|
||||
}
|
||||
if (ini_path[j - 1] != '\\'){ // 末尾が「\」でなければ付けておく
|
||||
ini_path[j ] = '\\';
|
||||
ini_path[j + 1] = 0;
|
||||
}
|
||||
//printf("Save Directory : %S\n", ini_path);
|
||||
j = GetFileAttributes(ini_path);
|
||||
if ((j == INVALID_FILE_ATTRIBUTES) || !(j & FILE_ATTRIBUTE_DIRECTORY)){
|
||||
printf("save-directory is invalid\n");
|
||||
return 1;
|
||||
}
|
||||
} else if (wcsncmp(tmp_p, L"d", 1) == 0){
|
||||
tmp_p++;
|
||||
j = copy_path_prefix(base_dir, MAX_LEN - 2, tmp_p, NULL); // 末尾に追加される分の余裕を見ておく
|
||||
if (j == 0){
|
||||
printf("base-directory is invalid\n");
|
||||
return 1;
|
||||
}
|
||||
if (base_dir[j - 1] != '\\'){ // 末尾が「\」でなければ付けておく
|
||||
base_dir[j ] = '\\';
|
||||
base_dir[j + 1] = 0;
|
||||
}
|
||||
j = GetFileAttributes(base_dir);
|
||||
if ((j == INVALID_FILE_ATTRIBUTES) || !(j & FILE_ATTRIBUTE_DIRECTORY)){
|
||||
printf("base-directory is invalid\n");
|
||||
return 1;
|
||||
}
|
||||
} else { // 未対応のオプション
|
||||
utf16_to_cp(tmp_p - 1, ascii_buf, MAX_LEN * 3, cp_output);
|
||||
printf("invalid option, %s\n", ascii_buf);
|
||||
return 1;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// オプション以外ならリカバリ・ファイル
|
||||
j = copy_path_prefix(checksum_file, MAX_LEN, tmp_p, NULL);
|
||||
if (j == 0){
|
||||
printf("checksum filename is invalid\n");
|
||||
return 1;
|
||||
}
|
||||
// 拡張子は SFV か MD5 のみ
|
||||
if (_wcsicmp(checksum_file + (j - 4), L".sfv") == 0){
|
||||
init_crc_table(); // CRC 計算用のテーブルを作る
|
||||
} else if (_wcsicmp(checksum_file + (j - 4), L".md5") == 0){
|
||||
if (recent_data != 0)
|
||||
init_crc_table();
|
||||
} else { // 拡張子が違うなら
|
||||
wcscpy(checksum_file + j, L".sfv"); // 標準で SFV 形式にする
|
||||
if (argv[1][0] == 'c'){ // 作成なら
|
||||
init_crc_table();
|
||||
} else { // 検査なら
|
||||
if (GetFileAttributes(checksum_file) == INVALID_FILE_ATTRIBUTES){
|
||||
wcscpy(checksum_file + j, L".md5"); // SFV で駄目なら MD5 にする
|
||||
if (GetFileAttributes(checksum_file) == INVALID_FILE_ATTRIBUTES){
|
||||
printf("file format is unknown\n");
|
||||
return 1;
|
||||
} else if (recent_data != 0){
|
||||
init_crc_table();
|
||||
}
|
||||
} else {
|
||||
init_crc_table();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (argv[1][0] == 'c'){ // 作成なら
|
||||
// 指定されたファイル名が適切か調べる
|
||||
if (sanitize_filename(offset_file_name(checksum_file)) != 0){
|
||||
printf("checksum filename is invalid\n");
|
||||
return 1;
|
||||
}
|
||||
} else { // 検査なら
|
||||
j = GetFileAttributes(checksum_file);
|
||||
if ((j == INVALID_FILE_ATTRIBUTES) || (j & FILE_ATTRIBUTE_DIRECTORY)){
|
||||
wchar_t search_path[MAX_LEN];
|
||||
long name_len, dir_len, path_len, find_flag = 0;
|
||||
HANDLE hFind;
|
||||
WIN32_FIND_DATA FindData;
|
||||
if (wcspbrk(offset_file_name(checksum_file), L"*?") == NULL){
|
||||
// 「*」や「?」で検索しない場合、ファイルが見つからなければエラーにする
|
||||
printf("valid file is not found\n");
|
||||
return 1;
|
||||
}
|
||||
// 指定された拡張子で検索する
|
||||
path_len = wcslen(checksum_file);
|
||||
hFind = FindFirstFile(checksum_file, &FindData);
|
||||
if (hFind != INVALID_HANDLE_VALUE){
|
||||
get_base_dir(checksum_file, search_path);
|
||||
dir_len = wcslen(search_path);
|
||||
do {
|
||||
//printf("file name = %S\n", FindData.cFileName);
|
||||
name_len = wcslen(FindData.cFileName);
|
||||
if ((dir_len + name_len < MAX_LEN) && // ファイル名が長すぎない
|
||||
(_wcsicmp(FindData.cFileName + (name_len - 4), checksum_file + (path_len - 4)) == 0)){ // 拡張子が同じ
|
||||
find_flag = 1;
|
||||
break; // 見つけたファイル名で問題なし
|
||||
}
|
||||
} while (FindNextFile(hFind, &FindData)); // 次のファイルを検索する
|
||||
FindClose(hFind);
|
||||
}
|
||||
if (find_flag == 0){
|
||||
printf("valid file is not found\n");
|
||||
return 1;
|
||||
}
|
||||
wcscpy(checksum_file + dir_len, FindData.cFileName);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (checksum_file[0] == 0){ // チェックサム・ファイルが指定されてないなら
|
||||
printf("checksum file is not specified\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// input file の位置が指定されて無くて、
|
||||
// 最初のソース・ファイル指定に絶対パスや相対パスが含まれてるなら、それを使う
|
||||
if (argv[1][0] == 'c'){
|
||||
if ((base_dir[0] == 0) && (i + 1 < argc)){
|
||||
tmp_p = argv[i + 1];
|
||||
if (is_full_path(tmp_p) != 0){ // 絶対パスなら
|
||||
if (copy_path_prefix(file_path, MAX_LEN - 2, tmp_p, NULL) == 0){
|
||||
printf("base-directory is invalid\n");
|
||||
return 1;
|
||||
}
|
||||
get_base_dir(file_path, base_dir); // 最初のソース・ファイルの位置にする
|
||||
if (len_without_prefix(base_dir) == 0) // サブ・ディレクトリが無ければ
|
||||
base_dir[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (base_dir[0] == 0) // input file の位置が指定されてないなら
|
||||
get_base_dir(checksum_file, base_dir); // リカバリ・ファイルの位置にする
|
||||
base_len = wcslen(base_dir);
|
||||
|
||||
// 動作環境の表示
|
||||
// 「\\?\」は常に付加されてるので表示する際には無視する
|
||||
printf_cp("Base Directory\t: \"%s\"\n", base_dir);
|
||||
printf_cp("Checksum File\t: \"%s\"\n", checksum_file);
|
||||
|
||||
if (argv[1][0] == 'c'){
|
||||
wchar_t *list_buf;
|
||||
long dir_len, list_len, list_max;
|
||||
__int64 total_size = 0; // 合計ファイル・サイズ
|
||||
// チェックサム・ファイル作成ならソース・ファイルのリストがいる
|
||||
i++;
|
||||
if (i >= argc){
|
||||
printf("input file is not specified\n");
|
||||
return 1;
|
||||
}
|
||||
// 入力ファイルの指定
|
||||
file_num = 0;
|
||||
list_len = 0;
|
||||
list_max = 0;
|
||||
list_buf = NULL;
|
||||
for (; i < argc; i++){
|
||||
// ファイルが基準ディレクトリ以下に存在することを確認する
|
||||
tmp_p = argv[i];
|
||||
j = copy_path_prefix(file_path, MAX_LEN - 2, tmp_p, base_dir); // 絶対パスにしてから比較する
|
||||
if (j == 0){
|
||||
free(list_buf);
|
||||
printf_cp("filename is invalid, %s\n", tmp_p);
|
||||
return 1;
|
||||
}
|
||||
if ((j <= base_len) || (_wcsnicmp(base_dir, file_path, base_len) != 0)){ // 基準ディレクトリ外なら
|
||||
free(list_buf);
|
||||
printf_cp("out of base-directory, %s\n", tmp_p);
|
||||
return 1;
|
||||
}
|
||||
//printf("%d = %S\n", i, argv[i]);
|
||||
//printf_cp("search = %s\n", file_path);
|
||||
// 「*」や「?」で検索しない場合、ファイルが見つからなければエラーにする
|
||||
j = -1;
|
||||
if (wcspbrk(file_path + base_len, L"*?") == NULL)
|
||||
j = file_num;
|
||||
// ファイルを検索する
|
||||
dir_len = wcslen(file_path) - 2; // ファイル名末尾の「\」を無視して、ディレクトリ部分の長さを求める
|
||||
while (file_path[dir_len] != '\\')
|
||||
dir_len--;
|
||||
dir_len++;
|
||||
list_buf = search_files(list_buf, file_path, dir_len, switch_set & 0x20, j, &list_max, &list_len, &total_size);
|
||||
if (list_buf == NULL)
|
||||
return 1;
|
||||
if ((j != -1) && (j == file_num)){ // ファイルが見つかったか確かめる
|
||||
free(list_buf);
|
||||
printf_cp("input file is not found, %s\n", file_path + base_len);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (list_len == 0){
|
||||
if (list_buf)
|
||||
free(list_buf);
|
||||
printf("input file is not found\n");
|
||||
return 1;
|
||||
}
|
||||
if (check_filename(list_buf, list_len)){
|
||||
free(list_buf);
|
||||
return 1;
|
||||
}
|
||||
/*{
|
||||
FILE *fp;
|
||||
fp = fopen("list_buf.txt", "wb");
|
||||
fwrite(list_buf, 2, list_len, fp);
|
||||
fclose(fp);
|
||||
}*/
|
||||
|
||||
// ファイル・リストの内容を並び替える (リストの末尾は null 1個にすること)
|
||||
sort_list(list_buf, list_len);
|
||||
|
||||
printf("\nInput File count\t: %d\n", file_num);
|
||||
printf("Input File total size\t: %I64d\n", total_size);
|
||||
i = write_checksum(file_path, list_buf, list_len, total_size, switch_set & 3);
|
||||
|
||||
} else {
|
||||
// 検査結果ファイルの位置が指定されてないなら
|
||||
if ((recent_data != 0) && (ini_path[0] == 0)){
|
||||
// 実行ファイルのディレクトリにする
|
||||
j = GetModuleFileName(NULL, ini_path, MAX_LEN);
|
||||
if ((j == 0) || (j >= MAX_LEN)){
|
||||
printf("GetModuleFileName\n");
|
||||
return 1;
|
||||
}
|
||||
while (j > 0){
|
||||
if (ini_path[j - 1] == '\\'){
|
||||
ini_path[j] = 0;
|
||||
break;
|
||||
}
|
||||
j--;
|
||||
}
|
||||
if (j >= MAX_LEN - INI_NAME_LEN - 1){
|
||||
printf("save-directory is invalid\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
i = read_checksum(ascii_buf, file_path);
|
||||
}
|
||||
|
||||
//printf("ExitCode: %d\n", i);
|
||||
return i;
|
||||
}
|
||||
|
||||
79
source/sfv_md5/phmd5.c
Normal file
79
source/sfv_md5/phmd5.c
Normal file
@@ -0,0 +1,79 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
;
|
||||
; MD5 hash generator -- Paul Houle (paulhoule.com) 11/13/2017
|
||||
;
|
||||
; Non-time critical C logic. All API entry points are here.
|
||||
; See phmd5.h for documentation.
|
||||
;
|
||||
;---------------------------------------------------------------------------*/
|
||||
|
||||
#include <string.h>
|
||||
#include "phmd5.h"
|
||||
|
||||
// First call -- initialize pmd5 structure for use.
|
||||
void Phmd5Begin(PHMD5 *pmd5) {
|
||||
unsigned __int32 *uhash = (unsigned __int32 *) pmd5->hash;
|
||||
|
||||
uhash[0] = 0x67452301; // init hash per rfc1321
|
||||
uhash[1] = 0xEFCDAB89;
|
||||
uhash[2] = 0x98BADCFE;
|
||||
uhash[3] = 0x10325476;
|
||||
|
||||
pmd5->totbyt = 0; // init count of data bytes processed
|
||||
}
|
||||
|
||||
// Last call -- after this, pmd5->hash holds final MD5 hash.
|
||||
void Phmd5End(PHMD5 *pmd5) {
|
||||
char pad[72]; // pad buffer (worst case is 72 bytes)
|
||||
unsigned padc; // size of needed pad (9-72 bytes)
|
||||
|
||||
padc = 64 - ((unsigned) pmd5->totbyt & 63); // pad to 64-byte boundary
|
||||
if (padc < 9) padc += 64; // add a block if we need more room
|
||||
memset(pad, 0, padc); // clear entire pad area
|
||||
pad[0] = (char) 0x80; // place input stream terminator
|
||||
// place 64-bit input data bit count
|
||||
*(unsigned __int64 *) &pad[padc - 8] = pmd5->totbyt << 3;
|
||||
Phmd5Process(pmd5, pad, padc); // process the pad
|
||||
}
|
||||
|
||||
// Work done here -- call for as many input blocks that need to be processed.
|
||||
// pdata points to the input data, bytecnt is pdata size (0..n bytes).
|
||||
// See phmd5.h regarding how to use this optimally.
|
||||
void Phmd5Process(PHMD5 *pmd5, char *pdata, size_t bytecnt) {
|
||||
unsigned resid = (unsigned) pmd5->totbyt;
|
||||
|
||||
pmd5->totbyt += bytecnt; // update total bytes processed
|
||||
|
||||
resid &= 63; // count of bytes now in pmd5->buf
|
||||
|
||||
// This block handles the case of residual data in pmd5->buf.
|
||||
// After this block pmd5->buf is empty (except perhaps on exit).
|
||||
|
||||
if (resid) { // if residual exists,
|
||||
unsigned cb = 64 - resid;
|
||||
if (cb > bytecnt) cb = (unsigned) bytecnt;
|
||||
memcpy(pmd5->buf + resid, pdata, cb);
|
||||
pdata += cb;
|
||||
bytecnt -= cb;
|
||||
if (resid + cb < 64) return;
|
||||
Phmd5DoBlocks(pmd5->hash, pmd5->buf, 64);
|
||||
}
|
||||
|
||||
// This block processes input data in-place, if the data is dword
|
||||
// aligned and in 64-byte chunks.
|
||||
|
||||
if ((unsigned) bytecnt & ~63 && ((size_t) pdata & 3) == 0) {
|
||||
Phmd5DoBlocks(pmd5->hash, pdata, bytecnt & ~63);
|
||||
pdata += bytecnt & ~63;
|
||||
bytecnt &= 63;
|
||||
}
|
||||
|
||||
while (bytecnt) { // handle residual/non-aligned data
|
||||
unsigned cb = 64 > (unsigned) bytecnt ? (unsigned) bytecnt : 64;
|
||||
memcpy(pmd5->buf, pdata, cb);
|
||||
pdata += cb;
|
||||
bytecnt -= cb;
|
||||
if (cb < 64) return;
|
||||
Phmd5DoBlocks(pmd5->hash, pmd5->buf, 64);
|
||||
};
|
||||
}
|
||||
59
source/sfv_md5/phmd5.h
Normal file
59
source/sfv_md5/phmd5.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
;
|
||||
; MD5 hash generator -- Paul Houle (paulhoule.com) 11/13/2017
|
||||
;
|
||||
; This code is in the public domain. Please attribute the author.
|
||||
;
|
||||
; There are a lot of MD5 generators; here's another. This one targets a
|
||||
; little-endian memory architecture only (eg X86). The benefit of this
|
||||
; is speed -- bytes within larger elements never need to be reversed,
|
||||
; which means the source data can be processed in-place.
|
||||
;
|
||||
; Though other compilers might be usable, this was developed using
|
||||
; Microsoft 32/64-bit C 12.0 [Version 18.00.30723]. Vendor specific
|
||||
; definitions (eg. _rotl, __int32, __int64) are used.
|
||||
; Build commands:
|
||||
;
|
||||
; cl /c /Ox phmd5.c
|
||||
; cl /c /Ox phmd5a.c
|
||||
;
|
||||
; Link the resulting .obj's into your executable and #include "phmd5.h"
|
||||
;
|
||||
; How to call the routines to generate a hash:
|
||||
;
|
||||
; (1) Allocate a PHMD5 type struct -- it's small, can be static or local.
|
||||
; A pointer to this struct is the first argument to all functions.
|
||||
;
|
||||
; (2) Call Phmd5Begin() once -- this initializes the PHMD5 struct.
|
||||
;
|
||||
; (3) Call Phmd5Process() as many times as necessary for all data
|
||||
; to be included in the MD5 hash.
|
||||
;
|
||||
; (4) Call Phmd5End() once. The final 16-byte MD5 hash will then be
|
||||
; available in PHMD5->hash. Note the finished hash is a simple array
|
||||
; of bytes, and must be treated/displayed/copied/etc that way.
|
||||
;
|
||||
; For best performance the Phmd5Process() "pdata" pointer should be 32-bit
|
||||
; aligned (a multiple of 4) and "bytecnt" should be a multiple of 64.
|
||||
; As long as both of these conditions continue to be met the input data is
|
||||
; processed in-place; otherwise, some speed (10-15%) is lost as the data
|
||||
; is copied to an internal blocking buffer before being proceessed.
|
||||
;
|
||||
;---------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef _PHMD5_DEFINED // include guard
|
||||
#define _PHMD5_DEFINED
|
||||
|
||||
#include <stddef.h>
|
||||
typedef struct {
|
||||
unsigned char hash[16]; // final 16-byte hash winds up here
|
||||
unsigned __int64 totbyt; // processed byte count
|
||||
char buf[64]; // input blocking buffer
|
||||
} PHMD5;
|
||||
|
||||
void Phmd5Begin(PHMD5 *pmd5);
|
||||
void Phmd5Process(PHMD5 *pmd5, char *pdata, size_t bytecnt);
|
||||
void Phmd5End(PHMD5 *pmd5);
|
||||
void Phmd5DoBlocks(unsigned char *hash, char *pdata, size_t bytecnt);
|
||||
|
||||
#endif
|
||||
130
source/sfv_md5/phmd5a.c
Normal file
130
source/sfv_md5/phmd5a.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/*----------------------------------------------------------------------------
|
||||
;
|
||||
; MD5 hash generator -- Paul Houle (paulhoule.com) 11/13/2017
|
||||
;
|
||||
; Called only from phmd5.c -- see phmd5.h for overview
|
||||
;
|
||||
; This is the same logic in phmd5a.asm, implemented (after the fact) in C.
|
||||
; The C compiler must support the "_rotl()" function generated inline to
|
||||
; achieve maximal performance.
|
||||
;
|
||||
; It turns out the MSFT C compiler, coupled with newer processor, results
|
||||
; in timings comparable to the 32-bit only phmd5a.asm hand-written assembly.
|
||||
; Therefore this "C" implementation is now used.
|
||||
; Avoiding assembly allows the code to be compiled either 32 or 64 bit.
|
||||
;
|
||||
; Note that a "little-endian" memory architecture is assumed.
|
||||
;
|
||||
; The Fx() and MD5STEP() macros were written by Colin Plumb in 1993.
|
||||
; MD5STEP() was changed slightly to match how phmd5a.asm operates.
|
||||
;
|
||||
;---------------------------------------------------------------------------*/
|
||||
|
||||
#include <stdlib.h> // for _rotl()
|
||||
#include "phmd5.h"
|
||||
|
||||
// MD5 Optimisation Tricks by Anime Tosho
|
||||
// https://github.com/animetosho/md5-optimisation#optimisation-tricks-single-buffer
|
||||
// Dependency shortcut in G function
|
||||
#define F1(x, y, z) ((x & y) + (~x & z))
|
||||
|
||||
//#define F1(x, y, z) (z ^ (x & (y ^ z)))
|
||||
#define F2(x, y, z) F1(z, x, y)
|
||||
#define F3(x, y, z) (x ^ y ^ z)
|
||||
#define F4(x, y, z) (y ^ (x | ~z))
|
||||
|
||||
#define MD5STEP(f, w, x, y, z, ix, s, sc) \
|
||||
w = _rotl(w + f(x, y, z) + ((unsigned *) pdata)[ix] + sc, s) + x
|
||||
|
||||
void Phmd5DoBlocks(
|
||||
unsigned char *hash,
|
||||
char *pdata,
|
||||
size_t bytecnt
|
||||
) {
|
||||
unsigned __int32 a = *(unsigned __int32 *) &hash[ 0];
|
||||
unsigned __int32 b = *(unsigned __int32 *) &hash[ 4];
|
||||
unsigned __int32 c = *(unsigned __int32 *) &hash[ 8];
|
||||
unsigned __int32 d = *(unsigned __int32 *) &hash[12];
|
||||
|
||||
do {
|
||||
MD5STEP(F1, a, b, c, d, 0, 7, 0xd76aa478);
|
||||
MD5STEP(F1, d, a, b, c, 1, 12, 0xe8c7b756);
|
||||
MD5STEP(F1, c, d, a, b, 2, 17, 0x242070db);
|
||||
MD5STEP(F1, b, c, d, a, 3, 22, 0xc1bdceee);
|
||||
MD5STEP(F1, a, b, c, d, 4, 7, 0xf57c0faf);
|
||||
MD5STEP(F1, d, a, b, c, 5, 12, 0x4787c62a);
|
||||
MD5STEP(F1, c, d, a, b, 6, 17, 0xa8304613);
|
||||
MD5STEP(F1, b, c, d, a, 7, 22, 0xfd469501);
|
||||
MD5STEP(F1, a, b, c, d, 8, 7, 0x698098d8);
|
||||
MD5STEP(F1, d, a, b, c, 9, 12, 0x8b44f7af);
|
||||
MD5STEP(F1, c, d, a, b, 10, 17, 0xffff5bb1);
|
||||
MD5STEP(F1, b, c, d, a, 11, 22, 0x895cd7be);
|
||||
MD5STEP(F1, a, b, c, d, 12, 7, 0x6b901122);
|
||||
MD5STEP(F1, d, a, b, c, 13, 12, 0xfd987193);
|
||||
MD5STEP(F1, c, d, a, b, 14, 17, 0xa679438e);
|
||||
MD5STEP(F1, b, c, d, a, 15, 22, 0x49b40821);
|
||||
|
||||
MD5STEP(F2, a, b, c, d, 1, 5, 0xf61e2562);
|
||||
MD5STEP(F2, d, a, b, c, 6, 9, 0xc040b340);
|
||||
MD5STEP(F2, c, d, a, b, 11, 14, 0x265e5a51);
|
||||
MD5STEP(F2, b, c, d, a, 0, 20, 0xe9b6c7aa);
|
||||
MD5STEP(F2, a, b, c, d, 5, 5, 0xd62f105d);
|
||||
MD5STEP(F2, d, a, b, c, 10, 9, 0x02441453);
|
||||
MD5STEP(F2, c, d, a, b, 15, 14, 0xd8a1e681);
|
||||
MD5STEP(F2, b, c, d, a, 4, 20, 0xe7d3fbc8);
|
||||
MD5STEP(F2, a, b, c, d, 9, 5, 0x21e1cde6);
|
||||
MD5STEP(F2, d, a, b, c, 14, 9, 0xc33707d6);
|
||||
MD5STEP(F2, c, d, a, b, 3, 14, 0xf4d50d87);
|
||||
MD5STEP(F2, b, c, d, a, 8, 20, 0x455a14ed);
|
||||
MD5STEP(F2, a, b, c, d, 13, 5, 0xa9e3e905);
|
||||
MD5STEP(F2, d, a, b, c, 2, 9, 0xfcefa3f8);
|
||||
MD5STEP(F2, c, d, a, b, 7, 14, 0x676f02d9);
|
||||
MD5STEP(F2, b, c, d, a, 12, 20, 0x8d2a4c8a);
|
||||
|
||||
MD5STEP(F3, a, b, c, d, 5, 4, 0xfffa3942);
|
||||
MD5STEP(F3, d, a, b, c, 8, 11, 0x8771f681);
|
||||
MD5STEP(F3, c, d, a, b, 11, 16, 0x6d9d6122);
|
||||
MD5STEP(F3, b, c, d, a, 14, 23, 0xfde5380c);
|
||||
MD5STEP(F3, a, b, c, d, 1, 4, 0xa4beea44);
|
||||
MD5STEP(F3, d, a, b, c, 4, 11, 0x4bdecfa9);
|
||||
MD5STEP(F3, c, d, a, b, 7, 16, 0xf6bb4b60);
|
||||
MD5STEP(F3, b, c, d, a, 10, 23, 0xbebfbc70);
|
||||
MD5STEP(F3, a, b, c, d, 13, 4, 0x289b7ec6);
|
||||
MD5STEP(F3, d, a, b, c, 0, 11, 0xeaa127fa);
|
||||
MD5STEP(F3, c, d, a, b, 3, 16, 0xd4ef3085);
|
||||
MD5STEP(F3, b, c, d, a, 6, 23, 0x04881d05);
|
||||
MD5STEP(F3, a, b, c, d, 9, 4, 0xd9d4d039);
|
||||
MD5STEP(F3, d, a, b, c, 12, 11, 0xe6db99e5);
|
||||
MD5STEP(F3, c, d, a, b, 15, 16, 0x1fa27cf8);
|
||||
MD5STEP(F3, b, c, d, a, 2, 23, 0xc4ac5665);
|
||||
|
||||
MD5STEP(F4, a, b, c, d, 0, 6, 0xf4292244);
|
||||
MD5STEP(F4, d, a, b, c, 7, 10, 0x432aff97);
|
||||
MD5STEP(F4, c, d, a, b, 14, 15, 0xab9423a7);
|
||||
MD5STEP(F4, b, c, d, a, 5, 21, 0xfc93a039);
|
||||
MD5STEP(F4, a, b, c, d, 12, 6, 0x655b59c3);
|
||||
MD5STEP(F4, d, a, b, c, 3, 10, 0x8f0ccc92);
|
||||
MD5STEP(F4, c, d, a, b, 10, 15, 0xffeff47d);
|
||||
MD5STEP(F4, b, c, d, a, 1, 21, 0x85845dd1);
|
||||
MD5STEP(F4, a, b, c, d, 8, 6, 0x6fa87e4f);
|
||||
MD5STEP(F4, d, a, b, c, 15, 10, 0xfe2ce6e0);
|
||||
MD5STEP(F4, c, d, a, b, 6, 15, 0xa3014314);
|
||||
MD5STEP(F4, b, c, d, a, 13, 21, 0x4e0811a1);
|
||||
MD5STEP(F4, a, b, c, d, 4, 6, 0xf7537e82);
|
||||
MD5STEP(F4, d, a, b, c, 11, 10, 0xbd3af235);
|
||||
MD5STEP(F4, c, d, a, b, 2, 15, 0x2ad7d2bb);
|
||||
MD5STEP(F4, b, c, d, a, 9, 21, 0xeb86d391);
|
||||
|
||||
a += *(unsigned __int32 *) &hash[ 0];
|
||||
b += *(unsigned __int32 *) &hash[ 4];
|
||||
c += *(unsigned __int32 *) &hash[ 8];
|
||||
d += *(unsigned __int32 *) &hash[12];
|
||||
|
||||
*(unsigned __int32 *) &hash[ 0] = a;
|
||||
*(unsigned __int32 *) &hash[ 4] = b;
|
||||
*(unsigned __int32 *) &hash[ 8] = c;
|
||||
*(unsigned __int32 *) &hash[12] = d;
|
||||
|
||||
pdata += 64;
|
||||
} while (bytecnt -= 64);
|
||||
}
|
||||
BIN
source/sfv_md5/res_sfv_md5.rc
Normal file
BIN
source/sfv_md5/res_sfv_md5.rc
Normal file
Binary file not shown.
88
source/sfv_md5/sfv_md5.vcxproj
Normal file
88
source/sfv_md5/sfv_md5.vcxproj
Normal file
@@ -0,0 +1,88 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{3B3B9386-A7FD-4ABB-AA3A-91F4AC1548FB}</ProjectGuid>
|
||||
<RootNamespace>sfv_md5</RootNamespace>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<PlatformToolset>v143</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup>
|
||||
<_ProjectFileVersion>16.0.31025.104</_ProjectFileVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<OutDir>$(SolutionDir)$(Configuration)\</OutDir>
|
||||
<IntDir>$(Configuration)\</IntDir>
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<GenerateManifest>false</GenerateManifest>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<DisableLanguageExtensions>false</DisableLanguageExtensions>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<PrecompiledHeader />
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat />
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>imagehlp.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<SetChecksum>true</SetChecksum>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="common.c" />
|
||||
<ClCompile Include="crc.c" />
|
||||
<ClCompile Include="create.c" />
|
||||
<ClCompile Include="ini.c" />
|
||||
<ClCompile Include="main.c" />
|
||||
<ClCompile Include="phmd5.c" />
|
||||
<ClCompile Include="phmd5a.c" />
|
||||
<ClCompile Include="verify.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="common.h" />
|
||||
<ClInclude Include="crc.h" />
|
||||
<ClInclude Include="create.h" />
|
||||
<ClInclude Include="ini.h" />
|
||||
<ClInclude Include="phmd5.h" />
|
||||
<ClInclude Include="verify.h" />
|
||||
<ClInclude Include="version.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="res_sfv_md5.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
969
source/sfv_md5/verify.c
Normal file
969
source/sfv_md5/verify.c
Normal file
@@ -0,0 +1,969 @@
|
||||
// verify.c
|
||||
// Copyright : 2022-02-25 Yutaka Sawada
|
||||
// License : The MIT license
|
||||
|
||||
#ifndef _UNICODE
|
||||
#define _UNICODE
|
||||
#endif
|
||||
#ifndef UNICODE
|
||||
#define UNICODE
|
||||
#endif
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0600 // Windows Vista 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;
|
||||
}
|
||||
|
||||
11
source/sfv_md5/verify.h
Normal file
11
source/sfv_md5/verify.h
Normal file
@@ -0,0 +1,11 @@
|
||||
|
||||
// SFV ファイル
|
||||
int verify_sfv(
|
||||
char *ascii_buf,
|
||||
wchar_t *file_path);
|
||||
|
||||
// MD5 ファイル
|
||||
int verify_md5(
|
||||
char *ascii_buf,
|
||||
wchar_t *file_path);
|
||||
|
||||
2
source/sfv_md5/version.h
Normal file
2
source/sfv_md5/version.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#define FILE_VERSION "1.3.2.8" // ファイルのバージョン番号
|
||||
#define PRODUCT_VERSION "1.3.2" // 製品のバージョン番号
|
||||
Reference in New Issue
Block a user