Leaked source code of windows server 2003
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.

617 lines
19 KiB

  1. #include <windows.h>
  2. #include <immdev.h>
  3. #include "imeattr.h"
  4. #include "imedefs.h"
  5. #include "imerc.h"
  6. #include "uniime.h"
  7. BOOL IsBig5Character( WCHAR wChar );
  8. /**********************************************************************/
  9. /* AddPhraseString() */
  10. /**********************************************************************/
  11. DWORD PASCAL AddPhraseString(
  12. LPIMEL lpImeL,
  13. LPCANDIDATELIST lpCandList,
  14. DWORD dwPhraseOffset,
  15. DWORD dwPhraseNextOffset,
  16. DWORD dwStartLen,
  17. DWORD dwEndLen,
  18. DWORD dwAddCandLimit,
  19. BOOL fConvertCP)
  20. {
  21. HANDLE hLCPhraseTbl;
  22. LPWSTR lpLCPhraseTbl;
  23. LPWSTR lpStart, lpEnd;
  24. int iBytes;
  25. DWORD dwMaxCand;
  26. DWORD dwOffset;
  27. BOOL bIsNotBig5Char, bIsBig5OnlyMode;
  28. // put the strings into candidate list
  29. hLCPhraseTbl = OpenFileMapping(FILE_MAP_READ, FALSE,
  30. sImeG.szTblFile[1]);
  31. if (!hLCPhraseTbl) {
  32. return (0);
  33. }
  34. lpLCPhraseTbl = (LPWSTR)MapViewOfFile(hLCPhraseTbl, FILE_MAP_READ,
  35. 0, 0, 0);
  36. if (!lpLCPhraseTbl) {
  37. dwOffset = 0;
  38. goto AddPhraseStringUnmap;
  39. }
  40. if (lpImeL->fdwModeConfig & MODE_CONFIG_BIG5ONLY)
  41. bIsBig5OnlyMode = TRUE;
  42. else
  43. bIsBig5OnlyMode = FALSE;
  44. lpStart = lpLCPhraseTbl + dwPhraseOffset;
  45. lpEnd = lpLCPhraseTbl + dwPhraseNextOffset;
  46. if (!lpCandList) {
  47. // ask how many candidate list strings
  48. dwOffset = 0;
  49. for (lpStart; lpStart < lpEnd;) {
  50. bIsNotBig5Char = FALSE;
  51. for (; lpStart < lpEnd; lpStart++) {
  52. WORD uCode;
  53. uCode = *lpStart;
  54. // one string finished
  55. #ifdef UNICODE
  56. if (!uCode) {
  57. #else
  58. if (!(uCode & 0x8000)) {
  59. #endif
  60. lpStart++;
  61. break;
  62. }
  63. if ( bIsBig5OnlyMode ) {
  64. if ( IsBig5Character((WCHAR)uCode) == FALSE )
  65. bIsNotBig5Char = TRUE;
  66. }
  67. }
  68. // if it is in Big5 Only Mode, and there is at least one char which is not
  69. // in Big5 charset, we don't count this string
  70. if ( bIsBig5OnlyMode && bIsNotBig5Char )
  71. continue;
  72. // string count plus 1
  73. dwOffset++;
  74. }
  75. goto AddPhraseStringUnmap;
  76. }
  77. // the offset of dwOffset[0]
  78. dwOffset = (DWORD)((LPBYTE)&lpCandList->dwOffset[0] - (LPBYTE)lpCandList);
  79. if (lpCandList->dwSize < dwOffset) {
  80. return (0);
  81. }
  82. // how many bytes of dwOffset[]
  83. iBytes = lpCandList->dwOffset[0] - dwOffset;
  84. // maybe the size is even smaller than it
  85. for (dwMaxCand = 1; dwMaxCand < lpCandList->dwCount; dwMaxCand++) {
  86. if ((int)(lpCandList->dwOffset[dwMaxCand] - dwOffset) < iBytes) {
  87. iBytes = (int)(lpCandList->dwOffset[dwMaxCand] - dwOffset);
  88. }
  89. }
  90. if (iBytes <= 0) {
  91. return (0);
  92. }
  93. dwMaxCand = (DWORD)iBytes / sizeof(DWORD);
  94. if (dwAddCandLimit < dwMaxCand) {
  95. dwMaxCand = dwAddCandLimit;
  96. }
  97. if (lpCandList->dwCount >= dwMaxCand) {
  98. // Grow memory here and do something,
  99. // if you still want to process it.
  100. return (0);
  101. }
  102. dwOffset = lpCandList->dwOffset[lpCandList->dwCount];
  103. for (lpStart; lpStart < lpEnd;) {
  104. BOOL fStrEnd;
  105. DWORD dwStrLen, dwCharLen, dwStrByteLen, dwCharByteLen;
  106. fStrEnd = FALSE;
  107. bIsNotBig5Char = FALSE;
  108. // get the whole string
  109. dwCharByteLen = sizeof(WCHAR);
  110. dwCharLen = sizeof(WCHAR) / sizeof(TCHAR);
  111. for (dwStrLen = dwStrByteLen = 0; !fStrEnd && (lpStart < lpEnd);
  112. lpStart++, dwStrLen+= dwCharLen, dwStrByteLen += dwCharByteLen) {
  113. WORD uCode;
  114. uCode = *lpStart;
  115. // one string finished
  116. #ifdef UNICODE
  117. if (!uCode) {
  118. #else
  119. if (!(uCode & 0x8000)) {
  120. #endif
  121. fStrEnd = TRUE;
  122. #ifdef UNICODE
  123. lpStart++;
  124. break;
  125. #else
  126. uCode |= 0x8000;
  127. #endif
  128. }
  129. // if it is Big5Only Mode, we need to check if this char is in Big5 charset
  130. if ( bIsBig5OnlyMode ) {
  131. if ( !IsBig5Character((WCHAR)uCode) )
  132. bIsNotBig5Char = TRUE;
  133. }
  134. #ifdef UNICODE
  135. if (fConvertCP) {
  136. CHAR szCode[4];
  137. dwCharLen = dwCharByteLen = WideCharToMultiByte(
  138. sImeG.uAnsiCodePage, WC_COMPOSITECHECK,
  139. (LPCWSTR)&uCode, 1, szCode, sizeof(szCode), NULL, NULL);
  140. // because this BIG5 code, convert to BIG5 string
  141. if (dwCharByteLen >= 2) {
  142. uCode = (BYTE)szCode[0] | ((UINT)(BYTE)szCode[1] << 8);
  143. } else {
  144. uCode = (UINT)szCode[0];
  145. }
  146. }
  147. #else
  148. // swap lead & second byte (as a string), UNICODE don't need it
  149. uCode = HIBYTE(uCode) | (LOBYTE(uCode) << 8);
  150. #endif
  151. if ((dwOffset + dwStrByteLen + dwCharByteLen) >=
  152. lpCandList->dwSize) {
  153. goto AddPhraseStringClose;
  154. }
  155. // add this char into candidate list
  156. #ifdef UNICODE
  157. if (dwCharByteLen == sizeof(WCHAR)) {
  158. *(LPWSTR)((LPBYTE)lpCandList + dwOffset + dwStrByteLen) =
  159. (WCHAR)uCode;
  160. } else {
  161. *(LPSTR)((LPBYTE)lpCandList + dwOffset + dwStrByteLen) =
  162. (CHAR)uCode;
  163. }
  164. #else
  165. *(LPWSTR)((LPBYTE)lpCandList + dwOffset + dwStrByteLen) =
  166. (WCHAR)uCode;
  167. #endif
  168. }
  169. if (dwStrLen < dwStartLen) {
  170. // the found string too short
  171. continue;
  172. } else if (dwStrLen >= dwEndLen) {
  173. // the found string too long
  174. continue;
  175. } else {
  176. }
  177. // if it is in Big5 Only Mode, and there is at least one char which is not in Big5
  178. // charset, we just ingore this string, do not put it into the candidate list
  179. if ( bIsBig5OnlyMode && bIsNotBig5Char ) {
  180. bIsNotBig5Char = FALSE;
  181. continue;
  182. }
  183. if ((dwOffset + dwStrByteLen + sizeof(TCHAR)) >= lpCandList->dwSize) {
  184. goto AddPhraseStringClose;
  185. }
  186. // null terminator
  187. *(LPTSTR)((LPBYTE)lpCandList + dwOffset + dwStrByteLen) = TEXT('\0');
  188. dwOffset += (dwStrByteLen + sizeof(TCHAR));
  189. // add one string into candidate list
  190. lpCandList->dwCount++;
  191. if (lpCandList->dwCount >= dwMaxCand) {
  192. // Grow memory here and do something,
  193. // if you still want to process it.
  194. break;
  195. }
  196. // string length plus size of the null terminator
  197. lpCandList->dwOffset[lpCandList->dwCount] = dwOffset;
  198. }
  199. AddPhraseStringUnmap:
  200. UnmapViewOfFile(lpLCPhraseTbl);
  201. AddPhraseStringClose:
  202. CloseHandle(hLCPhraseTbl);
  203. return (dwOffset);
  204. }
  205. /**********************************************************************/
  206. /* UniSearchPhrasePrediction() */
  207. /* Description: */
  208. /* file format can be changed in different version for */
  209. /* performance consideration, ISVs should not assume its format */
  210. /* and serach these files by themselves */
  211. /**********************************************************************/
  212. DWORD WINAPI UniSearchPhrasePrediction(
  213. LPIMEL lpImeL,
  214. UINT uCodePage,
  215. LPCTSTR lpszStr,
  216. DWORD dwStrLen,
  217. LPCTSTR lpszReadStr, // Phonetic reading string
  218. DWORD dwReadStrLen,
  219. DWORD dwStartLen, // find the string length >= this value
  220. DWORD dwEndLen, // find the string length < this value
  221. DWORD dwAddCandLimit,
  222. LPCANDIDATELIST lpCandList)
  223. {
  224. UINT uCode;
  225. HANDLE hLCPtrTbl;
  226. LPWORD lpLCPtrTbl;
  227. int iLo, iHi, iMid;
  228. BOOL fFound, fConvertCP;
  229. DWORD dwPhraseOffset, dwPhraseNextOffset;
  230. if (uCodePage == NATIVE_CP) {
  231. fConvertCP = FALSE;
  232. #ifdef UNICODE
  233. } else if (uCodePage == sImeG.uAnsiCodePage) {
  234. fConvertCP = TRUE;
  235. #endif
  236. } else {
  237. return (0);
  238. }
  239. if (dwStrLen != sizeof(WCHAR) / sizeof(TCHAR)) {
  240. return (0);
  241. }
  242. if (dwStartLen >= dwEndLen) {
  243. return (0);
  244. }
  245. #ifdef UNICODE
  246. uCode = lpszStr[0];
  247. #else
  248. // swap lead byte & second byte, UNICODE don't need it
  249. uCode = (BYTE)lpszStr[1];
  250. *((LPBYTE)&uCode + 1) = (BYTE)lpszStr[0];
  251. #endif
  252. iLo = 0;
  253. #ifdef UNICODE
  254. iHi = sImeG.uTblSize[0] / 6;
  255. #else
  256. iHi = sImeG.uTblSize[0] / 4;
  257. #endif
  258. iMid = (iHi + iLo) /2;
  259. fFound = FALSE;
  260. // LCPTR.TBL
  261. hLCPtrTbl = OpenFileMapping(FILE_MAP_READ, FALSE, sImeG.szTblFile[0]);
  262. if (!hLCPtrTbl) {
  263. return (0);
  264. }
  265. lpLCPtrTbl = MapViewOfFile(hLCPtrTbl, FILE_MAP_READ, 0, 0, 0);
  266. if (!lpLCPtrTbl) {
  267. goto SrchPhrPredictClose;
  268. }
  269. // binary search on phrase table,
  270. // one is multiple word phrase and the other is the two word phrase
  271. for (; iLo <= iHi;) {
  272. LPWORD lpCurr;
  273. #ifdef UNICODE
  274. lpCurr = lpLCPtrTbl + 3 * iMid;
  275. #else
  276. lpCurr = lpLCPtrTbl + 2 * iMid;
  277. #endif
  278. if (uCode > *lpCurr) {
  279. iLo = iMid + 1;
  280. } else if (uCode < *lpCurr) {
  281. iHi = iMid - 1;
  282. } else {
  283. fFound = TRUE;
  284. // use it on TAB key
  285. #ifdef UNICODE
  286. dwPhraseOffset = *(LPUNADWORD)(lpCurr + 1);
  287. dwPhraseNextOffset = *(LPUNADWORD)(lpCurr + 1 + 3);
  288. #else
  289. dwPhraseOffset = *(lpCurr + 1);
  290. dwPhraseNextOffset = *(lpCurr + 1 + 2);
  291. #endif
  292. break;
  293. }
  294. iMid = (iHi + iLo) /2;
  295. }
  296. UnmapViewOfFile(lpLCPtrTbl);
  297. SrchPhrPredictClose:
  298. CloseHandle(hLCPtrTbl);
  299. if (!fFound) {
  300. return (0);
  301. }
  302. // phrase string
  303. return AddPhraseString(lpImeL,lpCandList, dwPhraseOffset, dwPhraseNextOffset,
  304. dwStartLen, dwEndLen, dwAddCandLimit, fConvertCP);
  305. }
  306. /**********************************************************************/
  307. /* UniSearchPhrasePredictionStub() */
  308. /* Description: */
  309. /* file format can be changed in different version for */
  310. /* performance consideration, ISVs should not assume its format */
  311. /* and serach these files by themselves */
  312. /**********************************************************************/
  313. DWORD WINAPI UniSearchPhrasePredictionStub(
  314. LPIMEL lpImeL,
  315. UINT uCodePage,
  316. LPCSTUBSTR lpszStr,
  317. DWORD dwStrLen,
  318. LPCSTUBSTR lpszReadStr, // Phonetic reading string
  319. DWORD dwReadStrLen,
  320. DWORD dwStartLen, // find the string length >= this value
  321. DWORD dwEndLen, // find the string length < this value
  322. DWORD dwAddCandLimit,
  323. LPCANDIDATELIST lpCandList)
  324. {
  325. #ifdef UNICODE
  326. LPTSTR lpszWideStr, lpszWideReadStr;
  327. DWORD dwWideStrLen, dwWideReadStrLen;
  328. DWORD dwWideStartLen, dwWideEndLen;
  329. DWORD dwWideAddCandList, dwRet;
  330. LPCANDIDATELIST lpWideCandList;
  331. LPBYTE lpbBuf;
  332. if (uCodePage != sImeG.uAnsiCodePage) {
  333. return (0);
  334. }
  335. dwRet = dwStrLen * sizeof(WCHAR) + dwReadStrLen * sizeof(WCHAR);
  336. lpbBuf = (LPBYTE)GlobalAlloc(GPTR, dwRet);
  337. if ( lpbBuf == NULL )
  338. return 0;
  339. if (lpszStr) {
  340. lpszWideStr = (LPTSTR)lpbBuf;
  341. dwWideStrLen = MultiByteToWideChar(sImeG.uAnsiCodePage,
  342. MB_PRECOMPOSED, lpszStr, dwStrLen,
  343. lpszWideStr, dwStrLen);
  344. } else {
  345. lpszWideStr = NULL;
  346. dwWideStrLen = 0;
  347. }
  348. if (lpszReadStr) {
  349. lpszWideReadStr = (LPTSTR)(lpbBuf + dwStrLen * sizeof(WCHAR));
  350. dwWideReadStrLen = MultiByteToWideChar(sImeG.uAnsiCodePage,
  351. MB_PRECOMPOSED, lpszReadStr, dwReadStrLen,
  352. lpszWideReadStr, dwReadStrLen);
  353. } else {
  354. lpszWideReadStr = NULL;
  355. dwWideReadStrLen = 0;
  356. }
  357. dwRet = UniSearchPhrasePrediction(lpImeL,uCodePage, lpszWideStr, dwWideStrLen,
  358. lpszWideReadStr, dwWideReadStrLen, dwStartLen, dwEndLen,
  359. dwAddCandLimit, lpCandList);
  360. // now, start W to A conversion and fliter the real limit here
  361. GlobalFree((HGLOBAL)lpbBuf);
  362. return (dwRet);
  363. #else
  364. return (0);
  365. #endif
  366. }
  367. /**********************************************************************/
  368. /* MemoryLack() */
  369. /**********************************************************************/
  370. void PASCAL MemoryLack(
  371. DWORD fdwErrMsg)
  372. {
  373. TCHAR szErrMsg[64];
  374. TCHAR szIMEName[16];
  375. if (sImeG.fdwErrMsg & fdwErrMsg) {
  376. // message already prompted
  377. return;
  378. }
  379. LoadString(hInst, IDS_MEM_LACK_FAIL, szErrMsg, sizeof(szErrMsg)/sizeof(TCHAR));
  380. LoadString(hInst, IDS_IMENAME, szIMEName, sizeof(szIMEName)/sizeof(TCHAR) );
  381. sImeG.fdwErrMsg |= fdwErrMsg;
  382. MessageBeep((UINT)-1);
  383. MessageBox((HWND)NULL, szErrMsg, szIMEName,
  384. MB_OK|MB_ICONHAND|MB_TASKMODAL|MB_TOPMOST);
  385. return;
  386. }
  387. /**********************************************************************/
  388. /* LoadOneGlobalTable() */
  389. /* Description: */
  390. /* memory handle & size of .TBL file will be assigned to */
  391. /* sImeG */
  392. /* Eeturn Value: */
  393. /* length of directory of the .TBL file */
  394. /**********************************************************************/
  395. UINT PASCAL LoadOneGlobalTable( // load one of table file
  396. LPTSTR szTable, // file name of .TBL
  397. UINT uIndex, // the index of array to store memory handle
  398. UINT uLen, // length of the directory
  399. LPTSTR szPath) // buffer for directory
  400. {
  401. HANDLE hTblFile;
  402. HGLOBAL hMap;
  403. TCHAR szFullPathFile[MAX_PATH];
  404. PSECURITY_ATTRIBUTES psa;
  405. CopyMemory(szFullPathFile, szPath, uLen * sizeof(TCHAR));
  406. psa = CreateSecurityAttributes();
  407. if (uLen) {
  408. CopyMemory(&szFullPathFile[uLen], szTable, sizeof(sImeG.szTblFile[0]));
  409. hTblFile = CreateFile(szFullPathFile, GENERIC_READ,
  410. FILE_SHARE_READ|FILE_SHARE_WRITE,
  411. psa, OPEN_EXISTING,
  412. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  413. } else {
  414. // try system directory
  415. uLen = GetSystemDirectory(szFullPathFile, MAX_PATH);
  416. if (szFullPathFile[uLen - 1] != TEXT('\\')) { // consider N:\ ;
  417. szFullPathFile[uLen++] = TEXT('\\');
  418. }
  419. CopyMemory(&szFullPathFile[uLen], szTable, sizeof(sImeG.szTblFile[0]));
  420. hTblFile = CreateFile(szFullPathFile, GENERIC_READ,
  421. FILE_SHARE_READ|FILE_SHARE_WRITE,
  422. psa, OPEN_EXISTING,
  423. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  424. if (hTblFile != INVALID_HANDLE_VALUE) {
  425. goto CopyDicPath;
  426. }
  427. // if the work station version, SHARE_WRITE will fail
  428. hTblFile = CreateFile(szFullPathFile, GENERIC_READ,
  429. FILE_SHARE_READ,
  430. psa, OPEN_EXISTING,
  431. FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
  432. CopyDicPath:
  433. if (hTblFile != INVALID_HANDLE_VALUE) {
  434. CopyMemory(sImeG.szPhrasePath, szFullPathFile, uLen * sizeof(TCHAR));
  435. sImeG.uPathLen = uLen;
  436. goto OpenDicFile;
  437. }
  438. }
  439. OpenDicFile:
  440. // can not find the table file
  441. if (hTblFile != INVALID_HANDLE_VALUE) { // OK
  442. } else if (sImeG.fdwErrMsg & (ERRMSG_LOAD_0 << uIndex)) {
  443. // already prompt error message before, no more
  444. FreeSecurityAttributes(psa);
  445. return (0);
  446. } else { // prompt error message
  447. TCHAR szIMEName[64];
  448. TCHAR szErrMsg[2 * MAX_PATH];
  449. // temp use szIMEName as format string buffer of error message
  450. LoadString(hInst, IDS_FILE_OPEN_FAIL, szIMEName, sizeof(szIMEName)/sizeof(TCHAR));
  451. wsprintf(szErrMsg, szIMEName, szTable);
  452. LoadString(hInst, IDS_IMENAME, szIMEName, sizeof(szIMEName)/sizeof(TCHAR));
  453. sImeG.fdwErrMsg |= ERRMSG_LOAD_0 << uIndex;
  454. MessageBeep((UINT)-1);
  455. MessageBox((HWND)NULL, szErrMsg, szIMEName,
  456. MB_OK|MB_ICONHAND|MB_TASKMODAL|MB_TOPMOST);
  457. FreeSecurityAttributes(psa);
  458. return (0);
  459. }
  460. sImeG.fdwErrMsg &= ~(ERRMSG_LOAD_0 << uIndex);
  461. // create file mapping for IME tables
  462. hMap = CreateFileMapping((HANDLE)hTblFile, psa, PAGE_READONLY,
  463. 0, 0, szTable);
  464. if (!hMap) {
  465. MemoryLack(ERRMSG_MEM_0 << uIndex);
  466. CloseHandle(hTblFile);
  467. FreeSecurityAttributes(psa);
  468. return(0);
  469. }
  470. sImeG.fdwErrMsg &= ~(ERRMSG_MEM_0 << uIndex);
  471. sInstG.hMapTbl[uIndex] = hMap;
  472. // get file length
  473. sImeG.uTblSize[uIndex] = GetFileSize(hTblFile, (LPDWORD)NULL);
  474. CloseHandle(hTblFile);
  475. FreeSecurityAttributes(psa);
  476. return (uLen);
  477. }
  478. /**********************************************************************/
  479. /* LoadPhraseTable() */
  480. /* Return Value: */
  481. /* TRUE - successful, FALSE - failure */
  482. /**********************************************************************/
  483. BOOL PASCAL LoadPhraseTable( // load the phrase tables
  484. UINT uLen, // length of the directory
  485. LPTSTR szPath) // buffer for directory
  486. {
  487. int i;
  488. for (i = 0; i < MAX_PHRASE_TABLES; i++) {
  489. if (!*sImeG.szTblFile[i]) {
  490. } else if (sInstG.hMapTbl[i]) { // already loaded
  491. } else if (uLen = LoadOneGlobalTable(sImeG.szTblFile[i], i,
  492. uLen, szPath)) {
  493. } else {
  494. int j;
  495. for (j = 0; j < i; j++) {
  496. if (sInstG.hMapTbl[j]) {
  497. CloseHandle(sInstG.hMapTbl[j]);
  498. sInstG.hMapTbl[j] = (HANDLE)NULL;
  499. }
  500. }
  501. return (FALSE);
  502. }
  503. }
  504. return (TRUE);
  505. }