|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h> |
|
|
#include <stdlib.h> |
|
|
#include <string.h> |
|
|
#include <windows.h> |
|
|
|
|
|
|
|
|
typedef void* BCRYPT_ALG_HANDLE; |
|
|
typedef void* BCRYPT_KEY_HANDLE; |
|
|
typedef long NTSTATUS; |
|
|
|
|
|
typedef NTSTATUS (*fn_BCryptOpenAlgorithmProvider)(BCRYPT_ALG_HANDLE*, const wchar_t*, const wchar_t*, unsigned long); |
|
|
typedef NTSTATUS (*fn_BCryptSetProperty)(BCRYPT_ALG_HANDLE, const wchar_t*, unsigned char*, unsigned long, unsigned long); |
|
|
typedef NTSTATUS (*fn_BCryptGenerateSymmetricKey)(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE*, unsigned char*, unsigned long, unsigned char*, unsigned long, unsigned long); |
|
|
typedef NTSTATUS (*fn_BCryptEncrypt)(BCRYPT_KEY_HANDLE, unsigned char*, unsigned long, void*, unsigned char*, unsigned long, unsigned char*, unsigned long, unsigned long*, unsigned long); |
|
|
typedef NTSTATUS (*fn_BCryptDecrypt)(BCRYPT_KEY_HANDLE, unsigned char*, unsigned long, void*, unsigned char*, unsigned long, unsigned char*, unsigned long, unsigned long*, unsigned long); |
|
|
typedef NTSTATUS (*fn_BCryptCloseAlgorithmProvider)(BCRYPT_ALG_HANDLE, unsigned long); |
|
|
typedef NTSTATUS (*fn_BCryptDestroyKey)(BCRYPT_KEY_HANDLE); |
|
|
|
|
|
|
|
|
typedef long long (*fn_CreateOcrInitOptions)(long long*); |
|
|
typedef long long (*fn_OcrInitOptionsSetUseModelDelayLoad)(long long, char); |
|
|
typedef long long (*fn_CreateOcrPipeline)(const char*, const char*, long long, long long*); |
|
|
typedef void (*fn_ReleaseOcrInitOptions)(long long); |
|
|
typedef void (*fn_ReleaseOcrPipeline)(long long); |
|
|
|
|
|
static void test_file_access(const char* dll_dir) { |
|
|
printf("\n=== TEST 1: File Access ===\n"); |
|
|
|
|
|
char model_path[MAX_PATH]; |
|
|
snprintf(model_path, sizeof(model_path), "%s\\oneocr.onemodel", dll_dir); |
|
|
|
|
|
|
|
|
HANDLE hFile = CreateFileA(model_path, GENERIC_READ, FILE_SHARE_READ, NULL, |
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
|
|
if (hFile == INVALID_HANDLE_VALUE) { |
|
|
printf(" FAIL: Cannot open model file: %s (error %lu)\n", model_path, GetLastError()); |
|
|
|
|
|
|
|
|
printf(" Trying alternate paths...\n"); |
|
|
char alt1[MAX_PATH]; |
|
|
snprintf(alt1, sizeof(alt1), "%s/oneocr.onemodel", dll_dir); |
|
|
hFile = CreateFileA(alt1, GENERIC_READ, FILE_SHARE_READ, NULL, |
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
|
|
if (hFile != INVALID_HANDLE_VALUE) { |
|
|
printf(" OK with forward slashes: %s\n", alt1); |
|
|
} else { |
|
|
printf(" FAIL with forward slashes too (error %lu)\n", GetLastError()); |
|
|
} |
|
|
} |
|
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE) { |
|
|
LARGE_INTEGER size; |
|
|
GetFileSizeEx(hFile, &size); |
|
|
printf(" OK: Model file opened. Size: %lld bytes (%.1f MB)\n", |
|
|
size.QuadPart, size.QuadPart / 1e6); |
|
|
|
|
|
if (size.QuadPart < 1000000) { |
|
|
|
|
|
char buf[200] = {0}; |
|
|
DWORD read = 0; |
|
|
ReadFile(hFile, buf, 100, &read, NULL); |
|
|
if (strstr(buf, "version https://git-lfs") != NULL) { |
|
|
printf(" *** WARNING: File is a Git LFS POINTER, not actual data! ***\n"); |
|
|
printf(" Content: %s\n", buf); |
|
|
printf(" Run: git lfs pull\n"); |
|
|
} else { |
|
|
printf(" WARNING: File seems too small for a model!\n"); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
SetFilePointer(hFile, 0, NULL, FILE_BEGIN); |
|
|
unsigned char header[16]; |
|
|
DWORD bytesRead = 0; |
|
|
ReadFile(hFile, header, 16, &bytesRead, NULL); |
|
|
printf(" Header (first 16 bytes): "); |
|
|
for (int i = 0; i < 16; i++) printf("%02x ", header[i]); |
|
|
printf("\n"); |
|
|
|
|
|
CloseHandle(hFile); |
|
|
} |
|
|
|
|
|
|
|
|
char dll_path[MAX_PATH], ort_path[MAX_PATH]; |
|
|
snprintf(dll_path, sizeof(dll_path), "%s\\oneocr.dll", dll_dir); |
|
|
snprintf(ort_path, sizeof(ort_path), "%s\\onnxruntime.dll", dll_dir); |
|
|
|
|
|
HANDLE h1 = CreateFileA(dll_path, GENERIC_READ, FILE_SHARE_READ, NULL, |
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
|
|
if (h1 != INVALID_HANDLE_VALUE) { |
|
|
LARGE_INTEGER s; GetFileSizeEx(h1, &s); |
|
|
printf(" OK: oneocr.dll exists (%.1f MB)\n", s.QuadPart/1e6); |
|
|
CloseHandle(h1); |
|
|
} else { |
|
|
printf(" FAIL: oneocr.dll not found at %s (error %lu)\n", dll_path, GetLastError()); |
|
|
} |
|
|
|
|
|
HANDLE h2 = CreateFileA(ort_path, GENERIC_READ, FILE_SHARE_READ, NULL, |
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); |
|
|
if (h2 != INVALID_HANDLE_VALUE) { |
|
|
LARGE_INTEGER s; GetFileSizeEx(h2, &s); |
|
|
printf(" OK: onnxruntime.dll exists (%.1f MB)\n", s.QuadPart/1e6); |
|
|
CloseHandle(h2); |
|
|
} else { |
|
|
printf(" FAIL: onnxruntime.dll not found at %s (error %lu)\n", ort_path, GetLastError()); |
|
|
} |
|
|
} |
|
|
|
|
|
static void test_dll_loading(const char* dll_dir) { |
|
|
printf("\n=== TEST 2: DLL Loading ===\n"); |
|
|
|
|
|
SetDllDirectoryA(dll_dir); |
|
|
|
|
|
|
|
|
char ort_path[MAX_PATH]; |
|
|
snprintf(ort_path, sizeof(ort_path), "%s\\onnxruntime.dll", dll_dir); |
|
|
HMODULE hort = LoadLibraryA(ort_path); |
|
|
if (hort) { |
|
|
printf(" OK: onnxruntime.dll loaded\n"); |
|
|
FreeLibrary(hort); |
|
|
} else { |
|
|
printf(" FAIL: onnxruntime.dll LoadLibrary error %lu\n", GetLastError()); |
|
|
} |
|
|
|
|
|
|
|
|
char dll_path[MAX_PATH]; |
|
|
snprintf(dll_path, sizeof(dll_path), "%s\\oneocr.dll", dll_dir); |
|
|
HMODULE hmod = LoadLibraryA(dll_path); |
|
|
if (hmod) { |
|
|
printf(" OK: oneocr.dll loaded\n"); |
|
|
|
|
|
|
|
|
const char* exports[] = { |
|
|
"CreateOcrInitOptions", "CreateOcrPipeline", "RunOcrPipeline", |
|
|
"ReleaseOcrResult", "ReleaseOcrPipeline", NULL |
|
|
}; |
|
|
for (int i = 0; exports[i]; i++) { |
|
|
void* fn = GetProcAddress(hmod, exports[i]); |
|
|
printf(" %s %s\n", fn ? " OK:" : " FAIL:", exports[i]); |
|
|
} |
|
|
FreeLibrary(hmod); |
|
|
} else { |
|
|
printf(" FAIL: oneocr.dll LoadLibrary error %lu\n", GetLastError()); |
|
|
} |
|
|
} |
|
|
|
|
|
static void test_bcrypt_cfb(void) { |
|
|
printf("\n=== TEST 3: bcrypt AES-256-CFB128 ===\n"); |
|
|
|
|
|
HMODULE hbcrypt = LoadLibraryA("bcrypt.dll"); |
|
|
if (!hbcrypt) { |
|
|
printf(" FAIL: Cannot load bcrypt.dll (error %lu)\n", GetLastError()); |
|
|
return; |
|
|
} |
|
|
printf(" OK: bcrypt.dll loaded\n"); |
|
|
|
|
|
fn_BCryptOpenAlgorithmProvider pOpen = (fn_BCryptOpenAlgorithmProvider)GetProcAddress(hbcrypt, "BCryptOpenAlgorithmProvider"); |
|
|
fn_BCryptSetProperty pSetProp = (fn_BCryptSetProperty)GetProcAddress(hbcrypt, "BCryptSetProperty"); |
|
|
fn_BCryptGenerateSymmetricKey pGenKey = (fn_BCryptGenerateSymmetricKey)GetProcAddress(hbcrypt, "BCryptGenerateSymmetricKey"); |
|
|
fn_BCryptDecrypt pDecrypt = (fn_BCryptDecrypt)GetProcAddress(hbcrypt, "BCryptDecrypt"); |
|
|
fn_BCryptCloseAlgorithmProvider pClose = (fn_BCryptCloseAlgorithmProvider)GetProcAddress(hbcrypt, "BCryptCloseAlgorithmProvider"); |
|
|
fn_BCryptDestroyKey pDestroy = (fn_BCryptDestroyKey)GetProcAddress(hbcrypt, "BCryptDestroyKey"); |
|
|
|
|
|
if (!pOpen || !pSetProp || !pGenKey || !pDecrypt) { |
|
|
printf(" FAIL: Missing bcrypt functions\n"); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
BCRYPT_ALG_HANDLE hAlg = NULL; |
|
|
NTSTATUS status = pOpen(&hAlg, L"AES", NULL, 0); |
|
|
printf(" BCryptOpenAlgorithmProvider(AES): 0x%08lx %s\n", status, status == 0 ? "OK" : "FAIL"); |
|
|
if (status != 0) return; |
|
|
|
|
|
|
|
|
wchar_t cfb[] = L"ChainingModeCFB"; |
|
|
status = pSetProp(hAlg, L"ChainingMode", (unsigned char*)cfb, sizeof(cfb), 0); |
|
|
printf(" BCryptSetProperty(ChainingModeCFB): 0x%08lx %s\n", status, status == 0 ? "OK" : "FAIL"); |
|
|
|
|
|
if (status != 0) { |
|
|
printf(" *** CFB MODE NOT SUPPORTED IN THIS WINE VERSION! ***\n"); |
|
|
printf(" This is likely the root cause of error 6.\n"); |
|
|
printf(" Trying CBC mode instead...\n"); |
|
|
wchar_t cbc[] = L"ChainingModeCBC"; |
|
|
status = pSetProp(hAlg, L"ChainingMode", (unsigned char*)cbc, sizeof(cbc), 0); |
|
|
printf(" BCryptSetProperty(ChainingModeCBC): 0x%08lx %s\n", status, status == 0 ? "OK" : "FAIL"); |
|
|
|
|
|
printf(" Trying ECB mode...\n"); |
|
|
wchar_t ecb[] = L"ChainingModeECB"; |
|
|
status = pSetProp(hAlg, L"ChainingMode", (unsigned char*)ecb, sizeof(ecb), 0); |
|
|
printf(" BCryptSetProperty(ChainingModeECB): 0x%08lx %s\n", status, status == 0 ? "OK" : "FAIL"); |
|
|
|
|
|
printf(" Trying GCM mode...\n"); |
|
|
wchar_t gcm[] = L"ChainingModeGCM"; |
|
|
status = pSetProp(hAlg, L"ChainingMode", (unsigned char*)gcm, sizeof(gcm), 0); |
|
|
printf(" BCryptSetProperty(ChainingModeGCM): 0x%08lx %s\n", status, status == 0 ? "OK" : "FAIL"); |
|
|
} |
|
|
|
|
|
if (status == 0) { |
|
|
|
|
|
unsigned char test_key[32] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08, |
|
|
0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10, |
|
|
0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18, |
|
|
0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20}; |
|
|
BCRYPT_KEY_HANDLE hKey = NULL; |
|
|
status = pGenKey(hAlg, &hKey, NULL, 0, test_key, 32, 0); |
|
|
printf(" BCryptGenerateSymmetricKey: 0x%08lx %s\n", status, status == 0 ? "OK" : "FAIL"); |
|
|
|
|
|
if (status == 0 && hKey) { |
|
|
|
|
|
unsigned char iv[16] = {0}; |
|
|
unsigned char ciphertext[16] = {0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48, |
|
|
0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50}; |
|
|
unsigned char plaintext[16] = {0}; |
|
|
unsigned long cbResult = 0; |
|
|
status = pDecrypt(hKey, ciphertext, 16, NULL, iv, 16, plaintext, 16, &cbResult, 0); |
|
|
printf(" BCryptDecrypt: 0x%08lx %s (decrypted %lu bytes)\n", |
|
|
status, status == 0 ? "OK" : "FAIL", cbResult); |
|
|
if (hKey) pDestroy(hKey); |
|
|
} |
|
|
} |
|
|
|
|
|
pClose(hAlg, 0); |
|
|
FreeLibrary(hbcrypt); |
|
|
} |
|
|
|
|
|
static void test_pipeline(const char* dll_dir, const char* key_hex) { |
|
|
printf("\n=== TEST 4: CreateOcrPipeline ===\n"); |
|
|
|
|
|
SetDllDirectoryA(dll_dir); |
|
|
|
|
|
char dll_path[MAX_PATH]; |
|
|
snprintf(dll_path, sizeof(dll_path), "%s\\oneocr.dll", dll_dir); |
|
|
|
|
|
HMODULE hmod = LoadLibraryA(dll_path); |
|
|
if (!hmod) { |
|
|
printf(" FAIL: LoadLibrary failed: %lu\n", GetLastError()); |
|
|
return; |
|
|
} |
|
|
|
|
|
fn_CreateOcrInitOptions pCreateInit = (fn_CreateOcrInitOptions)GetProcAddress(hmod, "CreateOcrInitOptions"); |
|
|
fn_OcrInitOptionsSetUseModelDelayLoad pSetDelay = (fn_OcrInitOptionsSetUseModelDelayLoad)GetProcAddress(hmod, "OcrInitOptionsSetUseModelDelayLoad"); |
|
|
fn_CreateOcrPipeline pCreatePipeline = (fn_CreateOcrPipeline)GetProcAddress(hmod, "CreateOcrPipeline"); |
|
|
fn_ReleaseOcrInitOptions pRelInit = (fn_ReleaseOcrInitOptions)GetProcAddress(hmod, "ReleaseOcrInitOptions"); |
|
|
fn_ReleaseOcrPipeline pRelPipeline = (fn_ReleaseOcrPipeline)GetProcAddress(hmod, "ReleaseOcrPipeline"); |
|
|
|
|
|
if (!pCreateInit || !pCreatePipeline) { |
|
|
printf(" FAIL: Missing functions\n"); |
|
|
return; |
|
|
} |
|
|
|
|
|
|
|
|
long long init_opts = 0; |
|
|
long long res = pCreateInit(&init_opts); |
|
|
printf(" CreateOcrInitOptions: %lld %s\n", res, res == 0 ? "OK" : "FAIL"); |
|
|
|
|
|
if (pSetDelay) { |
|
|
|
|
|
res = pSetDelay(init_opts, 1); |
|
|
printf(" OcrInitOptionsSetUseModelDelayLoad(1): %lld %s\n", res, res == 0 ? "OK" : "FAIL"); |
|
|
} |
|
|
|
|
|
|
|
|
char model_path[MAX_PATH]; |
|
|
snprintf(model_path, sizeof(model_path), "%s\\oneocr.onemodel", dll_dir); |
|
|
printf(" Model path: %s\n", model_path); |
|
|
|
|
|
int key_len = strlen(key_hex) / 2; |
|
|
char key[64] = {0}; |
|
|
for (int i = 0; i < key_len && i < 63; i++) { |
|
|
sscanf(key_hex + i*2, "%2hhx", &key[i]); |
|
|
} |
|
|
printf(" Key length: %d bytes\n", key_len); |
|
|
printf(" Key (first 8): "); |
|
|
for (int i = 0; i < 8 && i < key_len; i++) printf("%02x", (unsigned char)key[i]); |
|
|
printf("...\n"); |
|
|
|
|
|
|
|
|
long long pipeline = 0; |
|
|
printf(" Calling CreateOcrPipeline...\n"); |
|
|
fflush(stdout); |
|
|
res = pCreatePipeline(model_path, key, init_opts, &pipeline); |
|
|
printf(" CreateOcrPipeline result: %lld %s\n", res, res == 0 ? "OK" : "FAIL"); |
|
|
|
|
|
if (res != 0) { |
|
|
printf("\n === DIAGNOSIS ===\n"); |
|
|
printf(" Error code %lld from CreateOcrPipeline.\n", res); |
|
|
printf(" Most likely causes:\n"); |
|
|
printf(" - bcrypt AES-256-CFB128 not supported in Wine (check TEST 3 above)\n"); |
|
|
printf(" - onnxruntime.dll initialization failed\n"); |
|
|
printf(" - Model file corrupted or git-lfs pointer\n"); |
|
|
} else { |
|
|
printf(" SUCCESS! Pipeline created.\n"); |
|
|
pRelPipeline(pipeline); |
|
|
} |
|
|
|
|
|
pRelInit(init_opts); |
|
|
FreeLibrary(hmod); |
|
|
} |
|
|
|
|
|
int main(int argc, char** argv) { |
|
|
if (argc < 2) { |
|
|
fprintf(stderr, "Usage: %s <dll_dir> [model_key_hex]\n", argv[0]); |
|
|
return 1; |
|
|
} |
|
|
|
|
|
const char* dll_dir = argv[1]; |
|
|
const char* key_hex = argc > 2 ? argv[2] : |
|
|
"6b6a29544774724b3e665d625b50696f772e67552b6e43407322222222222234"; |
|
|
|
|
|
printf("OneOCR Wine Debug Tool\n"); |
|
|
printf("DLL dir: %s\n", dll_dir); |
|
|
|
|
|
test_file_access(dll_dir); |
|
|
test_dll_loading(dll_dir); |
|
|
test_bcrypt_cfb(); |
|
|
test_pipeline(dll_dir, key_hex); |
|
|
|
|
|
printf("\n=== DONE ===\n"); |
|
|
return 0; |
|
|
} |
|
|
|