Add files via upload

This commit is contained in:
Yutaka Sawada
2023-03-12 11:01:22 +09:00
committed by GitHub
parent 86015cf083
commit dcd8047d73
20 changed files with 15669 additions and 0 deletions

176
source/par2j/com.cpp Normal file
View File

@@ -0,0 +1,176 @@
// com.c
// Copyright : 2022-01-30 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 <windows.h>
#include <Shobjidl.h>
extern "C" { // C 言語の関数呼び出しに対応する
/*
Sample code
https://docs.microsoft.com/ja-jp/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifileoperation-copyitem
HRESULT CopyItem(__in PCWSTR pszSrcItem, __in PCWSTR pszDest, PCWSTR pszNewName)
{
//
// Initialize COM as STA.
//
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
IFileOperation *pfo;
//
// Create the IFileOperation interface
//
hr = CoCreateInstance(CLSID_FileOperation,
NULL,
CLSCTX_ALL,
IID_PPV_ARGS(&pfo));
if (SUCCEEDED(hr))
{
//
// Set the operation flags. Turn off all UI from being shown to the
// user during the operation. This includes error, confirmation,
// and progress dialogs.
//
hr = pfo->SetOperationFlags(FOF_NO_UI);
if (SUCCEEDED(hr))
{
//
// Create an IShellItem from the supplied source path.
//
IShellItem *psiFrom = NULL;
hr = SHCreateItemFromParsingName(pszSrcItem,
NULL,
IID_PPV_ARGS(&psiFrom));
if (SUCCEEDED(hr))
{
IShellItem *psiTo = NULL;
if (NULL != pszDest)
{
//
// Create an IShellItem from the supplied
// destination path.
//
hr = SHCreateItemFromParsingName(pszDest,
NULL,
IID_PPV_ARGS(&psiTo));
}
if (SUCCEEDED(hr))
{
//
// Add the operation
//
hr = pfo->CopyItem(psiFrom, psiTo, pszNewName, NULL);
if (NULL != psiTo)
{
psiTo->Release();
}
}
psiFrom->Release();
}
if (SUCCEEDED(hr))
{
//
// Perform the operation to copy the file.
//
hr = pfo->PerformOperations();
}
}
//
// Release the IFileOperation interface.
//
pfo->Release();
}
CoUninitialize();
}
return hr;
}
*/
HRESULT DeleteItem(__in PCWSTR pszSrcItem)
{
//
// Initialize COM as STA.
//
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
IFileOperation *pfo;
//
// Create the IFileOperation interface
//
hr = CoCreateInstance(CLSID_FileOperation,
NULL,
CLSCTX_ALL,
IID_PPV_ARGS(&pfo));
if (SUCCEEDED(hr))
{
//
// Set the operation flags. Turn off all UI from being shown to the
// user during the operation. This includes error, confirmation,
// and progress dialogs.
//
hr = pfo->SetOperationFlags(FOF_ALLOWUNDO | FOF_NO_UI);
if (SUCCEEDED(hr))
{
//
// Create an IShellItem from the supplied source path.
//
IShellItem *psiFrom = NULL;
hr = SHCreateItemFromParsingName(pszSrcItem,
NULL,
IID_PPV_ARGS(&psiFrom));
if (SUCCEEDED(hr))
{
//
// Add the operation
//
hr = pfo->DeleteItem(psiFrom, NULL);
psiFrom->Release();
}
if (SUCCEEDED(hr))
{
//
// Perform the operation to delete the file.
//
hr = pfo->PerformOperations();
}
}
//
// Release the IFileOperation interface.
//
pfo->Release();
}
CoUninitialize();
}
return hr;
}
} // end of extern "C"

2608
source/par2j/common2.c Normal file

File diff suppressed because it is too large Load Diff

401
source/par2j/common2.h Normal file
View File

