Windows2000/private/ntos/rtl/nlsxlat.c
2020-09-30 17:12:32 +02:00

2512 lines
87 KiB
C

/***** Module Header *****\
* Module Name: nlsxlat.c
* Copyright (c) 1985-91, Microsoft Corporation
* This modules contains the private routines for character translation:
* 8-bit <=> Unicode.
* History:
* 03-Jan-1992 gregoryw
* 16-Feb-1993 JulieB Added Upcase Routines & Macros.
* 17-Feb-1993 JulieB Fixed Tables; Fixed DBCS Code.
* 08-Mar-1993 JulieB Moved Upcase Macro to ntrtlp.h.
*/
#include "ntrtlp.h"
NTSTATUS
RtlConsoleMultiByteToUnicodeN(
OUT PWCH UnicodeString,
IN ULONG MaxBytesInUnicodeString,
OUT PULONG BytesInUnicodeString OPTIONAL,
IN PCH MultiByteString,
IN ULONG BytesInMultiByteString,
OUT PULONG pdwSpecialChar );
VOID
RtlpInitUpcaseTable(
IN PUSHORT TableBase,
OUT PNLSTABLEINFO CodePageTable
);
#if defined(ALLOC_PRAGMA) && defined(NTOS_KERNEL_RUNTIME)
#pragma alloc_text(PAGE,RtlConsoleMultiByteToUnicodeN)
#pragma alloc_text(PAGE,RtlMultiByteToUnicodeN)
#pragma alloc_text(PAGE,RtlOemToUnicodeN)
#pragma alloc_text(PAGE,RtlUnicodeToMultiByteN)
#pragma alloc_text(PAGE,RtlUpcaseUnicodeToMultiByteN)
#pragma alloc_text(PAGE,RtlUnicodeToOemN)
#pragma alloc_text(PAGE,RtlUpcaseUnicodeToOemN)
#pragma alloc_text(PAGE,RtlpDidUnicodeToOemWork)
#pragma alloc_text(PAGE,RtlCustomCPToUnicodeN)
#pragma alloc_text(PAGE,RtlUnicodeToCustomCPN)
#pragma alloc_text(PAGE,RtlUpcaseUnicodeToCustomCPN)
#pragma alloc_text(PAGE,RtlInitCodePageTable)
#pragma alloc_text(PAGE,RtlpInitUpcaseTable)
#pragma alloc_text(PAGE,RtlInitNlsTables)
#pragma alloc_text(PAGE,RtlResetRtlTranslations)
#pragma alloc_text(PAGE,RtlMultiByteToUnicodeSize)
#pragma alloc_text(PAGE,RtlUnicodeToMultiByteSize)
#pragma alloc_text(PAGE,RtlGetDefaultCodePage)
#endif
// Various defines and convenient macros for data access
#define DBCS_TABLE_SIZE 256
/*
* Global data used by the translation routines.
*/
// Upcase and Lowercase data
PUSHORT Nls844UnicodeUpcaseTable;
PUSHORT Nls844UnicodeLowercaseTable;
// ACP related data
USHORT NlsLeadByteInfoTable[DBCS_TABLE_SIZE]; // Lead byte info. for ACP
USHORT NlsAnsiCodePage; // Default ANSI code page
USHORT NlsOemCodePage; // Default OEM code page
PUSHORT NlsLeadByteInfo = NlsLeadByteInfoTable;
PUSHORT NlsMbAnsiCodePageTables; // Multibyte to Unicode translation tables
PUSHORT NlsAnsiToUnicodeData; // Ansi CP to Unicode translation table
PCH NlsUnicodeToAnsiData; // Unicode to Ansi CP translation table
PUSHORT NlsUnicodeToMbAnsiData; // Unicode to Multibyte Ansi CP translation table
BOOLEAN NlsMbCodePageTag = FALSE; // TRUE -> Multibyte ACP, FALSE -> Singlebyte ACP
// OEM related data
USHORT NlsOemLeadByteInfoTable[DBCS_TABLE_SIZE]; // Lead byte info. for 0CP
PUSHORT NlsOemLeadByteInfo = NlsOemLeadByteInfoTable;
PUSHORT NlsMbOemCodePageTables; // OEM Multibyte to Unicode translation tables
PUSHORT NlsOemToUnicodeData; // Oem CP to Unicode translation table
PCH NlsUnicodeToOemData; // Unicode to Oem CP translation table
PUSHORT NlsUnicodeToMbOemData; // Unicode to Multibyte Oem CP translation table
BOOLEAN NlsMbOemCodePageTag = FALSE; // TRUE -> Multibyte OCP, FALSE -> Singlebyte OCP
// Default info taken from data files
USHORT UnicodeDefaultChar;
USHORT OemDefaultChar;
USHORT OemTransUniDefaultChar;
// Default info NOT taken from data files
USHORT UnicodeNull = 0x0000;
NTSTATUS
RtlConsoleMultiByteToUnicodeN(
OUT PWCH UnicodeString,
IN ULONG MaxBytesInUnicodeString,
OUT PULONG BytesInUnicodeString OPTIONAL,
IN PCH MultiByteString,
IN ULONG BytesInMultiByteString,
OUT PULONG pdwSpecialChar )
/*++
Routine Description:
This function is a superset of MultiByteToUnicode for the
console. It works just like the other, except it will detect
if any characters were under 0x20.
This functions converts the specified ansi source string into a
Unicode string. The translation is done with respect to the
ANSI Code Page (ACP) installed at boot time. Single byte characters
in the range 0x00 - 0x7f are simply zero extended as a performance
enhancement. In some far eastern code pages 0x5c is defined as the
Yen sign. For system translation we always want to consider 0x5c
to be the backslash character. We get this for free by zero extending.
NOTE: This routine only supports precomposed Unicode characters.
Arguments:
UnicodeString - Returns a unicode string that is equivalent to
the ansi source string.
MaxBytesInUnicodeString - Supplies the maximum number of bytes to be
written to UnicodeString. If this causes UnicodeString to be a
truncated equivalent of MultiByteString, no error condition results.
BytesInUnicodeString - Returns the number of bytes in the returned
unicode string pointed to by UnicodeString.
MultiByteString - Supplies the ansi source string that is to be
converted to unicode.
BytesInMultiByteString - The number of bytes in the string pointed to
by MultiByteString.
pdwSpecialChar - will be zero if non detected, else it will contain the
approximate index (can be off by 32).
Return Value:
SUCCESS - The conversion was successful.
--*/
{
ULONG LoopCount;
PUSHORT TranslateTable;
ULONG MaxCharsInUnicodeString;
RTL_PAGED_CODE();
*pdwSpecialChar = 0;
if (!NlsMbCodePageTag) {
MaxCharsInUnicodeString = MaxBytesInUnicodeString / sizeof(WCHAR);
LoopCount = (MaxCharsInUnicodeString < BytesInMultiByteString) ?
MaxCharsInUnicodeString : BytesInMultiByteString;
if (ARGUMENT_PRESENT(BytesInUnicodeString))
*BytesInUnicodeString = LoopCount * sizeof(WCHAR);
TranslateTable = NlsAnsiToUnicodeData; // used to help the mips compiler
quick_copy:
switch( LoopCount ) {
default:
if ((UCHAR)MultiByteString[0x1F] < 0x20) goto bad_case;
UnicodeString[0x1F] = TranslateTable[(UCHAR)MultiByteString[0x1F]];
case 0x1F:
if ((UCHAR)MultiByteString[0x1E] < 0x20) goto bad_case;
UnicodeString[0x1E] = TranslateTable[(UCHAR)MultiByteString[0x1E]];
case 0x1E:
if ((UCHAR)MultiByteString[0x1D] < 0x20) goto bad_case;
UnicodeString[0x1D] = TranslateTable[(UCHAR)MultiByteString[0x1D]];
case 0x1D:
if ((UCHAR)MultiByteString[0x1C] < 0x20) goto bad_case;
UnicodeString[0x1C] = TranslateTable[(UCHAR)MultiByteString[0x1C]];
case 0x1C:
if ((UCHAR)MultiByteString[0x1B] < 0x20) goto bad_case;
UnicodeString[0x1B] = TranslateTable[(UCHAR)MultiByteString[0x1B]];
case 0x1B:
if ((UCHAR)MultiByteString[0x1A] < 0x20) goto bad_case;
UnicodeString[0x1A] = TranslateTable[(UCHAR)MultiByteString[0x1A]];
case 0x1A:
if ((UCHAR)MultiByteString[0x19] < 0x20) goto bad_case;
UnicodeString[0x19] = TranslateTable[(UCHAR)MultiByteString[0x19]];
case 0x19:
if ((UCHAR)MultiByteString[0x18] < 0x20) goto bad_case;
UnicodeString[0x18] = TranslateTable[(UCHAR)MultiByteString[0x18]];
case 0x18:
if ((UCHAR)MultiByteString[0x17] < 0x20) goto bad_case;
UnicodeString[0x17] = TranslateTable[(UCHAR)MultiByteString[0x17]];
case 0x17:
if ((UCHAR)MultiByteString[0x16] < 0x20) goto bad_case;
UnicodeString[0x16] = TranslateTable[(UCHAR)MultiByteString[0x16]];
case 0x16:
if ((UCHAR)MultiByteString[0x15] < 0x20) goto bad_case;
UnicodeString[0x15] = TranslateTable[(UCHAR)MultiByteString[0x15]];
case 0x15:
if ((UCHAR)MultiByteString[0x14] < 0x20) goto bad_case;
UnicodeString[0x14] = TranslateTable[(UCHAR)MultiByteString[0x14]];
case 0x14:
if ((UCHAR)MultiByteString[0x13] < 0x20) goto bad_case;
UnicodeString[0x13] = TranslateTable[(UCHAR)MultiByteString[0x13]];
case 0x13:
if ((UCHAR)MultiByteString[0x12] < 0x20) goto bad_case;
UnicodeString[0x12] = TranslateTable[(UCHAR)MultiByteString[0x12]];
case 0x12:
if ((UCHAR)MultiByteString[0x11] < 0x20) goto bad_case;
UnicodeString[0x11] = TranslateTable[(UCHAR)MultiByteString[0x11]];
case 0x11:
if ((UCHAR)MultiByteString[0x10] < 0x20) goto bad_case;
UnicodeString[0x10] = TranslateTable[(UCHAR)MultiByteString[0x10]];
case 0x10:
if ((UCHAR)MultiByteString[0x0F] < 0x20) goto bad_case;
UnicodeString[0x0F] = TranslateTable[(UCHAR)MultiByteString[0x0F]];
case 0x0F:
if ((UCHAR)MultiByteString[0x0E] < 0x20) goto bad_case;
UnicodeString[0x0E] = TranslateTable[(UCHAR)MultiByteString[0x0E]];
case 0x0E:
if ((UCHAR)MultiByteString[0x0D] < 0x20) goto bad_case;
UnicodeString[0x0D] = TranslateTable[(UCHAR)MultiByteString[0x0D]];
case 0x0D:
if ((UCHAR)MultiByteString[0x0C] < 0x20) goto bad_case;
UnicodeString[0x0C] = TranslateTable[(UCHAR)MultiByteString[0x0C]];
case 0x0C:
if ((UCHAR)MultiByteString[0x0B] < 0x20) goto bad_case;
UnicodeString[0x0B] = TranslateTable[(UCHAR)MultiByteString[0x0B]];
case 0x0B:
if ((UCHAR)MultiByteString[0x0A] < 0x20) goto bad_case;
UnicodeString[0x0A] = TranslateTable[(UCHAR)MultiByteString[0x0A]];
case 0x0A:
if ((UCHAR)MultiByteString[0x09] < 0x20) goto bad_case;
UnicodeString[0x09] = TranslateTable[(UCHAR)MultiByteString[0x09]];
case 0x09:
if ((UCHAR)MultiByteString[0x08] < 0x20) goto bad_case;
UnicodeString[0x08] = TranslateTable[(UCHAR)MultiByteString[0x08]];
case 0x08:
if ((UCHAR)MultiByteString[0x07] < 0x20) goto bad_case;
UnicodeString[0x07] = TranslateTable[(UCHAR)MultiByteString[0x07]];
case 0x07:
if ((UCHAR)MultiByteString[0x06] < 0x20) goto bad_case;
UnicodeString[0x06] = TranslateTable[(UCHAR)MultiByteString[0x06]];
case 0x06:
if ((UCHAR)MultiByteString[0x05] < 0x20) goto bad_case;
UnicodeString[0x05] = TranslateTable[(UCHAR)MultiByteString[0x05]];
case 0x05:
if ((UCHAR)MultiByteString[0x04] < 0x20) goto bad_case;
UnicodeString[0x04] = TranslateTable[(UCHAR)MultiByteString[0x04]];
case 0x04:
if ((UCHAR)MultiByteString[0x03] < 0x20) goto bad_case;
UnicodeString[0x03] = TranslateTable[(UCHAR)MultiByteString[0x03]];
case 0x03:
if ((UCHAR)MultiByteString[0x02] < 0x20) goto bad_case;
UnicodeString[0x02] = TranslateTable[(UCHAR)MultiByteString[0x02]];
case 0x02:
if ((UCHAR)MultiByteString[0x01] < 0x20) goto bad_case;
UnicodeString[0x01] = TranslateTable[(UCHAR)MultiByteString[0x01]];
case 0x01:
if ((UCHAR)MultiByteString[0x00] < 0x20) goto bad_case;
UnicodeString[0x00] = TranslateTable[(UCHAR)MultiByteString[0x00]];
case 0x00:
;
}
if ( LoopCount > 0x20 ) {
LoopCount -= 0x20;
UnicodeString += 0x20;
MultiByteString += 0x20;
goto quick_copy;
}
/* end of copy... */
} else {
register USHORT Entry;
PWCH UnicodeStringAnchor = UnicodeString;
TranslateTable = (PUSHORT)NlsMbAnsiCodePageTables;
// yea, this line is duplicated, but the compiler can handle opt
// better by moving it around
MaxCharsInUnicodeString = MaxBytesInUnicodeString / sizeof(WCHAR);
// The ACP is a multibyte code page. Check each character
// to see if it is a lead byte before doing the translation.
while (MaxCharsInUnicodeString && BytesInMultiByteString) {
MaxCharsInUnicodeString--;
BytesInMultiByteString--;
if (NlsLeadByteInfo[*(PUCHAR)MultiByteString]) {
// Lead byte - Make sure there is a trail byte. If not,
// pass back a space rather than an error. Some 3.x
// applications pass incorrect strings and don't expect
// to get an error.
if (BytesInMultiByteString == 0)
{
*UnicodeString++ = UnicodeNull;
break;
}
// Get the unicode character.
Entry = NlsLeadByteInfo[*(PUCHAR)MultiByteString++];
*UnicodeString = (WCHAR)TranslateTable[ Entry + *(PUCHAR)MultiByteString++ ];
UnicodeString++;
// Decrement count of bytes in multibyte string to account
// for the double byte character.
BytesInMultiByteString--;
} else {
// Single byte character.
if ((UCHAR)MultiByteString[0x00] < 0x20)
*pdwSpecialChar = 1;
*UnicodeString++ = NlsAnsiToUnicodeData[*(PUCHAR)MultiByteString++];
}
}
if (ARGUMENT_PRESENT(BytesInUnicodeString))
*BytesInUnicodeString = (ULONG)((PCH)UnicodeString - (PCH)UnicodeStringAnchor);
}
return STATUS_SUCCESS;
bad_case:
// this is a low probability case, so we optimized the loop. If have a
// special char, finish trans and notify caller.
*pdwSpecialChar = 1;
return RtlMultiByteToUnicodeN(UnicodeString, MaxBytesInUnicodeString,
NULL, MultiByteString, LoopCount);
}
NTSTATUS
RtlMultiByteToUnicodeN(
OUT PWCH UnicodeString,
IN ULONG MaxBytesInUnicodeString,
OUT PULONG BytesInUnicodeString OPTIONAL,
IN PCH MultiByteString,
IN ULONG BytesInMultiByteString)
/*++
Routine Description:
This functions converts the specified ansi source string into a
Unicode string. The translation is done with respect to the
ANSI Code Page (ACP) installed at boot time. Single byte characters
in the range 0x00 - 0x7f are simply zero extended as a performance
enhancement. In some far eastern code pages 0x5c is defined as the
Yen sign. For system translation we always want to consider 0x5c
to be the backslash character. We get this for free by zero extending.
NOTE: This routine only supports precomposed Unicode characters.
Arguments:
UnicodeString - Returns a unicode string that is equivalent to
the ansi source string.
MaxBytesInUnicodeString - Supplies the maximum number of bytes to be
written to UnicodeString. If this causes UnicodeString to be a
truncated equivalent of MultiByteString, no error condition results.
BytesInUnicodeString - Returns the number of bytes in the returned
unicode string pointed to by UnicodeString.
MultiByteString - Supplies the ansi source string that is to be
converted to unicode. For single-byte character sets, this address
CAN be the same as UnicodeString.
BytesInMultiByteString - The number of bytes in the string pointed to
by MultiByteString.
Return Value:
SUCCESS - The conversion was successful.
--*/
{
ULONG LoopCount;
ULONG TmpCount;
PUSHORT TranslateTable;
ULONG MaxCharsInUnicodeString;
RTL_PAGED_CODE();
if (!NlsMbCodePageTag) {
MaxCharsInUnicodeString = MaxBytesInUnicodeString / sizeof(WCHAR);
LoopCount = (MaxCharsInUnicodeString < BytesInMultiByteString) ?
MaxCharsInUnicodeString : BytesInMultiByteString;
if (ARGUMENT_PRESENT(BytesInUnicodeString))
*BytesInUnicodeString = LoopCount * sizeof(WCHAR);
TranslateTable = NlsAnsiToUnicodeData; // used to help the mips compiler
TmpCount = LoopCount & 0x1F;
UnicodeString += (LoopCount - TmpCount);
MultiByteString += (LoopCount - TmpCount);
quick_copy:
switch( TmpCount ) {
default:
UnicodeString[0x1F] = TranslateTable[(UCHAR)MultiByteString[0x1F]];
case 0x1F:
UnicodeString[0x1E] = TranslateTable[(UCHAR)MultiByteString[0x1E]];
case 0x1E:
UnicodeString[0x1D] = TranslateTable[(UCHAR)MultiByteString[0x1D]];
case 0x1D:
UnicodeString[0x1C] = TranslateTable[(UCHAR)MultiByteString[0x1C]];
case 0x1C:
UnicodeString[0x1B] = TranslateTable[(UCHAR)MultiByteString[0x1B]];
case 0x1B:
UnicodeString[0x1A] = TranslateTable[(UCHAR)MultiByteString[0x1A]];
case 0x1A:
UnicodeString[0x19] = TranslateTable[(UCHAR)MultiByteString[0x19]];
case 0x19:
UnicodeString[0x18] = TranslateTable[(UCHAR)MultiByteString[0x18]];
case 0x18:
UnicodeString[0x17] = TranslateTable[(UCHAR)MultiByteString[0x17]];
case 0x17:
UnicodeString[0x16] = TranslateTable[(UCHAR)MultiByteString[0x16]];
case 0x16:
UnicodeString[0x15] = TranslateTable[(UCHAR)MultiByteString[0x15]];
case 0x15:
UnicodeString[0x14] = TranslateTable[(UCHAR)MultiByteString[0x14]];
case 0x14:
UnicodeString[0x13] = TranslateTable[(UCHAR)MultiByteString[0x13]];
case 0x13:
UnicodeString[0x12] = TranslateTable[(UCHAR)MultiByteString[0x12]];
case 0x12:
UnicodeString[0x11] = TranslateTable[(UCHAR)MultiByteString[0x11]];
case 0x11:
UnicodeString[0x10] = TranslateTable[(UCHAR)MultiByteString[0x10]];
case 0x10:
UnicodeString[0x0F] = TranslateTable[(UCHAR)MultiByteString[0x0F]];
case 0x0F:
UnicodeString[0x0E] = TranslateTable[(UCHAR)MultiByteString[0x0E]];
case 0x0E:
UnicodeString[0x0D] = TranslateTable[(UCHAR)MultiByteString[0x0D]];
case 0x0D:
UnicodeString[0x0C] = TranslateTable[(UCHAR)MultiByteString[0x0C]];
case 0x0C:
UnicodeString[0x0B] = TranslateTable[(UCHAR)MultiByteString[0x0B]];
case 0x0B:
UnicodeString[0x0A] = TranslateTable[(UCHAR)MultiByteString[0x0A]];
case 0x0A:
UnicodeString[0x09] = TranslateTable[(UCHAR)MultiByteString[0x09]];
case 0x09:
UnicodeString[0x08] = TranslateTable[(UCHAR)MultiByteString[0x08]];
case 0x08:
UnicodeString[0x07] = TranslateTable[(UCHAR)MultiByteString[0x07]];
case 0x07:
UnicodeString[0x06] = TranslateTable[(UCHAR)MultiByteString[0x06]];
case 0x06:
UnicodeString[0x05] = TranslateTable[(UCHAR)MultiByteString[0x05]];
case 0x05:
UnicodeString[0x04] = TranslateTable[(UCHAR)MultiByteString[0x04]];
case 0x04:
UnicodeString[0x03] = TranslateTable[(UCHAR)MultiByteString[0x03]];
case 0x03:
UnicodeString[0x02] = TranslateTable[(UCHAR)MultiByteString[0x02]];
case 0x02:
UnicodeString[0x01] = TranslateTable[(UCHAR)MultiByteString[0x01]];
case 0x01:
UnicodeString[0x00] = TranslateTable[(UCHAR)MultiByteString[0x00]];
case 0x00:
;
}
if ( LoopCount >= 0x20 ) {
TmpCount = 0x20;
LoopCount -= 0x20;
UnicodeString -= 0x20;
MultiByteString -= 0x20;
goto quick_copy;
}
/* end of copy... */
} else {
register USHORT Entry;
PWCH UnicodeStringAnchor = UnicodeString;
TranslateTable = (PUSHORT)NlsMbAnsiCodePageTables;
// yea, this line is duplicated, but the compiler can handle opt
// better buy moving it around
MaxCharsInUnicodeString = MaxBytesInUnicodeString / sizeof(WCHAR);
// The ACP is a multibyte code page. Check each character
// to see if it is a lead byte before doing the translation.
while (MaxCharsInUnicodeString && BytesInMultiByteString) {
MaxCharsInUnicodeString--;
BytesInMultiByteString--;
if (NlsLeadByteInfo[*(PUCHAR)MultiByteString]) {
// Lead byte - Make sure there is a trail byte. If not,
// pass back a space rather than an error. Some 3.x
// applications pass incorrect strings and don't expect
// to get an error.
if (BytesInMultiByteString == 0)
{
*UnicodeString++ = UnicodeNull;
break;
}
// Get the unicode character.
Entry = NlsLeadByteInfo[*(PUCHAR)MultiByteString++];
*UnicodeString = (WCHAR)TranslateTable[ Entry + *(PUCHAR)MultiByteString++ ];
UnicodeString++;
// Decrement count of bytes in multibyte string to account
// for the double byte character.
BytesInMultiByteString--;
} else {
// Single byte character.
*UnicodeString++ = NlsAnsiToUnicodeData[*(PUCHAR)MultiByteString++];
}
}
if (ARGUMENT_PRESENT(BytesInUnicodeString))
*BytesInUnicodeString = (ULONG)((PCH)UnicodeString - (PCH)UnicodeStringAnchor);
}
return STATUS_SUCCESS;
}
NTSTATUS
RtlOemToUnicodeN(
OUT PWCH UnicodeString,
IN ULONG MaxBytesInUnicodeString,
OUT PULONG BytesInUnicodeString OPTIONAL,
IN PCH OemString,
IN ULONG BytesInOemString)
/*++
Routine Description:
This functions converts the specified oem source string into a
Unicode string. The translation is done with respect to the
OEM Code Page (OCP) installed at boot time. Single byte characters
in the range 0x00 - 0x7f are simply zero extended as a performance
enhancement. In some far eastern code pages 0x5c is defined as the
Yen sign. For system translation we always want to consider 0x5c
to be the backslash character. We get this for free by zero extending.
NOTE: This routine only supports precomposed Unicode characters.
Arguments:
UnicodeString - Returns a unicode string that is equivalent to
the oem source string.
MaxBytesInUnicodeString - Supplies the maximum number of bytes to be
written to UnicodeString. If this causes UnicodeString to be a
truncated equivalent of OemString, no error condition results.
BytesInUnicodeString - Returns the number of bytes in the returned
unicode string pointed to by UnicodeString.
OemString - Supplies the oem source string that is to be
converted to unicode.
BytesInOemString - The number of bytes in the string pointed to
by OemString.
Return Value:
SUCCESS - The conversion was successful
STATUS_ILLEGAL_CHARACTER - The final Oem character was illegal
STATUS_BUFFER_OVERFLOW - MaxBytesInUnicodeString was not enough to hold
the whole Oem string. It was converted correct to the point though.
--*/
{
ULONG LoopCount;
PUSHORT TranslateTable;
ULONG MaxCharsInUnicodeString;
RTL_PAGED_CODE();
if (!NlsMbOemCodePageTag) {
// The OCP is a single byte code page.
MaxCharsInUnicodeString = MaxBytesInUnicodeString / sizeof(WCHAR);
LoopCount = (MaxCharsInUnicodeString < BytesInOemString) ?
MaxCharsInUnicodeString : BytesInOemString;
if (ARGUMENT_PRESENT(BytesInUnicodeString))
*BytesInUnicodeString = LoopCount * sizeof(WCHAR);
TranslateTable = NlsOemToUnicodeData; // used to help the mips compiler
quick_copy:
switch( LoopCount ) {
default:
UnicodeString[0x0F] = TranslateTable[(UCHAR)OemString[0x0F]];
case 0x0F:
UnicodeString[0x0E] = TranslateTable[(UCHAR)OemString[0x0E]];
case 0x0E:
UnicodeString[0x0D] = TranslateTable[(UCHAR)OemString[0x0D]];
case 0x0D:
UnicodeString[0x0C] = TranslateTable[(UCHAR)OemString[0x0C]];
case 0x0C:
UnicodeString[0x0B] = TranslateTable[(UCHAR)OemString[0x0B]];
case 0x0B:
UnicodeString[0x0A] = TranslateTable[(UCHAR)OemString[0x0A]];
case 0x0A:
UnicodeString[0x09] = TranslateTable[(UCHAR)OemString[0x09]];
case 0x09:
UnicodeString[0x08] = TranslateTable[(UCHAR)OemString[0x08]];
case 0x08:
UnicodeString[0x07] = TranslateTable[(UCHAR)OemString[0x07]];
case 0x07:
UnicodeString[0x06] = TranslateTable[(UCHAR)OemString[0x06]];
case 0x06:
UnicodeString[0x05] = TranslateTable[(UCHAR)OemString[0x05]];
case 0x05:
UnicodeString[0x04] = TranslateTable[(UCHAR)OemString[0x04]];
case 0x04:
UnicodeString[0x03] = TranslateTable[(UCHAR)OemString[0x03]];
case 0x03:
UnicodeString[0x02] = TranslateTable[(UCHAR)OemString[0x02]];
case 0x02:
UnicodeString[0x01] = TranslateTable[(UCHAR)OemString[0x01]];
case 0x01:
UnicodeString[0x00] = TranslateTable[(UCHAR)OemString[0x00]];
case 0x00:
;
}
if ( LoopCount > 0x10 ) {
LoopCount -= 0x10;
OemString += 0x10;
UnicodeString += 0x10;
goto quick_copy;
}
/* end of copy... */
} else {
register USHORT Entry;
PWCH UnicodeStringAnchor = UnicodeString;
// The OCP is a multibyte code page. Check each character
// to see if it is a lead byte before doing the translation.
MaxCharsInUnicodeString = MaxBytesInUnicodeString / sizeof(WCHAR);
TranslateTable = (PUSHORT)NlsMbOemCodePageTables;
while (MaxCharsInUnicodeString && BytesInOemString) {
MaxCharsInUnicodeString--;
BytesInOemString--;
if (NlsOemLeadByteInfo[*(PUCHAR)OemString]) {
// Lead byte - Make sure there is a trail byte. If not,
// pass back a space rather than an error. Some 3.x
// applications pass incorrect strings and don't expect
// to get an error.
if (BytesInOemString == 0)
{
*UnicodeString++ = UnicodeNull;
break;
}
// Get the unicode character.
Entry = NlsOemLeadByteInfo[*(PUCHAR)OemString++];
*UnicodeString = TranslateTable[ Entry + *(PUCHAR)OemString++ ];
UnicodeString++;
// Decrement count of bytes in oem string to account
// for the double byte character.
BytesInOemString--;
} else {
// Single byte character.
*UnicodeString++ = NlsOemToUnicodeData[*(PUCHAR)OemString++];
}
}
if (ARGUMENT_PRESENT(BytesInUnicodeString))
*BytesInUnicodeString = (ULONG)((PCH)UnicodeString - (PCH)UnicodeStringAnchor);
}
// Check if we were able to use all of the source Oem String
return (BytesInOemString <= MaxCharsInUnicodeString) ?
STATUS_SUCCESS :
STATUS_BUFFER_OVERFLOW;
}
NTSTATUS
RtlMultiByteToUnicodeSize(
OUT PULONG BytesInUnicodeString,
IN PCH MultiByteString,
IN ULONG BytesInMultiByteString)
/*++
Routine Description:
This functions determines how many bytes would be needed to represent
the specified ANSI source string in Unicode string (not counting the
null terminator)
The translation is done with respect to the ANSI Code Page (ACP) installed
at boot time. Single byte characters in the range 0x00 - 0x7f are simply
zero extended as a performance enhancement. In some far eastern code pages
0x5c is defined as the Yen sign. For system translation we always want to
consider 0x5c to be the backslash character. We get this for free by zero
extending.
NOTE: This routine only supports precomposed Unicode characters.
Arguments:
BytesInUnicodeString - Returns the number of bytes a Unicode translation
of the ANSI string pointed to by MultiByteString would contain.
MultiByteString - Supplies the ansi source string whose Unicode length
is to be calculated.
BytesInMultiByteString - The number of bytes in the string pointed to
by MultiByteString.
Return Value:
SUCCESS - The conversion was successful
--*/
{
ULONG cbUnicode = 0;
RTL_PAGED_CODE();
if (NlsMbCodePageTag) {
// The ACP is a multibyte code page. Check each character
// to see if it is a lead byte before doing the translation.
while (BytesInMultiByteString--) {
if (NlsLeadByteInfo[*(PUCHAR)MultiByteString++]) {
// Lead byte - translate the trail byte using the table
// that corresponds to this lead byte. NOTE: make sure
// we have a trail byte to convert.
if (BytesInMultiByteString == 0) {
// RtlMultibyteToUnicodeN() uses the unicode
// default character if the last multibyte
// character is a lead byte.
cbUnicode += sizeof(WCHAR);
break;
} else {
BytesInMultiByteString--;
MultiByteString++;
}
}
cbUnicode += sizeof(WCHAR);
}
*BytesInUnicodeString = cbUnicode;
} else {
// The ACP is a single byte code page.
*BytesInUnicodeString = BytesInMultiByteString * sizeof(WCHAR);
}
return STATUS_SUCCESS;
}
NTSTATUS
RtlUnicodeToMultiByteSize(
OUT PULONG BytesInMultiByteString,
IN PWCH UnicodeString,
IN ULONG BytesInUnicodeString)
/*++
Routine Description:
This functions determines how many bytes would be needed to represent
the specified Unicode source string as an ANSI string (not counting the
null terminator)
Arguments:
BytesInMultiByteString - Returns the number of bytes an ANSI translation
of the Unicode string pointed to by UnicodeString would contain.
UnicodeString - Supplies the unicode source string whose ANSI length
is to be calculated.
BytesInUnicodeString - The number of bytes in the the string pointed to by
UnicodeString.
Return Value:
SUCCESS - The conversion was successful
!SUCCESS - The conversion failed. A unicode character was encountered
that has no translation for the current ANSI Code Page (ACP).
--*/
{
ULONG cbMultiByte = 0;
ULONG CharsInUnicodeString;
RTL_PAGED_CODE();
/*
* convert from bytes to chars for easier loop handling.
*/
CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
if (NlsMbCodePageTag) {
USHORT MbChar;
while (CharsInUnicodeString--) {
MbChar = NlsUnicodeToMbAnsiData[ *UnicodeString++ ];
if (HIBYTE(MbChar) == 0) {
cbMultiByte++ ;
} else {
cbMultiByte += 2;
}
}
*BytesInMultiByteString = cbMultiByte;
}
else {
*BytesInMultiByteString = CharsInUnicodeString;
}
return STATUS_SUCCESS;
}
NTSTATUS
RtlUnicodeToMultiByteN(
OUT PCH MultiByteString,
IN ULONG MaxBytesInMultiByteString,
OUT PULONG BytesInMultiByteString OPTIONAL,
IN PWCH UnicodeString,
IN ULONG BytesInUnicodeString)
/*++
Routine Description:
This functions converts the specified unicode source string into an
ansi string. The translation is done with respect to the
ANSI Code Page (ACP) loaded at boot time.
Arguments:
MultiByteString - Returns an ansi string that is equivalent to the
unicode source string. If the translation can not be done,
an error is returned.
MaxBytesInMultiByteString - Supplies the maximum number of bytes to be
written to MultiByteString. If this causes MultiByteString to be a
truncated equivalent of UnicodeString, no error condition results.
BytesInMultiByteString - Returns the number of bytes in the returned
ansi string pointed to by MultiByteString.
UnicodeString - Supplies the unicode source string that is to be
converted to ansi.
BytesInUnicodeString - The number of bytes in the the string pointed to by
UnicodeString.
Return Value:
SUCCESS - The conversion was successful
--*/
{
ULONG TmpCount;
ULONG LoopCount;
PCH TranslateTable;
ULONG CharsInUnicodeString;
RTL_PAGED_CODE();
// Convert Unicode byte count to character count. Byte count of
// multibyte string is equivalent to character count.
if (!NlsMbCodePageTag) {
CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
LoopCount = (CharsInUnicodeString < MaxBytesInMultiByteString) ?
CharsInUnicodeString : MaxBytesInMultiByteString;
if (ARGUMENT_PRESENT(BytesInMultiByteString))
*BytesInMultiByteString = LoopCount;
TranslateTable = NlsUnicodeToAnsiData; // used to help the mips compiler
TmpCount = LoopCount & 0x0F;
UnicodeString += TmpCount;
MultiByteString += TmpCount;
do
{
switch( TmpCount ) {
default:
UnicodeString += 0x10;
MultiByteString += 0x10;
MultiByteString[-0x10] = TranslateTable[UnicodeString[-0x10]];
case 0x0F:
MultiByteString[-0x0F] = TranslateTable[UnicodeString[-0x0F]];
case 0x0E:
MultiByteString[-0x0E] = TranslateTable[UnicodeString[-0x0E]];
case 0x0D:
MultiByteString[-0x0D] = TranslateTable[UnicodeString[-0x0D]];
case 0x0C:
MultiByteString[-0x0C] = TranslateTable[UnicodeString[-0x0C]];
case 0x0B:
MultiByteString[-0x0B] = TranslateTable[UnicodeString[-0x0B]];
case 0x0A:
MultiByteString[-0x0A] = TranslateTable[UnicodeString[-0x0A]];
case 0x09:
MultiByteString[-0x09] = TranslateTable[UnicodeString[-0x09]];
case 0x08:
MultiByteString[-0x08] = TranslateTable[UnicodeString[-0x08]];
case 0x07:
MultiByteString[-0x07] = TranslateTable[UnicodeString[-0x07]];
case 0x06:
MultiByteString[-0x06] = TranslateTable[UnicodeString[-0x06]];
case 0x05:
MultiByteString[-0x05] = TranslateTable[UnicodeString[-0x05]];
case 0x04:
MultiByteString[-0x04] = TranslateTable[UnicodeString[-0x04]];
case 0x03:
MultiByteString[-0x03] = TranslateTable[UnicodeString[-0x03]];
case 0x02:
MultiByteString[-0x02] = TranslateTable[UnicodeString[-0x02]];
case 0x01:
MultiByteString[-0x01] = TranslateTable[UnicodeString[-0x01]];
case 0x00:
;
}
LoopCount -= TmpCount;
TmpCount = 0x10;
} while ( LoopCount > 0 );
/* end of copy... */
} else {
USHORT MbChar;
PCH MultiByteStringAnchor = MultiByteString;
CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
while ( CharsInUnicodeString && MaxBytesInMultiByteString ) {
MbChar = NlsUnicodeToMbAnsiData[ *UnicodeString++ ];
if (HIBYTE(MbChar) != 0) {
// Need at least 2 bytes to copy a double byte char.
// Don't want to truncate in the middle of a DBCS char.
if (MaxBytesInMultiByteString-- < 2) {
break;
}
*MultiByteString++ = HIBYTE(MbChar); // lead byte
}
*MultiByteString++ = LOBYTE(MbChar);
MaxBytesInMultiByteString--;
CharsInUnicodeString--;
}
if (ARGUMENT_PRESENT(BytesInMultiByteString))
*BytesInMultiByteString = (ULONG)(MultiByteString - MultiByteStringAnchor);
}
return STATUS_SUCCESS;
}
NTSTATUS
RtlUpcaseUnicodeToMultiByteN(
OUT PCH MultiByteString,
IN ULONG MaxBytesInMultiByteString,
OUT PULONG BytesInMultiByteString OPTIONAL,
IN PWCH UnicodeString,
IN ULONG BytesInUnicodeString)
/*++
Routine Description:
This functions upper cases the specified unicode source string and
converts it into an ansi string. The translation is done with respect
to the ANSI Code Page (ACP) loaded at boot time.
Arguments:
MultiByteString - Returns an ansi string that is equivalent to the
upper case of the unicode source string. If the translation can
not be done, an error is returned.
MaxBytesInMultiByteString - Supplies the maximum number of bytes to be
written to MultiByteString. If this causes MultiByteString to be a
truncated equivalent of UnicodeString, no error condition results.
BytesInMultiByteString - Returns the number of bytes in the returned
ansi string pointed to by MultiByteString.
UnicodeString - Supplies the unicode source string that is to be
converted to ansi.
BytesInUnicodeString - The number of bytes in the the string pointed to by
UnicodeString.
Return Value:
SUCCESS - The conversion was successful
--*/
{
ULONG TmpCount;
ULONG LoopCount;
PCH TranslateTable;
ULONG CharsInUnicodeString;
UCHAR SbChar;
WCHAR UnicodeChar;
RTL_PAGED_CODE();
// Convert Unicode byte count to character count. Byte count of
// multibyte string is equivalent to character count.
if (!NlsMbCodePageTag) {
CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
LoopCount = (CharsInUnicodeString < MaxBytesInMultiByteString) ?
CharsInUnicodeString : MaxBytesInMultiByteString;
if (ARGUMENT_PRESENT(BytesInMultiByteString))
*BytesInMultiByteString = LoopCount;
TranslateTable = NlsUnicodeToAnsiData; // used to help the mips compiler
TmpCount = LoopCount & 0x0F;
UnicodeString += TmpCount;
MultiByteString += TmpCount;
do
{
// Convert to ANSI and back to Unicode before upper casing
// to ensure the visual best fits are converted and
// upper cased properly.
switch( TmpCount ) {
default:
UnicodeString += 0x10;
MultiByteString += 0x10;
SbChar = TranslateTable[UnicodeString[-0x10]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x10] = TranslateTable[UnicodeChar];
case 0x0F:
SbChar = TranslateTable[UnicodeString[-0x0F]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x0F] = TranslateTable[UnicodeChar];
case 0x0E:
SbChar = TranslateTable[UnicodeString[-0x0E]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x0E] = TranslateTable[UnicodeChar];
case 0x0D:
SbChar = TranslateTable[UnicodeString[-0x0D]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x0D] = TranslateTable[UnicodeChar];
case 0x0C:
SbChar = TranslateTable[UnicodeString[-0x0C]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x0C] = TranslateTable[UnicodeChar];
case 0x0B:
SbChar = TranslateTable[UnicodeString[-0x0B]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x0B] = TranslateTable[UnicodeChar];
case 0x0A:
SbChar = TranslateTable[UnicodeString[-0x0A]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x0A] = TranslateTable[UnicodeChar];
case 0x09:
SbChar = TranslateTable[UnicodeString[-0x09]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x09] = TranslateTable[UnicodeChar];
case 0x08:
SbChar = TranslateTable[UnicodeString[-0x08]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x08] = TranslateTable[UnicodeChar];
case 0x07:
SbChar = TranslateTable[UnicodeString[-0x07]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x07] = TranslateTable[UnicodeChar];
case 0x06:
SbChar = TranslateTable[UnicodeString[-0x06]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x06] = TranslateTable[UnicodeChar];
case 0x05:
SbChar = TranslateTable[UnicodeString[-0x05]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x05] = TranslateTable[UnicodeChar];
case 0x04:
SbChar = TranslateTable[UnicodeString[-0x04]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x04] = TranslateTable[UnicodeChar];
case 0x03:
SbChar = TranslateTable[UnicodeString[-0x03]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x03] = TranslateTable[UnicodeChar];
case 0x02:
SbChar = TranslateTable[UnicodeString[-0x02]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x02] = TranslateTable[UnicodeChar];
case 0x01:
SbChar = TranslateTable[UnicodeString[-0x01]];
UnicodeChar = NlsAnsiToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MultiByteString[-0x01] = TranslateTable[UnicodeChar];
case 0x00:
;
}
LoopCount -= TmpCount;
TmpCount = 0x10;
} while ( LoopCount > 0 );
/* end of copy... */
} else {
USHORT MbChar;
register USHORT Entry;
PCH MultiByteStringAnchor = MultiByteString;
CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
while ( CharsInUnicodeString && MaxBytesInMultiByteString ) {
// Convert to ANSI and back to Unicode before upper casing
// to ensure the visual best fits are converted and
// upper cased properly.
MbChar = NlsUnicodeToMbAnsiData[ *UnicodeString++ ];
if ( NlsLeadByteInfo[HIBYTE(MbChar)] ) {
// Lead byte - translate the trail byte using the table
// that corresponds to this lead byte.
Entry = NlsLeadByteInfo[HIBYTE(MbChar)];
UnicodeChar = (WCHAR)NlsMbAnsiCodePageTables[ Entry + LOBYTE(MbChar) ];
} else {
// Single byte character.
UnicodeChar = NlsAnsiToUnicodeData[LOBYTE(MbChar)];
}
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MbChar = NlsUnicodeToMbAnsiData[UnicodeChar];
if (HIBYTE(MbChar) != 0) {
// Need at least 2 bytes to copy a double byte char.
// Don't want to truncate in the middle of a DBCS char.
if (MaxBytesInMultiByteString-- < 2) {
break;
}
*MultiByteString++ = HIBYTE(MbChar); // lead byte
}
*MultiByteString++ = LOBYTE(MbChar);
MaxBytesInMultiByteString--;
CharsInUnicodeString--;
}
if (ARGUMENT_PRESENT(BytesInMultiByteString))
*BytesInMultiByteString = (ULONG)(MultiByteString - MultiByteStringAnchor);
}
return STATUS_SUCCESS;
}
NTSTATUS
RtlUnicodeToOemN(
OUT PCH OemString,
IN ULONG MaxBytesInOemString,
OUT PULONG BytesInOemString OPTIONAL,
IN PWCH UnicodeString,
IN ULONG BytesInUnicodeString)
/*++
Routine Description:
This functions converts the specified unicode source string into an
oem string. The translation is done with respect to the OEM Code
Page (OCP) loaded at boot time.
Arguments:
OemString - Returns an oem string that is equivalent to the
unicode source string. If the translation can not be done,
an error is returned.
MaxBytesInOemString - Supplies the maximum number of bytes to be
written to OemString. If this causes OemString to be a
truncated equivalent of UnicodeString, no error condition results.
BytesInOemString - Returns the number of bytes in the returned
oem string pointed to by OemString.
UnicodeString - Supplies the unicode source string that is to be
converted to oem.
BytesInUnicodeString - The number of bytes in the the string pointed to by
UnicodeString.
Return Value:
SUCCESS - The conversion was successful
STATUS_BUFFER_OVERFLOW - MaxBytesInUnicodeString was not enough to hold
the whole Oem string. It was converted correct to the point though.
--*/
{
ULONG TmpCount;
ULONG LoopCount;
PCH TranslateTable;
ULONG CharsInUnicodeString;
RTL_PAGED_CODE();
// Convert Unicode byte count to character count. Byte count of
// multibyte string is equivalent to character count.
if (!NlsMbOemCodePageTag) {
CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
LoopCount = (CharsInUnicodeString < MaxBytesInOemString) ?
CharsInUnicodeString : MaxBytesInOemString;
if (ARGUMENT_PRESENT(BytesInOemString))
*BytesInOemString = LoopCount;
TranslateTable = NlsUnicodeToOemData; // used to help the mips compiler
TmpCount = LoopCount & 0x0F;
UnicodeString += TmpCount;
OemString += TmpCount;
do
{
switch( TmpCount ) {
default:
UnicodeString += 0x10;
OemString += 0x10;
OemString[-0x10] = TranslateTable[UnicodeString[-0x10]];
case 0x0F:
OemString[-0x0F] = TranslateTable[UnicodeString[-0x0F]];
case 0x0E:
OemString[-0x0E] = TranslateTable[UnicodeString[-0x0E]];
case 0x0D:
OemString[-0x0D] = TranslateTable[UnicodeString[-0x0D]];
case 0x0C:
OemString[-0x0C] = TranslateTable[UnicodeString[-0x0C]];
case 0x0B:
OemString[-0x0B] = TranslateTable[UnicodeString[-0x0B]];
case 0x0A:
OemString[-0x0A] = TranslateTable[UnicodeString[-0x0A]];
case 0x09:
OemString[-0x09] = TranslateTable[UnicodeString[-0x09]];
case 0x08:
OemString[-0x08] = TranslateTable[UnicodeString[-0x08]];
case 0x07:
OemString[-0x07] = TranslateTable[UnicodeString[-0x07]];
case 0x06:
OemString[-0x06] = TranslateTable[UnicodeString[-0x06]];
case 0x05:
OemString[-0x05] = TranslateTable[UnicodeString[-0x05]];
case 0x04:
OemString[-0x04] = TranslateTable[UnicodeString[-0x04]];
case 0x03:
OemString[-0x03] = TranslateTable[UnicodeString[-0x03]];
case 0x02:
OemString[-0x02] = TranslateTable[UnicodeString[-0x02]];
case 0x01:
OemString[-0x01] = TranslateTable[UnicodeString[-0x01]];
case 0x00:
;
}
LoopCount -= TmpCount;
TmpCount = 0x10;
} while ( LoopCount > 0 );
/* end of copy... */
} else {
register USHORT MbChar;
PCH OemStringAnchor = OemString;
CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
while ( CharsInUnicodeString && MaxBytesInOemString ) {
MbChar = NlsUnicodeToMbOemData[ *UnicodeString++ ];
if (HIBYTE(MbChar) != 0) {
// Need at least 2 bytes to copy a double byte char.
// Don't want to truncate in the middle of a DBCS char.
if (MaxBytesInOemString-- < 2) {
break;
}
*OemString++ = HIBYTE(MbChar); // lead byte
}
*OemString++ = LOBYTE(MbChar);
MaxBytesInOemString--;
CharsInUnicodeString--;
}
if (ARGUMENT_PRESENT(BytesInOemString))
*BytesInOemString = (ULONG)(OemString - OemStringAnchor);
}
// Check if we were able to use all of the source Unicode String
return ( CharsInUnicodeString <= MaxBytesInOemString ) ?
STATUS_SUCCESS :
STATUS_BUFFER_OVERFLOW;
}
NTSTATUS
RtlUpcaseUnicodeToOemN(
OUT PCH OemString,
IN ULONG MaxBytesInOemString,
OUT PULONG BytesInOemString OPTIONAL,
IN PWCH UnicodeString,
IN ULONG BytesInUnicodeString)
/*++
Routine Description:
This functions upper cases the specified unicode source string and
converts it into an oem string. The translation is done with respect
to the OEM Code Page (OCP) loaded at boot time.
Arguments:
OemString - Returns an oem string that is equivalent to the upper
case of the unicode source string. If the translation can not
be done, an error is returned.
MaxBytesInOemString - Supplies the maximum number of bytes to be
written to OemString. If this causes OemString to be a
truncated equivalent of UnicodeString, no error condition results.
BytesInOemString - Returns the number of bytes in the returned
oem string pointed to by OemString.
UnicodeString - Supplies the unicode source string that is to be
converted to oem.
BytesInUnicodeString - The number of bytes in the the string pointed
to by UnicodeString.
Return Value:
SUCCESS - The conversion was successful
STATUS_BUFFER_OVERFLOW - MaxBytesInUnicodeString was not enough to
hold the whole Oem string. It was converted correctly to that
point, though.
--*/
{
ULONG TmpCount;
ULONG LoopCount;
PCH TranslateTable;
ULONG CharsInUnicodeString;
UCHAR SbChar;
WCHAR UnicodeChar;
RTL_PAGED_CODE();
// Convert Unicode byte count to character count. Byte count of
// multibyte string is equivalent to character count.
if (!NlsMbOemCodePageTag) {
CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
LoopCount = (CharsInUnicodeString < MaxBytesInOemString) ?
CharsInUnicodeString : MaxBytesInOemString;
if (ARGUMENT_PRESENT(BytesInOemString))
*BytesInOemString = LoopCount;
TranslateTable = NlsUnicodeToOemData; // used to help the mips compiler
TmpCount = LoopCount & 0x0F;
UnicodeString += TmpCount;
OemString += TmpCount;
do
{
// Convert to OEM and back to Unicode before upper casing
// to ensure the visual best fits are converted and
// upper cased properly.
switch( TmpCount ) {
default:
UnicodeString += 0x10;
OemString += 0x10;
SbChar = TranslateTable[UnicodeString[-0x10]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x10] = TranslateTable[UnicodeChar];
case 0x0F:
SbChar = TranslateTable[UnicodeString[-0x0F]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x0F] = TranslateTable[UnicodeChar];
case 0x0E:
SbChar = TranslateTable[UnicodeString[-0x0E]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x0E] = TranslateTable[UnicodeChar];
case 0x0D:
SbChar = TranslateTable[UnicodeString[-0x0D]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x0D] = TranslateTable[UnicodeChar];
case 0x0C:
SbChar = TranslateTable[UnicodeString[-0x0C]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x0C] = TranslateTable[UnicodeChar];
case 0x0B:
SbChar = TranslateTable[UnicodeString[-0x0B]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x0B] = TranslateTable[UnicodeChar];
case 0x0A:
SbChar = TranslateTable[UnicodeString[-0x0A]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x0A] = TranslateTable[UnicodeChar];
case 0x09:
SbChar = TranslateTable[UnicodeString[-0x09]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x09] = TranslateTable[UnicodeChar];
case 0x08:
SbChar = TranslateTable[UnicodeString[-0x08]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x08] = TranslateTable[UnicodeChar];
case 0x07:
SbChar = TranslateTable[UnicodeString[-0x07]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x07] = TranslateTable[UnicodeChar];
case 0x06:
SbChar = TranslateTable[UnicodeString[-0x06]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x06] = TranslateTable[UnicodeChar];
case 0x05:
SbChar = TranslateTable[UnicodeString[-0x05]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x05] = TranslateTable[UnicodeChar];
case 0x04:
SbChar = TranslateTable[UnicodeString[-0x04]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x04] = TranslateTable[UnicodeChar];
case 0x03:
SbChar = TranslateTable[UnicodeString[-0x03]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x03] = TranslateTable[UnicodeChar];
case 0x02:
SbChar = TranslateTable[UnicodeString[-0x02]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x02] = TranslateTable[UnicodeChar];
case 0x01:
SbChar = TranslateTable[UnicodeString[-0x01]];
UnicodeChar = NlsOemToUnicodeData[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
OemString[-0x01] = TranslateTable[UnicodeChar];
case 0x00:
;
}
LoopCount -= TmpCount;
TmpCount = 0x10;
} while ( LoopCount > 0 );
/* end of copy... */
} else {
USHORT MbChar;
register USHORT Entry;
PCH OemStringAnchor = OemString;
CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
while ( CharsInUnicodeString && MaxBytesInOemString ) {
// Convert to OEM and back to Unicode before upper casing
// to ensure the visual best fits are converted and
// upper cased properly.
MbChar = NlsUnicodeToMbOemData[ *UnicodeString++ ];
if (NlsOemLeadByteInfo[HIBYTE(MbChar)]) {
// Lead byte - translate the trail byte using the table
// that corresponds to this lead byte.
Entry = NlsOemLeadByteInfo[HIBYTE(MbChar)];
UnicodeChar = (WCHAR)NlsMbOemCodePageTables[ Entry + LOBYTE(MbChar) ];
} else {
// Single byte character.
UnicodeChar = NlsOemToUnicodeData[LOBYTE(MbChar)];
}
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MbChar = NlsUnicodeToMbOemData[UnicodeChar];
if (HIBYTE(MbChar) != 0) {
// Need at least 2 bytes to copy a double byte char.
// Don't want to truncate in the middle of a DBCS char.
if (MaxBytesInOemString-- < 2) {
break;
}
*OemString++ = HIBYTE(MbChar); // lead byte
}
*OemString++ = LOBYTE(MbChar);
MaxBytesInOemString--;
CharsInUnicodeString--;
}
if (ARGUMENT_PRESENT(BytesInOemString))
*BytesInOemString = (ULONG)(OemString - OemStringAnchor);
}
// Check if we were able to use all of the source Unicode String
return ( CharsInUnicodeString <= MaxBytesInOemString ) ?
STATUS_SUCCESS :
STATUS_BUFFER_OVERFLOW;
}
BOOLEAN
RtlpDidUnicodeToOemWork(
IN POEM_STRING OemString,
IN PUNICODE_STRING UnicodeString
)
/*++
Routine Description:
This function looks for the default character in the Oem string, making
sure it was not a correct translation from the Unicode source string.
This allows us to test whether or not a translation was really successful.
Arguments:
OemString - The result of conversion from the unicode string.
UnicodeString - The source of the Oem string.
Return Value:
TRUE if the Unicode to Oem translation caused no default characters to be
inserted. FALSE otherwise.
--*/
{
ULONG OemOffset;
BOOLEAN Result = TRUE;
RTL_PAGED_CODE();
if (!NlsMbOemCodePageTag) {
for (OemOffset = 0;
OemOffset < OemString->Length;
OemOffset += 1) {
if ((OemString->Buffer[OemOffset] == (UCHAR)OemDefaultChar) &&
(UnicodeString->Buffer[OemOffset] != OemTransUniDefaultChar)) {
Result = FALSE;
break;
}
}
} else {
ULONG UnicodeOffset;
for (OemOffset = 0, UnicodeOffset = 0;
OemOffset < OemString->Length;
OemOffset += 1, UnicodeOffset += 1) {
// If we landed on a DBCS character handle it accordingly
if (NlsOemLeadByteInfo[(UCHAR)OemString->Buffer[OemOffset]]) {
USHORT DbcsChar;
ASSERT( OemOffset + 1 < OemString->Length );
DbcsChar = (OemString->Buffer[OemOffset] << 8) + (UCHAR)OemString->Buffer[OemOffset+1];
OemOffset++;
if ((DbcsChar == OemDefaultChar) &&
(UnicodeString->Buffer[UnicodeOffset] != OemTransUniDefaultChar)) {
Result = FALSE;
break;
}
continue;
}
if ((OemString->Buffer[OemOffset] == (UCHAR)OemDefaultChar) &&
(UnicodeString->Buffer[UnicodeOffset] != OemTransUniDefaultChar)) {
Result = FALSE;
break;
}
}
}
return Result;
}
NTSTATUS
RtlCustomCPToUnicodeN(
IN PCPTABLEINFO CustomCP,
OUT PWCH UnicodeString,
IN ULONG MaxBytesInUnicodeString,
OUT PULONG BytesInUnicodeString OPTIONAL,
IN PCH CustomCPString,
IN ULONG BytesInCustomCPString)
/*++
Routine Description:
This functions converts the specified CustomCP source string into a
Unicode string. The translation is done with respect to the
CustomCP Code Page specified. Single byte characters
in the range 0x00 - 0x7f are simply zero extended as a performance
enhancement. In some far eastern code pages 0x5c is defined as the
Yen sign. For system translation we always want to consider 0x5c
to be the backslash character. We get this for free by zero extending.
NOTE: This routine only supports precomposed Unicode characters.
Arguments:
CustomCP - Supplies the address of the code page that translations
are done relative to
UnicodeString - Returns a unicode string that is equivalent to
the CustomCP source string.
MaxBytesInUnicodeString - Supplies the maximum number of bytes to be
written to UnicodeString. If this causes UnicodeString to be a
truncated equivalent of CustomCPString, no error condition results.
BytesInUnicodeString - Returns the number of bytes in the returned
unicode string pointed to by UnicodeString.
CustomCPString - Supplies the CustomCP source string that is to be
converted to unicode.
BytesInCustomCPString - The number of bytes in the string pointed to
by CustomCPString.
Return Value:
SUCCESS - The conversion was successful
STATUS_ILLEGAL_CHARACTER - The final CustomCP character was illegal
STATUS_BUFFER_OVERFLOW - MaxBytesInUnicodeString was not enough to hold
the whole CustomCP string. It was converted correct to the point though.
--*/
{
ULONG LoopCount;
PUSHORT TranslateTable;
ULONG MaxCharsInUnicodeString;
RTL_PAGED_CODE();
if (!(CustomCP->DBCSCodePage)) {
// The Custom CP is a single byte code page.
MaxCharsInUnicodeString = MaxBytesInUnicodeString / sizeof(WCHAR);
LoopCount = (MaxCharsInUnicodeString < BytesInCustomCPString) ?
MaxCharsInUnicodeString : BytesInCustomCPString;
if (ARGUMENT_PRESENT(BytesInUnicodeString))
*BytesInUnicodeString = LoopCount * sizeof(WCHAR);
TranslateTable = CustomCP->MultiByteTable;
quick_copy:
switch( LoopCount ) {
default:
UnicodeString[0x0F] = TranslateTable[(UCHAR)CustomCPString[0x0F]];
case 0x0F:
UnicodeString[0x0E] = TranslateTable[(UCHAR)CustomCPString[0x0E]];
case 0x0E:
UnicodeString[0x0D] = TranslateTable[(UCHAR)CustomCPString[0x0D]];
case 0x0D:
UnicodeString[0x0C] = TranslateTable[(UCHAR)CustomCPString[0x0C]];
case 0x0C:
UnicodeString[0x0B] = TranslateTable[(UCHAR)CustomCPString[0x0B]];
case 0x0B:
UnicodeString[0x0A] = TranslateTable[(UCHAR)CustomCPString[0x0A]];
case 0x0A:
UnicodeString[0x09] = TranslateTable[(UCHAR)CustomCPString[0x09]];
case 0x09:
UnicodeString[0x08] = TranslateTable[(UCHAR)CustomCPString[0x08]];
case 0x08:
UnicodeString[0x07] = TranslateTable[(UCHAR)CustomCPString[0x07]];
case 0x07:
UnicodeString[0x06] = TranslateTable[(UCHAR)CustomCPString[0x06]];
case 0x06:
UnicodeString[0x05] = TranslateTable[(UCHAR)CustomCPString[0x05]];
case 0x05:
UnicodeString[0x04] = TranslateTable[(UCHAR)CustomCPString[0x04]];
case 0x04:
UnicodeString[0x03] = TranslateTable[(UCHAR)CustomCPString[0x03]];
case 0x03:
UnicodeString[0x02] = TranslateTable[(UCHAR)CustomCPString[0x02]];
case 0x02:
UnicodeString[0x01] = TranslateTable[(UCHAR)CustomCPString[0x01]];
case 0x01:
UnicodeString[0x00] = TranslateTable[(UCHAR)CustomCPString[0x00]];
case 0x00:
;
}
if ( LoopCount > 0x10 ) {
LoopCount -= 0x10;
CustomCPString += 0x10;
UnicodeString += 0x10;
goto quick_copy;
}
/* end of copy... */
} else {
register USHORT Entry;
PWCH UnicodeStringAnchor = UnicodeString;
PUSHORT NlsCustomLeadByteInfo = CustomCP->DBCSOffsets;
// The CP is a multibyte code page. Check each character
// to see if it is a lead byte before doing the translation.
MaxCharsInUnicodeString = MaxBytesInUnicodeString / sizeof(WCHAR);
TranslateTable = (PUSHORT)(CustomCP->DBCSOffsets);
while (MaxCharsInUnicodeString && BytesInCustomCPString) {
MaxCharsInUnicodeString--;
BytesInCustomCPString--;
if (NlsCustomLeadByteInfo[*(PUCHAR)CustomCPString]) {
// Lead byte - Make sure there is a trail byte. If not,
// pass back a space rather than an error. Some 3.x
// applications pass incorrect strings and don't expect
// to get an error.
if (BytesInCustomCPString == 0)
{
*UnicodeString++ = UnicodeNull;
break;
}
// Get the unicode character.
Entry = NlsCustomLeadByteInfo[*(PUCHAR)CustomCPString++];
*UnicodeString = TranslateTable[ Entry + *(PUCHAR)CustomCPString++ ];
UnicodeString++;
// Decrement count of bytes in multibyte string to account
// for the double byte character.
BytesInCustomCPString--;
} else {
// Single byte character.
*UnicodeString++ = (CustomCP->MultiByteTable)[*(PUCHAR)CustomCPString++];
}
}
if (ARGUMENT_PRESENT(BytesInUnicodeString))
*BytesInUnicodeString = (ULONG)((PCH)UnicodeString - (PCH)UnicodeStringAnchor);
}
// Check if we were able to use all of the source CustomCP String
return ( BytesInCustomCPString <= MaxCharsInUnicodeString ) ?
STATUS_SUCCESS :
STATUS_BUFFER_OVERFLOW;
}
NTSTATUS
RtlUnicodeToCustomCPN(
IN PCPTABLEINFO CustomCP,
OUT PCH CustomCPString,
IN ULONG MaxBytesInCustomCPString,
OUT PULONG BytesInCustomCPString OPTIONAL,
IN PWCH UnicodeString,
IN ULONG BytesInUnicodeString)
/*++
Routine Description:
This functions converts the specified unicode source string into an
CustomCP string. The translation is done with respect to the
CustomCP Code Page specified by CustomCp.
Arguments:
CustomCP - Supplies the address of the code page that translations
are done relative to
CustomCPString - Returns an CustomCP string that is equivalent to the
unicode source string. If the translation can not be done,
an error is returned.
MaxBytesInCustomCPString - Supplies the maximum number of bytes to be
written to CustomCPString. If this causes CustomCPString to be a
truncated equivalent of UnicodeString, no error condition results.
BytesInCustomCPString - Returns the number of bytes in the returned
CustomCP string pointed to by CustomCPString.
UnicodeString - Supplies the unicode source string that is to be
converted to CustomCP.
BytesInUnicodeString - The number of bytes in the the string pointed to by
UnicodeString.
Return Value:
SUCCESS - The conversion was successful
STATUS_BUFFER_OVERFLOW - MaxBytesInUnicodeString was not enough to hold
the whole CustomCP string. It was converted correct to the point though.
--*/
{
ULONG TmpCount;
ULONG LoopCount;
PCH TranslateTable;
PUSHORT WideTranslateTable;
ULONG CharsInUnicodeString;
RTL_PAGED_CODE();
// Convert Unicode byte count to character count. Byte count of
// multibyte string is equivalent to character count.
if (!(CustomCP->DBCSCodePage)) {
CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
LoopCount = (CharsInUnicodeString < MaxBytesInCustomCPString) ?
CharsInUnicodeString : MaxBytesInCustomCPString;
if (ARGUMENT_PRESENT(BytesInCustomCPString))
*BytesInCustomCPString = LoopCount;
TranslateTable = CustomCP->WideCharTable;
TmpCount = LoopCount & 0x0F;
UnicodeString += TmpCount;
CustomCPString += TmpCount;
do
{
switch( TmpCount ) {
default:
UnicodeString += 0x10;
CustomCPString += 0x10;
CustomCPString[-0x10] = TranslateTable[UnicodeString[-0x10]];
case 0x0F:
CustomCPString[-0x0F] = TranslateTable[UnicodeString[-0x0F]];
case 0x0E:
CustomCPString[-0x0E] = TranslateTable[UnicodeString[-0x0E]];
case 0x0D:
CustomCPString[-0x0D] = TranslateTable[UnicodeString[-0x0D]];
case 0x0C:
CustomCPString[-0x0C] = TranslateTable[UnicodeString[-0x0C]];
case 0x0B:
CustomCPString[-0x0B] = TranslateTable[UnicodeString[-0x0B]];
case 0x0A:
CustomCPString[-0x0A] = TranslateTable[UnicodeString[-0x0A]];
case 0x09:
CustomCPString[-0x09] = TranslateTable[UnicodeString[-0x09]];
case 0x08:
CustomCPString[-0x08] = TranslateTable[UnicodeString[-0x08]];
case 0x07:
CustomCPString[-0x07] = TranslateTable[UnicodeString[-0x07]];
case 0x06:
CustomCPString[-0x06] = TranslateTable[UnicodeString[-0x06]];
case 0x05:
CustomCPString[-0x05] = TranslateTable[UnicodeString[-0x05]];
case 0x04:
CustomCPString[-0x04] = TranslateTable[UnicodeString[-0x04]];
case 0x03:
CustomCPString[-0x03] = TranslateTable[UnicodeString[-0x03]];
case 0x02:
CustomCPString[-0x02] = TranslateTable[UnicodeString[-0x02]];
case 0x01:
CustomCPString[-0x01] = TranslateTable[UnicodeString[-0x01]];
case 0x00:
;
}
LoopCount -= TmpCount;
TmpCount = 0x10;
} while ( LoopCount > 0 );
/* end of copy... */
} else {
USHORT MbChar;
PCH CustomCPStringAnchor = CustomCPString;
WideTranslateTable = CustomCP->WideCharTable;
CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
while (CharsInUnicodeString && MaxBytesInCustomCPString) {
MbChar = WideTranslateTable[ *UnicodeString++ ];
if (HIBYTE(MbChar) != 0) {
// Need at least 2 bytes to copy a double byte char.
// Don't want to truncate in the middle of a DBCS char.
if (MaxBytesInCustomCPString-- < 2) {
break;
}
*CustomCPString++ = HIBYTE(MbChar); // lead byte
}
*CustomCPString++ = LOBYTE(MbChar);
MaxBytesInCustomCPString--;
CharsInUnicodeString--;
}
if (ARGUMENT_PRESENT(BytesInCustomCPString))
*BytesInCustomCPString = (ULONG)(CustomCPString - CustomCPStringAnchor);
}
// Check if we were able to use all of the source Unicode String
return ( CharsInUnicodeString <= MaxBytesInCustomCPString ) ?
STATUS_SUCCESS :
STATUS_BUFFER_OVERFLOW;
}
NTSTATUS
RtlUpcaseUnicodeToCustomCPN(
IN PCPTABLEINFO CustomCP,
OUT PCH CustomCPString,
IN ULONG MaxBytesInCustomCPString,
OUT PULONG BytesInCustomCPString OPTIONAL,
IN PWCH UnicodeString,
IN ULONG BytesInUnicodeString)
/*++
Routine Description:
This functions upper cases the specified unicode source string and
converts it into a CustomCP string. The translation is done with
respect to the CustomCP Code Page specified by CustomCp.
Arguments:
CustomCP - Supplies the address of the code page that translations
are done relative to
CustomCPString - Returns an CustomCP string that is equivalent to the
unicode source string. If the translation can not be done,
an error is returned.
MaxBytesInCustomCPString - Supplies the maximum number of bytes to be
written to CustomCPString. If this causes CustomCPString to be a
truncated equivalent of UnicodeString, no error condition results.
BytesInCustomCPString - Returns the number of bytes in the returned
CustomCP string pointed to by CustomCPString.
UnicodeString - Supplies the unicode source string that is to be
converted to CustomCP.
BytesInUnicodeString - The number of bytes in the the string pointed
to by UnicodeString.
Return Value:
SUCCESS - The conversion was successful
STATUS_BUFFER_OVERFLOW - MaxBytesInUnicodeString was not enough to
hold the whole CustomCP string. It was converted correctly to
that point, though.
--*/
{
ULONG TmpCount;
ULONG LoopCount;
PCH TranslateTable;
PUSHORT WideTranslateTable;
ULONG CharsInUnicodeString;
UCHAR SbChar;
WCHAR UnicodeChar;
RTL_PAGED_CODE();
// Convert Unicode byte count to character count. Byte count of
// multibyte string is equivalent to character count.
if (!(CustomCP->DBCSCodePage)) {
CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
LoopCount = (CharsInUnicodeString < MaxBytesInCustomCPString) ?
CharsInUnicodeString : MaxBytesInCustomCPString;
if (ARGUMENT_PRESENT(BytesInCustomCPString))
*BytesInCustomCPString = LoopCount;
TranslateTable = CustomCP->WideCharTable;
TmpCount = LoopCount & 0x0F;
UnicodeString += TmpCount;
CustomCPString += TmpCount;
do
{
// Convert to Single Byte and back to Unicode before upper
// casing to ensure the visual best fits are converted and
// upper cased properly.
switch( TmpCount ) {
default:
UnicodeString += 0x10;
CustomCPString += 0x10;
SbChar = TranslateTable[UnicodeString[-0x10]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x10] = TranslateTable[UnicodeChar];
case 0x0F:
SbChar = TranslateTable[UnicodeString[-0x0F]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x0F] = TranslateTable[UnicodeChar];
case 0x0E:
SbChar = TranslateTable[UnicodeString[-0x0E]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x0E] = TranslateTable[UnicodeChar];
case 0x0D:
SbChar = TranslateTable[UnicodeString[-0x0D]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x0D] = TranslateTable[UnicodeChar];
case 0x0C:
SbChar = TranslateTable[UnicodeString[-0x0C]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x0C] = TranslateTable[UnicodeChar];
case 0x0B:
SbChar = TranslateTable[UnicodeString[-0x0B]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x0B] = TranslateTable[UnicodeChar];
case 0x0A:
SbChar = TranslateTable[UnicodeString[-0x0A]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x0A] = TranslateTable[UnicodeChar];
case 0x09:
SbChar = TranslateTable[UnicodeString[-0x09]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x09] = TranslateTable[UnicodeChar];
case 0x08:
SbChar = TranslateTable[UnicodeString[-0x08]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x08] = TranslateTable[UnicodeChar];
case 0x07:
SbChar = TranslateTable[UnicodeString[-0x07]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x07] = TranslateTable[UnicodeChar];
case 0x06:
SbChar = TranslateTable[UnicodeString[-0x06]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x06] = TranslateTable[UnicodeChar];
case 0x05:
SbChar = TranslateTable[UnicodeString[-0x05]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x05] = TranslateTable[UnicodeChar];
case 0x04:
SbChar = TranslateTable[UnicodeString[-0x04]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x04] = TranslateTable[UnicodeChar];
case 0x03:
SbChar = TranslateTable[UnicodeString[-0x03]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x03] = TranslateTable[UnicodeChar];
case 0x02:
SbChar = TranslateTable[UnicodeString[-0x02]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x02] = TranslateTable[UnicodeChar];
case 0x01:
SbChar = TranslateTable[UnicodeString[-0x01]];
UnicodeChar = (CustomCP->MultiByteTable)[SbChar];
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
CustomCPString[-0x01] = TranslateTable[UnicodeChar];
case 0x00:
;
}
LoopCount -= TmpCount;
TmpCount = 0x10;
} while ( LoopCount > 0 );
/* end of copy... */
} else {
USHORT MbChar;
register USHORT Entry;
PCH CustomCPStringAnchor = CustomCPString;
PUSHORT NlsCustomLeadByteInfo = CustomCP->DBCSOffsets;
WideTranslateTable = CustomCP->WideCharTable;
CharsInUnicodeString = BytesInUnicodeString / sizeof(WCHAR);
while ( CharsInUnicodeString && MaxBytesInCustomCPString ) {
// Convert to Single Byte and back to Unicode before upper
// casing to ensure the visual best fits are converted and
// upper cased properly.
MbChar = WideTranslateTable[ *UnicodeString++ ];
if (NlsCustomLeadByteInfo[HIBYTE(MbChar)]) {
// Lead byte - translate the trail byte using the table
// that corresponds to this lead byte.
Entry = NlsCustomLeadByteInfo[HIBYTE(MbChar)];
UnicodeChar = NlsCustomLeadByteInfo[ Entry + LOBYTE(MbChar) ];
} else {
// Single byte character.
UnicodeChar = (CustomCP->MultiByteTable)[LOBYTE(MbChar)];
}
UnicodeChar = (WCHAR)NLS_UPCASE(UnicodeChar);
MbChar = WideTranslateTable[UnicodeChar];
if (HIBYTE(MbChar) != 0) {
// Need at least 2 bytes to copy a double byte char.
// Don't want to truncate in the middle of a DBCS char.
if (MaxBytesInCustomCPString-- < 2) {
break;
}
*CustomCPString++ = HIBYTE(MbChar); // lead byte
}
*CustomCPString++ = LOBYTE(MbChar);
MaxBytesInCustomCPString--;
CharsInUnicodeString--;
}
if (ARGUMENT_PRESENT(BytesInCustomCPString))
*BytesInCustomCPString = (ULONG)(CustomCPString - CustomCPStringAnchor);
}
// Check if we were able to use all of the source Unicode String
return ( CharsInUnicodeString <= MaxBytesInCustomCPString ) ?
STATUS_SUCCESS :
STATUS_BUFFER_OVERFLOW;
}
#define MB_TBL_SIZE 256 /* size of MB tables */
#define GLYPH_TBL_SIZE MB_TBL_SIZE /* size of GLYPH tables */
#define DBCS_TBL_SIZE 256 /* size of DBCS tables */
#define GLYPH_HEADER 1 /* size of GLYPH table header */
#define DBCS_HEADER 1 /* size of DBCS table header */
#define LANG_HEADER 1 /* size of LANGUAGE file header */
#define UP_HEADER 1 /* size of UPPERCASE table header */
#define LO_HEADER 1 /* size of LOWERCASE table header */
VOID
RtlInitCodePageTable(
IN PUSHORT TableBase,
OUT PCPTABLEINFO CodePageTable
)
{
USHORT offMB;
USHORT offWC;
PUSHORT pGlyph;
PUSHORT pRange;
RTL_PAGED_CODE();
// Get the offsets.
offMB = TableBase[0];
offWC = offMB + TableBase[offMB];
// Attach Code Page Info to CP hash node.
CodePageTable->CodePage = TableBase[1];
CodePageTable->MaximumCharacterSize = TableBase[2];
CodePageTable->DefaultChar = TableBase[3]; // default character (MB)
CodePageTable->UniDefaultChar = TableBase[4]; // default character (Unicode)
CodePageTable->TransDefaultChar = TableBase[5]; // trans of default char (Unicode)
CodePageTable->TransUniDefaultChar = TableBase[6]; // trans of Uni default char (MB)
RtlMoveMemory(
&CodePageTable->LeadByte,
&TableBase[7],
MAXIMUM_LEADBYTES
);
CodePageTable->MultiByteTable = (TableBase + offMB + 1);
pGlyph = CodePageTable->MultiByteTable + MB_TBL_SIZE;
if (pGlyph[0] != 0) {
pRange = CodePageTable->DBCSRanges = pGlyph + GLYPH_HEADER + GLYPH_TBL_SIZE;
}
else {
pRange = CodePageTable->DBCSRanges = pGlyph + GLYPH_HEADER;
}
// Attach DBCS information to CP hash node.
if (pRange[0] > 0) {
CodePageTable->DBCSOffsets = pRange + DBCS_HEADER;
CodePageTable->DBCSCodePage = 1;
}
else {
CodePageTable->DBCSCodePage = 0;
CodePageTable->DBCSOffsets = NULL;
}
CodePageTable->WideCharTable = (TableBase + offWC + 1);
}
VOID
RtlpInitUpcaseTable(
IN PUSHORT TableBase,
OUT PNLSTABLEINFO CodePageTable
)
{
USHORT offUP;
USHORT offLO;
// Get the offsets.
offUP = LANG_HEADER;
offLO = offUP + TableBase[offUP];
CodePageTable->UpperCaseTable = TableBase + offUP + UP_HEADER;
CodePageTable->LowerCaseTable = TableBase + offLO + LO_HEADER;
}
VOID
RtlInitNlsTables(
IN PUSHORT AnsiNlsBase,
IN PUSHORT OemNlsBase,
IN PUSHORT LanguageNlsBase,
OUT PNLSTABLEINFO TableInfo
)
{
RTL_PAGED_CODE();
RtlInitCodePageTable(AnsiNlsBase,&TableInfo->AnsiTableInfo);
RtlInitCodePageTable(OemNlsBase,&TableInfo->OemTableInfo);
RtlpInitUpcaseTable(LanguageNlsBase,TableInfo);
}
VOID
RtlResetRtlTranslations(
PNLSTABLEINFO TableInfo
)
{
RTL_PAGED_CODE();
if ( TableInfo->AnsiTableInfo.DBCSCodePage ) {
RtlMoveMemory(NlsLeadByteInfo,TableInfo->AnsiTableInfo.DBCSOffsets,DBCS_TBL_SIZE*sizeof(USHORT));
}
else {
RtlZeroMemory(NlsLeadByteInfo,DBCS_TBL_SIZE*sizeof(USHORT));
}
NlsMbAnsiCodePageTables = (PUSHORT)TableInfo->AnsiTableInfo.DBCSOffsets;
NlsAnsiToUnicodeData = TableInfo->AnsiTableInfo.MultiByteTable;
NlsUnicodeToAnsiData = (PCH)TableInfo->AnsiTableInfo.WideCharTable;
NlsUnicodeToMbAnsiData = (PUSHORT)TableInfo->AnsiTableInfo.WideCharTable;
NlsMbCodePageTag = TableInfo->AnsiTableInfo.DBCSCodePage ? TRUE : FALSE;
NlsAnsiCodePage = TableInfo->AnsiTableInfo.CodePage;
if ( TableInfo->OemTableInfo.DBCSCodePage ) {
RtlMoveMemory(NlsOemLeadByteInfo,TableInfo->OemTableInfo.DBCSOffsets,DBCS_TBL_SIZE*sizeof(USHORT));
}
else {
RtlZeroMemory(NlsOemLeadByteInfo,DBCS_TBL_SIZE*sizeof(USHORT));
}
NlsMbOemCodePageTables = (PUSHORT)TableInfo->OemTableInfo.DBCSOffsets;
NlsOemToUnicodeData = TableInfo->OemTableInfo.MultiByteTable;
NlsUnicodeToOemData = (PCH)TableInfo->OemTableInfo.WideCharTable;
NlsUnicodeToMbOemData = (PUSHORT)TableInfo->OemTableInfo.WideCharTable;
NlsMbOemCodePageTag = TableInfo->OemTableInfo.DBCSCodePage ? TRUE : FALSE;
NlsOemCodePage = TableInfo->OemTableInfo.CodePage;
OemDefaultChar = TableInfo->OemTableInfo.DefaultChar;
OemTransUniDefaultChar = TableInfo->OemTableInfo.TransDefaultChar;
Nls844UnicodeUpcaseTable = TableInfo->UpperCaseTable;
Nls844UnicodeLowercaseTable = TableInfo->LowerCaseTable;
UnicodeDefaultChar = TableInfo->AnsiTableInfo.UniDefaultChar;
}
void
RtlGetDefaultCodePage(
OUT PUSHORT AnsiCodePage,
OUT PUSHORT OemCodePage
)
{
RTL_PAGED_CODE();
*AnsiCodePage = NlsAnsiCodePage;
*OemCodePage = NlsOemCodePage;
}