spiegel-keyman/developer/src/kmcmpdll/NamedCodeConstants.cpp

316 lines
8.2 KiB
C++

/*
Name: NamedCodeConstants
Copyright: Copyright (C) 2003-2017 SIL International.
Documentation:
Description:
Create Date: 19 Jul 2011
Modified Date: 13 Dec 2012
Authors: mcdurdin
Related Files:
Dependencies:
Bugs:
Todo:
Notes:
History: 19 Jul 2011 - mcdurdin - I2993 - Named code constants cause a warning 0x208D to appear
24 Oct 2012 - mcdurdin - I3481 - V9.0 - Eliminate unsafe calls in C++
06 Feb 2012 - mcdurdin - I3056 - If file was not found in first search folder, named code constants failed to compile
06 Feb 2012 - mcdurdin - I3056 - UTF-8 support for named code constants file
03 Nov 2012 - mcdurdin - I3512 - V9.0 - Merge of I3056 - If file was not found in first search folder, named code constants failed to compile
13 Dec 2012 - mcdurdin - I3641 - V9.0 - compiler dll buffer overrun bugs
*/
#include "pch.h"
#include <comperr.h>
#include "NamedCodeConstants.h"
#include "CheckFilenameConsistency.h"
#include "kmcmpdll.h"
extern char CompileDir[];
int IsHangulSyllable(const wchar_t *codename, int *code);
NamedCodeConstants::NamedCodeConstants()
{
nEntries = 0;
entries = NULL;
nEntries_file = 0;
entries_file = NULL;
reindex();
}
NamedCodeConstants::~NamedCodeConstants()
{
if(entries) delete entries;
if(entries_file) delete entries_file;
}
void NamedCodeConstants::AddCode(int n, const wchar_t *p, DWORD storeIndex)
{
if((nEntries_file % ALLOC_SIZE) == 0)
{
NCCENTRY *bn = new NCCENTRY[nEntries_file + ALLOC_SIZE];
if(nEntries_file > 0)
{
memcpy(bn, entries_file, sizeof(NCCENTRY) * nEntries_file);
delete entries_file;
}
entries_file = bn;
}
entries_file[nEntries_file].code = n;
wcsncpy_s(entries_file[nEntries_file].name, _countof(entries_file[nEntries_file].name), p, MAX_ENAME); // I3481
entries_file[nEntries_file].name[MAX_ENAME] = 0;
for (wchar_t *r = entries_file[nEntries_file].name; *r; r++)
if (iswblank(*r) && *r != '-') *r = '_';
entries_file[nEntries_file].storeIndex = storeIndex;
nEntries_file++;
}
void NamedCodeConstants::AddCode_IncludedCodes(int n, const wchar_t *p)
{
if((nEntries % ALLOC_SIZE) == 0)
{
NCCENTRY *bn = new NCCENTRY[nEntries + ALLOC_SIZE];
if(nEntries > 0)
{
memcpy(bn, entries, sizeof(NCCENTRY) * nEntries);
delete entries;
}
entries = bn;
}
entries[nEntries].code = n;
wcsncpy_s(entries[nEntries].name, _countof(entries[nEntries].name), p, MAX_ENAME); // I3481
entries[nEntries].name[MAX_ENAME] = 0;
for (wchar_t *r = entries[nEntries].name; *r; r++)
if (iswblank(*r)) *r = '_';
entries[nEntries].storeIndex = 0xFFFFFFFFL;
nEntries++;
}
int __cdecl sort_entries(const void *elem1, const void *elem2)
{
return _wcsicmp(
((NCCENTRY *)elem1)->name,
((NCCENTRY *)elem2)->name);
}
BOOL NamedCodeConstants::IntLoadFile(const char *filename)
{
FILE *fp = NULL;
if (CheckFilenameConsistency(filename, FALSE) != CERR_None) {
return FALSE;
}
if(fopen_s(&fp, filename, "rt") != 0) return FALSE; // I3481
char str[256], *p, *q, *context = NULL;
BOOL neol, first = TRUE;
while(fgets(str, 256, fp))
{
neol = *(strchr(str, 0) - 1) == '\n';
p = strtok_s(str, ";", &context); // I3481
q = strtok_s(NULL, ";\n", &context);
if(p && q)
{
if(first && *p == (char)0xEF && *(p+1) == (char)0xBB && *(p+2) == (char)0xBF) p += 3; // I3056 UTF-8 // I3512
first = FALSE;
_strupr_s(q, strlen(q)+1); // I3481 // I3641
int n = strtol(p, NULL, 16);
if (*q != '<') {
PWSTR q0 = strtowstr(q);
AddCode_IncludedCodes(n, q0);
delete[] q0;
}
}
if(!neol)
{
while(fgets(str, 256, fp)) if(*(strchr(str, 0)-1) == '\n') break;
}
}
fclose(fp);
return TRUE;
}
BOOL NamedCodeConstants::LoadFile(const char *filename)
{
char buf[260];
// Look in current directory first
strncpy_s(buf, _countof(buf), filename, 259); buf[259] = 0; // I3481
if(FileExists(buf))
return IntLoadFile(buf);
// Then look in keyboard file directory (CompileDir)
strncpy_s(buf, _countof(buf), CompileDir, 259); buf[259] = 0; // I3481
strncat_s(buf, _countof(buf), filename, 259-strlen(CompileDir)); buf[259] = 0;
if(FileExists(buf))
return IntLoadFile(buf);
// Finally look in kmcmpdll.dll directory
GetModuleFileName(0, buf, 260);
char *p = strrchr(buf, '\\'); if(p) p++; else p = buf;
*p = 0;
strncat_s(buf, _countof(buf), filename, 259-strlen(buf)); buf[259] = 0; // I3481 // I3641
if(FileExists(buf))
return IntLoadFile(buf);
reindex();
return FALSE;
}
void NamedCodeConstants::reindex()
{
if (entries != NULL) {
qsort(entries, nEntries, sizeof(NCCENTRY), sort_entries);
}
wchar_t c = L'.', d;
int i;
for(i = 0; i < 128; i++) chrindexes[i] = -1;
if (entries != NULL) {
for (i = 0; i < nEntries; i++)
{
d = towupper(entries[i].name[0]);
if (d != c && d >= 32 && d <= 127)
chrindexes[c = d] = i;
}
}
}
int NamedCodeConstants::GetCode(const wchar_t *codename, DWORD *storeIndex)
{
*storeIndex = 0xFFFFFFFFL; // I2993
int code = GetCode_IncludedCodes(codename);
if(code) return code;
for(int i = 0; i < nEntries_file; i++)
if(!_wcsicmp(entries_file[i].name, codename))
{
*storeIndex = entries_file[i].storeIndex;
return entries_file[i].code;
}
return 0;
}
int NamedCodeConstants::GetCode_IncludedCodes(const wchar_t *codename)
{
wchar_t c = towupper(*codename);
int code;
if(IsHangulSyllable(codename, &code)) return code;
if(c < 32 || c > 127 || chrindexes[c] < 0) return 0;
for(int n = chrindexes[c]; n < nEntries && towupper(entries[n].name[0]) == c; n++)
{
int cmp = _wcsicmp(codename, entries[n].name);
if(cmp == 0) return entries[n].code;
if(cmp < 0) break;
}
return 0;
}
/*
Hangul Syllables
*/
const int
HangulSBase = 0xAC00,
HangulLBase = 0x1100,
HangulVBase = 0x1161,
HangulTBase = 0x11A7,
HangulLCount = 19,
HangulVCount = 21,
HangulTCount = 28,
HangulNCount = HangulVCount * HangulTCount, // 588
HangulSCount = HangulLCount * HangulNCount; // 11172
const wchar_t *
Hangul_JAMO_L_TABLE[] = {
L"G", L"GG", L"N", L"D", L"DD", L"R", L"M", L"B", L"BB",
L"S", L"SS", L"", L"J", L"JJ", L"C", L"K", L"T", L"P", L"H" };
const wchar_t *
Hangul_JAMO_V_TABLE[] = {
L"A", L"AE", L"YA", L"YAE", L"EO", L"E", L"YEO", L"YE", L"O",
L"WA", L"WAE", L"OE", L"YO", L"U", L"WEO", L"WE", L"WI",
L"YU", L"EU", L"YI", L"I" };
const wchar_t *
Hangul_JAMO_T_TABLE[] = {
L"", L"G", L"GG", L"GS", L"N", L"NJ", L"NH", L"D", L"L", L"LG", L"LM",
L"LB", L"LS", L"LT", L"LP", L"LH", L"M", L"B", L"BS",
L"S", L"SS", L"NG", L"J", L"C", L"K", L"T", L"P", L"H" };
int IsHangulSyllable(const wchar_t *codename, int *code)
{
if(_wcsnicmp(codename, L"HANGUL_SYLLABLE_", 16)) return 0;
codename += 16;
if(!*codename) return 0;
int i, LIndex, VIndex, TIndex;
/* Find initial */
int ch = towupper(*codename);
if(strchr("GNDRMBSJCKTPH", ch))
{
/* Has an initial syllable */
int fdouble = towupper(*(codename+1)) == ch;
LIndex = -1;
for(i = 0; i < HangulLCount; i++)
if(Hangul_JAMO_L_TABLE[i][0] == ch &&
(!fdouble || (Hangul_JAMO_L_TABLE[i][1] == ch && fdouble)))
{
LIndex = i;
break;
}
if(LIndex == -1) return 0;
codename++;
if(fdouble) codename++;
}
else LIndex = 11; /* no initial */
/* Find vowel */
wchar_t V[4] = L"";
V[0] = *codename;
if(V[0] && strchr("AEIOUWY", towupper(*(codename+1)))) V[1] = *(codename+1);
if(V[1] && strchr("AEIOUWY", towupper(*(codename+2)))) V[2] = *(codename+2);
VIndex = -1;
for(i = 0; i < HangulVCount; i++)
if(!_wcsicmp(Hangul_JAMO_V_TABLE[i], V)) { VIndex = i; break; }
if(VIndex == -1) return 0;
codename += wcslen(V);
/* Find final */
TIndex = -1;
for(i = 0; i < HangulTCount; i++)
if(!_wcsicmp(Hangul_JAMO_T_TABLE[i], codename)) { TIndex = i; break; }
if(TIndex == -1) return 0;
/* Composition */
*code = (HangulSBase + (LIndex * HangulVCount + VIndex) * HangulTCount) + TIndex;
return 1;
}