Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

519 lines
15 KiB

  1. /*++
  2. Copyright (c) 1990-1999 Microsoft Corporation, All Rights Reserved
  3. Module Name:
  4. DIC.c
  5. ++*/
  6. #include <windows.h>
  7. #include <winerror.h>
  8. #include <immdev.h>
  9. #include "imeattr.h"
  10. #include "imedefs.h"
  11. #include "imerc.h"
  12. #if !defined(ROMANIME)
  13. #if !defined(WINIME) && !defined(UNICDIME)
  14. /**********************************************************************/
  15. /* MemoryLess() */
  16. /**********************************************************************/
  17. void PASCAL MemoryLess(
  18. #if defined(UNIIME)
  19. LPINSTDATAL lpInstL,
  20. LPIMEL lpImeL,
  21. #endif
  22. DWORD fdwErrMsg)
  23. {
  24. TCHAR szErrMsg[64];
  25. if (lpImeL->fdwErrMsg & fdwErrMsg) {
  26. // message already prompted
  27. return;
  28. }
  29. LoadString(hInst, IDS_MEM_LESS_ERR, szErrMsg, sizeof(szErrMsg)/sizeof(TCHAR));
  30. lpImeL->fdwErrMsg |= fdwErrMsg;
  31. MessageBeep((UINT)-1);
  32. MessageBox((HWND)NULL, szErrMsg, lpImeL->szIMEName,
  33. MB_OK|MB_ICONHAND|MB_TASKMODAL|MB_TOPMOST);
  34. return;
  35. }
  36. /**********************************************************************/
  37. /* ReadUsrDicToMem() */
  38. /* Return Value: */
  39. /* TRUE - successful, FALSE - failure */
  40. /**********************************************************************/
  41. BOOL PASCAL ReadUsrDicToMem(
  42. #if defined(UNIIME)
  43. LPINSTDATAL lpInstL,
  44. LPIMEL lpImeL,
  45. #endif
  46. HANDLE hUsrDicFile,
  47. DWORD dwUsrDicSize,
  48. UINT uUsrDicSize,
  49. UINT uRecLen,
  50. UINT uReadLen,
  51. UINT uWriteLen)
  52. {
  53. LPBYTE lpUsrDicMem, lpMem, lpMemLimit;
  54. DWORD dwPos, dwReadByte;
  55. if (dwUsrDicSize < 258) { // no char in this dictionary
  56. return (TRUE);
  57. }
  58. lpUsrDicMem = MapViewOfFile(lpInstL->hUsrDicMem, FILE_MAP_WRITE, 0, 0,
  59. uUsrDicSize + 20);
  60. if (!lpUsrDicMem) {
  61. CloseHandle(lpInstL->hUsrDicMem);
  62. MemoryLess(
  63. #if defined(UNIIME)
  64. lpInstL, lpImeL,
  65. #endif
  66. ERRMSG_MEM_USRDIC);
  67. lpInstL->hUsrDicMem = NULL;
  68. return (FALSE);
  69. }
  70. lpMemLimit = lpUsrDicMem + uUsrDicSize;
  71. // read in data, skip header - two headers are similiar
  72. dwPos = SetFilePointer(hUsrDicFile, 258, (LPLONG)NULL, FILE_BEGIN);
  73. for (lpMem = lpUsrDicMem; dwPos < dwUsrDicSize; lpMem += uWriteLen) {
  74. short i;
  75. DWORD dwPattern;
  76. BOOL retVal;
  77. if (lpMem >= lpMemLimit) {
  78. break;
  79. }
  80. retVal = ReadFile(hUsrDicFile, lpMem, uReadLen, &dwReadByte,
  81. (LPOVERLAPPED)NULL);
  82. if ( retVal == FALSE )
  83. {
  84. UnmapViewOfFile(lpUsrDicMem);
  85. CloseHandle(lpInstL->hUsrDicMem);
  86. MemoryLess(
  87. #if defined(UNIIME)
  88. lpInstL, lpImeL,
  89. #endif
  90. ERRMSG_MEM_USRDIC);
  91. lpInstL->hUsrDicMem = NULL;
  92. return (FALSE);
  93. }
  94. // Compress the sequence code and put the first char most significant.
  95. // Limitation - 32 bits only
  96. dwPattern = 0;
  97. for (i = 0; i < lpImeL->nMaxKey; i++) {
  98. dwPattern <<= lpImeL->nSeqBits;
  99. dwPattern |= *(lpMem + 2 + i);
  100. }
  101. *(LPUNADWORD)(lpMem + 2) = dwPattern;
  102. // go to next record
  103. dwPos = SetFilePointer(hUsrDicFile, dwPos + uRecLen, (LPLONG)NULL,
  104. FILE_BEGIN);
  105. }
  106. UnmapViewOfFile(lpUsrDicMem);
  107. return (TRUE);
  108. }
  109. /**********************************************************************/
  110. /* LoadUsrDicFile() */
  111. /* Description: */
  112. /* try to convert to sequence code format, compression and */
  113. /* don't use two way to search */
  114. /**********************************************************************/
  115. void PASCAL LoadUsrDicFile( // load user dic file into memory
  116. LPINSTDATAL lpInstL,
  117. LPIMEL lpImeL)
  118. {
  119. HANDLE hReadUsrDicMem;
  120. HANDLE hUsrDicFile;
  121. DWORD dwUsrDicFileSize;
  122. UINT uRecLen, uReadLen, uWriteLen;
  123. UINT uUsrDicSize;
  124. BOOL fRet;
  125. PSECURITY_ATTRIBUTES psa;
  126. // no user dictionary
  127. if (!lpImeL->szUsrDicMap[0]) {
  128. lpImeL->uUsrDicSize = 0;
  129. CloseHandle(lpInstL->hUsrDicMem);
  130. lpInstL->hUsrDicMem = NULL;
  131. lpImeL->fdwErrMsg &= ~(ERRMSG_LOAD_USRDIC | ERRMSG_MEM_USRDIC);
  132. return;
  133. }
  134. psa = CreateSecurityAttributes();
  135. if (lpInstL->hUsrDicMem) {
  136. // the memory is already here
  137. goto LoadUsrDicErrMsg;
  138. }
  139. hReadUsrDicMem = OpenFileMapping(FILE_MAP_READ, FALSE,
  140. lpImeL->szUsrDicMap);
  141. if (hReadUsrDicMem) {
  142. // another process already create a mapping file, we will use it
  143. goto LoadUsrDicMem;
  144. }
  145. // read the user dic file into memory
  146. hUsrDicFile = CreateFile(lpImeL->szUsrDic, GENERIC_READ,
  147. FILE_SHARE_READ|FILE_SHARE_WRITE,
  148. psa, OPEN_EXISTING,
  149. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  150. if (hUsrDicFile != INVALID_HANDLE_VALUE) { // OK
  151. goto OpenUsrDicFile;
  152. }
  153. // if the work station version, SHARE_WRITE may fail
  154. hUsrDicFile = CreateFile(lpImeL->szUsrDic, GENERIC_READ,
  155. FILE_SHARE_READ,
  156. psa, OPEN_EXISTING,
  157. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  158. OpenUsrDicFile:
  159. if (hUsrDicFile != INVALID_HANDLE_VALUE) { // OK
  160. lpImeL->fdwErrMsg &= ~(ERRMSG_LOAD_USRDIC);
  161. } else if (lpImeL->fdwErrMsg & ERRMSG_LOAD_USRDIC) {
  162. // already prompt error message before, no more
  163. FreeSecurityAttributes(psa);
  164. return;
  165. } else {
  166. TCHAR szFmtStr[64];
  167. TCHAR szErrMsg[2 * MAX_PATH];
  168. // temp use szIMEName as format string buffer of error message
  169. LoadString(hInst, IDS_FILE_OPEN_ERR, szFmtStr, sizeof(szFmtStr)/sizeof(TCHAR));
  170. wsprintf(szErrMsg, szFmtStr, lpImeL->szUsrDic);
  171. lpImeL->fdwErrMsg |= ERRMSG_LOAD_USRDIC;
  172. MessageBeep((UINT)-1);
  173. MessageBox((HWND)NULL, szErrMsg, lpImeL->szIMEName,
  174. MB_OK|MB_ICONHAND|MB_TASKMODAL|MB_TOPMOST);
  175. FreeSecurityAttributes(psa);
  176. return;
  177. }
  178. // one record length - only sequence code, now
  179. uRecLen = lpImeL->nMaxKey + 4;
  180. // read sequence code and internal code
  181. uReadLen = lpImeL->nMaxKey + 2;
  182. // length write into memory handle
  183. uWriteLen = lpImeL->nSeqBytes + 2;
  184. // get the length of the file
  185. dwUsrDicFileSize = GetFileSize(hUsrDicFile, (LPDWORD)NULL);
  186. uUsrDicSize = (UINT)(dwUsrDicFileSize - 256) / uRecLen * uWriteLen;
  187. // max EUDC chars
  188. lpInstL->hUsrDicMem = CreateFileMapping(INVALID_HANDLE_VALUE,
  189. psa, PAGE_READWRITE, 0, MAX_EUDC_CHARS * uWriteLen + 20,
  190. lpImeL->szUsrDicMap);
  191. if (!lpInstL->hUsrDicMem) {
  192. MemoryLess(
  193. #if defined(UNIIME)
  194. lpInstL, lpImeL,
  195. #endif
  196. ERRMSG_MEM_USRDIC);
  197. fRet = FALSE;
  198. } else if (GetLastError() == ERROR_ALREADY_EXISTS) {
  199. // another process also create another one, we will use it
  200. hReadUsrDicMem = OpenFileMapping(FILE_MAP_READ, FALSE,
  201. lpImeL->szUsrDicMap);
  202. CloseHandle(lpInstL->hUsrDicMem);
  203. CloseHandle(hUsrDicFile);
  204. if (hReadUsrDicMem != NULL) { // OK
  205. lpInstL->hUsrDicMem = hReadUsrDicMem;
  206. lpImeL->uUsrDicSize = uUsrDicSize;
  207. lpImeL->fdwErrMsg &= ~(ERRMSG_MEM_USRDIC);
  208. } else {
  209. MemoryLess(
  210. #if defined(UNIIME)
  211. lpInstL, lpImeL,
  212. #endif
  213. ERRMSG_MEM_USRDIC);
  214. lpInstL->hUsrDicMem = NULL;
  215. }
  216. FreeSecurityAttributes(psa);
  217. return;
  218. } else {
  219. fRet = ReadUsrDicToMem(
  220. #if defined(UNIIME)
  221. lpInstL, lpImeL,
  222. #endif
  223. hUsrDicFile, dwUsrDicFileSize, uUsrDicSize, uRecLen,
  224. uReadLen, uWriteLen);
  225. }
  226. CloseHandle(hUsrDicFile);
  227. if (!fRet) {
  228. if (lpInstL->hUsrDicMem) {
  229. CloseHandle(lpInstL->hUsrDicMem);
  230. lpInstL->hUsrDicMem = NULL;
  231. }
  232. FreeSecurityAttributes(psa);
  233. return;
  234. }
  235. // open a read only memory for EUDC table
  236. hReadUsrDicMem = OpenFileMapping(FILE_MAP_READ, FALSE,
  237. lpImeL->szUsrDicMap);
  238. // reopen a read file and close the original write file
  239. CloseHandle(lpInstL->hUsrDicMem);
  240. lpImeL->uUsrDicSize = uUsrDicSize;
  241. LoadUsrDicMem:
  242. lpInstL->hUsrDicMem = hReadUsrDicMem;
  243. LoadUsrDicErrMsg:
  244. lpImeL->fdwErrMsg &= ~(ERRMSG_LOAD_USRDIC | ERRMSG_MEM_USRDIC);
  245. FreeSecurityAttributes(psa);
  246. return;
  247. }
  248. /**********************************************************************/
  249. /* LoadOneTable() */
  250. /* Description: */
  251. /* memory handle & size of .TBL file will be assigned to */
  252. /* lpImeL */
  253. /* Eeturn Value: */
  254. /* length of directory of the .TBL file */
  255. /**********************************************************************/
  256. UINT PASCAL LoadOneTable( // load one of table file
  257. #if defined(UNIIME)
  258. LPINSTDATAL lpInstL,
  259. LPIMEL lpImeL,
  260. #endif
  261. LPTSTR szTable, // file name of .TBL
  262. UINT uIndex, // the index of array to store memory handle
  263. UINT uLen, // length of the directory
  264. LPTSTR szPath) // buffer for directory
  265. {
  266. HANDLE hTblFile;
  267. HGLOBAL hMap;
  268. DWORD dwFileSize;
  269. PSECURITY_ATTRIBUTES psa;
  270. if (lpInstL->hMapTbl[uIndex]) { // already loaded
  271. CloseHandle(lpInstL->hMapTbl[uIndex]);
  272. lpInstL->hMapTbl[uIndex] = (HANDLE)NULL;
  273. }
  274. psa = CreateSecurityAttributes();
  275. if (uLen) {
  276. lstrcpy((LPTSTR)&szPath[uLen], szTable);
  277. hTblFile = CreateFile(szPath, GENERIC_READ,
  278. FILE_SHARE_READ|FILE_SHARE_WRITE,
  279. psa, OPEN_EXISTING,
  280. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  281. if (hTblFile != INVALID_HANDLE_VALUE) {
  282. goto OpenDicFile;
  283. }
  284. // if the work station version, SHARE_WRITE will fail
  285. hTblFile = CreateFile(szPath, GENERIC_READ,
  286. FILE_SHARE_READ, psa,
  287. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  288. } else {
  289. // try system directory next
  290. uLen = GetSystemDirectory(szPath, MAX_PATH);
  291. if (szPath[uLen - 1] != '\\') { // consider N:\ ;
  292. szPath[uLen++] = '\\';
  293. }
  294. lstrcpy((LPTSTR)&szPath[uLen], szTable);
  295. hTblFile = CreateFile(szPath, GENERIC_READ,
  296. FILE_SHARE_READ|FILE_SHARE_WRITE,
  297. psa, OPEN_EXISTING,
  298. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  299. if (hTblFile != INVALID_HANDLE_VALUE) {
  300. goto OpenDicFile;
  301. }
  302. // if the work station version, SHARE_WRITE will fail
  303. hTblFile = CreateFile(szPath, GENERIC_READ,
  304. FILE_SHARE_READ, psa,
  305. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  306. }
  307. OpenDicFile:
  308. // can not find the table file
  309. if (hTblFile != INVALID_HANDLE_VALUE) { // OK
  310. } else if (lpImeL->fdwErrMsg & (ERRMSG_LOAD_0 << uIndex)) {
  311. // already prompt error message before, no more
  312. FreeSecurityAttributes(psa);
  313. return (0);
  314. } else { // prompt error message
  315. TCHAR szFmtStr[64];
  316. TCHAR szErrMsg[2 * MAX_PATH];
  317. #if defined(WINAR30)
  318. if(uIndex==4 || uIndex==5)
  319. {
  320. return (uLen);
  321. }
  322. #endif
  323. // temp use szIMEName as format string buffer of error message
  324. LoadString(hInst, IDS_FILE_OPEN_ERR, szFmtStr, sizeof(szFmtStr)/sizeof(TCHAR));
  325. wsprintf(szErrMsg, szFmtStr, szTable);
  326. lpImeL->fdwErrMsg |= ERRMSG_LOAD_0 << uIndex;
  327. MessageBeep((UINT)-1);
  328. MessageBox((HWND)NULL, szErrMsg, lpImeL->szIMEName,
  329. MB_OK|MB_ICONHAND|MB_TASKMODAL|MB_TOPMOST);
  330. FreeSecurityAttributes(psa);
  331. return (0);
  332. }
  333. lpImeL->fdwErrMsg &= ~(ERRMSG_LOAD_0 << uIndex);
  334. // create file mapping for IME tables
  335. hMap = CreateFileMapping((HANDLE)hTblFile, psa, PAGE_READONLY,
  336. 0, 0, szTable);
  337. dwFileSize = GetFileSize(hTblFile, (LPDWORD)NULL);
  338. CloseHandle(hTblFile);
  339. FreeSecurityAttributes(psa);
  340. if (!hMap) {
  341. MemoryLess(
  342. #if defined(UNIIME)
  343. lpInstL, lpImeL,
  344. #endif
  345. ERRMSG_MEM_0 << uIndex);
  346. return (0);
  347. }
  348. lpImeL->fdwErrMsg &= ~(ERRMSG_MEM_0 << uIndex);
  349. lpInstL->hMapTbl[uIndex] = hMap;
  350. // get file length
  351. lpImeL->uTblSize[uIndex] = dwFileSize;
  352. return (uLen);
  353. }
  354. #endif
  355. /**********************************************************************/
  356. /* LoadTable() */
  357. /* Return Value: */
  358. /* TRUE - successful, FALSE - failure */
  359. /**********************************************************************/
  360. BOOL PASCAL LoadTable( // check the table files of IME, include user
  361. // defined dictionary
  362. LPINSTDATAL lpInstL,
  363. LPIMEL lpImeL)
  364. {
  365. #if !defined(WINIME) && !defined(UNICDIME)
  366. int i;
  367. UINT uLen;
  368. TCHAR szBuf[MAX_PATH];
  369. #endif
  370. if (lpInstL->fdwTblLoad == TBL_LOADED) {
  371. return (TRUE);
  372. }
  373. #if !defined(WINIME) && !defined(UNICDIME)
  374. uLen = 0;
  375. // A15.TBL, A234.TBL, ACODE.TBL, / PHON.TBL, PHONPTR.TBL, PHONCODE.TBL,
  376. for (i = 0; i < MAX_IME_TABLES; i++) {
  377. if (!*lpImeL->szTblFile[i]) {
  378. } else if (uLen = LoadOneTable(
  379. #if defined(UNIIME)
  380. lpInstL, lpImeL,
  381. #endif
  382. lpImeL->szTblFile[i], i, uLen, szBuf)) {
  383. } else {
  384. int j;
  385. for (j = 0; j < i; j++) {
  386. if (lpInstL->hMapTbl[j]) {
  387. CloseHandle(lpInstL->hMapTbl[j]);
  388. lpInstL->hMapTbl[j] = (HANDLE)NULL;
  389. }
  390. }
  391. lpInstL->fdwTblLoad = TBL_LOADERR;
  392. return (FALSE);
  393. }
  394. }
  395. #endif
  396. lpInstL->fdwTblLoad = TBL_LOADED;
  397. #if !defined(WINIME) && !defined(UNICDIME)
  398. if (lpImeL->szUsrDic[0]) {
  399. LoadUsrDicFile(lpInstL, lpImeL);
  400. }
  401. #endif
  402. return (TRUE);
  403. }
  404. /**********************************************************************/
  405. /* FreeTable() */
  406. /**********************************************************************/
  407. void PASCAL FreeTable(
  408. LPINSTDATAL lpInstL)
  409. {
  410. #if !defined(WINIME) && !defined(UNICDIME)
  411. int i;
  412. // A15.TBL, A234.TBL, ACODE.TBL, / PHON.TBL, PHONPTR.TBL, PHONCODE.TBL,
  413. for (i = 0; i < MAX_IME_TABLES; i++) {
  414. if (lpInstL->hMapTbl[i]) {
  415. CloseHandle(lpInstL->hMapTbl[i]);
  416. lpInstL->hMapTbl[i] = (HANDLE)NULL;
  417. }
  418. }
  419. // do not need to free phrase data base, maybe next IME will use it
  420. // uniime.dll will free it on library detach time
  421. if (lpInstL->hUsrDicMem) {
  422. CloseHandle(lpInstL->hUsrDicMem);
  423. lpInstL->hUsrDicMem = (HANDLE)NULL;
  424. }
  425. #endif
  426. lpInstL->fdwTblLoad = TBL_NOTLOADED;
  427. return;
  428. }
  429. #endif // !defined(ROMANIME)