@@ -0,0 +1,401 @@
#ifndef _COMMON_H_
#define _COMMON_H_
#ifdef __cplusplus
extern "C" {
#endif
#ifndef _WIN64 // 32-bit 版なら
#define MAX_CPU 8 // 32-bit 版は少なくしておく
#define MAX_MEM_SIZE 0x7F000000 // 確保するメモリー領域の最大値 2032MB
#define MAX_MEM_SIZE32 0x50000000 // 32-bit OS で確保するメモリー領域の最大値 1280MB
#else
#define MAX_CPU 16 // 最大 CPU/Core 個数 (スレッド本数)
#endif
#define MAX_LEN 1024 // ファイル名の最大文字数 (末尾のNULL文字も含む)
#define ADD_LEN 8 // 作業中にファイル名に追加する文字数
#define EXT_LEN 16 // 拡張子として認識する最大文字数
#define COMMENT_LEN 128 // コメントの最大文字数
#define ALLOC_LEN 16384 // 可変長文字列を何文字ごとに確保するか
#define IO_SIZE 131072 // 16384 以上にすること
#define STACK_SIZE 131072 // 65536 以上にすること
#define MAX_SOURCE_NUM 32768 // ソース・ブロック数の最大値
#define MAX_PARITY_NUM 65535 // パリティ・ブロック数の最大値
#define MAX_BLOCK_SIZE 0x7FFFFFFC // 対応するブロック・サイズの最大値 2 GB
#define SEARCH_SIZE 1048576 // リカバリ・ファイルの検査単位
#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 int base_len; // ソース・ファイルの基準ディレクトリの長さ
extern int recovery_limit; // 作成時はリカバリ・ファイルのサイズ制限
extern int first_num; // 作成時は最初のパリティ・ブロック番号、検査時は初めて見つけた数
extern int file_num; // ソース・ファイルの数
extern int entity_num; // 実体のあるファイルの数 (recovery set に含まれるファイル数)
extern int recovery_num; // リカバリ・ファイルの数
extern int source_num; // ソース・ブロックの数
extern int parity_num; // パリティ・ブロックの数
extern unsigned int block_size; // ブロック・サイズ
extern unsigned int split_size; // 分割サイズ
extern __int64 total_file_size; // 合計ファイル・サイズ
extern int switch_v; // 検査レベル
extern int switch_b; // バックアップを作るか
// 可変長サイズの領域にファイル名を記録する
extern wchar_t *list_buf; // ソース・ファイルのファイル名のリスト
extern int list_len; // ファイル・リストの文字数
extern int list_max; // ファイル・リストの最大文字数
extern wchar_t *recv_buf; // リカバリ・ファイルのリスト
extern int recv_len; // ファイル・リストの文字数
extern wchar_t *recv2_buf; // 有効なパケットを含むリカバリ・ファイルのリスト
extern int recv2_len; // ファイル・リストの文字数
extern wchar_t *list2_buf; // 指定された検査対象のファイル名のリスト
extern int list2_len;
extern int list2_max;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// 作成時
// ソース・ファイルの情報
typedef struct { // 44バイト
unsigned char id[16]; // File ID
unsigned char hash[16]; // ファイルの先頭 16KB のハッシュ値
__int64 size; // ファイル・サイズ (存在しない場合は -1)
int name; // ファイル名の開始位置
} file_ctx_c;
// ソース・ブロックの情報
typedef struct { // 12バイト
int file; // 属するソース・ファイルの番号
unsigned int size; // ソース・ファイルからの読み込みサイズ (ブロック・サイズ以下)
unsigned int crc; // ソース・ブロックの CRC-32
} source_ctx_c;
// パリティ・ブロックの情報
typedef struct { // 12バイト
__int64 off; // リカバリ・ファイル内での書き込み開始位置
int file; // 属するリカバリ・ファイルの番号
} parity_ctx_c;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// 検査・修復時
// ソース・ファイルの情報
typedef struct { // 72バイト
unsigned char id[16]; // File ID
unsigned char hash[32]; // ファイルのハッシュ値、と先頭 16KB のハッシュ値
__int64 size; // ファイル・サイズ
int b_off; // ソース・ブロックの開始番号
int b_num; // ソース・ブロックの個数
int name; // ファイル名の開始位置 (存在しない場合は -1 or 0)
int name2; // 名前が異なる場合のファイル名の開始位置
unsigned int state; // ファイルの状態
// 128=そのファイルのチェックサムが存在しない
// ファイルの状態 0=完全, 1=消失, 2=破損, 6=破損で上書き, 16=追加, 32=消失して別名&移動, 40=破損して別名&移動
// フォルダの状態 64=存在, 65=消失, 96=別名&移動
} file_ctx_r;
// ソース・ブロックの情報
typedef struct { // 36バイト
int file; // 属するソース・ファイルの番号
unsigned int size; // ソース・ファイルからの読み込みサイズ (ブロック・サイズ以下)
unsigned int crc; // ソース・ブロックの CRC-32
unsigned char hash[20]; // ソース・ブロックの MD5 と CRC-32
int exist;
// 0=存在しない, 1=完全なファイル内に存在する, 2=破損ファイル内に存在する、またはエラー訂正済み
// 3=内容は全て 0, 4=同じブロックが存在する, 5=CRCで内容を復元できる
// 検査中にそのファイル内で見つかった場合は +0x1000 する (検査成功後に消す)
} source_ctx_r;
// パリティ・ブロックの情報
typedef struct { // 16バイト
__int64 off; // リカバリ・ファイル内での読み込み開始位置
int file; // 属するリカバリ・ファイルの番号
int exist; // 0=存在しない, 1=存在する, 0x100=存在するけど利用せず
} parity_ctx_r;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern unsigned int cp_output; // Console Output Code Page
// 指定された Code Page から UTF-16 に変換する
int cp_to_utf16(char *in, wchar_t *out, unsigned int cp);
// Windown OS の UTF-16 から指定された Code Page に変換する
int utf16_to_cp(wchar_t *in, char *out, unsigned int cp);
// Windows OS の UTF-8 から UTF-16 に変換する
void utf8_to_utf16(char *in, wchar_t *out);
// Windown OS の UTF-16 から UTF-8 に変換する
void utf16_to_utf8(wchar_t *in, char *out);
// 文字列が UTF-8 かどうかを判定する (0 = maybe UTF-8)
int check_utf8(unsigned char *text);
// ファイル・パスから、先頭にある "\\?\" を省いて、指定された Code Page に変換する
int path_to_cp(wchar_t *path, char *out, unsigned int cp);
// 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);
// ファイルの指定バイト目から size バイトのデータを別のファイルに書き込む
int file_copy_data(
HANDLE hFileRead,
__int64 offset_read,
HANDLE hFileWrite,
__int64 offset_write,
unsigned int size);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// スライス断片用の構造体
typedef struct {
int id; // ブロック番号
int front_size; // 前半の占有サイズ
int rear_size; // 後半の占有サイズ
} flake_ctx;
// スライス検査用の構造体
typedef struct {
unsigned char *buf; // ブロック・サイズ *3 の作業領域
// ブロック比較用
int *order; // CRC-32 の順序を格納するバッファー
int block_count; // スライス検出で比較するブロックの数
int index_shift; // インデックス・サーチ用のシフト量
int short_count; // スライス検出で比較する半端なブロックの数
unsigned int min_size; // 半端なブロックの最小サイズ
// 作業ファイル用
int num;
HANDLE hFile_tmp;
int flake_count; // スライス断片を何個記録してるか
unsigned char *flk_buf; // スライス断片の記録領域
// IO のマルチスレッド用
volatile unsigned int size;
HANDLE volatile hFile;
HANDLE h;
HANDLE run;
HANDLE end;
} slice_ctx;
// 修復中のテンポラリ・ファイルの名前を作る
void get_temp_name(
wchar_t *file_path, // ファイル・パス
wchar_t *temp_path); // テンポラリ・ファイルのパス
// 作業用のゼロで埋められたテンポラリ・ファイルを作成する
int create_temp_file(
wchar_t *file_path, // ファイルのパス
__int64 file_size); // ファイルのサイズ
// 作業用のソース・ファイルを開く
HANDLE handle_temp_file(
wchar_t *file_name, // ソース・ファイル名
wchar_t *file_path); // 作業用、基準ディレクトリが入ってる
// 上書き用のソース・ファイルを開く
HANDLE handle_write_file(
wchar_t *file_name, // ソース・ファイル名
wchar_t *file_path, // 作業用、基準ディレクトリが入ってる
__int64 file_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_file_path(wchar_t *filename); // 追加するファイル名
// ファイル・リストから指定されたファイル・パスを取り除く
// 減らした後のファイル・リストの文字数を返す
int remove_file_path(
wchar_t *list, // ファイル・リスト
int total_len, // ファイル・リストの文字数
int file_off); // 取り除くファイル・パスの位置
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// ファイル・パスからファイル名の位置を戻す
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 compare_directory(wchar_t *path1, wchar_t *path2);
// ワイルドカードを含む文字列をコピーする
int copy_wild(wchar_t *dst, wchar_t *src);
// ワイルドカード('*', '?')を使ってユニコードのパスを比較する
int PathMatchWild(
wchar_t *text, // 比較する文字列
wchar_t *wild); // ワイルドカード
// ファイルのパスを除外リストと比較する
int exclude_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 make_dir(
wchar_t *file_path); // サブ・ディレクトリを含むファイル・パス
// ファイルを置き換える (ファイル名の修正、テンポラリー・ファイルからの書き戻しなど)
int replace_file(
wchar_t *dest_path, // ()
wchar_t *sorc_path); // 置き換える元のパス (移動元、現在のファイル名)
// ファイルをどかす
void move_away_file(
wchar_t *file_path); // ファイル・パス
// ファイルを指定サイズに縮小する
int shorten_file(
wchar_t *file_path, // ファイル・パス
__int64 new_size);
// ファイル名が有効かどうか調べる
int check_filename(
wchar_t *name); // 検査するファイル名
// ファイル名が有効か確かめて、問題があれば浄化する
int sanitize_filename(
wchar_t *name, // 検査するファイル名
file_ctx_r *files, // 各ソース・ファイルの情報
int num); // 比較から除外するファイル番号
// リカバリ・ファイルのパスから拡張子とボリューム番号を取り除く
void get_base_filename(
wchar_t *file_path, // リカバリ・ファイルのパス
wchar_t *base_path, // 基準ファイル名のパス
wchar_t *file_ext); // 拡張子 (存在するなら)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// ハッシュ値を表示する
void print_hash(unsigned char hash[16]);
// 64-bit 整数の平方根を求める
unsigned int sqrt64(__int64 num);
// 32-bit 整数の平方根を求める
int sqrt32(int num);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern int cpu_num;
extern unsigned int cpu_flag, cpu_cache;
extern unsigned int memory_use; // メモリー使用量 0=auto, 17 -> 1/8 7/8
void check_cpu(void);
int check_OS64(void);
// 空きメモリー量と制限値から使用できるメモリー量を計算する
size_t get_mem_size(size_t trial_alloc);
// 記録装置の特性を調べる
int check_seek_penalty(wchar_t *dir_path);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern int prog_last; // 前回と同じ進捗状況は出力しないので記録しておく
extern int count_last;
// 経過表示用
int print_progress(int prog_now);
void print_progress_text(int prog_now, char *text);
int print_progress_file(int prog_now, int count_now, wchar_t *file_name);
void print_progress_done(void);
// キャンセルと一時停止を行う
int cancel_progress(void);
// エラー発生時にキャンセルできるようにする
int error_progress(int error_now, int error_last);
// Win32 API のエラー・メッセージを表示する
void print_win32_err(void);
// ファイルをゴミ箱に移す
int delete_file_recycle(wchar_t *file_path);
#ifdef __cplusplus
}
#endif
#endif

419
source/par2j/crc.c Normal file
View File

@@ -0,0 +1,419 @@
// crc.c
// Copyright : 2022-02-09 Yutaka Sawada
// License : GPL
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600 // Windows Vista or later
#endif
#include <stdio.h>
#include <windows.h>
#include <nmmintrin.h> // MMX ~ SSE4.2 命令セットを使用する場合インクルード
#include <wmmintrin.h> // AES, CLMUL 命令セットを使用する場合インクルード
#include "crc.h"
extern unsigned int cpu_flag; // declared in common2.h
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// CRC-32 計算用
#define CRC32_POLY 0xEDB88320 // CRC-32-IEEE 802.3 (little endian)
unsigned int crc_table[256];
unsigned int reverse_table[256]; // CRC-32 逆算用のテーブル
// 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) ^ (CRC32_POLY & ~((r & 1) - 1));
crc_table[i] = r;
}
// crc の 最上位 1バイトからテーブルの位置がわかる
// まずは逆算用のテーブルを作る、テーブルを 8ビットずらして最下位に番号を入れておく
for (i = 0; i < 256; i++)
reverse_table[(crc_table[i] >> 24)] = (crc_table[i] << 8) | i;
}
// CRC-32 を更新する
unsigned int crc_update_std(unsigned int crc, unsigned char *buf, unsigned int len)
{
// 4バイト境界までは 1バイトずつ計算する
while ((len > 0) && (((ULONG_PTR)buf) & 3)){
crc = crc_table[(crc & 0xFF) ^ (*buf++)] ^ (crc >> 8);
len--;
}
// 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;
}
// 内容が全て 0 のデータの CRC-32 を更新する
/*
unsigned int crc_update_zero(unsigned int crc, unsigned int len)
{
while (len--)
crc = crc_table[crc & 0xFF] ^ (crc >> 8);
return crc;
}
*/
// 内容が全て 0 のデータの CRC-32 を逆算するための関数
unsigned int crc_reverse_zero(unsigned int crc, unsigned int len)
{
// crc2 = 前の crc ^ 0xFFFFFFFF;
// crc = table[crc2 & 0xff] ^ (crc2 >> 8);
//crc ^= 0xFFFFFFFF; // 最終処理を取り消す
while (len--)
crc = reverse_table[(crc >> 24)] ^ (crc << 8);
//crc ^= 0xFFFFFFFF; // 最終処理をし直す
return crc;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// CRC-32 with PCLMULQDQ Instruction is based on below source code.
/*
* Compute the CRC32 using a parallelized folding approach with the PCLMULQDQ
* instruction.
*
* A white paper describing this algorithm can be found at:
* http://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
*
* Copyright (C) 2013 Intel Corporation. All rights reserved.
* Authors:
* Wajdi Feghali <wajdi.k.feghali@intel.com>
* Jim Guilford <james.guilford@intel.com>
* Vinodh Gopal <vinodh.gopal@intel.com>
* Erdinc Ozturk <erdinc.ozturk@intel.com>
* Jim Kukunas <james.t.kukunas@linux.intel.com>
*
* For conditions of distribution and use, see copyright notice in zlib.h
*/
// PCLMULQDQ を使って CRC-32 を更新する
unsigned int crc_update(unsigned int crc, unsigned char *buf, unsigned int len)
{
__declspec( align(16) ) unsigned int buf128[4];
unsigned int i;
__m128i crc128, data128, temp128, two_k128;
// special case; shorter than 19 bytes or miss-alignment
if (((cpu_flag & 8) == 0) || (len < 19))
return crc_update_std(crc, buf, len);
// 4バイト境界までは 1バイトずつ計算する
while (((ULONG_PTR)buf) & 3){
crc = crc_table[(crc & 0xFF) ^ (*buf++)] ^ (crc >> 8);
len--;
}
i = ((ULONG_PTR)buf) & 12;
if (i != 0){ // read first 4, 8, or 12 bytes until memory alignment
i = 16 - i; // how many bytes to read
len -= i;
i /= 4;
buf128[0] = 0;
buf128[1] = 0;
buf128[2] = 0;
buf128[3] = 0;
buf128[4 - i] ^= crc; // set initial value
while (i > 0){
buf128[4 - i] ^= *((unsigned int *)buf);
buf += 4;
i--;
}
} else { // read first 16 bytes
buf128[0] = ((unsigned int *)buf)[0];
buf128[1] = ((unsigned int *)buf)[1];
buf128[2] = ((unsigned int *)buf)[2];
buf128[3] = ((unsigned int *)buf)[3];
buf128[0] ^= crc; // set initial value
len -= 16;
buf += 16;
}
crc128 = _mm_load_si128((__m128i *)buf128);
// set two constants; K1 = 0xccaa009e, K2 = 0x1751997d0
two_k128 = _mm_set_epi32(0x00000001, 0x751997d0, 0x00000000, 0xccaa009e);
// per 16 bytes
while (len >= 16){
data128 = _mm_load_si128((__m128i *)buf);
temp128 = _mm_clmulepi64_si128(crc128, two_k128, 0x10);
crc128 = _mm_clmulepi64_si128(crc128, two_k128, 0x01);
data128 = _mm_xor_si128(data128, temp128);
crc128 = _mm_xor_si128(crc128, data128);
len -= 16;
buf += 16;
}
// set two constants; K5 = 0xccaa009e, K6 = 0x163cd6124
two_k128 = _mm_set_epi32(0x00000001, 0x63cd6124, 0x00000000, 0xccaa009e);
// reduce from 128-bit to 96-bit by multiplication with K5
data128 = _mm_clmulepi64_si128(crc128, two_k128, 0);
temp128 = _mm_srli_si128(crc128, 8);
data128 = _mm_xor_si128(data128, temp128);
// reduce from 96-bit to 64-bit by multiplication with K6
temp128 = _mm_slli_si128(data128, 4);
crc128 = _mm_clmulepi64_si128(temp128, two_k128, 0x10);
crc128 = _mm_xor_si128(crc128, data128);
// set two constants; K7 = 0x1f7011640, K8 = 0x1db710640
two_k128 = _mm_set_epi32(0x00000001, 0xdb710640, 0x00000001, 0xf7011640);
// Barrett Reduction from 64-bit to 32-bit
data128 = _mm_and_si128(crc128, _mm_set_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000));
temp128 = _mm_clmulepi64_si128(data128, two_k128, 0);
temp128 = _mm_xor_si128(temp128, data128);
temp128 = _mm_and_si128(temp128, _mm_set_epi32(0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF));
crc128 = _mm_clmulepi64_si128(temp128, two_k128, 0x10);
crc128 = _mm_xor_si128(crc128, temp128);
crc128 = _mm_xor_si128(crc128, data128);
crc = _mm_extract_epi32(crc128, 2);
// per 1 byte rest
while (len--)
crc = crc_table[(crc & 0xFF) ^ (*buf++)] ^ (crc >> 8);
return crc;
}
// 内容が全て 0 のデータの CRC-32 を更新する
unsigned int crc_update_zero(unsigned int crc, unsigned int len)
{
__m128i crc128, data128, temp128, two_k128;
// special case; shorter than 16 bytes
if (((cpu_flag & 8) == 0) || (len < 16)){
while (len--)
crc = crc_table[crc & 0xFF] ^ (crc >> 8);
return crc;
}
// first 16 bytes
len -= 16;
crc128 = _mm_cvtsi32_si128(crc); // set initial value
// set two constants; K1 = 0xccaa009e, K2 = 0x1751997d0
two_k128 = _mm_set_epi32(0x00000001, 0x751997d0, 0x00000000, 0xccaa009e);
// per 16 bytes
while (len >= 16){
temp128 = _mm_clmulepi64_si128(crc128, two_k128, 0x10);
crc128 = _mm_clmulepi64_si128(crc128, two_k128, 0x01);
crc128 = _mm_xor_si128(crc128, temp128);
len -= 16;
}
// set two constants; K5 = 0xccaa009e, K6 = 0x163cd6124
two_k128 = _mm_set_epi32(0x00000001, 0x63cd6124, 0x00000000, 0xccaa009e);
// reduce from 128-bit to 96-bit by multiplication with K5
data128 = _mm_clmulepi64_si128(crc128, two_k128, 0);
temp128 = _mm_srli_si128(crc128, 8);
data128 = _mm_xor_si128(data128, temp128);
// reduce from 96-bit to 64-bit by multiplication with K6
temp128 = _mm_slli_si128(data128, 4);
crc128 = _mm_clmulepi64_si128(temp128, two_k128, 0x10);
crc128 = _mm_xor_si128(crc128, data128);
// set two constants; K7 = 0x1f7011640, K8 = 0x1db710640
two_k128 = _mm_set_epi32(0x00000001, 0xdb710640, 0x00000001, 0xf7011640);
// Barrett Reduction from 64-bit to 32-bit
data128 = _mm_and_si128(crc128, _mm_set_epi32(0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000));
temp128 = _mm_clmulepi64_si128(data128, two_k128, 0);
temp128 = _mm_xor_si128(temp128, data128);
temp128 = _mm_and_si128(temp128, _mm_set_epi32(0x00000000, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF));
crc128 = _mm_clmulepi64_si128(temp128, two_k128, 0x10);
crc128 = _mm_xor_si128(crc128, temp128);
crc128 = _mm_xor_si128(crc128, data128);
crc = _mm_extract_epi32(crc128, 2);
// per 1 byte rest
while (len--)
crc = crc_table[crc & 0xFF] ^ (crc >> 8);
return crc;
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// par2cmdline を参考にした関数
// window サイズの CRC を計算してある所に、1バイトずつ追加と削除をして、CRC を更新する
// This file is part of par2cmdline (a PAR 2.0 compatible file verification and
// repair tool). See http://parchive.sourceforge.net for details of PAR 2.0.
//
// Copyright (c) 2003 Peter Brian Clements
//
// par2cmdline is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
unsigned int window_table[256]; // 詳細検査で CRC-32 をスライドさせる為のテーブル
unsigned int window_mask = 0;
// 先に window_mask を計算してソース・ブロックのチェックサムに XOR することで、
// 初期値と最終処理の 0xFFFFFFFF の影響を消す。
// そうすることで、スライド時に window_mask を使わないで済む。
// Slide the CRC along a buffer by one character (removing the old and adding the new).
// The new character is added using the main CCITT CRC32 table, and the old character
// is removed using the windowtable.
/*
unsigned int crc_slide_char(unsigned int crc, unsigned char chNew, unsigned char chOld){
return crc_table[(crc & 0xFF) ^ chNew] ^ (crc >> 8) ^ window_table[chOld];
}
*/
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Jonathan Camacho が改良した計算方法
// CRC( XOR(A,B) ) == XOR(CRC(A), CRC(B))
// bit twiddling to construct windowtable and windowmask
// window_table と window_mask の計算が 257倍? 速くなるらしい。
static void compute_result_table(unsigned int result, unsigned int result_array[32])
{
int i;
for (i = 0; i < 32; i++){
result = ((result >> 1) & 0x7FFFFFFFL) ^ ((result & 1) ? CRC32_POLY : 0);
result_array[i] = result;
}
}
static void fast_compute_crc_table(unsigned int result_array[8], unsigned int table[256])
{
int i, j, value;
unsigned int new_crc;
table[0] = 0; // g_CrcTable[0 & 0xff] ^ (0 >> 8) は常に 0
for (i = 1; i < 256; i++){
//Firstly, find the correct masks that we need.
//result_array[0] is 128,
//result_array[1] is 64
//result_array[2] is 32
//result_array[3] is 16
//result_array[4] is 8
//result_array[5] is 4
//result_array[6] is 2
//result_array[7] is 1.
//The other values in result_array are not needed right now.
//So basically, for all values of i 0..255 we need to xor
//together the result_array values that it represents.
new_crc = 0;
value = i;
for (j = 0; j < 8; j++){
new_crc = new_crc ^ ( (value & 128) ? result_array[j] : 0) ;
value = value << 1;
}
table[i] = new_crc;
// printf("table[%d] = %08x\n", i, table[i]);
}
}
/*
unsigned int onepass_window_gen(unsigned int window_size, unsigned int window_table[256])
{
unsigned int result = 1;
unsigned int i;
unsigned int masked_result_array[32];
unsigned int window_mask;
if (window_size > 4){
result = crc_update_zero(result, window_size - 4);
compute_result_table(result, masked_result_array);
window_mask = 0;
for (i = 0; i < 32; i++){
window_mask = window_mask ^ masked_result_array[i];
}
window_mask = window_mask ^ ~0;
for (i = 0; i < 4; i++){
result = crc_table[(result & 0xFF)] ^ (result >> 8);
}
compute_result_table(result, masked_result_array);
fast_compute_crc_table(masked_result_array, window_table);
} else { // 普通? に計算する
window_table[0] = 0; // crc_table[0 & 0xff] ^ (0 >> 8) は常に 0
for (i = 1; i < 256; i++){
window_table[i] = crc_update_zero(crc_table[i], window_size); // 0が window サイズ個並んだデータの CRC
}
window_mask = crc_update_zero(0xFFFFFFFF, window_size);
window_mask ^= 0xFFFFFFFF;
}
// printf("window_mask = %08x\n", window_mask);
// for (i = 0; i < 256; i++)
// printf("window_table[%d] = %08x\n", i, window_table[i]);
return window_mask;
}
*/
void onepass_window_gen(unsigned int window_size)
{
unsigned int result = 1;
unsigned int i;
unsigned int masked_result_array[32];
if (window_size <= 4){
window_mask = 0x2144DF1C; // 4バイトの 0 に対する CRC-32
return; // ブロック・サイズが 4以下の時はスライド検査しない
}
result = crc_update_zero(result, window_size - 4);
compute_result_table(result, masked_result_array);
window_mask = 0;
for (i = 0; i < 32; i++){
window_mask = window_mask ^ masked_result_array[i];
}
window_mask = window_mask ^ 0xFFFFFFFF;
for (i = 0; i < 4; i++){
result = crc_table[(result & 0xFF)] ^ (result >> 8);
}
compute_result_table(result, masked_result_array);
fast_compute_crc_table(masked_result_array, window_table);
}
// 初期値と最終処理の 0xFFFFFFFF を使ってない CRC のスライドには window_mask は必要ない
void onepass_window_gen_short(unsigned int short_size, unsigned int short_table[256])
{
unsigned int result = 1;
unsigned int masked_result_array[32];
// short_size must be larger than 4-byte
result = crc_update_zero(result, short_size);
compute_result_table(result, masked_result_array);
fast_compute_crc_table(masked_result_array, short_table);
}

53
source/par2j/crc.h Normal file
View File

@@ -0,0 +1,53 @@
#ifndef _CRC_H_
#define _CRC_H_
#ifdef __cplusplus
extern "C" {
#endif
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// CRC-32 計算用
extern unsigned int crc_table[256];
extern unsigned int reverse_table[256]; // CRC-32 逆算用のテーブル
// CRC 計算用のテーブルを作る
void init_crc_table(void);
// CRC-32 を更新する
unsigned int crc_update(unsigned int crc, unsigned char *buf, unsigned int len);
unsigned int crc_update_std(unsigned int crc, unsigned char *buf, unsigned int len);
// 全て 0 のデータの CRC-32 を更新する
unsigned int crc_update_zero(unsigned int crc, unsigned int len);
// 内容が全て 0 のデータの CRC-32 を逆算するための関数
unsigned int crc_reverse_zero(unsigned int crc, unsigned int len);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// par2cmdline を参考にした関数
// window サイズの CRC を計算してある所に、1バイトずつ追加と削除をして、CRC を更新する
extern unsigned int window_table[256];
extern unsigned int window_mask;
void onepass_window_gen(unsigned int window_size);
void onepass_window_gen_short(unsigned int short_size, unsigned int short_table[256]);
// マクロなら
#define CRC_SLIDE_CHAR(x,y,z) (crc_table[((x) & 0xFF) ^ (y)] ^ ((x) >> 8) ^ window_table[z])
/*
// インライン展開なら
__inline unsigned int crc_slide_char(unsigned int crc, unsigned char chNew, unsigned char chOld){
return crc_table[(crc & 0xFF) ^ chNew] ^ (crc >> 8) ^ window_table[chOld];
}
*/
#ifdef __cplusplus
}
#endif
#endif

2240
source/par2j/create.c Normal file

File diff suppressed because it is too large Load Diff

125
source/par2j/create.h Normal file
View File

@@ -0,0 +1,125 @@
#ifndef _CREATE_H_
#define _CREATE_H_
#ifdef __cplusplus
extern "C" {
#endif
// PAR 2.0 のパケット・ヘッダーを作成する
void set_packet_header(
unsigned char *buf, // ヘッダーを格納する 64バイトのバッファー
unsigned char *set_id, // Recovery Set ID、16バイト
int type_num, // そのパケットの型番号
unsigned int body_size); // パケットのデータ・サイズ
// ソース・ファイルの情報を集める
int get_source_files(file_ctx_c *files);
// 共通パケットを作成する
int set_common_packet(
unsigned char *buf,
int *packet_num, // 共通パケットの数
int switch_u, // ユニコードのファイル名も記録する
file_ctx_c *files);
// 複数ファイルのハッシュ値を同時に求めるバージョン
int set_common_packet_multi(
unsigned char *buf,
int *packet_num, // 共通パケットの数
int switch_u, // ユニコードのファイル名も記録する
file_ctx_c *files);
// ハッシュ値を後で計算する
int set_common_packet_1pass(
unsigned char *buf,
int *packet_num, // 共通パケットの数
int switch_u, // ユニコードのファイル名も記録する
file_ctx_c *files);
// パケットは作成済みなので、ハッシュ値だけ計算して追加する
int set_common_packet_hash(
unsigned char *buf,
file_ctx_c *files);
// ソース・ファイルの情報から共通パケットのサイズを計算する
int measure_common_packet(
int *packet_num, // 共通パケットの数
int switch_u); // ユニコードのファイル名も記録する
// 末尾パケットを作成する
int set_footer_packet(
unsigned char *buf,
wchar_t *par_comment, // コメント
unsigned char *set_id); // Recovery Set ID
// 末尾パケットのサイズを計算する
int measure_footer_packet(
wchar_t *par_comment); // コメント
// リカバリ・ファイルを作成して共通パケットをコピーする
int create_recovery_file(
wchar_t *recovery_path, // 作業用
int packet_limit, // リカバリ・ファイルのパケット繰り返しの制限
int block_distri, // パリティ・ブロックの分配方法
int packet_num, // 共通パケットの数
unsigned char *common_buf, // 共通パケットのバッファー
int common_size, // 共通パケットのバッファー・サイズ
unsigned char *footer_buf, // 末尾パケットのバッファー
int footer_size, // 末尾パケットのバッファー・サイズ
HANDLE *rcv_hFile, // 各リカバリ・ファイルのハンドル
parity_ctx_c *p_blk); // 各パリティ・ブロックの情報
int create_recovery_file_1pass(
wchar_t *recovery_base,
wchar_t *recovery_path, // 作業用
int packet_limit, // リカバリ・ファイルのパケット繰り返しの制限
int block_distri, // (3-bit目は番号の付け方)
int packet_num, // 共通パケットの数
unsigned char *common_buf, // 共通パケットのバッファー
int common_size, // 共通パケットのバッファー・サイズ
unsigned char *footer_buf, // 末尾パケットのバッファー
int footer_size, // 末尾パケットのバッファー・サイズ
HANDLE *rcv_hFile, // 各リカバリ・ファイルのハンドル
unsigned char *p_buf, // 計算済みのパリティ・ブロック
unsigned int unit_size);
// 作成中のリカバリ・ファイルを削除する
void delete_recovery_file(
wchar_t *recovery_path, // 作業用
int block_distri, // パリティ・ブロックの分配方法
int switch_p, // インデックス・ファイルを作らない
HANDLE *rcv_hFile); // 各リカバリ・ファイルのハンドル
// リカバリ・ファイルのサイズを計算する
void measure_recovery_file(
wchar_t *recovery_path, // ()
int packet_limit, // リカバリ・ファイルのパケット繰り返しの制限
int block_distri, // パリティ・ブロックの分配方法
int packet_num, // 共通パケットの数
int common_size, // 共通パケットのバッファー・サイズ
int footer_size, // 末尾パケットのバッファー・サイズ
int switch_p); // インデックス・ファイルを作らない
// ソース・ファイルを分割する
int split_files(
file_ctx_c *files,
int *cur_num, int *cur_id); // エラー発生時は、その時点でのファイル番号と分割番号が戻る
// 分割されたソース・ファイルを削除する
void delete_split_files(
file_ctx_c *files,
int max_num, int max_id); // エラー発生時のファイル番号と分割番号
// リカバリ・ファイルをソース・ファイルの末尾にくっつける
int append_recovery_file(
wchar_t *file_name, // ソース・ファイルの名前
HANDLE *rcv_hFile, // 各リカバリ・ファイルのハンドル
int no_index); // インデックス・ファイルが存在しない
#ifdef __cplusplus
}
#endif
#endif

2749
source/par2j/gf16.c Normal file

File diff suppressed because it is too large Load Diff

72
source/par2j/gf16.h Normal file
View File

@@ -0,0 +1,72 @@
#ifndef _GF16_H_
#define _GF16_H_
#ifdef __cplusplus
extern "C" {
#endif
extern unsigned short *galois_log_table;
extern unsigned int cpu_flag;
int galois_create_table(void); // Returns 0 on success, -1 on failure
unsigned short galois_multiply(int x, int y);
unsigned short galois_multiply_fix(int x, int log_y);
unsigned short galois_divide(int x, int y);
unsigned short galois_power(int x, int y); // 乗数計算用に追加
unsigned short galois_reciprocal(int x); // 逆数計算用に追加
void galois_free_table(void); // 解放用に追加
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
extern int sse_unit;
void galois_region_multiply(
unsigned short *r1, // Region to multiply
unsigned short *r2, // Products go here
unsigned int count, // Count of number in short
int factor); // Number to multiply by
void galois_region_divide(
unsigned short *r1, // Region to divide. products go here
unsigned int count, // Count of number in short
int factor); // Number to divide by
void galois_align_xor(
unsigned char *r1, // Region to multiply
unsigned char *r2, // Products go here
unsigned int len); // Byte length
// 領域掛け算用の関数定義
typedef void (* REGION_MULTIPLY) (
unsigned char *r1, // Region to multiply
unsigned char *r2, // Products go here
unsigned int len, // Byte length
int factor); // Number to multiply by
REGION_MULTIPLY galois_align_multiply;
// 領域並び替え用の関数定義
typedef void (* REGION_ALTMAP) (unsigned char *data, unsigned int bsize);
REGION_ALTMAP galois_altmap_change;
REGION_ALTMAP galois_altmap_return;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#define HASH_SIZE 16
#define HASH_RANGE 128
void checksum16(unsigned char *data, unsigned char *hash, int byte_size);
// 領域並び替えとチェックサム計算の関数定義
typedef void (* region_checksum) (unsigned char *data, unsigned char *hash, int byte_size);
region_checksum checksum16_altmap;
region_checksum checksum16_return;
#ifdef __cplusplus
}
#endif
#endif

192
source/par2j/gf_jit.h Normal file
View File

@@ -0,0 +1,192 @@
#ifndef __GF_JIT__
#define __GF_JIT__
// from ParPar; "x86_jit.c"
#include <stdint.h>
#include <windows.h>
#ifdef _WIN64
typedef unsigned __int64 FAST_U8;
typedef unsigned __int64 FAST_U16;
typedef unsigned __int64 FAST_U32;
#define FAST_U8_SIZE 8
#define FAST_U16_SIZE 8
#define FAST_U32_SIZE 8
#else
typedef unsigned __int32 FAST_U8;
typedef unsigned __int32 FAST_U16;
typedef unsigned __int32 FAST_U32;
#define FAST_U8_SIZE 4
#define FAST_U16_SIZE 4
#define FAST_U32_SIZE 4
#endif
#define MAX_CPU 18 // Max number of threads
unsigned char *jit_code = NULL;
int *jit_id;
// 最初と最後に呼び出すこと (MAX_CPU スレッドまで対応できる)
static __inline int jit_alloc(void){ // 4KB should be enough (but, multiply for multi-core)
if (jit_code != NULL)
return 0;
jit_code = VirtualAlloc(NULL, 4096 * MAX_CPU, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
if (jit_code == NULL)
return -1;
jit_id = (int *)(jit_code + 4096 - 4 * MAX_CPU);
return 0;
}
static __inline void jit_free(void){
if (jit_code == NULL)
return;
VirtualFree(jit_code, 0, MEM_RELEASE);
jit_code = NULL;
}
// registers
#define AX 0
#define BX 3
#define CX 1
#define DX 2
#define DI 7
#define SI 6
#define BP 5
#define SP 4
// conditional jumps
#define JE 0x4
#define JNE 0x5
#define JL 0xC
#define JGE 0xD
#define JLE 0xE
#define JG 0xF
#if defined(_WIN64) // 64-bit 版なら
#define RXX_PREFIX *((*jit_ptr)++) = 0x48;
#else
#define RXX_PREFIX
#endif
static __inline void _jit_rex_pref(unsigned char **jit_ptr, uint8_t xreg, uint8_t xreg2){
#ifdef _WIN64
if (xreg > 7 || xreg2 > 7){
*((*jit_ptr)++) = 0x40 | (xreg2 >>3) | ((xreg >>1)&4);
}
#endif
}
static __inline void _jit_movaps_load(unsigned char **jit_ptr, uint8_t xreg, uint8_t mreg, int32_t offs){
_jit_rex_pref(jit_ptr, xreg, 0);
xreg &= 7;
if ((offs+128) & ~0xFF){
*(int32_t*)(*jit_ptr) = 0x80280F | (xreg <<19) | (mreg <<16);
*(int32_t*)((*jit_ptr) +3) = offs;
(*jit_ptr) += 7;
} else if (offs){
*(int32_t*)(*jit_ptr) = 0x40280F | (xreg <<19) | (mreg <<16) | (offs <<24);
(*jit_ptr) += 4;
} else {
// can overflow, but we don't care
*(int32_t*)(*jit_ptr) = 0x280F | (xreg <<19) | (mreg <<16);
(*jit_ptr) += 3;
}
}
static __inline void _jit_movaps_store(unsigned char **jit_ptr, uint8_t mreg, int32_t offs, uint8_t xreg){
_jit_rex_pref(jit_ptr, xreg, 0);
xreg &= 7;
if ((offs+128) & ~0xFF){
*(int32_t*)(*jit_ptr) = 0x80290F | (xreg <<19) | (mreg <<16);
*(int32_t*)((*jit_ptr) +3) = offs;
jit_ptr += 7;
} else if (offs){
*(int32_t*)(*jit_ptr) = 0x40290F | (xreg <<19) | (mreg <<16) | (offs <<24);
(*jit_ptr) += 4;
} else {
/* can overflow, but we don't care */
*(int32_t*)(*jit_ptr) = 0x290F | (xreg <<19) | (mreg <<16);
(*jit_ptr) += 3;
}
}
static __inline void _jit_push(unsigned char **jit_ptr, uint8_t reg){
*((*jit_ptr)++) = 0x50 | reg;
}
static __inline void _jit_pop(unsigned char **jit_ptr, uint8_t reg){
*((*jit_ptr)++) = 0x58 | reg;
}
static __inline void _jit_jcc(unsigned char **jit_ptr, char op, uint8_t* addr){
int32_t target = (int32_t)(addr - (*jit_ptr) -2);
if((target+128) & ~0xFF) {
*((*jit_ptr)++) = 0x0F;
*((*jit_ptr)++) = 0x80 | op;
*(int32_t*)(*jit_ptr) = target -4;
(*jit_ptr) += 4;
} else {
*(int16_t*)(*jit_ptr) = 0x70 | op | ((int8_t)target << 8);
(*jit_ptr) += 2;
}
}
static __inline void _jit_cmp_r(unsigned char **jit_ptr, uint8_t reg, uint8_t reg2){
RXX_PREFIX
*(int16_t*)(*jit_ptr) = 0xC039 | (reg2 << 11) | (reg << 8);
(*jit_ptr) += 2;
}
static __inline void _jit_add_i(unsigned char **jit_ptr, uint8_t reg, int32_t val){
RXX_PREFIX
*(int16_t*)(*jit_ptr) = 0xC081 | (reg << 8);
(*jit_ptr) += 2;
*(int32_t*)(*jit_ptr) = val;
(*jit_ptr) += 4;
}
static __inline void _jit_sub_r(unsigned char **jit_ptr, uint8_t reg, uint8_t reg2){
RXX_PREFIX
*(int16_t*)(*jit_ptr) = 0xC029 | (reg2 << 11) | (reg << 8);
(*jit_ptr) += 2;
}
static __inline void _jit_and_i(unsigned char **jit_ptr, uint8_t reg, int32_t val){
RXX_PREFIX
*(int16_t*)(*jit_ptr) = 0xE081 | (reg << 11);
(*jit_ptr) += 2;
*(int32_t*)(*jit_ptr) = val;
(*jit_ptr) += 4;
}
static __inline void _jit_mov_i(unsigned char **jit_ptr, uint8_t reg, intptr_t val){
#ifdef _WIN64
if (val > 0x3fffffff || val < 0x40000000){
*(int16_t*)(*jit_ptr) = 0xB848 | (reg << 8);
(*jit_ptr) += 2;
*(int64_t*)(*jit_ptr) = val;
(*jit_ptr) += 8;
} else {
*(int32_t*)(*jit_ptr) = 0xC0C748 | (reg << 16);
(*jit_ptr) += 3;
*(int32_t*)(*jit_ptr) = (int32_t)val;
(*jit_ptr) += 4;
}
#else
*((*jit_ptr)++) = 0xB8 | reg;
*(int32_t*)(*jit_ptr) = (int32_t)val;
(*jit_ptr) += 4;
#endif
}
static __inline void _jit_mov_r(unsigned char **jit_ptr, uint8_t reg, uint8_t reg2){
RXX_PREFIX
*(int16_t*)(*jit_ptr) = 0xC089 | (reg2 << 11) | (reg << 8);
(*jit_ptr) += 2;
}
static __inline void _jit_nop(unsigned char **jit_ptr){
*((*jit_ptr)++) = 0x90;
}
static __inline void _jit_align32(unsigned char **jit_ptr){
while ((intptr_t)(*jit_ptr) & 0x1F){
_jit_nop(jit_ptr);
}
}
static __inline void _jit_ret(unsigned char **jit_ptr){
*((*jit_ptr)++) = 0xC3;
}
#endif //__GF_JIT__

1768
source/par2j/ini.c Normal file

File diff suppressed because it is too large Load Diff

101
source/par2j/ini.h Normal file
View File

@@ -0,0 +1,101 @@
#ifndef _INI_H_
#define _INI_H_
#ifdef __cplusplus
extern "C" {
#endif
#define INI_NAME_LEN 38 // 検査結果ファイルのファイル名の文字数
extern int recent_data;
// リカバリ・ファイルの新規作成時に、同じ Set ID の記録があれば消去しておく
void reset_ini_file(unsigned char *set_id);
// 検査するリカバリ・ファイルが同じであれば、再検査する必要は無い
int check_ini_file(unsigned char *set_id);
void close_ini_file(void);
void write_ini_file2(unsigned char *par_client, wchar_t *par_comment);
void write_ini_file(file_ctx_r *files);
int read_ini_file(wchar_t *uni_buf, file_ctx_r *files);
int check_ini_recovery(
HANDLE hFile, // リカバリ・ファイルのハンドル
unsigned int meta[7]); // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
void write_ini_recovery(int id, __int64 off);
void write_ini_recovery2(
int packet_count, // そのリカバリ・ファイル内に含まれるパケットの数
int block_count, // そのリカバリ・ファイル内に含まれるパリティ・ブロックの数
int bad_flag,
unsigned int meta[7]); // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
int read_ini_recovery(
int num,
int *packet_count, // そのリカバリ・ファイル内に含まれるパケットの数
int *block_count, // そのリカバリ・ファイル内に含まれるパリティ・ブロックの数
int *bad_flag,
parity_ctx_r *p_blk); // 各パリティ・ブロックの情報
// Input File Slice Checksum を書き込む
void write_ini_checksum(
file_ctx_r *files, // 各ソース・ファイルの情報
source_ctx_r *s_blk); // 各ソース・ブロックの情報
// Input File Slice Checksum を読み込む
int read_ini_checksum(
file_ctx_r *files, // 各ソース・ファイルの情報
source_ctx_r *s_blk); // 各ソース・ブロックの情報
// Input File Slice Checksum が不完全でも読み書きする
void update_ini_checksum(
file_ctx_r *files, // 各ソース・ファイルの情報
source_ctx_r *s_blk); // 各ソース・ブロックの情報
void write_ini_state(
int num, // ファイル番号
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
int result); // 検査結果 0=何ブロック目まで一致, -3=完全に一致
int check_ini_state(
int num, // ファイル番号
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
HANDLE hFile); // そのファイルのハンドル
void write_ini_complete(
int num, // ファイル番号
wchar_t *file_path); // ソース・ファイルの絶対パス
int check_ini_verify(
wchar_t *file_name, // 表示するファイル名
HANDLE hFile, // ファイルのハンドル
int num1, // チェックサムを比較したファイルの番号
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
file_ctx_r *files, // 各ソース・ファイルの情報
source_ctx_r *s_blk, // 各ソース・ブロックの情報
slice_ctx *sc); // スライス検査用の情報
void write_ini_verify(int id, int flag, __int64 off);
void write_ini_verify2(
int num1, // チェックサムを比較したファイルの番号
unsigned int meta[7], // サイズ、作成日時、更新日時、ボリューム番号、オブジェクト番号
int max); // 記録したブロック数
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// 作業用のテンポラリ・ファイルを開く
int open_temp_file(
wchar_t *temp_path, // 作業用、基準ディレクトリが入ってる
int num, // 見つけたスライスが属するファイル番号
file_ctx_r *files, // 各ソース・ファイルの情報
slice_ctx *sc);
#ifdef __cplusplus
}
#endif
#endif

483
source/par2j/json.c Normal file
View File

@@ -0,0 +1,483 @@
// json.c
// Copyright : 2023-02-06 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 "common2.h"
/*
{
"SelectedFile":"Full path of selected recovery file",
"BaseDirectory":"Full path of base directory of source files",
"RecoveryFile":[
"Name of recovery file1",
"Name of recovery file2",
"Name of recovery file3"
],
"SourceFile":[
"Name of source file1",
"Name of source file2",
"Name of source file3"
],
"FoundFile":[
"Name of found file1",
"Name of found file2"
],
"ExternalFile":[
"Name of external file1",
"Name of external file2"
],
"DamagedFile":[
"Name of damaged file1",
"Name of damaged file2"
],
"AppendedFile":[
"Name of appended file1",
"Name of appended file2"
],
"MissingFile":[
"Name of missing file1",
"Name of missing file2"
],
"MisnamedFile":{
"Correct name of misnamed file1":"Wrong name",
"Correct name of misnamed file2":"Wrong name"
}
}
*/
static FILE *fp_json = NULL; // JSONファイル用
static wchar_t *list3_buf = NULL; // 検出ファイルの名前リスト
static int list3_len, list3_max;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// JSONファイルを開く
void json_open(void)
{
wchar_t path[MAX_LEN];
int len;
if (fp_json != NULL)
return; // 既に開いてる場合はそのまま
wcscpy(path, ini_path);
wcscat(path, offset_file_name(recovery_file));
wcscat(path, L".json");
//printf("json_path = %ls\n", path);
// 既に存在する場合は上書きして作り直す
fp_json = _wfopen(path, L"wt, ccs=UTF-8");
if (fp_json == NULL)
return;
// 基礎情報を書き込む
rewind(fp_json); // Remove BOM of UTF-8
copy_without_prefix(path, recovery_file);
unix_directory(path);
if (fwprintf(fp_json, L"{\n\"SelectedFile\":\"%s\"", path) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
len = copy_without_prefix(path, base_dir);
path[len - 1] = 0; // 末尾の「\」を取り除く
unix_directory(path);
if (fwprintf(fp_json, L",\n\"BaseDirectory\":\"%s\"", path) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
}
// JSONファイルを閉じる
void json_close(void)
{
if (fp_json == NULL)
return; // 既に閉じてる場合はそのまま
fputws(L"\n}\n", fp_json);
fclose(fp_json);
fp_json = NULL;
}
// ファイル一覧
void json_file_list(file_ctx_r *files)
{
wchar_t path[MAX_LEN];
int rv, i;
if (fp_json == NULL)
return; // 開いてない場合は何もしない
// パケットを含む (Good or Damaged) リカバリ・ファイルのリスト
// 全くパケットを含まない (Useless) ファイルは除く
if (fputws(L",\n\"RecoveryFile\":[", fp_json) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
i = 0;
while (i < recv2_len){
if (compare_directory(recovery_file, recv2_buf + i) == 0){
// 指定されたリカバリ・ファイルと同じ場所ならファイル名のみ
wcscpy(path, offset_file_name(recv2_buf + i));
} else {
// 異なる場所External Fileならフルパス
copy_without_prefix(path, recv2_buf + i);
unix_directory(path);
}
if (i == 0){
rv = fwprintf(fp_json, L"\n\"%s\"", path);
} else {
rv = fwprintf(fp_json, L",\n\"%s\"", path);
}
if (rv < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
while (recv2_buf[i] != 0)
i++;
i++;
}
if (fputws(L"\n]", fp_json) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
// ソース・ファイルのリスト
if (fputws(L",\n\"SourceFile\":[", fp_json) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
for (i = 0; i < file_num; i++){
wcscpy(path, list_buf + files[i].name);
unix_directory(path);
if (i == 0){
rv = fwprintf(fp_json, L"\n\"%s\"", path);
} else {
rv = fwprintf(fp_json, L",\n\"%s\"", path);
}
if (rv < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
}
if (fputws(L"\n]", fp_json) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
}
// ファイルの状態
void json_file_state(file_ctx_r *files)
{
wchar_t path[MAX_LEN], path2[MAX_LEN];
int rv, i, flag_item;
if (fp_json == NULL)
return; // 開いてない場合は何もしない
// 破損ファイル
flag_item = 0;
for (i = 0; i < file_num; i++){
if (files[i].state & 2){
wcscpy(path, list_buf + files[i].name);
unix_directory(path);
if (flag_item == 0){
flag_item = 1;
if (fputws(L",\n\"DamagedFile\":[", fp_json) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
rv = fwprintf(fp_json, L"\n\"%s\"", path);
} else {
rv = fwprintf(fp_json, L",\n\"%s\"", path);
}
if (rv < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
}
}
if (flag_item != 0){
if (fputws(L"\n]", fp_json) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
}
// 追加されたファイル
flag_item = 0;
for (i = 0; i < file_num; i++){
if (files[i].state & 16){
wcscpy(path, list_buf + files[i].name);
unix_directory(path);
if (flag_item == 0){
flag_item = 1;
if (fputws(L",\n\"AppendedFile\":[", fp_json) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
rv = fwprintf(fp_json, L"\n\"%s\"", path);
} else {
rv = fwprintf(fp_json, L",\n\"%s\"", path);
}
if (rv < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
}
}
if (flag_item != 0){
if (fputws(L"\n]", fp_json) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
}
// 消失ファイル
flag_item = 0;
for (i = 0; i < file_num; i++){
if (files[i].state & 1){
wcscpy(path, list_buf + files[i].name);
unix_directory(path);
if (flag_item == 0){
flag_item = 1;
if (fputws(L",\n\"MissingFile\":[", fp_json) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
rv = fwprintf(fp_json, L"\n\"%s\"", path);
} else {
rv = fwprintf(fp_json, L",\n\"%s\"", path);
}
if (rv < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
}
}
if (flag_item != 0){
if (fputws(L"\n]", fp_json) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
}
// 別名ファイルは、"本来の名前":"間違った名前" というセットにする
flag_item = 0;
for (i = 0; i < file_num; i++){
if (files[i].state & 32){
// ソースファイルの本来の名前
wcscpy(path, list_buf + files[i].name);
unix_directory(path);
// 別名
wcscpy(path2, list_buf + files[i].name2);
unix_directory(path2);
if (flag_item == 0){
flag_item = 1;
if (fputws(L",\n\"MisnamedFile\":{", fp_json) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
rv = fwprintf(fp_json, L"\n\"%s\":\"%s\"", path, path2);
} else {
rv = fwprintf(fp_json, L",\n\"%s\":\"%s\"", path, path2);
}
if (rv < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
}
}
if (flag_item != 0){
if (fputws(L"\n}", fp_json) < 0){
fclose(fp_json);
fp_json = NULL;
return;
}
}
}
// 検出されたファイル名を保持する
void json_add_found(wchar_t *filename, int flag_external)
{
wchar_t *tmp_p;
int len;
if (fp_json == NULL)
return; // 開いてない場合は何もしない
len = (int)wcslen(filename) + 1;
if (list3_buf == NULL){
list3_max = ALLOC_LEN;
list3_len = 0;
list3_buf = malloc(list3_max * 2);
if (list3_buf == NULL){
fclose(fp_json);
fp_json = NULL;
return;
}
} else if (list3_len + len >= list3_max){ // 領域が足りなくなるなら拡張する
list3_max += ALLOC_LEN;
tmp_p = (wchar_t *)realloc(list3_buf, list3_max * 2);
if (tmp_p == NULL){
free(list3_buf);
list3_buf = NULL;
fclose(fp_json);
fp_json = NULL;
return;
} else {
list3_buf = tmp_p;
}
}
if (flag_external != 0){
list3_buf[list3_len] = 'e';
} else {
list3_buf[list3_len] = 'f';
}
wcscpy(list3_buf + list3_len + 1, filename);
list3_len += len + 1;
}
// 検出されたファイル名を書き込む
void json_save_found(void)
{
wchar_t path[MAX_LEN];
int rv, i, flag_item;
if (fp_json == NULL)
return; // 開いてない場合は何もしない
if (list3_buf == NULL)
return; // 検出しなかった場合は何もしない
/*{
FILE *fp;
fp = fopen("list3.txt", "wb");
fwrite(list3_buf, 2, list3_len, fp);
fclose(fp);
}*/
// ブロックを検出したファイル
flag_item = 0;
i = 0;
while (i < list3_len){
if (list3_buf[i] == 'f'){
wcscpy(path, list3_buf + i + 1);
unix_directory(path);
if (flag_item == 0){
flag_item = 1;
if (fputws(L",\n\"FoundFile\":[", fp_json) < 0){
free(list3_buf);
list3_buf = NULL;
fclose(fp_json);
fp_json = NULL;
return;
}
rv = fwprintf(fp_json, L"\n\"%s\"", path);
} else {
rv = fwprintf(fp_json, L",\n\"%s\"", path);
}
if (rv < 0){
free(list3_buf);
list3_buf = NULL;
fclose(fp_json);
fp_json = NULL;
return;
}
}
while (list3_buf[i] != 0)
i++;
i++;
}
if (flag_item != 0){
if (fputws(L"\n]", fp_json) < 0){
free(list3_buf);
list3_buf = NULL;
fclose(fp_json);
fp_json = NULL;
return;
}
}
// ブロックを検出した外部ファイル
flag_item = 0;
i = 0;
while (i < list3_len){
if (list3_buf[i] == 'e'){
copy_without_prefix(path, list3_buf + i + 1);
unix_directory(path);
if (flag_item == 0){
flag_item = 1;
if (fputws(L",\n\"ExternalFile\":[", fp_json) < 0){
free(list3_buf);
list3_buf = NULL;
fclose(fp_json);
fp_json = NULL;
return;
}
rv = fwprintf(fp_json, L"\n\"%s\"", path);
} else {
rv = fwprintf(fp_json, L",\n\"%s\"", path);
}
if (rv < 0){
free(list3_buf);
list3_buf = NULL;
fclose(fp_json);
fp_json = NULL;
return;
}
}
while (list3_buf[i] != 0)
i++;
i++;
}
if (flag_item != 0){
if (fputws(L"\n]", fp_json) < 0){
free(list3_buf);
list3_buf = NULL;
fclose(fp_json);
fp_json = NULL;
return;
}
}
// 最後にメモリーを開放する
free(list3_buf);
list3_buf = NULL;
}

19
source/par2j/json.h Normal file
View File

@@ -0,0 +1,19 @@

// JSONファイルを開く
void json_open(void);
// JSONファイルを閉じる
void json_close(void);
// ファイル一覧
void json_file_list(file_ctx_r *files);
// ファイルの状態
void json_file_state(file_ctx_r *files);
// 検出されたファイル名を保持する
void json_add_found(wchar_t *filename, int flag_external);
// 検出されたファイル名を書き込む
void json_save_found(void);

833
source/par2j/lib_opencl.c Normal file
View File

@@ -0,0 +1,833 @@
// lib_opencl.c
// Copyright : 2022-01-15 Yutaka Sawada
// License : GPL
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600 // Windows Vista or later
#endif
#include <stdio.h>
#include <windows.h>
#include <opencl.h>
#include "gf16.h"
#include "lib_opencl.h"
//#define DEBUG_OUTPUT // 実験用
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// 関数の定義
// Platform API
typedef cl_int (CL_API_CALL *API_clGetPlatformIDs)(cl_uint, cl_platform_id *, cl_uint *);
typedef cl_int (CL_API_CALL *API_clGetPlatformInfo)(cl_platform_id, cl_platform_info, size_t, void *, size_t *);
// Device APIs
typedef cl_int (CL_API_CALL *API_clGetDeviceIDs)(cl_platform_id, cl_device_type, cl_uint, cl_device_id *, cl_uint *);
typedef cl_int (CL_API_CALL *API_clGetDeviceInfo)(cl_device_id, cl_device_info, size_t, void *, size_t *);
// Context APIs
typedef cl_context (CL_API_CALL *API_clCreateContext)(const cl_context_properties *, cl_uint, const cl_device_id *, void (CL_CALLBACK *)(const char *, const void *, size_t, void *), void *, cl_int *);
typedef cl_int (CL_API_CALL *API_clReleaseContext)(cl_context);
typedef cl_int (CL_API_CALL *API_clGetContextInfo)(cl_context, cl_context_info, size_t, void *, size_t *);
// Command Queue APIs
typedef cl_command_queue (CL_API_CALL *API_clCreateCommandQueue)(cl_context, cl_device_id, cl_command_queue_properties, cl_int *);
typedef cl_int (CL_API_CALL *API_clReleaseCommandQueue)(cl_command_queue);
// Memory Object APIs
typedef cl_mem (CL_API_CALL *API_clCreateBuffer)(cl_context, cl_mem_flags, size_t, void *, cl_int *);
typedef cl_int (CL_API_CALL *API_clReleaseMemObject)(cl_mem);
// Program Object APIs
typedef cl_program (CL_API_CALL *API_clCreateProgramWithSource)(cl_context, cl_uint, const char **, const size_t *, cl_int *);
typedef cl_int (CL_API_CALL *API_clReleaseProgram)(cl_program);
typedef cl_int (CL_API_CALL *API_clBuildProgram)(cl_program, cl_uint, const cl_device_id *,const char *, void (CL_CALLBACK *)(cl_program, void *), void *);
typedef cl_int (CL_API_CALL *API_clUnloadCompiler)(void);
typedef cl_int (CL_API_CALL *API_clUnloadPlatformCompiler)(cl_platform_id); // OpenCL 1.2 で追加された
typedef cl_int (CL_API_CALL *API_clGetProgramBuildInfo)(cl_program, cl_device_id, cl_program_build_info, size_t, void *, size_t *);
// Kernel Object APIs
typedef cl_kernel (CL_API_CALL *API_clCreateKernel)(cl_program, const char *, cl_int *);
typedef cl_int (CL_API_CALL *API_clReleaseKernel)(cl_kernel);
typedef cl_int (CL_API_CALL *API_clSetKernelArg)(cl_kernel, cl_uint, size_t, const void *);
typedef cl_int (CL_API_CALL *API_clGetKernelWorkGroupInfo)(cl_kernel, cl_device_id, cl_kernel_work_group_info, size_t, void *, size_t *);
// Event Object APIs
typedef cl_int (CL_API_CALL *API_clReleaseEvent)(cl_event);
typedef cl_int (CL_API_CALL *API_clGetEventInfo)(cl_event, cl_event_info, size_t, void *, size_t *);
// Flush and Finish APIs
typedef cl_int (CL_API_CALL *API_clFlush)(cl_command_queue);
typedef cl_int (CL_API_CALL *API_clFinish)(cl_command_queue);
// Enqueued Commands APIs
typedef cl_int (CL_API_CALL *API_clEnqueueReadBuffer)(cl_command_queue, cl_mem, cl_bool, size_t, size_t, void *, cl_uint, const cl_event *, cl_event *);
typedef cl_int (CL_API_CALL *API_clEnqueueWriteBuffer)(cl_command_queue, cl_mem, cl_bool, size_t, size_t, const void *, cl_uint, const cl_event *, cl_event *);
typedef void * (CL_API_CALL *API_clEnqueueMapBuffer)(cl_command_queue, cl_mem, cl_bool, cl_map_flags, size_t, size_t, cl_uint, const cl_event *, cl_event *, cl_int *);
typedef cl_int (CL_API_CALL *API_clEnqueueUnmapMemObject)(cl_command_queue, cl_mem, void *, cl_uint, const cl_event *, cl_event *);
typedef cl_int (CL_API_CALL *API_clEnqueueNDRangeKernel)(cl_command_queue, cl_kernel, cl_uint, const size_t *, const size_t *, const size_t *, cl_uint, const cl_event *, cl_event *);
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// グローバル変数
extern unsigned int cpu_flag, cpu_cache; // declared in common2.h
extern int cpu_num;
#define MAX_DEVICE 3
#define MAX_GROUP_NUM 64
HMODULE hLibOpenCL = NULL;
cl_context OpenCL_context = NULL;
cl_command_queue OpenCL_command = NULL;
cl_kernel OpenCL_kernel = NULL;
cl_mem OpenCL_src = NULL, OpenCL_dst = NULL, OpenCL_buf = NULL;
size_t OpenCL_group_num;
int OpenCL_method = 0; // 正=速い機器を選ぶ, 負=遅い機器を選ぶ
API_clCreateBuffer gfn_clCreateBuffer;
API_clReleaseMemObject gfn_clReleaseMemObject;
API_clSetKernelArg gfn_clSetKernelArg;
API_clFinish gfn_clFinish;
API_clEnqueueReadBuffer gfn_clEnqueueReadBuffer;
API_clEnqueueWriteBuffer gfn_clEnqueueWriteBuffer;
API_clEnqueueMapBuffer gfn_clEnqueueMapBuffer;
API_clEnqueueUnmapMemObject gfn_clEnqueueUnmapMemObject;
API_clEnqueueNDRangeKernel gfn_clEnqueueNDRangeKernel;
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
入力
OpenCL_method : どのデバイスを選ぶか
unit_size : ブロックの単位サイズ
src_max : ソース・ブロック個数
chunk_size = 0: 標準では分割しない
出力
return : エラー番号
src_max : 最大で何ブロックまでソースを読み込めるか
chunk_size : CPUスレッドの分割サイズ
OpenCL_method : 動作フラグいろいろ
*/
// 0=成功, 1エラー番号
int init_OpenCL(int unit_size, int *src_max, int *chunk_size)
{
char buf[2048], *p_source;
int err = 0, i, j;
int gpu_power, count;
size_t data_size, alloc_max;
//FILE *fp;
HRSRC res;
HGLOBAL glob;
API_clGetPlatformIDs fn_clGetPlatformIDs;
#ifdef DEBUG_OUTPUT
API_clGetPlatformInfo fn_clGetPlatformInfo;
#endif
API_clGetDeviceIDs fn_clGetDeviceIDs;
API_clGetDeviceInfo fn_clGetDeviceInfo;
API_clCreateContext fn_clCreateContext;
API_clCreateCommandQueue fn_clCreateCommandQueue;
API_clCreateProgramWithSource fn_clCreateProgramWithSource;
API_clBuildProgram fn_clBuildProgram;
API_clUnloadCompiler fn_clUnloadCompiler;
API_clUnloadPlatformCompiler fn_clUnloadPlatformCompiler;
API_clGetProgramBuildInfo fn_clGetProgramBuildInfo;
API_clReleaseProgram fn_clReleaseProgram;
API_clCreateKernel fn_clCreateKernel;
API_clGetKernelWorkGroupInfo fn_clGetKernelWorkGroupInfo;
cl_int ret;
cl_uint num_platforms = 0, num_devices = 0, num_groups, param_value;
cl_ulong param_value8, cache_size;
cl_platform_id platform_id[MAX_DEVICE], selected_platform; // Intel, AMD, Nvidia などドライバーの提供元
cl_device_id device_id[MAX_DEVICE], selected_device; // CPU や GPU など
cl_program program;
// ライブラリーを読み込む
hLibOpenCL = LoadLibraryA("OpenCL.DLL");
if (hLibOpenCL == NULL)
return 1;
// 関数のエントリー取得
err = 2;
fn_clGetPlatformIDs = (API_clGetPlatformIDs)GetProcAddress(hLibOpenCL, "clGetPlatformIDs");
if (fn_clGetPlatformIDs == NULL)
return err;
#ifdef DEBUG_OUTPUT
fn_clGetPlatformInfo = (API_clGetPlatformInfo)GetProcAddress(hLibOpenCL, "clGetPlatformInfo");
if (fn_clGetPlatformInfo == NULL)
return err;
#endif
fn_clGetDeviceIDs = (API_clGetDeviceIDs)GetProcAddress(hLibOpenCL, "clGetDeviceIDs");
if (fn_clGetDeviceIDs == NULL)
return err;
fn_clGetDeviceInfo = (API_clGetDeviceInfo)GetProcAddress(hLibOpenCL, "clGetDeviceInfo");
if (fn_clGetDeviceInfo == NULL)
return err;
fn_clCreateContext = (API_clCreateContext)GetProcAddress(hLibOpenCL, "clCreateContext");
if (fn_clCreateContext == NULL)
return err;
fn_clCreateCommandQueue = (API_clCreateCommandQueue)GetProcAddress(hLibOpenCL, "clCreateCommandQueue");
if (fn_clCreateCommandQueue == NULL)
return err;
gfn_clCreateBuffer = (API_clCreateBuffer)GetProcAddress(hLibOpenCL, "clCreateBuffer");
if (gfn_clCreateBuffer == NULL)
return err;
gfn_clReleaseMemObject = (API_clReleaseMemObject)GetProcAddress(hLibOpenCL, "clReleaseMemObject");
if (gfn_clReleaseMemObject == NULL)
return err;
gfn_clEnqueueReadBuffer = (API_clEnqueueReadBuffer)GetProcAddress(hLibOpenCL, "clEnqueueReadBuffer");
if (gfn_clEnqueueReadBuffer == NULL)
return err;
gfn_clEnqueueWriteBuffer = (API_clEnqueueWriteBuffer)GetProcAddress(hLibOpenCL, "clEnqueueWriteBuffer");
if (gfn_clEnqueueWriteBuffer == NULL)
return err;
gfn_clEnqueueMapBuffer = (API_clEnqueueMapBuffer)GetProcAddress(hLibOpenCL, "clEnqueueMapBuffer");
if (gfn_clEnqueueMapBuffer == NULL)
return err;
gfn_clEnqueueUnmapMemObject = (API_clEnqueueUnmapMemObject)GetProcAddress(hLibOpenCL, "clEnqueueUnmapMemObject");
if (gfn_clEnqueueUnmapMemObject == NULL)
return err;
fn_clCreateProgramWithSource = (API_clCreateProgramWithSource)GetProcAddress(hLibOpenCL, "clCreateProgramWithSource");
if (fn_clCreateProgramWithSource == NULL)
return err;
fn_clBuildProgram = (API_clBuildProgram)GetProcAddress(hLibOpenCL, "clBuildProgram");
if (fn_clBuildProgram == NULL)
return err;
fn_clGetProgramBuildInfo = (API_clGetProgramBuildInfo)GetProcAddress(hLibOpenCL, "clGetProgramBuildInfo");
if (fn_clGetProgramBuildInfo == NULL)
return err;
fn_clReleaseProgram = (API_clReleaseProgram)GetProcAddress(hLibOpenCL, "clReleaseProgram");
if (fn_clReleaseProgram == NULL)
return err;
fn_clUnloadPlatformCompiler = (API_clUnloadPlatformCompiler)GetProcAddress(hLibOpenCL, "clUnloadPlatformCompiler");
if (fn_clUnloadPlatformCompiler == NULL){ // OpenCL 1.1 なら clUnloadCompiler を使う
fn_clUnloadCompiler = (API_clUnloadCompiler)GetProcAddress(hLibOpenCL, "clUnloadCompiler");
if (fn_clUnloadCompiler == NULL)
return err;
}
fn_clCreateKernel = (API_clCreateKernel)GetProcAddress(hLibOpenCL, "clCreateKernel");
if (fn_clCreateKernel == NULL)
return err;
gfn_clSetKernelArg = (API_clSetKernelArg)GetProcAddress(hLibOpenCL, "clSetKernelArg");
if (gfn_clSetKernelArg == NULL)
return err;
fn_clGetKernelWorkGroupInfo = (API_clGetKernelWorkGroupInfo)GetProcAddress(hLibOpenCL, "clGetKernelWorkGroupInfo");
if (fn_clGetKernelWorkGroupInfo == NULL)
return err;
gfn_clFinish = (API_clFinish)GetProcAddress(hLibOpenCL, "clFinish");
if (gfn_clFinish == NULL)
return err;
gfn_clEnqueueNDRangeKernel = (API_clEnqueueNDRangeKernel)GetProcAddress(hLibOpenCL, "clEnqueueNDRangeKernel");
if (gfn_clEnqueueNDRangeKernel == NULL)
return err;
// OpenCL 環境の数
ret = fn_clGetPlatformIDs(MAX_DEVICE, platform_id, &num_platforms);
if (ret != CL_SUCCESS)
return (ret << 8) | 10;
if (OpenCL_method >= 0){ // 選択する順序と初期値を変える
OpenCL_method = 1;
gpu_power = 0;
} else {
OpenCL_method = -1;
gpu_power = INT_MIN;
}
alloc_max = 0;
for (i = 0; i < (int)num_platforms; i++){
#ifdef DEBUG_OUTPUT
// 環境の情報表示
if (fn_clGetPlatformInfo(platform_id[i], CL_PLATFORM_NAME, sizeof(buf), buf, NULL) == CL_SUCCESS)
printf("\nPlatform[%d] = %s\n", i, buf);
if (fn_clGetPlatformInfo(platform_id[i], CL_PLATFORM_VERSION, sizeof(buf), buf, NULL) == CL_SUCCESS)
printf("Platform version = %s\n", buf);
#endif
// 環境内の OpenCL 対応機器の数
if (fn_clGetDeviceIDs(platform_id[i], CL_DEVICE_TYPE_GPU, MAX_DEVICE, device_id, &num_devices) != CL_SUCCESS)
continue;
for (j = 0; j < (int)num_devices; j++){
// デバイスが利用可能か確かめる
ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_AVAILABLE, sizeof(cl_uint), &param_value, NULL);
if ((ret != CL_SUCCESS) || (param_value == CL_FALSE))
continue;
ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_COMPILER_AVAILABLE, sizeof(cl_uint), &param_value, NULL);
if ((ret != CL_SUCCESS) || (param_value == CL_FALSE))
continue;
#ifdef DEBUG_OUTPUT
// 機器の情報表示
ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_NAME, sizeof(buf), buf, NULL);
if (ret == CL_SUCCESS)
printf("\nDevice[%d] = %s\n", j, buf);
ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_VERSION, sizeof(buf), buf, NULL);
if (ret == CL_SUCCESS)
printf("Device version = %s\n", buf);
ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_LOCAL_MEM_SIZE, sizeof(cl_ulong), &param_value8, NULL);
if (ret == CL_SUCCESS)
printf("LOCAL_MEM_SIZE = %I64d KB\n", param_value8 >> 10);
// 無理とは思うけど、一応チェックする
//#define CL_DEVICE_SVM_CAPABILITIES 0x1053
//#define CL_DEVICE_SVM_COARSE_GRAIN_BUFFER (1 << 0)
//#define CL_DEVICE_SVM_FINE_GRAIN_BUFFER (1 << 1)
//#define CL_DEVICE_SVM_FINE_GRAIN_SYSTEM (1 << 2)
//#define CL_DEVICE_SVM_ATOMICS (1 << 3)
// ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_SVM_CAPABILITIES, sizeof(cl_ulong), &param_value8, NULL);
// if (ret == CL_INVALID_VALUE)
// printf("Shared Virtual Memory is not supported\n");
// if (ret == CL_SUCCESS)
// printf("Shared Virtual Memory = 0x%I64X\n", param_value8);
#endif
ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_ADDRESS_BITS, sizeof(cl_uint), &param_value, NULL);
if (ret != CL_SUCCESS)
continue;
ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(cl_ulong), &param_value8, NULL);
if (ret != CL_SUCCESS)
continue;
#ifdef DEBUG_OUTPUT
printf("ADDRESS_BITS = %d\n", param_value);
printf("MAX_MEM_ALLOC_SIZE = %I64d MB\n", param_value8 >> 20);
#endif
if (param_value == 32){ // CL_DEVICE_ADDRESS_BITS によって確保するメモリー領域の上限を変える
if (param_value8 > 0x30000000) // 768MB までにする
param_value8 = 0x30000000;
} else { // 64-bit OS でも 2GB までにする
if (param_value8 > 0x80000000)
param_value8 = 0x80000000;
}
ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(cl_uint), &num_groups, NULL);
if (ret != CL_SUCCESS)
continue;
ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(size_t), &data_size, NULL);
if (ret != CL_SUCCESS)
continue;
ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_HOST_UNIFIED_MEMORY, sizeof(cl_uint), &param_value, NULL);
if (ret != CL_SUCCESS)
continue;
if (param_value != 0)
param_value = 1;
#ifdef DEBUG_OUTPUT
printf("MAX_COMPUTE_UNITS = %d\n", num_groups);
printf("MAX_WORK_GROUP_SIZE = %d\n", data_size);
printf("HOST_UNIFIED_MEMORY = %d\n", param_value);
#endif
// MAX_COMPUTE_UNITS * MAX_WORK_GROUP_SIZE で計算力を測る、外付けGPUなら値を倍にする
count = (2 - param_value) * (int)data_size * num_groups;
count *= OpenCL_method; // 符号を変える
//printf("prev = %d, now = %d\n", gpu_power, count);
if ((count > gpu_power) && (data_size >= 256) && // 256以上ないとテーブルを作れない
(param_value8 / 8 > (cl_ulong)unit_size)){ // CL_DEVICE_MAX_MEM_ALLOC_SIZE に収まるか
gpu_power = count;
selected_device = device_id[j]; // 使うデバイスの ID
selected_platform = platform_id[i];
OpenCL_group_num = num_groups; // ワークグループ数は COMPUTE_UNITS 数にする
if (OpenCL_group_num > MAX_GROUP_NUM) // 制限を付けてローカルメモリーの消費を抑える
OpenCL_group_num = MAX_GROUP_NUM;
alloc_max = (size_t)param_value8;
// AMD Radeon ではメモリー領域が全体の 1/4 とは限らない
ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(cl_ulong), &param_value8, NULL);
if (ret == CL_SUCCESS){
#ifdef DEBUG_OUTPUT
printf("GLOBAL_MEM_SIZE = %I64d MB\n", param_value8 >> 20);
#endif
// 領域一個あたりのサイズは全体の 1/4 までにする
param_value8 /= 4;
if ((cl_ulong)alloc_max > param_value8)
alloc_max = (size_t)param_value8;
}
cache_size = 0;
ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_GLOBAL_MEM_CACHE_TYPE, sizeof(cl_uint), &num_groups, NULL);
if (ret == CL_SUCCESS){
#ifdef DEBUG_OUTPUT
printf("GLOBAL_MEM_CACHE_TYPE = %d\n", num_groups);
#endif
if (num_groups & 3){ // CL_READ_ONLY_CACHE or CL_READ_WRITE_CACHE
ret = fn_clGetDeviceInfo(device_id[j], CL_DEVICE_GLOBAL_MEM_CACHE_SIZE, sizeof(cl_ulong), &cache_size, NULL);
if (ret == CL_SUCCESS){
#ifdef DEBUG_OUTPUT
printf("GLOBAL_MEM_CACHE_SIZE = %I64d KB\n", cache_size >> 10);
#endif
if (param_value != 0){ // 内蔵 GPU なら CPU との共有キャッシュを活用する
if (cache_size >= 1048576) // サイズが小さい場合は分割しない
cache_size |= 0x40000000;
}
}
}
}
}
}
}
if (alloc_max == 0){
#ifdef DEBUG_OUTPUT
printf("\nAvailable GPU device was not found.\n");
#endif
return 3;
}
#ifdef DEBUG_OUTPUT
// デバイスの情報表示
ret = fn_clGetPlatformInfo(selected_platform, CL_PLATFORM_NAME, sizeof(buf), buf, NULL);
if (ret == CL_SUCCESS)
printf("\nSelected platform = %s\n", buf);
ret = fn_clGetDeviceInfo(selected_device, CL_DEVICE_NAME, sizeof(buf), buf, NULL);
if (ret == CL_SUCCESS)
printf("Selected device = %s\n", buf);
#endif
// OpenCL 利用環境を作成する
OpenCL_context = fn_clCreateContext(NULL, 1, &selected_device, NULL, NULL, &ret);
if (ret != CL_SUCCESS)
return (ret << 8) | 11;
OpenCL_command = fn_clCreateCommandQueue(OpenCL_context, selected_device, 0, &ret);
if (ret != CL_SUCCESS)
return (ret << 8) | 12;
// 計算方式を選択する
gpu_power = unit_size; // unit_size は MEM_UNIT の倍数になってる
if ((((cpu_flag & 0x101) == 1) || ((cpu_flag & 16) != 0)) && (sse_unit == 32)){
OpenCL_method = 2; // SSSE3 & ALTMAP または AVX2 ならデータの並び替え対応版を使う
if (cache_size & 0x40000000){ // 内蔵 GPU でキャッシュを利用できるなら、CPUスレッドと同じにする
j = cpu_cache & 0x7FFF8000; // CPUのキャッシュ上限サイズ
count = (int)(cache_size & 0x3FFFFFFF) / 4; // ただし、認識できるサイズの 1/4 までにする
if ((j == 0) || (j > count))
j = count;
count = 1;
while (gpu_power > j){ // 制限サイズより大きいなら
// 分割数を増やして chunk のサイズを試算してみる
count++;
gpu_power = (unit_size + count - 1) / count;
gpu_power = (gpu_power + (MEM_UNIT - 1)) & ~(MEM_UNIT - 1); // MEM_UNITの倍数にする
}
if (count > 1){
*chunk_size = gpu_power;
OpenCL_method = 3;
#ifdef DEBUG_OUTPUT
printf("gpu cache: limit size = %d, chunk size = %d, split = %d\n", j, gpu_power, count);
#endif
}
/*
// 32バイト単位のメモリーアクセスならキャッシュする必要なし計算速度が半減する・・・
} else if ((cache_size & 0x3FFFFFFF) > OpenCL_group_num * 4096){ // 2KB の倍はいるかも?
#ifdef DEBUG_OUTPUT
printf("gpu: cache size = %d, read size = %d\n", cache_size & 0x3FFFFFFF, OpenCL_group_num * 2048);
#endif
OpenCL_method = 1;
*/
}
} else if (((cpu_flag & 128) != 0) && (sse_unit == 256)){
OpenCL_method = 4; // JIT(SSE2) は bit ごとに上位から 16バイトずつ並ぶ
// ローカルのテーブルサイズが異なることに注意
// XOR 方式以外は 2KB (4バイト * 256項目 * 2個) 使う
// XOR (JIT) は 64バイト (4バイト * 16項目) 使う
#ifdef DEBUG_OUTPUT
// printf("4 KB cache (16-bytes * 256 work items), use if\n");
#endif
} else {
OpenCL_method = 0; // MMX用のコードは遅いので、キャッシュ最適化する必要が無い
}
// work group 数が必要以上に多い場合は減らす
/*
if (OpenCL_method == 4){
// work item 一個が 16バイトずつ計算する、256個なら work group ごとに 4KB 担当する
data_size = unit_size / 4096;
} else
*/
if (OpenCL_method & 2){
// work item 一個が 8バイトずつ計算する、256個なら work group ごとに 2KB 担当する
data_size = unit_size / 2048;
} else {
// work item 一個が 4バイトずつ計算する、256個なら work group ごとに 1KB 担当する
data_size = unit_size / 1024;
}
if (OpenCL_group_num > data_size){
OpenCL_group_num = data_size;
printf("Number of work groups is reduced to %d\n", (int)OpenCL_group_num);
}
// 最大で何ブロック分のメモリー領域を保持できるのか(ここではまだ確保しない)
// 後で実際に確保する量はこれよりも少なくなる
count = (int)(alloc_max / unit_size); // 確保できるメモリー量から逆算する
if (*src_max > count)
*src_max = count; // 指定されたソース・ブロックの個数が無理なら減らす
#ifdef DEBUG_OUTPUT
data_size = (size_t)unit_size * count;
printf("src buf : %d KB (%d blocks), possible\n", data_size >> 10, count);
#endif
// 出力先は1ブロック分だけあればいい
// CL_MEM_ALLOC_HOST_PTRを使えばpinned memoryになるらしい
data_size = unit_size;
OpenCL_dst = gfn_clCreateBuffer(OpenCL_context, CL_MEM_WRITE_ONLY | CL_MEM_ALLOC_HOST_PTR, data_size, NULL, &ret);
if (ret != CL_SUCCESS)
return (ret << 8) | 13;
#ifdef DEBUG_OUTPUT
printf("dst buf : %d KB (%d Bytes), OK\n", data_size >> 10, data_size);
#endif
// factor は最大個数分 (src_max個)
data_size = sizeof(unsigned short) * (*src_max);
OpenCL_buf = gfn_clCreateBuffer(OpenCL_context, CL_MEM_READ_ONLY, data_size, NULL, &ret);
if (ret != CL_SUCCESS)
return (ret << 8) | 14;
#ifdef DEBUG_OUTPUT
printf("factor buf : %d Bytes (%d factors), OK\n", data_size, (*src_max));
#endif
/*
// テキスト形式の OpenCL C ソース・コードを読み込む
err = 4;
fp = fopen("source.cl", "r");
if (fp == NULL){
printf("cannot open source code file\n");
return err;
}
ret = fseek(fp, 0, SEEK_END);
if (ret != 0){
printf("cannot read source code file\n");
fclose(fp);
return err;
}
data_size = ftell(fp);
ret = fseek(fp, 0, SEEK_SET);
if (ret != 0){
printf("cannot read source code file\n");
fclose(fp);
return err;
}
if (data_size > 102400){ // 100 KB まで
fclose(fp);
printf("source code file is too large\n");
return err;
}
p_source = (char *)malloc(data_size + 1);
if (p_source == NULL){
fclose(fp);
printf("malloc error\n");
return err;
}
data_size = fread(p_source, 1, data_size, fp);
fclose(fp);
printf("Source code length = %d characters\n", data_size);
p_source[data_size] = 0; // 末尾を null 文字にする
// プログラムを作成する
program = fn_clCreateProgramWithSource(OpenCL_context, 1, (char **)&p_source, NULL, &ret);
if (ret != CL_SUCCESS){
free(p_source);
return (ret << 8) | 20;
}
free(p_source); // もうテキストは要らないので開放しておく
*/
// リソースから OpenCL C ソース・コードを読み込む
err = 4;
// Referred to "Embedding OpenCL Kernel Files in the Application on Windows"
res = FindResource(NULL, L"#1", L"RT_STRING"); // find the resource
if (res == NULL){
//printf("cannot find resource\n");
return err;
}
glob = LoadResource(NULL, res); // load the resource.
if (glob == NULL){
//printf("cannot load resource\n");
return err;
}
p_source = (char *)LockResource(glob); // lock the resource to get a char*
if (res == NULL){
//printf("cannot lock resource\n");
return err;
}
data_size = SizeofResource(NULL, res);
if (data_size == 0){
//printf("cannot get size of resource\n");
return err;
}
//printf("Source code length = %d characters\n", data_size);
// プログラムを作成する
program = fn_clCreateProgramWithSource(OpenCL_context, 1, (char **)&p_source, &data_size, &ret);
if (ret != CL_SUCCESS)
return (ret << 8) | 20;
FreeResource(glob); // not required ?
// 定数を指定する
wsprintfA(buf, "-D BLK_SIZE=%d -D CHK_SIZE=%d", unit_size / 4, gpu_power / 4);
// 使用する OpenCL デバイス用にコンパイルする
ret = fn_clBuildProgram(program, 1, &selected_device, buf, NULL, NULL);
if (ret != CL_SUCCESS){
#ifdef DEBUG_OUTPUT
buf[0] = 0;
printf("clBuildProgram : Failed\n");
if (fn_clGetProgramBuildInfo(program, selected_device, CL_PROGRAM_BUILD_LOG, sizeof(buf), buf, NULL) == CL_SUCCESS)
printf("%s\n", buf);
#endif
return (ret << 8) | 21;
}
// カーネル関数を抽出する
wsprintfA(buf, "method%d", OpenCL_method & 7);
OpenCL_kernel = fn_clCreateKernel(program, buf, &ret);
if (ret != CL_SUCCESS)
return (ret << 8) | 22;
#ifdef DEBUG_OUTPUT
printf("CreateKernel : %s\n", buf);
#endif
// カーネルが実行できる work item 数を調べる
ret = fn_clGetKernelWorkGroupInfo(OpenCL_kernel, NULL, CL_KERNEL_WORK_GROUP_SIZE, sizeof(size_t), &data_size, NULL);
if ((ret == CL_SUCCESS) && (data_size < 256)){ // 最低でも 256以上は必要
#ifdef DEBUG_OUTPUT
printf("KERNEL_WORK_GROUP_SIZE = %d\n", data_size);
#endif
return (ret << 8) | 23;
}
// プログラムを破棄する
ret = fn_clReleaseProgram(program);
if (ret != CL_SUCCESS)
return (ret << 8) | 24;
// これ以上コンパイルしない
if (fn_clUnloadPlatformCompiler != NULL){ // OpenCL 1.2 なら
fn_clUnloadPlatformCompiler(selected_platform);
} else { // OpenCL 1.1 なら
fn_clUnloadCompiler();
}
// カーネル引数を指定する
ret = gfn_clSetKernelArg(OpenCL_kernel, 1, sizeof(cl_mem), &OpenCL_dst);
if (ret != CL_SUCCESS)
return (ret << 8) | 101;
ret = gfn_clSetKernelArg(OpenCL_kernel, 2, sizeof(cl_mem), &OpenCL_buf);
if (ret != CL_SUCCESS)
return (ret << 8) | 102;
if (ret != CL_SUCCESS)
return (ret << 8) | 103;
#ifdef DEBUG_OUTPUT
// ワークアイテム数
printf("\nMax number of work items = %d (256 * %d)\n", OpenCL_group_num * 256, OpenCL_group_num);
#endif
return 0;
}
int free_OpenCL(void)
{
API_clReleaseContext fn_clReleaseContext;
API_clReleaseCommandQueue fn_clReleaseCommandQueue;
API_clReleaseKernel fn_clReleaseKernel;
int err = 0; // 最初のエラーだけ記録する
cl_int ret;
if (hLibOpenCL == NULL)
return 0;
// OpenCL 関連のリソースを開放する
if (OpenCL_command != NULL){
// 動作中なら終了するのを待つ
ret = gfn_clFinish(OpenCL_command);
if ((err == 0) && (ret != CL_SUCCESS))
err = (ret << 8) | 1;
if (OpenCL_buf != NULL){
ret = gfn_clReleaseMemObject(OpenCL_buf);
if ((err == 0) && (ret != CL_SUCCESS))
err = (ret << 8) | 10;
OpenCL_buf = NULL;
}
if (OpenCL_src != NULL){
ret = gfn_clReleaseMemObject(OpenCL_src);
if ((err == 0) && (ret != CL_SUCCESS))
err = (ret << 8) | 11;
OpenCL_src = NULL;
}
if (OpenCL_dst != NULL){
ret = gfn_clReleaseMemObject(OpenCL_dst);
if ((err == 0) && (ret != CL_SUCCESS))
err = (ret << 8) | 12;
OpenCL_dst = NULL;
}
if (OpenCL_kernel != NULL){
fn_clReleaseKernel = (API_clReleaseKernel)GetProcAddress(hLibOpenCL, "clReleaseKernel");
if (fn_clReleaseKernel != NULL){
ret = fn_clReleaseKernel(OpenCL_kernel);
OpenCL_kernel = NULL;
} else {
ret = 1;
}
if ((err == 0) && (ret != CL_SUCCESS))
err = (ret << 8) | 3;
}
fn_clReleaseCommandQueue = (API_clReleaseCommandQueue)GetProcAddress(hLibOpenCL, "clReleaseCommandQueue");
if (fn_clReleaseCommandQueue != NULL){
ret = fn_clReleaseCommandQueue(OpenCL_command);
OpenCL_command = NULL;
} else {
ret = 1;
}
if ((err == 0) && (ret != CL_SUCCESS))
err = (ret << 8) | 4;
}
if (OpenCL_context != NULL){
fn_clReleaseContext = (API_clReleaseContext)GetProcAddress(hLibOpenCL, "clReleaseContext");
if (fn_clReleaseContext != NULL){
ret = fn_clReleaseContext(OpenCL_context);
OpenCL_context = NULL;
} else {
ret = 1;
}
if ((err == 0) && (ret != CL_SUCCESS))
err = (ret << 8) | 5;
}
FreeLibrary(hLibOpenCL);
hLibOpenCL = NULL;
return err;
}
void info_OpenCL(char *buf, int buf_size)
{
API_clGetContextInfo fn_clGetContextInfo;
API_clGetDeviceInfo fn_clGetDeviceInfo;
cl_int ret;
if ((hLibOpenCL == NULL) || (OpenCL_context == NULL))
return;
fn_clGetContextInfo = (API_clGetContextInfo)GetProcAddress(hLibOpenCL, "clGetContextInfo");
fn_clGetDeviceInfo = (API_clGetDeviceInfo)GetProcAddress(hLibOpenCL, "clGetDeviceInfo");
if ((fn_clGetContextInfo != NULL) && (fn_clGetDeviceInfo != NULL)){
cl_device_id device_id;
ret = fn_clGetContextInfo(OpenCL_context, CL_CONTEXT_DEVICES, sizeof(cl_device_id), &device_id, NULL);
if (ret == CL_SUCCESS){
ret = fn_clGetDeviceInfo(device_id, CL_DEVICE_NAME, buf_size / 2, buf, NULL);
if (ret == CL_SUCCESS){
ret = fn_clGetDeviceInfo(device_id, CL_DEVICE_VERSION, buf_size / 2, buf + buf_size / 2, NULL);
if (ret != CL_SUCCESS)
buf[buf_size / 2] = 0;
printf("\nOpenCL : %s, %s, 256*%d\n", buf, buf + buf_size / 2, (int)OpenCL_group_num);
}
}
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// ソース・ブロックをデバイス側にコピーする
int gpu_copy_blocks(
unsigned char *data, // ( 4096)
int unit_size, // 4096の倍数にすること
int src_num) // 何ブロックをコピーするのか
{
size_t data_size;
cl_int ret;
// Integrated GPU と Discrete GPU の違いに関係なく、使う分だけ毎回メモリー領域を確保する
data_size = (size_t)unit_size * src_num;
// Intel GPUならZeroCopyできる、GeForce GPUでもメモリー消費量が少なくてコピーが速い
OpenCL_src = gfn_clCreateBuffer(OpenCL_context, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, data_size, data, &ret);
if (ret != CL_SUCCESS)
return (ret << 8) | 1;
#ifdef DEBUG_OUTPUT
//printf("refer buf : %d KB (%d blocks), OK\n", data_size >> 10, src_num);
#endif
// メモリー領域を指定する
ret = gfn_clSetKernelArg(OpenCL_kernel, 0, sizeof(cl_mem), &OpenCL_src);
if (ret != CL_SUCCESS)
return (ret << 8) | 100;
return 0;
}
// ソース・ブロックを掛け算する
int gpu_multiply_blocks(
int src_num, // Number of multiplying source blocks
unsigned short *mat, // Matrix of numbers to multiply by
unsigned char *buf, // Products go here
int len) // Byte length
{
unsigned int *vram, *src, *dst;
size_t global_size, local_size;
cl_int ret;
// 倍率の配列をデバイス側に書き込む
ret = gfn_clEnqueueWriteBuffer(OpenCL_command, OpenCL_buf, CL_FALSE, 0, sizeof(short) * src_num, mat, 0, NULL, NULL);
if (ret != CL_SUCCESS)
return (ret << 8) | 10;
// 引数を指定する
ret = gfn_clSetKernelArg(OpenCL_kernel, 3, sizeof(int), &src_num);
if (ret != CL_SUCCESS)
return (ret << 8) | 103;
// カーネル並列実行
local_size = 256; // テーブルやキャッシュのため、work item 数は 256に固定する
global_size = OpenCL_group_num * 256;
//printf("group num = %d, global size = %d, local size = 256 \n", OpenCL_group_num, global_size);
ret = gfn_clEnqueueNDRangeKernel(OpenCL_command, OpenCL_kernel, 1, NULL, &global_size, &local_size, 0, NULL, NULL);
if (ret != CL_SUCCESS)
return (ret << 8) | 11;
// 出力内容をホスト側に反映させる
vram = gfn_clEnqueueMapBuffer(OpenCL_command, OpenCL_dst, CL_TRUE, CL_MAP_READ, 0, len, 0, NULL, NULL, &ret);
if (ret != CL_SUCCESS)
return (ret << 8) | 12;
// 4バイトごとに XOR する (SSE2 で XOR しても速くならず)
src = vram;
dst = (unsigned int *)buf;
while (len > 0){
*dst ^= *src;
dst++;
src++;
len -= 4;
}
// ホスト側でデータを変更しなくても、clEnqueueMapBufferと対で呼び出さないといけない
ret = gfn_clEnqueueUnmapMemObject(OpenCL_command, OpenCL_dst, vram, 0, NULL, NULL);
if (ret != CL_SUCCESS)
return (ret << 8) | 13;
return 0;
}
// 確保したVRAMとメモリーを解放する
int gpu_finish(void)
{
cl_int ret;
// 全ての処理が終わるのを待つ
ret = gfn_clFinish(OpenCL_command);
if (ret != CL_SUCCESS)
return (ret << 8) | 20;
if (OpenCL_src != NULL){ // 確保されてる場合は解除する
ret = gfn_clReleaseMemObject(OpenCL_src);
if (ret != CL_SUCCESS)
return (ret << 8) | 21;
OpenCL_src = NULL;
}
return 0;
}

34
source/par2j/lib_opencl.h Normal file
View File

@@ -0,0 +1,34 @@
#ifndef _OPENCL_H_
#define _OPENCL_H_
#ifdef __cplusplus
extern "C" {
#endif
// IntelやAMDのGPUでZeroCopyするにはメモリー境界をこの値にしないといけない
#define MEM_UNIT 4096
extern int OpenCL_method;
int init_OpenCL(int unit_size, int *src_max, int *chunk_size);
int free_OpenCL(void);
void info_OpenCL(char *buf, int buf_size);
int gpu_copy_blocks(
unsigned char *data,
int unit_size,
int src_end);
int gpu_multiply_blocks(
int src_num, // Number of multiplying source blocks
unsigned short *mat, // Matrix of numbers to multiply by
unsigned char *buf, // Products go here
int len); // Byte length
int gpu_finish(void);
#ifdef __cplusplus
}
#endif
#endif

1241
source/par2j/list.c Normal file

File diff suppressed because it is too large Load Diff

48
source/par2j/list.h Normal file
View File

@@ -0,0 +1,48 @@
#ifndef _LIST_H_
#define _LIST_H_
#ifdef __cplusplus
extern "C" {
#endif
// ソース・ファイルを検査せずに一覧を表示する
int list_file_data(
char *ascii_buf, // 作業用
file_ctx_r *files); // 各ソース・ファイルの情報
// ソース・ファイルが完全かどうかを一覧表示する
int check_file_complete(
char *ascii_buf,
wchar_t *file_path, // 作業用
file_ctx_r *files, // 各ソース・ファイルの情報
source_ctx_r *s_blk); // 各ソース・ブロックの情報
int check_file_complete_multi(
char *ascii_buf,
wchar_t *file_path, // 作業用
file_ctx_r *files, // 各ソース・ファイルの情報
source_ctx_r *s_blk); // 各ソース・ブロックの情報
// ソース・ファイルが不完全なら別名・移動ファイルを探す
int search_misnamed_file(
char *ascii_buf,
wchar_t *file_path, // 作業用
file_ctx_r *files, // 各ソース・ファイルの情報
source_ctx_r *s_blk); // 各ソース・ブロックの情報
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// 破損・分割・類似名のファイルから使えるスライスを探す
int search_file_slice(
char *ascii_buf, // 作業用
wchar_t *file_path, // 作業用
file_ctx_r *files, // 各ソース・ファイルの情報
source_ctx_r *s_blk); // 各ソース・ブロックの情報
#ifdef __cplusplus
}
#endif
#endif

1979
source/par2j/md5_crc.c Normal file

File diff suppressed because it is too large Load Diff

128
source/par2j/md5_crc.h Normal file
View File

@@ -0,0 +1,128 @@
#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 ハッシュ値を求める
void data_md5_block(
unsigned char *data_in, // ハッシュ値を求めるバイト配列
unsigned int data_len, // 入力バイト数
unsigned char *hash); // ハッシュ値 16バイト
// ファイルの MD5-16k ハッシュ値を求める
int file_md5_16(
wchar_t *file_path, // ハッシュ値を求めるファイル
unsigned char *hash); // ファイルの先頭 16KB 分のハッシュ値 (16バイト)
// ファイルの指定部分の MD5 ハッシュ値を求める
int file_md5(
HANDLE hFileRead, // ハッシュ値を求めるファイルのハンドル
__int64 offset,
unsigned int data_len, // 入力バイト数
unsigned char *hash); // ハッシュ値 (16バイト)
/*------------------ 以下は MD5 と CRC-32 の組合せ関数 ------------------*/
// 内容が全て 0 のデータの MD5 ハッシュ値と CRC-32 を求める
void data_md5_crc32_zero(
unsigned char *hash); // ハッシュ値 (16 + 4バイト, MD5 + CRC-32)
// 2GB 未満のファイルの開始位置以降のハッシュ値を計算する
unsigned int file_crc_part(HANDLE hFile);
// ファイルの offset バイト目からブロック・サイズ分の MD5 と CRC-32 を求める
int file_md5_crc32_block(
HANDLE hFileRead, // MD5 と CRC を求めるファイルのハンドル
__int64 offset,
unsigned int avail_size, // 入力バイト数
unsigned char *hash); // ハッシュ値 (16 + 4バイト, MD5 + CRC-32)
// ファイルのハッシュ値と各スライスのチェックサムを同時に計算する
int file_hash_crc(
wchar_t *file_name, // ハッシュ値を求めるファイル
__int64 file_left,
unsigned char *hash, // (16)
unsigned char *sum, // チェックサム (MD5 + CRC-32) の配列
unsigned int *time_last, // 前回に経過表示した時刻
__int64 *prog_now); // 経過表示での現在位置
typedef struct {
wchar_t *file_name;
__int64 file_size;
unsigned char *hash;
unsigned char *sum;
unsigned int *crc;
volatile int loop;
} FILE_HASH_TH;
DWORD WINAPI file_hash_crc2(LPVOID lpParameter);
// ファイルのハッシュ値が同じか調べる (全てのスライスのチェックサムも)
int file_hash_check(
int num, // file_ctx におけるファイル番号
wchar_t *file_name, // 表示するファイル名
HANDLE hFile, // ファイルのハンドル
int prog_min, // ()
file_ctx_r *files, // 各ソース・ファイルの情報
source_ctx_r *s_blk); // 各ソース・ブロックの情報 (NULL なら比較しない)
typedef struct {
HANDLE hFile;
file_ctx_r *files;
source_ctx_r *s_blk;
int num;
volatile int rv;
volatile int flag;
unsigned int meta[7];
} FILE_CHECK_TH;
DWORD WINAPI file_hash_background(LPVOID lpParameter);
// キャッシュ無しでファイルのハッシュ値が同じか調べる
int file_hash_direct(
int num, // file_ctx におけるファイル番号
wchar_t *file_path, // ハッシュ値を求めるファイル
wchar_t *file_name, // 表示するファイル名
file_ctx_r *files, // 各ソース・ファイルの情報
source_ctx_r *s_blk); // 各ソース・ブロックの情報 (NULL なら比較しない)
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// CRC-32 を使って 1バイト内のバースト・エラーを訂正する
// 全て 0 のデータの判定は他で行うこと
int correct_error(
unsigned char *data_in, // ハッシュ値を求めたバイト配列
unsigned int data_len, // 入力バイト数
unsigned char *hash, // (16, MD5)
unsigned int orig_crc, // 入力バイト数分の CRC-32
unsigned int *error_off, // エラー開始位置
unsigned char *error_mag); // エラー内容、XORでエラー訂正を取り消せる
// CRC-32 を使って 1バイト内のバースト・エラーを訂正する
// CRC-32 は既に計算済み、エラー無しも比較済み
int correct_error2(
unsigned char *data_in, // ハッシュ値を求めたバイト配列
unsigned int data_len, // 入力バイト数
unsigned int data_crc, // 入力バイト数分の CRC-32
unsigned char *hash, // (16, MD5)
unsigned int crc, // 入力バイト数分の CRC-32
unsigned int *error_off, // エラー開始位置
unsigned char *error_mag); // エラー内容、XORでエラー訂正を取り消せる
#ifdef __cplusplus
}
#endif
#endif