Skip to content

Instantly share code, notes, and snippets.

@katahiromz
Last active April 5, 2019 04:49
Show Gist options
  • Save katahiromz/c33393fe14f26b342545487ae744da35 to your computer and use it in GitHub Desktop.
Save katahiromz/c33393fe14f26b342545487ae744da35 to your computer and use it in GitHub Desktop.
japanese.c
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS system libraries
* FILE: dll/win32/kernel32/winnls/string/japanese.c
* PURPOSE: Japanese era support
* PROGRAMMER: Katayama Hirofumi MZ
*/
#include <k32.h>
#define NDEBUG
#include <debug.h>
#include "japanese.h"
#define JAPANESE_ERA_MAX 16
static DWORD s_JapaneseEraCount = 0;
static JAPANESE_ERA s_JapaneseEraTable[JAPANESE_ERA_MAX];
BOOL NLS_RegEnumValue(HANDLE hKey, UINT ulIndex,
LPWSTR szValueName, ULONG valueNameSize,
LPWSTR szValueData, ULONG valueDataSize);
INT JapaneseEra_Compare(LPCJAPANESE_ERA pEra1, LPCJAPANESE_ERA pEra2)
{
if (pEra1->wYear < pEra2->wYear)
return -1;
if (pEra1->wYear > pEra2->wYear)
return 1;
if (pEra1->wMonth < pEra2->wMonth)
return -1;
if (pEra1->wMonth > pEra2->wMonth)
return 1;
if (pEra1->wDay < pEra2->wDay)
return -1;
if (pEra1->wDay > pEra2->wDay)
return 1;
return 0;
}
INT JapaneseEra_Compare0(const void *pEra1, const void *pEra2)
{
return JapaneseEra_Compare((LPCJAPANESE_ERA)pEra1, (LPCJAPANESE_ERA)pEra2);
}
/*
* SEE ALSO:
* https://en.wikipedia.org/wiki/Japanese_era_name
* https://docs.microsoft.com/en-us/windows/desktop/Intl/era-handling-for-the-japanese-calendar
*/
LPCJAPANESE_ERA JapaneseEra_Load(DWORD *pdwCount)
{
HANDLE KeyHandle = NULL;
DWORD dwIndex;
WCHAR szName[128], szValue[128];
JAPANESE_ERA *pEntry;
LPWSTR pch1, pch2, pch3, pch4;
static UNICODE_STRING KeyName =
RTL_CONSTANT_STRING(L"\\Registry\\MACHINE\\SYSTEM\\CurrentControlSet"
L"\\Control\\Nls\\Calendars\\Japanese\\Eras");
static OBJECT_ATTRIBUTES KeyAttributes =
RTL_CONSTANT_OBJECT_ATTRIBUTES(&KeyName, OBJ_CASE_INSENSITIVE);
ASSERT(pdwCount != NULL);
/* return cache if any */
if (s_JapaneseEraCount != 0)
{
*pdwCount = s_JapaneseEraCount;
return s_JapaneseEraTable;
}
/* init */
*pdwCount = 0;
RtlZeroMemory(&s_JapaneseEraTable, sizeof(s_JapaneseEraTable));
/* open registry key */
Status = NtOpenKey(&KeyHandle, KEY_READ, &KeyAttributes);
if (!NT_SUCCESS(Status))
return NULL;
/* for all values */
for (dwIndex = 0; dwIndex < JAPANESE_ERA_MAX; ++dwIndex)
{
pEntry = &s_JapaneseEraTable[dwIndex];
/* get name and data */
if (!NLS_RegEnumValue(KeyHandle, dwIndex, szName, sizeof(szName),
szValue, sizeof(szValue)))
{
break;
}
/* split fields */
pch1 = szName;
pch2 = wcschr(pch1, L' ');
if (pch2 == NULL)
{
ASSERT(FALSE);
break;
}
*pch2++ = UNICODE_NULL;
pch3 = wcschr(pch2, L' ');
if (pch3 == NULL)
{
ASSERT(FALSE);
break;
}
*pch3++ = UNICODE_NULL;
pEntry->wYear = _wtoi(pch1);
pEntry->wMonth = _wtoi(pch2);
pEntry->wDay = _wtoi(pch3);
if (pEntry->wYear == 0 || pEntry->wMonth == 0 || pEntry->wDay == 0)
{
ASSERT(FALSE);
break;
}
/* split fields */
pch1 = szValue;
pch2 = wcschr(pch1, L'_');
if (pch2 == NULL)
{
ASSERT(FALSE);
break;
}
*pch2++ = UNICODE_NULL;
pch3 = wcschr(pch2, L'_');
if (pch3 == NULL)
{
ASSERT(FALSE);
break;
}
*pch3++ = UNICODE_NULL;
pch4 = wcschr(pch3, L'_');
if (pch4 == NULL)
{
ASSERT(FALSE);
break;
}
*pch4++ = UNICODE_NULL;
/* store */
RtlStringCbCopyW(pEntry->szEraName, sizeof(pEntry->szEraName), pch1);
RtlStringCbCopyW(pEntry->szEraInitial, sizeof(pEntry->szEraInitial), pch2);
RtlStringCbCopyW(pEntry->szEnglishEraName, sizeof(pEntry->szEnglishEraName), pch3);
RtlStringCbCopyW(pEntry->szEnglishEraInitial, sizeof(pEntry->szEnglishEraInitial), pch4);
}
/* close key */
NtClose(KeyHandle);
/* sort */
qsort(s_JapaneseEraTable, s_JapaneseEraCount, sizeof(JAPANESE_ERA),
JapaneseEra_Compare0);
/* make cache */
ASSERT(dwIndex > 0);
s_JapaneseEraCount = dwIndex;
return s_JapaneseEraTable;
}
BOOL JapaneseEra_ToSystemTime(LPCJAPANESE_ERA pEra, LPSYSTEMTIME pst)
{
ASSERT(pEra != NULL);
ASSERT(pst != NULL);
ZeroMemory(pst, sizeof(*pst));
pst->wYear = pEra->wYear;
pst->wMonth = pEra->wMonth;
pst->wDay = pEra->wDay;
return TRUE;
}
LPCJAPANESE_ERA JapaneseEra_Find(const SYSTEMTIME *pst OPTIONAL)
{
DWORD dwIndex, dwCount = 0;
LPCJAPANESE_ERA pTable, pEntry, pLatest = NULL;
SYSTEMTIME st1, st2;
FILETIME ft1, ft2;
LONG nCompare;
/* pst --> ft1 */
if (pst == NULL)
{
GetLocalTime(&st1);
pst = &st1;
}
SystemTimeToFileTime(pst, &ft1);
/* load era table */
pTable = JapaneseEra_Load(&dwCount);
if (pTable == NULL || dwCount == 0 || dwCount > JAPANESE_ERA_MAX)
{
ASSERT(FALSE);
return NULL;
}
/* for all eras */
for (dwIndex = 0; dwIndex < dwCount; dwIndex++)
{
pEntry = &pTable[dwIndex];
/* pEntry --> st2 --> ft2 */
JapaneseEra_ToSystemTime(pEntry, &st2);
SystemTimeToFileTime(&st2, &ft2);
/* ft1 <=> ft2 */
nCompare = CompareFileTime(&ft1, &ft2);
if (nCompare <= 0)
return pEntry;
}
return NULL;
}
LPCJAPANESE_ERA JapaneseEra_ConvertYear(const SYSTEMTIME *pst OPTIONAL, LPWORD pwNengoYearOut)
{
SYSTEMTIME st;
LPCJAPANESE_ERA pEra;
ASSERT(pwYearOut);
if (pst == NULL)
{
GetLocalTime(&st);
pst = &st;
}
pEra = JapaneseEra_Find(pst);
ASSERT(pEra != NULL);
if (pEra == NULL)
{
*pwNengoYearOut = 0;
return NULL;
}
*pwNengoYearOut = pst->wYear - pEra->wYear + 1;
return pEra;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment