2015 lines
55 KiB
C
2015 lines
55 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
util.c
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This file contains utility functions that are shared across NLS's code
|
||
|
modules, but are not necessarily part of any of the existing code
|
||
|
modules.
|
||
|
|
||
|
Private APIs found in this file:
|
||
|
NlsGetCacheUpdateCount
|
||
|
|
||
|
External Routines found in this file:
|
||
|
IsValidSeparatorString
|
||
|
IsValidGroupingString
|
||
|
IsValidCalendarType
|
||
|
IsValidCalendarTypeStr
|
||
|
GetUserInfo
|
||
|
GetPreComposedChar
|
||
|
GetCompositeChars
|
||
|
InsertPreComposedForm
|
||
|
InsertFullWidthPreComposedForm
|
||
|
InsertCompositeForm
|
||
|
NlsConvertIntegerToString
|
||
|
NlsConvertIntegerToHexStringW
|
||
|
NlsConvertStringToIntegerW
|
||
|
NlsStrCpyW
|
||
|
NlsStrCatW
|
||
|
NlsStrLenW
|
||
|
NlsStrNCatW
|
||
|
NlsStrEqualW
|
||
|
NlsStrNEqualW
|
||
|
GetStringTableEntry
|
||
|
NlsIsDll
|
||
|
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
05-31-91 JulieB Created.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Include Files.
|
||
|
//
|
||
|
|
||
|
#include "nls.h"
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// PRIVATE API ROUTINES //
|
||
|
//-------------------------------------------------------------------------//
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// NlsGetCacheUpdateCount
|
||
|
//
|
||
|
// Returns the current cache update count. The cache update count is
|
||
|
// updated whenever the HKCU\Control Panel\International settings are
|
||
|
// modified. This count allows the caller to see if the cache has been
|
||
|
// updated since the last time this function was called.
|
||
|
//
|
||
|
// This private api is needed by the Complex Script Language Pack
|
||
|
// (CSLPK) to enable it to quickly see if the international section of
|
||
|
// the registry has been modified.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
ULONG WINAPI NlsGetCacheUpdateCount(void)
|
||
|
{
|
||
|
return (pNlsUserInfo->ulCacheUpdateCount);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//-------------------------------------------------------------------------//
|
||
|
// EXTERNAL ROUTINES //
|
||
|
//-------------------------------------------------------------------------//
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// IsValidSeparatorString
|
||
|
//
|
||
|
// Returns TRUE if the given string is valid. Otherwise, it returns FALSE.
|
||
|
//
|
||
|
// A valid string is one that does NOT contain any code points between
|
||
|
// L'0' and L'9', and does NOT have a length greater than the maximum.
|
||
|
//
|
||
|
// NOTE: The string must be a null terminated string.
|
||
|
//
|
||
|
// 10-12-93 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL IsValidSeparatorString(
|
||
|
LPCWSTR pString,
|
||
|
ULONG MaxLength,
|
||
|
BOOL fCheckZeroLen)
|
||
|
{
|
||
|
ULONG Length; // string length
|
||
|
LPWSTR pCur; // ptr to current position in string
|
||
|
|
||
|
|
||
|
//
|
||
|
// Search down the string to see if the chars are valid.
|
||
|
// Save the length of the string.
|
||
|
//
|
||
|
pCur = (LPWSTR)pString;
|
||
|
while (*pCur)
|
||
|
{
|
||
|
if ((*pCur >= NLS_CHAR_ZERO) && (*pCur <= NLS_CHAR_NINE))
|
||
|
{
|
||
|
//
|
||
|
// String is NOT valid.
|
||
|
//
|
||
|
return (FALSE);
|
||
|
}
|
||
|
pCur++;
|
||
|
}
|
||
|
Length = (ULONG)(pCur - (LPWSTR)pString);
|
||
|
|
||
|
//
|
||
|
// Make sure the length is not greater than the maximum allowed.
|
||
|
// Also, check for 0 length string (if appropriate).
|
||
|
//
|
||
|
if ((Length >= MaxLength) ||
|
||
|
((fCheckZeroLen) && (Length == 0)))
|
||
|
{
|
||
|
//
|
||
|
// String is NOT valid.
|
||
|
//
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// String is valid.
|
||
|
//
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// IsValidGroupingString
|
||
|
//
|
||
|
// Returns TRUE if the given string is valid. Otherwise, it returns FALSE.
|
||
|
//
|
||
|
// A valid string is one that begins and ends with a number between
|
||
|
// L'0' and L'9', alternates between a number and a semicolon, and does
|
||
|
// NOT have a length greater than the maximum.
|
||
|
// (eg. 3;2;0 or 3;0 or 0 or 3)
|
||
|
//
|
||
|
// NOTE: The string must be a null terminated string.
|
||
|
//
|
||
|
// 01-05-98 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL IsValidGroupingString(
|
||
|
LPCWSTR pString,
|
||
|
ULONG MaxLength,
|
||
|
BOOL fCheckZeroLen)
|
||
|
{
|
||
|
ULONG Length; // string length
|
||
|
LPWSTR pCur; // ptr to current position in string
|
||
|
|
||
|
|
||
|
//
|
||
|
// Search down the string to see if the chars are valid.
|
||
|
// Save the length of the string.
|
||
|
//
|
||
|
pCur = (LPWSTR)pString;
|
||
|
while (*pCur)
|
||
|
{
|
||
|
if ((*pCur < NLS_CHAR_ZERO) || (*pCur > NLS_CHAR_NINE))
|
||
|
{
|
||
|
//
|
||
|
// String is NOT valid.
|
||
|
//
|
||
|
return (FALSE);
|
||
|
}
|
||
|
pCur++;
|
||
|
|
||
|
if (*pCur)
|
||
|
{
|
||
|
if ((*pCur != NLS_CHAR_SEMICOLON) || (*(pCur + 1) == 0))
|
||
|
{
|
||
|
//
|
||
|
// String is NOT valid.
|
||
|
//
|
||
|
return (FALSE);
|
||
|
}
|
||
|
pCur++;
|
||
|
}
|
||
|
}
|
||
|
Length = (ULONG)(pCur - (LPWSTR)pString);
|
||
|
|
||
|
//
|
||
|
// Make sure the length is not greater than the maximum allowed.
|
||
|
// Also, check for 0 length string (if appropriate).
|
||
|
//
|
||
|
if ((Length >= MaxLength) ||
|
||
|
((fCheckZeroLen) && (Length == 0)))
|
||
|
{
|
||
|
//
|
||
|
// String is NOT valid.
|
||
|
//
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// String is valid.
|
||
|
//
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// IsValidCalendarType
|
||
|
//
|
||
|
// Returns the pointer to the optional calendar structure if the given
|
||
|
// calendar type is valid for the given locale. Otherwise, it returns
|
||
|
// NULL.
|
||
|
//
|
||
|
// 10-12-93 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
LPWORD IsValidCalendarType(
|
||
|
PLOC_HASH pHashN,
|
||
|
CALID CalId)
|
||
|
{
|
||
|
LPWORD pOptCal; // ptr to list of optional calendars
|
||
|
LPWORD pEndOptCal; // ptr to end of list of optional calendars
|
||
|
|
||
|
|
||
|
//
|
||
|
// Make sure the Cal Id is not zero, since that may be in the
|
||
|
// optional calendar section (meaning no optional calendars).
|
||
|
//
|
||
|
if (CalId == 0)
|
||
|
{
|
||
|
return (NULL);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Search down the list of optional calendars.
|
||
|
//
|
||
|
pOptCal = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->IOptionalCal;
|
||
|
pEndOptCal = (LPWORD)(pHashN->pLocaleHdr) + pHashN->pLocaleHdr->SDayName1;
|
||
|
while (pOptCal < pEndOptCal)
|
||
|
{
|
||
|
//
|
||
|
// Check the calendar ids.
|
||
|
//
|
||
|
if (CalId == ((POPT_CAL)pOptCal)->CalId)
|
||
|
{
|
||
|
//
|
||
|
// Calendar id is valid for the given locale.
|
||
|
//
|
||
|
return (pOptCal);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Increment to the next optional calendar.
|
||
|
//
|
||
|
pOptCal += ((POPT_CAL)pOptCal)->Offset;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Calendar id is NOT valid if this point is reached.
|
||
|
//
|
||
|
return (NULL);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// IsValidCalendarTypeStr
|
||
|
//
|
||
|
// Converts the calendar string to an integer and validates the calendar
|
||
|
// id for the given locale. It return a pointer to the optional calendar
|
||
|
// structure, or null if the calendar id was invalid.
|
||
|
//
|
||
|
// 10-19-93 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
LPWORD IsValidCalendarTypeStr(
|
||
|
PLOC_HASH pHashN,
|
||
|
LPCWSTR pCalStr)
|
||
|
{
|
||
|
UNICODE_STRING ObUnicodeStr; // value string
|
||
|
CALID CalNum; // calendar id
|
||
|
|
||
|
|
||
|
//
|
||
|
// Convert the string to an integer value.
|
||
|
//
|
||
|
RtlInitUnicodeString(&ObUnicodeStr, pCalStr);
|
||
|
if (RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &CalNum))
|
||
|
{
|
||
|
return (NULL);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Validate the calendar id and return the pointer to the
|
||
|
// optional calendar structure.
|
||
|
//
|
||
|
return (IsValidCalendarType(pHashN, CalNum));
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// GetCPFileNameFromRegistry
|
||
|
//
|
||
|
// Gets the name of the code page file from the registry. If pResultBuf
|
||
|
// or Size == 0, then just return true if it exists in the registry, but
|
||
|
// don't return the actual value.
|
||
|
//
|
||
|
// 05-31-2002 ShawnSte Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL GetCPFileNameFromRegistry(
|
||
|
UINT CodePage,
|
||
|
LPWSTR pResultBuf,
|
||
|
UINT Size)
|
||
|
{
|
||
|
// Working things.
|
||
|
WCHAR pTmpBuf[MAX_SMALL_BUF_LEN]; // temp buffer
|
||
|
PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to query info
|
||
|
BYTE pStatic[MAX_KEY_VALUE_FULLINFO]; // ptr to static buffer
|
||
|
|
||
|
//
|
||
|
// Convert value to unicode string.
|
||
|
//
|
||
|
if (!NT_SUCCESS(NlsConvertIntegerToString( CodePage,
|
||
|
10,
|
||
|
0,
|
||
|
pTmpBuf,
|
||
|
MAX_SMALL_BUF_LEN )))
|
||
|
{
|
||
|
// Didn't work. (Don't bother closing key though, its used globally)
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
// Open hCodePageKey, return false if it fails
|
||
|
OPEN_CODEPAGE_KEY(FALSE);
|
||
|
|
||
|
//
|
||
|
// Query the registry value for that code page.
|
||
|
//
|
||
|
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
|
||
|
if ( NO_ERROR != QueryRegValue( hCodePageKey,
|
||
|
pTmpBuf,
|
||
|
&pKeyValueFull,
|
||
|
MAX_KEY_VALUE_FULLINFO,
|
||
|
NULL ) )
|
||
|
{
|
||
|
// Didn't work. (Don't bother closing key though, its used globally)
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure there is data with this value.
|
||
|
//
|
||
|
if (GET_VALUE_DATA_PTR(pKeyValueFull)[0] == 0)
|
||
|
{
|
||
|
// Nope, no file name for this code page. (Not installed).
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
// It worked, see if that's all they wanted.
|
||
|
if (!pResultBuf || Size == 0)
|
||
|
{
|
||
|
// Caller didn't want the name, just to know if it was there
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
// Now we have to copy the name to their buffer for them.
|
||
|
NlsStrCpyW(pResultBuf, GET_VALUE_DATA_PTR(pKeyValueFull));
|
||
|
|
||
|
// Yea, it worked
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// GetUserInfoFromRegistry
|
||
|
//
|
||
|
// Gets the information from the registry for the given value entry.
|
||
|
//
|
||
|
// 06-11-98 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL GetUserInfoFromRegistry(
|
||
|
LPWSTR pValue,
|
||
|
LPWSTR pOutput,
|
||
|
LCID Locale)
|
||
|
{
|
||
|
PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to query info
|
||
|
BYTE pStatic[MAX_KEY_VALUE_FULLINFO]; // ptr to static buffer
|
||
|
HANDLE hKey = NULL; // handle to intl key
|
||
|
ULONG rc = 0L; // return code
|
||
|
|
||
|
|
||
|
//
|
||
|
// Open the Control Panel International registry key.
|
||
|
//
|
||
|
OPEN_CPANEL_INTL_KEY(hKey, FALSE, KEY_READ);
|
||
|
|
||
|
//
|
||
|
// Initialize the output string.
|
||
|
//
|
||
|
*pOutput = 0;
|
||
|
|
||
|
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
|
||
|
|
||
|
//
|
||
|
// Check to be sure the current user is running in the given locale.
|
||
|
//
|
||
|
if (Locale)
|
||
|
{
|
||
|
if (NO_ERROR == QueryRegValue( hKey,
|
||
|
L"Locale",
|
||
|
&pKeyValueFull,
|
||
|
MAX_KEY_VALUE_FULLINFO,
|
||
|
NULL ))
|
||
|
{
|
||
|
UINT uiLocale;
|
||
|
|
||
|
if (NlsConvertStringToIntegerW(GET_VALUE_DATA_PTR(pKeyValueFull), 16, -1, &uiLocale) &&
|
||
|
uiLocale != Locale)
|
||
|
{
|
||
|
CLOSE_REG_KEY(hKey);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Query the registry value.
|
||
|
//
|
||
|
rc = QueryRegValue( hKey,
|
||
|
pValue,
|
||
|
&pKeyValueFull,
|
||
|
MAX_KEY_VALUE_FULLINFO,
|
||
|
NULL );
|
||
|
|
||
|
//
|
||
|
// Close the registry key.
|
||
|
//
|
||
|
CLOSE_REG_KEY(hKey);
|
||
|
|
||
|
//
|
||
|
// If the query failed or if the output buffer is not large enough,
|
||
|
// then return failure.
|
||
|
//
|
||
|
if ((rc != NO_ERROR) ||
|
||
|
(pKeyValueFull->DataLength > (MAX_REG_VAL_SIZE * sizeof(WCHAR))))
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Save the string in pOutput.
|
||
|
//
|
||
|
NlsStrCpyW(pOutput, GET_VALUE_DATA_PTR(pKeyValueFull));
|
||
|
|
||
|
//
|
||
|
// Return success.
|
||
|
//
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// GetUserInfo
|
||
|
//
|
||
|
// Gets the information from the registry for the given locale and user
|
||
|
// value entry.
|
||
|
//
|
||
|
// 05-31-91 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL GetUserInfo(
|
||
|
LCID Locale,
|
||
|
LCTYPE LCType,
|
||
|
SIZE_T CacheOffset,
|
||
|
LPWSTR pValue,
|
||
|
LPWSTR pOutput,
|
||
|
size_t cchOutput,
|
||
|
BOOL fCheckNull)
|
||
|
{
|
||
|
LCID UserLocale;
|
||
|
HRESULT hr; // return val for string copy
|
||
|
|
||
|
|
||
|
//
|
||
|
// Check if the current thread/process is impersonating
|
||
|
// or running in the context of a user other than the
|
||
|
// interactive one.
|
||
|
//
|
||
|
if (NT_SUCCESS( NlsGetCurrentUserNlsInfo( Locale,
|
||
|
LCType,
|
||
|
pValue,
|
||
|
pOutput,
|
||
|
FALSE )))
|
||
|
{
|
||
|
//
|
||
|
// See if we need to check for a null string.
|
||
|
//
|
||
|
if ((fCheckNull) && (*pOutput == 0))
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Running in the same security context as the logged-on user.
|
||
|
//
|
||
|
|
||
|
// Go to server side (csrss.exe) by calling CsrBasepNlsGetUserInfo(). The server side will enter a critical section to
|
||
|
// protect the cache reading, and Copy the data to the output buffer.
|
||
|
|
||
|
// NOTENOTE: CsrBasepNlsGetUserInfo takes the buffer size in BYTE, so
|
||
|
// we have to multiply cchOutput by sizeof(WCHAR)
|
||
|
|
||
|
if (!NT_SUCCESS(CsrBasepNlsGetUserInfo(Locale, CacheOffset, pOutput, cchOutput * sizeof(WCHAR))))
|
||
|
{
|
||
|
//
|
||
|
// Make sure the cache is valid.
|
||
|
//
|
||
|
// Also, check for an invalid entry. An invalid entry is marked
|
||
|
// with NLS_INVALID_INFO_CHAR in the first position of the string
|
||
|
// array.
|
||
|
//
|
||
|
//
|
||
|
// The cache is invalid, so try getting the information directly
|
||
|
// from the registry.
|
||
|
//
|
||
|
if (GetUserInfoFromRegistry(pValue, pOutput, Locale) == FALSE)
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// See if we need to check for a null string.
|
||
|
//
|
||
|
if ((fCheckNull) && (*pOutput == 0))
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return success.
|
||
|
//
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// GetPreComposedChar
|
||
|
//
|
||
|
// Gets the precomposed character form of a given base character and
|
||
|
// nonspacing character. If there is no precomposed form for the given
|
||
|
// character, it returns 0.
|
||
|
//
|
||
|
// 05-31-91 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
WCHAR FASTCALL GetPreComposedChar(
|
||
|
WCHAR wcNonSp,
|
||
|
WCHAR wcBase)
|
||
|
{
|
||
|
PCOMP_INFO pComp; // ptr to composite information
|
||
|
WORD BSOff = 0; // offset of base char in grid
|
||
|
WORD NSOff = 0; // offset of nonspace char in grid
|
||
|
int Index; // index into grid
|
||
|
|
||
|
|
||
|
//
|
||
|
// Store the ptr to the composite information. No need to check if
|
||
|
// it's a NULL pointer since all tables in the Unicode file are
|
||
|
// constructed during initialization.
|
||
|
//
|
||
|
pComp = pTblPtrs->pComposite;
|
||
|
|
||
|
//
|
||
|
// Traverse 8:4:4 table for Base character offset.
|
||
|
//
|
||
|
BSOff = TRAVERSE_844_W(pComp->pBase, wcBase);
|
||
|
if (!BSOff)
|
||
|
{
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Traverse 8:4:4 table for NonSpace character offset.
|
||
|
//
|
||
|
NSOff = TRAVERSE_844_W(pComp->pNonSp, wcNonSp);
|
||
|
if (!NSOff)
|
||
|
{
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get wide character value out of 2D grid.
|
||
|
// If there is no precomposed character at the location in the
|
||
|
// grid, it will return 0.
|
||
|
//
|
||
|
Index = (BSOff - 1) * pComp->NumNonSp + (NSOff - 1);
|
||
|
return ((pComp->pGrid)[Index]);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// GetCompositeChars
|
||
|
//
|
||
|
// Gets the composite characters of a given wide character. If the
|
||
|
// composite form is found, it returns TRUE. Otherwise, it returns
|
||
|
// FALSE.
|
||
|
//
|
||
|
// 05-31-91 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL FASTCALL GetCompositeChars(
|
||
|
WCHAR wch,
|
||
|
WCHAR *pNonSp,
|
||
|
WCHAR *pBase)
|
||
|
{
|
||
|
PPRECOMP pPreComp; // ptr to precomposed information
|
||
|
|
||
|
|
||
|
//
|
||
|
// Store the ptr to the precomposed information. No need to check if
|
||
|
// it's a NULL pointer since all tables in the Unicode file are
|
||
|
// constructed during initialization.
|
||
|
//
|
||
|
pPreComp = pTblPtrs->pPreComposed;
|
||
|
|
||
|
//
|
||
|
// Traverse 8:4:4 table for base and nonspace character translation.
|
||
|
//
|
||
|
TRAVERSE_844_D(pPreComp, wch, *pNonSp, *pBase);
|
||
|
|
||
|
//
|
||
|
// Return success if found. Otherwise, error.
|
||
|
//
|
||
|
return ((*pNonSp) && (*pBase));
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// InsertPreComposedForm
|
||
|
//
|
||
|
// Gets the precomposed form of a given wide character string, places it in
|
||
|
// the given wide character, and returns the number of composite characters
|
||
|
// used to form the precomposed form. If there is no precomposed form for
|
||
|
// the given character, nothing is written into pPreComp and it returns 1
|
||
|
// for the number of characters used.
|
||
|
//
|
||
|
// 05-31-91 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
int FASTCALL InsertPreComposedForm(
|
||
|
LPCWSTR pWCStr,
|
||
|
LPWSTR pEndWCStr,
|
||
|
LPWSTR pPreComp)
|
||
|
{
|
||
|
WCHAR wch; // precomposed character
|
||
|
LPWSTR pPos; // ptr to position in string
|
||
|
|
||
|
|
||
|
//
|
||
|
// If no precomposed form can be found, return 1 character used
|
||
|
// (base character).
|
||
|
//
|
||
|
if (((pWCStr + 1) >= pEndWCStr) ||
|
||
|
(!(wch = GetPreComposedChar(*(pWCStr + 1), *pWCStr))))
|
||
|
{
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the precomposed character from the given wide character string.
|
||
|
// Must check for multiple nonspacing characters for the same
|
||
|
// precomposed character.
|
||
|
//
|
||
|
*pPreComp = wch;
|
||
|
pPos = (LPWSTR)pWCStr + 2;
|
||
|
while ((pPos < pEndWCStr) &&
|
||
|
(wch = GetPreComposedChar(*pPos, *pPreComp)))
|
||
|
{
|
||
|
*pPreComp = wch;
|
||
|
pPos++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the number of characters used to form the precomposed
|
||
|
// character.
|
||
|
//
|
||
|
return ((int)(pPos - (LPWSTR)pWCStr));
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// InsertFullWidthPreComposedForm
|
||
|
//
|
||
|
// Gets the full width precomposed form of a given wide character string,
|
||
|
// places it in the given wide character, and returns the number of
|
||
|
// composite characters used to form the precomposed form. If there is
|
||
|
// no precomposed form for the given character, only the full width conversion
|
||
|
// of the first code point is written into pPreComp and it returns 1 for
|
||
|
// the number of characters used.
|
||
|
//
|
||
|
// 11-04-93 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
int FASTCALL InsertFullWidthPreComposedForm(
|
||
|
LPCWSTR pWCStr,
|
||
|
LPWSTR pEndWCStr,
|
||
|
LPWSTR pPreComp,
|
||
|
PCASE pCase)
|
||
|
{
|
||
|
WCHAR wch; // nonspace character
|
||
|
LPWSTR pPos; // ptr to position in string
|
||
|
|
||
|
|
||
|
//
|
||
|
// Get the case (if necessary).
|
||
|
//
|
||
|
*pPreComp = (pCase) ? GET_LOWER_UPPER_CASE(pCase, *pWCStr) : *pWCStr;
|
||
|
|
||
|
//
|
||
|
// Get the full width.
|
||
|
//
|
||
|
*pPreComp = GET_FULL_WIDTH(pTblPtrs->pFullWidth, *pPreComp);
|
||
|
|
||
|
if ((pPos = ((LPWSTR)pWCStr + 1)) >= pEndWCStr)
|
||
|
{
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
while (pPos < pEndWCStr)
|
||
|
{
|
||
|
wch = (pCase) ? GET_LOWER_UPPER_CASE(pCase, *pPos) : *pPos;
|
||
|
wch = GET_FULL_WIDTH(pTblPtrs->pFullWidth, wch);
|
||
|
if (wch = GetPreComposedChar(wch, *pPreComp))
|
||
|
{
|
||
|
*pPreComp = wch;
|
||
|
pPos++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the number of characters used to form the precomposed
|
||
|
// character.
|
||
|
//
|
||
|
return ((int)(pPos - (LPWSTR)pWCStr));
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// InsertCompositeForm
|
||
|
//
|
||
|
// Gets the composite form of a given wide character, places it in the
|
||
|
// wide character string, and returns the number of characters written.
|
||
|
// If there is no composite form for the given character, the wide character
|
||
|
// string is not touched. It will return 1 for the number of characters
|
||
|
// written, since the base character was already written.
|
||
|
//
|
||
|
// 05-31-91 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
int FASTCALL InsertCompositeForm(
|
||
|
LPWSTR pWCStr,
|
||
|
LPWSTR pEndWCStr)
|
||
|
{
|
||
|
WCHAR Base; // base character
|
||
|
WCHAR NonSp; // non space character
|
||
|
int wcCount = 0; // number of wide characters written
|
||
|
LPWSTR pEndComp; // ptr to end of composite form
|
||
|
int ctr; // loop counter
|
||
|
|
||
|
|
||
|
//
|
||
|
// If no composite form can be found, return 1 for the base
|
||
|
// character that was already written.
|
||
|
//
|
||
|
if (!GetCompositeChars(*pWCStr, &NonSp, &Base))
|
||
|
{
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the composite characters and write them to the pWCStr
|
||
|
// buffer. Must check for multiple breakdowns of the precomposed
|
||
|
// character into more than 2 characters (multiple nonspacing
|
||
|
// characters).
|
||
|
//
|
||
|
pEndComp = pWCStr;
|
||
|
do
|
||
|
{
|
||
|
//
|
||
|
// Make sure pWCStr is big enough to hold the nonspacing
|
||
|
// character.
|
||
|
//
|
||
|
if (pEndComp < (pEndWCStr - 1))
|
||
|
{
|
||
|
//
|
||
|
// Addition of next breakdown of nonspacing characters
|
||
|
// are to be added right after the base character. So,
|
||
|
// move all nonspacing characters ahead one position
|
||
|
// to make room for the next nonspacing character.
|
||
|
//
|
||
|
pEndComp++;
|
||
|
for (ctr = 0; ctr < wcCount; ctr++)
|
||
|
{
|
||
|
*(pEndComp - ctr) = *(pEndComp - (ctr + 1));
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Fill in the new base form and the new nonspacing character.
|
||
|
//
|
||
|
*pWCStr = Base;
|
||
|
*(pWCStr + 1) = NonSp;
|
||
|
wcCount++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Make sure we don't get into an infinite loop if the
|
||
|
// destination buffer isn't large enough.
|
||
|
//
|
||
|
break;
|
||
|
}
|
||
|
} while (GetCompositeChars(*pWCStr, &NonSp, &Base));
|
||
|
|
||
|
//
|
||
|
// Return number of wide characters written. Add 1 to include the
|
||
|
// base character.
|
||
|
//
|
||
|
return (wcCount + 1);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// NlsConvertIntegerToString
|
||
|
//
|
||
|
// This routine converts an integer to a Unicode string.
|
||
|
//
|
||
|
// 11-15-96 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
ULONG NlsConvertIntegerToString(
|
||
|
UINT Value,
|
||
|
UINT Base,
|
||
|
UINT Padding,
|
||
|
LPWSTR pResultBuf,
|
||
|
UINT Size)
|
||
|
{
|
||
|
UNICODE_STRING ObString; // value string
|
||
|
UINT ctr; // loop counter
|
||
|
LPWSTR pBufPtr; // ptr to result buffer
|
||
|
WCHAR pTmpBuf[MAX_PATH_LEN]; // ptr to temp buffer
|
||
|
ULONG rc = 0L; // return code
|
||
|
|
||
|
|
||
|
//
|
||
|
// Set up the Unicode string structure.
|
||
|
//
|
||
|
ObString.Length = (USHORT)(Size * sizeof(WCHAR));
|
||
|
ObString.MaximumLength = (USHORT)(Size * sizeof(WCHAR));
|
||
|
ObString.Buffer = pTmpBuf;
|
||
|
|
||
|
//
|
||
|
// Get the value as a string.
|
||
|
//
|
||
|
if (rc = RtlIntegerToUnicodeString(Value, Base, &ObString))
|
||
|
{
|
||
|
return (rc);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Pad the string with the appropriate number of zeros.
|
||
|
//
|
||
|
pBufPtr = pResultBuf;
|
||
|
for (ctr = GET_WC_COUNT(ObString.Length);
|
||
|
ctr < Padding;
|
||
|
ctr++, pBufPtr++)
|
||
|
{
|
||
|
*pBufPtr = NLS_CHAR_ZERO;
|
||
|
}
|
||
|
NlsStrCpyW(pBufPtr, ObString.Buffer);
|
||
|
|
||
|
//
|
||
|
// Return success.
|
||
|
//
|
||
|
return (NO_ERROR);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// NlsConvertIntegerToHexStringW
|
||
|
// Convert an integer value to an Unicode null-terminated string WITH
|
||
|
// leading zeros. E.g. 0x409 with Width 5 will be converted to L"0409".
|
||
|
// This function is faster than NlsConvertIntegerToString(), but it
|
||
|
// only supports hex numbers.
|
||
|
//
|
||
|
// Parameters:
|
||
|
// Value The number to be converted.
|
||
|
// UpperCase If TRUE, the hex digit will be uppercase.
|
||
|
// Str The buffer for the converted Unicode string.
|
||
|
// Width The character count of the buffer. The value should be the total
|
||
|
// heximal digit number plus one for null-terminiated.
|
||
|
// E.g. if the value is from 0x0000 - 0xffff, the Width should be 5.
|
||
|
//
|
||
|
// Return:
|
||
|
// TRUE if successful. FALSE if the width is not big enough to hold the converted string.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL FASTCALL NlsConvertIntegerToHexStringW(UINT Value, BOOL UpperCase, PWSTR Str, UINT CharCount)
|
||
|
{
|
||
|
int Digit;
|
||
|
PWSTR p;
|
||
|
|
||
|
if(Str == NULL)
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
p = Str + CharCount - 1;
|
||
|
*p-- = L'\0';
|
||
|
while (p >= Str)
|
||
|
{
|
||
|
Digit = Value & 0xf;
|
||
|
if (Digit < 10)
|
||
|
{
|
||
|
Digit = Digit + L'0';
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Digit = Digit - 10 + (UpperCase ? L'A' : L'a');
|
||
|
}
|
||
|
*p-- = (WCHAR)Digit;
|
||
|
Value >>= 4;
|
||
|
}
|
||
|
|
||
|
if (Value > 0)
|
||
|
{
|
||
|
//
|
||
|
// There are still digit remaining.
|
||
|
//
|
||
|
return (FALSE);
|
||
|
}
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// NlsConvertStringToIntegerW
|
||
|
//
|
||
|
// Parameters:
|
||
|
// Str the hex string to be converted.
|
||
|
// Base base
|
||
|
// CharCount
|
||
|
// the character count of the string (excluding the terminiated-null, if any).
|
||
|
// If the value is -1, this function assumes that
|
||
|
// Str is a null-terminated string.
|
||
|
// Result the pointer to the result.
|
||
|
//
|
||
|
// Result:
|
||
|
// TRUE if the operation is successful. FALSE if there is non-hex
|
||
|
// character in the string.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL FASTCALL NlsConvertStringToIntegerW(PWSTR Str, UINT Base, int CharCount, UINT* Result)
|
||
|
{
|
||
|
int i;
|
||
|
WCHAR Digit;
|
||
|
WCHAR c;
|
||
|
|
||
|
if (Str == NULL || Result == NULL)
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
*Result = 0;
|
||
|
|
||
|
if (CharCount == -1)
|
||
|
{
|
||
|
while (c = *Str)
|
||
|
{
|
||
|
c = *Str;
|
||
|
if (c >= L'0' && c <= L'9')
|
||
|
{
|
||
|
Digit = c - L'0';
|
||
|
}
|
||
|
else if(Base == 16)
|
||
|
{
|
||
|
if (c >= L'A' && c <= L'F')
|
||
|
{
|
||
|
Digit = c - L'A' + 10;
|
||
|
}
|
||
|
else if (c >= L'a' && c <= L'f')
|
||
|
{
|
||
|
Digit = c - L'a' + 10;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
if (Base == 16)
|
||
|
{
|
||
|
*Result = (*Result << 4) | Digit;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*Result = *Result*10 + Digit;
|
||
|
}
|
||
|
|
||
|
Str++;
|
||
|
}
|
||
|
} else
|
||
|
{
|
||
|
for (i=0; i< CharCount; i++) {
|
||
|
c = *Str++;
|
||
|
if (c >= L'0' && c <= L'9')
|
||
|
{
|
||
|
Digit = c - L'0';
|
||
|
}
|
||
|
else if(Base == 16)
|
||
|
{
|
||
|
if (c >= L'A' && c <= L'F')
|
||
|
{
|
||
|
Digit = c - L'A' + 10;
|
||
|
}
|
||
|
else if (c >= L'a' && c <= L'f')
|
||
|
{
|
||
|
Digit = c - L'a' + 10;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
if (Base == 16)
|
||
|
{
|
||
|
*Result = (*Result << 4) | Digit;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*Result = *Result*10 + Digit;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// NlsStrCpyW
|
||
|
//
|
||
|
// This routine copies the source wide character string to the destination
|
||
|
// wide character string buffer.
|
||
|
//
|
||
|
// NOTE: This routine is here to avoid any dependencies on other DLLs
|
||
|
// during initialization.
|
||
|
//
|
||
|
// 05-31-91 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
LPWSTR FASTCALL NlsStrCpyW(
|
||
|
LPWSTR pwszDest,
|
||
|
LPCWSTR pwszSrc)
|
||
|
{
|
||
|
LPWSTR pwszRet = pwszDest; // ptr to beginning of string
|
||
|
|
||
|
loop:
|
||
|
if (!(pwszDest[0x0] = pwszSrc[0x0])) goto done;
|
||
|
if (!(pwszDest[0x1] = pwszSrc[0x1])) goto done;
|
||
|
if (!(pwszDest[0x2] = pwszSrc[0x2])) goto done;
|
||
|
if (!(pwszDest[0x3] = pwszSrc[0x3])) goto done;
|
||
|
if (!(pwszDest[0x4] = pwszSrc[0x4])) goto done;
|
||
|
if (!(pwszDest[0x5] = pwszSrc[0x5])) goto done;
|
||
|
if (!(pwszDest[0x6] = pwszSrc[0x6])) goto done;
|
||
|
if (!(pwszDest[0x7] = pwszSrc[0x7])) goto done;
|
||
|
if (!(pwszDest[0x8] = pwszSrc[0x8])) goto done;
|
||
|
if (!(pwszDest[0x9] = pwszSrc[0x9])) goto done;
|
||
|
if (!(pwszDest[0xA] = pwszSrc[0xA])) goto done;
|
||
|
if (!(pwszDest[0xB] = pwszSrc[0xB])) goto done;
|
||
|
if (!(pwszDest[0xC] = pwszSrc[0xC])) goto done;
|
||
|
if (!(pwszDest[0xD] = pwszSrc[0xD])) goto done;
|
||
|
if (!(pwszDest[0xE] = pwszSrc[0xE])) goto done;
|
||
|
if (!(pwszDest[0xF] = pwszSrc[0xF])) goto done;
|
||
|
|
||
|
pwszDest+= 0x10;
|
||
|
pwszSrc+= 0x10;
|
||
|
|
||
|
goto loop;
|
||
|
|
||
|
done:
|
||
|
return (pwszRet);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// NlsStrCatW
|
||
|
//
|
||
|
// This routine attaches the second string to the first string.
|
||
|
//
|
||
|
// NOTE: This routine is here to avoid any dependencies on other DLLs
|
||
|
// during initialization.
|
||
|
//
|
||
|
// 05-31-91 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
LPWSTR FASTCALL NlsStrCatW(
|
||
|
LPWSTR pwsz1,
|
||
|
LPCWSTR pwsz2)
|
||
|
{
|
||
|
LPWSTR pwszRet = pwsz1; // ptr to beginning of string
|
||
|
|
||
|
strlen_loop:
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
if (*pwsz1) pwsz1++; else goto cat_loop;
|
||
|
|
||
|
goto strlen_loop;
|
||
|
|
||
|
cat_loop:
|
||
|
if (!(pwsz1[0x00] = pwsz2[0x00])) goto done;
|
||
|
if (!(pwsz1[0x01] = pwsz2[0x01])) goto done;
|
||
|
if (!(pwsz1[0x02] = pwsz2[0x02])) goto done;
|
||
|
if (!(pwsz1[0x03] = pwsz2[0x03])) goto done;
|
||
|
if (!(pwsz1[0x04] = pwsz2[0x04])) goto done;
|
||
|
if (!(pwsz1[0x05] = pwsz2[0x05])) goto done;
|
||
|
if (!(pwsz1[0x06] = pwsz2[0x06])) goto done;
|
||
|
if (!(pwsz1[0x07] = pwsz2[0x07])) goto done;
|
||
|
if (!(pwsz1[0x08] = pwsz2[0x08])) goto done;
|
||
|
if (!(pwsz1[0x09] = pwsz2[0x09])) goto done;
|
||
|
if (!(pwsz1[0x0A] = pwsz2[0x0A])) goto done;
|
||
|
if (!(pwsz1[0x0B] = pwsz2[0x0B])) goto done;
|
||
|
if (!(pwsz1[0x0C] = pwsz2[0x0C])) goto done;
|
||
|
if (!(pwsz1[0x0D] = pwsz2[0x0D])) goto done;
|
||
|
if (!(pwsz1[0x0E] = pwsz2[0x0E])) goto done;
|
||
|
if (!(pwsz1[0x0F] = pwsz2[0x0F])) goto done;
|
||
|
|
||
|
pwsz1 += 0x10;
|
||
|
pwsz2 += 0x10;
|
||
|
goto cat_loop;
|
||
|
|
||
|
done:
|
||
|
return (pwszRet);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// NlsStrLenW
|
||
|
//
|
||
|
// This routine returns the length of the given wide character string.
|
||
|
// The length does NOT include the null terminator.
|
||
|
//
|
||
|
// NOTE: This routine is here to avoid any dependencies on other DLLs
|
||
|
// during initialization.
|
||
|
//
|
||
|
// 05-31-91 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
int FASTCALL NlsStrLenW(
|
||
|
LPCWSTR pwsz)
|
||
|
{
|
||
|
LPCWSTR pwszStart = pwsz; // ptr to beginning of string
|
||
|
|
||
|
loop:
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
if (*pwsz) pwsz++; else goto done;
|
||
|
|
||
|
goto loop;
|
||
|
|
||
|
done:
|
||
|
return ((int)(pwsz - pwszStart));
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// NlsStrNCatW
|
||
|
//
|
||
|
// This routine concatenates two wide character strings for the count of
|
||
|
// characters given. It copies "Count" characters from the back string to
|
||
|
// the end of the "front" string.
|
||
|
//
|
||
|
// NOTE: This routine is here to avoid any dependencies on other DLLs
|
||
|
// during initialization.
|
||
|
//
|
||
|
// 05-31-91 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
LPWSTR FASTCALL NlsStrNCatW(
|
||
|
LPWSTR pwszFront,
|
||
|
LPCWSTR pwszBack,
|
||
|
int Count)
|
||
|
{
|
||
|
LPWSTR pwszStart = pwszFront; // ptr to beginning of string
|
||
|
|
||
|
strlen_loop:
|
||
|
if (*pwszFront) pwszFront++; goto cat_loop;
|
||
|
if (*pwszFront) pwszFront++; goto cat_loop;
|
||
|
if (*pwszFront) pwszFront++; goto cat_loop;
|
||
|
if (*pwszFront) pwszFront++; goto cat_loop;
|
||
|
if (*pwszFront) pwszFront++; goto cat_loop;
|
||
|
if (*pwszFront) pwszFront++; goto cat_loop;
|
||
|
if (*pwszFront) pwszFront++; goto cat_loop;
|
||
|
if (*pwszFront) pwszFront++; goto cat_loop;
|
||
|
|
||
|
goto strlen_loop;
|
||
|
|
||
|
cat_loop:
|
||
|
if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
|
||
|
pwszFront++; pwszBack++; Count--;
|
||
|
if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
|
||
|
pwszFront++; pwszBack++; Count--;
|
||
|
if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
|
||
|
pwszFront++; pwszBack++; Count--;
|
||
|
if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
|
||
|
pwszFront++; pwszBack++; Count--;
|
||
|
if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
|
||
|
pwszFront++; pwszBack++; Count--;
|
||
|
if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
|
||
|
pwszFront++; pwszBack++; Count--;
|
||
|
if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
|
||
|
pwszFront++; pwszBack++; Count--;
|
||
|
if (Count == 0 || !(*pwszFront = *pwszBack)) goto done;
|
||
|
pwszFront++; pwszBack++; Count--;
|
||
|
|
||
|
goto cat_loop;
|
||
|
|
||
|
done:
|
||
|
*pwszFront = (WCHAR)0;
|
||
|
return (pwszStart);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// NlsStrEqualW
|
||
|
//
|
||
|
// This routine compares two strings to see if they are exactly identical.
|
||
|
// It returns 1 if they are identical, 0 if they are different.
|
||
|
//
|
||
|
// NOTE: This routine is here to avoid any dependencies on other DLLs
|
||
|
// during initialization.
|
||
|
//
|
||
|
// 05-31-91 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
int FASTCALL NlsStrEqualW(
|
||
|
LPCWSTR pwszFirst,
|
||
|
LPCWSTR pwszSecond)
|
||
|
{
|
||
|
loop:
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
|
||
|
goto loop;
|
||
|
|
||
|
error:
|
||
|
//
|
||
|
// Return error.
|
||
|
//
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// NlsStrNEqualW
|
||
|
//
|
||
|
// This routine compares two strings to see if they are exactly identical
|
||
|
// for the count of characters given.
|
||
|
// It returns 1 if they are identical, 0 if they are different.
|
||
|
//
|
||
|
// NOTE: This routine is here to avoid any dependencies on other DLLs
|
||
|
// during initialization.
|
||
|
//
|
||
|
// 05-31-91 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
int FASTCALL NlsStrNEqualW(
|
||
|
LPCWSTR pwszFirst,
|
||
|
LPCWSTR pwszSecond,
|
||
|
int Count)
|
||
|
{
|
||
|
loop:
|
||
|
if (Count == 0) return (1);
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
Count--;
|
||
|
|
||
|
if (Count == 0) return (1);
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
Count--;
|
||
|
|
||
|
if (Count == 0) return (1);
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
Count--;
|
||
|
|
||
|
if (Count == 0) return (1);
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
Count--;
|
||
|
|
||
|
if (Count == 0) return (1);
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
Count--;
|
||
|
|
||
|
if (Count == 0) return (1);
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
Count--;
|
||
|
|
||
|
if (Count == 0) return (1);
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
Count--;
|
||
|
|
||
|
if (Count == 0) return (1);
|
||
|
if (*pwszFirst != *pwszSecond) goto error;
|
||
|
if (!*pwszFirst) return (1);
|
||
|
pwszFirst++;
|
||
|
pwszSecond++;
|
||
|
Count--;
|
||
|
|
||
|
goto loop;
|
||
|
|
||
|
error:
|
||
|
//
|
||
|
// Return error.
|
||
|
//
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// GetDefaultSortkeySize
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
ULONG GetDefaultSortkeySize(
|
||
|
PLARGE_INTEGER pSize)
|
||
|
{
|
||
|
*pSize = pTblPtrs->DefaultSortkeySize;
|
||
|
return (STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// GetLinguistLangSize
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
ULONG GetLinguistLangSize(
|
||
|
PLARGE_INTEGER pSize)
|
||
|
{
|
||
|
*pSize = pTblPtrs->LinguistLangSize;
|
||
|
return (STATUS_SUCCESS);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// ValidateLocale
|
||
|
//
|
||
|
// Internal routine, called from server. Validates that a locale is
|
||
|
// present in the registry. This code comes from IsValidLocale, but
|
||
|
// does not check the internal data to prevent recursive calls to the
|
||
|
// server.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL ValidateLocale(
|
||
|
LCID Locale)
|
||
|
{
|
||
|
PKEY_VALUE_FULL_INFORMATION pKeyValueFull;
|
||
|
BYTE pStatic1[MAX_KEY_VALUE_FULLINFO];
|
||
|
BYTE pStatic2[MAX_KEY_VALUE_FULLINFO];
|
||
|
|
||
|
WCHAR pTmpBuf[MAX_PATH]; // temp buffer
|
||
|
UNICODE_STRING ObUnicodeStr; // registry data value string
|
||
|
DWORD Data; // registry data value
|
||
|
LPWSTR pData; // ptr to registry data
|
||
|
BOOL bResult = FALSE; // result value
|
||
|
|
||
|
//
|
||
|
// Invalid Locale Check.
|
||
|
//
|
||
|
if (IS_INVALID_LOCALE(Locale))
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Open the Locale, the Alternate Sorts, and the Language Groups
|
||
|
// registry keys.
|
||
|
//
|
||
|
OPEN_LOCALE_KEY(FALSE);
|
||
|
OPEN_ALT_SORTS_KEY(FALSE);
|
||
|
OPEN_LANG_GROUPS_KEY(FALSE);
|
||
|
|
||
|
//
|
||
|
// Convert locale value to Unicode string.
|
||
|
//
|
||
|
if (NlsConvertIntegerToString(Locale, 16, 8, pTmpBuf, MAX_PATH))
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Query the registry for the value.
|
||
|
//
|
||
|
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic1;
|
||
|
if (((QueryRegValue( hLocaleKey,
|
||
|
pTmpBuf,
|
||
|
&pKeyValueFull,
|
||
|
MAX_KEY_VALUE_FULLINFO,
|
||
|
NULL ) == NO_ERROR) ||
|
||
|
(QueryRegValue( hAltSortsKey,
|
||
|
pTmpBuf,
|
||
|
&pKeyValueFull,
|
||
|
MAX_KEY_VALUE_FULLINFO,
|
||
|
NULL ) == NO_ERROR)) &&
|
||
|
(pKeyValueFull->DataLength > 2))
|
||
|
{
|
||
|
RtlInitUnicodeString(&ObUnicodeStr, GET_VALUE_DATA_PTR(pKeyValueFull));
|
||
|
if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 16, &Data) == NO_ERROR) &&
|
||
|
(Data != 0))
|
||
|
{
|
||
|
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic2;
|
||
|
if ((QueryRegValue( hLangGroupsKey,
|
||
|
ObUnicodeStr.Buffer,
|
||
|
&pKeyValueFull,
|
||
|
MAX_KEY_VALUE_FULLINFO,
|
||
|
NULL ) == NO_ERROR) &&
|
||
|
(pKeyValueFull->DataLength > 2))
|
||
|
{
|
||
|
pData = GET_VALUE_DATA_PTR(pKeyValueFull);
|
||
|
if ((pData[0] == L'1') && (pData[1] == 0))
|
||
|
{
|
||
|
bResult = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return the result.
|
||
|
//
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// ValidateLCType
|
||
|
//
|
||
|
// This routine is called from the server (and also from locale.c) in
|
||
|
// order to get a Registry key name and a field pointer in the NlsInfo
|
||
|
// structure given an LCType.
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL ValidateLCType(
|
||
|
PNLS_USER_INFO pInfo,
|
||
|
LCTYPE LCType,
|
||
|
LPWSTR *ppwReg,
|
||
|
LPWSTR *ppwCache)
|
||
|
{
|
||
|
switch (LCType)
|
||
|
{
|
||
|
case ( LOCALE_IFIRSTWEEKOFYEAR ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_IFIRSTWEEKOFYEAR;
|
||
|
*ppwCache = pInfo->iFirstWeek;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_IFIRSTDAYOFWEEK ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_IFIRSTDAYOFWEEK;
|
||
|
*ppwCache = pInfo->iFirstDay;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_ICALENDARTYPE ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_ICALENDARTYPE;
|
||
|
*ppwCache = pInfo->iCalType;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_SLONGDATE ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_SLONGDATE;
|
||
|
*ppwCache = pInfo->sLongDate;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_SYEARMONTH ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_SYEARMONTH;
|
||
|
*ppwCache = pInfo->sYearMonth;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_S1159 ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_S1159;
|
||
|
*ppwCache = pInfo->s1159;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_SNEGATIVESIGN ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_SNEGATIVESIGN;
|
||
|
*ppwCache = pInfo->sNegSign;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_SPOSITIVESIGN ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_SPOSITIVESIGN;
|
||
|
*ppwCache = pInfo->sPosSign;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_INEGCURR ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_INEGCURR;
|
||
|
*ppwCache = pInfo->iNegCurr;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_ICURRENCY ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_ICURRENCY;
|
||
|
*ppwCache = pInfo->iCurrency;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_ICURRDIGITS ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_ICURRDIGITS;
|
||
|
*ppwCache = pInfo->iCurrDigits;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_SMONGROUPING ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_SMONGROUPING;
|
||
|
*ppwCache = pInfo->sMonGrouping;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_SMONTHOUSANDSEP ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_SMONTHOUSANDSEP;
|
||
|
*ppwCache = pInfo->sMonThouSep;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_SMONDECIMALSEP ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_SMONDECIMALSEP;
|
||
|
*ppwCache = pInfo->sMonDecSep;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_SCURRENCY ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_SCURRENCY;
|
||
|
*ppwCache = pInfo->sCurrency;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_IDIGITSUBSTITUTION ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_IDIGITSUBST;
|
||
|
*ppwCache = pInfo->iDigitSubstitution;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_SNATIVEDIGITS ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_SNATIVEDIGITS;
|
||
|
*ppwCache = pInfo->sNativeDigits;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_INEGNUMBER ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_INEGNUMBER;
|
||
|
*ppwCache = pInfo->iNegNumber;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_ILZERO ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_ILZERO;
|
||
|
*ppwCache = pInfo->iLZero;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_IDIGITS ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_IDIGITS;
|
||
|
*ppwCache = pInfo->iDigits;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_SGROUPING ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_SGROUPING;
|
||
|
*ppwCache = pInfo->sGrouping;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_STHOUSAND ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_STHOUSAND;
|
||
|
*ppwCache = pInfo->sThousand;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_SDECIMAL ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_SDECIMAL;
|
||
|
*ppwCache = pInfo->sDecimal;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_IPAPERSIZE ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_IPAPERSIZE;
|
||
|
*ppwCache = pInfo->iPaperSize;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_IMEASURE ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_IMEASURE;
|
||
|
*ppwCache = pInfo->iMeasure;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_SLIST ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_SLIST;
|
||
|
*ppwCache = pInfo->sList;
|
||
|
break;
|
||
|
}
|
||
|
case ( LOCALE_S2359 ) :
|
||
|
{
|
||
|
*ppwReg = NLS_VALUE_S2359;
|
||
|
*ppwCache = pInfo->s2359;
|
||
|
break;
|
||
|
}
|
||
|
default :
|
||
|
{
|
||
|
return (FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// GetStringTableEntry
|
||
|
//
|
||
|
// Returns the localized version of the strings for the given resource
|
||
|
// id. It gets the information from the resource file in the language that
|
||
|
// the current user is using.
|
||
|
//
|
||
|
// The string table contains a series of strings in the following order:
|
||
|
// Language Name
|
||
|
// Country Name
|
||
|
// Language Group Name
|
||
|
// Code Page Name (decimal values converted to hex values)
|
||
|
// Region (Geo) Friendly Name (decimal values converted to hex values)
|
||
|
// Region (Geo) Official Name (decimal values converted to hex values)
|
||
|
// Sorting Names (in order starting with 0, separated by $)
|
||
|
//
|
||
|
// Each string is separated by $. The final string is terminated with
|
||
|
// a null.
|
||
|
//
|
||
|
// The sorting names are in order of the sort ids, starting with 0.
|
||
|
//
|
||
|
// For example,
|
||
|
// "Language$Country$LangGrp$CodePage$Geo1$Geo2$Sort0$Sort1" or
|
||
|
// "Language$Country" or
|
||
|
// "$$LangGrp$CodePage" or
|
||
|
// "$$$CodePage" or
|
||
|
// "$$$$Geo1$Geo2"
|
||
|
//
|
||
|
// 11-17-00 JulieB Created.
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
int GetStringTableEntry(
|
||
|
UINT ResourceID,
|
||
|
LANGID UILangId,
|
||
|
LPWSTR pBuffer,
|
||
|
int cchBuffer,
|
||
|
int WhichString)
|
||
|
{
|
||
|
HANDLE hFindRes; // handle from find resource
|
||
|
HANDLE hLoadRes; // handle from load resource
|
||
|
LPWSTR pSearch, pSearchEnd; // ptrs to search for correct string
|
||
|
LPWSTR pString; // ptr to final string
|
||
|
int cchCount = 0; // count of characters
|
||
|
|
||
|
|
||
|
//
|
||
|
// Make sure the buffer is ok.
|
||
|
//
|
||
|
if ((pBuffer == NULL) || (cchBuffer == 0))
|
||
|
{
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure we're not hitting the GEO ID that is out of bounds.
|
||
|
//
|
||
|
// !!! NOTE !!! This is needed because the East Timor Geo Id
|
||
|
// is out of bounds and wraps to 0x60e7.
|
||
|
//
|
||
|
if (ResourceID == 0x60e7)
|
||
|
{
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the UI Language Id.
|
||
|
//
|
||
|
if (UILangId == 0)
|
||
|
{
|
||
|
UILangId = GetUserDefaultUILanguage();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// String Tables are broken up into 16 string segments. Find the
|
||
|
// resource containing the string we want.
|
||
|
//
|
||
|
if ((!(hFindRes = FindResourceExW( hModule,
|
||
|
RT_STRING,
|
||
|
(LPWSTR)UlongToPtr((ULONG)(((USHORT)ResourceID >> 4) + 1)),
|
||
|
(WORD)UILangId ))))
|
||
|
{
|
||
|
//
|
||
|
// Could not find resource. Try NEUTRAL language id.
|
||
|
//
|
||
|
if ((!(hFindRes = FindResourceExW( hModule,
|
||
|
RT_STRING,
|
||
|
(LPWSTR)UlongToPtr((ULONG)(((USHORT)ResourceID >> 4) + 1)),
|
||
|
(WORD)0 ))))
|
||
|
{
|
||
|
//
|
||
|
// Could not find resource. Return 0.
|
||
|
//
|
||
|
return (0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Load the resource.
|
||
|
//
|
||
|
if (hLoadRes = LoadResource(hModule, hFindRes))
|
||
|
{
|
||
|
//
|
||
|
// Lock the resource. Store the found pointer in the given
|
||
|
// pointer.
|
||
|
//
|
||
|
if (pSearch = (LPWSTR)LockResource(hLoadRes))
|
||
|
{
|
||
|
//
|
||
|
// Move past the other strings in this segment.
|
||
|
// (16 strings in a segment -> & 0x0F)
|
||
|
//
|
||
|
ResourceID &= 0x0F;
|
||
|
|
||
|
//
|
||
|
// Find the correct string in this segment.
|
||
|
//
|
||
|
while (TRUE)
|
||
|
{
|
||
|
cchCount = *((WORD *)pSearch++);
|
||
|
if (ResourceID-- == 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
pSearch += cchCount;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Mark the end of the resource string since it is not
|
||
|
// NULL terminated.
|
||
|
//
|
||
|
pSearchEnd = pSearch + cchCount;
|
||
|
|
||
|
//
|
||
|
// Get to the appropriate string.
|
||
|
//
|
||
|
while ((WhichString > 0) && (pSearch < pSearchEnd))
|
||
|
{
|
||
|
do
|
||
|
{
|
||
|
if (*pSearch == RC_STRING_SEPARATOR)
|
||
|
{
|
||
|
pSearch++;
|
||
|
break;
|
||
|
}
|
||
|
pSearch++;
|
||
|
|
||
|
} while (pSearch < pSearchEnd);
|
||
|
|
||
|
WhichString--;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Count the number of characters for this string.
|
||
|
//
|
||
|
pString = pSearch;
|
||
|
cchCount = 0;
|
||
|
while ((pSearch < pSearchEnd) && (*pSearch != RC_STRING_SEPARATOR))
|
||
|
{
|
||
|
pSearch++;
|
||
|
cchCount++;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// See if there is anything to copy.
|
||
|
//
|
||
|
if (cchCount > 0)
|
||
|
{
|
||
|
//
|
||
|
// Don't copy more than the max allowed.
|
||
|
//
|
||
|
if (cchCount >= cchBuffer)
|
||
|
{
|
||
|
cchCount = cchBuffer - 1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Copy the string into the buffer and NULL terminate it.
|
||
|
//
|
||
|
CopyMemory(pBuffer, pString, cchCount * sizeof(WCHAR));
|
||
|
pBuffer[cchCount] = 0;
|
||
|
|
||
|
//
|
||
|
// Return the number of characters in the string, not
|
||
|
// including the NULL terminator.
|
||
|
//
|
||
|
return (cchCount);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Return failure.
|
||
|
//
|
||
|
return (0);
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// NlsIsDll
|
||
|
//
|
||
|
// Check if file extension is DLL
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
BOOL FASTCALL NlsIsDll(
|
||
|
LPCWSTR pFileName
|
||
|
)
|
||
|
{
|
||
|
BOOL bIsDll = FALSE;
|
||
|
|
||
|
|
||
|
if (pFileName)
|
||
|
{
|
||
|
int iLen = NlsStrLenW(pFileName);
|
||
|
|
||
|
//
|
||
|
// Check DLL extension, save the trouble of calling lstrcmp
|
||
|
//
|
||
|
if (iLen > 4)
|
||
|
{
|
||
|
pFileName += iLen-4;
|
||
|
|
||
|
if ((*pFileName++ == L'.') &&
|
||
|
(*pFileName == L'D' || *pFileName++ == L'd') &&
|
||
|
(*pFileName == L'L' || *pFileName++ == L'l') &&
|
||
|
(*pFileName == L'L' || *pFileName++ == L'l'))
|
||
|
{
|
||
|
bIsDll = TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return bIsDll;
|
||
|
}
|
||
|
|