|
|
#include <windows.h>
#include <immdev.h>
#include "imeattr.h"
#include "imedefs.h"
#include "imerc.h"
#include "uniime.h"
BOOL IsBig5Character( WCHAR wChar );
/**********************************************************************/ /* AddPhraseString() */ /**********************************************************************/ DWORD PASCAL AddPhraseString( LPIMEL lpImeL, LPCANDIDATELIST lpCandList, DWORD dwPhraseOffset, DWORD dwPhraseNextOffset, DWORD dwStartLen, DWORD dwEndLen, DWORD dwAddCandLimit, BOOL fConvertCP) { HANDLE hLCPhraseTbl; LPWSTR lpLCPhraseTbl; LPWSTR lpStart, lpEnd; int iBytes; DWORD dwMaxCand; DWORD dwOffset; BOOL bIsNotBig5Char, bIsBig5OnlyMode;
// put the strings into candidate list
hLCPhraseTbl = OpenFileMapping(FILE_MAP_READ, FALSE, sImeG.szTblFile[1]); if (!hLCPhraseTbl) { return (0); }
lpLCPhraseTbl = (LPWSTR)MapViewOfFile(hLCPhraseTbl, FILE_MAP_READ, 0, 0, 0); if (!lpLCPhraseTbl) { dwOffset = 0; goto AddPhraseStringUnmap; }
if (lpImeL->fdwModeConfig & MODE_CONFIG_BIG5ONLY) bIsBig5OnlyMode = TRUE; else bIsBig5OnlyMode = FALSE;
lpStart = lpLCPhraseTbl + dwPhraseOffset; lpEnd = lpLCPhraseTbl + dwPhraseNextOffset;
if (!lpCandList) { // ask how many candidate list strings
dwOffset = 0;
for (lpStart; lpStart < lpEnd;) {
bIsNotBig5Char = FALSE;
for (; lpStart < lpEnd; lpStart++) { WORD uCode;
uCode = *lpStart;
// one string finished
#ifdef UNICODE
if (!uCode) { #else
if (!(uCode & 0x8000)) { #endif
lpStart++; break; }
if ( bIsBig5OnlyMode ) {
if ( IsBig5Character((WCHAR)uCode) == FALSE ) bIsNotBig5Char = TRUE; }
}
// if it is in Big5 Only Mode, and there is at least one char which is not
// in Big5 charset, we don't count this string
if ( bIsBig5OnlyMode && bIsNotBig5Char ) continue;
// string count plus 1
dwOffset++; }
goto AddPhraseStringUnmap; }
// the offset of dwOffset[0]
dwOffset = (DWORD)((LPBYTE)&lpCandList->dwOffset[0] - (LPBYTE)lpCandList);
if (lpCandList->dwSize < dwOffset) { return (0); }
// how many bytes of dwOffset[]
iBytes = lpCandList->dwOffset[0] - dwOffset;
// maybe the size is even smaller than it
for (dwMaxCand = 1; dwMaxCand < lpCandList->dwCount; dwMaxCand++) { if ((int)(lpCandList->dwOffset[dwMaxCand] - dwOffset) < iBytes) { iBytes = (int)(lpCandList->dwOffset[dwMaxCand] - dwOffset); } }
if (iBytes <= 0) { return (0); }
dwMaxCand = (DWORD)iBytes / sizeof(DWORD);
if (dwAddCandLimit < dwMaxCand) { dwMaxCand = dwAddCandLimit; }
if (lpCandList->dwCount >= dwMaxCand) { // Grow memory here and do something,
// if you still want to process it.
return (0); }
dwOffset = lpCandList->dwOffset[lpCandList->dwCount];
for (lpStart; lpStart < lpEnd;) { BOOL fStrEnd; DWORD dwStrLen, dwCharLen, dwStrByteLen, dwCharByteLen;
fStrEnd = FALSE; bIsNotBig5Char = FALSE;
// get the whole string
dwCharByteLen = sizeof(WCHAR); dwCharLen = sizeof(WCHAR) / sizeof(TCHAR);
for (dwStrLen = dwStrByteLen = 0; !fStrEnd && (lpStart < lpEnd); lpStart++, dwStrLen+= dwCharLen, dwStrByteLen += dwCharByteLen) { WORD uCode;
uCode = *lpStart;
// one string finished
#ifdef UNICODE
if (!uCode) { #else
if (!(uCode & 0x8000)) { #endif
fStrEnd = TRUE; #ifdef UNICODE
lpStart++; break; #else
uCode |= 0x8000; #endif
}
// if it is Big5Only Mode, we need to check if this char is in Big5 charset
if ( bIsBig5OnlyMode ) {
if ( !IsBig5Character((WCHAR)uCode) ) bIsNotBig5Char = TRUE;
}
#ifdef UNICODE
if (fConvertCP) { CHAR szCode[4];
dwCharLen = dwCharByteLen = WideCharToMultiByte( sImeG.uAnsiCodePage, WC_COMPOSITECHECK, (LPCWSTR)&uCode, 1, szCode, sizeof(szCode), NULL, NULL);
// because this BIG5 code, convert to BIG5 string
if (dwCharByteLen >= 2) { uCode = (BYTE)szCode[0] | ((UINT)(BYTE)szCode[1] << 8); } else { uCode = (UINT)szCode[0]; } } #else
// swap lead & second byte (as a string), UNICODE don't need it
uCode = HIBYTE(uCode) | (LOBYTE(uCode) << 8); #endif
if ((dwOffset + dwStrByteLen + dwCharByteLen) >= lpCandList->dwSize) { goto AddPhraseStringClose; }
// add this char into candidate list
#ifdef UNICODE
if (dwCharByteLen == sizeof(WCHAR)) { *(LPWSTR)((LPBYTE)lpCandList + dwOffset + dwStrByteLen) = (WCHAR)uCode; } else { *(LPSTR)((LPBYTE)lpCandList + dwOffset + dwStrByteLen) = (CHAR)uCode; } #else
*(LPWSTR)((LPBYTE)lpCandList + dwOffset + dwStrByteLen) = (WCHAR)uCode; #endif
}
if (dwStrLen < dwStartLen) { // the found string too short
continue; } else if (dwStrLen >= dwEndLen) { // the found string too long
continue; } else { }
// if it is in Big5 Only Mode, and there is at least one char which is not in Big5
// charset, we just ingore this string, do not put it into the candidate list
if ( bIsBig5OnlyMode && bIsNotBig5Char ) {
bIsNotBig5Char = FALSE; continue; }
if ((dwOffset + dwStrByteLen + sizeof(TCHAR)) >= lpCandList->dwSize) { goto AddPhraseStringClose; }
// null terminator
*(LPTSTR)((LPBYTE)lpCandList + dwOffset + dwStrByteLen) = TEXT('\0'); dwOffset += (dwStrByteLen + sizeof(TCHAR));
// add one string into candidate list
lpCandList->dwCount++;
if (lpCandList->dwCount >= dwMaxCand) { // Grow memory here and do something,
// if you still want to process it.
break; }
// string length plus size of the null terminator
lpCandList->dwOffset[lpCandList->dwCount] = dwOffset; }
AddPhraseStringUnmap: UnmapViewOfFile(lpLCPhraseTbl); AddPhraseStringClose: CloseHandle(hLCPhraseTbl);
return (dwOffset); }
/**********************************************************************/ /* UniSearchPhrasePrediction() */ /* Description: */ /* file format can be changed in different version for */ /* performance consideration, ISVs should not assume its format */ /* and serach these files by themselves */ /**********************************************************************/ DWORD WINAPI UniSearchPhrasePrediction( LPIMEL lpImeL, UINT uCodePage, LPCTSTR lpszStr, DWORD dwStrLen, LPCTSTR lpszReadStr, // Phonetic reading string
DWORD dwReadStrLen, DWORD dwStartLen, // find the string length >= this value
DWORD dwEndLen, // find the string length < this value
DWORD dwAddCandLimit, LPCANDIDATELIST lpCandList) { UINT uCode; HANDLE hLCPtrTbl; LPWORD lpLCPtrTbl; int iLo, iHi, iMid; BOOL fFound, fConvertCP; DWORD dwPhraseOffset, dwPhraseNextOffset;
if (uCodePage == NATIVE_CP) { fConvertCP = FALSE; #ifdef UNICODE
} else if (uCodePage == sImeG.uAnsiCodePage) { fConvertCP = TRUE; #endif
} else { return (0); }
if (dwStrLen != sizeof(WCHAR) / sizeof(TCHAR)) { return (0); }
if (dwStartLen >= dwEndLen) { return (0); }
#ifdef UNICODE
uCode = lpszStr[0]; #else
// swap lead byte & second byte, UNICODE don't need it
uCode = (BYTE)lpszStr[1]; *((LPBYTE)&uCode + 1) = (BYTE)lpszStr[0]; #endif
iLo = 0; #ifdef UNICODE
iHi = sImeG.uTblSize[0] / 6; #else
iHi = sImeG.uTblSize[0] / 4; #endif
iMid = (iHi + iLo) /2;
fFound = FALSE;
// LCPTR.TBL
hLCPtrTbl = OpenFileMapping(FILE_MAP_READ, FALSE, sImeG.szTblFile[0]); if (!hLCPtrTbl) { return (0); }
lpLCPtrTbl = MapViewOfFile(hLCPtrTbl, FILE_MAP_READ, 0, 0, 0); if (!lpLCPtrTbl) { goto SrchPhrPredictClose; }
// binary search on phrase table,
// one is multiple word phrase and the other is the two word phrase
for (; iLo <= iHi;) { LPWORD lpCurr;
#ifdef UNICODE
lpCurr = lpLCPtrTbl + 3 * iMid; #else
lpCurr = lpLCPtrTbl + 2 * iMid; #endif
if (uCode > *lpCurr) { iLo = iMid + 1; } else if (uCode < *lpCurr) { iHi = iMid - 1; } else { fFound = TRUE; // use it on TAB key
#ifdef UNICODE
dwPhraseOffset = *(LPUNADWORD)(lpCurr + 1); dwPhraseNextOffset = *(LPUNADWORD)(lpCurr + 1 + 3); #else
dwPhraseOffset = *(lpCurr + 1); dwPhraseNextOffset = *(lpCurr + 1 + 2); #endif
break; }
iMid = (iHi + iLo) /2; }
UnmapViewOfFile(lpLCPtrTbl);
SrchPhrPredictClose: CloseHandle(hLCPtrTbl);
if (!fFound) { return (0); }
// phrase string
return AddPhraseString(lpImeL,lpCandList, dwPhraseOffset, dwPhraseNextOffset, dwStartLen, dwEndLen, dwAddCandLimit, fConvertCP); }
/**********************************************************************/ /* UniSearchPhrasePredictionStub() */ /* Description: */ /* file format can be changed in different version for */ /* performance consideration, ISVs should not assume its format */ /* and serach these files by themselves */ /**********************************************************************/ DWORD WINAPI UniSearchPhrasePredictionStub( LPIMEL lpImeL, UINT uCodePage, LPCSTUBSTR lpszStr, DWORD dwStrLen, LPCSTUBSTR lpszReadStr, // Phonetic reading string
DWORD dwReadStrLen, DWORD dwStartLen, // find the string length >= this value
DWORD dwEndLen, // find the string length < this value
DWORD dwAddCandLimit, LPCANDIDATELIST lpCandList) { #ifdef UNICODE
LPTSTR lpszWideStr, lpszWideReadStr; DWORD dwWideStrLen, dwWideReadStrLen; DWORD dwWideStartLen, dwWideEndLen; DWORD dwWideAddCandList, dwRet; LPCANDIDATELIST lpWideCandList; LPBYTE lpbBuf;
if (uCodePage != sImeG.uAnsiCodePage) { return (0); }
dwRet = dwStrLen * sizeof(WCHAR) + dwReadStrLen * sizeof(WCHAR);
lpbBuf = (LPBYTE)GlobalAlloc(GPTR, dwRet); if ( lpbBuf == NULL ) return 0;
if (lpszStr) { lpszWideStr = (LPTSTR)lpbBuf;
dwWideStrLen = MultiByteToWideChar(sImeG.uAnsiCodePage, MB_PRECOMPOSED, lpszStr, dwStrLen, lpszWideStr, dwStrLen); } else { lpszWideStr = NULL; dwWideStrLen = 0; }
if (lpszReadStr) { lpszWideReadStr = (LPTSTR)(lpbBuf + dwStrLen * sizeof(WCHAR));
dwWideReadStrLen = MultiByteToWideChar(sImeG.uAnsiCodePage, MB_PRECOMPOSED, lpszReadStr, dwReadStrLen, lpszWideReadStr, dwReadStrLen); } else { lpszWideReadStr = NULL; dwWideReadStrLen = 0; }
dwRet = UniSearchPhrasePrediction(lpImeL,uCodePage, lpszWideStr, dwWideStrLen, lpszWideReadStr, dwWideReadStrLen, dwStartLen, dwEndLen, dwAddCandLimit, lpCandList);
// now, start W to A conversion and fliter the real limit here
GlobalFree((HGLOBAL)lpbBuf);
return (dwRet); #else
return (0); #endif
}
/**********************************************************************/ /* MemoryLack() */ /**********************************************************************/ void PASCAL MemoryLack( DWORD fdwErrMsg) { TCHAR szErrMsg[64]; TCHAR szIMEName[16];
if (sImeG.fdwErrMsg & fdwErrMsg) { // message already prompted
return; }
LoadString(hInst, IDS_MEM_LACK_FAIL, szErrMsg, sizeof(szErrMsg)/sizeof(TCHAR)); LoadString(hInst, IDS_IMENAME, szIMEName, sizeof(szIMEName)/sizeof(TCHAR) );
sImeG.fdwErrMsg |= fdwErrMsg; MessageBeep((UINT)-1); MessageBox((HWND)NULL, szErrMsg, szIMEName, MB_OK|MB_ICONHAND|MB_TASKMODAL|MB_TOPMOST);
return; }
/**********************************************************************/ /* LoadOneGlobalTable() */ /* Description: */ /* memory handle & size of .TBL file will be assigned to */ /* sImeG */ /* Eeturn Value: */ /* length of directory of the .TBL file */ /**********************************************************************/ UINT PASCAL LoadOneGlobalTable( // load one of table file
LPTSTR szTable, // file name of .TBL
UINT uIndex, // the index of array to store memory handle
UINT uLen, // length of the directory
LPTSTR szPath) // buffer for directory
{ HANDLE hTblFile; HGLOBAL hMap; TCHAR szFullPathFile[MAX_PATH]; PSECURITY_ATTRIBUTES psa;
CopyMemory(szFullPathFile, szPath, uLen * sizeof(TCHAR));
psa = CreateSecurityAttributes();
if (uLen) { CopyMemory(&szFullPathFile[uLen], szTable, sizeof(sImeG.szTblFile[0])); hTblFile = CreateFile(szFullPathFile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, psa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL); } else { // try system directory
uLen = GetSystemDirectory(szFullPathFile, MAX_PATH); if (szFullPathFile[uLen - 1] != TEXT('\\')) { // consider N:\ ;
szFullPathFile[uLen++] = TEXT('\\'); }
CopyMemory(&szFullPathFile[uLen], szTable, sizeof(sImeG.szTblFile[0])); hTblFile = CreateFile(szFullPathFile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, psa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
if (hTblFile != INVALID_HANDLE_VALUE) { goto CopyDicPath; }
// if the work station version, SHARE_WRITE will fail
hTblFile = CreateFile(szFullPathFile, GENERIC_READ, FILE_SHARE_READ, psa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
CopyDicPath: if (hTblFile != INVALID_HANDLE_VALUE) { CopyMemory(sImeG.szPhrasePath, szFullPathFile, uLen * sizeof(TCHAR)); sImeG.uPathLen = uLen; goto OpenDicFile; } }
OpenDicFile: // can not find the table file
if (hTblFile != INVALID_HANDLE_VALUE) { // OK
} else if (sImeG.fdwErrMsg & (ERRMSG_LOAD_0 << uIndex)) { // already prompt error message before, no more
FreeSecurityAttributes(psa); return (0); } else { // prompt error message
TCHAR szIMEName[64]; TCHAR szErrMsg[2 * MAX_PATH];
// temp use szIMEName as format string buffer of error message
LoadString(hInst, IDS_FILE_OPEN_FAIL, szIMEName, sizeof(szIMEName)/sizeof(TCHAR)); wsprintf(szErrMsg, szIMEName, szTable);
LoadString(hInst, IDS_IMENAME, szIMEName, sizeof(szIMEName)/sizeof(TCHAR)); sImeG.fdwErrMsg |= ERRMSG_LOAD_0 << uIndex; MessageBeep((UINT)-1); MessageBox((HWND)NULL, szErrMsg, szIMEName, MB_OK|MB_ICONHAND|MB_TASKMODAL|MB_TOPMOST); FreeSecurityAttributes(psa); return (0); }
sImeG.fdwErrMsg &= ~(ERRMSG_LOAD_0 << uIndex);
// create file mapping for IME tables
hMap = CreateFileMapping((HANDLE)hTblFile, psa, PAGE_READONLY, 0, 0, szTable);
if (!hMap) { MemoryLack(ERRMSG_MEM_0 << uIndex); CloseHandle(hTblFile); FreeSecurityAttributes(psa); return(0); }
sImeG.fdwErrMsg &= ~(ERRMSG_MEM_0 << uIndex);
sInstG.hMapTbl[uIndex] = hMap;
// get file length
sImeG.uTblSize[uIndex] = GetFileSize(hTblFile, (LPDWORD)NULL);
CloseHandle(hTblFile); FreeSecurityAttributes(psa);
return (uLen); }
/**********************************************************************/ /* LoadPhraseTable() */ /* Return Value: */ /* TRUE - successful, FALSE - failure */ /**********************************************************************/ BOOL PASCAL LoadPhraseTable( // load the phrase tables
UINT uLen, // length of the directory
LPTSTR szPath) // buffer for directory
{ int i;
for (i = 0; i < MAX_PHRASE_TABLES; i++) { if (!*sImeG.szTblFile[i]) { } else if (sInstG.hMapTbl[i]) { // already loaded
} else if (uLen = LoadOneGlobalTable(sImeG.szTblFile[i], i, uLen, szPath)) { } else { int j;
for (j = 0; j < i; j++) { if (sInstG.hMapTbl[j]) { CloseHandle(sInstG.hMapTbl[j]); sInstG.hMapTbl[j] = (HANDLE)NULL; } }
return (FALSE); } }
return (TRUE); }
|