Add files via upload

This commit is contained in:
Yutaka Sawada
2023-03-12 10:41:47 +09:00
committed by GitHub
parent 0f1519770b
commit e218f5f634
16 changed files with 6303 additions and 0 deletions

1048
source/par1j/common1.c Normal file

File diff suppressed because it is too large Load Diff

134
source/par1j/common1.h Normal file
View File

@@ -0,0 +1,134 @@
#ifndef _COMMON_H_
#define _COMMON_H_
#ifdef __cplusplus
extern "C" {
#endif
#define MAX_LEN 1024 // ファイル名の最大文字数 (末尾のNULL文字も含む)
#define ADD_LEN 8 // 作業中にファイル名に追加する文字数
#define EXT_LEN 16 // 拡張子として認識する最大文字数
#define COMMENT_LEN 128 // コメントの最大文字数
#define ALLOC_LEN 4096 // 可変長領域を何バイトごとに確保するか
#define IO_SIZE 65536
#define UPDATE_TIME 1024 // 更新間隔 ms
// グローバル変数
extern wchar_t recovery_file[MAX_LEN]; // リカバリ・ファイルのパス
extern wchar_t base_dir[MAX_LEN]; // ソース・ファイルの基準ディレクトリ
extern wchar_t ini_path[MAX_LEN]; // 検査結果ファイルのパス
extern unsigned int cp_output;
// Windown OS の precomposed UTF-16 から Console Output Code Page に変換する
int utf16_to_cp(wchar_t *in, char *out);
// UTF-16 のファイル・パスを画面出力用の Code Page を使って表示する
void printf_cp(unsigned char *format, wchar_t *path);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// ファイル・パスがファイル・リスト上に既に存在するか調べる
int search_file_path(
wchar_t *list, // ファイル・リスト
int total_len, // ファイル・リストの文字数
wchar_t *search_file); // 検索するファイルのパス
// ファイル・リストの内容を並び替える
void sort_list(
wchar_t *list, // ファイル・リスト
int total_len); // ファイル・リストの文字数
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// ファイル・パスからファイル名の位置を戻す
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); // ディレクトリ
// 絶対パスかどうかを判定する
int is_full_path(wchar_t *path);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// 相対パスを絶対パスに変換し、パスの先頭に "\\?\" を追加する
// 戻り値 : 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);
// ファイル・パスから、先頭にある "\\?\" を省いてコピーする
int copy_without_prefix(
wchar_t *dst_path, // コピー先
wchar_t *src_path); // コピー元のパス
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// ファイルを置き換える (ファイル名の修正、テンポラリー・ファイルからの書き戻しなど)
int replace_file(
wchar_t *dest_path, // ()
wchar_t *sorc_path, // 置き換える元のパス (移動元、現在のファイル名)
int switch_b); // 既存のファイルをバックアップするかどうか
// ファイルを指定サイズに縮小する
int shorten_file(
wchar_t *file_path, // ファイル・パス
__int64 new_size,
int switch_b); // 既存のファイルをバックアップするかどうか
// ファイル名が有効か確かめて、問題があれば浄化する
int sanitize_filename(wchar_t *name);
// 修復中のテンポラリ・ファイルの名前を作る
void get_temp_name(
wchar_t *file_path, // ファイル・パス
wchar_t *temp_path); // テンポラリ・ファイルのパス
void print_hash(unsigned char hash[16]);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern unsigned int memory_use; // メモリー使用量 0=auto, 17 -> 1/8 7/8
// 空きメモリー量と制限値から使用できるメモリー量を計算する
unsigned int get_mem_size(unsigned __int64 data_size);
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);
// キャンセルと一時停止を行う
int cancel_progress(void);
// Win32 API のエラー・メッセージを表示する
void print_win32_err(void);
// ファイルをゴミ箱に移す
int delete_file_recycle(wchar_t *file_path);
#ifdef __cplusplus
}
#endif
#endif

205
source/par1j/gf8.c Normal file
View File

