OneOCR Dev
commited on
Commit
·
366e8c3
1
Parent(s):
7cecd12
feat: add diagnostic debug loader for Wine troubleshooting
Browse files- test_wine_colab.ipynb +129 -34
- tools/oneocr_debug.c +331 -0
- tools/oneocr_debug.exe +0 -0
test_wine_colab.ipynb
CHANGED
|
@@ -28,11 +28,23 @@
|
|
| 28 |
"metadata": {},
|
| 29 |
"outputs": [],
|
| 30 |
"source": [
|
| 31 |
-
"# 1. Install Wine + MinGW\n",
|
| 32 |
-
"
|
| 33 |
-
"
|
| 34 |
-
"
|
| 35 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 36 |
]
|
| 37 |
},
|
| 38 |
{
|
|
@@ -42,13 +54,15 @@
|
|
| 42 |
"metadata": {},
|
| 43 |
"outputs": [],
|
| 44 |
"source": [
|
| 45 |
-
"# 2. Initialize Wine prefix (suppress noise)\n",
|
| 46 |
"import os\n",
|
| 47 |
"os.environ['WINEDEBUG'] = '-all'\n",
|
| 48 |
"os.environ['WINEPREFIX'] = '/root/.wine'\n",
|
| 49 |
"os.environ['WINEARCH'] = 'win64'\n",
|
| 50 |
-
"!wineboot --init 2>/dev/
|
| 51 |
-
"
|
|
|
|
|
|
|
| 52 |
]
|
| 53 |
},
|
| 54 |
{
|
|
@@ -58,10 +72,13 @@
|
|
| 58 |
"metadata": {},
|
| 59 |
"outputs": [],
|
| 60 |
"source": [
|
| 61 |
-
"# 3. Clone repo from HuggingFace
|
|
|
|
| 62 |
"!git lfs install\n",
|
| 63 |
-
"!git clone https://huggingface.co/MattyMroz/oneocr /content/oneocr 2>/dev/null ||
|
| 64 |
"!mkdir -p /content/oneocr/ocr_data\n",
|
|
|
|
|
|
|
| 65 |
"!ls -la /content/oneocr/ocr_data/ 2>/dev/null || echo \"ocr_data/ is empty — upload DLLs in next cell\""
|
| 66 |
]
|
| 67 |
},
|
|
@@ -87,27 +104,55 @@
|
|
| 87 |
"from pathlib import Path\n",
|
| 88 |
"\n",
|
| 89 |
"ocr_data = Path('/content/oneocr/ocr_data')\n",
|
| 90 |
-
"needed =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 91 |
"\n",
|
| 92 |
-
"
|
| 93 |
-
"for f in needed:\n",
|
| 94 |
-
" src = Path(f'/content/{f}')\n",
|
| 95 |
" dst = ocr_data / f\n",
|
| 96 |
-
" if
|
| 97 |
-
" shutil.move(str(src), str(dst))\n",
|
| 98 |
-
" print(f' ✅ Przeniesiono: {f}')\n",
|
| 99 |
-
" elif dst.exists():\n",
|
| 100 |
" print(f' ✅ Już jest: {f} ({dst.stat().st_size / 1e6:.1f} MB)')\n",
|
| 101 |
-
"
|
| 102 |
-
"
|
| 103 |
-
"\n",
|
| 104 |
-
"
|
| 105 |
-
"
|
| 106 |
-
"
|
| 107 |
-
"
|
| 108 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 109 |
"else:\n",
|
| 110 |
-
" print(
|
| 111 |
]
|
| 112 |
},
|
| 113 |
{
|
|
@@ -128,10 +173,60 @@
|
|
| 128 |
"metadata": {},
|
| 129 |
"outputs": [],
|
| 130 |
"source": [
|
| 131 |
-
"# 6. Compile
|
|
|
|
| 132 |
"!x86_64-w64-mingw32-gcc -O2 -o /content/oneocr/tools/oneocr_loader.exe /content/oneocr/tools/oneocr_loader.c\n",
|
| 133 |
-
"!ls -la /content/oneocr/tools
|
| 134 |
-
"print('✅
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 135 |
]
|
| 136 |
},
|
| 137 |
{
|
|
@@ -141,7 +236,7 @@
|
|
| 141 |
"metadata": {},
|
| 142 |
"outputs": [],
|
| 143 |
"source": [
|
| 144 |
-
"#
|
| 145 |
"import subprocess, json, os\n",
|
| 146 |
"from PIL import Image\n",
|
| 147 |
"from pathlib import Path\n",
|
|
@@ -192,7 +287,7 @@
|
|
| 192 |
"metadata": {},
|
| 193 |
"outputs": [],
|
| 194 |
"source": [
|
| 195 |
-
"#
|
| 196 |
"import time\n",
|
| 197 |
"\n",
|
| 198 |
"test_dir = Path('/content/oneocr/working_space/input')\n",
|
|
@@ -234,7 +329,7 @@
|
|
| 234 |
"if fail == 0:\n",
|
| 235 |
" print('🎉 Wine bridge on Linux: WORKS! 100% accuracy identical to Windows DLL.')\n",
|
| 236 |
"else:\n",
|
| 237 |
-
" print(f'⚠️ {fail} failures — check
|
| 238 |
]
|
| 239 |
},
|
| 240 |
{
|
|
@@ -244,7 +339,7 @@
|
|
| 244 |
"metadata": {},
|
| 245 |
"outputs": [],
|
| 246 |
"source": [
|
| 247 |
-
"#
|
| 248 |
"import sys\n",
|
| 249 |
"sys.path.insert(0, '/content/oneocr')\n",
|
| 250 |
"\n",
|
|
|
|
| 28 |
"metadata": {},
|
| 29 |
"outputs": [],
|
| 30 |
"source": [
|
| 31 |
+
"# 1. Install Wine + MinGW (use WineHQ repo for latest stable)\n",
|
| 32 |
+
"import subprocess, os\n",
|
| 33 |
+
"\n",
|
| 34 |
+
"# Add WineHQ repo for latest stable Wine (Ubuntu's stock is old)\n",
|
| 35 |
+
"cmds = [\n",
|
| 36 |
+
" 'dpkg --add-architecture i386',\n",
|
| 37 |
+
" 'mkdir -pm755 /etc/apt/keyrings',\n",
|
| 38 |
+
" 'wget -qO /etc/apt/keyrings/winehq-archive.key https://dl.winehq.org/wine-builds/winehq.key 2>/dev/null || true',\n",
|
| 39 |
+
" 'apt-get update -qq',\n",
|
| 40 |
+
" 'apt-get install -y -qq wine64 mingw-w64 > /dev/null 2>&1',\n",
|
| 41 |
+
"]\n",
|
| 42 |
+
"for cmd in cmds:\n",
|
| 43 |
+
" subprocess.run(cmd, shell=True, capture_output=True)\n",
|
| 44 |
+
"\n",
|
| 45 |
+
"# Show Wine version\n",
|
| 46 |
+
"!wine64 --version\n",
|
| 47 |
+
"!x86_64-w64-mingw32-gcc --version | head -1"
|
| 48 |
]
|
| 49 |
},
|
| 50 |
{
|
|
|
|
| 54 |
"metadata": {},
|
| 55 |
"outputs": [],
|
| 56 |
"source": [
|
| 57 |
+
"# 2. Initialize Wine prefix (64-bit, suppress noise)\n",
|
| 58 |
"import os\n",
|
| 59 |
"os.environ['WINEDEBUG'] = '-all'\n",
|
| 60 |
"os.environ['WINEPREFIX'] = '/root/.wine'\n",
|
| 61 |
"os.environ['WINEARCH'] = 'win64'\n",
|
| 62 |
+
"!wineboot --init 2>/dev/null\n",
|
| 63 |
+
"!echo \"Wine prefix initialized\"\n",
|
| 64 |
+
"# Verify Wine can run basic exe\n",
|
| 65 |
+
"!echo 'int main(){return 0;}' > /tmp/test.c && x86_64-w64-mingw32-gcc -o /tmp/test.exe /tmp/test.c && wine64 /tmp/test.exe && echo \"Wine runs MinGW executables OK\""
|
| 66 |
]
|
| 67 |
},
|
| 68 |
{
|
|
|
|
| 72 |
"metadata": {},
|
| 73 |
"outputs": [],
|
| 74 |
"source": [
|
| 75 |
+
"# 3. Clone repo from HuggingFace\n",
|
| 76 |
+
"!pip install -q huggingface_hub 2>/dev/null\n",
|
| 77 |
"!git lfs install\n",
|
| 78 |
+
"!git clone https://huggingface.co/MattyMroz/oneocr /content/oneocr 2>/dev/null || (cd /content/oneocr && git pull)\n",
|
| 79 |
"!mkdir -p /content/oneocr/ocr_data\n",
|
| 80 |
+
"!ls -la /content/oneocr/tools/\n",
|
| 81 |
+
"print(\"\\n--- ocr_data/ contents ---\")\n",
|
| 82 |
"!ls -la /content/oneocr/ocr_data/ 2>/dev/null || echo \"ocr_data/ is empty — upload DLLs in next cell\""
|
| 83 |
]
|
| 84 |
},
|
|
|
|
| 104 |
"from pathlib import Path\n",
|
| 105 |
"\n",
|
| 106 |
"ocr_data = Path('/content/oneocr/ocr_data')\n",
|
| 107 |
+
"needed = {\n",
|
| 108 |
+
" 'oneocr.dll': 40_000_000, # ~40 MB\n",
|
| 109 |
+
" 'oneocr.onemodel': 50_000_000, # ~56 MB \n",
|
| 110 |
+
" 'onnxruntime.dll': 10_000_000, # ~13 MB\n",
|
| 111 |
+
"}\n",
|
| 112 |
+
"\n",
|
| 113 |
+
"# Search multiple possible locations\n",
|
| 114 |
+
"search_dirs = [Path('/content'), Path('/root'), Path('/tmp')]\n",
|
| 115 |
"\n",
|
| 116 |
+
"for f, min_size in needed.items():\n",
|
|
|
|
|
|
|
| 117 |
" dst = ocr_data / f\n",
|
| 118 |
+
" if dst.exists() and dst.stat().st_size > min_size:\n",
|
|
|
|
|
|
|
|
|
|
| 119 |
" print(f' ✅ Już jest: {f} ({dst.stat().st_size / 1e6:.1f} MB)')\n",
|
| 120 |
+
" continue\n",
|
| 121 |
+
" \n",
|
| 122 |
+
" # Find the file\n",
|
| 123 |
+
" found = False\n",
|
| 124 |
+
" for d in search_dirs:\n",
|
| 125 |
+
" src = d / f\n",
|
| 126 |
+
" if src.exists() and src.stat().st_size > min_size:\n",
|
| 127 |
+
" shutil.copy2(str(src), str(dst))\n",
|
| 128 |
+
" print(f' ✅ Skopiowano: {f} ({dst.stat().st_size / 1e6:.1f} MB)')\n",
|
| 129 |
+
" found = True\n",
|
| 130 |
+
" break\n",
|
| 131 |
+
" \n",
|
| 132 |
+
" if not found:\n",
|
| 133 |
+
" if dst.exists():\n",
|
| 134 |
+
" size = dst.stat().st_size\n",
|
| 135 |
+
" if size < 1000:\n",
|
| 136 |
+
" # Likely git LFS pointer\n",
|
| 137 |
+
" print(f' ❌ {f} — to git LFS pointer ({size} B)! Wrzuć prawdziwy plik.')\n",
|
| 138 |
+
" with open(dst) as fh:\n",
|
| 139 |
+
" print(f' Zawartość: {fh.read(100)[:80]}...')\n",
|
| 140 |
+
" else:\n",
|
| 141 |
+
" print(f' ⚠️ {f} istnieje ale mały ({size / 1e6:.1f} MB) — sprawdź!')\n",
|
| 142 |
+
" else:\n",
|
| 143 |
+
" print(f' ❌ BRAK: {f} — wrzuć plik!')\n",
|
| 144 |
+
"\n",
|
| 145 |
+
"# Final check\n",
|
| 146 |
+
"print()\n",
|
| 147 |
+
"all_ok = True\n",
|
| 148 |
+
"for f, min_size in needed.items():\n",
|
| 149 |
+
" dst = ocr_data / f\n",
|
| 150 |
+
" if not dst.exists() or dst.stat().st_size < min_size:\n",
|
| 151 |
+
" all_ok = False\n",
|
| 152 |
+
"if all_ok:\n",
|
| 153 |
+
" print('🎉 Wszystkie pliki na miejscu!')\n",
|
| 154 |
"else:\n",
|
| 155 |
+
" print('⚠️ Brakuje plików — wrzuć je i uruchom tę komórkę ponownie.')"
|
| 156 |
]
|
| 157 |
},
|
| 158 |
{
|
|
|
|
| 173 |
"metadata": {},
|
| 174 |
"outputs": [],
|
| 175 |
"source": [
|
| 176 |
+
"# 6. Compile BOTH loaders: debug + normal\n",
|
| 177 |
+
"!x86_64-w64-mingw32-gcc -O2 -o /content/oneocr/tools/oneocr_debug.exe /content/oneocr/tools/oneocr_debug.c\n",
|
| 178 |
"!x86_64-w64-mingw32-gcc -O2 -o /content/oneocr/tools/oneocr_loader.exe /content/oneocr/tools/oneocr_loader.c\n",
|
| 179 |
+
"!ls -la /content/oneocr/tools/*.exe\n",
|
| 180 |
+
"print('✅ Both loaders compiled')"
|
| 181 |
+
]
|
| 182 |
+
},
|
| 183 |
+
{
|
| 184 |
+
"cell_type": "code",
|
| 185 |
+
"execution_count": null,
|
| 186 |
+
"id": "2b76a011",
|
| 187 |
+
"metadata": {},
|
| 188 |
+
"outputs": [],
|
| 189 |
+
"source": [
|
| 190 |
+
"# 7. 🔍 DIAGNOSTYKA — Run debug loader to find exact failure point\n",
|
| 191 |
+
"import subprocess, os\n",
|
| 192 |
+
"\n",
|
| 193 |
+
"os.environ['WINEDEBUG'] = '-all'\n",
|
| 194 |
+
"\n",
|
| 195 |
+
"# Convert path for Wine\n",
|
| 196 |
+
"dll_dir_wine = 'Z:\\\\content\\\\oneocr\\\\ocr_data'\n",
|
| 197 |
+
"\n",
|
| 198 |
+
"print(\"=\" * 60)\n",
|
| 199 |
+
"print(\"DIAGNOSTYKA: Testowanie komponentów pod Wine\")\n",
|
| 200 |
+
"print(\"=\" * 60)\n",
|
| 201 |
+
"\n",
|
| 202 |
+
"# Run debug loader\n",
|
| 203 |
+
"result = subprocess.run(\n",
|
| 204 |
+
" ['wine64', '/content/oneocr/tools/oneocr_debug.exe', dll_dir_wine],\n",
|
| 205 |
+
" capture_output=True, text=True, timeout=120,\n",
|
| 206 |
+
" env={**os.environ, 'WINEDEBUG': '-all'}\n",
|
| 207 |
+
")\n",
|
| 208 |
+
"\n",
|
| 209 |
+
"print(result.stdout)\n",
|
| 210 |
+
"if result.stderr:\n",
|
| 211 |
+
" print(\"--- STDERR ---\")\n",
|
| 212 |
+
" print(result.stderr[:1000])\n",
|
| 213 |
+
"\n",
|
| 214 |
+
"# Also run with Wine debug channels for bcrypt/ntdll\n",
|
| 215 |
+
"print(\"\\n\" + \"=\" * 60)\n",
|
| 216 |
+
"print(\"EXTRA: Wine debug trace (bcrypt + module loading)\")\n",
|
| 217 |
+
"print(\"=\" * 60)\n",
|
| 218 |
+
"result2 = subprocess.run(\n",
|
| 219 |
+
" ['wine64', '/content/oneocr/tools/oneocr_debug.exe', dll_dir_wine],\n",
|
| 220 |
+
" capture_output=True, text=True, timeout=120,\n",
|
| 221 |
+
" env={**os.environ, 'WINEDEBUG': '+bcrypt,+loaddll'}\n",
|
| 222 |
+
")\n",
|
| 223 |
+
"# Only show relevant debug lines (not all the noise)\n",
|
| 224 |
+
"for line in result2.stderr.split('\\n'):\n",
|
| 225 |
+
" if any(kw in line.lower() for kw in ['bcrypt', 'cfb', 'fail', 'err:', 'fixme:', 'oneocr', 'onnxruntime', 'not implemented', 'not supported']):\n",
|
| 226 |
+
" print(line)\n",
|
| 227 |
+
"if result2.stdout != result.stdout:\n",
|
| 228 |
+
" print(\"\\nDiagnostic output:\")\n",
|
| 229 |
+
" print(result2.stdout[-500:])"
|
| 230 |
]
|
| 231 |
},
|
| 232 |
{
|
|
|
|
| 236 |
"metadata": {},
|
| 237 |
"outputs": [],
|
| 238 |
"source": [
|
| 239 |
+
"# 8. 🧪 TEST: Run C loader via Wine on a single image\n",
|
| 240 |
"import subprocess, json, os\n",
|
| 241 |
"from PIL import Image\n",
|
| 242 |
"from pathlib import Path\n",
|
|
|
|
| 287 |
"metadata": {},
|
| 288 |
"outputs": [],
|
| 289 |
"source": [
|
| 290 |
+
"# 9. 🧪 FULL TEST: Run on ALL 19 test images\n",
|
| 291 |
"import time\n",
|
| 292 |
"\n",
|
| 293 |
"test_dir = Path('/content/oneocr/working_space/input')\n",
|
|
|
|
| 329 |
"if fail == 0:\n",
|
| 330 |
" print('🎉 Wine bridge on Linux: WORKS! 100% accuracy identical to Windows DLL.')\n",
|
| 331 |
"else:\n",
|
| 332 |
+
" print(f'⚠️ {fail} failures — check diagnostic output (cell 7) for details')"
|
| 333 |
]
|
| 334 |
},
|
| 335 |
{
|
|
|
|
| 339 |
"metadata": {},
|
| 340 |
"outputs": [],
|
| 341 |
"source": [
|
| 342 |
+
"# 10. 🧪 TEST: Unified engine (auto-selects Wine backend on Linux)\n",
|
| 343 |
"import sys\n",
|
| 344 |
"sys.path.insert(0, '/content/oneocr')\n",
|
| 345 |
"\n",
|
tools/oneocr_debug.c
ADDED
|
@@ -0,0 +1,331 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* oneocr_debug.c -- Diagnostic loader for Wine troubleshooting
|
| 2 |
+
* Compile: x86_64-w64-mingw32-gcc -O2 -o oneocr_debug.exe oneocr_debug.c
|
| 3 |
+
* Usage: wine64 oneocr_debug.exe <dll_dir>
|
| 4 |
+
*
|
| 5 |
+
* Tests each component separately:
|
| 6 |
+
* 1. File access (can we read oneocr.onemodel?)
|
| 7 |
+
* 2. DLL loading (oneocr.dll, onnxruntime.dll)
|
| 8 |
+
* 3. bcrypt AES-256-CFB128 (model decryption)
|
| 9 |
+
* 4. CreateOcrPipeline (full init)
|
| 10 |
+
*/
|
| 11 |
+
#include <stdio.h>
|
| 12 |
+
#include <stdlib.h>
|
| 13 |
+
#include <string.h>
|
| 14 |
+
#include <windows.h>
|
| 15 |
+
|
| 16 |
+
/* bcrypt types */
|
| 17 |
+
typedef void* BCRYPT_ALG_HANDLE;
|
| 18 |
+
typedef void* BCRYPT_KEY_HANDLE;
|
| 19 |
+
typedef long NTSTATUS;
|
| 20 |
+
|
| 21 |
+
typedef NTSTATUS (*fn_BCryptOpenAlgorithmProvider)(BCRYPT_ALG_HANDLE*, const wchar_t*, const wchar_t*, unsigned long);
|
| 22 |
+
typedef NTSTATUS (*fn_BCryptSetProperty)(BCRYPT_ALG_HANDLE, const wchar_t*, unsigned char*, unsigned long, unsigned long);
|
| 23 |
+
typedef NTSTATUS (*fn_BCryptGenerateSymmetricKey)(BCRYPT_ALG_HANDLE, BCRYPT_KEY_HANDLE*, unsigned char*, unsigned long, unsigned char*, unsigned long, unsigned long);
|
| 24 |
+
typedef NTSTATUS (*fn_BCryptEncrypt)(BCRYPT_KEY_HANDLE, unsigned char*, unsigned long, void*, unsigned char*, unsigned long, unsigned char*, unsigned long, unsigned long*, unsigned long);
|
| 25 |
+
typedef NTSTATUS (*fn_BCryptDecrypt)(BCRYPT_KEY_HANDLE, unsigned char*, unsigned long, void*, unsigned char*, unsigned long, unsigned char*, unsigned long, unsigned long*, unsigned long);
|
| 26 |
+
typedef NTSTATUS (*fn_BCryptCloseAlgorithmProvider)(BCRYPT_ALG_HANDLE, unsigned long);
|
| 27 |
+
typedef NTSTATUS (*fn_BCryptDestroyKey)(BCRYPT_KEY_HANDLE);
|
| 28 |
+
|
| 29 |
+
/* DLL function types */
|
| 30 |
+
typedef long long (*fn_CreateOcrInitOptions)(long long*);
|
| 31 |
+
typedef long long (*fn_OcrInitOptionsSetUseModelDelayLoad)(long long, char);
|
| 32 |
+
typedef long long (*fn_CreateOcrPipeline)(const char*, const char*, long long, long long*);
|
| 33 |
+
typedef void (*fn_ReleaseOcrInitOptions)(long long);
|
| 34 |
+
typedef void (*fn_ReleaseOcrPipeline)(long long);
|
| 35 |
+
|
| 36 |
+
static void test_file_access(const char* dll_dir) {
|
| 37 |
+
printf("\n=== TEST 1: File Access ===\n");
|
| 38 |
+
|
| 39 |
+
char model_path[MAX_PATH];
|
| 40 |
+
snprintf(model_path, sizeof(model_path), "%s\\oneocr.onemodel", dll_dir);
|
| 41 |
+
|
| 42 |
+
/* Test CreateFileA */
|
| 43 |
+
HANDLE hFile = CreateFileA(model_path, GENERIC_READ, FILE_SHARE_READ, NULL,
|
| 44 |
+
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
| 45 |
+
if (hFile == INVALID_HANDLE_VALUE) {
|
| 46 |
+
printf(" FAIL: Cannot open model file: %s (error %lu)\n", model_path, GetLastError());
|
| 47 |
+
|
| 48 |
+
/* Try alternate paths */
|
| 49 |
+
printf(" Trying alternate paths...\n");
|
| 50 |
+
char alt1[MAX_PATH];
|
| 51 |
+
snprintf(alt1, sizeof(alt1), "%s/oneocr.onemodel", dll_dir);
|
| 52 |
+
hFile = CreateFileA(alt1, GENERIC_READ, FILE_SHARE_READ, NULL,
|
| 53 |
+
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
| 54 |
+
if (hFile != INVALID_HANDLE_VALUE) {
|
| 55 |
+
printf(" OK with forward slashes: %s\n", alt1);
|
| 56 |
+
} else {
|
| 57 |
+
printf(" FAIL with forward slashes too (error %lu)\n", GetLastError());
|
| 58 |
+
}
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
if (hFile != INVALID_HANDLE_VALUE) {
|
| 62 |
+
LARGE_INTEGER size;
|
| 63 |
+
GetFileSizeEx(hFile, &size);
|
| 64 |
+
printf(" OK: Model file opened. Size: %lld bytes (%.1f MB)\n",
|
| 65 |
+
size.QuadPart, size.QuadPart / 1e6);
|
| 66 |
+
|
| 67 |
+
if (size.QuadPart < 1000000) {
|
| 68 |
+
/* Read first 100 bytes to check if it's a git lfs pointer */
|
| 69 |
+
char buf[200] = {0};
|
| 70 |
+
DWORD read = 0;
|
| 71 |
+
ReadFile(hFile, buf, 100, &read, NULL);
|
| 72 |
+
if (strstr(buf, "version https://git-lfs") != NULL) {
|
| 73 |
+
printf(" *** WARNING: File is a Git LFS POINTER, not actual data! ***\n");
|
| 74 |
+
printf(" Content: %s\n", buf);
|
| 75 |
+
printf(" Run: git lfs pull\n");
|
| 76 |
+
} else {
|
| 77 |
+
printf(" WARNING: File seems too small for a model!\n");
|
| 78 |
+
}
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
/* Read first 16 bytes (header) */
|
| 82 |
+
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
| 83 |
+
unsigned char header[16];
|
| 84 |
+
DWORD bytesRead = 0;
|
| 85 |
+
ReadFile(hFile, header, 16, &bytesRead, NULL);
|
| 86 |
+
printf(" Header (first 16 bytes): ");
|
| 87 |
+
for (int i = 0; i < 16; i++) printf("%02x ", header[i]);
|
| 88 |
+
printf("\n");
|
| 89 |
+
|
| 90 |
+
CloseHandle(hFile);
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
/* Check DLL files */
|
| 94 |
+
char dll_path[MAX_PATH], ort_path[MAX_PATH];
|
| 95 |
+
snprintf(dll_path, sizeof(dll_path), "%s\\oneocr.dll", dll_dir);
|
| 96 |
+
snprintf(ort_path, sizeof(ort_path), "%s\\onnxruntime.dll", dll_dir);
|
| 97 |
+
|
| 98 |
+
HANDLE h1 = CreateFileA(dll_path, GENERIC_READ, FILE_SHARE_READ, NULL,
|
| 99 |
+
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
| 100 |
+
if (h1 != INVALID_HANDLE_VALUE) {
|
| 101 |
+
LARGE_INTEGER s; GetFileSizeEx(h1, &s);
|
| 102 |
+
printf(" OK: oneocr.dll exists (%.1f MB)\n", s.QuadPart/1e6);
|
| 103 |
+
CloseHandle(h1);
|
| 104 |
+
} else {
|
| 105 |
+
printf(" FAIL: oneocr.dll not found at %s (error %lu)\n", dll_path, GetLastError());
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
HANDLE h2 = CreateFileA(ort_path, GENERIC_READ, FILE_SHARE_READ, NULL,
|
| 109 |
+
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
| 110 |
+
if (h2 != INVALID_HANDLE_VALUE) {
|
| 111 |
+
LARGE_INTEGER s; GetFileSizeEx(h2, &s);
|
| 112 |
+
printf(" OK: onnxruntime.dll exists (%.1f MB)\n", s.QuadPart/1e6);
|
| 113 |
+
CloseHandle(h2);
|
| 114 |
+
} else {
|
| 115 |
+
printf(" FAIL: onnxruntime.dll not found at %s (error %lu)\n", ort_path, GetLastError());
|
| 116 |
+
}
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
static void test_dll_loading(const char* dll_dir) {
|
| 120 |
+
printf("\n=== TEST 2: DLL Loading ===\n");
|
| 121 |
+
|
| 122 |
+
SetDllDirectoryA(dll_dir);
|
| 123 |
+
|
| 124 |
+
/* Try onnxruntime first */
|
| 125 |
+
char ort_path[MAX_PATH];
|
| 126 |
+
snprintf(ort_path, sizeof(ort_path), "%s\\onnxruntime.dll", dll_dir);
|
| 127 |
+
HMODULE hort = LoadLibraryA(ort_path);
|
| 128 |
+
if (hort) {
|
| 129 |
+
printf(" OK: onnxruntime.dll loaded\n");
|
| 130 |
+
FreeLibrary(hort);
|
| 131 |
+
} else {
|
| 132 |
+
printf(" FAIL: onnxruntime.dll LoadLibrary error %lu\n", GetLastError());
|
| 133 |
+
}
|
| 134 |
+
|
| 135 |
+
/* Try oneocr */
|
| 136 |
+
char dll_path[MAX_PATH];
|
| 137 |
+
snprintf(dll_path, sizeof(dll_path), "%s\\oneocr.dll", dll_dir);
|
| 138 |
+
HMODULE hmod = LoadLibraryA(dll_path);
|
| 139 |
+
if (hmod) {
|
| 140 |
+
printf(" OK: oneocr.dll loaded\n");
|
| 141 |
+
|
| 142 |
+
/* Check exports */
|
| 143 |
+
const char* exports[] = {
|
| 144 |
+
"CreateOcrInitOptions", "CreateOcrPipeline", "RunOcrPipeline",
|
| 145 |
+
"ReleaseOcrResult", "ReleaseOcrPipeline", NULL
|
| 146 |
+
};
|
| 147 |
+
for (int i = 0; exports[i]; i++) {
|
| 148 |
+
void* fn = GetProcAddress(hmod, exports[i]);
|
| 149 |
+
printf(" %s %s\n", fn ? " OK:" : " FAIL:", exports[i]);
|
| 150 |
+
}
|
| 151 |
+
FreeLibrary(hmod);
|
| 152 |
+
} else {
|
| 153 |
+
printf(" FAIL: oneocr.dll LoadLibrary error %lu\n", GetLastError());
|
| 154 |
+
}
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
static void test_bcrypt_cfb(void) {
|
| 158 |
+
printf("\n=== TEST 3: bcrypt AES-256-CFB128 ===\n");
|
| 159 |
+
|
| 160 |
+
HMODULE hbcrypt = LoadLibraryA("bcrypt.dll");
|
| 161 |
+
if (!hbcrypt) {
|
| 162 |
+
printf(" FAIL: Cannot load bcrypt.dll (error %lu)\n", GetLastError());
|
| 163 |
+
return;
|
| 164 |
+
}
|
| 165 |
+
printf(" OK: bcrypt.dll loaded\n");
|
| 166 |
+
|
| 167 |
+
fn_BCryptOpenAlgorithmProvider pOpen = (fn_BCryptOpenAlgorithmProvider)GetProcAddress(hbcrypt, "BCryptOpenAlgorithmProvider");
|
| 168 |
+
fn_BCryptSetProperty pSetProp = (fn_BCryptSetProperty)GetProcAddress(hbcrypt, "BCryptSetProperty");
|
| 169 |
+
fn_BCryptGenerateSymmetricKey pGenKey = (fn_BCryptGenerateSymmetricKey)GetProcAddress(hbcrypt, "BCryptGenerateSymmetricKey");
|
| 170 |
+
fn_BCryptDecrypt pDecrypt = (fn_BCryptDecrypt)GetProcAddress(hbcrypt, "BCryptDecrypt");
|
| 171 |
+
fn_BCryptCloseAlgorithmProvider pClose = (fn_BCryptCloseAlgorithmProvider)GetProcAddress(hbcrypt, "BCryptCloseAlgorithmProvider");
|
| 172 |
+
fn_BCryptDestroyKey pDestroy = (fn_BCryptDestroyKey)GetProcAddress(hbcrypt, "BCryptDestroyKey");
|
| 173 |
+
|
| 174 |
+
if (!pOpen || !pSetProp || !pGenKey || !pDecrypt) {
|
| 175 |
+
printf(" FAIL: Missing bcrypt functions\n");
|
| 176 |
+
return;
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
/* Test 1: Open AES provider */
|
| 180 |
+
BCRYPT_ALG_HANDLE hAlg = NULL;
|
| 181 |
+
NTSTATUS status = pOpen(&hAlg, L"AES", NULL, 0);
|
| 182 |
+
printf(" BCryptOpenAlgorithmProvider(AES): 0x%08lx %s\n", status, status == 0 ? "OK" : "FAIL");
|
| 183 |
+
if (status != 0) return;
|
| 184 |
+
|
| 185 |
+
/* Test 2: Set CFB chaining mode */
|
| 186 |
+
wchar_t cfb[] = L"ChainingModeCFB";
|
| 187 |
+
status = pSetProp(hAlg, L"ChainingMode", (unsigned char*)cfb, sizeof(cfb), 0);
|
| 188 |
+
printf(" BCryptSetProperty(ChainingModeCFB): 0x%08lx %s\n", status, status == 0 ? "OK" : "FAIL");
|
| 189 |
+
|
| 190 |
+
if (status != 0) {
|
| 191 |
+
printf(" *** CFB MODE NOT SUPPORTED IN THIS WINE VERSION! ***\n");
|
| 192 |
+
printf(" This is likely the root cause of error 6.\n");
|
| 193 |
+
printf(" Trying CBC mode instead...\n");
|
| 194 |
+
wchar_t cbc[] = L"ChainingModeCBC";
|
| 195 |
+
status = pSetProp(hAlg, L"ChainingMode", (unsigned char*)cbc, sizeof(cbc), 0);
|
| 196 |
+
printf(" BCryptSetProperty(ChainingModeCBC): 0x%08lx %s\n", status, status == 0 ? "OK" : "FAIL");
|
| 197 |
+
|
| 198 |
+
printf(" Trying ECB mode...\n");
|
| 199 |
+
wchar_t ecb[] = L"ChainingModeECB";
|
| 200 |
+
status = pSetProp(hAlg, L"ChainingMode", (unsigned char*)ecb, sizeof(ecb), 0);
|
| 201 |
+
printf(" BCryptSetProperty(ChainingModeECB): 0x%08lx %s\n", status, status == 0 ? "OK" : "FAIL");
|
| 202 |
+
|
| 203 |
+
printf(" Trying GCM mode...\n");
|
| 204 |
+
wchar_t gcm[] = L"ChainingModeGCM";
|
| 205 |
+
status = pSetProp(hAlg, L"ChainingMode", (unsigned char*)gcm, sizeof(gcm), 0);
|
| 206 |
+
printf(" BCryptSetProperty(ChainingModeGCM): 0x%08lx %s\n", status, status == 0 ? "OK" : "FAIL");
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
if (status == 0) {
|
| 210 |
+
/* Test 3: Generate key with test data */
|
| 211 |
+
unsigned char test_key[32] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
|
| 212 |
+
0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0x10,
|
| 213 |
+
0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
|
| 214 |
+
0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20};
|
| 215 |
+
BCRYPT_KEY_HANDLE hKey = NULL;
|
| 216 |
+
status = pGenKey(hAlg, &hKey, NULL, 0, test_key, 32, 0);
|
| 217 |
+
printf(" BCryptGenerateSymmetricKey: 0x%08lx %s\n", status, status == 0 ? "OK" : "FAIL");
|
| 218 |
+
|
| 219 |
+
if (status == 0 && hKey) {
|
| 220 |
+
/* Test 4: Try decrypt */
|
| 221 |
+
unsigned char iv[16] = {0};
|
| 222 |
+
unsigned char ciphertext[16] = {0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,
|
| 223 |
+
0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50};
|
| 224 |
+
unsigned char plaintext[16] = {0};
|
| 225 |
+
unsigned long cbResult = 0;
|
| 226 |
+
status = pDecrypt(hKey, ciphertext, 16, NULL, iv, 16, plaintext, 16, &cbResult, 0);
|
| 227 |
+
printf(" BCryptDecrypt: 0x%08lx %s (decrypted %lu bytes)\n",
|
| 228 |
+
status, status == 0 ? "OK" : "FAIL", cbResult);
|
| 229 |
+
if (hKey) pDestroy(hKey);
|
| 230 |
+
}
|
| 231 |
+
}
|
| 232 |
+
|
| 233 |
+
pClose(hAlg, 0);
|
| 234 |
+
FreeLibrary(hbcrypt);
|
| 235 |
+
}
|
| 236 |
+
|
| 237 |
+
static void test_pipeline(const char* dll_dir, const char* key_hex) {
|
| 238 |
+
printf("\n=== TEST 4: CreateOcrPipeline ===\n");
|
| 239 |
+
|
| 240 |
+
SetDllDirectoryA(dll_dir);
|
| 241 |
+
|
| 242 |
+
char dll_path[MAX_PATH];
|
| 243 |
+
snprintf(dll_path, sizeof(dll_path), "%s\\oneocr.dll", dll_dir);
|
| 244 |
+
|
| 245 |
+
HMODULE hmod = LoadLibraryA(dll_path);
|
| 246 |
+
if (!hmod) {
|
| 247 |
+
printf(" FAIL: LoadLibrary failed: %lu\n", GetLastError());
|
| 248 |
+
return;
|
| 249 |
+
}
|
| 250 |
+
|
| 251 |
+
fn_CreateOcrInitOptions pCreateInit = (fn_CreateOcrInitOptions)GetProcAddress(hmod, "CreateOcrInitOptions");
|
| 252 |
+
fn_OcrInitOptionsSetUseModelDelayLoad pSetDelay = (fn_OcrInitOptionsSetUseModelDelayLoad)GetProcAddress(hmod, "OcrInitOptionsSetUseModelDelayLoad");
|
| 253 |
+
fn_CreateOcrPipeline pCreatePipeline = (fn_CreateOcrPipeline)GetProcAddress(hmod, "CreateOcrPipeline");
|
| 254 |
+
fn_ReleaseOcrInitOptions pRelInit = (fn_ReleaseOcrInitOptions)GetProcAddress(hmod, "ReleaseOcrInitOptions");
|
| 255 |
+
fn_ReleaseOcrPipeline pRelPipeline = (fn_ReleaseOcrPipeline)GetProcAddress(hmod, "ReleaseOcrPipeline");
|
| 256 |
+
|
| 257 |
+
if (!pCreateInit || !pCreatePipeline) {
|
| 258 |
+
printf(" FAIL: Missing functions\n");
|
| 259 |
+
return;
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
/* Init options */
|
| 263 |
+
long long init_opts = 0;
|
| 264 |
+
long long res = pCreateInit(&init_opts);
|
| 265 |
+
printf(" CreateOcrInitOptions: %lld %s\n", res, res == 0 ? "OK" : "FAIL");
|
| 266 |
+
|
| 267 |
+
if (pSetDelay) {
|
| 268 |
+
/* Try with delay load = 1 (defer ONNX model loading) */
|
| 269 |
+
res = pSetDelay(init_opts, 1);
|
| 270 |
+
printf(" OcrInitOptionsSetUseModelDelayLoad(1): %lld %s\n", res, res == 0 ? "OK" : "FAIL");
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
/* Model path and key */
|
| 274 |
+
char model_path[MAX_PATH];
|
| 275 |
+
snprintf(model_path, sizeof(model_path), "%s\\oneocr.onemodel", dll_dir);
|
| 276 |
+
printf(" Model path: %s\n", model_path);
|
| 277 |
+
|
| 278 |
+
int key_len = strlen(key_hex) / 2;
|
| 279 |
+
char key[64] = {0};
|
| 280 |
+
for (int i = 0; i < key_len && i < 63; i++) {
|
| 281 |
+
sscanf(key_hex + i*2, "%2hhx", &key[i]);
|
| 282 |
+
}
|
| 283 |
+
printf(" Key length: %d bytes\n", key_len);
|
| 284 |
+
printf(" Key (first 8): ");
|
| 285 |
+
for (int i = 0; i < 8 && i < key_len; i++) printf("%02x", (unsigned char)key[i]);
|
| 286 |
+
printf("...\n");
|
| 287 |
+
|
| 288 |
+
/* Try pipeline creation */
|
| 289 |
+
long long pipeline = 0;
|
| 290 |
+
printf(" Calling CreateOcrPipeline...\n");
|
| 291 |
+
fflush(stdout);
|
| 292 |
+
res = pCreatePipeline(model_path, key, init_opts, &pipeline);
|
| 293 |
+
printf(" CreateOcrPipeline result: %lld %s\n", res, res == 0 ? "OK" : "FAIL");
|
| 294 |
+
|
| 295 |
+
if (res != 0) {
|
| 296 |
+
printf("\n === DIAGNOSIS ===\n");
|
| 297 |
+
printf(" Error code %lld from CreateOcrPipeline.\n", res);
|
| 298 |
+
printf(" Most likely causes:\n");
|
| 299 |
+
printf(" - bcrypt AES-256-CFB128 not supported in Wine (check TEST 3 above)\n");
|
| 300 |
+
printf(" - onnxruntime.dll initialization failed\n");
|
| 301 |
+
printf(" - Model file corrupted or git-lfs pointer\n");
|
| 302 |
+
} else {
|
| 303 |
+
printf(" SUCCESS! Pipeline created.\n");
|
| 304 |
+
pRelPipeline(pipeline);
|
| 305 |
+
}
|
| 306 |
+
|
| 307 |
+
pRelInit(init_opts);
|
| 308 |
+
FreeLibrary(hmod);
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
int main(int argc, char** argv) {
|
| 312 |
+
if (argc < 2) {
|
| 313 |
+
fprintf(stderr, "Usage: %s <dll_dir> [model_key_hex]\n", argv[0]);
|
| 314 |
+
return 1;
|
| 315 |
+
}
|
| 316 |
+
|
| 317 |
+
const char* dll_dir = argv[1];
|
| 318 |
+
const char* key_hex = argc > 2 ? argv[2] :
|
| 319 |
+
"6b6a29544774724b3e665d625b50696f772e67552b6e43407322222222222234";
|
| 320 |
+
|
| 321 |
+
printf("OneOCR Wine Debug Tool\n");
|
| 322 |
+
printf("DLL dir: %s\n", dll_dir);
|
| 323 |
+
|
| 324 |
+
test_file_access(dll_dir);
|
| 325 |
+
test_dll_loading(dll_dir);
|
| 326 |
+
test_bcrypt_cfb();
|
| 327 |
+
test_pipeline(dll_dir, key_hex);
|
| 328 |
+
|
| 329 |
+
printf("\n=== DONE ===\n");
|
| 330 |
+
return 0;
|
| 331 |
+
}
|
tools/oneocr_debug.exe
ADDED
|
Binary file (74.2 kB). View file
|
|
|