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.
439 lines
14 KiB
439 lines
14 KiB
/****************************************************************************
|
|
HANJA.CPP
|
|
|
|
Owner: cslim
|
|
Copyright (c) 1997-1999 Microsoft Corporation
|
|
|
|
Hanja conversion and dictionary lookup functions. Dictionary index is
|
|
stored as globally shared memory.
|
|
|
|
History:
|
|
14-JUL-1999 cslim Copied from IME98 source tree
|
|
*****************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#include "apientry.h"
|
|
#include "ui.h"
|
|
#include "debug.h"
|
|
#include "lexheader.h"
|
|
#include "hanja.h"
|
|
#include "immsec.h"
|
|
#include "winex.h"
|
|
#include "common.h"
|
|
#include <WINERROR.H>
|
|
|
|
// NT5 Globally shared memory.
|
|
const TCHAR IMEKR_LEX_SHAREDDATA_MUTEX_NAME[] = TEXT("{C5AFBBF9-8383-490c-AA9E-4FE93FA05512}");
|
|
const TCHAR IMEKR_LEX_SHAREDDATA_NAME[] = TEXT("ImeKrLexHangul2Hanja.SharedMemory");
|
|
|
|
|
|
UINT vuNumofK0=0, vuNumofK1=0;
|
|
WCHAR vwcHangul=0;
|
|
|
|
// Private data
|
|
PRIVATE BOOL vfLexOpen = fFalse;
|
|
PRIVATE HANDLE vhLex=0;
|
|
PRIVATE HANDLE vhLexIndexTbl=0;
|
|
PRIVATE UINT vuNumOfHangulEntry=0;
|
|
PRIVATE DWORD viBufferStart=0; // seek point
|
|
|
|
// Private functions
|
|
PRIVATE BOOL OpenLex();
|
|
//static VOID ClearHanjaSenseArray();
|
|
PRIVATE INT SearchHanjaIndex(WCHAR wHChar, _LexIndex *pLexIndexTbl);
|
|
|
|
/*
|
|
CHanja::CHanja()
|
|
{
|
|
vfLexOpen = fFalse;
|
|
vhLex = vhLexIndexTbl = vhLexIndexTbl = NULL;
|
|
vuNumOfHangulEntry = 0;
|
|
|
|
for (int i=0; i<MAX_CANDSTR; i++)
|
|
vprwszHanjaMeaning[i] = 0;
|
|
}
|
|
*/
|
|
|
|
BOOL EnsureHanjaLexLoaded()
|
|
{
|
|
_DictHeader *pLexHeader;
|
|
DWORD dwReadBytes;
|
|
CHAR szLexFileName[MAX_PATH], szLexPathExpanded[MAX_PATH];
|
|
HKEY hKey;
|
|
DWORD dwType, dwCb;
|
|
CIMEData ImeData;
|
|
|
|
if (vfLexOpen)
|
|
return fTrue;
|
|
|
|
// Get Lex file name with full path
|
|
szLexFileName[0] = 0;
|
|
szLexPathExpanded[0] = 0;
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, g_szIMERootKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
|
|
{
|
|
dwCb = sizeof(szLexFileName);
|
|
dwType = REG_SZ;
|
|
|
|
if (RegQueryValueEx(hKey, g_szDictionary, NULL, &dwType, (LPBYTE)szLexFileName, &dwCb) == ERROR_SUCCESS)
|
|
ExpandEnvironmentStrings(szLexFileName, szLexPathExpanded, sizeof(szLexPathExpanded));
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
DbgAssert(szLexPathExpanded[0] != 0);
|
|
if (szLexPathExpanded[0] == 0)
|
|
return fFalse;
|
|
|
|
vhLex = CreateFile(szLexPathExpanded, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, NULL);
|
|
if (vhLex==INVALID_HANDLE_VALUE)
|
|
{
|
|
DbgAssert(0);
|
|
return fFalse;
|
|
}
|
|
|
|
pLexHeader = new _DictHeader;
|
|
if (!pLexHeader)
|
|
return fFalse;
|
|
|
|
if (ReadFile(vhLex, pLexHeader, sizeof(_DictHeader), &dwReadBytes, 0) == 0 || (dwReadBytes != sizeof(_DictHeader)))
|
|
{
|
|
DbgAssert(0);
|
|
return fFalse;
|
|
}
|
|
|
|
// Set member vars
|
|
vuNumOfHangulEntry = pLexHeader->NumOfHangulEntry;
|
|
viBufferStart = pLexHeader->iBufferStart;
|
|
|
|
if (pLexHeader->Version < LEX_VERSION || pLexHeader->Version > LEX_COMPATIBLE_VERSION_LIMIT )
|
|
{
|
|
delete pLexHeader;
|
|
return fFalse;
|
|
}
|
|
|
|
if (lstrcmpA(pLexHeader->COPYRIGHT_HEADER, COPYRIGHT_STR))
|
|
{
|
|
delete pLexHeader;
|
|
return fFalse;
|
|
}
|
|
|
|
// Read Index table
|
|
SetFilePointer(vhLex, pLexHeader->Headersize, 0, FILE_BEGIN);
|
|
delete pLexHeader;
|
|
|
|
return OpenLex();
|
|
}
|
|
|
|
BOOL OpenLex()
|
|
{
|
|
BOOL fRet = fFalse;
|
|
_LexIndex *pLexIndexTbl;
|
|
HANDLE hMutex;
|
|
DWORD dwReadBytes;
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Mapping Lex file
|
|
// The dictionary index is shared data between all IME instance
|
|
hMutex=CreateMutex(GetIMESecurityAttributes(), fFalse, IMEKR_LEX_SHAREDDATA_MUTEX_NAME);
|
|
|
|
if (hMutex != NULL)
|
|
{
|
|
if (DoEnterCriticalSection(hMutex) == fFalse)
|
|
goto ExitOpenLexCritSection;
|
|
|
|
vhLexIndexTbl = OpenFileMapping(FILE_MAP_READ, fTrue, IMEKR_LEX_SHAREDDATA_NAME);
|
|
|
|
if(vhLexIndexTbl)
|
|
{
|
|
Dbg(DBGID_Hanja|DBGID_Mem, TEXT("CHanja::OpenLex() - File mapping already exists"));
|
|
fRet = fTrue;
|
|
}
|
|
else
|
|
{
|
|
// if no file mapping exist
|
|
vhLexIndexTbl = CreateFileMapping(INVALID_HANDLE_VALUE, GetIMESecurityAttributes(), PAGE_READWRITE,
|
|
0, sizeof(_LexIndex)*(vuNumOfHangulEntry),
|
|
IMEKR_LEX_SHAREDDATA_NAME);
|
|
|
|
if (vhLexIndexTbl)
|
|
{
|
|
Dbg(DBGID_Hanja|DBGID_Mem, TEXT("CHanja::OpenLex() - File mapping Created"));
|
|
pLexIndexTbl = (_LexIndex*)MapViewOfFile(vhLexIndexTbl, FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
|
|
if (!pLexIndexTbl)
|
|
goto ExitOpenLexCritSection;
|
|
|
|
if (ReadFile(vhLex, pLexIndexTbl, vuNumOfHangulEntry*sizeof(_LexIndex), &dwReadBytes, 0) != 0 &&
|
|
dwReadBytes == vuNumOfHangulEntry*sizeof(_LexIndex))
|
|
{
|
|
fRet = fTrue;
|
|
}
|
|
else
|
|
{
|
|
fRet = fFalse;
|
|
}
|
|
|
|
UnmapViewOfFile(pLexIndexTbl);
|
|
}
|
|
#ifdef _DEBUG
|
|
else
|
|
DbgAssert(0);
|
|
#endif
|
|
}
|
|
|
|
ExitOpenLexCritSection:
|
|
ReleaseMutex(hMutex);
|
|
CloseHandle(hMutex);
|
|
}
|
|
|
|
FreeIMESecurityAttributes();
|
|
|
|
vfLexOpen = fRet;
|
|
return fRet;
|
|
}
|
|
|
|
BOOL CloseLex()
|
|
{
|
|
//ClearHanjaSenseArray();
|
|
|
|
if (vhLexIndexTbl)
|
|
{
|
|
CloseHandle(vhLexIndexTbl);
|
|
vhLexIndexTbl = 0;
|
|
}
|
|
|
|
if (vhLex)
|
|
{
|
|
CloseHandle(vhLex);
|
|
vhLex = 0;
|
|
}
|
|
|
|
vfLexOpen = fFalse;
|
|
return fTrue;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
BOOL GenerateHanjaCandList(PCIMECtx pImeCtx, WCHAR wcHangul)
|
|
{
|
|
WCHAR wcCandChar;
|
|
INT iMapCandStr;
|
|
UINT uNumOfCandStr;
|
|
_LexIndex *pLexIndexTbl;
|
|
WCHAR wszMeaning[MAX_SENSE_LENGTH+1];
|
|
BYTE cchMeaning = 0;
|
|
DWORD dwReadBytes;
|
|
BOOL fRet = fFalse;
|
|
|
|
Dbg(DBGID_Hanja, "GenerateHanjaCandList");
|
|
if (!EnsureHanjaLexLoaded())
|
|
{
|
|
MessageBeep(MB_ICONEXCLAMATION);
|
|
return fFalse;
|
|
}
|
|
|
|
// Get Current composition char
|
|
if (wcHangul == 0)
|
|
wcHangul = pImeCtx->GetCompBufStr();
|
|
|
|
if (wcHangul == 0)
|
|
return fFalse;
|
|
|
|
pLexIndexTbl = (_LexIndex*)MapViewOfFile(vhLexIndexTbl, FILE_MAP_READ, 0, 0, 0);
|
|
if (!pLexIndexTbl)
|
|
{
|
|
Dbg(DBGID_Hanja, TEXT("pLexIndexTbl==0"));
|
|
DbgAssert(0);
|
|
return fFalse;
|
|
}
|
|
|
|
if ((iMapCandStr = SearchHanjaIndex(wcHangul, pLexIndexTbl)) < 0)
|
|
MessageBeep(MB_ICONEXCLAMATION);
|
|
else
|
|
{
|
|
// Set member vars
|
|
vwcHangul = wcHangul;
|
|
vuNumofK0 = pLexIndexTbl[iMapCandStr].wNumOfK0;
|
|
|
|
// Is K1 Hanja enabled?
|
|
if (pImeCtx->GetGData() && pImeCtx->GetGData()->GetKSC5657Hanja() && (vpInstData->f16BitApps == fFalse) && !IsWin95())
|
|
vuNumofK1 = pLexIndexTbl[iMapCandStr].wNumOfK1;
|
|
else
|
|
vuNumofK1 = 0;
|
|
|
|
uNumOfCandStr = vuNumofK0 + vuNumofK1;
|
|
if (uNumOfCandStr == 0)
|
|
goto GenerateHanjaCandListExit;
|
|
|
|
Dbg(DBGID_Hanja, "Hangul = 0x%04X, K0=%d, K1=%d, iMapCandStr=%d", vwcHangul, vuNumofK0, vuNumofK1, iMapCandStr);
|
|
|
|
// Seek to mapping Hanja
|
|
SetFilePointer(vhLex, viBufferStart + pLexIndexTbl[iMapCandStr].iOffset, 0, FILE_BEGIN);
|
|
|
|
// Read all candidates
|
|
for (UINT i = 0; i < uNumOfCandStr; i++)
|
|
{
|
|
if (ReadFile(vhLex, &wcCandChar, sizeof(WCHAR), &dwReadBytes, 0) == 0)
|
|
goto GenerateHanjaCandListExit;
|
|
if (ReadFile(vhLex, &cchMeaning, sizeof(BYTE), &dwReadBytes, 0) == 0)
|
|
goto GenerateHanjaCandListExit;
|
|
if (wcCandChar && (cchMeaning < MAX_SENSE_LENGTH*sizeof(WCHAR)))
|
|
{
|
|
if (cchMeaning)
|
|
{
|
|
if (ReadFile(vhLex, wszMeaning, cchMeaning, &dwReadBytes, 0) == 0)
|
|
goto GenerateHanjaCandListExit;
|
|
}
|
|
|
|
wszMeaning[cchMeaning>>1] = L'\0';
|
|
Dbg(DBGID_Hanja, "Read Cand[%d], Hanja=0x%04X", i, wcCandChar);
|
|
pImeCtx->AppendCandidateStr(wcCandChar, wszMeaning);
|
|
}
|
|
}
|
|
|
|
pImeCtx->StoreCandidate();
|
|
|
|
fRet = fTrue;
|
|
}
|
|
|
|
GenerateHanjaCandListExit:
|
|
UnmapViewOfFile(pLexIndexTbl);
|
|
|
|
return fRet;
|
|
}
|
|
|
|
// For ImeConversionList.
|
|
DWORD GetConversionList(WCHAR wcReading, LPCANDIDATELIST lpCandList, DWORD dwBufLen)
|
|
{
|
|
_LexIndex *pLexIndexTbl;
|
|
INT iMaxCand;
|
|
INT i, iMapCandStr;
|
|
UINT uNumOfCandStr;
|
|
DWORD dwSize, readBytes, dwStartOfCandStr;
|
|
BYTE senseLen;
|
|
WCHAR szSense[MAX_SENSE_LENGTH];
|
|
CIMEData ImeData;
|
|
|
|
if (!EnsureHanjaLexLoaded())
|
|
return (0L);
|
|
|
|
// Calculate possible maximum candidates dwBufLen can contain.
|
|
if (dwBufLen)
|
|
{
|
|
iMaxCand = dwBufLen - sizeof(CANDIDATELIST) + sizeof(DWORD); // Minus header info.(unvariable part)
|
|
iMaxCand = iMaxCand / (sizeof(DWORD) + (sizeof(WCHAR)*2)); // DWORD: offset, WCHAR*2: 1 Character + null
|
|
}
|
|
else
|
|
iMaxCand = 0;
|
|
|
|
pLexIndexTbl = (_LexIndex*)MapViewOfFile(vhLexIndexTbl, FILE_MAP_READ, 0, 0, 0);
|
|
if (!pLexIndexTbl)
|
|
{
|
|
DbgAssert(0);
|
|
return (0L);
|
|
}
|
|
|
|
dwSize = 0;
|
|
|
|
if ((iMapCandStr = SearchHanjaIndex(wcReading, pLexIndexTbl)) < 0)
|
|
goto ConversionExit1;
|
|
else
|
|
{
|
|
vuNumofK0 = pLexIndexTbl[iMapCandStr].wNumOfK0;
|
|
|
|
if (ImeData->fKSC5657Hanja && (vpInstData->f16BitApps == fFalse) && !IsWin95())
|
|
vuNumofK1 = pLexIndexTbl[iMapCandStr].wNumOfK1;
|
|
else
|
|
vuNumofK1 = 0;
|
|
|
|
uNumOfCandStr = vuNumofK0 + vuNumofK1;
|
|
if (uNumOfCandStr == 0) // if no Hanja found
|
|
goto ConversionExit1;
|
|
|
|
dwSize = sizeof(CANDIDATELIST) + uNumOfCandStr*sizeof(DWORD)
|
|
+ uNumOfCandStr * sizeof(WCHAR) * 2;
|
|
// return required buffer size
|
|
if (dwBufLen == NULL)
|
|
goto ConversionExit1;
|
|
lpCandList->dwSize = dwSize;
|
|
lpCandList->dwStyle = IME_CAND_READ;
|
|
lpCandList->dwCount = uNumOfCandStr;
|
|
lpCandList->dwPageStart = lpCandList->dwSelection = 0;
|
|
lpCandList->dwPageSize = CAND_PAGE_SIZE;
|
|
|
|
//
|
|
SetFilePointer(vhLex, viBufferStart + pLexIndexTbl[iMapCandStr].iOffset, 0, FILE_BEGIN);
|
|
|
|
dwStartOfCandStr = sizeof(CANDIDATELIST)
|
|
+ sizeof(DWORD) * uNumOfCandStr; // for dwOffset array
|
|
|
|
for (i = 0; (i < (INT)uNumOfCandStr) && (i < iMaxCand); i++)
|
|
{
|
|
WCHAR wchHanja;
|
|
LPWSTR lpwchCand;
|
|
LPSTR lpchCand;
|
|
CHAR szCand[4] = ""; // one DBCS + one Null + one extra
|
|
|
|
lpCandList->dwOffset[i] = dwStartOfCandStr + (i<<2);
|
|
|
|
if (ReadFile(vhLex, &wchHanja, sizeof(WCHAR), &readBytes, 0) == 0)
|
|
goto ConversionExit1;
|
|
|
|
// if Unicode environment
|
|
if (vfUnicode)
|
|
{
|
|
lpwchCand = (LPWSTR)((LPSTR)lpCandList + lpCandList->dwOffset[i]);
|
|
*lpwchCand++ = wchHanja;
|
|
*lpwchCand = L'\0';
|
|
}
|
|
else
|
|
{
|
|
// Convert to ANSI
|
|
WideCharToMultiByte(CP_KOREA, 0,
|
|
&wchHanja, 1, (LPSTR)szCand, sizeof(szCand),
|
|
NULL, NULL);
|
|
lpchCand = (LPSTR)((LPSTR)lpCandList + lpCandList->dwOffset[i]);
|
|
*lpchCand++ = szCand[0];
|
|
*lpchCand++ = szCand[1];
|
|
*lpchCand = '\0';
|
|
}
|
|
// Skip meaning
|
|
if (ReadFile(vhLex, &senseLen, sizeof(BYTE), &readBytes, 0) == 0)
|
|
goto ConversionExit1;
|
|
if (senseLen < MAX_SENSE_LENGTH)
|
|
{
|
|
if (ReadFile(vhLex, szSense, senseLen, &readBytes, 0) == 0)
|
|
goto ConversionExit1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// if buffer size too small to copy all conversion list info
|
|
if (i == iMaxCand && i < (INT)uNumOfCandStr)
|
|
{
|
|
lpCandList->dwSize = dwSize = (sizeof(CANDIDATELIST) - sizeof(DWORD))+ i*sizeof(DWORD) + i*sizeof(WCHAR)*2;
|
|
lpCandList->dwCount = (UINT)i;
|
|
}
|
|
|
|
ConversionExit1:
|
|
UnmapViewOfFile(pLexIndexTbl);
|
|
|
|
return (dwSize);
|
|
}
|
|
|
|
INT SearchHanjaIndex(WCHAR wHChar, _LexIndex *pLexIndexTbl)
|
|
{
|
|
int iHead = 0, iTail = vuNumOfHangulEntry-1, iMid;
|
|
|
|
while (iHead <= iTail)
|
|
{
|
|
iMid = (iHead + iTail) >> 1;
|
|
|
|
if (pLexIndexTbl[iMid].wcHangul > wHChar)
|
|
iTail = iMid - 1;
|
|
else
|
|
if (pLexIndexTbl[iMid].wcHangul < wHChar)
|
|
iHead = iMid + 1;
|
|
else
|
|
return (iMid);
|
|
}
|
|
|
|
return (-1);
|
|
}
|