@@ -0,0 +1,205 @@
// This is a sub-set of Galois.c
// Modified by Yutaka Sawada for 8-bit only
/* Galois.c
* James S. Plank
* April, 2007
Galois.tar - Fast Galois Field Arithmetic Library in C/C++
Copright (C) 2007 James S. Plank
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License aint with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
James S. Plank
Department of Computer Science
University of Tennessee
Knoxville, TN 37996
plank@cs.utk.edu
*/
#include <stdlib.h>
#include "gf8.h"
#define NW 256
#define NWM1 255
#define PRIM_POLY 0x11D
static int *galois_log_table = NULL;
static int *galois_exp_table;
static int *galois_mult_table = NULL;
static int *galois_div_table;
int galois_create_log_tables(void)
{
int j, b;
if (galois_log_table != NULL) return 0;
galois_log_table = _aligned_malloc(sizeof(int) * NW * 4, 64);
if (galois_log_table == NULL) return -1;
galois_exp_table = galois_log_table + NW + 1; // 後で境界をあわせるため
b = 1;
for (j = 0; j < NWM1; j++){
galois_log_table[b] = j;
galois_exp_table[j] = b;
b = b << 1;
if (b & NW) b ^= PRIM_POLY;
}
galois_log_table[0] = -1;
for (j = 0; j < NWM1; j++){
galois_exp_table[j + NWM1 ] = galois_exp_table[j];
galois_exp_table[j + NWM1 * 2] = galois_exp_table[j];
}
galois_exp_table += NWM1;
return 0;
}
int galois_create_mult_tables(void)
{
int j, x, y, logx;
if (galois_mult_table != NULL) return 0;
galois_mult_table = _aligned_malloc(sizeof(int) * NW * NW * 2, 64);
if (galois_mult_table == NULL) return -1;
galois_div_table = galois_mult_table + NW * NW;
if (galois_log_table == NULL) {
if (galois_create_log_tables() < 0) {
_aligned_free(galois_mult_table);
galois_mult_table = NULL;
return -1;
}
}
/* Set mult/div tables for x = 0 */
j = 0;
galois_mult_table[j] = 0; /* y = 0 */
galois_div_table[j] = -1;
j++;
for (y = 1; y < NW; y++) { /* y > 0 */
galois_mult_table[j] = 0;
galois_div_table[j] = 0;
j++;
}
for (x = 1; x < NW; x++){ /* x > 0 */
galois_mult_table[j] = 0; /* y = 0 */
galois_div_table[j] = -1;
j++;
logx = galois_log_table[x];
for (y = 1; y < NW; y++){ /* y > 0 */
galois_mult_table[j] = galois_exp_table[logx + galois_log_table[y]];
galois_div_table[j] = galois_exp_table[logx - galois_log_table[y]];
j++;
}
}
return 0;
}
int galois_multtable_multiply(int x, int y)
{
return galois_mult_table[(x << 8) | y];
}
int galois_multtable_divide(int x, int y)
{
return galois_div_table[(x << 8) | y];
}
// ガロア体上での乗数計算、x の y 乗
int galois_power(int x, int y)
{
int sum_j;
if (y == 0) return 1; // x^0 = 1
sum_j = x;
while (y > 1){
sum_j = galois_multtable_multiply(sum_j, x);
y--;
}
return sum_j;
}
void galois_free_tables(void) // テーブルを一括して解放するために追加
{
if (galois_mult_table != NULL) {
_aligned_free(galois_mult_table);
galois_mult_table = NULL;
}
if (galois_log_table != NULL) {
_aligned_free(galois_log_table);
galois_log_table = NULL;
}
}
void galois_region_xor(
unsigned char *r1, // Region 1
unsigned char *r2, // Sum region (r2 = r1 ^ r2)
int nbytes) // Number of bytes in region
{
int i;
for (i = 0; i < nbytes; i++)
r2[i] ^= r1[i];
}
void galois_region_multiply(
unsigned char *r1, // Region to multiply
unsigned char *r2, // products go here.
int nbytes, // Number of bytes in region
int multby) // Number to multiply by
{
int i, *table;
table = galois_mult_table + (multby << 8);
for (i = 0; i < nbytes; i++)
r2[i] ^= table[ r1[i] ];
}
// チェックサムを計算する
void checksum4(unsigned char *data, unsigned char *hash, int byte_size)
{
int i, count;
unsigned int *data4, temp, prev, mask;
data4 = (unsigned int *)data;
count = byte_size / 4;
prev = 0;
while (count > 0){ // HASH_RANGE バイトごとに
// 4バイトに XOR する
temp = 0;
for (i = 0; i < HASH_RANGE / 4; i++){
temp ^= data4[i];
count--;
if (count == 0)
break;
}
data4 += HASH_RANGE / 4;
// 前回の値を 2倍して、今回の値を追加する
mask = (prev & 0x80808080) >> 7; // 0x01010101 or 0x00000000
prev = (prev & 0x7F7F7F7F) << 1; // 3倍する場合は「^=」にすればいい
prev ^= mask * 0x1D; // 0x1D1D1D1D or 0x00000000
prev ^= temp;
}
*((unsigned int *)hash) = prev;
}

67
source/par1j/gf8.h Normal file
View File

@@ -0,0 +1,67 @@
// This is a sub-set of Galois.h , and changed for 8-bit only
/* Galois.h
* James S. Plank
Galois.tar - Fast Galois Field Arithmetic Library in C/C++
Copright (C) 2007 James S. Plank
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
James S. Plank
Department of Computer Science
University of Tennessee
Knoxville, TN 37996
plank@cs.utk.edu
*/
#ifndef _GF8_H_
#define _GF8_H_
#ifdef __cplusplus
extern "C" {
#endif
extern int galois_create_log_tables(void); /* Returns 0 on success, -1 on failure */
extern int galois_create_mult_tables(void);
extern int galois_multtable_multiply(int x, int y);
extern int galois_multtable_divide(int x, int y);
extern int galois_power(int x, int y); // 乗数計算用に追加
extern void galois_free_tables(void); // 解放用に追加
void galois_region_xor(
unsigned char *r1, // Region 1
unsigned char *r2, // Sum region (r2 = r1 ^ r2)
int nbytes); // Number of bytes in region
void galois_region_multiply(
unsigned char *r1, // Region to multiply
unsigned char *r2, // products go here.
int nbytes, // Number of bytes in region
int multby); // Number to multiply by
#define HASH_SIZE 4
#define HASH_RANGE 128
void checksum4(unsigned char *data, unsigned char *hash, int byte_size);
#ifdef __cplusplus
}
#endif
#endif

446
source/par1j/ini.c Normal file
View File

