NT4/private/windows/winnls/util.c

994 lines
27 KiB
C
Raw Normal View History

2001-01-01 00:00:00 +01:00
/*++
Copyright (c) 1991-1996, 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.
External Routines found in this file:
IsValidSeparatorString
IsValidCalendarType
IsValidCalendarTypeStr
GetUserInfo
GetPreComposedChar
GetCompositeChars
InsertPreComposedForm
InsertFullWidthPreComposedForm
InsertCompositeForm
NlsStrCpyW
NlsStrCatW
NlsStrLenW
NlsStrNCatW
NlsStrEqualW
NlsStrNEqualW
Revision History:
05-31-91 JulieB Created.
--*/
//
// Include Files.
//
#include "nls.h"
//-------------------------------------------------------------------------//
// 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)
{
WCHAR wch; // wide character
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 (wch = *pCur)
{
if ((wch >= NLS_CHAR_ZERO) && (wch <= NLS_CHAR_NINE))
{
//
// String is NOT valid.
//
return (FALSE);
}
pCur++;
}
Length = pCur - (LPWSTR)pString;
//
// Make sure the length is not greater than the maximum allowed.
//
if (Length >= MaxLength)
{
//
// String is NOT valid.
//
return (FALSE);
}
//
// Check for 0 length string (if appropriate).
//
if ((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));
}
////////////////////////////////////////////////////////////////////////////
//
// GetUserInfo
//
// Gets the information from the registry for the given locale and user
// value entry.
//
// 05-31-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
BOOL GetUserInfo(
LCID Locale,
LPWSTR pCacheString,
LPWSTR pOutput,
BOOL fCheckNull)
{
BOOL fCacheValid; // flag for cache validity
//
// Check to be sure the current user is running in the given locale.
//
if (Locale != pNlsUserInfo->UserLocaleId)
{
return (FALSE);
}
//
// Get the cache mutant.
// Copy the data to the output buffer.
// Get the validity of the cache.
// Release the cache mutant.
//
NtWaitForSingleObject(hNlsCacheMutant, FALSE, NULL);
wcscpy(pOutput, pCacheString);
fCacheValid = pNlsUserInfo->fCacheValid;
NtReleaseMutant(hNlsCacheMutant, NULL);
//
// 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.
//
if ((fCacheValid == FALSE) ||
(*pOutput == NLS_INVALID_INFO_CHAR))
{
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 (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 (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);
}
////////////////////////////////////////////////////////////////////////////
//
// 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) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
if (!*pwsz1) goto cat_loop;
pwsz1++;
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) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
if (!*pwsz) goto done;
pwsz++;
goto loop;
done:
return (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) goto cat_loop;
pwszFront++;
if (!*pwszFront) goto cat_loop;
pwszFront++;
if (!*pwszFront) goto cat_loop;
pwszFront++;
if (!*pwszFront) goto cat_loop;
pwszFront++;
if (!*pwszFront) goto cat_loop;
pwszFront++;
if (!*pwszFront) goto cat_loop;
pwszFront++;
if (!*pwszFront) goto cat_loop;
pwszFront++;
if (!*pwszFront) goto cat_loop;
pwszFront++;
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);
}