windows-nt/Source/XPSP1/NT/inetsrv/query/qutil/querylib/weblcid.cxx
2020-09-26 16:20:57 +08:00

559 lines
19 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1996 - 2000.
//
// File: weblcid.hxx
//
// Contents: WEB CGI escape & unescape classes
//
// History: 96/Jan/3 DwightKr Created
// 97/Jan/7 AlanW Split from cgiesc.cxx,
// made non-destructive
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <mlang.h>
#include <weblcid.hxx>
//+---------------------------------------------------------------------------
//----------------------------------------------------------------------------
struct tagHTTPLocale
{
WCHAR * wcsHttpAcceptLanguage;
DWORD dwLocaleCode; // encoded form for searching
LCID lcid;
};
const struct tagHTTPLocale aHTTPLocale[] =
{
L"EN", 'EN', MAKELCID( MAKELANGID(LANG_ENGLISH, // English
SUBLANG_ENGLISH_US),
SORT_DEFAULT ),
L"EN-US", 'ENUS', MAKELCID( MAKELANGID(LANG_ENGLISH, // English-United States
SUBLANG_ENGLISH_US),
SORT_DEFAULT ),
L"ZH", 'ZH', MAKELCID( MAKELANGID(LANG_CHINESE, // Chinese
SUBLANG_CHINESE_SIMPLIFIED),
SORT_CHINESE_UNICODE ),
L"ZH-CN", 'ZHCN', MAKELCID( MAKELANGID(LANG_CHINESE, // Chinese/china
SUBLANG_CHINESE_SIMPLIFIED),
SORT_CHINESE_UNICODE ),
L"ZH-TW", 'ZHTW', MAKELCID( MAKELANGID(LANG_CHINESE, // Chinese/taiwan
SUBLANG_CHINESE_TRADITIONAL),
SORT_CHINESE_UNICODE ),
L"NL", 'NL', MAKELCID( MAKELANGID(LANG_DUTCH, // Dutch
SUBLANG_DUTCH),
SORT_DEFAULT ),
//
// Alphabetical from here
//
L"BG", 'BG', MAKELCID( MAKELANGID(LANG_BULGARIAN, // Bulgarian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"HR", 'HR', MAKELCID( MAKELANGID(LANG_CROATIAN, // Croatian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"CS", 'CS', MAKELCID( MAKELANGID(LANG_CZECH, // Czech
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"DA", 'DA', MAKELCID( MAKELANGID(LANG_DANISH, // Danish
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"FI", 'FI', MAKELCID( MAKELANGID(LANG_FINNISH, // Finnish
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"EL", 'EL', MAKELCID( MAKELANGID(LANG_GREEK, // Greek
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"EN-GB", 'ENGB', MAKELCID( MAKELANGID(LANG_ENGLISH, // English-United kingdom
SUBLANG_ENGLISH_UK),
SORT_DEFAULT ),
L"FR", 'FR', MAKELCID( MAKELANGID(LANG_FRENCH, // French
SUBLANG_FRENCH),
SORT_DEFAULT ),
L"FR-CA", 'FRCA', MAKELCID( MAKELANGID(LANG_FRENCH, // French-Canadian
SUBLANG_FRENCH_CANADIAN),
SORT_DEFAULT ),
L"FR-FR", 'FRFR', MAKELCID( MAKELANGID(LANG_FRENCH, // French-France
SUBLANG_FRENCH),
SORT_DEFAULT ),
L"DE", 'DE', MAKELCID( MAKELANGID(LANG_GERMAN, // German
SUBLANG_GERMAN),
SORT_DEFAULT ),
L"HU", 'HU', MAKELCID( MAKELANGID(LANG_HUNGARIAN, // Hungarian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"IS", 'IS', MAKELCID( MAKELANGID(LANG_ICELANDIC, // Icelandic
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"IT", 'IT', MAKELCID( MAKELANGID(LANG_ITALIAN, // Italian
SUBLANG_ITALIAN),
SORT_DEFAULT ),
L"JA", 'JA', MAKELCID( MAKELANGID(LANG_JAPANESE, // Japanese
SUBLANG_DEFAULT),
SORT_JAPANESE_UNICODE ),
L"KO", 'KO', MAKELCID( MAKELANGID(LANG_KOREAN, // Korean
SUBLANG_DEFAULT),
SORT_KOREAN_UNICODE ),
L"NO", 'NO', MAKELCID( MAKELANGID(LANG_NORWEGIAN, // Norwegian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"PL", 'PL', MAKELCID( MAKELANGID(LANG_POLISH, // Polish
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"PT", 'PT', MAKELCID( MAKELANGID(LANG_PORTUGUESE, // Portuguese
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"PT-BR", 'PTBR', MAKELCID( MAKELANGID(LANG_PORTUGUESE, // Portuguese-Brazil
SUBLANG_PORTUGUESE_BRAZILIAN),
SORT_DEFAULT ),
L"RO", 'RO', MAKELCID( MAKELANGID(LANG_ROMANIAN, // Romanian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"RU", 'RU', MAKELCID( MAKELANGID(LANG_RUSSIAN, // Russian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"SK", 'SK', MAKELCID( MAKELANGID(LANG_SLOVAK, // Slovak
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"SL", 'SL', MAKELCID( MAKELANGID(LANG_SLOVENIAN, // Slovenian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"ES", 'ES', MAKELCID( MAKELANGID(LANG_SPANISH, // Spanish
SUBLANG_SPANISH_MODERN),
SORT_DEFAULT ),
L"ES-ES", 'ESES', MAKELCID( MAKELANGID(LANG_SPANISH, // Spanish-Spain
SUBLANG_SPANISH),
SORT_DEFAULT ),
L"ES-MX", 'ESES', MAKELCID( MAKELANGID(LANG_SPANISH, // Spanish-Mexican
SUBLANG_SPANISH_MEXICAN),
SORT_DEFAULT ),
L"SV", 'SV', MAKELCID( MAKELANGID(LANG_SWEDISH, // Swedish
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"TR", 'TR', MAKELCID( MAKELANGID(LANG_TURKISH, // Turkish
SUBLANG_DEFAULT),
SORT_DEFAULT ),
// Less common languages
L"AF", 'AF', MAKELCID( MAKELANGID(LANG_AFRIKAANS, // Afrikaans
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"AR", 'AR', MAKELCID( MAKELANGID(LANG_ARABIC, // Arabic
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"EU", 'EU', MAKELCID( MAKELANGID(LANG_BASQUE, // Basque
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"BE", 'BE', MAKELCID( MAKELANGID(LANG_BELARUSIAN, // Byelorussian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"CA", 'CA', MAKELCID( MAKELANGID(LANG_CATALAN, // Catalan
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"HR", 'HR', MAKELCID( MAKELANGID(LANG_CROATIAN, // Croatian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"ET", 'ET', MAKELCID( MAKELANGID(LANG_ESTONIAN, // Estonian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"FO", 'FO', MAKELCID( MAKELANGID(LANG_FAEROESE, // Faeroese
SUBLANG_DEFAULT),
SORT_DEFAULT ),
// L"??", '??', MAKELCID( MAKELANGID(LANG_FARSI, // Farsi
// SUBLANG_DEFAULT),
// SORT_DEFAULT ),
L"HE", 'HE', MAKELCID( MAKELANGID(LANG_HEBREW, // Hebrew
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"IW", 'IW', MAKELCID( MAKELANGID(LANG_HEBREW, // Hebrew (ISO 639:1988)
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"ID", 'ID', MAKELCID( MAKELANGID(LANG_INDONESIAN, // Indonesian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"IN", 'IN', MAKELCID( MAKELANGID(LANG_INDONESIAN, // Indonesian (ISO 639:1988)
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"LV", 'LV', MAKELCID( MAKELANGID(LANG_LATVIAN, // Latvian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"LT", 'LT', MAKELCID( MAKELANGID(LANG_LITHUANIAN, // Lithuanian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"SR", 'SR', MAKELCID( MAKELANGID(LANG_SERBIAN, // Serbian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"TH", 'TH', MAKELCID( MAKELANGID(LANG_THAI, // Thai
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"UK", 'UK', MAKELCID( MAKELANGID(LANG_UKRAINIAN, // Ukrainian
SUBLANG_DEFAULT),
SORT_DEFAULT ),
L"VI", 'VI', MAKELCID( MAKELANGID(LANG_VIETNAMESE, // Vietnamese
SUBLANG_DEFAULT),
SORT_DEFAULT ),
// NOTE: Neutral must be last!
L"NEUTRAL", 'N', MAKELCID( MAKELANGID(LANG_NEUTRAL, // Neutral
SUBLANG_NEUTRAL),
SORT_DEFAULT ),
};
const unsigned cHTTPLocale = sizeof(aHTTPLocale) / sizeof(aHTTPLocale[0]);
//+-------------------------------------------------------------------------
//
// Function: GetLocaleString
//
// Synopsis: Looks up a locale string given an LCID
//
// Arguments: [lcid] -- The LCID to lookup
// [pwcLocale -- The resulting string
//
//--------------------------------------------------------------------------
void GetLocaleString( LCID lcid, WCHAR * pwcLocale )
{
wcscpy( pwcLocale, L"Neutral" );
XInterface<IMultiLanguage> xMultiLang;
SCODE sc = CoCreateInstance( CLSID_CMultiLanguage,
0,
CLSCTX_INPROC_SERVER,
IID_IMultiLanguage,
xMultiLang.GetQIPointer() );
if ( SUCCEEDED( sc ) )
{
BSTR bstrLocale;
sc = xMultiLang->GetRfc1766FromLcid( lcid, &bstrLocale );
if ( SUCCEEDED( sc ) )
{
wcscpy( pwcLocale, bstrLocale );
SysFreeString( bstrLocale );
}
}
} //GetLocaleString
//+---------------------------------------------------------------------------
//
// Function: GetStringFromLCID - public
//
// Synposis: Determines the string representation of an LCID
//
// Arguments: [lcid] -- The LCID to lookup
// [pwcLocale -- The resulting string
//
// History: 96-Apr-24 DwightKr Created
//
//----------------------------------------------------------------------------
void GetStringFromLCID( LCID lcid, WCHAR * pwcLocale )
{
//
// Be careful to compare only the language ID, and not the sort ID.
//
lcid = LANGIDFROMLCID(lcid);
for (ULONG i=0; i<cHTTPLocale; i++)
{
if ( lcid == LANGIDFROMLCID( aHTTPLocale[i].lcid ) )
{
qutilDebugOut(( DEB_ITRACE, "GetStringFromLCID: browser locale is %ws; lcid=0x%x\n",
aHTTPLocale[i].wcsHttpAcceptLanguage,
lcid ));
wcscpy( pwcLocale, aHTTPLocale[i].wcsHttpAcceptLanguage );
return;
}
}
// Give up and go for Neutral if the below call fails
qutilDebugOut(( DEB_ITRACE, "GetStringFromLCID: browser locale not found, lcid=0x%x\n",
lcid ));
wcscpy( pwcLocale, L"NEUTRAL" );
//
// This LCID was not found in the table, look one up.
//
GetLocaleString( lcid, pwcLocale );
} //GetStringFromLCID
//+---------------------------------------------------------------------------
//
// Function: EncodeLocale - public
//
// Synopsis: Compact a locale string for easier lookup.
//
// Arguments: [pwszLocale] - locale string
// [dwPrimaryLang] - set to the primary language encoding if
// there is a sublangage ID.
//
// Returns: DWORD - the significant characters in the locale or zero if
// ill-formed
//
//+---------------------------------------------------------------------------
inline DWORD EncodeLocale( WCHAR * pwszLocale, DWORD & dwPrimaryLang )
{
DWORD dwResult = 0;
dwPrimaryLang = 0;
if ( isalpha( pwszLocale[0] ) && isalpha( pwszLocale[1] ) )
{
dwResult = towupper(pwszLocale[0]) << 8;
dwResult |= towupper(pwszLocale[1]) << 0;
pwszLocale += 2;
if (*pwszLocale == L'-')
{
dwPrimaryLang = dwResult;
dwResult <<= 16;
pwszLocale++;
if ( isalpha( pwszLocale[0] ) && isalpha( pwszLocale[1] ) )
{
dwResult |= towupper(pwszLocale[0]) << 8;
dwResult |= towupper(pwszLocale[1]) << 0;
pwszLocale += 2;
}
}
else if (isalpha( *pwszLocale ))
{
// Treat the NEUTRAL locale as a special case
if (_wcsnicmp( pwszLocale-2,
aHTTPLocale[cHTTPLocale-1].wcsHttpAcceptLanguage,
wcslen(aHTTPLocale[cHTTPLocale-1].wcsHttpAcceptLanguage) ) == 0)
{
pwszLocale += wcslen(aHTTPLocale[cHTTPLocale-1].wcsHttpAcceptLanguage) - 2;
dwResult = aHTTPLocale[cHTTPLocale-1].dwLocaleCode;
}
}
}
if ( *pwszLocale != L'\0' &&
! iswspace( *pwszLocale ) &&
*pwszLocale != L',' && *pwszLocale != L';' )
dwResult = 0;
return dwResult;
} //EncodeLocale
//+---------------------------------------------------------------------------
//
// Function: LcidFromHttpAcceptLanguage
//
// Synposis: Determines the locale from the string passed in.
//
// Arguments: [pwc] the string representation of the locale
//
// History: 00-Oct-04 dlee Created
//
//----------------------------------------------------------------------------
LCID LcidFromHttpAcceptLanguage( WCHAR const * pwc )
{
// Default to an invalid lcid
LCID lcid = InvalidLCID;
if ( 0 != pwc )
{
XInterface<IMultiLanguage> xMultiLang;
SCODE sc = CoCreateInstance( CLSID_CMultiLanguage,
0,
CLSCTX_INPROC_SERVER,
IID_IMultiLanguage,
xMultiLang.GetQIPointer() );
if ( SUCCEEDED( sc ) )
{
BSTR bstr = SysAllocString( pwc );
if ( 0 != bstr )
{
sc = xMultiLang->GetLcidFromRfc1766( &lcid, bstr );
SysFreeString( bstr );
}
}
}
return lcid;
} //LcidFromHttpAcceptLanguage
//+---------------------------------------------------------------------------
//
// Function: GetLCIDFromString - public
//
// Synposis: Determines the locale from the string passed in.
//
// Arguments: [wcsLocale] the string representation of the locale
//
// History: 96-Apr-20 DwightKr Created
// 97-Jan-07 AlanW Made non-destructive
//
// Notes: The input string is assumed to be a language list as
// formatted for the Accept-Language header. This is a
// command separated list of language codes.
// The code here doesn't evaluate the quality parameter,
// it returns the first available language found.
//
//----------------------------------------------------------------------------
LCID GetLCIDFromString( WCHAR * wcsLocale )
{
unsigned iPrimaryLangEntry = 0xFFFFFFFF;
const WCHAR * wcsDelim = L" \t,;=";
WCHAR * wcsToken = wcsLocale;
while ( 0 != wcsToken )
{
wcsToken += wcsspn( wcsToken, wcsDelim );
DWORD dwPrimaryCode = 0;
DWORD dwLocaleCode = EncodeLocale(wcsToken, dwPrimaryCode);
if (dwLocaleCode != 0 || dwPrimaryCode != 0)
{
for (ULONG i=0; i<cHTTPLocale; i++)
{
if ( dwLocaleCode == aHTTPLocale[i].dwLocaleCode )
{
qutilDebugOut(( DEB_ITRACE,
"GetLCIDFromString is %ws; lcid=0x%x\n",
wcsToken,
aHTTPLocale[i].lcid ));
return LANGIDFROMLCID( aHTTPLocale[i].lcid );
}
if ( dwPrimaryCode == aHTTPLocale[i].dwLocaleCode &&
iPrimaryLangEntry == 0xFFFFFFFF )
iPrimaryLangEntry = i;
}
}
wcsToken = wcschr( wcsToken, L',' );
}
if (iPrimaryLangEntry != 0xFFFFFFFF)
return aHTTPLocale[iPrimaryLangEntry].lcid;
// Fall back to the slow approach.
return LcidFromHttpAcceptLanguage( wcsLocale );
} //GetLCIDFromString
WCHAR const * __stdcall GetStringFromLCID( LCID lcid );
//+---------------------------------------------------------------------------
//
// Function: GetStringFromLCID - public
//
// Synposis: Determines the string representation of an LCID
//
// Arguments: [lcid] - the LCID to lookup
//
// History: 96-Apr-24 DwightKr Created
//
// Note: This must be exported since SQL 7 calls this undocumented API
// It's otherwise unused by Indexing Service.
//
//----------------------------------------------------------------------------
WCHAR const * GetStringFromLCID( LCID lcid )
{
//
// Be careful to compare only the language ID, and not the sort ID.
//
lcid = LANGIDFROMLCID(lcid);
for (ULONG i=0; i<cHTTPLocale; i++)
{
if ( lcid == LANGIDFROMLCID( aHTTPLocale[i].lcid ) )
{
qutilDebugOut(( DEB_ITRACE, "GetStringFromLCID: browser locale is %ws; lcid=0x%x\n",
aHTTPLocale[i].wcsHttpAcceptLanguage,
lcid ));
return aHTTPLocale[i].wcsHttpAcceptLanguage;
}
}
//
// This LCID was not found in the table, report an error.
//
qutilDebugOut(( DEB_ITRACE, "GetStringFromLCID: browser locale not found, lcid=0x%x\n",
lcid ));
return L"NEUTRAL";
} //GetStringFromLCID