@@ -0,0 +1,446 @@
// ini.c
// Copyright : 2022-01-15 Yutaka Sawada
// License : GPL
#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 "common1.h"
#include "ini.h"
/*
ファイル名は 1_#.bin (2+32+4 = 38文字)
「#」部分は Set ID を 16進数表記にする。
ファイル・フォーマット
<!-- 検査結果ファイル識別用 -->
2: 検査結果の書式バージョン
4: 6バイト目以降からの CRC-32 チェックサム
<!-- リカバリ・セットの識別用 -->
4: ソース・ブロック数 (PAR1ではブロックを持つファイルだけが Set ID に反映される)
<!-- 検査状態をファイルごとに記録する -->
前半 13バイトでファイル項目を識別して、後半 17バイトに状態を保存する。
1: 0255=ソース・ファイル番号 (リカバリ・ファイルは常に 255)
4: ボリュームのシリアル番号
8: ファイルのオブジェクトID
8: ソース・ファイルのサイズ
4: ソース・ファイルの作成日時
4: ソース・ファイルの更新日時
1: ファイルの状態 0=完全, 1=破損あるいはエラー, 4=追加, +16=リカバリ・ファイル
*/
#define INI_VERSION 0x1270 // 検査結果の書式が決まった時のバージョン
#define REUSE_MIN 16384 // ファイル・サイズがこれより大きければ検査結果を利用する (16KB 以上 2GB 未満)
#define HEADER_SIZE 10
#define STATE_SIZE 30
#define STATE_READ 136
//#define VERBOSE 1 // 状態を冗長に出力する
static HANDLE hIniBin = NULL; // バイナリ・データ用の検査結果ファイル
static int ini_off;
// 検査結果をどのくらいの期間保存するか
int recent_data = 0;
/*
0 = 検査結果の再利用機能を無効にする(読み込まないし、記録もしない)
17= 前回の検査結果を読み込んで、今回のを記録する。
指定された期間よりも経過した古い記録は削除される。
1= 1日, 2= 3日, 3= 1週間, 4= 半月, 5= 1ヶ月, 6= 1年, 7= 無制限
+8 = 同じセットの記録を削除する、今回の結果は記録する。
他のセットは指定された期間よりも古いものだけ削除する。
*/
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// File Time (UTC) を UNIX Time (UTC) に変換する
static 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], *p;
unsigned int rv, crc = 0xFFFFFFFF;
unsigned int len, tmp, i;
// 末尾まで読み込む
do {
if (!ReadFile(hFile, buf, 4096, &rv, NULL) || (rv == 0))
break;
// CRC-32 計算
p = buf;
len = rv;
while (len--){
tmp = (*p++);
for (i = 0; i < 8; i++){
if ((tmp ^ crc) & 1){
crc = (crc >> 1) ^ 0xEDB88320;
} else {
crc = crc >> 1;
}
tmp = tmp >> 1;
}
}
} while (rv > 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;
}
// .BIN ファイルの offset バイト目に size バイトのデータを buf から書き込む
static int file_write_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 (!WriteFile(hIniBin, buf, size, &rv, NULL))
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, int block_num)
{
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;
// 設定ファイルのパス
swprintf(ini_name, _countof(ini_name), L"1_%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"1_*.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, &block_num, 4);
if (match != 0){ // ID が同じでも Set 内容が異なる場合は初期化する
i = file_read_bin(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_bin(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_bin(2, (unsigned char *)&old_crc, 4);
new_crc = file_crc_part(hIniBin);
if (new_crc != old_crc) // 検査結果が同じなら更新しない
file_write_bin(2, (unsigned char *)&new_crc, 4);
CloseHandle(hIniBin);
hIniBin = NULL;
}
}
// 検査結果が記録されてるかどうか
// -1=エラー, -2=記録なし、またはファイル項目はあるが状態が変化してる
// ファイルの状態 0=完全, 1=破損, 2=追加
int check_ini_state(
int num, // ファイル番号
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
HANDLE hFile) // そのファイルのハンドル
{
unsigned char buf[STATE_SIZE * STATE_READ], buf2[STATE_SIZE];
unsigned int rv, off;
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 {
return -1; // 属性の読み取りエラー
}
// 参照するファイル項目
buf2[0] = (unsigned char)(num & 0xFF);
memcpy(buf2 + 1, meta + 4, 12);
memcpy(buf2 + 13, meta, 16);
buf2[29] = (unsigned char)(num >> 8);
// ヘッダーの直後から開始する
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, buf2, 13) == 0) && ((buf[off + 29] & 0x10) == buf2[29])){
ini_off += off; // 同じファイルの記録があった
#ifdef VERBOSE
printf("check state, num = %d, offset = %d, state = 0x%02X\n", num & 0xFF, ini_off, buf[off + 29]);
#endif
// ファイルのサイズと日時を比較する
if (memcmp(buf + (off + 13), buf2 + 13, 16) == 0)
return buf[off + 29] & 0x0F;
return -2; // 状態が変化してる
}
}
ini_off += rv;
}
ini_off = 0;
return -2; // これ以上の検査記録は無い
}
// ソース・ファイル状態は完全か破損だけ (消失だと検査しない)
void write_ini_state(
int num, // ファイル番号
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
int state) // 状態、0=完全, 1=破損, 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;
}
}
// 今回の状態を書き込む
buf[0] = (unsigned char)(num & 0xFF);
memcpy(buf + 1, meta + 4, 12);
memcpy(buf + 13, meta, 16);
buf[29] = (unsigned char)((state & 0x0F) | (num >> 8));
#ifdef VERBOSE
printf("write state, num = %d, offset = %d, state = 0x%02X\n", num & 0xFF, ini_off, buf[29]);
#endif
if (file_write_bin(ini_off, buf, STATE_SIZE) != 0){
delete_ini_file();
return;
}
}

32
source/par1j/ini.h Normal file
View File

@@ -0,0 +1,32 @@
#ifndef _INI_H_
#define _INI_H_
#ifdef __cplusplus
extern "C" {
#endif
#define INI_NAME_LEN 38 // 検査結果ファイルのファイル名の文字数
extern int recent_data;
int check_ini_file(unsigned char *set_hash, int file_num);
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

223
source/par1j/md5_1.c Normal file
View File

@@ -0,0 +1,223 @@
// md5_1.c
// Copyright : 2021-05-14 Yutaka Sawada
// License : GPL
#include <windows.h>
#include "common1.h"
#include "phmd5.h"
#include "md5_1.h"
// バイト配列の MD5 ハッシュ値を求める
void data_md5(
unsigned char *data_in, // ハッシュ値を求めるバイト配列
unsigned int data_len, // 入力バイト数
unsigned char *hash) // ハッシュ値 16バイト
{
PHMD5 ctx;
Phmd5Begin(&ctx);
Phmd5Process(&ctx, data_in, data_len);
Phmd5End(&ctx);
memcpy(hash, ctx.hash, 16);
}
// ファイルの MD5 ハッシュ値を求める
int file_md5(
wchar_t *file_name, // 表示するファイル名
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
unsigned __int64 file_size,
unsigned char *hash) // ハッシュ値 (16バイト)
{
unsigned char buf[IO_SIZE];
unsigned int rv, len;
unsigned int time_last;
unsigned __int64 file_left;
PHMD5 hash_ctx;
// ファイルの先頭に戻す
file_left = 0;
if (!SetFilePointerEx(hFileRead, *((PLARGE_INTEGER)&file_left), NULL, FILE_BEGIN))
return 1;
prog_last = -1; // 検証中のファイル名を毎回表示する
time_last = GetTickCount();
file_left = file_size;
Phmd5Begin(&hash_ctx); // 初期化
while (file_left > 0){
if (file_left < IO_SIZE){
len = (unsigned int)file_left;
} else {
len = IO_SIZE;
}
if (!ReadFile(hFileRead, buf, len, &rv, NULL) || (len != rv))
return 1;
file_left -= len;
// MD5 計算
Phmd5Process(&hash_ctx, buf, len);
// 経過表示
if (GetTickCount() - time_last >= UPDATE_TIME){
if (print_progress_file((int)(((file_size - file_left) * 1000) / file_size), file_name))
return 2;
time_last = GetTickCount();
}
}
Phmd5End(&hash_ctx); // 最終処理
memcpy(hash, hash_ctx.hash, 16);
return 0;
}
// ファイルの MD5 ハッシュ値を求めて、全体的な経過を表示する
int file_md5_total(
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
unsigned __int64 file_size,
unsigned char *hash, // ハッシュ値 (16バイト)
unsigned char *hash16, // 先頭 16KB 分のハッシュ値
__int64 total_file_size,
__int64 *prog_now) // 経過表示での現在位置
{
unsigned char buf[IO_SIZE];
unsigned int rv, len;
unsigned int time_last;
unsigned __int64 file_left;
PHMD5 hash_ctx;
// ファイルの先頭に戻す
file_left = 0;
if (!SetFilePointerEx(hFileRead, *((PLARGE_INTEGER)&file_left), NULL, FILE_BEGIN))
return 1;
time_last = GetTickCount() / UPDATE_TIME; // 時刻の変化時に経過を表示する
file_left = file_size;
Phmd5Begin(&hash_ctx); // 初期化
while (file_left > 0){
if (file_left < IO_SIZE){
len = (unsigned int)file_left;
} else {
len = IO_SIZE;
}
if (!ReadFile(hFileRead, buf, len, &rv, NULL) || (len != rv))
return 2;
(*prog_now) += len;
if (file_left == file_size){ // 最初だけ先頭 16KB 分のハッシュ値を計算する
if (len > 16384){
Phmd5Process(&hash_ctx, buf, 16384);
Phmd5End(&hash_ctx); // 最終処理
memcpy(hash16, hash_ctx.hash, 16);
Phmd5Begin(&hash_ctx); // 初期化しなおす
} else { // ファイル・サイズが 16KB 以下なら
Phmd5Process(&hash_ctx, buf, len);
Phmd5End(&hash_ctx); // 最終処理
memcpy(hash, hash_ctx.hash, 16);
return 0;
}
}
file_left -= len;
// MD5 計算
Phmd5Process(&hash_ctx, buf, len);
// 経過表示
if (GetTickCount() / UPDATE_TIME != time_last){
if (print_progress((int)(((*prog_now) * 1000) / total_file_size)))
return -2;
time_last = GetTickCount() / UPDATE_TIME;
}
}
Phmd5End(&hash_ctx); // 最終処理
memcpy(hash, hash_ctx.hash, 16);
return 0;
}
// ファイルの先頭 16KB 分の MD5 ハッシュ値を求める
int file_md5_16k(
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
unsigned __int64 file_size,
unsigned char *hash) // ハッシュ値 (16バイト)
{
unsigned char buf[16384];
unsigned int len;
LARGE_INTEGER qwi; // Quad Word Integer
PHMD5 hash_ctx;
// ファイルの先頭に戻す
qwi.QuadPart = 0;
if (!SetFilePointerEx(hFileRead, qwi, NULL, FILE_BEGIN))
return 1;
Phmd5Begin(&hash_ctx); // 初期化
if (!ReadFile(hFileRead, buf, 16384, &len, NULL))
return 2;
if ((unsigned __int64)len > file_size)
len = (unsigned int)file_size;
// MD5 計算
Phmd5Process(&hash_ctx, buf, len);
Phmd5End(&hash_ctx); // 最終処理
memcpy(hash, hash_ctx.hash, 16);
return 0;
}
// ファイルの先頭 32バイト目からの MD5 ハッシュ値を求める
int file_md5_from32(
wchar_t *file_name, // 表示するファイル名
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
unsigned char *hash) // ハッシュ値 (16バイト)
{
unsigned char buf[IO_SIZE];
unsigned int rv, len;
unsigned int time_last;
unsigned __int64 file_size, file_left;
LARGE_INTEGER qwi; // Quad Word Integer
PHMD5 hash_ctx;
// ファイル・サイズを取得する
if (!GetFileSizeEx(hFileRead, (PLARGE_INTEGER)&file_size))
return 1;
if (file_size <= 32)
return 1;
// ファイルの開始位置を 32バイト目にする
qwi.QuadPart = 32;
if (!SetFilePointerEx(hFileRead, qwi, NULL, FILE_BEGIN))
return 1;
prog_last = -1; // 検証中のファイル名を毎回表示する
time_last = GetTickCount();
file_left = file_size - 32;
Phmd5Begin(&hash_ctx); // 初期化
while (file_left > 0){
if (file_left < IO_SIZE){
len = (unsigned int)file_left;
} else {
len = IO_SIZE;
}
if (!ReadFile(hFileRead, buf, len, &rv, NULL) || (len != rv))
return 1;
file_left -= len;
// MD5 計算
Phmd5Process(&hash_ctx, buf, len);
// 経過表示
if (GetTickCount() - time_last >= UPDATE_TIME){
if (print_progress_file((int)(((file_size - file_left) * 1000) / file_size), file_name))
return 2;
time_last = GetTickCount();
}
}
Phmd5End(&hash_ctx); // 最終処理
memcpy(hash, hash_ctx.hash, 16);
return 0;
}

48
source/par1j/md5_1.h Normal file
View File

@@ -0,0 +1,48 @@
#ifndef _MD5_H
#define _MD5_H
#ifdef __cplusplus
extern "C" {
#endif
// バイト配列の MD5 ハッシュ値を求める
void data_md5(
unsigned char *data_in, // ハッシュ値を求めるバイト配列
unsigned int data_len, // 入力バイト数
unsigned char *hash); // ハッシュ値 16バイト
// ファイルの MD5 ハッシュ値を求める
int file_md5(
wchar_t *file_name, // 表示するファイル名
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
unsigned __int64 file_size,
unsigned char *hash); // ハッシュ値 (16バイト)
// ファイルの MD5 ハッシュ値を求めて、全体的な経過を表示する
int file_md5_total(
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
unsigned __int64 file_size,
unsigned char *hash, // (16)
unsigned char *hash16, // 先頭 16KB 分のハッシュ値
__int64 total_file_size,
__int64 *prog_now); // 経過表示での現在位置
// ファイルの先頭 16KB 分の MD5 ハッシュ値を求める
int file_md5_16k(
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
unsigned __int64 file_size,
unsigned char *hash); // ハッシュ値 (16バイト)
// ファイルの先頭 32バイト目からの MD5 ハッシュ値を求める
int file_md5_from32(
wchar_t *file_name, // 表示するファイル名
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
unsigned char *hash); // ハッシュ値 (16バイト)
#ifdef __cplusplus
}
#endif
#endif // md5.h

3031
source/par1j/par1.c Normal file

File diff suppressed because it is too large Load Diff

46
source/par1j/par1.h Normal file
View File

@@ -0,0 +1,46 @@
#ifndef _PAR1_H_
#define _PAR1_H_
#ifdef __cplusplus
extern "C" {
#endif
// リカバリ・ファイルを作成する
int par1_create(
int switch_p, // インデックス・ファイルを作らない
int block_num, // ソース・ブロックの数
__int64 block_size, // ブロック・サイズ (最大ファイル・サイズ)
int parity_num, // パリティ・ブロックの数
int first_vol, // 最初のリカバリ・ファイル番号
int file_num, // ソース・ファイルの数
wchar_t *list_buf, // ソース・ファイルのリスト
int list_len, // ファイル・リストの文字数
wchar_t *par_comment); // コメント
// ソース・ファイルの破損や欠損を調べる
int par1_verify(
int switch_b, // 既存のファイルを別名にしてどかす
int switch_p, // インデックス・ファイルを作り直す
wchar_t *par_comment); // コメント
// ソース・ファイルの破損や欠損を修復する
int par1_repair(
int switch_b, // 既存のファイルを別名にしてどかす
int switch_p, // インデックス・ファイルを作り直す
wchar_t *par_comment); // コメント
// ソース・ファイルの一覧を表示する
int par1_list(
int switch_h, // ハッシュ値も表示する
wchar_t *par_comment); // コメント
// CRC-32 チェックサムを使って自分自身の破損を検出する
int par1_checksum(wchar_t *uni_buf); // 作業用
#ifdef __cplusplus
}
#endif
#endif

753
source/par1j/par1_cmd.c Normal file
View File

@@ -0,0 +1,753 @@
// par1_cmd.c
// Copyright : 2022-02-16 Yutaka Sawada
// License : GPL
#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 "common1.h"
#include "par1.h"
#include "ini.h"
#include "version.h"
void print_help(void)
{
printf(
"Usage\n"
"c(reate) [f,fu,r,n,p,m,c,d,in,u] <par file> [input files]\n"
"v(erify) [ vs,vd,d,i,u,b,br] <par file>\n"
"r(epair) [m,vs,vd,d,i,u,b,br] <par file>\n"
"l(ist) [u,h] <par file>\n"
"\nOption\n"
" /f : Use file-list instead of files\n"
" /fu : Use file-list which is encoded with UTF-8\n"
" /r<n> : Rate of redundancy (%%)\n"
" /n<n> : Number of parity volumes\n"
" /p<n> : First parity volume number\n"
" /m<n> : Memory usage\n"
" /vs<n>: Skip verification by recent result\n"
" /vd\"*\": Set directory of recent result\n"
" /c\"*\" : Set comment\n"
" /d\"*\" : Set directory of input files\n"
" /i : Recreate index file\n"
" /in : Do not create index file\n"
" /u : Console output is encoded with UTF-8\n"
" /b : Backup existing files at repair\n"
" /br : Send existing files into recycle bin at repair\n"
" /h : List hash value of input files\n"
);
}
// 動作環境の表示
static void print_environment(void)
{
MEMORYSTATUSEX statex;
// 「\\?\」は常に付加されてるので表示する際には無視する
printf_cp("Base Directory\t: \"%s\"\n", base_dir);
printf_cp("Recovery File\t: \"%s\"\n", recovery_file);
printf("Memory usage\t: ");
if (memory_use == 0){
printf("Auto");
} else {
printf("%d/8", memory_use);
}
statex.dwLength = sizeof(statex);
if (GlobalMemoryStatusEx(&statex))
printf(" (%I64d MB available)", statex.ullAvailPhys >> 20);
printf("\n\n");
}
// 格納ファイル・リストを読み込んでバッファーに書き込む
static wchar_t * read_list(
wchar_t *list_path, // リストのパス
int *file_num, // データ・ファイルの数
int *list_len, // ファイル・リストの文字数
int *block_num, // ソース・ブロックの数
__int64 *block_size, // ブロック・サイズ (最大ファイル・サイズ)
int switch_f) // 1=CP_OEMCP, 2=CP_UTF8
{
char buf[MAX_LEN * 3];
wchar_t *list_buf, file_name[MAX_LEN], file_path[MAX_LEN], *tmp_p;
int len, base_len, l_max, l_off = 0;
__int64 file_size;
FILE *fp;
WIN32_FILE_ATTRIBUTE_DATA AttrData;
base_len = wcslen(base_dir);
if (switch_f == 2){
switch_f = CP_UTF8;
} else {
switch_f = CP_OEMCP;
}
l_max = ALLOC_LEN;
list_buf = malloc(l_max);
if (list_buf == NULL){
printf("malloc, %d\n", l_max);
return NULL;
}
// 読み込むファイルを開く
fp = _wfopen(list_path, L"rb");
if (fp == NULL){
utf16_to_cp(list_path, buf);
free(list_buf);
printf("cannot open file-list, %s\n", buf);
return NULL;
}
// 一行ずつ読み込む
while (fgets(buf, MAX_LEN * 3, fp)){
if (ferror(fp))
break;
buf[MAX_LEN * 3 - 1] = 0;
// 末尾に改行があれば削除する
for (len = 0; len < MAX_LEN * 3; len++){
if (buf[len] == 0)
break;
if ((buf[len] == '\n') || (buf[len] == '\r')){
buf[len] = 0;
break;
}
}
if (buf[0] == 0)
continue; // 改行だけなら次の行へ
// 読み込んだ内容をユニコードに変換する
if (!MultiByteToWideChar(switch_f, 0, buf, -1, file_name, MAX_LEN)){
fclose(fp);
free(list_buf);
printf("MultiByteToWideChar, %s\n", buf);
return NULL;
}
// ファイルが基準ディレクトリ以下に存在することを確認する
len = copy_path_prefix(file_path, MAX_LEN - ADD_LEN, file_name, base_dir); // 絶対パスにしてから比較する
if (len == 0){
fclose(fp);
free(list_buf);
printf_cp("filename is invalid, %s\n", file_name);
return NULL;
}
if ((len <= base_len) || (_wcsnicmp(base_dir, file_path, base_len) != 0)){ // 基準ディレクトリ外なら
fclose(fp);
free(list_buf);
printf("out of base-directory, %s\n", buf);
return NULL;
}
wcscpy(file_name, file_path + base_len);
if (wcschr(file_name, '\\') != NULL){ // サブ・ディレクトリは拒否する
fclose(fp);
free(list_buf);
printf_cp("sub-directory is not supported, %s\n", file_name);
return NULL;
}
// ファイルが存在するか確かめる
if (!GetFileAttributesEx(file_path, GetFileExInfoStandard, &AttrData)){
print_win32_err();
fclose(fp);
free(list_buf);
printf("input file is not found, %s\n", buf);
return NULL;
}
if (AttrData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY){
fclose(fp);
free(list_buf);
printf("folder is not supported, %s\n", buf);
return NULL;
}
file_size = ((unsigned __int64)AttrData.nFileSizeHigh << 32) | (unsigned __int64)AttrData.nFileSizeLow;
if (*block_size < file_size)
*block_size = file_size;
// ファイル名が重複しないようにする
if (search_file_path(list_buf, l_off, file_name))
continue;
// バッファー容量が足りなければ再確保する
len = wcslen(file_name);
if ((l_off + len) * 2 >= l_max){
l_max += ALLOC_LEN;
tmp_p = (wchar_t *)realloc(list_buf, l_max);
if (tmp_p == NULL){
free(list_buf);
printf("realloc, %d\n", l_max);
return NULL;
} else {
list_buf = tmp_p;
}
}
// リストにコピーする
wcscpy(list_buf + l_off, file_name);
l_off += (len + 1);
*file_num += 1;
if (file_size > 0)
*block_num += 1; // 空のファイルはブロックの計算に含めない
}
*list_len = l_off;
fclose(fp);
/*
fp = fopen("list_buf.txt", "wb");
len = 0;
while (len < l_off){
fwprintf(fp, L"%s\n", list_buf + len);
len += (wcslen(list_buf + len) + 1);
}
fclose(fp);
*/
return list_buf;
}
// ファイルを検索してファイル・リストに追加する
static wchar_t * search_files(
wchar_t *list_buf, // ファイル・リスト
wchar_t *search_path, // 検索するファイルのフル・パス
int dir_len, // ディレクトリ部分の長さ
int single_file, // -1 = *や?で検索指定、0 = 単独指定
int *file_num, // データ・ファイルの数
int *list_max, // ファイル・リストの確保サイズ
int *list_len, // ファイル・リストの文字数
int *block_num, // ソース・ブロックの数
__int64 *block_size) // ブロック・サイズ (最大ファイル・サイズ)
{
wchar_t *tmp_p;
int len, l_max, l_off;
__int64 file_size;
HANDLE hFind;
WIN32_FIND_DATA FindData;
if (list_buf == NULL){
l_off = 0;
l_max = ALLOC_LEN;
list_buf = 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 (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
continue; // フォルダは無視する
if ((single_file < 0) && (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN))
continue; // 検索中は隠し属性が付いてるファイルを無視する
// フォルダは無視する、ファイル名が重複しないようにする
if (!search_file_path(list_buf, l_off, FindData.cFileName)){
//printf("FindData.cFileName =\n%S\n\n", FindData.cFileName);
len = wcslen(FindData.cFileName);
if (dir_len + len >= MAX_LEN - ADD_LEN){
FindClose(hFind);
free(list_buf);
printf("filename is too long\n");
return NULL;
}
if ((l_off + 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;
}
}
file_size = ((unsigned __int64)FindData.nFileSizeHigh << 32) | (unsigned __int64)FindData.nFileSizeLow;
if (*block_size < file_size)
*block_size = file_size;
// リストにコピーする
wcscpy(list_buf + l_off, FindData.cFileName);
l_off += len + 1;
*file_num += 1;
if (file_size > 0)
*block_num += 1; // 空のファイルはブロックの計算に含めない
}
} while (FindNextFile(hFind, &FindData)); // 次のファイルを検索する
FindClose(hFind);
*list_max = l_max;
*list_len = l_off;
return list_buf;
}
// リカバリ・ファイルとソース・ファイルが同じ名前にならないようにする
static int check_recovery_match(
int file_num,
wchar_t *list_buf,
int list_len,
int switch_p) // インデックス・ファイルを作らない
{
wchar_t *tmp_p;
int i, num, len, list_off = 0, recovery_len, base_len;
// 基準ディレクトリ外にリカバリ・ファイルが存在するなら問題なし
base_len = wcslen(base_dir);
if (_wcsnicmp(recovery_file, base_dir, base_len) != 0)
return 0;
// リカバリ・ファイル (*.PXX) の名前の基
recovery_len = wcslen(recovery_file);
recovery_len -= base_len + 2; // 末尾の 2文字を除くファイル名の長さ
// ファイルごとに比較する
for (num = 0; num < file_num; num++){
tmp_p = list_buf + list_off;
while (list_buf[list_off] != 0)
list_off++;
list_off++;
// ファイル名との前方一致を調べる
if (_wcsnicmp(recovery_file + base_len, tmp_p, recovery_len) == 0){ // リカバリ・ファイルと基準が同じ
len = wcslen(tmp_p);
// 拡張子も同じか調べる
if (len == recovery_len + 2){
// インデックス・ファイルと比較する
if (switch_p == 0){
if (_wcsicmp(tmp_p + recovery_len, L"ar") == 0){
printf_cp("filename is invalid, %s\n", tmp_p);
return 1;
}
}
// リカバリ・ファイル (*.PXX) と比較する
for (i = 1; i <= 99; i++){
if ((tmp_p[recovery_len ] == '0' + (i / 10)) &&
(tmp_p[recovery_len + 1] == '0' + (i % 10))){
printf_cp("filename is invalid, %s\n", tmp_p);
return 1;
}
}
}
}
}
return 0;
}
wmain(int argc, wchar_t *argv[])
{
wchar_t file_path[MAX_LEN], *list_buf;
wchar_t par_comment[COMMENT_LEN], *tmp_p;
int i, j;
int switch_b = 0, switch_p = 0, switch_f = 0, switch_r = 0, switch_h = 0;
int file_num = 0, source_num = 0, list_len = 0, parity_num = 0, first_vol = 1;
__int64 block_size = 0;
printf("Parchive 1.0 client version " FILE_VERSION " by Yutaka Sawada\n\n");
if (argc < 3){
printf("Self-Test: ");
i = par1_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;
}
// 初期化
recovery_file[0] = 0;
par_comment[0] = 0;
base_dir[0] = 0;
ini_path[0] = 0;
cp_output = GetConsoleOutputCP();
memory_use = 0;
// コマンド
switch (argv[1][0]){
case 'c': // create
case 'v': // verify
case 'r': // repair
case 'l': // list
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"b") == 0){
switch_b = 1;
} else if (wcscmp(tmp_p, L"br") == 0){
switch_b = 2;
} else if (wcscmp(tmp_p, L"f") == 0){
switch_f = 1;
} else if (wcscmp(tmp_p, L"fu") == 0){
switch_f = 2;
} else if (wcscmp(tmp_p, L"i") == 0){
switch_p = 1;
} else if (wcscmp(tmp_p, L"in") == 0){
switch_p = 2;
} else if (wcscmp(tmp_p, L"u") == 0){
cp_output = CP_UTF8;
} else if (wcscmp(tmp_p, L"h") == 0){
switch_h = 1;
// オプション (数値)
} else if (wcsncmp(tmp_p, L"n", 1) == 0){
j = 1;
while ((j < 1 + 4) && (tmp_p[j] >= 48) && (tmp_p[j] <= 57)){
parity_num = (parity_num * 10) + (tmp_p[j] - 48);
j++;
}
} else if (wcsncmp(tmp_p, L"r", 1) == 0){
j = 1;
while ((j < 1 + 5) && (tmp_p[j] >= 48) && (tmp_p[j] <= 57)){
switch_r = (switch_r * 10) + (tmp_p[j] - 48);
j++;
}
} else if (wcsncmp(tmp_p, L"p", 1) == 0){
j = 1;
first_vol = 0;
while ((j < 1 + 4) && (tmp_p[j] >= 48) && (tmp_p[j] <= 57)){
first_vol = (first_vol * 10) + (tmp_p[j] - 48);
j++;
}
if (first_vol < 1)
first_vol = 1;
if (first_vol > 99)
first_vol = 99;
} else if (wcsncmp(tmp_p, L"m", 1) == 0){
if ((tmp_p[1] >= 48) && (tmp_p[1] <= 55)) // 07 の範囲
memory_use = tmp_p[1] - 48;
} 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"c", 1) == 0){
tmp_p++;
if (wcslen(tmp_p) >= COMMENT_LEN){
printf("comment is too long\n");
return 1;
}
wcscpy(par_comment, tmp_p);
//printf("comment = %S\n", tmp_p);
} 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 { // 未対応のオプション
printf_cp("invalid option, %s\n", tmp_p - 1);
return 1;
}
continue;
}
// オプション以外ならリカバリ・ファイル
j = copy_path_prefix(recovery_file, MAX_LEN - 4, tmp_p, NULL); // 「.par」が追加されるかも
if (j == 0){
printf("PAR filename is invalid\n");
return 1;
}
if (argv[1][0] == 'c'){ // 作成なら
// 指定されたファイル名が適切か調べる
if (sanitize_filename(offset_file_name(recovery_file)) != 0){
printf("PAR filename is invalid\n");
return 1;
}
// 拡張子が「.par」以外なら標準の拡張子を追加する
j = wcslen(recovery_file); // 浄化でファイル名が短縮されるかもしれない
if (_wcsicmp(recovery_file + (j - 4), L".par"))
wcscpy(recovery_file + j, L".par");
} else { // 検査や修復なら
if (_wcsicmp(recovery_file + (j - 4), L".par")){
// 拡張子が「.par」以外でも「.p??」ならよい
if ((recovery_file[j - 4] != '.') ||
((recovery_file[j - 3] != 'p') && (recovery_file[j - 3] != 'P')) ||
(recovery_file[j - 2] < 48) || (recovery_file[j - 2] > 57) ||
(recovery_file[j - 1] < 48) || (recovery_file[j - 1] > 57) ){
wcscpy(recovery_file + j, L".par");
}
}
j = GetFileAttributes(recovery_file);
if ((j == INVALID_FILE_ATTRIBUTES) || (j & FILE_ATTRIBUTE_DIRECTORY)){
wchar_t search_path[MAX_LEN];
int name_len, dir_len, path_len, find_flag = 0;
HANDLE hFind;
WIN32_FIND_DATA FindData;
path_len = wcslen(recovery_file);
if (wcspbrk(offset_file_name(recovery_file), L"*?") != NULL){
// 「*」や「?」で検索する場合は指定された拡張子を優先する
hFind = FindFirstFile(recovery_file, &FindData);
if (hFind != INVALID_HANDLE_VALUE){
get_base_dir(recovery_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), recovery_file + (path_len - 4)) == 0)){
find_flag = 1;
break; // 見つけたファイル名で問題なし
}
} while (FindNextFile(hFind, &FindData)); // 次のファイルを検索する
FindClose(hFind);
}
}
if (find_flag == 0){ // リカバリ・ファイルの拡張子を「.p??」にして検索する
wcscpy(search_path, recovery_file);
search_path[path_len - 2] = '?';
search_path[path_len - 1] = '?';
hFind = FindFirstFile(search_path, &FindData);
if (hFind != INVALID_HANDLE_VALUE){
get_base_dir(recovery_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) && // ファイル名が長すぎない
(FindData.cFileName[name_len - 4] == '.') &&
((FindData.cFileName[name_len - 3] == 'p') || (FindData.cFileName[name_len - 3] == 'P')) &&
(FindData.cFileName[name_len - 2] >= '0') && (FindData.cFileName[name_len - 2] <= '9') &&
(FindData.cFileName[name_len - 1] >= '0') && (FindData.cFileName[name_len - 1] <= '9')){
find_flag = 1;
break; // 見つけたファイル名で問題なし
}
} while (FindNextFile(hFind, &FindData)); // 次のファイルを検索する
FindClose(hFind);
}
}
if (find_flag == 0){
printf("valid file is not found\n");
return 1;
}
wcscpy(recovery_file + dir_len, FindData.cFileName);
}
}
break;
}
//printf("m = %d, f = %d, p = %d, n = %d\n", switch_b, switch_f, switch_p, parity_num);
if (recovery_file[0] == 0){ // リカバリ・ファイルが指定されてないなら
printf("PAR file is not specified\n");
return 1;
}
// input file の位置が指定されて無くて、
// 最初のソース・ファイル指定に絶対パスが含まれてるなら、それを使う
if (argv[1][0] == 'c'){
if ((base_dir[0] == 0) && (switch_f == 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(recovery_file, base_dir); // リカバリ・ファイルの位置にする
// 環境の表示
print_environment();
switch (argv[1][0]){
case 'c':
// リカバリ・ファイル作成ならソース・ファイルのリストがいる
i++;
if (i >= argc){
printf("input file is not specified\n");
return 1;
}
if (switch_f){ // ファイル・リストの読み込み
list_buf = read_list(argv[i], &file_num, &list_len, &source_num, &block_size, switch_f);
if (list_buf == NULL)
return 1;
} else { // 入力ファイルの指定
int base_len, list_max;
base_len = wcslen(base_dir);
list_max = 0;
list_buf = NULL;
for (; i < argc; i++){
// 絶対パスや、親パスへの移動を含むパスは危険なのでファイル名だけにする
tmp_p = argv[i];
j = copy_path_prefix(file_path, MAX_LEN - ADD_LEN, 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;
}
if (wcschr(file_path + base_len, '\\') != NULL){
free(list_buf);
printf_cp("sub-directory is not supported, %s\n", file_path + base_len);
return 1;
}
//printf("%d = %S\nsearch = %S\n", i, argv[i], file_path);
// 「*」や「?」で検索しない場合、ファイルが見つからなければエラーにする
j = -1;
if (wcspbrk(file_path + base_len, L"*?") == NULL)
j = file_num;
// ファイルを検索する
list_buf = search_files(list_buf, file_path, base_len, j, &file_num, &list_max, &list_len, &source_num, &block_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_recovery_match(file_num, list_buf, list_len, switch_p & 2)){
free(list_buf);
return 1;
}
// ファイル・リストの内容を並び替える (リストの末尾は null 1個にすること)
sort_list(list_buf, list_len);
//printf("file_num = %d, source_num = %d, block_size = %I64d\n", file_num, source_num, block_size);
if ((parity_num == 0) && (switch_r > 0)){
parity_num = (source_num * switch_r) / 100;
if (parity_num == 0)
parity_num = 1;
}
printf("Input File count: %d\n", file_num);
printf("Data File count : %d\n", source_num);
printf("Max file size\t: %I64d\n", block_size);
printf("Parity Volume count\t: %d\n", parity_num);
if (first_vol > 1)
printf("Parity Volume start\t: %d\n", first_vol);
if (source_num != 0){
i = 100 * parity_num / source_num;
} else {
i = 0;
}
printf("Redundancy rate : %d%%\n", i);
if (source_num + parity_num + first_vol - 1 > 256){
free(list_buf);
printf("too many total volumes %d\n", source_num + parity_num + first_vol - 1);
return 1;
}
if (parity_num + first_vol - 1 > 99){
free(list_buf);
printf("too many parity volumes %d\n", parity_num + first_vol - 1);
return 1;
}
i = par1_create(switch_p & 2, source_num, block_size, parity_num, first_vol,
file_num, list_buf, list_len, par_comment);
break;
case 'v':
case 'r':
// 検査結果ファイルの位置が指定されてないなら
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;
}
}
if (argv[1][0] == 'v'){
i = par1_verify(switch_b, switch_p & 1, par_comment);
} else {
i = par1_repair(switch_b, switch_p & 1, par_comment);
}
break;
case 'l':
i = par1_list(switch_h, par_comment);
break;
}
//printf("ExitCode: 0x%02X\n", i);
return i;
}

79
source/par1j/phmd5.c Normal file
View 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/par1j/phmd5.h Normal file
View 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/par1j/phmd5a.c Normal file
View 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/par1j/res_par1j.rc Normal file

Binary file not shown.

2
source/par1j/version.h Normal file
View File

@@ -0,0 +1,2 @@
#define FILE_VERSION "1.3.2.8" // ファイルのバージョン番号
#define PRODUCT_VERSION 0x132 // クライアントのバージョン番号