File size: 14,004 Bytes
366e8c3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
/* oneocr_debug.c -- Diagnostic loader for Wine troubleshooting
 * Compile: x86_64-w64-mingw32-gcc -O2 -o oneocr_debug.exe oneocr_debug.c
 * Usage:   wine64 oneocr_debug.exe <dll_dir>
 *
 * Tests each component separately:
 *   1. File access (can we read oneocr.onemodel?)
 *   2. DLL loading (oneocr.dll, onnxruntime.dll)
 *   3. bcrypt AES-256-CFB128 (model decryption)
 *   4. CreateOcrPipeline (full init)
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

/* bcrypt types */
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);

/* DLL function types */
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);

    /* Test CreateFileA */
    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());

        /* Try alternate paths */
        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) {
            /* Read first 100 bytes to check if it's a git lfs pointer */
            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");
            }
        }

        /* Read first 16 bytes (header) */
        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);
    }

    /* Check DLL files */
    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);

    /* Try onnxruntime first */
    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());
    }

    /* Try oneocr */
    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");

        /* Check exports */
        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;
    }

    /* Test 1: Open AES provider */
    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;

    /* Test 2: Set CFB chaining mode */
    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) {
        /* Test 3: Generate key with test data */
        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) {
            /* Test 4: Try decrypt */
            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;
    }

    /* Init options */
    long long init_opts = 0;
    long long res = pCreateInit(&init_opts);
    printf("  CreateOcrInitOptions: %lld %s\n", res, res == 0 ? "OK" : "FAIL");

    if (pSetDelay) {
        /* Try with delay load = 1 (defer ONNX model loading) */
        res = pSetDelay(init_opts, 1);
        printf("  OcrInitOptionsSetUseModelDelayLoad(1): %lld %s\n", res, res == 0 ? "OK" : "FAIL");
    }

    /* Model path and key */
    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");

    /* Try pipeline creation */
    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;
}